diff --git a/src/RpcServer/RpcServer.Blockchain.cs b/src/RpcServer/RpcServer.Blockchain.cs index c09514107..9cc1abaaf 100644 --- a/src/RpcServer/RpcServer.Blockchain.cs +++ b/src/RpcServer/RpcServer.Blockchain.cs @@ -197,6 +197,56 @@ protected virtual JToken GetStorage(JArray _params) return Convert.ToBase64String(item.Value.Span); } + [RpcMethod] + protected virtual JToken FindStorage(JArray _params) + { + using var snapshot = system.GetSnapshot(); + if (!int.TryParse(_params[0].AsString(), out int id)) + { + UInt160 hash = UInt160.Parse(_params[0].AsString()); + ContractState contract = NativeContract.ContractManagement.GetContract(snapshot, hash); + if (contract is null) throw new RpcException(-100, "Unknown contract"); + id = contract.Id; + } + + byte[] prefix = Convert.FromBase64String(_params[1].AsString()); + byte[] prefix_key = StorageKey.CreateSearchPrefix(id, prefix); + + if (!int.TryParse(_params[2].AsString(), out int start)) + { + start = 0; + } + + JObject json = new(); + JArray jarr = new(); + int pageSize = settings.FindStoragePageSize; + int i = 0; + + using (var iter = snapshot.Find(prefix_key).Skip(count: start).GetEnumerator()) + { + var hasMore = false; + while (iter.MoveNext()) + { + if (i == pageSize) + { + hasMore = true; + break; + } + + JObject j = new(); + j["key"] = Convert.ToBase64String(iter.Current.Key.Key.Span); + j["value"] = Convert.ToBase64String(iter.Current.Value.Value.Span); + jarr.Add(j); + i++; + } + json["truncated"] = hasMore; + } + + json["next"] = start + i; + json["results"] = jarr; + return json; + } + [RpcMethod] protected virtual JToken GetTransactionHeight(JArray _params) { diff --git a/src/RpcServer/RpcServer.csproj b/src/RpcServer/RpcServer.csproj index 600eec6c3..77a4c158e 100644 --- a/src/RpcServer/RpcServer.csproj +++ b/src/RpcServer/RpcServer.csproj @@ -4,5 +4,5 @@ Neo.Plugins.RpcServer Neo.Plugins - + diff --git a/src/RpcServer/Settings.cs b/src/RpcServer/Settings.cs index 8bf8d0c95..6d5b1202a 100644 --- a/src/RpcServer/Settings.cs +++ b/src/RpcServer/Settings.cs @@ -45,6 +45,7 @@ public record RpcServerSettings public string[] DisabledMethods { get; init; } public bool SessionEnabled { get; init; } public TimeSpan SessionExpirationTime { get; init; } + public int FindStoragePageSize { get; init; } public static RpcServerSettings Default { get; } = new RpcServerSettings { @@ -60,7 +61,8 @@ public record RpcServerSettings DisabledMethods = Array.Empty(), MaxConcurrentConnections = 40, SessionEnabled = false, - SessionExpirationTime = TimeSpan.FromSeconds(60) + SessionExpirationTime = TimeSpan.FromSeconds(60), + FindStoragePageSize = 50 }; public static RpcServerSettings Load(IConfigurationSection section) => new() @@ -80,7 +82,8 @@ public record RpcServerSettings DisabledMethods = section.GetSection("DisabledMethods").GetChildren().Select(p => p.Get()).ToArray(), MaxConcurrentConnections = section.GetValue("MaxConcurrentConnections", Default.MaxConcurrentConnections), SessionEnabled = section.GetValue("SessionEnabled", Default.SessionEnabled), - SessionExpirationTime = TimeSpan.FromSeconds(section.GetValue("SessionExpirationTime", (int)Default.SessionExpirationTime.TotalSeconds)) + SessionExpirationTime = TimeSpan.FromSeconds(section.GetValue("SessionExpirationTime", (int)Default.SessionExpirationTime.TotalSeconds)), + FindStoragePageSize = section.GetValue("FindStoragePageSize", Default.FindStoragePageSize) }; } } diff --git a/src/RpcServer/config.json b/src/RpcServer/config.json index 89bc7f578..cfb60752f 100644 --- a/src/RpcServer/config.json +++ b/src/RpcServer/config.json @@ -17,7 +17,8 @@ "MaxStackSize": 65535, "DisabledMethods": [ "openwallet" ], "SessionEnabled": false, - "SessionExpirationTime": 60 + "SessionExpirationTime": 60, + "FindStoragePageSize": 50 } ] }