From c35d76c9531166f8c599699fdc70a685ad7c4e2a Mon Sep 17 00:00:00 2001 From: erikzhang Date: Fri, 29 Jun 2018 17:23:47 +0800 Subject: [PATCH 001/183] add SimplePolicy --- SimplePolicy/ConsensusLogger.cs | 28 +++++++++++++ SimplePolicy/Settings.cs | 59 +++++++++++++++++++++++++++ SimplePolicy/SimplePolicy.csproj | 20 +++++++++ SimplePolicy/SimplePolicy/config.json | 10 +++++ SimplePolicy/SimplePolicyPlugin.cs | 48 ++++++++++++++++++++++ neo-plugins.sln | 25 ++++++++++++ 6 files changed, 190 insertions(+) create mode 100644 SimplePolicy/ConsensusLogger.cs create mode 100644 SimplePolicy/Settings.cs create mode 100644 SimplePolicy/SimplePolicy.csproj create mode 100644 SimplePolicy/SimplePolicy/config.json create mode 100644 SimplePolicy/SimplePolicyPlugin.cs create mode 100644 neo-plugins.sln diff --git a/SimplePolicy/ConsensusLogger.cs b/SimplePolicy/ConsensusLogger.cs new file mode 100644 index 000000000..0c09ce50c --- /dev/null +++ b/SimplePolicy/ConsensusLogger.cs @@ -0,0 +1,28 @@ +using Neo.Consensus; +using System; +using System.IO; + +namespace Neo.Plugins +{ + public class ConsensusLogger : LogPlugin + { + private static string log_dictionary = Path.Combine(AppContext.BaseDirectory, "Logs"); + + public override string Name => nameof(ConsensusLogger); + + protected override void OnLog(string source, LogLevel level, string message) + { + if (source != nameof(ConsensusService)) return; + DateTime now = DateTime.Now; + string line = $"[{now.TimeOfDay:hh\\:mm\\:ss}] {message}"; + Console.WriteLine(line); + if (string.IsNullOrEmpty(log_dictionary)) return; + lock (log_dictionary) + { + Directory.CreateDirectory(log_dictionary); + string path = Path.Combine(log_dictionary, $"{now:yyyy-MM-dd}.log"); + File.AppendAllLines(path, new[] { line }); + } + } + } +} diff --git a/SimplePolicy/Settings.cs b/SimplePolicy/Settings.cs new file mode 100644 index 000000000..52efd35f3 --- /dev/null +++ b/SimplePolicy/Settings.cs @@ -0,0 +1,59 @@ +using Microsoft.Extensions.Configuration; +using Neo.Wallets; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; + +namespace Neo.Plugins +{ + internal class Settings + { + public int MaxTransactionsPerBlock { get; } + public int MaxFreeTransactionsPerBlock { get; } + public BlockedAccounts BlockedAccounts { get; } + + public static Settings Default { get; } + + static Settings() + { + string path = Path.Combine(Assembly.GetExecutingAssembly().GetName().Name, "config.json"); + IConfigurationSection section = new ConfigurationBuilder().AddJsonFile(path).Build().GetSection("PluginConfiguration"); + Default = new Settings(section); + } + + public Settings(IConfigurationSection section) + { + this.MaxTransactionsPerBlock = GetValueOrDefault(section.GetSection("MaxTransactionsPerBlock"), 500, p => int.Parse(p)); + this.MaxFreeTransactionsPerBlock = GetValueOrDefault(section.GetSection("MaxFreeTransactionsPerBlock"), 20, p => int.Parse(p)); + this.BlockedAccounts = new BlockedAccounts(section.GetSection("BlockedAccounts")); + } + + public T GetValueOrDefault(IConfigurationSection section, T defaultValue, Func selector) + { + if (section.Value == null) return defaultValue; + return selector(section.Value); + } + } + + internal enum PolicyType : byte + { + AllowAll, + DenyAll, + AllowList, + DenyList + } + + internal class BlockedAccounts + { + public PolicyType Type { get; } + public HashSet List { get; } + + public BlockedAccounts(IConfigurationSection section) + { + this.Type = (PolicyType)Enum.Parse(typeof(PolicyType), section.GetSection("Type").Value, true); + this.List = new HashSet(section.GetSection("List").GetChildren().Select(p => Wallet.ToScriptHash(p.Value))); + } + } +} diff --git a/SimplePolicy/SimplePolicy.csproj b/SimplePolicy/SimplePolicy.csproj new file mode 100644 index 000000000..5a2514683 --- /dev/null +++ b/SimplePolicy/SimplePolicy.csproj @@ -0,0 +1,20 @@ + + + + 3.0.0-preview2 + netstandard2.0;net47 + Neo.Plugins + + + + + PreserveNewest + PreserveNewest + + + + + + + + diff --git a/SimplePolicy/SimplePolicy/config.json b/SimplePolicy/SimplePolicy/config.json new file mode 100644 index 000000000..ed20082d9 --- /dev/null +++ b/SimplePolicy/SimplePolicy/config.json @@ -0,0 +1,10 @@ +{ + "PluginConfiguration": { + "MaxTransactionsPerBlock": 500, + "MaxFreeTransactionsPerBlock": 20, + "BlockedAccounts": { + "Type": "AllowAll", + "List": [] + } + } +} diff --git a/SimplePolicy/SimplePolicyPlugin.cs b/SimplePolicy/SimplePolicyPlugin.cs new file mode 100644 index 000000000..eff28f6b2 --- /dev/null +++ b/SimplePolicy/SimplePolicyPlugin.cs @@ -0,0 +1,48 @@ +using Neo.Network.P2P.Payloads; +using Neo.SmartContract; +using System.Collections.Generic; +using System.Linq; + +namespace Neo.Plugins +{ + public class SimplePolicyPlugin : PolicyPlugin + { + public override string Name => nameof(SimplePolicyPlugin); + + protected override bool CheckPolicy(Transaction tx) + { + switch (Settings.Default.BlockedAccounts.Type) + { + case PolicyType.AllowAll: + return true; + case PolicyType.AllowList: + return tx.Witnesses.All(p => Settings.Default.BlockedAccounts.List.Contains(p.VerificationScript.ToScriptHash())) || tx.Outputs.All(p => Settings.Default.BlockedAccounts.List.Contains(p.ScriptHash)); + case PolicyType.DenyList: + return tx.Witnesses.All(p => !Settings.Default.BlockedAccounts.List.Contains(p.VerificationScript.ToScriptHash())) && tx.Outputs.All(p => !Settings.Default.BlockedAccounts.List.Contains(p.ScriptHash)); + default: + return false; + } + } + + protected override IEnumerable Filter(IEnumerable transactions) + { + Transaction[] array = transactions.ToArray(); + if (array.Length + 1 <= Settings.Default.MaxTransactionsPerBlock) + return array; + transactions = array.OrderByDescending(p => p.NetworkFee / p.Size).Take(Settings.Default.MaxTransactionsPerBlock - 1); + return FilterFree(transactions); + } + + private IEnumerable FilterFree(IEnumerable transactions) + { + int count = 0; + foreach (Transaction tx in transactions) + if (tx.NetworkFee > Fixed8.Zero || tx.SystemFee > Fixed8.Zero) + yield return tx; + else if (count++ < Settings.Default.MaxFreeTransactionsPerBlock) + yield return tx; + else + yield break; + } + } +} diff --git a/neo-plugins.sln b/neo-plugins.sln new file mode 100644 index 000000000..53d847ebf --- /dev/null +++ b/neo-plugins.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.27428.2027 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SimplePolicy", "SimplePolicy\SimplePolicy.csproj", "{322C366E-F891-47FD-A039-0FEF79BCB6D5}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {322C366E-F891-47FD-A039-0FEF79BCB6D5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {322C366E-F891-47FD-A039-0FEF79BCB6D5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {322C366E-F891-47FD-A039-0FEF79BCB6D5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {322C366E-F891-47FD-A039-0FEF79BCB6D5}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {61D3ADE6-BBFC-402D-AB42-1C71C9F9EDE3} + EndGlobalSection +EndGlobal From 60fce608fdd8c53b020833c02f00189ab515f8c9 Mon Sep 17 00:00:00 2001 From: erikzhang Date: Fri, 29 Jun 2018 19:20:53 +0800 Subject: [PATCH 002/183] add ApplicationLogs --- ApplicationLogs/ApplicationLogs.csproj | 20 ++++++++ ApplicationLogs/ApplicationLogs/config.json | 5 ++ ApplicationLogs/LogReader.cs | 27 +++++++++++ ApplicationLogs/Logger.cs | 51 +++++++++++++++++++++ ApplicationLogs/Settings.cs | 23 ++++++++++ SimplePolicy/ConsensusLogger.cs | 28 ----------- SimplePolicy/Settings.cs | 5 +- SimplePolicy/SimplePolicy.csproj | 4 +- SimplePolicy/SimplePolicyPlugin.cs | 28 +++++++++-- neo-plugins.sln | 6 +++ 10 files changed, 158 insertions(+), 39 deletions(-) create mode 100644 ApplicationLogs/ApplicationLogs.csproj create mode 100644 ApplicationLogs/ApplicationLogs/config.json create mode 100644 ApplicationLogs/LogReader.cs create mode 100644 ApplicationLogs/Logger.cs create mode 100644 ApplicationLogs/Settings.cs delete mode 100644 SimplePolicy/ConsensusLogger.cs diff --git a/ApplicationLogs/ApplicationLogs.csproj b/ApplicationLogs/ApplicationLogs.csproj new file mode 100644 index 000000000..6e6278929 --- /dev/null +++ b/ApplicationLogs/ApplicationLogs.csproj @@ -0,0 +1,20 @@ + + + + 3.0.0-preview2-02 + netstandard2.0;net47 + Neo.Plugins + + + + + PreserveNewest + PreserveNewest + + + + + + + + diff --git a/ApplicationLogs/ApplicationLogs/config.json b/ApplicationLogs/ApplicationLogs/config.json new file mode 100644 index 000000000..b5f08f6f0 --- /dev/null +++ b/ApplicationLogs/ApplicationLogs/config.json @@ -0,0 +1,5 @@ +{ + "PluginConfiguration": { + "Path": "ApplicationLogs_{0}" + } +} diff --git a/ApplicationLogs/LogReader.cs b/ApplicationLogs/LogReader.cs new file mode 100644 index 000000000..2103be329 --- /dev/null +++ b/ApplicationLogs/LogReader.cs @@ -0,0 +1,27 @@ +using Microsoft.AspNetCore.Http; +using Neo.IO.Json; +using Neo.Network.RPC; +using System.IO; + +namespace Neo.Plugins +{ + public class LogReader : Plugin, IRpcPlugin + { + public override string Name => "ApplicationLogs"; + + public LogReader() + { + System.ActorSystem.ActorOf(Logger.Props(System.Blockchain)); + } + + public JObject OnProcess(HttpContext context, string method, JArray _params) + { + if (method != "getapplicationlog") return null; + UInt256 hash = UInt256.Parse(_params[0].AsString()); + string path = Path.Combine(Settings.Default.Path, $"{hash}.json"); + return File.Exists(path) + ? JObject.Parse(File.ReadAllText(path)) + : throw new RpcException(-100, "Unknown transaction"); + } + } +} diff --git a/ApplicationLogs/Logger.cs b/ApplicationLogs/Logger.cs new file mode 100644 index 000000000..cbb495263 --- /dev/null +++ b/ApplicationLogs/Logger.cs @@ -0,0 +1,51 @@ +using Akka.Actor; +using Neo.IO.Json; +using Neo.Ledger; +using Neo.VM; +using System.IO; +using System.Linq; + +namespace Neo.Plugins +{ + internal class Logger : UntypedActor + { + public Logger(IActorRef blockchain) + { + blockchain.Tell(new Blockchain.Register()); + } + + protected override void OnReceive(object message) + { + if (message is Blockchain.ApplicationExecuted e) + { + JObject json = new JObject(); + json["txid"] = e.Transaction.Hash.ToString(); + json["executions"] = e.ExecutionResults.Select(p => + { + JObject execution = new JObject(); + execution["trigger"] = p.Trigger; + execution["contract"] = p.ScriptHash.ToString(); + execution["vmstate"] = p.VMState; + execution["gas_consumed"] = p.GasConsumed.ToString(); + execution["stack"] = p.Stack.Select(q => q.ToParameter().ToJson()).ToArray(); + execution["notifications"] = p.Notifications.Select(q => + { + JObject notification = new JObject(); + notification["contract"] = q.ScriptHash.ToString(); + notification["state"] = q.State.ToParameter().ToJson(); + return notification; + }).ToArray(); + return execution; + }).ToArray(); + Directory.CreateDirectory(Settings.Default.Path); + string path = Path.Combine(Settings.Default.Path, $"{e.Transaction.Hash}.json"); + File.WriteAllText(path, json.ToString()); + } + } + + public static Props Props(IActorRef blockchain) + { + return Akka.Actor.Props.Create(() => new Logger(blockchain)); + } + } +} diff --git a/ApplicationLogs/Settings.cs b/ApplicationLogs/Settings.cs new file mode 100644 index 000000000..393a59a7c --- /dev/null +++ b/ApplicationLogs/Settings.cs @@ -0,0 +1,23 @@ +using Microsoft.Extensions.Configuration; +using Neo.Network.P2P; +using System.Reflection; + +namespace Neo.Plugins +{ + internal class Settings + { + public string Path { get; } + + public static Settings Default { get; } + + static Settings() + { + Default = new Settings(Assembly.GetExecutingAssembly().GetConfiguration()); + } + + public Settings(IConfigurationSection section) + { + this.Path = string.Format(section.GetSection("Path").Value, Message.Magic.ToString("X8")); + } + } +} diff --git a/SimplePolicy/ConsensusLogger.cs b/SimplePolicy/ConsensusLogger.cs deleted file mode 100644 index 0c09ce50c..000000000 --- a/SimplePolicy/ConsensusLogger.cs +++ /dev/null @@ -1,28 +0,0 @@ -using Neo.Consensus; -using System; -using System.IO; - -namespace Neo.Plugins -{ - public class ConsensusLogger : LogPlugin - { - private static string log_dictionary = Path.Combine(AppContext.BaseDirectory, "Logs"); - - public override string Name => nameof(ConsensusLogger); - - protected override void OnLog(string source, LogLevel level, string message) - { - if (source != nameof(ConsensusService)) return; - DateTime now = DateTime.Now; - string line = $"[{now.TimeOfDay:hh\\:mm\\:ss}] {message}"; - Console.WriteLine(line); - if (string.IsNullOrEmpty(log_dictionary)) return; - lock (log_dictionary) - { - Directory.CreateDirectory(log_dictionary); - string path = Path.Combine(log_dictionary, $"{now:yyyy-MM-dd}.log"); - File.AppendAllLines(path, new[] { line }); - } - } - } -} diff --git a/SimplePolicy/Settings.cs b/SimplePolicy/Settings.cs index 52efd35f3..ccd7c9b19 100644 --- a/SimplePolicy/Settings.cs +++ b/SimplePolicy/Settings.cs @@ -2,7 +2,6 @@ using Neo.Wallets; using System; using System.Collections.Generic; -using System.IO; using System.Linq; using System.Reflection; @@ -18,9 +17,7 @@ internal class Settings static Settings() { - string path = Path.Combine(Assembly.GetExecutingAssembly().GetName().Name, "config.json"); - IConfigurationSection section = new ConfigurationBuilder().AddJsonFile(path).Build().GetSection("PluginConfiguration"); - Default = new Settings(section); + Default = new Settings(Assembly.GetExecutingAssembly().GetConfiguration()); } public Settings(IConfigurationSection section) diff --git a/SimplePolicy/SimplePolicy.csproj b/SimplePolicy/SimplePolicy.csproj index 5a2514683..53e8946a3 100644 --- a/SimplePolicy/SimplePolicy.csproj +++ b/SimplePolicy/SimplePolicy.csproj @@ -1,7 +1,7 @@ - 3.0.0-preview2 + 3.0.0-preview2-02 netstandard2.0;net47 Neo.Plugins @@ -14,7 +14,7 @@ - + diff --git a/SimplePolicy/SimplePolicyPlugin.cs b/SimplePolicy/SimplePolicyPlugin.cs index eff28f6b2..1f81dd4d0 100644 --- a/SimplePolicy/SimplePolicyPlugin.cs +++ b/SimplePolicy/SimplePolicyPlugin.cs @@ -1,15 +1,18 @@ -using Neo.Network.P2P.Payloads; +using Neo.Consensus; +using Neo.Network.P2P.Payloads; using Neo.SmartContract; +using System; using System.Collections.Generic; +using System.IO; using System.Linq; namespace Neo.Plugins { - public class SimplePolicyPlugin : PolicyPlugin + public class SimplePolicyPlugin : Plugin, ILogPlugin, IPolicyPlugin { - public override string Name => nameof(SimplePolicyPlugin); + private static string log_dictionary = Path.Combine(AppContext.BaseDirectory, "Logs"); - protected override bool CheckPolicy(Transaction tx) + public bool CheckPolicy(Transaction tx) { switch (Settings.Default.BlockedAccounts.Type) { @@ -24,7 +27,7 @@ protected override bool CheckPolicy(Transaction tx) } } - protected override IEnumerable Filter(IEnumerable transactions) + public IEnumerable Filter(IEnumerable transactions) { Transaction[] array = transactions.ToArray(); if (array.Length + 1 <= Settings.Default.MaxTransactionsPerBlock) @@ -44,5 +47,20 @@ private IEnumerable FilterFree(IEnumerable transaction else yield break; } + + void ILogPlugin.Log(string source, LogLevel level, string message) + { + if (source != nameof(ConsensusService)) return; + DateTime now = DateTime.Now; + string line = $"[{now.TimeOfDay:hh\\:mm\\:ss}] {message}"; + Console.WriteLine(line); + if (string.IsNullOrEmpty(log_dictionary)) return; + lock (log_dictionary) + { + Directory.CreateDirectory(log_dictionary); + string path = Path.Combine(log_dictionary, $"{now:yyyy-MM-dd}.log"); + File.AppendAllLines(path, new[] { line }); + } + } } } diff --git a/neo-plugins.sln b/neo-plugins.sln index 53d847ebf..bc167da85 100644 --- a/neo-plugins.sln +++ b/neo-plugins.sln @@ -5,6 +5,8 @@ VisualStudioVersion = 15.0.27428.2027 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SimplePolicy", "SimplePolicy\SimplePolicy.csproj", "{322C366E-F891-47FD-A039-0FEF79BCB6D5}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ApplicationLogs", "ApplicationLogs\ApplicationLogs.csproj", "{84DA8EA6-EF60-4FCD-B1C6-65C1A8323B3F}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -15,6 +17,10 @@ Global {322C366E-F891-47FD-A039-0FEF79BCB6D5}.Debug|Any CPU.Build.0 = Debug|Any CPU {322C366E-F891-47FD-A039-0FEF79BCB6D5}.Release|Any CPU.ActiveCfg = Release|Any CPU {322C366E-F891-47FD-A039-0FEF79BCB6D5}.Release|Any CPU.Build.0 = Release|Any CPU + {84DA8EA6-EF60-4FCD-B1C6-65C1A8323B3F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {84DA8EA6-EF60-4FCD-B1C6-65C1A8323B3F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {84DA8EA6-EF60-4FCD-B1C6-65C1A8323B3F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {84DA8EA6-EF60-4FCD-B1C6-65C1A8323B3F}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From 90d1d634e040aa96192a496f224af251453c8838 Mon Sep 17 00:00:00 2001 From: erikzhang Date: Tue, 3 Jul 2018 11:34:13 +0800 Subject: [PATCH 003/183] use leveldb in ApplicationLogs --- ApplicationLogs/ApplicationLogs.csproj | 6 +++--- ApplicationLogs/LogReader.cs | 13 +++++++------ ApplicationLogs/Logger.cs | 16 +++++++++------- 3 files changed, 19 insertions(+), 16 deletions(-) diff --git a/ApplicationLogs/ApplicationLogs.csproj b/ApplicationLogs/ApplicationLogs.csproj index 6e6278929..8a91a1fab 100644 --- a/ApplicationLogs/ApplicationLogs.csproj +++ b/ApplicationLogs/ApplicationLogs.csproj @@ -1,7 +1,7 @@ - + - 3.0.0-preview2-02 + 3.0.0-preview2-03 netstandard2.0;net47 Neo.Plugins @@ -14,7 +14,7 @@ - + diff --git a/ApplicationLogs/LogReader.cs b/ApplicationLogs/LogReader.cs index 2103be329..a3d38c765 100644 --- a/ApplicationLogs/LogReader.cs +++ b/ApplicationLogs/LogReader.cs @@ -1,27 +1,28 @@ using Microsoft.AspNetCore.Http; +using Neo.IO.Data.LevelDB; using Neo.IO.Json; using Neo.Network.RPC; -using System.IO; namespace Neo.Plugins { public class LogReader : Plugin, IRpcPlugin { + private readonly DB db = DB.Open(Settings.Default.Path, new Options { CreateIfMissing = true }); + public override string Name => "ApplicationLogs"; public LogReader() { - System.ActorSystem.ActorOf(Logger.Props(System.Blockchain)); + System.ActorSystem.ActorOf(Logger.Props(System.Blockchain, db)); } public JObject OnProcess(HttpContext context, string method, JArray _params) { if (method != "getapplicationlog") return null; UInt256 hash = UInt256.Parse(_params[0].AsString()); - string path = Path.Combine(Settings.Default.Path, $"{hash}.json"); - return File.Exists(path) - ? JObject.Parse(File.ReadAllText(path)) - : throw new RpcException(-100, "Unknown transaction"); + if (!db.TryGet(ReadOptions.Default, hash.ToArray(), out Slice value)) + throw new RpcException(-100, "Unknown transaction"); + return JObject.Parse(value.ToString()); } } } diff --git a/ApplicationLogs/Logger.cs b/ApplicationLogs/Logger.cs index cbb495263..d32a03c97 100644 --- a/ApplicationLogs/Logger.cs +++ b/ApplicationLogs/Logger.cs @@ -1,16 +1,20 @@ using Akka.Actor; +using Neo.IO; +using Neo.IO.Data.LevelDB; using Neo.IO.Json; using Neo.Ledger; using Neo.VM; -using System.IO; using System.Linq; namespace Neo.Plugins { internal class Logger : UntypedActor { - public Logger(IActorRef blockchain) + private readonly DB db; + + public Logger(IActorRef blockchain, DB db) { + this.db = db; blockchain.Tell(new Blockchain.Register()); } @@ -37,15 +41,13 @@ protected override void OnReceive(object message) }).ToArray(); return execution; }).ToArray(); - Directory.CreateDirectory(Settings.Default.Path); - string path = Path.Combine(Settings.Default.Path, $"{e.Transaction.Hash}.json"); - File.WriteAllText(path, json.ToString()); + db.Put(WriteOptions.Default, e.Transaction.Hash.ToArray(), json.ToString()); } } - public static Props Props(IActorRef blockchain) + public static Props Props(IActorRef blockchain, DB db) { - return Akka.Actor.Props.Create(() => new Logger(blockchain)); + return Akka.Actor.Props.Create(() => new Logger(blockchain, db)); } } } From 041c489570107ee3845e8d3c61ea37c334324ec8 Mon Sep 17 00:00:00 2001 From: erikzhang Date: Mon, 9 Jul 2018 14:32:27 +0800 Subject: [PATCH 004/183] update dependency: Neo v3.0.0-preview2-04 Close #1 --- ApplicationLogs/ApplicationLogs.csproj | 4 ++-- SimplePolicy/Settings.cs | 2 +- SimplePolicy/SimplePolicy.csproj | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ApplicationLogs/ApplicationLogs.csproj b/ApplicationLogs/ApplicationLogs.csproj index 8a91a1fab..f268b253e 100644 --- a/ApplicationLogs/ApplicationLogs.csproj +++ b/ApplicationLogs/ApplicationLogs.csproj @@ -1,7 +1,7 @@  - 3.0.0-preview2-03 + 3.0.0-preview2-04 netstandard2.0;net47 Neo.Plugins @@ -14,7 +14,7 @@ - + diff --git a/SimplePolicy/Settings.cs b/SimplePolicy/Settings.cs index ccd7c9b19..3a88c6290 100644 --- a/SimplePolicy/Settings.cs +++ b/SimplePolicy/Settings.cs @@ -50,7 +50,7 @@ internal class BlockedAccounts public BlockedAccounts(IConfigurationSection section) { this.Type = (PolicyType)Enum.Parse(typeof(PolicyType), section.GetSection("Type").Value, true); - this.List = new HashSet(section.GetSection("List").GetChildren().Select(p => Wallet.ToScriptHash(p.Value))); + this.List = new HashSet(section.GetSection("List").GetChildren().Select(p => p.Value.ToScriptHash())); } } } diff --git a/SimplePolicy/SimplePolicy.csproj b/SimplePolicy/SimplePolicy.csproj index 53e8946a3..c7bf20eb8 100644 --- a/SimplePolicy/SimplePolicy.csproj +++ b/SimplePolicy/SimplePolicy.csproj @@ -1,7 +1,7 @@ - + - 3.0.0-preview2-02 + 3.0.0-preview2-04 netstandard2.0;net47 Neo.Plugins @@ -14,7 +14,7 @@ - + From b7bcde5bb7eccad0aeb8dde1832151eee9911334 Mon Sep 17 00:00:00 2001 From: Igor Machado Coelho Date: Mon, 13 Aug 2018 16:23:39 -0300 Subject: [PATCH 005/183] Logging in millisecs After change to Akka consensus in NEO 3.0, it's so fast that seconds do not mean much anymore.. now milliseconds is important to actually know of what is going on the consensus algorithm. --- SimplePolicy/SimplePolicyPlugin.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SimplePolicy/SimplePolicyPlugin.cs b/SimplePolicy/SimplePolicyPlugin.cs index 1f81dd4d0..c3175f376 100644 --- a/SimplePolicy/SimplePolicyPlugin.cs +++ b/SimplePolicy/SimplePolicyPlugin.cs @@ -52,7 +52,7 @@ void ILogPlugin.Log(string source, LogLevel level, string message) { if (source != nameof(ConsensusService)) return; DateTime now = DateTime.Now; - string line = $"[{now.TimeOfDay:hh\\:mm\\:ss}] {message}"; + string line = $"[{now.TimeOfDay:hh\\:mm\\:ss\\.fff}] {message}"; Console.WriteLine(line); if (string.IsNullOrEmpty(log_dictionary)) return; lock (log_dictionary) From a25d6860906ca02945b96a2ac0d6249fe42bb0d4 Mon Sep 17 00:00:00 2001 From: hal0x2328 Date: Fri, 24 Aug 2018 13:06:36 -0400 Subject: [PATCH 006/183] remove break statement from FilterFree --- SimplePolicy/SimplePolicyPlugin.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/SimplePolicy/SimplePolicyPlugin.cs b/SimplePolicy/SimplePolicyPlugin.cs index c3175f376..7095dacdf 100644 --- a/SimplePolicy/SimplePolicyPlugin.cs +++ b/SimplePolicy/SimplePolicyPlugin.cs @@ -44,8 +44,6 @@ private IEnumerable FilterFree(IEnumerable transaction yield return tx; else if (count++ < Settings.Default.MaxFreeTransactionsPerBlock) yield return tx; - else - yield break; } void ILogPlugin.Log(string source, LogLevel level, string message) From 095e89fb175e2b9a6c55bd0c88f7c039d2145d1c Mon Sep 17 00:00:00 2001 From: f27d <40597646+f27d@users.noreply.github.com> Date: Fri, 24 Aug 2018 20:46:55 +0100 Subject: [PATCH 007/183] Fix Priority Fee Transactions being treated as Free (#4) --- SimplePolicy/SimplePolicyPlugin.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SimplePolicy/SimplePolicyPlugin.cs b/SimplePolicy/SimplePolicyPlugin.cs index 7095dacdf..66f52d843 100644 --- a/SimplePolicy/SimplePolicyPlugin.cs +++ b/SimplePolicy/SimplePolicyPlugin.cs @@ -32,7 +32,7 @@ public IEnumerable Filter(IEnumerable transactions) Transaction[] array = transactions.ToArray(); if (array.Length + 1 <= Settings.Default.MaxTransactionsPerBlock) return array; - transactions = array.OrderByDescending(p => p.NetworkFee / p.Size).Take(Settings.Default.MaxTransactionsPerBlock - 1); + transactions = array.OrderByDescending(p => p.NetworkFee / p.Size).ThenByDescending(p => p.NetworkFee).Take(Settings.Default.MaxTransactionsPerBlock - 1); return FilterFree(transactions); } From 568e96654fd6c079952781446ccd984d3aa17b25 Mon Sep 17 00:00:00 2001 From: erikzhang Date: Wed, 29 Aug 2018 21:00:32 +0800 Subject: [PATCH 008/183] add RpcDisabled --- RpcDisabled/RpcDisabled.cs | 18 ++++++++++++++++++ RpcDisabled/RpcDisabled.csproj | 20 ++++++++++++++++++++ RpcDisabled/RpcDisabled/config.json | 5 +++++ RpcDisabled/Settings.cs | 23 +++++++++++++++++++++++ neo-plugins.sln | 8 +++++++- 5 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 RpcDisabled/RpcDisabled.cs create mode 100644 RpcDisabled/RpcDisabled.csproj create mode 100644 RpcDisabled/RpcDisabled/config.json create mode 100644 RpcDisabled/Settings.cs diff --git a/RpcDisabled/RpcDisabled.cs b/RpcDisabled/RpcDisabled.cs new file mode 100644 index 000000000..527f17d2a --- /dev/null +++ b/RpcDisabled/RpcDisabled.cs @@ -0,0 +1,18 @@ +using Microsoft.AspNetCore.Http; +using Neo.IO.Json; +using Neo.Network.RPC; +using System; +using System.Linq; + +namespace Neo.Plugins +{ + public class RpcDisabled : Plugin, IRpcPlugin + { + public JObject OnProcess(HttpContext context, string method, JArray _params) + { + if (Settings.Default.DisabledMethods.Contains(method)) + throw new RpcException(-400, "Access denied"); + return null; + } + } +} diff --git a/RpcDisabled/RpcDisabled.csproj b/RpcDisabled/RpcDisabled.csproj new file mode 100644 index 000000000..294574b9d --- /dev/null +++ b/RpcDisabled/RpcDisabled.csproj @@ -0,0 +1,20 @@ + + + + 3.0.0-preview2-09 + netstandard2.0;net47 + Neo.Plugins + + + + + PreserveNewest + PreserveNewest + + + + + + + + diff --git a/RpcDisabled/RpcDisabled/config.json b/RpcDisabled/RpcDisabled/config.json new file mode 100644 index 000000000..a3b288542 --- /dev/null +++ b/RpcDisabled/RpcDisabled/config.json @@ -0,0 +1,5 @@ +{ + "PluginConfiguration": { + "DisabledMethods": [] + } +} diff --git a/RpcDisabled/Settings.cs b/RpcDisabled/Settings.cs new file mode 100644 index 000000000..82bb0b128 --- /dev/null +++ b/RpcDisabled/Settings.cs @@ -0,0 +1,23 @@ +using Microsoft.Extensions.Configuration; +using System.Linq; +using System.Reflection; + +namespace Neo.Plugins +{ + internal class Settings + { + public string[] DisabledMethods { get; } + + public static Settings Default { get; } + + static Settings() + { + Default = new Settings(Assembly.GetExecutingAssembly().GetConfiguration()); + } + + public Settings(IConfigurationSection section) + { + this.DisabledMethods = section.GetSection("DisabledMethods").GetChildren().Select(p => p.Value).ToArray(); + } + } +} diff --git a/neo-plugins.sln b/neo-plugins.sln index bc167da85..54c3cb8dd 100644 --- a/neo-plugins.sln +++ b/neo-plugins.sln @@ -5,7 +5,9 @@ VisualStudioVersion = 15.0.27428.2027 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SimplePolicy", "SimplePolicy\SimplePolicy.csproj", "{322C366E-F891-47FD-A039-0FEF79BCB6D5}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ApplicationLogs", "ApplicationLogs\ApplicationLogs.csproj", "{84DA8EA6-EF60-4FCD-B1C6-65C1A8323B3F}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ApplicationLogs", "ApplicationLogs\ApplicationLogs.csproj", "{84DA8EA6-EF60-4FCD-B1C6-65C1A8323B3F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RpcDisabled", "RpcDisabled\RpcDisabled.csproj", "{6800D782-8EC0-49E9-98C4-195C8F781A1F}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -21,6 +23,10 @@ Global {84DA8EA6-EF60-4FCD-B1C6-65C1A8323B3F}.Debug|Any CPU.Build.0 = Debug|Any CPU {84DA8EA6-EF60-4FCD-B1C6-65C1A8323B3F}.Release|Any CPU.ActiveCfg = Release|Any CPU {84DA8EA6-EF60-4FCD-B1C6-65C1A8323B3F}.Release|Any CPU.Build.0 = Release|Any CPU + {6800D782-8EC0-49E9-98C4-195C8F781A1F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6800D782-8EC0-49E9-98C4-195C8F781A1F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6800D782-8EC0-49E9-98C4-195C8F781A1F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6800D782-8EC0-49E9-98C4-195C8F781A1F}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From 6f66abe005d98507e6ca06b705d820c5e8829e5c Mon Sep 17 00:00:00 2001 From: erikzhang Date: Sat, 1 Sep 2018 15:37:27 +0800 Subject: [PATCH 009/183] add StatesDumper --- StatesDumper/StatesDumper.cs | 46 ++++++++++++++++++++++++++++++++ StatesDumper/StatesDumper.csproj | 13 +++++++++ neo-plugins.sln | 8 +++++- 3 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 StatesDumper/StatesDumper.cs create mode 100644 StatesDumper/StatesDumper.csproj diff --git a/StatesDumper/StatesDumper.cs b/StatesDumper/StatesDumper.cs new file mode 100644 index 000000000..0ecaa11c3 --- /dev/null +++ b/StatesDumper/StatesDumper.cs @@ -0,0 +1,46 @@ +using Neo.IO; +using Neo.IO.Json; +using Neo.Ledger; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace Neo.Plugins +{ + public class StatesDumper : Plugin + { + protected override bool OnMessage(object message) + { + if (!(message is string[] args)) return false; + if (args.Length < 2) return false; + if (args[0] != "dump") return false; + switch (args[1]) + { + case "storage": + Dump(args.Length >= 3 + ? Blockchain.Singleton.Store.GetStorages().Find(UInt160.Parse(args[2]).ToArray()) + : Blockchain.Singleton.Store.GetStorages().Find()); + return true; + default: + return false; + } + } + + private static void Dump(IEnumerable> states) + where TKey : ISerializable + where TValue : ISerializable + { + const string path = "dump.json"; + JArray array = new JArray(states.Select(p => + { + JObject state = new JObject(); + state["key"] = p.Key.ToArray().ToHexString(); + state["value"] = p.Value.ToArray().ToHexString(); + return state; + })); + File.WriteAllText(path, array.ToString()); + Console.WriteLine($"States have been dumped into file {path}"); + } + } +} diff --git a/StatesDumper/StatesDumper.csproj b/StatesDumper/StatesDumper.csproj new file mode 100644 index 000000000..044c03e9d --- /dev/null +++ b/StatesDumper/StatesDumper.csproj @@ -0,0 +1,13 @@ + + + + 3.0.0-preview2-11 + netstandard2.0;net47 + Neo.Plugins + + + + + + + diff --git a/neo-plugins.sln b/neo-plugins.sln index 54c3cb8dd..779664930 100644 --- a/neo-plugins.sln +++ b/neo-plugins.sln @@ -7,7 +7,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SimplePolicy", "SimplePolic EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ApplicationLogs", "ApplicationLogs\ApplicationLogs.csproj", "{84DA8EA6-EF60-4FCD-B1C6-65C1A8323B3F}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RpcDisabled", "RpcDisabled\RpcDisabled.csproj", "{6800D782-8EC0-49E9-98C4-195C8F781A1F}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RpcDisabled", "RpcDisabled\RpcDisabled.csproj", "{6800D782-8EC0-49E9-98C4-195C8F781A1F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StatesDumper", "StatesDumper\StatesDumper.csproj", "{86531DB1-A231-46C4-823F-BE60972F7523}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -27,6 +29,10 @@ Global {6800D782-8EC0-49E9-98C4-195C8F781A1F}.Debug|Any CPU.Build.0 = Debug|Any CPU {6800D782-8EC0-49E9-98C4-195C8F781A1F}.Release|Any CPU.ActiveCfg = Release|Any CPU {6800D782-8EC0-49E9-98C4-195C8F781A1F}.Release|Any CPU.Build.0 = Release|Any CPU + {86531DB1-A231-46C4-823F-BE60972F7523}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {86531DB1-A231-46C4-823F-BE60972F7523}.Debug|Any CPU.Build.0 = Debug|Any CPU + {86531DB1-A231-46C4-823F-BE60972F7523}.Release|Any CPU.ActiveCfg = Release|Any CPU + {86531DB1-A231-46C4-823F-BE60972F7523}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From d30443463696190a45745aab352a3373272612fa Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Mon, 3 Sep 2018 16:16:40 +0800 Subject: [PATCH 010/183] add ImportBlocks (#7) --- ImportBlocks/ImportBlocks.cs | 91 +++++++++++++++++++++++++++ ImportBlocks/ImportBlocks.csproj | 13 ++++ ImportBlocks/ImportBlocks/config.json | 5 ++ ImportBlocks/Settings.cs | 29 +++++++++ neo-plugins.sln | 8 ++- 5 files changed, 145 insertions(+), 1 deletion(-) create mode 100644 ImportBlocks/ImportBlocks.cs create mode 100644 ImportBlocks/ImportBlocks.csproj create mode 100644 ImportBlocks/ImportBlocks/config.json create mode 100644 ImportBlocks/Settings.cs diff --git a/ImportBlocks/ImportBlocks.cs b/ImportBlocks/ImportBlocks.cs new file mode 100644 index 000000000..8db94879f --- /dev/null +++ b/ImportBlocks/ImportBlocks.cs @@ -0,0 +1,91 @@ +using Akka.Actor; +using Neo.IO; +using Neo.Ledger; +using Neo.Network.P2P.Payloads; +using System.Collections.Generic; +using System.IO; +using System.IO.Compression; +using System.Linq; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +namespace Neo.Plugins +{ + public class ImportBlocks : Plugin + { + public ImportBlocks() + { + Task.Run(() => + { + const string path_acc = "chain.acc"; + if (File.Exists(path_acc)) + using (FileStream fs = new FileStream(path_acc, FileMode.Open, FileAccess.Read, FileShare.Read)) + System.Blockchain.Ask(new Blockchain.Import + { + Blocks = GetBlocks(fs) + }).Wait(); + const string path_acc_zip = path_acc + ".zip"; + if (File.Exists(path_acc_zip)) + using (FileStream fs = new FileStream(path_acc_zip, FileMode.Open, FileAccess.Read, FileShare.Read)) + using (ZipArchive zip = new ZipArchive(fs, ZipArchiveMode.Read)) + using (Stream zs = zip.GetEntry(path_acc).Open()) + System.Blockchain.Ask(new Blockchain.Import + { + Blocks = GetBlocks(zs) + }).Wait(); + var paths = Directory.EnumerateFiles(".", "chain.*.acc", SearchOption.TopDirectoryOnly).Concat(Directory.EnumerateFiles(".", "chain.*.acc.zip", SearchOption.TopDirectoryOnly)).Select(p => new + { + FileName = Path.GetFileName(p), + Start = uint.Parse(Regex.Match(p, @"\d+").Value), + IsCompressed = p.EndsWith(".zip") + }).OrderBy(p => p.Start); + foreach (var path in paths) + { + if (path.Start > Blockchain.Singleton.Height + 1) break; + if (path.IsCompressed) + using (FileStream fs = new FileStream(path.FileName, FileMode.Open, FileAccess.Read, FileShare.Read)) + using (ZipArchive zip = new ZipArchive(fs, ZipArchiveMode.Read)) + using (Stream zs = zip.GetEntry(Path.GetFileNameWithoutExtension(path.FileName)).Open()) + System.Blockchain.Ask(new Blockchain.Import + { + Blocks = GetBlocks(zs, true) + }).Wait(); + else + using (FileStream fs = new FileStream(path.FileName, FileMode.Open, FileAccess.Read, FileShare.Read)) + System.Blockchain.Ask(new Blockchain.Import + { + Blocks = GetBlocks(fs, true) + }).Wait(); + } + }); + } + + private static IEnumerable GetBlocks(Stream stream, bool read_start = false) + { + using (BinaryReader r = new BinaryReader(stream)) + { + uint start = read_start ? r.ReadUInt32() : 0; + uint count = r.ReadUInt32(); + uint end = start + count - 1; + if (end <= Blockchain.Singleton.Height) yield break; + for (uint height = start; height <= end; height++) + { + byte[] array = r.ReadBytes(r.ReadInt32()); + + if (height > Blockchain.Singleton.Height && CheckMaxOnImportHeight(height)) + { + Block block = array.AsSerializable(); + yield return block; + } + } + } + } + + private static bool CheckMaxOnImportHeight(uint currentImportBlockHeight) + { + if (Settings.Default.MaxOnImportHeight == 0 || Settings.Default.MaxOnImportHeight >= currentImportBlockHeight) + return true; + return false; + } + } +} diff --git a/ImportBlocks/ImportBlocks.csproj b/ImportBlocks/ImportBlocks.csproj new file mode 100644 index 000000000..044c03e9d --- /dev/null +++ b/ImportBlocks/ImportBlocks.csproj @@ -0,0 +1,13 @@ + + + + 3.0.0-preview2-11 + netstandard2.0;net47 + Neo.Plugins + + + + + + + diff --git a/ImportBlocks/ImportBlocks/config.json b/ImportBlocks/ImportBlocks/config.json new file mode 100644 index 000000000..ed125974c --- /dev/null +++ b/ImportBlocks/ImportBlocks/config.json @@ -0,0 +1,5 @@ +{ + "PluginConfiguration": { + "MaxOnImportHeight": 0 + } +} diff --git a/ImportBlocks/Settings.cs b/ImportBlocks/Settings.cs new file mode 100644 index 000000000..17523d17d --- /dev/null +++ b/ImportBlocks/Settings.cs @@ -0,0 +1,29 @@ +using Microsoft.Extensions.Configuration; +using System; +using System.Reflection; + +namespace Neo.Plugins +{ + internal class Settings + { + public uint MaxOnImportHeight { get; } + + public static Settings Default { get; } + + static Settings() + { + Default = new Settings(Assembly.GetExecutingAssembly().GetConfiguration()); + } + + public Settings(IConfigurationSection section) + { + this.MaxOnImportHeight = GetValueOrDefault(section.GetSection("MaxOnImportHeight"), 0u, p => uint.Parse(p)); + } + + public T GetValueOrDefault(IConfigurationSection section, T defaultValue, Func selector) + { + if (section.Value == null) return defaultValue; + return selector(section.Value); + } + } +} diff --git a/neo-plugins.sln b/neo-plugins.sln index 779664930..c02fcbf41 100644 --- a/neo-plugins.sln +++ b/neo-plugins.sln @@ -9,7 +9,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ApplicationLogs", "Applicat EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RpcDisabled", "RpcDisabled\RpcDisabled.csproj", "{6800D782-8EC0-49E9-98C4-195C8F781A1F}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StatesDumper", "StatesDumper\StatesDumper.csproj", "{86531DB1-A231-46C4-823F-BE60972F7523}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StatesDumper", "StatesDumper\StatesDumper.csproj", "{86531DB1-A231-46C4-823F-BE60972F7523}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImportBlocks", "ImportBlocks\ImportBlocks.csproj", "{B7A42984-57BB-4F8D-967B-23B0E841B726}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -33,6 +35,10 @@ Global {86531DB1-A231-46C4-823F-BE60972F7523}.Debug|Any CPU.Build.0 = Debug|Any CPU {86531DB1-A231-46C4-823F-BE60972F7523}.Release|Any CPU.ActiveCfg = Release|Any CPU {86531DB1-A231-46C4-823F-BE60972F7523}.Release|Any CPU.Build.0 = Release|Any CPU + {B7A42984-57BB-4F8D-967B-23B0E841B726}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B7A42984-57BB-4F8D-967B-23B0E841B726}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B7A42984-57BB-4F8D-967B-23B0E841B726}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B7A42984-57BB-4F8D-967B-23B0E841B726}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From bd3db2ccd56706cb8496e0afdacd9bd002d72476 Mon Sep 17 00:00:00 2001 From: erikzhang Date: Thu, 6 Sep 2018 14:52:18 +0800 Subject: [PATCH 011/183] `yield break` when the height of the imported block reaches the limit --- ImportBlocks/ImportBlocks.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ImportBlocks/ImportBlocks.cs b/ImportBlocks/ImportBlocks.cs index 8db94879f..e1aa43647 100644 --- a/ImportBlocks/ImportBlocks.cs +++ b/ImportBlocks/ImportBlocks.cs @@ -71,8 +71,8 @@ private static IEnumerable GetBlocks(Stream stream, bool read_start = fal for (uint height = start; height <= end; height++) { byte[] array = r.ReadBytes(r.ReadInt32()); - - if (height > Blockchain.Singleton.Height && CheckMaxOnImportHeight(height)) + if (!CheckMaxOnImportHeight(height)) yield break; + if (height > Blockchain.Singleton.Height) { Block block = array.AsSerializable(); yield return block; From cb28c7915607a9026a629291b09e8b5441486a8b Mon Sep 17 00:00:00 2001 From: erikzhang Date: Mon, 10 Sep 2018 15:13:12 +0800 Subject: [PATCH 012/183] detect recursive references in ApplicationLogs --- ApplicationLogs/Logger.cs | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/ApplicationLogs/Logger.cs b/ApplicationLogs/Logger.cs index d32a03c97..ae793ebc1 100644 --- a/ApplicationLogs/Logger.cs +++ b/ApplicationLogs/Logger.cs @@ -4,6 +4,7 @@ using Neo.IO.Json; using Neo.Ledger; using Neo.VM; +using System; using System.Linq; namespace Neo.Plugins @@ -31,12 +32,26 @@ protected override void OnReceive(object message) execution["contract"] = p.ScriptHash.ToString(); execution["vmstate"] = p.VMState; execution["gas_consumed"] = p.GasConsumed.ToString(); - execution["stack"] = p.Stack.Select(q => q.ToParameter().ToJson()).ToArray(); + try + { + execution["stack"] = p.Stack.Select(q => q.ToParameter().ToJson()).ToArray(); + } + catch (InvalidOperationException) + { + execution["stack"] = "error: recursive reference"; + } execution["notifications"] = p.Notifications.Select(q => { JObject notification = new JObject(); notification["contract"] = q.ScriptHash.ToString(); - notification["state"] = q.State.ToParameter().ToJson(); + try + { + notification["state"] = q.State.ToParameter().ToJson(); + } + catch (InvalidOperationException) + { + notification["state"] = "error: recursive reference"; + } return notification; }).ToArray(); return execution; From fe125f621c58241e7c269fe366ce532ca05219af Mon Sep 17 00:00:00 2001 From: erikzhang Date: Mon, 10 Sep 2018 16:19:51 +0800 Subject: [PATCH 013/183] exporting blocks in plugin --- ImportBlocks/ImportBlocks.cs | 79 ++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/ImportBlocks/ImportBlocks.cs b/ImportBlocks/ImportBlocks.cs index e1aa43647..4f039aa5a 100644 --- a/ImportBlocks/ImportBlocks.cs +++ b/ImportBlocks/ImportBlocks.cs @@ -2,6 +2,8 @@ using Neo.IO; using Neo.Ledger; using Neo.Network.P2P.Payloads; +using Neo.Persistence; +using System; using System.Collections.Generic; using System.IO; using System.IO.Compression; @@ -87,5 +89,82 @@ private static bool CheckMaxOnImportHeight(uint currentImportBlockHeight) return true; return false; } + + protected override bool OnMessage(object message) + { + if (!(message is string[] args)) return false; + if (args.Length < 2) return false; + if (args[0] != "export") return false; + if (args[1] != "block" && args[1] != "blocks") return false; + if (args.Length >= 3 && uint.TryParse(args[2], out uint start)) + { + if (start > Blockchain.Singleton.Height) + return true; + uint count = args.Length >= 4 ? uint.Parse(args[3]) : uint.MaxValue; + count = Math.Min(count, Blockchain.Singleton.Height - start + 1); + uint end = start + count - 1; + string path = $"chain.{start}.acc"; + using (FileStream fs = new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None)) + { + if (fs.Length > 0) + { + fs.Seek(sizeof(uint), SeekOrigin.Begin); + byte[] buffer = new byte[sizeof(uint)]; + fs.Read(buffer, 0, buffer.Length); + start += BitConverter.ToUInt32(buffer, 0); + fs.Seek(sizeof(uint), SeekOrigin.Begin); + } + else + { + fs.Write(BitConverter.GetBytes(start), 0, sizeof(uint)); + } + if (start <= end) + fs.Write(BitConverter.GetBytes(count), 0, sizeof(uint)); + fs.Seek(0, SeekOrigin.End); + using (Snapshot snapshot = Blockchain.Singleton.GetSnapshot()) + for (uint i = start; i <= end; i++) + { + Block block = snapshot.GetBlock(i); + byte[] array = block.ToArray(); + fs.Write(BitConverter.GetBytes(array.Length), 0, sizeof(int)); + fs.Write(array, 0, array.Length); + Console.SetCursorPosition(0, Console.CursorTop); + Console.Write($"[{i}/{end}]"); + } + } + } + else + { + start = 0; + uint end = Blockchain.Singleton.Height; + uint count = end - start + 1; + string path = args.Length >= 3 ? args[2] : "chain.acc"; + using (FileStream fs = new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None)) + { + if (fs.Length > 0) + { + byte[] buffer = new byte[sizeof(uint)]; + fs.Read(buffer, 0, buffer.Length); + start = BitConverter.ToUInt32(buffer, 0); + fs.Seek(0, SeekOrigin.Begin); + } + if (start <= end) + fs.Write(BitConverter.GetBytes(count), 0, sizeof(uint)); + fs.Seek(0, SeekOrigin.End); + using (Snapshot snapshot = Blockchain.Singleton.GetSnapshot()) + for (uint i = start; i <= end; i++) + { + Block block = snapshot.GetBlock(i); + byte[] array = block.ToArray(); + fs.Write(BitConverter.GetBytes(array.Length), 0, sizeof(int)); + fs.Write(array, 0, array.Length); + Console.SetCursorPosition(0, Console.CursorTop); + Console.Write($"[{i}/{end}]"); + } + } + } + Console.WriteLine(); + return true; + } } } From 8fcf857da600b07a5a25079560480b5f3e758494 Mon Sep 17 00:00:00 2001 From: erikzhang Date: Wed, 12 Sep 2018 18:20:29 +0800 Subject: [PATCH 014/183] copy config.json to output directory automatically --- ImportBlocks/ImportBlocks.csproj | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ImportBlocks/ImportBlocks.csproj b/ImportBlocks/ImportBlocks.csproj index 044c03e9d..8d8b5876b 100644 --- a/ImportBlocks/ImportBlocks.csproj +++ b/ImportBlocks/ImportBlocks.csproj @@ -6,6 +6,13 @@ Neo.Plugins + + + PreserveNewest + PreserveNewest + + + From 9f5e9d25792e7c1a9b15c98afbdae63221bbf144 Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Sat, 15 Sep 2018 00:00:07 +0800 Subject: [PATCH 015/183] v2.9.0 (#9) --- ApplicationLogs/ApplicationLogs.csproj | 4 ++-- ImportBlocks/ImportBlocks.csproj | 6 +++--- RpcDisabled/RpcDisabled.csproj | 4 ++-- SimplePolicy/SimplePolicy.csproj | 4 ++-- StatesDumper/StatesDumper.csproj | 4 ++-- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/ApplicationLogs/ApplicationLogs.csproj b/ApplicationLogs/ApplicationLogs.csproj index f268b253e..dd21e92b1 100644 --- a/ApplicationLogs/ApplicationLogs.csproj +++ b/ApplicationLogs/ApplicationLogs.csproj @@ -1,7 +1,7 @@  - 3.0.0-preview2-04 + 2.9.0 netstandard2.0;net47 Neo.Plugins @@ -14,7 +14,7 @@ - + diff --git a/ImportBlocks/ImportBlocks.csproj b/ImportBlocks/ImportBlocks.csproj index 8d8b5876b..1866dc275 100644 --- a/ImportBlocks/ImportBlocks.csproj +++ b/ImportBlocks/ImportBlocks.csproj @@ -1,11 +1,11 @@  - 3.0.0-preview2-11 + 2.9.0 netstandard2.0;net47 Neo.Plugins - + PreserveNewest @@ -14,7 +14,7 @@ - + diff --git a/RpcDisabled/RpcDisabled.csproj b/RpcDisabled/RpcDisabled.csproj index 294574b9d..e983a4261 100644 --- a/RpcDisabled/RpcDisabled.csproj +++ b/RpcDisabled/RpcDisabled.csproj @@ -1,7 +1,7 @@  - 3.0.0-preview2-09 + 2.9.0 netstandard2.0;net47 Neo.Plugins @@ -14,7 +14,7 @@ - + diff --git a/SimplePolicy/SimplePolicy.csproj b/SimplePolicy/SimplePolicy.csproj index c7bf20eb8..7ef0c6446 100644 --- a/SimplePolicy/SimplePolicy.csproj +++ b/SimplePolicy/SimplePolicy.csproj @@ -1,7 +1,7 @@  - 3.0.0-preview2-04 + 2.9.0 netstandard2.0;net47 Neo.Plugins @@ -14,7 +14,7 @@ - + diff --git a/StatesDumper/StatesDumper.csproj b/StatesDumper/StatesDumper.csproj index 044c03e9d..0d1c24e83 100644 --- a/StatesDumper/StatesDumper.csproj +++ b/StatesDumper/StatesDumper.csproj @@ -1,13 +1,13 @@  - 3.0.0-preview2-11 + 2.9.0 netstandard2.0;net47 Neo.Plugins - + From 10a348b94374e5ae92c5b2204ff908753b2273dd Mon Sep 17 00:00:00 2001 From: erikzhang Date: Sat, 15 Sep 2018 00:13:15 +0800 Subject: [PATCH 016/183] fix SimplePolicyPlugin --- SimplePolicy/SimplePolicyPlugin.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SimplePolicy/SimplePolicyPlugin.cs b/SimplePolicy/SimplePolicyPlugin.cs index 66f52d843..f292090aa 100644 --- a/SimplePolicy/SimplePolicyPlugin.cs +++ b/SimplePolicy/SimplePolicyPlugin.cs @@ -12,7 +12,7 @@ public class SimplePolicyPlugin : Plugin, ILogPlugin, IPolicyPlugin { private static string log_dictionary = Path.Combine(AppContext.BaseDirectory, "Logs"); - public bool CheckPolicy(Transaction tx) + public bool FilterForMemoryPool(Transaction tx) { switch (Settings.Default.BlockedAccounts.Type) { @@ -27,7 +27,7 @@ public bool CheckPolicy(Transaction tx) } } - public IEnumerable Filter(IEnumerable transactions) + public IEnumerable FilterForBlock(IEnumerable transactions) { Transaction[] array = transactions.ToArray(); if (array.Length + 1 <= Settings.Default.MaxTransactionsPerBlock) From 6cf38267bb7ca55905b87d545a7042059f6b1aa6 Mon Sep 17 00:00:00 2001 From: erikzhang Date: Fri, 28 Sep 2018 15:36:31 +0800 Subject: [PATCH 017/183] fix neo-project/neo#395 --- ApplicationLogs/LogReader.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ApplicationLogs/LogReader.cs b/ApplicationLogs/LogReader.cs index a3d38c765..fe78c0964 100644 --- a/ApplicationLogs/LogReader.cs +++ b/ApplicationLogs/LogReader.cs @@ -2,12 +2,13 @@ using Neo.IO.Data.LevelDB; using Neo.IO.Json; using Neo.Network.RPC; +using System.IO; namespace Neo.Plugins { public class LogReader : Plugin, IRpcPlugin { - private readonly DB db = DB.Open(Settings.Default.Path, new Options { CreateIfMissing = true }); + private readonly DB db = DB.Open(Path.GetFullPath(Settings.Default.Path), new Options { CreateIfMissing = true }); public override string Name => "ApplicationLogs"; From 6a1c71b5a3d200c97ea8342aeb460a5b256e9cc5 Mon Sep 17 00:00:00 2001 From: belane Date: Tue, 9 Oct 2018 09:06:00 +0200 Subject: [PATCH 018/183] Rpc Basic Auth (#14) * Rpc Basic Auth * change plugin name to RpcSecurity --- RpcDisabled/RpcDisabled.cs | 18 -------- RpcSecurity/RpcSecurity.cs | 46 +++++++++++++++++++ .../RpcSecurity.csproj | 2 +- .../RpcSecurity}/config.json | 2 + {RpcDisabled => RpcSecurity}/Settings.cs | 4 ++ neo-plugins.sln | 4 +- 6 files changed, 55 insertions(+), 21 deletions(-) delete mode 100644 RpcDisabled/RpcDisabled.cs create mode 100644 RpcSecurity/RpcSecurity.cs rename RpcDisabled/RpcDisabled.csproj => RpcSecurity/RpcSecurity.csproj (91%) rename {RpcDisabled/RpcDisabled => RpcSecurity/RpcSecurity}/config.json (61%) rename {RpcDisabled => RpcSecurity}/Settings.cs (73%) diff --git a/RpcDisabled/RpcDisabled.cs b/RpcDisabled/RpcDisabled.cs deleted file mode 100644 index 527f17d2a..000000000 --- a/RpcDisabled/RpcDisabled.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Microsoft.AspNetCore.Http; -using Neo.IO.Json; -using Neo.Network.RPC; -using System; -using System.Linq; - -namespace Neo.Plugins -{ - public class RpcDisabled : Plugin, IRpcPlugin - { - public JObject OnProcess(HttpContext context, string method, JArray _params) - { - if (Settings.Default.DisabledMethods.Contains(method)) - throw new RpcException(-400, "Access denied"); - return null; - } - } -} diff --git a/RpcSecurity/RpcSecurity.cs b/RpcSecurity/RpcSecurity.cs new file mode 100644 index 000000000..70049de68 --- /dev/null +++ b/RpcSecurity/RpcSecurity.cs @@ -0,0 +1,46 @@ +using Microsoft.AspNetCore.Http; +using Neo.IO.Json; +using Neo.Network.RPC; +using System; +using System.Linq; +using System.Text; + +namespace Neo.Plugins +{ + public class RpcSecurity : Plugin, IRpcPlugin + { + public JObject OnProcess(HttpContext context, string method, JArray _params) + { + if (!CheckAuth(context) || Settings.Default.DisabledMethods.Contains(method)) + throw new RpcException(-400, "Access denied"); + return null; + } + + private bool CheckAuth(HttpContext context) + { + if (string.IsNullOrEmpty(Settings.Default.RpcUser)) + { + return true; + } + + context.Response.Headers["WWW-Authenticate"] = "Basic realm=\"Restricted\""; + + string reqauth = context.Request.Headers["Authorization"]; + string authstring = null; + try + { + authstring = Encoding.UTF8.GetString(Convert.FromBase64String(reqauth.Replace("Basic ", "").Trim())); + } + catch + { + return false; + } + + string[] authvalues = authstring.Split(new string[] { ":" }, StringSplitOptions.RemoveEmptyEntries); + if (authvalues.Length < 2) + return false; + + return authvalues[0] == Settings.Default.RpcUser && authvalues[1] == Settings.Default.RpcPass; + } + } +} diff --git a/RpcDisabled/RpcDisabled.csproj b/RpcSecurity/RpcSecurity.csproj similarity index 91% rename from RpcDisabled/RpcDisabled.csproj rename to RpcSecurity/RpcSecurity.csproj index e983a4261..b977eafce 100644 --- a/RpcDisabled/RpcDisabled.csproj +++ b/RpcSecurity/RpcSecurity.csproj @@ -7,7 +7,7 @@ - + PreserveNewest PreserveNewest diff --git a/RpcDisabled/RpcDisabled/config.json b/RpcSecurity/RpcSecurity/config.json similarity index 61% rename from RpcDisabled/RpcDisabled/config.json rename to RpcSecurity/RpcSecurity/config.json index a3b288542..8890f20b0 100644 --- a/RpcDisabled/RpcDisabled/config.json +++ b/RpcSecurity/RpcSecurity/config.json @@ -1,5 +1,7 @@ { "PluginConfiguration": { + "RpcUser": "", + "RpcPass": "", "DisabledMethods": [] } } diff --git a/RpcDisabled/Settings.cs b/RpcSecurity/Settings.cs similarity index 73% rename from RpcDisabled/Settings.cs rename to RpcSecurity/Settings.cs index 82bb0b128..c78a488c2 100644 --- a/RpcDisabled/Settings.cs +++ b/RpcSecurity/Settings.cs @@ -6,6 +6,8 @@ namespace Neo.Plugins { internal class Settings { + public string RpcUser { get; } + public string RpcPass { get; } public string[] DisabledMethods { get; } public static Settings Default { get; } @@ -17,6 +19,8 @@ static Settings() public Settings(IConfigurationSection section) { + this.RpcUser = section.GetSection("RpcUser").Value; + this.RpcPass = section.GetSection("RpcPass").Value; this.DisabledMethods = section.GetSection("DisabledMethods").GetChildren().Select(p => p.Value).ToArray(); } } diff --git a/neo-plugins.sln b/neo-plugins.sln index c02fcbf41..bf0ece785 100644 --- a/neo-plugins.sln +++ b/neo-plugins.sln @@ -7,11 +7,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SimplePolicy", "SimplePolic EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ApplicationLogs", "ApplicationLogs\ApplicationLogs.csproj", "{84DA8EA6-EF60-4FCD-B1C6-65C1A8323B3F}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RpcDisabled", "RpcDisabled\RpcDisabled.csproj", "{6800D782-8EC0-49E9-98C4-195C8F781A1F}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RpcSecurity", "RpcSecurity\RpcSecurity.csproj", "{6800D782-8EC0-49E9-98C4-195C8F781A1F}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StatesDumper", "StatesDumper\StatesDumper.csproj", "{86531DB1-A231-46C4-823F-BE60972F7523}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ImportBlocks", "ImportBlocks\ImportBlocks.csproj", "{B7A42984-57BB-4F8D-967B-23B0E841B726}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImportBlocks", "ImportBlocks\ImportBlocks.csproj", "{B7A42984-57BB-4F8D-967B-23B0E841B726}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution From ada292dec3c93cd478a101937f99af84a36654b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vitor=20Naz=C3=A1rio=20Coelho?= Date: Mon, 22 Oct 2018 12:02:55 -0300 Subject: [PATCH 019/183] Including number of dumped states (#17) * Including number of dumped states * Update StatesDumper/StatesDumper.cs Co-Authored-By: vncoelho --- StatesDumper/StatesDumper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/StatesDumper/StatesDumper.cs b/StatesDumper/StatesDumper.cs index 0ecaa11c3..11f98ae21 100644 --- a/StatesDumper/StatesDumper.cs +++ b/StatesDumper/StatesDumper.cs @@ -40,7 +40,7 @@ private static void Dump(IEnumerable> s return state; })); File.WriteAllText(path, array.ToString()); - Console.WriteLine($"States have been dumped into file {path}"); + Console.WriteLine($"States ({array.Count}) have been dumped into file {path}"); } } } From 39f0bde11f503bf2ab395489c41dfd0b61cc5367 Mon Sep 17 00:00:00 2001 From: Ricardo Prado <38396062+lock9@users.noreply.github.com> Date: Thu, 1 Nov 2018 10:06:00 -0300 Subject: [PATCH 020/183] Readme (#18) --- README.md | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 000000000..93db4625f --- /dev/null +++ b/README.md @@ -0,0 +1,39 @@ +## What is it +A set of plugins that can be used inside the Neo core library. Check [here](http://docs.neo.org/en-us/node/plugin.html) for the official documentation. + +## Using plugins +Plugins can be used to increase functionality in neo. One common example is to add the ApplicationLogs plugin in order to enable your node to create log files. + +To configure a plugin, do the following: + - Download the desired plugin from the [Releases page](https://github.com/neo-project/neo-plugins/releases) + - Alternative: Compile from source + - Clone this repository; + - Open it in Visual Studio, select the plugin you want to enable and select `publish` \(compile it using Release configuration\) + - Create the Plugins folder in neo-cli / neo-gui (where the binary is run from, like `/neo-cli/bin/debug/netcoreapp2.1/Plugins`) + - Copy the .dll and the folder with the configuration files into this Plugin folder. + - Start neo using additional parameters, if required; + - In order to start logging, start neo with the `--log` option. + +The resulting folder structure is going to be like this: + +```BASH +./neo-cli.dll +./Plugins/ApplicationLogs.dll +./Plugins/ApplicationsLogs/config.json +``` + +## Existing plugins +### Application Logs +Add this plugin to your application if need to access the log files. This can be useful to handle notifications, but remember that this also largely increases the space used by the application. + +### Import Blocks +Synchronizes the client using offline packages. Follow the instructions [here](http://docs.neo.org/en-us/network/syncblocks.html) to bootstrap your network using this plugin. + +### RPC Security +Improves security in RPC nodes. + +### Simpli Policy +Enables policies for consensus. + +### StatesDumper +Exports NEO-CLI status data \(useful for debugging\). From 4aa4a72b7d11eb4da72497e9357a4eaa747e0316 Mon Sep 17 00:00:00 2001 From: belane Date: Sun, 4 Nov 2018 00:40:12 +0100 Subject: [PATCH 021/183] misspelling (#26) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 93db4625f..2d2f7194d 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ Synchronizes the client using offline packages. Follow the instructions [here](h ### RPC Security Improves security in RPC nodes. -### Simpli Policy +### Simple Policy Enables policies for consensus. ### StatesDumper From d03cee8c53b5b6b3f0fbbd85142aec725349ea8c Mon Sep 17 00:00:00 2001 From: belane Date: Fri, 16 Nov 2018 08:38:07 +0100 Subject: [PATCH 022/183] Help for Plugins (#28) --- ImportBlocks/ImportBlocks.cs | 45 +++++++++++++++++++++++-------- StatesDumper/StatesDumper.cs | 51 +++++++++++++++++++++++++----------- 2 files changed, 70 insertions(+), 26 deletions(-) diff --git a/ImportBlocks/ImportBlocks.cs b/ImportBlocks/ImportBlocks.cs index 4f039aa5a..383a2431e 100644 --- a/ImportBlocks/ImportBlocks.cs +++ b/ImportBlocks/ImportBlocks.cs @@ -62,6 +62,13 @@ public ImportBlocks() }); } + private static bool CheckMaxOnImportHeight(uint currentImportBlockHeight) + { + if (Settings.Default.MaxOnImportHeight == 0 || Settings.Default.MaxOnImportHeight >= currentImportBlockHeight) + return true; + return false; + } + private static IEnumerable GetBlocks(Stream stream, bool read_start = false) { using (BinaryReader r = new BinaryReader(stream)) @@ -83,19 +90,12 @@ private static IEnumerable GetBlocks(Stream stream, bool read_start = fal } } - private static bool CheckMaxOnImportHeight(uint currentImportBlockHeight) - { - if (Settings.Default.MaxOnImportHeight == 0 || Settings.Default.MaxOnImportHeight >= currentImportBlockHeight) - return true; - return false; - } - - protected override bool OnMessage(object message) + private bool OnExport(string[] args) { - if (!(message is string[] args)) return false; if (args.Length < 2) return false; - if (args[0] != "export") return false; - if (args[1] != "block" && args[1] != "blocks") return false; + if (!string.Equals(args[1], "block", StringComparison.OrdinalIgnoreCase) + && !string.Equals(args[1], "blocks", StringComparison.OrdinalIgnoreCase)) + return false; if (args.Length >= 3 && uint.TryParse(args[2], out uint start)) { if (start > Blockchain.Singleton.Height) @@ -166,5 +166,28 @@ protected override bool OnMessage(object message) Console.WriteLine(); return true; } + + private bool OnHelp(string[] args) + { + if (args.Length < 2) return false; + if (!string.Equals(args[1], Name, StringComparison.OrdinalIgnoreCase)) + return false; + Console.Write($"{Name} Commands:\n" + "\texport block[s] \n"); + return true; + } + + protected override bool OnMessage(object message) + { + if (!(message is string[] args)) return false; + if (args.Length == 0) return false; + switch (args[0].ToLower()) + { + case "help": + return OnHelp(args); + case "export": + return OnExport(args); + } + return false; + } } } diff --git a/StatesDumper/StatesDumper.cs b/StatesDumper/StatesDumper.cs index 11f98ae21..fbe28a2d3 100644 --- a/StatesDumper/StatesDumper.cs +++ b/StatesDumper/StatesDumper.cs @@ -10,12 +10,40 @@ namespace Neo.Plugins { public class StatesDumper : Plugin { + private static void Dump(IEnumerable> states) + where TKey : ISerializable + where TValue : ISerializable + { + const string path = "dump.json"; + JArray array = new JArray(states.Select(p => + { + JObject state = new JObject(); + state["key"] = p.Key.ToArray().ToHexString(); + state["value"] = p.Value.ToArray().ToHexString(); + return state; + })); + File.WriteAllText(path, array.ToString()); + Console.WriteLine($"States ({array.Count}) have been dumped into file {path}"); + } + protected override bool OnMessage(object message) { if (!(message is string[] args)) return false; + if (args.Length == 0) return false; + switch (args[0].ToLower()) + { + case "help": + return OnHelp(args); + case "dump": + return OnDump(args); + } + return false; + } + + private bool OnDump(string[] args) + { if (args.Length < 2) return false; - if (args[0] != "dump") return false; - switch (args[1]) + switch (args[1].ToLower()) { case "storage": Dump(args.Length >= 3 @@ -27,20 +55,13 @@ protected override bool OnMessage(object message) } } - private static void Dump(IEnumerable> states) - where TKey : ISerializable - where TValue : ISerializable + private bool OnHelp(string[] args) { - const string path = "dump.json"; - JArray array = new JArray(states.Select(p => - { - JObject state = new JObject(); - state["key"] = p.Key.ToArray().ToHexString(); - state["value"] = p.Value.ToArray().ToHexString(); - return state; - })); - File.WriteAllText(path, array.ToString()); - Console.WriteLine($"States ({array.Count}) have been dumped into file {path}"); + if (args.Length < 2) return false; + if (!string.Equals(args[1], Name, StringComparison.OrdinalIgnoreCase)) + return false; + Console.Write($"{Name} Commands:\n" + "\tdump storage \n"); + return true; } } } From c3462c19fc59f1b160174a0c8020358011d98c55 Mon Sep 17 00:00:00 2001 From: belane Date: Fri, 16 Nov 2018 10:32:34 +0100 Subject: [PATCH 023/183] Transaction size plugin (#10) --- SimplePolicy/Settings.cs | 4 ++ SimplePolicy/SimplePolicy.csproj | 4 +- SimplePolicy/SimplePolicy/config.json | 2 + SimplePolicy/SimplePolicyPlugin.cs | 64 +++++++++++++---- neo-plugins.sln | 98 +++++++++++++-------------- 5 files changed, 107 insertions(+), 65 deletions(-) diff --git a/SimplePolicy/Settings.cs b/SimplePolicy/Settings.cs index 3a88c6290..47369a084 100644 --- a/SimplePolicy/Settings.cs +++ b/SimplePolicy/Settings.cs @@ -11,6 +11,8 @@ internal class Settings { public int MaxTransactionsPerBlock { get; } public int MaxFreeTransactionsPerBlock { get; } + public int MaxFreeTransactionSize { get; } + public Fixed8 FeePerExtraByte { get; } public BlockedAccounts BlockedAccounts { get; } public static Settings Default { get; } @@ -24,6 +26,8 @@ public Settings(IConfigurationSection section) { this.MaxTransactionsPerBlock = GetValueOrDefault(section.GetSection("MaxTransactionsPerBlock"), 500, p => int.Parse(p)); this.MaxFreeTransactionsPerBlock = GetValueOrDefault(section.GetSection("MaxFreeTransactionsPerBlock"), 20, p => int.Parse(p)); + this.MaxFreeTransactionSize = GetValueOrDefault(section.GetSection("MaxFreeTransactionSize"), 1024, p => int.Parse(p)); + this.FeePerExtraByte = GetValueOrDefault(section.GetSection("FeePerExtraByte"), Fixed8.FromDecimal(0.00001M), p => Fixed8.Parse(p)); this.BlockedAccounts = new BlockedAccounts(section.GetSection("BlockedAccounts")); } diff --git a/SimplePolicy/SimplePolicy.csproj b/SimplePolicy/SimplePolicy.csproj index 7ef0c6446..61c24d4b3 100644 --- a/SimplePolicy/SimplePolicy.csproj +++ b/SimplePolicy/SimplePolicy.csproj @@ -1,7 +1,7 @@  - 2.9.0 + 2.9.2 netstandard2.0;net47 Neo.Plugins @@ -14,7 +14,7 @@ - + diff --git a/SimplePolicy/SimplePolicy/config.json b/SimplePolicy/SimplePolicy/config.json index ed20082d9..85dd9cfbe 100644 --- a/SimplePolicy/SimplePolicy/config.json +++ b/SimplePolicy/SimplePolicy/config.json @@ -2,6 +2,8 @@ "PluginConfiguration": { "MaxTransactionsPerBlock": 500, "MaxFreeTransactionsPerBlock": 20, + "MaxFreeTransactionSize": 1024, + "FeePerExtraByte": 0.00001, "BlockedAccounts": { "Type": "AllowAll", "List": [] diff --git a/SimplePolicy/SimplePolicyPlugin.cs b/SimplePolicy/SimplePolicyPlugin.cs index f292090aa..f18680616 100644 --- a/SimplePolicy/SimplePolicyPlugin.cs +++ b/SimplePolicy/SimplePolicyPlugin.cs @@ -10,18 +10,22 @@ namespace Neo.Plugins { public class SimplePolicyPlugin : Plugin, ILogPlugin, IPolicyPlugin { - private static string log_dictionary = Path.Combine(AppContext.BaseDirectory, "Logs"); + private static readonly string log_dictionary = Path.Combine(AppContext.BaseDirectory, "Logs"); public bool FilterForMemoryPool(Transaction tx) { + if (!VerifySizeLimits(tx)) return false; + switch (Settings.Default.BlockedAccounts.Type) { case PolicyType.AllowAll: return true; case PolicyType.AllowList: - return tx.Witnesses.All(p => Settings.Default.BlockedAccounts.List.Contains(p.VerificationScript.ToScriptHash())) || tx.Outputs.All(p => Settings.Default.BlockedAccounts.List.Contains(p.ScriptHash)); + return tx.Witnesses.All(p => Settings.Default.BlockedAccounts.List.Contains(p.VerificationScript.ToScriptHash())) || + tx.Outputs.All(p => Settings.Default.BlockedAccounts.List.Contains(p.ScriptHash)); case PolicyType.DenyList: - return tx.Witnesses.All(p => !Settings.Default.BlockedAccounts.List.Contains(p.VerificationScript.ToScriptHash())) && tx.Outputs.All(p => !Settings.Default.BlockedAccounts.List.Contains(p.ScriptHash)); + return tx.Witnesses.All(p => !Settings.Default.BlockedAccounts.List.Contains(p.VerificationScript.ToScriptHash())) && + tx.Outputs.All(p => !Settings.Default.BlockedAccounts.List.Contains(p.ScriptHash)); default: return false; } @@ -29,21 +33,38 @@ public bool FilterForMemoryPool(Transaction tx) public IEnumerable FilterForBlock(IEnumerable transactions) { - Transaction[] array = transactions.ToArray(); - if (array.Length + 1 <= Settings.Default.MaxTransactionsPerBlock) - return array; - transactions = array.OrderByDescending(p => p.NetworkFee / p.Size).ThenByDescending(p => p.NetworkFee).Take(Settings.Default.MaxTransactionsPerBlock - 1); - return FilterFree(transactions); + return FilterForBlock_Policy2(transactions); } - private IEnumerable FilterFree(IEnumerable transactions) + private static IEnumerable FilterForBlock_Policy1(IEnumerable transactions) { - int count = 0; - foreach (Transaction tx in transactions) - if (tx.NetworkFee > Fixed8.Zero || tx.SystemFee > Fixed8.Zero) - yield return tx; - else if (count++ < Settings.Default.MaxFreeTransactionsPerBlock) + int count = 0, count_free = 0; + foreach (Transaction tx in transactions.OrderByDescending(p => p.NetworkFee / p.Size).ThenByDescending(p => p.NetworkFee)) + { + if (count++ >= Settings.Default.MaxTransactionsPerBlock - 1) break; + if (!tx.IsLowPriority || count_free++ < Settings.Default.MaxFreeTransactionsPerBlock) yield return tx; + } + } + + private static IEnumerable FilterForBlock_Policy2(IEnumerable transactions) + { + if (!(transactions is IReadOnlyList tx_list)) + tx_list = transactions.ToArray(); + + Transaction[] free = tx_list.Where(p => p.IsLowPriority) + .OrderByDescending(p => p.NetworkFee / p.Size) + .ThenByDescending(p => p.NetworkFee) + .Take(Settings.Default.MaxFreeTransactionsPerBlock) + .ToArray(); + + Transaction[] non_free = tx_list.Where(p => !p.IsLowPriority) + .OrderByDescending(p => p.NetworkFee / p.Size) + .ThenByDescending(p => p.NetworkFee) + .Take(Settings.Default.MaxTransactionsPerBlock - free.Length - 1) + .ToArray(); + + return non_free.Concat(free); } void ILogPlugin.Log(string source, LogLevel level, string message) @@ -60,5 +81,20 @@ void ILogPlugin.Log(string source, LogLevel level, string message) File.AppendAllLines(path, new[] { line }); } } + + private bool VerifySizeLimits(Transaction tx) + { + // Not Allow free TX bigger than MaxFreeTransactionSize + if (tx.IsLowPriority && tx.Size > Settings.Default.MaxFreeTransactionSize) return false; + + // Require proportional fee for TX bigger than MaxFreeTransactionSize + if (tx.Size > Settings.Default.MaxFreeTransactionSize) + { + Fixed8 fee = Settings.Default.FeePerExtraByte * (tx.Size - Settings.Default.MaxFreeTransactionSize); + + if (tx.NetworkFee < fee) return false; + } + return true; + } } } diff --git a/neo-plugins.sln b/neo-plugins.sln index bf0ece785..c0a23db38 100644 --- a/neo-plugins.sln +++ b/neo-plugins.sln @@ -1,49 +1,49 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.27428.2027 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SimplePolicy", "SimplePolicy\SimplePolicy.csproj", "{322C366E-F891-47FD-A039-0FEF79BCB6D5}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ApplicationLogs", "ApplicationLogs\ApplicationLogs.csproj", "{84DA8EA6-EF60-4FCD-B1C6-65C1A8323B3F}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RpcSecurity", "RpcSecurity\RpcSecurity.csproj", "{6800D782-8EC0-49E9-98C4-195C8F781A1F}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StatesDumper", "StatesDumper\StatesDumper.csproj", "{86531DB1-A231-46C4-823F-BE60972F7523}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImportBlocks", "ImportBlocks\ImportBlocks.csproj", "{B7A42984-57BB-4F8D-967B-23B0E841B726}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {322C366E-F891-47FD-A039-0FEF79BCB6D5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {322C366E-F891-47FD-A039-0FEF79BCB6D5}.Debug|Any CPU.Build.0 = Debug|Any CPU - {322C366E-F891-47FD-A039-0FEF79BCB6D5}.Release|Any CPU.ActiveCfg = Release|Any CPU - {322C366E-F891-47FD-A039-0FEF79BCB6D5}.Release|Any CPU.Build.0 = Release|Any CPU - {84DA8EA6-EF60-4FCD-B1C6-65C1A8323B3F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {84DA8EA6-EF60-4FCD-B1C6-65C1A8323B3F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {84DA8EA6-EF60-4FCD-B1C6-65C1A8323B3F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {84DA8EA6-EF60-4FCD-B1C6-65C1A8323B3F}.Release|Any CPU.Build.0 = Release|Any CPU - {6800D782-8EC0-49E9-98C4-195C8F781A1F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6800D782-8EC0-49E9-98C4-195C8F781A1F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6800D782-8EC0-49E9-98C4-195C8F781A1F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6800D782-8EC0-49E9-98C4-195C8F781A1F}.Release|Any CPU.Build.0 = Release|Any CPU - {86531DB1-A231-46C4-823F-BE60972F7523}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {86531DB1-A231-46C4-823F-BE60972F7523}.Debug|Any CPU.Build.0 = Debug|Any CPU - {86531DB1-A231-46C4-823F-BE60972F7523}.Release|Any CPU.ActiveCfg = Release|Any CPU - {86531DB1-A231-46C4-823F-BE60972F7523}.Release|Any CPU.Build.0 = Release|Any CPU - {B7A42984-57BB-4F8D-967B-23B0E841B726}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B7A42984-57BB-4F8D-967B-23B0E841B726}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B7A42984-57BB-4F8D-967B-23B0E841B726}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B7A42984-57BB-4F8D-967B-23B0E841B726}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {61D3ADE6-BBFC-402D-AB42-1C71C9F9EDE3} - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.27428.2027 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SimplePolicy", "SimplePolicy\SimplePolicy.csproj", "{322C366E-F891-47FD-A039-0FEF79BCB6D5}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ApplicationLogs", "ApplicationLogs\ApplicationLogs.csproj", "{84DA8EA6-EF60-4FCD-B1C6-65C1A8323B3F}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RpcSecurity", "RpcSecurity\RpcSecurity.csproj", "{6800D782-8EC0-49E9-98C4-195C8F781A1F}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StatesDumper", "StatesDumper\StatesDumper.csproj", "{86531DB1-A231-46C4-823F-BE60972F7523}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImportBlocks", "ImportBlocks\ImportBlocks.csproj", "{B7A42984-57BB-4F8D-967B-23B0E841B726}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {322C366E-F891-47FD-A039-0FEF79BCB6D5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {322C366E-F891-47FD-A039-0FEF79BCB6D5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {322C366E-F891-47FD-A039-0FEF79BCB6D5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {322C366E-F891-47FD-A039-0FEF79BCB6D5}.Release|Any CPU.Build.0 = Release|Any CPU + {84DA8EA6-EF60-4FCD-B1C6-65C1A8323B3F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {84DA8EA6-EF60-4FCD-B1C6-65C1A8323B3F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {84DA8EA6-EF60-4FCD-B1C6-65C1A8323B3F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {84DA8EA6-EF60-4FCD-B1C6-65C1A8323B3F}.Release|Any CPU.Build.0 = Release|Any CPU + {6800D782-8EC0-49E9-98C4-195C8F781A1F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6800D782-8EC0-49E9-98C4-195C8F781A1F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6800D782-8EC0-49E9-98C4-195C8F781A1F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6800D782-8EC0-49E9-98C4-195C8F781A1F}.Release|Any CPU.Build.0 = Release|Any CPU + {86531DB1-A231-46C4-823F-BE60972F7523}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {86531DB1-A231-46C4-823F-BE60972F7523}.Debug|Any CPU.Build.0 = Debug|Any CPU + {86531DB1-A231-46C4-823F-BE60972F7523}.Release|Any CPU.ActiveCfg = Release|Any CPU + {86531DB1-A231-46C4-823F-BE60972F7523}.Release|Any CPU.Build.0 = Release|Any CPU + {B7A42984-57BB-4F8D-967B-23B0E841B726}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B7A42984-57BB-4F8D-967B-23B0E841B726}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B7A42984-57BB-4F8D-967B-23B0E841B726}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B7A42984-57BB-4F8D-967B-23B0E841B726}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {61D3ADE6-BBFC-402D-AB42-1C71C9F9EDE3} + EndGlobalSection +EndGlobal From e9e97ba3aee5f857a422bc43e907d1cfefc9ade6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vitor=20Naz=C3=A1rio=20Coelho?= Date: Fri, 16 Nov 2018 07:39:45 -0200 Subject: [PATCH 024/183] Update packages reference (#22) --- ApplicationLogs/ApplicationLogs.csproj | 4 ++-- ImportBlocks/ImportBlocks.csproj | 4 ++-- RpcSecurity/RpcSecurity.csproj | 4 ++-- StatesDumper/StatesDumper.csproj | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ApplicationLogs/ApplicationLogs.csproj b/ApplicationLogs/ApplicationLogs.csproj index dd21e92b1..d25e916b0 100644 --- a/ApplicationLogs/ApplicationLogs.csproj +++ b/ApplicationLogs/ApplicationLogs.csproj @@ -1,7 +1,7 @@  - 2.9.0 + 2.9.2 netstandard2.0;net47 Neo.Plugins @@ -14,7 +14,7 @@ - + diff --git a/ImportBlocks/ImportBlocks.csproj b/ImportBlocks/ImportBlocks.csproj index 1866dc275..36a61047b 100644 --- a/ImportBlocks/ImportBlocks.csproj +++ b/ImportBlocks/ImportBlocks.csproj @@ -1,7 +1,7 @@  - 2.9.0 + 2.9.2 netstandard2.0;net47 Neo.Plugins @@ -14,7 +14,7 @@ - + diff --git a/RpcSecurity/RpcSecurity.csproj b/RpcSecurity/RpcSecurity.csproj index b977eafce..fb4d8eaf2 100644 --- a/RpcSecurity/RpcSecurity.csproj +++ b/RpcSecurity/RpcSecurity.csproj @@ -1,7 +1,7 @@  - 2.9.0 + 2.9.2 netstandard2.0;net47 Neo.Plugins @@ -14,7 +14,7 @@ - + diff --git a/StatesDumper/StatesDumper.csproj b/StatesDumper/StatesDumper.csproj index 0d1c24e83..b79de5c2f 100644 --- a/StatesDumper/StatesDumper.csproj +++ b/StatesDumper/StatesDumper.csproj @@ -1,13 +1,13 @@  - 2.9.0 + 2.9.2 netstandard2.0;net47 Neo.Plugins - + From 250889ee73d41a490c31cfa9934886ed47f1b92d Mon Sep 17 00:00:00 2001 From: Igor Machado Coelho Date: Tue, 20 Nov 2018 05:29:30 -0200 Subject: [PATCH 025/183] Basic unit test structure for SimplePolicyPlugin (#25) --- .../SimplePolicy.UnitTests.csproj | 21 ++++ SimplePolicy.UnitTests/UT_SimplePolicy.cs | 26 +++++ SimplePolicy/Helper.cs | 14 +++ SimplePolicy/Settings.cs | 2 +- SimplePolicy/SimplePolicyPlugin.cs | 3 + neo-plugins.sln | 104 +++++++++--------- 6 files changed, 120 insertions(+), 50 deletions(-) create mode 100644 SimplePolicy.UnitTests/SimplePolicy.UnitTests.csproj create mode 100644 SimplePolicy.UnitTests/UT_SimplePolicy.cs create mode 100644 SimplePolicy/Helper.cs diff --git a/SimplePolicy.UnitTests/SimplePolicy.UnitTests.csproj b/SimplePolicy.UnitTests/SimplePolicy.UnitTests.csproj new file mode 100644 index 000000000..d49e54aec --- /dev/null +++ b/SimplePolicy.UnitTests/SimplePolicy.UnitTests.csproj @@ -0,0 +1,21 @@ + + + + Exe + netcoreapp2.0 + SimplePolicy.UnitTests + SimplePolicy.UnitTests + + + + + + + + + + + + + + diff --git a/SimplePolicy.UnitTests/UT_SimplePolicy.cs b/SimplePolicy.UnitTests/UT_SimplePolicy.cs new file mode 100644 index 000000000..3f7d7b9e1 --- /dev/null +++ b/SimplePolicy.UnitTests/UT_SimplePolicy.cs @@ -0,0 +1,26 @@ +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Plugins; + + +namespace SimplePolicy.UnitTests +{ + [TestClass] + public class UT_SimplePolicy + { + SimplePolicyPlugin uut; + + [TestInitialize] + public void TestSetup() + { + uut = new SimplePolicyPlugin(); + } + + [TestMethod] + public void TestMaxTransactionsPerBlock() + { + Settings.Default.MaxTransactionsPerBlock.Should().Be(500); + Settings.Default.MaxFreeTransactionsPerBlock.Should().Be(20); + } + } +} diff --git a/SimplePolicy/Helper.cs b/SimplePolicy/Helper.cs new file mode 100644 index 000000000..895731aaf --- /dev/null +++ b/SimplePolicy/Helper.cs @@ -0,0 +1,14 @@ +using Microsoft.Extensions.Configuration; +using System; + +namespace Neo.Plugins +{ + internal static class Helper + { + public static T GetValueOrDefault(this IConfigurationSection section, T defaultValue, Func selector) + { + if (section.Value == null) return defaultValue; + return selector(section.Value); + } + } +} diff --git a/SimplePolicy/Settings.cs b/SimplePolicy/Settings.cs index 47369a084..c6f8f6760 100644 --- a/SimplePolicy/Settings.cs +++ b/SimplePolicy/Settings.cs @@ -53,7 +53,7 @@ internal class BlockedAccounts public BlockedAccounts(IConfigurationSection section) { - this.Type = (PolicyType)Enum.Parse(typeof(PolicyType), section.GetSection("Type").Value, true); + this.Type = section.GetSection("Type").GetValueOrDefault(PolicyType.AllowAll, p => (PolicyType)Enum.Parse(typeof(PolicyType), p, true)); this.List = new HashSet(section.GetSection("List").GetChildren().Select(p => p.Value.ToScriptHash())); } } diff --git a/SimplePolicy/SimplePolicyPlugin.cs b/SimplePolicy/SimplePolicyPlugin.cs index f18680616..933c5ae86 100644 --- a/SimplePolicy/SimplePolicyPlugin.cs +++ b/SimplePolicy/SimplePolicyPlugin.cs @@ -5,6 +5,9 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("SimplePolicy.UnitTests")] namespace Neo.Plugins { diff --git a/neo-plugins.sln b/neo-plugins.sln index c0a23db38..83027c37d 100644 --- a/neo-plugins.sln +++ b/neo-plugins.sln @@ -1,49 +1,55 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.27428.2027 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SimplePolicy", "SimplePolicy\SimplePolicy.csproj", "{322C366E-F891-47FD-A039-0FEF79BCB6D5}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ApplicationLogs", "ApplicationLogs\ApplicationLogs.csproj", "{84DA8EA6-EF60-4FCD-B1C6-65C1A8323B3F}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RpcSecurity", "RpcSecurity\RpcSecurity.csproj", "{6800D782-8EC0-49E9-98C4-195C8F781A1F}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StatesDumper", "StatesDumper\StatesDumper.csproj", "{86531DB1-A231-46C4-823F-BE60972F7523}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImportBlocks", "ImportBlocks\ImportBlocks.csproj", "{B7A42984-57BB-4F8D-967B-23B0E841B726}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {322C366E-F891-47FD-A039-0FEF79BCB6D5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {322C366E-F891-47FD-A039-0FEF79BCB6D5}.Debug|Any CPU.Build.0 = Debug|Any CPU - {322C366E-F891-47FD-A039-0FEF79BCB6D5}.Release|Any CPU.ActiveCfg = Release|Any CPU - {322C366E-F891-47FD-A039-0FEF79BCB6D5}.Release|Any CPU.Build.0 = Release|Any CPU - {84DA8EA6-EF60-4FCD-B1C6-65C1A8323B3F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {84DA8EA6-EF60-4FCD-B1C6-65C1A8323B3F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {84DA8EA6-EF60-4FCD-B1C6-65C1A8323B3F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {84DA8EA6-EF60-4FCD-B1C6-65C1A8323B3F}.Release|Any CPU.Build.0 = Release|Any CPU - {6800D782-8EC0-49E9-98C4-195C8F781A1F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6800D782-8EC0-49E9-98C4-195C8F781A1F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6800D782-8EC0-49E9-98C4-195C8F781A1F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6800D782-8EC0-49E9-98C4-195C8F781A1F}.Release|Any CPU.Build.0 = Release|Any CPU - {86531DB1-A231-46C4-823F-BE60972F7523}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {86531DB1-A231-46C4-823F-BE60972F7523}.Debug|Any CPU.Build.0 = Debug|Any CPU - {86531DB1-A231-46C4-823F-BE60972F7523}.Release|Any CPU.ActiveCfg = Release|Any CPU - {86531DB1-A231-46C4-823F-BE60972F7523}.Release|Any CPU.Build.0 = Release|Any CPU - {B7A42984-57BB-4F8D-967B-23B0E841B726}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B7A42984-57BB-4F8D-967B-23B0E841B726}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B7A42984-57BB-4F8D-967B-23B0E841B726}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B7A42984-57BB-4F8D-967B-23B0E841B726}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {61D3ADE6-BBFC-402D-AB42-1C71C9F9EDE3} - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.27428.2027 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SimplePolicy", "SimplePolicy\SimplePolicy.csproj", "{322C366E-F891-47FD-A039-0FEF79BCB6D5}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ApplicationLogs", "ApplicationLogs\ApplicationLogs.csproj", "{84DA8EA6-EF60-4FCD-B1C6-65C1A8323B3F}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RpcSecurity", "RpcSecurity\RpcSecurity.csproj", "{6800D782-8EC0-49E9-98C4-195C8F781A1F}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StatesDumper", "StatesDumper\StatesDumper.csproj", "{86531DB1-A231-46C4-823F-BE60972F7523}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImportBlocks", "ImportBlocks\ImportBlocks.csproj", "{B7A42984-57BB-4F8D-967B-23B0E841B726}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SimplePolicy.UnitTests", "SimplePolicy.UnitTests\SimplePolicy.UnitTests.csproj", "{0DA81327-DC81-4960-91C8-4C5F8B9B804C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {322C366E-F891-47FD-A039-0FEF79BCB6D5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {322C366E-F891-47FD-A039-0FEF79BCB6D5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {322C366E-F891-47FD-A039-0FEF79BCB6D5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {322C366E-F891-47FD-A039-0FEF79BCB6D5}.Release|Any CPU.Build.0 = Release|Any CPU + {84DA8EA6-EF60-4FCD-B1C6-65C1A8323B3F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {84DA8EA6-EF60-4FCD-B1C6-65C1A8323B3F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {84DA8EA6-EF60-4FCD-B1C6-65C1A8323B3F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {84DA8EA6-EF60-4FCD-B1C6-65C1A8323B3F}.Release|Any CPU.Build.0 = Release|Any CPU + {6800D782-8EC0-49E9-98C4-195C8F781A1F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6800D782-8EC0-49E9-98C4-195C8F781A1F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6800D782-8EC0-49E9-98C4-195C8F781A1F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6800D782-8EC0-49E9-98C4-195C8F781A1F}.Release|Any CPU.Build.0 = Release|Any CPU + {86531DB1-A231-46C4-823F-BE60972F7523}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {86531DB1-A231-46C4-823F-BE60972F7523}.Debug|Any CPU.Build.0 = Debug|Any CPU + {86531DB1-A231-46C4-823F-BE60972F7523}.Release|Any CPU.ActiveCfg = Release|Any CPU + {86531DB1-A231-46C4-823F-BE60972F7523}.Release|Any CPU.Build.0 = Release|Any CPU + {B7A42984-57BB-4F8D-967B-23B0E841B726}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B7A42984-57BB-4F8D-967B-23B0E841B726}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B7A42984-57BB-4F8D-967B-23B0E841B726}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B7A42984-57BB-4F8D-967B-23B0E841B726}.Release|Any CPU.Build.0 = Release|Any CPU + {0DA81327-DC81-4960-91C8-4C5F8B9B804C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0DA81327-DC81-4960-91C8-4C5F8B9B804C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0DA81327-DC81-4960-91C8-4C5F8B9B804C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0DA81327-DC81-4960-91C8-4C5F8B9B804C}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {61D3ADE6-BBFC-402D-AB42-1C71C9F9EDE3} + EndGlobalSection +EndGlobal From db04e756a64c149e86d117fe89879c72f319c7df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vitor=20Naz=C3=A1rio=20Coelho?= Date: Tue, 4 Dec 2018 07:55:28 -0200 Subject: [PATCH 026/183] Persitence Plugin for exporting storage changes (#21) * Persitence Plugin first draft * Fixing some compiling problems. Trackable is still not found in the local scope. * Minnor changes. Trackable still not found * Fixing all compiling errors and Trackable * Fixing StorageKey and Item get values * Switch case Persist Action and fixing Storage export * Adding Height To Being * Moving plugin to StatesDumper * minnor comments * remove StatesDumper.sln * format * remove `Settings.BlockStorageCache` * add `PersistActions` --- StatesDumper/PersistActions.cs | 10 ++++ StatesDumper/Settings.cs | 48 +++++++++++++++++ StatesDumper/StatesDumper.cs | 75 ++++++++++++++++++++++++++- StatesDumper/StatesDumper.csproj | 7 +++ StatesDumper/StatesDumper/config.json | 8 +++ 5 files changed, 147 insertions(+), 1 deletion(-) create mode 100644 StatesDumper/PersistActions.cs create mode 100644 StatesDumper/Settings.cs create mode 100644 StatesDumper/StatesDumper/config.json diff --git a/StatesDumper/PersistActions.cs b/StatesDumper/PersistActions.cs new file mode 100644 index 000000000..b7016ab8e --- /dev/null +++ b/StatesDumper/PersistActions.cs @@ -0,0 +1,10 @@ +using System; + +namespace Neo.Plugins +{ + [Flags] + internal enum PersistActions : byte + { + StorageChanges = 0b00000001 + } +} diff --git a/StatesDumper/Settings.cs b/StatesDumper/Settings.cs new file mode 100644 index 000000000..e747af133 --- /dev/null +++ b/StatesDumper/Settings.cs @@ -0,0 +1,48 @@ +using Microsoft.Extensions.Configuration; +using System; +using System.Reflection; + +namespace Neo.Plugins +{ + internal class Settings + { + /// + /// Amount of storages states (heights) to be dump in a given json file + /// + public uint BlockCacheSize { get; } + /// + /// Height to begin storage dump + /// + public uint HeightToBegin { get; } + /// + /// Height to begin real-time syncing and dumping on, consequently, dumping every block into a single files + /// + public uint HeightToStartRealTimeSyncing { get; } + /// + /// Persisting actions + /// + public PersistActions PersistAction { get; } + + public static Settings Default { get; } + + static Settings() + { + Default = new Settings(Assembly.GetExecutingAssembly().GetConfiguration()); + } + + public Settings(IConfigurationSection section) + { + /// Geting settings for storage changes state dumper + this.BlockCacheSize = GetValueOrDefault(section.GetSection("BlockCacheSize"), 1000u, p => uint.Parse(p)); + this.HeightToBegin = GetValueOrDefault(section.GetSection("HeightToBegin"), 0u, p => uint.Parse(p)); + this.HeightToStartRealTimeSyncing = GetValueOrDefault(section.GetSection("HeightToStartRealTimeSyncing"), 2883000u, p => uint.Parse(p)); + this.PersistAction = GetValueOrDefault(section.GetSection("PersistAction"), PersistActions.StorageChanges, p => (PersistActions)Enum.Parse(typeof(PersistActions), p)); + } + + public T GetValueOrDefault(IConfigurationSection section, T defaultValue, Func selector) + { + if (section.Value == null) return defaultValue; + return selector(section.Value); + } + } +} diff --git a/StatesDumper/StatesDumper.cs b/StatesDumper/StatesDumper.cs index fbe28a2d3..4add46abf 100644 --- a/StatesDumper/StatesDumper.cs +++ b/StatesDumper/StatesDumper.cs @@ -1,6 +1,8 @@ using Neo.IO; +using Neo.IO.Caching; using Neo.IO.Json; using Neo.Ledger; +using Neo.Persistence; using System; using System.Collections.Generic; using System.IO; @@ -8,8 +10,10 @@ namespace Neo.Plugins { - public class StatesDumper : Plugin + public class StatesDumper : Plugin, IPersistencePlugin { + private readonly JArray bs_cache = new JArray(); + private static void Dump(IEnumerable> states) where TKey : ISerializable where TValue : ISerializable @@ -63,5 +67,74 @@ private bool OnHelp(string[] args) Console.Write($"{Name} Commands:\n" + "\tdump storage \n"); return true; } + + public void OnPersist(Snapshot snapshot) + { + if (Settings.Default.PersistAction.HasFlag(PersistActions.StorageChanges)) + OnPersistStorage(snapshot); + } + + private void OnPersistStorage(Snapshot snapshot) + { + uint blockIndex = snapshot.Height; + if (blockIndex >= Settings.Default.HeightToBegin) + { + string dirPath = "./Storage"; + Directory.CreateDirectory(dirPath); + string path = $"{HandlePaths(dirPath, blockIndex)}/dump-block-{blockIndex.ToString()}.json"; + + JArray array = new JArray(); + + foreach (DataCache.Trackable trackable in snapshot.Storages.GetChangeSet()) + { + JObject state = new JObject(); + + switch (trackable.State) + { + + case TrackState.Added: + state["state"] = "Added"; + state["key"] = trackable.Key.ToArray().ToHexString(); + state["value"] = trackable.Item.ToArray().ToHexString(); + // Here we have a new trackable.Key and trackable.Item + break; + case TrackState.Changed: + state["state"] = "Changed"; + state["key"] = trackable.Key.ToArray().ToHexString(); + state["value"] = trackable.Item.ToArray().ToHexString(); + break; + case TrackState.Deleted: + state["state"] = "Deleted"; + state["key"] = trackable.Key.ToArray().ToHexString(); + break; + } + array.Add(state); + } + + JObject bs_item = new JObject(); + bs_item["block"] = blockIndex; + bs_item["size"] = array.Count; + bs_item["storage"] = array; + bs_cache.Add(bs_item); + + if ((blockIndex % Settings.Default.BlockCacheSize == 0) || (blockIndex > Settings.Default.HeightToStartRealTimeSyncing)) + { + File.WriteAllText(path, bs_cache.ToString()); + bs_cache.Clear(); + } + } + } + + private static string HandlePaths(string dirPath, uint blockIndex) + { + //Default Parameter + uint storagePerFolder = 100000; + uint folder = (((blockIndex - 1) / storagePerFolder) + 1) * storagePerFolder; + if (blockIndex == 0) + folder = 0; + string dirPathWithBlock = $"{dirPath}/BlockStorage_{folder}"; + Directory.CreateDirectory(dirPathWithBlock); + return dirPathWithBlock; + } } } diff --git a/StatesDumper/StatesDumper.csproj b/StatesDumper/StatesDumper.csproj index b79de5c2f..799391d52 100644 --- a/StatesDumper/StatesDumper.csproj +++ b/StatesDumper/StatesDumper.csproj @@ -6,6 +6,13 @@ Neo.Plugins + + + PreserveNewest + PreserveNewest + + + diff --git a/StatesDumper/StatesDumper/config.json b/StatesDumper/StatesDumper/config.json new file mode 100644 index 000000000..7e1e2a347 --- /dev/null +++ b/StatesDumper/StatesDumper/config.json @@ -0,0 +1,8 @@ +{ + "PluginConfiguration": { + "PersistAction": "StorageChanges", + "BlockCacheSize": 1000, + "HeightToBegin": 0, + "HeightToRealTimeSyncing": 2883000 + } +} From 768b885e43c9976650e0dd2a9d2bf36c435793d9 Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Fri, 14 Dec 2018 14:59:44 +0800 Subject: [PATCH 027/183] v2.9.3 (#31) * Update packages reference * Fix claim (#34) --- ApplicationLogs/ApplicationLogs.csproj | 4 +- ApplicationLogs/LogReader.cs | 8 +- ApplicationLogs/Settings.cs | 11 +- ImportBlocks/ImportBlocks.cs | 5 + ImportBlocks/ImportBlocks.csproj | 4 +- ImportBlocks/Settings.cs | 15 +- RpcSecurity/RpcSecurity.cs | 5 + RpcSecurity/RpcSecurity.csproj | 4 +- RpcSecurity/Settings.cs | 15 +- .../SimplePolicy.UnitTests.csproj | 15 +- SimplePolicy.UnitTests/UT_SimplePolicy.cs | 277 +++++++++++++++++- SimplePolicy.UnitTests/protocol.json | 30 ++ SimplePolicy/Settings.cs | 33 ++- SimplePolicy/SimplePolicy.csproj | 5 +- SimplePolicy/SimplePolicy/config.json | 6 +- SimplePolicy/SimplePolicyPlugin.cs | 15 +- StatesDumper/Settings.cs | 15 +- StatesDumper/StatesDumper.cs | 5 + StatesDumper/StatesDumper.csproj | 4 +- 19 files changed, 418 insertions(+), 58 deletions(-) create mode 100644 SimplePolicy.UnitTests/protocol.json diff --git a/ApplicationLogs/ApplicationLogs.csproj b/ApplicationLogs/ApplicationLogs.csproj index d25e916b0..15ceaf9e2 100644 --- a/ApplicationLogs/ApplicationLogs.csproj +++ b/ApplicationLogs/ApplicationLogs.csproj @@ -1,7 +1,7 @@  - 2.9.2 + 2.9.3 netstandard2.0;net47 Neo.Plugins @@ -14,7 +14,7 @@ - + diff --git a/ApplicationLogs/LogReader.cs b/ApplicationLogs/LogReader.cs index fe78c0964..12968441c 100644 --- a/ApplicationLogs/LogReader.cs +++ b/ApplicationLogs/LogReader.cs @@ -8,15 +8,21 @@ namespace Neo.Plugins { public class LogReader : Plugin, IRpcPlugin { - private readonly DB db = DB.Open(Path.GetFullPath(Settings.Default.Path), new Options { CreateIfMissing = true }); + private readonly DB db; public override string Name => "ApplicationLogs"; public LogReader() { + this.db = DB.Open(Path.GetFullPath(Settings.Default.Path), new Options { CreateIfMissing = true }); System.ActorSystem.ActorOf(Logger.Props(System.Blockchain, db)); } + public override void Configure() + { + Settings.Load(GetConfiguration()); + } + public JObject OnProcess(HttpContext context, string method, JArray _params) { if (method != "getapplicationlog") return null; diff --git a/ApplicationLogs/Settings.cs b/ApplicationLogs/Settings.cs index 393a59a7c..234972e7c 100644 --- a/ApplicationLogs/Settings.cs +++ b/ApplicationLogs/Settings.cs @@ -1,6 +1,5 @@ using Microsoft.Extensions.Configuration; using Neo.Network.P2P; -using System.Reflection; namespace Neo.Plugins { @@ -8,16 +7,16 @@ internal class Settings { public string Path { get; } - public static Settings Default { get; } + public static Settings Default { get; private set; } - static Settings() + private Settings(IConfigurationSection section) { - Default = new Settings(Assembly.GetExecutingAssembly().GetConfiguration()); + this.Path = string.Format(section.GetSection("Path").Value, Message.Magic.ToString("X8")); } - public Settings(IConfigurationSection section) + public static void Load(IConfigurationSection section) { - this.Path = string.Format(section.GetSection("Path").Value, Message.Magic.ToString("X8")); + Default = new Settings(section); } } } diff --git a/ImportBlocks/ImportBlocks.cs b/ImportBlocks/ImportBlocks.cs index 383a2431e..786986ecd 100644 --- a/ImportBlocks/ImportBlocks.cs +++ b/ImportBlocks/ImportBlocks.cs @@ -69,6 +69,11 @@ private static bool CheckMaxOnImportHeight(uint currentImportBlockHeight) return false; } + public override void Configure() + { + Settings.Load(GetConfiguration()); + } + private static IEnumerable GetBlocks(Stream stream, bool read_start = false) { using (BinaryReader r = new BinaryReader(stream)) diff --git a/ImportBlocks/ImportBlocks.csproj b/ImportBlocks/ImportBlocks.csproj index 36a61047b..fffab1628 100644 --- a/ImportBlocks/ImportBlocks.csproj +++ b/ImportBlocks/ImportBlocks.csproj @@ -1,7 +1,7 @@  - 2.9.2 + 2.9.3 netstandard2.0;net47 Neo.Plugins @@ -14,7 +14,7 @@ - + diff --git a/ImportBlocks/Settings.cs b/ImportBlocks/Settings.cs index 17523d17d..279e80127 100644 --- a/ImportBlocks/Settings.cs +++ b/ImportBlocks/Settings.cs @@ -1,6 +1,5 @@ using Microsoft.Extensions.Configuration; using System; -using System.Reflection; namespace Neo.Plugins { @@ -8,14 +7,9 @@ internal class Settings { public uint MaxOnImportHeight { get; } - public static Settings Default { get; } + public static Settings Default { get; private set; } - static Settings() - { - Default = new Settings(Assembly.GetExecutingAssembly().GetConfiguration()); - } - - public Settings(IConfigurationSection section) + private Settings(IConfigurationSection section) { this.MaxOnImportHeight = GetValueOrDefault(section.GetSection("MaxOnImportHeight"), 0u, p => uint.Parse(p)); } @@ -25,5 +19,10 @@ public T GetValueOrDefault(IConfigurationSection section, T defaultValue, Fun if (section.Value == null) return defaultValue; return selector(section.Value); } + + public static void Load(IConfigurationSection section) + { + Default = new Settings(section); + } } } diff --git a/RpcSecurity/RpcSecurity.cs b/RpcSecurity/RpcSecurity.cs index 70049de68..dec271dc2 100644 --- a/RpcSecurity/RpcSecurity.cs +++ b/RpcSecurity/RpcSecurity.cs @@ -9,6 +9,11 @@ namespace Neo.Plugins { public class RpcSecurity : Plugin, IRpcPlugin { + public override void Configure() + { + Settings.Load(GetConfiguration()); + } + public JObject OnProcess(HttpContext context, string method, JArray _params) { if (!CheckAuth(context) || Settings.Default.DisabledMethods.Contains(method)) diff --git a/RpcSecurity/RpcSecurity.csproj b/RpcSecurity/RpcSecurity.csproj index fb4d8eaf2..7c64c9140 100644 --- a/RpcSecurity/RpcSecurity.csproj +++ b/RpcSecurity/RpcSecurity.csproj @@ -1,7 +1,7 @@  - 2.9.2 + 2.9.3 netstandard2.0;net47 Neo.Plugins @@ -14,7 +14,7 @@ - + diff --git a/RpcSecurity/Settings.cs b/RpcSecurity/Settings.cs index c78a488c2..4d83ff7d5 100644 --- a/RpcSecurity/Settings.cs +++ b/RpcSecurity/Settings.cs @@ -1,6 +1,5 @@ using Microsoft.Extensions.Configuration; using System.Linq; -using System.Reflection; namespace Neo.Plugins { @@ -10,18 +9,18 @@ internal class Settings public string RpcPass { get; } public string[] DisabledMethods { get; } - public static Settings Default { get; } + public static Settings Default { get; private set; } - static Settings() - { - Default = new Settings(Assembly.GetExecutingAssembly().GetConfiguration()); - } - - public Settings(IConfigurationSection section) + private Settings(IConfigurationSection section) { this.RpcUser = section.GetSection("RpcUser").Value; this.RpcPass = section.GetSection("RpcPass").Value; this.DisabledMethods = section.GetSection("DisabledMethods").GetChildren().Select(p => p.Value).ToArray(); } + + public static void Load(IConfigurationSection section) + { + Default = new Settings(section); + } } } diff --git a/SimplePolicy.UnitTests/SimplePolicy.UnitTests.csproj b/SimplePolicy.UnitTests/SimplePolicy.UnitTests.csproj index d49e54aec..6fc475c8f 100644 --- a/SimplePolicy.UnitTests/SimplePolicy.UnitTests.csproj +++ b/SimplePolicy.UnitTests/SimplePolicy.UnitTests.csproj @@ -8,10 +8,17 @@ - - - - + + PreserveNewest + + + + + + + + + diff --git a/SimplePolicy.UnitTests/UT_SimplePolicy.cs b/SimplePolicy.UnitTests/UT_SimplePolicy.cs index 3f7d7b9e1..550b5825b 100644 --- a/SimplePolicy.UnitTests/UT_SimplePolicy.cs +++ b/SimplePolicy.UnitTests/UT_SimplePolicy.cs @@ -1,7 +1,16 @@ using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.Plugins; - +using Neo.Network.P2P.Payloads; +using Neo; +using Settings = Neo.Plugins.Settings; +using System.Collections.Generic; +using Neo.Cryptography; +using System.Numerics; +using System.Collections; +using System.Linq; +using System; +using Moq; namespace SimplePolicy.UnitTests { @@ -22,5 +31,271 @@ public void TestMaxTransactionsPerBlock() Settings.Default.MaxTransactionsPerBlock.Should().Be(500); Settings.Default.MaxFreeTransactionsPerBlock.Should().Be(20); } + + + [TestMethod] + public void TestFilterForBlock_ClaimHasPriority() + { + // Should contain "ClaimTransaction" in "HighPriorityTxType" + Settings.Default.HighPriorityTxType.Contains(TransactionType.ClaimTransaction).Should().Be(true); + + ClaimTransaction claimTxZero = GetClaimTransaction(0); + claimTxZero.Size.Should().Be(7); // 7 + ClaimTransaction claimTxOne = GetClaimTransaction(1); + claimTxOne.Size.Should().Be(41); // 34 + 7 + ClaimTransaction claimTxTwo = GetClaimTransaction(2); + claimTxTwo.Size.Should().Be(75); // 2*34 + 7 + + ClaimTransaction claimTx30 = GetClaimTransaction(30); + claimTx30.Size.Should().Be(1027); // 30*34 + 7 + claimTx30.NetworkFee.Should().Be(Fixed8.Zero); + claimTx30.IsLowPriority.Should().Be(true); // by default is Low Priority, but plugin makes it High Priority + //uut.IsLowPriority -> cannot inspect because it's private... no problem! + + List TxList = new List(); + TxList.Insert(0, claimTxZero); + TxList.Insert(0, claimTxOne); + TxList.Insert(0, claimTxTwo); + TxList.Insert(0, claimTx30); + + // ======================== BEGIN TESTS ============================ + + // insert 100 paid invocation transactions + for (var i = 0; i < 100; i++) + { + TxList.Insert(0, MockGenerateInvocationTransaction(Fixed8.One, 50).Object); + } + + // insert 100 low priority invocation transactions (18 satoshi + 82 zero) + for (var i = 0; i < 100; i++) + { + if (i < 18) + TxList.Insert(0, MockGenerateInvocationTransaction(Fixed8.Satoshi, 50).Object); + else + TxList.Insert(0, MockGenerateInvocationTransaction(Fixed8.Zero, 50).Object); + } + + TxList.Count().Should().Be(204); // 100 free + 100 paid + 4 claims + TxList.Where(tx => tx.NetworkFee == Fixed8.Zero).Count().Should().Be(100-18+4); // 82 fully free + 4 claims + + IEnumerable filteredTxList = uut.FilterForBlock(TxList); + //filteredTxList.Count().Should().Be(124); // 20 free + 100 paid + 4 claims + filteredTxList.Count().Should().Be(120); // 20 free (including 2 claims) + 100 paid + filteredTxList.Where(tx => tx.NetworkFee == Fixed8.Zero).Count().Should().Be(2); // 2 fully free (2 claims) + + // will select 20 low priority (including Claims) + var vx = filteredTxList.Where(tx => tx.IsLowPriority == true); + vx.Count().Should().Be(20); + + // two Claim Transaction will survive + vx = filteredTxList.Where(tx => tx.Type == TransactionType.ClaimTransaction); + vx.Count().Should().Be(2); + + // ================================================================= + + // insert more paid invocation transactions (400 of each) + for (var i = 0; i < 400; i++) + { + TxList.Insert(0, MockGenerateInvocationTransaction(Fixed8.One, 50).Object); + } + + // insert more free invocation transactions (400 of each) + for (var i = 0; i < 400; i++) + { + TxList.Insert(0, MockGenerateInvocationTransaction(Fixed8.Zero, 50).Object); + } + + TxList.Count().Should().Be(1004); // 500 free + 500 paid + 4 claims + TxList.Where(tx => tx.NetworkFee == Fixed8.Zero).Count().Should().Be(400+100-18+4); // 500-18 fully free + 4 claims + + filteredTxList = uut.FilterForBlock(TxList); + filteredTxList.Count().Should().Be(499); // full block + + // will select 20 low priority (including Claims) + vx = filteredTxList.Where(tx => tx.IsLowPriority == true); + vx.Count().Should().Be(20); + + // will still select Claim Transactions + vx = filteredTxList.Where(tx => tx.Type == TransactionType.ClaimTransaction); + vx.Count().Should().Be(2); + } + + + [TestMethod] + public void FreeTxVerifySort_NoHighPriority() + { + List txList = new List(); + // three different sizes, but it doesn't matter + for (var size = 10; size <= 20; size += 5) + { + for (var netFeeSatoshi = 0; netFeeSatoshi <= 90000; netFeeSatoshi += 10000) + { + var testTx = MockGenerateInvocationTransaction(new Fixed8(netFeeSatoshi), size).Object; + testTx.IsLowPriority.Should().Be(true); // "LowPriorityThreshold": 0.001 + txList.Insert(0, testTx); + } + } + + txList.Count.Should().Be(30); + // transactions => size: [10, 15, 20] x price: [0 ... 90000, step by 10000] + //foreach(var tx in txList) + // Console.WriteLine($"TX fee: {tx.NetworkFee} size: {tx.Size} ratio: {tx.FeePerByte}"); + /* + TX fee: 0.0009 size: 20 ratio: 0.000045 + TX fee: 0.0008 size: 20 ratio: 0.00004 + TX fee: 0.0007 size: 20 ratio: 0.000035 + TX fee: 0.0006 size: 20 ratio: 0.00003 + TX fee: 0.0005 size: 20 ratio: 0.000025 + TX fee: 0.0004 size: 20 ratio: 0.00002 + TX fee: 0.0003 size: 20 ratio: 0.000015 + TX fee: 0.0002 size: 20 ratio: 0.00001 + TX fee: 0.0001 size: 20 ratio: 0.000005 + TX fee: 0 size: 20 ratio: 0 + TX fee: 0.0009 size: 15 ratio: 0.00006 + TX fee: 0.0008 size: 15 ratio: 0.00005333 + TX fee: 0.0007 size: 15 ratio: 0.00004666 + TX fee: 0.0006 size: 15 ratio: 0.00004 + TX fee: 0.0005 size: 15 ratio: 0.00003333 + TX fee: 0.0004 size: 15 ratio: 0.00002666 + TX fee: 0.0003 size: 15 ratio: 0.00002 + TX fee: 0.0002 size: 15 ratio: 0.00001333 + TX fee: 0.0001 size: 15 ratio: 0.00000666 + TX fee: 0 size: 15 ratio: 0 + TX fee: 0.0009 size: 10 ratio: 0.00009 + TX fee: 0.0008 size: 10 ratio: 0.00008 + TX fee: 0.0007 size: 10 ratio: 0.00007 + TX fee: 0.0006 size: 10 ratio: 0.00006 + TX fee: 0.0005 size: 10 ratio: 0.00005 + TX fee: 0.0004 size: 10 ratio: 0.00004 + TX fee: 0.0003 size: 10 ratio: 0.00003 + TX fee: 0.0002 size: 10 ratio: 0.00002 + TX fee: 0.0001 size: 10 ratio: 0.00001 + */ + + IEnumerable filteredTxList = uut.FilterForBlock(txList); + filteredTxList.Count().Should().Be(20); + + // will select top 20 + // part A: 18 transactions with ratio >= 0.000025 + // part B: 2 transactions with ratio = 0.00002 (but one with this ratio will be discarded, with fee 0.0002) + //foreach(var tx in filteredTxList) + // Console.WriteLine($"TX20 fee: {tx.NetworkFee} size: {tx.Size} ratio: {tx.NetworkFee / tx.Size}"); + /* + TX20 fee: 0.0009 size: 10 ratio: 0.00009 + TX20 fee: 0.0008 size: 10 ratio: 0.00008 + TX20 fee: 0.0007 size: 10 ratio: 0.00007 + TX20 fee: 0.0009 size: 15 ratio: 0.00006 + TX20 fee: 0.0006 size: 10 ratio: 0.00006 + TX20 fee: 0.0008 size: 15 ratio: 0.00005333 + TX20 fee: 0.0005 size: 10 ratio: 0.00005 + TX20 fee: 0.0007 size: 15 ratio: 0.00004666 + TX20 fee: 0.0009 size: 20 ratio: 0.000045 + TX20 fee: 0.0008 size: 20 ratio: 0.00004 + TX20 fee: 0.0006 size: 15 ratio: 0.00004 + TX20 fee: 0.0004 size: 10 ratio: 0.00004 + TX20 fee: 0.0007 size: 20 ratio: 0.000035 + TX20 fee: 0.0005 size: 15 ratio: 0.00003333 + TX20 fee: 0.0006 size: 20 ratio: 0.00003 + TX20 fee: 0.0003 size: 10 ratio: 0.00003 + TX20 fee: 0.0004 size: 15 ratio: 0.00002666 + TX20 fee: 0.0005 size: 20 ratio: 0.000025 + TX20 fee: 0.0004 size: 20 ratio: 0.00002 + TX20 fee: 0.0003 size: 15 ratio: 0.00002 + */ + + // part A + filteredTxList.Where(tx => (tx.NetworkFee / tx.Size) >= new Fixed8(2500)).Count().Should().Be(18); // 18 enter in part A + txList.Where(tx => (tx.NetworkFee / tx.Size) >= new Fixed8(2500)).Count().Should().Be(18); // they also exist in main list + txList.Where(tx => (tx.NetworkFee / tx.Size) < new Fixed8(2500)).Count().Should().Be(30 - 18); // 12 not selected transactions in part A + // part B + filteredTxList.Where(tx => (tx.NetworkFee / tx.Size) < new Fixed8(2500)).Count().Should().Be(2); // only two enter in part B + filteredTxList.Where(tx => (tx.NetworkFee / tx.Size) == new Fixed8(2000)).Count().Should().Be(2); // only two enter in part B with ratio 0.00002 + txList.Where(tx => (tx.NetworkFee / tx.Size) == new Fixed8(2000)).Count().Should().Be(3); // 3 in tie (ratio 0.00002) + txList.Where(tx => (tx.NetworkFee / tx.Size) == new Fixed8(2000) && (tx.NetworkFee > new Fixed8(20000))).Count().Should().Be(2); // only 2 survive (fee > 0.0002) + } + + + [TestMethod] + public void FreeTxVerifySortWithPriority() + { + List txList = new List(); + // three different sizes, but it doesn't matter + for (var size = 10; size <= 15; size += 5) + { + for (var netFeeSatoshi = 0; netFeeSatoshi <= 90000; netFeeSatoshi += 10000) + { + var testTx = MockGenerateInvocationTransaction(new Fixed8(netFeeSatoshi), size).Object; + testTx.IsLowPriority.Should().Be(true); // "LowPriorityThreshold": 0.001 + txList.Insert(0, testTx); + } + } + + txList.Insert(0, GetClaimTransaction(1)); + txList.Insert(0, GetClaimTransaction(10)); + txList.Insert(0, GetClaimTransaction(20)); + txList.Insert(0, GetClaimTransaction(30)); + + txList.Count.Should().Be(24); // 20 free + 4 claims + + IEnumerable filteredTxList = uut.FilterForBlock(txList); + filteredTxList.Count().Should().Be(20); + + filteredTxList.Where(tx => tx.Type == TransactionType.ClaimTransaction).Count().Should().Be(2); // 2 claims will be selected + } + + + [TestMethod] + public void TestMock_GenerateInvocationTransaction() + { + var txHighPriority = MockGenerateInvocationTransaction(Fixed8.One, 50); + // testing default values + Fixed8 txHighPriority_ratio = txHighPriority.Object.NetworkFee / txHighPriority.Object.Size; + txHighPriority_ratio.Should().Be(new Fixed8(2000000)); // 0.02 + txHighPriority.Object.IsLowPriority.Should().Be(false); + + var txLowPriority = MockGenerateInvocationTransaction(Fixed8.One / 10000, 50); // 0.00001 + // testing default values + Fixed8 txLowPriority_ratio = txLowPriority.Object.NetworkFee / txLowPriority.Object.Size; + txLowPriority_ratio.Should().Be(new Fixed8(200)); // 0.000002 -> 200 satoshi / Byte + txLowPriority.Object.IsLowPriority.Should().Be(true); + } + + // Generate Mock InvocationTransaction with different sizes and prices + public static Mock MockGenerateInvocationTransaction(Fixed8 networkFee, int size) + { + var mockTx = new Mock(TransactionType.InvocationTransaction); + mockTx.SetupGet(mr => mr.NetworkFee).Returns(networkFee); + mockTx.SetupGet(mr => mr.Size).Returns(size); + return mockTx; + } + + // Create ClaimTransaction with 'countRefs' CoinReferences + public static ClaimTransaction GetClaimTransaction(int countRefs) + { + CoinReference[] refs = new CoinReference[countRefs]; + for (var i = 0; i < countRefs; i++) + { + refs[i] = GetCoinReference(new UInt256(Crypto.Default.Hash256(new BigInteger(i).ToByteArray()))); + } + + return new ClaimTransaction + { + Claims = refs, + Attributes = new TransactionAttribute[0], + Inputs = new CoinReference[0], + Outputs = new TransactionOutput[0], + Witnesses = new Witness[0] + }; + } + + public static CoinReference GetCoinReference(UInt256 prevHash) + { + if (prevHash == null) prevHash = UInt256.Zero; + return new CoinReference + { + PrevHash = prevHash, + PrevIndex = 0 + }; + } } } diff --git a/SimplePolicy.UnitTests/protocol.json b/SimplePolicy.UnitTests/protocol.json new file mode 100644 index 000000000..e770c2648 --- /dev/null +++ b/SimplePolicy.UnitTests/protocol.json @@ -0,0 +1,30 @@ +{ + "ProtocolConfiguration": { + "Magic": 7630401, + "AddressVersion": 23, + "SecondsPerBlock": 15, + "LowPriorityThreshold": 0.001, + "StandbyValidators": [ + "03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c", + "02df48f60e8f3e01c48ff40b9b7f1310d7a8b2a193188befe1c2e3df740e895093", + "03b8d9d5771d8f513aa0869b9cc8d50986403b78c6da36890638c3d46a5adce04a", + "02ca0e27697b9c248f6f16e085fd0061e26f44da85b58ee835c110caa5ec3ba554", + "024c7b7fb6c310fccf1ba33b082519d82964ea93868d676662d4a59ad548df0e7d", + "02aaec38470f6aad0042c6e877cfd8087d2676b0f516fddd362801b9bd3936399e", + "02486fd15702c4490a26703112a5cc1d0923fd697a33406bd5a1c00e0013b09a70" + ], + "SeedList": [ + "seed1.neo.org:10333", + "seed2.neo.org:10333", + "seed3.neo.org:10333", + "seed4.neo.org:10333", + "seed5.neo.org:10333" + ], + "SystemFee": { + "EnrollmentTransaction": 1000, + "IssueTransaction": 500, + "PublishTransaction": 500, + "RegisterTransaction": 10000 + } + } +} diff --git a/SimplePolicy/Settings.cs b/SimplePolicy/Settings.cs index c6f8f6760..146047788 100644 --- a/SimplePolicy/Settings.cs +++ b/SimplePolicy/Settings.cs @@ -1,9 +1,9 @@ -using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Configuration; +using Neo.Network.P2P.Payloads; using Neo.Wallets; using System; using System.Collections.Generic; using System.Linq; -using System.Reflection; namespace Neo.Plugins { @@ -13,21 +13,18 @@ internal class Settings public int MaxFreeTransactionsPerBlock { get; } public int MaxFreeTransactionSize { get; } public Fixed8 FeePerExtraByte { get; } + public EnumSet HighPriorityTxType { get; } public BlockedAccounts BlockedAccounts { get; } - public static Settings Default { get; } + public static Settings Default { get; private set; } - static Settings() - { - Default = new Settings(Assembly.GetExecutingAssembly().GetConfiguration()); - } - - public Settings(IConfigurationSection section) + private Settings(IConfigurationSection section) { this.MaxTransactionsPerBlock = GetValueOrDefault(section.GetSection("MaxTransactionsPerBlock"), 500, p => int.Parse(p)); this.MaxFreeTransactionsPerBlock = GetValueOrDefault(section.GetSection("MaxFreeTransactionsPerBlock"), 20, p => int.Parse(p)); this.MaxFreeTransactionSize = GetValueOrDefault(section.GetSection("MaxFreeTransactionSize"), 1024, p => int.Parse(p)); this.FeePerExtraByte = GetValueOrDefault(section.GetSection("FeePerExtraByte"), Fixed8.FromDecimal(0.00001M), p => Fixed8.Parse(p)); + this.HighPriorityTxType = new EnumSet(section.GetSection("HighPriorityTxType"), TransactionType.ClaimTransaction); this.BlockedAccounts = new BlockedAccounts(section.GetSection("BlockedAccounts")); } @@ -36,6 +33,24 @@ public T GetValueOrDefault(IConfigurationSection section, T defaultValue, Fun if (section.Value == null) return defaultValue; return selector(section.Value); } + + public static void Load(IConfigurationSection section) + { + Default = new Settings(section); + } + } + + internal class EnumSet : HashSet + where T : Enum + { + public EnumSet(IConfigurationSection section, params T[] defaultValues) + { + if (section.Exists()) + foreach (IConfigurationSection child in section.GetChildren()) + Add((T)Enum.Parse(typeof(T), child.Value)); + else + UnionWith(defaultValues); + } } internal enum PolicyType : byte diff --git a/SimplePolicy/SimplePolicy.csproj b/SimplePolicy/SimplePolicy.csproj index 61c24d4b3..c29ff0ef9 100644 --- a/SimplePolicy/SimplePolicy.csproj +++ b/SimplePolicy/SimplePolicy.csproj @@ -1,9 +1,10 @@  - 2.9.2 + 2.9.3 netstandard2.0;net47 Neo.Plugins + latest @@ -14,7 +15,7 @@ - + diff --git a/SimplePolicy/SimplePolicy/config.json b/SimplePolicy/SimplePolicy/config.json index 85dd9cfbe..bb49ca3d2 100644 --- a/SimplePolicy/SimplePolicy/config.json +++ b/SimplePolicy/SimplePolicy/config.json @@ -4,9 +4,13 @@ "MaxFreeTransactionsPerBlock": 20, "MaxFreeTransactionSize": 1024, "FeePerExtraByte": 0.00001, + "HighPriorityTxType": + [ + "ClaimTransaction" + ], "BlockedAccounts": { "Type": "AllowAll", "List": [] } } -} +} \ No newline at end of file diff --git a/SimplePolicy/SimplePolicyPlugin.cs b/SimplePolicy/SimplePolicyPlugin.cs index 933c5ae86..c93032d07 100644 --- a/SimplePolicy/SimplePolicyPlugin.cs +++ b/SimplePolicy/SimplePolicyPlugin.cs @@ -15,6 +15,11 @@ public class SimplePolicyPlugin : Plugin, ILogPlugin, IPolicyPlugin { private static readonly string log_dictionary = Path.Combine(AppContext.BaseDirectory, "Logs"); + public override void Configure() + { + Settings.Load(GetConfiguration()); + } + public bool FilterForMemoryPool(Transaction tx) { if (!VerifySizeLimits(tx)) return false; @@ -42,7 +47,7 @@ public IEnumerable FilterForBlock(IEnumerable transact private static IEnumerable FilterForBlock_Policy1(IEnumerable transactions) { int count = 0, count_free = 0; - foreach (Transaction tx in transactions.OrderByDescending(p => p.NetworkFee / p.Size).ThenByDescending(p => p.NetworkFee)) + foreach (Transaction tx in transactions.OrderByDescending(p => p.NetworkFee / p.Size).ThenByDescending(p => p.NetworkFee).ThenByDescending(p => InHighPriorityList(p))) { if (count++ >= Settings.Default.MaxTransactionsPerBlock - 1) break; if (!tx.IsLowPriority || count_free++ < Settings.Default.MaxFreeTransactionsPerBlock) @@ -58,6 +63,7 @@ private static IEnumerable FilterForBlock_Policy2(IEnumerable p.IsLowPriority) .OrderByDescending(p => p.NetworkFee / p.Size) .ThenByDescending(p => p.NetworkFee) + .ThenByDescending(p => InHighPriorityList(p)) .Take(Settings.Default.MaxFreeTransactionsPerBlock) .ToArray(); @@ -87,10 +93,12 @@ void ILogPlugin.Log(string source, LogLevel level, string message) private bool VerifySizeLimits(Transaction tx) { + if (InHighPriorityList(tx)) return true; + // Not Allow free TX bigger than MaxFreeTransactionSize if (tx.IsLowPriority && tx.Size > Settings.Default.MaxFreeTransactionSize) return false; - // Require proportional fee for TX bigger than MaxFreeTransactionSize + // Require proportional fee for TX bigger than MaxFreeTransactionSize if (tx.Size > Settings.Default.MaxFreeTransactionSize) { Fixed8 fee = Settings.Default.FeePerExtraByte * (tx.Size - Settings.Default.MaxFreeTransactionSize); @@ -99,5 +107,8 @@ private bool VerifySizeLimits(Transaction tx) } return true; } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool InHighPriorityList(Transaction tx) => Settings.Default.HighPriorityTxType.Contains(tx.Type); } } diff --git a/StatesDumper/Settings.cs b/StatesDumper/Settings.cs index e747af133..37622df2f 100644 --- a/StatesDumper/Settings.cs +++ b/StatesDumper/Settings.cs @@ -1,6 +1,5 @@ using Microsoft.Extensions.Configuration; using System; -using System.Reflection; namespace Neo.Plugins { @@ -23,14 +22,9 @@ internal class Settings /// public PersistActions PersistAction { get; } - public static Settings Default { get; } + public static Settings Default { get; private set; } - static Settings() - { - Default = new Settings(Assembly.GetExecutingAssembly().GetConfiguration()); - } - - public Settings(IConfigurationSection section) + private Settings(IConfigurationSection section) { /// Geting settings for storage changes state dumper this.BlockCacheSize = GetValueOrDefault(section.GetSection("BlockCacheSize"), 1000u, p => uint.Parse(p)); @@ -44,5 +38,10 @@ public T GetValueOrDefault(IConfigurationSection section, T defaultValue, Fun if (section.Value == null) return defaultValue; return selector(section.Value); } + + public static void Load(IConfigurationSection section) + { + Default = new Settings(section); + } } } diff --git a/StatesDumper/StatesDumper.cs b/StatesDumper/StatesDumper.cs index 4add46abf..4822ed73d 100644 --- a/StatesDumper/StatesDumper.cs +++ b/StatesDumper/StatesDumper.cs @@ -14,6 +14,11 @@ public class StatesDumper : Plugin, IPersistencePlugin { private readonly JArray bs_cache = new JArray(); + public override void Configure() + { + Settings.Load(GetConfiguration()); + } + private static void Dump(IEnumerable> states) where TKey : ISerializable where TValue : ISerializable diff --git a/StatesDumper/StatesDumper.csproj b/StatesDumper/StatesDumper.csproj index 799391d52..fd87ea39a 100644 --- a/StatesDumper/StatesDumper.csproj +++ b/StatesDumper/StatesDumper.csproj @@ -1,7 +1,7 @@  - 2.9.2 + 2.9.3 netstandard2.0;net47 Neo.Plugins @@ -14,7 +14,7 @@ - + From 64826c08ae5c3b7017b2772811e65dfea67bbcf3 Mon Sep 17 00:00:00 2001 From: erikzhang Date: Mon, 7 Jan 2019 19:07:21 +0800 Subject: [PATCH 028/183] v2.9.4 --- ApplicationLogs/ApplicationLogs.csproj | 4 +- ImportBlocks/ImportBlocks.cs | 91 +++++++++++++------------- ImportBlocks/ImportBlocks.csproj | 4 +- RpcSecurity/RpcSecurity.csproj | 4 +- SimplePolicy/SimplePolicy.csproj | 4 +- StatesDumper/StatesDumper.cs | 2 +- StatesDumper/StatesDumper.csproj | 4 +- 7 files changed, 58 insertions(+), 55 deletions(-) diff --git a/ApplicationLogs/ApplicationLogs.csproj b/ApplicationLogs/ApplicationLogs.csproj index 15ceaf9e2..4c5a41dea 100644 --- a/ApplicationLogs/ApplicationLogs.csproj +++ b/ApplicationLogs/ApplicationLogs.csproj @@ -1,7 +1,7 @@  - 2.9.3 + 2.9.4 netstandard2.0;net47 Neo.Plugins @@ -14,7 +14,7 @@ - + diff --git a/ImportBlocks/ImportBlocks.cs b/ImportBlocks/ImportBlocks.cs index 786986ecd..31c38b606 100644 --- a/ImportBlocks/ImportBlocks.cs +++ b/ImportBlocks/ImportBlocks.cs @@ -9,7 +9,6 @@ using System.IO.Compression; using System.Linq; using System.Text.RegularExpressions; -using System.Threading.Tasks; namespace Neo.Plugins { @@ -17,49 +16,7 @@ public class ImportBlocks : Plugin { public ImportBlocks() { - Task.Run(() => - { - const string path_acc = "chain.acc"; - if (File.Exists(path_acc)) - using (FileStream fs = new FileStream(path_acc, FileMode.Open, FileAccess.Read, FileShare.Read)) - System.Blockchain.Ask(new Blockchain.Import - { - Blocks = GetBlocks(fs) - }).Wait(); - const string path_acc_zip = path_acc + ".zip"; - if (File.Exists(path_acc_zip)) - using (FileStream fs = new FileStream(path_acc_zip, FileMode.Open, FileAccess.Read, FileShare.Read)) - using (ZipArchive zip = new ZipArchive(fs, ZipArchiveMode.Read)) - using (Stream zs = zip.GetEntry(path_acc).Open()) - System.Blockchain.Ask(new Blockchain.Import - { - Blocks = GetBlocks(zs) - }).Wait(); - var paths = Directory.EnumerateFiles(".", "chain.*.acc", SearchOption.TopDirectoryOnly).Concat(Directory.EnumerateFiles(".", "chain.*.acc.zip", SearchOption.TopDirectoryOnly)).Select(p => new - { - FileName = Path.GetFileName(p), - Start = uint.Parse(Regex.Match(p, @"\d+").Value), - IsCompressed = p.EndsWith(".zip") - }).OrderBy(p => p.Start); - foreach (var path in paths) - { - if (path.Start > Blockchain.Singleton.Height + 1) break; - if (path.IsCompressed) - using (FileStream fs = new FileStream(path.FileName, FileMode.Open, FileAccess.Read, FileShare.Read)) - using (ZipArchive zip = new ZipArchive(fs, ZipArchiveMode.Read)) - using (Stream zs = zip.GetEntry(Path.GetFileNameWithoutExtension(path.FileName)).Open()) - System.Blockchain.Ask(new Blockchain.Import - { - Blocks = GetBlocks(zs, true) - }).Wait(); - else - using (FileStream fs = new FileStream(path.FileName, FileMode.Open, FileAccess.Read, FileShare.Read)) - System.Blockchain.Ask(new Blockchain.Import - { - Blocks = GetBlocks(fs, true) - }).Wait(); - } - }); + OnImport(); } private static bool CheckMaxOnImportHeight(uint currentImportBlockHeight) @@ -181,6 +138,52 @@ private bool OnHelp(string[] args) return true; } + private async void OnImport() + { + SuspendNodeStartup(); + const string path_acc = "chain.acc"; + if (File.Exists(path_acc)) + using (FileStream fs = new FileStream(path_acc, FileMode.Open, FileAccess.Read, FileShare.Read)) + await System.Blockchain.Ask(new Blockchain.Import + { + Blocks = GetBlocks(fs) + }); + const string path_acc_zip = path_acc + ".zip"; + if (File.Exists(path_acc_zip)) + using (FileStream fs = new FileStream(path_acc_zip, FileMode.Open, FileAccess.Read, FileShare.Read)) + using (ZipArchive zip = new ZipArchive(fs, ZipArchiveMode.Read)) + using (Stream zs = zip.GetEntry(path_acc).Open()) + await System.Blockchain.Ask(new Blockchain.Import + { + Blocks = GetBlocks(zs) + }); + var paths = Directory.EnumerateFiles(".", "chain.*.acc", SearchOption.TopDirectoryOnly).Concat(Directory.EnumerateFiles(".", "chain.*.acc.zip", SearchOption.TopDirectoryOnly)).Select(p => new + { + FileName = Path.GetFileName(p), + Start = uint.Parse(Regex.Match(p, @"\d+").Value), + IsCompressed = p.EndsWith(".zip") + }).OrderBy(p => p.Start); + foreach (var path in paths) + { + if (path.Start > Blockchain.Singleton.Height + 1) break; + if (path.IsCompressed) + using (FileStream fs = new FileStream(path.FileName, FileMode.Open, FileAccess.Read, FileShare.Read)) + using (ZipArchive zip = new ZipArchive(fs, ZipArchiveMode.Read)) + using (Stream zs = zip.GetEntry(Path.GetFileNameWithoutExtension(path.FileName)).Open()) + await System.Blockchain.Ask(new Blockchain.Import + { + Blocks = GetBlocks(zs, true) + }); + else + using (FileStream fs = new FileStream(path.FileName, FileMode.Open, FileAccess.Read, FileShare.Read)) + await System.Blockchain.Ask(new Blockchain.Import + { + Blocks = GetBlocks(fs, true) + }); + } + ResumeNodeStartup(); + } + protected override bool OnMessage(object message) { if (!(message is string[] args)) return false; diff --git a/ImportBlocks/ImportBlocks.csproj b/ImportBlocks/ImportBlocks.csproj index fffab1628..b053a32dd 100644 --- a/ImportBlocks/ImportBlocks.csproj +++ b/ImportBlocks/ImportBlocks.csproj @@ -1,7 +1,7 @@  - 2.9.3 + 2.9.4 netstandard2.0;net47 Neo.Plugins @@ -14,7 +14,7 @@ - + diff --git a/RpcSecurity/RpcSecurity.csproj b/RpcSecurity/RpcSecurity.csproj index 7c64c9140..1b783ee4d 100644 --- a/RpcSecurity/RpcSecurity.csproj +++ b/RpcSecurity/RpcSecurity.csproj @@ -1,7 +1,7 @@  - 2.9.3 + 2.9.4 netstandard2.0;net47 Neo.Plugins @@ -14,7 +14,7 @@ - + diff --git a/SimplePolicy/SimplePolicy.csproj b/SimplePolicy/SimplePolicy.csproj index c29ff0ef9..39981afff 100644 --- a/SimplePolicy/SimplePolicy.csproj +++ b/SimplePolicy/SimplePolicy.csproj @@ -1,7 +1,7 @@  - 2.9.3 + 2.9.4 netstandard2.0;net47 Neo.Plugins latest @@ -15,7 +15,7 @@ - + diff --git a/StatesDumper/StatesDumper.cs b/StatesDumper/StatesDumper.cs index 4822ed73d..1600a4543 100644 --- a/StatesDumper/StatesDumper.cs +++ b/StatesDumper/StatesDumper.cs @@ -73,7 +73,7 @@ private bool OnHelp(string[] args) return true; } - public void OnPersist(Snapshot snapshot) + public void OnPersist(Snapshot snapshot, IReadOnlyList applicationExecutedList) { if (Settings.Default.PersistAction.HasFlag(PersistActions.StorageChanges)) OnPersistStorage(snapshot); diff --git a/StatesDumper/StatesDumper.csproj b/StatesDumper/StatesDumper.csproj index fd87ea39a..12337b3ee 100644 --- a/StatesDumper/StatesDumper.csproj +++ b/StatesDumper/StatesDumper.csproj @@ -1,7 +1,7 @@  - 2.9.3 + 2.9.4 netstandard2.0;net47 Neo.Plugins @@ -14,7 +14,7 @@ - + From a7fd6590cea4530d2e2082aec0a1a6ea5bdd6451 Mon Sep 17 00:00:00 2001 From: jsolman Date: Sun, 13 Jan 2019 00:21:58 -0800 Subject: [PATCH 029/183] Expose the max TX per block and max low priority TX per block. (#37) --- SimplePolicy/SimplePolicyPlugin.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/SimplePolicy/SimplePolicyPlugin.cs b/SimplePolicy/SimplePolicyPlugin.cs index c93032d07..432f82191 100644 --- a/SimplePolicy/SimplePolicyPlugin.cs +++ b/SimplePolicy/SimplePolicyPlugin.cs @@ -44,6 +44,9 @@ public IEnumerable FilterForBlock(IEnumerable transact return FilterForBlock_Policy2(transactions); } + public int MaxTxPerBlock => Settings.Default.MaxTransactionsPerBlock; + public int MaxLowPriorityTxPerBlock => Settings.Default.MaxFreeTransactionsPerBlock; + private static IEnumerable FilterForBlock_Policy1(IEnumerable transactions) { int count = 0, count_free = 0; From 9fb033be7aa221fa9eb79504ba24dc38adb69441 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vitor=20Naz=C3=A1rio=20Coelho?= Date: Sat, 19 Jan 2019 09:16:10 -0200 Subject: [PATCH 030/183] Ensure PoW correct order for TXs tiebreakers (#38) * Ensure PoW correct order for TXs tiebreakers * ThenByAscending for Hash --- SimplePolicy/SimplePolicyPlugin.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/SimplePolicy/SimplePolicyPlugin.cs b/SimplePolicy/SimplePolicyPlugin.cs index 432f82191..021ca364c 100644 --- a/SimplePolicy/SimplePolicyPlugin.cs +++ b/SimplePolicy/SimplePolicyPlugin.cs @@ -67,12 +67,14 @@ private static IEnumerable FilterForBlock_Policy2(IEnumerable p.NetworkFee / p.Size) .ThenByDescending(p => p.NetworkFee) .ThenByDescending(p => InHighPriorityList(p)) + .ThenByAscending(p => p.Transaction.Hash) .Take(Settings.Default.MaxFreeTransactionsPerBlock) .ToArray(); Transaction[] non_free = tx_list.Where(p => !p.IsLowPriority) .OrderByDescending(p => p.NetworkFee / p.Size) .ThenByDescending(p => p.NetworkFee) + .ThenByAscending(p => p.Transaction.Hash) .Take(Settings.Default.MaxTransactionsPerBlock - free.Length - 1) .ToArray(); From d35297618006bc0dfdae3bacab22e98df682d84b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vitor=20Naz=C3=A1rio=20Coelho?= Date: Sun, 20 Jan 2019 11:02:14 -0200 Subject: [PATCH 031/183] Expose HighPriorityTxType (#39) * Expose HighPriorityTxType * HigherLowPriorityTxTypes * InHigherLowPriorityList * Modify missing InHigherLowPriorityList * Missing InHigherLowPriorityList * Use InHigherLowPriorityList and change to public * Clean * Clean II --- SimplePolicy/SimplePolicyPlugin.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/SimplePolicy/SimplePolicyPlugin.cs b/SimplePolicy/SimplePolicyPlugin.cs index 021ca364c..7aec73d53 100644 --- a/SimplePolicy/SimplePolicyPlugin.cs +++ b/SimplePolicy/SimplePolicyPlugin.cs @@ -50,7 +50,7 @@ public IEnumerable FilterForBlock(IEnumerable transact private static IEnumerable FilterForBlock_Policy1(IEnumerable transactions) { int count = 0, count_free = 0; - foreach (Transaction tx in transactions.OrderByDescending(p => p.NetworkFee / p.Size).ThenByDescending(p => p.NetworkFee).ThenByDescending(p => InHighPriorityList(p))) + foreach (Transaction tx in transactions.OrderByDescending(p => p.NetworkFee / p.Size).ThenByDescending(p => p.NetworkFee).ThenByDescending(p => InHigherLowPriorityList(p))) { if (count++ >= Settings.Default.MaxTransactionsPerBlock - 1) break; if (!tx.IsLowPriority || count_free++ < Settings.Default.MaxFreeTransactionsPerBlock) @@ -66,7 +66,7 @@ private static IEnumerable FilterForBlock_Policy2(IEnumerable p.IsLowPriority) .OrderByDescending(p => p.NetworkFee / p.Size) .ThenByDescending(p => p.NetworkFee) - .ThenByDescending(p => InHighPriorityList(p)) + .ThenByDescending(p => InHigherLowPriorityList(p)) .ThenByAscending(p => p.Transaction.Hash) .Take(Settings.Default.MaxFreeTransactionsPerBlock) .ToArray(); @@ -98,7 +98,7 @@ void ILogPlugin.Log(string source, LogLevel level, string message) private bool VerifySizeLimits(Transaction tx) { - if (InHighPriorityList(tx)) return true; + if (InHigherLowPriorityList(tx)) return true; // Not Allow free TX bigger than MaxFreeTransactionSize if (tx.IsLowPriority && tx.Size > Settings.Default.MaxFreeTransactionSize) return false; @@ -114,6 +114,6 @@ private bool VerifySizeLimits(Transaction tx) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static bool InHighPriorityList(Transaction tx) => Settings.Default.HighPriorityTxType.Contains(tx.Type); + public static bool InHigherLowPriorityList(Transaction tx) => Settings.Default.HighPriorityTxType.Contains(tx.Type); } } From bab9d09ca3572a0cc3ebfdf478dd1f417a0cfb98 Mon Sep 17 00:00:00 2001 From: jsolman Date: Sun, 27 Jan 2019 12:20:08 -0800 Subject: [PATCH 032/183] Commit as the final step of persistence in StatesDumper (#40) * Support commit as the final step of persistence. * Update for new method . * OnCommitStorage --- StatesDumper/StatesDumper.cs | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/StatesDumper/StatesDumper.cs b/StatesDumper/StatesDumper.cs index 1600a4543..5cc95fa3b 100644 --- a/StatesDumper/StatesDumper.cs +++ b/StatesDumper/StatesDumper.cs @@ -84,10 +84,6 @@ private void OnPersistStorage(Snapshot snapshot) uint blockIndex = snapshot.Height; if (blockIndex >= Settings.Default.HeightToBegin) { - string dirPath = "./Storage"; - Directory.CreateDirectory(dirPath); - string path = $"{HandlePaths(dirPath, blockIndex)}/dump-block-{blockIndex.ToString()}.json"; - JArray array = new JArray(); foreach (DataCache.Trackable trackable in snapshot.Storages.GetChangeSet()) @@ -121,14 +117,37 @@ private void OnPersistStorage(Snapshot snapshot) bs_item["size"] = array.Count; bs_item["storage"] = array; bs_cache.Add(bs_item); + } + } + + public void OnCommit(Snapshot snapshot) + { + if (Settings.Default.PersistAction.HasFlag(PersistActions.StorageChanges)) + OnCommitStorage(snapshot); + } + public void OnCommitStorage(Snapshot snapshot) + { + uint blockIndex = snapshot.Height; + if (bs_cache.Count > 0) + { if ((blockIndex % Settings.Default.BlockCacheSize == 0) || (blockIndex > Settings.Default.HeightToStartRealTimeSyncing)) { + string dirPath = "./Storage"; + Directory.CreateDirectory(dirPath); + string path = $"{HandlePaths(dirPath, blockIndex)}/dump-block-{blockIndex.ToString()}.json"; + File.WriteAllText(path, bs_cache.ToString()); bs_cache.Clear(); } } } + + public bool ShouldThrowExceptionFromCommit(Exception ex) + { + Console.WriteLine($"Error writing States with StatesDumper.{Environment.NewLine}{ex}"); + return true; + } private static string HandlePaths(string dirPath, uint blockIndex) { From 69782e99e134f141e20b3b31c986cd30938f26b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vitor=20Naz=C3=A1rio=20Coelho?= Date: Sun, 27 Jan 2019 19:25:01 -0200 Subject: [PATCH 033/183] Adding tests and fixing typo (#41) * Adding tests and fixing typo * adding random attribute to claim * unit tests for hash compare --- SimplePolicy.UnitTests/UT_SimplePolicy.cs | 77 +++++++++++++++++++---- SimplePolicy/SimplePolicyPlugin.cs | 4 +- 2 files changed, 66 insertions(+), 15 deletions(-) diff --git a/SimplePolicy.UnitTests/UT_SimplePolicy.cs b/SimplePolicy.UnitTests/UT_SimplePolicy.cs index 550b5825b..f22d6aff9 100644 --- a/SimplePolicy.UnitTests/UT_SimplePolicy.cs +++ b/SimplePolicy.UnitTests/UT_SimplePolicy.cs @@ -3,6 +3,7 @@ using Neo.Plugins; using Neo.Network.P2P.Payloads; using Neo; +using Neo.Persistence; using Settings = Neo.Plugins.Settings; using System.Collections.Generic; using Neo.Cryptography; @@ -17,6 +18,8 @@ namespace SimplePolicy.UnitTests [TestClass] public class UT_SimplePolicy { + private static Random _random = new Random(11121990); + SimplePolicyPlugin uut; [TestInitialize] @@ -39,25 +42,36 @@ public void TestFilterForBlock_ClaimHasPriority() // Should contain "ClaimTransaction" in "HighPriorityTxType" Settings.Default.HighPriorityTxType.Contains(TransactionType.ClaimTransaction).Should().Be(true); - ClaimTransaction claimTxZero = GetClaimTransaction(0); - claimTxZero.Size.Should().Be(7); // 7 - ClaimTransaction claimTxOne = GetClaimTransaction(1); - claimTxOne.Size.Should().Be(41); // 34 + 7 - ClaimTransaction claimTxTwo = GetClaimTransaction(2); - claimTxTwo.Size.Should().Be(75); // 2*34 + 7 + ClaimTransaction claimTxZero1 = GetClaimTransaction(0); + claimTxZero1.Size.Should().Be(7 + 21); // 7 + 21 (random script) + claimTxZero1.Hash.ToString().Should().Be("0x60037520be0fd903703c2b67973296f22cac8932db07a2723addf79478aea75f"); + ClaimTransaction claimTxZero2 = GetClaimTransaction(0); + claimTxZero2.Size.Should().Be(7 + 21); // 7 + 21 (random script) + claimTxZero2.Hash.ToString().Should().Be("0xb29426673b3ef5c226bd35d53c2cb2242e09c06f0efe9c0d5be2034f41cb85ba"); + ClaimTransaction claimTxZero3 = GetClaimTransaction(0); + claimTxZero3.Size.Should().Be(7 + 21); // 7 + 21 (random script) + claimTxZero3.Hash.ToString().Should().Be("0x01027faead9a0538048db7ac5657172f6e2240bff3f7d902e490bb1bd75c2df7"); + + //ClaimTransaction claimTxTwo = GetClaimTransaction(2); + //claimTxTwo.Size.Should().Be(75 + 21); // 2*34 + 7 + 21 ClaimTransaction claimTx30 = GetClaimTransaction(30); - claimTx30.Size.Should().Be(1027); // 30*34 + 7 + claimTx30.Size.Should().Be(1027 + 21); // 30*34 + 7 + 21 claimTx30.NetworkFee.Should().Be(Fixed8.Zero); claimTx30.IsLowPriority.Should().Be(true); // by default is Low Priority, but plugin makes it High Priority //uut.IsLowPriority -> cannot inspect because it's private... no problem! List TxList = new List(); - TxList.Insert(0, claimTxZero); - TxList.Insert(0, claimTxOne); - TxList.Insert(0, claimTxTwo); + TxList.Insert(0, claimTxZero1); + TxList.Insert(0, claimTxZero2); + TxList.Insert(0, claimTxZero3); TxList.Insert(0, claimTx30); + //Console.WriteLine("Tx List Claim"); + //foreach(var tx in TxList) + // Console.WriteLine($"Claim TX fee: {tx.NetworkFee} size: {tx.Size} ratio: {tx.FeePerByte} hash: {tx.Hash}" ); + + // ======================== BEGIN TESTS ============================ // insert 100 paid invocation transactions @@ -118,6 +132,22 @@ public void TestFilterForBlock_ClaimHasPriority() // will still select Claim Transactions vx = filteredTxList.Where(tx => tx.Type == TransactionType.ClaimTransaction); vx.Count().Should().Be(2); + + // there are 3 tied Claim tx, will solve it based on smaller hash (0x01, 0x60) => 0xb2 is excluded + // 0x01027faead9a0538048db7ac5657172f6e2240bff3f7d902e490bb1bd75c2df7 + // 0x60037520be0fd903703c2b67973296f22cac8932db07a2723addf79478aea75f + // 0xb29426673b3ef5c226bd35d53c2cb2242e09c06f0efe9c0d5be2034f41cb85ba + vx = filteredTxList.Where(tx => tx.Hash.ToString() == "0x01027faead9a0538048db7ac5657172f6e2240bff3f7d902e490bb1bd75c2df7"); + vx.Count().Should().Be(1); + vx = filteredTxList.Where(tx => tx.Hash.ToString() == "0x60037520be0fd903703c2b67973296f22cac8932db07a2723addf79478aea75f"); + vx.Count().Should().Be(1); + vx = filteredTxList.Where(tx => tx.Hash.ToString() == "0xb29426673b3ef5c226bd35d53c2cb2242e09c06f0efe9c0d5be2034f41cb85ba"); + vx.Count().Should().Be(0); + + //Console.WriteLine("filtered"); + //foreach(var tx in filteredTxList) + // Console.WriteLine($"TX fee: {tx.NetworkFee} size: {tx.Size} ratio: {tx.FeePerByte} hash: {tx.Hash}" ); + } @@ -261,14 +291,30 @@ public void TestMock_GenerateInvocationTransaction() } // Generate Mock InvocationTransaction with different sizes and prices - public static Mock MockGenerateInvocationTransaction(Fixed8 networkFee, int size) + public static Mock MockGenerateInvocationTransaction(Fixed8 networkFee, int size) { - var mockTx = new Mock(TransactionType.InvocationTransaction); + var mockTx = new Mock(); mockTx.SetupGet(mr => mr.NetworkFee).Returns(networkFee); mockTx.SetupGet(mr => mr.Size).Returns(size); + + //============================== + //=== Generating random Hash === + mockTx.CallBase = true; + mockTx.Setup(p => p.Verify(It.IsAny(), It.IsAny>())).Returns(true); + var tx = mockTx.Object; + var randomBytes = new byte[16]; + _random.NextBytes(randomBytes); + tx.Script = randomBytes; + tx.Attributes = new TransactionAttribute[0]; + tx.Inputs = new CoinReference[0]; + tx.Outputs = new TransactionOutput[0]; + tx.Witnesses = new Witness[0]; + //============================== + return mockTx; } + // Create ClaimTransaction with 'countRefs' CoinReferences public static ClaimTransaction GetClaimTransaction(int countRefs) { @@ -278,10 +324,15 @@ public static ClaimTransaction GetClaimTransaction(int countRefs) refs[i] = GetCoinReference(new UInt256(Crypto.Default.Hash256(new BigInteger(i).ToByteArray()))); } + //============================== + //=== Generating random Hash === + var randomBytes = new byte[20]; + _random.NextBytes(randomBytes); + //============================== return new ClaimTransaction { Claims = refs, - Attributes = new TransactionAttribute[0], + Attributes = new TransactionAttribute[]{new TransactionAttribute{Usage = TransactionAttributeUsage.Script, Data = randomBytes} }, Inputs = new CoinReference[0], Outputs = new TransactionOutput[0], Witnesses = new Witness[0] diff --git a/SimplePolicy/SimplePolicyPlugin.cs b/SimplePolicy/SimplePolicyPlugin.cs index 7aec73d53..f6cfc487a 100644 --- a/SimplePolicy/SimplePolicyPlugin.cs +++ b/SimplePolicy/SimplePolicyPlugin.cs @@ -67,14 +67,14 @@ private static IEnumerable FilterForBlock_Policy2(IEnumerable p.NetworkFee / p.Size) .ThenByDescending(p => p.NetworkFee) .ThenByDescending(p => InHigherLowPriorityList(p)) - .ThenByAscending(p => p.Transaction.Hash) + .ThenBy(p => p.Hash) .Take(Settings.Default.MaxFreeTransactionsPerBlock) .ToArray(); Transaction[] non_free = tx_list.Where(p => !p.IsLowPriority) .OrderByDescending(p => p.NetworkFee / p.Size) .ThenByDescending(p => p.NetworkFee) - .ThenByAscending(p => p.Transaction.Hash) + .ThenBy(p => p.Hash) .Take(Settings.Default.MaxTransactionsPerBlock - free.Length - 1) .ToArray(); From e41d3441d43d9813bf6fa2a401bcbb9fb9b5267c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vitor=20Naz=C3=A1rio=20Coelho?= Date: Mon, 28 Jan 2019 06:30:26 -0200 Subject: [PATCH 034/183] Creating Travis CI for neo-plugins (#42) --- .travis.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 000000000..b244dbc7f --- /dev/null +++ b/.travis.yml @@ -0,0 +1,19 @@ +language: csharp + +os: + - linux + - osx + +dist: trusty +osx_image: xcode9.1 + +mono: none +dotnet: 2.1.300 + +before_install: + - cd SimplePolicy.UnitTests + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then ulimit -n 2048; fi + +script: + - dotnet restore + - dotnet test From 363b279bac458921a6b758d886cc940cc81d6f68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vitor=20Naz=C3=A1rio=20Coelho?= Date: Wed, 6 Mar 2019 15:28:40 -0300 Subject: [PATCH 035/183] Including PreProcess and PostProcess functions (#46) * Including PreProcess and PostProcess functions * Adding pre-post to RpcSecurity --- ApplicationLogs/LogReader.cs | 8 ++++++++ RpcSecurity/RpcSecurity.cs | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/ApplicationLogs/LogReader.cs b/ApplicationLogs/LogReader.cs index 12968441c..93c5e47b5 100644 --- a/ApplicationLogs/LogReader.cs +++ b/ApplicationLogs/LogReader.cs @@ -23,6 +23,10 @@ public override void Configure() Settings.Load(GetConfiguration()); } + void PreProcess(HttpContext context, string method, JArray _params) + { + } + public JObject OnProcess(HttpContext context, string method, JArray _params) { if (method != "getapplicationlog") return null; @@ -31,5 +35,9 @@ public JObject OnProcess(HttpContext context, string method, JArray _params) throw new RpcException(-100, "Unknown transaction"); return JObject.Parse(value.ToString()); } + + void PostProcess(HttpContext context, string method, JArray _params, JObject result) + { + } } } diff --git a/RpcSecurity/RpcSecurity.cs b/RpcSecurity/RpcSecurity.cs index dec271dc2..68949c412 100644 --- a/RpcSecurity/RpcSecurity.cs +++ b/RpcSecurity/RpcSecurity.cs @@ -14,6 +14,10 @@ public override void Configure() Settings.Load(GetConfiguration()); } + void PreProcess(HttpContext context, string method, JArray _params) + { + } + public JObject OnProcess(HttpContext context, string method, JArray _params) { if (!CheckAuth(context) || Settings.Default.DisabledMethods.Contains(method)) @@ -21,6 +25,10 @@ public JObject OnProcess(HttpContext context, string method, JArray _params) return null; } + void PostProcess(HttpContext context, string method, JArray _params, JObject result) + { + } + private bool CheckAuth(HttpContext context) { if (string.IsNullOrEmpty(Settings.Default.RpcUser)) From 937a44378f41d65d57f314302c3d29d80fb4510f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vitor=20Naz=C3=A1rio=20Coelho?= Date: Wed, 6 Mar 2019 16:02:27 -0300 Subject: [PATCH 036/183] Fix missing public declaration (#48) --- ApplicationLogs/LogReader.cs | 4 ++-- RpcSecurity/RpcSecurity.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ApplicationLogs/LogReader.cs b/ApplicationLogs/LogReader.cs index 93c5e47b5..ad1a8c3ae 100644 --- a/ApplicationLogs/LogReader.cs +++ b/ApplicationLogs/LogReader.cs @@ -23,7 +23,7 @@ public override void Configure() Settings.Load(GetConfiguration()); } - void PreProcess(HttpContext context, string method, JArray _params) + public void PreProcess(HttpContext context, string method, JArray _params) { } @@ -36,7 +36,7 @@ public JObject OnProcess(HttpContext context, string method, JArray _params) return JObject.Parse(value.ToString()); } - void PostProcess(HttpContext context, string method, JArray _params, JObject result) + public void PostProcess(HttpContext context, string method, JArray _params, JObject result) { } } diff --git a/RpcSecurity/RpcSecurity.cs b/RpcSecurity/RpcSecurity.cs index 68949c412..84873f774 100644 --- a/RpcSecurity/RpcSecurity.cs +++ b/RpcSecurity/RpcSecurity.cs @@ -14,7 +14,7 @@ public override void Configure() Settings.Load(GetConfiguration()); } - void PreProcess(HttpContext context, string method, JArray _params) + public void PreProcess(HttpContext context, string method, JArray _params) { } @@ -25,7 +25,7 @@ public JObject OnProcess(HttpContext context, string method, JArray _params) return null; } - void PostProcess(HttpContext context, string method, JArray _params, JObject result) + public void PostProcess(HttpContext context, string method, JArray _params, JObject result) { } From 56ed6a479e076586bcb713afea4e2266e7807d97 Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Thu, 7 Mar 2019 16:45:05 +0800 Subject: [PATCH 037/183] Add RpcWallet (#44) * Add RpcWallet * Add `importprivkey` * Add `from` parameter to `sendmany` * Add `getunclaimedgas` * Add `claimgas` * Add reference: Neo 2.10.0 * Fix `importprivkey` --- RpcWallet/RpcWallet.cs | 365 +++++++++++++++++++++++++++++++++++++ RpcWallet/RpcWallet.csproj | 13 ++ neo-plugins.sln | 6 + 3 files changed, 384 insertions(+) create mode 100644 RpcWallet/RpcWallet.cs create mode 100644 RpcWallet/RpcWallet.csproj diff --git a/RpcWallet/RpcWallet.cs b/RpcWallet/RpcWallet.cs new file mode 100644 index 000000000..6c33f92b1 --- /dev/null +++ b/RpcWallet/RpcWallet.cs @@ -0,0 +1,365 @@ +using Akka.Actor; +using Microsoft.AspNetCore.Http; +using Neo.IO; +using Neo.IO.Json; +using Neo.Ledger; +using Neo.Network.P2P; +using Neo.Network.P2P.Payloads; +using Neo.Network.RPC; +using Neo.Persistence; +using Neo.SmartContract; +using Neo.Wallets; +using Neo.Wallets.NEP6; +using System.Collections.Generic; +using System.Linq; + +namespace Neo.Plugins +{ + public class RpcWallet : Plugin, IRpcPlugin + { + private Wallet Wallet => System.RpcServer.Wallet; + + public override void Configure() + { + } + + public void PreProcess(HttpContext context, string method, JArray _params) + { + } + + public JObject OnProcess(HttpContext context, string method, JArray _params) + { + switch (method) + { + case "claimgas": + { + UInt160 to = _params.Count >= 1 ? _params[0].AsString().ToScriptHash() : null; + return ClaimGas(to); + } + case "dumpprivkey": + { + UInt160 scriptHash = _params[0].AsString().ToScriptHash(); + return DumpPrivKey(scriptHash); + } + case "getbalance": + { + UIntBase asset_id = UIntBase.Parse(_params[0].AsString()); + return GetBalance(asset_id); + } + case "getnewaddress": + { + return GetNewAddress(); + } + case "getunclaimedgas": + { + return GetUnclaimedGas(); + } + case "getwalletheight": + { + return GetWalletHeight(); + } + case "importprivkey": + { + string privkey = _params[0].AsString(); + return ImportPrivKey(privkey); + } + case "listaddress": + { + return ListAddress(); + } + case "sendfrom": + { + UIntBase assetId = UIntBase.Parse(_params[0].AsString()); + UInt160 from = _params[1].AsString().ToScriptHash(); + UInt160 to = _params[2].AsString().ToScriptHash(); + string value = _params[3].AsString(); + Fixed8 fee = _params.Count >= 5 ? Fixed8.Parse(_params[4].AsString()) : Fixed8.Zero; + UInt160 change_address = _params.Count >= 6 ? _params[5].AsString().ToScriptHash() : null; + return SendFrom(assetId, from, to, value, fee, change_address); + } + case "sendmany": + { + int to_start = 0; + UInt160 from = null; + if (_params[0] is JString) + { + from = _params[0].AsString().ToScriptHash(); + to_start = 1; + } + JArray to = (JArray)_params[to_start + 0]; + Fixed8 fee = _params.Count >= to_start + 2 ? Fixed8.Parse(_params[to_start + 1].AsString()) : Fixed8.Zero; + UInt160 change_address = _params.Count >= to_start + 3 ? _params[to_start + 2].AsString().ToScriptHash() : null; + return SendMany(from, to, fee, change_address); + } + case "sendtoaddress": + { + UIntBase assetId = UIntBase.Parse(_params[0].AsString()); + UInt160 scriptHash = _params[1].AsString().ToScriptHash(); + string value = _params[2].AsString(); + Fixed8 fee = _params.Count >= 4 ? Fixed8.Parse(_params[3].AsString()) : Fixed8.Zero; + UInt160 change_address = _params.Count >= 5 ? _params[4].AsString().ToScriptHash() : null; + return SendToAddress(assetId, scriptHash, value, fee, change_address); + } + default: + return null; + } + } + + public void PostProcess(HttpContext context, string method, JArray _params, JObject result) + { + switch (method) + { + case "invoke": + case "invokefunction": + case "invokescript": + ProcessInvoke(result); + break; + } + } + + private void ProcessInvoke(JObject result) + { + if (Wallet != null) + { + InvocationTransaction tx = new InvocationTransaction + { + Version = 1, + Script = result["script"].AsString().HexToBytes(), + Gas = Fixed8.Parse(result["gas_consumed"].AsString()) + }; + tx.Gas -= Fixed8.FromDecimal(10); + if (tx.Gas < Fixed8.Zero) tx.Gas = Fixed8.Zero; + tx.Gas = tx.Gas.Ceiling(); + tx = Wallet.MakeTransaction(tx); + if (tx != null) + { + ContractParametersContext context = new ContractParametersContext(tx); + Wallet.Sign(context); + if (context.Completed) + tx.Witnesses = context.GetWitnesses(); + else + tx = null; + } + result["tx"] = tx?.ToArray().ToHexString(); + } + } + + private void CheckWallet() + { + if (Wallet is null) + throw new RpcException(-400, "Access denied"); + } + + private JObject SignAndRelay(Transaction tx) + { + ContractParametersContext context = new ContractParametersContext(tx); + Wallet.Sign(context); + if (context.Completed) + { + tx.Witnesses = context.GetWitnesses(); + Wallet.ApplyTransaction(tx); + System.LocalNode.Tell(new LocalNode.Relay { Inventory = tx }); + return tx.ToJson(); + } + else + { + return context.ToJson(); + } + } + + private JObject ClaimGas(UInt160 to) + { + CheckWallet(); + const int MAX_CLAIMS_AMOUNT = 50; + CoinReference[] claims = Wallet.GetUnclaimedCoins().Select(p => p.Reference).ToArray(); + if (claims.Length == 0) + throw new RpcException(-300, "No gas to claim"); + ClaimTransaction tx; + using (Snapshot snapshot = Blockchain.Singleton.GetSnapshot()) + { + tx = new ClaimTransaction + { + Claims = claims.Take(MAX_CLAIMS_AMOUNT).ToArray(), + Attributes = new TransactionAttribute[0], + Inputs = new CoinReference[0], + Outputs = new[] + { + new TransactionOutput + { + AssetId = Blockchain.UtilityToken.Hash, + Value = snapshot.CalculateBonus(claims.Take(MAX_CLAIMS_AMOUNT)), + ScriptHash = to ?? Wallet.GetChangeAddress() + } + } + + }; + } + return SignAndRelay(tx); + } + + private JObject DumpPrivKey(UInt160 scriptHash) + { + CheckWallet(); + WalletAccount account = Wallet.GetAccount(scriptHash); + return account.GetKey().Export(); + } + + private JObject GetBalance(UIntBase asset_id) + { + CheckWallet(); + JObject json = new JObject(); + switch (asset_id) + { + case UInt160 asset_id_160: //NEP-5 balance + json["balance"] = Wallet.GetAvailable(asset_id_160).ToString(); + break; + case UInt256 asset_id_256: //Global Assets balance + IEnumerable coins = Wallet.GetCoins().Where(p => !p.State.HasFlag(CoinState.Spent) && p.Output.AssetId.Equals(asset_id_256)); + json["balance"] = coins.Sum(p => p.Output.Value).ToString(); + json["confirmed"] = coins.Where(p => p.State.HasFlag(CoinState.Confirmed)).Sum(p => p.Output.Value).ToString(); + break; + } + return json; + } + + private JObject GetNewAddress() + { + CheckWallet(); + WalletAccount account = Wallet.CreateAccount(); + if (Wallet is NEP6Wallet nep6) + nep6.Save(); + return account.Address; + } + + private JObject GetUnclaimedGas() + { + CheckWallet(); + using (Snapshot snapshot = Blockchain.Singleton.GetSnapshot()) + { + uint height = snapshot.Height + 1; + Fixed8 unavailable; + try + { + unavailable = snapshot.CalculateBonus(Wallet.FindUnspentCoins().Where(p => p.Output.AssetId.Equals(Blockchain.GoverningToken.Hash)).Select(p => p.Reference), height); + } + catch + { + unavailable = Fixed8.Zero; + } + return new JObject + { + ["available"] = snapshot.CalculateBonus(Wallet.GetUnclaimedCoins().Select(p => p.Reference)).ToString(), + ["unavailable"] = unavailable.ToString() + }; + } + } + + private JObject GetWalletHeight() + { + CheckWallet(); + return (Wallet.WalletHeight > 0) ? Wallet.WalletHeight - 1 : 0; + } + + private JObject ImportPrivKey(string privkey) + { + CheckWallet(); + WalletAccount account = Wallet.Import(privkey); + if (Wallet is NEP6Wallet nep6wallet) + nep6wallet.Save(); + return new JObject + { + ["address"] = account.Address, + ["haskey"] = account.HasKey, + ["label"] = account.Label, + ["watchonly"] = account.WatchOnly + }; + } + + private JObject ListAddress() + { + CheckWallet(); + return Wallet.GetAccounts().Select(p => + { + JObject account = new JObject(); + account["address"] = p.Address; + account["haskey"] = p.HasKey; + account["label"] = p.Label; + account["watchonly"] = p.WatchOnly; + return account; + }).ToArray(); + } + + private JObject SendFrom(UIntBase assetId, UInt160 from, UInt160 to, string value, Fixed8 fee, UInt160 change_address) + { + CheckWallet(); + AssetDescriptor descriptor = new AssetDescriptor(assetId); + BigDecimal amount = BigDecimal.Parse(value, descriptor.Decimals); + if (amount.Sign <= 0) + throw new RpcException(-32602, "Invalid params"); + if (fee < Fixed8.Zero) + throw new RpcException(-32602, "Invalid params"); + Transaction tx = Wallet.MakeTransaction(null, new[] + { + new TransferOutput + { + AssetId = assetId, + Value = amount, + ScriptHash = to + } + }, from: from, change_address: change_address, fee: fee); + if (tx == null) + throw new RpcException(-300, "Insufficient funds"); + return SignAndRelay(tx); + } + + private JObject SendMany(UInt160 from, JArray to, Fixed8 fee, UInt160 change_address) + { + CheckWallet(); + if (to.Count == 0) + throw new RpcException(-32602, "Invalid params"); + TransferOutput[] outputs = new TransferOutput[to.Count]; + for (int i = 0; i < to.Count; i++) + { + UIntBase asset_id = UIntBase.Parse(to[i]["asset"].AsString()); + AssetDescriptor descriptor = new AssetDescriptor(asset_id); + outputs[i] = new TransferOutput + { + AssetId = asset_id, + Value = BigDecimal.Parse(to[i]["value"].AsString(), descriptor.Decimals), + ScriptHash = to[i]["address"].AsString().ToScriptHash() + }; + if (outputs[i].Value.Sign <= 0) + throw new RpcException(-32602, "Invalid params"); + } + if (fee < Fixed8.Zero) + throw new RpcException(-32602, "Invalid params"); + Transaction tx = Wallet.MakeTransaction(null, outputs, from: from, change_address: change_address, fee: fee); + if (tx == null) + throw new RpcException(-300, "Insufficient funds"); + return SignAndRelay(tx); + } + + private JObject SendToAddress(UIntBase assetId, UInt160 scriptHash, string value, Fixed8 fee, UInt160 change_address) + { + CheckWallet(); + AssetDescriptor descriptor = new AssetDescriptor(assetId); + BigDecimal amount = BigDecimal.Parse(value, descriptor.Decimals); + if (amount.Sign <= 0) + throw new RpcException(-32602, "Invalid params"); + if (fee < Fixed8.Zero) + throw new RpcException(-32602, "Invalid params"); + Transaction tx = Wallet.MakeTransaction(null, new[] + { + new TransferOutput + { + AssetId = assetId, + Value = amount, + ScriptHash = scriptHash + } + }, change_address: change_address, fee: fee); + if (tx == null) + throw new RpcException(-300, "Insufficient funds"); + return SignAndRelay(tx); + } + } +} diff --git a/RpcWallet/RpcWallet.csproj b/RpcWallet/RpcWallet.csproj new file mode 100644 index 000000000..a88f11518 --- /dev/null +++ b/RpcWallet/RpcWallet.csproj @@ -0,0 +1,13 @@ + + + + 2.10.0 + netstandard2.0 + Neo.Plugins + + + + + + + diff --git a/neo-plugins.sln b/neo-plugins.sln index 83027c37d..5189c54c2 100644 --- a/neo-plugins.sln +++ b/neo-plugins.sln @@ -15,6 +15,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImportBlocks", "ImportBlock EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SimplePolicy.UnitTests", "SimplePolicy.UnitTests\SimplePolicy.UnitTests.csproj", "{0DA81327-DC81-4960-91C8-4C5F8B9B804C}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RpcWallet", "RpcWallet\RpcWallet.csproj", "{EF32A7E5-EDF9-438C-8041-8DA6E675A7FD}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -45,6 +47,10 @@ Global {0DA81327-DC81-4960-91C8-4C5F8B9B804C}.Debug|Any CPU.Build.0 = Debug|Any CPU {0DA81327-DC81-4960-91C8-4C5F8B9B804C}.Release|Any CPU.ActiveCfg = Release|Any CPU {0DA81327-DC81-4960-91C8-4C5F8B9B804C}.Release|Any CPU.Build.0 = Release|Any CPU + {EF32A7E5-EDF9-438C-8041-8DA6E675A7FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EF32A7E5-EDF9-438C-8041-8DA6E675A7FD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EF32A7E5-EDF9-438C-8041-8DA6E675A7FD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EF32A7E5-EDF9-438C-8041-8DA6E675A7FD}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From eb7052a4bcbec5c7e356f41b0218da11dadab6ae Mon Sep 17 00:00:00 2001 From: jsolman Date: Fri, 8 Mar 2019 21:58:50 -0800 Subject: [PATCH 038/183] Add plugin for NEP5 balances and transfer history (Persistence + RPC) (#43) --- RpcNep5Tracker/Helper.cs | 33 +++ RpcNep5Tracker/Nep5Balance.cs | 42 ++++ RpcNep5Tracker/Nep5BalanceKey.cs | 69 ++++++ RpcNep5Tracker/Nep5Transfer.cs | 55 +++++ RpcNep5Tracker/Nep5TransferKey.cs | 90 +++++++ RpcNep5Tracker/RpcNep5Tracker.cs | 272 ++++++++++++++++++++++ RpcNep5Tracker/RpcNep5Tracker.csproj | 17 ++ RpcNep5Tracker/RpcNep5Tracker/config.json | 6 + neo-plugins.sln | 8 +- 9 files changed, 591 insertions(+), 1 deletion(-) create mode 100644 RpcNep5Tracker/Helper.cs create mode 100644 RpcNep5Tracker/Nep5Balance.cs create mode 100644 RpcNep5Tracker/Nep5BalanceKey.cs create mode 100644 RpcNep5Tracker/Nep5Transfer.cs create mode 100644 RpcNep5Tracker/Nep5TransferKey.cs create mode 100644 RpcNep5Tracker/RpcNep5Tracker.cs create mode 100644 RpcNep5Tracker/RpcNep5Tracker.csproj create mode 100644 RpcNep5Tracker/RpcNep5Tracker/config.json diff --git a/RpcNep5Tracker/Helper.cs b/RpcNep5Tracker/Helper.cs new file mode 100644 index 000000000..a65682e84 --- /dev/null +++ b/RpcNep5Tracker/Helper.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using Neo.IO; +using Neo.IO.Data.LevelDB; + +namespace Neo.Plugins +{ + internal static class Helper + { + public static IEnumerable FindRange(this DB db, ReadOptions options, Slice startKey, Slice endKey, Func resultSelector) + { + using (Iterator it = db.NewIterator(options)) + { + for (it.Seek(startKey); it.Valid(); it.Next()) + { + Slice key = it.Key(); + if (key > endKey) break; + yield return resultSelector(key, it.Value()); + } + } + } + + public static IEnumerable> FindRange(this DB db, byte[] startKeyBytes, byte[] endKeyBytes) + where TKey : IEquatable, ISerializable, new() + where TValue : class, ICloneable, ISerializable, new() + { + return db.FindRange(ReadOptions.Default, SliceBuilder.Begin().Add(startKeyBytes), + SliceBuilder.Begin().Add(endKeyBytes), + (k, v) => new KeyValuePair(k.ToArray().AsSerializable(1), + v.ToArray().AsSerializable())); + } + } +} \ No newline at end of file diff --git a/RpcNep5Tracker/Nep5Balance.cs b/RpcNep5Tracker/Nep5Balance.cs new file mode 100644 index 000000000..efdfa04df --- /dev/null +++ b/RpcNep5Tracker/Nep5Balance.cs @@ -0,0 +1,42 @@ +using System.IO; +using System.Numerics; +using Neo.IO; +using Neo.Ledger; + +namespace Neo.Plugins +{ + public class Nep5Balance : StateBase, ICloneable + { + public BigInteger Balance; + public uint LastUpdatedBlock; + + public override int Size => base.Size + Balance.ToByteArray().GetVarSize(); + + public override void Serialize(BinaryWriter writer) + { + base.Serialize(writer); + writer.WriteVarBytes(Balance.ToByteArray()); + } + + public override void Deserialize(BinaryReader reader) + { + base.Deserialize(reader); + Balance = new BigInteger(reader.ReadVarBytes(512)); + } + + public Nep5Balance Clone() + { + return new Nep5Balance + { + Balance = Balance, + LastUpdatedBlock = LastUpdatedBlock + }; + } + + public void FromReplica(Nep5Balance replica) + { + Balance = replica.Balance; + LastUpdatedBlock = replica.LastUpdatedBlock; + } + } +} \ No newline at end of file diff --git a/RpcNep5Tracker/Nep5BalanceKey.cs b/RpcNep5Tracker/Nep5BalanceKey.cs new file mode 100644 index 000000000..0af045c97 --- /dev/null +++ b/RpcNep5Tracker/Nep5BalanceKey.cs @@ -0,0 +1,69 @@ +using System; +using System.IO; +using Neo.IO; + +namespace Neo.Plugins +{ + public class Nep5BalanceKey : IComparable, IEquatable, ISerializable + { + public readonly UInt160 UserScriptHash; + public readonly UInt160 AssetScriptHash; + + public Nep5BalanceKey() : this(new UInt160(), new UInt160()) + { + } + + public Nep5BalanceKey(UInt160 userScriptHash, UInt160 assetScriptHash) + { + if (userScriptHash == null || assetScriptHash == null) + throw new ArgumentNullException(); + UserScriptHash = userScriptHash; + AssetScriptHash = assetScriptHash; + } + + public int CompareTo(Nep5BalanceKey other) + { + if (other is null) return 1; + if (ReferenceEquals(this, other)) return 0; + int result = UserScriptHash.CompareTo(other.UserScriptHash); + if (result != 0) return result; + return AssetScriptHash.CompareTo(other.AssetScriptHash); + } + + public bool Equals(Nep5BalanceKey other) + { + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; + return UserScriptHash.Equals(other.UserScriptHash) && AssetScriptHash.Equals(AssetScriptHash); + } + + public override bool Equals(Object other) + { + return other is Nep5BalanceKey otherKey && Equals(otherKey); + } + + public override int GetHashCode() + { + unchecked + { + var hashCode = UserScriptHash.GetHashCode(); + hashCode = (hashCode * 397) ^ AssetScriptHash.GetHashCode(); + return hashCode; + } + } + + public void Serialize(BinaryWriter writer) + { + writer.Write(UserScriptHash); + writer.Write(AssetScriptHash); + } + + public void Deserialize(BinaryReader reader) + { + ((ISerializable) UserScriptHash).Deserialize(reader); + ((ISerializable) AssetScriptHash).Deserialize(reader); + } + + public int Size { get; } = 20 + 20; + } +} \ No newline at end of file diff --git a/RpcNep5Tracker/Nep5Transfer.cs b/RpcNep5Tracker/Nep5Transfer.cs new file mode 100644 index 000000000..df012634e --- /dev/null +++ b/RpcNep5Tracker/Nep5Transfer.cs @@ -0,0 +1,55 @@ +using System.IO; +using System.Numerics; +using Neo.IO; +using Neo.Ledger; +using Neo.Network.P2P.Payloads; + +namespace Neo.Plugins +{ + public class Nep5Transfer : StateBase, ICloneable + { + public UInt160 UserScriptHash; + public uint BlockIndex; + public UInt256 TxHash; + public BigInteger Amount; + + public override int Size => base.Size + 20 + Amount.ToByteArray().GetVarSize(); + + public override void Serialize(BinaryWriter writer) + { + base.Serialize(writer); + writer.Write(UserScriptHash); + writer.Write(BlockIndex); + writer.Write(TxHash); + writer.WriteVarBytes(Amount.ToByteArray()); + } + + public override void Deserialize(BinaryReader reader) + { + base.Deserialize(reader); + UserScriptHash = reader.ReadSerializable(); + BlockIndex = reader.ReadUInt32(); + TxHash = reader.ReadSerializable(); + Amount = new BigInteger(reader.ReadVarBytes(512)); + } + + public Nep5Transfer Clone() + { + return new Nep5Transfer + { + UserScriptHash = UserScriptHash, + BlockIndex = BlockIndex, + TxHash = TxHash, + Amount = Amount + }; + } + + public void FromReplica(Nep5Transfer replica) + { + UserScriptHash = replica.UserScriptHash; + BlockIndex = replica.BlockIndex; + TxHash = replica.TxHash; + Amount = replica.Amount; + } + } +} \ No newline at end of file diff --git a/RpcNep5Tracker/Nep5TransferKey.cs b/RpcNep5Tracker/Nep5TransferKey.cs new file mode 100644 index 000000000..3df0af23e --- /dev/null +++ b/RpcNep5Tracker/Nep5TransferKey.cs @@ -0,0 +1,90 @@ +using System; +using System.IO; +using Neo.IO; + +namespace Neo.Plugins +{ + public class Nep5TransferKey : IComparable, IEquatable, ISerializable + { + public readonly UInt160 UserScriptHash; + public uint Timestamp { get; private set; } + public readonly UInt160 AssetScriptHash; + public ushort BlockXferNotificationIndex { get; private set; } + + public Nep5TransferKey() : this(new UInt160(), 0, new UInt160(), 0) + { + } + + public Nep5TransferKey(UInt160 userScriptHash, uint timestamp, UInt160 assetScriptHash, ushort xferIndex) + { + if (userScriptHash is null || assetScriptHash is null) + throw new ArgumentNullException(); + UserScriptHash = userScriptHash; + Timestamp = timestamp; + AssetScriptHash = assetScriptHash; + BlockXferNotificationIndex = xferIndex; + } + + public int CompareTo(Nep5TransferKey other) + { + if (other is null) return 1; + if (ReferenceEquals(this, other)) return 0; + int result = UserScriptHash.CompareTo(other.UserScriptHash); + if (result != 0) return result; + int result2 = Timestamp.CompareTo(other.Timestamp); + if (result2 != 0) return result2; + int result3 = AssetScriptHash.CompareTo(other.AssetScriptHash); + if (result3 != 0) return result3; + return BlockXferNotificationIndex.CompareTo(other.BlockXferNotificationIndex); + } + + public bool Equals(Nep5TransferKey other) + { + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; + return UserScriptHash.Equals(other.UserScriptHash) + && Timestamp.Equals(other.Timestamp) && AssetScriptHash.Equals(other.AssetScriptHash) + && BlockXferNotificationIndex.Equals(other.BlockXferNotificationIndex); + } + + public override bool Equals(Object other) + { + return other is Nep5TransferKey otherKey && Equals(otherKey); + } + + public override int GetHashCode() + { + unchecked + { + var hashCode = UserScriptHash.GetHashCode(); + hashCode = (hashCode * 397) ^ Timestamp.GetHashCode(); + hashCode = (hashCode * 397) ^ AssetScriptHash.GetHashCode(); + hashCode = (hashCode * 397) ^ BlockXferNotificationIndex.GetHashCode(); + return hashCode; + } + } + + public void Serialize(BinaryWriter writer) + { + writer.Write(UserScriptHash); + var timestampBytes = BitConverter.GetBytes(Timestamp); + if (BitConverter.IsLittleEndian) Array.Reverse(timestampBytes); + writer.Write(timestampBytes); + writer.Write(AssetScriptHash); + writer.Write(BlockXferNotificationIndex); + } + + public void Deserialize(BinaryReader reader) + { + ((ISerializable) UserScriptHash).Deserialize(reader); + byte[] timestampBytes = new byte[sizeof(uint)]; + reader.Read(timestampBytes, 0, sizeof(uint)); + if (BitConverter.IsLittleEndian) Array.Reverse(timestampBytes); + Timestamp = BitConverter.ToUInt32(timestampBytes, 0); + ((ISerializable) AssetScriptHash).Deserialize(reader); + BlockXferNotificationIndex = reader.ReadUInt16(); + } + + public int Size { get; } = 20 + sizeof(byte) + sizeof(uint) + 20 + sizeof(ushort); + } +} \ No newline at end of file diff --git a/RpcNep5Tracker/RpcNep5Tracker.cs b/RpcNep5Tracker/RpcNep5Tracker.cs new file mode 100644 index 000000000..faa3371be --- /dev/null +++ b/RpcNep5Tracker/RpcNep5Tracker.cs @@ -0,0 +1,272 @@ +using Microsoft.AspNetCore.Http; +using Neo.IO.Caching; +using Neo.IO.Data.LevelDB; +using Neo.IO.Json; +using Neo.Ledger; +using Neo.Network.P2P.Payloads; +using Neo.Network.RPC; +using Neo.Persistence; +using Neo.Persistence.LevelDB; +using Neo.SmartContract; +using Neo.VM; +using Neo.Wallets; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Numerics; +using System.Text; +using Snapshot = Neo.Persistence.Snapshot; + +namespace Neo.Plugins +{ + public class RpcNep5Tracker : Plugin, IPersistencePlugin, IRpcPlugin + { + private const byte Nep5BalancePrefix = 0xf8; + private const byte Nep5TransferSentPrefix = 0xf9; + private const byte Nep5TransferReceivedPrefix = 0xfa; + private DB _db; + private DataCache _balances; + private DataCache _transfersSent; + private DataCache _transfersReceived; + private WriteBatch _writeBatch; + private bool _shouldTrackHistory; + + public override void Configure() + { + if (_db == null) + { + var dbPath = GetConfiguration().GetSection("DBPath").Value ?? "Nep5BalanceData"; + _shouldTrackHistory = (GetConfiguration().GetSection("TrackHistory").Value ?? true.ToString()) != false.ToString(); + _db = DB.Open(dbPath, new Options { CreateIfMissing = true }); + } + } + + private void ResetBatch() + { + _writeBatch = new WriteBatch(); + var balancesSnapshot = _db.GetSnapshot(); + ReadOptions dbOptions = new ReadOptions { FillCache = false, Snapshot = balancesSnapshot }; + _balances = new DbCache(_db, dbOptions, _writeBatch, Nep5BalancePrefix); + if (_shouldTrackHistory) + { + _transfersSent = + new DbCache(_db, dbOptions, _writeBatch, Nep5TransferSentPrefix); + _transfersReceived = + new DbCache(_db, dbOptions, _writeBatch, Nep5TransferReceivedPrefix); + } + } + + private void HandleNotification(Snapshot snapshot, Transaction transaction, UInt160 scriptHash, + VM.Types.Array stateItems, + Dictionary nep5BalancesChanged, ref ushort transferIndex) + { + // Event name should be encoded as a byte array. + if (!(stateItems[0] is VM.Types.ByteArray)) return; + var eventName = Encoding.UTF8.GetString(stateItems[0].GetByteArray()); + + // Only care about transfers + if (eventName != "transfer") return; + + if (!(stateItems[1] is VM.Types.ByteArray)) + return; + if (!(stateItems[2] is VM.Types.ByteArray)) + return; + var amountItem = stateItems[3]; + if (!(amountItem is VM.Types.ByteArray || amountItem is VM.Types.Integer)) + return; + byte[] fromBytes = stateItems[1].GetByteArray(); + if (fromBytes.Length != 20) fromBytes = null; + byte[] toBytes = stateItems[2].GetByteArray(); + if (toBytes.Length != 20) toBytes = null; + if (fromBytes == null && toBytes == null) return; + var from = new UInt160(fromBytes); + var to = new UInt160(toBytes); + + var fromKey = new Nep5BalanceKey(from, scriptHash); + if (!nep5BalancesChanged.ContainsKey(fromKey)) nep5BalancesChanged.Add(fromKey, new Nep5Balance()); + var toKey = new Nep5BalanceKey(to, scriptHash); + if (!nep5BalancesChanged.ContainsKey(toKey)) nep5BalancesChanged.Add(toKey, new Nep5Balance()); + + if (!_shouldTrackHistory) return; + BigInteger amount = amountItem.GetBigInteger(); + _transfersSent.Add(new Nep5TransferKey(from, + snapshot.GetHeader(snapshot.Height).Timestamp, scriptHash, transferIndex), + new Nep5Transfer + { + Amount = amount, + UserScriptHash = to, + BlockIndex = snapshot.Height, + TxHash = transaction.Hash + }); + _transfersReceived.Add(new Nep5TransferKey(to, + snapshot.GetHeader(snapshot.Height).Timestamp, scriptHash, transferIndex), + new Nep5Transfer + { + Amount = amount, + UserScriptHash = from, + BlockIndex = snapshot.Height, + TxHash = transaction.Hash + }); + transferIndex++; + } + + public void OnPersist(Snapshot snapshot, IReadOnlyList applicationExecutedList) + { + // Start freshly with a new DBCache for each block. + ResetBatch(); + Dictionary nep5BalancesChanged = new Dictionary(); + + ushort transferIndex = 0; + foreach (Blockchain.ApplicationExecuted appExecuted in applicationExecutedList) + { + foreach (var executionResults in appExecuted.ExecutionResults) + { + // Executions that fault won't modify storage, so we can skip them. + if (executionResults.VMState.HasFlag(VMState.FAULT)) continue; + foreach (var notifyEventArgs in executionResults.Notifications) + { + if (!(notifyEventArgs?.State is VM.Types.Array stateItems) || stateItems.Count == 0 + || !(notifyEventArgs.ScriptContainer is Transaction transaction)) + continue; + HandleNotification(snapshot, transaction, notifyEventArgs.ScriptHash, stateItems, + nep5BalancesChanged, ref transferIndex); + } + } + } + + foreach (var nep5BalancePair in nep5BalancesChanged) + { + // get guarantee accurate balances by calling balanceOf for keys that changed. + byte[] script; + using (ScriptBuilder sb = new ScriptBuilder()) + { + sb.EmitAppCall(nep5BalancePair.Key.AssetScriptHash, "balanceOf", + nep5BalancePair.Key.UserScriptHash.ToArray()); + script = sb.ToArray(); + } + + ApplicationEngine engine = ApplicationEngine.Run(script, snapshot); + if (engine.State.HasFlag(VMState.FAULT)) continue; + if (engine.ResultStack.Count <= 0) continue; + nep5BalancePair.Value.Balance = engine.ResultStack.Pop().GetBigInteger(); + nep5BalancePair.Value.LastUpdatedBlock = snapshot.Height; + if (nep5BalancePair.Value.Balance == 0) + { + _balances.Delete(nep5BalancePair.Key); + continue; + } + var itemToChange = _balances.GetAndChange(nep5BalancePair.Key, () => nep5BalancePair.Value); + if (itemToChange != nep5BalancePair.Value) + itemToChange.FromReplica(nep5BalancePair.Value); + } + } + + public void OnCommit(Snapshot snapshot) + { + _balances.Commit(); + if (_shouldTrackHistory) + { + _transfersSent.Commit(); + _transfersReceived.Commit(); + } + + _db.Write(WriteOptions.Default, _writeBatch); + } + + public bool ShouldThrowExceptionFromCommit(Exception ex) + { + return true; + } + + private void AddTransfers(byte dbPrefix, UInt160 userScriptHash, uint startTime, uint endTime, + JArray parentJArray) + { + var prefix = new[] { dbPrefix }.Concat(userScriptHash.ToArray()).ToArray(); + var startTimeBytes = BitConverter.GetBytes(startTime); + var endTimeBytes = BitConverter.GetBytes(endTime); + if (BitConverter.IsLittleEndian) + { + Array.Reverse(startTimeBytes); + Array.Reverse(endTimeBytes); + } + + var transferPairs = _db.FindRange( + prefix.Concat(startTimeBytes).ToArray(), + prefix.Concat(endTimeBytes).ToArray()); + + foreach (var transferPair in transferPairs) + { + JObject transfer = new JObject(); + transfer["timestamp"] = transferPair.Key.Timestamp; + transfer["asset_hash"] = transferPair.Key.AssetScriptHash.ToArray().Reverse().ToHexString(); + transfer["transfer_address"] = transferPair.Value.UserScriptHash.ToAddress(); + transfer["amount"] = transferPair.Value.Amount.ToString(); + transfer["block_index"] = transferPair.Value.BlockIndex; + transfer["transfer_notify_index"] = transferPair.Key.BlockXferNotificationIndex; + transfer["tx_hash"] = transferPair.Value.TxHash.ToArray().Reverse().ToHexString(); + parentJArray.Add(transfer); + } + } + + private UInt160 GetScriptHashFromParam(string addressOrScriptHash) + { + return addressOrScriptHash.Length < 40 ? + addressOrScriptHash.ToScriptHash() : UInt160.Parse(addressOrScriptHash); + } + private JObject GetNep5Transfers(JArray _params) + { + UInt160 userScriptHash = GetScriptHashFromParam(_params[0].AsString()); + // If start time not present, default to 1 week of history. + uint startTime = _params.Count > 1 ? (uint)_params[1].AsNumber() : + (DateTime.UtcNow - TimeSpan.FromDays(7)).ToTimestamp(); + uint endTime = _params.Count > 2 ? (uint)_params[2].AsNumber() : DateTime.UtcNow.ToTimestamp(); + + if (endTime < startTime) throw new RpcException(-32602, "Invalid params"); + + JObject json = new JObject(); + JArray transfersSent = new JArray(); + json["sent"] = transfersSent; + JArray transfersReceived = new JArray(); + json["received"] = transfersReceived; + json["address"] = userScriptHash.ToAddress(); + AddTransfers(Nep5TransferSentPrefix, userScriptHash, startTime, endTime, transfersSent); + AddTransfers(Nep5TransferReceivedPrefix, userScriptHash, startTime, endTime, transfersReceived); + return json; + } + + private JObject GetNep5Balances(JArray _params) + { + UInt160 userScriptHash = GetScriptHashFromParam(_params[0].AsString()); + + JObject json = new JObject(); + JArray balances = new JArray(); + json["balance"] = balances; + json["address"] = userScriptHash.ToAddress(); + var dbCache = new DbCache(_db, null, null, Nep5BalancePrefix); + byte[] prefix = userScriptHash.ToArray(); + foreach (var storageKeyValuePair in dbCache.Find(prefix)) + { + JObject balance = new JObject(); + balance["asset_hash"] = storageKeyValuePair.Key.AssetScriptHash.ToArray().Reverse().ToHexString(); + balance["amount"] = storageKeyValuePair.Value.Balance.ToString(); + balance["last_updated_block"] = storageKeyValuePair.Value.LastUpdatedBlock; + balances.Add(balance); + } + return json; + } + + public void PreProcess(HttpContext context, string method, JArray _params) + { + } + + public JObject OnProcess(HttpContext context, string method, JArray _params) + { + if (_shouldTrackHistory && method == "getnep5transfers") return GetNep5Transfers(_params); + return method == "getnep5balances" ? GetNep5Balances(_params) : null; + } + + public void PostProcess(HttpContext context, string method, JArray _params, JObject result) + { + } + } +} diff --git a/RpcNep5Tracker/RpcNep5Tracker.csproj b/RpcNep5Tracker/RpcNep5Tracker.csproj new file mode 100644 index 000000000..f9e2e4be8 --- /dev/null +++ b/RpcNep5Tracker/RpcNep5Tracker.csproj @@ -0,0 +1,17 @@ + + + 2.10.0 + netstandard2.0 + Neo.Plugins + latest + + + + PreserveNewest + PreserveNewest + + + + + + diff --git a/RpcNep5Tracker/RpcNep5Tracker/config.json b/RpcNep5Tracker/RpcNep5Tracker/config.json new file mode 100644 index 000000000..3d7efb4fe --- /dev/null +++ b/RpcNep5Tracker/RpcNep5Tracker/config.json @@ -0,0 +1,6 @@ +{ + "PluginConfiguration": { + "DBPath": "Nep5BalanceData", + "TrackHistory" : true + } +} diff --git a/neo-plugins.sln b/neo-plugins.sln index 5189c54c2..dd29792b5 100644 --- a/neo-plugins.sln +++ b/neo-plugins.sln @@ -17,6 +17,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SimplePolicy.UnitTests", "S EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RpcWallet", "RpcWallet\RpcWallet.csproj", "{EF32A7E5-EDF9-438C-8041-8DA6E675A7FD}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RpcNep5Tracker", "RpcNep5Tracker\RpcNep5Tracker.csproj", "{BBE8AC15-12DF-4AF0-ABC1-F1557EB5DC8E}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -46,11 +48,15 @@ Global {0DA81327-DC81-4960-91C8-4C5F8B9B804C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {0DA81327-DC81-4960-91C8-4C5F8B9B804C}.Debug|Any CPU.Build.0 = Debug|Any CPU {0DA81327-DC81-4960-91C8-4C5F8B9B804C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0DA81327-DC81-4960-91C8-4C5F8B9B804C}.Release|Any CPU.Build.0 = Release|Any CPU + {0DA81327-DC81-4960-91C8-4C5F8B9B804C}.Release|Any CPU.Build.0 = Release|Any CPU {EF32A7E5-EDF9-438C-8041-8DA6E675A7FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {EF32A7E5-EDF9-438C-8041-8DA6E675A7FD}.Debug|Any CPU.Build.0 = Debug|Any CPU {EF32A7E5-EDF9-438C-8041-8DA6E675A7FD}.Release|Any CPU.ActiveCfg = Release|Any CPU {EF32A7E5-EDF9-438C-8041-8DA6E675A7FD}.Release|Any CPU.Build.0 = Release|Any CPU + {BBE8AC15-12DF-4AF0-ABC1-F1557EB5DC8E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BBE8AC15-12DF-4AF0-ABC1-F1557EB5DC8E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BBE8AC15-12DF-4AF0-ABC1-F1557EB5DC8E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BBE8AC15-12DF-4AF0-ABC1-F1557EB5DC8E}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From d33ceb59210f95b00c935bf2dad13e234c4ad2dd Mon Sep 17 00:00:00 2001 From: jsolman Date: Mon, 11 Mar 2019 18:12:55 -0700 Subject: [PATCH 039/183] Check authentication during pre-processing. (#54) --- RpcSecurity/RpcSecurity.cs | 6 +++--- RpcSecurity/RpcSecurity.csproj | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/RpcSecurity/RpcSecurity.cs b/RpcSecurity/RpcSecurity.cs index 84873f774..16054c3a8 100644 --- a/RpcSecurity/RpcSecurity.cs +++ b/RpcSecurity/RpcSecurity.cs @@ -16,12 +16,12 @@ public override void Configure() public void PreProcess(HttpContext context, string method, JArray _params) { + if (!CheckAuth(context) || Settings.Default.DisabledMethods.Contains(method)) + throw new RpcException(-400, "Access denied"); } - + public JObject OnProcess(HttpContext context, string method, JArray _params) { - if (!CheckAuth(context) || Settings.Default.DisabledMethods.Contains(method)) - throw new RpcException(-400, "Access denied"); return null; } diff --git a/RpcSecurity/RpcSecurity.csproj b/RpcSecurity/RpcSecurity.csproj index 1b783ee4d..480f774ca 100644 --- a/RpcSecurity/RpcSecurity.csproj +++ b/RpcSecurity/RpcSecurity.csproj @@ -1,7 +1,7 @@  - 2.9.4 + 2.10.0 netstandard2.0;net47 Neo.Plugins @@ -14,7 +14,7 @@ - + From 1643a8f998be372345b6b4900d46ce5b84e00263 Mon Sep 17 00:00:00 2001 From: erikzhang Date: Wed, 13 Mar 2019 16:09:46 +0800 Subject: [PATCH 040/183] v2.10.0 --- ApplicationLogs/ApplicationLogs.csproj | 6 +++--- ImportBlocks/ImportBlocks.csproj | 6 +++--- RpcNep5Tracker/RpcNep5Tracker.csproj | 2 +- RpcSecurity/RpcSecurity.csproj | 2 +- SimplePolicy/SimplePolicy.csproj | 6 +++--- StatesDumper/StatesDumper.csproj | 6 +++--- neo-plugins.sln | 5 ++--- 7 files changed, 16 insertions(+), 17 deletions(-) diff --git a/ApplicationLogs/ApplicationLogs.csproj b/ApplicationLogs/ApplicationLogs.csproj index 4c5a41dea..d8d5f27bb 100644 --- a/ApplicationLogs/ApplicationLogs.csproj +++ b/ApplicationLogs/ApplicationLogs.csproj @@ -1,8 +1,8 @@  - 2.9.4 - netstandard2.0;net47 + 2.10.0 + netstandard2.0 Neo.Plugins @@ -14,7 +14,7 @@ - + diff --git a/ImportBlocks/ImportBlocks.csproj b/ImportBlocks/ImportBlocks.csproj index b053a32dd..174fe8e08 100644 --- a/ImportBlocks/ImportBlocks.csproj +++ b/ImportBlocks/ImportBlocks.csproj @@ -1,8 +1,8 @@  - 2.9.4 - netstandard2.0;net47 + 2.10.0 + netstandard2.0 Neo.Plugins @@ -14,7 +14,7 @@ - + diff --git a/RpcNep5Tracker/RpcNep5Tracker.csproj b/RpcNep5Tracker/RpcNep5Tracker.csproj index f9e2e4be8..39f8c5674 100644 --- a/RpcNep5Tracker/RpcNep5Tracker.csproj +++ b/RpcNep5Tracker/RpcNep5Tracker.csproj @@ -1,7 +1,7 @@  2.10.0 - netstandard2.0 + netstandard2.0 Neo.Plugins latest diff --git a/RpcSecurity/RpcSecurity.csproj b/RpcSecurity/RpcSecurity.csproj index 480f774ca..5ae23ce07 100644 --- a/RpcSecurity/RpcSecurity.csproj +++ b/RpcSecurity/RpcSecurity.csproj @@ -2,7 +2,7 @@ 2.10.0 - netstandard2.0;net47 + netstandard2.0 Neo.Plugins diff --git a/SimplePolicy/SimplePolicy.csproj b/SimplePolicy/SimplePolicy.csproj index 39981afff..6d1be1a01 100644 --- a/SimplePolicy/SimplePolicy.csproj +++ b/SimplePolicy/SimplePolicy.csproj @@ -1,8 +1,8 @@  - 2.9.4 - netstandard2.0;net47 + 2.10.0 + netstandard2.0 Neo.Plugins latest @@ -15,7 +15,7 @@ - + diff --git a/StatesDumper/StatesDumper.csproj b/StatesDumper/StatesDumper.csproj index 12337b3ee..bda2c6ec0 100644 --- a/StatesDumper/StatesDumper.csproj +++ b/StatesDumper/StatesDumper.csproj @@ -1,8 +1,8 @@  - 2.9.4 - netstandard2.0;net47 + 2.10.0 + netstandard2.0 Neo.Plugins @@ -14,7 +14,7 @@ - + diff --git a/neo-plugins.sln b/neo-plugins.sln index dd29792b5..f6e27ed6b 100644 --- a/neo-plugins.sln +++ b/neo-plugins.sln @@ -15,7 +15,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImportBlocks", "ImportBlock EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SimplePolicy.UnitTests", "SimplePolicy.UnitTests\SimplePolicy.UnitTests.csproj", "{0DA81327-DC81-4960-91C8-4C5F8B9B804C}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RpcWallet", "RpcWallet\RpcWallet.csproj", "{EF32A7E5-EDF9-438C-8041-8DA6E675A7FD}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RpcWallet", "RpcWallet\RpcWallet.csproj", "{EF32A7E5-EDF9-438C-8041-8DA6E675A7FD}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RpcNep5Tracker", "RpcNep5Tracker\RpcNep5Tracker.csproj", "{BBE8AC15-12DF-4AF0-ABC1-F1557EB5DC8E}" EndProject @@ -48,12 +48,11 @@ Global {0DA81327-DC81-4960-91C8-4C5F8B9B804C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {0DA81327-DC81-4960-91C8-4C5F8B9B804C}.Debug|Any CPU.Build.0 = Debug|Any CPU {0DA81327-DC81-4960-91C8-4C5F8B9B804C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0DA81327-DC81-4960-91C8-4C5F8B9B804C}.Release|Any CPU.Build.0 = Release|Any CPU {EF32A7E5-EDF9-438C-8041-8DA6E675A7FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {EF32A7E5-EDF9-438C-8041-8DA6E675A7FD}.Debug|Any CPU.Build.0 = Debug|Any CPU {EF32A7E5-EDF9-438C-8041-8DA6E675A7FD}.Release|Any CPU.ActiveCfg = Release|Any CPU {EF32A7E5-EDF9-438C-8041-8DA6E675A7FD}.Release|Any CPU.Build.0 = Release|Any CPU - {BBE8AC15-12DF-4AF0-ABC1-F1557EB5DC8E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BBE8AC15-12DF-4AF0-ABC1-F1557EB5DC8E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {BBE8AC15-12DF-4AF0-ABC1-F1557EB5DC8E}.Debug|Any CPU.Build.0 = Debug|Any CPU {BBE8AC15-12DF-4AF0-ABC1-F1557EB5DC8E}.Release|Any CPU.ActiveCfg = Release|Any CPU {BBE8AC15-12DF-4AF0-ABC1-F1557EB5DC8E}.Release|Any CPU.Build.0 = Release|Any CPU From 08cda72187ccd1fe8722856959644b393784c328 Mon Sep 17 00:00:00 2001 From: jsolman Date: Wed, 13 Mar 2019 13:45:50 -0700 Subject: [PATCH 041/183] Fix memory leak of LevelDB snapshots. (#57) --- RpcNep5Tracker/RpcNep5Tracker.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/RpcNep5Tracker/RpcNep5Tracker.cs b/RpcNep5Tracker/RpcNep5Tracker.cs index faa3371be..ed7a48f4e 100644 --- a/RpcNep5Tracker/RpcNep5Tracker.cs +++ b/RpcNep5Tracker/RpcNep5Tracker.cs @@ -30,6 +30,7 @@ public class RpcNep5Tracker : Plugin, IPersistencePlugin, IRpcPlugin private DataCache _transfersReceived; private WriteBatch _writeBatch; private bool _shouldTrackHistory; + private Neo.IO.Data.LevelDB.Snapshot _levelDbSnapshot; public override void Configure() { @@ -44,8 +45,9 @@ public override void Configure() private void ResetBatch() { _writeBatch = new WriteBatch(); - var balancesSnapshot = _db.GetSnapshot(); - ReadOptions dbOptions = new ReadOptions { FillCache = false, Snapshot = balancesSnapshot }; + _levelDbSnapshot?.Dispose(); + _levelDbSnapshot = _db.GetSnapshot(); + ReadOptions dbOptions = new ReadOptions { FillCache = false, Snapshot = _levelDbSnapshot }; _balances = new DbCache(_db, dbOptions, _writeBatch, Nep5BalancePrefix); if (_shouldTrackHistory) { From 685f44833466bcbc09cb684a1c434fb61d41ce35 Mon Sep 17 00:00:00 2001 From: jsolman Date: Sun, 17 Mar 2019 01:38:43 -0700 Subject: [PATCH 042/183] Use IPersistencePlugin and batch Application Log writes. (#62) --- ApplicationLogs/LogReader.cs | 68 +++++++++++++++++++++++++++++++++--- ApplicationLogs/Logger.cs | 68 ------------------------------------ 2 files changed, 63 insertions(+), 73 deletions(-) delete mode 100644 ApplicationLogs/Logger.cs diff --git a/ApplicationLogs/LogReader.cs b/ApplicationLogs/LogReader.cs index ad1a8c3ae..0ee121c5e 100644 --- a/ApplicationLogs/LogReader.cs +++ b/ApplicationLogs/LogReader.cs @@ -1,12 +1,18 @@ using Microsoft.AspNetCore.Http; using Neo.IO.Data.LevelDB; using Neo.IO.Json; +using Neo.Ledger; using Neo.Network.RPC; +using Neo.VM; +using System; +using System.Collections.Generic; using System.IO; +using System.Linq; +using Snapshot = Neo.Persistence.Snapshot; namespace Neo.Plugins { - public class LogReader : Plugin, IRpcPlugin + public class LogReader : Plugin, IRpcPlugin, IPersistencePlugin { private readonly DB db; @@ -14,8 +20,7 @@ public class LogReader : Plugin, IRpcPlugin public LogReader() { - this.db = DB.Open(Path.GetFullPath(Settings.Default.Path), new Options { CreateIfMissing = true }); - System.ActorSystem.ActorOf(Logger.Props(System.Blockchain, db)); + db = DB.Open(Path.GetFullPath(Settings.Default.Path), new Options { CreateIfMissing = true }); } public override void Configure() @@ -26,7 +31,7 @@ public override void Configure() public void PreProcess(HttpContext context, string method, JArray _params) { } - + public JObject OnProcess(HttpContext context, string method, JArray _params) { if (method != "getapplicationlog") return null; @@ -35,9 +40,62 @@ public JObject OnProcess(HttpContext context, string method, JArray _params) throw new RpcException(-100, "Unknown transaction"); return JObject.Parse(value.ToString()); } - + public void PostProcess(HttpContext context, string method, JArray _params, JObject result) { } + + public void OnPersist(Snapshot snapshot, IReadOnlyList applicationExecutedList) + { + WriteBatch writeBatch = new WriteBatch(); + + foreach (var appExec in applicationExecutedList) + { + JObject json = new JObject(); + json["txid"] = appExec.Transaction.Hash.ToString(); + json["executions"] = appExec.ExecutionResults.Select(p => + { + JObject execution = new JObject(); + execution["trigger"] = p.Trigger; + execution["contract"] = p.ScriptHash.ToString(); + execution["vmstate"] = p.VMState; + execution["gas_consumed"] = p.GasConsumed.ToString(); + try + { + execution["stack"] = p.Stack.Select(q => q.ToParameter().ToJson()).ToArray(); + } + catch (InvalidOperationException) + { + execution["stack"] = "error: recursive reference"; + } + execution["notifications"] = p.Notifications.Select(q => + { + JObject notification = new JObject(); + notification["contract"] = q.ScriptHash.ToString(); + try + { + notification["state"] = q.State.ToParameter().ToJson(); + } + catch (InvalidOperationException) + { + notification["state"] = "error: recursive reference"; + } + return notification; + }).ToArray(); + return execution; + }).ToArray(); + writeBatch.Put(appExec.Transaction.Hash.ToArray(), json.ToString()); + } + db.Write(WriteOptions.Default, writeBatch); + } + + public void OnCommit(Snapshot snapshot) + { + } + + public bool ShouldThrowExceptionFromCommit(Exception ex) + { + return false; + } } } diff --git a/ApplicationLogs/Logger.cs b/ApplicationLogs/Logger.cs deleted file mode 100644 index ae793ebc1..000000000 --- a/ApplicationLogs/Logger.cs +++ /dev/null @@ -1,68 +0,0 @@ -using Akka.Actor; -using Neo.IO; -using Neo.IO.Data.LevelDB; -using Neo.IO.Json; -using Neo.Ledger; -using Neo.VM; -using System; -using System.Linq; - -namespace Neo.Plugins -{ - internal class Logger : UntypedActor - { - private readonly DB db; - - public Logger(IActorRef blockchain, DB db) - { - this.db = db; - blockchain.Tell(new Blockchain.Register()); - } - - protected override void OnReceive(object message) - { - if (message is Blockchain.ApplicationExecuted e) - { - JObject json = new JObject(); - json["txid"] = e.Transaction.Hash.ToString(); - json["executions"] = e.ExecutionResults.Select(p => - { - JObject execution = new JObject(); - execution["trigger"] = p.Trigger; - execution["contract"] = p.ScriptHash.ToString(); - execution["vmstate"] = p.VMState; - execution["gas_consumed"] = p.GasConsumed.ToString(); - try - { - execution["stack"] = p.Stack.Select(q => q.ToParameter().ToJson()).ToArray(); - } - catch (InvalidOperationException) - { - execution["stack"] = "error: recursive reference"; - } - execution["notifications"] = p.Notifications.Select(q => - { - JObject notification = new JObject(); - notification["contract"] = q.ScriptHash.ToString(); - try - { - notification["state"] = q.State.ToParameter().ToJson(); - } - catch (InvalidOperationException) - { - notification["state"] = "error: recursive reference"; - } - return notification; - }).ToArray(); - return execution; - }).ToArray(); - db.Put(WriteOptions.Default, e.Transaction.Hash.ToArray(), json.ToString()); - } - } - - public static Props Props(IActorRef blockchain, DB db) - { - return Akka.Actor.Props.Create(() => new Logger(blockchain, db)); - } - } -} From 8137d5c991a54616b7657c12b895597212d2df87 Mon Sep 17 00:00:00 2001 From: Shargon Date: Mon, 18 Mar 2019 17:06:48 +0100 Subject: [PATCH 043/183] Fix sizes for RpcNep5Tracker (#67) --- RpcNep5Tracker/Nep5Balance.cs | 4 +++- RpcNep5Tracker/Nep5BalanceKey.cs | 4 ++-- RpcNep5Tracker/Nep5Transfer.cs | 3 +-- RpcNep5Tracker/Nep5TransferKey.cs | 8 ++++---- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/RpcNep5Tracker/Nep5Balance.cs b/RpcNep5Tracker/Nep5Balance.cs index efdfa04df..304028d08 100644 --- a/RpcNep5Tracker/Nep5Balance.cs +++ b/RpcNep5Tracker/Nep5Balance.cs @@ -10,18 +10,20 @@ public class Nep5Balance : StateBase, ICloneable public BigInteger Balance; public uint LastUpdatedBlock; - public override int Size => base.Size + Balance.ToByteArray().GetVarSize(); + public override int Size => base.Size + Balance.ToByteArray().GetVarSize() + sizeof(uint); public override void Serialize(BinaryWriter writer) { base.Serialize(writer); writer.WriteVarBytes(Balance.ToByteArray()); + writer.Write(LastUpdatedBlock); } public override void Deserialize(BinaryReader reader) { base.Deserialize(reader); Balance = new BigInteger(reader.ReadVarBytes(512)); + LastUpdatedBlock = reader.ReadUInt32(); } public Nep5Balance Clone() diff --git a/RpcNep5Tracker/Nep5BalanceKey.cs b/RpcNep5Tracker/Nep5BalanceKey.cs index 0af045c97..b4a1710cf 100644 --- a/RpcNep5Tracker/Nep5BalanceKey.cs +++ b/RpcNep5Tracker/Nep5BalanceKey.cs @@ -9,6 +9,8 @@ public class Nep5BalanceKey : IComparable, IEquatable 20 + 20; + public Nep5BalanceKey() : this(new UInt160(), new UInt160()) { } @@ -63,7 +65,5 @@ public void Deserialize(BinaryReader reader) ((ISerializable) UserScriptHash).Deserialize(reader); ((ISerializable) AssetScriptHash).Deserialize(reader); } - - public int Size { get; } = 20 + 20; } } \ No newline at end of file diff --git a/RpcNep5Tracker/Nep5Transfer.cs b/RpcNep5Tracker/Nep5Transfer.cs index df012634e..7ddf8c54a 100644 --- a/RpcNep5Tracker/Nep5Transfer.cs +++ b/RpcNep5Tracker/Nep5Transfer.cs @@ -2,7 +2,6 @@ using System.Numerics; using Neo.IO; using Neo.Ledger; -using Neo.Network.P2P.Payloads; namespace Neo.Plugins { @@ -13,7 +12,7 @@ public class Nep5Transfer : StateBase, ICloneable public UInt256 TxHash; public BigInteger Amount; - public override int Size => base.Size + 20 + Amount.ToByteArray().GetVarSize(); + public override int Size => base.Size + 20 + sizeof(uint) + 32 + Amount.ToByteArray().GetVarSize(); public override void Serialize(BinaryWriter writer) { diff --git a/RpcNep5Tracker/Nep5TransferKey.cs b/RpcNep5Tracker/Nep5TransferKey.cs index 3df0af23e..a1892d54a 100644 --- a/RpcNep5Tracker/Nep5TransferKey.cs +++ b/RpcNep5Tracker/Nep5TransferKey.cs @@ -11,6 +11,8 @@ public class Nep5TransferKey : IComparable, IEquatable 20 + sizeof(uint) + 20 + sizeof(ushort); + public Nep5TransferKey() : this(new UInt160(), 0, new UInt160(), 0) { } @@ -76,15 +78,13 @@ public void Serialize(BinaryWriter writer) public void Deserialize(BinaryReader reader) { - ((ISerializable) UserScriptHash).Deserialize(reader); + ((ISerializable)UserScriptHash).Deserialize(reader); byte[] timestampBytes = new byte[sizeof(uint)]; reader.Read(timestampBytes, 0, sizeof(uint)); if (BitConverter.IsLittleEndian) Array.Reverse(timestampBytes); Timestamp = BitConverter.ToUInt32(timestampBytes, 0); - ((ISerializable) AssetScriptHash).Deserialize(reader); + ((ISerializable)AssetScriptHash).Deserialize(reader); BlockXferNotificationIndex = reader.ReadUInt16(); } - - public int Size { get; } = 20 + sizeof(byte) + sizeof(uint) + 20 + sizeof(ushort); } } \ No newline at end of file From c611239c781394c7a4fd8e5184061143982bc2a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vitor=20Naz=C3=A1rio=20Coelho?= Date: Wed, 20 Mar 2019 13:09:30 -0300 Subject: [PATCH 044/183] Plugin CoreMetrics (#68) * Plugin coreMetrics. * Organize project files * metric prefix --- CoreMetrics/CoreMetrics.cs | 90 ++++++++++++++++++++++++++++++++++ CoreMetrics/CoreMetrics.csproj | 13 +++++ neo-plugins.sln | 6 +++ 3 files changed, 109 insertions(+) create mode 100644 CoreMetrics/CoreMetrics.cs create mode 100644 CoreMetrics/CoreMetrics.csproj diff --git a/CoreMetrics/CoreMetrics.cs b/CoreMetrics/CoreMetrics.cs new file mode 100644 index 000000000..a1c10af5d --- /dev/null +++ b/CoreMetrics/CoreMetrics.cs @@ -0,0 +1,90 @@ +using Microsoft.AspNetCore.Http; +using Neo.IO.Json; +using Neo.Ledger; +using Neo.Network.P2P.Payloads; +using Neo.Persistence; + +namespace Neo.Plugins +{ + public class CoreMetrics : Plugin, IRpcPlugin + { + public override void Configure() + { + } + + public void PreProcess(HttpContext context, string method, JArray _params) + { + } + + public JObject OnProcess(HttpContext context, string method, JArray _params) + { + switch (method) + { + case "getmetricblocktimestamp": + { + + uint nBlocks = (uint)_params[0].AsNumber(); + uint lastHeight = _params.Count >= 2 ? lastHeight = (uint)_params[1].AsNumber() : 0; + return GetBlocksTime(nBlocks, lastHeight); + } + default: + return null; + } + } + + public void PostProcess(HttpContext context, string method, JArray _params, JObject result) + { + } + + private JObject GetBlocksTime(uint nBlocks, uint lastHeight) + { + // It is currently limited to query blocks generated in the last 24hours (86400 seconds) + uint maxNBlocksPerDay = 86400 / Blockchain.SecondsPerBlock; + if (lastHeight != 0) + { + if (lastHeight >= Blockchain.Singleton.Height) + { + JObject json = new JObject(); + return json["error"] = "Requested height to start " + lastHeight + " exceeds " + Blockchain.Singleton.Height; + } + + if (nBlocks > lastHeight) + { + JObject json = new JObject(); + return json["error"] = "Requested " + nBlocks + " blocks timestamps is greater than starting at height " + lastHeight; + } + } + + if (nBlocks > maxNBlocksPerDay) + { + JObject json = new JObject(); + return json["error"] = "Requested number of blocks timestamps exceeds " + maxNBlocksPerDay; + } + + if (nBlocks >= Blockchain.Singleton.Height) + { + JObject json = new JObject(); + return json["error"] = "Requested number of blocks timestamps exceeds quantity of known blocks " + Blockchain.Singleton.Height; + } + + if (nBlocks <= 0) + { + JObject json = new JObject(); + return json["error"] = "Requested number of block times can not be <= 0"; + } + + JArray array = new JArray(); + uint heightToBegin = lastHeight > 0 ? lastHeight - nBlocks : Blockchain.Singleton.Height - nBlocks; + for (uint i = heightToBegin; i <= Blockchain.Singleton.HeaderHeight; i++) + { + JObject json = new JObject(); + Header header = Blockchain.Singleton.Store.GetHeader(i); + json["timestamp"] = header.Timestamp; + json["height"] = i; + array.Add(json); + } + + return array; + } + } +} diff --git a/CoreMetrics/CoreMetrics.csproj b/CoreMetrics/CoreMetrics.csproj new file mode 100644 index 000000000..a88f11518 --- /dev/null +++ b/CoreMetrics/CoreMetrics.csproj @@ -0,0 +1,13 @@ + + + + 2.10.0 + netstandard2.0 + Neo.Plugins + + + + + + + diff --git a/neo-plugins.sln b/neo-plugins.sln index f6e27ed6b..08db236ee 100644 --- a/neo-plugins.sln +++ b/neo-plugins.sln @@ -19,6 +19,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RpcWallet", "RpcWallet\RpcW EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RpcNep5Tracker", "RpcNep5Tracker\RpcNep5Tracker.csproj", "{BBE8AC15-12DF-4AF0-ABC1-F1557EB5DC8E}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CoreMetrics", "CoreMetrics\CoreMetrics.csproj", "{AEFFF003-3500-416B-AD9B-8C838C33C1F4}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -56,6 +58,10 @@ Global {BBE8AC15-12DF-4AF0-ABC1-F1557EB5DC8E}.Debug|Any CPU.Build.0 = Debug|Any CPU {BBE8AC15-12DF-4AF0-ABC1-F1557EB5DC8E}.Release|Any CPU.ActiveCfg = Release|Any CPU {BBE8AC15-12DF-4AF0-ABC1-F1557EB5DC8E}.Release|Any CPU.Build.0 = Release|Any CPU + {AEFFF003-3500-416B-AD9B-8C838C33C1F4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AEFFF003-3500-416B-AD9B-8C838C33C1F4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AEFFF003-3500-416B-AD9B-8C838C33C1F4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AEFFF003-3500-416B-AD9B-8C838C33C1F4}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From a3d2b6e354575922844471f2400b095b6390c2ac Mon Sep 17 00:00:00 2001 From: Owen Zhang <38493437+superboyiii@users.noreply.github.com> Date: Thu, 21 Mar 2019 16:32:41 +0800 Subject: [PATCH 045/183] Make calculation for extra gas on "send*" RPC (#70) * Make calculation for extra gas on "send*" RPC * Fix for the calculation when little overstep --- RpcWallet/RpcWallet.cs | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/RpcWallet/RpcWallet.cs b/RpcWallet/RpcWallet.cs index 6c33f92b1..ff9e91cb8 100644 --- a/RpcWallet/RpcWallet.cs +++ b/RpcWallet/RpcWallet.cs @@ -1,4 +1,4 @@ -using Akka.Actor; +using Akka.Actor; using Microsoft.AspNetCore.Http; using Neo.IO; using Neo.IO.Json; @@ -307,6 +307,19 @@ private JObject SendFrom(UIntBase assetId, UInt160 from, UInt160 to, string valu ScriptHash = to } }, from: from, change_address: change_address, fee: fee); + if (tx.Size > 1024) + { + fee += Fixed8.FromDecimal(tx.Size * 0.00001m + 0.001m); + tx = Wallet.MakeTransaction(null, new[] + { + new TransferOutput + { + AssetId = assetId, + Value = amount, + ScriptHash = to + } + }, from: from, change_address: change_address, fee: fee); + } if (tx == null) throw new RpcException(-300, "Insufficient funds"); return SignAndRelay(tx); @@ -334,6 +347,11 @@ private JObject SendMany(UInt160 from, JArray to, Fixed8 fee, UInt160 change_add if (fee < Fixed8.Zero) throw new RpcException(-32602, "Invalid params"); Transaction tx = Wallet.MakeTransaction(null, outputs, from: from, change_address: change_address, fee: fee); + if (tx.Size > 1024) + { + fee += Fixed8.FromDecimal(tx.Size * 0.00001m + 0.001m); + tx = Wallet.MakeTransaction(null, outputs, from: from, change_address: change_address, fee: fee); + } if (tx == null) throw new RpcException(-300, "Insufficient funds"); return SignAndRelay(tx); @@ -357,6 +375,19 @@ private JObject SendToAddress(UIntBase assetId, UInt160 scriptHash, string value ScriptHash = scriptHash } }, change_address: change_address, fee: fee); + if (tx.Size > 1024) + { + fee += Fixed8.FromDecimal(tx.Size * 0.00001m + 0.001m); + tx = Wallet.MakeTransaction(null, new[] + { + new TransferOutput + { + AssetId = assetId, + Value = amount, + ScriptHash = scriptHash + } + }, change_address: change_address, fee: fee); + } if (tx == null) throw new RpcException(-300, "Insufficient funds"); return SignAndRelay(tx); From 6449d7c969b8449e6956289d5a80e09d2f01fc41 Mon Sep 17 00:00:00 2001 From: Owen Zhang <38493437+superboyiii@users.noreply.github.com> Date: Mon, 1 Apr 2019 16:41:35 +0800 Subject: [PATCH 046/183] Add Max_Fee as the optional for gas limit. (#74) * Make calculation for extra gas on "send*" RPC (#70) * Make calculation for extra gas on "send*" RPC * Fix for the calculation when little overstep * Delete the dependency which is for testing purpose * Choose the max_fee between fee and extra_fee * Change error codes * Update Settings.cs * format --- RpcWallet/RpcWallet.cs | 13 ++++++++++--- RpcWallet/RpcWallet.csproj | 7 +++++++ RpcWallet/RpcWallet/config.json | 5 +++++ RpcWallet/Settings.cs | 21 +++++++++++++++++++++ 4 files changed, 43 insertions(+), 3 deletions(-) create mode 100644 RpcWallet/RpcWallet/config.json create mode 100644 RpcWallet/Settings.cs diff --git a/RpcWallet/RpcWallet.cs b/RpcWallet/RpcWallet.cs index ff9e91cb8..98bbfea80 100644 --- a/RpcWallet/RpcWallet.cs +++ b/RpcWallet/RpcWallet.cs @@ -21,6 +21,7 @@ public class RpcWallet : Plugin, IRpcPlugin public override void Configure() { + Settings.Load(GetConfiguration()); } public void PreProcess(HttpContext context, string method, JArray _params) @@ -309,7 +310,7 @@ private JObject SendFrom(UIntBase assetId, UInt160 from, UInt160 to, string valu }, from: from, change_address: change_address, fee: fee); if (tx.Size > 1024) { - fee += Fixed8.FromDecimal(tx.Size * 0.00001m + 0.001m); + fee = Fixed8.Max(Fixed8.FromDecimal(tx.Size * 0.00001m + 0.001m), fee); tx = Wallet.MakeTransaction(null, new[] { new TransferOutput @@ -322,6 +323,8 @@ private JObject SendFrom(UIntBase assetId, UInt160 from, UInt160 to, string valu } if (tx == null) throw new RpcException(-300, "Insufficient funds"); + if (fee > Settings.Default.MaxFee) + throw new RpcException(-301, "The necessary fee is more than the Max_fee, this transaction is failed. Please increase your Max_fee value."); return SignAndRelay(tx); } @@ -349,11 +352,13 @@ private JObject SendMany(UInt160 from, JArray to, Fixed8 fee, UInt160 change_add Transaction tx = Wallet.MakeTransaction(null, outputs, from: from, change_address: change_address, fee: fee); if (tx.Size > 1024) { - fee += Fixed8.FromDecimal(tx.Size * 0.00001m + 0.001m); + fee = Fixed8.Max(Fixed8.FromDecimal(tx.Size * 0.00001m + 0.001m), fee); tx = Wallet.MakeTransaction(null, outputs, from: from, change_address: change_address, fee: fee); } if (tx == null) throw new RpcException(-300, "Insufficient funds"); + if (fee > Settings.Default.MaxFee) + throw new RpcException(-301, "The necessary fee is more than the Max_fee, this transaction is failed. Please increase your Max_fee value."); return SignAndRelay(tx); } @@ -377,7 +382,7 @@ private JObject SendToAddress(UIntBase assetId, UInt160 scriptHash, string value }, change_address: change_address, fee: fee); if (tx.Size > 1024) { - fee += Fixed8.FromDecimal(tx.Size * 0.00001m + 0.001m); + fee = Fixed8.Max(Fixed8.FromDecimal(tx.Size * 0.00001m + 0.001m), fee); tx = Wallet.MakeTransaction(null, new[] { new TransferOutput @@ -390,6 +395,8 @@ private JObject SendToAddress(UIntBase assetId, UInt160 scriptHash, string value } if (tx == null) throw new RpcException(-300, "Insufficient funds"); + if (fee > Settings.Default.MaxFee) + throw new RpcException(-301, "The necessary fee is more than the Max_fee, this transaction is failed. Please increase your Max_fee value."); return SignAndRelay(tx); } } diff --git a/RpcWallet/RpcWallet.csproj b/RpcWallet/RpcWallet.csproj index a88f11518..24a002d34 100644 --- a/RpcWallet/RpcWallet.csproj +++ b/RpcWallet/RpcWallet.csproj @@ -5,6 +5,13 @@ netstandard2.0 Neo.Plugins + + + + PreserveNewest + PreserveNewest + + diff --git a/RpcWallet/RpcWallet/config.json b/RpcWallet/RpcWallet/config.json new file mode 100644 index 000000000..752d78ff9 --- /dev/null +++ b/RpcWallet/RpcWallet/config.json @@ -0,0 +1,5 @@ +{ + "PluginConfiguration": { + "MaxFee": 0.1 + } +} diff --git a/RpcWallet/Settings.cs b/RpcWallet/Settings.cs new file mode 100644 index 000000000..1e94b2224 --- /dev/null +++ b/RpcWallet/Settings.cs @@ -0,0 +1,21 @@ +using Microsoft.Extensions.Configuration; + +namespace Neo.Plugins +{ + internal class Settings + { + public Fixed8 MaxFee { get; } + + public static Settings Default { get; private set; } + + private Settings(IConfigurationSection section) + { + this.MaxFee = Fixed8.Parse(section.GetValue("MaxFee", "0.1")); + } + + public static void Load(IConfigurationSection section) + { + Default = new Settings(section); + } + } +} From b073322db993752e9bca012cbca765f628c9b98c Mon Sep 17 00:00:00 2001 From: erikzhang Date: Tue, 2 Apr 2019 19:49:30 +0800 Subject: [PATCH 047/183] Add `NuGet.Config` --- NuGet.Config | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 NuGet.Config diff --git a/NuGet.Config b/NuGet.Config new file mode 100644 index 000000000..640fd0fe3 --- /dev/null +++ b/NuGet.Config @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file From d4fd6c87554fd6263cffd6c8f06ef1dc518acb63 Mon Sep 17 00:00:00 2001 From: Owen Zhang <38493437+superboyiii@users.noreply.github.com> Date: Thu, 4 Apr 2019 00:39:13 +0800 Subject: [PATCH 048/183] fix size calculation (#75) --- RpcWallet/RpcWallet.cs | 82 ++++++++++++++++++++++++++++-------------- 1 file changed, 56 insertions(+), 26 deletions(-) diff --git a/RpcWallet/RpcWallet.cs b/RpcWallet/RpcWallet.cs index 98bbfea80..4807fb3cc 100644 --- a/RpcWallet/RpcWallet.cs +++ b/RpcWallet/RpcWallet.cs @@ -308,21 +308,31 @@ private JObject SendFrom(UIntBase assetId, UInt160 from, UInt160 to, string valu ScriptHash = to } }, from: from, change_address: change_address, fee: fee); + if (tx == null) + throw new RpcException(-300, "Insufficient funds"); + + ContractParametersContext transContext = new ContractParametersContext(tx); + Wallet.Sign(transContext); + tx.Witnesses = transContext.GetWitnesses(); if (tx.Size > 1024) { - fee = Fixed8.Max(Fixed8.FromDecimal(tx.Size * 0.00001m + 0.001m), fee); - tx = Wallet.MakeTransaction(null, new[] + Fixed8 calFee = Fixed8.FromDecimal(tx.Size * 0.00001m + 0.001m); + if (fee < calFee) { - new TransferOutput - { - AssetId = assetId, - Value = amount, - ScriptHash = to - } - }, from: from, change_address: change_address, fee: fee); + fee = calFee; + tx = Wallet.MakeTransaction(null, new[] + { + new TransferOutput + { + AssetId = assetId, + Value = amount, + ScriptHash = to + } + }, from: from, change_address: change_address, fee: fee); + if (tx == null) + throw new RpcException(-300, "Insufficient funds"); + } } - if (tx == null) - throw new RpcException(-300, "Insufficient funds"); if (fee > Settings.Default.MaxFee) throw new RpcException(-301, "The necessary fee is more than the Max_fee, this transaction is failed. Please increase your Max_fee value."); return SignAndRelay(tx); @@ -350,13 +360,23 @@ private JObject SendMany(UInt160 from, JArray to, Fixed8 fee, UInt160 change_add if (fee < Fixed8.Zero) throw new RpcException(-32602, "Invalid params"); Transaction tx = Wallet.MakeTransaction(null, outputs, from: from, change_address: change_address, fee: fee); + if (tx == null) + throw new RpcException(-300, "Insufficient funds"); + + ContractParametersContext transContext = new ContractParametersContext(tx); + Wallet.Sign(transContext); + tx.Witnesses = transContext.GetWitnesses(); if (tx.Size > 1024) { - fee = Fixed8.Max(Fixed8.FromDecimal(tx.Size * 0.00001m + 0.001m), fee); - tx = Wallet.MakeTransaction(null, outputs, from: from, change_address: change_address, fee: fee); + Fixed8 calFee = Fixed8.FromDecimal(tx.Size * 0.00001m + 0.001m); + if (fee < calFee) + { + fee = calFee; + tx = Wallet.MakeTransaction(null, outputs, from: from, change_address: change_address, fee: fee); + if (tx == null) + throw new RpcException(-300, "Insufficient funds"); + } } - if (tx == null) - throw new RpcException(-300, "Insufficient funds"); if (fee > Settings.Default.MaxFee) throw new RpcException(-301, "The necessary fee is more than the Max_fee, this transaction is failed. Please increase your Max_fee value."); return SignAndRelay(tx); @@ -380,21 +400,31 @@ private JObject SendToAddress(UIntBase assetId, UInt160 scriptHash, string value ScriptHash = scriptHash } }, change_address: change_address, fee: fee); + if (tx == null) + throw new RpcException(-300, "Insufficient funds"); + + ContractParametersContext transContext = new ContractParametersContext(tx); + Wallet.Sign(transContext); + tx.Witnesses = transContext.GetWitnesses(); if (tx.Size > 1024) { - fee = Fixed8.Max(Fixed8.FromDecimal(tx.Size * 0.00001m + 0.001m), fee); - tx = Wallet.MakeTransaction(null, new[] + Fixed8 calFee = Fixed8.FromDecimal(tx.Size * 0.00001m + 0.001m); + if (fee < calFee) { - new TransferOutput + fee = calFee; + tx = Wallet.MakeTransaction(null, new[] { - AssetId = assetId, - Value = amount, - ScriptHash = scriptHash - } - }, change_address: change_address, fee: fee); - } - if (tx == null) - throw new RpcException(-300, "Insufficient funds"); + new TransferOutput + { + AssetId = assetId, + Value = amount, + ScriptHash = scriptHash + } + }, change_address: change_address, fee: fee); + if (tx == null) + throw new RpcException(-300, "Insufficient funds"); + } + } if (fee > Settings.Default.MaxFee) throw new RpcException(-301, "The necessary fee is more than the Max_fee, this transaction is failed. Please increase your Max_fee value."); return SignAndRelay(tx); From 1e2a3eb97dde45dc2ca603ad4f14f0dbb6be7e72 Mon Sep 17 00:00:00 2001 From: jsolman Date: Fri, 5 Apr 2019 06:03:12 -0700 Subject: [PATCH 049/183] Add Plugin for UTXO tracking by account. (#65) * Add Plugin for UTXO tracking by account. * Rename RpcSystemAssetPlugin -> RpcSystemAssetTracker. * Accept address or script hash. * Remove unnecessary white space. * Update project ref to Neo 2.10.1-CI00002. * Ensure consistency in case of crash or kill. * Fix setting lastPersistedBlock after each block is persisted. * Performance optimization: Don't write block number for empty blocks. * Optimize. * Add support for tracking unclaimed spent outputs. * Provide getclaimable RPC call for getting available claim spent outputs. * Clean-up. * Don't leak memory. * Implement getclaimable to get get total unclaimed amount for an address. * Remove unnecessary comment. * Fix size of UserSystemAssetCoinOutputs. Remove unused using statement. * Reload max utxo's from configuration if it changes. * Upgrade dependency --- .../RpcSystemAssetTracker.csproj | 17 + .../RpcSystemAssetTracker/config.json | 7 + .../RpcSystemAssetTrackerPlugin.cs | 426 ++++++++++++++++++ .../UserSystemAssetCoinOutputs.cs | 79 ++++ .../UserSystemAssetCoinOutputsKey.cs | 81 ++++ 5 files changed, 610 insertions(+) create mode 100644 RpcSystemAssetTracker/RpcSystemAssetTracker.csproj create mode 100644 RpcSystemAssetTracker/RpcSystemAssetTracker/config.json create mode 100644 RpcSystemAssetTracker/RpcSystemAssetTrackerPlugin.cs create mode 100644 RpcSystemAssetTracker/UserSystemAssetCoinOutputs.cs create mode 100644 RpcSystemAssetTracker/UserSystemAssetCoinOutputsKey.cs diff --git a/RpcSystemAssetTracker/RpcSystemAssetTracker.csproj b/RpcSystemAssetTracker/RpcSystemAssetTracker.csproj new file mode 100644 index 000000000..4d03ef295 --- /dev/null +++ b/RpcSystemAssetTracker/RpcSystemAssetTracker.csproj @@ -0,0 +1,17 @@ + + + 2.10.1 + netstandard2.0 + Neo.Plugins + latest + + + + PreserveNewest + PreserveNewest + + + + + + diff --git a/RpcSystemAssetTracker/RpcSystemAssetTracker/config.json b/RpcSystemAssetTracker/RpcSystemAssetTracker/config.json new file mode 100644 index 000000000..214c08939 --- /dev/null +++ b/RpcSystemAssetTracker/RpcSystemAssetTracker/config.json @@ -0,0 +1,7 @@ +{ + "PluginConfiguration": { + "DBPath": "SystemAssetBalanceData", + "MaxReturnedUnspents": 1000, + "TrackUnclaimed": true + } +} diff --git a/RpcSystemAssetTracker/RpcSystemAssetTrackerPlugin.cs b/RpcSystemAssetTracker/RpcSystemAssetTrackerPlugin.cs new file mode 100644 index 000000000..076bb4f6a --- /dev/null +++ b/RpcSystemAssetTracker/RpcSystemAssetTrackerPlugin.cs @@ -0,0 +1,426 @@ +using Microsoft.AspNetCore.Http; +using Neo.IO.Caching; +using Neo.IO.Data.LevelDB; +using Neo.IO.Json; +using Neo.Network.P2P.Payloads; +using Neo.Persistence.LevelDB; +using Neo.Wallets; +using System; +using System.Collections.Generic; +using System.Linq; +using Neo.Ledger; +using Neo.Persistence; +using Snapshot = Neo.Persistence.Snapshot; + +namespace Neo.Plugins +{ + public class RpcSystemAssetTrackerPlugin : Plugin, IPersistencePlugin, IRpcPlugin + { + private const byte SystemAssetUnspentCoinsPrefix = 0xfb; + private const byte SystemAssetSpentUnclaimedCoinsPrefix = 0xfc; + private DB _db; + private DataCache _userUnspentCoins; + private bool _shouldTrackUnclaimed; + private DataCache _userSpentUnclaimedCoins; + private WriteBatch _writeBatch; + private int _rpcMaxUnspents; + private uint _lastPersistedBlock; + private bool _shouldPersistBlock; + private Neo.IO.Data.LevelDB.Snapshot _levelDbSnapshot; + + public override void Configure() + { + if (_db == null) + { + var dbPath = GetConfiguration().GetSection("DBPath").Value ?? "SystemAssetBalanceData"; + _db = DB.Open(dbPath, new Options { CreateIfMissing = true }); + _shouldTrackUnclaimed = (GetConfiguration().GetSection("TrackUnclaimed").Value ?? true.ToString()) != false.ToString(); + try + { + _lastPersistedBlock = _db.Get(ReadOptions.Default, SystemAssetUnspentCoinsPrefix).ToUInt32(); + } + catch (LevelDBException ex) + { + if (!ex.Message.Contains("not found")) + throw; + _lastPersistedBlock = 0; + } + } + _rpcMaxUnspents = int.Parse(GetConfiguration().GetSection("MaxReturnedUnspents").Value ?? "0"); + } + + private void ResetBatch() + { + _writeBatch = new WriteBatch(); + _levelDbSnapshot?.Dispose(); + _levelDbSnapshot = _db.GetSnapshot(); + var dbOptions = new ReadOptions { FillCache = false, Snapshot = _levelDbSnapshot }; + _userUnspentCoins = new DbCache(_db, dbOptions, + _writeBatch, SystemAssetUnspentCoinsPrefix); + if (!_shouldTrackUnclaimed) return; + _userSpentUnclaimedCoins = new DbCache(_db, dbOptions, + _writeBatch, SystemAssetSpentUnclaimedCoinsPrefix); + } + + private bool ProcessBlock(Snapshot snapshot, Block block) + { + if (block.Transactions.Length <= 1) + { + _lastPersistedBlock = block.Index; + return false; + } + + ResetBatch(); + + var transactionsCache = snapshot.Transactions; + foreach (Transaction tx in block.Transactions) + { + ushort outputIndex = 0; + foreach (TransactionOutput output in tx.Outputs) + { + bool isGoverningToken = output.AssetId.Equals(Blockchain.GoverningToken.Hash); + if (isGoverningToken || output.AssetId.Equals(Blockchain.UtilityToken.Hash)) + { + // Add new unspent UTXOs by account script hash. + UserSystemAssetCoinOutputs outputs = _userUnspentCoins.GetAndChange( + new UserSystemAssetCoinOutputsKey(isGoverningToken, output.ScriptHash, tx.Hash), + () => new UserSystemAssetCoinOutputs()); + outputs.AddTxIndex(outputIndex, output.Value); + } + outputIndex++; + } + + // Iterate all input Transactions by grouping by common input hashes. + foreach (var group in tx.Inputs.GroupBy(p => p.PrevHash)) + { + TransactionState txPrev = transactionsCache[group.Key]; + // For each input being spent by this transaction. + foreach (CoinReference input in group) + { + // Get the output from the the previous transaction that is now being spent. + var outPrev = txPrev.Transaction.Outputs[input.PrevIndex]; + + bool isGoverningToken = outPrev.AssetId.Equals(Blockchain.GoverningToken.Hash); + if (isGoverningToken || outPrev.AssetId.Equals(Blockchain.UtilityToken.Hash)) + { + // Remove spent UTXOs for unspent outputs by account script hash. + var userCoinOutputsKey = + new UserSystemAssetCoinOutputsKey(isGoverningToken, outPrev.ScriptHash, input.PrevHash); + UserSystemAssetCoinOutputs outputs = _userUnspentCoins.GetAndChange( + userCoinOutputsKey, () => new UserSystemAssetCoinOutputs()); + outputs.RemoveTxIndex(input.PrevIndex); + if (outputs.AmountByTxIndex.Count == 0) + _userUnspentCoins.Delete(userCoinOutputsKey); + + if (_shouldTrackUnclaimed && isGoverningToken) + { + UserSystemAssetCoinOutputs spentUnclaimedOutputs = _userSpentUnclaimedCoins.GetAndChange( + userCoinOutputsKey, () => new UserSystemAssetCoinOutputs()); + spentUnclaimedOutputs.AddTxIndex(input.PrevIndex, outPrev.Value); + } + } + } + } + + if (_shouldTrackUnclaimed && tx is ClaimTransaction claimTransaction) + { + foreach (CoinReference input in claimTransaction.Claims) + { + TransactionState txPrev = transactionsCache[input.PrevHash]; + var outPrev = txPrev.Transaction.Outputs[input.PrevIndex]; + + var claimedCoinKey = + new UserSystemAssetCoinOutputsKey(true, outPrev.ScriptHash, input.PrevHash); + UserSystemAssetCoinOutputs spentUnclaimedOutputs = _userSpentUnclaimedCoins.GetAndChange( + claimedCoinKey, () => new UserSystemAssetCoinOutputs()); + spentUnclaimedOutputs.RemoveTxIndex(input.PrevIndex); + if (spentUnclaimedOutputs.AmountByTxIndex.Count == 0) + _userSpentUnclaimedCoins.Delete(claimedCoinKey); + + if (snapshot.SpentCoins.TryGet(input.PrevHash)?.Items.Remove(input.PrevIndex) == true) + snapshot.SpentCoins.GetAndChange(input.PrevHash); + } + } + } + + // Write the current height into the key of the prefix itself + _writeBatch.Put(SystemAssetUnspentCoinsPrefix, block.Index); + _lastPersistedBlock = block.Index; + return true; + } + + + private void ProcessSkippedBlocks(Snapshot snapshot) + { + for (uint blockIndex = _lastPersistedBlock + 1; blockIndex < snapshot.PersistingBlock.Index; blockIndex++) + { + var skippedBlock = Blockchain.Singleton.Store.GetBlock(blockIndex); + if (skippedBlock.Transactions.Length <= 1) + { + _lastPersistedBlock = skippedBlock.Index; + continue; + } + + _shouldPersistBlock = ProcessBlock(snapshot, skippedBlock); + OnCommit(snapshot); + } + } + + public void OnPersist(Snapshot snapshot, IReadOnlyList applicationExecutedList) + { + if (snapshot.PersistingBlock.Index > _lastPersistedBlock + 1) + ProcessSkippedBlocks(snapshot); + + _shouldPersistBlock = ProcessBlock(snapshot, snapshot.PersistingBlock); + } + + public void OnCommit(Snapshot snapshot) + { + if (!_shouldPersistBlock) return; + _userUnspentCoins.Commit(); + if (_shouldTrackUnclaimed) _userSpentUnclaimedCoins.Commit(); + _db.Write(WriteOptions.Default, _writeBatch); + } + + public bool ShouldThrowExceptionFromCommit(Exception ex) + { + return true; + } + + public void PreProcess(HttpContext context, string method, JArray _params) + { + } + + private UInt160 GetScriptHashFromParam(string addressOrScriptHash) + { + return addressOrScriptHash.Length < 40 ? + addressOrScriptHash.ToScriptHash() : UInt160.Parse(addressOrScriptHash); + } + + + private long GetSysFeeAmountForHeight(DataCache blocks, uint height) + { + return blocks.TryGet(Blockchain.Singleton.GetBlockHash(height)).SystemFeeAmount; + } + + private void CalculateClaimable(Snapshot snapshot, Fixed8 value, uint startHeight, uint endHeight, out Fixed8 generated, out Fixed8 sysFee) + { + uint amount = 0; + uint ustart = startHeight / Blockchain.DecrementInterval; + if (ustart < Blockchain.GenerationAmount.Length) + { + uint istart = startHeight % Blockchain.DecrementInterval; + uint uend = endHeight / Blockchain.DecrementInterval; + uint iend = endHeight % Blockchain.DecrementInterval; + if (uend >= Blockchain.GenerationAmount.Length) + { + uend = (uint)Blockchain.GenerationAmount.Length; + iend = 0; + } + if (iend == 0) + { + uend--; + iend = Blockchain.DecrementInterval; + } + while (ustart < uend) + { + amount += (Blockchain.DecrementInterval - istart) * Blockchain.GenerationAmount[ustart]; + ustart++; + istart = 0; + } + amount += (iend - istart) * Blockchain.GenerationAmount[ustart]; + } + + Fixed8 fractionalShare = value / 100000000; + generated = fractionalShare * amount; + sysFee = fractionalShare * (GetSysFeeAmountForHeight(snapshot.Blocks, endHeight - 1) - + (startHeight == 0 ? 0 : GetSysFeeAmountForHeight(snapshot.Blocks, startHeight - 1))); + } + + private bool AddClaims(JArray claimableOutput, ref Fixed8 runningTotal, int maxClaims, + Snapshot snapshot, DataCache storeSpentCoins, + KeyValuePair claimableInTx) + { + foreach (var claimTransaction in claimableInTx.Value.AmountByTxIndex) + { + var utxo = new JObject(); + var txId = claimableInTx.Key.TxHash.ToString().Substring(2); + utxo["txid"] = txId; + utxo["n"] = claimTransaction.Key; + var spentCoinState = storeSpentCoins.TryGet(claimableInTx.Key.TxHash); + var startHeight = spentCoinState.TransactionHeight; + var endHeight = spentCoinState.Items[claimTransaction.Key]; + CalculateClaimable(snapshot, claimTransaction.Value, startHeight, endHeight, out var generated, + out var sysFee); + var unclaimed = generated + sysFee; + utxo["value"] = (double) (decimal) claimTransaction.Value; + utxo["start_height"] = startHeight; + utxo["end_height"] = endHeight; + utxo["generated"] = (double) (decimal) generated; + utxo["sys_fee"] = (double) (decimal) sysFee; + utxo["unclaimed"] = (double) (decimal) unclaimed; + runningTotal += unclaimed; + claimableOutput.Add(utxo); + if (claimableOutput.Count > maxClaims) + return false; + } + + return true; + } + + private JObject ProcessGetClaimableSpents(JArray parameters) + { + UInt160 scriptHash = GetScriptHashFromParam(parameters[0].AsString()); + var dbCache = new DbCache( + _db, null, null, SystemAssetSpentUnclaimedCoinsPrefix); + + JObject json = new JObject(); + JArray claimable = new JArray(); + json["claimable"] = claimable; + json["address"] = scriptHash.ToAddress(); + + Fixed8 totalUnclaimed = Fixed8.Zero; + using (Snapshot snapshot = Blockchain.Singleton.GetSnapshot()) + { + var storeSpentCoins = snapshot.SpentCoins; + byte[] prefix = new [] { (byte) 1 }.Concat(scriptHash.ToArray()).ToArray(); + foreach (var claimableInTx in dbCache.Find(prefix)) + if (!AddClaims(claimable, ref totalUnclaimed, _rpcMaxUnspents, snapshot, storeSpentCoins, + claimableInTx)) + break; + } + json["unclaimed"] = (double) (decimal) totalUnclaimed; + return json; + } + + private JObject ProcessGetUnclaimed(JArray parameters) + { + UInt160 scriptHash = GetScriptHashFromParam(parameters[0].AsString()); + JObject json = new JObject(); + + Fixed8 available = Fixed8.Zero; + Fixed8 unavailable = Fixed8.Zero; + var spentsCache = new DbCache( + _db, null, null, SystemAssetSpentUnclaimedCoinsPrefix); + var unspentsCache = new DbCache( + _db, null, null, SystemAssetUnspentCoinsPrefix); + using (Snapshot snapshot = Blockchain.Singleton.GetSnapshot()) + { + var storeSpentCoins = snapshot.SpentCoins; + byte[] prefix = new [] { (byte) 1 }.Concat(scriptHash.ToArray()).ToArray(); + foreach (var claimableInTx in spentsCache.Find(prefix)) + { + var spentCoinState = storeSpentCoins.TryGet(claimableInTx.Key.TxHash); + foreach (var claimTxIndex in claimableInTx.Value.AmountByTxIndex) + { + var startHeight = spentCoinState.TransactionHeight; + var endHeight = spentCoinState.Items[claimTxIndex.Key]; + CalculateClaimable(snapshot, claimTxIndex.Value, startHeight, endHeight, out var generated, + out var sysFee); + available += generated + sysFee; + } + } + + var transactionsCache = snapshot.Transactions; + foreach (var claimableInTx in unspentsCache.Find(prefix)) + { + var transaction = transactionsCache.TryGet(claimableInTx.Key.TxHash); + + foreach (var claimTxIndex in claimableInTx.Value.AmountByTxIndex) + { + var startHeight = transaction.BlockIndex; + var endHeight = Blockchain.Singleton.Height; + CalculateClaimable(snapshot, claimTxIndex.Value, startHeight, endHeight, + out var generated, + out var sysFee); + unavailable += generated + sysFee; + } + } + } + + json["available"] = (double) (decimal) available; + json["unavailable"] = (double) (decimal) unavailable; + json["unclaimed"] = (double) (decimal) (available + unavailable); + return json; + } + + private bool AddUnspents(JArray unspents, ref Fixed8 runningTotal, + KeyValuePair unspentInTx) + { + var txId = unspentInTx.Key.TxHash.ToString().Substring(2); + foreach (var unspent in unspentInTx.Value.AmountByTxIndex) + { + var utxo = new JObject(); + utxo["txid"] = txId; + utxo["n"] = unspent.Key; + utxo["value"] = (double) (decimal) unspent.Value; + runningTotal += unspent.Value; + + unspents.Add(utxo); + if (unspents.Count > _rpcMaxUnspents) + return false; + } + return true; + } + + private JObject ProcessGetUnspents(JArray _params) + { + UInt160 scriptHash = GetScriptHashFromParam(_params[0].AsString()); + byte startingToken = 0; // 0 = Utility Token (GAS), 1 = Governing Token (NEO) + int maxIterations = 2; + + if (_params.Count > 1) + { + maxIterations = 1; + bool isGoverningToken = _params[1].AsBoolean(); + if (isGoverningToken) startingToken = 1; + } + + var unspentsCache = new DbCache( + _db, null, null, SystemAssetUnspentCoinsPrefix); + + string[] nativeAssetNames = {"GAS", "NEO"}; + UInt256[] nativeAssetIds = {Blockchain.UtilityToken.Hash, Blockchain.GoverningToken.Hash}; + + JObject json = new JObject(); + JArray balances = new JArray(); + json["balance"] = balances; + json["address"] = scriptHash.ToAddress(); + for (byte tokenIndex = startingToken; maxIterations-- > 0; tokenIndex++) + { + byte[] prefix = new [] { tokenIndex }.Concat(scriptHash.ToArray()).ToArray(); + + var unspents = new JArray(); + Fixed8 total = new Fixed8(0); + + foreach (var unspentInTx in unspentsCache.Find(prefix)) + if (!AddUnspents(unspents, ref total, unspentInTx)) break; + + if (unspents.Count <= 0) continue; + + var balance = new JObject(); + balance["unspent"] = unspents; + balance["asset_hash"] = nativeAssetIds[tokenIndex].ToString().Substring(2); + balance["asset_symbol"] = balance["asset"] = nativeAssetNames[tokenIndex]; + balance["amount"] = new JNumber((double) (decimal) total); ; + balances.Add(balance); + } + + return json; + } + + public JObject OnProcess(HttpContext context, string method, JArray parameters) + { + if (_shouldTrackUnclaimed) + { + if (method == "getclaimable") return ProcessGetClaimableSpents(parameters); + if (method == "getunclaimed") return ProcessGetUnclaimed(parameters); + } + return method != "getunspents" ? null : ProcessGetUnspents(parameters); + } + + public void PostProcess(HttpContext context, string method, JArray _params, JObject result) + { + } + } +} diff --git a/RpcSystemAssetTracker/UserSystemAssetCoinOutputs.cs b/RpcSystemAssetTracker/UserSystemAssetCoinOutputs.cs new file mode 100644 index 000000000..9d6251ea6 --- /dev/null +++ b/RpcSystemAssetTracker/UserSystemAssetCoinOutputs.cs @@ -0,0 +1,79 @@ +using System.Collections.Generic; +using System.IO; +using Neo.IO; +using Neo.Ledger; + +namespace Neo.Plugins +{ + public class UserSystemAssetCoinOutputs : StateBase, ICloneable + { + public Fixed8 TotalAmount; + public Dictionary AmountByTxIndex; + + public override int Size => base.Size + TotalAmount.Size + sizeof(ushort) + + (AmountByTxIndex.Count * (sizeof(ushort) + sizeof(ulong))); + + public UserSystemAssetCoinOutputs() + { + TotalAmount = new Fixed8(0); + AmountByTxIndex = new Dictionary(); + } + + public void AddTxIndex(ushort index, Fixed8 amount) + { + TotalAmount += amount; + AmountByTxIndex.Add(index, amount); + } + + public bool RemoveTxIndex(ushort index) + { + if(AmountByTxIndex.TryGetValue(index, out Fixed8 amount)) + { + AmountByTxIndex.Remove(index); + TotalAmount -= amount; + return true; + } + + return false; + } + public UserSystemAssetCoinOutputs Clone() + { + return new UserSystemAssetCoinOutputs() + { + TotalAmount = TotalAmount, + AmountByTxIndex = new Dictionary(AmountByTxIndex) + }; + } + + public void FromReplica(UserSystemAssetCoinOutputs replica) + { + TotalAmount = replica.TotalAmount; + AmountByTxIndex = replica.AmountByTxIndex; + } + + public override void Serialize(BinaryWriter writer) + { + base.Serialize(writer); + writer.Write(TotalAmount); + writer.Write((ushort)AmountByTxIndex.Count); + foreach (KeyValuePair txIndex in AmountByTxIndex) + { + writer.Write(txIndex.Key); + writer.Write(txIndex.Value); + } + } + + public override void Deserialize(BinaryReader reader) + { + base.Deserialize(reader); + ((ISerializable)TotalAmount).Deserialize(reader); + ushort count = reader.ReadUInt16(); + for (int i = 0; i < count; i++) + { + ushort txIndex = reader.ReadUInt16(); + Fixed8 amount = reader.ReadSerializable(); + AmountByTxIndex.Add(txIndex, amount); + } + } + } +} \ No newline at end of file diff --git a/RpcSystemAssetTracker/UserSystemAssetCoinOutputsKey.cs b/RpcSystemAssetTracker/UserSystemAssetCoinOutputsKey.cs new file mode 100644 index 000000000..7f0cad859 --- /dev/null +++ b/RpcSystemAssetTracker/UserSystemAssetCoinOutputsKey.cs @@ -0,0 +1,81 @@ +using System; +using System.Collections.Generic; +using System.IO; +using Neo.IO; + +namespace Neo.Plugins +{ + public class UserSystemAssetCoinOutputsKey : IComparable, IEquatable, + ISerializable + { + public bool IsGoverningToken; // It's either the governing token or the utility token + public readonly UInt160 UserAddress; + public readonly UInt256 TxHash; + + public int Size => 1 + UserAddress.Size + TxHash.Size; + + public bool Equals(UserSystemAssetCoinOutputsKey other) + { + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; + return IsGoverningToken == other.IsGoverningToken && Equals(UserAddress, other.UserAddress) && Equals(TxHash, other.TxHash); + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != this.GetType()) return false; + return Equals((UserSystemAssetCoinOutputsKey) obj); + } + + public int CompareTo(UserSystemAssetCoinOutputsKey other) + { + if (ReferenceEquals(this, other)) return 0; + if (ReferenceEquals(null, other)) return 1; + var isGoverningTokenComparison = IsGoverningToken.CompareTo(other.IsGoverningToken); + if (isGoverningTokenComparison != 0) return isGoverningTokenComparison; + var userAddressComparison = Comparer.Default.Compare(UserAddress, other.UserAddress); + if (userAddressComparison != 0) return userAddressComparison; + return Comparer.Default.Compare(TxHash, other.TxHash); + } + + public override int GetHashCode() + { + unchecked + { + var hashCode = IsGoverningToken.GetHashCode(); + hashCode = (hashCode * 397) ^ (UserAddress != null ? UserAddress.GetHashCode() : 0); + hashCode = (hashCode * 397) ^ (TxHash != null ? TxHash.GetHashCode() : 0); + return hashCode; + } + } + + public UserSystemAssetCoinOutputsKey() + { + UserAddress = new UInt160(); + TxHash = new UInt256(); + } + + public UserSystemAssetCoinOutputsKey(bool isGoverningToken, UInt160 userAddress, UInt256 txHash) + { + IsGoverningToken = isGoverningToken; + UserAddress = userAddress; + TxHash = txHash; + } + + public void Serialize(BinaryWriter writer) + { + writer.Write(IsGoverningToken); + writer.Write(UserAddress.ToArray()); + writer.Write(TxHash.ToArray()); + } + + public void Deserialize(BinaryReader reader) + { + IsGoverningToken = reader.ReadBoolean(); + ((ISerializable) UserAddress).Deserialize(reader); + ((ISerializable) TxHash).Deserialize(reader); + } + } +} \ No newline at end of file From 05b573f715b4a1f2e9cac5d5475620b2a3f0c6db Mon Sep 17 00:00:00 2001 From: erikzhang Date: Fri, 5 Apr 2019 21:35:04 +0800 Subject: [PATCH 050/183] Fix .sln for #65 --- neo-plugins.sln | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/neo-plugins.sln b/neo-plugins.sln index 08db236ee..4c1f919f6 100644 --- a/neo-plugins.sln +++ b/neo-plugins.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.27428.2027 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.28729.10 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SimplePolicy", "SimplePolicy\SimplePolicy.csproj", "{322C366E-F891-47FD-A039-0FEF79BCB6D5}" EndProject @@ -21,6 +21,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RpcNep5Tracker", "RpcNep5Tr EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CoreMetrics", "CoreMetrics\CoreMetrics.csproj", "{AEFFF003-3500-416B-AD9B-8C838C33C1F4}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RpcSystemAssetTracker", "RpcSystemAssetTracker\RpcSystemAssetTracker.csproj", "{D3C183C1-8C23-4566-8909-EBF468DAD67A}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -62,6 +64,10 @@ Global {AEFFF003-3500-416B-AD9B-8C838C33C1F4}.Debug|Any CPU.Build.0 = Debug|Any CPU {AEFFF003-3500-416B-AD9B-8C838C33C1F4}.Release|Any CPU.ActiveCfg = Release|Any CPU {AEFFF003-3500-416B-AD9B-8C838C33C1F4}.Release|Any CPU.Build.0 = Release|Any CPU + {D3C183C1-8C23-4566-8909-EBF468DAD67A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D3C183C1-8C23-4566-8909-EBF468DAD67A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D3C183C1-8C23-4566-8909-EBF468DAD67A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D3C183C1-8C23-4566-8909-EBF468DAD67A}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From 325a12ffc60ae0b02dc8a9e30f9769bc18d1167a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vitor=20Naz=C3=A1rio=20Coelho?= Date: Fri, 5 Apr 2019 13:48:15 -0300 Subject: [PATCH 051/183] Updating Readme information (#76) --- README.md | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 2d2f7194d..4b5a3170f 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,9 @@ ## What is it -A set of plugins that can be used inside the Neo core library. Check [here](http://docs.neo.org/en-us/node/plugin.html) for the official documentation. +A set of plugins that can be used inside the NEO core library. Check [here](http://docs.neo.org/en-us/node/plugin.html) for the official documentation. ## Using plugins -Plugins can be used to increase functionality in neo. One common example is to add the ApplicationLogs plugin in order to enable your node to create log files. +Plugins can be used to increase functionality, as well as providing policies definitions of the network. +One common example is to add the ApplicationLogs plugin in order to enable your node to create log files. To configure a plugin, do the following: - Download the desired plugin from the [Releases page](https://github.com/neo-project/neo-plugins/releases) @@ -26,14 +27,23 @@ The resulting folder structure is going to be like this: ### Application Logs Add this plugin to your application if need to access the log files. This can be useful to handle notifications, but remember that this also largely increases the space used by the application. +### Core Metrics +Metrics from the Blockchain. This can involve reports through RPC calls or other form of persisting. + ### Import Blocks Synchronizes the client using offline packages. Follow the instructions [here](http://docs.neo.org/en-us/network/syncblocks.html) to bootstrap your network using this plugin. +### RPC NEP5 Tracker +Plugin that enables NEP5 tracking using LevelDB. + ### RPC Security Improves security in RPC nodes. +### RPC System Asset Tracker +Plugin that enables Assets tracker. In particular, it enables RPC calls for `getunpents` and `claimables`. + ### Simple Policy -Enables policies for consensus. +Enables policies for Consensus or Seed Nodes. In particular, policies for accepting transactions in the mempool and managing them. ### StatesDumper Exports NEO-CLI status data \(useful for debugging\). From 5dfd53c7daecc3c316f4654bff9bf47314e43408 Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Sun, 7 Apr 2019 16:00:48 +0800 Subject: [PATCH 052/183] Fixes `ImportBlocks` for Neo 2.10.1 (#78) --- ImportBlocks/ImportBlocks.cs | 7 +------ ImportBlocks/ImportBlocks.csproj | 4 ++-- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/ImportBlocks/ImportBlocks.cs b/ImportBlocks/ImportBlocks.cs index 31c38b606..8b5f00aa8 100644 --- a/ImportBlocks/ImportBlocks.cs +++ b/ImportBlocks/ImportBlocks.cs @@ -14,11 +14,6 @@ namespace Neo.Plugins { public class ImportBlocks : Plugin { - public ImportBlocks() - { - OnImport(); - } - private static bool CheckMaxOnImportHeight(uint currentImportBlockHeight) { if (Settings.Default.MaxOnImportHeight == 0 || Settings.Default.MaxOnImportHeight >= currentImportBlockHeight) @@ -138,7 +133,7 @@ private bool OnHelp(string[] args) return true; } - private async void OnImport() + protected override async void OnPluginsLoaded() { SuspendNodeStartup(); const string path_acc = "chain.acc"; diff --git a/ImportBlocks/ImportBlocks.csproj b/ImportBlocks/ImportBlocks.csproj index 174fe8e08..d064bfbb7 100644 --- a/ImportBlocks/ImportBlocks.csproj +++ b/ImportBlocks/ImportBlocks.csproj @@ -1,7 +1,7 @@  - 2.10.0 + 2.10.1 netstandard2.0 Neo.Plugins @@ -14,7 +14,7 @@ - + From 9875883c33626ab6b92bf14064e5c0dc463876a2 Mon Sep 17 00:00:00 2001 From: erikzhang Date: Sun, 7 Apr 2019 16:06:59 +0800 Subject: [PATCH 053/183] v2.10.1 --- ApplicationLogs/ApplicationLogs.csproj | 4 ++-- CoreMetrics/CoreMetrics.csproj | 4 ++-- RpcNep5Tracker/RpcNep5Tracker.csproj | 4 ++-- RpcSecurity/RpcSecurity.csproj | 4 ++-- RpcWallet/RpcWallet.csproj | 4 ++-- SimplePolicy/SimplePolicy.csproj | 4 ++-- StatesDumper/StatesDumper.csproj | 4 ++-- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/ApplicationLogs/ApplicationLogs.csproj b/ApplicationLogs/ApplicationLogs.csproj index d8d5f27bb..bdd93b725 100644 --- a/ApplicationLogs/ApplicationLogs.csproj +++ b/ApplicationLogs/ApplicationLogs.csproj @@ -1,7 +1,7 @@  - 2.10.0 + 2.10.1 netstandard2.0 Neo.Plugins @@ -14,7 +14,7 @@ - + diff --git a/CoreMetrics/CoreMetrics.csproj b/CoreMetrics/CoreMetrics.csproj index a88f11518..51bfdcb43 100644 --- a/CoreMetrics/CoreMetrics.csproj +++ b/CoreMetrics/CoreMetrics.csproj @@ -1,13 +1,13 @@  - 2.10.0 + 2.10.1 netstandard2.0 Neo.Plugins - + diff --git a/RpcNep5Tracker/RpcNep5Tracker.csproj b/RpcNep5Tracker/RpcNep5Tracker.csproj index 39f8c5674..89dcb4d13 100644 --- a/RpcNep5Tracker/RpcNep5Tracker.csproj +++ b/RpcNep5Tracker/RpcNep5Tracker.csproj @@ -1,6 +1,6 @@  - 2.10.0 + 2.10.1 netstandard2.0 Neo.Plugins latest @@ -12,6 +12,6 @@ - + diff --git a/RpcSecurity/RpcSecurity.csproj b/RpcSecurity/RpcSecurity.csproj index 5ae23ce07..6cdef86c2 100644 --- a/RpcSecurity/RpcSecurity.csproj +++ b/RpcSecurity/RpcSecurity.csproj @@ -1,7 +1,7 @@  - 2.10.0 + 2.10.1 netstandard2.0 Neo.Plugins @@ -14,7 +14,7 @@ - + diff --git a/RpcWallet/RpcWallet.csproj b/RpcWallet/RpcWallet.csproj index 24a002d34..db6f412f7 100644 --- a/RpcWallet/RpcWallet.csproj +++ b/RpcWallet/RpcWallet.csproj @@ -1,7 +1,7 @@  - 2.10.0 + 2.10.1 netstandard2.0 Neo.Plugins @@ -14,7 +14,7 @@ - + diff --git a/SimplePolicy/SimplePolicy.csproj b/SimplePolicy/SimplePolicy.csproj index 6d1be1a01..bbff08a06 100644 --- a/SimplePolicy/SimplePolicy.csproj +++ b/SimplePolicy/SimplePolicy.csproj @@ -1,7 +1,7 @@  - 2.10.0 + 2.10.1 netstandard2.0 Neo.Plugins latest @@ -15,7 +15,7 @@ - + diff --git a/StatesDumper/StatesDumper.csproj b/StatesDumper/StatesDumper.csproj index bda2c6ec0..a251b4407 100644 --- a/StatesDumper/StatesDumper.csproj +++ b/StatesDumper/StatesDumper.csproj @@ -1,7 +1,7 @@  - 2.10.0 + 2.10.1 netstandard2.0 Neo.Plugins @@ -14,7 +14,7 @@ - + From b3d49a0990aa0d988f4c70af029c703c18c49a48 Mon Sep 17 00:00:00 2001 From: jsolman Date: Sun, 7 Apr 2019 12:54:09 -0700 Subject: [PATCH 054/183] Properly stop importing blocks on system shutdown. (#66) --- ImportBlocks/BlockImporter.cs | 129 ++++++++++++++++++++++++++++++++++ ImportBlocks/ImportBlocks.cs | 83 +++------------------- 2 files changed, 139 insertions(+), 73 deletions(-) create mode 100644 ImportBlocks/BlockImporter.cs diff --git a/ImportBlocks/BlockImporter.cs b/ImportBlocks/BlockImporter.cs new file mode 100644 index 000000000..8d5249c20 --- /dev/null +++ b/ImportBlocks/BlockImporter.cs @@ -0,0 +1,129 @@ +using Akka.Actor; +using Neo.IO; +using Neo.Ledger; +using Neo.Network.P2P.Payloads; +using System; +using System.Collections.Generic; +using System.IO; +using System.IO.Compression; +using System.Linq; +using System.Text.RegularExpressions; + +namespace Neo.Plugins +{ + public class BlockImporter : UntypedActor + { + public class StartImport { public IActorRef BlockchainActorRef; public Action OnComplete; } + + private const int BlocksPerBatch = 10; + private IActorRef _blockchainActorRef; + private bool isImporting; + private IEnumerator blocksBeingImported; + private Action _doneAction; + + private static bool CheckMaxOnImportHeight(uint currentImportBlockHeight) + { + if (Settings.Default.MaxOnImportHeight == 0 || Settings.Default.MaxOnImportHeight >= currentImportBlockHeight) + return true; + return false; + } + + private static IEnumerable GetBlocks(Stream stream, bool read_start = false) + { + using (BinaryReader r = new BinaryReader(stream)) + { + uint start = read_start ? r.ReadUInt32() : 0; + uint count = r.ReadUInt32(); + uint end = start + count - 1; + if (end <= Blockchain.Singleton.Height) yield break; + for (uint height = start; height <= end; height++) + { + byte[] array = r.ReadBytes(r.ReadInt32()); + if (!CheckMaxOnImportHeight(height)) yield break; + if (height > Blockchain.Singleton.Height) + { + Block block = array.AsSerializable(); + yield return block; + } + } + } + } + + private IEnumerable GetBlocksFromFile() + { + const string pathAcc = "chain.acc"; + if (File.Exists(pathAcc)) + using (FileStream fs = new FileStream(pathAcc, FileMode.Open, FileAccess.Read, FileShare.Read)) + foreach (var block in GetBlocks(fs)) + yield return block; + + const string pathAccZip = pathAcc + ".zip"; + if (File.Exists(pathAccZip)) + using (FileStream fs = new FileStream(pathAccZip, FileMode.Open, FileAccess.Read, FileShare.Read)) + using (ZipArchive zip = new ZipArchive(fs, ZipArchiveMode.Read)) + using (Stream zs = zip.GetEntry(pathAcc).Open()) + foreach (var block in GetBlocks(zs)) + yield return block; + + var paths = Directory.EnumerateFiles(".", "chain.*.acc", SearchOption.TopDirectoryOnly).Concat(Directory.EnumerateFiles(".", "chain.*.acc.zip", SearchOption.TopDirectoryOnly)).Select(p => new + { + FileName = Path.GetFileName(p), + Start = uint.Parse(Regex.Match(p, @"\d+").Value), + IsCompressed = p.EndsWith(".zip") + }).OrderBy(p => p.Start); + + foreach (var path in paths) + { + if (path.Start > Blockchain.Singleton.Height + 1) break; + if (path.IsCompressed) + using (FileStream fs = new FileStream(path.FileName, FileMode.Open, FileAccess.Read, FileShare.Read)) + using (ZipArchive zip = new ZipArchive(fs, ZipArchiveMode.Read)) + using (Stream zs = zip.GetEntry(Path.GetFileNameWithoutExtension(path.FileName)).Open()) + foreach (var block in GetBlocks(zs, true)) + yield return block; + else + using (FileStream fs = new FileStream(path.FileName, FileMode.Open, FileAccess.Read, FileShare.Read)) + foreach (var block in GetBlocks(fs, true)) + yield return block; + } + } + + protected override void OnReceive(object message) + { + switch (message) + { + case StartImport startImport: + if (isImporting) return; + isImporting = true; + _blockchainActorRef = startImport.BlockchainActorRef; + _doneAction = startImport.OnComplete; + blocksBeingImported = GetBlocksFromFile().GetEnumerator(); + // Start the first import + Self.Tell(new Blockchain.ImportCompleted()); + break; + case Blockchain.ImportCompleted _: + // Import the next batch + List blocksToImport = new List(); + for (int i = 0; i < BlocksPerBatch; i++) + { + if (!blocksBeingImported.MoveNext()) + break; + blocksToImport.Add(blocksBeingImported.Current); + } + if (blocksToImport.Count > 0) + _blockchainActorRef.Tell(new Blockchain.Import { Blocks = blocksToImport }); + else + { + blocksBeingImported.Dispose(); + _doneAction(); + } + break; + } + } + + public static Props Props() + { + return Akka.Actor.Props.Create(() => new BlockImporter()); + } + } +} diff --git a/ImportBlocks/ImportBlocks.cs b/ImportBlocks/ImportBlocks.cs index 8b5f00aa8..8c7d37cd6 100644 --- a/ImportBlocks/ImportBlocks.cs +++ b/ImportBlocks/ImportBlocks.cs @@ -4,49 +4,19 @@ using Neo.Network.P2P.Payloads; using Neo.Persistence; using System; -using System.Collections.Generic; using System.IO; -using System.IO.Compression; -using System.Linq; -using System.Text.RegularExpressions; namespace Neo.Plugins { public class ImportBlocks : Plugin { - private static bool CheckMaxOnImportHeight(uint currentImportBlockHeight) - { - if (Settings.Default.MaxOnImportHeight == 0 || Settings.Default.MaxOnImportHeight >= currentImportBlockHeight) - return true; - return false; - } + private IActorRef _blockImporter; public override void Configure() { Settings.Load(GetConfiguration()); } - private static IEnumerable GetBlocks(Stream stream, bool read_start = false) - { - using (BinaryReader r = new BinaryReader(stream)) - { - uint start = read_start ? r.ReadUInt32() : 0; - uint count = r.ReadUInt32(); - uint end = start + count - 1; - if (end <= Blockchain.Singleton.Height) yield break; - for (uint height = start; height <= end; height++) - { - byte[] array = r.ReadBytes(r.ReadInt32()); - if (!CheckMaxOnImportHeight(height)) yield break; - if (height > Blockchain.Singleton.Height) - { - Block block = array.AsSerializable(); - yield return block; - } - } - } - } - private bool OnExport(string[] args) { if (args.Length < 2) return false; @@ -133,50 +103,17 @@ private bool OnHelp(string[] args) return true; } - protected override async void OnPluginsLoaded() + private void OnImportComplete() { - SuspendNodeStartup(); - const string path_acc = "chain.acc"; - if (File.Exists(path_acc)) - using (FileStream fs = new FileStream(path_acc, FileMode.Open, FileAccess.Read, FileShare.Read)) - await System.Blockchain.Ask(new Blockchain.Import - { - Blocks = GetBlocks(fs) - }); - const string path_acc_zip = path_acc + ".zip"; - if (File.Exists(path_acc_zip)) - using (FileStream fs = new FileStream(path_acc_zip, FileMode.Open, FileAccess.Read, FileShare.Read)) - using (ZipArchive zip = new ZipArchive(fs, ZipArchiveMode.Read)) - using (Stream zs = zip.GetEntry(path_acc).Open()) - await System.Blockchain.Ask(new Blockchain.Import - { - Blocks = GetBlocks(zs) - }); - var paths = Directory.EnumerateFiles(".", "chain.*.acc", SearchOption.TopDirectoryOnly).Concat(Directory.EnumerateFiles(".", "chain.*.acc.zip", SearchOption.TopDirectoryOnly)).Select(p => new - { - FileName = Path.GetFileName(p), - Start = uint.Parse(Regex.Match(p, @"\d+").Value), - IsCompressed = p.EndsWith(".zip") - }).OrderBy(p => p.Start); - foreach (var path in paths) - { - if (path.Start > Blockchain.Singleton.Height + 1) break; - if (path.IsCompressed) - using (FileStream fs = new FileStream(path.FileName, FileMode.Open, FileAccess.Read, FileShare.Read)) - using (ZipArchive zip = new ZipArchive(fs, ZipArchiveMode.Read)) - using (Stream zs = zip.GetEntry(Path.GetFileNameWithoutExtension(path.FileName)).Open()) - await System.Blockchain.Ask(new Blockchain.Import - { - Blocks = GetBlocks(zs, true) - }); - else - using (FileStream fs = new FileStream(path.FileName, FileMode.Open, FileAccess.Read, FileShare.Read)) - await System.Blockchain.Ask(new Blockchain.Import - { - Blocks = GetBlocks(fs, true) - }); - } ResumeNodeStartup(); + System.ActorSystem.Stop(_blockImporter); + } + + protected override void OnPluginsLoaded() + { + SuspendNodeStartup(); + _blockImporter = System.ActorSystem.ActorOf(BlockImporter.Props()); + _blockImporter.Tell(new BlockImporter.StartImport { BlockchainActorRef = System.Blockchain, OnComplete = OnImportComplete }); } protected override bool OnMessage(object message) From f4b83e05b38a9cacbecb298430a4016cd1468b4c Mon Sep 17 00:00:00 2001 From: jsolman Date: Tue, 9 Apr 2019 01:09:23 -0700 Subject: [PATCH 055/183] RpcNep5Tracker: Handle NEP5 transfers to/from null & limit max results (#71) * Handle NEP5 transfers to/from null. * Add support for tracking tokens using non-standard mintToken event. * Implement maximum results to return for transfer history. * Make whether to support tracking null address history configurable. Default to false. * Better input validation * Support tracking non-standard mintTokens event, but default to off. --- RpcNep5Tracker/RpcNep5Tracker.cs | 112 +++++++++++++++------- RpcNep5Tracker/RpcNep5Tracker/config.json | 4 +- 2 files changed, 82 insertions(+), 34 deletions(-) diff --git a/RpcNep5Tracker/RpcNep5Tracker.cs b/RpcNep5Tracker/RpcNep5Tracker.cs index ed7a48f4e..517849de1 100644 --- a/RpcNep5Tracker/RpcNep5Tracker.cs +++ b/RpcNep5Tracker/RpcNep5Tracker.cs @@ -30,6 +30,9 @@ public class RpcNep5Tracker : Plugin, IPersistencePlugin, IRpcPlugin private DataCache _transfersReceived; private WriteBatch _writeBatch; private bool _shouldTrackHistory; + private bool _recordNullAddressHistory; + private uint _maxResults; + private bool _shouldTrackNonStandardMintTokensEvent; private Neo.IO.Data.LevelDB.Snapshot _levelDbSnapshot; public override void Configure() @@ -37,9 +40,12 @@ public override void Configure() if (_db == null) { var dbPath = GetConfiguration().GetSection("DBPath").Value ?? "Nep5BalanceData"; - _shouldTrackHistory = (GetConfiguration().GetSection("TrackHistory").Value ?? true.ToString()) != false.ToString(); _db = DB.Open(dbPath, new Options { CreateIfMissing = true }); } + _shouldTrackHistory = (GetConfiguration().GetSection("TrackHistory").Value ?? true.ToString()) != false.ToString(); + _recordNullAddressHistory = (GetConfiguration().GetSection("RecordNullAddressHistory").Value ?? false.ToString()) != false.ToString(); + _maxResults = uint.Parse(GetConfiguration().GetSection("MaxResults").Value ?? "1000"); + _shouldTrackNonStandardMintTokensEvent = (GetConfiguration().GetSection("TrackNonStandardMintTokens").Value ?? false.ToString()) != false.ToString(); } private void ResetBatch() @@ -58,58 +64,96 @@ private void ResetBatch() } } + private void RecordTransferHistory(Snapshot snapshot, UInt160 scriptHash, UInt160 from, UInt160 to, BigInteger amount, UInt256 txHash, ref ushort transferIndex) + { + if (!_shouldTrackHistory) return; + if (_recordNullAddressHistory || from != UInt160.Zero) + { + _transfersSent.Add(new Nep5TransferKey(from, + snapshot.GetHeader(snapshot.Height).Timestamp, scriptHash, transferIndex), + new Nep5Transfer + { + Amount = amount, + UserScriptHash = to, + BlockIndex = snapshot.Height, + TxHash = txHash + }); + } + + if (_recordNullAddressHistory || to != UInt160.Zero) + { + _transfersReceived.Add(new Nep5TransferKey(to, + snapshot.GetHeader(snapshot.Height).Timestamp, scriptHash, transferIndex), + new Nep5Transfer + { + Amount = amount, + UserScriptHash = from, + BlockIndex = snapshot.Height, + TxHash = txHash + }); + } + transferIndex++; + } + private void HandleNotification(Snapshot snapshot, Transaction transaction, UInt160 scriptHash, VM.Types.Array stateItems, Dictionary nep5BalancesChanged, ref ushort transferIndex) { + if (stateItems.Count == 0) return; // Event name should be encoded as a byte array. if (!(stateItems[0] is VM.Types.ByteArray)) return; var eventName = Encoding.UTF8.GetString(stateItems[0].GetByteArray()); - // Only care about transfers + if (_shouldTrackNonStandardMintTokensEvent && eventName == "mintTokens") + { + if (stateItems.Count < 4) return; + // This is not an official standard but at least one token uses it, and so it is needed for proper + // balance tracking to support all tokens in use. + if (!(stateItems[2] is VM.Types.ByteArray)) + return; + byte[] mintToBytes = stateItems[2].GetByteArray(); + if (mintToBytes.Length != 20) return; + var mintTo = new UInt160(mintToBytes); + + var mintAmountItem = stateItems[3]; + if (!(mintAmountItem is VM.Types.ByteArray || mintAmountItem is VM.Types.Integer)) + return; + + var toKey = new Nep5BalanceKey(mintTo, scriptHash); + if (!nep5BalancesChanged.ContainsKey(toKey)) nep5BalancesChanged.Add(toKey, new Nep5Balance()); + RecordTransferHistory(snapshot, scriptHash, UInt160.Zero, mintTo, mintAmountItem.GetBigInteger(), transaction.Hash, ref transferIndex); + return; + } if (eventName != "transfer") return; + if (stateItems.Count < 4) return; - if (!(stateItems[1] is VM.Types.ByteArray)) + if (!(stateItems[1] is null) && !(stateItems[1] is VM.Types.ByteArray)) return; - if (!(stateItems[2] is VM.Types.ByteArray)) + if (!(stateItems[2] is null) && !(stateItems[2] is VM.Types.ByteArray)) return; var amountItem = stateItems[3]; if (!(amountItem is VM.Types.ByteArray || amountItem is VM.Types.Integer)) return; - byte[] fromBytes = stateItems[1].GetByteArray(); - if (fromBytes.Length != 20) fromBytes = null; - byte[] toBytes = stateItems[2].GetByteArray(); - if (toBytes.Length != 20) toBytes = null; + byte[] fromBytes = stateItems[1]?.GetByteArray(); + if (fromBytes?.Length != 20) fromBytes = null; + byte[] toBytes = stateItems[2]?.GetByteArray(); + if (toBytes?.Length != 20) toBytes = null; if (fromBytes == null && toBytes == null) return; var from = new UInt160(fromBytes); var to = new UInt160(toBytes); - var fromKey = new Nep5BalanceKey(from, scriptHash); - if (!nep5BalancesChanged.ContainsKey(fromKey)) nep5BalancesChanged.Add(fromKey, new Nep5Balance()); - var toKey = new Nep5BalanceKey(to, scriptHash); - if (!nep5BalancesChanged.ContainsKey(toKey)) nep5BalancesChanged.Add(toKey, new Nep5Balance()); + if (fromBytes != null) + { + var fromKey = new Nep5BalanceKey(from, scriptHash); + if (!nep5BalancesChanged.ContainsKey(fromKey)) nep5BalancesChanged.Add(fromKey, new Nep5Balance()); + } - if (!_shouldTrackHistory) return; - BigInteger amount = amountItem.GetBigInteger(); - _transfersSent.Add(new Nep5TransferKey(from, - snapshot.GetHeader(snapshot.Height).Timestamp, scriptHash, transferIndex), - new Nep5Transfer - { - Amount = amount, - UserScriptHash = to, - BlockIndex = snapshot.Height, - TxHash = transaction.Hash - }); - _transfersReceived.Add(new Nep5TransferKey(to, - snapshot.GetHeader(snapshot.Height).Timestamp, scriptHash, transferIndex), - new Nep5Transfer - { - Amount = amount, - UserScriptHash = from, - BlockIndex = snapshot.Height, - TxHash = transaction.Hash - }); - transferIndex++; + if (toBytes != null) + { + var toKey = new Nep5BalanceKey(to, scriptHash); + if (!nep5BalancesChanged.ContainsKey(toKey)) nep5BalancesChanged.Add(toKey, new Nep5Balance()); + } + RecordTransferHistory(snapshot, scriptHash, from, to, amountItem.GetBigInteger(), transaction.Hash, ref transferIndex); } public void OnPersist(Snapshot snapshot, IReadOnlyList applicationExecutedList) @@ -196,8 +240,10 @@ private void AddTransfers(byte dbPrefix, UInt160 userScriptHash, uint startTime, prefix.Concat(startTimeBytes).ToArray(), prefix.Concat(endTimeBytes).ToArray()); + int resultCount = 0; foreach (var transferPair in transferPairs) { + if (++resultCount > _maxResults) break; JObject transfer = new JObject(); transfer["timestamp"] = transferPair.Key.Timestamp; transfer["asset_hash"] = transferPair.Key.AssetScriptHash.ToArray().Reverse().ToHexString(); diff --git a/RpcNep5Tracker/RpcNep5Tracker/config.json b/RpcNep5Tracker/RpcNep5Tracker/config.json index 3d7efb4fe..13e79b805 100644 --- a/RpcNep5Tracker/RpcNep5Tracker/config.json +++ b/RpcNep5Tracker/RpcNep5Tracker/config.json @@ -1,6 +1,8 @@ { "PluginConfiguration": { "DBPath": "Nep5BalanceData", - "TrackHistory" : true + "TrackHistory" : true, + "RecordNullAddressHistory": false, + "MaxResults" : 1000 } } From 7347fba3351f7eb26096900cb94a019d609c15b1 Mon Sep 17 00:00:00 2001 From: Shargon Date: Tue, 16 Apr 2019 09:05:15 +0200 Subject: [PATCH 056/183] Small optimization (#82) --- RpcSystemAssetTracker/UserSystemAssetCoinOutputsKey.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/RpcSystemAssetTracker/UserSystemAssetCoinOutputsKey.cs b/RpcSystemAssetTracker/UserSystemAssetCoinOutputsKey.cs index 7f0cad859..3e4439b50 100644 --- a/RpcSystemAssetTracker/UserSystemAssetCoinOutputsKey.cs +++ b/RpcSystemAssetTracker/UserSystemAssetCoinOutputsKey.cs @@ -25,8 +25,8 @@ public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != this.GetType()) return false; - return Equals((UserSystemAssetCoinOutputsKey) obj); + if (!(obj is UserSystemAssetCoinOutputsKey b)) return false; + return Equals(b); } public int CompareTo(UserSystemAssetCoinOutputsKey other) From c45e3f4df3406086e54057cf518478495c6794a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vitor=20Naz=C3=A1rio=20Coelho?= Date: Mon, 22 Apr 2019 12:01:37 -0300 Subject: [PATCH 057/183] Updating travis (#84) --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index b244dbc7f..9695107d5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,7 @@ os: - linux - osx -dist: trusty +dist: bionic osx_image: xcode9.1 mono: none From dc45d33f62554db799f726a874791d5f9b90d606 Mon Sep 17 00:00:00 2001 From: Owen Zhang <38493437+superboyiii@users.noreply.github.com> Date: Tue, 23 Apr 2019 10:30:05 +0800 Subject: [PATCH 058/183] Fix output json for multisigaddress transaction (#86) * Fix output json for multisigaddress transaction Fix output json for multisigaddress transaction * format * format --- RpcWallet/RpcWallet.cs | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/RpcWallet/RpcWallet.cs b/RpcWallet/RpcWallet.cs index 4807fb3cc..3d934b8b8 100644 --- a/RpcWallet/RpcWallet.cs +++ b/RpcWallet/RpcWallet.cs @@ -313,6 +313,8 @@ private JObject SendFrom(UIntBase assetId, UInt160 from, UInt160 to, string valu ContractParametersContext transContext = new ContractParametersContext(tx); Wallet.Sign(transContext); + if (!transContext.Completed) + return transContext.ToJson(); tx.Witnesses = transContext.GetWitnesses(); if (tx.Size > 1024) { @@ -323,11 +325,11 @@ private JObject SendFrom(UIntBase assetId, UInt160 from, UInt160 to, string valu tx = Wallet.MakeTransaction(null, new[] { new TransferOutput - { - AssetId = assetId, - Value = amount, - ScriptHash = to - } + { + AssetId = assetId, + Value = amount, + ScriptHash = to + } }, from: from, change_address: change_address, fee: fee); if (tx == null) throw new RpcException(-300, "Insufficient funds"); @@ -365,6 +367,8 @@ private JObject SendMany(UInt160 from, JArray to, Fixed8 fee, UInt160 change_add ContractParametersContext transContext = new ContractParametersContext(tx); Wallet.Sign(transContext); + if (!transContext.Completed) + return transContext.ToJson(); tx.Witnesses = transContext.GetWitnesses(); if (tx.Size > 1024) { @@ -375,7 +379,7 @@ private JObject SendMany(UInt160 from, JArray to, Fixed8 fee, UInt160 change_add tx = Wallet.MakeTransaction(null, outputs, from: from, change_address: change_address, fee: fee); if (tx == null) throw new RpcException(-300, "Insufficient funds"); - } + } } if (fee > Settings.Default.MaxFee) throw new RpcException(-301, "The necessary fee is more than the Max_fee, this transaction is failed. Please increase your Max_fee value."); @@ -405,6 +409,8 @@ private JObject SendToAddress(UIntBase assetId, UInt160 scriptHash, string value ContractParametersContext transContext = new ContractParametersContext(tx); Wallet.Sign(transContext); + if (!transContext.Completed) + return transContext.ToJson(); tx.Witnesses = transContext.GetWitnesses(); if (tx.Size > 1024) { @@ -423,8 +429,8 @@ private JObject SendToAddress(UIntBase assetId, UInt160 scriptHash, string value }, change_address: change_address, fee: fee); if (tx == null) throw new RpcException(-300, "Insufficient funds"); - } - } + } + } if (fee > Settings.Default.MaxFee) throw new RpcException(-301, "The necessary fee is more than the Max_fee, this transaction is failed. Please increase your Max_fee value."); return SignAndRelay(tx); From 9ae210f2b40f8368303997f1e1fa9e9b7f94f47f Mon Sep 17 00:00:00 2001 From: Owen Zhang <38493437+superboyiii@users.noreply.github.com> Date: Wed, 24 Apr 2019 03:21:37 +0800 Subject: [PATCH 059/183] Fix the height to end with (#88) * Fix-heightToEnd * Minor fix and comment --- CoreMetrics/CoreMetrics.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CoreMetrics/CoreMetrics.cs b/CoreMetrics/CoreMetrics.cs index a1c10af5d..5be9d35ca 100644 --- a/CoreMetrics/CoreMetrics.cs +++ b/CoreMetrics/CoreMetrics.cs @@ -64,7 +64,7 @@ private JObject GetBlocksTime(uint nBlocks, uint lastHeight) if (nBlocks >= Blockchain.Singleton.Height) { JObject json = new JObject(); - return json["error"] = "Requested number of blocks timestamps exceeds quantity of known blocks " + Blockchain.Singleton.Height; + return json["error"] = "Requested number of blocks timestamps " + nBlocks + " exceeds quantity of known blocks " + Blockchain.Singleton.Height; } if (nBlocks <= 0) @@ -74,8 +74,8 @@ private JObject GetBlocksTime(uint nBlocks, uint lastHeight) } JArray array = new JArray(); - uint heightToBegin = lastHeight > 0 ? lastHeight - nBlocks : Blockchain.Singleton.Height - nBlocks; - for (uint i = heightToBegin; i <= Blockchain.Singleton.HeaderHeight; i++) + uint heightToBegin = lastHeight > 0 ? lastHeight - nBlocks : (Blockchain.Singleton.Height - 1) - nBlocks; + for (uint i = heightToBegin; i <= heightToBegin + nBlocks; i++) { JObject json = new JObject(); Header header = Blockchain.Singleton.Store.GetHeader(i); From 14eb335917c592646c74b02c057e42d34646a615 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vitor=20Naz=C3=A1rio=20Coelho?= Date: Tue, 30 Apr 2019 19:51:26 -0300 Subject: [PATCH 060/183] Minor fix on storage state dumper parameter HeightToStartRealTimeSyncing (#91) * Minor fix on storage state dumper parameter HeightToStartRealTimeSyncing * Update StatesDumper/StatesDumper.cs Co-Authored-By: vncoelho --- StatesDumper/Settings.cs | 4 ++-- StatesDumper/StatesDumper.cs | 2 +- StatesDumper/StatesDumper/config.json | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/StatesDumper/Settings.cs b/StatesDumper/Settings.cs index 37622df2f..a1fa53d16 100644 --- a/StatesDumper/Settings.cs +++ b/StatesDumper/Settings.cs @@ -16,7 +16,7 @@ internal class Settings /// /// Height to begin real-time syncing and dumping on, consequently, dumping every block into a single files /// - public uint HeightToStartRealTimeSyncing { get; } + public int HeightToStartRealTimeSyncing { get; } /// /// Persisting actions /// @@ -29,7 +29,7 @@ private Settings(IConfigurationSection section) /// Geting settings for storage changes state dumper this.BlockCacheSize = GetValueOrDefault(section.GetSection("BlockCacheSize"), 1000u, p => uint.Parse(p)); this.HeightToBegin = GetValueOrDefault(section.GetSection("HeightToBegin"), 0u, p => uint.Parse(p)); - this.HeightToStartRealTimeSyncing = GetValueOrDefault(section.GetSection("HeightToStartRealTimeSyncing"), 2883000u, p => uint.Parse(p)); + this.HeightToStartRealTimeSyncing = GetValueOrDefault(section.GetSection("HeightToStartRealTimeSyncing"), -1, p => int.Parse(p)); this.PersistAction = GetValueOrDefault(section.GetSection("PersistAction"), PersistActions.StorageChanges, p => (PersistActions)Enum.Parse(typeof(PersistActions), p)); } diff --git a/StatesDumper/StatesDumper.cs b/StatesDumper/StatesDumper.cs index 5cc95fa3b..44addf688 100644 --- a/StatesDumper/StatesDumper.cs +++ b/StatesDumper/StatesDumper.cs @@ -131,7 +131,7 @@ public void OnCommitStorage(Snapshot snapshot) uint blockIndex = snapshot.Height; if (bs_cache.Count > 0) { - if ((blockIndex % Settings.Default.BlockCacheSize == 0) || (blockIndex > Settings.Default.HeightToStartRealTimeSyncing)) + if ((blockIndex % Settings.Default.BlockCacheSize == 0) || (Settings.Default.HeightToStartRealTimeSyncing != -1 && blockIndex >= Settings.Default.HeightToStartRealTimeSyncing)) { string dirPath = "./Storage"; Directory.CreateDirectory(dirPath); diff --git a/StatesDumper/StatesDumper/config.json b/StatesDumper/StatesDumper/config.json index 7e1e2a347..52ab5ccf8 100644 --- a/StatesDumper/StatesDumper/config.json +++ b/StatesDumper/StatesDumper/config.json @@ -3,6 +3,6 @@ "PersistAction": "StorageChanges", "BlockCacheSize": 1000, "HeightToBegin": 0, - "HeightToRealTimeSyncing": 2883000 + "HeightToStartRealTimeSyncing": -1 } } From 45b10101e93ffe1f5c155e1cc9856cc5515b40eb Mon Sep 17 00:00:00 2001 From: Shargon Date: Thu, 16 May 2019 17:09:45 +0200 Subject: [PATCH 061/183] Prevent exceed the height (#92) * Update CoreMetrics.cs I think that it could be exceeded the max height using the `lastHeight` parameter * Update CoreMetrics.cs --- CoreMetrics/CoreMetrics.cs | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/CoreMetrics/CoreMetrics.cs b/CoreMetrics/CoreMetrics.cs index 5be9d35ca..7800b9131 100644 --- a/CoreMetrics/CoreMetrics.cs +++ b/CoreMetrics/CoreMetrics.cs @@ -8,13 +8,9 @@ namespace Neo.Plugins { public class CoreMetrics : Plugin, IRpcPlugin { - public override void Configure() - { - } + public override void Configure() { } - public void PreProcess(HttpContext context, string method, JArray _params) - { - } + public void PreProcess(HttpContext context, string method, JArray _params) { } public JObject OnProcess(HttpContext context, string method, JArray _params) { @@ -32,9 +28,7 @@ public JObject OnProcess(HttpContext context, string method, JArray _params) } } - public void PostProcess(HttpContext context, string method, JArray _params, JObject result) - { - } + public void PostProcess(HttpContext context, string method, JArray _params, JObject result) { } private JObject GetBlocksTime(uint nBlocks, uint lastHeight) { @@ -79,6 +73,8 @@ private JObject GetBlocksTime(uint nBlocks, uint lastHeight) { JObject json = new JObject(); Header header = Blockchain.Singleton.Store.GetHeader(i); + if (header == null) break; + json["timestamp"] = header.Timestamp; json["height"] = i; array.Add(json); From 04fedf5b9003fdc6a90d7fab2d2b998b32b655cc Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Fri, 17 May 2019 21:59:26 +0800 Subject: [PATCH 062/183] v2.10.2 (#96) --- ApplicationLogs/ApplicationLogs.csproj | 4 ++-- CoreMetrics/CoreMetrics.csproj | 4 ++-- ImportBlocks/ImportBlocks.csproj | 4 ++-- RpcNep5Tracker/RpcNep5Tracker.csproj | 4 ++-- RpcSecurity/RpcSecurity.csproj | 4 ++-- RpcSystemAssetTracker/RpcSystemAssetTracker.csproj | 4 ++-- RpcWallet/RpcWallet.csproj | 4 ++-- SimplePolicy/SimplePolicy.csproj | 4 ++-- StatesDumper/StatesDumper.csproj | 4 ++-- 9 files changed, 18 insertions(+), 18 deletions(-) diff --git a/ApplicationLogs/ApplicationLogs.csproj b/ApplicationLogs/ApplicationLogs.csproj index bdd93b725..c2b8d3673 100644 --- a/ApplicationLogs/ApplicationLogs.csproj +++ b/ApplicationLogs/ApplicationLogs.csproj @@ -1,7 +1,7 @@  - 2.10.1 + 2.10.2 netstandard2.0 Neo.Plugins @@ -14,7 +14,7 @@ - + diff --git a/CoreMetrics/CoreMetrics.csproj b/CoreMetrics/CoreMetrics.csproj index 51bfdcb43..01e53fe4e 100644 --- a/CoreMetrics/CoreMetrics.csproj +++ b/CoreMetrics/CoreMetrics.csproj @@ -1,13 +1,13 @@  - 2.10.1 + 2.10.2 netstandard2.0 Neo.Plugins - + diff --git a/ImportBlocks/ImportBlocks.csproj b/ImportBlocks/ImportBlocks.csproj index d064bfbb7..6584133f0 100644 --- a/ImportBlocks/ImportBlocks.csproj +++ b/ImportBlocks/ImportBlocks.csproj @@ -1,7 +1,7 @@  - 2.10.1 + 2.10.2 netstandard2.0 Neo.Plugins @@ -14,7 +14,7 @@ - + diff --git a/RpcNep5Tracker/RpcNep5Tracker.csproj b/RpcNep5Tracker/RpcNep5Tracker.csproj index 89dcb4d13..f1138b747 100644 --- a/RpcNep5Tracker/RpcNep5Tracker.csproj +++ b/RpcNep5Tracker/RpcNep5Tracker.csproj @@ -1,6 +1,6 @@  - 2.10.1 + 2.10.2 netstandard2.0 Neo.Plugins latest @@ -12,6 +12,6 @@ - + diff --git a/RpcSecurity/RpcSecurity.csproj b/RpcSecurity/RpcSecurity.csproj index 6cdef86c2..8878830f9 100644 --- a/RpcSecurity/RpcSecurity.csproj +++ b/RpcSecurity/RpcSecurity.csproj @@ -1,7 +1,7 @@  - 2.10.1 + 2.10.2 netstandard2.0 Neo.Plugins @@ -14,7 +14,7 @@ - + diff --git a/RpcSystemAssetTracker/RpcSystemAssetTracker.csproj b/RpcSystemAssetTracker/RpcSystemAssetTracker.csproj index 4d03ef295..44eab88a4 100644 --- a/RpcSystemAssetTracker/RpcSystemAssetTracker.csproj +++ b/RpcSystemAssetTracker/RpcSystemAssetTracker.csproj @@ -1,6 +1,6 @@  - 2.10.1 + 2.10.2 netstandard2.0 Neo.Plugins latest @@ -12,6 +12,6 @@ - + diff --git a/RpcWallet/RpcWallet.csproj b/RpcWallet/RpcWallet.csproj index db6f412f7..a8e7f0e76 100644 --- a/RpcWallet/RpcWallet.csproj +++ b/RpcWallet/RpcWallet.csproj @@ -1,7 +1,7 @@  - 2.10.1 + 2.10.2 netstandard2.0 Neo.Plugins @@ -14,7 +14,7 @@ - + diff --git a/SimplePolicy/SimplePolicy.csproj b/SimplePolicy/SimplePolicy.csproj index bbff08a06..b2001eac2 100644 --- a/SimplePolicy/SimplePolicy.csproj +++ b/SimplePolicy/SimplePolicy.csproj @@ -1,7 +1,7 @@  - 2.10.1 + 2.10.2 netstandard2.0 Neo.Plugins latest @@ -15,7 +15,7 @@ - + diff --git a/StatesDumper/StatesDumper.csproj b/StatesDumper/StatesDumper.csproj index a251b4407..0f848c148 100644 --- a/StatesDumper/StatesDumper.csproj +++ b/StatesDumper/StatesDumper.csproj @@ -1,7 +1,7 @@  - 2.10.1 + 2.10.2 netstandard2.0 Neo.Plugins @@ -14,7 +14,7 @@ - + From e1c0276ead71bca4d5f0d447a24f89e43ea25509 Mon Sep 17 00:00:00 2001 From: Shargon Date: Sun, 19 May 2019 17:09:16 +0200 Subject: [PATCH 063/183] Update CoreMetrics.cs (#94) --- CoreMetrics/CoreMetrics.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CoreMetrics/CoreMetrics.cs b/CoreMetrics/CoreMetrics.cs index 7800b9131..b9df0022e 100644 --- a/CoreMetrics/CoreMetrics.cs +++ b/CoreMetrics/CoreMetrics.cs @@ -71,10 +71,10 @@ private JObject GetBlocksTime(uint nBlocks, uint lastHeight) uint heightToBegin = lastHeight > 0 ? lastHeight - nBlocks : (Blockchain.Singleton.Height - 1) - nBlocks; for (uint i = heightToBegin; i <= heightToBegin + nBlocks; i++) { - JObject json = new JObject(); Header header = Blockchain.Singleton.Store.GetHeader(i); if (header == null) break; + JObject json = new JObject(); json["timestamp"] = header.Timestamp; json["height"] = i; array.Add(json); From a72c44813271efcafe0a4fcee2505fae3a3b4716 Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Mon, 20 May 2019 03:15:59 +0800 Subject: [PATCH 064/183] Update dependency: Neo v3.0.0-CI00044 (#98) --- ApplicationLogs/ApplicationLogs.csproj | 2 +- ApplicationLogs/LogReader.cs | 40 +- ApplicationLogs/Settings.cs | 3 +- CoreMetrics/CoreMetrics.csproj | 2 +- ImportBlocks/ImportBlocks.csproj | 2 +- RpcNep5Tracker/Nep5Balance.cs | 15 +- RpcNep5Tracker/Nep5Transfer.cs | 15 +- RpcNep5Tracker/RpcNep5Tracker.cs | 19 +- RpcNep5Tracker/RpcNep5Tracker.csproj | 2 +- RpcSecurity/RpcSecurity.csproj | 2 +- .../RpcSystemAssetTracker.csproj | 17 - .../RpcSystemAssetTracker/config.json | 7 - .../RpcSystemAssetTrackerPlugin.cs | 426 ------------------ .../UserSystemAssetCoinOutputs.cs | 79 ---- .../UserSystemAssetCoinOutputsKey.cs | 81 ---- RpcWallet/RpcWallet.cs | 193 ++------ RpcWallet/RpcWallet.csproj | 2 +- RpcWallet/Settings.cs | 5 +- SimplePolicy.UnitTests/UT_SimplePolicy.cs | 241 ++-------- SimplePolicy/Settings.cs | 21 +- SimplePolicy/SimplePolicy.csproj | 2 +- SimplePolicy/SimplePolicy/config.json | 4 - SimplePolicy/SimplePolicyPlugin.cs | 16 +- StatesDumper/StatesDumper.csproj | 2 +- neo-plugins.sln | 7 +- 25 files changed, 135 insertions(+), 1070 deletions(-) delete mode 100644 RpcSystemAssetTracker/RpcSystemAssetTracker.csproj delete mode 100644 RpcSystemAssetTracker/RpcSystemAssetTracker/config.json delete mode 100644 RpcSystemAssetTracker/RpcSystemAssetTrackerPlugin.cs delete mode 100644 RpcSystemAssetTracker/UserSystemAssetCoinOutputs.cs delete mode 100644 RpcSystemAssetTracker/UserSystemAssetCoinOutputsKey.cs diff --git a/ApplicationLogs/ApplicationLogs.csproj b/ApplicationLogs/ApplicationLogs.csproj index c2b8d3673..ca2946f4e 100644 --- a/ApplicationLogs/ApplicationLogs.csproj +++ b/ApplicationLogs/ApplicationLogs.csproj @@ -14,7 +14,7 @@ - + diff --git a/ApplicationLogs/LogReader.cs b/ApplicationLogs/LogReader.cs index 0ee121c5e..c316659d3 100644 --- a/ApplicationLogs/LogReader.cs +++ b/ApplicationLogs/LogReader.cs @@ -53,36 +53,30 @@ public void OnPersist(Snapshot snapshot, IReadOnlyList + json["trigger"] = appExec.Trigger; + json["vmstate"] = appExec.VMState; + json["gas_consumed"] = appExec.GasConsumed.ToString(); + try { - JObject execution = new JObject(); - execution["trigger"] = p.Trigger; - execution["contract"] = p.ScriptHash.ToString(); - execution["vmstate"] = p.VMState; - execution["gas_consumed"] = p.GasConsumed.ToString(); + json["stack"] = appExec.Stack.Select(q => q.ToParameter().ToJson()).ToArray(); + } + catch (InvalidOperationException) + { + json["stack"] = "error: recursive reference"; + } + json["notifications"] = appExec.Notifications.Select(q => + { + JObject notification = new JObject(); + notification["contract"] = q.ScriptHash.ToString(); try { - execution["stack"] = p.Stack.Select(q => q.ToParameter().ToJson()).ToArray(); + notification["state"] = q.State.ToParameter().ToJson(); } catch (InvalidOperationException) { - execution["stack"] = "error: recursive reference"; + notification["state"] = "error: recursive reference"; } - execution["notifications"] = p.Notifications.Select(q => - { - JObject notification = new JObject(); - notification["contract"] = q.ScriptHash.ToString(); - try - { - notification["state"] = q.State.ToParameter().ToJson(); - } - catch (InvalidOperationException) - { - notification["state"] = "error: recursive reference"; - } - return notification; - }).ToArray(); - return execution; + return notification; }).ToArray(); writeBatch.Put(appExec.Transaction.Hash.ToArray(), json.ToString()); } diff --git a/ApplicationLogs/Settings.cs b/ApplicationLogs/Settings.cs index 234972e7c..82a501e90 100644 --- a/ApplicationLogs/Settings.cs +++ b/ApplicationLogs/Settings.cs @@ -1,5 +1,4 @@ using Microsoft.Extensions.Configuration; -using Neo.Network.P2P; namespace Neo.Plugins { @@ -11,7 +10,7 @@ internal class Settings private Settings(IConfigurationSection section) { - this.Path = string.Format(section.GetSection("Path").Value, Message.Magic.ToString("X8")); + this.Path = string.Format(section.GetSection("Path").Value, ProtocolSettings.Default.Magic.ToString("X8")); } public static void Load(IConfigurationSection section) diff --git a/CoreMetrics/CoreMetrics.csproj b/CoreMetrics/CoreMetrics.csproj index 01e53fe4e..91bb46e49 100644 --- a/CoreMetrics/CoreMetrics.csproj +++ b/CoreMetrics/CoreMetrics.csproj @@ -7,7 +7,7 @@ - + diff --git a/ImportBlocks/ImportBlocks.csproj b/ImportBlocks/ImportBlocks.csproj index 6584133f0..56a2d5578 100644 --- a/ImportBlocks/ImportBlocks.csproj +++ b/ImportBlocks/ImportBlocks.csproj @@ -14,7 +14,7 @@ - + diff --git a/RpcNep5Tracker/Nep5Balance.cs b/RpcNep5Tracker/Nep5Balance.cs index 304028d08..c848879f5 100644 --- a/RpcNep5Tracker/Nep5Balance.cs +++ b/RpcNep5Tracker/Nep5Balance.cs @@ -1,32 +1,29 @@ using System.IO; using System.Numerics; using Neo.IO; -using Neo.Ledger; namespace Neo.Plugins { - public class Nep5Balance : StateBase, ICloneable + public class Nep5Balance : ICloneable, ISerializable { public BigInteger Balance; public uint LastUpdatedBlock; - public override int Size => base.Size + Balance.ToByteArray().GetVarSize() + sizeof(uint); + int ISerializable.Size => Balance.ToByteArray().GetVarSize() + sizeof(uint); - public override void Serialize(BinaryWriter writer) + void ISerializable.Serialize(BinaryWriter writer) { - base.Serialize(writer); writer.WriteVarBytes(Balance.ToByteArray()); writer.Write(LastUpdatedBlock); } - public override void Deserialize(BinaryReader reader) + void ISerializable.Deserialize(BinaryReader reader) { - base.Deserialize(reader); Balance = new BigInteger(reader.ReadVarBytes(512)); LastUpdatedBlock = reader.ReadUInt32(); } - public Nep5Balance Clone() + Nep5Balance ICloneable.Clone() { return new Nep5Balance { @@ -41,4 +38,4 @@ public void FromReplica(Nep5Balance replica) LastUpdatedBlock = replica.LastUpdatedBlock; } } -} \ No newline at end of file +} diff --git a/RpcNep5Tracker/Nep5Transfer.cs b/RpcNep5Tracker/Nep5Transfer.cs index 7ddf8c54a..9c4b2307b 100644 --- a/RpcNep5Tracker/Nep5Transfer.cs +++ b/RpcNep5Tracker/Nep5Transfer.cs @@ -1,38 +1,35 @@ using System.IO; using System.Numerics; using Neo.IO; -using Neo.Ledger; namespace Neo.Plugins { - public class Nep5Transfer : StateBase, ICloneable + public class Nep5Transfer : ICloneable, ISerializable { public UInt160 UserScriptHash; public uint BlockIndex; public UInt256 TxHash; public BigInteger Amount; - public override int Size => base.Size + 20 + sizeof(uint) + 32 + Amount.ToByteArray().GetVarSize(); + int ISerializable.Size => 20 + sizeof(uint) + 32 + Amount.ToByteArray().GetVarSize(); - public override void Serialize(BinaryWriter writer) + void ISerializable.Serialize(BinaryWriter writer) { - base.Serialize(writer); writer.Write(UserScriptHash); writer.Write(BlockIndex); writer.Write(TxHash); writer.WriteVarBytes(Amount.ToByteArray()); } - public override void Deserialize(BinaryReader reader) + void ISerializable.Deserialize(BinaryReader reader) { - base.Deserialize(reader); UserScriptHash = reader.ReadSerializable(); BlockIndex = reader.ReadUInt32(); TxHash = reader.ReadSerializable(); Amount = new BigInteger(reader.ReadVarBytes(512)); } - public Nep5Transfer Clone() + Nep5Transfer ICloneable.Clone() { return new Nep5Transfer { @@ -43,7 +40,7 @@ public Nep5Transfer Clone() }; } - public void FromReplica(Nep5Transfer replica) + void ICloneable.FromReplica(Nep5Transfer replica) { UserScriptHash = replica.UserScriptHash; BlockIndex = replica.BlockIndex; diff --git a/RpcNep5Tracker/RpcNep5Tracker.cs b/RpcNep5Tracker/RpcNep5Tracker.cs index 517849de1..60599c160 100644 --- a/RpcNep5Tracker/RpcNep5Tracker.cs +++ b/RpcNep5Tracker/RpcNep5Tracker.cs @@ -165,18 +165,15 @@ public void OnPersist(Snapshot snapshot, IReadOnlyList - + diff --git a/RpcSecurity/RpcSecurity.csproj b/RpcSecurity/RpcSecurity.csproj index 8878830f9..77998bf66 100644 --- a/RpcSecurity/RpcSecurity.csproj +++ b/RpcSecurity/RpcSecurity.csproj @@ -14,7 +14,7 @@ - + diff --git a/RpcSystemAssetTracker/RpcSystemAssetTracker.csproj b/RpcSystemAssetTracker/RpcSystemAssetTracker.csproj deleted file mode 100644 index 44eab88a4..000000000 --- a/RpcSystemAssetTracker/RpcSystemAssetTracker.csproj +++ /dev/null @@ -1,17 +0,0 @@ - - - 2.10.2 - netstandard2.0 - Neo.Plugins - latest - - - - PreserveNewest - PreserveNewest - - - - - - diff --git a/RpcSystemAssetTracker/RpcSystemAssetTracker/config.json b/RpcSystemAssetTracker/RpcSystemAssetTracker/config.json deleted file mode 100644 index 214c08939..000000000 --- a/RpcSystemAssetTracker/RpcSystemAssetTracker/config.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "PluginConfiguration": { - "DBPath": "SystemAssetBalanceData", - "MaxReturnedUnspents": 1000, - "TrackUnclaimed": true - } -} diff --git a/RpcSystemAssetTracker/RpcSystemAssetTrackerPlugin.cs b/RpcSystemAssetTracker/RpcSystemAssetTrackerPlugin.cs deleted file mode 100644 index 076bb4f6a..000000000 --- a/RpcSystemAssetTracker/RpcSystemAssetTrackerPlugin.cs +++ /dev/null @@ -1,426 +0,0 @@ -using Microsoft.AspNetCore.Http; -using Neo.IO.Caching; -using Neo.IO.Data.LevelDB; -using Neo.IO.Json; -using Neo.Network.P2P.Payloads; -using Neo.Persistence.LevelDB; -using Neo.Wallets; -using System; -using System.Collections.Generic; -using System.Linq; -using Neo.Ledger; -using Neo.Persistence; -using Snapshot = Neo.Persistence.Snapshot; - -namespace Neo.Plugins -{ - public class RpcSystemAssetTrackerPlugin : Plugin, IPersistencePlugin, IRpcPlugin - { - private const byte SystemAssetUnspentCoinsPrefix = 0xfb; - private const byte SystemAssetSpentUnclaimedCoinsPrefix = 0xfc; - private DB _db; - private DataCache _userUnspentCoins; - private bool _shouldTrackUnclaimed; - private DataCache _userSpentUnclaimedCoins; - private WriteBatch _writeBatch; - private int _rpcMaxUnspents; - private uint _lastPersistedBlock; - private bool _shouldPersistBlock; - private Neo.IO.Data.LevelDB.Snapshot _levelDbSnapshot; - - public override void Configure() - { - if (_db == null) - { - var dbPath = GetConfiguration().GetSection("DBPath").Value ?? "SystemAssetBalanceData"; - _db = DB.Open(dbPath, new Options { CreateIfMissing = true }); - _shouldTrackUnclaimed = (GetConfiguration().GetSection("TrackUnclaimed").Value ?? true.ToString()) != false.ToString(); - try - { - _lastPersistedBlock = _db.Get(ReadOptions.Default, SystemAssetUnspentCoinsPrefix).ToUInt32(); - } - catch (LevelDBException ex) - { - if (!ex.Message.Contains("not found")) - throw; - _lastPersistedBlock = 0; - } - } - _rpcMaxUnspents = int.Parse(GetConfiguration().GetSection("MaxReturnedUnspents").Value ?? "0"); - } - - private void ResetBatch() - { - _writeBatch = new WriteBatch(); - _levelDbSnapshot?.Dispose(); - _levelDbSnapshot = _db.GetSnapshot(); - var dbOptions = new ReadOptions { FillCache = false, Snapshot = _levelDbSnapshot }; - _userUnspentCoins = new DbCache(_db, dbOptions, - _writeBatch, SystemAssetUnspentCoinsPrefix); - if (!_shouldTrackUnclaimed) return; - _userSpentUnclaimedCoins = new DbCache(_db, dbOptions, - _writeBatch, SystemAssetSpentUnclaimedCoinsPrefix); - } - - private bool ProcessBlock(Snapshot snapshot, Block block) - { - if (block.Transactions.Length <= 1) - { - _lastPersistedBlock = block.Index; - return false; - } - - ResetBatch(); - - var transactionsCache = snapshot.Transactions; - foreach (Transaction tx in block.Transactions) - { - ushort outputIndex = 0; - foreach (TransactionOutput output in tx.Outputs) - { - bool isGoverningToken = output.AssetId.Equals(Blockchain.GoverningToken.Hash); - if (isGoverningToken || output.AssetId.Equals(Blockchain.UtilityToken.Hash)) - { - // Add new unspent UTXOs by account script hash. - UserSystemAssetCoinOutputs outputs = _userUnspentCoins.GetAndChange( - new UserSystemAssetCoinOutputsKey(isGoverningToken, output.ScriptHash, tx.Hash), - () => new UserSystemAssetCoinOutputs()); - outputs.AddTxIndex(outputIndex, output.Value); - } - outputIndex++; - } - - // Iterate all input Transactions by grouping by common input hashes. - foreach (var group in tx.Inputs.GroupBy(p => p.PrevHash)) - { - TransactionState txPrev = transactionsCache[group.Key]; - // For each input being spent by this transaction. - foreach (CoinReference input in group) - { - // Get the output from the the previous transaction that is now being spent. - var outPrev = txPrev.Transaction.Outputs[input.PrevIndex]; - - bool isGoverningToken = outPrev.AssetId.Equals(Blockchain.GoverningToken.Hash); - if (isGoverningToken || outPrev.AssetId.Equals(Blockchain.UtilityToken.Hash)) - { - // Remove spent UTXOs for unspent outputs by account script hash. - var userCoinOutputsKey = - new UserSystemAssetCoinOutputsKey(isGoverningToken, outPrev.ScriptHash, input.PrevHash); - UserSystemAssetCoinOutputs outputs = _userUnspentCoins.GetAndChange( - userCoinOutputsKey, () => new UserSystemAssetCoinOutputs()); - outputs.RemoveTxIndex(input.PrevIndex); - if (outputs.AmountByTxIndex.Count == 0) - _userUnspentCoins.Delete(userCoinOutputsKey); - - if (_shouldTrackUnclaimed && isGoverningToken) - { - UserSystemAssetCoinOutputs spentUnclaimedOutputs = _userSpentUnclaimedCoins.GetAndChange( - userCoinOutputsKey, () => new UserSystemAssetCoinOutputs()); - spentUnclaimedOutputs.AddTxIndex(input.PrevIndex, outPrev.Value); - } - } - } - } - - if (_shouldTrackUnclaimed && tx is ClaimTransaction claimTransaction) - { - foreach (CoinReference input in claimTransaction.Claims) - { - TransactionState txPrev = transactionsCache[input.PrevHash]; - var outPrev = txPrev.Transaction.Outputs[input.PrevIndex]; - - var claimedCoinKey = - new UserSystemAssetCoinOutputsKey(true, outPrev.ScriptHash, input.PrevHash); - UserSystemAssetCoinOutputs spentUnclaimedOutputs = _userSpentUnclaimedCoins.GetAndChange( - claimedCoinKey, () => new UserSystemAssetCoinOutputs()); - spentUnclaimedOutputs.RemoveTxIndex(input.PrevIndex); - if (spentUnclaimedOutputs.AmountByTxIndex.Count == 0) - _userSpentUnclaimedCoins.Delete(claimedCoinKey); - - if (snapshot.SpentCoins.TryGet(input.PrevHash)?.Items.Remove(input.PrevIndex) == true) - snapshot.SpentCoins.GetAndChange(input.PrevHash); - } - } - } - - // Write the current height into the key of the prefix itself - _writeBatch.Put(SystemAssetUnspentCoinsPrefix, block.Index); - _lastPersistedBlock = block.Index; - return true; - } - - - private void ProcessSkippedBlocks(Snapshot snapshot) - { - for (uint blockIndex = _lastPersistedBlock + 1; blockIndex < snapshot.PersistingBlock.Index; blockIndex++) - { - var skippedBlock = Blockchain.Singleton.Store.GetBlock(blockIndex); - if (skippedBlock.Transactions.Length <= 1) - { - _lastPersistedBlock = skippedBlock.Index; - continue; - } - - _shouldPersistBlock = ProcessBlock(snapshot, skippedBlock); - OnCommit(snapshot); - } - } - - public void OnPersist(Snapshot snapshot, IReadOnlyList applicationExecutedList) - { - if (snapshot.PersistingBlock.Index > _lastPersistedBlock + 1) - ProcessSkippedBlocks(snapshot); - - _shouldPersistBlock = ProcessBlock(snapshot, snapshot.PersistingBlock); - } - - public void OnCommit(Snapshot snapshot) - { - if (!_shouldPersistBlock) return; - _userUnspentCoins.Commit(); - if (_shouldTrackUnclaimed) _userSpentUnclaimedCoins.Commit(); - _db.Write(WriteOptions.Default, _writeBatch); - } - - public bool ShouldThrowExceptionFromCommit(Exception ex) - { - return true; - } - - public void PreProcess(HttpContext context, string method, JArray _params) - { - } - - private UInt160 GetScriptHashFromParam(string addressOrScriptHash) - { - return addressOrScriptHash.Length < 40 ? - addressOrScriptHash.ToScriptHash() : UInt160.Parse(addressOrScriptHash); - } - - - private long GetSysFeeAmountForHeight(DataCache blocks, uint height) - { - return blocks.TryGet(Blockchain.Singleton.GetBlockHash(height)).SystemFeeAmount; - } - - private void CalculateClaimable(Snapshot snapshot, Fixed8 value, uint startHeight, uint endHeight, out Fixed8 generated, out Fixed8 sysFee) - { - uint amount = 0; - uint ustart = startHeight / Blockchain.DecrementInterval; - if (ustart < Blockchain.GenerationAmount.Length) - { - uint istart = startHeight % Blockchain.DecrementInterval; - uint uend = endHeight / Blockchain.DecrementInterval; - uint iend = endHeight % Blockchain.DecrementInterval; - if (uend >= Blockchain.GenerationAmount.Length) - { - uend = (uint)Blockchain.GenerationAmount.Length; - iend = 0; - } - if (iend == 0) - { - uend--; - iend = Blockchain.DecrementInterval; - } - while (ustart < uend) - { - amount += (Blockchain.DecrementInterval - istart) * Blockchain.GenerationAmount[ustart]; - ustart++; - istart = 0; - } - amount += (iend - istart) * Blockchain.GenerationAmount[ustart]; - } - - Fixed8 fractionalShare = value / 100000000; - generated = fractionalShare * amount; - sysFee = fractionalShare * (GetSysFeeAmountForHeight(snapshot.Blocks, endHeight - 1) - - (startHeight == 0 ? 0 : GetSysFeeAmountForHeight(snapshot.Blocks, startHeight - 1))); - } - - private bool AddClaims(JArray claimableOutput, ref Fixed8 runningTotal, int maxClaims, - Snapshot snapshot, DataCache storeSpentCoins, - KeyValuePair claimableInTx) - { - foreach (var claimTransaction in claimableInTx.Value.AmountByTxIndex) - { - var utxo = new JObject(); - var txId = claimableInTx.Key.TxHash.ToString().Substring(2); - utxo["txid"] = txId; - utxo["n"] = claimTransaction.Key; - var spentCoinState = storeSpentCoins.TryGet(claimableInTx.Key.TxHash); - var startHeight = spentCoinState.TransactionHeight; - var endHeight = spentCoinState.Items[claimTransaction.Key]; - CalculateClaimable(snapshot, claimTransaction.Value, startHeight, endHeight, out var generated, - out var sysFee); - var unclaimed = generated + sysFee; - utxo["value"] = (double) (decimal) claimTransaction.Value; - utxo["start_height"] = startHeight; - utxo["end_height"] = endHeight; - utxo["generated"] = (double) (decimal) generated; - utxo["sys_fee"] = (double) (decimal) sysFee; - utxo["unclaimed"] = (double) (decimal) unclaimed; - runningTotal += unclaimed; - claimableOutput.Add(utxo); - if (claimableOutput.Count > maxClaims) - return false; - } - - return true; - } - - private JObject ProcessGetClaimableSpents(JArray parameters) - { - UInt160 scriptHash = GetScriptHashFromParam(parameters[0].AsString()); - var dbCache = new DbCache( - _db, null, null, SystemAssetSpentUnclaimedCoinsPrefix); - - JObject json = new JObject(); - JArray claimable = new JArray(); - json["claimable"] = claimable; - json["address"] = scriptHash.ToAddress(); - - Fixed8 totalUnclaimed = Fixed8.Zero; - using (Snapshot snapshot = Blockchain.Singleton.GetSnapshot()) - { - var storeSpentCoins = snapshot.SpentCoins; - byte[] prefix = new [] { (byte) 1 }.Concat(scriptHash.ToArray()).ToArray(); - foreach (var claimableInTx in dbCache.Find(prefix)) - if (!AddClaims(claimable, ref totalUnclaimed, _rpcMaxUnspents, snapshot, storeSpentCoins, - claimableInTx)) - break; - } - json["unclaimed"] = (double) (decimal) totalUnclaimed; - return json; - } - - private JObject ProcessGetUnclaimed(JArray parameters) - { - UInt160 scriptHash = GetScriptHashFromParam(parameters[0].AsString()); - JObject json = new JObject(); - - Fixed8 available = Fixed8.Zero; - Fixed8 unavailable = Fixed8.Zero; - var spentsCache = new DbCache( - _db, null, null, SystemAssetSpentUnclaimedCoinsPrefix); - var unspentsCache = new DbCache( - _db, null, null, SystemAssetUnspentCoinsPrefix); - using (Snapshot snapshot = Blockchain.Singleton.GetSnapshot()) - { - var storeSpentCoins = snapshot.SpentCoins; - byte[] prefix = new [] { (byte) 1 }.Concat(scriptHash.ToArray()).ToArray(); - foreach (var claimableInTx in spentsCache.Find(prefix)) - { - var spentCoinState = storeSpentCoins.TryGet(claimableInTx.Key.TxHash); - foreach (var claimTxIndex in claimableInTx.Value.AmountByTxIndex) - { - var startHeight = spentCoinState.TransactionHeight; - var endHeight = spentCoinState.Items[claimTxIndex.Key]; - CalculateClaimable(snapshot, claimTxIndex.Value, startHeight, endHeight, out var generated, - out var sysFee); - available += generated + sysFee; - } - } - - var transactionsCache = snapshot.Transactions; - foreach (var claimableInTx in unspentsCache.Find(prefix)) - { - var transaction = transactionsCache.TryGet(claimableInTx.Key.TxHash); - - foreach (var claimTxIndex in claimableInTx.Value.AmountByTxIndex) - { - var startHeight = transaction.BlockIndex; - var endHeight = Blockchain.Singleton.Height; - CalculateClaimable(snapshot, claimTxIndex.Value, startHeight, endHeight, - out var generated, - out var sysFee); - unavailable += generated + sysFee; - } - } - } - - json["available"] = (double) (decimal) available; - json["unavailable"] = (double) (decimal) unavailable; - json["unclaimed"] = (double) (decimal) (available + unavailable); - return json; - } - - private bool AddUnspents(JArray unspents, ref Fixed8 runningTotal, - KeyValuePair unspentInTx) - { - var txId = unspentInTx.Key.TxHash.ToString().Substring(2); - foreach (var unspent in unspentInTx.Value.AmountByTxIndex) - { - var utxo = new JObject(); - utxo["txid"] = txId; - utxo["n"] = unspent.Key; - utxo["value"] = (double) (decimal) unspent.Value; - runningTotal += unspent.Value; - - unspents.Add(utxo); - if (unspents.Count > _rpcMaxUnspents) - return false; - } - return true; - } - - private JObject ProcessGetUnspents(JArray _params) - { - UInt160 scriptHash = GetScriptHashFromParam(_params[0].AsString()); - byte startingToken = 0; // 0 = Utility Token (GAS), 1 = Governing Token (NEO) - int maxIterations = 2; - - if (_params.Count > 1) - { - maxIterations = 1; - bool isGoverningToken = _params[1].AsBoolean(); - if (isGoverningToken) startingToken = 1; - } - - var unspentsCache = new DbCache( - _db, null, null, SystemAssetUnspentCoinsPrefix); - - string[] nativeAssetNames = {"GAS", "NEO"}; - UInt256[] nativeAssetIds = {Blockchain.UtilityToken.Hash, Blockchain.GoverningToken.Hash}; - - JObject json = new JObject(); - JArray balances = new JArray(); - json["balance"] = balances; - json["address"] = scriptHash.ToAddress(); - for (byte tokenIndex = startingToken; maxIterations-- > 0; tokenIndex++) - { - byte[] prefix = new [] { tokenIndex }.Concat(scriptHash.ToArray()).ToArray(); - - var unspents = new JArray(); - Fixed8 total = new Fixed8(0); - - foreach (var unspentInTx in unspentsCache.Find(prefix)) - if (!AddUnspents(unspents, ref total, unspentInTx)) break; - - if (unspents.Count <= 0) continue; - - var balance = new JObject(); - balance["unspent"] = unspents; - balance["asset_hash"] = nativeAssetIds[tokenIndex].ToString().Substring(2); - balance["asset_symbol"] = balance["asset"] = nativeAssetNames[tokenIndex]; - balance["amount"] = new JNumber((double) (decimal) total); ; - balances.Add(balance); - } - - return json; - } - - public JObject OnProcess(HttpContext context, string method, JArray parameters) - { - if (_shouldTrackUnclaimed) - { - if (method == "getclaimable") return ProcessGetClaimableSpents(parameters); - if (method == "getunclaimed") return ProcessGetUnclaimed(parameters); - } - return method != "getunspents" ? null : ProcessGetUnspents(parameters); - } - - public void PostProcess(HttpContext context, string method, JArray _params, JObject result) - { - } - } -} diff --git a/RpcSystemAssetTracker/UserSystemAssetCoinOutputs.cs b/RpcSystemAssetTracker/UserSystemAssetCoinOutputs.cs deleted file mode 100644 index 9d6251ea6..000000000 --- a/RpcSystemAssetTracker/UserSystemAssetCoinOutputs.cs +++ /dev/null @@ -1,79 +0,0 @@ -using System.Collections.Generic; -using System.IO; -using Neo.IO; -using Neo.Ledger; - -namespace Neo.Plugins -{ - public class UserSystemAssetCoinOutputs : StateBase, ICloneable - { - public Fixed8 TotalAmount; - public Dictionary AmountByTxIndex; - - public override int Size => base.Size + TotalAmount.Size + sizeof(ushort) + - (AmountByTxIndex.Count * (sizeof(ushort) + sizeof(ulong))); - - public UserSystemAssetCoinOutputs() - { - TotalAmount = new Fixed8(0); - AmountByTxIndex = new Dictionary(); - } - - public void AddTxIndex(ushort index, Fixed8 amount) - { - TotalAmount += amount; - AmountByTxIndex.Add(index, amount); - } - - public bool RemoveTxIndex(ushort index) - { - if(AmountByTxIndex.TryGetValue(index, out Fixed8 amount)) - { - AmountByTxIndex.Remove(index); - TotalAmount -= amount; - return true; - } - - return false; - } - public UserSystemAssetCoinOutputs Clone() - { - return new UserSystemAssetCoinOutputs() - { - TotalAmount = TotalAmount, - AmountByTxIndex = new Dictionary(AmountByTxIndex) - }; - } - - public void FromReplica(UserSystemAssetCoinOutputs replica) - { - TotalAmount = replica.TotalAmount; - AmountByTxIndex = replica.AmountByTxIndex; - } - - public override void Serialize(BinaryWriter writer) - { - base.Serialize(writer); - writer.Write(TotalAmount); - writer.Write((ushort)AmountByTxIndex.Count); - foreach (KeyValuePair txIndex in AmountByTxIndex) - { - writer.Write(txIndex.Key); - writer.Write(txIndex.Value); - } - } - - public override void Deserialize(BinaryReader reader) - { - base.Deserialize(reader); - ((ISerializable)TotalAmount).Deserialize(reader); - ushort count = reader.ReadUInt16(); - for (int i = 0; i < count; i++) - { - ushort txIndex = reader.ReadUInt16(); - Fixed8 amount = reader.ReadSerializable(); - AmountByTxIndex.Add(txIndex, amount); - } - } - } -} \ No newline at end of file diff --git a/RpcSystemAssetTracker/UserSystemAssetCoinOutputsKey.cs b/RpcSystemAssetTracker/UserSystemAssetCoinOutputsKey.cs deleted file mode 100644 index 3e4439b50..000000000 --- a/RpcSystemAssetTracker/UserSystemAssetCoinOutputsKey.cs +++ /dev/null @@ -1,81 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using Neo.IO; - -namespace Neo.Plugins -{ - public class UserSystemAssetCoinOutputsKey : IComparable, IEquatable, - ISerializable - { - public bool IsGoverningToken; // It's either the governing token or the utility token - public readonly UInt160 UserAddress; - public readonly UInt256 TxHash; - - public int Size => 1 + UserAddress.Size + TxHash.Size; - - public bool Equals(UserSystemAssetCoinOutputsKey other) - { - if (ReferenceEquals(null, other)) return false; - if (ReferenceEquals(this, other)) return true; - return IsGoverningToken == other.IsGoverningToken && Equals(UserAddress, other.UserAddress) && Equals(TxHash, other.TxHash); - } - - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) return false; - if (ReferenceEquals(this, obj)) return true; - if (!(obj is UserSystemAssetCoinOutputsKey b)) return false; - return Equals(b); - } - - public int CompareTo(UserSystemAssetCoinOutputsKey other) - { - if (ReferenceEquals(this, other)) return 0; - if (ReferenceEquals(null, other)) return 1; - var isGoverningTokenComparison = IsGoverningToken.CompareTo(other.IsGoverningToken); - if (isGoverningTokenComparison != 0) return isGoverningTokenComparison; - var userAddressComparison = Comparer.Default.Compare(UserAddress, other.UserAddress); - if (userAddressComparison != 0) return userAddressComparison; - return Comparer.Default.Compare(TxHash, other.TxHash); - } - - public override int GetHashCode() - { - unchecked - { - var hashCode = IsGoverningToken.GetHashCode(); - hashCode = (hashCode * 397) ^ (UserAddress != null ? UserAddress.GetHashCode() : 0); - hashCode = (hashCode * 397) ^ (TxHash != null ? TxHash.GetHashCode() : 0); - return hashCode; - } - } - - public UserSystemAssetCoinOutputsKey() - { - UserAddress = new UInt160(); - TxHash = new UInt256(); - } - - public UserSystemAssetCoinOutputsKey(bool isGoverningToken, UInt160 userAddress, UInt256 txHash) - { - IsGoverningToken = isGoverningToken; - UserAddress = userAddress; - TxHash = txHash; - } - - public void Serialize(BinaryWriter writer) - { - writer.Write(IsGoverningToken); - writer.Write(UserAddress.ToArray()); - writer.Write(TxHash.ToArray()); - } - - public void Deserialize(BinaryReader reader) - { - IsGoverningToken = reader.ReadBoolean(); - ((ISerializable) UserAddress).Deserialize(reader); - ((ISerializable) TxHash).Deserialize(reader); - } - } -} \ No newline at end of file diff --git a/RpcWallet/RpcWallet.cs b/RpcWallet/RpcWallet.cs index 3d934b8b8..04e8759d3 100644 --- a/RpcWallet/RpcWallet.cs +++ b/RpcWallet/RpcWallet.cs @@ -8,10 +8,11 @@ using Neo.Network.RPC; using Neo.Persistence; using Neo.SmartContract; +using Neo.SmartContract.Native; using Neo.Wallets; using Neo.Wallets.NEP6; -using System.Collections.Generic; using System.Linq; +using System.Numerics; namespace Neo.Plugins { @@ -32,11 +33,6 @@ public JObject OnProcess(HttpContext context, string method, JArray _params) { switch (method) { - case "claimgas": - { - UInt160 to = _params.Count >= 1 ? _params[0].AsString().ToScriptHash() : null; - return ClaimGas(to); - } case "dumpprivkey": { UInt160 scriptHash = _params[0].AsString().ToScriptHash(); @@ -44,7 +40,7 @@ public JObject OnProcess(HttpContext context, string method, JArray _params) } case "getbalance": { - UIntBase asset_id = UIntBase.Parse(_params[0].AsString()); + UInt160 asset_id = UInt160.Parse(_params[0].AsString()); return GetBalance(asset_id); } case "getnewaddress": @@ -70,13 +66,12 @@ public JObject OnProcess(HttpContext context, string method, JArray _params) } case "sendfrom": { - UIntBase assetId = UIntBase.Parse(_params[0].AsString()); + UInt160 assetId = UInt160.Parse(_params[0].AsString()); UInt160 from = _params[1].AsString().ToScriptHash(); UInt160 to = _params[2].AsString().ToScriptHash(); string value = _params[3].AsString(); - Fixed8 fee = _params.Count >= 5 ? Fixed8.Parse(_params[4].AsString()) : Fixed8.Zero; - UInt160 change_address = _params.Count >= 6 ? _params[5].AsString().ToScriptHash() : null; - return SendFrom(assetId, from, to, value, fee, change_address); + long fee = _params.Count >= 5 ? long.Parse(_params[4].AsString()) : 0; + return SendFrom(assetId, from, to, value, fee); } case "sendmany": { @@ -88,18 +83,16 @@ public JObject OnProcess(HttpContext context, string method, JArray _params) to_start = 1; } JArray to = (JArray)_params[to_start + 0]; - Fixed8 fee = _params.Count >= to_start + 2 ? Fixed8.Parse(_params[to_start + 1].AsString()) : Fixed8.Zero; - UInt160 change_address = _params.Count >= to_start + 3 ? _params[to_start + 2].AsString().ToScriptHash() : null; - return SendMany(from, to, fee, change_address); + long fee = _params.Count >= to_start + 2 ? long.Parse(_params[to_start + 1].AsString()) : 0; + return SendMany(from, to, fee); } case "sendtoaddress": { - UIntBase assetId = UIntBase.Parse(_params[0].AsString()); + UInt160 assetId = UInt160.Parse(_params[0].AsString()); UInt160 scriptHash = _params[1].AsString().ToScriptHash(); string value = _params[2].AsString(); - Fixed8 fee = _params.Count >= 4 ? Fixed8.Parse(_params[3].AsString()) : Fixed8.Zero; - UInt160 change_address = _params.Count >= 5 ? _params[4].AsString().ToScriptHash() : null; - return SendToAddress(assetId, scriptHash, value, fee, change_address); + long fee = _params.Count >= 4 ? long.Parse(_params[3].AsString()) : 0; + return SendToAddress(assetId, scriptHash, value, fee); } default: return null; @@ -122,25 +115,17 @@ private void ProcessInvoke(JObject result) { if (Wallet != null) { - InvocationTransaction tx = new InvocationTransaction + Transaction tx = new Transaction { - Version = 1, - Script = result["script"].AsString().HexToBytes(), - Gas = Fixed8.Parse(result["gas_consumed"].AsString()) + Script = result["script"].AsString().HexToBytes() }; - tx.Gas -= Fixed8.FromDecimal(10); - if (tx.Gas < Fixed8.Zero) tx.Gas = Fixed8.Zero; - tx.Gas = tx.Gas.Ceiling(); - tx = Wallet.MakeTransaction(tx); - if (tx != null) - { - ContractParametersContext context = new ContractParametersContext(tx); - Wallet.Sign(context); - if (context.Completed) - tx.Witnesses = context.GetWitnesses(); - else - tx = null; - } + Wallet.FillTransaction(tx); + ContractParametersContext context = new ContractParametersContext(tx); + Wallet.Sign(context); + if (context.Completed) + tx.Witnesses = context.GetWitnesses(); + else + tx = null; result["tx"] = tx?.ToArray().ToHexString(); } } @@ -168,36 +153,6 @@ private JObject SignAndRelay(Transaction tx) } } - private JObject ClaimGas(UInt160 to) - { - CheckWallet(); - const int MAX_CLAIMS_AMOUNT = 50; - CoinReference[] claims = Wallet.GetUnclaimedCoins().Select(p => p.Reference).ToArray(); - if (claims.Length == 0) - throw new RpcException(-300, "No gas to claim"); - ClaimTransaction tx; - using (Snapshot snapshot = Blockchain.Singleton.GetSnapshot()) - { - tx = new ClaimTransaction - { - Claims = claims.Take(MAX_CLAIMS_AMOUNT).ToArray(), - Attributes = new TransactionAttribute[0], - Inputs = new CoinReference[0], - Outputs = new[] - { - new TransactionOutput - { - AssetId = Blockchain.UtilityToken.Hash, - Value = snapshot.CalculateBonus(claims.Take(MAX_CLAIMS_AMOUNT)), - ScriptHash = to ?? Wallet.GetChangeAddress() - } - } - - }; - } - return SignAndRelay(tx); - } - private JObject DumpPrivKey(UInt160 scriptHash) { CheckWallet(); @@ -205,21 +160,11 @@ private JObject DumpPrivKey(UInt160 scriptHash) return account.GetKey().Export(); } - private JObject GetBalance(UIntBase asset_id) + private JObject GetBalance(UInt160 asset_id) { CheckWallet(); JObject json = new JObject(); - switch (asset_id) - { - case UInt160 asset_id_160: //NEP-5 balance - json["balance"] = Wallet.GetAvailable(asset_id_160).ToString(); - break; - case UInt256 asset_id_256: //Global Assets balance - IEnumerable coins = Wallet.GetCoins().Where(p => !p.State.HasFlag(CoinState.Spent) && p.Output.AssetId.Equals(asset_id_256)); - json["balance"] = coins.Sum(p => p.Output.Value).ToString(); - json["confirmed"] = coins.Where(p => p.State.HasFlag(CoinState.Confirmed)).Sum(p => p.Output.Value).ToString(); - break; - } + json["balance"] = Wallet.GetAvailable(asset_id).ToString(); return json; } @@ -235,24 +180,13 @@ private JObject GetNewAddress() private JObject GetUnclaimedGas() { CheckWallet(); + BigInteger gas = BigInteger.Zero; using (Snapshot snapshot = Blockchain.Singleton.GetSnapshot()) - { - uint height = snapshot.Height + 1; - Fixed8 unavailable; - try - { - unavailable = snapshot.CalculateBonus(Wallet.FindUnspentCoins().Where(p => p.Output.AssetId.Equals(Blockchain.GoverningToken.Hash)).Select(p => p.Reference), height); - } - catch + foreach (UInt160 account in Wallet.GetAccounts().Select(p => p.ScriptHash)) { - unavailable = Fixed8.Zero; + gas += NativeContract.NEO.UnclaimedGas(snapshot, account, snapshot.Height + 1); } - return new JObject - { - ["available"] = snapshot.CalculateBonus(Wallet.GetUnclaimedCoins().Select(p => p.Reference)).ToString(), - ["unavailable"] = unavailable.ToString() - }; - } + return gas.ToString(); } private JObject GetWalletHeight() @@ -290,14 +224,14 @@ private JObject ListAddress() }).ToArray(); } - private JObject SendFrom(UIntBase assetId, UInt160 from, UInt160 to, string value, Fixed8 fee, UInt160 change_address) + private JObject SendFrom(UInt160 assetId, UInt160 from, UInt160 to, string value, long fee) { CheckWallet(); AssetDescriptor descriptor = new AssetDescriptor(assetId); BigDecimal amount = BigDecimal.Parse(value, descriptor.Decimals); if (amount.Sign <= 0) throw new RpcException(-32602, "Invalid params"); - if (fee < Fixed8.Zero) + if (fee < 0) throw new RpcException(-32602, "Invalid params"); Transaction tx = Wallet.MakeTransaction(null, new[] { @@ -307,7 +241,7 @@ private JObject SendFrom(UIntBase assetId, UInt160 from, UInt160 to, string valu Value = amount, ScriptHash = to } - }, from: from, change_address: change_address, fee: fee); + }, from: from, net_fee: fee); if (tx == null) throw new RpcException(-300, "Insufficient funds"); @@ -318,29 +252,16 @@ private JObject SendFrom(UIntBase assetId, UInt160 from, UInt160 to, string valu tx.Witnesses = transContext.GetWitnesses(); if (tx.Size > 1024) { - Fixed8 calFee = Fixed8.FromDecimal(tx.Size * 0.00001m + 0.001m); - if (fee < calFee) - { - fee = calFee; - tx = Wallet.MakeTransaction(null, new[] - { - new TransferOutput - { - AssetId = assetId, - Value = amount, - ScriptHash = to - } - }, from: from, change_address: change_address, fee: fee); - if (tx == null) - throw new RpcException(-300, "Insufficient funds"); - } + long calFee = tx.Size * 1000 + 100000; + if (tx.NetworkFee < calFee) + tx.NetworkFee = calFee; } - if (fee > Settings.Default.MaxFee) + if (tx.NetworkFee > Settings.Default.MaxFee) throw new RpcException(-301, "The necessary fee is more than the Max_fee, this transaction is failed. Please increase your Max_fee value."); return SignAndRelay(tx); } - private JObject SendMany(UInt160 from, JArray to, Fixed8 fee, UInt160 change_address) + private JObject SendMany(UInt160 from, JArray to, long fee) { CheckWallet(); if (to.Count == 0) @@ -348,7 +269,7 @@ private JObject SendMany(UInt160 from, JArray to, Fixed8 fee, UInt160 change_add TransferOutput[] outputs = new TransferOutput[to.Count]; for (int i = 0; i < to.Count; i++) { - UIntBase asset_id = UIntBase.Parse(to[i]["asset"].AsString()); + UInt160 asset_id = UInt160.Parse(to[i]["asset"].AsString()); AssetDescriptor descriptor = new AssetDescriptor(asset_id); outputs[i] = new TransferOutput { @@ -359,9 +280,9 @@ private JObject SendMany(UInt160 from, JArray to, Fixed8 fee, UInt160 change_add if (outputs[i].Value.Sign <= 0) throw new RpcException(-32602, "Invalid params"); } - if (fee < Fixed8.Zero) + if (fee < 0) throw new RpcException(-32602, "Invalid params"); - Transaction tx = Wallet.MakeTransaction(null, outputs, from: from, change_address: change_address, fee: fee); + Transaction tx = Wallet.MakeTransaction(null, outputs, from: from, net_fee: fee); if (tx == null) throw new RpcException(-300, "Insufficient funds"); @@ -372,28 +293,23 @@ private JObject SendMany(UInt160 from, JArray to, Fixed8 fee, UInt160 change_add tx.Witnesses = transContext.GetWitnesses(); if (tx.Size > 1024) { - Fixed8 calFee = Fixed8.FromDecimal(tx.Size * 0.00001m + 0.001m); - if (fee < calFee) - { - fee = calFee; - tx = Wallet.MakeTransaction(null, outputs, from: from, change_address: change_address, fee: fee); - if (tx == null) - throw new RpcException(-300, "Insufficient funds"); - } + long calFee = tx.Size * 1000 + 100000; + if (tx.NetworkFee < calFee) + tx.NetworkFee = calFee; } - if (fee > Settings.Default.MaxFee) + if (tx.NetworkFee > Settings.Default.MaxFee) throw new RpcException(-301, "The necessary fee is more than the Max_fee, this transaction is failed. Please increase your Max_fee value."); return SignAndRelay(tx); } - private JObject SendToAddress(UIntBase assetId, UInt160 scriptHash, string value, Fixed8 fee, UInt160 change_address) + private JObject SendToAddress(UInt160 assetId, UInt160 scriptHash, string value, long fee) { CheckWallet(); AssetDescriptor descriptor = new AssetDescriptor(assetId); BigDecimal amount = BigDecimal.Parse(value, descriptor.Decimals); if (amount.Sign <= 0) throw new RpcException(-32602, "Invalid params"); - if (fee < Fixed8.Zero) + if (fee < 0) throw new RpcException(-32602, "Invalid params"); Transaction tx = Wallet.MakeTransaction(null, new[] { @@ -403,7 +319,7 @@ private JObject SendToAddress(UIntBase assetId, UInt160 scriptHash, string value Value = amount, ScriptHash = scriptHash } - }, change_address: change_address, fee: fee); + }, net_fee: fee); if (tx == null) throw new RpcException(-300, "Insufficient funds"); @@ -414,24 +330,11 @@ private JObject SendToAddress(UIntBase assetId, UInt160 scriptHash, string value tx.Witnesses = transContext.GetWitnesses(); if (tx.Size > 1024) { - Fixed8 calFee = Fixed8.FromDecimal(tx.Size * 0.00001m + 0.001m); - if (fee < calFee) - { - fee = calFee; - tx = Wallet.MakeTransaction(null, new[] - { - new TransferOutput - { - AssetId = assetId, - Value = amount, - ScriptHash = scriptHash - } - }, change_address: change_address, fee: fee); - if (tx == null) - throw new RpcException(-300, "Insufficient funds"); - } + long calFee = tx.Size * 1000 + 100000; + if (tx.NetworkFee < calFee) + tx.NetworkFee = calFee; } - if (fee > Settings.Default.MaxFee) + if (tx.NetworkFee > Settings.Default.MaxFee) throw new RpcException(-301, "The necessary fee is more than the Max_fee, this transaction is failed. Please increase your Max_fee value."); return SignAndRelay(tx); } diff --git a/RpcWallet/RpcWallet.csproj b/RpcWallet/RpcWallet.csproj index a8e7f0e76..04ee59222 100644 --- a/RpcWallet/RpcWallet.csproj +++ b/RpcWallet/RpcWallet.csproj @@ -14,7 +14,7 @@ - + diff --git a/RpcWallet/Settings.cs b/RpcWallet/Settings.cs index 1e94b2224..371032b5c 100644 --- a/RpcWallet/Settings.cs +++ b/RpcWallet/Settings.cs @@ -1,16 +1,17 @@ using Microsoft.Extensions.Configuration; +using Neo.SmartContract.Native; namespace Neo.Plugins { internal class Settings { - public Fixed8 MaxFee { get; } + public long MaxFee { get; } public static Settings Default { get; private set; } private Settings(IConfigurationSection section) { - this.MaxFee = Fixed8.Parse(section.GetValue("MaxFee", "0.1")); + this.MaxFee = (long)BigDecimal.Parse(section.GetValue("MaxFee", "0.1"), NativeContract.GAS.Decimals).Value; } public static void Load(IConfigurationSection section) diff --git a/SimplePolicy.UnitTests/UT_SimplePolicy.cs b/SimplePolicy.UnitTests/UT_SimplePolicy.cs index f22d6aff9..00d1dc794 100644 --- a/SimplePolicy.UnitTests/UT_SimplePolicy.cs +++ b/SimplePolicy.UnitTests/UT_SimplePolicy.cs @@ -6,9 +6,6 @@ using Neo.Persistence; using Settings = Neo.Plugins.Settings; using System.Collections.Generic; -using Neo.Cryptography; -using System.Numerics; -using System.Collections; using System.Linq; using System; using Moq; @@ -35,132 +32,16 @@ public void TestMaxTransactionsPerBlock() Settings.Default.MaxFreeTransactionsPerBlock.Should().Be(20); } - - [TestMethod] - public void TestFilterForBlock_ClaimHasPriority() - { - // Should contain "ClaimTransaction" in "HighPriorityTxType" - Settings.Default.HighPriorityTxType.Contains(TransactionType.ClaimTransaction).Should().Be(true); - - ClaimTransaction claimTxZero1 = GetClaimTransaction(0); - claimTxZero1.Size.Should().Be(7 + 21); // 7 + 21 (random script) - claimTxZero1.Hash.ToString().Should().Be("0x60037520be0fd903703c2b67973296f22cac8932db07a2723addf79478aea75f"); - ClaimTransaction claimTxZero2 = GetClaimTransaction(0); - claimTxZero2.Size.Should().Be(7 + 21); // 7 + 21 (random script) - claimTxZero2.Hash.ToString().Should().Be("0xb29426673b3ef5c226bd35d53c2cb2242e09c06f0efe9c0d5be2034f41cb85ba"); - ClaimTransaction claimTxZero3 = GetClaimTransaction(0); - claimTxZero3.Size.Should().Be(7 + 21); // 7 + 21 (random script) - claimTxZero3.Hash.ToString().Should().Be("0x01027faead9a0538048db7ac5657172f6e2240bff3f7d902e490bb1bd75c2df7"); - - //ClaimTransaction claimTxTwo = GetClaimTransaction(2); - //claimTxTwo.Size.Should().Be(75 + 21); // 2*34 + 7 + 21 - - ClaimTransaction claimTx30 = GetClaimTransaction(30); - claimTx30.Size.Should().Be(1027 + 21); // 30*34 + 7 + 21 - claimTx30.NetworkFee.Should().Be(Fixed8.Zero); - claimTx30.IsLowPriority.Should().Be(true); // by default is Low Priority, but plugin makes it High Priority - //uut.IsLowPriority -> cannot inspect because it's private... no problem! - - List TxList = new List(); - TxList.Insert(0, claimTxZero1); - TxList.Insert(0, claimTxZero2); - TxList.Insert(0, claimTxZero3); - TxList.Insert(0, claimTx30); - - //Console.WriteLine("Tx List Claim"); - //foreach(var tx in TxList) - // Console.WriteLine($"Claim TX fee: {tx.NetworkFee} size: {tx.Size} ratio: {tx.FeePerByte} hash: {tx.Hash}" ); - - - // ======================== BEGIN TESTS ============================ - - // insert 100 paid invocation transactions - for (var i = 0; i < 100; i++) - { - TxList.Insert(0, MockGenerateInvocationTransaction(Fixed8.One, 50).Object); - } - - // insert 100 low priority invocation transactions (18 satoshi + 82 zero) - for (var i = 0; i < 100; i++) - { - if (i < 18) - TxList.Insert(0, MockGenerateInvocationTransaction(Fixed8.Satoshi, 50).Object); - else - TxList.Insert(0, MockGenerateInvocationTransaction(Fixed8.Zero, 50).Object); - } - - TxList.Count().Should().Be(204); // 100 free + 100 paid + 4 claims - TxList.Where(tx => tx.NetworkFee == Fixed8.Zero).Count().Should().Be(100-18+4); // 82 fully free + 4 claims - - IEnumerable filteredTxList = uut.FilterForBlock(TxList); - //filteredTxList.Count().Should().Be(124); // 20 free + 100 paid + 4 claims - filteredTxList.Count().Should().Be(120); // 20 free (including 2 claims) + 100 paid - filteredTxList.Where(tx => tx.NetworkFee == Fixed8.Zero).Count().Should().Be(2); // 2 fully free (2 claims) - - // will select 20 low priority (including Claims) - var vx = filteredTxList.Where(tx => tx.IsLowPriority == true); - vx.Count().Should().Be(20); - - // two Claim Transaction will survive - vx = filteredTxList.Where(tx => tx.Type == TransactionType.ClaimTransaction); - vx.Count().Should().Be(2); - - // ================================================================= - - // insert more paid invocation transactions (400 of each) - for (var i = 0; i < 400; i++) - { - TxList.Insert(0, MockGenerateInvocationTransaction(Fixed8.One, 50).Object); - } - - // insert more free invocation transactions (400 of each) - for (var i = 0; i < 400; i++) - { - TxList.Insert(0, MockGenerateInvocationTransaction(Fixed8.Zero, 50).Object); - } - - TxList.Count().Should().Be(1004); // 500 free + 500 paid + 4 claims - TxList.Where(tx => tx.NetworkFee == Fixed8.Zero).Count().Should().Be(400+100-18+4); // 500-18 fully free + 4 claims - - filteredTxList = uut.FilterForBlock(TxList); - filteredTxList.Count().Should().Be(499); // full block - - // will select 20 low priority (including Claims) - vx = filteredTxList.Where(tx => tx.IsLowPriority == true); - vx.Count().Should().Be(20); - - // will still select Claim Transactions - vx = filteredTxList.Where(tx => tx.Type == TransactionType.ClaimTransaction); - vx.Count().Should().Be(2); - - // there are 3 tied Claim tx, will solve it based on smaller hash (0x01, 0x60) => 0xb2 is excluded - // 0x01027faead9a0538048db7ac5657172f6e2240bff3f7d902e490bb1bd75c2df7 - // 0x60037520be0fd903703c2b67973296f22cac8932db07a2723addf79478aea75f - // 0xb29426673b3ef5c226bd35d53c2cb2242e09c06f0efe9c0d5be2034f41cb85ba - vx = filteredTxList.Where(tx => tx.Hash.ToString() == "0x01027faead9a0538048db7ac5657172f6e2240bff3f7d902e490bb1bd75c2df7"); - vx.Count().Should().Be(1); - vx = filteredTxList.Where(tx => tx.Hash.ToString() == "0x60037520be0fd903703c2b67973296f22cac8932db07a2723addf79478aea75f"); - vx.Count().Should().Be(1); - vx = filteredTxList.Where(tx => tx.Hash.ToString() == "0xb29426673b3ef5c226bd35d53c2cb2242e09c06f0efe9c0d5be2034f41cb85ba"); - vx.Count().Should().Be(0); - - //Console.WriteLine("filtered"); - //foreach(var tx in filteredTxList) - // Console.WriteLine($"TX fee: {tx.NetworkFee} size: {tx.Size} ratio: {tx.FeePerByte} hash: {tx.Hash}" ); - - } - - [TestMethod] public void FreeTxVerifySort_NoHighPriority() { List txList = new List(); // three different sizes, but it doesn't matter - for (var size = 10; size <= 20; size += 5) + for (var size = 100; size <= 200; size += 50) { for (var netFeeSatoshi = 0; netFeeSatoshi <= 90000; netFeeSatoshi += 10000) { - var testTx = MockGenerateInvocationTransaction(new Fixed8(netFeeSatoshi), size).Object; + var testTx = MockGenerateTransaction(netFeeSatoshi, size).Object; testTx.IsLowPriority.Should().Be(true); // "LowPriorityThreshold": 0.001 txList.Insert(0, testTx); } @@ -234,119 +115,57 @@ public void FreeTxVerifySort_NoHighPriority() */ // part A - filteredTxList.Where(tx => (tx.NetworkFee / tx.Size) >= new Fixed8(2500)).Count().Should().Be(18); // 18 enter in part A - txList.Where(tx => (tx.NetworkFee / tx.Size) >= new Fixed8(2500)).Count().Should().Be(18); // they also exist in main list - txList.Where(tx => (tx.NetworkFee / tx.Size) < new Fixed8(2500)).Count().Should().Be(30 - 18); // 12 not selected transactions in part A + filteredTxList.Where(tx => (tx.NetworkFee / tx.Size) >= 250).Count().Should().Be(18); // 18 enter in part A + txList.Where(tx => (tx.NetworkFee / tx.Size) >= 250).Count().Should().Be(18); // they also exist in main list + txList.Where(tx => (tx.NetworkFee / tx.Size) < 250).Count().Should().Be(30 - 18); // 12 not selected transactions in part A // part B - filteredTxList.Where(tx => (tx.NetworkFee / tx.Size) < new Fixed8(2500)).Count().Should().Be(2); // only two enter in part B - filteredTxList.Where(tx => (tx.NetworkFee / tx.Size) == new Fixed8(2000)).Count().Should().Be(2); // only two enter in part B with ratio 0.00002 - txList.Where(tx => (tx.NetworkFee / tx.Size) == new Fixed8(2000)).Count().Should().Be(3); // 3 in tie (ratio 0.00002) - txList.Where(tx => (tx.NetworkFee / tx.Size) == new Fixed8(2000) && (tx.NetworkFee > new Fixed8(20000))).Count().Should().Be(2); // only 2 survive (fee > 0.0002) + filteredTxList.Where(tx => (tx.NetworkFee / tx.Size) < 250).Count().Should().Be(2); // only two enter in part B + filteredTxList.Where(tx => (tx.NetworkFee / tx.Size) == 200).Count().Should().Be(2); // only two enter in part B with ratio 0.00002 + txList.Where(tx => (tx.NetworkFee / tx.Size) == 200).Count().Should().Be(3); // 3 in tie (ratio 0.00002) + txList.Where(tx => (tx.NetworkFee / tx.Size) == 200 && (tx.NetworkFee > 20000)).Count().Should().Be(2); // only 2 survive (fee > 0.0002) } - [TestMethod] - public void FreeTxVerifySortWithPriority() + public void TestMock_GenerateTransaction() { - List txList = new List(); - // three different sizes, but it doesn't matter - for (var size = 10; size <= 15; size += 5) - { - for (var netFeeSatoshi = 0; netFeeSatoshi <= 90000; netFeeSatoshi += 10000) - { - var testTx = MockGenerateInvocationTransaction(new Fixed8(netFeeSatoshi), size).Object; - testTx.IsLowPriority.Should().Be(true); // "LowPriorityThreshold": 0.001 - txList.Insert(0, testTx); - } - } - - txList.Insert(0, GetClaimTransaction(1)); - txList.Insert(0, GetClaimTransaction(10)); - txList.Insert(0, GetClaimTransaction(20)); - txList.Insert(0, GetClaimTransaction(30)); - - txList.Count.Should().Be(24); // 20 free + 4 claims - - IEnumerable filteredTxList = uut.FilterForBlock(txList); - filteredTxList.Count().Should().Be(20); - - filteredTxList.Where(tx => tx.Type == TransactionType.ClaimTransaction).Count().Should().Be(2); // 2 claims will be selected - } - - - [TestMethod] - public void TestMock_GenerateInvocationTransaction() - { - var txHighPriority = MockGenerateInvocationTransaction(Fixed8.One, 50); + var txHighPriority = MockGenerateTransaction(100000000, 50); // testing default values - Fixed8 txHighPriority_ratio = txHighPriority.Object.NetworkFee / txHighPriority.Object.Size; - txHighPriority_ratio.Should().Be(new Fixed8(2000000)); // 0.02 + long txHighPriority_ratio = txHighPriority.Object.NetworkFee / txHighPriority.Object.Size; + txHighPriority_ratio.Should().Be(2000000); // 0.02 txHighPriority.Object.IsLowPriority.Should().Be(false); - var txLowPriority = MockGenerateInvocationTransaction(Fixed8.One / 10000, 50); // 0.00001 + var txLowPriority = MockGenerateTransaction(100000000 / 10000, 50); // 0.00001 // testing default values - Fixed8 txLowPriority_ratio = txLowPriority.Object.NetworkFee / txLowPriority.Object.Size; - txLowPriority_ratio.Should().Be(new Fixed8(200)); // 0.000002 -> 200 satoshi / Byte + long txLowPriority_ratio = txLowPriority.Object.NetworkFee / txLowPriority.Object.Size; + txLowPriority_ratio.Should().Be(200); // 0.000002 -> 200 satoshi / Byte txLowPriority.Object.IsLowPriority.Should().Be(true); } // Generate Mock InvocationTransaction with different sizes and prices - public static Mock MockGenerateInvocationTransaction(Fixed8 networkFee, int size) + public static Mock MockGenerateTransaction(long networkFee, int size) { - var mockTx = new Mock(); - mockTx.SetupGet(mr => mr.NetworkFee).Returns(networkFee); - mockTx.SetupGet(mr => mr.Size).Returns(size); + var mockTx = new Mock + { + CallBase = true + }; - //============================== - //=== Generating random Hash === - mockTx.CallBase = true; mockTx.Setup(p => p.Verify(It.IsAny(), It.IsAny>())).Returns(true); var tx = mockTx.Object; - var randomBytes = new byte[16]; - _random.NextBytes(randomBytes); - tx.Script = randomBytes; + tx.Script = new byte[0]; + tx.Sender = UInt160.Zero; + tx.NetworkFee = networkFee; tx.Attributes = new TransactionAttribute[0]; - tx.Inputs = new CoinReference[0]; - tx.Outputs = new TransactionOutput[0]; tx.Witnesses = new Witness[0]; - //============================== - - return mockTx; - } - - // Create ClaimTransaction with 'countRefs' CoinReferences - public static ClaimTransaction GetClaimTransaction(int countRefs) - { - CoinReference[] refs = new CoinReference[countRefs]; - for (var i = 0; i < countRefs; i++) + int diff = size - tx.Size; + if (diff < 0) throw new InvalidOperationException(); + if (diff > 0) { - refs[i] = GetCoinReference(new UInt256(Crypto.Default.Hash256(new BigInteger(i).ToByteArray()))); + tx.Script = new byte[diff]; + _random.NextBytes(tx.Script); } - //============================== - //=== Generating random Hash === - var randomBytes = new byte[20]; - _random.NextBytes(randomBytes); - //============================== - return new ClaimTransaction - { - Claims = refs, - Attributes = new TransactionAttribute[]{new TransactionAttribute{Usage = TransactionAttributeUsage.Script, Data = randomBytes} }, - Inputs = new CoinReference[0], - Outputs = new TransactionOutput[0], - Witnesses = new Witness[0] - }; - } - - public static CoinReference GetCoinReference(UInt256 prevHash) - { - if (prevHash == null) prevHash = UInt256.Zero; - return new CoinReference - { - PrevHash = prevHash, - PrevIndex = 0 - }; + return mockTx; } } } diff --git a/SimplePolicy/Settings.cs b/SimplePolicy/Settings.cs index 146047788..36c4756a5 100644 --- a/SimplePolicy/Settings.cs +++ b/SimplePolicy/Settings.cs @@ -1,5 +1,5 @@ using Microsoft.Extensions.Configuration; -using Neo.Network.P2P.Payloads; +using Neo.SmartContract.Native; using Neo.Wallets; using System; using System.Collections.Generic; @@ -12,8 +12,7 @@ internal class Settings public int MaxTransactionsPerBlock { get; } public int MaxFreeTransactionsPerBlock { get; } public int MaxFreeTransactionSize { get; } - public Fixed8 FeePerExtraByte { get; } - public EnumSet HighPriorityTxType { get; } + public long FeePerExtraByte { get; } public BlockedAccounts BlockedAccounts { get; } public static Settings Default { get; private set; } @@ -23,8 +22,7 @@ private Settings(IConfigurationSection section) this.MaxTransactionsPerBlock = GetValueOrDefault(section.GetSection("MaxTransactionsPerBlock"), 500, p => int.Parse(p)); this.MaxFreeTransactionsPerBlock = GetValueOrDefault(section.GetSection("MaxFreeTransactionsPerBlock"), 20, p => int.Parse(p)); this.MaxFreeTransactionSize = GetValueOrDefault(section.GetSection("MaxFreeTransactionSize"), 1024, p => int.Parse(p)); - this.FeePerExtraByte = GetValueOrDefault(section.GetSection("FeePerExtraByte"), Fixed8.FromDecimal(0.00001M), p => Fixed8.Parse(p)); - this.HighPriorityTxType = new EnumSet(section.GetSection("HighPriorityTxType"), TransactionType.ClaimTransaction); + this.FeePerExtraByte = GetValueOrDefault(section.GetSection("FeePerExtraByte"), 1000L, p => (long)BigDecimal.Parse(p, NativeContract.GAS.Decimals).Value); this.BlockedAccounts = new BlockedAccounts(section.GetSection("BlockedAccounts")); } @@ -40,19 +38,6 @@ public static void Load(IConfigurationSection section) } } - internal class EnumSet : HashSet - where T : Enum - { - public EnumSet(IConfigurationSection section, params T[] defaultValues) - { - if (section.Exists()) - foreach (IConfigurationSection child in section.GetChildren()) - Add((T)Enum.Parse(typeof(T), child.Value)); - else - UnionWith(defaultValues); - } - } - internal enum PolicyType : byte { AllowAll, diff --git a/SimplePolicy/SimplePolicy.csproj b/SimplePolicy/SimplePolicy.csproj index b2001eac2..3f01397be 100644 --- a/SimplePolicy/SimplePolicy.csproj +++ b/SimplePolicy/SimplePolicy.csproj @@ -15,7 +15,7 @@ - + diff --git a/SimplePolicy/SimplePolicy/config.json b/SimplePolicy/SimplePolicy/config.json index bb49ca3d2..c17821e5e 100644 --- a/SimplePolicy/SimplePolicy/config.json +++ b/SimplePolicy/SimplePolicy/config.json @@ -4,10 +4,6 @@ "MaxFreeTransactionsPerBlock": 20, "MaxFreeTransactionSize": 1024, "FeePerExtraByte": 0.00001, - "HighPriorityTxType": - [ - "ClaimTransaction" - ], "BlockedAccounts": { "Type": "AllowAll", "List": [] diff --git a/SimplePolicy/SimplePolicyPlugin.cs b/SimplePolicy/SimplePolicyPlugin.cs index f6cfc487a..e28876589 100644 --- a/SimplePolicy/SimplePolicyPlugin.cs +++ b/SimplePolicy/SimplePolicyPlugin.cs @@ -29,11 +29,9 @@ public bool FilterForMemoryPool(Transaction tx) case PolicyType.AllowAll: return true; case PolicyType.AllowList: - return tx.Witnesses.All(p => Settings.Default.BlockedAccounts.List.Contains(p.VerificationScript.ToScriptHash())) || - tx.Outputs.All(p => Settings.Default.BlockedAccounts.List.Contains(p.ScriptHash)); + return tx.Witnesses.All(p => Settings.Default.BlockedAccounts.List.Contains(p.VerificationScript.ToScriptHash())); case PolicyType.DenyList: - return tx.Witnesses.All(p => !Settings.Default.BlockedAccounts.List.Contains(p.VerificationScript.ToScriptHash())) && - tx.Outputs.All(p => !Settings.Default.BlockedAccounts.List.Contains(p.ScriptHash)); + return tx.Witnesses.All(p => !Settings.Default.BlockedAccounts.List.Contains(p.VerificationScript.ToScriptHash())); default: return false; } @@ -50,7 +48,7 @@ public IEnumerable FilterForBlock(IEnumerable transact private static IEnumerable FilterForBlock_Policy1(IEnumerable transactions) { int count = 0, count_free = 0; - foreach (Transaction tx in transactions.OrderByDescending(p => p.NetworkFee / p.Size).ThenByDescending(p => p.NetworkFee).ThenByDescending(p => InHigherLowPriorityList(p))) + foreach (Transaction tx in transactions.OrderByDescending(p => p.NetworkFee / p.Size).ThenByDescending(p => p.NetworkFee)) { if (count++ >= Settings.Default.MaxTransactionsPerBlock - 1) break; if (!tx.IsLowPriority || count_free++ < Settings.Default.MaxFreeTransactionsPerBlock) @@ -66,7 +64,6 @@ private static IEnumerable FilterForBlock_Policy2(IEnumerable p.IsLowPriority) .OrderByDescending(p => p.NetworkFee / p.Size) .ThenByDescending(p => p.NetworkFee) - .ThenByDescending(p => InHigherLowPriorityList(p)) .ThenBy(p => p.Hash) .Take(Settings.Default.MaxFreeTransactionsPerBlock) .ToArray(); @@ -98,22 +95,17 @@ void ILogPlugin.Log(string source, LogLevel level, string message) private bool VerifySizeLimits(Transaction tx) { - if (InHigherLowPriorityList(tx)) return true; - // Not Allow free TX bigger than MaxFreeTransactionSize if (tx.IsLowPriority && tx.Size > Settings.Default.MaxFreeTransactionSize) return false; // Require proportional fee for TX bigger than MaxFreeTransactionSize if (tx.Size > Settings.Default.MaxFreeTransactionSize) { - Fixed8 fee = Settings.Default.FeePerExtraByte * (tx.Size - Settings.Default.MaxFreeTransactionSize); + long fee = Settings.Default.FeePerExtraByte * (tx.Size - Settings.Default.MaxFreeTransactionSize); if (tx.NetworkFee < fee) return false; } return true; } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool InHigherLowPriorityList(Transaction tx) => Settings.Default.HighPriorityTxType.Contains(tx.Type); } } diff --git a/StatesDumper/StatesDumper.csproj b/StatesDumper/StatesDumper.csproj index 0f848c148..532688d67 100644 --- a/StatesDumper/StatesDumper.csproj +++ b/StatesDumper/StatesDumper.csproj @@ -14,7 +14,7 @@ - + diff --git a/neo-plugins.sln b/neo-plugins.sln index 4c1f919f6..9df0cbc46 100644 --- a/neo-plugins.sln +++ b/neo-plugins.sln @@ -21,8 +21,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RpcNep5Tracker", "RpcNep5Tr EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CoreMetrics", "CoreMetrics\CoreMetrics.csproj", "{AEFFF003-3500-416B-AD9B-8C838C33C1F4}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RpcSystemAssetTracker", "RpcSystemAssetTracker\RpcSystemAssetTracker.csproj", "{D3C183C1-8C23-4566-8909-EBF468DAD67A}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -52,6 +50,7 @@ Global {0DA81327-DC81-4960-91C8-4C5F8B9B804C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {0DA81327-DC81-4960-91C8-4C5F8B9B804C}.Debug|Any CPU.Build.0 = Debug|Any CPU {0DA81327-DC81-4960-91C8-4C5F8B9B804C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0DA81327-DC81-4960-91C8-4C5F8B9B804C}.Release|Any CPU.Build.0 = Release|Any CPU {EF32A7E5-EDF9-438C-8041-8DA6E675A7FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {EF32A7E5-EDF9-438C-8041-8DA6E675A7FD}.Debug|Any CPU.Build.0 = Debug|Any CPU {EF32A7E5-EDF9-438C-8041-8DA6E675A7FD}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -64,10 +63,6 @@ Global {AEFFF003-3500-416B-AD9B-8C838C33C1F4}.Debug|Any CPU.Build.0 = Debug|Any CPU {AEFFF003-3500-416B-AD9B-8C838C33C1F4}.Release|Any CPU.ActiveCfg = Release|Any CPU {AEFFF003-3500-416B-AD9B-8C838C33C1F4}.Release|Any CPU.Build.0 = Release|Any CPU - {D3C183C1-8C23-4566-8909-EBF468DAD67A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D3C183C1-8C23-4566-8909-EBF468DAD67A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D3C183C1-8C23-4566-8909-EBF468DAD67A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D3C183C1-8C23-4566-8909-EBF468DAD67A}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From eabfd782242bda946311b8016ce4c8979fce05e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vitor=20Naz=C3=A1rio=20Coelho?= Date: Mon, 3 Jun 2019 13:08:26 -0300 Subject: [PATCH 065/183] Updating README - Removing Asset Tracker plugin (#104) Removing description of asset tracker plugin from NEO 3.0 plugins readme --- README.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/README.md b/README.md index 4b5a3170f..a8dae3592 100644 --- a/README.md +++ b/README.md @@ -39,9 +39,6 @@ Plugin that enables NEP5 tracking using LevelDB. ### RPC Security Improves security in RPC nodes. -### RPC System Asset Tracker -Plugin that enables Assets tracker. In particular, it enables RPC calls for `getunpents` and `claimables`. - ### Simple Policy Enables policies for Consensus or Seed Nodes. In particular, policies for accepting transactions in the mempool and managing them. From 3774004b6a4bb45034458fd90698079640f6079e Mon Sep 17 00:00:00 2001 From: Shargon Date: Sun, 14 Jul 2019 12:14:27 +0200 Subject: [PATCH 066/183] Prevent DoS with wrong files (#81) * Prevent DoS with wrong files * Constant * Throw exception * Clean --- ImportBlocks/BlockImporter.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ImportBlocks/BlockImporter.cs b/ImportBlocks/BlockImporter.cs index 8d5249c20..83d350f28 100644 --- a/ImportBlocks/BlockImporter.cs +++ b/ImportBlocks/BlockImporter.cs @@ -1,6 +1,7 @@ using Akka.Actor; using Neo.IO; using Neo.Ledger; +using Neo.Network.P2P; using Neo.Network.P2P.Payloads; using System; using System.Collections.Generic; @@ -38,7 +39,11 @@ private static IEnumerable GetBlocks(Stream stream, bool read_start = fal if (end <= Blockchain.Singleton.Height) yield break; for (uint height = start; height <= end; height++) { - byte[] array = r.ReadBytes(r.ReadInt32()); + var size = r.ReadInt32(); + if (size > Message.PayloadMaxSize) + throw new ArgumentException($"Block {height} exceeds the maximum allowed size"); + + byte[] array = r.ReadBytes(size); if (!CheckMaxOnImportHeight(height)) yield break; if (height > Blockchain.Singleton.Height) { From 9618682d5dd72c77b9f49a6d804e808d5c386a2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vitor=20Naz=C3=A1rio=20Coelho?= Date: Tue, 30 Jul 2019 11:20:06 -0300 Subject: [PATCH 067/183] Fixing uint to ulong for some plugins due to seconds to ms change (#107) * Fixing uint to ulong for some plugins * Removing .sln files * Updating nuget to more recent daily build --- CoreMetrics/CoreMetrics.cs | 2 +- CoreMetrics/CoreMetrics.csproj | 2 +- RpcNep5Tracker/Nep5TransferKey.cs | 6 +++--- RpcNep5Tracker/RpcNep5Tracker.csproj | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/CoreMetrics/CoreMetrics.cs b/CoreMetrics/CoreMetrics.cs index b9df0022e..4b2e62303 100644 --- a/CoreMetrics/CoreMetrics.cs +++ b/CoreMetrics/CoreMetrics.cs @@ -33,7 +33,7 @@ public void PostProcess(HttpContext context, string method, JArray _params, JObj private JObject GetBlocksTime(uint nBlocks, uint lastHeight) { // It is currently limited to query blocks generated in the last 24hours (86400 seconds) - uint maxNBlocksPerDay = 86400 / Blockchain.SecondsPerBlock; + uint maxNBlocksPerDay = 86400 / Blockchain.MillisecondsPerBlock * 1000; if (lastHeight != 0) { if (lastHeight >= Blockchain.Singleton.Height) diff --git a/CoreMetrics/CoreMetrics.csproj b/CoreMetrics/CoreMetrics.csproj index 91bb46e49..088f619a5 100644 --- a/CoreMetrics/CoreMetrics.csproj +++ b/CoreMetrics/CoreMetrics.csproj @@ -7,7 +7,7 @@ - + diff --git a/RpcNep5Tracker/Nep5TransferKey.cs b/RpcNep5Tracker/Nep5TransferKey.cs index a1892d54a..7ffeacef2 100644 --- a/RpcNep5Tracker/Nep5TransferKey.cs +++ b/RpcNep5Tracker/Nep5TransferKey.cs @@ -7,7 +7,7 @@ namespace Neo.Plugins public class Nep5TransferKey : IComparable, IEquatable, ISerializable { public readonly UInt160 UserScriptHash; - public uint Timestamp { get; private set; } + public ulong Timestamp { get; private set; } public readonly UInt160 AssetScriptHash; public ushort BlockXferNotificationIndex { get; private set; } @@ -17,7 +17,7 @@ public class Nep5TransferKey : IComparable, IEquatable - + From c8360313992c38b9a9866f84320e7ecd7dbd180d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vitor=20Naz=C3=A1rio=20Coelho?= Date: Wed, 31 Jul 2019 16:49:31 -0300 Subject: [PATCH 068/183] Removing SimplePolicy plugin (#110) * Clean SimplePolicy * Removing travis * Completely removing SimplePolicy * Updating readme * Re-adding travis * Dotnet restore on Travis * Cleaning .sln * Cleaning SP-UT --- .travis.yml | 7 +- README.md | 5 +- .../SimplePolicy.UnitTests.csproj | 28 --- SimplePolicy.UnitTests/UT_SimplePolicy.cs | 171 ------------------ SimplePolicy.UnitTests/protocol.json | 30 --- SimplePolicy/Helper.cs | 14 -- SimplePolicy/Settings.cs | 60 ------ SimplePolicy/SimplePolicy.csproj | 21 --- SimplePolicy/SimplePolicy/config.json | 12 -- SimplePolicy/SimplePolicyPlugin.cs | 111 ------------ neo-plugins.sln | 12 -- 11 files changed, 2 insertions(+), 469 deletions(-) delete mode 100644 SimplePolicy.UnitTests/SimplePolicy.UnitTests.csproj delete mode 100644 SimplePolicy.UnitTests/UT_SimplePolicy.cs delete mode 100644 SimplePolicy.UnitTests/protocol.json delete mode 100644 SimplePolicy/Helper.cs delete mode 100644 SimplePolicy/Settings.cs delete mode 100644 SimplePolicy/SimplePolicy.csproj delete mode 100644 SimplePolicy/SimplePolicy/config.json delete mode 100644 SimplePolicy/SimplePolicyPlugin.cs diff --git a/.travis.yml b/.travis.yml index 9695107d5..951b8c3e2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,10 +10,5 @@ osx_image: xcode9.1 mono: none dotnet: 2.1.300 -before_install: - - cd SimplePolicy.UnitTests - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then ulimit -n 2048; fi - -script: +script: - dotnet restore - - dotnet test diff --git a/README.md b/README.md index a8dae3592..6577f0dc9 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ A set of plugins that can be used inside the NEO core library. Check [here](http://docs.neo.org/en-us/node/plugin.html) for the official documentation. ## Using plugins -Plugins can be used to increase functionality, as well as providing policies definitions of the network. +Plugins can be used to increase functionality, as well as providing policies definitions of the network. One common example is to add the ApplicationLogs plugin in order to enable your node to create log files. To configure a plugin, do the following: @@ -39,8 +39,5 @@ Plugin that enables NEP5 tracking using LevelDB. ### RPC Security Improves security in RPC nodes. -### Simple Policy -Enables policies for Consensus or Seed Nodes. In particular, policies for accepting transactions in the mempool and managing them. - ### StatesDumper Exports NEO-CLI status data \(useful for debugging\). diff --git a/SimplePolicy.UnitTests/SimplePolicy.UnitTests.csproj b/SimplePolicy.UnitTests/SimplePolicy.UnitTests.csproj deleted file mode 100644 index 6fc475c8f..000000000 --- a/SimplePolicy.UnitTests/SimplePolicy.UnitTests.csproj +++ /dev/null @@ -1,28 +0,0 @@ - - - - Exe - netcoreapp2.0 - SimplePolicy.UnitTests - SimplePolicy.UnitTests - - - - - PreserveNewest - - - - - - - - - - - - - - - - diff --git a/SimplePolicy.UnitTests/UT_SimplePolicy.cs b/SimplePolicy.UnitTests/UT_SimplePolicy.cs deleted file mode 100644 index 00d1dc794..000000000 --- a/SimplePolicy.UnitTests/UT_SimplePolicy.cs +++ /dev/null @@ -1,171 +0,0 @@ -using FluentAssertions; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Neo.Plugins; -using Neo.Network.P2P.Payloads; -using Neo; -using Neo.Persistence; -using Settings = Neo.Plugins.Settings; -using System.Collections.Generic; -using System.Linq; -using System; -using Moq; - -namespace SimplePolicy.UnitTests -{ - [TestClass] - public class UT_SimplePolicy - { - private static Random _random = new Random(11121990); - - SimplePolicyPlugin uut; - - [TestInitialize] - public void TestSetup() - { - uut = new SimplePolicyPlugin(); - } - - [TestMethod] - public void TestMaxTransactionsPerBlock() - { - Settings.Default.MaxTransactionsPerBlock.Should().Be(500); - Settings.Default.MaxFreeTransactionsPerBlock.Should().Be(20); - } - - [TestMethod] - public void FreeTxVerifySort_NoHighPriority() - { - List txList = new List(); - // three different sizes, but it doesn't matter - for (var size = 100; size <= 200; size += 50) - { - for (var netFeeSatoshi = 0; netFeeSatoshi <= 90000; netFeeSatoshi += 10000) - { - var testTx = MockGenerateTransaction(netFeeSatoshi, size).Object; - testTx.IsLowPriority.Should().Be(true); // "LowPriorityThreshold": 0.001 - txList.Insert(0, testTx); - } - } - - txList.Count.Should().Be(30); - // transactions => size: [10, 15, 20] x price: [0 ... 90000, step by 10000] - //foreach(var tx in txList) - // Console.WriteLine($"TX fee: {tx.NetworkFee} size: {tx.Size} ratio: {tx.FeePerByte}"); - /* - TX fee: 0.0009 size: 20 ratio: 0.000045 - TX fee: 0.0008 size: 20 ratio: 0.00004 - TX fee: 0.0007 size: 20 ratio: 0.000035 - TX fee: 0.0006 size: 20 ratio: 0.00003 - TX fee: 0.0005 size: 20 ratio: 0.000025 - TX fee: 0.0004 size: 20 ratio: 0.00002 - TX fee: 0.0003 size: 20 ratio: 0.000015 - TX fee: 0.0002 size: 20 ratio: 0.00001 - TX fee: 0.0001 size: 20 ratio: 0.000005 - TX fee: 0 size: 20 ratio: 0 - TX fee: 0.0009 size: 15 ratio: 0.00006 - TX fee: 0.0008 size: 15 ratio: 0.00005333 - TX fee: 0.0007 size: 15 ratio: 0.00004666 - TX fee: 0.0006 size: 15 ratio: 0.00004 - TX fee: 0.0005 size: 15 ratio: 0.00003333 - TX fee: 0.0004 size: 15 ratio: 0.00002666 - TX fee: 0.0003 size: 15 ratio: 0.00002 - TX fee: 0.0002 size: 15 ratio: 0.00001333 - TX fee: 0.0001 size: 15 ratio: 0.00000666 - TX fee: 0 size: 15 ratio: 0 - TX fee: 0.0009 size: 10 ratio: 0.00009 - TX fee: 0.0008 size: 10 ratio: 0.00008 - TX fee: 0.0007 size: 10 ratio: 0.00007 - TX fee: 0.0006 size: 10 ratio: 0.00006 - TX fee: 0.0005 size: 10 ratio: 0.00005 - TX fee: 0.0004 size: 10 ratio: 0.00004 - TX fee: 0.0003 size: 10 ratio: 0.00003 - TX fee: 0.0002 size: 10 ratio: 0.00002 - TX fee: 0.0001 size: 10 ratio: 0.00001 - */ - - IEnumerable filteredTxList = uut.FilterForBlock(txList); - filteredTxList.Count().Should().Be(20); - - // will select top 20 - // part A: 18 transactions with ratio >= 0.000025 - // part B: 2 transactions with ratio = 0.00002 (but one with this ratio will be discarded, with fee 0.0002) - //foreach(var tx in filteredTxList) - // Console.WriteLine($"TX20 fee: {tx.NetworkFee} size: {tx.Size} ratio: {tx.NetworkFee / tx.Size}"); - /* - TX20 fee: 0.0009 size: 10 ratio: 0.00009 - TX20 fee: 0.0008 size: 10 ratio: 0.00008 - TX20 fee: 0.0007 size: 10 ratio: 0.00007 - TX20 fee: 0.0009 size: 15 ratio: 0.00006 - TX20 fee: 0.0006 size: 10 ratio: 0.00006 - TX20 fee: 0.0008 size: 15 ratio: 0.00005333 - TX20 fee: 0.0005 size: 10 ratio: 0.00005 - TX20 fee: 0.0007 size: 15 ratio: 0.00004666 - TX20 fee: 0.0009 size: 20 ratio: 0.000045 - TX20 fee: 0.0008 size: 20 ratio: 0.00004 - TX20 fee: 0.0006 size: 15 ratio: 0.00004 - TX20 fee: 0.0004 size: 10 ratio: 0.00004 - TX20 fee: 0.0007 size: 20 ratio: 0.000035 - TX20 fee: 0.0005 size: 15 ratio: 0.00003333 - TX20 fee: 0.0006 size: 20 ratio: 0.00003 - TX20 fee: 0.0003 size: 10 ratio: 0.00003 - TX20 fee: 0.0004 size: 15 ratio: 0.00002666 - TX20 fee: 0.0005 size: 20 ratio: 0.000025 - TX20 fee: 0.0004 size: 20 ratio: 0.00002 - TX20 fee: 0.0003 size: 15 ratio: 0.00002 - */ - - // part A - filteredTxList.Where(tx => (tx.NetworkFee / tx.Size) >= 250).Count().Should().Be(18); // 18 enter in part A - txList.Where(tx => (tx.NetworkFee / tx.Size) >= 250).Count().Should().Be(18); // they also exist in main list - txList.Where(tx => (tx.NetworkFee / tx.Size) < 250).Count().Should().Be(30 - 18); // 12 not selected transactions in part A - // part B - filteredTxList.Where(tx => (tx.NetworkFee / tx.Size) < 250).Count().Should().Be(2); // only two enter in part B - filteredTxList.Where(tx => (tx.NetworkFee / tx.Size) == 200).Count().Should().Be(2); // only two enter in part B with ratio 0.00002 - txList.Where(tx => (tx.NetworkFee / tx.Size) == 200).Count().Should().Be(3); // 3 in tie (ratio 0.00002) - txList.Where(tx => (tx.NetworkFee / tx.Size) == 200 && (tx.NetworkFee > 20000)).Count().Should().Be(2); // only 2 survive (fee > 0.0002) - } - - [TestMethod] - public void TestMock_GenerateTransaction() - { - var txHighPriority = MockGenerateTransaction(100000000, 50); - // testing default values - long txHighPriority_ratio = txHighPriority.Object.NetworkFee / txHighPriority.Object.Size; - txHighPriority_ratio.Should().Be(2000000); // 0.02 - txHighPriority.Object.IsLowPriority.Should().Be(false); - - var txLowPriority = MockGenerateTransaction(100000000 / 10000, 50); // 0.00001 - // testing default values - long txLowPriority_ratio = txLowPriority.Object.NetworkFee / txLowPriority.Object.Size; - txLowPriority_ratio.Should().Be(200); // 0.000002 -> 200 satoshi / Byte - txLowPriority.Object.IsLowPriority.Should().Be(true); - } - - // Generate Mock InvocationTransaction with different sizes and prices - public static Mock MockGenerateTransaction(long networkFee, int size) - { - var mockTx = new Mock - { - CallBase = true - }; - - mockTx.Setup(p => p.Verify(It.IsAny(), It.IsAny>())).Returns(true); - var tx = mockTx.Object; - tx.Script = new byte[0]; - tx.Sender = UInt160.Zero; - tx.NetworkFee = networkFee; - tx.Attributes = new TransactionAttribute[0]; - tx.Witnesses = new Witness[0]; - - int diff = size - tx.Size; - if (diff < 0) throw new InvalidOperationException(); - if (diff > 0) - { - tx.Script = new byte[diff]; - _random.NextBytes(tx.Script); - } - - return mockTx; - } - } -} diff --git a/SimplePolicy.UnitTests/protocol.json b/SimplePolicy.UnitTests/protocol.json deleted file mode 100644 index e770c2648..000000000 --- a/SimplePolicy.UnitTests/protocol.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "ProtocolConfiguration": { - "Magic": 7630401, - "AddressVersion": 23, - "SecondsPerBlock": 15, - "LowPriorityThreshold": 0.001, - "StandbyValidators": [ - "03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c", - "02df48f60e8f3e01c48ff40b9b7f1310d7a8b2a193188befe1c2e3df740e895093", - "03b8d9d5771d8f513aa0869b9cc8d50986403b78c6da36890638c3d46a5adce04a", - "02ca0e27697b9c248f6f16e085fd0061e26f44da85b58ee835c110caa5ec3ba554", - "024c7b7fb6c310fccf1ba33b082519d82964ea93868d676662d4a59ad548df0e7d", - "02aaec38470f6aad0042c6e877cfd8087d2676b0f516fddd362801b9bd3936399e", - "02486fd15702c4490a26703112a5cc1d0923fd697a33406bd5a1c00e0013b09a70" - ], - "SeedList": [ - "seed1.neo.org:10333", - "seed2.neo.org:10333", - "seed3.neo.org:10333", - "seed4.neo.org:10333", - "seed5.neo.org:10333" - ], - "SystemFee": { - "EnrollmentTransaction": 1000, - "IssueTransaction": 500, - "PublishTransaction": 500, - "RegisterTransaction": 10000 - } - } -} diff --git a/SimplePolicy/Helper.cs b/SimplePolicy/Helper.cs deleted file mode 100644 index 895731aaf..000000000 --- a/SimplePolicy/Helper.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Microsoft.Extensions.Configuration; -using System; - -namespace Neo.Plugins -{ - internal static class Helper - { - public static T GetValueOrDefault(this IConfigurationSection section, T defaultValue, Func selector) - { - if (section.Value == null) return defaultValue; - return selector(section.Value); - } - } -} diff --git a/SimplePolicy/Settings.cs b/SimplePolicy/Settings.cs deleted file mode 100644 index 36c4756a5..000000000 --- a/SimplePolicy/Settings.cs +++ /dev/null @@ -1,60 +0,0 @@ -using Microsoft.Extensions.Configuration; -using Neo.SmartContract.Native; -using Neo.Wallets; -using System; -using System.Collections.Generic; -using System.Linq; - -namespace Neo.Plugins -{ - internal class Settings - { - public int MaxTransactionsPerBlock { get; } - public int MaxFreeTransactionsPerBlock { get; } - public int MaxFreeTransactionSize { get; } - public long FeePerExtraByte { get; } - public BlockedAccounts BlockedAccounts { get; } - - public static Settings Default { get; private set; } - - private Settings(IConfigurationSection section) - { - this.MaxTransactionsPerBlock = GetValueOrDefault(section.GetSection("MaxTransactionsPerBlock"), 500, p => int.Parse(p)); - this.MaxFreeTransactionsPerBlock = GetValueOrDefault(section.GetSection("MaxFreeTransactionsPerBlock"), 20, p => int.Parse(p)); - this.MaxFreeTransactionSize = GetValueOrDefault(section.GetSection("MaxFreeTransactionSize"), 1024, p => int.Parse(p)); - this.FeePerExtraByte = GetValueOrDefault(section.GetSection("FeePerExtraByte"), 1000L, p => (long)BigDecimal.Parse(p, NativeContract.GAS.Decimals).Value); - this.BlockedAccounts = new BlockedAccounts(section.GetSection("BlockedAccounts")); - } - - public T GetValueOrDefault(IConfigurationSection section, T defaultValue, Func selector) - { - if (section.Value == null) return defaultValue; - return selector(section.Value); - } - - public static void Load(IConfigurationSection section) - { - Default = new Settings(section); - } - } - - internal enum PolicyType : byte - { - AllowAll, - DenyAll, - AllowList, - DenyList - } - - internal class BlockedAccounts - { - public PolicyType Type { get; } - public HashSet List { get; } - - public BlockedAccounts(IConfigurationSection section) - { - this.Type = section.GetSection("Type").GetValueOrDefault(PolicyType.AllowAll, p => (PolicyType)Enum.Parse(typeof(PolicyType), p, true)); - this.List = new HashSet(section.GetSection("List").GetChildren().Select(p => p.Value.ToScriptHash())); - } - } -} diff --git a/SimplePolicy/SimplePolicy.csproj b/SimplePolicy/SimplePolicy.csproj deleted file mode 100644 index 3f01397be..000000000 --- a/SimplePolicy/SimplePolicy.csproj +++ /dev/null @@ -1,21 +0,0 @@ - - - - 2.10.2 - netstandard2.0 - Neo.Plugins - latest - - - - - PreserveNewest - PreserveNewest - - - - - - - - diff --git a/SimplePolicy/SimplePolicy/config.json b/SimplePolicy/SimplePolicy/config.json deleted file mode 100644 index c17821e5e..000000000 --- a/SimplePolicy/SimplePolicy/config.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "PluginConfiguration": { - "MaxTransactionsPerBlock": 500, - "MaxFreeTransactionsPerBlock": 20, - "MaxFreeTransactionSize": 1024, - "FeePerExtraByte": 0.00001, - "BlockedAccounts": { - "Type": "AllowAll", - "List": [] - } - } -} \ No newline at end of file diff --git a/SimplePolicy/SimplePolicyPlugin.cs b/SimplePolicy/SimplePolicyPlugin.cs deleted file mode 100644 index e28876589..000000000 --- a/SimplePolicy/SimplePolicyPlugin.cs +++ /dev/null @@ -1,111 +0,0 @@ -using Neo.Consensus; -using Neo.Network.P2P.Payloads; -using Neo.SmartContract; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Runtime.CompilerServices; - -[assembly: InternalsVisibleTo("SimplePolicy.UnitTests")] - -namespace Neo.Plugins -{ - public class SimplePolicyPlugin : Plugin, ILogPlugin, IPolicyPlugin - { - private static readonly string log_dictionary = Path.Combine(AppContext.BaseDirectory, "Logs"); - - public override void Configure() - { - Settings.Load(GetConfiguration()); - } - - public bool FilterForMemoryPool(Transaction tx) - { - if (!VerifySizeLimits(tx)) return false; - - switch (Settings.Default.BlockedAccounts.Type) - { - case PolicyType.AllowAll: - return true; - case PolicyType.AllowList: - return tx.Witnesses.All(p => Settings.Default.BlockedAccounts.List.Contains(p.VerificationScript.ToScriptHash())); - case PolicyType.DenyList: - return tx.Witnesses.All(p => !Settings.Default.BlockedAccounts.List.Contains(p.VerificationScript.ToScriptHash())); - default: - return false; - } - } - - public IEnumerable FilterForBlock(IEnumerable transactions) - { - return FilterForBlock_Policy2(transactions); - } - - public int MaxTxPerBlock => Settings.Default.MaxTransactionsPerBlock; - public int MaxLowPriorityTxPerBlock => Settings.Default.MaxFreeTransactionsPerBlock; - - private static IEnumerable FilterForBlock_Policy1(IEnumerable transactions) - { - int count = 0, count_free = 0; - foreach (Transaction tx in transactions.OrderByDescending(p => p.NetworkFee / p.Size).ThenByDescending(p => p.NetworkFee)) - { - if (count++ >= Settings.Default.MaxTransactionsPerBlock - 1) break; - if (!tx.IsLowPriority || count_free++ < Settings.Default.MaxFreeTransactionsPerBlock) - yield return tx; - } - } - - private static IEnumerable FilterForBlock_Policy2(IEnumerable transactions) - { - if (!(transactions is IReadOnlyList tx_list)) - tx_list = transactions.ToArray(); - - Transaction[] free = tx_list.Where(p => p.IsLowPriority) - .OrderByDescending(p => p.NetworkFee / p.Size) - .ThenByDescending(p => p.NetworkFee) - .ThenBy(p => p.Hash) - .Take(Settings.Default.MaxFreeTransactionsPerBlock) - .ToArray(); - - Transaction[] non_free = tx_list.Where(p => !p.IsLowPriority) - .OrderByDescending(p => p.NetworkFee / p.Size) - .ThenByDescending(p => p.NetworkFee) - .ThenBy(p => p.Hash) - .Take(Settings.Default.MaxTransactionsPerBlock - free.Length - 1) - .ToArray(); - - return non_free.Concat(free); - } - - void ILogPlugin.Log(string source, LogLevel level, string message) - { - if (source != nameof(ConsensusService)) return; - DateTime now = DateTime.Now; - string line = $"[{now.TimeOfDay:hh\\:mm\\:ss\\.fff}] {message}"; - Console.WriteLine(line); - if (string.IsNullOrEmpty(log_dictionary)) return; - lock (log_dictionary) - { - Directory.CreateDirectory(log_dictionary); - string path = Path.Combine(log_dictionary, $"{now:yyyy-MM-dd}.log"); - File.AppendAllLines(path, new[] { line }); - } - } - - private bool VerifySizeLimits(Transaction tx) - { - // Not Allow free TX bigger than MaxFreeTransactionSize - if (tx.IsLowPriority && tx.Size > Settings.Default.MaxFreeTransactionSize) return false; - - // Require proportional fee for TX bigger than MaxFreeTransactionSize - if (tx.Size > Settings.Default.MaxFreeTransactionSize) - { - long fee = Settings.Default.FeePerExtraByte * (tx.Size - Settings.Default.MaxFreeTransactionSize); - - if (tx.NetworkFee < fee) return false; - } - return true; - } - } -} diff --git a/neo-plugins.sln b/neo-plugins.sln index 9df0cbc46..a5b749641 100644 --- a/neo-plugins.sln +++ b/neo-plugins.sln @@ -3,8 +3,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.28729.10 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SimplePolicy", "SimplePolicy\SimplePolicy.csproj", "{322C366E-F891-47FD-A039-0FEF79BCB6D5}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ApplicationLogs", "ApplicationLogs\ApplicationLogs.csproj", "{84DA8EA6-EF60-4FCD-B1C6-65C1A8323B3F}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RpcSecurity", "RpcSecurity\RpcSecurity.csproj", "{6800D782-8EC0-49E9-98C4-195C8F781A1F}" @@ -13,8 +11,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StatesDumper", "StatesDumpe EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImportBlocks", "ImportBlocks\ImportBlocks.csproj", "{B7A42984-57BB-4F8D-967B-23B0E841B726}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SimplePolicy.UnitTests", "SimplePolicy.UnitTests\SimplePolicy.UnitTests.csproj", "{0DA81327-DC81-4960-91C8-4C5F8B9B804C}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RpcWallet", "RpcWallet\RpcWallet.csproj", "{EF32A7E5-EDF9-438C-8041-8DA6E675A7FD}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RpcNep5Tracker", "RpcNep5Tracker\RpcNep5Tracker.csproj", "{BBE8AC15-12DF-4AF0-ABC1-F1557EB5DC8E}" @@ -27,10 +23,6 @@ Global Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {322C366E-F891-47FD-A039-0FEF79BCB6D5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {322C366E-F891-47FD-A039-0FEF79BCB6D5}.Debug|Any CPU.Build.0 = Debug|Any CPU - {322C366E-F891-47FD-A039-0FEF79BCB6D5}.Release|Any CPU.ActiveCfg = Release|Any CPU - {322C366E-F891-47FD-A039-0FEF79BCB6D5}.Release|Any CPU.Build.0 = Release|Any CPU {84DA8EA6-EF60-4FCD-B1C6-65C1A8323B3F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {84DA8EA6-EF60-4FCD-B1C6-65C1A8323B3F}.Debug|Any CPU.Build.0 = Debug|Any CPU {84DA8EA6-EF60-4FCD-B1C6-65C1A8323B3F}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -47,10 +39,6 @@ Global {B7A42984-57BB-4F8D-967B-23B0E841B726}.Debug|Any CPU.Build.0 = Debug|Any CPU {B7A42984-57BB-4F8D-967B-23B0E841B726}.Release|Any CPU.ActiveCfg = Release|Any CPU {B7A42984-57BB-4F8D-967B-23B0E841B726}.Release|Any CPU.Build.0 = Release|Any CPU - {0DA81327-DC81-4960-91C8-4C5F8B9B804C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0DA81327-DC81-4960-91C8-4C5F8B9B804C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0DA81327-DC81-4960-91C8-4C5F8B9B804C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0DA81327-DC81-4960-91C8-4C5F8B9B804C}.Release|Any CPU.Build.0 = Release|Any CPU {EF32A7E5-EDF9-438C-8041-8DA6E675A7FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {EF32A7E5-EDF9-438C-8041-8DA6E675A7FD}.Debug|Any CPU.Build.0 = Debug|Any CPU {EF32A7E5-EDF9-438C-8041-8DA6E675A7FD}.Release|Any CPU.ActiveCfg = Release|Any CPU From 36544d8f70e58f5046b529fb38d97dbb83e1a372 Mon Sep 17 00:00:00 2001 From: Shargon Date: Fri, 16 Aug 2019 13:09:17 +0300 Subject: [PATCH 069/183] SystemLog plugin (#117) --- SystemLog/ConsoleColorSet.cs | 51 +++++++++++++++++++++++++++++++++ SystemLog/Logger.cs | 49 +++++++++++++++++++++++++++++++ SystemLog/Settings.cs | 23 +++++++++++++++ SystemLog/SystemLog.csproj | 19 ++++++++++++ SystemLog/SystemLog/config.json | 7 +++++ neo-plugins.sln | 6 ++++ 6 files changed, 155 insertions(+) create mode 100644 SystemLog/ConsoleColorSet.cs create mode 100644 SystemLog/Logger.cs create mode 100644 SystemLog/Settings.cs create mode 100644 SystemLog/SystemLog.csproj create mode 100644 SystemLog/SystemLog/config.json diff --git a/SystemLog/ConsoleColorSet.cs b/SystemLog/ConsoleColorSet.cs new file mode 100644 index 000000000..e8fa58872 --- /dev/null +++ b/SystemLog/ConsoleColorSet.cs @@ -0,0 +1,51 @@ +using System; + +namespace Neo.Plugins +{ + internal class ConsoleColorSet + { + #region Constants + + public static readonly ConsoleColorSet Debug = new ConsoleColorSet(ConsoleColor.Cyan); + public static readonly ConsoleColorSet Info = new ConsoleColorSet(ConsoleColor.White); + public static readonly ConsoleColorSet Warning = new ConsoleColorSet(ConsoleColor.Yellow); + public static readonly ConsoleColorSet Error = new ConsoleColorSet(ConsoleColor.Red); + public static readonly ConsoleColorSet Fatal = new ConsoleColorSet(ConsoleColor.Red); + + #endregion + + public ConsoleColor Foreground; + public ConsoleColor Background; + + /// + /// Create a new color set with the current console colors + /// + public ConsoleColorSet() : this(Console.ForegroundColor, Console.BackgroundColor) { } + + /// + /// Create a new color set + /// + /// Foreground color + public ConsoleColorSet(ConsoleColor foreground) : this(foreground, Console.BackgroundColor) { } + + /// + /// Create a new color set + /// + /// Foreground color + /// Background color + public ConsoleColorSet(ConsoleColor foreground, ConsoleColor background) + { + Foreground = foreground; + Background = background; + } + + /// + /// Apply the current set + /// + public void Apply() + { + Console.ForegroundColor = Foreground; + Console.BackgroundColor = Background; + } + } +} \ No newline at end of file diff --git a/SystemLog/Logger.cs b/SystemLog/Logger.cs new file mode 100644 index 000000000..70ee1b392 --- /dev/null +++ b/SystemLog/Logger.cs @@ -0,0 +1,49 @@ +using System; +using System.IO; + +namespace Neo.Plugins +{ + public class Logger : Plugin, ILogPlugin + { + public override string Name => "SystemLogs"; + + public override void Configure() + { + Settings.Load(GetConfiguration()); + } + + public new void Log(string source, LogLevel level, string message) + { + lock (typeof(Logger)) + { + DateTime now = DateTime.Now; + var log = $"[{now.TimeOfDay:hh\\:mm\\:ss\\.fff}] {message}"; + + if (Settings.Default.ConsoleOutput) + { + var currentColor = new ConsoleColorSet(); + + switch (level) + { + case LogLevel.Debug: ConsoleColorSet.Debug.Apply(); break; + case LogLevel.Error: ConsoleColorSet.Error.Apply(); break; + case LogLevel.Fatal: ConsoleColorSet.Fatal.Apply(); break; + case LogLevel.Info: ConsoleColorSet.Info.Apply(); break; + case LogLevel.Warning: ConsoleColorSet.Warning.Apply(); break; + } + + Console.WriteLine(log); + currentColor.Apply(); + } + + if (!string.IsNullOrEmpty(Settings.Default.Path)) + { + var path = Path.Combine(Settings.Default.Path, source); + Directory.CreateDirectory(path); + path = Path.Combine(path, $"{now:yyyy-MM-dd}.log"); + File.AppendAllLines(path, new[] { $"[{level}]{log}" }); + } + } + } + } +} diff --git a/SystemLog/Settings.cs b/SystemLog/Settings.cs new file mode 100644 index 000000000..939a778aa --- /dev/null +++ b/SystemLog/Settings.cs @@ -0,0 +1,23 @@ +using Microsoft.Extensions.Configuration; + +namespace Neo.Plugins +{ + internal class Settings + { + public string Path { get; } + public bool ConsoleOutput { get; } + + public static Settings Default { get; private set; } + + private Settings(IConfigurationSection section) + { + this.Path = string.Format(section.GetSection("Path").Value, ProtocolSettings.Default.Magic.ToString("X8")); + this.ConsoleOutput = section.GetSection("ConsoleOutput").Get(); + } + + public static void Load(IConfigurationSection section) + { + Default = new Settings(section); + } + } +} \ No newline at end of file diff --git a/SystemLog/SystemLog.csproj b/SystemLog/SystemLog.csproj new file mode 100644 index 000000000..636ab88d2 --- /dev/null +++ b/SystemLog/SystemLog.csproj @@ -0,0 +1,19 @@ + + + + netstandard2.0 + Neo.Plugins + + + + + + + + + PreserveNewest + PreserveNewest + + + + diff --git a/SystemLog/SystemLog/config.json b/SystemLog/SystemLog/config.json new file mode 100644 index 000000000..8164bf7ce --- /dev/null +++ b/SystemLog/SystemLog/config.json @@ -0,0 +1,7 @@ +{ + "PluginConfiguration": + { + "Path": "SystemLogs_{0}", + "ConsoleOutput": true + } +} diff --git a/neo-plugins.sln b/neo-plugins.sln index a5b749641..a016e7d01 100644 --- a/neo-plugins.sln +++ b/neo-plugins.sln @@ -17,6 +17,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RpcNep5Tracker", "RpcNep5Tr EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CoreMetrics", "CoreMetrics\CoreMetrics.csproj", "{AEFFF003-3500-416B-AD9B-8C838C33C1F4}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SystemLog", "SystemLog\SystemLog.csproj", "{14DB62D5-0EA1-4A98-8656-1AA2D0345206}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -51,6 +53,10 @@ Global {AEFFF003-3500-416B-AD9B-8C838C33C1F4}.Debug|Any CPU.Build.0 = Debug|Any CPU {AEFFF003-3500-416B-AD9B-8C838C33C1F4}.Release|Any CPU.ActiveCfg = Release|Any CPU {AEFFF003-3500-416B-AD9B-8C838C33C1F4}.Release|Any CPU.Build.0 = Release|Any CPU + {14DB62D5-0EA1-4A98-8656-1AA2D0345206}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {14DB62D5-0EA1-4A98-8656-1AA2D0345206}.Debug|Any CPU.Build.0 = Debug|Any CPU + {14DB62D5-0EA1-4A98-8656-1AA2D0345206}.Release|Any CPU.ActiveCfg = Release|Any CPU + {14DB62D5-0EA1-4A98-8656-1AA2D0345206}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From b30acd54c65df48a5f6538437fafc46f0dd17689 Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Fri, 16 Aug 2019 18:15:04 +0800 Subject: [PATCH 070/183] CI00151 (#111) --- ApplicationLogs/ApplicationLogs.csproj | 2 +- ApplicationLogs/LogReader.cs | 4 +-- CoreMetrics/CoreMetrics.csproj | 2 +- ImportBlocks/ImportBlocks.csproj | 2 +- RpcNep5Tracker/RpcNep5Tracker.csproj | 2 +- RpcSecurity/RpcSecurity.csproj | 2 +- RpcWallet/RpcWallet.cs | 50 +++++++------------------- RpcWallet/RpcWallet.csproj | 2 +- StatesDumper/StatesDumper.csproj | 2 +- SystemLog/SystemLog.csproj | 2 +- 10 files changed, 23 insertions(+), 47 deletions(-) diff --git a/ApplicationLogs/ApplicationLogs.csproj b/ApplicationLogs/ApplicationLogs.csproj index ca2946f4e..0a446836d 100644 --- a/ApplicationLogs/ApplicationLogs.csproj +++ b/ApplicationLogs/ApplicationLogs.csproj @@ -14,7 +14,7 @@ - + diff --git a/ApplicationLogs/LogReader.cs b/ApplicationLogs/LogReader.cs index c316659d3..ccacde2db 100644 --- a/ApplicationLogs/LogReader.cs +++ b/ApplicationLogs/LogReader.cs @@ -52,7 +52,7 @@ public void OnPersist(Snapshot snapshot, IReadOnlyList - + diff --git a/ImportBlocks/ImportBlocks.csproj b/ImportBlocks/ImportBlocks.csproj index 56a2d5578..013eb9500 100644 --- a/ImportBlocks/ImportBlocks.csproj +++ b/ImportBlocks/ImportBlocks.csproj @@ -14,7 +14,7 @@ - + diff --git a/RpcNep5Tracker/RpcNep5Tracker.csproj b/RpcNep5Tracker/RpcNep5Tracker.csproj index 90b5e0803..3c1df5efd 100644 --- a/RpcNep5Tracker/RpcNep5Tracker.csproj +++ b/RpcNep5Tracker/RpcNep5Tracker.csproj @@ -12,6 +12,6 @@ - + diff --git a/RpcSecurity/RpcSecurity.csproj b/RpcSecurity/RpcSecurity.csproj index 77998bf66..5147ab011 100644 --- a/RpcSecurity/RpcSecurity.csproj +++ b/RpcSecurity/RpcSecurity.csproj @@ -14,7 +14,7 @@ - + diff --git a/RpcWallet/RpcWallet.cs b/RpcWallet/RpcWallet.cs index 04e8759d3..570e49190 100644 --- a/RpcWallet/RpcWallet.cs +++ b/RpcWallet/RpcWallet.cs @@ -51,10 +51,6 @@ public JObject OnProcess(HttpContext context, string method, JArray _params) { return GetUnclaimedGas(); } - case "getwalletheight": - { - return GetWalletHeight(); - } case "importprivkey": { string privkey = _params[0].AsString(); @@ -70,8 +66,7 @@ public JObject OnProcess(HttpContext context, string method, JArray _params) UInt160 from = _params[1].AsString().ToScriptHash(); UInt160 to = _params[2].AsString().ToScriptHash(); string value = _params[3].AsString(); - long fee = _params.Count >= 5 ? long.Parse(_params[4].AsString()) : 0; - return SendFrom(assetId, from, to, value, fee); + return SendFrom(assetId, from, to, value); } case "sendmany": { @@ -82,17 +77,15 @@ public JObject OnProcess(HttpContext context, string method, JArray _params) from = _params[0].AsString().ToScriptHash(); to_start = 1; } - JArray to = (JArray)_params[to_start + 0]; - long fee = _params.Count >= to_start + 2 ? long.Parse(_params[to_start + 1].AsString()) : 0; - return SendMany(from, to, fee); + JArray to = (JArray)_params[to_start]; + return SendMany(from, to); } case "sendtoaddress": { UInt160 assetId = UInt160.Parse(_params[0].AsString()); UInt160 scriptHash = _params[1].AsString().ToScriptHash(); string value = _params[2].AsString(); - long fee = _params.Count >= 4 ? long.Parse(_params[3].AsString()) : 0; - return SendToAddress(assetId, scriptHash, value, fee); + return SendToAddress(assetId, scriptHash, value); } default: return null; @@ -115,11 +108,7 @@ private void ProcessInvoke(JObject result) { if (Wallet != null) { - Transaction tx = new Transaction - { - Script = result["script"].AsString().HexToBytes() - }; - Wallet.FillTransaction(tx); + Transaction tx = Wallet.MakeTransaction(result["script"].AsString().HexToBytes()); ContractParametersContext context = new ContractParametersContext(tx); Wallet.Sign(context); if (context.Completed) @@ -143,7 +132,6 @@ private JObject SignAndRelay(Transaction tx) if (context.Completed) { tx.Witnesses = context.GetWitnesses(); - Wallet.ApplyTransaction(tx); System.LocalNode.Tell(new LocalNode.Relay { Inventory = tx }); return tx.ToJson(); } @@ -189,12 +177,6 @@ private JObject GetUnclaimedGas() return gas.ToString(); } - private JObject GetWalletHeight() - { - CheckWallet(); - return (Wallet.WalletHeight > 0) ? Wallet.WalletHeight - 1 : 0; - } - private JObject ImportPrivKey(string privkey) { CheckWallet(); @@ -224,16 +206,14 @@ private JObject ListAddress() }).ToArray(); } - private JObject SendFrom(UInt160 assetId, UInt160 from, UInt160 to, string value, long fee) + private JObject SendFrom(UInt160 assetId, UInt160 from, UInt160 to, string value) { CheckWallet(); AssetDescriptor descriptor = new AssetDescriptor(assetId); BigDecimal amount = BigDecimal.Parse(value, descriptor.Decimals); if (amount.Sign <= 0) throw new RpcException(-32602, "Invalid params"); - if (fee < 0) - throw new RpcException(-32602, "Invalid params"); - Transaction tx = Wallet.MakeTransaction(null, new[] + Transaction tx = Wallet.MakeTransaction(new[] { new TransferOutput { @@ -241,7 +221,7 @@ private JObject SendFrom(UInt160 assetId, UInt160 from, UInt160 to, string value Value = amount, ScriptHash = to } - }, from: from, net_fee: fee); + }, from); if (tx == null) throw new RpcException(-300, "Insufficient funds"); @@ -261,7 +241,7 @@ private JObject SendFrom(UInt160 assetId, UInt160 from, UInt160 to, string value return SignAndRelay(tx); } - private JObject SendMany(UInt160 from, JArray to, long fee) + private JObject SendMany(UInt160 from, JArray to) { CheckWallet(); if (to.Count == 0) @@ -280,9 +260,7 @@ private JObject SendMany(UInt160 from, JArray to, long fee) if (outputs[i].Value.Sign <= 0) throw new RpcException(-32602, "Invalid params"); } - if (fee < 0) - throw new RpcException(-32602, "Invalid params"); - Transaction tx = Wallet.MakeTransaction(null, outputs, from: from, net_fee: fee); + Transaction tx = Wallet.MakeTransaction(outputs, from); if (tx == null) throw new RpcException(-300, "Insufficient funds"); @@ -302,16 +280,14 @@ private JObject SendMany(UInt160 from, JArray to, long fee) return SignAndRelay(tx); } - private JObject SendToAddress(UInt160 assetId, UInt160 scriptHash, string value, long fee) + private JObject SendToAddress(UInt160 assetId, UInt160 scriptHash, string value) { CheckWallet(); AssetDescriptor descriptor = new AssetDescriptor(assetId); BigDecimal amount = BigDecimal.Parse(value, descriptor.Decimals); if (amount.Sign <= 0) throw new RpcException(-32602, "Invalid params"); - if (fee < 0) - throw new RpcException(-32602, "Invalid params"); - Transaction tx = Wallet.MakeTransaction(null, new[] + Transaction tx = Wallet.MakeTransaction(new[] { new TransferOutput { @@ -319,7 +295,7 @@ private JObject SendToAddress(UInt160 assetId, UInt160 scriptHash, string value, Value = amount, ScriptHash = scriptHash } - }, net_fee: fee); + }); if (tx == null) throw new RpcException(-300, "Insufficient funds"); diff --git a/RpcWallet/RpcWallet.csproj b/RpcWallet/RpcWallet.csproj index 04ee59222..9d25b652a 100644 --- a/RpcWallet/RpcWallet.csproj +++ b/RpcWallet/RpcWallet.csproj @@ -14,7 +14,7 @@ - + diff --git a/StatesDumper/StatesDumper.csproj b/StatesDumper/StatesDumper.csproj index 532688d67..4ff52770a 100644 --- a/StatesDumper/StatesDumper.csproj +++ b/StatesDumper/StatesDumper.csproj @@ -14,7 +14,7 @@ - + diff --git a/SystemLog/SystemLog.csproj b/SystemLog/SystemLog.csproj index 636ab88d2..02f0303fe 100644 --- a/SystemLog/SystemLog.csproj +++ b/SystemLog/SystemLog.csproj @@ -6,7 +6,7 @@ - + From 7bac2dc0720e370e16cc1a58a064518882e31d87 Mon Sep 17 00:00:00 2001 From: erikzhang Date: Thu, 22 Aug 2019 16:52:34 +0800 Subject: [PATCH 071/183] Remove `mintTokens` from RpcNep5Tracker --- RpcNep5Tracker/RpcNep5Tracker.cs | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/RpcNep5Tracker/RpcNep5Tracker.cs b/RpcNep5Tracker/RpcNep5Tracker.cs index 60599c160..d6c1855b0 100644 --- a/RpcNep5Tracker/RpcNep5Tracker.cs +++ b/RpcNep5Tracker/RpcNep5Tracker.cs @@ -32,7 +32,6 @@ public class RpcNep5Tracker : Plugin, IPersistencePlugin, IRpcPlugin private bool _shouldTrackHistory; private bool _recordNullAddressHistory; private uint _maxResults; - private bool _shouldTrackNonStandardMintTokensEvent; private Neo.IO.Data.LevelDB.Snapshot _levelDbSnapshot; public override void Configure() @@ -45,7 +44,6 @@ public override void Configure() _shouldTrackHistory = (GetConfiguration().GetSection("TrackHistory").Value ?? true.ToString()) != false.ToString(); _recordNullAddressHistory = (GetConfiguration().GetSection("RecordNullAddressHistory").Value ?? false.ToString()) != false.ToString(); _maxResults = uint.Parse(GetConfiguration().GetSection("MaxResults").Value ?? "1000"); - _shouldTrackNonStandardMintTokensEvent = (GetConfiguration().GetSection("TrackNonStandardMintTokens").Value ?? false.ToString()) != false.ToString(); } private void ResetBatch() @@ -103,27 +101,6 @@ private void HandleNotification(Snapshot snapshot, Transaction transaction, UInt // Event name should be encoded as a byte array. if (!(stateItems[0] is VM.Types.ByteArray)) return; var eventName = Encoding.UTF8.GetString(stateItems[0].GetByteArray()); - - if (_shouldTrackNonStandardMintTokensEvent && eventName == "mintTokens") - { - if (stateItems.Count < 4) return; - // This is not an official standard but at least one token uses it, and so it is needed for proper - // balance tracking to support all tokens in use. - if (!(stateItems[2] is VM.Types.ByteArray)) - return; - byte[] mintToBytes = stateItems[2].GetByteArray(); - if (mintToBytes.Length != 20) return; - var mintTo = new UInt160(mintToBytes); - - var mintAmountItem = stateItems[3]; - if (!(mintAmountItem is VM.Types.ByteArray || mintAmountItem is VM.Types.Integer)) - return; - - var toKey = new Nep5BalanceKey(mintTo, scriptHash); - if (!nep5BalancesChanged.ContainsKey(toKey)) nep5BalancesChanged.Add(toKey, new Nep5Balance()); - RecordTransferHistory(snapshot, scriptHash, UInt160.Zero, mintTo, mintAmountItem.GetBigInteger(), transaction.Hash, ref transferIndex); - return; - } if (eventName != "transfer") return; if (stateItems.Count < 4) return; From 3715bf7d5b1c777e195e8fc457ffc4b51700ccb2 Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Thu, 22 Aug 2019 18:33:36 +0800 Subject: [PATCH 072/183] Fixes deadlock in RpcNep5Tracker (#128) --- RpcNep5Tracker/RpcNep5Tracker.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/RpcNep5Tracker/RpcNep5Tracker.cs b/RpcNep5Tracker/RpcNep5Tracker.cs index d6c1855b0..56b1c03a4 100644 --- a/RpcNep5Tracker/RpcNep5Tracker.cs +++ b/RpcNep5Tracker/RpcNep5Tracker.cs @@ -12,6 +12,7 @@ using Neo.Wallets; using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Numerics; using System.Text; @@ -39,7 +40,7 @@ public override void Configure() if (_db == null) { var dbPath = GetConfiguration().GetSection("DBPath").Value ?? "Nep5BalanceData"; - _db = DB.Open(dbPath, new Options { CreateIfMissing = true }); + _db = DB.Open(Path.GetFullPath(dbPath), new Options { CreateIfMissing = true }); } _shouldTrackHistory = (GetConfiguration().GetSection("TrackHistory").Value ?? true.ToString()) != false.ToString(); _recordNullAddressHistory = (GetConfiguration().GetSection("RecordNullAddressHistory").Value ?? false.ToString()) != false.ToString(); From a6cf62f8297c96e80788f8d59a1fe1a2d4168cb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vitor=20Naz=C3=A1rio=20Coelho?= Date: Fri, 23 Aug 2019 01:55:37 +0400 Subject: [PATCH 073/183] Updating README with RPC Wallet and SystemLog (#126) --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 6577f0dc9..62e429ad2 100644 --- a/README.md +++ b/README.md @@ -39,5 +39,11 @@ Plugin that enables NEP5 tracking using LevelDB. ### RPC Security Improves security in RPC nodes. +### RPC Wallet +Client commands for wallet management functionalities, such as signing and invoking. + ### StatesDumper Exports NEO-CLI status data \(useful for debugging\). + +### SystemLog +Enables neo-cli Logging, with timestamps, by showing messages with different levels (differentiated by colors) \(useful for debugging\). From f8105d0907177ecc906909a0c5fb69fbad5b5285 Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Sat, 24 Aug 2019 19:28:58 +0800 Subject: [PATCH 074/183] Fix RpcNep5Tracker (#125) --- RpcNep5Tracker/Nep5TransferKey.cs | 28 ++++++++++++++++------------ RpcNep5Tracker/RpcNep5Tracker.cs | 23 ++++++++++++----------- RpcNep5Tracker/RpcNep5Tracker.csproj | 2 +- 3 files changed, 29 insertions(+), 24 deletions(-) diff --git a/RpcNep5Tracker/Nep5TransferKey.cs b/RpcNep5Tracker/Nep5TransferKey.cs index 7ffeacef2..69e7fc735 100644 --- a/RpcNep5Tracker/Nep5TransferKey.cs +++ b/RpcNep5Tracker/Nep5TransferKey.cs @@ -1,17 +1,21 @@ +using Neo.IO; using System; using System.IO; -using Neo.IO; namespace Neo.Plugins { public class Nep5TransferKey : IComparable, IEquatable, ISerializable { public readonly UInt160 UserScriptHash; - public ulong Timestamp { get; private set; } + public ulong TimestampMS { get; private set; } public readonly UInt160 AssetScriptHash; public ushort BlockXferNotificationIndex { get; private set; } - public int Size => 20 + sizeof(uint) + 20 + sizeof(ushort); + public int Size => + UInt160.Length + //UserScriptHash + sizeof(ulong) + //TimestampMS + UInt160.Length + //AssetScriptHash + sizeof(ushort); //BlockXferNotificationIndex public Nep5TransferKey() : this(new UInt160(), 0, new UInt160(), 0) { @@ -22,7 +26,7 @@ public Nep5TransferKey(UInt160 userScriptHash, ulong timestamp, UInt160 assetScr if (userScriptHash is null || assetScriptHash is null) throw new ArgumentNullException(); UserScriptHash = userScriptHash; - Timestamp = timestamp; + TimestampMS = timestamp; AssetScriptHash = assetScriptHash; BlockXferNotificationIndex = xferIndex; } @@ -33,7 +37,7 @@ public int CompareTo(Nep5TransferKey other) if (ReferenceEquals(this, other)) return 0; int result = UserScriptHash.CompareTo(other.UserScriptHash); if (result != 0) return result; - int result2 = Timestamp.CompareTo(other.Timestamp); + int result2 = TimestampMS.CompareTo(other.TimestampMS); if (result2 != 0) return result2; int result3 = AssetScriptHash.CompareTo(other.AssetScriptHash); if (result3 != 0) return result3; @@ -45,7 +49,7 @@ public bool Equals(Nep5TransferKey other) if (ReferenceEquals(null, other)) return false; if (ReferenceEquals(this, other)) return true; return UserScriptHash.Equals(other.UserScriptHash) - && Timestamp.Equals(other.Timestamp) && AssetScriptHash.Equals(other.AssetScriptHash) + && TimestampMS.Equals(other.TimestampMS) && AssetScriptHash.Equals(other.AssetScriptHash) && BlockXferNotificationIndex.Equals(other.BlockXferNotificationIndex); } @@ -59,7 +63,7 @@ public override int GetHashCode() unchecked { var hashCode = UserScriptHash.GetHashCode(); - hashCode = (hashCode * 397) ^ Timestamp.GetHashCode(); + hashCode = (hashCode * 397) ^ TimestampMS.GetHashCode(); hashCode = (hashCode * 397) ^ AssetScriptHash.GetHashCode(); hashCode = (hashCode * 397) ^ BlockXferNotificationIndex.GetHashCode(); return hashCode; @@ -69,7 +73,7 @@ public override int GetHashCode() public void Serialize(BinaryWriter writer) { writer.Write(UserScriptHash); - var timestampBytes = BitConverter.GetBytes(Timestamp); + var timestampBytes = BitConverter.GetBytes(TimestampMS); if (BitConverter.IsLittleEndian) Array.Reverse(timestampBytes); writer.Write(timestampBytes); writer.Write(AssetScriptHash); @@ -79,12 +83,12 @@ public void Serialize(BinaryWriter writer) public void Deserialize(BinaryReader reader) { ((ISerializable)UserScriptHash).Deserialize(reader); - byte[] timestampBytes = new byte[sizeof(uint)]; - reader.Read(timestampBytes, 0, sizeof(uint)); + byte[] timestampBytes = new byte[sizeof(ulong)]; + reader.Read(timestampBytes, 0, timestampBytes.Length); if (BitConverter.IsLittleEndian) Array.Reverse(timestampBytes); - Timestamp = BitConverter.ToUInt64(timestampBytes, 0); + TimestampMS = BitConverter.ToUInt64(timestampBytes, 0); ((ISerializable)AssetScriptHash).Deserialize(reader); BlockXferNotificationIndex = reader.ReadUInt16(); } } -} \ No newline at end of file +} diff --git a/RpcNep5Tracker/RpcNep5Tracker.cs b/RpcNep5Tracker/RpcNep5Tracker.cs index 56b1c03a4..a0118a03b 100644 --- a/RpcNep5Tracker/RpcNep5Tracker.cs +++ b/RpcNep5Tracker/RpcNep5Tracker.cs @@ -66,10 +66,12 @@ private void ResetBatch() private void RecordTransferHistory(Snapshot snapshot, UInt160 scriptHash, UInt160 from, UInt160 to, BigInteger amount, UInt256 txHash, ref ushort transferIndex) { if (!_shouldTrackHistory) return; + + Header header = snapshot.GetHeader(snapshot.Height); + if (_recordNullAddressHistory || from != UInt160.Zero) { - _transfersSent.Add(new Nep5TransferKey(from, - snapshot.GetHeader(snapshot.Height).Timestamp, scriptHash, transferIndex), + _transfersSent.Add(new Nep5TransferKey(from, header.Timestamp, scriptHash, transferIndex), new Nep5Transfer { Amount = amount, @@ -81,8 +83,7 @@ private void RecordTransferHistory(Snapshot snapshot, UInt160 scriptHash, UInt16 if (_recordNullAddressHistory || to != UInt160.Zero) { - _transfersReceived.Add(new Nep5TransferKey(to, - snapshot.GetHeader(snapshot.Height).Timestamp, scriptHash, transferIndex), + _transfersReceived.Add(new Nep5TransferKey(to, header.Timestamp, scriptHash, transferIndex), new Nep5Transfer { Amount = amount, @@ -102,7 +103,7 @@ private void HandleNotification(Snapshot snapshot, Transaction transaction, UInt // Event name should be encoded as a byte array. if (!(stateItems[0] is VM.Types.ByteArray)) return; var eventName = Encoding.UTF8.GetString(stateItems[0].GetByteArray()); - if (eventName != "transfer") return; + if (eventName != "Transfer") return; if (stateItems.Count < 4) return; if (!(stateItems[1] is null) && !(stateItems[1] is VM.Types.ByteArray)) @@ -166,7 +167,7 @@ public void OnPersist(Snapshot snapshot, IReadOnlyList _maxResults) break; JObject transfer = new JObject(); - transfer["timestamp"] = transferPair.Key.Timestamp; + transfer["timestamp"] = transferPair.Key.TimestampMS; transfer["asset_hash"] = transferPair.Key.AssetScriptHash.ToArray().Reverse().ToHexString(); transfer["transfer_address"] = transferPair.Value.UserScriptHash.ToAddress(); transfer["amount"] = transferPair.Value.Amount.ToString(); @@ -240,9 +241,9 @@ private JObject GetNep5Transfers(JArray _params) { UInt160 userScriptHash = GetScriptHashFromParam(_params[0].AsString()); // If start time not present, default to 1 week of history. - uint startTime = _params.Count > 1 ? (uint)_params[1].AsNumber() : - (DateTime.UtcNow - TimeSpan.FromDays(7)).ToTimestamp(); - uint endTime = _params.Count > 2 ? (uint)_params[2].AsNumber() : DateTime.UtcNow.ToTimestamp(); + ulong startTime = _params.Count > 1 ? (ulong)_params[1].AsNumber() : + (DateTime.UtcNow - TimeSpan.FromDays(7)).ToTimestampMS(); + ulong endTime = _params.Count > 2 ? (ulong)_params[2].AsNumber() : DateTime.UtcNow.ToTimestampMS(); if (endTime < startTime) throw new RpcException(-32602, "Invalid params"); diff --git a/RpcNep5Tracker/RpcNep5Tracker.csproj b/RpcNep5Tracker/RpcNep5Tracker.csproj index 3c1df5efd..d41ed830f 100644 --- a/RpcNep5Tracker/RpcNep5Tracker.csproj +++ b/RpcNep5Tracker/RpcNep5Tracker.csproj @@ -12,6 +12,6 @@ - + From 1c91346338c78537bec2760adfb363f3eb1619f5 Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Thu, 29 Aug 2019 15:12:34 +0800 Subject: [PATCH 075/183] Fixes output of `getbalance` (#132) --- RpcWallet/RpcWallet.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RpcWallet/RpcWallet.cs b/RpcWallet/RpcWallet.cs index 570e49190..b3b0e6a63 100644 --- a/RpcWallet/RpcWallet.cs +++ b/RpcWallet/RpcWallet.cs @@ -152,7 +152,7 @@ private JObject GetBalance(UInt160 asset_id) { CheckWallet(); JObject json = new JObject(); - json["balance"] = Wallet.GetAvailable(asset_id).ToString(); + json["balance"] = Wallet.GetAvailable(asset_id).Value.ToString(); return json; } From 42e74040cf76bd6a318c20a68df6a48affcd5cd8 Mon Sep 17 00:00:00 2001 From: zhangtao Date: Tue, 17 Sep 2019 17:37:49 +0800 Subject: [PATCH 076/183] Fix/memory (#135) * use Singleton.Store.GetBlock optimize memory cause * refactor --- ImportBlocks/ImportBlocks.cs | 100 +++++++++++++++++------------------ 1 file changed, 49 insertions(+), 51 deletions(-) diff --git a/ImportBlocks/ImportBlocks.cs b/ImportBlocks/ImportBlocks.cs index 8c7d37cd6..45143f3a4 100644 --- a/ImportBlocks/ImportBlocks.cs +++ b/ImportBlocks/ImportBlocks.cs @@ -19,79 +19,77 @@ public override void Configure() private bool OnExport(string[] args) { + bool writeStart; + uint start, count; + string path; if (args.Length < 2) return false; if (!string.Equals(args[1], "block", StringComparison.OrdinalIgnoreCase) && !string.Equals(args[1], "blocks", StringComparison.OrdinalIgnoreCase)) return false; - if (args.Length >= 3 && uint.TryParse(args[2], out uint start)) + if (args.Length >= 3 && uint.TryParse(args[2], out start)) { - if (start > Blockchain.Singleton.Height) - return true; - uint count = args.Length >= 4 ? uint.Parse(args[3]) : uint.MaxValue; + if (Blockchain.Singleton.Height < start) return true; + count = args.Length >= 4 ? uint.Parse(args[3]) : uint.MaxValue; count = Math.Min(count, Blockchain.Singleton.Height - start + 1); - uint end = start + count - 1; - string path = $"chain.{start}.acc"; - using (FileStream fs = new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None)) + path = $"chain.{start}.acc"; + writeStart = true; + } + else + { + start = 0; + count = Blockchain.Singleton.Height - start + 1; + path = args.Length >= 3 ? args[2] : "chain.acc"; + writeStart = false; + } + + WriteBlocks(start, count, path, writeStart); + + Console.WriteLine(); + return true; + } + + private void WriteBlocks(uint start, uint count, string path, bool writeStart) + { + uint end = start + count - 1; + using (FileStream fs = new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None, 4096, FileOptions.WriteThrough)) + { + if (fs.Length > 0) { - if (fs.Length > 0) + byte[] buffer = new byte[sizeof(uint)]; + if (writeStart) { fs.Seek(sizeof(uint), SeekOrigin.Begin); - byte[] buffer = new byte[sizeof(uint)]; fs.Read(buffer, 0, buffer.Length); start += BitConverter.ToUInt32(buffer, 0); fs.Seek(sizeof(uint), SeekOrigin.Begin); } else { - fs.Write(BitConverter.GetBytes(start), 0, sizeof(uint)); + fs.Read(buffer, 0, buffer.Length); + start = BitConverter.ToUInt32(buffer, 0); + fs.Seek(0, SeekOrigin.Begin); } - if (start <= end) - fs.Write(BitConverter.GetBytes(count), 0, sizeof(uint)); - fs.Seek(0, SeekOrigin.End); - using (Snapshot snapshot = Blockchain.Singleton.GetSnapshot()) - for (uint i = start; i <= end; i++) - { - Block block = snapshot.GetBlock(i); - byte[] array = block.ToArray(); - fs.Write(BitConverter.GetBytes(array.Length), 0, sizeof(int)); - fs.Write(array, 0, array.Length); - Console.SetCursorPosition(0, Console.CursorTop); - Console.Write($"[{i}/{end}]"); - } } - } - else - { - start = 0; - uint end = Blockchain.Singleton.Height; - uint count = end - start + 1; - string path = args.Length >= 3 ? args[2] : "chain.acc"; - using (FileStream fs = new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None)) + else { - if (fs.Length > 0) + if (writeStart) { - byte[] buffer = new byte[sizeof(uint)]; - fs.Read(buffer, 0, buffer.Length); - start = BitConverter.ToUInt32(buffer, 0); - fs.Seek(0, SeekOrigin.Begin); + fs.Write(BitConverter.GetBytes(start), 0, sizeof(uint)); } - if (start <= end) - fs.Write(BitConverter.GetBytes(count), 0, sizeof(uint)); - fs.Seek(0, SeekOrigin.End); - using (Snapshot snapshot = Blockchain.Singleton.GetSnapshot()) - for (uint i = start; i <= end; i++) - { - Block block = snapshot.GetBlock(i); - byte[] array = block.ToArray(); - fs.Write(BitConverter.GetBytes(array.Length), 0, sizeof(int)); - fs.Write(array, 0, array.Length); - Console.SetCursorPosition(0, Console.CursorTop); - Console.Write($"[{i}/{end}]"); - } + } + if (start <= end) + fs.Write(BitConverter.GetBytes(count), 0, sizeof(uint)); + fs.Seek(0, SeekOrigin.End); + for (uint i = start; i <= end; i++) + { + Block block = Blockchain.Singleton.Store.GetBlock(i); + byte[] array = block.ToArray(); + fs.Write(BitConverter.GetBytes(array.Length), 0, sizeof(int)); + fs.Write(array, 0, array.Length); + Console.SetCursorPosition(0, Console.CursorTop); + Console.Write($"[{i}/{end}]"); } } - Console.WriteLine(); - return true; } private bool OnHelp(string[] args) From 90c15dc4de570e8de19769e5e95b04a86814ef59 Mon Sep 17 00:00:00 2001 From: Owen Zhang <38493437+superboyiii@users.noreply.github.com> Date: Wed, 18 Sep 2019 16:57:25 +0800 Subject: [PATCH 077/183] v3.0.0-preview1 (#136) * Update to v3.0.0-preview1 * update version number --- ApplicationLogs/ApplicationLogs.csproj | 4 ++-- CoreMetrics/CoreMetrics.csproj | 4 ++-- ImportBlocks/ImportBlocks.csproj | 4 ++-- RpcNep5Tracker/RpcNep5Tracker.csproj | 4 ++-- RpcSecurity/RpcSecurity.csproj | 4 ++-- RpcWallet/RpcWallet.csproj | 4 ++-- StatesDumper/StatesDumper.csproj | 4 ++-- SystemLog/SystemLog.csproj | 9 +++++---- 8 files changed, 19 insertions(+), 18 deletions(-) diff --git a/ApplicationLogs/ApplicationLogs.csproj b/ApplicationLogs/ApplicationLogs.csproj index 0a446836d..18c1be6b6 100644 --- a/ApplicationLogs/ApplicationLogs.csproj +++ b/ApplicationLogs/ApplicationLogs.csproj @@ -1,7 +1,7 @@  - 2.10.2 + 3.0.0-preview1 netstandard2.0 Neo.Plugins @@ -14,7 +14,7 @@ - + diff --git a/CoreMetrics/CoreMetrics.csproj b/CoreMetrics/CoreMetrics.csproj index 2451ec640..88a1575a2 100644 --- a/CoreMetrics/CoreMetrics.csproj +++ b/CoreMetrics/CoreMetrics.csproj @@ -1,13 +1,13 @@  - 2.10.2 + 3.0.0-preview1 netstandard2.0 Neo.Plugins - + diff --git a/ImportBlocks/ImportBlocks.csproj b/ImportBlocks/ImportBlocks.csproj index 013eb9500..9439433db 100644 --- a/ImportBlocks/ImportBlocks.csproj +++ b/ImportBlocks/ImportBlocks.csproj @@ -1,7 +1,7 @@  - 2.10.2 + 3.0.0-preview1 netstandard2.0 Neo.Plugins @@ -14,7 +14,7 @@ - + diff --git a/RpcNep5Tracker/RpcNep5Tracker.csproj b/RpcNep5Tracker/RpcNep5Tracker.csproj index d41ed830f..a5b7dab26 100644 --- a/RpcNep5Tracker/RpcNep5Tracker.csproj +++ b/RpcNep5Tracker/RpcNep5Tracker.csproj @@ -1,6 +1,6 @@  - 2.10.2 + 3.0.0-preview1 netstandard2.0 Neo.Plugins latest @@ -12,6 +12,6 @@ - + diff --git a/RpcSecurity/RpcSecurity.csproj b/RpcSecurity/RpcSecurity.csproj index 5147ab011..ef3df6d19 100644 --- a/RpcSecurity/RpcSecurity.csproj +++ b/RpcSecurity/RpcSecurity.csproj @@ -1,7 +1,7 @@  - 2.10.2 + 3.0.0-preview1 netstandard2.0 Neo.Plugins @@ -14,7 +14,7 @@ - + diff --git a/RpcWallet/RpcWallet.csproj b/RpcWallet/RpcWallet.csproj index 9d25b652a..37234f38d 100644 --- a/RpcWallet/RpcWallet.csproj +++ b/RpcWallet/RpcWallet.csproj @@ -1,7 +1,7 @@  - 2.10.2 + 3.0.0-preview1 netstandard2.0 Neo.Plugins @@ -14,7 +14,7 @@ - + diff --git a/StatesDumper/StatesDumper.csproj b/StatesDumper/StatesDumper.csproj index 4ff52770a..44ce1908d 100644 --- a/StatesDumper/StatesDumper.csproj +++ b/StatesDumper/StatesDumper.csproj @@ -1,7 +1,7 @@  - 2.10.2 + 3.0.0-preview1 netstandard2.0 Neo.Plugins @@ -14,7 +14,7 @@ - + diff --git a/SystemLog/SystemLog.csproj b/SystemLog/SystemLog.csproj index 02f0303fe..5b669c51c 100644 --- a/SystemLog/SystemLog.csproj +++ b/SystemLog/SystemLog.csproj @@ -1,14 +1,11 @@  + 3.0.0-preview1 netstandard2.0 Neo.Plugins - - - - PreserveNewest @@ -16,4 +13,8 @@ + + + + From 7ca6354df7289e133074f980405b8d96e64d8064 Mon Sep 17 00:00:00 2001 From: Owen Zhang <38493437+superboyiii@users.noreply.github.com> Date: Wed, 13 Nov 2019 11:15:13 +0800 Subject: [PATCH 078/183] Fix cell on maxNBlocksPerDay (3.X) (#142) * Fix cell on maxNBlocksPerDay uint (86400/15000*10000) equals 5000 but not 5760 because ```maxNBlocksPerDay``` is uint but not float. * Delete incoverable code Delete incoverable code since unint can't be <0,. For example: uint(-1) = uint 4294967295. * Fix nBlocks == 0 Fix nBlocks == 0 --- CoreMetrics/CoreMetrics.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/CoreMetrics/CoreMetrics.cs b/CoreMetrics/CoreMetrics.cs index 4b2e62303..5601fe93c 100644 --- a/CoreMetrics/CoreMetrics.cs +++ b/CoreMetrics/CoreMetrics.cs @@ -33,7 +33,7 @@ public void PostProcess(HttpContext context, string method, JArray _params, JObj private JObject GetBlocksTime(uint nBlocks, uint lastHeight) { // It is currently limited to query blocks generated in the last 24hours (86400 seconds) - uint maxNBlocksPerDay = 86400 / Blockchain.MillisecondsPerBlock * 1000; + uint maxNBlocksPerDay = 86400 / (Blockchain.MillisecondsPerBlock / 1000); if (lastHeight != 0) { if (lastHeight >= Blockchain.Singleton.Height) @@ -60,13 +60,13 @@ private JObject GetBlocksTime(uint nBlocks, uint lastHeight) JObject json = new JObject(); return json["error"] = "Requested number of blocks timestamps " + nBlocks + " exceeds quantity of known blocks " + Blockchain.Singleton.Height; } - - if (nBlocks <= 0) + + if (nBlocks == 0) { JObject json = new JObject(); - return json["error"] = "Requested number of block times can not be <= 0"; + return json["error"] = "Requested number of block times can not be = 0"; } - + JArray array = new JArray(); uint heightToBegin = lastHeight > 0 ? lastHeight - nBlocks : (Blockchain.Singleton.Height - 1) - nBlocks; for (uint i = heightToBegin; i <= heightToBegin + nBlocks; i++) From 9c82661628f33129f3e41764ebbbecb13a70e492 Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Sun, 1 Dec 2019 03:34:21 +0800 Subject: [PATCH 079/183] Upgrade dependencies and target frameworks (#147) * Upgrade dependencies and target frameworks * Update .travis.yml * IStorage (#148) * Fix UT (#149) * Update RpcNep5Tracker/RpcNep5Tracker.cs Co-Authored-By: Erik Zhang * Update RpcNep5Tracker/RpcNep5Tracker.cs Co-Authored-By: Erik Zhang * Update RpcNep5Tracker/RpcNep5Tracker.cs Co-Authored-By: Erik Zhang --- .travis.yml | 5 +-- ApplicationLogs/ApplicationLogs.csproj | 4 +- ApplicationLogs/LogReader.cs | 6 +-- CoreMetrics/CoreMetrics.cs | 10 ++--- CoreMetrics/CoreMetrics.csproj | 4 +- ImportBlocks/ImportBlocks.cs | 3 +- ImportBlocks/ImportBlocks.csproj | 4 +- RpcNep5Tracker/DbCache.cs | 56 ++++++++++++++++++++++++++ RpcNep5Tracker/RpcNep5Tracker.cs | 31 +++++++------- RpcNep5Tracker/RpcNep5Tracker.csproj | 5 +-- RpcSecurity/RpcSecurity.csproj | 4 +- RpcWallet/RpcWallet.cs | 2 +- RpcWallet/RpcWallet.csproj | 4 +- StatesDumper/StatesDumper.cs | 28 ++++++------- StatesDumper/StatesDumper.csproj | 4 +- SystemLog/SystemLog.csproj | 4 +- 16 files changed, 109 insertions(+), 65 deletions(-) create mode 100644 RpcNep5Tracker/DbCache.cs diff --git a/.travis.yml b/.travis.yml index 951b8c3e2..9b1df48e0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,13 +2,10 @@ language: csharp os: - linux - - osx dist: bionic -osx_image: xcode9.1 - mono: none -dotnet: 2.1.300 +dotnet: 3.0.100 script: - dotnet restore diff --git a/ApplicationLogs/ApplicationLogs.csproj b/ApplicationLogs/ApplicationLogs.csproj index 18c1be6b6..01107b06c 100644 --- a/ApplicationLogs/ApplicationLogs.csproj +++ b/ApplicationLogs/ApplicationLogs.csproj @@ -2,7 +2,7 @@ 3.0.0-preview1 - netstandard2.0 + netstandard2.1 Neo.Plugins @@ -14,7 +14,7 @@ - + diff --git a/ApplicationLogs/LogReader.cs b/ApplicationLogs/LogReader.cs index ccacde2db..4d9273c6b 100644 --- a/ApplicationLogs/LogReader.cs +++ b/ApplicationLogs/LogReader.cs @@ -3,12 +3,12 @@ using Neo.IO.Json; using Neo.Ledger; using Neo.Network.RPC; +using Neo.Persistence; using Neo.VM; using System; using System.Collections.Generic; using System.IO; using System.Linq; -using Snapshot = Neo.Persistence.Snapshot; namespace Neo.Plugins { @@ -45,7 +45,7 @@ public void PostProcess(HttpContext context, string method, JArray _params, JObj { } - public void OnPersist(Snapshot snapshot, IReadOnlyList applicationExecutedList) + public void OnPersist(StoreView snapshot, IReadOnlyList applicationExecutedList) { WriteBatch writeBatch = new WriteBatch(); @@ -83,7 +83,7 @@ public void OnPersist(Snapshot snapshot, IReadOnlyList= 2 ? lastHeight = (uint)_params[1].AsNumber() : 0; + uint lastHeight = _params.Count >= 2 ? (uint)_params[1].AsNumber() : 0; return GetBlocksTime(nBlocks, lastHeight); } default: @@ -60,18 +58,18 @@ private JObject GetBlocksTime(uint nBlocks, uint lastHeight) JObject json = new JObject(); return json["error"] = "Requested number of blocks timestamps " + nBlocks + " exceeds quantity of known blocks " + Blockchain.Singleton.Height; } - + if (nBlocks == 0) { JObject json = new JObject(); return json["error"] = "Requested number of block times can not be = 0"; } - + JArray array = new JArray(); uint heightToBegin = lastHeight > 0 ? lastHeight - nBlocks : (Blockchain.Singleton.Height - 1) - nBlocks; for (uint i = heightToBegin; i <= heightToBegin + nBlocks; i++) { - Header header = Blockchain.Singleton.Store.GetHeader(i); + Header header = Blockchain.Singleton.GetHeader(i); if (header == null) break; JObject json = new JObject(); diff --git a/CoreMetrics/CoreMetrics.csproj b/CoreMetrics/CoreMetrics.csproj index 88a1575a2..977514faa 100644 --- a/CoreMetrics/CoreMetrics.csproj +++ b/CoreMetrics/CoreMetrics.csproj @@ -2,12 +2,12 @@ 3.0.0-preview1 - netstandard2.0 + netstandard2.1 Neo.Plugins - + diff --git a/ImportBlocks/ImportBlocks.cs b/ImportBlocks/ImportBlocks.cs index 45143f3a4..160a8f504 100644 --- a/ImportBlocks/ImportBlocks.cs +++ b/ImportBlocks/ImportBlocks.cs @@ -2,7 +2,6 @@ using Neo.IO; using Neo.Ledger; using Neo.Network.P2P.Payloads; -using Neo.Persistence; using System; using System.IO; @@ -82,7 +81,7 @@ private void WriteBlocks(uint start, uint count, string path, bool writeStart) fs.Seek(0, SeekOrigin.End); for (uint i = start; i <= end; i++) { - Block block = Blockchain.Singleton.Store.GetBlock(i); + Block block = Blockchain.Singleton.GetBlock(i); byte[] array = block.ToArray(); fs.Write(BitConverter.GetBytes(array.Length), 0, sizeof(int)); fs.Write(array, 0, array.Length); diff --git a/ImportBlocks/ImportBlocks.csproj b/ImportBlocks/ImportBlocks.csproj index 9439433db..243ffdb82 100644 --- a/ImportBlocks/ImportBlocks.csproj +++ b/ImportBlocks/ImportBlocks.csproj @@ -2,7 +2,7 @@ 3.0.0-preview1 - netstandard2.0 + netstandard2.1 Neo.Plugins @@ -14,7 +14,7 @@ - + diff --git a/RpcNep5Tracker/DbCache.cs b/RpcNep5Tracker/DbCache.cs new file mode 100644 index 000000000..99f1d61fe --- /dev/null +++ b/RpcNep5Tracker/DbCache.cs @@ -0,0 +1,56 @@ +using Neo.IO; +using Neo.IO.Caching; +using Neo.IO.Data.LevelDB; +using System; +using System.Collections.Generic; + +namespace Neo.Plugins +{ + public class DbCache : DataCache + where TKey : IEquatable, ISerializable, new() + where TValue : class, ICloneable, ISerializable, new() + { + private readonly DB db; + private readonly ReadOptions options; + private readonly WriteBatch batch; + private readonly byte prefix; + + public DbCache(DB db, ReadOptions options, WriteBatch batch, byte prefix) + { + this.db = db; + this.options = options ?? ReadOptions.Default; + this.batch = batch; + this.prefix = prefix; + } + + protected override void AddInternal(TKey key, TValue value) + { + batch?.Put(prefix, key, value); + } + + protected override void DeleteInternal(TKey key) + { + batch?.Delete(prefix, key); + } + + protected override IEnumerable<(TKey, TValue)> FindInternal(byte[] key_prefix) + { + return db.Find(options, SliceBuilder.Begin(prefix).Add(key_prefix), (k, v) => (k.ToArray().AsSerializable(1), v.ToArray().AsSerializable())); + } + + protected override TValue GetInternal(TKey key) + { + return db.Get(options, prefix, key); + } + + protected override TValue TryGetInternal(TKey key) + { + return db.TryGet(options, prefix, key); + } + + protected override void UpdateInternal(TKey key, TValue value) + { + batch?.Put(prefix, key, value); + } + } +} diff --git a/RpcNep5Tracker/RpcNep5Tracker.cs b/RpcNep5Tracker/RpcNep5Tracker.cs index a0118a03b..0982a14bd 100644 --- a/RpcNep5Tracker/RpcNep5Tracker.cs +++ b/RpcNep5Tracker/RpcNep5Tracker.cs @@ -6,7 +6,6 @@ using Neo.Network.P2P.Payloads; using Neo.Network.RPC; using Neo.Persistence; -using Neo.Persistence.LevelDB; using Neo.SmartContract; using Neo.VM; using Neo.Wallets; @@ -15,8 +14,6 @@ using System.IO; using System.Linq; using System.Numerics; -using System.Text; -using Snapshot = Neo.Persistence.Snapshot; namespace Neo.Plugins { @@ -63,11 +60,11 @@ private void ResetBatch() } } - private void RecordTransferHistory(Snapshot snapshot, UInt160 scriptHash, UInt160 from, UInt160 to, BigInteger amount, UInt256 txHash, ref ushort transferIndex) + private void RecordTransferHistory(StoreView snapshot, UInt160 scriptHash, UInt160 from, UInt160 to, BigInteger amount, UInt256 txHash, ref ushort transferIndex) { if (!_shouldTrackHistory) return; - Header header = snapshot.GetHeader(snapshot.Height); + Header header = snapshot.GetHeader(snapshot.CurrentBlockHash); if (_recordNullAddressHistory || from != UInt160.Zero) { @@ -95,14 +92,14 @@ private void RecordTransferHistory(Snapshot snapshot, UInt160 scriptHash, UInt16 transferIndex++; } - private void HandleNotification(Snapshot snapshot, Transaction transaction, UInt160 scriptHash, + private void HandleNotification(StoreView snapshot, Transaction transaction, UInt160 scriptHash, VM.Types.Array stateItems, Dictionary nep5BalancesChanged, ref ushort transferIndex) { if (stateItems.Count == 0) return; // Event name should be encoded as a byte array. if (!(stateItems[0] is VM.Types.ByteArray)) return; - var eventName = Encoding.UTF8.GetString(stateItems[0].GetByteArray()); + var eventName = stateItems[0].GetString(); if (eventName != "Transfer") return; if (stateItems.Count < 4) return; @@ -113,9 +110,9 @@ private void HandleNotification(Snapshot snapshot, Transaction transaction, UInt var amountItem = stateItems[3]; if (!(amountItem is VM.Types.ByteArray || amountItem is VM.Types.Integer)) return; - byte[] fromBytes = stateItems[1]?.GetByteArray(); + byte[] fromBytes = stateItems[1]?.GetSpan().ToArray(); if (fromBytes?.Length != 20) fromBytes = null; - byte[] toBytes = stateItems[2]?.GetByteArray(); + byte[] toBytes = stateItems[2]?.GetSpan().ToArray(); if (toBytes?.Length != 20) toBytes = null; if (fromBytes == null && toBytes == null) return; var from = new UInt160(fromBytes); @@ -135,7 +132,7 @@ private void HandleNotification(Snapshot snapshot, Transaction transaction, UInt RecordTransferHistory(snapshot, scriptHash, from, to, amountItem.GetBigInteger(), transaction.Hash, ref transferIndex); } - public void OnPersist(Snapshot snapshot, IReadOnlyList applicationExecutedList) + public void OnPersist(StoreView snapshot, IReadOnlyList applicationExecutedList) { // Start freshly with a new DBCache for each block. ResetBatch(); @@ -183,7 +180,7 @@ public void OnPersist(Snapshot snapshot, IReadOnlyList _maxResults) break; JObject transfer = new JObject(); transfer["timestamp"] = transferPair.Key.TimestampMS; - transfer["asset_hash"] = transferPair.Key.AssetScriptHash.ToArray().Reverse().ToHexString(); + transfer["asset_hash"] = transferPair.Key.AssetScriptHash.ToString(); transfer["transfer_address"] = transferPair.Value.UserScriptHash.ToAddress(); transfer["amount"] = transferPair.Value.Amount.ToString(); transfer["block_index"] = transferPair.Value.BlockIndex; transfer["transfer_notify_index"] = transferPair.Key.BlockXferNotificationIndex; - transfer["tx_hash"] = transferPair.Value.TxHash.ToArray().Reverse().ToHexString(); + transfer["tx_hash"] = transferPair.Value.TxHash.ToString(); parentJArray.Add(transfer); } } @@ -268,12 +265,12 @@ private JObject GetNep5Balances(JArray _params) json["address"] = userScriptHash.ToAddress(); var dbCache = new DbCache(_db, null, null, Nep5BalancePrefix); byte[] prefix = userScriptHash.ToArray(); - foreach (var storageKeyValuePair in dbCache.Find(prefix)) + foreach (var (key, value) in dbCache.Find(prefix)) { JObject balance = new JObject(); - balance["asset_hash"] = storageKeyValuePair.Key.AssetScriptHash.ToArray().Reverse().ToHexString(); - balance["amount"] = storageKeyValuePair.Value.Balance.ToString(); - balance["last_updated_block"] = storageKeyValuePair.Value.LastUpdatedBlock; + balance["asset_hash"] = key.AssetScriptHash.ToString(); + balance["amount"] = value.Balance.ToString(); + balance["last_updated_block"] = value.LastUpdatedBlock; balances.Add(balance); } return json; diff --git a/RpcNep5Tracker/RpcNep5Tracker.csproj b/RpcNep5Tracker/RpcNep5Tracker.csproj index a5b7dab26..693295439 100644 --- a/RpcNep5Tracker/RpcNep5Tracker.csproj +++ b/RpcNep5Tracker/RpcNep5Tracker.csproj @@ -1,9 +1,8 @@  3.0.0-preview1 - netstandard2.0 + netstandard2.1 Neo.Plugins - latest @@ -12,6 +11,6 @@ - + diff --git a/RpcSecurity/RpcSecurity.csproj b/RpcSecurity/RpcSecurity.csproj index ef3df6d19..1d88451b2 100644 --- a/RpcSecurity/RpcSecurity.csproj +++ b/RpcSecurity/RpcSecurity.csproj @@ -2,7 +2,7 @@ 3.0.0-preview1 - netstandard2.0 + netstandard2.1 Neo.Plugins @@ -14,7 +14,7 @@ - + diff --git a/RpcWallet/RpcWallet.cs b/RpcWallet/RpcWallet.cs index b3b0e6a63..451e9358a 100644 --- a/RpcWallet/RpcWallet.cs +++ b/RpcWallet/RpcWallet.cs @@ -169,7 +169,7 @@ private JObject GetUnclaimedGas() { CheckWallet(); BigInteger gas = BigInteger.Zero; - using (Snapshot snapshot = Blockchain.Singleton.GetSnapshot()) + using (SnapshotView snapshot = Blockchain.Singleton.GetSnapshot()) foreach (UInt160 account in Wallet.GetAccounts().Select(p => p.ScriptHash)) { gas += NativeContract.NEO.UnclaimedGas(snapshot, account, snapshot.Height + 1); diff --git a/RpcWallet/RpcWallet.csproj b/RpcWallet/RpcWallet.csproj index 37234f38d..bcfafc45b 100644 --- a/RpcWallet/RpcWallet.csproj +++ b/RpcWallet/RpcWallet.csproj @@ -2,7 +2,7 @@ 3.0.0-preview1 - netstandard2.0 + netstandard2.1 Neo.Plugins @@ -14,7 +14,7 @@ - + diff --git a/StatesDumper/StatesDumper.cs b/StatesDumper/StatesDumper.cs index 44addf688..a0d50fc3e 100644 --- a/StatesDumper/StatesDumper.cs +++ b/StatesDumper/StatesDumper.cs @@ -19,7 +19,7 @@ public override void Configure() Settings.Load(GetConfiguration()); } - private static void Dump(IEnumerable> states) + private static void Dump(IEnumerable<(TKey Key, TValue Value)> states) where TKey : ISerializable where TValue : ISerializable { @@ -39,14 +39,12 @@ protected override bool OnMessage(object message) { if (!(message is string[] args)) return false; if (args.Length == 0) return false; - switch (args[0].ToLower()) + return (args[0].ToLower()) switch { - case "help": - return OnHelp(args); - case "dump": - return OnDump(args); - } - return false; + "help" => OnHelp(args), + "dump" => OnDump(args), + _ => false, + }; } private bool OnDump(string[] args) @@ -56,8 +54,8 @@ private bool OnDump(string[] args) { case "storage": Dump(args.Length >= 3 - ? Blockchain.Singleton.Store.GetStorages().Find(UInt160.Parse(args[2]).ToArray()) - : Blockchain.Singleton.Store.GetStorages().Find()); + ? Blockchain.Singleton.View.Storages.Find(UInt160.Parse(args[2]).ToArray()) + : Blockchain.Singleton.View.Storages.Find()); return true; default: return false; @@ -73,13 +71,13 @@ private bool OnHelp(string[] args) return true; } - public void OnPersist(Snapshot snapshot, IReadOnlyList applicationExecutedList) + public void OnPersist(StoreView snapshot, IReadOnlyList applicationExecutedList) { if (Settings.Default.PersistAction.HasFlag(PersistActions.StorageChanges)) OnPersistStorage(snapshot); } - private void OnPersistStorage(Snapshot snapshot) + private void OnPersistStorage(StoreView snapshot) { uint blockIndex = snapshot.Height; if (blockIndex >= Settings.Default.HeightToBegin) @@ -120,13 +118,13 @@ private void OnPersistStorage(Snapshot snapshot) } } - public void OnCommit(Snapshot snapshot) + public void OnCommit(StoreView snapshot) { if (Settings.Default.PersistAction.HasFlag(PersistActions.StorageChanges)) OnCommitStorage(snapshot); } - public void OnCommitStorage(Snapshot snapshot) + public void OnCommitStorage(StoreView snapshot) { uint blockIndex = snapshot.Height; if (bs_cache.Count > 0) @@ -142,7 +140,7 @@ public void OnCommitStorage(Snapshot snapshot) } } } - + public bool ShouldThrowExceptionFromCommit(Exception ex) { Console.WriteLine($"Error writing States with StatesDumper.{Environment.NewLine}{ex}"); diff --git a/StatesDumper/StatesDumper.csproj b/StatesDumper/StatesDumper.csproj index 44ce1908d..4a0f0299d 100644 --- a/StatesDumper/StatesDumper.csproj +++ b/StatesDumper/StatesDumper.csproj @@ -2,7 +2,7 @@ 3.0.0-preview1 - netstandard2.0 + netstandard2.1 Neo.Plugins @@ -14,7 +14,7 @@ - + diff --git a/SystemLog/SystemLog.csproj b/SystemLog/SystemLog.csproj index 5b669c51c..de98acd2a 100644 --- a/SystemLog/SystemLog.csproj +++ b/SystemLog/SystemLog.csproj @@ -2,7 +2,7 @@ 3.0.0-preview1 - netstandard2.0 + netstandard2.1 Neo.Plugins @@ -14,7 +14,7 @@ - + From b2e9e291f4c9a62e299fe45b53850ee3e9e0bbf5 Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Mon, 2 Dec 2019 23:39:43 +0800 Subject: [PATCH 080/183] Remove Travis and use Github Actions (#151) --- .editorconfig | 17 +++++++++++++++++ .github/workflows/dotnetcore.yml | 24 ++++++++++++++++++++++++ .travis.yml | 11 ----------- RpcNep5Tracker/Helper.cs | 2 +- RpcNep5Tracker/Nep5BalanceKey.cs | 6 +++--- RpcNep5Tracker/Nep5Transfer.cs | 2 +- SystemLog/ConsoleColorSet.cs | 4 ++-- SystemLog/Settings.cs | 4 ++-- 8 files changed, 50 insertions(+), 20 deletions(-) create mode 100644 .editorconfig create mode 100644 .github/workflows/dotnetcore.yml delete mode 100644 .travis.yml diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..5acd074d2 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,17 @@ +############################### +# Core EditorConfig Options # +############################### + +# dotnet-format requires version 3.1.37601 +# dotnet tool update -g dotnet-format +# remember to have: git config --global core.autocrlf false #(which is usually default) + +root = true + +# Every file + +[*] +insert_final_newline = true +trim_trailing_whitespace = true +charset = utf-8 +end_of_line = lf diff --git a/.github/workflows/dotnetcore.yml b/.github/workflows/dotnetcore.yml new file mode 100644 index 000000000..71250ece7 --- /dev/null +++ b/.github/workflows/dotnetcore.yml @@ -0,0 +1,24 @@ +name: .NET Core Test and Publish + +on: pull_request + +env: + DOTNET_VERSION: 3.0.100 + +jobs: + + Test: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v1 + - name: Setup .NET Core + uses: actions/setup-dotnet@v1 + with: + dotnet-version: ${{ env.DOTNET_VERSION }} + - name: Check format + run: | + dotnet tool install --tool-path ./ dotnet-format + ./dotnet-format --check --dry-run -v diagnostic + - name: Build + run: dotnet build diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 9b1df48e0..000000000 --- a/.travis.yml +++ /dev/null @@ -1,11 +0,0 @@ -language: csharp - -os: - - linux - -dist: bionic -mono: none -dotnet: 3.0.100 - -script: - - dotnet restore diff --git a/RpcNep5Tracker/Helper.cs b/RpcNep5Tracker/Helper.cs index a65682e84..7e76bc44b 100644 --- a/RpcNep5Tracker/Helper.cs +++ b/RpcNep5Tracker/Helper.cs @@ -30,4 +30,4 @@ public static IEnumerable> FindRange(th v.ToArray().AsSerializable())); } } -} \ No newline at end of file +} diff --git a/RpcNep5Tracker/Nep5BalanceKey.cs b/RpcNep5Tracker/Nep5BalanceKey.cs index b4a1710cf..ec1fc218d 100644 --- a/RpcNep5Tracker/Nep5BalanceKey.cs +++ b/RpcNep5Tracker/Nep5BalanceKey.cs @@ -62,8 +62,8 @@ public void Serialize(BinaryWriter writer) public void Deserialize(BinaryReader reader) { - ((ISerializable) UserScriptHash).Deserialize(reader); - ((ISerializable) AssetScriptHash).Deserialize(reader); + ((ISerializable)UserScriptHash).Deserialize(reader); + ((ISerializable)AssetScriptHash).Deserialize(reader); } } -} \ No newline at end of file +} diff --git a/RpcNep5Tracker/Nep5Transfer.cs b/RpcNep5Tracker/Nep5Transfer.cs index 9c4b2307b..84c71f1d7 100644 --- a/RpcNep5Tracker/Nep5Transfer.cs +++ b/RpcNep5Tracker/Nep5Transfer.cs @@ -48,4 +48,4 @@ void ICloneable.FromReplica(Nep5Transfer replica) Amount = replica.Amount; } } -} \ No newline at end of file +} diff --git a/SystemLog/ConsoleColorSet.cs b/SystemLog/ConsoleColorSet.cs index e8fa58872..6ca6549bf 100644 --- a/SystemLog/ConsoleColorSet.cs +++ b/SystemLog/ConsoleColorSet.cs @@ -1,4 +1,4 @@ -using System; +using System; namespace Neo.Plugins { @@ -48,4 +48,4 @@ public void Apply() Console.BackgroundColor = Background; } } -} \ No newline at end of file +} diff --git a/SystemLog/Settings.cs b/SystemLog/Settings.cs index 939a778aa..242da4d5c 100644 --- a/SystemLog/Settings.cs +++ b/SystemLog/Settings.cs @@ -1,4 +1,4 @@ -using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Configuration; namespace Neo.Plugins { @@ -20,4 +20,4 @@ public static void Load(IConfigurationSection section) Default = new Settings(section); } } -} \ No newline at end of file +} From 80c66e1865fc507c3c80931022f8f0ab7c423306 Mon Sep 17 00:00:00 2001 From: erikzhang Date: Tue, 3 Dec 2019 15:34:38 +0800 Subject: [PATCH 081/183] Fix SystemLog --- SystemLog/Logger.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SystemLog/Logger.cs b/SystemLog/Logger.cs index 70ee1b392..875592315 100644 --- a/SystemLog/Logger.cs +++ b/SystemLog/Logger.cs @@ -1,11 +1,11 @@ -using System; +using System; using System.IO; namespace Neo.Plugins { public class Logger : Plugin, ILogPlugin { - public override string Name => "SystemLogs"; + public override string Name => "SystemLog"; public override void Configure() { From b50e790803af65335376339b2d159e2a19c1f6cd Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Tue, 3 Dec 2019 16:24:14 +0800 Subject: [PATCH 082/183] Add LevelDBStore (#150) --- ApplicationLogs/ApplicationLogs.csproj | 2 +- ApplicationLogs/LogReader.cs | 7 +- LevelDBStore/IO/Data/LevelDB/DB.cs | 103 ++++++++ LevelDBStore/IO/Data/LevelDB/Helper.cs | 40 +++ LevelDBStore/IO/Data/LevelDB/Iterator.cs | 75 ++++++ .../IO/Data/LevelDB/LevelDBException.cs | 12 + LevelDBStore/IO/Data/LevelDB/Native.cs | 248 ++++++++++++++++++ LevelDBStore/IO/Data/LevelDB/Options.cs | 87 ++++++ LevelDBStore/IO/Data/LevelDB/ReadOptions.cs | 39 +++ LevelDBStore/IO/Data/LevelDB/Snapshot.cs | 24 ++ LevelDBStore/IO/Data/LevelDB/WriteBatch.cs | 29 ++ LevelDBStore/IO/Data/LevelDB/WriteOptions.cs | 25 ++ LevelDBStore/LevelDBStore.csproj | 21 ++ LevelDBStore/LevelDBStore/config.json | 5 + LevelDBStore/Plugins/Storage/Helper.cs | 16 ++ LevelDBStore/Plugins/Storage/LevelDBStore.cs | 19 ++ LevelDBStore/Plugins/Storage/Snapshot.cs | 53 ++++ LevelDBStore/Plugins/Storage/Store.cs | 69 +++++ RpcNep5Tracker/DbCache.cs | 26 +- RpcNep5Tracker/Helper.cs | 20 +- RpcNep5Tracker/RpcNep5Tracker.cs | 17 +- RpcNep5Tracker/RpcNep5Tracker.csproj | 2 +- neo-plugins.sln | 8 +- 23 files changed, 910 insertions(+), 37 deletions(-) create mode 100644 LevelDBStore/IO/Data/LevelDB/DB.cs create mode 100644 LevelDBStore/IO/Data/LevelDB/Helper.cs create mode 100644 LevelDBStore/IO/Data/LevelDB/Iterator.cs create mode 100644 LevelDBStore/IO/Data/LevelDB/LevelDBException.cs create mode 100644 LevelDBStore/IO/Data/LevelDB/Native.cs create mode 100644 LevelDBStore/IO/Data/LevelDB/Options.cs create mode 100644 LevelDBStore/IO/Data/LevelDB/ReadOptions.cs create mode 100644 LevelDBStore/IO/Data/LevelDB/Snapshot.cs create mode 100644 LevelDBStore/IO/Data/LevelDB/WriteBatch.cs create mode 100644 LevelDBStore/IO/Data/LevelDB/WriteOptions.cs create mode 100644 LevelDBStore/LevelDBStore.csproj create mode 100644 LevelDBStore/LevelDBStore/config.json create mode 100644 LevelDBStore/Plugins/Storage/Helper.cs create mode 100644 LevelDBStore/Plugins/Storage/LevelDBStore.cs create mode 100644 LevelDBStore/Plugins/Storage/Snapshot.cs create mode 100644 LevelDBStore/Plugins/Storage/Store.cs diff --git a/ApplicationLogs/ApplicationLogs.csproj b/ApplicationLogs/ApplicationLogs.csproj index 01107b06c..4aeeb578a 100644 --- a/ApplicationLogs/ApplicationLogs.csproj +++ b/ApplicationLogs/ApplicationLogs.csproj @@ -14,7 +14,7 @@ - + diff --git a/ApplicationLogs/LogReader.cs b/ApplicationLogs/LogReader.cs index 4d9273c6b..169fddd88 100644 --- a/ApplicationLogs/LogReader.cs +++ b/ApplicationLogs/LogReader.cs @@ -1,4 +1,5 @@ using Microsoft.AspNetCore.Http; +using Neo.IO; using Neo.IO.Data.LevelDB; using Neo.IO.Json; using Neo.Ledger; @@ -9,6 +10,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using System.Text; namespace Neo.Plugins { @@ -36,7 +38,8 @@ public JObject OnProcess(HttpContext context, string method, JArray _params) { if (method != "getapplicationlog") return null; UInt256 hash = UInt256.Parse(_params[0].AsString()); - if (!db.TryGet(ReadOptions.Default, hash.ToArray(), out Slice value)) + byte[] value = db.Get(ReadOptions.Default, hash.ToArray()); + if (value is null) throw new RpcException(-100, "Unknown transaction"); return JObject.Parse(value.ToString()); } @@ -78,7 +81,7 @@ public void OnPersist(StoreView snapshot, IReadOnlyList + /// Return true if haven't got valid handle + /// + public bool IsDisposed => handle == IntPtr.Zero; + + private DB(IntPtr handle) + { + this.handle = handle; + } + + public void Dispose() + { + if (handle != IntPtr.Zero) + { + Native.leveldb_close(handle); + handle = IntPtr.Zero; + } + } + + public void Delete(WriteOptions options, byte[] key) + { + Native.leveldb_delete(handle, options.handle, key, (UIntPtr)key.Length, out IntPtr error); + NativeHelper.CheckError(error); + } + + public byte[] Get(ReadOptions options, byte[] key) + { + IntPtr value = Native.leveldb_get(handle, options.handle, key, (UIntPtr)key.Length, out UIntPtr length, out IntPtr error); + try + { + if (error != IntPtr.Zero) + { + Native.leveldb_free(error); + return null; + } + return value.ToByteArray(length); + } + finally + { + if (value != IntPtr.Zero) Native.leveldb_free(value); + } + } + + public Snapshot GetSnapshot() + { + return new Snapshot(handle); + } + + public Iterator NewIterator(ReadOptions options) + { + return new Iterator(Native.leveldb_create_iterator(handle, options.handle)); + } + + public static DB Open(string name) + { + return Open(name, Options.Default); + } + + public static DB Open(string name, Options options) + { + IntPtr handle = Native.leveldb_open(options.handle, name, out IntPtr error); + NativeHelper.CheckError(error); + return new DB(handle); + } + + public void Put(WriteOptions options, byte[] key, byte[] value) + { + Native.leveldb_put(handle, options.handle, key, (UIntPtr)key.Length, value, (UIntPtr)value.Length, out IntPtr error); + NativeHelper.CheckError(error); + } + + public void Write(WriteOptions options, WriteBatch write_batch) + { + // There's a bug in .Net Core. + // When calling DB.Write(), it will throw LevelDBException sometimes. + // But when you try to catch the exception, the bug disappears. + // We shall remove the "try...catch" clause when Microsoft fix the bug. + byte retry = 0; + while (true) + { + try + { + Native.leveldb_write(handle, options.handle, write_batch.handle, out IntPtr error); + NativeHelper.CheckError(error); + break; + } + catch (LevelDBException ex) + { + if (++retry >= 4) throw; + System.IO.File.AppendAllText("leveldb.log", ex.Message + "\r\n"); + } + } + } + } +} diff --git a/LevelDBStore/IO/Data/LevelDB/Helper.cs b/LevelDBStore/IO/Data/LevelDB/Helper.cs new file mode 100644 index 000000000..dc44be92b --- /dev/null +++ b/LevelDBStore/IO/Data/LevelDB/Helper.cs @@ -0,0 +1,40 @@ +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; + +namespace Neo.IO.Data.LevelDB +{ + public static class Helper + { + public static IEnumerable Find(this DB db, ReadOptions options, byte[] prefix, Func resultSelector) + { + using Iterator it = db.NewIterator(options); + for (it.Seek(prefix); it.Valid(); it.Next()) + { + byte[] key = it.Key(); + if (key.Length < prefix.Length) break; + if (!key.AsSpan().StartsWith(prefix)) break; + yield return resultSelector(key, it.Value()); + } + } + + public static IEnumerable FindRange(this DB db, ReadOptions options, byte[] startKey, byte[] endKey, Func resultSelector) + { + using Iterator it = db.NewIterator(options); + for (it.Seek(startKey); it.Valid(); it.Next()) + { + byte[] key = it.Key(); + if (key.AsSpan().SequenceCompareTo(endKey) > 0) break; + yield return resultSelector(key, it.Value()); + } + } + + internal static byte[] ToByteArray(this IntPtr data, UIntPtr length) + { + if (data == IntPtr.Zero) return null; + byte[] buffer = new byte[(int)length]; + Marshal.Copy(data, buffer, 0, (int)length); + return buffer; + } + } +} diff --git a/LevelDBStore/IO/Data/LevelDB/Iterator.cs b/LevelDBStore/IO/Data/LevelDB/Iterator.cs new file mode 100644 index 000000000..58ddb8b01 --- /dev/null +++ b/LevelDBStore/IO/Data/LevelDB/Iterator.cs @@ -0,0 +1,75 @@ +using System; + +namespace Neo.IO.Data.LevelDB +{ + public class Iterator : IDisposable + { + private IntPtr handle; + + internal Iterator(IntPtr handle) + { + this.handle = handle; + } + + private void CheckError() + { + Native.leveldb_iter_get_error(handle, out IntPtr error); + NativeHelper.CheckError(error); + } + + public void Dispose() + { + if (handle != IntPtr.Zero) + { + Native.leveldb_iter_destroy(handle); + handle = IntPtr.Zero; + } + } + + public byte[] Key() + { + IntPtr key = Native.leveldb_iter_key(handle, out UIntPtr length); + CheckError(); + return key.ToByteArray(length); + } + + public void Next() + { + Native.leveldb_iter_next(handle); + CheckError(); + } + + public void Prev() + { + Native.leveldb_iter_prev(handle); + CheckError(); + } + + public void Seek(byte[] target) + { + Native.leveldb_iter_seek(handle, target, (UIntPtr)target.Length); + } + + public void SeekToFirst() + { + Native.leveldb_iter_seek_to_first(handle); + } + + public void SeekToLast() + { + Native.leveldb_iter_seek_to_last(handle); + } + + public bool Valid() + { + return Native.leveldb_iter_valid(handle); + } + + public byte[] Value() + { + IntPtr value = Native.leveldb_iter_value(handle, out UIntPtr length); + CheckError(); + return value.ToByteArray(length); + } + } +} diff --git a/LevelDBStore/IO/Data/LevelDB/LevelDBException.cs b/LevelDBStore/IO/Data/LevelDB/LevelDBException.cs new file mode 100644 index 000000000..8804f1f7f --- /dev/null +++ b/LevelDBStore/IO/Data/LevelDB/LevelDBException.cs @@ -0,0 +1,12 @@ +using System.Data.Common; + +namespace Neo.IO.Data.LevelDB +{ + public class LevelDBException : DbException + { + internal LevelDBException(string message) + : base(message) + { + } + } +} diff --git a/LevelDBStore/IO/Data/LevelDB/Native.cs b/LevelDBStore/IO/Data/LevelDB/Native.cs new file mode 100644 index 000000000..f9991ff81 --- /dev/null +++ b/LevelDBStore/IO/Data/LevelDB/Native.cs @@ -0,0 +1,248 @@ +using System; +using System.Runtime.InteropServices; + +namespace Neo.IO.Data.LevelDB +{ + public enum CompressionType : byte + { + kNoCompression = 0x0, + kSnappyCompression = 0x1 + } + + public static class Native + { + #region Logger + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr leveldb_logger_create(IntPtr /* Action */ logger); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_logger_destroy(IntPtr /* logger*/ option); + #endregion + + #region DB + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr leveldb_open(IntPtr /* Options*/ options, string name, out IntPtr error); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_close(IntPtr /*DB */ db); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_put(IntPtr /* DB */ db, IntPtr /* WriteOptions*/ options, byte[] key, UIntPtr keylen, byte[] val, UIntPtr vallen, out IntPtr errptr); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_delete(IntPtr /* DB */ db, IntPtr /* WriteOptions*/ options, byte[] key, UIntPtr keylen, out IntPtr errptr); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_write(IntPtr /* DB */ db, IntPtr /* WriteOptions*/ options, IntPtr /* WriteBatch */ batch, out IntPtr errptr); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr leveldb_get(IntPtr /* DB */ db, IntPtr /* ReadOptions*/ options, byte[] key, UIntPtr keylen, out UIntPtr vallen, out IntPtr errptr); + + //[DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + //static extern void leveldb_approximate_sizes(IntPtr /* DB */ db, int num_ranges, byte[] range_start_key, long range_start_key_len, byte[] range_limit_key, long range_limit_key_len, out long sizes); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr leveldb_create_iterator(IntPtr /* DB */ db, IntPtr /* ReadOption */ options); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr leveldb_create_snapshot(IntPtr /* DB */ db); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_release_snapshot(IntPtr /* DB */ db, IntPtr /* SnapShot*/ snapshot); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr leveldb_property_value(IntPtr /* DB */ db, string propname); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_repair_db(IntPtr /* Options*/ options, string name, out IntPtr error); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_destroy_db(IntPtr /* Options*/ options, string name, out IntPtr error); + + #region extensions + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_free(IntPtr /* void */ ptr); + + #endregion + + + #endregion + + #region Env + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr leveldb_create_default_env(); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_env_destroy(IntPtr /*Env*/ cache); + #endregion + + #region Iterator + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_iter_destroy(IntPtr /*Iterator*/ iterator); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.U1)] + public static extern bool leveldb_iter_valid(IntPtr /*Iterator*/ iterator); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_iter_seek_to_first(IntPtr /*Iterator*/ iterator); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_iter_seek_to_last(IntPtr /*Iterator*/ iterator); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_iter_seek(IntPtr /*Iterator*/ iterator, byte[] key, UIntPtr length); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_iter_next(IntPtr /*Iterator*/ iterator); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_iter_prev(IntPtr /*Iterator*/ iterator); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr leveldb_iter_key(IntPtr /*Iterator*/ iterator, out UIntPtr length); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr leveldb_iter_value(IntPtr /*Iterator*/ iterator, out UIntPtr length); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_iter_get_error(IntPtr /*Iterator*/ iterator, out IntPtr error); + #endregion + + #region Options + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr leveldb_options_create(); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_options_destroy(IntPtr /*Options*/ options); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_options_set_create_if_missing(IntPtr /*Options*/ options, [MarshalAs(UnmanagedType.U1)] bool o); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_options_set_error_if_exists(IntPtr /*Options*/ options, [MarshalAs(UnmanagedType.U1)] bool o); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_options_set_info_log(IntPtr /*Options*/ options, IntPtr /* Logger */ logger); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_options_set_paranoid_checks(IntPtr /*Options*/ options, [MarshalAs(UnmanagedType.U1)] bool o); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_options_set_env(IntPtr /*Options*/ options, IntPtr /*Env*/ env); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_options_set_write_buffer_size(IntPtr /*Options*/ options, UIntPtr size); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_options_set_max_open_files(IntPtr /*Options*/ options, int max); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_options_set_cache(IntPtr /*Options*/ options, IntPtr /*Cache*/ cache); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_options_set_block_size(IntPtr /*Options*/ options, UIntPtr size); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_options_set_block_restart_interval(IntPtr /*Options*/ options, int interval); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_options_set_compression(IntPtr /*Options*/ options, CompressionType level); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_options_set_comparator(IntPtr /*Options*/ options, IntPtr /*Comparator*/ comparer); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_options_set_filter_policy(IntPtr /*Options*/ options, IntPtr /*FilterPolicy*/ policy); + #endregion + + #region ReadOptions + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr leveldb_readoptions_create(); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_readoptions_destroy(IntPtr /*ReadOptions*/ options); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_readoptions_set_verify_checksums(IntPtr /*ReadOptions*/ options, [MarshalAs(UnmanagedType.U1)] bool o); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_readoptions_set_fill_cache(IntPtr /*ReadOptions*/ options, [MarshalAs(UnmanagedType.U1)] bool o); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_readoptions_set_snapshot(IntPtr /*ReadOptions*/ options, IntPtr /*SnapShot*/ snapshot); + #endregion + + #region WriteBatch + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr leveldb_writebatch_create(); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_writebatch_destroy(IntPtr /* WriteBatch */ batch); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_writebatch_clear(IntPtr /* WriteBatch */ batch); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_writebatch_put(IntPtr /* WriteBatch */ batch, byte[] key, UIntPtr keylen, byte[] val, UIntPtr vallen); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_writebatch_delete(IntPtr /* WriteBatch */ batch, byte[] key, UIntPtr keylen); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_writebatch_iterate(IntPtr /* WriteBatch */ batch, object state, Action put, Action deleted); + #endregion + + #region WriteOptions + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr leveldb_writeoptions_create(); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_writeoptions_destroy(IntPtr /*WriteOptions*/ options); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_writeoptions_set_sync(IntPtr /*WriteOptions*/ options, [MarshalAs(UnmanagedType.U1)] bool o); + #endregion + + #region Cache + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr leveldb_cache_create_lru(int capacity); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_cache_destroy(IntPtr /*Cache*/ cache); + #endregion + + #region Comparator + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr /* leveldb_comparator_t* */ + leveldb_comparator_create( + IntPtr /* void* */ state, + IntPtr /* void (*)(void*) */ destructor, + IntPtr + /* int (*compare)(void*, + const char* a, size_t alen, + const char* b, size_t blen) */ + compare, + IntPtr /* const char* (*)(void*) */ name); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_comparator_destroy(IntPtr /* leveldb_comparator_t* */ cmp); + + #endregion + } + + internal static class NativeHelper + { + public static void CheckError(IntPtr error) + { + if (error != IntPtr.Zero) + { + string message = Marshal.PtrToStringAnsi(error); + Native.leveldb_free(error); + throw new LevelDBException(message); + } + } + } +} diff --git a/LevelDBStore/IO/Data/LevelDB/Options.cs b/LevelDBStore/IO/Data/LevelDB/Options.cs new file mode 100644 index 000000000..53dd6e488 --- /dev/null +++ b/LevelDBStore/IO/Data/LevelDB/Options.cs @@ -0,0 +1,87 @@ +using System; + +namespace Neo.IO.Data.LevelDB +{ + public class Options + { + public static readonly Options Default = new Options(); + internal readonly IntPtr handle = Native.leveldb_options_create(); + + public bool CreateIfMissing + { + set + { + Native.leveldb_options_set_create_if_missing(handle, value); + } + } + + public bool ErrorIfExists + { + set + { + Native.leveldb_options_set_error_if_exists(handle, value); + } + } + + public bool ParanoidChecks + { + set + { + Native.leveldb_options_set_paranoid_checks(handle, value); + } + } + + public int WriteBufferSize + { + set + { + Native.leveldb_options_set_write_buffer_size(handle, (UIntPtr)value); + } + } + + public int MaxOpenFiles + { + set + { + Native.leveldb_options_set_max_open_files(handle, value); + } + } + + public int BlockSize + { + set + { + Native.leveldb_options_set_block_size(handle, (UIntPtr)value); + } + } + + public int BlockRestartInterval + { + set + { + Native.leveldb_options_set_block_restart_interval(handle, value); + } + } + + public CompressionType Compression + { + set + { + Native.leveldb_options_set_compression(handle, value); + } + } + + public IntPtr FilterPolicy + { + set + { + Native.leveldb_options_set_filter_policy(handle, value); + } + } + + ~Options() + { + Native.leveldb_options_destroy(handle); + } + } +} diff --git a/LevelDBStore/IO/Data/LevelDB/ReadOptions.cs b/LevelDBStore/IO/Data/LevelDB/ReadOptions.cs new file mode 100644 index 000000000..9c198cfba --- /dev/null +++ b/LevelDBStore/IO/Data/LevelDB/ReadOptions.cs @@ -0,0 +1,39 @@ +using System; + +namespace Neo.IO.Data.LevelDB +{ + public class ReadOptions + { + public static readonly ReadOptions Default = new ReadOptions(); + internal readonly IntPtr handle = Native.leveldb_readoptions_create(); + + public bool VerifyChecksums + { + set + { + Native.leveldb_readoptions_set_verify_checksums(handle, value); + } + } + + public bool FillCache + { + set + { + Native.leveldb_readoptions_set_fill_cache(handle, value); + } + } + + public Snapshot Snapshot + { + set + { + Native.leveldb_readoptions_set_snapshot(handle, value.handle); + } + } + + ~ReadOptions() + { + Native.leveldb_readoptions_destroy(handle); + } + } +} diff --git a/LevelDBStore/IO/Data/LevelDB/Snapshot.cs b/LevelDBStore/IO/Data/LevelDB/Snapshot.cs new file mode 100644 index 000000000..d65109838 --- /dev/null +++ b/LevelDBStore/IO/Data/LevelDB/Snapshot.cs @@ -0,0 +1,24 @@ +using System; + +namespace Neo.IO.Data.LevelDB +{ + public class Snapshot : IDisposable + { + internal IntPtr db, handle; + + internal Snapshot(IntPtr db) + { + this.db = db; + this.handle = Native.leveldb_create_snapshot(db); + } + + public void Dispose() + { + if (handle != IntPtr.Zero) + { + Native.leveldb_release_snapshot(db, handle); + handle = IntPtr.Zero; + } + } + } +} diff --git a/LevelDBStore/IO/Data/LevelDB/WriteBatch.cs b/LevelDBStore/IO/Data/LevelDB/WriteBatch.cs new file mode 100644 index 000000000..8434038ba --- /dev/null +++ b/LevelDBStore/IO/Data/LevelDB/WriteBatch.cs @@ -0,0 +1,29 @@ +using System; + +namespace Neo.IO.Data.LevelDB +{ + public class WriteBatch + { + internal readonly IntPtr handle = Native.leveldb_writebatch_create(); + + ~WriteBatch() + { + Native.leveldb_writebatch_destroy(handle); + } + + public void Clear() + { + Native.leveldb_writebatch_clear(handle); + } + + public void Delete(byte[] key) + { + Native.leveldb_writebatch_delete(handle, key, (UIntPtr)key.Length); + } + + public void Put(byte[] key, byte[] value) + { + Native.leveldb_writebatch_put(handle, key, (UIntPtr)key.Length, value, (UIntPtr)value.Length); + } + } +} diff --git a/LevelDBStore/IO/Data/LevelDB/WriteOptions.cs b/LevelDBStore/IO/Data/LevelDB/WriteOptions.cs new file mode 100644 index 000000000..7fb46cdf6 --- /dev/null +++ b/LevelDBStore/IO/Data/LevelDB/WriteOptions.cs @@ -0,0 +1,25 @@ +using System; + +namespace Neo.IO.Data.LevelDB +{ + public class WriteOptions + { + public static readonly WriteOptions Default = new WriteOptions(); + public static readonly WriteOptions SyncWrite = new WriteOptions { Sync = true }; + + internal readonly IntPtr handle = Native.leveldb_writeoptions_create(); + + public bool Sync + { + set + { + Native.leveldb_writeoptions_set_sync(handle, value); + } + } + + ~WriteOptions() + { + Native.leveldb_writeoptions_destroy(handle); + } + } +} diff --git a/LevelDBStore/LevelDBStore.csproj b/LevelDBStore/LevelDBStore.csproj new file mode 100644 index 000000000..3dccf2e5c --- /dev/null +++ b/LevelDBStore/LevelDBStore.csproj @@ -0,0 +1,21 @@ + + + + 3.0.0-CI00810 + netstandard2.1 + Neo + true + + + + + PreserveNewest + PreserveNewest + + + + + + + + diff --git a/LevelDBStore/LevelDBStore/config.json b/LevelDBStore/LevelDBStore/config.json new file mode 100644 index 000000000..e6683b8e4 --- /dev/null +++ b/LevelDBStore/LevelDBStore/config.json @@ -0,0 +1,5 @@ +{ + "PluginConfiguration": { + "Path": "Data_LevelDB_{0}" + } +} diff --git a/LevelDBStore/Plugins/Storage/Helper.cs b/LevelDBStore/Plugins/Storage/Helper.cs new file mode 100644 index 000000000..dbb1271f0 --- /dev/null +++ b/LevelDBStore/Plugins/Storage/Helper.cs @@ -0,0 +1,16 @@ +using System; + +namespace Neo.Plugins.Storage +{ + internal static class Helper + { + public static byte[] CreateKey(byte table, byte[] key = null) + { + if (key is null) return new[] { table }; + byte[] buffer = new byte[1 + key.Length]; + buffer[0] = table; + Buffer.BlockCopy(key, 0, buffer, 1, key.Length); + return buffer; + } + } +} diff --git a/LevelDBStore/Plugins/Storage/LevelDBStore.cs b/LevelDBStore/Plugins/Storage/LevelDBStore.cs new file mode 100644 index 000000000..9501e0e26 --- /dev/null +++ b/LevelDBStore/Plugins/Storage/LevelDBStore.cs @@ -0,0 +1,19 @@ +using Neo.Persistence; + +namespace Neo.Plugins.Storage +{ + public class LevelDBStore : Plugin, IStoragePlugin + { + private string path; + + public override void Configure() + { + path = string.Format(GetConfiguration().GetSection("Path").Value, ProtocolSettings.Default.Magic.ToString("X8")); + } + + public IStore GetStore() + { + return new Store(path); + } + } +} diff --git a/LevelDBStore/Plugins/Storage/Snapshot.cs b/LevelDBStore/Plugins/Storage/Snapshot.cs new file mode 100644 index 000000000..aaba9951c --- /dev/null +++ b/LevelDBStore/Plugins/Storage/Snapshot.cs @@ -0,0 +1,53 @@ +using Neo.IO.Data.LevelDB; +using Neo.Persistence; +using System.Collections.Generic; +using LSnapshot = Neo.IO.Data.LevelDB.Snapshot; + +namespace Neo.Plugins.Storage +{ + internal class Snapshot : ISnapshot + { + private readonly DB db; + private readonly LSnapshot snapshot; + private readonly ReadOptions options; + private readonly WriteBatch batch; + + public Snapshot(DB db) + { + this.db = db; + this.snapshot = db.GetSnapshot(); + this.options = new ReadOptions { FillCache = false, Snapshot = snapshot }; + this.batch = new WriteBatch(); + } + + public void Commit() + { + db.Write(WriteOptions.Default, batch); + } + + public void Delete(byte table, byte[] key) + { + batch.Delete(Helper.CreateKey(table, key)); + } + + public void Dispose() + { + snapshot.Dispose(); + } + + public IEnumerable<(byte[] Key, byte[] Value)> Find(byte table, byte[] prefix) + { + return db.Find(options, Helper.CreateKey(table, prefix), (k, v) => (k[1..], v)); + } + + public void Put(byte table, byte[] key, byte[] value) + { + batch.Put(Helper.CreateKey(table, key), value); + } + + public byte[] TryGet(byte table, byte[] key) + { + return db.Get(options, Helper.CreateKey(table, key)); + } + } +} diff --git a/LevelDBStore/Plugins/Storage/Store.cs b/LevelDBStore/Plugins/Storage/Store.cs new file mode 100644 index 000000000..b5f422fce --- /dev/null +++ b/LevelDBStore/Plugins/Storage/Store.cs @@ -0,0 +1,69 @@ +using Neo.IO.Data.LevelDB; +using Neo.Persistence; +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Text; + +namespace Neo.Plugins.Storage +{ + internal class Store : IStore + { + private const byte SYS_Version = 0xf0; + private readonly DB db; + + public Store(string path) + { + this.db = DB.Open(path, new Options { CreateIfMissing = true }); + byte[] value = db.Get(ReadOptions.Default, Helper.CreateKey(SYS_Version)); + if (value != null && Version.TryParse(Encoding.ASCII.GetString(value), out Version version) && version >= Version.Parse("3.0.0")) + return; + WriteBatch batch = new WriteBatch(); + ReadOptions options = new ReadOptions { FillCache = false }; + using (Iterator it = db.NewIterator(options)) + { + for (it.SeekToFirst(); it.Valid(); it.Next()) + { + batch.Delete(it.Key()); + } + } + db.Put(WriteOptions.Default, Helper.CreateKey(SYS_Version), Encoding.ASCII.GetBytes(Assembly.GetExecutingAssembly().GetName().Version.ToString())); + db.Write(WriteOptions.Default, batch); + } + + public void Delete(byte table, byte[] key) + { + db.Delete(WriteOptions.Default, Helper.CreateKey(table, key)); + } + + public void Dispose() + { + db.Dispose(); + } + + public IEnumerable<(byte[], byte[])> Find(byte table, byte[] prefix) + { + return db.Find(ReadOptions.Default, Helper.CreateKey(table, prefix), (k, v) => (k[1..], v)); + } + + public ISnapshot GetSnapshot() + { + return new Snapshot(db); + } + + public void Put(byte table, byte[] key, byte[] value) + { + db.Put(WriteOptions.Default, Helper.CreateKey(table, key), value); + } + + public void PutSync(byte table, byte[] key, byte[] value) + { + db.Put(WriteOptions.SyncWrite, Helper.CreateKey(table, key), value); + } + + public byte[] TryGet(byte table, byte[] key) + { + return db.Get(ReadOptions.Default, Helper.CreateKey(table, key)); + } + } +} diff --git a/RpcNep5Tracker/DbCache.cs b/RpcNep5Tracker/DbCache.cs index 99f1d61fe..8c07630a2 100644 --- a/RpcNep5Tracker/DbCache.cs +++ b/RpcNep5Tracker/DbCache.cs @@ -25,32 +25,46 @@ public DbCache(DB db, ReadOptions options, WriteBatch batch, byte prefix) protected override void AddInternal(TKey key, TValue value) { - batch?.Put(prefix, key, value); + batch?.Put(CreateKey(prefix, key), value.ToArray()); + } + + private static byte[] CreateKey(byte prefix, byte[] key = null) + { + if (key is null) return new[] { prefix }; + byte[] buffer = new byte[1 + key.Length]; + buffer[0] = prefix; + Buffer.BlockCopy(key, 0, buffer, 1, key.Length); + return buffer; + } + + private static byte[] CreateKey(byte prefix, ISerializable key) + { + return CreateKey(prefix, key.ToArray()); } protected override void DeleteInternal(TKey key) { - batch?.Delete(prefix, key); + batch?.Delete(CreateKey(prefix, key)); } protected override IEnumerable<(TKey, TValue)> FindInternal(byte[] key_prefix) { - return db.Find(options, SliceBuilder.Begin(prefix).Add(key_prefix), (k, v) => (k.ToArray().AsSerializable(1), v.ToArray().AsSerializable())); + return db.Find(options, CreateKey(prefix, key_prefix), (k, v) => (k.AsSerializable(1), v.AsSerializable())); } protected override TValue GetInternal(TKey key) { - return db.Get(options, prefix, key); + return TryGetInternal(key) ?? throw new InvalidOperationException(); } protected override TValue TryGetInternal(TKey key) { - return db.TryGet(options, prefix, key); + return db.Get(options, CreateKey(prefix, key))?.AsSerializable(); } protected override void UpdateInternal(TKey key, TValue value) { - batch?.Put(prefix, key, value); + batch?.Put(CreateKey(prefix, key), value.ToArray()); } } } diff --git a/RpcNep5Tracker/Helper.cs b/RpcNep5Tracker/Helper.cs index 7e76bc44b..54ae8376d 100644 --- a/RpcNep5Tracker/Helper.cs +++ b/RpcNep5Tracker/Helper.cs @@ -7,27 +7,11 @@ namespace Neo.Plugins { internal static class Helper { - public static IEnumerable FindRange(this DB db, ReadOptions options, Slice startKey, Slice endKey, Func resultSelector) - { - using (Iterator it = db.NewIterator(options)) - { - for (it.Seek(startKey); it.Valid(); it.Next()) - { - Slice key = it.Key(); - if (key > endKey) break; - yield return resultSelector(key, it.Value()); - } - } - } - - public static IEnumerable> FindRange(this DB db, byte[] startKeyBytes, byte[] endKeyBytes) + public static IEnumerable<(TKey, TValue)> FindRange(this DB db, byte[] startKeyBytes, byte[] endKeyBytes) where TKey : IEquatable, ISerializable, new() where TValue : class, ICloneable, ISerializable, new() { - return db.FindRange(ReadOptions.Default, SliceBuilder.Begin().Add(startKeyBytes), - SliceBuilder.Begin().Add(endKeyBytes), - (k, v) => new KeyValuePair(k.ToArray().AsSerializable(1), - v.ToArray().AsSerializable())); + return db.FindRange(ReadOptions.Default, startKeyBytes, endKeyBytes, (k, v) => (k.AsSerializable(1), v.AsSerializable())); } } } diff --git a/RpcNep5Tracker/RpcNep5Tracker.cs b/RpcNep5Tracker/RpcNep5Tracker.cs index 0982a14bd..57f6e4e77 100644 --- a/RpcNep5Tracker/RpcNep5Tracker.cs +++ b/RpcNep5Tracker/RpcNep5Tracker.cs @@ -1,4 +1,5 @@ using Microsoft.AspNetCore.Http; +using Neo.IO; using Neo.IO.Caching; using Neo.IO.Data.LevelDB; using Neo.IO.Json; @@ -214,17 +215,17 @@ private void AddTransfers(byte dbPrefix, UInt160 userScriptHash, ulong startTime prefix.Concat(endTimeBytes).ToArray()); int resultCount = 0; - foreach (var transferPair in transferPairs) + foreach (var (key, value) in transferPairs) { if (++resultCount > _maxResults) break; JObject transfer = new JObject(); - transfer["timestamp"] = transferPair.Key.TimestampMS; - transfer["asset_hash"] = transferPair.Key.AssetScriptHash.ToString(); - transfer["transfer_address"] = transferPair.Value.UserScriptHash.ToAddress(); - transfer["amount"] = transferPair.Value.Amount.ToString(); - transfer["block_index"] = transferPair.Value.BlockIndex; - transfer["transfer_notify_index"] = transferPair.Key.BlockXferNotificationIndex; - transfer["tx_hash"] = transferPair.Value.TxHash.ToString(); + transfer["timestamp"] = key.TimestampMS; + transfer["asset_hash"] = key.AssetScriptHash.ToString(); + transfer["transfer_address"] = value.UserScriptHash.ToAddress(); + transfer["amount"] = value.Amount.ToString(); + transfer["block_index"] = value.BlockIndex; + transfer["transfer_notify_index"] = key.BlockXferNotificationIndex; + transfer["tx_hash"] = value.TxHash.ToString(); parentJArray.Add(transfer); } } diff --git a/RpcNep5Tracker/RpcNep5Tracker.csproj b/RpcNep5Tracker/RpcNep5Tracker.csproj index 693295439..6cac14be3 100644 --- a/RpcNep5Tracker/RpcNep5Tracker.csproj +++ b/RpcNep5Tracker/RpcNep5Tracker.csproj @@ -11,6 +11,6 @@ - + diff --git a/neo-plugins.sln b/neo-plugins.sln index a016e7d01..01c09ea7d 100644 --- a/neo-plugins.sln +++ b/neo-plugins.sln @@ -17,7 +17,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RpcNep5Tracker", "RpcNep5Tr EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CoreMetrics", "CoreMetrics\CoreMetrics.csproj", "{AEFFF003-3500-416B-AD9B-8C838C33C1F4}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SystemLog", "SystemLog\SystemLog.csproj", "{14DB62D5-0EA1-4A98-8656-1AA2D0345206}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SystemLog", "SystemLog\SystemLog.csproj", "{14DB62D5-0EA1-4A98-8656-1AA2D0345206}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LevelDBStore", "LevelDBStore\LevelDBStore.csproj", "{C66214CD-0B97-4EA5-B7A2-164F54346F19}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -57,6 +59,10 @@ Global {14DB62D5-0EA1-4A98-8656-1AA2D0345206}.Debug|Any CPU.Build.0 = Debug|Any CPU {14DB62D5-0EA1-4A98-8656-1AA2D0345206}.Release|Any CPU.ActiveCfg = Release|Any CPU {14DB62D5-0EA1-4A98-8656-1AA2D0345206}.Release|Any CPU.Build.0 = Release|Any CPU + {C66214CD-0B97-4EA5-B7A2-164F54346F19}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C66214CD-0B97-4EA5-B7A2-164F54346F19}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C66214CD-0B97-4EA5-B7A2-164F54346F19}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C66214CD-0B97-4EA5-B7A2-164F54346F19}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From e48eae0a9273d6a8b07ce761bd33a7ee78bba93e Mon Sep 17 00:00:00 2001 From: erikzhang Date: Wed, 4 Dec 2019 13:30:46 +0800 Subject: [PATCH 083/183] Neo v3.0.0-CI00817 --- ApplicationLogs/LogReader.cs | 8 ++++---- CoreMetrics/CoreMetrics.cs | 4 ++-- CoreMetrics/CoreMetrics.csproj | 4 ++-- ImportBlocks/ImportBlocks.cs | 4 ++-- ImportBlocks/ImportBlocks.csproj | 4 ++-- LevelDBStore/LevelDBStore.csproj | 4 ++-- LevelDBStore/Plugins/Storage/LevelDBStore.cs | 4 ++-- RpcNep5Tracker/RpcNep5Tracker.cs | 6 +++--- RpcSecurity/RpcSecurity.cs | 4 ++-- RpcSecurity/RpcSecurity.csproj | 4 ++-- RpcWallet/RpcWallet.cs | 2 +- RpcWallet/RpcWallet.csproj | 4 ++-- StatesDumper/StatesDumper.cs | 4 ++-- StatesDumper/StatesDumper.csproj | 4 ++-- SystemLog/Logger.cs | 9 +++++---- SystemLog/SystemLog.csproj | 4 ++-- 16 files changed, 37 insertions(+), 36 deletions(-) diff --git a/ApplicationLogs/LogReader.cs b/ApplicationLogs/LogReader.cs index 169fddd88..efb7c589c 100644 --- a/ApplicationLogs/LogReader.cs +++ b/ApplicationLogs/LogReader.cs @@ -1,4 +1,4 @@ -using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http; using Neo.IO; using Neo.IO.Data.LevelDB; using Neo.IO.Json; @@ -8,9 +8,9 @@ using Neo.VM; using System; using System.Collections.Generic; -using System.IO; using System.Linq; using System.Text; +using static System.IO.Path; namespace Neo.Plugins { @@ -22,10 +22,10 @@ public class LogReader : Plugin, IRpcPlugin, IPersistencePlugin public LogReader() { - db = DB.Open(Path.GetFullPath(Settings.Default.Path), new Options { CreateIfMissing = true }); + db = DB.Open(GetFullPath(Settings.Default.Path), new Options { CreateIfMissing = true }); } - public override void Configure() + protected override void Configure() { Settings.Load(GetConfiguration()); } diff --git a/CoreMetrics/CoreMetrics.cs b/CoreMetrics/CoreMetrics.cs index 00788987f..8b5d9aedd 100644 --- a/CoreMetrics/CoreMetrics.cs +++ b/CoreMetrics/CoreMetrics.cs @@ -1,4 +1,4 @@ -using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http; using Neo.IO.Json; using Neo.Ledger; using Neo.Network.P2P.Payloads; @@ -7,7 +7,7 @@ namespace Neo.Plugins { public class CoreMetrics : Plugin, IRpcPlugin { - public override void Configure() { } + protected override void Configure() { } public void PreProcess(HttpContext context, string method, JArray _params) { } diff --git a/CoreMetrics/CoreMetrics.csproj b/CoreMetrics/CoreMetrics.csproj index 977514faa..fe79e4b58 100644 --- a/CoreMetrics/CoreMetrics.csproj +++ b/CoreMetrics/CoreMetrics.csproj @@ -1,4 +1,4 @@ - + 3.0.0-preview1 @@ -7,7 +7,7 @@ - + diff --git a/ImportBlocks/ImportBlocks.cs b/ImportBlocks/ImportBlocks.cs index 160a8f504..e93413421 100644 --- a/ImportBlocks/ImportBlocks.cs +++ b/ImportBlocks/ImportBlocks.cs @@ -1,4 +1,4 @@ -using Akka.Actor; +using Akka.Actor; using Neo.IO; using Neo.Ledger; using Neo.Network.P2P.Payloads; @@ -11,7 +11,7 @@ public class ImportBlocks : Plugin { private IActorRef _blockImporter; - public override void Configure() + protected override void Configure() { Settings.Load(GetConfiguration()); } diff --git a/ImportBlocks/ImportBlocks.csproj b/ImportBlocks/ImportBlocks.csproj index 243ffdb82..c76c33e35 100644 --- a/ImportBlocks/ImportBlocks.csproj +++ b/ImportBlocks/ImportBlocks.csproj @@ -1,4 +1,4 @@ - + 3.0.0-preview1 @@ -14,7 +14,7 @@ - + diff --git a/LevelDBStore/LevelDBStore.csproj b/LevelDBStore/LevelDBStore.csproj index 3dccf2e5c..cc598ac64 100644 --- a/LevelDBStore/LevelDBStore.csproj +++ b/LevelDBStore/LevelDBStore.csproj @@ -1,7 +1,7 @@  - 3.0.0-CI00810 + 3.0.0-CI00817 netstandard2.1 Neo true @@ -15,7 +15,7 @@ - + diff --git a/LevelDBStore/Plugins/Storage/LevelDBStore.cs b/LevelDBStore/Plugins/Storage/LevelDBStore.cs index 9501e0e26..7783f3988 100644 --- a/LevelDBStore/Plugins/Storage/LevelDBStore.cs +++ b/LevelDBStore/Plugins/Storage/LevelDBStore.cs @@ -1,4 +1,4 @@ -using Neo.Persistence; +using Neo.Persistence; namespace Neo.Plugins.Storage { @@ -6,7 +6,7 @@ public class LevelDBStore : Plugin, IStoragePlugin { private string path; - public override void Configure() + protected override void Configure() { path = string.Format(GetConfiguration().GetSection("Path").Value, ProtocolSettings.Default.Magic.ToString("X8")); } diff --git a/RpcNep5Tracker/RpcNep5Tracker.cs b/RpcNep5Tracker/RpcNep5Tracker.cs index 57f6e4e77..75788a683 100644 --- a/RpcNep5Tracker/RpcNep5Tracker.cs +++ b/RpcNep5Tracker/RpcNep5Tracker.cs @@ -12,9 +12,9 @@ using Neo.Wallets; using System; using System.Collections.Generic; -using System.IO; using System.Linq; using System.Numerics; +using static System.IO.Path; namespace Neo.Plugins { @@ -33,12 +33,12 @@ public class RpcNep5Tracker : Plugin, IPersistencePlugin, IRpcPlugin private uint _maxResults; private Neo.IO.Data.LevelDB.Snapshot _levelDbSnapshot; - public override void Configure() + protected override void Configure() { if (_db == null) { var dbPath = GetConfiguration().GetSection("DBPath").Value ?? "Nep5BalanceData"; - _db = DB.Open(Path.GetFullPath(dbPath), new Options { CreateIfMissing = true }); + _db = DB.Open(GetFullPath(dbPath), new Options { CreateIfMissing = true }); } _shouldTrackHistory = (GetConfiguration().GetSection("TrackHistory").Value ?? true.ToString()) != false.ToString(); _recordNullAddressHistory = (GetConfiguration().GetSection("RecordNullAddressHistory").Value ?? false.ToString()) != false.ToString(); diff --git a/RpcSecurity/RpcSecurity.cs b/RpcSecurity/RpcSecurity.cs index 16054c3a8..a63f8b88c 100644 --- a/RpcSecurity/RpcSecurity.cs +++ b/RpcSecurity/RpcSecurity.cs @@ -1,4 +1,4 @@ -using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http; using Neo.IO.Json; using Neo.Network.RPC; using System; @@ -9,7 +9,7 @@ namespace Neo.Plugins { public class RpcSecurity : Plugin, IRpcPlugin { - public override void Configure() + protected override void Configure() { Settings.Load(GetConfiguration()); } diff --git a/RpcSecurity/RpcSecurity.csproj b/RpcSecurity/RpcSecurity.csproj index 1d88451b2..2d5a348cf 100644 --- a/RpcSecurity/RpcSecurity.csproj +++ b/RpcSecurity/RpcSecurity.csproj @@ -1,4 +1,4 @@ - + 3.0.0-preview1 @@ -14,7 +14,7 @@ - + diff --git a/RpcWallet/RpcWallet.cs b/RpcWallet/RpcWallet.cs index 451e9358a..12178ad10 100644 --- a/RpcWallet/RpcWallet.cs +++ b/RpcWallet/RpcWallet.cs @@ -20,7 +20,7 @@ public class RpcWallet : Plugin, IRpcPlugin { private Wallet Wallet => System.RpcServer.Wallet; - public override void Configure() + protected override void Configure() { Settings.Load(GetConfiguration()); } diff --git a/RpcWallet/RpcWallet.csproj b/RpcWallet/RpcWallet.csproj index bcfafc45b..e85fcc9e7 100644 --- a/RpcWallet/RpcWallet.csproj +++ b/RpcWallet/RpcWallet.csproj @@ -1,4 +1,4 @@ - + 3.0.0-preview1 @@ -14,7 +14,7 @@ - + diff --git a/StatesDumper/StatesDumper.cs b/StatesDumper/StatesDumper.cs index a0d50fc3e..fb80ff2a8 100644 --- a/StatesDumper/StatesDumper.cs +++ b/StatesDumper/StatesDumper.cs @@ -1,4 +1,4 @@ -using Neo.IO; +using Neo.IO; using Neo.IO.Caching; using Neo.IO.Json; using Neo.Ledger; @@ -14,7 +14,7 @@ public class StatesDumper : Plugin, IPersistencePlugin { private readonly JArray bs_cache = new JArray(); - public override void Configure() + protected override void Configure() { Settings.Load(GetConfiguration()); } diff --git a/StatesDumper/StatesDumper.csproj b/StatesDumper/StatesDumper.csproj index 4a0f0299d..192acce64 100644 --- a/StatesDumper/StatesDumper.csproj +++ b/StatesDumper/StatesDumper.csproj @@ -1,4 +1,4 @@ - + 3.0.0-preview1 @@ -14,7 +14,7 @@ - + diff --git a/SystemLog/Logger.cs b/SystemLog/Logger.cs index 875592315..8ce3981ee 100644 --- a/SystemLog/Logger.cs +++ b/SystemLog/Logger.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using static System.IO.Path; namespace Neo.Plugins { @@ -7,12 +8,12 @@ public class Logger : Plugin, ILogPlugin { public override string Name => "SystemLog"; - public override void Configure() + protected override void Configure() { Settings.Load(GetConfiguration()); } - public new void Log(string source, LogLevel level, string message) + void ILogPlugin.Log(string source, LogLevel level, string message) { lock (typeof(Logger)) { @@ -38,9 +39,9 @@ public override void Configure() if (!string.IsNullOrEmpty(Settings.Default.Path)) { - var path = Path.Combine(Settings.Default.Path, source); + var path = Combine(Settings.Default.Path, source); Directory.CreateDirectory(path); - path = Path.Combine(path, $"{now:yyyy-MM-dd}.log"); + path = Combine(path, $"{now:yyyy-MM-dd}.log"); File.AppendAllLines(path, new[] { $"[{level}]{log}" }); } } diff --git a/SystemLog/SystemLog.csproj b/SystemLog/SystemLog.csproj index de98acd2a..fccf50cab 100644 --- a/SystemLog/SystemLog.csproj +++ b/SystemLog/SystemLog.csproj @@ -1,4 +1,4 @@ - + 3.0.0-preview1 @@ -14,7 +14,7 @@ - + From bd2d33ac20b9d4eb76a3336d44def183633ee382 Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Thu, 5 Dec 2019 21:54:30 +0800 Subject: [PATCH 084/183] Fix leveldb (#153) --- LevelDBStore/IO/Data/LevelDB/DB.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/LevelDBStore/IO/Data/LevelDB/DB.cs b/LevelDBStore/IO/Data/LevelDB/DB.cs index 5995cb9f1..82ccf933b 100644 --- a/LevelDBStore/IO/Data/LevelDB/DB.cs +++ b/LevelDBStore/IO/Data/LevelDB/DB.cs @@ -1,4 +1,5 @@ using System; +using System.IO; namespace Neo.IO.Data.LevelDB { @@ -66,7 +67,7 @@ public static DB Open(string name) public static DB Open(string name, Options options) { - IntPtr handle = Native.leveldb_open(options.handle, name, out IntPtr error); + IntPtr handle = Native.leveldb_open(options.handle, Path.GetFullPath(name), out IntPtr error); NativeHelper.CheckError(error); return new DB(handle); } From 29fee59944fb4ae3a9e8d644c3d334fd3df5b474 Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Thu, 5 Dec 2019 21:56:15 +0800 Subject: [PATCH 085/183] Fix ApplicationLog (#154) --- ApplicationLogs/LogReader.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ApplicationLogs/LogReader.cs b/ApplicationLogs/LogReader.cs index efb7c589c..969094293 100644 --- a/ApplicationLogs/LogReader.cs +++ b/ApplicationLogs/LogReader.cs @@ -41,7 +41,7 @@ public JObject OnProcess(HttpContext context, string method, JArray _params) byte[] value = db.Get(ReadOptions.Default, hash.ToArray()); if (value is null) throw new RpcException(-100, "Unknown transaction"); - return JObject.Parse(value.ToString()); + return JObject.Parse(Encoding.UTF8.GetString(value)); } public void PostProcess(HttpContext context, string method, JArray _params, JObject result) From 48e1ce8331d9dd72bd7cb481075978bc2cf0c4fa Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Sat, 7 Dec 2019 03:27:13 +0800 Subject: [PATCH 086/183] Dispose ApplicationEngine after using (#156) --- RpcNep5Tracker/RpcNep5Tracker.cs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/RpcNep5Tracker/RpcNep5Tracker.cs b/RpcNep5Tracker/RpcNep5Tracker.cs index 75788a683..183ae23b3 100644 --- a/RpcNep5Tracker/RpcNep5Tracker.cs +++ b/RpcNep5Tracker/RpcNep5Tracker.cs @@ -165,10 +165,12 @@ public void OnPersist(StoreView snapshot, IReadOnlyList Date: Sat, 7 Dec 2019 14:37:17 +0100 Subject: [PATCH 087/183] RocksDb storage plugin (#144) * RocksDb plugin * Update IStoragePlugin.cs * Clean name * Refactor as IStore * Remove Helper * Reorder * Remove IStorage * Reduce sln changes * sln bom * Clean and optimize * Update nuget * Create and cache only families if are used * Rename namespaces * Rename classes * 3.0 version * Format * Rename the directory * SetSync * Remove the DbOptions wrapper * Update Options.cs * Remove RocksDBCore * Remove ColumnFamily.cs * Rename RocksDbSnapshot to Snapshot * Add config.json * Update RocksDBStore.csproj * Add storage UT * Fix RocksDb * Update dotnetcore.yml * Update dotnetcore.yml * Copy fix leveldb * Remove test * Remove comment * Fix the fix * Fix Clear method * Some changes * Fix sln * Update dotnetcore.yml * sudo apt * add leveldb * Update dotnetcore.yml * Fix Dispose and add UT * Clean using * Optimize LevelDB init --- .github/workflows/dotnetcore.yml | 7 +- LevelDBStore/Plugins/Storage/LevelDBStore.cs | 2 +- LevelDBStore/Plugins/Storage/Store.cs | 18 ++- RocksDBStore/Plugins/Storage/Options.cs | 25 ++++ RocksDBStore/Plugins/Storage/RocksDBStore.cs | 21 ++++ RocksDBStore/Plugins/Storage/Settings.cs | 21 ++++ RocksDBStore/Plugins/Storage/Snapshot.cs | 67 ++++++++++ RocksDBStore/Plugins/Storage/Store.cs | 117 ++++++++++++++++++ RocksDBStore/RocksDBStore.csproj | 22 ++++ RocksDBStore/RocksDBStore/config.json | 5 + neo-plugins.sln | 17 +++ tests/neo-plugins.Tests/StoreTest.cs | 110 ++++++++++++++++ .../neo-plugins.Tests.csproj | 20 +++ 13 files changed, 444 insertions(+), 8 deletions(-) create mode 100644 RocksDBStore/Plugins/Storage/Options.cs create mode 100644 RocksDBStore/Plugins/Storage/RocksDBStore.cs create mode 100644 RocksDBStore/Plugins/Storage/Settings.cs create mode 100644 RocksDBStore/Plugins/Storage/Snapshot.cs create mode 100644 RocksDBStore/Plugins/Storage/Store.cs create mode 100644 RocksDBStore/RocksDBStore.csproj create mode 100644 RocksDBStore/RocksDBStore/config.json create mode 100644 tests/neo-plugins.Tests/StoreTest.cs create mode 100644 tests/neo-plugins.Tests/neo-plugins.Tests.csproj diff --git a/.github/workflows/dotnetcore.yml b/.github/workflows/dotnetcore.yml index 71250ece7..431d34ee4 100644 --- a/.github/workflows/dotnetcore.yml +++ b/.github/workflows/dotnetcore.yml @@ -20,5 +20,8 @@ jobs: run: | dotnet tool install --tool-path ./ dotnet-format ./dotnet-format --check --dry-run -v diagnostic - - name: Build - run: dotnet build + - name: Test + run: | + sudo apt-get --assume-yes install libleveldb-dev libsnappy-dev libc6-dev + find tests -name *.csproj | xargs -I % dotnet add % package coverlet.msbuild + dotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=lcov /p:CoverletOutput=${GITHUB_WORKSPACE}/coverage/lcov diff --git a/LevelDBStore/Plugins/Storage/LevelDBStore.cs b/LevelDBStore/Plugins/Storage/LevelDBStore.cs index 7783f3988..265c4286b 100644 --- a/LevelDBStore/Plugins/Storage/LevelDBStore.cs +++ b/LevelDBStore/Plugins/Storage/LevelDBStore.cs @@ -8,7 +8,7 @@ public class LevelDBStore : Plugin, IStoragePlugin protected override void Configure() { - path = string.Format(GetConfiguration().GetSection("Path").Value, ProtocolSettings.Default.Magic.ToString("X8")); + path = string.Format(GetConfiguration().GetSection("Path").Value ?? "Data_LevelDB_{0}", ProtocolSettings.Default.Magic.ToString("X8")); } public IStore GetStore() diff --git a/LevelDBStore/Plugins/Storage/Store.cs b/LevelDBStore/Plugins/Storage/Store.cs index b5f422fce..fef486d27 100644 --- a/LevelDBStore/Plugins/Storage/Store.cs +++ b/LevelDBStore/Plugins/Storage/Store.cs @@ -1,4 +1,4 @@ -using Neo.IO.Data.LevelDB; +using Neo.IO.Data.LevelDB; using Neo.Persistence; using System; using System.Collections.Generic; @@ -18,15 +18,23 @@ public Store(string path) byte[] value = db.Get(ReadOptions.Default, Helper.CreateKey(SYS_Version)); if (value != null && Version.TryParse(Encoding.ASCII.GetString(value), out Version version) && version >= Version.Parse("3.0.0")) return; + WriteBatch batch = new WriteBatch(); - ReadOptions options = new ReadOptions { FillCache = false }; - using (Iterator it = db.NewIterator(options)) + + if (value != null) { - for (it.SeekToFirst(); it.Valid(); it.Next()) + // Clean all entries only if the version are different + + ReadOptions options = new ReadOptions { FillCache = false }; + using (Iterator it = db.NewIterator(options)) { - batch.Delete(it.Key()); + for (it.SeekToFirst(); it.Valid(); it.Next()) + { + batch.Delete(it.Key()); + } } } + db.Put(WriteOptions.Default, Helper.CreateKey(SYS_Version), Encoding.ASCII.GetBytes(Assembly.GetExecutingAssembly().GetName().Version.ToString())); db.Write(WriteOptions.Default, batch); } diff --git a/RocksDBStore/Plugins/Storage/Options.cs b/RocksDBStore/Plugins/Storage/Options.cs new file mode 100644 index 000000000..56357a0ee --- /dev/null +++ b/RocksDBStore/Plugins/Storage/Options.cs @@ -0,0 +1,25 @@ +using RocksDbSharp; + +namespace Neo.Plugins.Storage +{ + public static class Options + { + public static readonly DbOptions Default = CreateDbOptions(); + public static readonly ReadOptions ReadDefault = new ReadOptions(); + public static readonly WriteOptions WriteDefault = new WriteOptions(); + public static readonly WriteOptions WriteDefaultSync = new WriteOptions().SetSync(true); + + public static DbOptions CreateDbOptions() + { + DbOptions options = new DbOptions(); + options.SetCreateMissingColumnFamilies(true); + options.SetCreateIfMissing(true); + options.SetErrorIfExists(false); + options.SetMaxOpenFiles(1000); + options.SetParanoidChecks(false); + options.SetWriteBufferSize(4 << 20); + options.SetBlockBasedTableFactory(new BlockBasedTableOptions().SetBlockSize(4096)); + return options; + } + } +} diff --git a/RocksDBStore/Plugins/Storage/RocksDBStore.cs b/RocksDBStore/Plugins/Storage/RocksDBStore.cs new file mode 100644 index 000000000..5e8b540b7 --- /dev/null +++ b/RocksDBStore/Plugins/Storage/RocksDBStore.cs @@ -0,0 +1,21 @@ +using Neo.Persistence; + +namespace Neo.Plugins.Storage +{ + public class RocksDBStore : Plugin, IStoragePlugin + { + /// + /// Configure + /// + public override void Configure() + { + Settings.Load(GetConfiguration()); + } + + /// + /// Get store + /// + /// RocksDbStore + public IStore GetStore() => new Store(Settings.Default.Path); + } +} diff --git a/RocksDBStore/Plugins/Storage/Settings.cs b/RocksDBStore/Plugins/Storage/Settings.cs new file mode 100644 index 000000000..253be9751 --- /dev/null +++ b/RocksDBStore/Plugins/Storage/Settings.cs @@ -0,0 +1,21 @@ +using Microsoft.Extensions.Configuration; + +namespace Neo.Plugins.Storage +{ + internal class Settings + { + public string Path { get; } + + public static Settings Default { get; private set; } + + private Settings(IConfigurationSection section) + { + this.Path = string.Format(section.GetSection("Path").Value ?? "Data_RocksDB_{0}", ProtocolSettings.Default.Magic.ToString("X8")); + } + + public static void Load(IConfigurationSection section) + { + Default = new Settings(section); + } + } +} diff --git a/RocksDBStore/Plugins/Storage/Snapshot.cs b/RocksDBStore/Plugins/Storage/Snapshot.cs new file mode 100644 index 000000000..163a8e661 --- /dev/null +++ b/RocksDBStore/Plugins/Storage/Snapshot.cs @@ -0,0 +1,67 @@ +using Neo.Persistence; +using RocksDbSharp; +using System; +using System.Collections.Generic; + +namespace Neo.Plugins.Storage +{ + internal class Snapshot : ISnapshot + { + private readonly Store store; + private readonly RocksDb db; + private readonly RocksDbSharp.Snapshot snapshot; + private readonly WriteBatch batch; + private readonly ReadOptions options; + + public Snapshot(Store store, RocksDb db) + { + this.store = store; + this.db = db; + this.snapshot = db.CreateSnapshot(); + this.batch = new WriteBatch(); + + options = new ReadOptions(); + options.SetFillCache(false); + options.SetSnapshot(snapshot); + } + + public void Commit() + { + db.Write(batch, Options.WriteDefault); + } + + public void Delete(byte table, byte[] key) + { + batch.Delete(key, store.GetFamily(table)); + } + + public void Put(byte table, byte[] key, byte[] value) + { + batch.Put(key, value, store.GetFamily(table)); + } + + public IEnumerable<(byte[] Key, byte[] Value)> Find(byte table, byte[] prefix) + { + using var it = db.NewIterator(store.GetFamily(table), options); + for (it.Seek(prefix); it.Valid(); it.Next()) + { + var key = it.Key(); + byte[] y = prefix; + if (key.Length < y.Length) break; + if (!key.AsSpan().StartsWith(y)) break; + yield return (key, it.Value()); + } + } + + public byte[] TryGet(byte table, byte[] key) + { + return db.Get(key, store.GetFamily(table), options); + } + + public void Dispose() + { + snapshot.Dispose(); + batch.Dispose(); + } + } +} diff --git a/RocksDBStore/Plugins/Storage/Store.cs b/RocksDBStore/Plugins/Storage/Store.cs new file mode 100644 index 000000000..97d0e2f2c --- /dev/null +++ b/RocksDBStore/Plugins/Storage/Store.cs @@ -0,0 +1,117 @@ +using Neo.Persistence; +using RocksDbSharp; +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; + +namespace Neo.Plugins.Storage +{ + internal class Store : IStore + { + private static readonly byte[] SYS_Version = { 0xf0 }; + private readonly RocksDb db; + private readonly Dictionary _families = new Dictionary(); + + public Store(string path) + { + var families = new ColumnFamilies(); + for (int x = 0; x <= byte.MaxValue; x++) + families.Add(new ColumnFamilies.Descriptor(x.ToString(), new ColumnFamilyOptions())); + db = RocksDb.Open(Options.Default, Path.GetFullPath(path), families); + + ColumnFamilyHandle defaultFamily = db.GetDefaultColumnFamily(); + byte[] value = db.Get(SYS_Version, defaultFamily, Options.ReadDefault); + if (value != null && Version.TryParse(Encoding.ASCII.GetString(value), out Version version) && version >= Version.Parse("3.0.0")) + return; + + if (value != null) + { + // Clean all families only if the version are different + + Parallel.For(0, byte.MaxValue + 1, (x) => db.DropColumnFamily(x.ToString())); + _families.Clear(); + } + + // Update version + + db.Put(SYS_Version, Encoding.ASCII.GetBytes(Assembly.GetExecutingAssembly().GetName().Version.ToString()), defaultFamily, Options.WriteDefault); + } + + public void Dispose() + { + db.Dispose(); + _families.Clear(); + } + + /// + /// Get family + /// + /// Table + /// Return column family + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ColumnFamilyHandle GetFamily(byte table) + { + if (!_families.TryGetValue(table, out var family)) + { + try + { + // Try to find the family + + family = db.GetColumnFamily(table.ToString()); + _families.Add(table, family); + } + catch (KeyNotFoundException) + { + // Try to create the family + + family = db.CreateColumnFamily(new ColumnFamilyOptions(), table.ToString()); + _families.Add(table, family); + } + } + + return family; + } + + public ISnapshot GetSnapshot() + { + return new Snapshot(this, db); + } + + public IEnumerable<(byte[] Key, byte[] Value)> Find(byte table, byte[] prefix) + { + using var it = db.NewIterator(GetFamily(table), Options.ReadDefault); + for (it.Seek(prefix); it.Valid(); it.Next()) + { + var key = it.Key(); + byte[] y = prefix; + if (key.Length < y.Length) break; + if (!key.AsSpan().StartsWith(y)) break; + yield return (key, it.Value()); + } + } + + public byte[] TryGet(byte table, byte[] key) + { + return db.Get(key, GetFamily(table), Options.ReadDefault); + } + + public void Delete(byte table, byte[] key) + { + db.Remove(key, GetFamily(table), Options.WriteDefault); + } + + public void Put(byte table, byte[] key, byte[] value) + { + db.Put(key, value, GetFamily(table), Options.WriteDefault); + } + + public void PutSync(byte table, byte[] key, byte[] value) + { + db.Put(key, value, GetFamily(table), Options.WriteDefaultSync); + } + } +} diff --git a/RocksDBStore/RocksDBStore.csproj b/RocksDBStore/RocksDBStore.csproj new file mode 100644 index 000000000..9d07eea87 --- /dev/null +++ b/RocksDBStore/RocksDBStore.csproj @@ -0,0 +1,22 @@ + + + + 3.0.0-CI00810 + netstandard2.1 + Neo.Plugins.Storage + + + + + PreserveNewest + PreserveNewest + + + + + + + + + + diff --git a/RocksDBStore/RocksDBStore/config.json b/RocksDBStore/RocksDBStore/config.json new file mode 100644 index 000000000..5ded6dfe1 --- /dev/null +++ b/RocksDBStore/RocksDBStore/config.json @@ -0,0 +1,5 @@ +{ + "PluginConfiguration": { + "Path": "Data_RocksDB_{0}" + } +} diff --git a/neo-plugins.sln b/neo-plugins.sln index 01c09ea7d..3700cfc55 100644 --- a/neo-plugins.sln +++ b/neo-plugins.sln @@ -21,6 +21,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SystemLog", "SystemLog\Syst EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LevelDBStore", "LevelDBStore\LevelDBStore.csproj", "{C66214CD-0B97-4EA5-B7A2-164F54346F19}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RocksDBStore", "RocksDBStore\RocksDBStore.csproj", "{0E2AAF05-C55A-4B36-8750-F55743FBE4B3}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{59D802AB-C552-422A-B9C3-64D329FBCDCC}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "neo-plugins.Tests", "tests\neo-plugins.Tests\neo-plugins.Tests.csproj", "{9E7EA895-302A-4C0C-BA9B-54F9A67AD75C}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -63,10 +69,21 @@ Global {C66214CD-0B97-4EA5-B7A2-164F54346F19}.Debug|Any CPU.Build.0 = Debug|Any CPU {C66214CD-0B97-4EA5-B7A2-164F54346F19}.Release|Any CPU.ActiveCfg = Release|Any CPU {C66214CD-0B97-4EA5-B7A2-164F54346F19}.Release|Any CPU.Build.0 = Release|Any CPU + {0E2AAF05-C55A-4B36-8750-F55743FBE4B3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0E2AAF05-C55A-4B36-8750-F55743FBE4B3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0E2AAF05-C55A-4B36-8750-F55743FBE4B3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0E2AAF05-C55A-4B36-8750-F55743FBE4B3}.Release|Any CPU.Build.0 = Release|Any CPU + {9E7EA895-302A-4C0C-BA9B-54F9A67AD75C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9E7EA895-302A-4C0C-BA9B-54F9A67AD75C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9E7EA895-302A-4C0C-BA9B-54F9A67AD75C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9E7EA895-302A-4C0C-BA9B-54F9A67AD75C}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {9E7EA895-302A-4C0C-BA9B-54F9A67AD75C} = {59D802AB-C552-422A-B9C3-64D329FBCDCC} + EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {61D3ADE6-BBFC-402D-AB42-1C71C9F9EDE3} EndGlobalSection diff --git a/tests/neo-plugins.Tests/StoreTest.cs b/tests/neo-plugins.Tests/StoreTest.cs new file mode 100644 index 000000000..5035644ea --- /dev/null +++ b/tests/neo-plugins.Tests/StoreTest.cs @@ -0,0 +1,110 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Persistence; + +namespace neo_plugins.Tests +{ + [TestClass] + public class StoreTest + { + [TestMethod] + public void TestLevelDb() + { + using (var plugin = new Neo.Plugins.Storage.LevelDBStore()) + { + // Test all with the same store + + TestStorage(plugin.GetStore()); + + // Test with different storages + + TestPersistenceWrite(plugin.GetStore()); + TestPersistenceRead(plugin.GetStore(), true); + TestPersistenceDelete(plugin.GetStore()); + TestPersistenceRead(plugin.GetStore(), false); + } + } + + [TestMethod] + public void TestRocksDb() + { + using (var plugin = new Neo.Plugins.Storage.RocksDBStore()) + { + // Test all with the same store + + TestStorage(plugin.GetStore()); + + // Test with different storages + + TestPersistenceWrite(plugin.GetStore()); + TestPersistenceRead(plugin.GetStore(), true); + TestPersistenceDelete(plugin.GetStore()); + TestPersistenceRead(plugin.GetStore(), false); + } + } + + /// + /// Test Put/Delete/TryGet + /// + /// Store + private void TestStorage(IStore store) + { + using (store) + { + var ret = store.TryGet(0, new byte[] { 0x01, 0x02 }); + Assert.IsNull(ret); + + store.Put(0, new byte[] { 0x01, 0x02 }, new byte[] { 0x03, 0x04 }); + ret = store.TryGet(0, new byte[] { 0x01, 0x02 }); + CollectionAssert.AreEqual(new byte[] { 0x03, 0x04 }, ret); + + ret = store.TryGet(1, new byte[] { 0x01, 0x02 }); + Assert.IsNull(ret); + + store.Delete(0, new byte[] { 0x01, 0x02 }); + + ret = store.TryGet(0, new byte[] { 0x01, 0x02 }); + Assert.IsNull(ret); + } + } + + /// + /// Test Put + /// + /// Store + private void TestPersistenceWrite(IStore store) + { + using (store) + { + store.Put(byte.MaxValue, new byte[] { 0x01, 0x02, 0x03 }, new byte[] { 0x04, 0x05, 0x06 }); + } + } + + /// + /// Test Put + /// + /// Store + private void TestPersistenceDelete(IStore store) + { + using (store) + { + store.Delete(byte.MaxValue, new byte[] { 0x01, 0x02, 0x03 }); + } + } + + /// + /// Test Read + /// + /// Store + /// Should exist + private void TestPersistenceRead(IStore store, bool shouldExist) + { + using (store) + { + var ret = store.TryGet(byte.MaxValue, new byte[] { 0x01, 0x02, 0x03 }); + + if (shouldExist) CollectionAssert.AreEqual(new byte[] { 0x04, 0x05, 0x06 }, ret); + else Assert.IsNull(ret); + } + } + } +} diff --git a/tests/neo-plugins.Tests/neo-plugins.Tests.csproj b/tests/neo-plugins.Tests/neo-plugins.Tests.csproj new file mode 100644 index 000000000..45fc1d07e --- /dev/null +++ b/tests/neo-plugins.Tests/neo-plugins.Tests.csproj @@ -0,0 +1,20 @@ + + + + netcoreapp3.0 + neo_plugins.Tests + false + + + + + + + + + + + + + + From 971c25174f584e50589cf551355797d0b275cad5 Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Sat, 7 Dec 2019 23:59:35 +0800 Subject: [PATCH 088/183] Move projects to src (#159) --- neo-plugins.sln | 38 ++++++++++++------- .../ApplicationLogs}/ApplicationLogs.csproj | 2 +- .../ApplicationLogs/config.json | 0 .../ApplicationLogs}/LogReader.cs | 0 .../ApplicationLogs}/Settings.cs | 0 .../CoreMetrics}/CoreMetrics.cs | 0 .../CoreMetrics}/CoreMetrics.csproj | 0 .../ImportBlocks}/BlockImporter.cs | 0 .../ImportBlocks}/ImportBlocks.cs | 0 .../ImportBlocks}/ImportBlocks.csproj | 0 .../ImportBlocks}/ImportBlocks/config.json | 0 .../ImportBlocks}/Settings.cs | 0 .../LevelDBStore}/IO/Data/LevelDB/DB.cs | 0 .../LevelDBStore}/IO/Data/LevelDB/Helper.cs | 0 .../LevelDBStore}/IO/Data/LevelDB/Iterator.cs | 0 .../IO/Data/LevelDB/LevelDBException.cs | 0 .../LevelDBStore}/IO/Data/LevelDB/Native.cs | 0 .../LevelDBStore}/IO/Data/LevelDB/Options.cs | 0 .../IO/Data/LevelDB/ReadOptions.cs | 0 .../LevelDBStore}/IO/Data/LevelDB/Snapshot.cs | 0 .../IO/Data/LevelDB/WriteBatch.cs | 0 .../IO/Data/LevelDB/WriteOptions.cs | 0 .../LevelDBStore}/LevelDBStore.csproj | 0 .../LevelDBStore}/LevelDBStore/config.json | 0 .../LevelDBStore}/Plugins/Storage/Helper.cs | 0 .../Plugins/Storage/LevelDBStore.cs | 0 .../LevelDBStore}/Plugins/Storage/Snapshot.cs | 0 .../LevelDBStore}/Plugins/Storage/Store.cs | 0 .../RocksDBStore}/Plugins/Storage/Options.cs | 0 .../Plugins/Storage/RocksDBStore.cs | 0 .../RocksDBStore}/Plugins/Storage/Settings.cs | 0 .../RocksDBStore}/Plugins/Storage/Snapshot.cs | 0 .../RocksDBStore}/Plugins/Storage/Store.cs | 0 .../RocksDBStore}/RocksDBStore.csproj | 0 .../RocksDBStore}/RocksDBStore/config.json | 0 .../RpcNep5Tracker}/DbCache.cs | 0 .../RpcNep5Tracker}/Helper.cs | 0 .../RpcNep5Tracker}/Nep5Balance.cs | 0 .../RpcNep5Tracker}/Nep5BalanceKey.cs | 0 .../RpcNep5Tracker}/Nep5Transfer.cs | 0 .../RpcNep5Tracker}/Nep5TransferKey.cs | 0 .../RpcNep5Tracker}/RpcNep5Tracker.cs | 0 .../RpcNep5Tracker}/RpcNep5Tracker.csproj | 2 +- .../RpcNep5Tracker/config.json | 0 .../RpcSecurity}/RpcSecurity.cs | 0 .../RpcSecurity}/RpcSecurity.csproj | 0 .../RpcSecurity}/RpcSecurity/config.json | 0 {RpcSecurity => src/RpcSecurity}/Settings.cs | 0 {RpcWallet => src/RpcWallet}/RpcWallet.cs | 0 {RpcWallet => src/RpcWallet}/RpcWallet.csproj | 0 .../RpcWallet}/RpcWallet/config.json | 0 {RpcWallet => src/RpcWallet}/Settings.cs | 0 .../StatesDumper}/PersistActions.cs | 0 .../StatesDumper}/Settings.cs | 0 .../StatesDumper}/StatesDumper.cs | 0 .../StatesDumper}/StatesDumper.csproj | 0 .../StatesDumper}/StatesDumper/config.json | 0 .../SystemLog}/ConsoleColorSet.cs | 0 {SystemLog => src/SystemLog}/Logger.cs | 0 {SystemLog => src/SystemLog}/Settings.cs | 0 {SystemLog => src/SystemLog}/SystemLog.csproj | 0 .../SystemLog}/SystemLog/config.json | 0 .../neo-plugins.Tests.csproj | 4 +- 63 files changed, 29 insertions(+), 17 deletions(-) rename {ApplicationLogs => src/ApplicationLogs}/ApplicationLogs.csproj (93%) rename {ApplicationLogs => src/ApplicationLogs}/ApplicationLogs/config.json (100%) rename {ApplicationLogs => src/ApplicationLogs}/LogReader.cs (100%) rename {ApplicationLogs => src/ApplicationLogs}/Settings.cs (100%) rename {CoreMetrics => src/CoreMetrics}/CoreMetrics.cs (100%) rename {CoreMetrics => src/CoreMetrics}/CoreMetrics.csproj (100%) rename {ImportBlocks => src/ImportBlocks}/BlockImporter.cs (100%) rename {ImportBlocks => src/ImportBlocks}/ImportBlocks.cs (100%) rename {ImportBlocks => src/ImportBlocks}/ImportBlocks.csproj (100%) rename {ImportBlocks => src/ImportBlocks}/ImportBlocks/config.json (100%) rename {ImportBlocks => src/ImportBlocks}/Settings.cs (100%) rename {LevelDBStore => src/LevelDBStore}/IO/Data/LevelDB/DB.cs (100%) rename {LevelDBStore => src/LevelDBStore}/IO/Data/LevelDB/Helper.cs (100%) rename {LevelDBStore => src/LevelDBStore}/IO/Data/LevelDB/Iterator.cs (100%) rename {LevelDBStore => src/LevelDBStore}/IO/Data/LevelDB/LevelDBException.cs (100%) rename {LevelDBStore => src/LevelDBStore}/IO/Data/LevelDB/Native.cs (100%) rename {LevelDBStore => src/LevelDBStore}/IO/Data/LevelDB/Options.cs (100%) rename {LevelDBStore => src/LevelDBStore}/IO/Data/LevelDB/ReadOptions.cs (100%) rename {LevelDBStore => src/LevelDBStore}/IO/Data/LevelDB/Snapshot.cs (100%) rename {LevelDBStore => src/LevelDBStore}/IO/Data/LevelDB/WriteBatch.cs (100%) rename {LevelDBStore => src/LevelDBStore}/IO/Data/LevelDB/WriteOptions.cs (100%) rename {LevelDBStore => src/LevelDBStore}/LevelDBStore.csproj (100%) rename {LevelDBStore => src/LevelDBStore}/LevelDBStore/config.json (100%) rename {LevelDBStore => src/LevelDBStore}/Plugins/Storage/Helper.cs (100%) rename {LevelDBStore => src/LevelDBStore}/Plugins/Storage/LevelDBStore.cs (100%) rename {LevelDBStore => src/LevelDBStore}/Plugins/Storage/Snapshot.cs (100%) rename {LevelDBStore => src/LevelDBStore}/Plugins/Storage/Store.cs (100%) rename {RocksDBStore => src/RocksDBStore}/Plugins/Storage/Options.cs (100%) rename {RocksDBStore => src/RocksDBStore}/Plugins/Storage/RocksDBStore.cs (100%) rename {RocksDBStore => src/RocksDBStore}/Plugins/Storage/Settings.cs (100%) rename {RocksDBStore => src/RocksDBStore}/Plugins/Storage/Snapshot.cs (100%) rename {RocksDBStore => src/RocksDBStore}/Plugins/Storage/Store.cs (100%) rename {RocksDBStore => src/RocksDBStore}/RocksDBStore.csproj (100%) rename {RocksDBStore => src/RocksDBStore}/RocksDBStore/config.json (100%) rename {RpcNep5Tracker => src/RpcNep5Tracker}/DbCache.cs (100%) rename {RpcNep5Tracker => src/RpcNep5Tracker}/Helper.cs (100%) rename {RpcNep5Tracker => src/RpcNep5Tracker}/Nep5Balance.cs (100%) rename {RpcNep5Tracker => src/RpcNep5Tracker}/Nep5BalanceKey.cs (100%) rename {RpcNep5Tracker => src/RpcNep5Tracker}/Nep5Transfer.cs (100%) rename {RpcNep5Tracker => src/RpcNep5Tracker}/Nep5TransferKey.cs (100%) rename {RpcNep5Tracker => src/RpcNep5Tracker}/RpcNep5Tracker.cs (100%) rename {RpcNep5Tracker => src/RpcNep5Tracker}/RpcNep5Tracker.csproj (93%) rename {RpcNep5Tracker => src/RpcNep5Tracker}/RpcNep5Tracker/config.json (100%) rename {RpcSecurity => src/RpcSecurity}/RpcSecurity.cs (100%) rename {RpcSecurity => src/RpcSecurity}/RpcSecurity.csproj (100%) rename {RpcSecurity => src/RpcSecurity}/RpcSecurity/config.json (100%) rename {RpcSecurity => src/RpcSecurity}/Settings.cs (100%) rename {RpcWallet => src/RpcWallet}/RpcWallet.cs (100%) rename {RpcWallet => src/RpcWallet}/RpcWallet.csproj (100%) rename {RpcWallet => src/RpcWallet}/RpcWallet/config.json (100%) rename {RpcWallet => src/RpcWallet}/Settings.cs (100%) rename {StatesDumper => src/StatesDumper}/PersistActions.cs (100%) rename {StatesDumper => src/StatesDumper}/Settings.cs (100%) rename {StatesDumper => src/StatesDumper}/StatesDumper.cs (100%) rename {StatesDumper => src/StatesDumper}/StatesDumper.csproj (100%) rename {StatesDumper => src/StatesDumper}/StatesDumper/config.json (100%) rename {SystemLog => src/SystemLog}/ConsoleColorSet.cs (100%) rename {SystemLog => src/SystemLog}/Logger.cs (100%) rename {SystemLog => src/SystemLog}/Settings.cs (100%) rename {SystemLog => src/SystemLog}/SystemLog.csproj (100%) rename {SystemLog => src/SystemLog}/SystemLog/config.json (100%) diff --git a/neo-plugins.sln b/neo-plugins.sln index 3700cfc55..107bd4127 100644 --- a/neo-plugins.sln +++ b/neo-plugins.sln @@ -1,31 +1,33 @@ - + Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.28729.10 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ApplicationLogs", "ApplicationLogs\ApplicationLogs.csproj", "{84DA8EA6-EF60-4FCD-B1C6-65C1A8323B3F}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{97E81C78-1637-481F-9485-DA1225E94C23}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RpcSecurity", "RpcSecurity\RpcSecurity.csproj", "{6800D782-8EC0-49E9-98C4-195C8F781A1F}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{59D802AB-C552-422A-B9C3-64D329FBCDCC}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StatesDumper", "StatesDumper\StatesDumper.csproj", "{86531DB1-A231-46C4-823F-BE60972F7523}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ApplicationLogs", "src\ApplicationLogs\ApplicationLogs.csproj", "{84DA8EA6-EF60-4FCD-B1C6-65C1A8323B3F}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImportBlocks", "ImportBlocks\ImportBlocks.csproj", "{B7A42984-57BB-4F8D-967B-23B0E841B726}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RpcSecurity", "src\RpcSecurity\RpcSecurity.csproj", "{6800D782-8EC0-49E9-98C4-195C8F781A1F}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RpcWallet", "RpcWallet\RpcWallet.csproj", "{EF32A7E5-EDF9-438C-8041-8DA6E675A7FD}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StatesDumper", "src\StatesDumper\StatesDumper.csproj", "{86531DB1-A231-46C4-823F-BE60972F7523}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RpcNep5Tracker", "RpcNep5Tracker\RpcNep5Tracker.csproj", "{BBE8AC15-12DF-4AF0-ABC1-F1557EB5DC8E}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImportBlocks", "src\ImportBlocks\ImportBlocks.csproj", "{B7A42984-57BB-4F8D-967B-23B0E841B726}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CoreMetrics", "CoreMetrics\CoreMetrics.csproj", "{AEFFF003-3500-416B-AD9B-8C838C33C1F4}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RpcWallet", "src\RpcWallet\RpcWallet.csproj", "{EF32A7E5-EDF9-438C-8041-8DA6E675A7FD}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SystemLog", "SystemLog\SystemLog.csproj", "{14DB62D5-0EA1-4A98-8656-1AA2D0345206}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RpcNep5Tracker", "src\RpcNep5Tracker\RpcNep5Tracker.csproj", "{BBE8AC15-12DF-4AF0-ABC1-F1557EB5DC8E}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LevelDBStore", "LevelDBStore\LevelDBStore.csproj", "{C66214CD-0B97-4EA5-B7A2-164F54346F19}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CoreMetrics", "src\CoreMetrics\CoreMetrics.csproj", "{AEFFF003-3500-416B-AD9B-8C838C33C1F4}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RocksDBStore", "RocksDBStore\RocksDBStore.csproj", "{0E2AAF05-C55A-4B36-8750-F55743FBE4B3}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SystemLog", "src\SystemLog\SystemLog.csproj", "{14DB62D5-0EA1-4A98-8656-1AA2D0345206}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{59D802AB-C552-422A-B9C3-64D329FBCDCC}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LevelDBStore", "src\LevelDBStore\LevelDBStore.csproj", "{C66214CD-0B97-4EA5-B7A2-164F54346F19}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RocksDBStore", "src\RocksDBStore\RocksDBStore.csproj", "{0E2AAF05-C55A-4B36-8750-F55743FBE4B3}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "neo-plugins.Tests", "tests\neo-plugins.Tests\neo-plugins.Tests.csproj", "{9E7EA895-302A-4C0C-BA9B-54F9A67AD75C}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "neo-plugins.Tests", "tests\neo-plugins.Tests\neo-plugins.Tests.csproj", "{9E7EA895-302A-4C0C-BA9B-54F9A67AD75C}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -82,6 +84,16 @@ Global HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution + {84DA8EA6-EF60-4FCD-B1C6-65C1A8323B3F} = {97E81C78-1637-481F-9485-DA1225E94C23} + {6800D782-8EC0-49E9-98C4-195C8F781A1F} = {97E81C78-1637-481F-9485-DA1225E94C23} + {86531DB1-A231-46C4-823F-BE60972F7523} = {97E81C78-1637-481F-9485-DA1225E94C23} + {B7A42984-57BB-4F8D-967B-23B0E841B726} = {97E81C78-1637-481F-9485-DA1225E94C23} + {EF32A7E5-EDF9-438C-8041-8DA6E675A7FD} = {97E81C78-1637-481F-9485-DA1225E94C23} + {BBE8AC15-12DF-4AF0-ABC1-F1557EB5DC8E} = {97E81C78-1637-481F-9485-DA1225E94C23} + {AEFFF003-3500-416B-AD9B-8C838C33C1F4} = {97E81C78-1637-481F-9485-DA1225E94C23} + {14DB62D5-0EA1-4A98-8656-1AA2D0345206} = {97E81C78-1637-481F-9485-DA1225E94C23} + {C66214CD-0B97-4EA5-B7A2-164F54346F19} = {97E81C78-1637-481F-9485-DA1225E94C23} + {0E2AAF05-C55A-4B36-8750-F55743FBE4B3} = {97E81C78-1637-481F-9485-DA1225E94C23} {9E7EA895-302A-4C0C-BA9B-54F9A67AD75C} = {59D802AB-C552-422A-B9C3-64D329FBCDCC} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution diff --git a/ApplicationLogs/ApplicationLogs.csproj b/src/ApplicationLogs/ApplicationLogs.csproj similarity index 93% rename from ApplicationLogs/ApplicationLogs.csproj rename to src/ApplicationLogs/ApplicationLogs.csproj index 4aeeb578a..d8976e093 100644 --- a/ApplicationLogs/ApplicationLogs.csproj +++ b/src/ApplicationLogs/ApplicationLogs.csproj @@ -1,4 +1,4 @@ - + 3.0.0-preview1 diff --git a/ApplicationLogs/ApplicationLogs/config.json b/src/ApplicationLogs/ApplicationLogs/config.json similarity index 100% rename from ApplicationLogs/ApplicationLogs/config.json rename to src/ApplicationLogs/ApplicationLogs/config.json diff --git a/ApplicationLogs/LogReader.cs b/src/ApplicationLogs/LogReader.cs similarity index 100% rename from ApplicationLogs/LogReader.cs rename to src/ApplicationLogs/LogReader.cs diff --git a/ApplicationLogs/Settings.cs b/src/ApplicationLogs/Settings.cs similarity index 100% rename from ApplicationLogs/Settings.cs rename to src/ApplicationLogs/Settings.cs diff --git a/CoreMetrics/CoreMetrics.cs b/src/CoreMetrics/CoreMetrics.cs similarity index 100% rename from CoreMetrics/CoreMetrics.cs rename to src/CoreMetrics/CoreMetrics.cs diff --git a/CoreMetrics/CoreMetrics.csproj b/src/CoreMetrics/CoreMetrics.csproj similarity index 100% rename from CoreMetrics/CoreMetrics.csproj rename to src/CoreMetrics/CoreMetrics.csproj diff --git a/ImportBlocks/BlockImporter.cs b/src/ImportBlocks/BlockImporter.cs similarity index 100% rename from ImportBlocks/BlockImporter.cs rename to src/ImportBlocks/BlockImporter.cs diff --git a/ImportBlocks/ImportBlocks.cs b/src/ImportBlocks/ImportBlocks.cs similarity index 100% rename from ImportBlocks/ImportBlocks.cs rename to src/ImportBlocks/ImportBlocks.cs diff --git a/ImportBlocks/ImportBlocks.csproj b/src/ImportBlocks/ImportBlocks.csproj similarity index 100% rename from ImportBlocks/ImportBlocks.csproj rename to src/ImportBlocks/ImportBlocks.csproj diff --git a/ImportBlocks/ImportBlocks/config.json b/src/ImportBlocks/ImportBlocks/config.json similarity index 100% rename from ImportBlocks/ImportBlocks/config.json rename to src/ImportBlocks/ImportBlocks/config.json diff --git a/ImportBlocks/Settings.cs b/src/ImportBlocks/Settings.cs similarity index 100% rename from ImportBlocks/Settings.cs rename to src/ImportBlocks/Settings.cs diff --git a/LevelDBStore/IO/Data/LevelDB/DB.cs b/src/LevelDBStore/IO/Data/LevelDB/DB.cs similarity index 100% rename from LevelDBStore/IO/Data/LevelDB/DB.cs rename to src/LevelDBStore/IO/Data/LevelDB/DB.cs diff --git a/LevelDBStore/IO/Data/LevelDB/Helper.cs b/src/LevelDBStore/IO/Data/LevelDB/Helper.cs similarity index 100% rename from LevelDBStore/IO/Data/LevelDB/Helper.cs rename to src/LevelDBStore/IO/Data/LevelDB/Helper.cs diff --git a/LevelDBStore/IO/Data/LevelDB/Iterator.cs b/src/LevelDBStore/IO/Data/LevelDB/Iterator.cs similarity index 100% rename from LevelDBStore/IO/Data/LevelDB/Iterator.cs rename to src/LevelDBStore/IO/Data/LevelDB/Iterator.cs diff --git a/LevelDBStore/IO/Data/LevelDB/LevelDBException.cs b/src/LevelDBStore/IO/Data/LevelDB/LevelDBException.cs similarity index 100% rename from LevelDBStore/IO/Data/LevelDB/LevelDBException.cs rename to src/LevelDBStore/IO/Data/LevelDB/LevelDBException.cs diff --git a/LevelDBStore/IO/Data/LevelDB/Native.cs b/src/LevelDBStore/IO/Data/LevelDB/Native.cs similarity index 100% rename from LevelDBStore/IO/Data/LevelDB/Native.cs rename to src/LevelDBStore/IO/Data/LevelDB/Native.cs diff --git a/LevelDBStore/IO/Data/LevelDB/Options.cs b/src/LevelDBStore/IO/Data/LevelDB/Options.cs similarity index 100% rename from LevelDBStore/IO/Data/LevelDB/Options.cs rename to src/LevelDBStore/IO/Data/LevelDB/Options.cs diff --git a/LevelDBStore/IO/Data/LevelDB/ReadOptions.cs b/src/LevelDBStore/IO/Data/LevelDB/ReadOptions.cs similarity index 100% rename from LevelDBStore/IO/Data/LevelDB/ReadOptions.cs rename to src/LevelDBStore/IO/Data/LevelDB/ReadOptions.cs diff --git a/LevelDBStore/IO/Data/LevelDB/Snapshot.cs b/src/LevelDBStore/IO/Data/LevelDB/Snapshot.cs similarity index 100% rename from LevelDBStore/IO/Data/LevelDB/Snapshot.cs rename to src/LevelDBStore/IO/Data/LevelDB/Snapshot.cs diff --git a/LevelDBStore/IO/Data/LevelDB/WriteBatch.cs b/src/LevelDBStore/IO/Data/LevelDB/WriteBatch.cs similarity index 100% rename from LevelDBStore/IO/Data/LevelDB/WriteBatch.cs rename to src/LevelDBStore/IO/Data/LevelDB/WriteBatch.cs diff --git a/LevelDBStore/IO/Data/LevelDB/WriteOptions.cs b/src/LevelDBStore/IO/Data/LevelDB/WriteOptions.cs similarity index 100% rename from LevelDBStore/IO/Data/LevelDB/WriteOptions.cs rename to src/LevelDBStore/IO/Data/LevelDB/WriteOptions.cs diff --git a/LevelDBStore/LevelDBStore.csproj b/src/LevelDBStore/LevelDBStore.csproj similarity index 100% rename from LevelDBStore/LevelDBStore.csproj rename to src/LevelDBStore/LevelDBStore.csproj diff --git a/LevelDBStore/LevelDBStore/config.json b/src/LevelDBStore/LevelDBStore/config.json similarity index 100% rename from LevelDBStore/LevelDBStore/config.json rename to src/LevelDBStore/LevelDBStore/config.json diff --git a/LevelDBStore/Plugins/Storage/Helper.cs b/src/LevelDBStore/Plugins/Storage/Helper.cs similarity index 100% rename from LevelDBStore/Plugins/Storage/Helper.cs rename to src/LevelDBStore/Plugins/Storage/Helper.cs diff --git a/LevelDBStore/Plugins/Storage/LevelDBStore.cs b/src/LevelDBStore/Plugins/Storage/LevelDBStore.cs similarity index 100% rename from LevelDBStore/Plugins/Storage/LevelDBStore.cs rename to src/LevelDBStore/Plugins/Storage/LevelDBStore.cs diff --git a/LevelDBStore/Plugins/Storage/Snapshot.cs b/src/LevelDBStore/Plugins/Storage/Snapshot.cs similarity index 100% rename from LevelDBStore/Plugins/Storage/Snapshot.cs rename to src/LevelDBStore/Plugins/Storage/Snapshot.cs diff --git a/LevelDBStore/Plugins/Storage/Store.cs b/src/LevelDBStore/Plugins/Storage/Store.cs similarity index 100% rename from LevelDBStore/Plugins/Storage/Store.cs rename to src/LevelDBStore/Plugins/Storage/Store.cs diff --git a/RocksDBStore/Plugins/Storage/Options.cs b/src/RocksDBStore/Plugins/Storage/Options.cs similarity index 100% rename from RocksDBStore/Plugins/Storage/Options.cs rename to src/RocksDBStore/Plugins/Storage/Options.cs diff --git a/RocksDBStore/Plugins/Storage/RocksDBStore.cs b/src/RocksDBStore/Plugins/Storage/RocksDBStore.cs similarity index 100% rename from RocksDBStore/Plugins/Storage/RocksDBStore.cs rename to src/RocksDBStore/Plugins/Storage/RocksDBStore.cs diff --git a/RocksDBStore/Plugins/Storage/Settings.cs b/src/RocksDBStore/Plugins/Storage/Settings.cs similarity index 100% rename from RocksDBStore/Plugins/Storage/Settings.cs rename to src/RocksDBStore/Plugins/Storage/Settings.cs diff --git a/RocksDBStore/Plugins/Storage/Snapshot.cs b/src/RocksDBStore/Plugins/Storage/Snapshot.cs similarity index 100% rename from RocksDBStore/Plugins/Storage/Snapshot.cs rename to src/RocksDBStore/Plugins/Storage/Snapshot.cs diff --git a/RocksDBStore/Plugins/Storage/Store.cs b/src/RocksDBStore/Plugins/Storage/Store.cs similarity index 100% rename from RocksDBStore/Plugins/Storage/Store.cs rename to src/RocksDBStore/Plugins/Storage/Store.cs diff --git a/RocksDBStore/RocksDBStore.csproj b/src/RocksDBStore/RocksDBStore.csproj similarity index 100% rename from RocksDBStore/RocksDBStore.csproj rename to src/RocksDBStore/RocksDBStore.csproj diff --git a/RocksDBStore/RocksDBStore/config.json b/src/RocksDBStore/RocksDBStore/config.json similarity index 100% rename from RocksDBStore/RocksDBStore/config.json rename to src/RocksDBStore/RocksDBStore/config.json diff --git a/RpcNep5Tracker/DbCache.cs b/src/RpcNep5Tracker/DbCache.cs similarity index 100% rename from RpcNep5Tracker/DbCache.cs rename to src/RpcNep5Tracker/DbCache.cs diff --git a/RpcNep5Tracker/Helper.cs b/src/RpcNep5Tracker/Helper.cs similarity index 100% rename from RpcNep5Tracker/Helper.cs rename to src/RpcNep5Tracker/Helper.cs diff --git a/RpcNep5Tracker/Nep5Balance.cs b/src/RpcNep5Tracker/Nep5Balance.cs similarity index 100% rename from RpcNep5Tracker/Nep5Balance.cs rename to src/RpcNep5Tracker/Nep5Balance.cs diff --git a/RpcNep5Tracker/Nep5BalanceKey.cs b/src/RpcNep5Tracker/Nep5BalanceKey.cs similarity index 100% rename from RpcNep5Tracker/Nep5BalanceKey.cs rename to src/RpcNep5Tracker/Nep5BalanceKey.cs diff --git a/RpcNep5Tracker/Nep5Transfer.cs b/src/RpcNep5Tracker/Nep5Transfer.cs similarity index 100% rename from RpcNep5Tracker/Nep5Transfer.cs rename to src/RpcNep5Tracker/Nep5Transfer.cs diff --git a/RpcNep5Tracker/Nep5TransferKey.cs b/src/RpcNep5Tracker/Nep5TransferKey.cs similarity index 100% rename from RpcNep5Tracker/Nep5TransferKey.cs rename to src/RpcNep5Tracker/Nep5TransferKey.cs diff --git a/RpcNep5Tracker/RpcNep5Tracker.cs b/src/RpcNep5Tracker/RpcNep5Tracker.cs similarity index 100% rename from RpcNep5Tracker/RpcNep5Tracker.cs rename to src/RpcNep5Tracker/RpcNep5Tracker.cs diff --git a/RpcNep5Tracker/RpcNep5Tracker.csproj b/src/RpcNep5Tracker/RpcNep5Tracker.csproj similarity index 93% rename from RpcNep5Tracker/RpcNep5Tracker.csproj rename to src/RpcNep5Tracker/RpcNep5Tracker.csproj index 6cac14be3..bc700a468 100644 --- a/RpcNep5Tracker/RpcNep5Tracker.csproj +++ b/src/RpcNep5Tracker/RpcNep5Tracker.csproj @@ -1,4 +1,4 @@ - + 3.0.0-preview1 netstandard2.1 diff --git a/RpcNep5Tracker/RpcNep5Tracker/config.json b/src/RpcNep5Tracker/RpcNep5Tracker/config.json similarity index 100% rename from RpcNep5Tracker/RpcNep5Tracker/config.json rename to src/RpcNep5Tracker/RpcNep5Tracker/config.json diff --git a/RpcSecurity/RpcSecurity.cs b/src/RpcSecurity/RpcSecurity.cs similarity index 100% rename from RpcSecurity/RpcSecurity.cs rename to src/RpcSecurity/RpcSecurity.cs diff --git a/RpcSecurity/RpcSecurity.csproj b/src/RpcSecurity/RpcSecurity.csproj similarity index 100% rename from RpcSecurity/RpcSecurity.csproj rename to src/RpcSecurity/RpcSecurity.csproj diff --git a/RpcSecurity/RpcSecurity/config.json b/src/RpcSecurity/RpcSecurity/config.json similarity index 100% rename from RpcSecurity/RpcSecurity/config.json rename to src/RpcSecurity/RpcSecurity/config.json diff --git a/RpcSecurity/Settings.cs b/src/RpcSecurity/Settings.cs similarity index 100% rename from RpcSecurity/Settings.cs rename to src/RpcSecurity/Settings.cs diff --git a/RpcWallet/RpcWallet.cs b/src/RpcWallet/RpcWallet.cs similarity index 100% rename from RpcWallet/RpcWallet.cs rename to src/RpcWallet/RpcWallet.cs diff --git a/RpcWallet/RpcWallet.csproj b/src/RpcWallet/RpcWallet.csproj similarity index 100% rename from RpcWallet/RpcWallet.csproj rename to src/RpcWallet/RpcWallet.csproj diff --git a/RpcWallet/RpcWallet/config.json b/src/RpcWallet/RpcWallet/config.json similarity index 100% rename from RpcWallet/RpcWallet/config.json rename to src/RpcWallet/RpcWallet/config.json diff --git a/RpcWallet/Settings.cs b/src/RpcWallet/Settings.cs similarity index 100% rename from RpcWallet/Settings.cs rename to src/RpcWallet/Settings.cs diff --git a/StatesDumper/PersistActions.cs b/src/StatesDumper/PersistActions.cs similarity index 100% rename from StatesDumper/PersistActions.cs rename to src/StatesDumper/PersistActions.cs diff --git a/StatesDumper/Settings.cs b/src/StatesDumper/Settings.cs similarity index 100% rename from StatesDumper/Settings.cs rename to src/StatesDumper/Settings.cs diff --git a/StatesDumper/StatesDumper.cs b/src/StatesDumper/StatesDumper.cs similarity index 100% rename from StatesDumper/StatesDumper.cs rename to src/StatesDumper/StatesDumper.cs diff --git a/StatesDumper/StatesDumper.csproj b/src/StatesDumper/StatesDumper.csproj similarity index 100% rename from StatesDumper/StatesDumper.csproj rename to src/StatesDumper/StatesDumper.csproj diff --git a/StatesDumper/StatesDumper/config.json b/src/StatesDumper/StatesDumper/config.json similarity index 100% rename from StatesDumper/StatesDumper/config.json rename to src/StatesDumper/StatesDumper/config.json diff --git a/SystemLog/ConsoleColorSet.cs b/src/SystemLog/ConsoleColorSet.cs similarity index 100% rename from SystemLog/ConsoleColorSet.cs rename to src/SystemLog/ConsoleColorSet.cs diff --git a/SystemLog/Logger.cs b/src/SystemLog/Logger.cs similarity index 100% rename from SystemLog/Logger.cs rename to src/SystemLog/Logger.cs diff --git a/SystemLog/Settings.cs b/src/SystemLog/Settings.cs similarity index 100% rename from SystemLog/Settings.cs rename to src/SystemLog/Settings.cs diff --git a/SystemLog/SystemLog.csproj b/src/SystemLog/SystemLog.csproj similarity index 100% rename from SystemLog/SystemLog.csproj rename to src/SystemLog/SystemLog.csproj diff --git a/SystemLog/SystemLog/config.json b/src/SystemLog/SystemLog/config.json similarity index 100% rename from SystemLog/SystemLog/config.json rename to src/SystemLog/SystemLog/config.json diff --git a/tests/neo-plugins.Tests/neo-plugins.Tests.csproj b/tests/neo-plugins.Tests/neo-plugins.Tests.csproj index 45fc1d07e..92f285abd 100644 --- a/tests/neo-plugins.Tests/neo-plugins.Tests.csproj +++ b/tests/neo-plugins.Tests/neo-plugins.Tests.csproj @@ -13,8 +13,8 @@ - - + + From 9fce80e8e7e2f81ba3c763c67c8ac2ab1975372c Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Sun, 8 Dec 2019 21:46:02 +0800 Subject: [PATCH 089/183] Remove ImportBlocks (#161) --- neo-plugins.sln | 8 -- src/ImportBlocks/BlockImporter.cs | 134 ---------------------- src/ImportBlocks/ImportBlocks.cs | 130 --------------------- src/ImportBlocks/ImportBlocks.csproj | 20 ---- src/ImportBlocks/ImportBlocks/config.json | 5 - src/ImportBlocks/Settings.cs | 28 ----- 6 files changed, 325 deletions(-) delete mode 100644 src/ImportBlocks/BlockImporter.cs delete mode 100644 src/ImportBlocks/ImportBlocks.cs delete mode 100644 src/ImportBlocks/ImportBlocks.csproj delete mode 100644 src/ImportBlocks/ImportBlocks/config.json delete mode 100644 src/ImportBlocks/Settings.cs diff --git a/neo-plugins.sln b/neo-plugins.sln index 107bd4127..ae23c748c 100644 --- a/neo-plugins.sln +++ b/neo-plugins.sln @@ -1,4 +1,3 @@ - Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.28729.10 @@ -13,8 +12,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RpcSecurity", "src\RpcSecur EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StatesDumper", "src\StatesDumper\StatesDumper.csproj", "{86531DB1-A231-46C4-823F-BE60972F7523}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImportBlocks", "src\ImportBlocks\ImportBlocks.csproj", "{B7A42984-57BB-4F8D-967B-23B0E841B726}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RpcWallet", "src\RpcWallet\RpcWallet.csproj", "{EF32A7E5-EDF9-438C-8041-8DA6E675A7FD}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RpcNep5Tracker", "src\RpcNep5Tracker\RpcNep5Tracker.csproj", "{BBE8AC15-12DF-4AF0-ABC1-F1557EB5DC8E}" @@ -47,10 +44,6 @@ Global {86531DB1-A231-46C4-823F-BE60972F7523}.Debug|Any CPU.Build.0 = Debug|Any CPU {86531DB1-A231-46C4-823F-BE60972F7523}.Release|Any CPU.ActiveCfg = Release|Any CPU {86531DB1-A231-46C4-823F-BE60972F7523}.Release|Any CPU.Build.0 = Release|Any CPU - {B7A42984-57BB-4F8D-967B-23B0E841B726}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B7A42984-57BB-4F8D-967B-23B0E841B726}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B7A42984-57BB-4F8D-967B-23B0E841B726}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B7A42984-57BB-4F8D-967B-23B0E841B726}.Release|Any CPU.Build.0 = Release|Any CPU {EF32A7E5-EDF9-438C-8041-8DA6E675A7FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {EF32A7E5-EDF9-438C-8041-8DA6E675A7FD}.Debug|Any CPU.Build.0 = Debug|Any CPU {EF32A7E5-EDF9-438C-8041-8DA6E675A7FD}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -87,7 +80,6 @@ Global {84DA8EA6-EF60-4FCD-B1C6-65C1A8323B3F} = {97E81C78-1637-481F-9485-DA1225E94C23} {6800D782-8EC0-49E9-98C4-195C8F781A1F} = {97E81C78-1637-481F-9485-DA1225E94C23} {86531DB1-A231-46C4-823F-BE60972F7523} = {97E81C78-1637-481F-9485-DA1225E94C23} - {B7A42984-57BB-4F8D-967B-23B0E841B726} = {97E81C78-1637-481F-9485-DA1225E94C23} {EF32A7E5-EDF9-438C-8041-8DA6E675A7FD} = {97E81C78-1637-481F-9485-DA1225E94C23} {BBE8AC15-12DF-4AF0-ABC1-F1557EB5DC8E} = {97E81C78-1637-481F-9485-DA1225E94C23} {AEFFF003-3500-416B-AD9B-8C838C33C1F4} = {97E81C78-1637-481F-9485-DA1225E94C23} diff --git a/src/ImportBlocks/BlockImporter.cs b/src/ImportBlocks/BlockImporter.cs deleted file mode 100644 index 83d350f28..000000000 --- a/src/ImportBlocks/BlockImporter.cs +++ /dev/null @@ -1,134 +0,0 @@ -using Akka.Actor; -using Neo.IO; -using Neo.Ledger; -using Neo.Network.P2P; -using Neo.Network.P2P.Payloads; -using System; -using System.Collections.Generic; -using System.IO; -using System.IO.Compression; -using System.Linq; -using System.Text.RegularExpressions; - -namespace Neo.Plugins -{ - public class BlockImporter : UntypedActor - { - public class StartImport { public IActorRef BlockchainActorRef; public Action OnComplete; } - - private const int BlocksPerBatch = 10; - private IActorRef _blockchainActorRef; - private bool isImporting; - private IEnumerator blocksBeingImported; - private Action _doneAction; - - private static bool CheckMaxOnImportHeight(uint currentImportBlockHeight) - { - if (Settings.Default.MaxOnImportHeight == 0 || Settings.Default.MaxOnImportHeight >= currentImportBlockHeight) - return true; - return false; - } - - private static IEnumerable GetBlocks(Stream stream, bool read_start = false) - { - using (BinaryReader r = new BinaryReader(stream)) - { - uint start = read_start ? r.ReadUInt32() : 0; - uint count = r.ReadUInt32(); - uint end = start + count - 1; - if (end <= Blockchain.Singleton.Height) yield break; - for (uint height = start; height <= end; height++) - { - var size = r.ReadInt32(); - if (size > Message.PayloadMaxSize) - throw new ArgumentException($"Block {height} exceeds the maximum allowed size"); - - byte[] array = r.ReadBytes(size); - if (!CheckMaxOnImportHeight(height)) yield break; - if (height > Blockchain.Singleton.Height) - { - Block block = array.AsSerializable(); - yield return block; - } - } - } - } - - private IEnumerable GetBlocksFromFile() - { - const string pathAcc = "chain.acc"; - if (File.Exists(pathAcc)) - using (FileStream fs = new FileStream(pathAcc, FileMode.Open, FileAccess.Read, FileShare.Read)) - foreach (var block in GetBlocks(fs)) - yield return block; - - const string pathAccZip = pathAcc + ".zip"; - if (File.Exists(pathAccZip)) - using (FileStream fs = new FileStream(pathAccZip, FileMode.Open, FileAccess.Read, FileShare.Read)) - using (ZipArchive zip = new ZipArchive(fs, ZipArchiveMode.Read)) - using (Stream zs = zip.GetEntry(pathAcc).Open()) - foreach (var block in GetBlocks(zs)) - yield return block; - - var paths = Directory.EnumerateFiles(".", "chain.*.acc", SearchOption.TopDirectoryOnly).Concat(Directory.EnumerateFiles(".", "chain.*.acc.zip", SearchOption.TopDirectoryOnly)).Select(p => new - { - FileName = Path.GetFileName(p), - Start = uint.Parse(Regex.Match(p, @"\d+").Value), - IsCompressed = p.EndsWith(".zip") - }).OrderBy(p => p.Start); - - foreach (var path in paths) - { - if (path.Start > Blockchain.Singleton.Height + 1) break; - if (path.IsCompressed) - using (FileStream fs = new FileStream(path.FileName, FileMode.Open, FileAccess.Read, FileShare.Read)) - using (ZipArchive zip = new ZipArchive(fs, ZipArchiveMode.Read)) - using (Stream zs = zip.GetEntry(Path.GetFileNameWithoutExtension(path.FileName)).Open()) - foreach (var block in GetBlocks(zs, true)) - yield return block; - else - using (FileStream fs = new FileStream(path.FileName, FileMode.Open, FileAccess.Read, FileShare.Read)) - foreach (var block in GetBlocks(fs, true)) - yield return block; - } - } - - protected override void OnReceive(object message) - { - switch (message) - { - case StartImport startImport: - if (isImporting) return; - isImporting = true; - _blockchainActorRef = startImport.BlockchainActorRef; - _doneAction = startImport.OnComplete; - blocksBeingImported = GetBlocksFromFile().GetEnumerator(); - // Start the first import - Self.Tell(new Blockchain.ImportCompleted()); - break; - case Blockchain.ImportCompleted _: - // Import the next batch - List blocksToImport = new List(); - for (int i = 0; i < BlocksPerBatch; i++) - { - if (!blocksBeingImported.MoveNext()) - break; - blocksToImport.Add(blocksBeingImported.Current); - } - if (blocksToImport.Count > 0) - _blockchainActorRef.Tell(new Blockchain.Import { Blocks = blocksToImport }); - else - { - blocksBeingImported.Dispose(); - _doneAction(); - } - break; - } - } - - public static Props Props() - { - return Akka.Actor.Props.Create(() => new BlockImporter()); - } - } -} diff --git a/src/ImportBlocks/ImportBlocks.cs b/src/ImportBlocks/ImportBlocks.cs deleted file mode 100644 index e93413421..000000000 --- a/src/ImportBlocks/ImportBlocks.cs +++ /dev/null @@ -1,130 +0,0 @@ -using Akka.Actor; -using Neo.IO; -using Neo.Ledger; -using Neo.Network.P2P.Payloads; -using System; -using System.IO; - -namespace Neo.Plugins -{ - public class ImportBlocks : Plugin - { - private IActorRef _blockImporter; - - protected override void Configure() - { - Settings.Load(GetConfiguration()); - } - - private bool OnExport(string[] args) - { - bool writeStart; - uint start, count; - string path; - if (args.Length < 2) return false; - if (!string.Equals(args[1], "block", StringComparison.OrdinalIgnoreCase) - && !string.Equals(args[1], "blocks", StringComparison.OrdinalIgnoreCase)) - return false; - if (args.Length >= 3 && uint.TryParse(args[2], out start)) - { - if (Blockchain.Singleton.Height < start) return true; - count = args.Length >= 4 ? uint.Parse(args[3]) : uint.MaxValue; - count = Math.Min(count, Blockchain.Singleton.Height - start + 1); - path = $"chain.{start}.acc"; - writeStart = true; - } - else - { - start = 0; - count = Blockchain.Singleton.Height - start + 1; - path = args.Length >= 3 ? args[2] : "chain.acc"; - writeStart = false; - } - - WriteBlocks(start, count, path, writeStart); - - Console.WriteLine(); - return true; - } - - private void WriteBlocks(uint start, uint count, string path, bool writeStart) - { - uint end = start + count - 1; - using (FileStream fs = new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None, 4096, FileOptions.WriteThrough)) - { - if (fs.Length > 0) - { - byte[] buffer = new byte[sizeof(uint)]; - if (writeStart) - { - fs.Seek(sizeof(uint), SeekOrigin.Begin); - fs.Read(buffer, 0, buffer.Length); - start += BitConverter.ToUInt32(buffer, 0); - fs.Seek(sizeof(uint), SeekOrigin.Begin); - } - else - { - fs.Read(buffer, 0, buffer.Length); - start = BitConverter.ToUInt32(buffer, 0); - fs.Seek(0, SeekOrigin.Begin); - } - } - else - { - if (writeStart) - { - fs.Write(BitConverter.GetBytes(start), 0, sizeof(uint)); - } - } - if (start <= end) - fs.Write(BitConverter.GetBytes(count), 0, sizeof(uint)); - fs.Seek(0, SeekOrigin.End); - for (uint i = start; i <= end; i++) - { - Block block = Blockchain.Singleton.GetBlock(i); - byte[] array = block.ToArray(); - fs.Write(BitConverter.GetBytes(array.Length), 0, sizeof(int)); - fs.Write(array, 0, array.Length); - Console.SetCursorPosition(0, Console.CursorTop); - Console.Write($"[{i}/{end}]"); - } - } - } - - private bool OnHelp(string[] args) - { - if (args.Length < 2) return false; - if (!string.Equals(args[1], Name, StringComparison.OrdinalIgnoreCase)) - return false; - Console.Write($"{Name} Commands:\n" + "\texport block[s] \n"); - return true; - } - - private void OnImportComplete() - { - ResumeNodeStartup(); - System.ActorSystem.Stop(_blockImporter); - } - - protected override void OnPluginsLoaded() - { - SuspendNodeStartup(); - _blockImporter = System.ActorSystem.ActorOf(BlockImporter.Props()); - _blockImporter.Tell(new BlockImporter.StartImport { BlockchainActorRef = System.Blockchain, OnComplete = OnImportComplete }); - } - - protected override bool OnMessage(object message) - { - if (!(message is string[] args)) return false; - if (args.Length == 0) return false; - switch (args[0].ToLower()) - { - case "help": - return OnHelp(args); - case "export": - return OnExport(args); - } - return false; - } - } -} diff --git a/src/ImportBlocks/ImportBlocks.csproj b/src/ImportBlocks/ImportBlocks.csproj deleted file mode 100644 index c76c33e35..000000000 --- a/src/ImportBlocks/ImportBlocks.csproj +++ /dev/null @@ -1,20 +0,0 @@ - - - - 3.0.0-preview1 - netstandard2.1 - Neo.Plugins - - - - - PreserveNewest - PreserveNewest - - - - - - - - diff --git a/src/ImportBlocks/ImportBlocks/config.json b/src/ImportBlocks/ImportBlocks/config.json deleted file mode 100644 index ed125974c..000000000 --- a/src/ImportBlocks/ImportBlocks/config.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "PluginConfiguration": { - "MaxOnImportHeight": 0 - } -} diff --git a/src/ImportBlocks/Settings.cs b/src/ImportBlocks/Settings.cs deleted file mode 100644 index 279e80127..000000000 --- a/src/ImportBlocks/Settings.cs +++ /dev/null @@ -1,28 +0,0 @@ -using Microsoft.Extensions.Configuration; -using System; - -namespace Neo.Plugins -{ - internal class Settings - { - public uint MaxOnImportHeight { get; } - - public static Settings Default { get; private set; } - - private Settings(IConfigurationSection section) - { - this.MaxOnImportHeight = GetValueOrDefault(section.GetSection("MaxOnImportHeight"), 0u, p => uint.Parse(p)); - } - - public T GetValueOrDefault(IConfigurationSection section, T defaultValue, Func selector) - { - if (section.Value == null) return defaultValue; - return selector(section.Value); - } - - public static void Load(IConfigurationSection section) - { - Default = new Settings(section); - } - } -} From d3603c5e602035858bfed43dd94a965f73b2ee39 Mon Sep 17 00:00:00 2001 From: erikzhang Date: Sun, 8 Dec 2019 21:51:12 +0800 Subject: [PATCH 090/183] Update .sln --- neo-plugins.sln => neo-modules.sln | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename neo-plugins.sln => neo-modules.sln (100%) diff --git a/neo-plugins.sln b/neo-modules.sln similarity index 100% rename from neo-plugins.sln rename to neo-modules.sln From f326b21b751b30cfbbabdddc0c9b7887eb5dcd73 Mon Sep 17 00:00:00 2001 From: erikzhang Date: Mon, 9 Dec 2019 11:34:23 +0800 Subject: [PATCH 091/183] Rename tests --- neo-modules.sln | 2 +- .../Neo.Plugins.Storage.Tests.csproj} | 40 +++++++++---------- .../StoreTest.cs | 2 +- 3 files changed, 22 insertions(+), 22 deletions(-) rename tests/{neo-plugins.Tests/neo-plugins.Tests.csproj => Neo.Plugins.Storage.Tests/Neo.Plugins.Storage.Tests.csproj} (89%) rename tests/{neo-plugins.Tests => Neo.Plugins.Storage.Tests}/StoreTest.cs (98%) diff --git a/neo-modules.sln b/neo-modules.sln index ae23c748c..5ef1ba616 100644 --- a/neo-modules.sln +++ b/neo-modules.sln @@ -24,7 +24,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LevelDBStore", "src\LevelDB EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RocksDBStore", "src\RocksDBStore\RocksDBStore.csproj", "{0E2AAF05-C55A-4B36-8750-F55743FBE4B3}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "neo-plugins.Tests", "tests\neo-plugins.Tests\neo-plugins.Tests.csproj", "{9E7EA895-302A-4C0C-BA9B-54F9A67AD75C}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.Plugins.Storage.Tests", "tests\Neo.Plugins.Storage.Tests\Neo.Plugins.Storage.Tests.csproj", "{9E7EA895-302A-4C0C-BA9B-54F9A67AD75C}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/tests/neo-plugins.Tests/neo-plugins.Tests.csproj b/tests/Neo.Plugins.Storage.Tests/Neo.Plugins.Storage.Tests.csproj similarity index 89% rename from tests/neo-plugins.Tests/neo-plugins.Tests.csproj rename to tests/Neo.Plugins.Storage.Tests/Neo.Plugins.Storage.Tests.csproj index 92f285abd..bac39ca1f 100644 --- a/tests/neo-plugins.Tests/neo-plugins.Tests.csproj +++ b/tests/Neo.Plugins.Storage.Tests/Neo.Plugins.Storage.Tests.csproj @@ -1,20 +1,20 @@ - - - - netcoreapp3.0 - neo_plugins.Tests - false - - - - - - - - - - - - - - + + + + netcoreapp3.0 + Neo.Plugins.Storage.Tests + false + + + + + + + + + + + + + + diff --git a/tests/neo-plugins.Tests/StoreTest.cs b/tests/Neo.Plugins.Storage.Tests/StoreTest.cs similarity index 98% rename from tests/neo-plugins.Tests/StoreTest.cs rename to tests/Neo.Plugins.Storage.Tests/StoreTest.cs index 5035644ea..ee83c8a42 100644 --- a/tests/neo-plugins.Tests/StoreTest.cs +++ b/tests/Neo.Plugins.Storage.Tests/StoreTest.cs @@ -1,7 +1,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.Persistence; -namespace neo_plugins.Tests +namespace Neo.Plugins.Storage.Tests { [TestClass] public class StoreTest From c369cd228bd39620e5e8e537ae013cc1d762abc4 Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Mon, 9 Dec 2019 12:41:04 +0800 Subject: [PATCH 092/183] Add RpcClient (#163) --- .github/workflows/dotnetcore.yml | 2 +- neo-modules.sln | 14 + src/RpcClient/ContractClient.cs | 66 +++ src/RpcClient/Models/RpcBlock.cs | 37 ++ src/RpcClient/Models/RpcBlockHeader.cs | 37 ++ src/RpcClient/Models/RpcInvokeResult.cs | 60 ++ src/RpcClient/Models/RpcNep5Balances.cs | 57 ++ src/RpcClient/Models/RpcNep5TokenInfo.cs | 15 + src/RpcClient/Models/RpcPeers.cs | 55 ++ src/RpcClient/Models/RpcPlugin.cs | 32 + src/RpcClient/Models/RpcRawMemPool.cs | 32 + src/RpcClient/Models/RpcRequest.cs | 37 ++ src/RpcClient/Models/RpcResponse.cs | 72 +++ src/RpcClient/Models/RpcTransaction.cs | 49 ++ .../Models/RpcValidateAddressResult.cs | 27 + src/RpcClient/Models/RpcValidator.cs | 32 + src/RpcClient/Models/RpcVersion.cs | 35 ++ src/RpcClient/Nep5API.cs | 122 ++++ src/RpcClient/PolicyAPI.cs | 57 ++ src/RpcClient/Properties/AssemblyInfo.cs | 3 + src/RpcClient/RpcClient.cs | 311 ++++++++++ src/RpcClient/RpcClient.csproj | 20 + src/RpcClient/RpcException.cs | 12 + src/RpcClient/TransactionManager.cs | 226 +++++++ src/RpcClient/Utility.cs | 92 +++ src/RpcClient/WalletAPI.cs | 192 ++++++ .../Models/UT_RpcBlock.cs | 24 + .../Models/UT_RpcBlockHeader.cs | 24 + .../Models/UT_RpcNep5Balance.cs | 66 +++ .../Models/UT_RpcNep5Balances.cs | 66 +++ .../Models/UT_RpcPeer.cs | 23 + .../Models/UT_RpcPeers.cs | 44 ++ .../Models/UT_RpcRawMemPool.cs | 29 + .../Models/UT_RpcRequest.cs | 31 + .../Models/UT_RpcResponse.cs | 34 ++ .../Models/UT_RpcVersion.cs | 27 + .../Neo.Network.RPC.Tests.csproj | 22 + tests/Neo.Network.RPC.Tests/TestUtils.cs | 49 ++ .../UT_ContractClient.cs | 58 ++ tests/Neo.Network.RPC.Tests/UT_Nep5API.cs | 111 ++++ tests/Neo.Network.RPC.Tests/UT_PolicyAPI.cs | 68 +++ tests/Neo.Network.RPC.Tests/UT_RpcClient.cs | 558 ++++++++++++++++++ .../UT_TransactionManager.cs | 186 ++++++ tests/Neo.Network.RPC.Tests/UT_Utility.cs | 74 +++ tests/Neo.Network.RPC.Tests/UT_WalletAPI.cs | 116 ++++ 45 files changed, 3303 insertions(+), 1 deletion(-) create mode 100644 src/RpcClient/ContractClient.cs create mode 100644 src/RpcClient/Models/RpcBlock.cs create mode 100644 src/RpcClient/Models/RpcBlockHeader.cs create mode 100644 src/RpcClient/Models/RpcInvokeResult.cs create mode 100644 src/RpcClient/Models/RpcNep5Balances.cs create mode 100644 src/RpcClient/Models/RpcNep5TokenInfo.cs create mode 100644 src/RpcClient/Models/RpcPeers.cs create mode 100644 src/RpcClient/Models/RpcPlugin.cs create mode 100644 src/RpcClient/Models/RpcRawMemPool.cs create mode 100644 src/RpcClient/Models/RpcRequest.cs create mode 100644 src/RpcClient/Models/RpcResponse.cs create mode 100644 src/RpcClient/Models/RpcTransaction.cs create mode 100644 src/RpcClient/Models/RpcValidateAddressResult.cs create mode 100644 src/RpcClient/Models/RpcValidator.cs create mode 100644 src/RpcClient/Models/RpcVersion.cs create mode 100644 src/RpcClient/Nep5API.cs create mode 100644 src/RpcClient/PolicyAPI.cs create mode 100644 src/RpcClient/Properties/AssemblyInfo.cs create mode 100644 src/RpcClient/RpcClient.cs create mode 100644 src/RpcClient/RpcClient.csproj create mode 100644 src/RpcClient/RpcException.cs create mode 100644 src/RpcClient/TransactionManager.cs create mode 100644 src/RpcClient/Utility.cs create mode 100644 src/RpcClient/WalletAPI.cs create mode 100644 tests/Neo.Network.RPC.Tests/Models/UT_RpcBlock.cs create mode 100644 tests/Neo.Network.RPC.Tests/Models/UT_RpcBlockHeader.cs create mode 100644 tests/Neo.Network.RPC.Tests/Models/UT_RpcNep5Balance.cs create mode 100644 tests/Neo.Network.RPC.Tests/Models/UT_RpcNep5Balances.cs create mode 100644 tests/Neo.Network.RPC.Tests/Models/UT_RpcPeer.cs create mode 100644 tests/Neo.Network.RPC.Tests/Models/UT_RpcPeers.cs create mode 100644 tests/Neo.Network.RPC.Tests/Models/UT_RpcRawMemPool.cs create mode 100644 tests/Neo.Network.RPC.Tests/Models/UT_RpcRequest.cs create mode 100644 tests/Neo.Network.RPC.Tests/Models/UT_RpcResponse.cs create mode 100644 tests/Neo.Network.RPC.Tests/Models/UT_RpcVersion.cs create mode 100644 tests/Neo.Network.RPC.Tests/Neo.Network.RPC.Tests.csproj create mode 100644 tests/Neo.Network.RPC.Tests/TestUtils.cs create mode 100644 tests/Neo.Network.RPC.Tests/UT_ContractClient.cs create mode 100644 tests/Neo.Network.RPC.Tests/UT_Nep5API.cs create mode 100644 tests/Neo.Network.RPC.Tests/UT_PolicyAPI.cs create mode 100644 tests/Neo.Network.RPC.Tests/UT_RpcClient.cs create mode 100644 tests/Neo.Network.RPC.Tests/UT_TransactionManager.cs create mode 100644 tests/Neo.Network.RPC.Tests/UT_Utility.cs create mode 100644 tests/Neo.Network.RPC.Tests/UT_WalletAPI.cs diff --git a/.github/workflows/dotnetcore.yml b/.github/workflows/dotnetcore.yml index 431d34ee4..868557c9e 100644 --- a/.github/workflows/dotnetcore.yml +++ b/.github/workflows/dotnetcore.yml @@ -3,7 +3,7 @@ name: .NET Core Test and Publish on: pull_request env: - DOTNET_VERSION: 3.0.100 + DOTNET_VERSION: 3.1.100 jobs: diff --git a/neo-modules.sln b/neo-modules.sln index 5ef1ba616..8b4af9232 100644 --- a/neo-modules.sln +++ b/neo-modules.sln @@ -24,6 +24,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LevelDBStore", "src\LevelDB EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RocksDBStore", "src\RocksDBStore\RocksDBStore.csproj", "{0E2AAF05-C55A-4B36-8750-F55743FBE4B3}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RpcClient", "src\RpcClient\RpcClient.csproj", "{8DC57A45-A192-4953-81B1-6907FB7C28D2}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.Network.RPC.Tests", "tests\Neo.Network.RPC.Tests\Neo.Network.RPC.Tests.csproj", "{D52460B3-AB5C-4D07-B400-9E7ADCB01FF5}" +EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.Plugins.Storage.Tests", "tests\Neo.Plugins.Storage.Tests\Neo.Plugins.Storage.Tests.csproj", "{9E7EA895-302A-4C0C-BA9B-54F9A67AD75C}" EndProject Global @@ -68,6 +72,14 @@ Global {0E2AAF05-C55A-4B36-8750-F55743FBE4B3}.Debug|Any CPU.Build.0 = Debug|Any CPU {0E2AAF05-C55A-4B36-8750-F55743FBE4B3}.Release|Any CPU.ActiveCfg = Release|Any CPU {0E2AAF05-C55A-4B36-8750-F55743FBE4B3}.Release|Any CPU.Build.0 = Release|Any CPU + {8DC57A45-A192-4953-81B1-6907FB7C28D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8DC57A45-A192-4953-81B1-6907FB7C28D2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8DC57A45-A192-4953-81B1-6907FB7C28D2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8DC57A45-A192-4953-81B1-6907FB7C28D2}.Release|Any CPU.Build.0 = Release|Any CPU + {D52460B3-AB5C-4D07-B400-9E7ADCB01FF5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D52460B3-AB5C-4D07-B400-9E7ADCB01FF5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D52460B3-AB5C-4D07-B400-9E7ADCB01FF5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D52460B3-AB5C-4D07-B400-9E7ADCB01FF5}.Release|Any CPU.Build.0 = Release|Any CPU {9E7EA895-302A-4C0C-BA9B-54F9A67AD75C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {9E7EA895-302A-4C0C-BA9B-54F9A67AD75C}.Debug|Any CPU.Build.0 = Debug|Any CPU {9E7EA895-302A-4C0C-BA9B-54F9A67AD75C}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -86,6 +98,8 @@ Global {14DB62D5-0EA1-4A98-8656-1AA2D0345206} = {97E81C78-1637-481F-9485-DA1225E94C23} {C66214CD-0B97-4EA5-B7A2-164F54346F19} = {97E81C78-1637-481F-9485-DA1225E94C23} {0E2AAF05-C55A-4B36-8750-F55743FBE4B3} = {97E81C78-1637-481F-9485-DA1225E94C23} + {8DC57A45-A192-4953-81B1-6907FB7C28D2} = {97E81C78-1637-481F-9485-DA1225E94C23} + {D52460B3-AB5C-4D07-B400-9E7ADCB01FF5} = {59D802AB-C552-422A-B9C3-64D329FBCDCC} {9E7EA895-302A-4C0C-BA9B-54F9A67AD75C} = {59D802AB-C552-422A-B9C3-64D329FBCDCC} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution diff --git a/src/RpcClient/ContractClient.cs b/src/RpcClient/ContractClient.cs new file mode 100644 index 000000000..45fb31d26 --- /dev/null +++ b/src/RpcClient/ContractClient.cs @@ -0,0 +1,66 @@ +using Neo.Network.P2P.Payloads; +using Neo.Network.RPC.Models; +using Neo.SmartContract; +using Neo.SmartContract.Manifest; +using Neo.VM; +using Neo.Wallets; + +namespace Neo.Network.RPC +{ + /// + /// Contract related operations through RPC API + /// + public class ContractClient + { + protected readonly RpcClient rpcClient; + + /// + /// ContractClient Constructor + /// + /// the RPC client to call NEO RPC methods + public ContractClient(RpcClient rpc) + { + rpcClient = rpc; + } + + /// + /// Use RPC method to test invoke operation. + /// + /// contract script hash + /// contract operation + /// operation arguments + /// + public RpcInvokeResult TestInvoke(UInt160 scriptHash, string operation, params object[] args) + { + byte[] script = scriptHash.MakeScript(operation, args); + return rpcClient.InvokeScript(script); + } + + /// + /// Deploy Contract, return signed transaction + /// + /// contract script + /// contract manifest + /// sender KeyPair + /// transaction NetworkFee, set to be 0 if you don't need higher priority + /// + public Transaction CreateDeployContractTx(byte[] contractScript, ContractManifest manifest, KeyPair key, long networkFee = 0) + { + byte[] script; + using (ScriptBuilder sb = new ScriptBuilder()) + { + sb.EmitSysCall(InteropService.Neo_Contract_Create, contractScript, manifest.ToString()); + script = sb.ToArray(); + } + + UInt160 sender = Contract.CreateSignatureRedeemScript(key.PublicKey).ToScriptHash(); + Transaction tx = new TransactionManager(rpcClient, sender) + .MakeTransaction(script, null, null, networkFee) + .AddSignature(key) + .Sign() + .Tx; + + return tx; + } + } +} diff --git a/src/RpcClient/Models/RpcBlock.cs b/src/RpcClient/Models/RpcBlock.cs new file mode 100644 index 000000000..1ff485f96 --- /dev/null +++ b/src/RpcClient/Models/RpcBlock.cs @@ -0,0 +1,37 @@ +using Neo.IO.Json; +using Neo.Network.P2P.Payloads; + +namespace Neo.Network.RPC.Models +{ + public class RpcBlock + { + public Block Block { get; set; } + + public int Confirmations { get; set; } + + public UInt256 NextBlockHash { get; set; } + + public JObject ToJson() + { + JObject json = Block.ToJson(); + json["confirmations"] = Confirmations; + if (NextBlockHash != null) + { + json["nextblockhash"] = NextBlockHash.ToString(); + } + return json; + } + + public static RpcBlock FromJson(JObject json) + { + RpcBlock block = new RpcBlock(); + block.Block = Block.FromJson(json); + block.Confirmations = (int)json["confirmations"].AsNumber(); + if (json["nextblockhash"] != null) + { + block.NextBlockHash = UInt256.Parse(json["nextblockhash"].AsString()); + } + return block; + } + } +} diff --git a/src/RpcClient/Models/RpcBlockHeader.cs b/src/RpcClient/Models/RpcBlockHeader.cs new file mode 100644 index 000000000..5346dffd9 --- /dev/null +++ b/src/RpcClient/Models/RpcBlockHeader.cs @@ -0,0 +1,37 @@ +using Neo.IO.Json; +using Neo.Network.P2P.Payloads; + +namespace Neo.Network.RPC.Models +{ + public class RpcBlockHeader + { + public Header Header { get; set; } + + public int Confirmations { get; set; } + + public UInt256 NextBlockHash { get; set; } + + public JObject ToJson() + { + JObject json = Header.ToJson(); + json["confirmations"] = Confirmations; + if (NextBlockHash != null) + { + json["nextblockhash"] = NextBlockHash.ToString(); + } + return json; + } + + public static RpcBlockHeader FromJson(JObject json) + { + RpcBlockHeader block = new RpcBlockHeader(); + block.Header = Header.FromJson(json); + block.Confirmations = (int)json["confirmations"].AsNumber(); + if (json["nextblockhash"] != null) + { + block.NextBlockHash = UInt256.Parse(json["nextblockhash"].AsString()); + } + return block; + } + } +} diff --git a/src/RpcClient/Models/RpcInvokeResult.cs b/src/RpcClient/Models/RpcInvokeResult.cs new file mode 100644 index 000000000..a9c5f04c4 --- /dev/null +++ b/src/RpcClient/Models/RpcInvokeResult.cs @@ -0,0 +1,60 @@ +using Neo.IO.Json; +using Neo.SmartContract; +using System.Linq; + +namespace Neo.Network.RPC.Models +{ + public class RpcInvokeResult + { + public string Script { get; set; } + + public string State { get; set; } + + public string GasConsumed { get; set; } + + public ContractParameter[] Stack { get; set; } + + public JObject ToJson() + { + JObject json = new JObject(); + json["script"] = Script; + json["state"] = State; + json["gas_consumed"] = GasConsumed; + json["stack"] = new JArray(Stack.Select(p => p.ToJson())); + return json; + } + + public static RpcInvokeResult FromJson(JObject json) + { + RpcInvokeResult invokeScriptResult = new RpcInvokeResult(); + invokeScriptResult.Script = json["script"].AsString(); + invokeScriptResult.State = json["state"].AsString(); + invokeScriptResult.GasConsumed = json["gas_consumed"].AsString(); + invokeScriptResult.Stack = ((JArray)json["stack"]).Select(p => ContractParameter.FromJson(p)).ToArray(); + return invokeScriptResult; + } + } + + public class RpcStack + { + public string Type { get; set; } + + public string Value { get; set; } + + public JObject ToJson() + { + JObject json = new JObject(); + json["type"] = Type; + json["value"] = Value; + return json; + } + + public static RpcStack FromJson(JObject json) + { + RpcStack stackJson = new RpcStack(); + stackJson.Type = json["type"].AsString(); + stackJson.Value = json["value"].AsString(); + return stackJson; + } + } +} diff --git a/src/RpcClient/Models/RpcNep5Balances.cs b/src/RpcClient/Models/RpcNep5Balances.cs new file mode 100644 index 000000000..74fe7be72 --- /dev/null +++ b/src/RpcClient/Models/RpcNep5Balances.cs @@ -0,0 +1,57 @@ +using Neo.IO.Json; +using System.Linq; +using System.Numerics; + +namespace Neo.Network.RPC.Models +{ + public class RpcNep5Balances + { + public string Address { get; set; } + + public RpcNep5Balance[] Balances { get; set; } + + public JObject ToJson() + { + JObject json = new JObject(); + json["address"] = Address; + json["balance"] = Balances.Select(p => p.ToJson()).ToArray(); + return json; + } + + public static RpcNep5Balances FromJson(JObject json) + { + RpcNep5Balances nep5Balance = new RpcNep5Balances(); + nep5Balance.Address = json["address"].AsString(); + //List listBalance = new List(); + nep5Balance.Balances = ((JArray)json["balance"]).Select(p => RpcNep5Balance.FromJson(p)).ToArray(); + return nep5Balance; + } + } + + public class RpcNep5Balance + { + public UInt160 AssetHash { get; set; } + + public BigInteger Amount { get; set; } + + public uint LastUpdatedBlock { get; set; } + + public JObject ToJson() + { + JObject json = new JObject(); + json["asset_hash"] = AssetHash.ToString(); + json["amount"] = Amount.ToString(); + json["last_updated_block"] = LastUpdatedBlock.ToString(); + return json; + } + + public static RpcNep5Balance FromJson(JObject json) + { + RpcNep5Balance balance = new RpcNep5Balance(); + balance.AssetHash = UInt160.Parse(json["asset_hash"].AsString()); + balance.Amount = BigInteger.Parse(json["amount"].AsString()); + balance.LastUpdatedBlock = uint.Parse(json["last_updated_block"].AsString()); + return balance; + } + } +} diff --git a/src/RpcClient/Models/RpcNep5TokenInfo.cs b/src/RpcClient/Models/RpcNep5TokenInfo.cs new file mode 100644 index 000000000..0f251a5a3 --- /dev/null +++ b/src/RpcClient/Models/RpcNep5TokenInfo.cs @@ -0,0 +1,15 @@ +using System.Numerics; + +namespace Neo.Network.RPC.Models +{ + public class RpcNep5TokenInfo + { + public string Name { get; set; } + + public string Symbol { get; set; } + + public uint Decimals { get; set; } + + public BigInteger TotalSupply { get; set; } + } +} diff --git a/src/RpcClient/Models/RpcPeers.cs b/src/RpcClient/Models/RpcPeers.cs new file mode 100644 index 000000000..fac73842d --- /dev/null +++ b/src/RpcClient/Models/RpcPeers.cs @@ -0,0 +1,55 @@ +using Neo.IO.Json; +using System.Linq; + +namespace Neo.Network.RPC.Models +{ + public class RpcPeers + { + public RpcPeer[] Unconnected { get; set; } + + public RpcPeer[] Bad { get; set; } + + public RpcPeer[] Connected { get; set; } + + public JObject ToJson() + { + JObject json = new JObject(); + json["unconnected"] = new JArray(Unconnected.Select(p => p.ToJson())); + json["bad"] = new JArray(Bad.Select(p => p.ToJson())); + json["connected"] = new JArray(Connected.Select(p => p.ToJson())); + return json; + } + + public static RpcPeers FromJson(JObject json) + { + RpcPeers result = new RpcPeers(); + result.Unconnected = ((JArray)json["unconnected"]).Select(p => RpcPeer.FromJson(p)).ToArray(); + result.Bad = ((JArray)json["bad"]).Select(p => RpcPeer.FromJson(p)).ToArray(); + result.Connected = ((JArray)json["connected"]).Select(p => RpcPeer.FromJson(p)).ToArray(); + return result; + } + } + + public class RpcPeer + { + public string Address { get; set; } + + public int Port { get; set; } + + public JObject ToJson() + { + JObject json = new JObject(); + json["address"] = Address; + json["port"] = Port; + return json; + } + + public static RpcPeer FromJson(JObject json) + { + RpcPeer peer = new RpcPeer(); + peer.Address = json["address"].AsString(); + peer.Port = int.Parse(json["port"].AsString()); + return peer; + } + } +} diff --git a/src/RpcClient/Models/RpcPlugin.cs b/src/RpcClient/Models/RpcPlugin.cs new file mode 100644 index 000000000..db03f70eb --- /dev/null +++ b/src/RpcClient/Models/RpcPlugin.cs @@ -0,0 +1,32 @@ +using Neo.IO.Json; +using System.Linq; + +namespace Neo.Network.RPC.Models +{ + public class RpcPlugin + { + public string Name { get; set; } + + public string Version { get; set; } + + public string[] Interfaces { get; set; } + + public JObject ToJson() + { + JObject json = new JObject(); + json["name"] = Name; + json["version"] = Version; + json["interfaces"] = new JArray(Interfaces.Select(p => (JObject)p)); + return json; + } + + public static RpcPlugin FromJson(JObject json) + { + RpcPlugin plugin = new RpcPlugin(); + plugin.Name = json["name"].AsString(); + plugin.Version = json["version"].AsString(); + plugin.Interfaces = ((JArray)json["interfaces"]).Select(p => p.AsString()).ToArray(); + return plugin; + } + } +} diff --git a/src/RpcClient/Models/RpcRawMemPool.cs b/src/RpcClient/Models/RpcRawMemPool.cs new file mode 100644 index 000000000..c5ebd6341 --- /dev/null +++ b/src/RpcClient/Models/RpcRawMemPool.cs @@ -0,0 +1,32 @@ +using Neo.IO.Json; +using System.Linq; + +namespace Neo.Network.RPC.Models +{ + public class RpcRawMemPool + { + public uint Height { get; set; } + + public string[] Verified { get; set; } + + public string[] UnVerified { get; set; } + + public JObject ToJson() + { + JObject json = new JObject(); + json["height"] = Height; + json["verified"] = new JArray(Verified.Select(p => (JObject)p)); + json["unverified"] = new JArray(UnVerified.Select(p => (JObject)p)); + return json; + } + + public static RpcRawMemPool FromJson(JObject json) + { + RpcRawMemPool rawMemPool = new RpcRawMemPool(); + rawMemPool.Height = uint.Parse(json["height"].AsString()); + rawMemPool.Verified = ((JArray)json["verified"]).Select(p => p.AsString()).ToArray(); + rawMemPool.UnVerified = ((JArray)json["unverified"]).Select(p => p.AsString()).ToArray(); + return rawMemPool; + } + } +} diff --git a/src/RpcClient/Models/RpcRequest.cs b/src/RpcClient/Models/RpcRequest.cs new file mode 100644 index 000000000..1970adedb --- /dev/null +++ b/src/RpcClient/Models/RpcRequest.cs @@ -0,0 +1,37 @@ +using Neo.IO.Json; +using System.Linq; + +namespace Neo.Network.RPC.Models +{ + public class RpcRequest + { + public int Id { get; set; } + + public string Jsonrpc { get; set; } + + public string Method { get; set; } + + public JObject[] Params { get; set; } + + public static RpcRequest FromJson(JObject json) + { + return new RpcRequest + { + Id = (int)json["id"].AsNumber(), + Jsonrpc = json["jsonrpc"].AsString(), + Method = json["method"].AsString(), + Params = ((JArray)json["params"]).ToArray() + }; + } + + public JObject ToJson() + { + var json = new JObject(); + json["id"] = Id; + json["jsonrpc"] = Jsonrpc; + json["method"] = Method; + json["params"] = new JArray(Params); + return json; + } + } +} diff --git a/src/RpcClient/Models/RpcResponse.cs b/src/RpcClient/Models/RpcResponse.cs new file mode 100644 index 000000000..e4ebcaed1 --- /dev/null +++ b/src/RpcClient/Models/RpcResponse.cs @@ -0,0 +1,72 @@ +using Neo.IO.Json; + +namespace Neo.Network.RPC.Models +{ + public class RpcResponse + { + public int? Id { get; set; } + + public string Jsonrpc { get; set; } + + public RpcResponseError Error { get; set; } + + public JObject Result { get; set; } + + public string RawResponse { get; set; } + + public static RpcResponse FromJson(JObject json) + { + var response = new RpcResponse + { + Id = (int?)json["id"]?.AsNumber(), + Jsonrpc = json["jsonrpc"].AsString(), + Result = json["result"] + }; + + if (json["error"] != null) + { + response.Error = RpcResponseError.FromJson(json["error"]); + } + + return response; + } + + public JObject ToJson() + { + var json = new JObject(); + json["id"] = Id; + json["jsonrpc"] = Jsonrpc; + json["error"] = Error.ToJson(); + json["result"] = Result; + return json; + } + } + + public class RpcResponseError + { + public int Code { get; set; } + + public string Message { get; set; } + + public JObject Data { get; set; } + + public static RpcResponseError FromJson(JObject json) + { + return new RpcResponseError + { + Code = (int)json["code"].AsNumber(), + Message = json["message"].AsString(), + Data = json["data"], + }; + } + + public JObject ToJson() + { + var json = new JObject(); + json["code"] = Code; + json["message"] = Message; + json["data"] = Data; + return json; + } + } +} diff --git a/src/RpcClient/Models/RpcTransaction.cs b/src/RpcClient/Models/RpcTransaction.cs new file mode 100644 index 000000000..48b1e19bd --- /dev/null +++ b/src/RpcClient/Models/RpcTransaction.cs @@ -0,0 +1,49 @@ +using Neo.IO.Json; +using Neo.Network.P2P.Payloads; +using Neo.VM; + +namespace Neo.Network.RPC.Models +{ + public class RpcTransaction + { + public Transaction Transaction { get; set; } + + public UInt256 BlockHash { get; set; } + + public int? Confirmations { get; set; } + + public uint? BlockTime { get; set; } + + public VMState? VMState { get; set; } + + public JObject ToJson() + { + JObject json = Transaction.ToJson(); + if (Confirmations != null) + { + json["blockhash"] = BlockHash.ToString(); + json["confirmations"] = Confirmations; + json["blocktime"] = BlockTime; + if (VMState != null) + { + json["vmState"] = VMState; + } + } + return json; + } + + public static RpcTransaction FromJson(JObject json) + { + RpcTransaction transaction = new RpcTransaction(); + transaction.Transaction = Transaction.FromJson(json); + if (json["confirmations"] != null) + { + transaction.BlockHash = UInt256.Parse(json["blockhash"].AsString()); + transaction.Confirmations = (int)json["confirmations"].AsNumber(); + transaction.BlockTime = (uint)json["blocktime"].AsNumber(); + transaction.VMState = json["vmState"]?.TryGetEnum(); + } + return transaction; + } + } +} diff --git a/src/RpcClient/Models/RpcValidateAddressResult.cs b/src/RpcClient/Models/RpcValidateAddressResult.cs new file mode 100644 index 000000000..5e0a70479 --- /dev/null +++ b/src/RpcClient/Models/RpcValidateAddressResult.cs @@ -0,0 +1,27 @@ +using Neo.IO.Json; + +namespace Neo.Network.RPC.Models +{ + public class RpcValidateAddressResult + { + public string Address { get; set; } + + public bool IsValid { get; set; } + + public JObject ToJson() + { + JObject json = new JObject(); + json["address"] = Address; + json["isvalid"] = IsValid; + return json; + } + + public static RpcValidateAddressResult FromJson(JObject json) + { + RpcValidateAddressResult validateAddress = new RpcValidateAddressResult(); + validateAddress.Address = json["address"].AsString(); + validateAddress.IsValid = json["isvalid"].AsBoolean(); + return validateAddress; + } + } +} diff --git a/src/RpcClient/Models/RpcValidator.cs b/src/RpcClient/Models/RpcValidator.cs new file mode 100644 index 000000000..f3116ed2e --- /dev/null +++ b/src/RpcClient/Models/RpcValidator.cs @@ -0,0 +1,32 @@ +using Neo.IO.Json; +using System.Numerics; + +namespace Neo.Network.RPC.Models +{ + public class RpcValidator + { + public string PublicKey { get; set; } + + public BigInteger Votes { get; set; } + + public bool Active { get; set; } + + public JObject ToJson() + { + JObject json = new JObject(); + json["publickey"] = PublicKey; + json["votes"] = Votes.ToString(); + json["active"] = Active; + return json; + } + + public static RpcValidator FromJson(JObject json) + { + RpcValidator validator = new RpcValidator(); + validator.PublicKey = json["publickey"].AsString(); + validator.Votes = BigInteger.Parse(json["votes"].AsString()); + validator.Active = json["active"].AsBoolean(); + return validator; + } + } +} diff --git a/src/RpcClient/Models/RpcVersion.cs b/src/RpcClient/Models/RpcVersion.cs new file mode 100644 index 000000000..8163875b6 --- /dev/null +++ b/src/RpcClient/Models/RpcVersion.cs @@ -0,0 +1,35 @@ +using Neo.IO.Json; + +namespace Neo.Network.RPC.Models +{ + public class RpcVersion + { + public int TcpPort { get; set; } + + public int WsPort { get; set; } + + public uint Nonce { get; set; } + + public string UserAgent { get; set; } + + public JObject ToJson() + { + JObject json = new JObject(); + json["topPort"] = TcpPort.ToString(); + json["wsPort"] = WsPort.ToString(); + json["nonce"] = Nonce.ToString(); + json["useragent"] = UserAgent; + return json; + } + + public static RpcVersion FromJson(JObject json) + { + RpcVersion version = new RpcVersion(); + version.TcpPort = int.Parse(json["tcpPort"].AsString()); + version.WsPort = int.Parse(json["wsPort"].AsString()); + version.Nonce = uint.Parse(json["nonce"].AsString()); + version.UserAgent = json["useragent"].AsString(); + return version; + } + } +} diff --git a/src/RpcClient/Nep5API.cs b/src/RpcClient/Nep5API.cs new file mode 100644 index 000000000..619c75528 --- /dev/null +++ b/src/RpcClient/Nep5API.cs @@ -0,0 +1,122 @@ +using Neo.Network.P2P.Payloads; +using Neo.Network.RPC.Models; +using Neo.SmartContract; +using Neo.VM; +using Neo.Wallets; +using System.Linq; +using System.Numerics; +using static Neo.Helper; + +namespace Neo.Network.RPC +{ + /// + /// Call NEP5 methods with RPC API + /// + public class Nep5API : ContractClient + { + /// + /// Nep5API Constructor + /// + /// the RPC client to call NEO RPC methods + public Nep5API(RpcClient rpcClient) : base(rpcClient) { } + + /// + /// Get balance of NEP5 token + /// + /// contract script hash + /// account script hash + /// + public BigInteger BalanceOf(UInt160 scriptHash, UInt160 account) + { + BigInteger balance = TestInvoke(scriptHash, "balanceOf", account).Stack.Single().ToStackItem().GetBigInteger(); + return balance; + } + + /// + /// Get name of NEP5 token + /// + /// contract script hash + /// + public string Name(UInt160 scriptHash) + { + return TestInvoke(scriptHash, "name").Stack.Single().ToStackItem().GetString(); + } + + /// + /// Get symbol of NEP5 token + /// + /// contract script hash + /// + public string Symbol(UInt160 scriptHash) + { + return TestInvoke(scriptHash, "symbol").Stack.Single().ToStackItem().GetString(); + } + + /// + /// Get decimals of NEP5 token + /// + /// contract script hash + /// + public uint Decimals(UInt160 scriptHash) + { + return (uint)TestInvoke(scriptHash, "decimals").Stack.Single().ToStackItem().GetBigInteger(); + } + + /// + /// Get total supply of NEP5 token + /// + /// contract script hash + /// + public BigInteger TotalSupply(UInt160 scriptHash) + { + return TestInvoke(scriptHash, "totalSupply").Stack.Single().ToStackItem().GetBigInteger(); + } + + /// + /// Get token information in one rpc call + /// + /// contract script hash + /// + public RpcNep5TokenInfo GetTokenInfo(UInt160 scriptHash) + { + byte[] script = Concat(scriptHash.MakeScript("name"), + scriptHash.MakeScript("symbol"), + scriptHash.MakeScript("decimals"), + scriptHash.MakeScript("totalSupply")); + + var result = rpcClient.InvokeScript(script).Stack; + + return new RpcNep5TokenInfo + { + Name = result[0].ToStackItem().GetString(), + Symbol = result[1].ToStackItem().GetString(), + Decimals = (uint)result[2].ToStackItem().GetBigInteger(), + TotalSupply = result[3].ToStackItem().GetBigInteger() + }; + } + + /// + /// Create NEP5 token transfer transaction + /// + /// contract script hash + /// from KeyPair + /// to account script hash + /// transfer amount + /// netwotk fee, set to be 0 will auto calculate the least fee + /// + public Transaction CreateTransferTx(UInt160 scriptHash, KeyPair fromKey, UInt160 to, BigInteger amount, long networkFee = 0) + { + var sender = Contract.CreateSignatureRedeemScript(fromKey.PublicKey).ToScriptHash(); + Cosigner[] cosigners = new[] { new Cosigner { Scopes = WitnessScope.CalledByEntry, Account = sender } }; + + byte[] script = scriptHash.MakeScript("transfer", sender, to, amount); + Transaction tx = new TransactionManager(rpcClient, sender) + .MakeTransaction(script, null, cosigners, networkFee) + .AddSignature(fromKey) + .Sign() + .Tx; + + return tx; + } + } +} diff --git a/src/RpcClient/PolicyAPI.cs b/src/RpcClient/PolicyAPI.cs new file mode 100644 index 000000000..1b401cd7e --- /dev/null +++ b/src/RpcClient/PolicyAPI.cs @@ -0,0 +1,57 @@ +using Neo.SmartContract.Native; +using Neo.VM; +using System.Linq; + +namespace Neo.Network.RPC +{ + /// + /// Get Policy info by RPC API + /// + public class PolicyAPI : ContractClient + { + readonly UInt160 scriptHash = NativeContract.Policy.Hash; + + /// + /// PolicyAPI Constructor + /// + /// the RPC client to call NEO RPC methods + public PolicyAPI(RpcClient rpcClient) : base(rpcClient) { } + + /// + /// Get Max Transactions Count Per Block + /// + /// + public uint GetMaxTransactionsPerBlock() + { + return (uint)TestInvoke(scriptHash, "getMaxTransactionsPerBlock").Stack.Single().ToStackItem().GetBigInteger(); + } + + /// + /// Get Max Block Size + /// + /// + public uint GetMaxBlockSize() + { + return (uint)TestInvoke(scriptHash, "getMaxBlockSize").Stack.Single().ToStackItem().GetBigInteger(); + } + + /// + /// Get Network Fee Per Byte + /// + /// + public long GetFeePerByte() + { + return (long)TestInvoke(scriptHash, "getFeePerByte").Stack.Single().ToStackItem().GetBigInteger(); + } + + /// + /// Get Ploicy Blocked Accounts + /// + /// + public UInt160[] GetBlockedAccounts() + { + var result = (VM.Types.Array)TestInvoke(scriptHash, "getBlockedAccounts").Stack.Single().ToStackItem(); + return result.Select(p => new UInt160(p.GetSpan().ToArray())).ToArray(); + } + } +} diff --git a/src/RpcClient/Properties/AssemblyInfo.cs b/src/RpcClient/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..46ff5b88b --- /dev/null +++ b/src/RpcClient/Properties/AssemblyInfo.cs @@ -0,0 +1,3 @@ +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("Neo.Network.RPC.Tests")] diff --git a/src/RpcClient/RpcClient.cs b/src/RpcClient/RpcClient.cs new file mode 100644 index 000000000..2bb4fcdec --- /dev/null +++ b/src/RpcClient/RpcClient.cs @@ -0,0 +1,311 @@ +using Neo.IO; +using Neo.IO.Json; +using Neo.Ledger; +using Neo.Network.P2P.Payloads; +using Neo.Network.RPC.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; + +namespace Neo.Network.RPC +{ + /// + /// The RPC client to call NEO RPC methods + /// + public class RpcClient : IDisposable + { + private readonly HttpClient httpClient; + + public RpcClient(string url) + { + httpClient = new HttpClient() { BaseAddress = new Uri(url) }; + } + + public RpcClient(HttpClient client) + { + httpClient = client; + } + + public void Dispose() + { + httpClient?.Dispose(); + } + + public async Task SendAsync(RpcRequest request) + { + var requestJson = request.ToJson().ToString(); + using var result = await httpClient.PostAsync(httpClient.BaseAddress, new StringContent(requestJson, Encoding.UTF8)); + var content = await result.Content.ReadAsStringAsync(); + var response = RpcResponse.FromJson(JObject.Parse(content)); + response.RawResponse = content; + + if (response.Error != null) + { + throw new RpcException(response.Error.Code, response.Error.Message); + } + + return response; + } + + public RpcResponse Send(RpcRequest request) + { + try + { + return SendAsync(request).Result; + } + catch (AggregateException ex) + { + throw ex.GetBaseException(); + } + } + + public virtual JObject RpcSend(string method, params JObject[] paraArgs) + { + var request = new RpcRequest + { + Id = 1, + Jsonrpc = "2.0", + Method = method, + Params = paraArgs.Select(p => p).ToArray() + }; + return Send(request).Result; + } + + /// + /// Returns the hash of the tallest block in the main chain. + /// + public string GetBestBlockHash() + { + return RpcSend("getbestblockhash").AsString(); + } + + /// + /// Returns the hash of the tallest block in the main chain. + /// The serialized information of the block is returned, represented by a hexadecimal string. + /// + public string GetBlockHex(string hashOrIndex) + { + if (int.TryParse(hashOrIndex, out int index)) + { + return RpcSend("getblock", index).AsString(); + } + return RpcSend("getblock", hashOrIndex).AsString(); + } + + /// + /// Returns the hash of the tallest block in the main chain. + /// + public RpcBlock GetBlock(string hashOrIndex) + { + if (int.TryParse(hashOrIndex, out int index)) + { + return RpcBlock.FromJson(RpcSend("getblock", index, true)); + } + return RpcBlock.FromJson(RpcSend("getblock", hashOrIndex, true)); + } + + /// + /// Gets the number of blocks in the main chain. + /// + public uint GetBlockCount() + { + return (uint)RpcSend("getblockcount").AsNumber(); + } + + /// + /// Returns the hash value of the corresponding block, based on the specified index. + /// + public string GetBlockHash(int index) + { + return RpcSend("getblockhash", index).AsString(); + } + + /// + /// Returns the corresponding block header information according to the specified script hash. + /// + public string GetBlockHeaderHex(string hashOrIndex) + { + if (int.TryParse(hashOrIndex, out int index)) + { + return RpcSend("getblockheader", index).AsString(); + } + return RpcSend("getblockheader", hashOrIndex).AsString(); + } + + /// + /// Returns the corresponding block header information according to the specified script hash. + /// + public RpcBlockHeader GetBlockHeader(string hashOrIndex) + { + if (int.TryParse(hashOrIndex, out int index)) + { + return RpcBlockHeader.FromJson(RpcSend("getblockheader", index, true)); + } + return RpcBlockHeader.FromJson(RpcSend("getblockheader", hashOrIndex, true)); + } + + /// + /// Returns the system fees of the block, based on the specified index. + /// + public string GetBlockSysFee(int height) + { + return RpcSend("getblocksysfee", height).AsString(); + } + + /// + /// Gets the current number of connections for the node. + /// + public int GetConnectionCount() + { + return (int)RpcSend("getconnectioncount").AsNumber(); + } + + /// + /// Queries contract information, according to the contract script hash. + /// + public ContractState GetContractState(string hash) + { + return ContractState.FromJson(RpcSend("getcontractstate", hash)); + } + + /// + /// Gets the list of nodes that the node is currently connected/disconnected from. + /// + public RpcPeers GetPeers() + { + return RpcPeers.FromJson(RpcSend("getpeers")); + } + + /// + /// Obtains the list of unconfirmed transactions in memory. + /// + public string[] GetRawMempool() + { + return ((JArray)RpcSend("getrawmempool")).Select(p => p.AsString()).ToArray(); + } + + /// + /// Obtains the list of unconfirmed transactions in memory. + /// shouldGetUnverified = true + /// + public RpcRawMemPool GetRawMempoolBoth() + { + return RpcRawMemPool.FromJson(RpcSend("getrawmempool", true)); + } + + /// + /// Returns the corresponding transaction information, based on the specified hash value. + /// + public string GetRawTransactionHex(string txid) + { + return RpcSend("getrawtransaction", txid).AsString(); + } + + /// + /// Returns the corresponding transaction information, based on the specified hash value. + /// verbose = true + /// + public RpcTransaction GetRawTransaction(string txid) + { + return RpcTransaction.FromJson(RpcSend("getrawtransaction", txid, true)); + } + + /// + /// Returns the stored value, according to the contract script hash and the stored key. + /// + public string GetStorage(string script_hash, string key) + { + return RpcSend("getstorage", script_hash, key).AsString(); + } + + /// + /// Returns the block index in which the transaction is found. + /// + public uint GetTransactionHeight(string txid) + { + return uint.Parse(RpcSend("gettransactionheight", txid).AsString()); + } + + /// + /// Returns the current NEO consensus nodes information and voting status. + /// + public RpcValidator[] GetValidators() + { + return ((JArray)RpcSend("getvalidators")).Select(p => RpcValidator.FromJson(p)).ToArray(); + } + + /// + /// Returns the version information about the queried node. + /// + public RpcVersion GetVersion() + { + return RpcVersion.FromJson(RpcSend("getversion")); + } + + /// + /// Returns the result after calling a smart contract at scripthash with the given operation and parameters. + /// This RPC call does not affect the blockchain in any way. + /// + public RpcInvokeResult InvokeFunction(string address, string function, RpcStack[] stacks) + { + return RpcInvokeResult.FromJson(RpcSend("invokefunction", address, function, stacks.Select(p => p.ToJson()).ToArray())); + } + + /// + /// Returns the result after passing a script through the VM. + /// This RPC call does not affect the blockchain in any way. + /// + public RpcInvokeResult InvokeScript(byte[] script, params UInt160[] scriptHashesForVerifying) + { + List parameters = new List + { + script.ToHexString() + }; + parameters.AddRange(scriptHashesForVerifying.Select(p => (JObject)p.ToString())); + return RpcInvokeResult.FromJson(RpcSend("invokescript", parameters.ToArray())); + } + + /// + /// Returns a list of plugins loaded by the node. + /// + public RpcPlugin[] ListPlugins() + { + return ((JArray)RpcSend("listplugins")).Select(p => RpcPlugin.FromJson(p)).ToArray(); + } + + /// + /// Broadcasts a serialized transaction over the NEO network. + /// + public bool SendRawTransaction(byte[] rawTransaction) + { + return RpcSend("sendrawtransaction", rawTransaction.ToHexString()).AsBoolean(); + } + + /// + /// Broadcasts a transaction over the NEO network. + /// + public bool SendRawTransaction(Transaction transaction) + { + return SendRawTransaction(transaction.ToArray()); + } + + /// + /// Broadcasts a serialized block over the NEO network. + /// + public bool SubmitBlock(byte[] block) + { + return RpcSend("submitblock", block.ToHexString()).AsBoolean(); + } + + /// + /// Verifies that the address is a correct NEO address. + /// + public RpcValidateAddressResult ValidateAddress(string address) + { + return RpcValidateAddressResult.FromJson(RpcSend("validateaddress", address)); + } + } +} diff --git a/src/RpcClient/RpcClient.csproj b/src/RpcClient/RpcClient.csproj new file mode 100644 index 000000000..670812162 --- /dev/null +++ b/src/RpcClient/RpcClient.csproj @@ -0,0 +1,20 @@ + + + + 3.0.0-CI00825 + netstandard2.1 + Neo.Network.RPC + The Neo Project + Neo.Network.RPC.RpcClient + NEO;Blockchain + https://github.com/neo-project/neo-modules + MIT + git + https://github.com/neo-project/neo-modules.git + + + + + + + diff --git a/src/RpcClient/RpcException.cs b/src/RpcClient/RpcException.cs new file mode 100644 index 000000000..b5030750c --- /dev/null +++ b/src/RpcClient/RpcException.cs @@ -0,0 +1,12 @@ +using System; + +namespace Neo.Network.RPC +{ + public class RpcException : Exception + { + public RpcException(int code, string message) : base(message) + { + HResult = code; + } + } +} diff --git a/src/RpcClient/TransactionManager.cs b/src/RpcClient/TransactionManager.cs new file mode 100644 index 000000000..7841ba852 --- /dev/null +++ b/src/RpcClient/TransactionManager.cs @@ -0,0 +1,226 @@ +using Neo.Cryptography.ECC; +using Neo.IO; +using Neo.Network.P2P.Payloads; +using Neo.Network.RPC.Models; +using Neo.SmartContract; +using Neo.SmartContract.Native; +using Neo.VM; +using Neo.Wallets; +using System; + +namespace Neo.Network.RPC +{ + /// + /// This class helps to create transaction with RPC API. + /// + public class TransactionManager + { + private readonly RpcClient rpcClient; + private readonly PolicyAPI policyAPI; + private readonly Nep5API nep5API; + private readonly UInt160 sender; + + /// + /// The Transaction context to manage the witnesses + /// + private ContractParametersContext context; + + /// + /// The Transaction managed by this class + /// + public Transaction Tx { get; private set; } + + /// + /// TransactionManager Constructor + /// + /// the RPC client to call NEO RPC API + /// the account script hash of sender + public TransactionManager(RpcClient rpc, UInt160 sender) + { + rpcClient = rpc; + policyAPI = new PolicyAPI(rpc); + nep5API = new Nep5API(rpc); + this.sender = sender; + } + + /// + /// Create an unsigned Transaction object with given parameters. + /// + /// Transaction Script + /// Transaction Attributes + /// Transaction Cosigners + /// Transaction NetworkFee, will set to estimate value(with only basic signatures) when networkFee is 0 + /// + public TransactionManager MakeTransaction(byte[] script, TransactionAttribute[] attributes = null, Cosigner[] cosigners = null, long networkFee = 0) + { + var random = new Random(); + uint height = rpcClient.GetBlockCount() - 1; + Tx = new Transaction + { + Version = 0, + Nonce = (uint)random.Next(), + Script = script, + Sender = sender, + ValidUntilBlock = height + Transaction.MaxValidUntilBlockIncrement, + Attributes = attributes ?? new TransactionAttribute[0], + Cosigners = cosigners ?? new Cosigner[0], + Witnesses = new Witness[0] + }; + + // Add witness hashes parameter to pass CheckWitness + UInt160[] hashes = Tx.GetScriptHashesForVerifying(null); + RpcInvokeResult result = rpcClient.InvokeScript(script, hashes); + Tx.SystemFee = Math.Max(long.Parse(result.GasConsumed) - ApplicationEngine.GasFree, 0); + if (Tx.SystemFee > 0) + { + long d = (long)NativeContract.GAS.Factor; + long remainder = Tx.SystemFee % d; + if (remainder > 0) + Tx.SystemFee += d - remainder; + else if (remainder < 0) + Tx.SystemFee -= remainder; + } + + context = new ContractParametersContext(Tx); + + // set networkfee to estimate value when networkFee is 0 + Tx.NetworkFee = networkFee == 0 ? EstimateNetworkFee() : networkFee; + + var gasBalance = nep5API.BalanceOf(NativeContract.GAS.Hash, sender); + if (gasBalance >= Tx.SystemFee + Tx.NetworkFee) return this; + throw new InvalidOperationException($"Insufficient GAS in address: {sender.ToAddress()}"); + } + + /// + /// Estimate NetworkFee, assuming the witnesses are basic Signature Contract + /// + private long EstimateNetworkFee() + { + long networkFee = 0; + UInt160[] hashes = Tx.GetScriptHashesForVerifying(null); + int size = Transaction.HeaderSize + Tx.Attributes.GetVarSize() + Tx.Script.GetVarSize() + IO.Helper.GetVarSize(hashes.Length); + + // assume the hashes are single Signature + foreach (var hash in hashes) + { + size += 166; + networkFee += ApplicationEngine.OpCodePrices[OpCode.PUSHBYTES64] + ApplicationEngine.OpCodePrices[OpCode.PUSHBYTES33] + InteropService.GetPrice(InteropService.Neo_Crypto_ECDsaVerify, null); + } + + networkFee += size * policyAPI.GetFeePerByte(); + return networkFee; + } + + /// + /// Calculate NetworkFee with context items + /// + private long CalculateNetworkFee() + { + long networkFee = 0; + UInt160[] hashes = Tx.GetScriptHashesForVerifying(null); + int size = Transaction.HeaderSize + Tx.Attributes.GetVarSize() + Tx.Script.GetVarSize() + IO.Helper.GetVarSize(hashes.Length); + foreach (UInt160 hash in hashes) + { + byte[] witness_script = context.GetScript(hash); + if (witness_script is null || witness_script.Length == 0) + { + try + { + witness_script = rpcClient.GetContractState(hash.ToString())?.Script; + } + catch { } + } + + if (witness_script is null) continue; + + networkFee += Wallet.CalculateNetWorkFee(witness_script, ref size); + } + networkFee += size * policyAPI.GetFeePerByte(); + return networkFee; + } + + /// + /// Add Signature + /// + /// The KeyPair to sign transction + /// + public TransactionManager AddSignature(KeyPair key) + { + var contract = Contract.CreateSignatureContract(key.PublicKey); + + byte[] signature = Tx.Sign(key); + if (!context.AddSignature(contract, key.PublicKey, signature)) + { + throw new Exception("AddSignature failed!"); + } + + return this; + } + + /// + /// Add Multi-Signature + /// + /// The KeyPair to sign transction + /// The least count of signatures needed for multiple signature contract + /// The Public Keys construct the multiple signature contract + public TransactionManager AddMultiSig(KeyPair key, int m, params ECPoint[] publicKeys) + { + Contract contract = Contract.CreateMultiSigContract(m, publicKeys); + + byte[] signature = Tx.Sign(key); + if (!context.AddSignature(contract, key.PublicKey, signature)) + { + throw new Exception("AddMultiSig failed!"); + } + + return this; + } + + /// + /// Add Witness with contract + /// + /// The witness verification contract + /// The witness invocation parameters + public TransactionManager AddWitness(Contract contract, params object[] parameters) + { + if (!context.Add(contract, parameters)) + { + throw new Exception("AddWitness failed!"); + }; + return this; + } + + /// + /// Add Witness with scriptHash + /// + /// The witness verification contract hash + /// The witness invocation parameters + public TransactionManager AddWitness(UInt160 scriptHash, params object[] parameters) + { + var contract = Contract.Create(scriptHash); + return AddWitness(contract, parameters); + } + + /// + /// Verify Witness count and add witnesses + /// + public TransactionManager Sign() + { + // Verify witness count + if (!context.Completed) + { + throw new Exception($"Please add signature or witness first!"); + } + + // Calculate NetworkFee + long leastNetworkFee = CalculateNetworkFee(); + if (Tx.NetworkFee < leastNetworkFee) + { + throw new InvalidOperationException("Insufficient NetworkFee"); + } + + Tx.Witnesses = context.GetWitnesses(); + return this; + } + } +} diff --git a/src/RpcClient/Utility.cs b/src/RpcClient/Utility.cs new file mode 100644 index 000000000..198c31dd9 --- /dev/null +++ b/src/RpcClient/Utility.cs @@ -0,0 +1,92 @@ +using Neo.Cryptography.ECC; +using Neo.SmartContract; +using Neo.Wallets; +using System; +using System.Numerics; + +namespace Neo.Network.RPC +{ + public static class Utility + { + private static (BigInteger numerator, BigInteger denominator) Fraction(decimal d) + { + int[] bits = decimal.GetBits(d); + BigInteger numerator = (1 - ((bits[3] >> 30) & 2)) * + unchecked(((BigInteger)(uint)bits[2] << 64) | + ((BigInteger)(uint)bits[1] << 32) | + (uint)bits[0]); + BigInteger denominator = BigInteger.Pow(10, (bits[3] >> 16) & 0xff); + return (numerator, denominator); + } + + /// + /// Parse WIF or private key hex string to KeyPair + /// + /// WIF or private key hex string + /// Example: WIF ("KyXwTh1hB76RRMquSvnxZrJzQx7h9nQP2PCRL38v6VDb5ip3nf1p"), PrivateKey ("450d6c2a04b5b470339a745427bae6828400cf048400837d73c415063835e005") + /// + public static KeyPair GetKeyPair(string key) + { + if (string.IsNullOrEmpty(key)) { throw new ArgumentNullException(nameof(key)); } + if (key.StartsWith("0x")) { key = key.Substring(2); } + + if (key.Length == 52) + { + return new KeyPair(Wallet.GetPrivateKeyFromWIF(key)); + } + else if (key.Length == 64) + { + return new KeyPair(key.HexToBytes()); + } + + throw new FormatException(); + } + + /// + /// Parse address, scripthash or public key string to UInt160 + /// + /// account address, scripthash or public key string + /// Example: address ("AV556nYUwyJKNv8Xy7hVMLQnkmKPukw6x5"), scripthash ("0x6a38cd693b615aea24dd00de12a9f5836844da91"), public key ("02f9ec1fd0a98796cf75b586772a4ddd41a0af07a1dbdf86a7238f74fb72503575") + /// + public static UInt160 GetScriptHash(string account) + { + if (string.IsNullOrEmpty(account)) { throw new ArgumentNullException(nameof(account)); } + if (account.StartsWith("0x")) { account = account.Substring(2); } + + if (account.Length == 34) + { + return Wallets.Helper.ToScriptHash(account); + } + else if (account.Length == 40) + { + return UInt160.Parse(account); + } + else if (account.Length == 66) + { + var pubKey = ECPoint.Parse(account, ECCurve.Secp256r1); + return Contract.CreateSignatureRedeemScript(pubKey).ToScriptHash(); + } + + throw new FormatException(); + } + + /// + /// Convert decimal amount to BigInteger: amount * 10 ^ decimals + /// + /// float value + /// token decimals + /// + internal static BigInteger ToBigInteger(this decimal amount, uint decimals) + { + BigInteger factor = BigInteger.Pow(10, (int)decimals); + var (numerator, denominator) = Fraction(amount); + if (factor < denominator) + { + throw new OverflowException("The decimal places is too long."); + } + + BigInteger res = factor * numerator / denominator; + return res; + } + } +} diff --git a/src/RpcClient/WalletAPI.cs b/src/RpcClient/WalletAPI.cs new file mode 100644 index 000000000..e1ab3b777 --- /dev/null +++ b/src/RpcClient/WalletAPI.cs @@ -0,0 +1,192 @@ +using Neo.Ledger; +using Neo.Network.P2P.Payloads; +using Neo.Network.RPC.Models; +using Neo.SmartContract; +using Neo.SmartContract.Native; +using Neo.VM; +using Neo.Wallets; +using System; +using System.Linq; +using System.Numerics; +using System.Threading.Tasks; + +namespace Neo.Network.RPC +{ + /// + /// Wallet Common APIs + /// + public class WalletAPI + { + private readonly RpcClient rpcClient; + private readonly Nep5API nep5API; + + /// + /// WalletAPI Constructor + /// + /// the RPC client to call NEO RPC methods + public WalletAPI(RpcClient rpc) + { + rpcClient = rpc; + nep5API = new Nep5API(rpc); + } + + /// + /// Get unclaimed gas with address, scripthash or public key string + /// + /// address, scripthash or public key string + /// Example: address ("AV556nYUwyJKNv8Xy7hVMLQnkmKPukw6x5"), scripthash ("0x6a38cd693b615aea24dd00de12a9f5836844da91"), public key ("02f9ec1fd0a98796cf75b586772a4ddd41a0af07a1dbdf86a7238f74fb72503575") + /// + public decimal GetUnclaimedGas(string account) + { + UInt160 accountHash = Utility.GetScriptHash(account); + return GetUnclaimedGas(accountHash); + } + + /// + /// Get unclaimed gas + /// + /// account scripthash + /// + public decimal GetUnclaimedGas(UInt160 account) + { + UInt160 scriptHash = NativeContract.NEO.Hash; + BigInteger balance = nep5API.TestInvoke(scriptHash, "unclaimedGas", account, rpcClient.GetBlockCount() - 1) + .Stack.Single().ToStackItem().GetBigInteger(); + return ((decimal)balance) / (long)NativeContract.GAS.Factor; + } + + /// + /// Get Neo Balance + /// + /// address, scripthash or public key string + /// Example: address ("AV556nYUwyJKNv8Xy7hVMLQnkmKPukw6x5"), scripthash ("0x6a38cd693b615aea24dd00de12a9f5836844da91"), public key ("02f9ec1fd0a98796cf75b586772a4ddd41a0af07a1dbdf86a7238f74fb72503575") + /// + public uint GetNeoBalance(string account) + { + BigInteger balance = GetTokenBalance(NativeContract.NEO.Hash.ToString(), account); + return (uint)balance; + } + + /// + /// Get Gas Balance + /// + /// address, scripthash or public key string + /// Example: address ("AV556nYUwyJKNv8Xy7hVMLQnkmKPukw6x5"), scripthash ("0x6a38cd693b615aea24dd00de12a9f5836844da91"), public key ("02f9ec1fd0a98796cf75b586772a4ddd41a0af07a1dbdf86a7238f74fb72503575") + /// + public decimal GetGasBalance(string account) + { + BigInteger balance = GetTokenBalance(NativeContract.GAS.Hash.ToString(), account); + return ((decimal)balance) / (long)NativeContract.GAS.Factor; + } + + /// + /// Get token balance with string parameters + /// + /// token script hash, Example: "0x43cf98eddbe047e198a3e5d57006311442a0ca15"(NEO) + /// address, scripthash or public key string + /// Example: address ("AV556nYUwyJKNv8Xy7hVMLQnkmKPukw6x5"), scripthash ("0x6a38cd693b615aea24dd00de12a9f5836844da91"), public key ("02f9ec1fd0a98796cf75b586772a4ddd41a0af07a1dbdf86a7238f74fb72503575") + /// + public BigInteger GetTokenBalance(string tokenHash, string account) + { + UInt160 scriptHash = Utility.GetScriptHash(tokenHash); + UInt160 accountHash = Utility.GetScriptHash(account); + return nep5API.BalanceOf(scriptHash, accountHash); + } + + /// + /// The GAS is claimed when doing NEO transfer + /// This function will transfer NEO balance from account to itself + /// + /// wif or private key + /// Example: WIF ("KyXwTh1hB76RRMquSvnxZrJzQx7h9nQP2PCRL38v6VDb5ip3nf1p"), PrivateKey ("450d6c2a04b5b470339a745427bae6828400cf048400837d73c415063835e005") + /// The transaction sended + public Transaction ClaimGas(string key) + { + KeyPair keyPair = Utility.GetKeyPair(key); + return ClaimGas(keyPair); + } + + /// + /// The GAS is claimed when doing NEO transfer + /// This function will transfer NEO balance from account to itself + /// + /// keyPair + /// The transaction sended + public Transaction ClaimGas(KeyPair keyPair) + { + UInt160 toHash = Contract.CreateSignatureRedeemScript(keyPair.PublicKey).ToScriptHash(); + BigInteger balance = nep5API.BalanceOf(NativeContract.NEO.Hash, toHash); + Transaction transaction = nep5API.CreateTransferTx(NativeContract.NEO.Hash, keyPair, toHash, balance); + rpcClient.SendRawTransaction(transaction); + return transaction; + } + + /// + /// Transfer NEP5 token balance, with common data types + /// + /// nep5 token script hash, Example: scripthash ("0x6a38cd693b615aea24dd00de12a9f5836844da91") + /// wif or private key + /// Example: WIF ("KyXwTh1hB76RRMquSvnxZrJzQx7h9nQP2PCRL38v6VDb5ip3nf1p"), PrivateKey ("450d6c2a04b5b470339a745427bae6828400cf048400837d73c415063835e005") + /// address or account script hash + /// token amount + /// netwotk fee, set to be 0 will auto calculate the least fee + /// + public Transaction Transfer(string tokenHash, string fromKey, string toAddress, decimal amount, decimal networkFee = 0) + { + UInt160 scriptHash = Utility.GetScriptHash(tokenHash); + var decimals = nep5API.Decimals(scriptHash); + + KeyPair from = Utility.GetKeyPair(fromKey); + UInt160 to = Utility.GetScriptHash(toAddress); + BigInteger amountInteger = amount.ToBigInteger(decimals); + BigInteger networkFeeInteger = networkFee.ToBigInteger(NativeContract.GAS.Decimals); + return Transfer(scriptHash, from, to, amountInteger, (long)networkFeeInteger); + } + + /// + /// Transfer NEP5 token balance + /// + /// contract script hash + /// from KeyPair + /// to account script hash + /// transfer amount + /// netwotk fee, set to be 0 will auto calculate the least fee + /// + public Transaction Transfer(UInt160 scriptHash, KeyPair from, UInt160 to, BigInteger amountInteger, BigInteger networkFeeInteger = default) + { + Transaction transaction = nep5API.CreateTransferTx(scriptHash, from, to, amountInteger, (long)networkFeeInteger); + rpcClient.SendRawTransaction(transaction); + return transaction; + } + + /// + /// Wait until the transaction is observable block chain + /// + /// the transaction to observe + /// TimeoutException throws after "timeout" seconds + /// the Transaction state, including vmState and blockhash + public async Task WaitTransaction(Transaction transaction, int timeout = 60) + { + DateTime deadline = DateTime.UtcNow.AddSeconds(timeout); + RpcTransaction rpcTx = null; + while (rpcTx == null || rpcTx.Confirmations == null) + { + if (deadline < DateTime.UtcNow) + { + throw new TimeoutException(); + } + + try + { + rpcTx = rpcClient.GetRawTransaction(transaction.Hash.ToString()); + if (rpcTx == null || rpcTx.Confirmations == null) + { + await Task.Delay((int)Blockchain.MillisecondsPerBlock / 2); + } + } + catch (Exception) { } + } + return rpcTx; + } + } +} diff --git a/tests/Neo.Network.RPC.Tests/Models/UT_RpcBlock.cs b/tests/Neo.Network.RPC.Tests/Models/UT_RpcBlock.cs new file mode 100644 index 000000000..61887f784 --- /dev/null +++ b/tests/Neo.Network.RPC.Tests/Models/UT_RpcBlock.cs @@ -0,0 +1,24 @@ +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Network.RPC.Models; + +namespace Neo.Network.RPC.Tests.Models +{ + [TestClass] + public class UT_RpcBlock + { + [TestMethod] + public void TestToJson() + { + var rpcBlock = new RpcBlock + { + Block = TestUtils.GetBlock(1), + Confirmations = 1, + NextBlockHash = UInt256.Zero + }; + var json = rpcBlock.ToJson(); + json["previousblockhash"].AsString().Should().Be("0x0000000000000000000000000000000000000000000000000000000000000000"); + json["confirmations"].AsNumber().Should().Be(1); + } + } +} diff --git a/tests/Neo.Network.RPC.Tests/Models/UT_RpcBlockHeader.cs b/tests/Neo.Network.RPC.Tests/Models/UT_RpcBlockHeader.cs new file mode 100644 index 000000000..f756ab572 --- /dev/null +++ b/tests/Neo.Network.RPC.Tests/Models/UT_RpcBlockHeader.cs @@ -0,0 +1,24 @@ +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Network.RPC.Models; + +namespace Neo.Network.RPC.Tests.Models +{ + [TestClass] + public class UT_RpcBlockHeader + { + [TestMethod] + public void TestToJson() + { + var rpcBlockHeader = new RpcBlockHeader + { + Header = TestUtils.GetHeader(), + Confirmations = 1, + NextBlockHash = UInt256.Zero + }; + var json = rpcBlockHeader.ToJson(); + json["previousblockhash"].AsString().Should().Be("0x0000000000000000000000000000000000000000000000000000000000000000"); + json["confirmations"].AsNumber().Should().Be(1); + } + } +} diff --git a/tests/Neo.Network.RPC.Tests/Models/UT_RpcNep5Balance.cs b/tests/Neo.Network.RPC.Tests/Models/UT_RpcNep5Balance.cs new file mode 100644 index 000000000..1aeda4998 --- /dev/null +++ b/tests/Neo.Network.RPC.Tests/Models/UT_RpcNep5Balance.cs @@ -0,0 +1,66 @@ +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.IO.Json; +using Neo.Network.RPC.Models; +using System.Numerics; + +namespace Neo.Network.RPC.Tests.Models +{ + [TestClass] + public class UT_RpcNep5Balance + { + private RpcNep5Balance balance; + + [TestInitialize] + public void Setup() + { + balance = new RpcNep5Balance(); + } + + [TestMethod] + public void TestAssetHash() + { + balance.AssetHash = UInt160.Zero; + balance.AssetHash.Should().Be(UInt160.Zero); + } + + [TestMethod] + public void TestAmount() + { + balance.Amount = BigInteger.Zero; + balance.Amount.Should().Be(BigInteger.Zero); + } + + [TestMethod] + public void TestLastUpdatedBlock() + { + balance.LastUpdatedBlock = 0; + balance.LastUpdatedBlock.Should().Be(0); + } + + [TestMethod] + public void TestToJson() + { + balance.AssetHash = UInt160.Zero; + balance.Amount = BigInteger.Zero; + balance.LastUpdatedBlock = 0; + var json = balance.ToJson(); + json["asset_hash"].AsString().Should().Be("0x0000000000000000000000000000000000000000"); + json["amount"].AsNumber().Should().Be(0); + json["last_updated_block"].AsNumber().Should().Be(0); + } + + [TestMethod] + public void TestFromJson() + { + var json = new JObject(); + json["asset_hash"] = "0x0000000000000000000000000000000000000000"; + json["amount"] = "0"; + json["last_updated_block"] = "0"; + var rpcNep5Balance = RpcNep5Balance.FromJson(json); + rpcNep5Balance.AssetHash.Should().Be(UInt160.Zero); + rpcNep5Balance.Amount.Should().Be(BigInteger.Zero); + rpcNep5Balance.LastUpdatedBlock.Should().Be(0); + } + } +} diff --git a/tests/Neo.Network.RPC.Tests/Models/UT_RpcNep5Balances.cs b/tests/Neo.Network.RPC.Tests/Models/UT_RpcNep5Balances.cs new file mode 100644 index 000000000..da0752222 --- /dev/null +++ b/tests/Neo.Network.RPC.Tests/Models/UT_RpcNep5Balances.cs @@ -0,0 +1,66 @@ +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.IO.Json; +using Neo.Network.RPC.Models; +using System.Numerics; + +namespace Neo.Network.RPC.Tests.Models +{ + [TestClass] + public class UT_RpcNep5Balances + { + private RpcNep5Balances balances; + + [TestInitialize] + public void Setup() + { + balances = new RpcNep5Balances() + { + Address = "abc", + Balances = new RpcNep5Balance[] { + new RpcNep5Balance() + { + AssetHash = UInt160.Zero, + Amount = BigInteger.Zero, + LastUpdatedBlock = 0 + }, + new RpcNep5Balance() + { + AssetHash = UInt160.Parse("0xa400ff00ff00ff00ff00ff00ff00ff00ff00ff01"), + Amount = new BigInteger(1), + LastUpdatedBlock = 1 + } + } + }; + } + + [TestMethod] + public void TestAddress() + { + balances.Address.Should().Be("abc"); + } + + [TestMethod] + public void TestBalances() + { + balances.Balances.Length.Should().Be(2); + } + + [TestMethod] + public void TestToJson() + { + var json = balances.ToJson(); + json["address"].AsString().Should().Be("abc"); + ((JArray)json["balance"]).Count.Should().Be(2); + } + + [TestMethod] + public void TestFromJson() + { + var json = balances.ToJson(); + var rpcNep5Balances = RpcNep5Balances.FromJson(json); + rpcNep5Balances.Address.Should().Be("abc"); + rpcNep5Balances.Balances.Length.Should().Be(2); + } + } +} diff --git a/tests/Neo.Network.RPC.Tests/Models/UT_RpcPeer.cs b/tests/Neo.Network.RPC.Tests/Models/UT_RpcPeer.cs new file mode 100644 index 000000000..838aad486 --- /dev/null +++ b/tests/Neo.Network.RPC.Tests/Models/UT_RpcPeer.cs @@ -0,0 +1,23 @@ +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Network.RPC.Models; + +namespace Neo.Network.RPC.Tests.Models +{ + [TestClass] + public class UT_RpcPeer + { + [TestMethod] + public void TestToJson() + { + var rpcPeer = new RpcPeer() + { + Address = "abc", + Port = 800 + }; + var json = rpcPeer.ToJson(); + json["address"].AsString().Should().Be("abc"); + json["port"].AsNumber().Should().Be(800); + } + } +} diff --git a/tests/Neo.Network.RPC.Tests/Models/UT_RpcPeers.cs b/tests/Neo.Network.RPC.Tests/Models/UT_RpcPeers.cs new file mode 100644 index 000000000..fba07ea70 --- /dev/null +++ b/tests/Neo.Network.RPC.Tests/Models/UT_RpcPeers.cs @@ -0,0 +1,44 @@ +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.IO.Json; +using Neo.Network.RPC.Models; + +namespace Neo.Network.RPC.Tests.Models +{ + [TestClass] + public class UT_RpcPeers + { + [TestMethod] + public void TestToJson() + { + var rpcPeers = new RpcPeers() + { + Unconnected = new RpcPeer[] { + new RpcPeer() + { + Address = "Unconnected", + Port = 600 + } + }, + Bad = new RpcPeer[] { + new RpcPeer() + { + Address = "Bad", + Port = 700 + } + }, + Connected = new RpcPeer[] { + new RpcPeer() + { + Address = "Connected", + Port = 800 + } + } + }; + var json = rpcPeers.ToJson(); + ((JArray)json["unconnected"]).Count.Should().Be(1); + ((JArray)json["bad"]).Count.Should().Be(1); + ((JArray)json["connected"]).Count.Should().Be(1); + } + } +} diff --git a/tests/Neo.Network.RPC.Tests/Models/UT_RpcRawMemPool.cs b/tests/Neo.Network.RPC.Tests/Models/UT_RpcRawMemPool.cs new file mode 100644 index 000000000..fbfd6719c --- /dev/null +++ b/tests/Neo.Network.RPC.Tests/Models/UT_RpcRawMemPool.cs @@ -0,0 +1,29 @@ +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Network.RPC.Models; + +namespace Neo.Network.RPC.Tests.Models +{ + [TestClass] + public class UT_RpcRawMemPool + { + [TestMethod] + public void TestToJson() + { + var pool = new RpcRawMemPool + { + Height = 1, + Verified = new string[] { + "a", "b" + }, + UnVerified = new string[] { + "c", "d" + } + }; + var json = pool.ToJson(); + json["height"].AsNumber().Should().Be(1); + json["verified"].AsString().Should().Be("a,b"); + json["unverified"].AsString().Should().Be("c,d"); + } + } +} diff --git a/tests/Neo.Network.RPC.Tests/Models/UT_RpcRequest.cs b/tests/Neo.Network.RPC.Tests/Models/UT_RpcRequest.cs new file mode 100644 index 000000000..3aec7e9d1 --- /dev/null +++ b/tests/Neo.Network.RPC.Tests/Models/UT_RpcRequest.cs @@ -0,0 +1,31 @@ +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.IO.Json; +using Neo.Network.RPC.Models; + +namespace Neo.Network.RPC.Tests.Models +{ + [TestClass] + public class UT_RpcRequest + { + [TestMethod] + public void TestFromJson() + { + var req = new RpcRequest() + { + Id = 1, + Jsonrpc = "myrpc", + Method = "get", + Params = new JObject[] { + new JBoolean(true) + } + }; + var json = req.ToJson(); + var rpcRequest = RpcRequest.FromJson(json); + rpcRequest.Jsonrpc.Should().Be("myrpc"); + rpcRequest.Method.Should().Be("get"); + rpcRequest.Id.Should().Be(1); + rpcRequest.Params.Length.Should().Be(1); + } + } +} diff --git a/tests/Neo.Network.RPC.Tests/Models/UT_RpcResponse.cs b/tests/Neo.Network.RPC.Tests/Models/UT_RpcResponse.cs new file mode 100644 index 000000000..6265fb436 --- /dev/null +++ b/tests/Neo.Network.RPC.Tests/Models/UT_RpcResponse.cs @@ -0,0 +1,34 @@ +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.IO.Json; +using Neo.Network.RPC.Models; + +namespace Neo.Network.RPC.Tests.Models +{ + [TestClass] + public class UT_RpcResponse + { + [TestMethod] + public void TestToJson() + { + var error = new RpcResponseError() + { + Code = 0, + Message = "msg", + Data = new JBoolean(true) + }; + var rep = new RpcResponse() + { + Id = 1, + Jsonrpc = "rpc", + Error = error, + Result = new JBoolean(true) + }; + var json = rep.ToJson(); + json["id"].AsNumber().Should().Be(1); + json["jsonrpc"].AsString().Should().Be("rpc"); + json["error"].AsString().Should().Be(error.ToJson().AsString()); + json["result"].AsBoolean().Should().BeTrue(); + } + } +} diff --git a/tests/Neo.Network.RPC.Tests/Models/UT_RpcVersion.cs b/tests/Neo.Network.RPC.Tests/Models/UT_RpcVersion.cs new file mode 100644 index 000000000..e6ce63500 --- /dev/null +++ b/tests/Neo.Network.RPC.Tests/Models/UT_RpcVersion.cs @@ -0,0 +1,27 @@ +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Network.RPC.Models; + +namespace Neo.Network.RPC.Tests.Models +{ + [TestClass] + public class UT_RpcVersion + { + [TestMethod] + public void TestToJson() + { + var version = new RpcVersion() + { + TcpPort = 800, + WsPort = 900, + Nonce = 1, + UserAgent = "agent" + }; + var json = version.ToJson(); + json["topPort"].AsNumber().Should().Be(800); + json["wsPort"].AsNumber().Should().Be(900); + json["nonce"].AsNumber().Should().Be(1); + json["useragent"].AsString().Should().Be("agent"); + } + } +} diff --git a/tests/Neo.Network.RPC.Tests/Neo.Network.RPC.Tests.csproj b/tests/Neo.Network.RPC.Tests/Neo.Network.RPC.Tests.csproj new file mode 100644 index 000000000..3c4da3a16 --- /dev/null +++ b/tests/Neo.Network.RPC.Tests/Neo.Network.RPC.Tests.csproj @@ -0,0 +1,22 @@ + + + + netcoreapp3.1 + Neo.Network.RPC.Tests + false + + + + + + + + + + + + + + + + diff --git a/tests/Neo.Network.RPC.Tests/TestUtils.cs b/tests/Neo.Network.RPC.Tests/TestUtils.cs new file mode 100644 index 000000000..dd1b45aa0 --- /dev/null +++ b/tests/Neo.Network.RPC.Tests/TestUtils.cs @@ -0,0 +1,49 @@ +using Neo.Network.P2P.Payloads; +using System.Linq; + +namespace Neo.Network.RPC.Tests +{ + internal static class TestUtils + { + public static Block GetBlock(int txCount) + { + return new Block + { + PrevHash = UInt256.Zero, + MerkleRoot = UInt256.Zero, + NextConsensus = UInt160.Zero, + Witness = new Witness + { + InvocationScript = new byte[0], + VerificationScript = new byte[0] + }, + ConsensusData = new ConsensusData(), + Transactions = Enumerable.Range(0, txCount).Select(p => GetTransaction()).ToArray() + }; + } + + public static Header GetHeader() + { + return GetBlock(0).Header; + } + + public static Transaction GetTransaction() + { + return new Transaction + { + Script = new byte[1], + Sender = UInt160.Zero, + Attributes = new TransactionAttribute[0], + Cosigners = new Cosigner[0], + Witnesses = new Witness[] + { + new Witness + { + InvocationScript = new byte[0], + VerificationScript = new byte[0] + } + } + }; + } + } +} diff --git a/tests/Neo.Network.RPC.Tests/UT_ContractClient.cs b/tests/Neo.Network.RPC.Tests/UT_ContractClient.cs new file mode 100644 index 000000000..0fb19faa5 --- /dev/null +++ b/tests/Neo.Network.RPC.Tests/UT_ContractClient.cs @@ -0,0 +1,58 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +using Neo.SmartContract; +using Neo.SmartContract.Manifest; +using Neo.SmartContract.Native; +using Neo.VM; +using Neo.Wallets; + +namespace Neo.Network.RPC.Tests +{ + [TestClass] + public class UT_ContractClient + { + Mock rpcClientMock; + KeyPair keyPair1; + UInt160 sender; + + [TestInitialize] + public void TestSetup() + { + keyPair1 = new KeyPair(Wallet.GetPrivateKeyFromWIF("KyXwTh1hB76RRMquSvnxZrJzQx7h9nQP2PCRL38v6VDb5ip3nf1p")); + sender = Contract.CreateSignatureRedeemScript(keyPair1.PublicKey).ToScriptHash(); + rpcClientMock = UT_TransactionManager.MockRpcClient(sender, new byte[0]); + } + + [TestMethod] + public void TestInvoke() + { + byte[] testScript = NativeContract.GAS.Hash.MakeScript("balanceOf", UInt160.Zero); + UT_TransactionManager.MockInvokeScript(rpcClientMock, testScript, new ContractParameter { Type = ContractParameterType.ByteArray, Value = "00e057eb481b".HexToBytes() }); + + ContractClient contractClient = new ContractClient(rpcClientMock.Object); + var result = contractClient.TestInvoke(NativeContract.GAS.Hash, "balanceOf", UInt160.Zero); + + Assert.AreEqual(30000000000000L, (long)result.Stack[0].ToStackItem().GetBigInteger()); + } + + [TestMethod] + public void TestDeployContract() + { + byte[] script; + var manifest = ContractManifest.CreateDefault(new byte[1].ToScriptHash()); + manifest.Features = ContractFeatures.HasStorage | ContractFeatures.Payable; + using (ScriptBuilder sb = new ScriptBuilder()) + { + sb.EmitSysCall(InteropService.Neo_Contract_Create, new byte[1], manifest.ToString()); + script = sb.ToArray(); + } + + UT_TransactionManager.MockInvokeScript(rpcClientMock, script, new ContractParameter()); + + ContractClient contractClient = new ContractClient(rpcClientMock.Object); + var result = contractClient.CreateDeployContractTx(new byte[1], manifest, keyPair1); + + Assert.IsNotNull(result); + } + } +} diff --git a/tests/Neo.Network.RPC.Tests/UT_Nep5API.cs b/tests/Neo.Network.RPC.Tests/UT_Nep5API.cs new file mode 100644 index 000000000..b21482441 --- /dev/null +++ b/tests/Neo.Network.RPC.Tests/UT_Nep5API.cs @@ -0,0 +1,111 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +using Neo.SmartContract; +using Neo.SmartContract.Native; +using Neo.VM; +using Neo.Wallets; +using System.Linq; +using System.Numerics; + +namespace Neo.Network.RPC.Tests +{ + [TestClass] + public class UT_Nep5API + { + Mock rpcClientMock; + KeyPair keyPair1; + UInt160 sender; + Nep5API nep5API; + + [TestInitialize] + public void TestSetup() + { + keyPair1 = new KeyPair(Wallet.GetPrivateKeyFromWIF("KyXwTh1hB76RRMquSvnxZrJzQx7h9nQP2PCRL38v6VDb5ip3nf1p")); + sender = Contract.CreateSignatureRedeemScript(keyPair1.PublicKey).ToScriptHash(); + rpcClientMock = UT_TransactionManager.MockRpcClient(sender, new byte[0]); + nep5API = new Nep5API(rpcClientMock.Object); + } + + [TestMethod] + public void TestBalanceOf() + { + byte[] testScript = NativeContract.GAS.Hash.MakeScript("balanceOf", UInt160.Zero); + UT_TransactionManager.MockInvokeScript(rpcClientMock, testScript, new ContractParameter { Type = ContractParameterType.Integer, Value = new BigInteger(10000) }); + + var balance = nep5API.BalanceOf(NativeContract.GAS.Hash, UInt160.Zero); + Assert.AreEqual(10000, (int)balance); + } + + [TestMethod] + public void TestGetName() + { + byte[] testScript = NativeContract.GAS.Hash.MakeScript("name"); + UT_TransactionManager.MockInvokeScript(rpcClientMock, testScript, new ContractParameter { Type = ContractParameterType.String, Value = NativeContract.GAS.Name }); + + var result = nep5API.Name(NativeContract.GAS.Hash); + Assert.AreEqual(NativeContract.GAS.Name, result); + } + + [TestMethod] + public void TestGetSymbol() + { + byte[] testScript = NativeContract.GAS.Hash.MakeScript("symbol"); + UT_TransactionManager.MockInvokeScript(rpcClientMock, testScript, new ContractParameter { Type = ContractParameterType.String, Value = NativeContract.GAS.Symbol }); + + var result = nep5API.Symbol(NativeContract.GAS.Hash); + Assert.AreEqual(NativeContract.GAS.Symbol, result); + } + + [TestMethod] + public void TestGetDecimals() + { + byte[] testScript = NativeContract.GAS.Hash.MakeScript("decimals"); + UT_TransactionManager.MockInvokeScript(rpcClientMock, testScript, new ContractParameter { Type = ContractParameterType.Integer, Value = new BigInteger(NativeContract.GAS.Decimals) }); + + var result = nep5API.Decimals(NativeContract.GAS.Hash); + Assert.AreEqual(NativeContract.GAS.Decimals, (byte)result); + } + + [TestMethod] + public void TestGetTotalSupply() + { + byte[] testScript = NativeContract.GAS.Hash.MakeScript("totalSupply"); + UT_TransactionManager.MockInvokeScript(rpcClientMock, testScript, new ContractParameter { Type = ContractParameterType.Integer, Value = new BigInteger(1_00000000) }); + + var result = nep5API.TotalSupply(NativeContract.GAS.Hash); + Assert.AreEqual(1_00000000, (int)result); + } + + [TestMethod] + public void TestGetTokenInfo() + { + UInt160 scriptHash = NativeContract.GAS.Hash; + byte[] testScript = scriptHash.MakeScript("name") + .Concat(scriptHash.MakeScript("symbol")) + .Concat(scriptHash.MakeScript("decimals")) + .Concat(scriptHash.MakeScript("totalSupply")) + .ToArray(); ; + UT_TransactionManager.MockInvokeScript(rpcClientMock, testScript, + new ContractParameter { Type = ContractParameterType.String, Value = NativeContract.GAS.Name }, + new ContractParameter { Type = ContractParameterType.String, Value = NativeContract.GAS.Symbol }, + new ContractParameter { Type = ContractParameterType.Integer, Value = new BigInteger(NativeContract.GAS.Decimals) }, + new ContractParameter { Type = ContractParameterType.Integer, Value = new BigInteger(1_00000000) }); + + var result = nep5API.GetTokenInfo(NativeContract.GAS.Hash); + Assert.AreEqual(NativeContract.GAS.Name, result.Name); + Assert.AreEqual(NativeContract.GAS.Symbol, result.Symbol); + Assert.AreEqual(8, (int)result.Decimals); + Assert.AreEqual(1_00000000, (int)result.TotalSupply); + } + + [TestMethod] + public void TestTransfer() + { + byte[] testScript = NativeContract.GAS.Hash.MakeScript("transfer", sender, UInt160.Zero, new BigInteger(1_00000000)); + UT_TransactionManager.MockInvokeScript(rpcClientMock, testScript, new ContractParameter()); + + var result = nep5API.CreateTransferTx(NativeContract.GAS.Hash, keyPair1, UInt160.Zero, new BigInteger(1_00000000)); + Assert.IsNotNull(result); + } + } +} diff --git a/tests/Neo.Network.RPC.Tests/UT_PolicyAPI.cs b/tests/Neo.Network.RPC.Tests/UT_PolicyAPI.cs new file mode 100644 index 000000000..b6a8bdd01 --- /dev/null +++ b/tests/Neo.Network.RPC.Tests/UT_PolicyAPI.cs @@ -0,0 +1,68 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +using Neo.SmartContract; +using Neo.SmartContract.Native; +using Neo.VM; +using Neo.Wallets; +using System.Numerics; + +namespace Neo.Network.RPC.Tests +{ + [TestClass] + public class UT_PolicyAPI + { + Mock rpcClientMock; + KeyPair keyPair1; + UInt160 sender; + PolicyAPI policyAPI; + + [TestInitialize] + public void TestSetup() + { + keyPair1 = new KeyPair(Wallet.GetPrivateKeyFromWIF("KyXwTh1hB76RRMquSvnxZrJzQx7h9nQP2PCRL38v6VDb5ip3nf1p")); + sender = Contract.CreateSignatureRedeemScript(keyPair1.PublicKey).ToScriptHash(); + rpcClientMock = UT_TransactionManager.MockRpcClient(sender, new byte[0]); + policyAPI = new PolicyAPI(rpcClientMock.Object); + } + + [TestMethod] + public void TestGetMaxTransactionsPerBlock() + { + byte[] testScript = NativeContract.Policy.Hash.MakeScript("getMaxTransactionsPerBlock"); + UT_TransactionManager.MockInvokeScript(rpcClientMock, testScript, new ContractParameter { Type = ContractParameterType.Integer, Value = new BigInteger(512) }); + + var result = policyAPI.GetMaxTransactionsPerBlock(); + Assert.AreEqual(512u, result); + } + + [TestMethod] + public void TestGetMaxBlockSize() + { + byte[] testScript = NativeContract.Policy.Hash.MakeScript("getMaxBlockSize"); + UT_TransactionManager.MockInvokeScript(rpcClientMock, testScript, new ContractParameter { Type = ContractParameterType.Integer, Value = new BigInteger(1024u * 256u) }); + + var result = policyAPI.GetMaxBlockSize(); + Assert.AreEqual(1024u * 256u, result); + } + + [TestMethod] + public void TestGetFeePerByte() + { + byte[] testScript = NativeContract.Policy.Hash.MakeScript("getFeePerByte"); + UT_TransactionManager.MockInvokeScript(rpcClientMock, testScript, new ContractParameter { Type = ContractParameterType.Integer, Value = new BigInteger(1000) }); + + var result = policyAPI.GetFeePerByte(); + Assert.AreEqual(1000L, result); + } + + [TestMethod] + public void TestGetBlockedAccounts() + { + byte[] testScript = NativeContract.Policy.Hash.MakeScript("getBlockedAccounts"); + UT_TransactionManager.MockInvokeScript(rpcClientMock, testScript, new ContractParameter { Type = ContractParameterType.Array, Value = new[] { new ContractParameter { Type = ContractParameterType.Hash160, Value = UInt160.Zero } } }); + + var result = policyAPI.GetBlockedAccounts(); + Assert.AreEqual(UInt160.Zero, result[0]); + } + } +} diff --git a/tests/Neo.Network.RPC.Tests/UT_RpcClient.cs b/tests/Neo.Network.RPC.Tests/UT_RpcClient.cs new file mode 100644 index 000000000..1ced6b077 --- /dev/null +++ b/tests/Neo.Network.RPC.Tests/UT_RpcClient.cs @@ -0,0 +1,558 @@ +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +using Moq.Protected; +using Neo.IO; +using Neo.IO.Json; +using Neo.Ledger; +using Neo.Network.P2P.Payloads; +using Neo.Network.RPC.Models; +using Neo.SmartContract; +using Neo.SmartContract.Manifest; +using Neo.VM; +using System; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; + +namespace Neo.Network.RPC.Tests +{ + [TestClass] + public class UT_RpcClient + { + RpcClient rpc; + Mock handlerMock; + + [TestInitialize] + public void TestSetup() + { + handlerMock = new Mock(MockBehavior.Strict); + + // use real http client with mocked handler here + var httpClient = new HttpClient(handlerMock.Object) + { + BaseAddress = new Uri("http://seed1.neo.org:10331"), + }; + + rpc = new RpcClient(httpClient); + } + + private void MockResponse(string content) + { + handlerMock.Protected() + // Setup the PROTECTED method to mock + .Setup>( + "SendAsync", + ItExpr.IsAny(), + ItExpr.IsAny() + ) + // prepare the expected response of the mocked http call + .ReturnsAsync(new HttpResponseMessage() + { + StatusCode = HttpStatusCode.OK, + Content = new StringContent(content), + }) + .Verifiable(); + } + + private JObject CreateErrorResponse(JObject id, int code, string message, JObject data = null) + { + JObject response = CreateResponse(id); + response["error"] = new JObject(); + response["error"]["code"] = code; + response["error"]["message"] = message; + if (data != null) + response["error"]["data"] = data; + return response; + } + + private JObject CreateResponse(JObject id) + { + JObject response = new JObject(); + response["jsonrpc"] = "2.0"; + response["id"] = id; + return response; + } + + [TestMethod] + public void TestErrorResponse() + { + JObject response = CreateErrorResponse(null, -32700, "Parse error"); + MockResponse(response.ToString()); + try + { + var result = rpc.GetBlockHex("773dd2dae4a9c9275290f89b56e67d7363ea4826dfd4fc13cc01cf73a44b0d0e"); + } + catch (RpcException ex) + { + Assert.AreEqual(-32700, ex.HResult); + Assert.AreEqual("Parse error", ex.Message); + } + } + + [TestMethod] + public void TestGetBestBlockHash() + { + JObject response = CreateResponse(1); + response["result"] = "000000002deadfa82cbc4682f5800"; + MockResponse(response.ToString()); + + var result = rpc.GetBestBlockHash(); + Assert.AreEqual("000000002deadfa82cbc4682f5800", result); + } + + [TestMethod] + public void TestGetBlockHex() + { + JObject response = CreateResponse(1); + response["result"] = "000000002deadfa82cbc4682f5800"; + MockResponse(response.ToString()); + + var result = rpc.GetBlockHex("773dd2dae4a9c9275290f89b56e67d7363ea4826dfd4fc13cc01cf73a44b0d0e"); + Assert.AreEqual("000000002deadfa82cbc4682f5800", result); + } + + [TestMethod] + public void TestGetBlock() + { + // create block + var block = TestUtils.GetBlock(3); + + JObject json = block.ToJson(); + json["confirmations"] = 20; + JObject response = CreateResponse(1); + response["result"] = json; + MockResponse(response.ToString()); + + var result = rpc.GetBlock("773dd2dae4a9c9275290f89b56e67d7363ea4826dfd4fc13cc01cf73a44b0d0e"); + Assert.AreEqual(block.Hash.ToString(), result.Block.Hash.ToString()); + Assert.IsNull(result.NextBlockHash); + Assert.AreEqual(20, result.Confirmations); + Assert.AreEqual(block.Transactions.Length, result.Block.Transactions.Length); + Assert.AreEqual(block.Transactions[0].Hash.ToString(), result.Block.Transactions[0].Hash.ToString()); + + // verbose with confirmations + json["confirmations"] = 20; + json["nextblockhash"] = "773dd2dae4a9c9275290f89b56e67d7363ea4826dfd4fc13cc01cf73a44b0d0e"; + MockResponse(response.ToString()); + result = rpc.GetBlock("773dd2dae4a9c9275290f89b56e67d7363ea4826dfd4fc13cc01cf73a44b0d0e"); + Assert.AreEqual(block.Hash.ToString(), result.Block.Hash.ToString()); + Assert.AreEqual(20, result.Confirmations); + Assert.AreEqual("0x773dd2dae4a9c9275290f89b56e67d7363ea4826dfd4fc13cc01cf73a44b0d0e", result.NextBlockHash.ToString()); + Assert.AreEqual(block.Transactions.Length, result.Block.Transactions.Length); + Assert.AreEqual(block.Transactions[0].Hash.ToString(), result.Block.Transactions[0].Hash.ToString()); + } + + [TestMethod] + public void TestGetBlockCount() + { + JObject response = CreateResponse(1); + response["result"] = 100; + MockResponse(response.ToString()); + + var result = rpc.GetBlockCount(); + Assert.AreEqual(100u, result); + } + + [TestMethod] + public void TestGetBlockHash() + { + JObject response = CreateResponse(1); + response["result"] = "0x4c1e879872344349067c3b1a30781eeb4f9040d3795db7922f513f6f9660b9b2"; + MockResponse(response.ToString()); + + var result = rpc.GetBlockHash(100); + Assert.AreEqual("0x4c1e879872344349067c3b1a30781eeb4f9040d3795db7922f513f6f9660b9b2", result); + } + + [TestMethod] + public void TestGetBlockHeaderHex() + { + JObject response = CreateResponse(1); + response["result"] = "0x4c1e879872344349067c3b1a30781eeb4f9040d3795db7922f513f6f9660b9b2"; + MockResponse(response.ToString()); + + var result = rpc.GetBlockHeaderHex("100"); + Assert.AreEqual("0x4c1e879872344349067c3b1a30781eeb4f9040d3795db7922f513f6f9660b9b2", result); + } + + [TestMethod] + public void TestGetBlockHeader() + { + Header header = TestUtils.GetHeader(); + + JObject json = header.ToJson(); + json["confirmations"] = 20; + JObject response = CreateResponse(1); + response["result"] = json; + MockResponse(response.ToString()); + + var result = rpc.GetBlockHeader("100"); + Assert.AreEqual(header.Hash.ToString(), result.Header.Hash.ToString()); + Assert.IsNull(result.NextBlockHash); + Assert.AreEqual(20, result.Confirmations); + + json["confirmations"] = 20; + json["nextblockhash"] = "4c1e879872344349067c3b1a30781eeb4f9040d3795db7922f513f6f9660b9b2"; + MockResponse(response.ToString()); + result = rpc.GetBlockHeader("100"); + Assert.AreEqual(header.Hash.ToString(), result.Header.Hash.ToString()); + Assert.AreEqual(20, result.Confirmations); + } + + [TestMethod] + public void TestGetBlockSysFee() + { + JObject response = CreateResponse(1); + response["result"] = "195500"; + MockResponse(response.ToString()); + + var result = rpc.GetBlockSysFee(100); + Assert.AreEqual("195500", result); + } + + [TestMethod] + public void TestGetConnectionCount() + { + JObject response = CreateResponse(1); + response["result"] = 9; + MockResponse(response.ToString()); + + var result = rpc.GetConnectionCount(); + Assert.AreEqual(9, result); + } + + [TestMethod] + public void TestGetContractState() + { + byte[] script; + using (var sb = new ScriptBuilder()) + { + sb.EmitSysCall(InteropService.System_Runtime_GetInvocationCounter); + script = sb.ToArray(); + } + + ContractState state = new ContractState + { + Script = new byte[] { (byte)OpCode.DROP, (byte)OpCode.DROP }.Concat(script).ToArray(), + Manifest = ContractManifest.CreateDefault(UInt160.Parse("0xa400ff00ff00ff00ff00ff00ff00ff00ff00ff01")) + }; + + JObject response = CreateResponse(1); + response["result"] = state.ToJson(); + MockResponse(response.ToString()); + + var result = rpc.GetContractState("17694b31cc7ee215cea2ded146e0b2b28768fc46"); + + Assert.AreEqual(state.Script.ToHexString(), result.Script.ToHexString()); + Assert.AreEqual(state.Manifest.Abi.EntryPoint.Name, result.Manifest.Abi.EntryPoint.Name); + } + + [TestMethod] + public void TestGetPeers() + { + JObject response = CreateResponse(1); + response["result"] = JObject.Parse(@"{ + ""unconnected"": [ + { + ""address"": ""::ffff:70.73.16.236"", + ""port"": 10333 + }, + { + ""address"": ""::ffff:82.95.77.148"", + ""port"": 10333 + }, + { + ""address"": ""::ffff:49.50.215.166"", + ""port"": 10333 + } + ], + ""bad"": [], + ""connected"": [ + { + ""address"": ""::ffff:139.219.106.33"", + ""port"": 10333 + }, + { + ""address"": ""::ffff:47.88.53.224"", + ""port"": 10333 + } + ] + }"); + MockResponse(response.ToString()); + + var result = rpc.GetPeers(); + Assert.AreEqual("::ffff:139.219.106.33", result.Connected[0].Address); + Assert.AreEqual("::ffff:82.95.77.148", result.Unconnected[1].Address); + } + + [TestMethod] + public void TestGetRawMempool() + { + JObject response = CreateResponse(1); + response["result"] = JObject.Parse(@"[ + ""0x9786cce0dddb524c40ddbdd5e31a41ed1f6b5c8a683c122f627ca4a007a7cf4e"", + ""0xb488ad25eb474f89d5ca3f985cc047ca96bc7373a6d3da8c0f192722896c1cd7"", + ""0xf86f6f2c08fbf766ebe59dc84bc3b8829f1053f0a01deb26bf7960d99fa86cd6"" + ]"); + MockResponse(response.ToString()); + + var result = rpc.GetRawMempool(); + Assert.AreEqual("0xb488ad25eb474f89d5ca3f985cc047ca96bc7373a6d3da8c0f192722896c1cd7", result[1]); + } + + [TestMethod] + public void TestGetRawMempoolBoth() + { + JObject json = new JObject(); + json["height"] = 65535; + json["verified"] = new JArray(new[] { "0x9786cce0dddb524c40ddbdd5e31a41ed1f6b5c8a683c122f627ca4a007a7cf4e" }.Select(p => (JObject)p)); + json["unverified"] = new JArray(new[] { "0xb488ad25eb474f89d5ca3f985cc047ca96bc7373a6d3da8c0f192722896c1cd7", "0xf86f6f2c08fbf766ebe59dc84bc3b8829f1053f0a01deb26bf7960d99fa86cd6" }.Select(p => (JObject)p)); + + JObject response = CreateResponse(1); + response["result"] = json; + MockResponse(response.ToString()); + + var result = rpc.GetRawMempoolBoth(); + Assert.AreEqual(65535u, result.Height); + Assert.AreEqual("0x9786cce0dddb524c40ddbdd5e31a41ed1f6b5c8a683c122f627ca4a007a7cf4e", result.Verified[0]); + Assert.AreEqual("0xf86f6f2c08fbf766ebe59dc84bc3b8829f1053f0a01deb26bf7960d99fa86cd6", result.UnVerified[1]); + } + + [TestMethod] + public void TestGetRawTransactionHex() + { + var json = TestUtils.GetTransaction().ToArray().ToHexString(); + + JObject response = CreateResponse(1); + response["result"] = json; + MockResponse(response.ToString()); + + //var result = rpc.GetRawTransactionHex("0x9786cce0dddb524c40ddbdd5e31a41ed1f6b5c8a683c122f627ca4a007a7cf4e"); + var result = rpc.GetRawTransactionHex(TestUtils.GetTransaction().Hash.ToString()); + Assert.AreEqual(json, result); + } + + [TestMethod] + public void TestGetRawTransaction() + { + var transaction = TestUtils.GetTransaction(); + JObject json = transaction.ToJson(); + JObject response = CreateResponse(1); + response["result"] = json; + MockResponse(response.ToString()); + + var result = rpc.GetRawTransaction("0x9786cce0dddb524c40ddbdd5e31a41ed1f6b5c8a683c122f627ca4a007a7cf4e"); + Assert.AreEqual(transaction.Hash, result.Transaction.Hash); + Assert.AreEqual(json.ToString(), result.ToJson().ToString()); + + // make the code compatible with the old version + json["blockhash"] = UInt256.Zero.ToString(); + json["confirmations"] = 100; + json["blocktime"] = 10; + MockResponse(response.ToString()); + + result = rpc.GetRawTransaction("0x9786cce0dddb524c40ddbdd5e31a41ed1f6b5c8a683c122f627ca4a007a7cf4e"); + Assert.AreEqual(transaction.Hash, result.Transaction.Hash); + Assert.AreEqual(100, result.Confirmations); + Assert.AreEqual(null, result.VMState); + Assert.AreEqual(json.ToString(), result.ToJson().ToString()); + + json["vmState"] = VMState.HALT; + MockResponse(response.ToString()); + + result = rpc.GetRawTransaction("0x9786cce0dddb524c40ddbdd5e31a41ed1f6b5c8a683c122f627ca4a007a7cf4e"); + Assert.AreEqual(transaction.Hash, result.Transaction.Hash); + Assert.AreEqual(100, result.Confirmations); + Assert.AreEqual(VMState.HALT, result.VMState); + Assert.AreEqual(json.ToString(), result.ToJson().ToString()); + } + + [TestMethod] + public void TestGetStorage() + { + JObject json = "4c696e"; + JObject response = CreateResponse(1); + response["result"] = json; + MockResponse(response.ToString()); + + var result = rpc.GetStorage("03febccf81ac85e3d795bc5cbd4e84e907812aa3", "5065746572"); + Assert.AreEqual("4c696e", result); + } + + [TestMethod] + public void TestGetTransactionHeight() + { + JObject json = 10000; + JObject response = CreateResponse(1); + response["result"] = json; + MockResponse(response.ToString()); + + var result = rpc.GetTransactionHeight("9c909e1e3ba03290553a68d862e002c7a21ba302e043fc492fe069bf6a134d29"); + Assert.AreEqual(json.ToString(), result.ToString()); + } + + [TestMethod] + public void TestGetValidators() + { + JObject json = JObject.Parse(@"[ + { + ""publickey"": ""02486fd15702c4490a26703112a5cc1d0923fd697a33406bd5a1c00e0013b09a70"", + ""votes"": ""46632420"", + ""active"": true + }, + { + ""publickey"": ""024c7b7fb6c310fccf1ba33b082519d82964ea93868d676662d4a59ad548df0e7d"", + ""votes"": ""46632420"", + ""active"": true + } + ]"); + JObject response = CreateResponse(1); + response["result"] = json; + MockResponse(response.ToString()); + + var result = rpc.GetValidators(); + Assert.AreEqual(((JArray)json)[0].ToString(), (result[0]).ToJson().ToString()); + } + + [TestMethod] + public void TestGetVersion() + { + JObject json = new JObject(); + json["tcpPort"] = 30001; + json["wsPort"] = 30002; + json["nonce"] = 1546258664; + json["useragent"] = "/NEO:2.7.5/"; + + var json1 = JObject.Parse(@"{ + ""tcpPort"": 30001, + ""wsPort"": 30002, + ""nonce"": 1546258664, + ""useragent"": ""/NEO:2.7.5/"" + }"); + Assert.AreEqual(json.ToString(), json1.ToString()); + + JObject response = CreateResponse(1); + response["result"] = json; + MockResponse(response.ToString()); + + var result = rpc.GetVersion(); + Assert.AreEqual(30001, result.TcpPort); + Assert.AreEqual("/NEO:2.7.5/", result.UserAgent); + } + + [TestMethod] + public void TestInvokeFunction() + { + JObject json = JObject.Parse(@" + { + ""script"": ""1426ae7c6c9861ec418468c1f0fdc4a7f2963eb89151c10962616c616e63654f6667be39e7b562f60cbfe2aebca375a2e5ee28737caf"", + ""state"": ""HALT"", + ""gas_consumed"": ""0.311"", + ""stack"": [ + { + ""type"": ""ByteArray"", + ""value"": ""262bec084432"" + } + ] + }"); + JObject response = CreateResponse(1); + response["result"] = json; + MockResponse(response.ToString()); + + var result = rpc.InvokeFunction("af7c7328eee5a275a3bcaee2bf0cf662b5e739be", "balanceOf", new[] { new RpcStack { Type = "Hash160", Value = "91b83e96f2a7c4fdf0c1688441ec61986c7cae26" } }); + Assert.AreEqual(json.ToString(), result.ToJson().ToString()); + } + + [TestMethod] + public void TestInvokeScript() + { + JObject json = JObject.Parse(@" + { + ""script"": ""1426ae7c6c9861ec418468c1f0fdc4a7f2963eb89151c10962616c616e63654f6667be39e7b562f60cbfe2aebca375a2e5ee28737caf"", + ""state"": ""HALT"", + ""gas_consumed"": ""0.311"", + ""stack"": [ + { + ""type"": ""ByteArray"", + ""value"": ""262bec084432"" + } + ] + }"); + JObject response = CreateResponse(1); + response["result"] = json; + MockResponse(response.ToString()); + + var result = rpc.InvokeScript("00046e616d656724058e5e1b6008847cd662728549088a9ee82191".HexToBytes()); + Assert.AreEqual(json.ToString(), result.ToJson().ToString()); + } + + [TestMethod] + public void TestListPlugins() + { + JObject json = JObject.Parse(@"[{ + ""name"": ""SimplePolicyPlugin"", + ""version"": ""2.10.1.0"", + ""interfaces"": [ + ""ILogPlugin"", + ""IPolicyPlugin"" + ] + }]"); + JObject response = CreateResponse(1); + response["result"] = json; + MockResponse(response.ToString()); + + var result = rpc.ListPlugins(); + Assert.AreEqual(((JArray)json)[0].ToString(), result[0].ToJson().ToString()); + } + + [TestMethod] + public void TestSendRawTransaction() + { + JObject json = true; + JObject response = CreateResponse(1); + response["result"] = json; + MockResponse(response.ToString()); + + var result = rpc.SendRawTransaction("80000001195876cb34364dc38b730077156c6bc3a7fc570044a66fbfeeea56f71327e8ab0000029b7cffdaa674beae0f930ebe6085af9093e5fe56b34a5c220ccdcf6efc336fc500c65eaf440000000f9a23e06f74cf86b8827a9108ec2e0f89ad956c9b7cffdaa674beae0f930ebe6085af9093e5fe56b34a5c220ccdcf6efc336fc50092e14b5e00000030aab52ad93f6ce17ca07fa88fc191828c58cb71014140915467ecd359684b2dc358024ca750609591aa731a0b309c7fb3cab5cd0836ad3992aa0a24da431f43b68883ea5651d548feb6bd3c8e16376e6e426f91f84c58232103322f35c7819267e721335948d385fae5be66e7ba8c748ac15467dcca0693692dac".HexToBytes()); + Assert.AreEqual(json.ToString(), ((JObject)result).ToString()); + } + + [TestMethod] + public void TestSubmitBlock() + { + JObject json = true; + JObject response = CreateResponse(1); + response["result"] = json; + MockResponse(response.ToString()); + + var result = rpc.SubmitBlock("03febccf81ac85e3d795bc5cbd4e84e907812aa3".HexToBytes()); + Assert.AreEqual(json.ToString(), ((JObject)result).ToString()); + } + + [TestMethod] + public void TestValidateAddress() + { + JObject json = new JObject(); + json["address"] = "AQVh2pG732YvtNaxEGkQUei3YA4cvo7d2i"; + json["isvalid"] = false; + JObject response = CreateResponse(1); + response["result"] = json; + MockResponse(response.ToString()); + + var result = rpc.ValidateAddress("AQVh2pG732YvtNaxEGkQUei3YA4cvo7d2i"); + Assert.AreEqual(json.ToString(), result.ToJson().ToString()); + } + + [TestMethod] + public void TestConstructorByUrlAndDispose() + { + //dummy url for test + var client = new RpcClient("http://www.xxx.yyy"); + Action action = () => client.Dispose(); + action.Should().NotThrow(); + } + } +} diff --git a/tests/Neo.Network.RPC.Tests/UT_TransactionManager.cs b/tests/Neo.Network.RPC.Tests/UT_TransactionManager.cs new file mode 100644 index 000000000..45814d259 --- /dev/null +++ b/tests/Neo.Network.RPC.Tests/UT_TransactionManager.cs @@ -0,0 +1,186 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +using Neo.Cryptography; +using Neo.IO; +using Neo.IO.Json; +using Neo.Network.P2P; +using Neo.Network.P2P.Payloads; +using Neo.Network.RPC.Models; +using Neo.SmartContract; +using Neo.SmartContract.Native; +using Neo.VM; +using Neo.Wallets; +using System; +using System.Linq; +using System.Numerics; + +namespace Neo.Network.RPC.Tests +{ + [TestClass] + public class UT_TransactionManager + { + TransactionManager txManager; + Mock rpcClientMock; + KeyPair keyPair1; + KeyPair keyPair2; + UInt160 sender; + + [TestInitialize] + public void TestSetup() + { + keyPair1 = new KeyPair(Wallet.GetPrivateKeyFromWIF("KyXwTh1hB76RRMquSvnxZrJzQx7h9nQP2PCRL38v6VDb5ip3nf1p")); + keyPair2 = new KeyPair(Wallet.GetPrivateKeyFromWIF("L2LGkrwiNmUAnWYb1XGd5mv7v2eDf6P4F3gHyXSrNJJR4ArmBp7Q")); + sender = Contract.CreateSignatureRedeemScript(keyPair1.PublicKey).ToScriptHash(); + rpcClientMock = MockRpcClient(sender, new byte[1]); + } + + public static Mock MockRpcClient(UInt160 sender, byte[] script) + { + var mockRpc = new Mock(MockBehavior.Strict, "http://seed1.neo.org:10331"); + + // MockHeight + mockRpc.Setup(p => p.RpcSend("getblockcount")).Returns(100).Verifiable(); + + // MockGasBalance + byte[] balanceScript = NativeContract.GAS.Hash.MakeScript("balanceOf", sender); + var balanceResult = new ContractParameter() { Type = ContractParameterType.Integer, Value = BigInteger.Parse("10000000000000000") }; + + MockInvokeScript(mockRpc, balanceScript, balanceResult); + + // MockFeePerByte + byte[] policyScript = NativeContract.Policy.Hash.MakeScript("getFeePerByte"); + var policyResult = new ContractParameter() { Type = ContractParameterType.Integer, Value = BigInteger.Parse("1000") }; + + MockInvokeScript(mockRpc, policyScript, policyResult); + + // MockGasConsumed + var result = new ContractParameter(); + MockInvokeScript(mockRpc, script, result); + + return mockRpc; + } + + public static void MockInvokeScript(Mock mockClient, byte[] script, params ContractParameter[] parameters) + { + var result = new RpcInvokeResult() + { + Stack = parameters, + GasConsumed = "100", + Script = script.ToHexString(), + State = "" + }; + + mockClient.Setup(p => p.RpcSend("invokescript", It.Is(j => j[0].AsString() == script.ToHexString()))) + .Returns(result.ToJson()) + .Verifiable(); + } + + [TestMethod] + public void TestMakeTransaction() + { + txManager = new TransactionManager(rpcClientMock.Object, sender); + + TransactionAttribute[] attributes = new TransactionAttribute[1] + { + new TransactionAttribute + { + Usage = TransactionAttributeUsage.Url, + Data = "53616d706c6555726c".HexToBytes() // "SampleUrl" + } + }; + + byte[] script = new byte[1]; + txManager.MakeTransaction(script, attributes, null, 60000); + + var tx = txManager.Tx; + Assert.AreEqual("53616d706c6555726c", tx.Attributes[0].Data.ToHexString()); + Assert.AreEqual(0, tx.SystemFee % (long)NativeContract.GAS.Factor); + Assert.AreEqual(60000, tx.NetworkFee); + } + + [TestMethod] + public void TestSign() + { + txManager = new TransactionManager(rpcClientMock.Object, sender); + + TransactionAttribute[] attributes = new TransactionAttribute[1] + { + new TransactionAttribute + { + Usage = TransactionAttributeUsage.Url, + Data = "53616d706c6555726c".HexToBytes() // "SampleUrl" + } + }; + + byte[] script = new byte[1]; + txManager.MakeTransaction(script, attributes) + .AddSignature(keyPair1) + .Sign(); + + // get signature from Witnesses + var tx = txManager.Tx; + byte[] signature = tx.Witnesses[0].InvocationScript.Skip(1).ToArray(); + + Assert.IsTrue(Crypto.VerifySignature(tx.GetHashData(), signature, keyPair1.PublicKey.EncodePoint(false).Skip(1).ToArray())); + + // duplicate sign should not add new witness + txManager.AddSignature(keyPair1).Sign(); + Assert.AreEqual(1, txManager.Tx.Witnesses.Length); + + // throw exception when the KeyPair is wrong + Assert.ThrowsException(() => txManager.AddSignature(keyPair2)); + } + + [TestMethod] + public void TestSignMulti() + { + txManager = new TransactionManager(rpcClientMock.Object, sender); + + var multiContract = Contract.CreateMultiSigContract(2, keyPair1.PublicKey, keyPair2.PublicKey); + + // Cosigner needs multi signature + Cosigner[] cosigners = new Cosigner[1] + { + new Cosigner + { + Account = multiContract.ScriptHash, + Scopes = WitnessScope.Global + } + }; + + byte[] script = new byte[1]; + txManager.MakeTransaction(script, null, cosigners, 0_10000000) + .AddMultiSig(keyPair1, 2, keyPair1.PublicKey, keyPair2.PublicKey) + .AddMultiSig(keyPair2, 2, keyPair1.PublicKey, keyPair2.PublicKey) + .AddSignature(keyPair1) + .Sign(); + } + + [TestMethod] + public void TestAddWitness() + { + txManager = new TransactionManager(rpcClientMock.Object, sender); + + // Cosigner as contract scripthash + Cosigner[] cosigners = new Cosigner[1] + { + new Cosigner + { + Account = UInt160.Zero, + Scopes = WitnessScope.Global + } + }; + + byte[] script = new byte[1]; + txManager.MakeTransaction(script, null, cosigners, 0_10000000); + txManager.AddWitness(UInt160.Zero); + txManager.AddSignature(keyPair1); + txManager.Sign(); + + var tx = txManager.Tx; + Assert.AreEqual(2, tx.Witnesses.Length); + Assert.AreEqual(0, tx.Witnesses[0].VerificationScript.Length); + Assert.AreEqual(0, tx.Witnesses[0].InvocationScript.Length); + } + } +} diff --git a/tests/Neo.Network.RPC.Tests/UT_Utility.cs b/tests/Neo.Network.RPC.Tests/UT_Utility.cs new file mode 100644 index 000000000..00098b092 --- /dev/null +++ b/tests/Neo.Network.RPC.Tests/UT_Utility.cs @@ -0,0 +1,74 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.SmartContract; +using Neo.Wallets; +using System; +using System.Numerics; + +namespace Neo.Network.RPC.Tests +{ + [TestClass] + public class UT_Utility + { + private KeyPair keyPair; + private UInt160 scriptHash; + + [TestInitialize] + public void TestSetup() + { + keyPair = new KeyPair(Wallet.GetPrivateKeyFromWIF("KyXwTh1hB76RRMquSvnxZrJzQx7h9nQP2PCRL38v6VDb5ip3nf1p")); + scriptHash = Contract.CreateSignatureRedeemScript(keyPair.PublicKey).ToScriptHash(); + } + + [TestMethod] + public void TestGetKeyPair() + { + string nul = null; + Assert.ThrowsException(() => Utility.GetKeyPair(nul)); + + string wif = "KyXwTh1hB76RRMquSvnxZrJzQx7h9nQP2PCRL38v6VDb5ip3nf1p"; + var result = Utility.GetKeyPair(wif); + Assert.AreEqual(keyPair, result); + + string privateKey = keyPair.PrivateKey.ToHexString(); + result = Utility.GetKeyPair(privateKey); + Assert.AreEqual(keyPair, result); + } + + [TestMethod] + public void TestGetScriptHash() + { + string nul = null; + Assert.ThrowsException(() => Utility.GetScriptHash(nul)); + + string addr = scriptHash.ToAddress(); + var result = Utility.GetScriptHash(addr); + Assert.AreEqual(scriptHash, result); + + string hash = scriptHash.ToString(); + result = Utility.GetScriptHash(hash); + Assert.AreEqual(scriptHash, result); + + string publicKey = keyPair.PublicKey.ToString(); + result = Utility.GetScriptHash(publicKey); + Assert.AreEqual(scriptHash, result); + } + + [TestMethod] + public void TestToBigInteger() + { + decimal amount = 1.23456789m; + uint decimals = 9; + var result = amount.ToBigInteger(decimals); + Assert.AreEqual(1234567890, result); + + amount = 1.23456789m; + decimals = 18; + result = amount.ToBigInteger(decimals); + Assert.AreEqual(BigInteger.Parse("1234567890000000000"), result); + + amount = 1.23456789m; + decimals = 4; + Assert.ThrowsException(() => result = amount.ToBigInteger(decimals)); + } + } +} diff --git a/tests/Neo.Network.RPC.Tests/UT_WalletAPI.cs b/tests/Neo.Network.RPC.Tests/UT_WalletAPI.cs new file mode 100644 index 000000000..a2f738048 --- /dev/null +++ b/tests/Neo.Network.RPC.Tests/UT_WalletAPI.cs @@ -0,0 +1,116 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +using Neo.IO.Json; +using Neo.Network.P2P.Payloads; +using Neo.Network.RPC; +using Neo.Network.RPC.Models; +using Neo.SmartContract; +using Neo.SmartContract.Native; +using Neo.VM; +using Neo.Wallets; +using System.Numerics; + +namespace Neo.Network.RPC.Tests +{ + [TestClass] + public class UT_WalletAPI + { + Mock rpcClientMock; + KeyPair keyPair1; + string address1; + UInt160 sender; + WalletAPI walletAPI; + + [TestInitialize] + public void TestSetup() + { + keyPair1 = new KeyPair(Wallet.GetPrivateKeyFromWIF("KyXwTh1hB76RRMquSvnxZrJzQx7h9nQP2PCRL38v6VDb5ip3nf1p")); + sender = Contract.CreateSignatureRedeemScript(keyPair1.PublicKey).ToScriptHash(); + address1 = Neo.Wallets.Helper.ToAddress(sender); + rpcClientMock = UT_TransactionManager.MockRpcClient(sender, new byte[0]); + walletAPI = new WalletAPI(rpcClientMock.Object); + } + + [TestMethod] + public void TestGetUnclaimedGas() + { + byte[] testScript = NativeContract.NEO.Hash.MakeScript("unclaimedGas", sender, 99); + UT_TransactionManager.MockInvokeScript(rpcClientMock, testScript, new ContractParameter { Type = ContractParameterType.Integer, Value = new BigInteger(1_10000000) }); + + var balance = walletAPI.GetUnclaimedGas(address1); + Assert.AreEqual(1.1m, balance); + } + + [TestMethod] + public void TestGetNeoBalance() + { + byte[] testScript = NativeContract.NEO.Hash.MakeScript("balanceOf", sender); + UT_TransactionManager.MockInvokeScript(rpcClientMock, testScript, new ContractParameter { Type = ContractParameterType.Integer, Value = new BigInteger(1_00000000) }); + + var balance = walletAPI.GetNeoBalance(address1); + Assert.AreEqual(1_00000000u, balance); + } + + [TestMethod] + public void TestGetGasBalance() + { + byte[] testScript = NativeContract.GAS.Hash.MakeScript("balanceOf", sender); + UT_TransactionManager.MockInvokeScript(rpcClientMock, testScript, new ContractParameter { Type = ContractParameterType.Integer, Value = new BigInteger(1_10000000) }); + + var balance = walletAPI.GetGasBalance(address1); + Assert.AreEqual(1.1m, balance); + } + + [TestMethod] + public void TestGetTokenBalance() + { + byte[] testScript = UInt160.Zero.MakeScript("balanceOf", sender); + UT_TransactionManager.MockInvokeScript(rpcClientMock, testScript, new ContractParameter { Type = ContractParameterType.Integer, Value = new BigInteger(1_10000000) }); + + var balance = walletAPI.GetTokenBalance(UInt160.Zero.ToString(), address1); + Assert.AreEqual(1_10000000, balance); + } + + [TestMethod] + public void TestClaimGas() + { + byte[] balanceScript = NativeContract.NEO.Hash.MakeScript("balanceOf", sender); + UT_TransactionManager.MockInvokeScript(rpcClientMock, balanceScript, new ContractParameter { Type = ContractParameterType.Integer, Value = new BigInteger(1_00000000) }); + + byte[] testScript = NativeContract.NEO.Hash.MakeScript("transfer", sender, sender, new BigInteger(1_00000000)); + UT_TransactionManager.MockInvokeScript(rpcClientMock, testScript, new ContractParameter { Type = ContractParameterType.Integer, Value = new BigInteger(1_10000000) }); + + rpcClientMock.Setup(p => p.RpcSend("sendrawtransaction", It.IsAny())).Returns(true); + + var tranaction = walletAPI.ClaimGas(keyPair1.Export()); + Assert.AreEqual(testScript.ToHexString(), tranaction.Script.ToHexString()); + } + + [TestMethod] + public void TestTransfer() + { + byte[] decimalsScript = NativeContract.GAS.Hash.MakeScript("decimals"); + UT_TransactionManager.MockInvokeScript(rpcClientMock, decimalsScript, new ContractParameter { Type = ContractParameterType.Integer, Value = new BigInteger(8) }); + + byte[] testScript = NativeContract.GAS.Hash.MakeScript("transfer", sender, UInt160.Zero, NativeContract.GAS.Factor * 100); + UT_TransactionManager.MockInvokeScript(rpcClientMock, testScript, new ContractParameter { Type = ContractParameterType.Integer, Value = new BigInteger(1_10000000) }); + + rpcClientMock.Setup(p => p.RpcSend("sendrawtransaction", It.IsAny())).Returns(true); + + var tranaction = walletAPI.Transfer(NativeContract.GAS.Hash.ToString(), keyPair1.Export(), UInt160.Zero.ToAddress(), 100, 1.1m); + Assert.AreEqual(testScript.ToHexString(), tranaction.Script.ToHexString()); + } + + [TestMethod] + public void TestWaitTransaction() + { + Transaction transaction = TestUtils.GetTransaction(); + rpcClientMock.Setup(p => p.RpcSend("getrawtransaction", It.Is(j => j[0].AsString() == transaction.Hash.ToString()))) + .Returns(new RpcTransaction { Transaction = transaction, VMState = VMState.HALT, BlockHash = UInt256.Zero, BlockTime = 100, Confirmations = 1 }.ToJson()); + + var tx = walletAPI.WaitTransaction(transaction).Result; + Assert.AreEqual(VMState.HALT, tx.VMState); + Assert.AreEqual(UInt256.Zero, tx.BlockHash); + } + } +} From 68957fb40ff556292318a47e0b06c6c2da728572 Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Mon, 9 Dec 2019 19:27:27 +0800 Subject: [PATCH 093/183] Remove CoreMetrics (#164) --- neo-modules.sln | 7 --- src/CoreMetrics/CoreMetrics.cs | 84 ------------------------------ src/CoreMetrics/CoreMetrics.csproj | 13 ----- 3 files changed, 104 deletions(-) delete mode 100644 src/CoreMetrics/CoreMetrics.cs delete mode 100644 src/CoreMetrics/CoreMetrics.csproj diff --git a/neo-modules.sln b/neo-modules.sln index 8b4af9232..bd53f4dd4 100644 --- a/neo-modules.sln +++ b/neo-modules.sln @@ -16,8 +16,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RpcWallet", "src\RpcWallet\ EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RpcNep5Tracker", "src\RpcNep5Tracker\RpcNep5Tracker.csproj", "{BBE8AC15-12DF-4AF0-ABC1-F1557EB5DC8E}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CoreMetrics", "src\CoreMetrics\CoreMetrics.csproj", "{AEFFF003-3500-416B-AD9B-8C838C33C1F4}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SystemLog", "src\SystemLog\SystemLog.csproj", "{14DB62D5-0EA1-4A98-8656-1AA2D0345206}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LevelDBStore", "src\LevelDBStore\LevelDBStore.csproj", "{C66214CD-0B97-4EA5-B7A2-164F54346F19}" @@ -56,10 +54,6 @@ Global {BBE8AC15-12DF-4AF0-ABC1-F1557EB5DC8E}.Debug|Any CPU.Build.0 = Debug|Any CPU {BBE8AC15-12DF-4AF0-ABC1-F1557EB5DC8E}.Release|Any CPU.ActiveCfg = Release|Any CPU {BBE8AC15-12DF-4AF0-ABC1-F1557EB5DC8E}.Release|Any CPU.Build.0 = Release|Any CPU - {AEFFF003-3500-416B-AD9B-8C838C33C1F4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {AEFFF003-3500-416B-AD9B-8C838C33C1F4}.Debug|Any CPU.Build.0 = Debug|Any CPU - {AEFFF003-3500-416B-AD9B-8C838C33C1F4}.Release|Any CPU.ActiveCfg = Release|Any CPU - {AEFFF003-3500-416B-AD9B-8C838C33C1F4}.Release|Any CPU.Build.0 = Release|Any CPU {14DB62D5-0EA1-4A98-8656-1AA2D0345206}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {14DB62D5-0EA1-4A98-8656-1AA2D0345206}.Debug|Any CPU.Build.0 = Debug|Any CPU {14DB62D5-0EA1-4A98-8656-1AA2D0345206}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -94,7 +88,6 @@ Global {86531DB1-A231-46C4-823F-BE60972F7523} = {97E81C78-1637-481F-9485-DA1225E94C23} {EF32A7E5-EDF9-438C-8041-8DA6E675A7FD} = {97E81C78-1637-481F-9485-DA1225E94C23} {BBE8AC15-12DF-4AF0-ABC1-F1557EB5DC8E} = {97E81C78-1637-481F-9485-DA1225E94C23} - {AEFFF003-3500-416B-AD9B-8C838C33C1F4} = {97E81C78-1637-481F-9485-DA1225E94C23} {14DB62D5-0EA1-4A98-8656-1AA2D0345206} = {97E81C78-1637-481F-9485-DA1225E94C23} {C66214CD-0B97-4EA5-B7A2-164F54346F19} = {97E81C78-1637-481F-9485-DA1225E94C23} {0E2AAF05-C55A-4B36-8750-F55743FBE4B3} = {97E81C78-1637-481F-9485-DA1225E94C23} diff --git a/src/CoreMetrics/CoreMetrics.cs b/src/CoreMetrics/CoreMetrics.cs deleted file mode 100644 index 8b5d9aedd..000000000 --- a/src/CoreMetrics/CoreMetrics.cs +++ /dev/null @@ -1,84 +0,0 @@ -using Microsoft.AspNetCore.Http; -using Neo.IO.Json; -using Neo.Ledger; -using Neo.Network.P2P.Payloads; - -namespace Neo.Plugins -{ - public class CoreMetrics : Plugin, IRpcPlugin - { - protected override void Configure() { } - - public void PreProcess(HttpContext context, string method, JArray _params) { } - - public JObject OnProcess(HttpContext context, string method, JArray _params) - { - switch (method) - { - case "getmetricblocktimestamp": - { - uint nBlocks = (uint)_params[0].AsNumber(); - uint lastHeight = _params.Count >= 2 ? (uint)_params[1].AsNumber() : 0; - return GetBlocksTime(nBlocks, lastHeight); - } - default: - return null; - } - } - - public void PostProcess(HttpContext context, string method, JArray _params, JObject result) { } - - private JObject GetBlocksTime(uint nBlocks, uint lastHeight) - { - // It is currently limited to query blocks generated in the last 24hours (86400 seconds) - uint maxNBlocksPerDay = 86400 / (Blockchain.MillisecondsPerBlock / 1000); - if (lastHeight != 0) - { - if (lastHeight >= Blockchain.Singleton.Height) - { - JObject json = new JObject(); - return json["error"] = "Requested height to start " + lastHeight + " exceeds " + Blockchain.Singleton.Height; - } - - if (nBlocks > lastHeight) - { - JObject json = new JObject(); - return json["error"] = "Requested " + nBlocks + " blocks timestamps is greater than starting at height " + lastHeight; - } - } - - if (nBlocks > maxNBlocksPerDay) - { - JObject json = new JObject(); - return json["error"] = "Requested number of blocks timestamps exceeds " + maxNBlocksPerDay; - } - - if (nBlocks >= Blockchain.Singleton.Height) - { - JObject json = new JObject(); - return json["error"] = "Requested number of blocks timestamps " + nBlocks + " exceeds quantity of known blocks " + Blockchain.Singleton.Height; - } - - if (nBlocks == 0) - { - JObject json = new JObject(); - return json["error"] = "Requested number of block times can not be = 0"; - } - - JArray array = new JArray(); - uint heightToBegin = lastHeight > 0 ? lastHeight - nBlocks : (Blockchain.Singleton.Height - 1) - nBlocks; - for (uint i = heightToBegin; i <= heightToBegin + nBlocks; i++) - { - Header header = Blockchain.Singleton.GetHeader(i); - if (header == null) break; - - JObject json = new JObject(); - json["timestamp"] = header.Timestamp; - json["height"] = i; - array.Add(json); - } - - return array; - } - } -} diff --git a/src/CoreMetrics/CoreMetrics.csproj b/src/CoreMetrics/CoreMetrics.csproj deleted file mode 100644 index fe79e4b58..000000000 --- a/src/CoreMetrics/CoreMetrics.csproj +++ /dev/null @@ -1,13 +0,0 @@ - - - - 3.0.0-preview1 - netstandard2.1 - Neo.Plugins - - - - - - - From 68fbc692fb182e7225aabc3d0cf91c958607fd18 Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Mon, 9 Dec 2019 21:27:41 +0800 Subject: [PATCH 094/183] Coveralls (#165) --- .github/workflows/{dotnetcore.yml => main.yml} | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) rename .github/workflows/{dotnetcore.yml => main.yml} (58%) diff --git a/.github/workflows/dotnetcore.yml b/.github/workflows/main.yml similarity index 58% rename from .github/workflows/dotnetcore.yml rename to .github/workflows/main.yml index 868557c9e..12e09452f 100644 --- a/.github/workflows/dotnetcore.yml +++ b/.github/workflows/main.yml @@ -24,4 +24,9 @@ jobs: run: | sudo apt-get --assume-yes install libleveldb-dev libsnappy-dev libc6-dev find tests -name *.csproj | xargs -I % dotnet add % package coverlet.msbuild - dotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=lcov /p:CoverletOutput=${GITHUB_WORKSPACE}/coverage/lcov + dotnet test tests/Neo.Network.RPC.Tests /p:CollectCoverage=true /p:CoverletOutput=${GITHUB_WORKSPACE}/coverage/ + dotnet test tests/Neo.Plugins.Storage.Tests /p:CollectCoverage=true /p:CoverletOutput=${GITHUB_WORKSPACE}/coverage/lcov /p:MergeWith=${GITHUB_WORKSPACE}/coverage/coverage.json /p:CoverletOutputFormat=lcov + - name: Coveralls + uses: coverallsapp/github-action@master + with: + github-token: ${{ secrets.GITHUB_TOKEN }} From fa5a83c0d63670f9ffb1c7d5105c7c39a735c0ed Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Sun, 15 Dec 2019 09:39:06 +0800 Subject: [PATCH 095/183] Add RpcServer (#160) --- neo-modules.sln | 21 +- src/ApplicationLogs/ApplicationLogs.csproj | 1 + src/ApplicationLogs/LogReader.cs | 17 +- src/RpcNep5Tracker/RpcNep5Tracker.cs | 30 +- src/RpcNep5Tracker/RpcNep5Tracker.csproj | 1 + src/RpcSecurity/RpcSecurity.cs | 59 ---- src/RpcSecurity/RpcSecurity/config.json | 7 - src/RpcSecurity/Settings.cs | 26 -- src/RpcServer/RpcException.cs | 12 + src/RpcServer/RpcMethodAttribute.cs | 10 + src/RpcServer/RpcServer.Blockchain.cs | 204 ++++++++++++++ src/RpcServer/RpcServer.Node.cs | 85 ++++++ src/RpcServer/RpcServer.SmartContract.cs | 100 +++++++ src/RpcServer/RpcServer.Utilities.cs | 47 ++++ .../RpcServer.Wallet.cs} | 263 ++++++++---------- src/RpcServer/RpcServer.cs | 243 ++++++++++++++++ .../RpcServer.csproj} | 5 +- src/RpcServer/RpcServer/config.json | 14 + src/RpcServer/Settings.cs | 42 +++ src/RpcWallet/RpcWallet.csproj | 20 -- src/RpcWallet/RpcWallet/config.json | 5 - src/RpcWallet/Settings.cs | 22 -- 22 files changed, 906 insertions(+), 328 deletions(-) delete mode 100644 src/RpcSecurity/RpcSecurity.cs delete mode 100644 src/RpcSecurity/RpcSecurity/config.json delete mode 100644 src/RpcSecurity/Settings.cs create mode 100644 src/RpcServer/RpcException.cs create mode 100644 src/RpcServer/RpcMethodAttribute.cs create mode 100644 src/RpcServer/RpcServer.Blockchain.cs create mode 100644 src/RpcServer/RpcServer.Node.cs create mode 100644 src/RpcServer/RpcServer.SmartContract.cs create mode 100644 src/RpcServer/RpcServer.Utilities.cs rename src/{RpcWallet/RpcWallet.cs => RpcServer/RpcServer.Wallet.cs} (59%) create mode 100644 src/RpcServer/RpcServer.cs rename src/{RpcSecurity/RpcSecurity.csproj => RpcServer/RpcServer.csproj} (68%) create mode 100644 src/RpcServer/RpcServer/config.json create mode 100644 src/RpcServer/Settings.cs delete mode 100644 src/RpcWallet/RpcWallet.csproj delete mode 100644 src/RpcWallet/RpcWallet/config.json delete mode 100644 src/RpcWallet/Settings.cs diff --git a/neo-modules.sln b/neo-modules.sln index bd53f4dd4..1f5f32fbc 100644 --- a/neo-modules.sln +++ b/neo-modules.sln @@ -8,12 +8,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{59D802AB EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ApplicationLogs", "src\ApplicationLogs\ApplicationLogs.csproj", "{84DA8EA6-EF60-4FCD-B1C6-65C1A8323B3F}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RpcSecurity", "src\RpcSecurity\RpcSecurity.csproj", "{6800D782-8EC0-49E9-98C4-195C8F781A1F}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StatesDumper", "src\StatesDumper\StatesDumper.csproj", "{86531DB1-A231-46C4-823F-BE60972F7523}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RpcWallet", "src\RpcWallet\RpcWallet.csproj", "{EF32A7E5-EDF9-438C-8041-8DA6E675A7FD}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RpcNep5Tracker", "src\RpcNep5Tracker\RpcNep5Tracker.csproj", "{BBE8AC15-12DF-4AF0-ABC1-F1557EB5DC8E}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SystemLog", "src\SystemLog\SystemLog.csproj", "{14DB62D5-0EA1-4A98-8656-1AA2D0345206}" @@ -24,6 +20,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RocksDBStore", "src\RocksDB EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RpcClient", "src\RpcClient\RpcClient.csproj", "{8DC57A45-A192-4953-81B1-6907FB7C28D2}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RpcServer", "src\RpcServer\RpcServer.csproj", "{1403FFE9-4265-4269-8E3D-5A79EFD108CA}" +EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.Network.RPC.Tests", "tests\Neo.Network.RPC.Tests\Neo.Network.RPC.Tests.csproj", "{D52460B3-AB5C-4D07-B400-9E7ADCB01FF5}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.Plugins.Storage.Tests", "tests\Neo.Plugins.Storage.Tests\Neo.Plugins.Storage.Tests.csproj", "{9E7EA895-302A-4C0C-BA9B-54F9A67AD75C}" @@ -38,18 +36,10 @@ Global {84DA8EA6-EF60-4FCD-B1C6-65C1A8323B3F}.Debug|Any CPU.Build.0 = Debug|Any CPU {84DA8EA6-EF60-4FCD-B1C6-65C1A8323B3F}.Release|Any CPU.ActiveCfg = Release|Any CPU {84DA8EA6-EF60-4FCD-B1C6-65C1A8323B3F}.Release|Any CPU.Build.0 = Release|Any CPU - {6800D782-8EC0-49E9-98C4-195C8F781A1F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6800D782-8EC0-49E9-98C4-195C8F781A1F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6800D782-8EC0-49E9-98C4-195C8F781A1F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6800D782-8EC0-49E9-98C4-195C8F781A1F}.Release|Any CPU.Build.0 = Release|Any CPU {86531DB1-A231-46C4-823F-BE60972F7523}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {86531DB1-A231-46C4-823F-BE60972F7523}.Debug|Any CPU.Build.0 = Debug|Any CPU {86531DB1-A231-46C4-823F-BE60972F7523}.Release|Any CPU.ActiveCfg = Release|Any CPU {86531DB1-A231-46C4-823F-BE60972F7523}.Release|Any CPU.Build.0 = Release|Any CPU - {EF32A7E5-EDF9-438C-8041-8DA6E675A7FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {EF32A7E5-EDF9-438C-8041-8DA6E675A7FD}.Debug|Any CPU.Build.0 = Debug|Any CPU - {EF32A7E5-EDF9-438C-8041-8DA6E675A7FD}.Release|Any CPU.ActiveCfg = Release|Any CPU - {EF32A7E5-EDF9-438C-8041-8DA6E675A7FD}.Release|Any CPU.Build.0 = Release|Any CPU {BBE8AC15-12DF-4AF0-ABC1-F1557EB5DC8E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {BBE8AC15-12DF-4AF0-ABC1-F1557EB5DC8E}.Debug|Any CPU.Build.0 = Debug|Any CPU {BBE8AC15-12DF-4AF0-ABC1-F1557EB5DC8E}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -70,6 +60,10 @@ Global {8DC57A45-A192-4953-81B1-6907FB7C28D2}.Debug|Any CPU.Build.0 = Debug|Any CPU {8DC57A45-A192-4953-81B1-6907FB7C28D2}.Release|Any CPU.ActiveCfg = Release|Any CPU {8DC57A45-A192-4953-81B1-6907FB7C28D2}.Release|Any CPU.Build.0 = Release|Any CPU + {1403FFE9-4265-4269-8E3D-5A79EFD108CA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1403FFE9-4265-4269-8E3D-5A79EFD108CA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1403FFE9-4265-4269-8E3D-5A79EFD108CA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1403FFE9-4265-4269-8E3D-5A79EFD108CA}.Release|Any CPU.Build.0 = Release|Any CPU {D52460B3-AB5C-4D07-B400-9E7ADCB01FF5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D52460B3-AB5C-4D07-B400-9E7ADCB01FF5}.Debug|Any CPU.Build.0 = Debug|Any CPU {D52460B3-AB5C-4D07-B400-9E7ADCB01FF5}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -84,14 +78,13 @@ Global EndGlobalSection GlobalSection(NestedProjects) = preSolution {84DA8EA6-EF60-4FCD-B1C6-65C1A8323B3F} = {97E81C78-1637-481F-9485-DA1225E94C23} - {6800D782-8EC0-49E9-98C4-195C8F781A1F} = {97E81C78-1637-481F-9485-DA1225E94C23} {86531DB1-A231-46C4-823F-BE60972F7523} = {97E81C78-1637-481F-9485-DA1225E94C23} - {EF32A7E5-EDF9-438C-8041-8DA6E675A7FD} = {97E81C78-1637-481F-9485-DA1225E94C23} {BBE8AC15-12DF-4AF0-ABC1-F1557EB5DC8E} = {97E81C78-1637-481F-9485-DA1225E94C23} {14DB62D5-0EA1-4A98-8656-1AA2D0345206} = {97E81C78-1637-481F-9485-DA1225E94C23} {C66214CD-0B97-4EA5-B7A2-164F54346F19} = {97E81C78-1637-481F-9485-DA1225E94C23} {0E2AAF05-C55A-4B36-8750-F55743FBE4B3} = {97E81C78-1637-481F-9485-DA1225E94C23} {8DC57A45-A192-4953-81B1-6907FB7C28D2} = {97E81C78-1637-481F-9485-DA1225E94C23} + {1403FFE9-4265-4269-8E3D-5A79EFD108CA} = {97E81C78-1637-481F-9485-DA1225E94C23} {D52460B3-AB5C-4D07-B400-9E7ADCB01FF5} = {59D802AB-C552-422A-B9C3-64D329FBCDCC} {9E7EA895-302A-4C0C-BA9B-54F9A67AD75C} = {59D802AB-C552-422A-B9C3-64D329FBCDCC} EndGlobalSection diff --git a/src/ApplicationLogs/ApplicationLogs.csproj b/src/ApplicationLogs/ApplicationLogs.csproj index d8976e093..f545f43d3 100644 --- a/src/ApplicationLogs/ApplicationLogs.csproj +++ b/src/ApplicationLogs/ApplicationLogs.csproj @@ -15,6 +15,7 @@ + diff --git a/src/ApplicationLogs/LogReader.cs b/src/ApplicationLogs/LogReader.cs index 969094293..af577dcd3 100644 --- a/src/ApplicationLogs/LogReader.cs +++ b/src/ApplicationLogs/LogReader.cs @@ -1,9 +1,7 @@ -using Microsoft.AspNetCore.Http; using Neo.IO; using Neo.IO.Data.LevelDB; using Neo.IO.Json; using Neo.Ledger; -using Neo.Network.RPC; using Neo.Persistence; using Neo.VM; using System; @@ -14,7 +12,7 @@ namespace Neo.Plugins { - public class LogReader : Plugin, IRpcPlugin, IPersistencePlugin + public class LogReader : Plugin, IPersistencePlugin { private readonly DB db; @@ -23,6 +21,7 @@ public class LogReader : Plugin, IRpcPlugin, IPersistencePlugin public LogReader() { db = DB.Open(GetFullPath(Settings.Default.Path), new Options { CreateIfMissing = true }); + RpcServer.RegisterMethods(this); } protected override void Configure() @@ -30,13 +29,9 @@ protected override void Configure() Settings.Load(GetConfiguration()); } - public void PreProcess(HttpContext context, string method, JArray _params) + [RpcMethod] + public JObject GetApplicationLog(JArray _params) { - } - - public JObject OnProcess(HttpContext context, string method, JArray _params) - { - if (method != "getapplicationlog") return null; UInt256 hash = UInt256.Parse(_params[0].AsString()); byte[] value = db.Get(ReadOptions.Default, hash.ToArray()); if (value is null) @@ -44,10 +39,6 @@ public JObject OnProcess(HttpContext context, string method, JArray _params) return JObject.Parse(Encoding.UTF8.GetString(value)); } - public void PostProcess(HttpContext context, string method, JArray _params, JObject result) - { - } - public void OnPersist(StoreView snapshot, IReadOnlyList applicationExecutedList) { WriteBatch writeBatch = new WriteBatch(); diff --git a/src/RpcNep5Tracker/RpcNep5Tracker.cs b/src/RpcNep5Tracker/RpcNep5Tracker.cs index 183ae23b3..e89948890 100644 --- a/src/RpcNep5Tracker/RpcNep5Tracker.cs +++ b/src/RpcNep5Tracker/RpcNep5Tracker.cs @@ -5,7 +5,6 @@ using Neo.IO.Json; using Neo.Ledger; using Neo.Network.P2P.Payloads; -using Neo.Network.RPC; using Neo.Persistence; using Neo.SmartContract; using Neo.VM; @@ -18,7 +17,7 @@ namespace Neo.Plugins { - public class RpcNep5Tracker : Plugin, IPersistencePlugin, IRpcPlugin + public class RpcNep5Tracker : Plugin, IPersistencePlugin { private const byte Nep5BalancePrefix = 0xf8; private const byte Nep5TransferSentPrefix = 0xf9; @@ -33,6 +32,11 @@ public class RpcNep5Tracker : Plugin, IPersistencePlugin, IRpcPlugin private uint _maxResults; private Neo.IO.Data.LevelDB.Snapshot _levelDbSnapshot; + public RpcNep5Tracker() + { + RpcServer.RegisterMethods(this); + } + protected override void Configure() { if (_db == null) @@ -237,8 +241,11 @@ private UInt160 GetScriptHashFromParam(string addressOrScriptHash) return addressOrScriptHash.Length < 40 ? addressOrScriptHash.ToScriptHash() : UInt160.Parse(addressOrScriptHash); } - private JObject GetNep5Transfers(JArray _params) + + [RpcMethod] + public JObject GetNep5Transfers(JArray _params) { + if (!_shouldTrackHistory) throw new RpcException(-32601, "Method not found"); UInt160 userScriptHash = GetScriptHashFromParam(_params[0].AsString()); // If start time not present, default to 1 week of history. ulong startTime = _params.Count > 1 ? (ulong)_params[1].AsNumber() : @@ -258,7 +265,8 @@ private JObject GetNep5Transfers(JArray _params) return json; } - private JObject GetNep5Balances(JArray _params) + [RpcMethod] + public JObject GetNep5Balances(JArray _params) { UInt160 userScriptHash = GetScriptHashFromParam(_params[0].AsString()); @@ -278,19 +286,5 @@ private JObject GetNep5Balances(JArray _params) } return json; } - - public void PreProcess(HttpContext context, string method, JArray _params) - { - } - - public JObject OnProcess(HttpContext context, string method, JArray _params) - { - if (_shouldTrackHistory && method == "getnep5transfers") return GetNep5Transfers(_params); - return method == "getnep5balances" ? GetNep5Balances(_params) : null; - } - - public void PostProcess(HttpContext context, string method, JArray _params, JObject result) - { - } } } diff --git a/src/RpcNep5Tracker/RpcNep5Tracker.csproj b/src/RpcNep5Tracker/RpcNep5Tracker.csproj index bc700a468..059356665 100644 --- a/src/RpcNep5Tracker/RpcNep5Tracker.csproj +++ b/src/RpcNep5Tracker/RpcNep5Tracker.csproj @@ -12,5 +12,6 @@ + diff --git a/src/RpcSecurity/RpcSecurity.cs b/src/RpcSecurity/RpcSecurity.cs deleted file mode 100644 index a63f8b88c..000000000 --- a/src/RpcSecurity/RpcSecurity.cs +++ /dev/null @@ -1,59 +0,0 @@ -using Microsoft.AspNetCore.Http; -using Neo.IO.Json; -using Neo.Network.RPC; -using System; -using System.Linq; -using System.Text; - -namespace Neo.Plugins -{ - public class RpcSecurity : Plugin, IRpcPlugin - { - protected override void Configure() - { - Settings.Load(GetConfiguration()); - } - - public void PreProcess(HttpContext context, string method, JArray _params) - { - if (!CheckAuth(context) || Settings.Default.DisabledMethods.Contains(method)) - throw new RpcException(-400, "Access denied"); - } - - public JObject OnProcess(HttpContext context, string method, JArray _params) - { - return null; - } - - public void PostProcess(HttpContext context, string method, JArray _params, JObject result) - { - } - - private bool CheckAuth(HttpContext context) - { - if (string.IsNullOrEmpty(Settings.Default.RpcUser)) - { - return true; - } - - context.Response.Headers["WWW-Authenticate"] = "Basic realm=\"Restricted\""; - - string reqauth = context.Request.Headers["Authorization"]; - string authstring = null; - try - { - authstring = Encoding.UTF8.GetString(Convert.FromBase64String(reqauth.Replace("Basic ", "").Trim())); - } - catch - { - return false; - } - - string[] authvalues = authstring.Split(new string[] { ":" }, StringSplitOptions.RemoveEmptyEntries); - if (authvalues.Length < 2) - return false; - - return authvalues[0] == Settings.Default.RpcUser && authvalues[1] == Settings.Default.RpcPass; - } - } -} diff --git a/src/RpcSecurity/RpcSecurity/config.json b/src/RpcSecurity/RpcSecurity/config.json deleted file mode 100644 index 8890f20b0..000000000 --- a/src/RpcSecurity/RpcSecurity/config.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "PluginConfiguration": { - "RpcUser": "", - "RpcPass": "", - "DisabledMethods": [] - } -} diff --git a/src/RpcSecurity/Settings.cs b/src/RpcSecurity/Settings.cs deleted file mode 100644 index 4d83ff7d5..000000000 --- a/src/RpcSecurity/Settings.cs +++ /dev/null @@ -1,26 +0,0 @@ -using Microsoft.Extensions.Configuration; -using System.Linq; - -namespace Neo.Plugins -{ - internal class Settings - { - public string RpcUser { get; } - public string RpcPass { get; } - public string[] DisabledMethods { get; } - - public static Settings Default { get; private set; } - - private Settings(IConfigurationSection section) - { - this.RpcUser = section.GetSection("RpcUser").Value; - this.RpcPass = section.GetSection("RpcPass").Value; - this.DisabledMethods = section.GetSection("DisabledMethods").GetChildren().Select(p => p.Value).ToArray(); - } - - public static void Load(IConfigurationSection section) - { - Default = new Settings(section); - } - } -} diff --git a/src/RpcServer/RpcException.cs b/src/RpcServer/RpcException.cs new file mode 100644 index 000000000..dbe03c109 --- /dev/null +++ b/src/RpcServer/RpcException.cs @@ -0,0 +1,12 @@ +using System; + +namespace Neo.Plugins +{ + public class RpcException : Exception + { + public RpcException(int code, string message) : base(message) + { + HResult = code; + } + } +} diff --git a/src/RpcServer/RpcMethodAttribute.cs b/src/RpcServer/RpcMethodAttribute.cs new file mode 100644 index 000000000..f560ba555 --- /dev/null +++ b/src/RpcServer/RpcMethodAttribute.cs @@ -0,0 +1,10 @@ +using System; + +namespace Neo.Plugins +{ + [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] + public class RpcMethodAttribute : Attribute + { + public string Name { get; set; } + } +} diff --git a/src/RpcServer/RpcServer.Blockchain.cs b/src/RpcServer/RpcServer.Blockchain.cs new file mode 100644 index 000000000..2511736ca --- /dev/null +++ b/src/RpcServer/RpcServer.Blockchain.cs @@ -0,0 +1,204 @@ +#pragma warning disable IDE0051 +#pragma warning disable IDE0060 + +using Neo.IO; +using Neo.IO.Json; +using Neo.Ledger; +using Neo.Network.P2P.Payloads; +using Neo.Persistence; +using Neo.SmartContract; +using Neo.SmartContract.Native; +using Neo.VM; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Neo.Plugins +{ + partial class RpcServer + { + [RpcMethod] + private JObject GetBestBlockHash(JArray _params) + { + return Blockchain.Singleton.CurrentBlockHash.ToString(); + } + + [RpcMethod] + private JObject GetBlock(JArray _params) + { + JObject key = _params[0]; + bool verbose = _params.Count >= 2 && _params[1].AsBoolean(); + Block block; + if (key is JNumber) + { + uint index = uint.Parse(key.AsString()); + block = Blockchain.Singleton.GetBlock(index); + } + else + { + UInt256 hash = UInt256.Parse(key.AsString()); + block = Blockchain.Singleton.View.GetBlock(hash); + } + if (block == null) + throw new RpcException(-100, "Unknown block"); + if (verbose) + { + JObject json = block.ToJson(); + json["confirmations"] = Blockchain.Singleton.Height - block.Index + 1; + UInt256 hash = Blockchain.Singleton.GetNextBlockHash(block.Hash); + if (hash != null) + json["nextblockhash"] = hash.ToString(); + return json; + } + return block.ToArray().ToHexString(); + } + + [RpcMethod] + private JObject GetBlockCount(JArray _params) + { + return Blockchain.Singleton.Height + 1; + } + + [RpcMethod] + private JObject GetBlockHash(JArray _params) + { + uint height = uint.Parse(_params[0].AsString()); + if (height <= Blockchain.Singleton.Height) + { + return Blockchain.Singleton.GetBlockHash(height).ToString(); + } + throw new RpcException(-100, "Invalid Height"); + } + + [RpcMethod] + private JObject GetBlockHeader(JArray _params) + { + JObject key = _params[0]; + bool verbose = _params.Count >= 2 && _params[1].AsBoolean(); + Header header; + if (key is JNumber) + { + uint height = uint.Parse(key.AsString()); + header = Blockchain.Singleton.GetHeader(height); + } + else + { + UInt256 hash = UInt256.Parse(key.AsString()); + header = Blockchain.Singleton.View.GetHeader(hash); + } + if (header == null) + throw new RpcException(-100, "Unknown block"); + + if (verbose) + { + JObject json = header.ToJson(); + json["confirmations"] = Blockchain.Singleton.Height - header.Index + 1; + UInt256 hash = Blockchain.Singleton.GetNextBlockHash(header.Hash); + if (hash != null) + json["nextblockhash"] = hash.ToString(); + return json; + } + + return header.ToArray().ToHexString(); + } + + [RpcMethod] + private JObject GetBlockSysFee(JArray _params) + { + uint height = uint.Parse(_params[0].AsString()); + if (height <= Blockchain.Singleton.Height) + using (ApplicationEngine engine = NativeContract.GAS.TestCall("getSysFeeAmount", height)) + { + return engine.ResultStack.Peek().GetBigInteger().ToString(); + } + throw new RpcException(-100, "Invalid Height"); + } + + [RpcMethod] + private JObject GetContractState(JArray _params) + { + UInt160 script_hash = UInt160.Parse(_params[0].AsString()); + ContractState contract = Blockchain.Singleton.View.Contracts.TryGet(script_hash); + return contract?.ToJson() ?? throw new RpcException(-100, "Unknown contract"); + } + + [RpcMethod] + private JObject GetRawMemPool(JArray _params) + { + bool shouldGetUnverified = _params.Count >= 1 && _params[0].AsBoolean(); + if (!shouldGetUnverified) + return new JArray(Blockchain.Singleton.MemPool.GetVerifiedTransactions().Select(p => (JObject)p.Hash.ToString())); + + JObject json = new JObject(); + json["height"] = Blockchain.Singleton.Height; + Blockchain.Singleton.MemPool.GetVerifiedAndUnverifiedTransactions( + out IEnumerable verifiedTransactions, + out IEnumerable unverifiedTransactions); + json["verified"] = new JArray(verifiedTransactions.Select(p => (JObject)p.Hash.ToString())); + json["unverified"] = new JArray(unverifiedTransactions.Select(p => (JObject)p.Hash.ToString())); + return json; + } + + [RpcMethod] + private JObject GetRawTransaction(JArray _params) + { + UInt256 hash = UInt256.Parse(_params[0].AsString()); + bool verbose = _params.Count >= 2 && _params[1].AsBoolean(); + Transaction tx = Blockchain.Singleton.GetTransaction(hash); + if (tx == null) + throw new RpcException(-100, "Unknown transaction"); + if (verbose) + { + JObject json = tx.ToJson(); + TransactionState txState = Blockchain.Singleton.View.Transactions.TryGet(hash); + if (txState != null) + { + Header header = Blockchain.Singleton.GetHeader(txState.BlockIndex); + json["blockhash"] = header.Hash.ToString(); + json["confirmations"] = Blockchain.Singleton.Height - header.Index + 1; + json["blocktime"] = header.Timestamp; + json["vmState"] = txState.VMState; + } + return json; + } + return tx.ToArray().ToHexString(); + } + + [RpcMethod] + private JObject GetStorage(JArray _params) + { + UInt160 script_hash = UInt160.Parse(_params[0].AsString()); + byte[] key = _params[1].AsString().HexToBytes(); + StorageItem item = Blockchain.Singleton.View.Storages.TryGet(new StorageKey + { + ScriptHash = script_hash, + Key = key + }) ?? new StorageItem(); + return item.Value?.ToHexString(); + } + + [RpcMethod] + private JObject GetTransactionHeight(JArray _params) + { + UInt256 hash = UInt256.Parse(_params[0].AsString()); + uint? height = Blockchain.Singleton.View.Transactions.TryGet(hash)?.BlockIndex; + if (height.HasValue) return height.Value; + throw new RpcException(-100, "Unknown transaction"); + } + + [RpcMethod] + private JObject GetValidators(JArray _params) + { + using SnapshotView snapshot = Blockchain.Singleton.GetSnapshot(); + var validators = NativeContract.NEO.GetValidators(snapshot); + return NativeContract.NEO.GetRegisteredValidators(snapshot).Select(p => + { + JObject validator = new JObject(); + validator["publickey"] = p.PublicKey.ToString(); + validator["votes"] = p.Votes.ToString(); + validator["active"] = validators.Contains(p.PublicKey); + return validator; + }).ToArray(); + } + } +} diff --git a/src/RpcServer/RpcServer.Node.cs b/src/RpcServer/RpcServer.Node.cs new file mode 100644 index 000000000..2b1018e8d --- /dev/null +++ b/src/RpcServer/RpcServer.Node.cs @@ -0,0 +1,85 @@ +#pragma warning disable IDE0051 +#pragma warning disable IDE0060 + +using Akka.Actor; +using Neo.IO; +using Neo.IO.Json; +using Neo.Ledger; +using Neo.Network.P2P; +using Neo.Network.P2P.Payloads; +using System.Linq; + +namespace Neo.Plugins +{ + partial class RpcServer + { + [RpcMethod] + private JObject GetConnectionCount(JArray _params) + { + return LocalNode.Singleton.ConnectedCount; + } + + [RpcMethod] + private JObject GetPeers(JArray _params) + { + JObject json = new JObject(); + json["unconnected"] = new JArray(LocalNode.Singleton.GetUnconnectedPeers().Select(p => + { + JObject peerJson = new JObject(); + peerJson["address"] = p.Address.ToString(); + peerJson["port"] = p.Port; + return peerJson; + })); + json["bad"] = new JArray(); //badpeers has been removed + json["connected"] = new JArray(LocalNode.Singleton.GetRemoteNodes().Select(p => + { + JObject peerJson = new JObject(); + peerJson["address"] = p.Remote.Address.ToString(); + peerJson["port"] = p.ListenerTcpPort; + return peerJson; + })); + return json; + } + + private static JObject GetRelayResult(RelayResultReason reason, UInt256 hash) + { + if (reason == RelayResultReason.Succeed) + { + var ret = new JObject(); + ret["hash"] = hash.ToString(); + return ret; + } + else + { + throw new RpcException(-500, reason.ToString()); + } + } + + [RpcMethod] + private JObject GetVersion(JArray _params) + { + JObject json = new JObject(); + json["tcpPort"] = LocalNode.Singleton.ListenerTcpPort; + json["wsPort"] = LocalNode.Singleton.ListenerWsPort; + json["nonce"] = LocalNode.Nonce; + json["useragent"] = LocalNode.UserAgent; + return json; + } + + [RpcMethod] + private JObject SendRawTransaction(JArray _params) + { + Transaction tx = _params[0].AsString().HexToBytes().AsSerializable(); + RelayResultReason reason = System.Blockchain.Ask(tx).Result; + return GetRelayResult(reason, tx.Hash); + } + + [RpcMethod] + private JObject SubmitBlock(JArray _params) + { + Block block = _params[0].AsString().HexToBytes().AsSerializable(); + RelayResultReason reason = System.Blockchain.Ask(block).Result; + return GetRelayResult(reason, block.Hash); + } + } +} diff --git a/src/RpcServer/RpcServer.SmartContract.cs b/src/RpcServer/RpcServer.SmartContract.cs new file mode 100644 index 000000000..60069ea75 --- /dev/null +++ b/src/RpcServer/RpcServer.SmartContract.cs @@ -0,0 +1,100 @@ +#pragma warning disable IDE0051 +#pragma warning disable IDE0060 + +using Neo.IO.Json; +using Neo.Network.P2P.Payloads; +using Neo.Persistence; +using Neo.SmartContract; +using Neo.VM; +using System; +using System.IO; +using System.Linq; + +namespace Neo.Plugins +{ + partial class RpcServer + { + private class CheckWitnessHashes : IVerifiable + { + private readonly UInt160[] _scriptHashesForVerifying; + public Witness[] Witnesses { get; set; } + public int Size { get; } + + public CheckWitnessHashes(UInt160[] scriptHashesForVerifying) + { + _scriptHashesForVerifying = scriptHashesForVerifying; + } + + public void Serialize(BinaryWriter writer) + { + throw new NotImplementedException(); + } + + public void Deserialize(BinaryReader reader) + { + throw new NotImplementedException(); + } + + public void DeserializeUnsigned(BinaryReader reader) + { + throw new NotImplementedException(); + } + + public UInt160[] GetScriptHashesForVerifying(StoreView snapshot) + { + return _scriptHashesForVerifying; + } + + public void SerializeUnsigned(BinaryWriter writer) + { + throw new NotImplementedException(); + } + } + + private JObject GetInvokeResult(byte[] script, IVerifiable checkWitnessHashes = null) + { + using ApplicationEngine engine = ApplicationEngine.Run(script, checkWitnessHashes, extraGAS: Settings.Default.MaxGasInvoke); + JObject json = new JObject(); + json["script"] = script.ToHexString(); + json["state"] = engine.State; + json["gas_consumed"] = engine.GasConsumed.ToString(); + try + { + json["stack"] = new JArray(engine.ResultStack.Select(p => p.ToParameter().ToJson())); + } + catch (InvalidOperationException) + { + json["stack"] = "error: recursive reference"; + } + ProcessInvokeWithWallet(json); + return json; + } + + [RpcMethod] + private JObject InvokeFunction(JArray _params) + { + UInt160 script_hash = UInt160.Parse(_params[0].AsString()); + string operation = _params[1].AsString(); + ContractParameter[] args = _params.Count >= 3 ? ((JArray)_params[2]).Select(p => ContractParameter.FromJson(p)).ToArray() : new ContractParameter[0]; + byte[] script; + using (ScriptBuilder sb = new ScriptBuilder()) + { + script = sb.EmitAppCall(script_hash, operation, args).ToArray(); + } + return GetInvokeResult(script); + } + + [RpcMethod] + private JObject InvokeScript(JArray _params) + { + byte[] script = _params[0].AsString().HexToBytes(); + CheckWitnessHashes checkWitnessHashes = null; + if (_params.Count > 1) + { + UInt160[] scriptHashesForVerifying = _params.Skip(1).Select(u => UInt160.Parse(u.AsString())).ToArray(); + checkWitnessHashes = new CheckWitnessHashes(scriptHashesForVerifying); + } + return GetInvokeResult(script, checkWitnessHashes); + } + } +} diff --git a/src/RpcServer/RpcServer.Utilities.cs b/src/RpcServer/RpcServer.Utilities.cs new file mode 100644 index 000000000..281fa6726 --- /dev/null +++ b/src/RpcServer/RpcServer.Utilities.cs @@ -0,0 +1,47 @@ +#pragma warning disable IDE0051 +#pragma warning disable IDE0060 + +using Neo.IO.Json; +using Neo.Wallets; +using System.Linq; + +namespace Neo.Plugins +{ + partial class RpcServer + { + [RpcMethod] + private JObject ListPlugins(JArray _params) + { + return new JArray(Plugins + .OrderBy(u => u.Name) + .Select(u => new JObject + { + ["name"] = u.Name, + ["version"] = u.Version.ToString(), + ["interfaces"] = new JArray(u.GetType().GetInterfaces() + .Select(p => p.Name) + .Where(p => p.EndsWith("Plugin")) + .Select(p => (JObject)p)) + })); + } + + [RpcMethod] + private JObject ValidateAddress(JArray _params) + { + string address = _params[0].AsString(); + JObject json = new JObject(); + UInt160 scriptHash; + try + { + scriptHash = address.ToScriptHash(); + } + catch + { + scriptHash = null; + } + json["address"] = address; + json["isvalid"] = scriptHash != null; + return json; + } + } +} diff --git a/src/RpcWallet/RpcWallet.cs b/src/RpcServer/RpcServer.Wallet.cs similarity index 59% rename from src/RpcWallet/RpcWallet.cs rename to src/RpcServer/RpcServer.Wallet.cs index 12178ad10..7d183fd96 100644 --- a/src/RpcWallet/RpcWallet.cs +++ b/src/RpcServer/RpcServer.Wallet.cs @@ -1,187 +1,92 @@ +#pragma warning disable IDE0051 +#pragma warning disable IDE0060 + using Akka.Actor; -using Microsoft.AspNetCore.Http; using Neo.IO; using Neo.IO.Json; using Neo.Ledger; using Neo.Network.P2P; using Neo.Network.P2P.Payloads; -using Neo.Network.RPC; using Neo.Persistence; using Neo.SmartContract; using Neo.SmartContract.Native; using Neo.Wallets; using Neo.Wallets.NEP6; +using Neo.Wallets.SQLite; +using System; +using System.IO; using System.Linq; using System.Numerics; +using static System.IO.Path; namespace Neo.Plugins { - public class RpcWallet : Plugin, IRpcPlugin + partial class RpcServer { - private Wallet Wallet => System.RpcServer.Wallet; - - protected override void Configure() - { - Settings.Load(GetConfiguration()); - } - - public void PreProcess(HttpContext context, string method, JArray _params) - { - } - - public JObject OnProcess(HttpContext context, string method, JArray _params) - { - switch (method) - { - case "dumpprivkey": - { - UInt160 scriptHash = _params[0].AsString().ToScriptHash(); - return DumpPrivKey(scriptHash); - } - case "getbalance": - { - UInt160 asset_id = UInt160.Parse(_params[0].AsString()); - return GetBalance(asset_id); - } - case "getnewaddress": - { - return GetNewAddress(); - } - case "getunclaimedgas": - { - return GetUnclaimedGas(); - } - case "importprivkey": - { - string privkey = _params[0].AsString(); - return ImportPrivKey(privkey); - } - case "listaddress": - { - return ListAddress(); - } - case "sendfrom": - { - UInt160 assetId = UInt160.Parse(_params[0].AsString()); - UInt160 from = _params[1].AsString().ToScriptHash(); - UInt160 to = _params[2].AsString().ToScriptHash(); - string value = _params[3].AsString(); - return SendFrom(assetId, from, to, value); - } - case "sendmany": - { - int to_start = 0; - UInt160 from = null; - if (_params[0] is JString) - { - from = _params[0].AsString().ToScriptHash(); - to_start = 1; - } - JArray to = (JArray)_params[to_start]; - return SendMany(from, to); - } - case "sendtoaddress": - { - UInt160 assetId = UInt160.Parse(_params[0].AsString()); - UInt160 scriptHash = _params[1].AsString().ToScriptHash(); - string value = _params[2].AsString(); - return SendToAddress(assetId, scriptHash, value); - } - default: - return null; - } - } - - public void PostProcess(HttpContext context, string method, JArray _params, JObject result) - { - switch (method) - { - case "invoke": - case "invokefunction": - case "invokescript": - ProcessInvoke(result); - break; - } - } - - private void ProcessInvoke(JObject result) - { - if (Wallet != null) - { - Transaction tx = Wallet.MakeTransaction(result["script"].AsString().HexToBytes()); - ContractParametersContext context = new ContractParametersContext(tx); - Wallet.Sign(context); - if (context.Completed) - tx.Witnesses = context.GetWitnesses(); - else - tx = null; - result["tx"] = tx?.ToArray().ToHexString(); - } - } + private Wallet wallet; private void CheckWallet() { - if (Wallet is null) + if (wallet is null) throw new RpcException(-400, "Access denied"); } - private JObject SignAndRelay(Transaction tx) + [RpcMethod] + private JObject CloseWallet(JArray _params) { - ContractParametersContext context = new ContractParametersContext(tx); - Wallet.Sign(context); - if (context.Completed) - { - tx.Witnesses = context.GetWitnesses(); - System.LocalNode.Tell(new LocalNode.Relay { Inventory = tx }); - return tx.ToJson(); - } - else - { - return context.ToJson(); - } + wallet = null; + return true; } - private JObject DumpPrivKey(UInt160 scriptHash) + [RpcMethod] + private JObject DumpPrivKey(JArray _params) { CheckWallet(); - WalletAccount account = Wallet.GetAccount(scriptHash); + UInt160 scriptHash = _params[0].AsString().ToScriptHash(); + WalletAccount account = wallet.GetAccount(scriptHash); return account.GetKey().Export(); } - private JObject GetBalance(UInt160 asset_id) + [RpcMethod] + private JObject GetBalance(JArray _params) { CheckWallet(); + UInt160 asset_id = UInt160.Parse(_params[0].AsString()); JObject json = new JObject(); - json["balance"] = Wallet.GetAvailable(asset_id).Value.ToString(); + json["balance"] = wallet.GetAvailable(asset_id).Value.ToString(); return json; } - private JObject GetNewAddress() + [RpcMethod] + private JObject GetNewAddress(JArray _params) { CheckWallet(); - WalletAccount account = Wallet.CreateAccount(); - if (Wallet is NEP6Wallet nep6) + WalletAccount account = wallet.CreateAccount(); + if (wallet is NEP6Wallet nep6) nep6.Save(); return account.Address; } - private JObject GetUnclaimedGas() + [RpcMethod] + private JObject GetUnclaimedGas(JArray _params) { CheckWallet(); BigInteger gas = BigInteger.Zero; using (SnapshotView snapshot = Blockchain.Singleton.GetSnapshot()) - foreach (UInt160 account in Wallet.GetAccounts().Select(p => p.ScriptHash)) + foreach (UInt160 account in wallet.GetAccounts().Select(p => p.ScriptHash)) { gas += NativeContract.NEO.UnclaimedGas(snapshot, account, snapshot.Height + 1); } return gas.ToString(); } - private JObject ImportPrivKey(string privkey) + [RpcMethod] + private JObject ImportPrivKey(JArray _params) { CheckWallet(); - WalletAccount account = Wallet.Import(privkey); - if (Wallet is NEP6Wallet nep6wallet) + string privkey = _params[0].AsString(); + WalletAccount account = wallet.Import(privkey); + if (wallet is NEP6Wallet nep6wallet) nep6wallet.Save(); return new JObject { @@ -192,10 +97,11 @@ private JObject ImportPrivKey(string privkey) }; } - private JObject ListAddress() + [RpcMethod] + private JObject ListAddress(JArray _params) { CheckWallet(); - return Wallet.GetAccounts().Select(p => + return wallet.GetAccounts().Select(p => { JObject account = new JObject(); account["address"] = p.Address; @@ -206,14 +112,59 @@ private JObject ListAddress() }).ToArray(); } - private JObject SendFrom(UInt160 assetId, UInt160 from, UInt160 to, string value) + [RpcMethod] + private JObject OpenWallet(JArray _params) + { + string path = _params[0].AsString(); + string password = _params[1].AsString(); + if (!File.Exists(path)) throw new FileNotFoundException(); + switch (GetExtension(path)) + { + case ".db3": + { + wallet = UserWallet.Open(path, password); + break; + } + case ".json": + { + NEP6Wallet nep6wallet = new NEP6Wallet(path); + nep6wallet.Unlock(password); + wallet = nep6wallet; + break; + } + default: + throw new NotSupportedException(); + } + return true; + } + + private void ProcessInvokeWithWallet(JObject result) + { + if (wallet != null) + { + Transaction tx = wallet.MakeTransaction(result["script"].AsString().HexToBytes()); + ContractParametersContext context = new ContractParametersContext(tx); + wallet.Sign(context); + if (context.Completed) + tx.Witnesses = context.GetWitnesses(); + else + tx = null; + result["tx"] = tx?.ToArray().ToHexString(); + } + } + + [RpcMethod] + private JObject SendFrom(JArray _params) { CheckWallet(); + UInt160 assetId = UInt160.Parse(_params[0].AsString()); + UInt160 from = _params[1].AsString().ToScriptHash(); + UInt160 to = _params[2].AsString().ToScriptHash(); AssetDescriptor descriptor = new AssetDescriptor(assetId); - BigDecimal amount = BigDecimal.Parse(value, descriptor.Decimals); + BigDecimal amount = BigDecimal.Parse(_params[3].AsString(), descriptor.Decimals); if (amount.Sign <= 0) throw new RpcException(-32602, "Invalid params"); - Transaction tx = Wallet.MakeTransaction(new[] + Transaction tx = wallet.MakeTransaction(new[] { new TransferOutput { @@ -226,7 +177,7 @@ private JObject SendFrom(UInt160 assetId, UInt160 from, UInt160 to, string value throw new RpcException(-300, "Insufficient funds"); ContractParametersContext transContext = new ContractParametersContext(tx); - Wallet.Sign(transContext); + wallet.Sign(transContext); if (!transContext.Completed) return transContext.ToJson(); tx.Witnesses = transContext.GetWitnesses(); @@ -241,9 +192,18 @@ private JObject SendFrom(UInt160 assetId, UInt160 from, UInt160 to, string value return SignAndRelay(tx); } - private JObject SendMany(UInt160 from, JArray to) + [RpcMethod] + private JObject SendMany(JArray _params) { CheckWallet(); + int to_start = 0; + UInt160 from = null; + if (_params[0] is JString) + { + from = _params[0].AsString().ToScriptHash(); + to_start = 1; + } + JArray to = (JArray)_params[to_start]; if (to.Count == 0) throw new RpcException(-32602, "Invalid params"); TransferOutput[] outputs = new TransferOutput[to.Count]; @@ -260,12 +220,12 @@ private JObject SendMany(UInt160 from, JArray to) if (outputs[i].Value.Sign <= 0) throw new RpcException(-32602, "Invalid params"); } - Transaction tx = Wallet.MakeTransaction(outputs, from); + Transaction tx = wallet.MakeTransaction(outputs, from); if (tx == null) throw new RpcException(-300, "Insufficient funds"); ContractParametersContext transContext = new ContractParametersContext(tx); - Wallet.Sign(transContext); + wallet.Sign(transContext); if (!transContext.Completed) return transContext.ToJson(); tx.Witnesses = transContext.GetWitnesses(); @@ -280,14 +240,17 @@ private JObject SendMany(UInt160 from, JArray to) return SignAndRelay(tx); } - private JObject SendToAddress(UInt160 assetId, UInt160 scriptHash, string value) + [RpcMethod] + private JObject SendToAddress(JArray _params) { CheckWallet(); + UInt160 assetId = UInt160.Parse(_params[0].AsString()); + UInt160 scriptHash = _params[1].AsString().ToScriptHash(); AssetDescriptor descriptor = new AssetDescriptor(assetId); - BigDecimal amount = BigDecimal.Parse(value, descriptor.Decimals); + BigDecimal amount = BigDecimal.Parse(_params[2].AsString(), descriptor.Decimals); if (amount.Sign <= 0) throw new RpcException(-32602, "Invalid params"); - Transaction tx = Wallet.MakeTransaction(new[] + Transaction tx = wallet.MakeTransaction(new[] { new TransferOutput { @@ -300,7 +263,7 @@ private JObject SendToAddress(UInt160 assetId, UInt160 scriptHash, string value) throw new RpcException(-300, "Insufficient funds"); ContractParametersContext transContext = new ContractParametersContext(tx); - Wallet.Sign(transContext); + wallet.Sign(transContext); if (!transContext.Completed) return transContext.ToJson(); tx.Witnesses = transContext.GetWitnesses(); @@ -314,5 +277,21 @@ private JObject SendToAddress(UInt160 assetId, UInt160 scriptHash, string value) throw new RpcException(-301, "The necessary fee is more than the Max_fee, this transaction is failed. Please increase your Max_fee value."); return SignAndRelay(tx); } + + private JObject SignAndRelay(Transaction tx) + { + ContractParametersContext context = new ContractParametersContext(tx); + wallet.Sign(context); + if (context.Completed) + { + tx.Witnesses = context.GetWitnesses(); + System.LocalNode.Tell(new LocalNode.Relay { Inventory = tx }); + return tx.ToJson(); + } + else + { + return context.ToJson(); + } + } } } diff --git a/src/RpcServer/RpcServer.cs b/src/RpcServer/RpcServer.cs new file mode 100644 index 000000000..d263f3dac --- /dev/null +++ b/src/RpcServer/RpcServer.cs @@ -0,0 +1,243 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.ResponseCompression; +using Microsoft.AspNetCore.Server.Kestrel.Https; +using Microsoft.Extensions.DependencyInjection; +using Neo.IO; +using Neo.IO.Json; +using System; +using System.Collections.Generic; +using System.IO; +using System.IO.Compression; +using System.Linq; +using System.Net.Security; +using System.Reflection; +using System.Security.Cryptography.X509Certificates; +using System.Text; +using System.Threading.Tasks; + +namespace Neo.Plugins +{ + public sealed partial class RpcServer : Plugin + { + private static readonly Dictionary> methods = new Dictionary>(); + private IWebHost host; + + public RpcServer() + { + RegisterMethods(this); + } + + private bool CheckAuth(HttpContext context) + { + if (string.IsNullOrEmpty(Settings.Default.RpcUser)) return true; + + context.Response.Headers["WWW-Authenticate"] = "Basic realm=\"Restricted\""; + + string reqauth = context.Request.Headers["Authorization"]; + string authstring; + try + { + authstring = Encoding.UTF8.GetString(Convert.FromBase64String(reqauth.Replace("Basic ", "").Trim())); + } + catch + { + return false; + } + + string[] authvalues = authstring.Split(new string[] { ":" }, StringSplitOptions.RemoveEmptyEntries); + if (authvalues.Length < 2) + return false; + + return authvalues[0] == Settings.Default.RpcUser && authvalues[1] == Settings.Default.RpcPass; + } + + protected override void Configure() + { + Settings.Load(GetConfiguration()); + } + + private static JObject CreateErrorResponse(JObject id, int code, string message, JObject data = null) + { + JObject response = CreateResponse(id); + response["error"] = new JObject(); + response["error"]["code"] = code; + response["error"]["message"] = message; + if (data != null) + response["error"]["data"] = data; + return response; + } + + private static JObject CreateResponse(JObject id) + { + JObject response = new JObject(); + response["jsonrpc"] = "2.0"; + response["id"] = id; + return response; + } + + public override void Dispose() + { + base.Dispose(); + if (host != null) + { + host.Dispose(); + host = null; + } + } + + protected override void OnPluginsLoaded() + { + host = new WebHostBuilder().UseKestrel(options => options.Listen(Settings.Default.BindAddress, Settings.Default.Port, listenOptions => + { + if (string.IsNullOrEmpty(Settings.Default.SslCert)) return; + listenOptions.UseHttps(Settings.Default.SslCert, Settings.Default.SslCertPassword, httpsConnectionAdapterOptions => + { + if (Settings.Default.TrustedAuthorities is null || Settings.Default.TrustedAuthorities.Length == 0) + return; + httpsConnectionAdapterOptions.ClientCertificateMode = ClientCertificateMode.RequireCertificate; + httpsConnectionAdapterOptions.ClientCertificateValidation = (cert, chain, err) => + { + if (err != SslPolicyErrors.None) + return false; + X509Certificate2 authority = chain.ChainElements[chain.ChainElements.Count - 1].Certificate; + return Settings.Default.TrustedAuthorities.Contains(authority.Thumbprint); + }; + }); + })) + .Configure(app => + { + app.UseResponseCompression(); + app.Run(ProcessAsync); + }) + .ConfigureServices(services => + { + services.AddResponseCompression(options => + { + // options.EnableForHttps = false; + options.Providers.Add(); + options.MimeTypes = ResponseCompressionDefaults.MimeTypes.Append("application/json"); + }); + + services.Configure(options => + { + options.Level = CompressionLevel.Fastest; + }); + }) + .Build(); + + host.Start(); + } + + private async Task ProcessAsync(HttpContext context) + { + context.Response.Headers["Access-Control-Allow-Origin"] = "*"; + context.Response.Headers["Access-Control-Allow-Methods"] = "GET, POST"; + context.Response.Headers["Access-Control-Allow-Headers"] = "Content-Type"; + context.Response.Headers["Access-Control-Max-Age"] = "31536000"; + if (context.Request.Method != "GET" && context.Request.Method != "POST") return; + JObject request = null; + if (context.Request.Method == "GET") + { + string jsonrpc = context.Request.Query["jsonrpc"]; + string id = context.Request.Query["id"]; + string method = context.Request.Query["method"]; + string _params = context.Request.Query["params"]; + if (!string.IsNullOrEmpty(id) && !string.IsNullOrEmpty(method) && !string.IsNullOrEmpty(_params)) + { + try + { + _params = Encoding.UTF8.GetString(Convert.FromBase64String(_params)); + } + catch (FormatException) { } + request = new JObject(); + if (!string.IsNullOrEmpty(jsonrpc)) + request["jsonrpc"] = jsonrpc; + request["id"] = id; + request["method"] = method; + request["params"] = JObject.Parse(_params); + } + } + else if (context.Request.Method == "POST") + { + using StreamReader reader = new StreamReader(context.Request.Body); + try + { + request = JObject.Parse(reader.ReadToEnd()); + } + catch (FormatException) { } + } + JObject response; + if (request == null) + { + response = CreateErrorResponse(null, -32700, "Parse error"); + } + else if (request is JArray array) + { + if (array.Count == 0) + { + response = CreateErrorResponse(request["id"], -32600, "Invalid Request"); + } + else + { + response = array.Select(p => ProcessRequest(context, p)).Where(p => p != null).ToArray(); + } + } + else + { + response = ProcessRequest(context, request); + } + if (response == null || (response as JArray)?.Count == 0) return; + context.Response.ContentType = "application/json"; + await context.Response.WriteAsync(response.ToString(), Encoding.UTF8); + } + + private JObject ProcessRequest(HttpContext context, JObject request) + { + if (!request.ContainsProperty("id")) return null; + if (!request.ContainsProperty("method") || !request.ContainsProperty("params") || !(request["params"] is JArray)) + { + return CreateErrorResponse(request["id"], -32600, "Invalid Request"); + } + JObject response = CreateResponse(request["id"]); + try + { + string method = request["method"].AsString(); + if (!CheckAuth(context) || Settings.Default.DisabledMethods.Contains(method)) + throw new RpcException(-400, "Access denied"); + if (!methods.TryGetValue(method, out var func)) + throw new RpcException(-32601, "Method not found"); + response["result"] = func((JArray)request["params"]); + return response; + } + catch (FormatException) + { + return CreateErrorResponse(request["id"], -32602, "Invalid params"); + } + catch (IndexOutOfRangeException) + { + return CreateErrorResponse(request["id"], -32602, "Invalid params"); + } + catch (Exception ex) + { +#if DEBUG + return CreateErrorResponse(request["id"], ex.HResult, ex.Message, ex.StackTrace); +#else + return CreateErrorResponse(request["id"], ex.HResult, ex.Message); +#endif + } + } + + public static void RegisterMethods(object handler) + { + foreach (MethodInfo method in handler.GetType().GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) + { + RpcMethodAttribute attribute = method.GetCustomAttribute(); + if (attribute is null) continue; + string name = string.IsNullOrEmpty(attribute.Name) ? method.Name.ToLowerInvariant() : attribute.Name; + methods[name] = (Func)method.CreateDelegate(typeof(Func), handler); + } + } + } +} diff --git a/src/RpcSecurity/RpcSecurity.csproj b/src/RpcServer/RpcServer.csproj similarity index 68% rename from src/RpcSecurity/RpcSecurity.csproj rename to src/RpcServer/RpcServer.csproj index 2d5a348cf..7dc1754e0 100644 --- a/src/RpcSecurity/RpcSecurity.csproj +++ b/src/RpcServer/RpcServer.csproj @@ -7,14 +7,15 @@ - + PreserveNewest PreserveNewest - + + diff --git a/src/RpcServer/RpcServer/config.json b/src/RpcServer/RpcServer/config.json new file mode 100644 index 000000000..39d4639c0 --- /dev/null +++ b/src/RpcServer/RpcServer/config.json @@ -0,0 +1,14 @@ +{ + "PluginConfiguration": { + "BindAddress": "127.0.0.1", + "Port": 10332, + "SslCert": "", + "SslCertPassword": "", + "TrustedAuthorities": [], + "RpcUser": "", + "RpcPass": "", + "MaxGasInvoke": 10, + "MaxFee": 0.1, + "DisabledMethods": [ "openwallet" ] + } +} diff --git a/src/RpcServer/Settings.cs b/src/RpcServer/Settings.cs new file mode 100644 index 000000000..d955e48d8 --- /dev/null +++ b/src/RpcServer/Settings.cs @@ -0,0 +1,42 @@ +using Microsoft.Extensions.Configuration; +using Neo.SmartContract.Native; +using System.Linq; +using System.Net; + +namespace Neo.Plugins +{ + internal class Settings + { + public IPAddress BindAddress { get; } + public ushort Port { get; } + public string SslCert { get; } + public string SslCertPassword { get; } + public string[] TrustedAuthorities { get; } + public string RpcUser { get; } + public string RpcPass { get; } + public long MaxGasInvoke { get; } + public long MaxFee { get; } + public string[] DisabledMethods { get; } + + public static Settings Default { get; private set; } + + private Settings(IConfigurationSection section) + { + this.BindAddress = IPAddress.Parse(section.GetSection("BindAddress").Value); + this.Port = ushort.Parse(section.GetSection("Port").Value); + this.SslCert = section.GetSection("SslCert").Value; + this.SslCertPassword = section.GetSection("SslCertPassword").Value; + this.TrustedAuthorities = section.GetSection("TrustedAuthorities").GetChildren().Select(p => p.Get()).ToArray(); + this.RpcUser = section.GetSection("RpcUser").Value; + this.RpcPass = section.GetSection("RpcPass").Value; + this.MaxGasInvoke = (long)BigDecimal.Parse(section.GetValue("MaxGasInvoke", "10"), NativeContract.GAS.Decimals).Value; + this.MaxFee = (long)BigDecimal.Parse(section.GetValue("MaxFee", "0.1"), NativeContract.GAS.Decimals).Value; + this.DisabledMethods = section.GetSection("DisabledMethods").GetChildren().Select(p => p.Get()).ToArray(); + } + + public static void Load(IConfigurationSection section) + { + Default = new Settings(section); + } + } +} diff --git a/src/RpcWallet/RpcWallet.csproj b/src/RpcWallet/RpcWallet.csproj deleted file mode 100644 index e85fcc9e7..000000000 --- a/src/RpcWallet/RpcWallet.csproj +++ /dev/null @@ -1,20 +0,0 @@ - - - - 3.0.0-preview1 - netstandard2.1 - Neo.Plugins - - - - - PreserveNewest - PreserveNewest - - - - - - - - diff --git a/src/RpcWallet/RpcWallet/config.json b/src/RpcWallet/RpcWallet/config.json deleted file mode 100644 index 752d78ff9..000000000 --- a/src/RpcWallet/RpcWallet/config.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "PluginConfiguration": { - "MaxFee": 0.1 - } -} diff --git a/src/RpcWallet/Settings.cs b/src/RpcWallet/Settings.cs deleted file mode 100644 index 371032b5c..000000000 --- a/src/RpcWallet/Settings.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Microsoft.Extensions.Configuration; -using Neo.SmartContract.Native; - -namespace Neo.Plugins -{ - internal class Settings - { - public long MaxFee { get; } - - public static Settings Default { get; private set; } - - private Settings(IConfigurationSection section) - { - this.MaxFee = (long)BigDecimal.Parse(section.GetValue("MaxFee", "0.1"), NativeContract.GAS.Decimals).Value; - } - - public static void Load(IConfigurationSection section) - { - Default = new Settings(section); - } - } -} From c08ce9017ea62ef59ec69136005d40fda642537b Mon Sep 17 00:00:00 2001 From: Celia18305 <32253925+Celia18305@users.noreply.github.com> Date: Tue, 24 Dec 2019 19:20:28 +0800 Subject: [PATCH 096/183] Update README.md (#146) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 62e429ad2..5309b99a1 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ ## What is it -A set of plugins that can be used inside the NEO core library. Check [here](http://docs.neo.org/en-us/node/plugin.html) for the official documentation. +A set of plugins that can be used inside the NEO core library. Check [here](https://docs.neo.org/docs/en-us/node/cli/setup.html) for the official documentation. ## Using plugins Plugins can be used to increase functionality, as well as providing policies definitions of the network. From b3fcf1f7d9a087df5491006ce7520fa65da77c0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vitor=20Naz=C3=A1rio=20Coelho?= Date: Sat, 11 Jan 2020 19:10:48 -0300 Subject: [PATCH 097/183] Update NuGet versions of all modules (#174) * Update-package-rpc-client * Update nuget * Update Crypto.ECDsaVerify * Update TransactionManager.cs * Some fixes * Change from public to protected as in level db (#177) * Change from public to protected as in level db * Update RocksDBStore.csproj Co-authored-by: Shargon * Update neo nuget * change network fee calculation (#178) * change network fee calculation * update to CI00847 * fix fee issue * add UT for network fee * Update versions * Update src/RpcClient/TransactionManager.cs Co-authored-by: Shargon Co-authored-by: Krain Chen --- src/ApplicationLogs/ApplicationLogs.csproj | 2 +- src/LevelDBStore/LevelDBStore.csproj | 6 +- .../Plugins/Storage/RocksDBStore.cs | 2 +- src/RocksDBStore/RocksDBStore.csproj | 4 +- src/RpcClient/ContractClient.cs | 2 +- src/RpcClient/RpcClient.csproj | 4 +- src/RpcClient/TransactionManager.cs | 67 +++++++++---------- src/RpcNep5Tracker/RpcNep5Tracker.csproj | 2 +- src/RpcServer/RpcServer.csproj | 4 +- src/StatesDumper/StatesDumper.csproj | 4 +- src/SystemLog/SystemLog.csproj | 4 +- .../UT_ContractClient.cs | 2 +- tests/Neo.Network.RPC.Tests/UT_RpcClient.cs | 2 +- .../UT_TransactionManager.cs | 14 +++- 14 files changed, 62 insertions(+), 57 deletions(-) diff --git a/src/ApplicationLogs/ApplicationLogs.csproj b/src/ApplicationLogs/ApplicationLogs.csproj index f545f43d3..afef18509 100644 --- a/src/ApplicationLogs/ApplicationLogs.csproj +++ b/src/ApplicationLogs/ApplicationLogs.csproj @@ -1,7 +1,7 @@ - 3.0.0-preview1 + 3.0.0-CI00847 netstandard2.1 Neo.Plugins diff --git a/src/LevelDBStore/LevelDBStore.csproj b/src/LevelDBStore/LevelDBStore.csproj index cc598ac64..cb42ba2a1 100644 --- a/src/LevelDBStore/LevelDBStore.csproj +++ b/src/LevelDBStore/LevelDBStore.csproj @@ -1,7 +1,7 @@ - + - 3.0.0-CI00817 + 3.0.0-CI00847 netstandard2.1 Neo true @@ -15,7 +15,7 @@ - + diff --git a/src/RocksDBStore/Plugins/Storage/RocksDBStore.cs b/src/RocksDBStore/Plugins/Storage/RocksDBStore.cs index 5e8b540b7..d847da5d1 100644 --- a/src/RocksDBStore/Plugins/Storage/RocksDBStore.cs +++ b/src/RocksDBStore/Plugins/Storage/RocksDBStore.cs @@ -7,7 +7,7 @@ public class RocksDBStore : Plugin, IStoragePlugin /// /// Configure /// - public override void Configure() + protected override void Configure() { Settings.Load(GetConfiguration()); } diff --git a/src/RocksDBStore/RocksDBStore.csproj b/src/RocksDBStore/RocksDBStore.csproj index 9d07eea87..fe0df2434 100644 --- a/src/RocksDBStore/RocksDBStore.csproj +++ b/src/RocksDBStore/RocksDBStore.csproj @@ -1,7 +1,7 @@ - 3.0.0-CI00810 + 3.0.0-CI00847 netstandard2.1 Neo.Plugins.Storage @@ -14,7 +14,7 @@ - + diff --git a/src/RpcClient/ContractClient.cs b/src/RpcClient/ContractClient.cs index 45fb31d26..bf29dbb87 100644 --- a/src/RpcClient/ContractClient.cs +++ b/src/RpcClient/ContractClient.cs @@ -49,7 +49,7 @@ public Transaction CreateDeployContractTx(byte[] contractScript, ContractManifes byte[] script; using (ScriptBuilder sb = new ScriptBuilder()) { - sb.EmitSysCall(InteropService.Neo_Contract_Create, contractScript, manifest.ToString()); + sb.EmitSysCall(InteropService.Contract.Create, contractScript, manifest.ToString()); script = sb.ToArray(); } diff --git a/src/RpcClient/RpcClient.csproj b/src/RpcClient/RpcClient.csproj index 670812162..2f4aed74b 100644 --- a/src/RpcClient/RpcClient.csproj +++ b/src/RpcClient/RpcClient.csproj @@ -1,7 +1,7 @@ - 3.0.0-CI00825 + 3.0.0-CI00847 netstandard2.1 Neo.Network.RPC The Neo Project @@ -14,7 +14,7 @@ - + diff --git a/src/RpcClient/TransactionManager.cs b/src/RpcClient/TransactionManager.cs index 7841ba852..8d345f651 100644 --- a/src/RpcClient/TransactionManager.cs +++ b/src/RpcClient/TransactionManager.cs @@ -4,9 +4,9 @@ using Neo.Network.RPC.Models; using Neo.SmartContract; using Neo.SmartContract.Native; -using Neo.VM; using Neo.Wallets; using System; +using System.Linq; namespace Neo.Network.RPC { @@ -62,9 +62,9 @@ public TransactionManager MakeTransaction(byte[] script, TransactionAttribute[] Script = script, Sender = sender, ValidUntilBlock = height + Transaction.MaxValidUntilBlockIncrement, - Attributes = attributes ?? new TransactionAttribute[0], - Cosigners = cosigners ?? new Cosigner[0], - Witnesses = new Witness[0] + Attributes = attributes ?? Array.Empty(), + Cosigners = cosigners ?? Array.Empty(), + Witnesses = Array.Empty() }; // Add witness hashes parameter to pass CheckWitness @@ -84,7 +84,7 @@ public TransactionManager MakeTransaction(byte[] script, TransactionAttribute[] context = new ContractParametersContext(Tx); // set networkfee to estimate value when networkFee is 0 - Tx.NetworkFee = networkFee == 0 ? EstimateNetworkFee() : networkFee; + Tx.NetworkFee = networkFee == 0 ? CalculateNetworkFee(true) : networkFee; var gasBalance = nep5API.BalanceOf(NativeContract.GAS.Hash, sender); if (gasBalance >= Tx.SystemFee + Tx.NetworkFee) return this; @@ -92,48 +92,43 @@ public TransactionManager MakeTransaction(byte[] script, TransactionAttribute[] } /// - /// Estimate NetworkFee, assuming the witnesses are basic Signature Contract + /// Calculate NetworkFee /// - private long EstimateNetworkFee() - { - long networkFee = 0; - UInt160[] hashes = Tx.GetScriptHashesForVerifying(null); - int size = Transaction.HeaderSize + Tx.Attributes.GetVarSize() + Tx.Script.GetVarSize() + IO.Helper.GetVarSize(hashes.Length); - - // assume the hashes are single Signature - foreach (var hash in hashes) - { - size += 166; - networkFee += ApplicationEngine.OpCodePrices[OpCode.PUSHBYTES64] + ApplicationEngine.OpCodePrices[OpCode.PUSHBYTES33] + InteropService.GetPrice(InteropService.Neo_Crypto_ECDsaVerify, null); - } - - networkFee += size * policyAPI.GetFeePerByte(); - return networkFee; - } - - /// - /// Calculate NetworkFee with context items - /// - private long CalculateNetworkFee() + /// assuming the witnesses are basic Signature Contract if set to true + /// + private long CalculateNetworkFee(bool isEstimate = false) { long networkFee = 0; UInt160[] hashes = Tx.GetScriptHashesForVerifying(null); - int size = Transaction.HeaderSize + Tx.Attributes.GetVarSize() + Tx.Script.GetVarSize() + IO.Helper.GetVarSize(hashes.Length); + int size = Transaction.HeaderSize + Tx.Attributes.GetVarSize() + Tx.Cosigners.GetVarSize() + Tx.Script.GetVarSize() + IO.Helper.GetVarSize(hashes.Length); foreach (UInt160 hash in hashes) { - byte[] witness_script = context.GetScript(hash); - if (witness_script is null || witness_script.Length == 0) + byte[] witness_script = null; + if (isEstimate) { - try + // assuming the witnesses are basic Signature Contract + var dummyKey = new byte[32]; + dummyKey[31] = 0x01; + KeyPair one = new KeyPair(dummyKey); + witness_script = Contract.CreateSignatureRedeemScript(one.PublicKey); + } + else + { + // calculate NetworkFee with context items + witness_script = context.GetScript(hash); + if (witness_script is null || witness_script.Length == 0) { - witness_script = rpcClient.GetContractState(hash.ToString())?.Script; + try + { + witness_script = rpcClient.GetContractState(hash.ToString())?.Script; + } + catch { } } - catch { } - } - if (witness_script is null) continue; + if (witness_script is null) continue; + } - networkFee += Wallet.CalculateNetWorkFee(witness_script, ref size); + networkFee += Wallet.CalculateNetworkFee(witness_script, ref size); } networkFee += size * policyAPI.GetFeePerByte(); return networkFee; diff --git a/src/RpcNep5Tracker/RpcNep5Tracker.csproj b/src/RpcNep5Tracker/RpcNep5Tracker.csproj index 059356665..840a5c92a 100644 --- a/src/RpcNep5Tracker/RpcNep5Tracker.csproj +++ b/src/RpcNep5Tracker/RpcNep5Tracker.csproj @@ -1,6 +1,6 @@ - 3.0.0-preview1 + 3.0.0-CI00847 netstandard2.1 Neo.Plugins diff --git a/src/RpcServer/RpcServer.csproj b/src/RpcServer/RpcServer.csproj index 7dc1754e0..336da6aa9 100644 --- a/src/RpcServer/RpcServer.csproj +++ b/src/RpcServer/RpcServer.csproj @@ -1,7 +1,7 @@ - 3.0.0-preview1 + 3.0.0-CI00847 netstandard2.1 Neo.Plugins @@ -15,7 +15,7 @@ - + diff --git a/src/StatesDumper/StatesDumper.csproj b/src/StatesDumper/StatesDumper.csproj index 192acce64..2131895e8 100644 --- a/src/StatesDumper/StatesDumper.csproj +++ b/src/StatesDumper/StatesDumper.csproj @@ -1,7 +1,7 @@ - 3.0.0-preview1 + 3.0.0-CI00847 netstandard2.1 Neo.Plugins @@ -14,7 +14,7 @@ - + diff --git a/src/SystemLog/SystemLog.csproj b/src/SystemLog/SystemLog.csproj index fccf50cab..707a8c145 100644 --- a/src/SystemLog/SystemLog.csproj +++ b/src/SystemLog/SystemLog.csproj @@ -1,7 +1,7 @@ - 3.0.0-preview1 + 3.0.0-CI00847 netstandard2.1 Neo.Plugins @@ -14,7 +14,7 @@ - + diff --git a/tests/Neo.Network.RPC.Tests/UT_ContractClient.cs b/tests/Neo.Network.RPC.Tests/UT_ContractClient.cs index 0fb19faa5..f6fde1567 100644 --- a/tests/Neo.Network.RPC.Tests/UT_ContractClient.cs +++ b/tests/Neo.Network.RPC.Tests/UT_ContractClient.cs @@ -43,7 +43,7 @@ public void TestDeployContract() manifest.Features = ContractFeatures.HasStorage | ContractFeatures.Payable; using (ScriptBuilder sb = new ScriptBuilder()) { - sb.EmitSysCall(InteropService.Neo_Contract_Create, new byte[1], manifest.ToString()); + sb.EmitSysCall(InteropService.Contract.Create, new byte[1], manifest.ToString()); script = sb.ToArray(); } diff --git a/tests/Neo.Network.RPC.Tests/UT_RpcClient.cs b/tests/Neo.Network.RPC.Tests/UT_RpcClient.cs index 1ced6b077..b6ccbad17 100644 --- a/tests/Neo.Network.RPC.Tests/UT_RpcClient.cs +++ b/tests/Neo.Network.RPC.Tests/UT_RpcClient.cs @@ -230,7 +230,7 @@ public void TestGetContractState() byte[] script; using (var sb = new ScriptBuilder()) { - sb.EmitSysCall(InteropService.System_Runtime_GetInvocationCounter); + sb.EmitSysCall(InteropService.Runtime.GetInvocationCounter); script = sb.ToArray(); } diff --git a/tests/Neo.Network.RPC.Tests/UT_TransactionManager.cs b/tests/Neo.Network.RPC.Tests/UT_TransactionManager.cs index 45814d259..56925ff58 100644 --- a/tests/Neo.Network.RPC.Tests/UT_TransactionManager.cs +++ b/tests/Neo.Network.RPC.Tests/UT_TransactionManager.cs @@ -112,16 +112,26 @@ public void TestSign() } }; + Cosigner[] cosigners = new Cosigner[1] { + new Cosigner{ + Account = sender, + Scopes = WitnessScope.Global + } + }; + byte[] script = new byte[1]; - txManager.MakeTransaction(script, attributes) + txManager.MakeTransaction(script, attributes, cosigners) .AddSignature(keyPair1) .Sign(); // get signature from Witnesses var tx = txManager.Tx; - byte[] signature = tx.Witnesses[0].InvocationScript.Skip(1).ToArray(); + byte[] signature = tx.Witnesses[0].InvocationScript.Skip(2).ToArray(); Assert.IsTrue(Crypto.VerifySignature(tx.GetHashData(), signature, keyPair1.PublicKey.EncodePoint(false).Skip(1).ToArray())); + // verify network fee + long networkFee = tx.Size * (long)1000 + ApplicationEngine.OpCodePrices[OpCode.PUSHDATA1] + ApplicationEngine.OpCodePrices[OpCode.PUSHDATA1] + ApplicationEngine.OpCodePrices[OpCode.PUSHNULL] + InteropService.GetPrice(InteropService.Crypto.ECDsaVerify, null); + Assert.AreEqual(networkFee, tx.NetworkFee); // duplicate sign should not add new witness txManager.AddSignature(keyPair1).Sign(); From ef91c522f13ef30bc6308a2e343a4c3466bb3885 Mon Sep 17 00:00:00 2001 From: Shargon Date: Wed, 15 Jan 2020 10:19:32 +0100 Subject: [PATCH 098/183] Rpc limits (3x) (#172) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add some limits to rpc * Updating to peer and comments * Allow to configure MaxConcurrentConnections * Enter Co-authored-by: Vitor Nazário Coelho --- src/RpcServer/RpcServer.cs | 7 +++++++ src/RpcServer/RpcServer/config.json | 1 + src/RpcServer/Settings.cs | 2 ++ 3 files changed, 10 insertions(+) diff --git a/src/RpcServer/RpcServer.cs b/src/RpcServer/RpcServer.cs index d263f3dac..ee027543e 100644 --- a/src/RpcServer/RpcServer.cs +++ b/src/RpcServer/RpcServer.cs @@ -91,6 +91,13 @@ protected override void OnPluginsLoaded() { host = new WebHostBuilder().UseKestrel(options => options.Listen(Settings.Default.BindAddress, Settings.Default.Port, listenOptions => { + // Default value is unlimited + options.Limits.MaxConcurrentConnections = Settings.Default.MaxConcurrentConnections; + // Default value is 2 minutes + options.Limits.KeepAliveTimeout = TimeSpan.FromMinutes(1); + // Default value is 30 seconds + options.Limits.RequestHeadersTimeout = TimeSpan.FromSeconds(15); + if (string.IsNullOrEmpty(Settings.Default.SslCert)) return; listenOptions.UseHttps(Settings.Default.SslCert, Settings.Default.SslCertPassword, httpsConnectionAdapterOptions => { diff --git a/src/RpcServer/RpcServer/config.json b/src/RpcServer/RpcServer/config.json index 39d4639c0..d51daac31 100644 --- a/src/RpcServer/RpcServer/config.json +++ b/src/RpcServer/RpcServer/config.json @@ -9,6 +9,7 @@ "RpcPass": "", "MaxGasInvoke": 10, "MaxFee": 0.1, + "MaxConcurrentConnections": 40, "DisabledMethods": [ "openwallet" ] } } diff --git a/src/RpcServer/Settings.cs b/src/RpcServer/Settings.cs index d955e48d8..1b6a6acd6 100644 --- a/src/RpcServer/Settings.cs +++ b/src/RpcServer/Settings.cs @@ -17,6 +17,7 @@ internal class Settings public long MaxGasInvoke { get; } public long MaxFee { get; } public string[] DisabledMethods { get; } + public int MaxConcurrentConnections { get; } public static Settings Default { get; private set; } @@ -32,6 +33,7 @@ private Settings(IConfigurationSection section) this.MaxGasInvoke = (long)BigDecimal.Parse(section.GetValue("MaxGasInvoke", "10"), NativeContract.GAS.Decimals).Value; this.MaxFee = (long)BigDecimal.Parse(section.GetValue("MaxFee", "0.1"), NativeContract.GAS.Decimals).Value; this.DisabledMethods = section.GetSection("DisabledMethods").GetChildren().Select(p => p.Get()).ToArray(); + this.MaxConcurrentConnections = section.GetValue("MaxConcurrentConnections", 40); } public static void Load(IConfigurationSection section) From febc7f57b8306a01785efc0a143279dd15e85ffb Mon Sep 17 00:00:00 2001 From: cn1010 <1062108372@qq.com> Date: Wed, 22 Jan 2020 15:20:12 +0800 Subject: [PATCH 099/183] update readme (#169) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * update readme * more details for rpc-related plugins * desc for plugin dependency * add logo * Improvement Improvement * Delete --log Delete --log * Format Format * Minor changes * Adding note about NEP5 functionalities * Updating with RpcServer * Fix Fix * Format Format * Remove StorageEngine Remove StorageEngine Co-authored-by: Owen Zhang <38493437+superboyiii@users.noreply.github.com> Co-authored-by: Vitor Nazário Coelho Co-authored-by: Shargon --- README.md | 85 ++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 56 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index 5309b99a1..bb73063d3 100644 --- a/README.md +++ b/README.md @@ -1,49 +1,76 @@ +

+ + neo-logo + +

+ +

+ + Current TravisCI build status. + + + License + + + Current neo-modules version. + +

+ ## What is it -A set of plugins that can be used inside the NEO core library. Check [here](https://docs.neo.org/docs/en-us/node/cli/setup.html) for the official documentation. -## Using plugins +A set of plugins/modules that can be used inside the NEO core library is available in this repository. You can refer to [the official documentation](https://docs.neo.org/docs/en-us/node/cli/setup.html) for the more detailed usage guide. + +In addition, a C# SDK module is included for developers to call RPC methods with ease. + +## Using Plugins Plugins can be used to increase functionality, as well as providing policies definitions of the network. One common example is to add the ApplicationLogs plugin in order to enable your node to create log files. -To configure a plugin, do the following: - - Download the desired plugin from the [Releases page](https://github.com/neo-project/neo-plugins/releases) - - Alternative: Compile from source - - Clone this repository; - - Open it in Visual Studio, select the plugin you want to enable and select `publish` \(compile it using Release configuration\) - - Create the Plugins folder in neo-cli / neo-gui (where the binary is run from, like `/neo-cli/bin/debug/netcoreapp2.1/Plugins`) - - Copy the .dll and the folder with the configuration files into this Plugin folder. - - Start neo using additional parameters, if required; - - In order to start logging, start neo with the `--log` option. +To configure a plugin, you can directly download the desired plugin from the [Releases page](https://github.com/neo-project/neo-modules/releases). + +Alternatively, you can compile from source code by following the below steps: +- Clone this repository; +- Open it in Visual Studio, select the plugin you want to enable and select `publish` \(compile it using Release configuration\) +- Create the Plugins folder in neo-cli / neo-gui (where the binary file is located, such as `/neo-cli/bin/Release/netcoreapp3.0/Plugins`) +- Copy the .dll and the folder with the configuration files into the `Plugins` folder. + - Remarkably, you should put the dependency of the plugin in the `Plugins` folder as well. For example, since the `RpcServer` has the package reference on the `Microsoft.AspNetCore.ResponseCompression`, so the corresponding dll file should be put together with the plugin. The resulting folder structure is going to be like this: -```BASH +```sh ./neo-cli.dll ./Plugins/ApplicationLogs.dll ./Plugins/ApplicationsLogs/config.json ``` -## Existing plugins -### Application Logs -Add this plugin to your application if need to access the log files. This can be useful to handle notifications, but remember that this also largely increases the space used by the application. +## Plugins/Modules -### Core Metrics -Metrics from the Blockchain. This can involve reports through RPC calls or other form of persisting. +### ApplicationLogs +Add this plugin to your application if need to access the log files. This can be useful to handle notifications, but remember that this also largely increases the space used by the application. `LevelDBStore` and `RpcServer` are also needed for this plugin. You can find more details [here](https://docs.neo.org/docs/en-us/reference/rpc/latest-version/api/getapplicationlog.html). -### Import Blocks -Synchronizes the client using offline packages. Follow the instructions [here](http://docs.neo.org/en-us/network/syncblocks.html) to bootstrap your network using this plugin. +### SystemLog +Enable neo-cli Logging with timestamps by showing messages with different levels (shown with different colors) \(useful for debugging\). -### RPC NEP5 Tracker -Plugin that enables NEP5 tracking using LevelDB. +### StatesDumper +Exports neo-cli status data \(useful for debugging\), such as storage modifications block by block. -### RPC Security -Improves security in RPC nodes. +### LevelDBStore +If there is no further modification of the configuration file of the neo-node, it is the default storage engine in the NEO system. In this case, you should paste the `LevelDBStore` in the Plugins before launching the node. -### RPC Wallet -Client commands for wallet management functionalities, such as signing and invoking. +### RocksDBStore +You can also use `RocksDBStore` in the NEO system by modifying the default storage engine section in the configuration file. -### StatesDumper -Exports NEO-CLI status data \(useful for debugging\). +### RpcServer +Plugin for hosting a RpcServer on the neo-node, being able to disable specific calls. -### SystemLog -Enables neo-cli Logging, with timestamps, by showing messages with different levels (differentiated by colors) \(useful for debugging\). +### RpcNep5Tracker +Plugin that enables NEP5 tracking using LevelDB. +This module works in conjunction with RpcServer, otherwise, just local storage (on leveldb) would be created. + +## C# SDK + +### RpcClient +The RpcClient Plugin is an individual SDK which is used to call NEO RPC methods for development using. +In order to use the module for interacting with NEP5 functionalities `RPC NEP5 Tracker` Plugin will be needed. From 7769261cbcb44ab1065116e63453e8794f87f2c8 Mon Sep 17 00:00:00 2001 From: Shargon Date: Tue, 11 Feb 2020 09:05:18 +0100 Subject: [PATCH 100/183] dotnet-format (#185) * Fix * Fix * Add dotnet format version * Fix version * Update main.yml * Update main.yml * Update main.yml --- .github/workflows/main.yml | 2 +- .gitignore | 660 ++++++++++----------- LICENSE | 42 +- NuGet.Config | 14 +- src/ApplicationLogs/Settings.cs | 2 +- src/LevelDBStore/Plugins/Storage/Helper.cs | 2 +- src/RpcNep5Tracker/DbCache.cs | 2 +- src/StatesDumper/PersistActions.cs | 2 +- src/StatesDumper/Settings.cs | 2 +- 9 files changed, 364 insertions(+), 364 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 12e09452f..0c57bda8d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -18,7 +18,7 @@ jobs: dotnet-version: ${{ env.DOTNET_VERSION }} - name: Check format run: | - dotnet tool install --tool-path ./ dotnet-format + dotnet tool install --version 3.2.111002 --tool-path ./ dotnet-format --add-source https://dotnet.myget.org/F/format/api/v3/index.json ./dotnet-format --check --dry-run -v diagnostic - name: Test run: | diff --git a/.gitignore b/.gitignore index 3e759b75b..29c559f83 100644 --- a/.gitignore +++ b/.gitignore @@ -1,330 +1,330 @@ -## Ignore Visual Studio temporary files, build results, and -## files generated by popular Visual Studio add-ons. -## -## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore - -# User-specific files -*.suo -*.user -*.userosscache -*.sln.docstates - -# User-specific files (MonoDevelop/Xamarin Studio) -*.userprefs - -# Build results -[Dd]ebug/ -[Dd]ebugPublic/ -[Rr]elease/ -[Rr]eleases/ -x64/ -x86/ -bld/ -[Bb]in/ -[Oo]bj/ -[Ll]og/ - -# Visual Studio 2015/2017 cache/options directory -.vs/ -# Uncomment if you have tasks that create the project's static files in wwwroot -#wwwroot/ - -# Visual Studio 2017 auto generated files -Generated\ Files/ - -# MSTest test Results -[Tt]est[Rr]esult*/ -[Bb]uild[Ll]og.* - -# NUNIT -*.VisualState.xml -TestResult.xml - -# Build Results of an ATL Project -[Dd]ebugPS/ -[Rr]eleasePS/ -dlldata.c - -# Benchmark Results -BenchmarkDotNet.Artifacts/ - -# .NET Core -project.lock.json -project.fragment.lock.json -artifacts/ -**/Properties/launchSettings.json - -# StyleCop -StyleCopReport.xml - -# Files built by Visual Studio -*_i.c -*_p.c -*_i.h -*.ilk -*.meta -*.obj -*.iobj -*.pch -*.pdb -*.ipdb -*.pgc -*.pgd -*.rsp -*.sbr -*.tlb -*.tli -*.tlh -*.tmp -*.tmp_proj -*.log -*.vspscc -*.vssscc -.builds -*.pidb -*.svclog -*.scc - -# Chutzpah Test files -_Chutzpah* - -# Visual C++ cache files -ipch/ -*.aps -*.ncb -*.opendb -*.opensdf -*.sdf -*.cachefile -*.VC.db -*.VC.VC.opendb - -# Visual Studio profiler -*.psess -*.vsp -*.vspx -*.sap - -# Visual Studio Trace Files -*.e2e - -# TFS 2012 Local Workspace -$tf/ - -# Guidance Automation Toolkit -*.gpState - -# ReSharper is a .NET coding add-in -_ReSharper*/ -*.[Rr]e[Ss]harper -*.DotSettings.user - -# JustCode is a .NET coding add-in -.JustCode - -# TeamCity is a build add-in -_TeamCity* - -# DotCover is a Code Coverage Tool -*.dotCover - -# AxoCover is a Code Coverage Tool -.axoCover/* -!.axoCover/settings.json - -# Visual Studio code coverage results -*.coverage -*.coveragexml - -# NCrunch -_NCrunch_* -.*crunch*.local.xml -nCrunchTemp_* - -# MightyMoose -*.mm.* -AutoTest.Net/ - -# Web workbench (sass) -.sass-cache/ - -# Installshield output folder -[Ee]xpress/ - -# DocProject is a documentation generator add-in -DocProject/buildhelp/ -DocProject/Help/*.HxT -DocProject/Help/*.HxC -DocProject/Help/*.hhc -DocProject/Help/*.hhk -DocProject/Help/*.hhp -DocProject/Help/Html2 -DocProject/Help/html - -# Click-Once directory -publish/ - -# Publish Web Output -*.[Pp]ublish.xml -*.azurePubxml -# Note: Comment the next line if you want to checkin your web deploy settings, -# but database connection strings (with potential passwords) will be unencrypted -*.pubxml -*.publishproj - -# Microsoft Azure Web App publish settings. Comment the next line if you want to -# checkin your Azure Web App publish settings, but sensitive information contained -# in these scripts will be unencrypted -PublishScripts/ - -# NuGet Packages -*.nupkg -# The packages folder can be ignored because of Package Restore -**/[Pp]ackages/* -# except build/, which is used as an MSBuild target. -!**/[Pp]ackages/build/ -# Uncomment if necessary however generally it will be regenerated when needed -#!**/[Pp]ackages/repositories.config -# NuGet v3's project.json files produces more ignorable files -*.nuget.props -*.nuget.targets - -# Microsoft Azure Build Output -csx/ -*.build.csdef - -# Microsoft Azure Emulator -ecf/ -rcf/ - -# Windows Store app package directories and files -AppPackages/ -BundleArtifacts/ -Package.StoreAssociation.xml -_pkginfo.txt -*.appx - -# Visual Studio cache files -# files ending in .cache can be ignored -*.[Cc]ache -# but keep track of directories ending in .cache -!*.[Cc]ache/ - -# Others -ClientBin/ -~$* -*~ -*.dbmdl -*.dbproj.schemaview -*.jfm -*.pfx -*.publishsettings -orleans.codegen.cs - -# Including strong name files can present a security risk -# (https://github.com/github/gitignore/pull/2483#issue-259490424) -#*.snk - -# Since there are multiple workflows, uncomment next line to ignore bower_components -# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) -#bower_components/ - -# RIA/Silverlight projects -Generated_Code/ - -# Backup & report files from converting an old project file -# to a newer Visual Studio version. Backup files are not needed, -# because we have git ;-) -_UpgradeReport_Files/ -Backup*/ -UpgradeLog*.XML -UpgradeLog*.htm -ServiceFabricBackup/ -*.rptproj.bak - -# SQL Server files -*.mdf -*.ldf -*.ndf - -# Business Intelligence projects -*.rdl.data -*.bim.layout -*.bim_*.settings -*.rptproj.rsuser - -# Microsoft Fakes -FakesAssemblies/ - -# GhostDoc plugin setting file -*.GhostDoc.xml - -# Node.js Tools for Visual Studio -.ntvs_analysis.dat -node_modules/ - -# Visual Studio 6 build log -*.plg - -# Visual Studio 6 workspace options file -*.opt - -# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) -*.vbw - -# Visual Studio LightSwitch build output -**/*.HTMLClient/GeneratedArtifacts -**/*.DesktopClient/GeneratedArtifacts -**/*.DesktopClient/ModelManifest.xml -**/*.Server/GeneratedArtifacts -**/*.Server/ModelManifest.xml -_Pvt_Extensions - -# Paket dependency manager -.paket/paket.exe -paket-files/ - -# FAKE - F# Make -.fake/ - -# JetBrains Rider -.idea/ -*.sln.iml - -# CodeRush -.cr/ - -# Python Tools for Visual Studio (PTVS) -__pycache__/ -*.pyc - -# Cake - Uncomment if you are using it -# tools/** -# !tools/packages.config - -# Tabs Studio -*.tss - -# Telerik's JustMock configuration file -*.jmconfig - -# BizTalk build output -*.btp.cs -*.btm.cs -*.odx.cs -*.xsd.cs - -# OpenCover UI analysis results -OpenCover/ - -# Azure Stream Analytics local run output -ASALocalRun/ - -# MSBuild Binary and Structured Log -*.binlog - -# NVidia Nsight GPU debugger configuration file -*.nvuser - -# MFractors (Xamarin productivity tool) working folder -.mfractor/ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ +**/Properties/launchSettings.json + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ diff --git a/LICENSE b/LICENSE index 914d5c70d..93691646b 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,21 @@ -MIT License - -Copyright (c) 2018 The Neo Project - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +MIT License + +Copyright (c) 2018 The Neo Project + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/NuGet.Config b/NuGet.Config index 640fd0fe3..5b8642861 100644 --- a/NuGet.Config +++ b/NuGet.Config @@ -1,8 +1,8 @@ - - - - - - - + + + + + + + \ No newline at end of file diff --git a/src/ApplicationLogs/Settings.cs b/src/ApplicationLogs/Settings.cs index 82a501e90..f178992b5 100644 --- a/src/ApplicationLogs/Settings.cs +++ b/src/ApplicationLogs/Settings.cs @@ -1,4 +1,4 @@ -using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Configuration; namespace Neo.Plugins { diff --git a/src/LevelDBStore/Plugins/Storage/Helper.cs b/src/LevelDBStore/Plugins/Storage/Helper.cs index dbb1271f0..ff54faebe 100644 --- a/src/LevelDBStore/Plugins/Storage/Helper.cs +++ b/src/LevelDBStore/Plugins/Storage/Helper.cs @@ -1,4 +1,4 @@ -using System; +using System; namespace Neo.Plugins.Storage { diff --git a/src/RpcNep5Tracker/DbCache.cs b/src/RpcNep5Tracker/DbCache.cs index 8c07630a2..681b6404a 100644 --- a/src/RpcNep5Tracker/DbCache.cs +++ b/src/RpcNep5Tracker/DbCache.cs @@ -1,4 +1,4 @@ -using Neo.IO; +using Neo.IO; using Neo.IO.Caching; using Neo.IO.Data.LevelDB; using System; diff --git a/src/StatesDumper/PersistActions.cs b/src/StatesDumper/PersistActions.cs index b7016ab8e..2359e9a1a 100644 --- a/src/StatesDumper/PersistActions.cs +++ b/src/StatesDumper/PersistActions.cs @@ -1,4 +1,4 @@ -using System; +using System; namespace Neo.Plugins { diff --git a/src/StatesDumper/Settings.cs b/src/StatesDumper/Settings.cs index a1fa53d16..17600eea7 100644 --- a/src/StatesDumper/Settings.cs +++ b/src/StatesDumper/Settings.cs @@ -1,4 +1,4 @@ -using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Configuration; using System; namespace Neo.Plugins From 3bab3e103107f80bdd6ef74fc68c3228fbf7fc20 Mon Sep 17 00:00:00 2001 From: Owen Zhang <38493437+superboyiii@users.noreply.github.com> Date: Tue, 11 Feb 2020 19:31:24 +0800 Subject: [PATCH 101/183] Fix RpcServer[GetStorage] (#183) * Fix RpcServer.Blockchain.cs[GetStorage], using id to be key. * Accept id and hash Co-authored-by: Shargon --- src/RpcServer/RpcServer.Blockchain.cs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/RpcServer/RpcServer.Blockchain.cs b/src/RpcServer/RpcServer.Blockchain.cs index 2511736ca..c689757cc 100644 --- a/src/RpcServer/RpcServer.Blockchain.cs +++ b/src/RpcServer/RpcServer.Blockchain.cs @@ -167,11 +167,17 @@ private JObject GetRawTransaction(JArray _params) [RpcMethod] private JObject GetStorage(JArray _params) { - UInt160 script_hash = UInt160.Parse(_params[0].AsString()); + if (!int.TryParse(_params[0].AsString(), out int id)) + { + UInt160 script_hash = UInt160.Parse(_params[0].AsString()); + ContractState contract = Blockchain.Singleton.View.Contracts.TryGet(script_hash); + if (contract == null) return null; + id = contract.Id; + } byte[] key = _params[1].AsString().HexToBytes(); StorageItem item = Blockchain.Singleton.View.Storages.TryGet(new StorageKey { - ScriptHash = script_hash, + Id = id, Key = key }) ?? new StorageItem(); return item.Value?.ToHexString(); From 9c28decce49c28192a5ccded574e0b964e2cf0a3 Mon Sep 17 00:00:00 2001 From: Owen Zhang <38493437+superboyiii@users.noreply.github.com> Date: Wed, 19 Feb 2020 14:19:36 +0800 Subject: [PATCH 102/183] Update Neo nuget to 3.0.0-CI00855 (#186) * Update Neo nuget to 3.0.0-CI00855 * update update --- src/LevelDBStore/LevelDBStore.csproj | 2 +- src/RocksDBStore/RocksDBStore.csproj | 2 +- src/RpcServer/RpcServer.csproj | 2 +- src/StatesDumper/StatesDumper.csproj | 2 +- src/SystemLog/SystemLog.csproj | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/LevelDBStore/LevelDBStore.csproj b/src/LevelDBStore/LevelDBStore.csproj index cb42ba2a1..4df986e1a 100644 --- a/src/LevelDBStore/LevelDBStore.csproj +++ b/src/LevelDBStore/LevelDBStore.csproj @@ -15,7 +15,7 @@ - +
diff --git a/src/RocksDBStore/RocksDBStore.csproj b/src/RocksDBStore/RocksDBStore.csproj index fe0df2434..fd9eaaada 100644 --- a/src/RocksDBStore/RocksDBStore.csproj +++ b/src/RocksDBStore/RocksDBStore.csproj @@ -14,7 +14,7 @@ - + diff --git a/src/RpcServer/RpcServer.csproj b/src/RpcServer/RpcServer.csproj index 336da6aa9..4b571e502 100644 --- a/src/RpcServer/RpcServer.csproj +++ b/src/RpcServer/RpcServer.csproj @@ -15,7 +15,7 @@ - +
diff --git a/src/StatesDumper/StatesDumper.csproj b/src/StatesDumper/StatesDumper.csproj index 2131895e8..b9c4144ec 100644 --- a/src/StatesDumper/StatesDumper.csproj +++ b/src/StatesDumper/StatesDumper.csproj @@ -14,7 +14,7 @@ - +
diff --git a/src/SystemLog/SystemLog.csproj b/src/SystemLog/SystemLog.csproj index 707a8c145..952373bc1 100644 --- a/src/SystemLog/SystemLog.csproj +++ b/src/SystemLog/SystemLog.csproj @@ -14,7 +14,7 @@ - +
From 862cc79464d871e407b837e98eceee62aba8a41c Mon Sep 17 00:00:00 2001 From: cn1010 <1062108372@qq.com> Date: Wed, 11 Mar 2020 17:04:20 +0800 Subject: [PATCH 103/183] fix balance not change for non-transfer tx (#181) * fix balance not change for non-transfer tx * deal with gas burn seperately * remove conversion to null * check stackitem null * Fix IsNull * Remove nullable * Use constant * PR correction * modify check statement * bug ifix * send stackitem.null * not tracker non-tx transfer history * format * format * add check for invalid address Co-authored-by: Shargon --- src/RpcNep5Tracker/RpcNep5Tracker.cs | 35 +++++++++++++++++----------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/src/RpcNep5Tracker/RpcNep5Tracker.cs b/src/RpcNep5Tracker/RpcNep5Tracker.cs index e89948890..d94ab0d60 100644 --- a/src/RpcNep5Tracker/RpcNep5Tracker.cs +++ b/src/RpcNep5Tracker/RpcNep5Tracker.cs @@ -7,6 +7,7 @@ using Neo.Network.P2P.Payloads; using Neo.Persistence; using Neo.SmartContract; +using Neo.SmartContract.Native; using Neo.VM; using Neo.Wallets; using System; @@ -30,7 +31,7 @@ public class RpcNep5Tracker : Plugin, IPersistencePlugin private bool _shouldTrackHistory; private bool _recordNullAddressHistory; private uint _maxResults; - private Neo.IO.Data.LevelDB.Snapshot _levelDbSnapshot; + private Snapshot _levelDbSnapshot; public RpcNep5Tracker() { @@ -97,7 +98,7 @@ private void RecordTransferHistory(StoreView snapshot, UInt160 scriptHash, UInt1 transferIndex++; } - private void HandleNotification(StoreView snapshot, Transaction transaction, UInt160 scriptHash, + private void HandleNotification(StoreView snapshot, IVerifiable scriptContainer, UInt160 scriptHash, VM.Types.Array stateItems, Dictionary nep5BalancesChanged, ref ushort transferIndex) { @@ -108,33 +109,40 @@ private void HandleNotification(StoreView snapshot, Transaction transaction, UIn if (eventName != "Transfer") return; if (stateItems.Count < 4) return; - if (!(stateItems[1] is null) && !(stateItems[1] is VM.Types.ByteArray)) + if (!(stateItems[1].IsNull) && !(stateItems[1] is VM.Types.ByteArray)) return; - if (!(stateItems[2] is null) && !(stateItems[2] is VM.Types.ByteArray)) + if (!(stateItems[2].IsNull) && !(stateItems[2] is VM.Types.ByteArray)) return; var amountItem = stateItems[3]; if (!(amountItem is VM.Types.ByteArray || amountItem is VM.Types.Integer)) return; - byte[] fromBytes = stateItems[1]?.GetSpan().ToArray(); - if (fromBytes?.Length != 20) fromBytes = null; - byte[] toBytes = stateItems[2]?.GetSpan().ToArray(); - if (toBytes?.Length != 20) toBytes = null; + byte[] fromBytes = stateItems[1].IsNull ? null : stateItems[1].GetSpan().ToArray(); + if (fromBytes != null && fromBytes.Length != UInt160.Length) + return; + byte[] toBytes = stateItems[2].IsNull ? null : stateItems[2].GetSpan().ToArray(); + if (toBytes != null && toBytes.Length != UInt160.Length) + return; if (fromBytes == null && toBytes == null) return; - var from = new UInt160(fromBytes); - var to = new UInt160(toBytes); + var from = UInt160.Zero; + var to = UInt160.Zero; if (fromBytes != null) { + from = new UInt160(fromBytes); var fromKey = new Nep5BalanceKey(from, scriptHash); if (!nep5BalancesChanged.ContainsKey(fromKey)) nep5BalancesChanged.Add(fromKey, new Nep5Balance()); } if (toBytes != null) { + to = new UInt160(toBytes); var toKey = new Nep5BalanceKey(to, scriptHash); if (!nep5BalancesChanged.ContainsKey(toKey)) nep5BalancesChanged.Add(toKey, new Nep5Balance()); } - RecordTransferHistory(snapshot, scriptHash, from, to, amountItem.GetBigInteger(), transaction.Hash, ref transferIndex); + if (scriptContainer is Transaction transaction) + { + RecordTransferHistory(snapshot, scriptHash, from, to, amountItem.GetBigInteger(), transaction.Hash, ref transferIndex); + } } public void OnPersist(StoreView snapshot, IReadOnlyList applicationExecutedList) @@ -150,10 +158,9 @@ public void OnPersist(StoreView snapshot, IReadOnlyList Date: Thu, 19 Mar 2020 15:58:57 +0800 Subject: [PATCH 104/183] adapt RpcClient to modules (#171) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * adapt RpcClient to modules * fix json issue * fix size calculate * Fix getnep5balances name issue * add wallet rpc methods, reconstruct rpc UT * PR correction * move models to rpc server * delete models from rpcclient * change plugins with model * format names * move models back to rpc client * fix build error * change test file * auto calculate network fee, update version * format code * fix issue #1416 Deal with ContractParameterType.Any * change GetStorage parameter to enable id query * add test for issue #1416 * PR correction * use snake_case in json * update neo version * Update src/RpcClient/RpcClient.cs Co-Authored-By: Shargon * Update src/RpcClient/RpcClient.cs Co-Authored-By: Shargon * PR correction * update neo version Co-authored-by: Vitor Nazário Coelho Co-authored-by: Nicole <43694095+nicolegys@users.noreply.github.com> Co-authored-by: Shargon --- README.md | 4 +- src/LevelDBStore/LevelDBStore.csproj | 4 +- src/RocksDBStore/RocksDBStore.csproj | 4 +- src/RpcClient/ContractClient.cs | 5 +- src/RpcClient/Models/RpcAccount.cs | 37 + src/RpcClient/Models/RpcApplicationLog.cs | 71 + src/RpcClient/Models/RpcBlock.cs | 14 +- src/RpcClient/Models/RpcBlockHeader.cs | 14 +- src/RpcClient/Models/RpcContractState.cs | 26 + src/RpcClient/Models/RpcInvokeResult.cs | 25 +- src/RpcClient/Models/RpcNep5Balances.cs | 29 +- src/RpcClient/Models/RpcNep5TokenInfo.cs | 2 +- src/RpcClient/Models/RpcNep5Transfers.cs | 81 ++ src/RpcClient/Models/RpcRawMemPool.cs | 13 +- src/RpcClient/Models/RpcRequest.cs | 10 +- src/RpcClient/Models/RpcResponse.cs | 12 +- src/RpcClient/Models/RpcTransaction.cs | 12 +- src/RpcClient/Models/RpcTransferOut.cs | 34 + src/RpcClient/Models/RpcVersion.cs | 16 +- src/RpcClient/Nep5API.cs | 11 +- src/RpcClient/RpcClient.cs | 283 +++- src/RpcClient/RpcClient.csproj | 4 +- src/RpcClient/TransactionManager.cs | 102 +- src/RpcClient/Utility.cs | 4 +- src/RpcClient/WalletAPI.cs | 25 +- src/RpcServer/RpcServer.Blockchain.cs | 2 +- src/RpcServer/RpcServer.Node.cs | 6 +- src/RpcServer/RpcServer.csproj | 4 +- src/StatesDumper/StatesDumper.csproj | 4 +- src/SystemLog/SystemLog.csproj | 4 +- .../Models/UT_RpcBlock.cs | 24 - .../Models/UT_RpcBlockHeader.cs | 24 - .../Models/UT_RpcNep5Balance.cs | 66 - .../Models/UT_RpcNep5Balances.cs | 66 - .../Models/UT_RpcPeer.cs | 23 - .../Models/UT_RpcPeers.cs | 44 - .../Models/UT_RpcRawMemPool.cs | 29 - .../Models/UT_RpcRequest.cs | 31 - .../Models/UT_RpcResponse.cs | 34 - .../Models/UT_RpcVersion.cs | 27 - .../Neo.Network.RPC.Tests.csproj | 6 + tests/Neo.Network.RPC.Tests/RpcTestCases.json | 1279 +++++++++++++++++ tests/Neo.Network.RPC.Tests/TestUtils.cs | 34 + tests/Neo.Network.RPC.Tests/UT_Nep5API.cs | 2 +- tests/Neo.Network.RPC.Tests/UT_RpcClient.cs | 612 ++++---- tests/Neo.Network.RPC.Tests/UT_RpcModels.cs | 139 ++ .../UT_TransactionManager.cs | 17 +- tests/Neo.Network.RPC.Tests/UT_Utility.cs | 2 +- tests/Neo.Network.RPC.Tests/UT_WalletAPI.cs | 13 +- 49 files changed, 2382 insertions(+), 952 deletions(-) create mode 100644 src/RpcClient/Models/RpcAccount.cs create mode 100644 src/RpcClient/Models/RpcApplicationLog.cs create mode 100644 src/RpcClient/Models/RpcContractState.cs create mode 100644 src/RpcClient/Models/RpcNep5Transfers.cs create mode 100644 src/RpcClient/Models/RpcTransferOut.cs delete mode 100644 tests/Neo.Network.RPC.Tests/Models/UT_RpcBlock.cs delete mode 100644 tests/Neo.Network.RPC.Tests/Models/UT_RpcBlockHeader.cs delete mode 100644 tests/Neo.Network.RPC.Tests/Models/UT_RpcNep5Balance.cs delete mode 100644 tests/Neo.Network.RPC.Tests/Models/UT_RpcNep5Balances.cs delete mode 100644 tests/Neo.Network.RPC.Tests/Models/UT_RpcPeer.cs delete mode 100644 tests/Neo.Network.RPC.Tests/Models/UT_RpcPeers.cs delete mode 100644 tests/Neo.Network.RPC.Tests/Models/UT_RpcRawMemPool.cs delete mode 100644 tests/Neo.Network.RPC.Tests/Models/UT_RpcRequest.cs delete mode 100644 tests/Neo.Network.RPC.Tests/Models/UT_RpcResponse.cs delete mode 100644 tests/Neo.Network.RPC.Tests/Models/UT_RpcVersion.cs create mode 100644 tests/Neo.Network.RPC.Tests/RpcTestCases.json create mode 100644 tests/Neo.Network.RPC.Tests/UT_RpcModels.cs diff --git a/README.md b/README.md index bb73063d3..4712b5be2 100644 --- a/README.md +++ b/README.md @@ -72,5 +72,5 @@ This module works in conjunction with RpcServer, otherwise, just local storage ( ## C# SDK ### RpcClient -The RpcClient Plugin is an individual SDK which is used to call NEO RPC methods for development using. -In order to use the module for interacting with NEP5 functionalities `RPC NEP5 Tracker` Plugin will be needed. +The RpcClient Project is an individual SDK that is used to interact with NEO blockchain through NEO RPC methods for development using. The main functions include RPC calling, Transaction making, Contract deployment & calling, and Asset transfering. +It needs a NEO node with the `RpcServer` plugin as a provider. And the provider needs more plugins like `RpcNep5Tracker` and `ApplicationLogs` if you want to call RPC methods supplied by the plugins. diff --git a/src/LevelDBStore/LevelDBStore.csproj b/src/LevelDBStore/LevelDBStore.csproj index 4df986e1a..1fadbf184 100644 --- a/src/LevelDBStore/LevelDBStore.csproj +++ b/src/LevelDBStore/LevelDBStore.csproj @@ -1,7 +1,7 @@ - 3.0.0-CI00847 + 3.0.0-CI00863 netstandard2.1 Neo true @@ -15,7 +15,7 @@ - + diff --git a/src/RocksDBStore/RocksDBStore.csproj b/src/RocksDBStore/RocksDBStore.csproj index fd9eaaada..26249747a 100644 --- a/src/RocksDBStore/RocksDBStore.csproj +++ b/src/RocksDBStore/RocksDBStore.csproj @@ -1,7 +1,7 @@ - 3.0.0-CI00847 + 3.0.0-CI00863 netstandard2.1 Neo.Plugins.Storage @@ -14,7 +14,7 @@ - + diff --git a/src/RpcClient/ContractClient.cs b/src/RpcClient/ContractClient.cs index bf29dbb87..c00b799e0 100644 --- a/src/RpcClient/ContractClient.cs +++ b/src/RpcClient/ContractClient.cs @@ -42,9 +42,8 @@ public RpcInvokeResult TestInvoke(UInt160 scriptHash, string operation, params o /// contract script /// contract manifest /// sender KeyPair - /// transaction NetworkFee, set to be 0 if you don't need higher priority /// - public Transaction CreateDeployContractTx(byte[] contractScript, ContractManifest manifest, KeyPair key, long networkFee = 0) + public Transaction CreateDeployContractTx(byte[] contractScript, ContractManifest manifest, KeyPair key) { byte[] script; using (ScriptBuilder sb = new ScriptBuilder()) @@ -55,7 +54,7 @@ public Transaction CreateDeployContractTx(byte[] contractScript, ContractManifes UInt160 sender = Contract.CreateSignatureRedeemScript(key.PublicKey).ToScriptHash(); Transaction tx = new TransactionManager(rpcClient, sender) - .MakeTransaction(script, null, null, networkFee) + .MakeTransaction(script, null, null) .AddSignature(key) .Sign() .Tx; diff --git a/src/RpcClient/Models/RpcAccount.cs b/src/RpcClient/Models/RpcAccount.cs new file mode 100644 index 000000000..8a4d78922 --- /dev/null +++ b/src/RpcClient/Models/RpcAccount.cs @@ -0,0 +1,37 @@ +using Neo.IO.Json; + +namespace Neo.Network.RPC.Models +{ + public class RpcAccount + { + public string Address { get; set; } + + public bool HasKey { get; set; } + + public string Label { get; set; } + + public bool WatchOnly { get; set; } + + public JObject ToJson() + { + return new JObject + { + ["address"] = Address, + ["haskey"] = HasKey, + ["label"] = Label, + ["watchonly"] = WatchOnly + }; + } + + public static RpcAccount FromJson(JObject json) + { + return new RpcAccount + { + Address = json["address"].AsString(), + HasKey = json["haskey"].AsBoolean(), + Label = json["label"]?.AsString(), + WatchOnly = json["watchonly"].AsBoolean(), + }; + } + } +} diff --git a/src/RpcClient/Models/RpcApplicationLog.cs b/src/RpcClient/Models/RpcApplicationLog.cs new file mode 100644 index 000000000..2b17a9dc9 --- /dev/null +++ b/src/RpcClient/Models/RpcApplicationLog.cs @@ -0,0 +1,71 @@ +using Neo.IO.Json; +using Neo.SmartContract; +using Neo.VM; +using System.Collections.Generic; +using System.Linq; + +namespace Neo.Network.RPC.Models +{ + public class RpcApplicationLog + { + public UInt256 TxId { get; set; } + + public TriggerType Trigger { get; set; } + + public VMState VMState { get; set; } + + public long GasConsumed { get; set; } + + public List Stack { get; set; } + + public List Notifications { get; set; } + + public JObject ToJson() + { + JObject json = new JObject(); + json["txid"] = TxId?.ToString(); + json["trigger"] = Trigger; + json["vmstate"] = VMState; + json["gas_consumed"] = GasConsumed.ToString(); + json["stack"] = Stack.Select(q => q.ToJson()).ToArray(); + json["notifications"] = Notifications.Select(q => q.ToJson()).ToArray(); + return json; + } + + public static RpcApplicationLog FromJson(JObject json) + { + RpcApplicationLog log = new RpcApplicationLog(); + log.TxId = json["txid"] is null ? null : UInt256.Parse(json["txid"].AsString()); + log.Trigger = json["trigger"].TryGetEnum(); + log.VMState = json["vmstate"].TryGetEnum(); + log.GasConsumed = long.Parse(json["gas_consumed"].AsString()); + log.Stack = ((JArray)json["stack"]).Select(p => ContractParameter.FromJson(p)).ToList(); + log.Notifications = ((JArray)json["notifications"]).Select(p => RpcNotifyEventArgs.FromJson(p)).ToList(); + return log; + } + } + + public class RpcNotifyEventArgs + { + public UInt160 Contract { get; set; } + + public ContractParameter State { get; set; } + + public JObject ToJson() + { + JObject json = new JObject(); + json["contract"] = Contract.ToString(); + json["state"] = State.ToJson(); + return json; + } + + public static RpcNotifyEventArgs FromJson(JObject json) + { + return new RpcNotifyEventArgs + { + Contract = UInt160.Parse(json["contract"].AsString()), + State = ContractParameter.FromJson(json["state"]) + }; + } + } +} diff --git a/src/RpcClient/Models/RpcBlock.cs b/src/RpcClient/Models/RpcBlock.cs index 1ff485f96..6689572e5 100644 --- a/src/RpcClient/Models/RpcBlock.cs +++ b/src/RpcClient/Models/RpcBlock.cs @@ -7,7 +7,7 @@ public class RpcBlock { public Block Block { get; set; } - public int Confirmations { get; set; } + public uint Confirmations { get; set; } public UInt256 NextBlockHash { get; set; } @@ -15,10 +15,7 @@ public JObject ToJson() { JObject json = Block.ToJson(); json["confirmations"] = Confirmations; - if (NextBlockHash != null) - { - json["nextblockhash"] = NextBlockHash.ToString(); - } + json["nextblockhash"] = NextBlockHash?.ToString(); return json; } @@ -26,11 +23,8 @@ public static RpcBlock FromJson(JObject json) { RpcBlock block = new RpcBlock(); block.Block = Block.FromJson(json); - block.Confirmations = (int)json["confirmations"].AsNumber(); - if (json["nextblockhash"] != null) - { - block.NextBlockHash = UInt256.Parse(json["nextblockhash"].AsString()); - } + block.Confirmations = (uint)json["confirmations"].AsNumber(); + block.NextBlockHash = json["nextblockhash"] is null ? null : UInt256.Parse(json["nextblockhash"].AsString()); return block; } } diff --git a/src/RpcClient/Models/RpcBlockHeader.cs b/src/RpcClient/Models/RpcBlockHeader.cs index 5346dffd9..94def029f 100644 --- a/src/RpcClient/Models/RpcBlockHeader.cs +++ b/src/RpcClient/Models/RpcBlockHeader.cs @@ -7,7 +7,7 @@ public class RpcBlockHeader { public Header Header { get; set; } - public int Confirmations { get; set; } + public uint Confirmations { get; set; } public UInt256 NextBlockHash { get; set; } @@ -15,10 +15,7 @@ public JObject ToJson() { JObject json = Header.ToJson(); json["confirmations"] = Confirmations; - if (NextBlockHash != null) - { - json["nextblockhash"] = NextBlockHash.ToString(); - } + json["nextblockhash"] = NextBlockHash?.ToString(); return json; } @@ -26,11 +23,8 @@ public static RpcBlockHeader FromJson(JObject json) { RpcBlockHeader block = new RpcBlockHeader(); block.Header = Header.FromJson(json); - block.Confirmations = (int)json["confirmations"].AsNumber(); - if (json["nextblockhash"] != null) - { - block.NextBlockHash = UInt256.Parse(json["nextblockhash"].AsString()); - } + block.Confirmations = (uint)json["confirmations"].AsNumber(); + block.NextBlockHash = json["nextblockhash"] is null ? null : UInt256.Parse(json["nextblockhash"].AsString()); return block; } } diff --git a/src/RpcClient/Models/RpcContractState.cs b/src/RpcClient/Models/RpcContractState.cs new file mode 100644 index 000000000..b87351884 --- /dev/null +++ b/src/RpcClient/Models/RpcContractState.cs @@ -0,0 +1,26 @@ +using Neo.IO.Json; +using Neo.Ledger; +using Neo.SmartContract.Manifest; +using System; + +public class RpcContractState +{ + public ContractState ContractState { get; set; } + + public JObject ToJson() + { + return ContractState.ToJson(); + } + + public static RpcContractState FromJson(JObject json) + { + RpcContractState state = new RpcContractState(); + state.ContractState = new ContractState + { + Id = (int)json["id"].AsNumber(), + Script = Convert.FromBase64String(json["script"].AsString()), + Manifest = ContractManifest.FromJson(json["manifest"]) + }; + return state; + } +} diff --git a/src/RpcClient/Models/RpcInvokeResult.cs b/src/RpcClient/Models/RpcInvokeResult.cs index a9c5f04c4..c58c0afe4 100644 --- a/src/RpcClient/Models/RpcInvokeResult.cs +++ b/src/RpcClient/Models/RpcInvokeResult.cs @@ -1,5 +1,6 @@ using Neo.IO.Json; using Neo.SmartContract; +using System; using System.Linq; namespace Neo.Network.RPC.Models @@ -8,19 +9,30 @@ public class RpcInvokeResult { public string Script { get; set; } - public string State { get; set; } + public VM.VMState State { get; set; } public string GasConsumed { get; set; } public ContractParameter[] Stack { get; set; } + public string Tx { get; set; } + public JObject ToJson() { JObject json = new JObject(); json["script"] = Script; json["state"] = State; json["gas_consumed"] = GasConsumed; - json["stack"] = new JArray(Stack.Select(p => p.ToJson())); + try + { + json["stack"] = new JArray(Stack.Select(p => p.ToJson())); + } + catch (InvalidOperationException) + { + // ContractParameter.ToJson() may cause InvalidOperationException + json["stack"] = "error: recursive reference"; + } + if (!string.IsNullOrEmpty(Tx)) json["tx"] = Tx; return json; } @@ -28,9 +40,14 @@ public static RpcInvokeResult FromJson(JObject json) { RpcInvokeResult invokeScriptResult = new RpcInvokeResult(); invokeScriptResult.Script = json["script"].AsString(); - invokeScriptResult.State = json["state"].AsString(); + invokeScriptResult.State = json["state"].TryGetEnum(); invokeScriptResult.GasConsumed = json["gas_consumed"].AsString(); - invokeScriptResult.Stack = ((JArray)json["stack"]).Select(p => ContractParameter.FromJson(p)).ToArray(); + try + { + invokeScriptResult.Stack = ((JArray)json["stack"]).Select(p => ContractParameter.FromJson(p)).ToArray(); + } + catch { } + invokeScriptResult.Tx = json["tx"]?.AsString(); return invokeScriptResult; } } diff --git a/src/RpcClient/Models/RpcNep5Balances.cs b/src/RpcClient/Models/RpcNep5Balances.cs index 74fe7be72..0b8f79c17 100644 --- a/src/RpcClient/Models/RpcNep5Balances.cs +++ b/src/RpcClient/Models/RpcNep5Balances.cs @@ -1,4 +1,6 @@ using Neo.IO.Json; +using Neo.Wallets; +using System.Collections.Generic; using System.Linq; using System.Numerics; @@ -6,24 +8,25 @@ namespace Neo.Network.RPC.Models { public class RpcNep5Balances { - public string Address { get; set; } + public UInt160 UserScriptHash { get; set; } - public RpcNep5Balance[] Balances { get; set; } + public List Balances { get; set; } public JObject ToJson() { JObject json = new JObject(); - json["address"] = Address; json["balance"] = Balances.Select(p => p.ToJson()).ToArray(); + json["address"] = UserScriptHash.ToAddress(); return json; } public static RpcNep5Balances FromJson(JObject json) { - RpcNep5Balances nep5Balance = new RpcNep5Balances(); - nep5Balance.Address = json["address"].AsString(); - //List listBalance = new List(); - nep5Balance.Balances = ((JArray)json["balance"]).Select(p => RpcNep5Balance.FromJson(p)).ToArray(); + RpcNep5Balances nep5Balance = new RpcNep5Balances + { + Balances = ((JArray)json["balance"]).Select(p => RpcNep5Balance.FromJson(p)).ToList(), + UserScriptHash = json["address"].AsString().ToScriptHash() + }; return nep5Balance; } } @@ -41,16 +44,18 @@ public JObject ToJson() JObject json = new JObject(); json["asset_hash"] = AssetHash.ToString(); json["amount"] = Amount.ToString(); - json["last_updated_block"] = LastUpdatedBlock.ToString(); + json["last_updated_block"] = LastUpdatedBlock; return json; } public static RpcNep5Balance FromJson(JObject json) { - RpcNep5Balance balance = new RpcNep5Balance(); - balance.AssetHash = UInt160.Parse(json["asset_hash"].AsString()); - balance.Amount = BigInteger.Parse(json["amount"].AsString()); - balance.LastUpdatedBlock = uint.Parse(json["last_updated_block"].AsString()); + RpcNep5Balance balance = new RpcNep5Balance + { + AssetHash = UInt160.Parse(json["asset_hash"].AsString()), + Amount = BigInteger.Parse(json["amount"].AsString()), + LastUpdatedBlock = (uint)json["last_updated_block"].AsNumber() + }; return balance; } } diff --git a/src/RpcClient/Models/RpcNep5TokenInfo.cs b/src/RpcClient/Models/RpcNep5TokenInfo.cs index 0f251a5a3..cb609b8a9 100644 --- a/src/RpcClient/Models/RpcNep5TokenInfo.cs +++ b/src/RpcClient/Models/RpcNep5TokenInfo.cs @@ -8,7 +8,7 @@ public class RpcNep5TokenInfo public string Symbol { get; set; } - public uint Decimals { get; set; } + public byte Decimals { get; set; } public BigInteger TotalSupply { get; set; } } diff --git a/src/RpcClient/Models/RpcNep5Transfers.cs b/src/RpcClient/Models/RpcNep5Transfers.cs new file mode 100644 index 000000000..f44180554 --- /dev/null +++ b/src/RpcClient/Models/RpcNep5Transfers.cs @@ -0,0 +1,81 @@ +using Neo.IO.Json; +using Neo.SmartContract; +using Neo.Wallets; +using System.Collections.Generic; +using System.Linq; +using System.Numerics; + +namespace Neo.Network.RPC.Models +{ + public class RpcNep5Transfers + { + public UInt160 UserScriptHash { get; set; } + + public List Sent { get; set; } + + public List Received { get; set; } + + public JObject ToJson() + { + JObject json = new JObject(); + json["sent"] = Sent.Select(p => p.ToJson()).ToArray(); + json["received"] = Received.Select(p => p.ToJson()).ToArray(); + json["address"] = UserScriptHash.ToAddress(); + return json; + } + + public static RpcNep5Transfers FromJson(JObject json) + { + RpcNep5Transfers transfers = new RpcNep5Transfers + { + Sent = ((JArray)json["sent"]).Select(p => RpcNep5Transfer.FromJson(p)).ToList(), + Received = ((JArray)json["received"]).Select(p => RpcNep5Transfer.FromJson(p)).ToList(), + UserScriptHash = json["address"].AsString().ToScriptHash() + }; + return transfers; + } + } + + public class RpcNep5Transfer + { + public ulong TimestampMS { get; set; } + + public UInt160 AssetHash { get; set; } + + public UInt160 UserScriptHash { get; set; } + + public BigInteger Amount { get; set; } + + public uint BlockIndex { get; set; } + + public ushort TransferNotifyIndex { get; set; } + + public UInt256 TxHash { get; set; } + + public JObject ToJson() + { + JObject json = new JObject(); + json["timestamp"] = TimestampMS; + json["asset_hash"] = AssetHash.ToString(); + json["transfer_address"] = UserScriptHash.ToAddress(); + json["amount"] = Amount.ToString(); + json["block_index"] = BlockIndex; + json["transfer_notify_index"] = TransferNotifyIndex; + json["tx_hash"] = TxHash.ToString(); + return json; + } + + public static RpcNep5Transfer FromJson(JObject json) + { + RpcNep5Transfer transfer = new RpcNep5Transfer(); + transfer.TimestampMS = (ulong)json["timestamp"].AsNumber(); + transfer.AssetHash = UInt160.Parse(json["asset_hash"].AsString()); + transfer.UserScriptHash = json["transfer_address"].AsString().ToScriptHash(); + transfer.Amount = BigInteger.Parse(json["amount"].AsString()); + transfer.BlockIndex = (uint)json["block_index"].AsNumber(); + transfer.TransferNotifyIndex = (ushort)json["transfer_notify_index"].AsNumber(); + transfer.TxHash = UInt256.Parse(json["tx_hash"].AsString()); + return transfer; + } + } +} diff --git a/src/RpcClient/Models/RpcRawMemPool.cs b/src/RpcClient/Models/RpcRawMemPool.cs index c5ebd6341..61d8bcf99 100644 --- a/src/RpcClient/Models/RpcRawMemPool.cs +++ b/src/RpcClient/Models/RpcRawMemPool.cs @@ -1,4 +1,5 @@ using Neo.IO.Json; +using System.Collections.Generic; using System.Linq; namespace Neo.Network.RPC.Models @@ -7,16 +8,16 @@ public class RpcRawMemPool { public uint Height { get; set; } - public string[] Verified { get; set; } + public List Verified { get; set; } - public string[] UnVerified { get; set; } + public List UnVerified { get; set; } public JObject ToJson() { JObject json = new JObject(); json["height"] = Height; - json["verified"] = new JArray(Verified.Select(p => (JObject)p)); - json["unverified"] = new JArray(UnVerified.Select(p => (JObject)p)); + json["verified"] = new JArray(Verified.Select(p => (JObject)p.ToString())); + json["unverified"] = new JArray(UnVerified.Select(p => (JObject)p.ToString())); return json; } @@ -24,8 +25,8 @@ public static RpcRawMemPool FromJson(JObject json) { RpcRawMemPool rawMemPool = new RpcRawMemPool(); rawMemPool.Height = uint.Parse(json["height"].AsString()); - rawMemPool.Verified = ((JArray)json["verified"]).Select(p => p.AsString()).ToArray(); - rawMemPool.UnVerified = ((JArray)json["unverified"]).Select(p => p.AsString()).ToArray(); + rawMemPool.Verified = ((JArray)json["verified"]).Select(p => UInt256.Parse(p.AsString())).ToList(); + rawMemPool.UnVerified = ((JArray)json["unverified"]).Select(p => UInt256.Parse(p.AsString())).ToList(); return rawMemPool; } } diff --git a/src/RpcClient/Models/RpcRequest.cs b/src/RpcClient/Models/RpcRequest.cs index 1970adedb..6165e97f6 100644 --- a/src/RpcClient/Models/RpcRequest.cs +++ b/src/RpcClient/Models/RpcRequest.cs @@ -5,9 +5,9 @@ namespace Neo.Network.RPC.Models { public class RpcRequest { - public int Id { get; set; } + public JObject Id { get; set; } - public string Jsonrpc { get; set; } + public string JsonRpc { get; set; } public string Method { get; set; } @@ -17,8 +17,8 @@ public static RpcRequest FromJson(JObject json) { return new RpcRequest { - Id = (int)json["id"].AsNumber(), - Jsonrpc = json["jsonrpc"].AsString(), + Id = json["id"], + JsonRpc = json["jsonrpc"].AsString(), Method = json["method"].AsString(), Params = ((JArray)json["params"]).ToArray() }; @@ -28,7 +28,7 @@ public JObject ToJson() { var json = new JObject(); json["id"] = Id; - json["jsonrpc"] = Jsonrpc; + json["jsonrpc"] = JsonRpc; json["method"] = Method; json["params"] = new JArray(Params); return json; diff --git a/src/RpcClient/Models/RpcResponse.cs b/src/RpcClient/Models/RpcResponse.cs index e4ebcaed1..e8a62af14 100644 --- a/src/RpcClient/Models/RpcResponse.cs +++ b/src/RpcClient/Models/RpcResponse.cs @@ -4,9 +4,9 @@ namespace Neo.Network.RPC.Models { public class RpcResponse { - public int? Id { get; set; } + public JObject Id { get; set; } - public string Jsonrpc { get; set; } + public string JsonRpc { get; set; } public RpcResponseError Error { get; set; } @@ -18,8 +18,8 @@ public static RpcResponse FromJson(JObject json) { var response = new RpcResponse { - Id = (int?)json["id"]?.AsNumber(), - Jsonrpc = json["jsonrpc"].AsString(), + Id = json["id"], + JsonRpc = json["jsonrpc"].AsString(), Result = json["result"] }; @@ -35,8 +35,8 @@ public JObject ToJson() { var json = new JObject(); json["id"] = Id; - json["jsonrpc"] = Jsonrpc; - json["error"] = Error.ToJson(); + json["jsonrpc"] = JsonRpc; + json["error"] = Error?.ToJson(); json["result"] = Result; return json; } diff --git a/src/RpcClient/Models/RpcTransaction.cs b/src/RpcClient/Models/RpcTransaction.cs index 48b1e19bd..6b5a0743c 100644 --- a/src/RpcClient/Models/RpcTransaction.cs +++ b/src/RpcClient/Models/RpcTransaction.cs @@ -10,9 +10,9 @@ public class RpcTransaction public UInt256 BlockHash { get; set; } - public int? Confirmations { get; set; } + public uint? Confirmations { get; set; } - public uint? BlockTime { get; set; } + public ulong? BlockTime { get; set; } public VMState? VMState { get; set; } @@ -26,7 +26,7 @@ public JObject ToJson() json["blocktime"] = BlockTime; if (VMState != null) { - json["vmState"] = VMState; + json["vm_state"] = VMState; } } return json; @@ -39,9 +39,9 @@ public static RpcTransaction FromJson(JObject json) if (json["confirmations"] != null) { transaction.BlockHash = UInt256.Parse(json["blockhash"].AsString()); - transaction.Confirmations = (int)json["confirmations"].AsNumber(); - transaction.BlockTime = (uint)json["blocktime"].AsNumber(); - transaction.VMState = json["vmState"]?.TryGetEnum(); + transaction.Confirmations = (uint)json["confirmations"].AsNumber(); + transaction.BlockTime = (ulong)json["blocktime"].AsNumber(); + transaction.VMState = json["vm_state"]?.TryGetEnum(); } return transaction; } diff --git a/src/RpcClient/Models/RpcTransferOut.cs b/src/RpcClient/Models/RpcTransferOut.cs new file mode 100644 index 000000000..6f582dfe3 --- /dev/null +++ b/src/RpcClient/Models/RpcTransferOut.cs @@ -0,0 +1,34 @@ +using Neo.IO.Json; +using Neo.Wallets; + +namespace Neo.Network.RPC.Models +{ + public class RpcTransferOut + { + public UInt160 Asset { get; set; } + + public UInt160 ScriptHash { get; set; } + + public string Value { get; set; } + + public JObject ToJson() + { + return new JObject + { + ["asset"] = Asset.ToString(), + ["value"] = Value, + ["address"] = ScriptHash.ToAddress(), + }; + } + + public static RpcTransferOut FromJson(JObject json) + { + return new RpcTransferOut + { + Asset = UInt160.Parse(json["asset"].AsString()), + Value = json["value"].AsString(), + ScriptHash = json["address"].AsString().ToScriptHash(), + }; + } + } +} diff --git a/src/RpcClient/Models/RpcVersion.cs b/src/RpcClient/Models/RpcVersion.cs index 8163875b6..11d831d74 100644 --- a/src/RpcClient/Models/RpcVersion.cs +++ b/src/RpcClient/Models/RpcVersion.cs @@ -15,20 +15,20 @@ public class RpcVersion public JObject ToJson() { JObject json = new JObject(); - json["topPort"] = TcpPort.ToString(); - json["wsPort"] = WsPort.ToString(); - json["nonce"] = Nonce.ToString(); - json["useragent"] = UserAgent; + json["tcp_port"] = TcpPort; + json["ws_port"] = WsPort; + json["nonce"] = Nonce; + json["user_agent"] = UserAgent; return json; } public static RpcVersion FromJson(JObject json) { RpcVersion version = new RpcVersion(); - version.TcpPort = int.Parse(json["tcpPort"].AsString()); - version.WsPort = int.Parse(json["wsPort"].AsString()); - version.Nonce = uint.Parse(json["nonce"].AsString()); - version.UserAgent = json["useragent"].AsString(); + version.TcpPort = (int)json["tcp_port"].AsNumber(); + version.WsPort = (int)json["ws_port"].AsNumber(); + version.Nonce = (uint)json["nonce"].AsNumber(); + version.UserAgent = json["user_agent"].AsString(); return version; } } diff --git a/src/RpcClient/Nep5API.cs b/src/RpcClient/Nep5API.cs index 619c75528..558c5453e 100644 --- a/src/RpcClient/Nep5API.cs +++ b/src/RpcClient/Nep5API.cs @@ -57,9 +57,9 @@ public string Symbol(UInt160 scriptHash) /// /// contract script hash /// - public uint Decimals(UInt160 scriptHash) + public byte Decimals(UInt160 scriptHash) { - return (uint)TestInvoke(scriptHash, "decimals").Stack.Single().ToStackItem().GetBigInteger(); + return (byte)TestInvoke(scriptHash, "decimals").Stack.Single().ToStackItem().GetBigInteger(); } /// @@ -90,7 +90,7 @@ public RpcNep5TokenInfo GetTokenInfo(UInt160 scriptHash) { Name = result[0].ToStackItem().GetString(), Symbol = result[1].ToStackItem().GetString(), - Decimals = (uint)result[2].ToStackItem().GetBigInteger(), + Decimals = (byte)result[2].ToStackItem().GetBigInteger(), TotalSupply = result[3].ToStackItem().GetBigInteger() }; } @@ -102,16 +102,15 @@ public RpcNep5TokenInfo GetTokenInfo(UInt160 scriptHash) /// from KeyPair /// to account script hash /// transfer amount - /// netwotk fee, set to be 0 will auto calculate the least fee /// - public Transaction CreateTransferTx(UInt160 scriptHash, KeyPair fromKey, UInt160 to, BigInteger amount, long networkFee = 0) + public Transaction CreateTransferTx(UInt160 scriptHash, KeyPair fromKey, UInt160 to, BigInteger amount) { var sender = Contract.CreateSignatureRedeemScript(fromKey.PublicKey).ToScriptHash(); Cosigner[] cosigners = new[] { new Cosigner { Scopes = WitnessScope.CalledByEntry, Account = sender } }; byte[] script = scriptHash.MakeScript("transfer", sender, to, amount); Transaction tx = new TransactionManager(rpcClient, sender) - .MakeTransaction(script, null, cosigners, networkFee) + .MakeTransaction(script, null, cosigners) .AddSignature(fromKey) .Sign() .Tx; diff --git a/src/RpcClient/RpcClient.cs b/src/RpcClient/RpcClient.cs index 2bb4fcdec..057cc9556 100644 --- a/src/RpcClient/RpcClient.cs +++ b/src/RpcClient/RpcClient.cs @@ -7,6 +7,8 @@ using System.Collections.Generic; using System.Linq; using System.Net.Http; +using System.Net.Http.Headers; +using System.Numerics; using System.Text; using System.Threading.Tasks; @@ -17,11 +19,16 @@ namespace Neo.Network.RPC /// public class RpcClient : IDisposable { - private readonly HttpClient httpClient; + private HttpClient httpClient; - public RpcClient(string url) + public RpcClient(string url, string rpcUser = default, string rpcPass = default) { httpClient = new HttpClient() { BaseAddress = new Uri(url) }; + if (!string.IsNullOrEmpty(rpcUser) && !string.IsNullOrEmpty(rpcPass)) + { + string token = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{rpcUser}:{rpcPass}")); + httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", token); + } } public RpcClient(HttpClient client) @@ -29,10 +36,28 @@ public RpcClient(HttpClient client) httpClient = client; } + #region IDisposable Support + private bool disposedValue = false; // To detect redundant calls + + protected virtual void Dispose(bool disposing) + { + if (!disposedValue) + { + if (disposing) + { + httpClient?.Dispose(); + } + + httpClient = null; + disposedValue = true; + } + } + public void Dispose() { - httpClient?.Dispose(); + Dispose(true); } + #endregion public async Task SendAsync(RpcRequest request) { @@ -67,13 +92,15 @@ public virtual JObject RpcSend(string method, params JObject[] paraArgs) var request = new RpcRequest { Id = 1, - Jsonrpc = "2.0", + JsonRpc = "2.0", Method = method, - Params = paraArgs.Select(p => p).ToArray() + Params = paraArgs }; return Send(request).Result; } + #region Blockchain + /// /// Returns the hash of the tallest block in the main chain. /// @@ -150,17 +177,9 @@ public RpcBlockHeader GetBlockHeader(string hashOrIndex) /// /// Returns the system fees of the block, based on the specified index. /// - public string GetBlockSysFee(int height) + public BigInteger GetBlockSysFee(int height) { - return RpcSend("getblocksysfee", height).AsString(); - } - - /// - /// Gets the current number of connections for the node. - /// - public int GetConnectionCount() - { - return (int)RpcSend("getconnectioncount").AsNumber(); + return BigInteger.Parse(RpcSend("getblocksysfee", height).AsString()); } /// @@ -168,15 +187,7 @@ public int GetConnectionCount() /// public ContractState GetContractState(string hash) { - return ContractState.FromJson(RpcSend("getcontractstate", hash)); - } - - /// - /// Gets the list of nodes that the node is currently connected/disconnected from. - /// - public RpcPeers GetPeers() - { - return RpcPeers.FromJson(RpcSend("getpeers")); + return RpcContractState.FromJson(RpcSend("getcontractstate", hash)).ContractState; } /// @@ -199,34 +210,39 @@ public RpcRawMemPool GetRawMempoolBoth() /// /// Returns the corresponding transaction information, based on the specified hash value. /// - public string GetRawTransactionHex(string txid) + public string GetRawTransactionHex(string txHash) { - return RpcSend("getrawtransaction", txid).AsString(); + return RpcSend("getrawtransaction", txHash).AsString(); } /// /// Returns the corresponding transaction information, based on the specified hash value. /// verbose = true /// - public RpcTransaction GetRawTransaction(string txid) + public RpcTransaction GetRawTransaction(string txHash) { - return RpcTransaction.FromJson(RpcSend("getrawtransaction", txid, true)); + return RpcTransaction.FromJson(RpcSend("getrawtransaction", txHash, true)); } /// - /// Returns the stored value, according to the contract script hash and the stored key. + /// Returns the stored value, according to the contract script hash (or Id) and the stored key. /// - public string GetStorage(string script_hash, string key) + public string GetStorage(string scriptHashOrId, string key) { - return RpcSend("getstorage", script_hash, key).AsString(); + if (int.TryParse(scriptHashOrId, out int id)) + { + return RpcSend("getstorage", id, key).AsString(); + } + + return RpcSend("getstorage", scriptHashOrId, key).AsString(); } /// /// Returns the block index in which the transaction is found. /// - public uint GetTransactionHeight(string txid) + public uint GetTransactionHeight(string txHash) { - return uint.Parse(RpcSend("gettransactionheight", txid).AsString()); + return uint.Parse(RpcSend("gettransactionheight", txHash).AsString()); } /// @@ -237,6 +253,26 @@ public RpcValidator[] GetValidators() return ((JArray)RpcSend("getvalidators")).Select(p => RpcValidator.FromJson(p)).ToArray(); } + #endregion Blockchain + + #region Node + + /// + /// Gets the current number of connections for the node. + /// + public int GetConnectionCount() + { + return (int)RpcSend("getconnectioncount").AsNumber(); + } + + /// + /// Gets the list of nodes that the node is currently connected/disconnected from. + /// + public RpcPeers GetPeers() + { + return RpcPeers.FromJson(RpcSend("getpeers")); + } + /// /// Returns the version information about the queried node. /// @@ -245,13 +281,41 @@ public RpcVersion GetVersion() return RpcVersion.FromJson(RpcSend("getversion")); } + /// + /// Broadcasts a serialized transaction over the NEO network. + /// + public UInt256 SendRawTransaction(byte[] rawTransaction) + { + return UInt256.Parse(RpcSend("sendrawtransaction", rawTransaction.ToHexString())["hash"].AsString()); + } + + /// + /// Broadcasts a transaction over the NEO network. + /// + public UInt256 SendRawTransaction(Transaction transaction) + { + return SendRawTransaction(transaction.ToArray()); + } + + /// + /// Broadcasts a serialized block over the NEO network. + /// + public UInt256 SubmitBlock(byte[] block) + { + return UInt256.Parse(RpcSend("submitblock", block.ToHexString())["hash"].AsString()); + } + + #endregion Node + + #region SmartContract + /// /// Returns the result after calling a smart contract at scripthash with the given operation and parameters. /// This RPC call does not affect the blockchain in any way. /// - public RpcInvokeResult InvokeFunction(string address, string function, RpcStack[] stacks) + public RpcInvokeResult InvokeFunction(string scriptHash, string operation, RpcStack[] stacks) { - return RpcInvokeResult.FromJson(RpcSend("invokefunction", address, function, stacks.Select(p => p.ToJson()).ToArray())); + return RpcInvokeResult.FromJson(RpcSend("invokefunction", scriptHash, operation, stacks.Select(p => p.ToJson()).ToArray())); } /// @@ -268,6 +332,10 @@ public RpcInvokeResult InvokeScript(byte[] script, params UInt160[] scriptHashes return RpcInvokeResult.FromJson(RpcSend("invokescript", parameters.ToArray())); } + #endregion SmartContract + + #region Utilities + /// /// Returns a list of plugins loaded by the node. /// @@ -277,35 +345,156 @@ public RpcPlugin[] ListPlugins() } /// - /// Broadcasts a serialized transaction over the NEO network. + /// Verifies that the address is a correct NEO address. /// - public bool SendRawTransaction(byte[] rawTransaction) + public RpcValidateAddressResult ValidateAddress(string address) { - return RpcSend("sendrawtransaction", rawTransaction.ToHexString()).AsBoolean(); + return RpcValidateAddressResult.FromJson(RpcSend("validateaddress", address)); } + #endregion Utilities + + #region Wallet + /// - /// Broadcasts a transaction over the NEO network. + /// Close the wallet opened by RPC. /// - public bool SendRawTransaction(Transaction transaction) + public bool CloseWallet() { - return SendRawTransaction(transaction.ToArray()); + return RpcSend("closewallet").AsBoolean(); } /// - /// Broadcasts a serialized block over the NEO network. + /// Exports the private key of the specified address. /// - public bool SubmitBlock(byte[] block) + public string DumpPrivKey(string address) { - return RpcSend("submitblock", block.ToHexString()).AsBoolean(); + return RpcSend("dumpprivkey", address).AsString(); } /// - /// Verifies that the address is a correct NEO address. + /// Returns the balance of the corresponding asset in the wallet, based on the specified asset Id. + /// This method applies to assets that conform to NEP-5 standards. /// - public RpcValidateAddressResult ValidateAddress(string address) + /// new address as string + public BigDecimal GetBalance(string assetId) { - return RpcValidateAddressResult.FromJson(RpcSend("validateaddress", address)); + byte decimals = new Nep5API(this).Decimals(UInt160.Parse(assetId)); + BigInteger balance = BigInteger.Parse(RpcSend("getbalance", assetId)["balance"].AsString()); + return new BigDecimal(balance, decimals); + } + + /// + /// Creates a new account in the wallet opened by RPC. + /// + public string GetNewAddress() + { + return RpcSend("getnewaddress").AsString(); + } + + /// + /// Gets the amount of unclaimed GAS in the wallet. + /// + public BigInteger GetUnclaimedGas() + { + return BigInteger.Parse(RpcSend("getunclaimedgas").AsString()); + } + + /// + /// Imports the private key to the wallet. + /// + public RpcAccount ImportPrivKey(string wif) + { + return RpcAccount.FromJson(RpcSend("importprivkey", wif)); + } + + /// + /// Lists all the accounts in the current wallet. + /// + public List ListAddress() + { + return ((JArray)RpcSend("listaddress")).Select(p => RpcAccount.FromJson(p)).ToList(); } + + /// + /// Open wallet file in the provider's machine. + /// By default, this method is disabled by RpcServer config.json. + /// + public bool OpenWallet(string path, string password) + { + return RpcSend("openwallet", path, password).AsBoolean(); + } + + /// + /// Transfer from the specified address to the destination address. + /// + /// This function returns Signed Transaction JSON if successful, ContractParametersContext JSON if signing failed. + public JObject SendFrom(string assetId, string fromAddress, string toAddress, string amount) + { + return RpcSend("sendfrom", assetId, fromAddress, toAddress, amount); + } + + /// + /// Bulk transfer order, and you can specify a sender address. + /// + /// This function returns Signed Transaction JSON if successful, ContractParametersContext JSON if signing failed. + public JObject SendMany(string fromAddress, IEnumerable outputs) + { + var parameters = new List(); + if (!string.IsNullOrEmpty(fromAddress)) + { + parameters.Add(fromAddress); + } + parameters.Add(outputs.Select(p => p.ToJson()).ToArray()); + + return RpcSend("sendmany", paraArgs: parameters.ToArray()); + } + + /// + /// Transfer asset from the wallet to the destination address. + /// + /// This function returns Signed Transaction JSON if successful, ContractParametersContext JSON if signing failed. + public JObject SendToAddress(string assetId, string address, string amount) + { + return RpcSend("sendtoaddress", assetId, address, amount); + } + + #endregion Utilities + + #region Plugins + + /// + /// Returns the contract log based on the specified txHash. The complete contract logs are stored under the ApplicationLogs directory. + /// This method is provided by the plugin ApplicationLogs. + /// + public RpcApplicationLog GetApplicationLog(string txHash) + { + return RpcApplicationLog.FromJson(RpcSend("getapplicationlog", txHash)); + } + + /// + /// Returns all the NEP-5 transaction information occurred in the specified address. + /// This method is provided by the plugin RpcNep5Tracker. + /// + /// The address to query the transaction information. + /// The start block Timestamp, default to seven days before UtcNow + /// The end block Timestamp, default to UtcNow + public RpcNep5Transfers GetNep5Transfers(string address, ulong? startTimestamp = default, ulong? endTimestamp = default) + { + startTimestamp ??= 0; + endTimestamp ??= DateTime.UtcNow.ToTimestampMS(); + return RpcNep5Transfers.FromJson(RpcSend("getnep5transfers", address, startTimestamp, endTimestamp)); + } + + /// + /// Returns the balance of all NEP-5 assets in the specified address. + /// This method is provided by the plugin RpcNep5Tracker. + /// + public RpcNep5Balances GetNep5Balances(string address) + { + return RpcNep5Balances.FromJson(RpcSend("getnep5balances", address)); + } + + #endregion Plugins } } diff --git a/src/RpcClient/RpcClient.csproj b/src/RpcClient/RpcClient.csproj index 2f4aed74b..a6d1ea769 100644 --- a/src/RpcClient/RpcClient.csproj +++ b/src/RpcClient/RpcClient.csproj @@ -1,7 +1,7 @@ - 3.0.0-CI00847 + 3.0.0-CI00863 netstandard2.1 Neo.Network.RPC The Neo Project @@ -14,7 +14,7 @@ - + diff --git a/src/RpcClient/TransactionManager.cs b/src/RpcClient/TransactionManager.cs index 8d345f651..43d182c8b 100644 --- a/src/RpcClient/TransactionManager.cs +++ b/src/RpcClient/TransactionManager.cs @@ -6,6 +6,7 @@ using Neo.SmartContract.Native; using Neo.Wallets; using System; +using System.Collections.Generic; using System.Linq; namespace Neo.Network.RPC @@ -20,11 +21,18 @@ public class TransactionManager private readonly Nep5API nep5API; private readonly UInt160 sender; + private class SignItem { public Contract Contract; public HashSet KeyPairs; } + /// /// The Transaction context to manage the witnesses /// private ContractParametersContext context; + /// + /// This container stores the keys for sign the transaction + /// + private List signStore; + /// /// The Transaction managed by this class /// @@ -49,9 +57,8 @@ public TransactionManager(RpcClient rpc, UInt160 sender) /// Transaction Script /// Transaction Attributes /// Transaction Cosigners - /// Transaction NetworkFee, will set to estimate value(with only basic signatures) when networkFee is 0 /// - public TransactionManager MakeTransaction(byte[] script, TransactionAttribute[] attributes = null, Cosigner[] cosigners = null, long networkFee = 0) + public TransactionManager MakeTransaction(byte[] script, TransactionAttribute[] attributes = null, Cosigner[] cosigners = null) { var random = new Random(); uint height = rpcClient.GetBlockCount() - 1; @@ -82,21 +89,16 @@ public TransactionManager MakeTransaction(byte[] script, TransactionAttribute[] } context = new ContractParametersContext(Tx); + signStore = new List(); - // set networkfee to estimate value when networkFee is 0 - Tx.NetworkFee = networkFee == 0 ? CalculateNetworkFee(true) : networkFee; - - var gasBalance = nep5API.BalanceOf(NativeContract.GAS.Hash, sender); - if (gasBalance >= Tx.SystemFee + Tx.NetworkFee) return this; - throw new InvalidOperationException($"Insufficient GAS in address: {sender.ToAddress()}"); + return this; } /// /// Calculate NetworkFee /// - /// assuming the witnesses are basic Signature Contract if set to true /// - private long CalculateNetworkFee(bool isEstimate = false) + private long CalculateNetworkFee() { long networkFee = 0; UInt160[] hashes = Tx.GetScriptHashesForVerifying(null); @@ -104,30 +106,19 @@ private long CalculateNetworkFee(bool isEstimate = false) foreach (UInt160 hash in hashes) { byte[] witness_script = null; - if (isEstimate) - { - // assuming the witnesses are basic Signature Contract - var dummyKey = new byte[32]; - dummyKey[31] = 0x01; - KeyPair one = new KeyPair(dummyKey); - witness_script = Contract.CreateSignatureRedeemScript(one.PublicKey); - } - else + + // calculate NetworkFee + witness_script = signStore.FirstOrDefault(p => p.Contract.ScriptHash == hash)?.Contract?.Script; + if (witness_script is null || witness_script.Length == 0) { - // calculate NetworkFee with context items - witness_script = context.GetScript(hash); - if (witness_script is null || witness_script.Length == 0) + try { - try - { - witness_script = rpcClient.GetContractState(hash.ToString())?.Script; - } - catch { } + witness_script = rpcClient.GetContractState(hash.ToString())?.Script; } - - if (witness_script is null) continue; + catch { } } + if (witness_script is null) continue; networkFee += Wallet.CalculateNetworkFee(witness_script, ref size); } networkFee += size * policyAPI.GetFeePerByte(); @@ -142,13 +133,7 @@ private long CalculateNetworkFee(bool isEstimate = false) public TransactionManager AddSignature(KeyPair key) { var contract = Contract.CreateSignatureContract(key.PublicKey); - - byte[] signature = Tx.Sign(key); - if (!context.AddSignature(contract, key.PublicKey, signature)) - { - throw new Exception("AddSignature failed!"); - } - + AddSignItem(contract, key); return this; } @@ -161,14 +146,26 @@ public TransactionManager AddSignature(KeyPair key) public TransactionManager AddMultiSig(KeyPair key, int m, params ECPoint[] publicKeys) { Contract contract = Contract.CreateMultiSigContract(m, publicKeys); + AddSignItem(contract, key); + return this; + } - byte[] signature = Tx.Sign(key); - if (!context.AddSignature(contract, key.PublicKey, signature)) + private void AddSignItem(Contract contract, KeyPair key) + { + if (!Tx.GetScriptHashesForVerifying(null).Contains(contract.ScriptHash)) { - throw new Exception("AddMultiSig failed!"); + throw new Exception($"Add SignItem error: Mismatch ScriptHash ({contract.ScriptHash.ToString()})"); } - return this; + SignItem item = signStore.FirstOrDefault(p => p.Contract.ScriptHash == contract.ScriptHash); + if (item is null) + { + signStore.Add(new SignItem { Contract = contract, KeyPairs = new HashSet { key } }); + } + else if (!item.KeyPairs.Contains(key)) + { + item.KeyPairs.Add(key); + } } /// @@ -201,19 +198,28 @@ public TransactionManager AddWitness(UInt160 scriptHash, params object[] paramet /// public TransactionManager Sign() { + // Calculate NetworkFee + Tx.NetworkFee = CalculateNetworkFee(); + var gasBalance = nep5API.BalanceOf(NativeContract.GAS.Hash, sender); + if (gasBalance < Tx.SystemFee + Tx.NetworkFee) + throw new InvalidOperationException($"Insufficient GAS in address: {sender.ToAddress()}"); + + // Sign with signStore + foreach (var item in signStore) + foreach (var key in item.KeyPairs) + { + byte[] signature = Tx.Sign(key); + if (!context.AddSignature(item.Contract, key.PublicKey, signature)) + { + throw new Exception("AddSignature failed!"); + } + } + // Verify witness count if (!context.Completed) { throw new Exception($"Please add signature or witness first!"); } - - // Calculate NetworkFee - long leastNetworkFee = CalculateNetworkFee(); - if (Tx.NetworkFee < leastNetworkFee) - { - throw new InvalidOperationException("Insufficient NetworkFee"); - } - Tx.Witnesses = context.GetWitnesses(); return this; } diff --git a/src/RpcClient/Utility.cs b/src/RpcClient/Utility.cs index 198c31dd9..bf7c95fe2 100644 --- a/src/RpcClient/Utility.cs +++ b/src/RpcClient/Utility.cs @@ -46,7 +46,7 @@ public static KeyPair GetKeyPair(string key) /// Parse address, scripthash or public key string to UInt160 /// /// account address, scripthash or public key string - /// Example: address ("AV556nYUwyJKNv8Xy7hVMLQnkmKPukw6x5"), scripthash ("0x6a38cd693b615aea24dd00de12a9f5836844da91"), public key ("02f9ec1fd0a98796cf75b586772a4ddd41a0af07a1dbdf86a7238f74fb72503575") + /// Example: address ("Ncm9TEzrp8SSer6Wa3UCSLTRnqzwVhCfuE"), scripthash ("0xb0a31817c80ad5f87b6ed390ecb3f9d312f7ceb8"), public key ("02f9ec1fd0a98796cf75b586772a4ddd41a0af07a1dbdf86a7238f74fb72503575") /// public static UInt160 GetScriptHash(string account) { @@ -82,7 +82,7 @@ internal static BigInteger ToBigInteger(this decimal amount, uint decimals) var (numerator, denominator) = Fraction(amount); if (factor < denominator) { - throw new OverflowException("The decimal places is too long."); + throw new ArgumentException("The decimal places is too long."); } BigInteger res = factor * numerator / denominator; diff --git a/src/RpcClient/WalletAPI.cs b/src/RpcClient/WalletAPI.cs index e1ab3b777..afb44e6d4 100644 --- a/src/RpcClient/WalletAPI.cs +++ b/src/RpcClient/WalletAPI.cs @@ -34,7 +34,7 @@ public WalletAPI(RpcClient rpc) /// Get unclaimed gas with address, scripthash or public key string /// /// address, scripthash or public key string - /// Example: address ("AV556nYUwyJKNv8Xy7hVMLQnkmKPukw6x5"), scripthash ("0x6a38cd693b615aea24dd00de12a9f5836844da91"), public key ("02f9ec1fd0a98796cf75b586772a4ddd41a0af07a1dbdf86a7238f74fb72503575") + /// Example: address ("Ncm9TEzrp8SSer6Wa3UCSLTRnqzwVhCfuE"), scripthash ("0xb0a31817c80ad5f87b6ed390ecb3f9d312f7ceb8"), public key ("02f9ec1fd0a98796cf75b586772a4ddd41a0af07a1dbdf86a7238f74fb72503575") /// public decimal GetUnclaimedGas(string account) { @@ -59,7 +59,7 @@ public decimal GetUnclaimedGas(UInt160 account) /// Get Neo Balance /// /// address, scripthash or public key string - /// Example: address ("AV556nYUwyJKNv8Xy7hVMLQnkmKPukw6x5"), scripthash ("0x6a38cd693b615aea24dd00de12a9f5836844da91"), public key ("02f9ec1fd0a98796cf75b586772a4ddd41a0af07a1dbdf86a7238f74fb72503575") + /// Example: address ("Ncm9TEzrp8SSer6Wa3UCSLTRnqzwVhCfuE"), scripthash ("0xb0a31817c80ad5f87b6ed390ecb3f9d312f7ceb8"), public key ("02f9ec1fd0a98796cf75b586772a4ddd41a0af07a1dbdf86a7238f74fb72503575") /// public uint GetNeoBalance(string account) { @@ -71,7 +71,7 @@ public uint GetNeoBalance(string account) /// Get Gas Balance /// /// address, scripthash or public key string - /// Example: address ("AV556nYUwyJKNv8Xy7hVMLQnkmKPukw6x5"), scripthash ("0x6a38cd693b615aea24dd00de12a9f5836844da91"), public key ("02f9ec1fd0a98796cf75b586772a4ddd41a0af07a1dbdf86a7238f74fb72503575") + /// Example: address ("Ncm9TEzrp8SSer6Wa3UCSLTRnqzwVhCfuE"), scripthash ("0xb0a31817c80ad5f87b6ed390ecb3f9d312f7ceb8"), public key ("02f9ec1fd0a98796cf75b586772a4ddd41a0af07a1dbdf86a7238f74fb72503575") /// public decimal GetGasBalance(string account) { @@ -84,7 +84,7 @@ public decimal GetGasBalance(string account) /// /// token script hash, Example: "0x43cf98eddbe047e198a3e5d57006311442a0ca15"(NEO) /// address, scripthash or public key string - /// Example: address ("AV556nYUwyJKNv8Xy7hVMLQnkmKPukw6x5"), scripthash ("0x6a38cd693b615aea24dd00de12a9f5836844da91"), public key ("02f9ec1fd0a98796cf75b586772a4ddd41a0af07a1dbdf86a7238f74fb72503575") + /// Example: address ("Ncm9TEzrp8SSer6Wa3UCSLTRnqzwVhCfuE"), scripthash ("0xb0a31817c80ad5f87b6ed390ecb3f9d312f7ceb8"), public key ("02f9ec1fd0a98796cf75b586772a4ddd41a0af07a1dbdf86a7238f74fb72503575") /// public BigInteger GetTokenBalance(string tokenHash, string account) { @@ -124,14 +124,13 @@ public Transaction ClaimGas(KeyPair keyPair) /// /// Transfer NEP5 token balance, with common data types /// - /// nep5 token script hash, Example: scripthash ("0x6a38cd693b615aea24dd00de12a9f5836844da91") + /// nep5 token script hash, Example: scripthash ("0xb0a31817c80ad5f87b6ed390ecb3f9d312f7ceb8") /// wif or private key /// Example: WIF ("KyXwTh1hB76RRMquSvnxZrJzQx7h9nQP2PCRL38v6VDb5ip3nf1p"), PrivateKey ("450d6c2a04b5b470339a745427bae6828400cf048400837d73c415063835e005") /// address or account script hash /// token amount - /// netwotk fee, set to be 0 will auto calculate the least fee /// - public Transaction Transfer(string tokenHash, string fromKey, string toAddress, decimal amount, decimal networkFee = 0) + public Transaction Transfer(string tokenHash, string fromKey, string toAddress, decimal amount) { UInt160 scriptHash = Utility.GetScriptHash(tokenHash); var decimals = nep5API.Decimals(scriptHash); @@ -139,22 +138,20 @@ public Transaction Transfer(string tokenHash, string fromKey, string toAddress, KeyPair from = Utility.GetKeyPair(fromKey); UInt160 to = Utility.GetScriptHash(toAddress); BigInteger amountInteger = amount.ToBigInteger(decimals); - BigInteger networkFeeInteger = networkFee.ToBigInteger(NativeContract.GAS.Decimals); - return Transfer(scriptHash, from, to, amountInteger, (long)networkFeeInteger); + return Transfer(scriptHash, from, to, amountInteger); } /// /// Transfer NEP5 token balance /// /// contract script hash - /// from KeyPair + /// from KeyPair /// to account script hash - /// transfer amount - /// netwotk fee, set to be 0 will auto calculate the least fee + /// transfer amount /// - public Transaction Transfer(UInt160 scriptHash, KeyPair from, UInt160 to, BigInteger amountInteger, BigInteger networkFeeInteger = default) + public Transaction Transfer(UInt160 scriptHash, KeyPair from, UInt160 to, BigInteger amountInteger) { - Transaction transaction = nep5API.CreateTransferTx(scriptHash, from, to, amountInteger, (long)networkFeeInteger); + Transaction transaction = nep5API.CreateTransferTx(scriptHash, from, to, amountInteger); rpcClient.SendRawTransaction(transaction); return transaction; } diff --git a/src/RpcServer/RpcServer.Blockchain.cs b/src/RpcServer/RpcServer.Blockchain.cs index c689757cc..0f5e9cd8a 100644 --- a/src/RpcServer/RpcServer.Blockchain.cs +++ b/src/RpcServer/RpcServer.Blockchain.cs @@ -157,7 +157,7 @@ private JObject GetRawTransaction(JArray _params) json["blockhash"] = header.Hash.ToString(); json["confirmations"] = Blockchain.Singleton.Height - header.Index + 1; json["blocktime"] = header.Timestamp; - json["vmState"] = txState.VMState; + json["vm_state"] = txState.VMState; } return json; } diff --git a/src/RpcServer/RpcServer.Node.cs b/src/RpcServer/RpcServer.Node.cs index 2b1018e8d..cdec3f405 100644 --- a/src/RpcServer/RpcServer.Node.cs +++ b/src/RpcServer/RpcServer.Node.cs @@ -59,10 +59,10 @@ private static JObject GetRelayResult(RelayResultReason reason, UInt256 hash) private JObject GetVersion(JArray _params) { JObject json = new JObject(); - json["tcpPort"] = LocalNode.Singleton.ListenerTcpPort; - json["wsPort"] = LocalNode.Singleton.ListenerWsPort; + json["tcp_port"] = LocalNode.Singleton.ListenerTcpPort; + json["ws_port"] = LocalNode.Singleton.ListenerWsPort; json["nonce"] = LocalNode.Nonce; - json["useragent"] = LocalNode.UserAgent; + json["user_agent"] = LocalNode.UserAgent; return json; } diff --git a/src/RpcServer/RpcServer.csproj b/src/RpcServer/RpcServer.csproj index 4b571e502..de60f6a7d 100644 --- a/src/RpcServer/RpcServer.csproj +++ b/src/RpcServer/RpcServer.csproj @@ -1,7 +1,7 @@ - 3.0.0-CI00847 + 3.0.0-CI00863 netstandard2.1 Neo.Plugins @@ -15,7 +15,7 @@ - + diff --git a/src/StatesDumper/StatesDumper.csproj b/src/StatesDumper/StatesDumper.csproj index b9c4144ec..4cf60681d 100644 --- a/src/StatesDumper/StatesDumper.csproj +++ b/src/StatesDumper/StatesDumper.csproj @@ -1,7 +1,7 @@ - 3.0.0-CI00847 + 3.0.0-CI00863 netstandard2.1 Neo.Plugins @@ -14,7 +14,7 @@ - + diff --git a/src/SystemLog/SystemLog.csproj b/src/SystemLog/SystemLog.csproj index 952373bc1..d5dc065c4 100644 --- a/src/SystemLog/SystemLog.csproj +++ b/src/SystemLog/SystemLog.csproj @@ -1,7 +1,7 @@ - 3.0.0-CI00847 + 3.0.0-CI00863 netstandard2.1 Neo.Plugins @@ -14,7 +14,7 @@ - + diff --git a/tests/Neo.Network.RPC.Tests/Models/UT_RpcBlock.cs b/tests/Neo.Network.RPC.Tests/Models/UT_RpcBlock.cs deleted file mode 100644 index 61887f784..000000000 --- a/tests/Neo.Network.RPC.Tests/Models/UT_RpcBlock.cs +++ /dev/null @@ -1,24 +0,0 @@ -using FluentAssertions; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Neo.Network.RPC.Models; - -namespace Neo.Network.RPC.Tests.Models -{ - [TestClass] - public class UT_RpcBlock - { - [TestMethod] - public void TestToJson() - { - var rpcBlock = new RpcBlock - { - Block = TestUtils.GetBlock(1), - Confirmations = 1, - NextBlockHash = UInt256.Zero - }; - var json = rpcBlock.ToJson(); - json["previousblockhash"].AsString().Should().Be("0x0000000000000000000000000000000000000000000000000000000000000000"); - json["confirmations"].AsNumber().Should().Be(1); - } - } -} diff --git a/tests/Neo.Network.RPC.Tests/Models/UT_RpcBlockHeader.cs b/tests/Neo.Network.RPC.Tests/Models/UT_RpcBlockHeader.cs deleted file mode 100644 index f756ab572..000000000 --- a/tests/Neo.Network.RPC.Tests/Models/UT_RpcBlockHeader.cs +++ /dev/null @@ -1,24 +0,0 @@ -using FluentAssertions; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Neo.Network.RPC.Models; - -namespace Neo.Network.RPC.Tests.Models -{ - [TestClass] - public class UT_RpcBlockHeader - { - [TestMethod] - public void TestToJson() - { - var rpcBlockHeader = new RpcBlockHeader - { - Header = TestUtils.GetHeader(), - Confirmations = 1, - NextBlockHash = UInt256.Zero - }; - var json = rpcBlockHeader.ToJson(); - json["previousblockhash"].AsString().Should().Be("0x0000000000000000000000000000000000000000000000000000000000000000"); - json["confirmations"].AsNumber().Should().Be(1); - } - } -} diff --git a/tests/Neo.Network.RPC.Tests/Models/UT_RpcNep5Balance.cs b/tests/Neo.Network.RPC.Tests/Models/UT_RpcNep5Balance.cs deleted file mode 100644 index 1aeda4998..000000000 --- a/tests/Neo.Network.RPC.Tests/Models/UT_RpcNep5Balance.cs +++ /dev/null @@ -1,66 +0,0 @@ -using FluentAssertions; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Neo.IO.Json; -using Neo.Network.RPC.Models; -using System.Numerics; - -namespace Neo.Network.RPC.Tests.Models -{ - [TestClass] - public class UT_RpcNep5Balance - { - private RpcNep5Balance balance; - - [TestInitialize] - public void Setup() - { - balance = new RpcNep5Balance(); - } - - [TestMethod] - public void TestAssetHash() - { - balance.AssetHash = UInt160.Zero; - balance.AssetHash.Should().Be(UInt160.Zero); - } - - [TestMethod] - public void TestAmount() - { - balance.Amount = BigInteger.Zero; - balance.Amount.Should().Be(BigInteger.Zero); - } - - [TestMethod] - public void TestLastUpdatedBlock() - { - balance.LastUpdatedBlock = 0; - balance.LastUpdatedBlock.Should().Be(0); - } - - [TestMethod] - public void TestToJson() - { - balance.AssetHash = UInt160.Zero; - balance.Amount = BigInteger.Zero; - balance.LastUpdatedBlock = 0; - var json = balance.ToJson(); - json["asset_hash"].AsString().Should().Be("0x0000000000000000000000000000000000000000"); - json["amount"].AsNumber().Should().Be(0); - json["last_updated_block"].AsNumber().Should().Be(0); - } - - [TestMethod] - public void TestFromJson() - { - var json = new JObject(); - json["asset_hash"] = "0x0000000000000000000000000000000000000000"; - json["amount"] = "0"; - json["last_updated_block"] = "0"; - var rpcNep5Balance = RpcNep5Balance.FromJson(json); - rpcNep5Balance.AssetHash.Should().Be(UInt160.Zero); - rpcNep5Balance.Amount.Should().Be(BigInteger.Zero); - rpcNep5Balance.LastUpdatedBlock.Should().Be(0); - } - } -} diff --git a/tests/Neo.Network.RPC.Tests/Models/UT_RpcNep5Balances.cs b/tests/Neo.Network.RPC.Tests/Models/UT_RpcNep5Balances.cs deleted file mode 100644 index da0752222..000000000 --- a/tests/Neo.Network.RPC.Tests/Models/UT_RpcNep5Balances.cs +++ /dev/null @@ -1,66 +0,0 @@ -using FluentAssertions; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Neo.IO.Json; -using Neo.Network.RPC.Models; -using System.Numerics; - -namespace Neo.Network.RPC.Tests.Models -{ - [TestClass] - public class UT_RpcNep5Balances - { - private RpcNep5Balances balances; - - [TestInitialize] - public void Setup() - { - balances = new RpcNep5Balances() - { - Address = "abc", - Balances = new RpcNep5Balance[] { - new RpcNep5Balance() - { - AssetHash = UInt160.Zero, - Amount = BigInteger.Zero, - LastUpdatedBlock = 0 - }, - new RpcNep5Balance() - { - AssetHash = UInt160.Parse("0xa400ff00ff00ff00ff00ff00ff00ff00ff00ff01"), - Amount = new BigInteger(1), - LastUpdatedBlock = 1 - } - } - }; - } - - [TestMethod] - public void TestAddress() - { - balances.Address.Should().Be("abc"); - } - - [TestMethod] - public void TestBalances() - { - balances.Balances.Length.Should().Be(2); - } - - [TestMethod] - public void TestToJson() - { - var json = balances.ToJson(); - json["address"].AsString().Should().Be("abc"); - ((JArray)json["balance"]).Count.Should().Be(2); - } - - [TestMethod] - public void TestFromJson() - { - var json = balances.ToJson(); - var rpcNep5Balances = RpcNep5Balances.FromJson(json); - rpcNep5Balances.Address.Should().Be("abc"); - rpcNep5Balances.Balances.Length.Should().Be(2); - } - } -} diff --git a/tests/Neo.Network.RPC.Tests/Models/UT_RpcPeer.cs b/tests/Neo.Network.RPC.Tests/Models/UT_RpcPeer.cs deleted file mode 100644 index 838aad486..000000000 --- a/tests/Neo.Network.RPC.Tests/Models/UT_RpcPeer.cs +++ /dev/null @@ -1,23 +0,0 @@ -using FluentAssertions; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Neo.Network.RPC.Models; - -namespace Neo.Network.RPC.Tests.Models -{ - [TestClass] - public class UT_RpcPeer - { - [TestMethod] - public void TestToJson() - { - var rpcPeer = new RpcPeer() - { - Address = "abc", - Port = 800 - }; - var json = rpcPeer.ToJson(); - json["address"].AsString().Should().Be("abc"); - json["port"].AsNumber().Should().Be(800); - } - } -} diff --git a/tests/Neo.Network.RPC.Tests/Models/UT_RpcPeers.cs b/tests/Neo.Network.RPC.Tests/Models/UT_RpcPeers.cs deleted file mode 100644 index fba07ea70..000000000 --- a/tests/Neo.Network.RPC.Tests/Models/UT_RpcPeers.cs +++ /dev/null @@ -1,44 +0,0 @@ -using FluentAssertions; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Neo.IO.Json; -using Neo.Network.RPC.Models; - -namespace Neo.Network.RPC.Tests.Models -{ - [TestClass] - public class UT_RpcPeers - { - [TestMethod] - public void TestToJson() - { - var rpcPeers = new RpcPeers() - { - Unconnected = new RpcPeer[] { - new RpcPeer() - { - Address = "Unconnected", - Port = 600 - } - }, - Bad = new RpcPeer[] { - new RpcPeer() - { - Address = "Bad", - Port = 700 - } - }, - Connected = new RpcPeer[] { - new RpcPeer() - { - Address = "Connected", - Port = 800 - } - } - }; - var json = rpcPeers.ToJson(); - ((JArray)json["unconnected"]).Count.Should().Be(1); - ((JArray)json["bad"]).Count.Should().Be(1); - ((JArray)json["connected"]).Count.Should().Be(1); - } - } -} diff --git a/tests/Neo.Network.RPC.Tests/Models/UT_RpcRawMemPool.cs b/tests/Neo.Network.RPC.Tests/Models/UT_RpcRawMemPool.cs deleted file mode 100644 index fbfd6719c..000000000 --- a/tests/Neo.Network.RPC.Tests/Models/UT_RpcRawMemPool.cs +++ /dev/null @@ -1,29 +0,0 @@ -using FluentAssertions; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Neo.Network.RPC.Models; - -namespace Neo.Network.RPC.Tests.Models -{ - [TestClass] - public class UT_RpcRawMemPool - { - [TestMethod] - public void TestToJson() - { - var pool = new RpcRawMemPool - { - Height = 1, - Verified = new string[] { - "a", "b" - }, - UnVerified = new string[] { - "c", "d" - } - }; - var json = pool.ToJson(); - json["height"].AsNumber().Should().Be(1); - json["verified"].AsString().Should().Be("a,b"); - json["unverified"].AsString().Should().Be("c,d"); - } - } -} diff --git a/tests/Neo.Network.RPC.Tests/Models/UT_RpcRequest.cs b/tests/Neo.Network.RPC.Tests/Models/UT_RpcRequest.cs deleted file mode 100644 index 3aec7e9d1..000000000 --- a/tests/Neo.Network.RPC.Tests/Models/UT_RpcRequest.cs +++ /dev/null @@ -1,31 +0,0 @@ -using FluentAssertions; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Neo.IO.Json; -using Neo.Network.RPC.Models; - -namespace Neo.Network.RPC.Tests.Models -{ - [TestClass] - public class UT_RpcRequest - { - [TestMethod] - public void TestFromJson() - { - var req = new RpcRequest() - { - Id = 1, - Jsonrpc = "myrpc", - Method = "get", - Params = new JObject[] { - new JBoolean(true) - } - }; - var json = req.ToJson(); - var rpcRequest = RpcRequest.FromJson(json); - rpcRequest.Jsonrpc.Should().Be("myrpc"); - rpcRequest.Method.Should().Be("get"); - rpcRequest.Id.Should().Be(1); - rpcRequest.Params.Length.Should().Be(1); - } - } -} diff --git a/tests/Neo.Network.RPC.Tests/Models/UT_RpcResponse.cs b/tests/Neo.Network.RPC.Tests/Models/UT_RpcResponse.cs deleted file mode 100644 index 6265fb436..000000000 --- a/tests/Neo.Network.RPC.Tests/Models/UT_RpcResponse.cs +++ /dev/null @@ -1,34 +0,0 @@ -using FluentAssertions; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Neo.IO.Json; -using Neo.Network.RPC.Models; - -namespace Neo.Network.RPC.Tests.Models -{ - [TestClass] - public class UT_RpcResponse - { - [TestMethod] - public void TestToJson() - { - var error = new RpcResponseError() - { - Code = 0, - Message = "msg", - Data = new JBoolean(true) - }; - var rep = new RpcResponse() - { - Id = 1, - Jsonrpc = "rpc", - Error = error, - Result = new JBoolean(true) - }; - var json = rep.ToJson(); - json["id"].AsNumber().Should().Be(1); - json["jsonrpc"].AsString().Should().Be("rpc"); - json["error"].AsString().Should().Be(error.ToJson().AsString()); - json["result"].AsBoolean().Should().BeTrue(); - } - } -} diff --git a/tests/Neo.Network.RPC.Tests/Models/UT_RpcVersion.cs b/tests/Neo.Network.RPC.Tests/Models/UT_RpcVersion.cs deleted file mode 100644 index e6ce63500..000000000 --- a/tests/Neo.Network.RPC.Tests/Models/UT_RpcVersion.cs +++ /dev/null @@ -1,27 +0,0 @@ -using FluentAssertions; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Neo.Network.RPC.Models; - -namespace Neo.Network.RPC.Tests.Models -{ - [TestClass] - public class UT_RpcVersion - { - [TestMethod] - public void TestToJson() - { - var version = new RpcVersion() - { - TcpPort = 800, - WsPort = 900, - Nonce = 1, - UserAgent = "agent" - }; - var json = version.ToJson(); - json["topPort"].AsNumber().Should().Be(800); - json["wsPort"].AsNumber().Should().Be(900); - json["nonce"].AsNumber().Should().Be(1); - json["useragent"].AsString().Should().Be("agent"); - } - } -} diff --git a/tests/Neo.Network.RPC.Tests/Neo.Network.RPC.Tests.csproj b/tests/Neo.Network.RPC.Tests/Neo.Network.RPC.Tests.csproj index 3c4da3a16..af5c7c416 100644 --- a/tests/Neo.Network.RPC.Tests/Neo.Network.RPC.Tests.csproj +++ b/tests/Neo.Network.RPC.Tests/Neo.Network.RPC.Tests.csproj @@ -19,4 +19,10 @@ + + + PreserveNewest + + + diff --git a/tests/Neo.Network.RPC.Tests/RpcTestCases.json b/tests/Neo.Network.RPC.Tests/RpcTestCases.json new file mode 100644 index 000000000..95c7b1409 --- /dev/null +++ b/tests/Neo.Network.RPC.Tests/RpcTestCases.json @@ -0,0 +1,1279 @@ +[ + { + "Name": "sendrawtransactionerror", + "Request": { + "jsonrpc": "2.0", + "method": "sendrawtransaction", + "params": [ "00b5077e7bb8cef712d3f9b3ec90d36e7bf8d50ac81718a3b000e1f5050000000080778e0600000000e31420000001b8cef712d3f9b3ec90d36e7bf8d50ac81718a3b0015c0300e40b54020000000c1400000000000000000000000000000000000000000c14b8cef712d3f9b3ec90d36e7bf8d50ac81718a3b013c00c087472616e736665720c143b7d3711c6f0ccf9b1dca903d1bfa1d896f1238c41627d5b5201420c4077a5ffdc41dce3b06418879a26bac0fcea06af4a833446c90f63a3e80b85d13e07ca9084989e7c7e4535187409058dc7233ba8ee4638593605134e2c2c8f3c9f290c2102f9ec1fd0a98796cf75b586772a4ddd41a0af07a1dbdf86a7238f74fb725035750b410a906ad4" ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "error": { + "code": -500, + "message": "InsufficientFunds", + "data": " at Neo.Plugins.RpcServer.GetRelayResult(RelayResultReason reason, UInt256 hash)\r\n at Neo.Network.RPC.Models.RpcServer.SendRawTransaction(JArray _params)\r\n at Neo.Network.RPC.Models.RpcServer.ProcessRequest(HttpContext context, JObject request)" + } + } + }, + { + "Name": "getbestblockhash", + "Request": { + "jsonrpc": "2.0", + "method": "getbestblockhash", + "params": [], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": "0x530de76326a8662d1b730ba4fbdf011051eabd142015587e846da42376adf35f" + } + }, + { + "Name": "getblockhex", + "Request": { + "jsonrpc": "2.0", + "method": "getblock", + "params": [ 0 ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": "0000000000000000000000000000000000000000000000000000000000000000000000002bbb6298fc7039330cdfd2e4dfbe976ee72c4cba6c16d68f0b49ab1bca685b7388ea19ef55010000000000009903b0c3d292988febe5f306a02f654ea2eb16290100011102001dac2b7c000000000000000000ca61e52e881d41374e640f819cd118cc153b21a7000000000000000000000000000000000000000000000541123e7fe801000111" + } + }, + { + "Name": "getblockhex", + "Request": { + "jsonrpc": "2.0", + "method": "getblock", + "params": [ "0x5bb05a3b857c9eaaf94dc33fa5b4a2278601eefcdb90703698972ef7d029e445" ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": "0000000000000000000000000000000000000000000000000000000000000000000000002bbb6298fc7039330cdfd2e4dfbe976ee72c4cba6c16d68f0b49ab1bca685b7388ea19ef55010000000000009903b0c3d292988febe5f306a02f654ea2eb16290100011102001dac2b7c000000000000000000ca61e52e881d41374e640f819cd118cc153b21a7000000000000000000000000000000000000000000000541123e7fe801000111" + } + }, + { + "Name": "getblock", + "Request": { + "jsonrpc": "2.0", + "method": "getblock", + "params": [ 0, true ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": { + "hash": "0x5bb05a3b857c9eaaf94dc33fa5b4a2278601eefcdb90703698972ef7d029e445", + "size": 171, + "version": 0, + "previousblockhash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "merkleroot": "0x735b68ca1bab490b8fd6166cba4c2ce76e97bedfe4d2df0c333970fc9862bb2b", + "time": 1468595301000, + "index": 0, + "nextconsensus": "NZs2zXSPuuv9ZF6TDGSWT1RBmE8rfGj7UW", + "witnesses": [ + { + "invocation": "", + "verification": "EQ==" + } + ], + "consensus_data": { + "primary": 0, + "nonce": "000000007c2bac1d" + }, + "tx": [ + { + "hash": "0xb13fd7940186896233272811e61b69a0c4b7dd576fdf3b89987c8cdee2d71e37", + "size": 57, + "version": 0, + "nonce": 0, + "sender": "NeN4xPMn4kHoj7G8Lciq9oorgLTvqt4qi1", + "sys_fee": "0", + "net_fee": "0", + "valid_until_block": 0, + "attributes": [], + "cosigners": [], + "script": "QRI+f+g=", + "witnesses": [ + { + "invocation": "", + "verification": "EQ==" + } + ] + } + ], + "confirmations": 2671, + "nextblockhash": "0x423173109798b038019b35129417b55cc4b5976ac79978dfab8ea2512d155f69" + } + } + }, + { + "Name": "getblock", + "Request": { + "jsonrpc": "2.0", + "method": "getblock", + "params": [ "0x5bb05a3b857c9eaaf94dc33fa5b4a2278601eefcdb90703698972ef7d029e445", true ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": { + "hash": "0x5bb05a3b857c9eaaf94dc33fa5b4a2278601eefcdb90703698972ef7d029e445", + "size": 171, + "version": 0, + "previousblockhash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "merkleroot": "0x735b68ca1bab490b8fd6166cba4c2ce76e97bedfe4d2df0c333970fc9862bb2b", + "time": 1468595301000, + "index": 0, + "nextconsensus": "NZs2zXSPuuv9ZF6TDGSWT1RBmE8rfGj7UW", + "witnesses": [ + { + "invocation": "", + "verification": "EQ==" + } + ], + "consensus_data": { + "primary": 0, + "nonce": "000000007c2bac1d" + }, + "tx": [ + { + "hash": "0xb13fd7940186896233272811e61b69a0c4b7dd576fdf3b89987c8cdee2d71e37", + "size": 57, + "version": 0, + "nonce": 0, + "sender": "NeN4xPMn4kHoj7G8Lciq9oorgLTvqt4qi1", + "sys_fee": "0", + "net_fee": "0", + "valid_until_block": 0, + "attributes": [], + "cosigners": [], + "script": "QRI+f+g=", + "witnesses": [ + { + "invocation": "", + "verification": "EQ==" + } + ] + } + ], + "confirmations": 2671, + "nextblockhash": "0x423173109798b038019b35129417b55cc4b5976ac79978dfab8ea2512d155f69" + } + } + }, + { + "Name": "getblockcount", + "Request": { + "jsonrpc": "2.0", + "method": "getblockcount", + "params": [], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": 2691 + } + }, + { + "Name": "getblockhash", + "Request": { + "jsonrpc": "2.0", + "method": "getblockhash", + "params": [ 0 ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": "0x5bb05a3b857c9eaaf94dc33fa5b4a2278601eefcdb90703698972ef7d029e445" + } + }, + { + "Name": "getblockheaderhex", + "Request": { + "jsonrpc": "2.0", + "method": "getblockheader", + "params": [ 0 ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": "0000000000000000000000000000000000000000000000000000000000000000000000002bbb6298fc7039330cdfd2e4dfbe976ee72c4cba6c16d68f0b49ab1bca685b7388ea19ef55010000000000009903b0c3d292988febe5f306a02f654ea2eb16290100011100" + } + }, + { + "Name": "getblockheaderhex", + "Request": { + "jsonrpc": "2.0", + "method": "getblockheader", + "params": [ "0x5bb05a3b857c9eaaf94dc33fa5b4a2278601eefcdb90703698972ef7d029e445" ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": "0000000000000000000000000000000000000000000000000000000000000000000000002bbb6298fc7039330cdfd2e4dfbe976ee72c4cba6c16d68f0b49ab1bca685b7388ea19ef55010000000000009903b0c3d292988febe5f306a02f654ea2eb16290100011100" + } + }, + { + "Name": "getblockheader", + "Request": { + "jsonrpc": "2.0", + "method": "getblockheader", + "params": [ 0, true ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": { + "hash": "0x5bb05a3b857c9eaaf94dc33fa5b4a2278601eefcdb90703698972ef7d029e445", + "size": 105, + "version": 0, + "previousblockhash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "merkleroot": "0x735b68ca1bab490b8fd6166cba4c2ce76e97bedfe4d2df0c333970fc9862bb2b", + "time": 1468595301000, + "index": 0, + "nextconsensus": "NZs2zXSPuuv9ZF6TDGSWT1RBmE8rfGj7UW", + "witnesses": [ + { + "invocation": "", + "verification": "EQ==" + } + ], + "confirmations": 2700, + "nextblockhash": "0x423173109798b038019b35129417b55cc4b5976ac79978dfab8ea2512d155f69" + } + } + }, + { + "Name": "getblockheader", + "Request": { + "jsonrpc": "2.0", + "method": "getblockheader", + "params": [ "0x5bb05a3b857c9eaaf94dc33fa5b4a2278601eefcdb90703698972ef7d029e445", true ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": { + "hash": "0x5bb05a3b857c9eaaf94dc33fa5b4a2278601eefcdb90703698972ef7d029e445", + "size": 105, + "version": 0, + "previousblockhash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "merkleroot": "0x735b68ca1bab490b8fd6166cba4c2ce76e97bedfe4d2df0c333970fc9862bb2b", + "time": 1468595301000, + "index": 0, + "nextconsensus": "NZs2zXSPuuv9ZF6TDGSWT1RBmE8rfGj7UW", + "witnesses": [ + { + "invocation": "", + "verification": "EQ==" + } + ], + "confirmations": 2700, + "nextblockhash": "0x423173109798b038019b35129417b55cc4b5976ac79978dfab8ea2512d155f69" + } + } + }, + { + "Name": "getblocksysfee", + "Request": { + "jsonrpc": "2.0", + "method": "getblocksysfee", + "params": [ 100 ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": "300000000" + } + }, + { + "Name": "getcontractstate", + "Request": { + "jsonrpc": "2.0", + "method": "getcontractstate", + "params": [ "0x8c23f196d8a1bfd103a9dcb1f9ccf0c611377d3b" ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": { + "id": -2, + "hash": "0x8c23f196d8a1bfd103a9dcb1f9ccf0c611377d3b", + "script": "QetD9PQ=", + "manifest": { + "groups": [], + "features": { + "storage": true, + "payable": false + }, + "abi": { + "hash": "0x8c23f196d8a1bfd103a9dcb1f9ccf0c611377d3b", + "entryPoint": { + "name": "Main", + "parameters": [ + { + "name": "operation", + "type": "String" + }, + { + "name": "args", + "type": "Array" + } + ], + "returnType": "Any" + }, + "methods": [ + { + "name": "getSysFeeAmount", + "parameters": [ + { + "name": "index", + "type": "Integer" + } + ], + "returnType": "Integer" + }, + { + "name": "name", + "parameters": [], + "returnType": "String" + }, + { + "name": "symbol", + "parameters": [], + "returnType": "String" + }, + { + "name": "decimals", + "parameters": [], + "returnType": "Integer" + }, + { + "name": "totalSupply", + "parameters": [], + "returnType": "Integer" + }, + { + "name": "balanceOf", + "parameters": [ + { + "name": "account", + "type": "Hash160" + } + ], + "returnType": "Integer" + }, + { + "name": "transfer", + "parameters": [ + { + "name": "from", + "type": "Hash160" + }, + { + "name": "to", + "type": "Hash160" + }, + { + "name": "amount", + "type": "Integer" + } + ], + "returnType": "Boolean" + }, + { + "name": "onPersist", + "parameters": [], + "returnType": "Boolean" + }, + { + "name": "supportedStandards", + "parameters": [], + "returnType": "Array" + } + ], + "events": [ + { + "name": "Transfer", + "parameters": [ + { + "name": "from", + "type": "Hash160" + }, + { + "name": "to", + "type": "Hash160" + }, + { + "name": "amount", + "type": "Integer" + } + ], + "returnType": "Signature" + } + ] + }, + "permissions": [ + { + "contract": "*", + "methods": "*" + } + ], + "trusts": [], + "safeMethods": [ + "getSysFeeAmount", + "name", + "symbol", + "decimals", + "totalSupply", + "balanceOf", + "supportedStandards" + ], + "extra": null + } + } + } + }, + { + "Name": "getrawmempool", + "Request": { + "jsonrpc": "2.0", + "method": "getrawmempool", + "params": [], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": [ "0x9786cce0dddb524c40ddbdd5e31a41ed1f6b5c8a683c122f627ca4a007a7cf4e", "0xb488ad25eb474f89d5ca3f985cc047ca96bc7373a6d3da8c0f192722896c1cd7" ] + } + }, + { + "Name": "getrawmempoolboth", + "Request": { + "jsonrpc": "2.0", + "method": "getrawmempool", + "params": [ true ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": { + "height": 2846, + "verified": [ "0x9786cce0dddb524c40ddbdd5e31a41ed1f6b5c8a683c122f627ca4a007a7cf4e" ], + "unverified": [ "0xb488ad25eb474f89d5ca3f985cc047ca96bc7373a6d3da8c0f192722896c1cd7" ] + } + } + }, + { + "Name": "getrawtransactionhex", + "Request": { + "jsonrpc": "2.0", + "method": "getrawtransaction", + "params": [ "0xd159457e12f6b0d4910fc6729f426be5d0c06f0f149d0836db9f634a5cf216fb" ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": "004cdec1396925aa554712439a9c613ba114efa3fac23ddbca00e1f50500000000466a130000000000311d200000016925aa554712439a9c613ba114efa3fac23ddbca015d030010a5d4e80000000c149903b0c3d292988febe5f306a02f654ea2eb16290c146925aa554712439a9c613ba114efa3fac23ddbca13c00c087472616e736665720c143b7d3711c6f0ccf9b1dca903d1bfa1d896f1238c41627d5b523901420c401f85b40d7fa12164aa1d4d18b06ca470f2c89572dc5b901ab1667faebb587cf536454b98a09018adac72376c5e7c5d164535155b763564347aa47b69aa01b3cc290c2103aa052fbcb8e5b33a4eefd662536f8684641f04109f1d5e69cdda6f084890286a0b410a906ad4" + } + }, + { + "Name": "getrawtransaction", + "Request": { + "jsonrpc": "2.0", + "method": "getrawtransaction", + "params": [ "0xd159457e12f6b0d4910fc6729f426be5d0c06f0f149d0836db9f634a5cf216fb", true ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": { + "hash": "0xd159457e12f6b0d4910fc6729f426be5d0c06f0f149d0836db9f634a5cf216fb", + "size": 272, + "version": 0, + "nonce": 969006668, + "sender": "NVVwFw6XyhtRCFQ8SpUTMdPyYt4Vd9A1XQ", + "sys_fee": "100000000", + "net_fee": "1272390", + "valid_until_block": 2104625, + "attributes": [], + "cosigners": [ + { + "account": "0xcadb3dc2faa3ef14a13b619c9a43124755aa2569", + "scopes": "CalledByEntry" + } + ], + "script": "AwAQpdToAAAADBSZA7DD0pKYj+vl8wagL2VOousWKQwUaSWqVUcSQ5qcYTuhFO+j+sI928oTwAwIdHJhbnNmZXIMFDt9NxHG8Mz5sdypA9G/odiW8SOMQWJ9W1I5", + "witnesses": [ + { + "invocation": "DEAfhbQNf6EhZKodTRiwbKRw8siVctxbkBqxZn+uu1h89TZFS5igkBitrHI3bF58XRZFNRVbdjVkNHqke2mqAbPM", + "verification": "DCEDqgUvvLjlszpO79ZiU2+GhGQfBBCfHV5pzdpvCEiQKGoLQQqQatQ=" + } + ], + "blockhash": "0xc1ed259e394c9cd93c1e0eb1e0f144c0d10da64861a24c0084f0d98270b698f1", + "confirmations": 643, + "blocktime": 1579417249620, + "vm_state": "HALT" + } + } + }, + { + "Name": "getstorage", + "Request": { + "jsonrpc": "2.0", + "method": "getstorage", + "params": [ "0x8c23f196d8a1bfd103a9dcb1f9ccf0c611377d3b", "146925aa554712439a9c613ba114efa3fac23ddbca" ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": "410121064c5d11a2a700" + } + }, + { + "Name": "getstorage", + "Request": { + "jsonrpc": "2.0", + "method": "getstorage", + "params": [ -2, "146925aa554712439a9c613ba114efa3fac23ddbca" ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": "410121064c5d11a2a700" + } + }, + { + "Name": "gettransactionheight", + "Request": { + "jsonrpc": "2.0", + "method": "gettransactionheight", + "params": [ "0xd159457e12f6b0d4910fc6729f426be5d0c06f0f149d0836db9f634a5cf216fb" ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": 2226 + } + }, + { + "Name": "getvalidators", + "Request": { + "jsonrpc": "2.0", + "method": "getvalidators", + "params": [], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": [ + { + "publickey": "03aa052fbcb8e5b33a4eefd662536f8684641f04109f1d5e69cdda6f084890286a", + "votes": "0", + "active": true + } + ] + } + }, + + + { + "Name": "getconnectioncount", + "Request": { + "jsonrpc": "2.0", + "method": "getconnectioncount", + "params": [], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": 0 + } + }, + { + "Name": "getpeers", + "Request": { + "jsonrpc": "2.0", + "method": "getpeers", + "params": [], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": { + "unconnected": [ + { + "address": "::ffff:70.73.16.236", + "port": 10333 + } + ], + "bad": [], + "connected": [ + { + "address": "::ffff:139.219.106.33", + "port": 10333 + }, + { + "address": "::ffff:47.88.53.224", + "port": 10333 + } + ] + } + } + }, + { + "Name": "getversion", + "Request": { + "jsonrpc": "2.0", + "method": "getversion", + "params": [], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": { + "tcp_port": 20333, + "ws_port": 20334, + "nonce": 592651621, + "user_agent": "/Neo:3.0.0-preview1/" + } + } + }, + { + "Name": "sendrawtransaction", + "Request": { + "jsonrpc": "2.0", + "method": "sendrawtransaction", + "params": [ "00142449186925aa554712439a9c613ba114efa3fac23ddbca00e1f50500000000a65a1300000000001d20200000016925aa554712439a9c613ba114efa3fac23ddbca01590200e1f5050c149903b0c3d292988febe5f306a02f654ea2eb16290c146925aa554712439a9c613ba114efa3fac23ddbca13c00c087472616e736665720c143b7d3711c6f0ccf9b1dca903d1bfa1d896f1238c41627d5b523901420c4076507ef5922e84aac57f09cb699ecbb10bc3d9c06ef908bed812c35fd2651531de27091f1e6e81566454fcc1c5f129d1051b08704c3fec3f6ed793563cfd30bb290c2103aa052fbcb8e5b33a4eefd662536f8684641f04109f1d5e69cdda6f084890286a0b410a906ad4" ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": { + "hash": "0x32cda8771aca33da2f7a022b33468fd658abd2521b58dd6ba1ffb89883903405" + } + } + }, + { + "Name": "submitblock", + "Request": { + "jsonrpc": "2.0", + "method": "submitblock", + "params": [ "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100010000" ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": { + "hash": "0xa11c9d14748f967178fe22fdcfb829354ae6ccb86824675e147cb128f16d8171" + } + } + }, + + + { + "Name": "invokefunction", + "Request": { + "jsonrpc": "2.0", + "method": "invokefunction", + "params": [ + "0x8c23f196d8a1bfd103a9dcb1f9ccf0c611377d3b", + "balanceOf", + [ + { + "type": "Hash160", + "value": "91b83e96f2a7c4fdf0c1688441ec61986c7cae26" + } + ] + ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": { + "script": "0c1426ae7c6c9861ec418468c1f0fdc4a7f2963eb89111c00c0962616c616e63654f660c143b7d3711c6f0ccf9b1dca903d1bfa1d896f1238c41627d5b52", + "state": "HALT", + "gas_consumed": "2007570", + "stack": [ + { + "type": "Integer", + "value": "0" + } + ], + "tx": "00d1eb88136925aa554712439a9c613ba114efa3fac23ddbca00e1f50500000000269f1200000000004520200000003e0c1426ae7c6c9861ec418468c1f0fdc4a7f2963eb89111c00c0962616c616e63654f660c143b7d3711c6f0ccf9b1dca903d1bfa1d896f1238c41627d5b5201420c40794c91299bba340ea2505c777d15ca898f75bcce686461066a2b8018cc1de114a122dcdbc77b447ac7db5fb1584f1533b164fbc8f30ddf5bd6acf016a125e983290c2103aa052fbcb8e5b33a4eefd662536f8684641f04109f1d5e69cdda6f084890286a0b410a906ad4" + } + } + }, + { + "Name": "invokescript", + "Request": { + "jsonrpc": "2.0", + "method": "invokescript", + "params": [ "10c30c046e616d650c143b7d3711c6f0ccf9b1dca903d1bfa1d896f1238c41627d5b5210c30c0673796d626f6c0c143b7d3711c6f0ccf9b1dca903d1bfa1d896f1238c41627d5b5210c30c08646563696d616c730c143b7d3711c6f0ccf9b1dca903d1bfa1d896f1238c41627d5b5210c30c0b746f74616c537570706c790c143b7d3711c6f0ccf9b1dca903d1bfa1d896f1238c41627d5b52" ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": { + "script": "10c30c046e616d650c143b7d3711c6f0ccf9b1dca903d1bfa1d896f1238c41627d5b5210c30c0673796d626f6c0c143b7d3711c6f0ccf9b1dca903d1bfa1d896f1238c41627d5b5210c30c08646563696d616c730c143b7d3711c6f0ccf9b1dca903d1bfa1d896f1238c41627d5b5210c30c0b746f74616c537570706c790c143b7d3711c6f0ccf9b1dca903d1bfa1d896f1238c41627d5b52", + "state": "HALT", + "gas_consumed": "5061560", + "stack": [ + { + "type": "ByteArray", + "value": "R0FT" + }, + { + "type": "ByteArray", + "value": "Z2Fz" + }, + { + "type": "Integer", + "value": "8" + }, + { + "type": "Integer", + "value": "3001101329992600" + } + ], + "tx": "00769d16556925aa554712439a9c613ba114efa3fac23ddbca00e1f505000000009e021400000000005620200000009910c30c046e616d650c143b7d3711c6f0ccf9b1dca903d1bfa1d896f1238c41627d5b5210c30c0673796d626f6c0c143b7d3711c6f0ccf9b1dca903d1bfa1d896f1238c41627d5b5210c30c08646563696d616c730c143b7d3711c6f0ccf9b1dca903d1bfa1d896f1238c41627d5b5210c30c0b746f74616c537570706c790c143b7d3711c6f0ccf9b1dca903d1bfa1d896f1238c41627d5b5201420c40c848d0fcbf5e6a820508242ea8b7ccbeed3caefeed5db570537279c2154f7cfd8b0d8f477f37f4e6ca912935b732684d57c455dff7aa525ad4ab000931f22208290c2103aa052fbcb8e5b33a4eefd662536f8684641f04109f1d5e69cdda6f084890286a0b410a906ad4" + } + } + }, + + + { + "Name": "listplugins", + "Request": { + "jsonrpc": "2.0", + "method": "listplugins", + "params": [], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": [ + { + "name": "ApplicationLogs", + "version": "3.0.0.0", + "interfaces": [ + "IPersistencePlugin" + ] + }, + { + "name": "LevelDBStore", + "version": "3.0.0.0", + "interfaces": [ + "IStoragePlugin" + ] + }, + { + "name": "RpcNep5Tracker", + "version": "3.0.0.0", + "interfaces": [ + "IPersistencePlugin" + ] + }, + { + "name": "RpcServer", + "version": "3.0.0.0", + "interfaces": [] + } + ] + } + }, + { + "Name": "validateaddress", + "Request": { + "jsonrpc": "2.0", + "method": "validateaddress", + "params": [ "NZs2zXSPuuv9ZF6TDGSWT1RBmE8rfGj7UW" ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": { + "address": "NZs2zXSPuuv9ZF6TDGSWT1RBmE8rfGj7UW", + "isvalid": true + } + } + }, + + + { + "Name": "closewallet", + "Request": { + "jsonrpc": "2.0", + "method": "closewallet", + "params": [], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": true + } + }, + { + "Name": "dumpprivkey", + "Request": { + "jsonrpc": "2.0", + "method": "dumpprivkey", + "params": [ "NVVwFw6XyhtRCFQ8SpUTMdPyYt4Vd9A1XQ" ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": "KyoYyZpoccbR6KZ25eLzhMTUxREwCpJzDsnuodGTKXSG8fDW9t7x" + } + }, + { + "Name": "getbalance", + "Request": { + "jsonrpc": "2.0", + "method": "getbalance", + "params": [ "0x8c23f196d8a1bfd103a9dcb1f9ccf0c611377d3b" ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": { + "balance": "3001101329992600" + } + } + }, + // mock decimals + { + "Name": "invokescript", + "Request": { + "jsonrpc": "2.0", + "method": "invokescript", + "params": [ "10c30c08646563696d616c730c143b7d3711c6f0ccf9b1dca903d1bfa1d896f1238c41627d5b52" ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": { + "script": "10c30c08646563696d616c730c143b7d3711c6f0ccf9b1dca903d1bfa1d896f1238c41627d5b52", + "state": "HALT", + "gas_consumed": "5061560", + "stack": [ + { + "type": "Integer", + "value": "8" + } + ], + "tx": "00769d16556925aa554712439a9c613ba114efa3fac23ddbca00e1f505000000009e021400000000005620200000009910c30c046e616d650c143b7d3711c6f0ccf9b1dca903d1bfa1d896f1238c41627d5b5210c30c0673796d626f6c0c143b7d3711c6f0ccf9b1dca903d1bfa1d896f1238c41627d5b5210c30c08646563696d616c730c143b7d3711c6f0ccf9b1dca903d1bfa1d896f1238c41627d5b5210c30c0b746f74616c537570706c790c143b7d3711c6f0ccf9b1dca903d1bfa1d896f1238c41627d5b5201420c40c848d0fcbf5e6a820508242ea8b7ccbeed3caefeed5db570537279c2154f7cfd8b0d8f477f37f4e6ca912935b732684d57c455dff7aa525ad4ab000931f22208290c2103aa052fbcb8e5b33a4eefd662536f8684641f04109f1d5e69cdda6f084890286a0b410a906ad4" + } + } + }, + { + "Name": "getnewaddress", + "Request": { + "jsonrpc": "2.0", + "method": "getnewaddress", + "params": [], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": "NXpCs9kcDkPvfyAobNYmFg8yfRZaDopDbf" + } + }, + { + "Name": "getunclaimedgas", + "Request": { + "jsonrpc": "2.0", + "method": "getunclaimedgas", + "params": [], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": "735870007400" + } + }, + { + "Name": "importprivkey", + "Request": { + "jsonrpc": "2.0", + "method": "importprivkey", + "params": [ "KyoYyZpoccbR6KZ25eLzhMTUxREwCpJzDsnuodGTKXSG8fDW9t7x" ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": { + "address": "NVVwFw6XyhtRCFQ8SpUTMdPyYt4Vd9A1XQ", + "haskey": true, + "label": null, + "watchonly": false + } + } + }, + { + "Name": "listaddress", + "Request": { + "jsonrpc": "2.0", + "method": "listaddress", + "params": [], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": [ + { + "address": "NVVwFw6XyhtRCFQ8SpUTMdPyYt4Vd9A1XQ", + "haskey": true, + "label": null, + "watchonly": false + }, + { + "address": "NZs2zXSPuuv9ZF6TDGSWT1RBmE8rfGj7UW", + "haskey": true, + "label": null, + "watchonly": false + } + ] + } + }, + { + "Name": "openwallet", + "Request": { + "jsonrpc": "2.0", + "method": "openwallet", + "params": [ "D:\\temp\\3.json", "1111" ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": true + } + }, + { + "Name": "sendfrom", + "Request": { + "jsonrpc": "2.0", + "method": "sendfrom", + "params": [ "0x8c23f196d8a1bfd103a9dcb1f9ccf0c611377d3b", "NVVwFw6XyhtRCFQ8SpUTMdPyYt4Vd9A1XQ", "NZs2zXSPuuv9ZF6TDGSWT1RBmE8rfGj7UW", "100.123" ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": { + "hash": "0x035facc3be1fc57da1690e3d2f8214f449d368437d8557ffabb2d408caf9ad76", + "size": 272, + "version": 0, + "nonce": 1553700339, + "sender": "NVVwFw6XyhtRCFQ8SpUTMdPyYt4Vd9A1XQ", + "sys_fee": "100000000", + "net_fee": "1272390", + "valid_until_block": 2105487, + "attributes": [], + "cosigners": [ + { + "account": "0xcadb3dc2faa3ef14a13b619c9a43124755aa2569", + "scopes": "CalledByEntry" + } + ], + "script": "A+CSx1QCAAAADBSZA7DD0pKYj+vl8wagL2VOousWKQwUaSWqVUcSQ5qcYTuhFO+j+sI928oTwAwIdHJhbnNmZXIMFDt9NxHG8Mz5sdypA9G/odiW8SOMQWJ9W1I5", + "witnesses": [ + { + "invocation": "DEDOA/QF5jYT2TCl9T94fFwAncuBhVhciISaq4fZ3WqGarEoT/0iDo3RIwGjfRW0mm/SV3nAVGEQeZInLqKQ98HX", + "verification": "DCEDqgUvvLjlszpO79ZiU2+GhGQfBBCfHV5pzdpvCEiQKGoLQQqQatQ=" + } + ] + } + } + }, + { + "Name": "sendmany", + "Request": { + "jsonrpc": "2.0", + "method": "sendmany", + "params": [ + "NVVwFw6XyhtRCFQ8SpUTMdPyYt4Vd9A1XQ", + [ + { + "asset": "0x9bde8f209c88dd0e7ca3bf0af0f476cdd8207789", + "value": "10", + "address": "NVVwFw6XyhtRCFQ8SpUTMdPyYt4Vd9A1XQ" + }, + { + "asset": "0x8c23f196d8a1bfd103a9dcb1f9ccf0c611377d3b", + "value": "1.2345", + "address": "NZs2zXSPuuv9ZF6TDGSWT1RBmE8rfGj7UW" + } + ] + ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": { + "hash": "0x542e64a9048bbe1ee565b840c41ccf9b5a1ef11f52e5a6858a523938a20c53ec", + "size": 483, + "version": 0, + "nonce": 34429660, + "sender": "NUMK37TV9yYKbJr1Gufh74nZiM623eBLqX", + "sys_fee": "100000000", + "net_fee": "2483780", + "valid_until_block": 2105494, + "attributes": [], + "cosigners": [ + { + "account": "0x36d6200fb4c9737c7b552d2b5530ab43605c5869", + "scopes": "CalledByEntry" + }, + { + "account": "0x9a55ca1006e2c359bbc8b9b0de6458abdff98b5c", + "scopes": "CalledByEntry" + } + ], + "script": "GgwUaSWqVUcSQ5qcYTuhFO+j+sI928oMFGlYXGBDqzBVKy1Ve3xzybQPINY2E8AMCHRyYW5zZmVyDBSJdyDYzXb08Aq/o3wO3YicII/em0FifVtSOQKQslsHDBSZA7DD0pKYj+vl8wagL2VOousWKQwUXIv536tYZN6wuci7WcPiBhDKVZoTwAwIdHJhbnNmZXIMFDt9NxHG8Mz5sdypA9G/odiW8SOMQWJ9W1I5", + "witnesses": [ + { + "invocation": "DECOdTEWg1WkuHN0GNV67kwxeuKADyC6TO59vTaU5dK6K1BGt8+EM6L3TdMga4qB2J+Meez8eYwZkSSRubkuvfr9", + "verification": "DCECeiS9CyBqFJwNKzonOs/yzajOraFep4IqFJVxBe6TesULQQqQatQ=" + }, + { + "invocation": "DEB1Laj6lvjoBJLTgE/RdvbJiXOmaKp6eNWDJt+p8kxnW6jbeKoaBRZWfUflqrKV7mZEE2JHA5MxrL5TkRIvsL5K", + "verification": "DCECkXL4gxd936eGEDt3KWfIuAsBsQcfyyBUcS8ggF6lZnwLQQqQatQ=" + } + ] + } + } + }, + { + "Name": "sendtoaddress", + "Request": { + "jsonrpc": "2.0", + "method": "sendtoaddress", + "params": [ "0x8c23f196d8a1bfd103a9dcb1f9ccf0c611377d3b", "NVVwFw6XyhtRCFQ8SpUTMdPyYt4Vd9A1XQ", "100.123" ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": { + "hash": "0xee5fc3f57d9f9bc9695c88ecc504444aab622b1680b1cb0848d5b6e39e7fd118", + "size": 381, + "version": 0, + "nonce": 330056065, + "sender": "NUMK37TV9yYKbJr1Gufh74nZiM623eBLqX", + "sys_fee": "100000000", + "net_fee": "2381780", + "valid_until_block": 2105500, + "attributes": [], + "cosigners": [ + { + "account": "0xcadb3dc2faa3ef14a13b619c9a43124755aa2569", + "scopes": "CalledByEntry" + } + ], + "script": "A+CSx1QCAAAADBRpJapVRxJDmpxhO6EU76P6wj3bygwUaSWqVUcSQ5qcYTuhFO+j+sI928oTwAwIdHJhbnNmZXIMFDt9NxHG8Mz5sdypA9G/odiW8SOMQWJ9W1I5", + "witnesses": [ + { + "invocation": "DECruSKmQKs0Y2cxplKROjPx8HKiyiYrrPn7zaV9zwHPumLzFc8DvgIo2JxmTnJsORyygN/su8mTmSLLb3PesBvY", + "verification": "DCECkXL4gxd936eGEDt3KWfIuAsBsQcfyyBUcS8ggF6lZnwLQQqQatQ=" + }, + { + "invocation": "DECS5npCs5PwsPUAQ01KyHyCev27dt3kDdT1Vi0K8PwnEoSlxYTOGGQCAwaiNEXSyBdBmT6unhZydmFnkezD7qzW", + "verification": "DCEDqgUvvLjlszpO79ZiU2+GhGQfBBCfHV5pzdpvCEiQKGoLQQqQatQ=" + } + ] + } + } + }, + + + { + "Name": "getapplicationlog", + "Request": { + "jsonrpc": "2.0", + "method": "getapplicationlog", + "params": [ "0x183cd84359cd9f8b956afcd02403ec07361c1dba55f0800241b4ef2b28e88bbb" ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": { + "txid": "0x183cd84359cd9f8b956afcd02403ec07361c1dba55f0800241b4ef2b28e88bbb", + "trigger": "Application", + "vmstate": "HALT", + "gas_consumed": "9007810", + "stack": [], + "notifications": [ + { + "contract": "0x8c23f196d8a1bfd103a9dcb1f9ccf0c611377d3b", + "state": { + "type": "Array", + "value": [ + { + "type": "ByteArray", + "value": "VHJhbnNmZXI=" + }, + { + "type": "Any" + }, + { + "type": "ByteArray", + "value": "eU9We10tADBFvus3caGe5hjcaNE=" + }, + { + "type": "Integer", + "value": "6321697534537" + } + ] + } + }, + { + "contract": "0x9bde8f209c88dd0e7ca3bf0af0f476cdd8207789", + "state": { + "type": "Array", + "value": [ + { + "type": "ByteArray", + "value": "VHJhbnNmZXI=" + }, + { + "type": "ByteArray", + "value": "eU9We10tADBFvus3caGe5hjcaNE=" + }, + { + "type": "ByteArray", + "value": "eU9We10tADBFvus3caGe5hjcaNE=" + }, + { + "type": "Integer", + "value": "99999961" + } + ] + } + } + ] + } + } + }, + { + "Name": "getnep5transfers", + "Request": { + "jsonrpc": "2.0", + "method": "getnep5transfers", + "params": [ "NVVwFw6XyhtRCFQ8SpUTMdPyYt4Vd9A1XQ", 0, 1868595301000 ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": { + "sent": [ + { + "timestamp": 1579250114541, + "asset_hash": "0x8c23f196d8a1bfd103a9dcb1f9ccf0c611377d3b", + "transfer_address": "NVVwFw6XyhtRCFQ8SpUTMdPyYt4Vd9A1XQ", + "amount": "1000000000", + "block_index": 603, + "transfer_notify_index": 0, + "tx_hash": "0x5e177b8d1dc33e9103c0cfd42f6dbf4efbe43029e2d6a18ea5ba0cb8437056b3" + }, + { + "timestamp": 1579406581635, + "asset_hash": "0x8c23f196d8a1bfd103a9dcb1f9ccf0c611377d3b", + "transfer_address": "NUMK37TV9yYKbJr1Gufh74nZiM623eBLqX", + "amount": "1000000000", + "block_index": 1525, + "transfer_notify_index": 0, + "tx_hash": "0xc9c618b48972b240e0058d97b8d79b807ad51015418c84012765298526aeb77d" + } + ], + "received": [ + { + "timestamp": 1579250114541, + "asset_hash": "0x8c23f196d8a1bfd103a9dcb1f9ccf0c611377d3b", + "transfer_address": "NVVwFw6XyhtRCFQ8SpUTMdPyYt4Vd9A1XQ", + "amount": "1000000000", + "block_index": 603, + "transfer_notify_index": 0, + "tx_hash": "0x5e177b8d1dc33e9103c0cfd42f6dbf4efbe43029e2d6a18ea5ba0cb8437056b3" + } + ], + "address": "NVVwFw6XyhtRCFQ8SpUTMdPyYt4Vd9A1XQ" + } + } + }, + { + "Name": "getnep5balances", + "Request": { + "jsonrpc": "2.0", + "method": "getnep5balances", + "params": [ "NVVwFw6XyhtRCFQ8SpUTMdPyYt4Vd9A1XQ" ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": { + "balance": [ + { + "asset_hash": "0x8c23f196d8a1bfd103a9dcb1f9ccf0c611377d3b", + "amount": "719978585420", + "last_updated_block": 3101 + }, + { + "asset_hash": "0x9bde8f209c88dd0e7ca3bf0af0f476cdd8207789", + "amount": "89999810", + "last_updated_block": 3096 + } + ], + "address": "NVVwFw6XyhtRCFQ8SpUTMdPyYt4Vd9A1XQ" + } + } + } +] diff --git a/tests/Neo.Network.RPC.Tests/TestUtils.cs b/tests/Neo.Network.RPC.Tests/TestUtils.cs index dd1b45aa0..2c4128376 100644 --- a/tests/Neo.Network.RPC.Tests/TestUtils.cs +++ b/tests/Neo.Network.RPC.Tests/TestUtils.cs @@ -1,10 +1,16 @@ +using Neo.IO.Json; using Neo.Network.P2P.Payloads; +using Neo.Network.RPC.Models; +using System.Collections.Generic; +using System.IO; using System.Linq; namespace Neo.Network.RPC.Tests { internal static class TestUtils { + public readonly static List RpcTestCases = ((JArray)JObject.Parse(File.ReadAllText("RpcTestCases.json"))).Select(p => RpcTestCase.FromJson(p)).ToList(); + public static Block GetBlock(int txCount) { return new Block @@ -46,4 +52,32 @@ public static Transaction GetTransaction() }; } } + + internal class RpcTestCase + { + public string Name { get; set; } + public RpcRequest Request { get; set; } + public RpcResponse Response { get; set; } + + public JObject ToJson() + { + return new JObject + { + ["Name"] = Name, + ["Request"] = Request.ToJson(), + ["Response"] = Response.ToJson(), + }; + } + + public static RpcTestCase FromJson(JObject json) + { + return new RpcTestCase + { + Name = json["Name"].AsString(), + Request = RpcRequest.FromJson(json["Request"]), + Response = RpcResponse.FromJson(json["Response"]), + }; + } + + } } diff --git a/tests/Neo.Network.RPC.Tests/UT_Nep5API.cs b/tests/Neo.Network.RPC.Tests/UT_Nep5API.cs index b21482441..8454d4afa 100644 --- a/tests/Neo.Network.RPC.Tests/UT_Nep5API.cs +++ b/tests/Neo.Network.RPC.Tests/UT_Nep5API.cs @@ -63,7 +63,7 @@ public void TestGetDecimals() UT_TransactionManager.MockInvokeScript(rpcClientMock, testScript, new ContractParameter { Type = ContractParameterType.Integer, Value = new BigInteger(NativeContract.GAS.Decimals) }); var result = nep5API.Decimals(NativeContract.GAS.Hash); - Assert.AreEqual(NativeContract.GAS.Decimals, (byte)result); + Assert.AreEqual(NativeContract.GAS.Decimals, result); } [TestMethod] diff --git a/tests/Neo.Network.RPC.Tests/UT_RpcClient.cs b/tests/Neo.Network.RPC.Tests/UT_RpcClient.cs index b6ccbad17..4020555ca 100644 --- a/tests/Neo.Network.RPC.Tests/UT_RpcClient.cs +++ b/tests/Neo.Network.RPC.Tests/UT_RpcClient.cs @@ -4,12 +4,8 @@ using Moq.Protected; using Neo.IO; using Neo.IO.Json; -using Neo.Ledger; using Neo.Network.P2P.Payloads; using Neo.Network.RPC.Models; -using Neo.SmartContract; -using Neo.SmartContract.Manifest; -using Neo.VM; using System; using System.Linq; using System.Net; @@ -37,522 +33,414 @@ public void TestSetup() }; rpc = new RpcClient(httpClient); + foreach (var test in TestUtils.RpcTestCases) + { + MockResponse(test.Request, test.Response); + } } - private void MockResponse(string content) + private void MockResponse(RpcRequest request, RpcResponse response) { handlerMock.Protected() // Setup the PROTECTED method to mock .Setup>( "SendAsync", - ItExpr.IsAny(), + ItExpr.Is(p => p.Content.ReadAsStringAsync().Result == request.ToJson().ToString()), ItExpr.IsAny() ) // prepare the expected response of the mocked http call .ReturnsAsync(new HttpResponseMessage() { StatusCode = HttpStatusCode.OK, - Content = new StringContent(content), + Content = new StringContent(response.ToJson().ToString()), }) .Verifiable(); } - private JObject CreateErrorResponse(JObject id, int code, string message, JObject data = null) - { - JObject response = CreateResponse(id); - response["error"] = new JObject(); - response["error"]["code"] = code; - response["error"]["message"] = message; - if (data != null) - response["error"]["data"] = data; - return response; - } - - private JObject CreateResponse(JObject id) - { - JObject response = new JObject(); - response["jsonrpc"] = "2.0"; - response["id"] = id; - return response; - } - [TestMethod] public void TestErrorResponse() { - JObject response = CreateErrorResponse(null, -32700, "Parse error"); - MockResponse(response.ToString()); + var test = TestUtils.RpcTestCases.Find(p => p.Name == (nameof(rpc.SendRawTransaction) + "error").ToLower()); try { - var result = rpc.GetBlockHex("773dd2dae4a9c9275290f89b56e67d7363ea4826dfd4fc13cc01cf73a44b0d0e"); + var result = rpc.SendRawTransaction(test.Request.Params[0].AsString().HexToBytes().AsSerializable()); } catch (RpcException ex) { - Assert.AreEqual(-32700, ex.HResult); - Assert.AreEqual("Parse error", ex.Message); + Assert.AreEqual(-500, ex.HResult); + Assert.AreEqual("InsufficientFunds", ex.Message); } } [TestMethod] - public void TestGetBestBlockHash() + public void TestConstructorByUrlAndDispose() { - JObject response = CreateResponse(1); - response["result"] = "000000002deadfa82cbc4682f5800"; - MockResponse(response.ToString()); + //dummy url for test + var client = new RpcClient("http://www.xxx.yyy"); + Action action = () => client.Dispose(); + action.Should().NotThrow(); + } + + [TestMethod] + public void TestConstructorWithBasicAuth() + { + var client = new RpcClient("http://www.xxx.yyy", "krain", "123456"); + client.Dispose(); + } + + #region Blockchain + [TestMethod] + public void TestGetBestBlockHash() + { + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetBestBlockHash).ToLower()); var result = rpc.GetBestBlockHash(); - Assert.AreEqual("000000002deadfa82cbc4682f5800", result); + Assert.AreEqual(test.Response.Result.AsString(), result); } [TestMethod] public void TestGetBlockHex() { - JObject response = CreateResponse(1); - response["result"] = "000000002deadfa82cbc4682f5800"; - MockResponse(response.ToString()); - - var result = rpc.GetBlockHex("773dd2dae4a9c9275290f89b56e67d7363ea4826dfd4fc13cc01cf73a44b0d0e"); - Assert.AreEqual("000000002deadfa82cbc4682f5800", result); + var tests = TestUtils.RpcTestCases.Where(p => p.Name == nameof(rpc.GetBlockHex).ToLower()); + foreach (var test in tests) + { + var result = rpc.GetBlockHex(test.Request.Params[0].AsString()); + Assert.AreEqual(test.Response.Result.AsString(), result); + } } [TestMethod] public void TestGetBlock() { - // create block - var block = TestUtils.GetBlock(3); - - JObject json = block.ToJson(); - json["confirmations"] = 20; - JObject response = CreateResponse(1); - response["result"] = json; - MockResponse(response.ToString()); - - var result = rpc.GetBlock("773dd2dae4a9c9275290f89b56e67d7363ea4826dfd4fc13cc01cf73a44b0d0e"); - Assert.AreEqual(block.Hash.ToString(), result.Block.Hash.ToString()); - Assert.IsNull(result.NextBlockHash); - Assert.AreEqual(20, result.Confirmations); - Assert.AreEqual(block.Transactions.Length, result.Block.Transactions.Length); - Assert.AreEqual(block.Transactions[0].Hash.ToString(), result.Block.Transactions[0].Hash.ToString()); - - // verbose with confirmations - json["confirmations"] = 20; - json["nextblockhash"] = "773dd2dae4a9c9275290f89b56e67d7363ea4826dfd4fc13cc01cf73a44b0d0e"; - MockResponse(response.ToString()); - result = rpc.GetBlock("773dd2dae4a9c9275290f89b56e67d7363ea4826dfd4fc13cc01cf73a44b0d0e"); - Assert.AreEqual(block.Hash.ToString(), result.Block.Hash.ToString()); - Assert.AreEqual(20, result.Confirmations); - Assert.AreEqual("0x773dd2dae4a9c9275290f89b56e67d7363ea4826dfd4fc13cc01cf73a44b0d0e", result.NextBlockHash.ToString()); - Assert.AreEqual(block.Transactions.Length, result.Block.Transactions.Length); - Assert.AreEqual(block.Transactions[0].Hash.ToString(), result.Block.Transactions[0].Hash.ToString()); + var tests = TestUtils.RpcTestCases.Where(p => p.Name == nameof(rpc.GetBlock).ToLower()); + foreach (var test in tests) + { + var result = rpc.GetBlock(test.Request.Params[0].AsString()); + Assert.AreEqual(test.Response.Result.AsString(), result.ToJson().ToString()); + } } [TestMethod] public void TestGetBlockCount() { - JObject response = CreateResponse(1); - response["result"] = 100; - MockResponse(response.ToString()); - + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetBlockCount).ToLower()); var result = rpc.GetBlockCount(); - Assert.AreEqual(100u, result); + Assert.AreEqual(test.Response.Result.AsString(), result.ToString()); } [TestMethod] public void TestGetBlockHash() { - JObject response = CreateResponse(1); - response["result"] = "0x4c1e879872344349067c3b1a30781eeb4f9040d3795db7922f513f6f9660b9b2"; - MockResponse(response.ToString()); - - var result = rpc.GetBlockHash(100); - Assert.AreEqual("0x4c1e879872344349067c3b1a30781eeb4f9040d3795db7922f513f6f9660b9b2", result); + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetBlockHash).ToLower()); + var result = rpc.GetBlockHash((int)test.Request.Params[0].AsNumber()); + Assert.AreEqual(test.Response.Result.AsString(), result.ToString()); } [TestMethod] public void TestGetBlockHeaderHex() { - JObject response = CreateResponse(1); - response["result"] = "0x4c1e879872344349067c3b1a30781eeb4f9040d3795db7922f513f6f9660b9b2"; - MockResponse(response.ToString()); - - var result = rpc.GetBlockHeaderHex("100"); - Assert.AreEqual("0x4c1e879872344349067c3b1a30781eeb4f9040d3795db7922f513f6f9660b9b2", result); + var tests = TestUtils.RpcTestCases.Where(p => p.Name == nameof(rpc.GetBlockHeaderHex).ToLower()); + foreach (var test in tests) + { + var result = rpc.GetBlockHeaderHex(test.Request.Params[0].AsString()); + Assert.AreEqual(test.Response.Result.AsString(), result); + } } [TestMethod] public void TestGetBlockHeader() { - Header header = TestUtils.GetHeader(); + var tests = TestUtils.RpcTestCases.Where(p => p.Name == nameof(rpc.GetBlockHeader).ToLower()); + foreach (var test in tests) + { + var result = rpc.GetBlockHeader(test.Request.Params[0].AsString()); + Assert.AreEqual(test.Response.Result.ToString(), result.ToJson().ToString()); + } + } - JObject json = header.ToJson(); - json["confirmations"] = 20; - JObject response = CreateResponse(1); - response["result"] = json; - MockResponse(response.ToString()); + [TestMethod] + public void TestGetBlockSysFee() + { + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetBlockSysFee).ToLower()); + var result = rpc.GetBlockSysFee((int)test.Request.Params[0].AsNumber()); + Assert.AreEqual(test.Response.Result.AsString(), result.ToString()); + } - var result = rpc.GetBlockHeader("100"); - Assert.AreEqual(header.Hash.ToString(), result.Header.Hash.ToString()); - Assert.IsNull(result.NextBlockHash); - Assert.AreEqual(20, result.Confirmations); + [TestMethod] + public void TestGetContractState() + { + var tests = TestUtils.RpcTestCases.Where(p => p.Name == nameof(rpc.GetContractState).ToLower()); + foreach (var test in tests) + { + var result = rpc.GetContractState(test.Request.Params[0].AsString()); + Assert.AreEqual(test.Response.Result.ToString(), result.ToJson().ToString()); + } + } - json["confirmations"] = 20; - json["nextblockhash"] = "4c1e879872344349067c3b1a30781eeb4f9040d3795db7922f513f6f9660b9b2"; - MockResponse(response.ToString()); - result = rpc.GetBlockHeader("100"); - Assert.AreEqual(header.Hash.ToString(), result.Header.Hash.ToString()); - Assert.AreEqual(20, result.Confirmations); + [TestMethod] + public void TestGetRawMempool() + { + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetRawMempool).ToLower()); + var result = rpc.GetRawMempool(); + Assert.AreEqual(test.Response.Result.ToString(), ((JArray)result.Select(p => (JObject)p).ToArray()).ToString()); } [TestMethod] - public void TestGetBlockSysFee() + public void TestGetRawMempoolBoth() { - JObject response = CreateResponse(1); - response["result"] = "195500"; - MockResponse(response.ToString()); + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetRawMempoolBoth).ToLower()); + var result = rpc.GetRawMempoolBoth(); + Assert.AreEqual(test.Response.Result.ToString(), result.ToJson().ToString()); + } - var result = rpc.GetBlockSysFee(100); - Assert.AreEqual("195500", result); + [TestMethod] + public void TestGetRawTransactionHex() + { + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetRawTransactionHex).ToLower()); + var result = rpc.GetRawTransactionHex(test.Request.Params[0].AsString()); + Assert.AreEqual(test.Response.Result.AsString(), result); } [TestMethod] - public void TestGetConnectionCount() + public void TestGetRawTransaction() { - JObject response = CreateResponse(1); - response["result"] = 9; - MockResponse(response.ToString()); + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetRawTransaction).ToLower()); + var result = rpc.GetRawTransaction(test.Request.Params[0].AsString()); + Assert.AreEqual(test.Response.Result.ToString(), result.ToJson().ToString()); + } - var result = rpc.GetConnectionCount(); - Assert.AreEqual(9, result); + [TestMethod] + public void TestGetStorage() + { + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetStorage).ToLower()); + var result = rpc.GetStorage(test.Request.Params[0].AsString(), test.Request.Params[1].AsString()); + Assert.AreEqual(test.Response.Result.AsString(), result); } [TestMethod] - public void TestGetContractState() + public void TestGetTransactionHeight() { - byte[] script; - using (var sb = new ScriptBuilder()) - { - sb.EmitSysCall(InteropService.Runtime.GetInvocationCounter); - script = sb.ToArray(); - } + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetTransactionHeight).ToLower()); + var result = rpc.GetTransactionHeight(test.Request.Params[0].AsString()); + Assert.AreEqual(test.Response.Result.ToString(), result.ToString()); + } - ContractState state = new ContractState - { - Script = new byte[] { (byte)OpCode.DROP, (byte)OpCode.DROP }.Concat(script).ToArray(), - Manifest = ContractManifest.CreateDefault(UInt160.Parse("0xa400ff00ff00ff00ff00ff00ff00ff00ff00ff01")) - }; + [TestMethod] + public void TestGetValidators() + { + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetValidators).ToLower()); + var result = rpc.GetValidators(); + Assert.AreEqual(test.Response.Result.ToString(), ((JArray)result.Select(p => p.ToJson()).ToArray()).ToString()); + } - JObject response = CreateResponse(1); - response["result"] = state.ToJson(); - MockResponse(response.ToString()); + #endregion Blockchain - var result = rpc.GetContractState("17694b31cc7ee215cea2ded146e0b2b28768fc46"); + #region Node - Assert.AreEqual(state.Script.ToHexString(), result.Script.ToHexString()); - Assert.AreEqual(state.Manifest.Abi.EntryPoint.Name, result.Manifest.Abi.EntryPoint.Name); + [TestMethod] + public void TestGetConnectionCount() + { + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetConnectionCount).ToLower()); + var result = rpc.GetConnectionCount(); + Assert.AreEqual(test.Response.Result.ToString(), result.ToString()); } [TestMethod] public void TestGetPeers() { - JObject response = CreateResponse(1); - response["result"] = JObject.Parse(@"{ - ""unconnected"": [ - { - ""address"": ""::ffff:70.73.16.236"", - ""port"": 10333 - }, - { - ""address"": ""::ffff:82.95.77.148"", - ""port"": 10333 - }, - { - ""address"": ""::ffff:49.50.215.166"", - ""port"": 10333 - } - ], - ""bad"": [], - ""connected"": [ - { - ""address"": ""::ffff:139.219.106.33"", - ""port"": 10333 - }, - { - ""address"": ""::ffff:47.88.53.224"", - ""port"": 10333 - } - ] - }"); - MockResponse(response.ToString()); - + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetPeers).ToLower()); var result = rpc.GetPeers(); - Assert.AreEqual("::ffff:139.219.106.33", result.Connected[0].Address); - Assert.AreEqual("::ffff:82.95.77.148", result.Unconnected[1].Address); + Assert.AreEqual(test.Response.Result.ToString(), result.ToJson().ToString()); } [TestMethod] - public void TestGetRawMempool() + public void TestGetVersion() { - JObject response = CreateResponse(1); - response["result"] = JObject.Parse(@"[ - ""0x9786cce0dddb524c40ddbdd5e31a41ed1f6b5c8a683c122f627ca4a007a7cf4e"", - ""0xb488ad25eb474f89d5ca3f985cc047ca96bc7373a6d3da8c0f192722896c1cd7"", - ""0xf86f6f2c08fbf766ebe59dc84bc3b8829f1053f0a01deb26bf7960d99fa86cd6"" - ]"); - MockResponse(response.ToString()); + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetVersion).ToLower()); + var result = rpc.GetVersion(); + Assert.AreEqual(test.Response.Result.ToString(), result.ToJson().ToString()); + } - var result = rpc.GetRawMempool(); - Assert.AreEqual("0xb488ad25eb474f89d5ca3f985cc047ca96bc7373a6d3da8c0f192722896c1cd7", result[1]); + [TestMethod] + public void TestSendRawTransaction() + { + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.SendRawTransaction).ToLower()); + var result = rpc.SendRawTransaction(test.Request.Params[0].AsString().HexToBytes().AsSerializable()); + Assert.AreEqual(test.Response.Result["hash"].AsString(), result.ToString()); } [TestMethod] - public void TestGetRawMempoolBoth() + public void TestSubmitBlock() { - JObject json = new JObject(); - json["height"] = 65535; - json["verified"] = new JArray(new[] { "0x9786cce0dddb524c40ddbdd5e31a41ed1f6b5c8a683c122f627ca4a007a7cf4e" }.Select(p => (JObject)p)); - json["unverified"] = new JArray(new[] { "0xb488ad25eb474f89d5ca3f985cc047ca96bc7373a6d3da8c0f192722896c1cd7", "0xf86f6f2c08fbf766ebe59dc84bc3b8829f1053f0a01deb26bf7960d99fa86cd6" }.Select(p => (JObject)p)); + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.SubmitBlock).ToLower()); + var block = TestUtils.GetBlock(2).Hash; + var result = rpc.SubmitBlock(test.Request.Params[0].AsString().HexToBytes()); + Assert.AreEqual(test.Response.Result["hash"].AsString(), result.ToString()); + } - JObject response = CreateResponse(1); - response["result"] = json; - MockResponse(response.ToString()); + #endregion Node - var result = rpc.GetRawMempoolBoth(); - Assert.AreEqual(65535u, result.Height); - Assert.AreEqual("0x9786cce0dddb524c40ddbdd5e31a41ed1f6b5c8a683c122f627ca4a007a7cf4e", result.Verified[0]); - Assert.AreEqual("0xf86f6f2c08fbf766ebe59dc84bc3b8829f1053f0a01deb26bf7960d99fa86cd6", result.UnVerified[1]); + #region SmartContract + + [TestMethod] + public void TestInvokeFunction() + { + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.InvokeFunction).ToLower()); + var result = rpc.InvokeFunction(test.Request.Params[0].AsString(), test.Request.Params[1].AsString(), + ((JArray)test.Request.Params[2]).Select(p => RpcStack.FromJson(p)).ToArray()); + Assert.AreEqual(test.Response.Result.ToString(), result.ToJson().ToString()); } [TestMethod] - public void TestGetRawTransactionHex() + public void TestInvokeScript() { - var json = TestUtils.GetTransaction().ToArray().ToHexString(); + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.InvokeScript).ToLower()); + var result = rpc.InvokeScript(test.Request.Params[0].AsString().HexToBytes()); + Assert.AreEqual(test.Response.Result.ToString(), result.ToJson().ToString()); + } - JObject response = CreateResponse(1); - response["result"] = json; - MockResponse(response.ToString()); + #endregion SmartContract - //var result = rpc.GetRawTransactionHex("0x9786cce0dddb524c40ddbdd5e31a41ed1f6b5c8a683c122f627ca4a007a7cf4e"); - var result = rpc.GetRawTransactionHex(TestUtils.GetTransaction().Hash.ToString()); - Assert.AreEqual(json, result); - } + #region Utilities [TestMethod] - public void TestGetRawTransaction() + public void TestListPlugins() { - var transaction = TestUtils.GetTransaction(); - JObject json = transaction.ToJson(); - JObject response = CreateResponse(1); - response["result"] = json; - MockResponse(response.ToString()); - - var result = rpc.GetRawTransaction("0x9786cce0dddb524c40ddbdd5e31a41ed1f6b5c8a683c122f627ca4a007a7cf4e"); - Assert.AreEqual(transaction.Hash, result.Transaction.Hash); - Assert.AreEqual(json.ToString(), result.ToJson().ToString()); + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.ListPlugins).ToLower()); + var result = rpc.ListPlugins(); + Assert.AreEqual(test.Response.Result.ToString(), ((JArray)result.Select(p => p.ToJson()).ToArray()).ToString()); + } - // make the code compatible with the old version - json["blockhash"] = UInt256.Zero.ToString(); - json["confirmations"] = 100; - json["blocktime"] = 10; - MockResponse(response.ToString()); + [TestMethod] + public void TestValidateAddress() + { + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.ValidateAddress).ToLower()); + var result = rpc.ValidateAddress(test.Request.Params[0].AsString()); + Assert.AreEqual(test.Response.Result.ToString(), result.ToJson().ToString()); + } - result = rpc.GetRawTransaction("0x9786cce0dddb524c40ddbdd5e31a41ed1f6b5c8a683c122f627ca4a007a7cf4e"); - Assert.AreEqual(transaction.Hash, result.Transaction.Hash); - Assert.AreEqual(100, result.Confirmations); - Assert.AreEqual(null, result.VMState); - Assert.AreEqual(json.ToString(), result.ToJson().ToString()); + #endregion Utilities - json["vmState"] = VMState.HALT; - MockResponse(response.ToString()); + #region Wallet - result = rpc.GetRawTransaction("0x9786cce0dddb524c40ddbdd5e31a41ed1f6b5c8a683c122f627ca4a007a7cf4e"); - Assert.AreEqual(transaction.Hash, result.Transaction.Hash); - Assert.AreEqual(100, result.Confirmations); - Assert.AreEqual(VMState.HALT, result.VMState); - Assert.AreEqual(json.ToString(), result.ToJson().ToString()); + [TestMethod] + public void TestCloseWallet() + { + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.CloseWallet).ToLower()); + var result = rpc.CloseWallet(); + Assert.AreEqual(test.Response.Result.AsBoolean(), result); } [TestMethod] - public void TestGetStorage() + public void TestDumpPrivKey() { - JObject json = "4c696e"; - JObject response = CreateResponse(1); - response["result"] = json; - MockResponse(response.ToString()); - - var result = rpc.GetStorage("03febccf81ac85e3d795bc5cbd4e84e907812aa3", "5065746572"); - Assert.AreEqual("4c696e", result); + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.DumpPrivKey).ToLower()); + var result = rpc.DumpPrivKey(test.Request.Params[0].AsString()); + Assert.AreEqual(test.Response.Result.AsString(), result); } [TestMethod] - public void TestGetTransactionHeight() + public void TestGetBalance() { - JObject json = 10000; - JObject response = CreateResponse(1); - response["result"] = json; - MockResponse(response.ToString()); - - var result = rpc.GetTransactionHeight("9c909e1e3ba03290553a68d862e002c7a21ba302e043fc492fe069bf6a134d29"); - Assert.AreEqual(json.ToString(), result.ToString()); + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetBalance).ToLower()); + var result = rpc.GetBalance(test.Request.Params[0].AsString()); + Assert.AreEqual(test.Response.Result["balance"].AsString(), result.Value.ToString()); } [TestMethod] - public void TestGetValidators() + public void TestGetNewAddress() { - JObject json = JObject.Parse(@"[ - { - ""publickey"": ""02486fd15702c4490a26703112a5cc1d0923fd697a33406bd5a1c00e0013b09a70"", - ""votes"": ""46632420"", - ""active"": true - }, - { - ""publickey"": ""024c7b7fb6c310fccf1ba33b082519d82964ea93868d676662d4a59ad548df0e7d"", - ""votes"": ""46632420"", - ""active"": true - } - ]"); - JObject response = CreateResponse(1); - response["result"] = json; - MockResponse(response.ToString()); - - var result = rpc.GetValidators(); - Assert.AreEqual(((JArray)json)[0].ToString(), (result[0]).ToJson().ToString()); + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetNewAddress).ToLower()); + var result = rpc.GetNewAddress(); + Assert.AreEqual(test.Response.Result.AsString(), result); } [TestMethod] - public void TestGetVersion() + public void TestGetUnclaimedGas() { - JObject json = new JObject(); - json["tcpPort"] = 30001; - json["wsPort"] = 30002; - json["nonce"] = 1546258664; - json["useragent"] = "/NEO:2.7.5/"; - - var json1 = JObject.Parse(@"{ - ""tcpPort"": 30001, - ""wsPort"": 30002, - ""nonce"": 1546258664, - ""useragent"": ""/NEO:2.7.5/"" - }"); - Assert.AreEqual(json.ToString(), json1.ToString()); - - JObject response = CreateResponse(1); - response["result"] = json; - MockResponse(response.ToString()); - - var result = rpc.GetVersion(); - Assert.AreEqual(30001, result.TcpPort); - Assert.AreEqual("/NEO:2.7.5/", result.UserAgent); + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetUnclaimedGas).ToLower()); + var result = rpc.GetUnclaimedGas(); + Assert.AreEqual(test.Response.Result.AsString(), result.ToString()); } [TestMethod] - public void TestInvokeFunction() + public void TestImportPrivKey() { - JObject json = JObject.Parse(@" - { - ""script"": ""1426ae7c6c9861ec418468c1f0fdc4a7f2963eb89151c10962616c616e63654f6667be39e7b562f60cbfe2aebca375a2e5ee28737caf"", - ""state"": ""HALT"", - ""gas_consumed"": ""0.311"", - ""stack"": [ - { - ""type"": ""ByteArray"", - ""value"": ""262bec084432"" - } - ] - }"); - JObject response = CreateResponse(1); - response["result"] = json; - MockResponse(response.ToString()); - - var result = rpc.InvokeFunction("af7c7328eee5a275a3bcaee2bf0cf662b5e739be", "balanceOf", new[] { new RpcStack { Type = "Hash160", Value = "91b83e96f2a7c4fdf0c1688441ec61986c7cae26" } }); - Assert.AreEqual(json.ToString(), result.ToJson().ToString()); + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.ImportPrivKey).ToLower()); + var result = rpc.ImportPrivKey(test.Request.Params[0].AsString()); + Assert.AreEqual(test.Response.Result.ToString(), result.ToJson().ToString()); } [TestMethod] - public void TestInvokeScript() + public void TestListAddress() { - JObject json = JObject.Parse(@" - { - ""script"": ""1426ae7c6c9861ec418468c1f0fdc4a7f2963eb89151c10962616c616e63654f6667be39e7b562f60cbfe2aebca375a2e5ee28737caf"", - ""state"": ""HALT"", - ""gas_consumed"": ""0.311"", - ""stack"": [ - { - ""type"": ""ByteArray"", - ""value"": ""262bec084432"" - } - ] - }"); - JObject response = CreateResponse(1); - response["result"] = json; - MockResponse(response.ToString()); - - var result = rpc.InvokeScript("00046e616d656724058e5e1b6008847cd662728549088a9ee82191".HexToBytes()); - Assert.AreEqual(json.ToString(), result.ToJson().ToString()); + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.ListAddress).ToLower()); + var result = rpc.ListAddress(); + Assert.AreEqual(test.Response.Result.ToString(), ((JArray)result.Select(p => p.ToJson()).ToArray()).ToString()); } [TestMethod] - public void TestListPlugins() + public void TestOpenWallet() { - JObject json = JObject.Parse(@"[{ - ""name"": ""SimplePolicyPlugin"", - ""version"": ""2.10.1.0"", - ""interfaces"": [ - ""ILogPlugin"", - ""IPolicyPlugin"" - ] - }]"); - JObject response = CreateResponse(1); - response["result"] = json; - MockResponse(response.ToString()); - - var result = rpc.ListPlugins(); - Assert.AreEqual(((JArray)json)[0].ToString(), result[0].ToJson().ToString()); + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.OpenWallet).ToLower()); + var result = rpc.OpenWallet(test.Request.Params[0].AsString(), test.Request.Params[1].AsString()); + Assert.AreEqual(test.Response.Result.AsBoolean(), result); } [TestMethod] - public void TestSendRawTransaction() + public void TestSendFrom() { - JObject json = true; - JObject response = CreateResponse(1); - response["result"] = json; - MockResponse(response.ToString()); - - var result = rpc.SendRawTransaction("80000001195876cb34364dc38b730077156c6bc3a7fc570044a66fbfeeea56f71327e8ab0000029b7cffdaa674beae0f930ebe6085af9093e5fe56b34a5c220ccdcf6efc336fc500c65eaf440000000f9a23e06f74cf86b8827a9108ec2e0f89ad956c9b7cffdaa674beae0f930ebe6085af9093e5fe56b34a5c220ccdcf6efc336fc50092e14b5e00000030aab52ad93f6ce17ca07fa88fc191828c58cb71014140915467ecd359684b2dc358024ca750609591aa731a0b309c7fb3cab5cd0836ad3992aa0a24da431f43b68883ea5651d548feb6bd3c8e16376e6e426f91f84c58232103322f35c7819267e721335948d385fae5be66e7ba8c748ac15467dcca0693692dac".HexToBytes()); - Assert.AreEqual(json.ToString(), ((JObject)result).ToString()); + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.SendFrom).ToLower()); + var result = rpc.SendFrom(test.Request.Params[0].AsString(), test.Request.Params[1].AsString(), + test.Request.Params[2].AsString(), test.Request.Params[3].AsString()); + Assert.AreEqual(test.Response.Result.ToString(), result.ToString()); } [TestMethod] - public void TestSubmitBlock() + public void TestSendMany() { - JObject json = true; - JObject response = CreateResponse(1); - response["result"] = json; - MockResponse(response.ToString()); - - var result = rpc.SubmitBlock("03febccf81ac85e3d795bc5cbd4e84e907812aa3".HexToBytes()); - Assert.AreEqual(json.ToString(), ((JObject)result).ToString()); + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.SendMany).ToLower()); + var result = rpc.SendMany(test.Request.Params[0].AsString(), ((JArray)test.Request.Params[1]).Select(p => RpcTransferOut.FromJson(p))); + Assert.AreEqual(test.Response.Result.ToString(), result.ToString()); } [TestMethod] - public void TestValidateAddress() + public void TestSendToAddress() { - JObject json = new JObject(); - json["address"] = "AQVh2pG732YvtNaxEGkQUei3YA4cvo7d2i"; - json["isvalid"] = false; - JObject response = CreateResponse(1); - response["result"] = json; - MockResponse(response.ToString()); + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.SendToAddress).ToLower()); + var result = rpc.SendToAddress(test.Request.Params[0].AsString(), test.Request.Params[1].AsString(), test.Request.Params[2].AsString()); + Assert.AreEqual(test.Response.Result.ToString(), result.ToString()); + } + + #endregion Wallet + + #region Plugins - var result = rpc.ValidateAddress("AQVh2pG732YvtNaxEGkQUei3YA4cvo7d2i"); - Assert.AreEqual(json.ToString(), result.ToJson().ToString()); + [TestMethod()] + public void GetApplicationLogTest() + { + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetApplicationLog).ToLower()); + var result = rpc.GetApplicationLog(test.Request.Params[0].AsString()); + Assert.AreEqual(test.Response.Result.ToString(), result.ToJson().ToString()); } - [TestMethod] - public void TestConstructorByUrlAndDispose() + [TestMethod()] + public void GetNep5TransfersTest() { - //dummy url for test - var client = new RpcClient("http://www.xxx.yyy"); - Action action = () => client.Dispose(); - action.Should().NotThrow(); + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetNep5Transfers).ToLower()); + var result = rpc.GetNep5Transfers(test.Request.Params[0].AsString(), (ulong)test.Request.Params[1].AsNumber(), + (ulong)test.Request.Params[2].AsNumber()); + Assert.AreEqual(test.Response.Result.ToString(), result.ToJson().ToString()); } + + [TestMethod()] + public void GetNep5BalancesTest() + { + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetNep5Balances).ToLower()); + var result = rpc.GetNep5Balances(test.Request.Params[0].AsString()); + Assert.AreEqual(test.Response.Result.ToString(), result.ToJson().ToString()); + } + + #endregion Plugins } } diff --git a/tests/Neo.Network.RPC.Tests/UT_RpcModels.cs b/tests/Neo.Network.RPC.Tests/UT_RpcModels.cs new file mode 100644 index 000000000..313f757f6 --- /dev/null +++ b/tests/Neo.Network.RPC.Tests/UT_RpcModels.cs @@ -0,0 +1,139 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.IO.Json; +using Neo.Network.RPC.Models; +using System.Linq; + +namespace Neo.Network.RPC.Tests +{ + [TestClass()] + public class UT_RpcModels + { + [TestMethod()] + public void TestRpcAccount() + { + JObject json = TestUtils.RpcTestCases.Find(p => p.Name == nameof(RpcClient.ImportPrivKey).ToLower()).Response.Result; + var item = RpcAccount.FromJson(json); + Assert.AreEqual(json.ToString(), item.ToJson().ToString()); + } + + [TestMethod()] + public void TestRpcApplicationLog() + { + JObject json = TestUtils.RpcTestCases.Find(p => p.Name == nameof(RpcClient.GetApplicationLog).ToLower()).Response.Result; + var item = RpcApplicationLog.FromJson(json); + Assert.AreEqual(json.ToString(), item.ToJson().ToString()); + } + + [TestMethod()] + public void TestRpcBlock() + { + JObject json = TestUtils.RpcTestCases.Find(p => p.Name == nameof(RpcClient.GetBlock).ToLower()).Response.Result; + var item = RpcBlock.FromJson(json); + Assert.AreEqual(json.ToString(), item.ToJson().ToString()); + } + + [TestMethod()] + public void TestRpcBlockHeader() + { + JObject json = TestUtils.RpcTestCases.Find(p => p.Name == nameof(RpcClient.GetBlockHeader).ToLower()).Response.Result; + var item = RpcBlockHeader.FromJson(json); + Assert.AreEqual(json.ToString(), item.ToJson().ToString()); + } + + [TestMethod()] + public void TestGetContractState() + { + JObject json = TestUtils.RpcTestCases.Find(p => p.Name == nameof(RpcClient.GetContractState).ToLower()).Response.Result; + var item = RpcContractState.FromJson(json); + Assert.AreEqual(json.ToString(), item.ToJson().ToString()); + } + + [TestMethod()] + public void TestRpcInvokeResult() + { + JObject json = TestUtils.RpcTestCases.Find(p => p.Name == nameof(RpcClient.InvokeFunction).ToLower()).Response.Result; + var item = RpcInvokeResult.FromJson(json); + Assert.AreEqual(json.ToString(), item.ToJson().ToString()); + } + + [TestMethod()] + public void TestRpcNep5Balances() + { + JObject json = TestUtils.RpcTestCases.Find(p => p.Name == nameof(RpcClient.GetNep5Balances).ToLower()).Response.Result; + var item = RpcNep5Balances.FromJson(json); + Assert.AreEqual(json.ToString(), item.ToJson().ToString()); + } + + [TestMethod()] + public void TestRpcNep5Transfers() + { + JObject json = TestUtils.RpcTestCases.Find(p => p.Name == nameof(RpcClient.GetNep5Transfers).ToLower()).Response.Result; + var item = RpcNep5Transfers.FromJson(json); + Assert.AreEqual(json.ToString(), item.ToJson().ToString()); + } + + [TestMethod()] + public void TestRpcPeers() + { + JObject json = TestUtils.RpcTestCases.Find(p => p.Name == nameof(RpcClient.GetPeers).ToLower()).Response.Result; + var item = RpcPeers.FromJson(json); + Assert.AreEqual(json.ToString(), item.ToJson().ToString()); + } + + [TestMethod()] + public void TestRpcPlugin() + { + JObject json = TestUtils.RpcTestCases.Find(p => p.Name == nameof(RpcClient.ListPlugins).ToLower()).Response.Result; + var item = ((JArray)json).Select(p => RpcPlugin.FromJson(p)); + Assert.AreEqual(json.ToString(), ((JArray)item.Select(p => p.ToJson()).ToArray()).ToString()); + } + + [TestMethod()] + public void TestRpcRawMemPool() + { + JObject json = TestUtils.RpcTestCases.Find(p => p.Name == nameof(RpcClient.GetRawMempoolBoth).ToLower()).Response.Result; + var item = RpcRawMemPool.FromJson(json); + Assert.AreEqual(json.ToString(), item.ToJson().ToString()); + } + + [TestMethod()] + public void TestRpcTransaction() + { + JObject json = TestUtils.RpcTestCases.Find(p => p.Name == nameof(RpcClient.GetRawTransaction).ToLower()).Response.Result; + var item = RpcTransaction.FromJson(json); + Assert.AreEqual(json.ToString(), item.ToJson().ToString()); + } + + [TestMethod()] + public void TestRpcTransferOut() + { + JObject json = TestUtils.RpcTestCases.Find(p => p.Name == nameof(RpcClient.SendMany).ToLower()).Request.Params[1]; + var item = ((JArray)json).Select(p => RpcTransferOut.FromJson(p)); + Assert.AreEqual(json.ToString(), ((JArray)item.Select(p => p.ToJson()).ToArray()).ToString()); + } + + [TestMethod()] + public void TestRpcValidateAddressResult() + { + JObject json = TestUtils.RpcTestCases.Find(p => p.Name == nameof(RpcClient.ValidateAddress).ToLower()).Response.Result; + var item = RpcValidateAddressResult.FromJson(json); + Assert.AreEqual(json.ToString(), item.ToJson().ToString()); + } + + [TestMethod()] + public void TestRpcValidator() + { + JObject json = TestUtils.RpcTestCases.Find(p => p.Name == nameof(RpcClient.GetValidators).ToLower()).Response.Result; + var item = ((JArray)json).Select(p => RpcValidator.FromJson(p)); + Assert.AreEqual(json.ToString(), ((JArray)item.Select(p => p.ToJson()).ToArray()).ToString()); + } + + [TestMethod()] + public void TestRpcVersion() + { + JObject json = TestUtils.RpcTestCases.Find(p => p.Name == nameof(RpcClient.GetVersion).ToLower()).Response.Result; + var item = RpcVersion.FromJson(json); + Assert.AreEqual(json.ToString(), item.ToJson().ToString()); + } + } +} diff --git a/tests/Neo.Network.RPC.Tests/UT_TransactionManager.cs b/tests/Neo.Network.RPC.Tests/UT_TransactionManager.cs index 56925ff58..b48c71519 100644 --- a/tests/Neo.Network.RPC.Tests/UT_TransactionManager.cs +++ b/tests/Neo.Network.RPC.Tests/UT_TransactionManager.cs @@ -36,7 +36,7 @@ public void TestSetup() public static Mock MockRpcClient(UInt160 sender, byte[] script) { - var mockRpc = new Mock(MockBehavior.Strict, "http://seed1.neo.org:10331"); + var mockRpc = new Mock(MockBehavior.Strict, "http://seed1.neo.org:10331", null, null); // MockHeight mockRpc.Setup(p => p.RpcSend("getblockcount")).Returns(100).Verifiable(); @@ -67,7 +67,7 @@ public static void MockInvokeScript(Mock mockClient, byte[] script, p Stack = parameters, GasConsumed = "100", Script = script.ToHexString(), - State = "" + State = VMState.HALT }; mockClient.Setup(p => p.RpcSend("invokescript", It.Is(j => j[0].AsString() == script.ToHexString()))) @@ -90,12 +90,11 @@ public void TestMakeTransaction() }; byte[] script = new byte[1]; - txManager.MakeTransaction(script, attributes, null, 60000); + txManager.MakeTransaction(script, attributes, null); var tx = txManager.Tx; Assert.AreEqual("53616d706c6555726c", tx.Attributes[0].Data.ToHexString()); - Assert.AreEqual(0, tx.SystemFee % (long)NativeContract.GAS.Factor); - Assert.AreEqual(60000, tx.NetworkFee); + Assert.AreEqual(1, tx.SystemFee / (long)NativeContract.GAS.Factor); } [TestMethod] @@ -130,7 +129,7 @@ public void TestSign() Assert.IsTrue(Crypto.VerifySignature(tx.GetHashData(), signature, keyPair1.PublicKey.EncodePoint(false).Skip(1).ToArray())); // verify network fee - long networkFee = tx.Size * (long)1000 + ApplicationEngine.OpCodePrices[OpCode.PUSHDATA1] + ApplicationEngine.OpCodePrices[OpCode.PUSHDATA1] + ApplicationEngine.OpCodePrices[OpCode.PUSHNULL] + InteropService.GetPrice(InteropService.Crypto.ECDsaVerify, null); + long networkFee = tx.Size * (long)1000 + ApplicationEngine.OpCodePrices[OpCode.PUSHDATA1] + ApplicationEngine.OpCodePrices[OpCode.PUSHDATA1] + ApplicationEngine.OpCodePrices[OpCode.PUSHNULL] + InteropService.GetPrice(InteropService.Crypto.ECDsaVerify, null, null); Assert.AreEqual(networkFee, tx.NetworkFee); // duplicate sign should not add new witness @@ -138,7 +137,7 @@ public void TestSign() Assert.AreEqual(1, txManager.Tx.Witnesses.Length); // throw exception when the KeyPair is wrong - Assert.ThrowsException(() => txManager.AddSignature(keyPair2)); + Assert.ThrowsException(() => txManager.AddSignature(keyPair2).Sign()); } [TestMethod] @@ -159,7 +158,7 @@ public void TestSignMulti() }; byte[] script = new byte[1]; - txManager.MakeTransaction(script, null, cosigners, 0_10000000) + txManager.MakeTransaction(script, null, cosigners) .AddMultiSig(keyPair1, 2, keyPair1.PublicKey, keyPair2.PublicKey) .AddMultiSig(keyPair2, 2, keyPair1.PublicKey, keyPair2.PublicKey) .AddSignature(keyPair1) @@ -182,7 +181,7 @@ public void TestAddWitness() }; byte[] script = new byte[1]; - txManager.MakeTransaction(script, null, cosigners, 0_10000000); + txManager.MakeTransaction(script, null, cosigners); txManager.AddWitness(UInt160.Zero); txManager.AddSignature(keyPair1); txManager.Sign(); diff --git a/tests/Neo.Network.RPC.Tests/UT_Utility.cs b/tests/Neo.Network.RPC.Tests/UT_Utility.cs index 00098b092..870cfe5a1 100644 --- a/tests/Neo.Network.RPC.Tests/UT_Utility.cs +++ b/tests/Neo.Network.RPC.Tests/UT_Utility.cs @@ -68,7 +68,7 @@ public void TestToBigInteger() amount = 1.23456789m; decimals = 4; - Assert.ThrowsException(() => result = amount.ToBigInteger(decimals)); + Assert.ThrowsException(() => result = amount.ToBigInteger(decimals)); } } } diff --git a/tests/Neo.Network.RPC.Tests/UT_WalletAPI.cs b/tests/Neo.Network.RPC.Tests/UT_WalletAPI.cs index a2f738048..72b83af8a 100644 --- a/tests/Neo.Network.RPC.Tests/UT_WalletAPI.cs +++ b/tests/Neo.Network.RPC.Tests/UT_WalletAPI.cs @@ -2,7 +2,6 @@ using Moq; using Neo.IO.Json; using Neo.Network.P2P.Payloads; -using Neo.Network.RPC; using Neo.Network.RPC.Models; using Neo.SmartContract; using Neo.SmartContract.Native; @@ -26,7 +25,7 @@ public void TestSetup() { keyPair1 = new KeyPair(Wallet.GetPrivateKeyFromWIF("KyXwTh1hB76RRMquSvnxZrJzQx7h9nQP2PCRL38v6VDb5ip3nf1p")); sender = Contract.CreateSignatureRedeemScript(keyPair1.PublicKey).ToScriptHash(); - address1 = Neo.Wallets.Helper.ToAddress(sender); + address1 = Wallets.Helper.ToAddress(sender); rpcClientMock = UT_TransactionManager.MockRpcClient(sender, new byte[0]); walletAPI = new WalletAPI(rpcClientMock.Object); } @@ -80,7 +79,9 @@ public void TestClaimGas() byte[] testScript = NativeContract.NEO.Hash.MakeScript("transfer", sender, sender, new BigInteger(1_00000000)); UT_TransactionManager.MockInvokeScript(rpcClientMock, testScript, new ContractParameter { Type = ContractParameterType.Integer, Value = new BigInteger(1_10000000) }); - rpcClientMock.Setup(p => p.RpcSend("sendrawtransaction", It.IsAny())).Returns(true); + var json = new JObject(); + json["hash"] = UInt256.Zero.ToString(); + rpcClientMock.Setup(p => p.RpcSend("sendrawtransaction", It.IsAny())).Returns(json); var tranaction = walletAPI.ClaimGas(keyPair1.Export()); Assert.AreEqual(testScript.ToHexString(), tranaction.Script.ToHexString()); @@ -95,9 +96,11 @@ public void TestTransfer() byte[] testScript = NativeContract.GAS.Hash.MakeScript("transfer", sender, UInt160.Zero, NativeContract.GAS.Factor * 100); UT_TransactionManager.MockInvokeScript(rpcClientMock, testScript, new ContractParameter { Type = ContractParameterType.Integer, Value = new BigInteger(1_10000000) }); - rpcClientMock.Setup(p => p.RpcSend("sendrawtransaction", It.IsAny())).Returns(true); + var json = new JObject(); + json["hash"] = UInt256.Zero.ToString(); + rpcClientMock.Setup(p => p.RpcSend("sendrawtransaction", It.IsAny())).Returns(json); - var tranaction = walletAPI.Transfer(NativeContract.GAS.Hash.ToString(), keyPair1.Export(), UInt160.Zero.ToAddress(), 100, 1.1m); + var tranaction = walletAPI.Transfer(NativeContract.GAS.Hash.ToString(), keyPair1.Export(), UInt160.Zero.ToAddress(), 100); Assert.AreEqual(testScript.ToHexString(), tranaction.Script.ToHexString()); } From 74f3ebdb02cc5fc35feebc43427df3dfe3f958cd Mon Sep 17 00:00:00 2001 From: cn1010 Date: Thu, 26 Mar 2020 21:31:49 +0800 Subject: [PATCH 105/183] Deal with contract destory (#196) * deal with contract destory * remove delete key --- src/RpcNep5Tracker/RpcNep5Tracker.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/RpcNep5Tracker/RpcNep5Tracker.cs b/src/RpcNep5Tracker/RpcNep5Tracker.cs index d94ab0d60..62a68cb34 100644 --- a/src/RpcNep5Tracker/RpcNep5Tracker.cs +++ b/src/RpcNep5Tracker/RpcNep5Tracker.cs @@ -286,6 +286,8 @@ public JObject GetNep5Balances(JArray _params) foreach (var (key, value) in dbCache.Find(prefix)) { JObject balance = new JObject(); + if (Blockchain.Singleton.View.Contracts.TryGet(key.AssetScriptHash) is null) + continue; balance["asset_hash"] = key.AssetScriptHash.ToString(); balance["amount"] = value.Balance.ToString(); balance["last_updated_block"] = value.LastUpdatedBlock; From bd4b9ceee45abe3d3c02bb5c547df6698617c705 Mon Sep 17 00:00:00 2001 From: cn1010 Date: Fri, 27 Mar 2020 10:18:23 +0800 Subject: [PATCH 106/183] Remove GetBlockSysFee (#199) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * remove GetSysFeeAmount in rpcserver * remove getblocksysfee in rpcclient * fix ut Co-authored-by: Vitor Nazário Coelho --- src/RpcClient/RpcClient.cs | 8 -------- src/RpcServer/RpcServer.Blockchain.cs | 12 ------------ tests/Neo.Network.RPC.Tests/UT_RpcClient.cs | 8 -------- 3 files changed, 28 deletions(-) diff --git a/src/RpcClient/RpcClient.cs b/src/RpcClient/RpcClient.cs index 057cc9556..58cc53934 100644 --- a/src/RpcClient/RpcClient.cs +++ b/src/RpcClient/RpcClient.cs @@ -174,14 +174,6 @@ public RpcBlockHeader GetBlockHeader(string hashOrIndex) return RpcBlockHeader.FromJson(RpcSend("getblockheader", hashOrIndex, true)); } - /// - /// Returns the system fees of the block, based on the specified index. - /// - public BigInteger GetBlockSysFee(int height) - { - return BigInteger.Parse(RpcSend("getblocksysfee", height).AsString()); - } - /// /// Queries contract information, according to the contract script hash. /// diff --git a/src/RpcServer/RpcServer.Blockchain.cs b/src/RpcServer/RpcServer.Blockchain.cs index 0f5e9cd8a..ef52b4a1b 100644 --- a/src/RpcServer/RpcServer.Blockchain.cs +++ b/src/RpcServer/RpcServer.Blockchain.cs @@ -102,18 +102,6 @@ private JObject GetBlockHeader(JArray _params) return header.ToArray().ToHexString(); } - [RpcMethod] - private JObject GetBlockSysFee(JArray _params) - { - uint height = uint.Parse(_params[0].AsString()); - if (height <= Blockchain.Singleton.Height) - using (ApplicationEngine engine = NativeContract.GAS.TestCall("getSysFeeAmount", height)) - { - return engine.ResultStack.Peek().GetBigInteger().ToString(); - } - throw new RpcException(-100, "Invalid Height"); - } - [RpcMethod] private JObject GetContractState(JArray _params) { diff --git a/tests/Neo.Network.RPC.Tests/UT_RpcClient.cs b/tests/Neo.Network.RPC.Tests/UT_RpcClient.cs index 4020555ca..d4f9cca5e 100644 --- a/tests/Neo.Network.RPC.Tests/UT_RpcClient.cs +++ b/tests/Neo.Network.RPC.Tests/UT_RpcClient.cs @@ -158,14 +158,6 @@ public void TestGetBlockHeader() } } - [TestMethod] - public void TestGetBlockSysFee() - { - var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetBlockSysFee).ToLower()); - var result = rpc.GetBlockSysFee((int)test.Request.Params[0].AsNumber()); - Assert.AreEqual(test.Response.Result.AsString(), result.ToString()); - } - [TestMethod] public void TestGetContractState() { From 3e1078d57c8450e24bab4f17c3ab55506ee625cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vitor=20Naz=C3=A1rio=20Coelho?= Date: Sat, 4 Apr 2020 07:12:52 -0300 Subject: [PATCH 107/183] ByteArray -> ByteString (#215) --- src/RpcNep5Tracker/RpcNep5Tracker.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/RpcNep5Tracker/RpcNep5Tracker.cs b/src/RpcNep5Tracker/RpcNep5Tracker.cs index 62a68cb34..3d1196418 100644 --- a/src/RpcNep5Tracker/RpcNep5Tracker.cs +++ b/src/RpcNep5Tracker/RpcNep5Tracker.cs @@ -104,17 +104,17 @@ private void HandleNotification(StoreView snapshot, IVerifiable scriptContainer, { if (stateItems.Count == 0) return; // Event name should be encoded as a byte array. - if (!(stateItems[0] is VM.Types.ByteArray)) return; + if (!(stateItems[0] is VM.Types.ByteString)) return; var eventName = stateItems[0].GetString(); if (eventName != "Transfer") return; if (stateItems.Count < 4) return; - if (!(stateItems[1].IsNull) && !(stateItems[1] is VM.Types.ByteArray)) + if (!(stateItems[1].IsNull) && !(stateItems[1] is VM.Types.ByteString)) return; - if (!(stateItems[2].IsNull) && !(stateItems[2] is VM.Types.ByteArray)) + if (!(stateItems[2].IsNull) && !(stateItems[2] is VM.Types.ByteString)) return; var amountItem = stateItems[3]; - if (!(amountItem is VM.Types.ByteArray || amountItem is VM.Types.Integer)) + if (!(amountItem is VM.Types.ByteString || amountItem is VM.Types.Integer)) return; byte[] fromBytes = stateItems[1].IsNull ? null : stateItems[1].GetSpan().ToArray(); if (fromBytes != null && fromBytes.Length != UInt160.Length) From d53fc240077e2311a490dad5377dd14e2b806c1f Mon Sep 17 00:00:00 2001 From: Shargon Date: Fri, 10 Apr 2020 18:10:09 +0200 Subject: [PATCH 108/183] Change module command (#187) * change command * Change comment * Add nuget * Update StatesDumper.cs --- src/StatesDumper/StatesDumper.cs | 42 ++++++---------------------- src/StatesDumper/StatesDumper.csproj | 1 + 2 files changed, 10 insertions(+), 33 deletions(-) diff --git a/src/StatesDumper/StatesDumper.cs b/src/StatesDumper/StatesDumper.cs index fb80ff2a8..02f969d89 100644 --- a/src/StatesDumper/StatesDumper.cs +++ b/src/StatesDumper/StatesDumper.cs @@ -1,3 +1,4 @@ +using Neo.ConsoleService; using Neo.IO; using Neo.IO.Caching; using Neo.IO.Json; @@ -35,40 +36,15 @@ private static void Dump(IEnumerable<(TKey Key, TValue Value)> sta Console.WriteLine($"States ({array.Count}) have been dumped into file {path}"); } - protected override bool OnMessage(object message) + /// + /// Process "dump storage" command + /// + [ConsoleCommand("dump storage", Category = "Storage", Description = "You can specify the key or use null to get the corresponding information from the storage")] + private void OnDumpStorage(UInt160 key = null) { - if (!(message is string[] args)) return false; - if (args.Length == 0) return false; - return (args[0].ToLower()) switch - { - "help" => OnHelp(args), - "dump" => OnDump(args), - _ => false, - }; - } - - private bool OnDump(string[] args) - { - if (args.Length < 2) return false; - switch (args[1].ToLower()) - { - case "storage": - Dump(args.Length >= 3 - ? Blockchain.Singleton.View.Storages.Find(UInt160.Parse(args[2]).ToArray()) - : Blockchain.Singleton.View.Storages.Find()); - return true; - default: - return false; - } - } - - private bool OnHelp(string[] args) - { - if (args.Length < 2) return false; - if (!string.Equals(args[1], Name, StringComparison.OrdinalIgnoreCase)) - return false; - Console.Write($"{Name} Commands:\n" + "\tdump storage \n"); - return true; + Dump(key != null + ? Blockchain.Singleton.View.Storages.Find(key.ToArray()) + : Blockchain.Singleton.View.Storages.Find()); } public void OnPersist(StoreView snapshot, IReadOnlyList applicationExecutedList) diff --git a/src/StatesDumper/StatesDumper.csproj b/src/StatesDumper/StatesDumper.csproj index 4cf60681d..17d361ca2 100644 --- a/src/StatesDumper/StatesDumper.csproj +++ b/src/StatesDumper/StatesDumper.csproj @@ -15,6 +15,7 @@ +
From 01948ba3ccbb829fb56be1ce8917fae9738d7510 Mon Sep 17 00:00:00 2001 From: cn1010 Date: Mon, 13 Apr 2020 13:42:16 +0800 Subject: [PATCH 109/183] Fix RelayResult issue (#220) --- src/RpcServer/RpcServer.Node.cs | 13 +++++++------ src/RpcServer/RpcServer.csproj | 2 +- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/RpcServer/RpcServer.Node.cs b/src/RpcServer/RpcServer.Node.cs index cdec3f405..9eaacc8e1 100644 --- a/src/RpcServer/RpcServer.Node.cs +++ b/src/RpcServer/RpcServer.Node.cs @@ -8,6 +8,7 @@ using Neo.Network.P2P; using Neo.Network.P2P.Payloads; using System.Linq; +using static Neo.Ledger.Blockchain; namespace Neo.Plugins { @@ -41,9 +42,9 @@ private JObject GetPeers(JArray _params) return json; } - private static JObject GetRelayResult(RelayResultReason reason, UInt256 hash) + private static JObject GetRelayResult(VerifyResult reason, UInt256 hash) { - if (reason == RelayResultReason.Succeed) + if (reason == VerifyResult.Succeed) { var ret = new JObject(); ret["hash"] = hash.ToString(); @@ -70,16 +71,16 @@ private JObject GetVersion(JArray _params) private JObject SendRawTransaction(JArray _params) { Transaction tx = _params[0].AsString().HexToBytes().AsSerializable(); - RelayResultReason reason = System.Blockchain.Ask(tx).Result; - return GetRelayResult(reason, tx.Hash); + RelayResult reason = System.Blockchain.Ask(tx).Result; + return GetRelayResult(reason.Result, tx.Hash); } [RpcMethod] private JObject SubmitBlock(JArray _params) { Block block = _params[0].AsString().HexToBytes().AsSerializable(); - RelayResultReason reason = System.Blockchain.Ask(block).Result; - return GetRelayResult(reason, block.Hash); + RelayResult reason = System.Blockchain.Ask(block).Result; + return GetRelayResult(reason.Result, block.Hash); } } } diff --git a/src/RpcServer/RpcServer.csproj b/src/RpcServer/RpcServer.csproj index de60f6a7d..644f0e54d 100644 --- a/src/RpcServer/RpcServer.csproj +++ b/src/RpcServer/RpcServer.csproj @@ -15,7 +15,7 @@ - +
From 12dcef00cbf808067214cf5e0e3a4db5c17763e1 Mon Sep 17 00:00:00 2001 From: Qiao Jin <43407364+Qiao-Jin@users.noreply.github.com> Date: Mon, 13 Apr 2020 15:21:23 +0800 Subject: [PATCH 110/183] Add CheckWitness to func invokefunction (#214) --- src/RpcServer/RpcServer.SmartContract.cs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/RpcServer/RpcServer.SmartContract.cs b/src/RpcServer/RpcServer.SmartContract.cs index 60069ea75..340942f00 100644 --- a/src/RpcServer/RpcServer.SmartContract.cs +++ b/src/RpcServer/RpcServer.SmartContract.cs @@ -76,24 +76,20 @@ private JObject InvokeFunction(JArray _params) UInt160 script_hash = UInt160.Parse(_params[0].AsString()); string operation = _params[1].AsString(); ContractParameter[] args = _params.Count >= 3 ? ((JArray)_params[2]).Select(p => ContractParameter.FromJson(p)).ToArray() : new ContractParameter[0]; + CheckWitnessHashes checkWitnessHashes = _params.Count >= 4 ? new CheckWitnessHashes(((JArray)_params[3]).Select(u => UInt160.Parse(u.AsString())).ToArray()) : null; byte[] script; using (ScriptBuilder sb = new ScriptBuilder()) { script = sb.EmitAppCall(script_hash, operation, args).ToArray(); } - return GetInvokeResult(script); + return GetInvokeResult(script, checkWitnessHashes); } [RpcMethod] private JObject InvokeScript(JArray _params) { byte[] script = _params[0].AsString().HexToBytes(); - CheckWitnessHashes checkWitnessHashes = null; - if (_params.Count > 1) - { - UInt160[] scriptHashesForVerifying = _params.Skip(1).Select(u => UInt160.Parse(u.AsString())).ToArray(); - checkWitnessHashes = new CheckWitnessHashes(scriptHashesForVerifying); - } + CheckWitnessHashes checkWitnessHashes = _params.Count >= 2 ? new CheckWitnessHashes(((JArray)_params[1]).Select(u => UInt160.Parse(u.AsString())).ToArray()) : null; return GetInvokeResult(script, checkWitnessHashes); } } From f451ca8d96ca7ace6c9b2b75cc1e992c8b255e16 Mon Sep 17 00:00:00 2001 From: cn1010 Date: Tue, 14 Apr 2020 00:16:40 +0800 Subject: [PATCH 111/183] remove round up sysfee (#219) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Vitor Nazário Coelho --- src/RpcClient/TransactionManager.cs | 9 --------- tests/Neo.Network.RPC.Tests/UT_TransactionManager.cs | 1 - 2 files changed, 10 deletions(-) diff --git a/src/RpcClient/TransactionManager.cs b/src/RpcClient/TransactionManager.cs index 43d182c8b..1ce09d6d9 100644 --- a/src/RpcClient/TransactionManager.cs +++ b/src/RpcClient/TransactionManager.cs @@ -78,15 +78,6 @@ public TransactionManager MakeTransaction(byte[] script, TransactionAttribute[] UInt160[] hashes = Tx.GetScriptHashesForVerifying(null); RpcInvokeResult result = rpcClient.InvokeScript(script, hashes); Tx.SystemFee = Math.Max(long.Parse(result.GasConsumed) - ApplicationEngine.GasFree, 0); - if (Tx.SystemFee > 0) - { - long d = (long)NativeContract.GAS.Factor; - long remainder = Tx.SystemFee % d; - if (remainder > 0) - Tx.SystemFee += d - remainder; - else if (remainder < 0) - Tx.SystemFee -= remainder; - } context = new ContractParametersContext(Tx); signStore = new List(); diff --git a/tests/Neo.Network.RPC.Tests/UT_TransactionManager.cs b/tests/Neo.Network.RPC.Tests/UT_TransactionManager.cs index b48c71519..722c1bb04 100644 --- a/tests/Neo.Network.RPC.Tests/UT_TransactionManager.cs +++ b/tests/Neo.Network.RPC.Tests/UT_TransactionManager.cs @@ -94,7 +94,6 @@ public void TestMakeTransaction() var tx = txManager.Tx; Assert.AreEqual("53616d706c6555726c", tx.Attributes[0].Data.ToHexString()); - Assert.AreEqual(1, tx.SystemFee / (long)NativeContract.GAS.Factor); } [TestMethod] From d62b18bcea99186614c3043603fcaa8e6214ba77 Mon Sep 17 00:00:00 2001 From: Harry Pierson Date: Wed, 15 Apr 2020 11:09:07 -0700 Subject: [PATCH 112/183] Enable programmatic configuration of RpcServer plugin (#206) * seperate out plugin from rpcServer functionality * Update src/RpcServer/RpcServer.cs * CR Feedback * fix encoding * fix build break Co-authored-by: Harry Pierson Co-authored-by: Shargon --- src/ApplicationLogs/LogReader.cs | 2 +- src/RpcNep5Tracker/RpcNep5Tracker.cs | 2 +- src/RpcServer/RpcServer.Node.cs | 4 +- src/RpcServer/RpcServer.SmartContract.cs | 2 +- src/RpcServer/RpcServer.Utilities.cs | 2 +- src/RpcServer/RpcServer.Wallet.cs | 8 +-- src/RpcServer/RpcServer.cs | 41 ++++++------ src/RpcServer/RpcServerPlugin.cs | 63 ++++++++++++++++++ src/RpcServer/RpcServerSettings.cs | 81 ++++++++++++++++++++++++ src/RpcServer/Settings.cs | 44 ------------- 10 files changed, 174 insertions(+), 75 deletions(-) create mode 100644 src/RpcServer/RpcServerPlugin.cs create mode 100644 src/RpcServer/RpcServerSettings.cs delete mode 100644 src/RpcServer/Settings.cs diff --git a/src/ApplicationLogs/LogReader.cs b/src/ApplicationLogs/LogReader.cs index af577dcd3..da3978920 100644 --- a/src/ApplicationLogs/LogReader.cs +++ b/src/ApplicationLogs/LogReader.cs @@ -21,7 +21,7 @@ public class LogReader : Plugin, IPersistencePlugin public LogReader() { db = DB.Open(GetFullPath(Settings.Default.Path), new Options { CreateIfMissing = true }); - RpcServer.RegisterMethods(this); + RpcServerPlugin.RegisterMethods(this); } protected override void Configure() diff --git a/src/RpcNep5Tracker/RpcNep5Tracker.cs b/src/RpcNep5Tracker/RpcNep5Tracker.cs index 3d1196418..2406c344c 100644 --- a/src/RpcNep5Tracker/RpcNep5Tracker.cs +++ b/src/RpcNep5Tracker/RpcNep5Tracker.cs @@ -35,7 +35,7 @@ public class RpcNep5Tracker : Plugin, IPersistencePlugin public RpcNep5Tracker() { - RpcServer.RegisterMethods(this); + RpcServerPlugin.RegisterMethods(this); } protected override void Configure() diff --git a/src/RpcServer/RpcServer.Node.cs b/src/RpcServer/RpcServer.Node.cs index 9eaacc8e1..0483f5ed1 100644 --- a/src/RpcServer/RpcServer.Node.cs +++ b/src/RpcServer/RpcServer.Node.cs @@ -71,7 +71,7 @@ private JObject GetVersion(JArray _params) private JObject SendRawTransaction(JArray _params) { Transaction tx = _params[0].AsString().HexToBytes().AsSerializable(); - RelayResult reason = System.Blockchain.Ask(tx).Result; + RelayResult reason = system.Blockchain.Ask(tx).Result; return GetRelayResult(reason.Result, tx.Hash); } @@ -79,7 +79,7 @@ private JObject SendRawTransaction(JArray _params) private JObject SubmitBlock(JArray _params) { Block block = _params[0].AsString().HexToBytes().AsSerializable(); - RelayResult reason = System.Blockchain.Ask(block).Result; + RelayResult reason = system.Blockchain.Ask(block).Result; return GetRelayResult(reason.Result, block.Hash); } } diff --git a/src/RpcServer/RpcServer.SmartContract.cs b/src/RpcServer/RpcServer.SmartContract.cs index 340942f00..639288656 100644 --- a/src/RpcServer/RpcServer.SmartContract.cs +++ b/src/RpcServer/RpcServer.SmartContract.cs @@ -53,7 +53,7 @@ public void SerializeUnsigned(BinaryWriter writer) private JObject GetInvokeResult(byte[] script, IVerifiable checkWitnessHashes = null) { - using ApplicationEngine engine = ApplicationEngine.Run(script, checkWitnessHashes, extraGAS: Settings.Default.MaxGasInvoke); + using ApplicationEngine engine = ApplicationEngine.Run(script, checkWitnessHashes, extraGAS: settings.MaxGasInvoke); JObject json = new JObject(); json["script"] = script.ToHexString(); json["state"] = engine.State; diff --git a/src/RpcServer/RpcServer.Utilities.cs b/src/RpcServer/RpcServer.Utilities.cs index 281fa6726..41b22d741 100644 --- a/src/RpcServer/RpcServer.Utilities.cs +++ b/src/RpcServer/RpcServer.Utilities.cs @@ -12,7 +12,7 @@ partial class RpcServer [RpcMethod] private JObject ListPlugins(JArray _params) { - return new JArray(Plugins + return new JArray(Neo.Plugins.Plugin.Plugins .OrderBy(u => u.Name) .Select(u => new JObject { diff --git a/src/RpcServer/RpcServer.Wallet.cs b/src/RpcServer/RpcServer.Wallet.cs index 7d183fd96..0a47622ef 100644 --- a/src/RpcServer/RpcServer.Wallet.cs +++ b/src/RpcServer/RpcServer.Wallet.cs @@ -187,7 +187,7 @@ private JObject SendFrom(JArray _params) if (tx.NetworkFee < calFee) tx.NetworkFee = calFee; } - if (tx.NetworkFee > Settings.Default.MaxFee) + if (tx.NetworkFee > settings.MaxFee) throw new RpcException(-301, "The necessary fee is more than the Max_fee, this transaction is failed. Please increase your Max_fee value."); return SignAndRelay(tx); } @@ -235,7 +235,7 @@ private JObject SendMany(JArray _params) if (tx.NetworkFee < calFee) tx.NetworkFee = calFee; } - if (tx.NetworkFee > Settings.Default.MaxFee) + if (tx.NetworkFee > settings.MaxFee) throw new RpcException(-301, "The necessary fee is more than the Max_fee, this transaction is failed. Please increase your Max_fee value."); return SignAndRelay(tx); } @@ -273,7 +273,7 @@ private JObject SendToAddress(JArray _params) if (tx.NetworkFee < calFee) tx.NetworkFee = calFee; } - if (tx.NetworkFee > Settings.Default.MaxFee) + if (tx.NetworkFee > settings.MaxFee) throw new RpcException(-301, "The necessary fee is more than the Max_fee, this transaction is failed. Please increase your Max_fee value."); return SignAndRelay(tx); } @@ -285,7 +285,7 @@ private JObject SignAndRelay(Transaction tx) if (context.Completed) { tx.Witnesses = context.GetWitnesses(); - System.LocalNode.Tell(new LocalNode.Relay { Inventory = tx }); + system.LocalNode.Tell(new LocalNode.Relay { Inventory = tx }); return tx.ToJson(); } else diff --git a/src/RpcServer/RpcServer.cs b/src/RpcServer/RpcServer.cs index ee027543e..e21755b5a 100644 --- a/src/RpcServer/RpcServer.cs +++ b/src/RpcServer/RpcServer.cs @@ -19,19 +19,24 @@ namespace Neo.Plugins { - public sealed partial class RpcServer : Plugin + public sealed partial class RpcServer : IDisposable { - private static readonly Dictionary> methods = new Dictionary>(); + private readonly Dictionary> methods = new Dictionary>(); + private IWebHost host; + private readonly RpcServerSettings settings; + private readonly NeoSystem system; - public RpcServer() + public RpcServer(NeoSystem system, RpcServerSettings settings) { + this.system = system; + this.settings = settings; RegisterMethods(this); } private bool CheckAuth(HttpContext context) { - if (string.IsNullOrEmpty(Settings.Default.RpcUser)) return true; + if (string.IsNullOrEmpty(settings.RpcUser)) return true; context.Response.Headers["WWW-Authenticate"] = "Basic realm=\"Restricted\""; @@ -50,12 +55,7 @@ private bool CheckAuth(HttpContext context) if (authvalues.Length < 2) return false; - return authvalues[0] == Settings.Default.RpcUser && authvalues[1] == Settings.Default.RpcPass; - } - - protected override void Configure() - { - Settings.Load(GetConfiguration()); + return authvalues[0] == settings.RpcUser && authvalues[1] == settings.RpcPass; } private static JObject CreateErrorResponse(JObject id, int code, string message, JObject data = null) @@ -77,9 +77,8 @@ private static JObject CreateResponse(JObject id) return response; } - public override void Dispose() + public void Dispose() { - base.Dispose(); if (host != null) { host.Dispose(); @@ -87,21 +86,21 @@ public override void Dispose() } } - protected override void OnPluginsLoaded() + public void StartRpcServer() { - host = new WebHostBuilder().UseKestrel(options => options.Listen(Settings.Default.BindAddress, Settings.Default.Port, listenOptions => + host = new WebHostBuilder().UseKestrel(options => options.Listen(settings.BindAddress, settings.Port, listenOptions => { // Default value is unlimited - options.Limits.MaxConcurrentConnections = Settings.Default.MaxConcurrentConnections; + options.Limits.MaxConcurrentConnections = settings.MaxConcurrentConnections; // Default value is 2 minutes options.Limits.KeepAliveTimeout = TimeSpan.FromMinutes(1); // Default value is 30 seconds options.Limits.RequestHeadersTimeout = TimeSpan.FromSeconds(15); - if (string.IsNullOrEmpty(Settings.Default.SslCert)) return; - listenOptions.UseHttps(Settings.Default.SslCert, Settings.Default.SslCertPassword, httpsConnectionAdapterOptions => + if (string.IsNullOrEmpty(settings.SslCert)) return; + listenOptions.UseHttps(settings.SslCert, settings.SslCertPassword, httpsConnectionAdapterOptions => { - if (Settings.Default.TrustedAuthorities is null || Settings.Default.TrustedAuthorities.Length == 0) + if (settings.TrustedAuthorities is null || settings.TrustedAuthorities.Length == 0) return; httpsConnectionAdapterOptions.ClientCertificateMode = ClientCertificateMode.RequireCertificate; httpsConnectionAdapterOptions.ClientCertificateValidation = (cert, chain, err) => @@ -109,7 +108,7 @@ protected override void OnPluginsLoaded() if (err != SslPolicyErrors.None) return false; X509Certificate2 authority = chain.ChainElements[chain.ChainElements.Count - 1].Certificate; - return Settings.Default.TrustedAuthorities.Contains(authority.Thumbprint); + return settings.TrustedAuthorities.Contains(authority.Thumbprint); }; }); })) @@ -211,7 +210,7 @@ private JObject ProcessRequest(HttpContext context, JObject request) try { string method = request["method"].AsString(); - if (!CheckAuth(context) || Settings.Default.DisabledMethods.Contains(method)) + if (!CheckAuth(context) || settings.DisabledMethods.Contains(method)) throw new RpcException(-400, "Access denied"); if (!methods.TryGetValue(method, out var func)) throw new RpcException(-32601, "Method not found"); @@ -236,7 +235,7 @@ private JObject ProcessRequest(HttpContext context, JObject request) } } - public static void RegisterMethods(object handler) + public void RegisterMethods(object handler) { foreach (MethodInfo method in handler.GetType().GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) { diff --git a/src/RpcServer/RpcServerPlugin.cs b/src/RpcServer/RpcServerPlugin.cs new file mode 100644 index 000000000..e2ff2d838 --- /dev/null +++ b/src/RpcServer/RpcServerPlugin.cs @@ -0,0 +1,63 @@ +using System.Collections.Generic; + +namespace Neo.Plugins +{ + public sealed class RpcServerPlugin : Plugin + { + static List handlers = new List(); + RpcServer server; + RpcServerSettings settings; + + protected override void Configure() + { + var loadedSettings = new RpcServerSettings(GetConfiguration()); + if (this.settings == null) + { + this.settings = loadedSettings; + } + else + { + this.settings.UpdateSettings(loadedSettings); + } + } + + public override void Dispose() + { + base.Dispose(); + if (server != null) + { + server.Dispose(); + server = null; + } + } + + protected override void OnPluginsLoaded() + { + this.server = new RpcServer(System, settings); + + foreach (var handler in handlers) + { + this.server.RegisterMethods(handler); + } + handlers.Clear(); + + server.StartRpcServer(); + } + + public static void RegisterMethods(object handler) + { + // if RpcServerPlugin is already loaded, call RegisterMethods directly + foreach (var plugin in Plugin.Plugins) + { + if (plugin is RpcServerPlugin rpcServerPlugin) + { + rpcServerPlugin.server.RegisterMethods(handler); + return; + } + } + + // otherwise, save the handler for use during RpcServerPlugin load + handlers.Add(handler); + } + } +} diff --git a/src/RpcServer/RpcServerSettings.cs b/src/RpcServer/RpcServerSettings.cs new file mode 100644 index 000000000..93a23586c --- /dev/null +++ b/src/RpcServer/RpcServerSettings.cs @@ -0,0 +1,81 @@ +using Microsoft.Extensions.Configuration; +using Neo.SmartContract.Native; +using System; +using System.Linq; +using System.Net; +using System.Numerics; + +namespace Neo.Plugins +{ + public class RpcServerSettings + { + // These read-only properties are used to in the creation + // of the WebHost RPC endpoint. These cannot be changed + // while the server is running + + public IPAddress BindAddress { get; } + public ushort Port { get; } + public string SslCert { get; } + public string SslCertPassword { get; } + public string[] TrustedAuthorities { get; } + public int MaxConcurrentConnections { get; } + + // these read-write properties can be changed while + // the server is running via auto-reconfiguration + + public string RpcUser { get; private set; } + public string RpcPass { get; private set; } + public long MaxGasInvoke { get; private set; } + public long MaxFee { get; private set; } + public string[] DisabledMethods { get; private set; } + + public RpcServerSettings(IPAddress bindAddress = null, + ushort port = 10332, + string sslCert = "", + string sslCertPassword = "", + string[] trustedAuthorities = null, + string rpcUser = "", + string rpcPass = "", + decimal maxGasInvoke = 10, + decimal maxFee = (decimal)0.1, + string[] disabledMethods = null, + int maxConcurrentConnections = 40) + { + this.BindAddress = bindAddress ?? IPAddress.Loopback; + this.Port = port; + this.SslCert = sslCert; + this.SslCertPassword = sslCertPassword; + this.TrustedAuthorities = trustedAuthorities ?? Array.Empty(); + this.RpcUser = rpcUser; + this.RpcPass = rpcPass; + this.MaxGasInvoke = (long)BigDecimal.Parse(maxGasInvoke.ToString(), NativeContract.GAS.Decimals).Value; + this.MaxFee = (long)BigDecimal.Parse(maxFee.ToString(), NativeContract.GAS.Decimals).Value; + this.DisabledMethods = disabledMethods ?? Array.Empty(); + this.MaxConcurrentConnections = maxConcurrentConnections; + } + + public RpcServerSettings(IConfigurationSection section) + { + this.BindAddress = IPAddress.Parse(section.GetSection("BindAddress").Value); + this.Port = ushort.Parse(section.GetSection("Port").Value); + this.SslCert = section.GetSection("SslCert").Value; + this.SslCertPassword = section.GetSection("SslCertPassword").Value; + this.TrustedAuthorities = section.GetSection("TrustedAuthorities").GetChildren().Select(p => p.Get()).ToArray(); + this.RpcUser = section.GetSection("RpcUser").Value; + this.RpcPass = section.GetSection("RpcPass").Value; + this.MaxGasInvoke = (long)BigDecimal.Parse(section.GetValue("MaxGasInvoke", "10"), NativeContract.GAS.Decimals).Value; + this.MaxFee = (long)BigDecimal.Parse(section.GetValue("MaxFee", "0.1"), NativeContract.GAS.Decimals).Value; + this.DisabledMethods = section.GetSection("DisabledMethods").GetChildren().Select(p => p.Get()).ToArray(); + this.MaxConcurrentConnections = section.GetValue("MaxConcurrentConnections", 40); + } + + public void UpdateSettings(RpcServerSettings settings) + { + this.RpcUser = settings.RpcUser; + this.RpcPass = settings.RpcPass; + this.MaxGasInvoke = settings.MaxGasInvoke; + this.MaxFee = settings.MaxFee; + this.DisabledMethods = settings.DisabledMethods; + } + } +} diff --git a/src/RpcServer/Settings.cs b/src/RpcServer/Settings.cs deleted file mode 100644 index 1b6a6acd6..000000000 --- a/src/RpcServer/Settings.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Microsoft.Extensions.Configuration; -using Neo.SmartContract.Native; -using System.Linq; -using System.Net; - -namespace Neo.Plugins -{ - internal class Settings - { - public IPAddress BindAddress { get; } - public ushort Port { get; } - public string SslCert { get; } - public string SslCertPassword { get; } - public string[] TrustedAuthorities { get; } - public string RpcUser { get; } - public string RpcPass { get; } - public long MaxGasInvoke { get; } - public long MaxFee { get; } - public string[] DisabledMethods { get; } - public int MaxConcurrentConnections { get; } - - public static Settings Default { get; private set; } - - private Settings(IConfigurationSection section) - { - this.BindAddress = IPAddress.Parse(section.GetSection("BindAddress").Value); - this.Port = ushort.Parse(section.GetSection("Port").Value); - this.SslCert = section.GetSection("SslCert").Value; - this.SslCertPassword = section.GetSection("SslCertPassword").Value; - this.TrustedAuthorities = section.GetSection("TrustedAuthorities").GetChildren().Select(p => p.Get()).ToArray(); - this.RpcUser = section.GetSection("RpcUser").Value; - this.RpcPass = section.GetSection("RpcPass").Value; - this.MaxGasInvoke = (long)BigDecimal.Parse(section.GetValue("MaxGasInvoke", "10"), NativeContract.GAS.Decimals).Value; - this.MaxFee = (long)BigDecimal.Parse(section.GetValue("MaxFee", "0.1"), NativeContract.GAS.Decimals).Value; - this.DisabledMethods = section.GetSection("DisabledMethods").GetChildren().Select(p => p.Get()).ToArray(); - this.MaxConcurrentConnections = section.GetValue("MaxConcurrentConnections", 40); - } - - public static void Load(IConfigurationSection section) - { - Default = new Settings(section); - } - } -} From 14f3f4b43b7fca50b038343e63c74e2f5f26e167 Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Thu, 16 Apr 2020 12:54:25 +0800 Subject: [PATCH 113/183] Fix SystemLog (#222) --- src/SystemLog/Logger.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/SystemLog/Logger.cs b/src/SystemLog/Logger.cs index 8ce3981ee..0e759b2a2 100644 --- a/src/SystemLog/Logger.cs +++ b/src/SystemLog/Logger.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using System.Text; using static System.IO.Path; namespace Neo.Plugins @@ -39,7 +40,10 @@ void ILogPlugin.Log(string source, LogLevel level, string message) if (!string.IsNullOrEmpty(Settings.Default.Path)) { - var path = Combine(Settings.Default.Path, source); + StringBuilder sb = new StringBuilder(source); + foreach (char c in GetInvalidFileNameChars()) + sb.Replace(c, '-'); + var path = Combine(Settings.Default.Path, sb.ToString()); Directory.CreateDirectory(path); path = Combine(path, $"{now:yyyy-MM-dd}.log"); File.AppendAllLines(path, new[] { $"[{level}]{log}" }); From 6d2ba88531df69a97a48b2bde152363e649e1712 Mon Sep 17 00:00:00 2001 From: Shargon Date: Thu, 16 Apr 2020 07:43:10 +0200 Subject: [PATCH 114/183] Update and consolidate nugets (#194) --- src/RpcClient/RpcClient.cs | 13 ++++++++++++- .../Neo.Plugins.Storage.Tests.csproj | 6 +++--- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/RpcClient/RpcClient.cs b/src/RpcClient/RpcClient.cs index 58cc53934..1bd381cb2 100644 --- a/src/RpcClient/RpcClient.cs +++ b/src/RpcClient/RpcClient.cs @@ -3,6 +3,7 @@ using Neo.Ledger; using Neo.Network.P2P.Payloads; using Neo.Network.RPC.Models; +using Neo.SmartContract.Manifest; using System; using System.Collections.Generic; using System.Linq; @@ -179,7 +180,17 @@ public RpcBlockHeader GetBlockHeader(string hashOrIndex) /// public ContractState GetContractState(string hash) { - return RpcContractState.FromJson(RpcSend("getcontractstate", hash)).ContractState; + return ContractStateFromJson(RpcSend("getcontractstate", hash)); + } + + public static ContractState ContractStateFromJson(JObject json) + { + return new ContractState + { + Id = (int)json["id"].AsNumber(), + Script = Convert.FromBase64String(json["script"].AsString()), + Manifest = ContractManifest.FromJson(json["manifest"]) + }; } /// diff --git a/tests/Neo.Plugins.Storage.Tests/Neo.Plugins.Storage.Tests.csproj b/tests/Neo.Plugins.Storage.Tests/Neo.Plugins.Storage.Tests.csproj index bac39ca1f..ac7f99449 100644 --- a/tests/Neo.Plugins.Storage.Tests/Neo.Plugins.Storage.Tests.csproj +++ b/tests/Neo.Plugins.Storage.Tests/Neo.Plugins.Storage.Tests.csproj @@ -7,9 +7,9 @@ - - - + + + From 5adfcd5340b13179936e95760cb4374feabc8275 Mon Sep 17 00:00:00 2001 From: Krain Chen Date: Sat, 18 Apr 2020 14:40:17 +0800 Subject: [PATCH 115/183] add multi-sig-transfer (#213) --- src/RpcClient/Nep5API.cs | 29 +++++++++++++++++++ src/RpcClient/RpcClient.cs | 17 +++++++---- src/RpcClient/TransactionManager.cs | 16 +++++++++- src/RpcClient/Utility.cs | 2 +- src/RpcClient/WalletAPI.cs | 20 ++++++++++++- .../UT_TransactionManager.cs | 3 +- tests/Neo.Network.RPC.Tests/UT_WalletAPI.cs | 24 +++++++++++++++ 7 files changed, 101 insertions(+), 10 deletions(-) diff --git a/src/RpcClient/Nep5API.cs b/src/RpcClient/Nep5API.cs index 558c5453e..c6ffe60c9 100644 --- a/src/RpcClient/Nep5API.cs +++ b/src/RpcClient/Nep5API.cs @@ -1,8 +1,10 @@ +using Neo.Cryptography.ECC; using Neo.Network.P2P.Payloads; using Neo.Network.RPC.Models; using Neo.SmartContract; using Neo.VM; using Neo.Wallets; +using System; using System.Linq; using System.Numerics; using static Neo.Helper; @@ -117,5 +119,32 @@ public Transaction CreateTransferTx(UInt160 scriptHash, KeyPair fromKey, UInt160 return tx; } + + /// + /// Create NEP5 token transfer transaction from multi-sig account + /// + /// contract script hash + /// multi-sig min signature count + /// multi-sig pubKeys + /// sign keys + /// to account + /// transfer amount + /// + public Transaction CreateTransferTx(UInt160 scriptHash, int m, ECPoint[] pubKeys, KeyPair[] fromKeys, UInt160 to, BigInteger amount) + { + if (m > fromKeys.Length) + throw new ArgumentException($"Need at least {m} KeyPairs for signing!"); + var sender = Contract.CreateMultiSigContract(m, pubKeys).ScriptHash; + Cosigner[] cosigners = new[] { new Cosigner { Scopes = WitnessScope.CalledByEntry, Account = sender } }; + + byte[] script = scriptHash.MakeScript("transfer", sender, to, amount); + Transaction tx = new TransactionManager(rpcClient, sender) + .MakeTransaction(script, null, cosigners) + .AddMultiSig(fromKeys, m, pubKeys) + .Sign() + .Tx; + + return tx; + } } } diff --git a/src/RpcClient/RpcClient.cs b/src/RpcClient/RpcClient.cs index 1bd381cb2..ea1eebeaf 100644 --- a/src/RpcClient/RpcClient.cs +++ b/src/RpcClient/RpcClient.cs @@ -316,9 +316,14 @@ public UInt256 SubmitBlock(byte[] block) /// Returns the result after calling a smart contract at scripthash with the given operation and parameters. /// This RPC call does not affect the blockchain in any way. /// - public RpcInvokeResult InvokeFunction(string scriptHash, string operation, RpcStack[] stacks) + public RpcInvokeResult InvokeFunction(string scriptHash, string operation, RpcStack[] stacks, params UInt160[] scriptHashesForVerifying) { - return RpcInvokeResult.FromJson(RpcSend("invokefunction", scriptHash, operation, stacks.Select(p => p.ToJson()).ToArray())); + List parameters = new List { scriptHash, operation, stacks.Select(p => p.ToJson()).ToArray() }; + if (scriptHashesForVerifying.Length > 0) + { + parameters.Add(scriptHashesForVerifying.Select(p => (JObject)p.ToString()).ToArray()); + } + return RpcInvokeResult.FromJson(RpcSend("invokefunction", parameters.ToArray())); } /// @@ -327,11 +332,11 @@ public RpcInvokeResult InvokeFunction(string scriptHash, string operation, RpcSt /// public RpcInvokeResult InvokeScript(byte[] script, params UInt160[] scriptHashesForVerifying) { - List parameters = new List + List parameters = new List { script.ToHexString() }; + if (scriptHashesForVerifying.Length > 0) { - script.ToHexString() - }; - parameters.AddRange(scriptHashesForVerifying.Select(p => (JObject)p.ToString())); + parameters.Add(scriptHashesForVerifying.Select(p => (JObject)p.ToString()).ToArray()); + } return RpcInvokeResult.FromJson(RpcSend("invokescript", parameters.ToArray())); } diff --git a/src/RpcClient/TransactionManager.cs b/src/RpcClient/TransactionManager.cs index 1ce09d6d9..f71482400 100644 --- a/src/RpcClient/TransactionManager.cs +++ b/src/RpcClient/TransactionManager.cs @@ -78,7 +78,6 @@ public TransactionManager MakeTransaction(byte[] script, TransactionAttribute[] UInt160[] hashes = Tx.GetScriptHashesForVerifying(null); RpcInvokeResult result = rpcClient.InvokeScript(script, hashes); Tx.SystemFee = Math.Max(long.Parse(result.GasConsumed) - ApplicationEngine.GasFree, 0); - context = new ContractParametersContext(Tx); signStore = new List(); @@ -141,6 +140,21 @@ public TransactionManager AddMultiSig(KeyPair key, int m, params ECPoint[] publi return this; } + /// + /// Add Multi-Signature + /// + /// The KeyPairs to sign transction + /// The least count of signatures needed for multiple signature contract + /// The Public Keys construct the multiple signature contract + public TransactionManager AddMultiSig(KeyPair[] keys, int m, params ECPoint[] publicKeys) + { + foreach (var key in keys) + { + AddMultiSig(key, m, publicKeys); + } + return this; + } + private void AddSignItem(Contract contract, KeyPair key) { if (!Tx.GetScriptHashesForVerifying(null).Contains(contract.ScriptHash)) diff --git a/src/RpcClient/Utility.cs b/src/RpcClient/Utility.cs index bf7c95fe2..e6a6aa847 100644 --- a/src/RpcClient/Utility.cs +++ b/src/RpcClient/Utility.cs @@ -76,7 +76,7 @@ public static UInt160 GetScriptHash(string account) /// float value /// token decimals /// - internal static BigInteger ToBigInteger(this decimal amount, uint decimals) + public static BigInteger ToBigInteger(this decimal amount, uint decimals) { BigInteger factor = BigInteger.Pow(10, (int)decimals); var (numerator, denominator) = Fraction(amount); diff --git a/src/RpcClient/WalletAPI.cs b/src/RpcClient/WalletAPI.cs index afb44e6d4..c00b6d188 100644 --- a/src/RpcClient/WalletAPI.cs +++ b/src/RpcClient/WalletAPI.cs @@ -1,3 +1,4 @@ +using Neo.Cryptography.ECC; using Neo.Ledger; using Neo.Network.P2P.Payloads; using Neo.Network.RPC.Models; @@ -142,7 +143,7 @@ public Transaction Transfer(string tokenHash, string fromKey, string toAddress, } /// - /// Transfer NEP5 token balance + /// Transfer NEP5 token from single-sig account /// /// contract script hash /// from KeyPair @@ -156,6 +157,23 @@ public Transaction Transfer(UInt160 scriptHash, KeyPair from, UInt160 to, BigInt return transaction; } + /// + /// Transfer NEP5 token from multi-sig account + /// + /// contract script hash + /// multi-sig min signature count + /// multi-sig pubKeys + /// sign keys + /// to account + /// transfer amount + /// + public Transaction Transfer(UInt160 scriptHash, int m, ECPoint[] pubKeys, KeyPair[] keys, UInt160 to, BigInteger amountInteger) + { + Transaction transaction = nep5API.CreateTransferTx(scriptHash, m, pubKeys, keys, to, amountInteger); + rpcClient.SendRawTransaction(transaction); + return transaction; + } + /// /// Wait until the transaction is observable block chain /// diff --git a/tests/Neo.Network.RPC.Tests/UT_TransactionManager.cs b/tests/Neo.Network.RPC.Tests/UT_TransactionManager.cs index 722c1bb04..976dbf0b9 100644 --- a/tests/Neo.Network.RPC.Tests/UT_TransactionManager.cs +++ b/tests/Neo.Network.RPC.Tests/UT_TransactionManager.cs @@ -127,9 +127,10 @@ public void TestSign() byte[] signature = tx.Witnesses[0].InvocationScript.Skip(2).ToArray(); Assert.IsTrue(Crypto.VerifySignature(tx.GetHashData(), signature, keyPair1.PublicKey.EncodePoint(false).Skip(1).ToArray())); - // verify network fee + // verify network fee and system fee long networkFee = tx.Size * (long)1000 + ApplicationEngine.OpCodePrices[OpCode.PUSHDATA1] + ApplicationEngine.OpCodePrices[OpCode.PUSHDATA1] + ApplicationEngine.OpCodePrices[OpCode.PUSHNULL] + InteropService.GetPrice(InteropService.Crypto.ECDsaVerify, null, null); Assert.AreEqual(networkFee, tx.NetworkFee); + Assert.AreEqual(100, tx.SystemFee); // duplicate sign should not add new witness txManager.AddSignature(keyPair1).Sign(); diff --git a/tests/Neo.Network.RPC.Tests/UT_WalletAPI.cs b/tests/Neo.Network.RPC.Tests/UT_WalletAPI.cs index 72b83af8a..37a0cc181 100644 --- a/tests/Neo.Network.RPC.Tests/UT_WalletAPI.cs +++ b/tests/Neo.Network.RPC.Tests/UT_WalletAPI.cs @@ -19,12 +19,14 @@ public class UT_WalletAPI string address1; UInt160 sender; WalletAPI walletAPI; + UInt160 multiSender; [TestInitialize] public void TestSetup() { keyPair1 = new KeyPair(Wallet.GetPrivateKeyFromWIF("KyXwTh1hB76RRMquSvnxZrJzQx7h9nQP2PCRL38v6VDb5ip3nf1p")); sender = Contract.CreateSignatureRedeemScript(keyPair1.PublicKey).ToScriptHash(); + multiSender = Contract.CreateMultiSigContract(1, keyPair1.PublicKey).ScriptHash; address1 = Wallets.Helper.ToAddress(sender); rpcClientMock = UT_TransactionManager.MockRpcClient(sender, new byte[0]); walletAPI = new WalletAPI(rpcClientMock.Object); @@ -104,6 +106,28 @@ public void TestTransfer() Assert.AreEqual(testScript.ToHexString(), tranaction.Script.ToHexString()); } + [TestMethod] + public void TestTransferfromMultiSigAccount() + { + byte[] balanceScript = NativeContract.GAS.Hash.MakeScript("balanceOf", multiSender); + var balanceResult = new ContractParameter() { Type = ContractParameterType.Integer, Value = BigInteger.Parse("10000000000000000") }; + + UT_TransactionManager.MockInvokeScript(rpcClientMock, balanceScript, balanceResult); + + byte[] decimalsScript = NativeContract.GAS.Hash.MakeScript("decimals"); + UT_TransactionManager.MockInvokeScript(rpcClientMock, decimalsScript, new ContractParameter { Type = ContractParameterType.Integer, Value = new BigInteger(8) }); + + byte[] testScript = NativeContract.GAS.Hash.MakeScript("transfer", multiSender, UInt160.Zero, NativeContract.GAS.Factor * 100); + UT_TransactionManager.MockInvokeScript(rpcClientMock, testScript, new ContractParameter { Type = ContractParameterType.Integer, Value = new BigInteger(1_10000000) }); + + var json = new JObject(); + json["hash"] = UInt256.Zero.ToString(); + rpcClientMock.Setup(p => p.RpcSend("sendrawtransaction", It.IsAny())).Returns(json); + + var tranaction = walletAPI.Transfer(NativeContract.GAS.Hash, 1, new[] { keyPair1.PublicKey }, new[] { keyPair1 }, UInt160.Zero, NativeContract.GAS.Factor * 100); + Assert.AreEqual(testScript.ToHexString(), tranaction.Script.ToHexString()); + } + [TestMethod] public void TestWaitTransaction() { From db682b695b83169c23d612fa2106517384cd1b67 Mon Sep 17 00:00:00 2001 From: cn1010 Date: Wed, 22 Apr 2020 11:59:26 +0800 Subject: [PATCH 116/183] Update nugets (#226) --- src/ApplicationLogs/ApplicationLogs.csproj | 2 +- src/LevelDBStore/LevelDBStore.csproj | 4 +- src/RocksDBStore/RocksDBStore.csproj | 4 +- src/RpcClient/RpcClient.csproj | 4 +- src/RpcNep5Tracker/RpcNep5Tracker.csproj | 2 +- src/RpcServer/RpcServer.Blockchain.cs | 2 +- src/RpcServer/RpcServer.csproj | 4 +- src/StatesDumper/StatesDumper.csproj | 4 +- src/SystemLog/SystemLog.csproj | 4 +- tests/Neo.Network.RPC.Tests/RpcTestCases.json | 170 +++++++++--------- .../UT_ContractClient.cs | 15 +- 11 files changed, 111 insertions(+), 104 deletions(-) diff --git a/src/ApplicationLogs/ApplicationLogs.csproj b/src/ApplicationLogs/ApplicationLogs.csproj index afef18509..c06947925 100644 --- a/src/ApplicationLogs/ApplicationLogs.csproj +++ b/src/ApplicationLogs/ApplicationLogs.csproj @@ -1,7 +1,7 @@ - 3.0.0-CI00847 + 3.0.0-preview2 netstandard2.1 Neo.Plugins diff --git a/src/LevelDBStore/LevelDBStore.csproj b/src/LevelDBStore/LevelDBStore.csproj index 1fadbf184..50333d3ad 100644 --- a/src/LevelDBStore/LevelDBStore.csproj +++ b/src/LevelDBStore/LevelDBStore.csproj @@ -1,7 +1,7 @@ - 3.0.0-CI00863 + 3.0.0-preview2 netstandard2.1 Neo true @@ -15,7 +15,7 @@ - + diff --git a/src/RocksDBStore/RocksDBStore.csproj b/src/RocksDBStore/RocksDBStore.csproj index 26249747a..50cdd8140 100644 --- a/src/RocksDBStore/RocksDBStore.csproj +++ b/src/RocksDBStore/RocksDBStore.csproj @@ -1,7 +1,7 @@ - 3.0.0-CI00863 + 3.0.0-preview2 netstandard2.1 Neo.Plugins.Storage @@ -14,7 +14,7 @@ - + diff --git a/src/RpcClient/RpcClient.csproj b/src/RpcClient/RpcClient.csproj index a6d1ea769..4e50acdb5 100644 --- a/src/RpcClient/RpcClient.csproj +++ b/src/RpcClient/RpcClient.csproj @@ -1,7 +1,7 @@ - 3.0.0-CI00863 + 3.0.0-preview2 netstandard2.1 Neo.Network.RPC The Neo Project @@ -14,7 +14,7 @@ - + diff --git a/src/RpcNep5Tracker/RpcNep5Tracker.csproj b/src/RpcNep5Tracker/RpcNep5Tracker.csproj index 840a5c92a..408ffed03 100644 --- a/src/RpcNep5Tracker/RpcNep5Tracker.csproj +++ b/src/RpcNep5Tracker/RpcNep5Tracker.csproj @@ -1,6 +1,6 @@ - 3.0.0-CI00847 + 3.0.0-preview2 netstandard2.1 Neo.Plugins diff --git a/src/RpcServer/RpcServer.Blockchain.cs b/src/RpcServer/RpcServer.Blockchain.cs index ef52b4a1b..0bb0b0371 100644 --- a/src/RpcServer/RpcServer.Blockchain.cs +++ b/src/RpcServer/RpcServer.Blockchain.cs @@ -185,7 +185,7 @@ private JObject GetValidators(JArray _params) { using SnapshotView snapshot = Blockchain.Singleton.GetSnapshot(); var validators = NativeContract.NEO.GetValidators(snapshot); - return NativeContract.NEO.GetRegisteredValidators(snapshot).Select(p => + return NativeContract.NEO.GetCandidates(snapshot).Select(p => { JObject validator = new JObject(); validator["publickey"] = p.PublicKey.ToString(); diff --git a/src/RpcServer/RpcServer.csproj b/src/RpcServer/RpcServer.csproj index 644f0e54d..147b24854 100644 --- a/src/RpcServer/RpcServer.csproj +++ b/src/RpcServer/RpcServer.csproj @@ -1,7 +1,7 @@ - 3.0.0-CI00863 + 3.0.0-preview2 netstandard2.1 Neo.Plugins @@ -15,7 +15,7 @@ - + diff --git a/src/StatesDumper/StatesDumper.csproj b/src/StatesDumper/StatesDumper.csproj index 17d361ca2..d700a251e 100644 --- a/src/StatesDumper/StatesDumper.csproj +++ b/src/StatesDumper/StatesDumper.csproj @@ -1,7 +1,7 @@ - 3.0.0-CI00863 + 3.0.0-preview2 netstandard2.1 Neo.Plugins @@ -14,7 +14,7 @@ - + diff --git a/src/SystemLog/SystemLog.csproj b/src/SystemLog/SystemLog.csproj index d5dc065c4..6f4f0b309 100644 --- a/src/SystemLog/SystemLog.csproj +++ b/src/SystemLog/SystemLog.csproj @@ -1,7 +1,7 @@ - 3.0.0-CI00863 + 3.0.0-preview2 netstandard2.1 Neo.Plugins @@ -14,7 +14,7 @@ - + diff --git a/tests/Neo.Network.RPC.Tests/RpcTestCases.json b/tests/Neo.Network.RPC.Tests/RpcTestCases.json index 95c7b1409..b8505f2e3 100644 --- a/tests/Neo.Network.RPC.Tests/RpcTestCases.json +++ b/tests/Neo.Network.RPC.Tests/RpcTestCases.json @@ -50,7 +50,7 @@ "Request": { "jsonrpc": "2.0", "method": "getblock", - "params": [ "0x5bb05a3b857c9eaaf94dc33fa5b4a2278601eefcdb90703698972ef7d029e445" ], + "params": [ "0xe191fe1aea732c3e23f20af8a95e09f95891176f8064a2fce8571d51f80619a8" ], "id": 1 }, "Response": { @@ -71,7 +71,7 @@ "jsonrpc": "2.0", "id": 1, "result": { - "hash": "0x5bb05a3b857c9eaaf94dc33fa5b4a2278601eefcdb90703698972ef7d029e445", + "hash": "0xe191fe1aea732c3e23f20af8a95e09f95891176f8064a2fce8571d51f80619a8", "size": 171, "version": 0, "previousblockhash": "0x0000000000000000000000000000000000000000000000000000000000000000", @@ -91,7 +91,7 @@ }, "tx": [ { - "hash": "0xb13fd7940186896233272811e61b69a0c4b7dd576fdf3b89987c8cdee2d71e37", + "hash": "0x019befa728a371a08fb0f78330b3c697ebc9d8bbf252bd173b17cc2bd6e97e9c", "size": 57, "version": 0, "nonce": 0, @@ -120,14 +120,14 @@ "Request": { "jsonrpc": "2.0", "method": "getblock", - "params": [ "0x5bb05a3b857c9eaaf94dc33fa5b4a2278601eefcdb90703698972ef7d029e445", true ], + "params": [ "0xe191fe1aea732c3e23f20af8a95e09f95891176f8064a2fce8571d51f80619a8", true ], "id": 1 }, "Response": { "jsonrpc": "2.0", "id": 1, "result": { - "hash": "0x5bb05a3b857c9eaaf94dc33fa5b4a2278601eefcdb90703698972ef7d029e445", + "hash": "0xe191fe1aea732c3e23f20af8a95e09f95891176f8064a2fce8571d51f80619a8", "size": 171, "version": 0, "previousblockhash": "0x0000000000000000000000000000000000000000000000000000000000000000", @@ -147,7 +147,7 @@ }, "tx": [ { - "hash": "0xb13fd7940186896233272811e61b69a0c4b7dd576fdf3b89987c8cdee2d71e37", + "hash": "0x019befa728a371a08fb0f78330b3c697ebc9d8bbf252bd173b17cc2bd6e97e9c", "size": 57, "version": 0, "nonce": 0, @@ -196,7 +196,7 @@ "Response": { "jsonrpc": "2.0", "id": 1, - "result": "0x5bb05a3b857c9eaaf94dc33fa5b4a2278601eefcdb90703698972ef7d029e445" + "result": "0xe191fe1aea732c3e23f20af8a95e09f95891176f8064a2fce8571d51f80619a8" } }, { @@ -218,7 +218,7 @@ "Request": { "jsonrpc": "2.0", "method": "getblockheader", - "params": [ "0x5bb05a3b857c9eaaf94dc33fa5b4a2278601eefcdb90703698972ef7d029e445" ], + "params": [ "0xe191fe1aea732c3e23f20af8a95e09f95891176f8064a2fce8571d51f80619a8" ], "id": 1 }, "Response": { @@ -239,7 +239,7 @@ "jsonrpc": "2.0", "id": 1, "result": { - "hash": "0x5bb05a3b857c9eaaf94dc33fa5b4a2278601eefcdb90703698972ef7d029e445", + "hash": "0xe191fe1aea732c3e23f20af8a95e09f95891176f8064a2fce8571d51f80619a8", "size": 105, "version": 0, "previousblockhash": "0x0000000000000000000000000000000000000000000000000000000000000000", @@ -263,14 +263,14 @@ "Request": { "jsonrpc": "2.0", "method": "getblockheader", - "params": [ "0x5bb05a3b857c9eaaf94dc33fa5b4a2278601eefcdb90703698972ef7d029e445", true ], + "params": [ "0xe191fe1aea732c3e23f20af8a95e09f95891176f8064a2fce8571d51f80619a8", true ], "id": 1 }, "Response": { "jsonrpc": "2.0", "id": 1, "result": { - "hash": "0x5bb05a3b857c9eaaf94dc33fa5b4a2278601eefcdb90703698972ef7d029e445", + "hash": "0xe191fe1aea732c3e23f20af8a95e09f95891176f8064a2fce8571d51f80619a8", "size": 105, "version": 0, "previousblockhash": "0x0000000000000000000000000000000000000000000000000000000000000000", @@ -308,106 +308,107 @@ "Request": { "jsonrpc": "2.0", "method": "getcontractstate", - "params": [ "0x8c23f196d8a1bfd103a9dcb1f9ccf0c611377d3b" ], + "params": [ "0x806b7fa0db3b46d6c42e1e1b0a7fd50db9d4a9b0" ], "id": 1 }, "Response": { "jsonrpc": "2.0", "id": 1, "result": { - "id": -2, - "hash": "0x8c23f196d8a1bfd103a9dcb1f9ccf0c611377d3b", - "script": "QetD9PQ=", + "id": 0, + "hash": "0x806b7fa0db3b46d6c42e1e1b0a7fd50db9d4a9b0", + "script": "VgIMFGklqlVHEkOanGE7oRTvo/rCPdvKYAwDKiwKYVcDAiFB6X04oAwBINshmlCaULQlIwAAACEMFGklqlVHEkOanGE7oRTvo/rCPdvKIUH4J+yMQCFB6X04oAwBQNshmlCaULQlKQEAAHgMCWJhbGFuY2VPZpcnDwAAAHkQziE1WgEAAEB4DAhkZWNpbWFsc5cnDAAAACE1sQEAAEB4DAZkZXBsb3mXJwwAAAAhNbQBAABAeAwEbmFtZZcnDAAAACE1OQIAAEB4DAZzeW1ib2yXJwwAAAAhNTsCAABAeAwSc3VwcG9ydGVkU3RhbmRhcmRzlycMAAAAITUfAgAAQHgMC3RvdGFsU3VwcGx5lycMAAAAITUmAgAAQHgMCHRyYW5zZmVylyclAAAAecoTsyUHAAAAEEB5EM55Ec5weRLOcWhpIVM1EgIAAEB4DAdkZXN0cm95lycMAAAAITUzAAAAQHgMB21pZ3JhdGWXJyAAAAB5yhKzJQcAAAAQQHkQznkRznJqIVA1EAAAAEAQQCFBxp8d8BFAVwACIQwUaSWqVUcSQ5qcYTuhFO+j+sI928ohQfgn7IwlBwAAABBAeMonDAAAAHnKJQcAAAAQQHh5IVBBMcYzHRFAVwEBeMoMARTbIbMlPAAAAAwyVGhlIHBhcmFtZXRlciBhY2NvdW50IFNIT1VMRCBiZSAyMC1ieXRlIGFkZHJlc3Nlcy4hRTohQZv2Z854IVBBkl3oMRBwJQcAAABoQCFBm/ZnznghUEGSXegx2yFAGEBXAQF4IUGpxUtBcGgnCQAAAGgSzkARQCFBm/ZnzgwLdG90YWxTdXBwbHkhUEGSXegxRSFBm/ZnziEMFGklqlVHEkOanGE7oRTvo/rCPdvKIQwDKiwKIVNB5j8YhCFBm/ZnzgwLdG90YWxTdXBwbHkhDAMqLAohU0HmPxiEIQshDBRpJapVRxJDmpxhO6EU76P6wj3byiEMAyosCiFTDAhUcmFuc2ZlchTAQZUBb2ERQAwVTmVwNSBOZW8zIFRlbXBsYXRlIDEgQAwDTk5EQBPDShAMBU5FUC010EoRDAVORVAtN9BKEgwGTkVQLTEw0EAhQZv2Z84MC3RvdGFsU3VwcGx5IVBBkl3oMdshQFcCA3oQticHAAAAEEB4IUH4J+yMJQcAAAAQQHnKDAEU2yGzJQcAAAAQQCFBm/ZnznghUEGSXegx2yFwaHq1JwcAAAAQQHh5mlCaULQlBwAAABFAaHqzJxgAAAAhQZv2Z854IVBBL1jF7SMWAAAAIUGb9mfOeGh6nyFTQeY/GIQhQZv2Z855IVBBkl3oMXFpJ0QAAAAMB2lmIHBhc3MhQc/nR5YhQZv2Z855adshep4hU0HmPxiEDBBTdG9yYWdlLnB1dCBwYXNzIUHP50eWIzsAAAAMCWVsc2UgcGFzcyFBz+dHliFBm/Znznl6IVNB5j8YhAwOYW1vdW50IC0+IHBhc3MhQc/nR5YheHl6IVMMCFRyYW5zZmVyFMBBlQFvYRFA", "manifest": { "groups": [], "features": { "storage": true, - "payable": false + "payable": true }, "abi": { - "hash": "0x8c23f196d8a1bfd103a9dcb1f9ccf0c611377d3b", - "entryPoint": { - "name": "Main", - "parameters": [ - { - "name": "operation", - "type": "String" - }, - { - "name": "args", - "type": "Array" - } - ], - "returnType": "Any" - }, + "hash": "0x806b7fa0db3b46d6c42e1e1b0a7fd50db9d4a9b0", "methods": [ { - "name": "getSysFeeAmount", + "name": "main", "parameters": [ { - "name": "index", - "type": "Integer" + "name": "method", + "type": "String" + }, + { + "name": "args", + "type": "Array" } ], - "returnType": "Integer" + "offset": 0, + "returnType": "ByteArray" }, { - "name": "name", + "name": "Destroy", "parameters": [], - "returnType": "String" - }, - { - "name": "symbol", - "parameters": [], - "returnType": "String" - }, - { - "name": "decimals", - "parameters": [], - "returnType": "Integer" - }, - { - "name": "totalSupply", - "parameters": [], - "returnType": "Integer" + "offset": 400, + "returnType": "Boolean" }, { - "name": "balanceOf", + "name": "Migrate", "parameters": [ { - "name": "account", - "type": "Hash160" + "name": "script", + "type": "ByteArray" + }, + { + "name": "manifest", + "type": "String" } ], - "returnType": "Integer" + "offset": 408, + "returnType": "Boolean" }, { - "name": "transfer", + "name": "BalanceOf", "parameters": [ { - "name": "from", - "type": "Hash160" - }, - { - "name": "to", - "type": "Hash160" - }, - { - "name": "amount", - "type": "Integer" + "name": "account", + "type": "ByteArray" } ], - "returnType": "Boolean" + "offset": 474, + "returnType": "Integer" + }, + { + "name": "Decimals", + "parameters": [], + "offset": 585, + "returnType": "Integer" }, { - "name": "onPersist", + "name": "Deploy", "parameters": [], + "offset": 610, "returnType": "Boolean" }, { - "name": "supportedStandards", + "name": "Name", "parameters": [], + "offset": 763, + "returnType": "String" + }, + { + "name": "Symbol", + "parameters": [], + "offset": 787, + "returnType": "String" + }, + { + "name": "SupportedStandards", + "parameters": [], + "offset": 793, "returnType": "Array" + }, + { + "name": "TotalSupply", + "parameters": [], + "offset": 827, + "returnType": "Integer" } ], "events": [ @@ -415,18 +416,19 @@ "name": "Transfer", "parameters": [ { - "name": "from", - "type": "Hash160" + "name": "arg1", + "type": "ByteArray" }, { - "name": "to", - "type": "Hash160" + "name": "arg2", + "type": "ByteArray" }, { - "name": "amount", + "name": "arg3", "type": "Integer" } ], + "offset": 0, "returnType": "Signature" } ] @@ -438,15 +440,7 @@ } ], "trusts": [], - "safeMethods": [ - "getSysFeeAmount", - "name", - "symbol", - "decimals", - "totalSupply", - "balanceOf", - "supportedStandards" - ], + "safeMethods": [], "extra": null } } @@ -489,7 +483,7 @@ "Request": { "jsonrpc": "2.0", "method": "getrawtransaction", - "params": [ "0xd159457e12f6b0d4910fc6729f426be5d0c06f0f149d0836db9f634a5cf216fb" ], + "params": [ "0x0cfd49c48306f9027dc71585589b6456bcc53567c359fb7858eabca482186b78" ], "id": 1 }, "Response": { @@ -503,14 +497,14 @@ "Request": { "jsonrpc": "2.0", "method": "getrawtransaction", - "params": [ "0xd159457e12f6b0d4910fc6729f426be5d0c06f0f149d0836db9f634a5cf216fb", true ], + "params": [ "0x0cfd49c48306f9027dc71585589b6456bcc53567c359fb7858eabca482186b78", true ], "id": 1 }, "Response": { "jsonrpc": "2.0", "id": 1, "result": { - "hash": "0xd159457e12f6b0d4910fc6729f426be5d0c06f0f149d0836db9f634a5cf216fb", + "hash": "0x0cfd49c48306f9027dc71585589b6456bcc53567c359fb7858eabca482186b78", "size": 272, "version": 0, "nonce": 969006668, @@ -572,7 +566,7 @@ "Request": { "jsonrpc": "2.0", "method": "gettransactionheight", - "params": [ "0xd159457e12f6b0d4910fc6729f426be5d0c06f0f149d0836db9f634a5cf216fb" ], + "params": [ "0x0cfd49c48306f9027dc71585589b6456bcc53567c359fb7858eabca482186b78" ], "id": 1 }, "Response": { diff --git a/tests/Neo.Network.RPC.Tests/UT_ContractClient.cs b/tests/Neo.Network.RPC.Tests/UT_ContractClient.cs index f6fde1567..9d2a1fb2c 100644 --- a/tests/Neo.Network.RPC.Tests/UT_ContractClient.cs +++ b/tests/Neo.Network.RPC.Tests/UT_ContractClient.cs @@ -39,7 +39,20 @@ public void TestInvoke() public void TestDeployContract() { byte[] script; - var manifest = ContractManifest.CreateDefault(new byte[1].ToScriptHash()); + var manifest = new ContractManifest() + { + Permissions = new[] { ContractPermission.DefaultPermission }, + Abi = new ContractAbi() + { + Hash = new byte[1].ToScriptHash(), + Events = new ContractEventDescriptor[0], + Methods = new ContractMethodDescriptor[0] + }, + Groups = new ContractGroup[0], + SafeMethods = WildcardContainer.Create(), + Trusts = WildcardContainer.Create(), + Extra = null, + }; manifest.Features = ContractFeatures.HasStorage | ContractFeatures.Payable; using (ScriptBuilder sb = new ScriptBuilder()) { From 3cf726b7c639922c4d4a2b6b63ca741265207f73 Mon Sep 17 00:00:00 2001 From: cn1010 Date: Tue, 28 Apr 2020 17:24:10 +0800 Subject: [PATCH 117/183] Add StackItem ToJson (#221) --- src/ApplicationLogs/LogReader.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ApplicationLogs/LogReader.cs b/src/ApplicationLogs/LogReader.cs index da3978920..5983b0fca 100644 --- a/src/ApplicationLogs/LogReader.cs +++ b/src/ApplicationLogs/LogReader.cs @@ -52,7 +52,7 @@ public void OnPersist(StoreView snapshot, IReadOnlyList q.ToParameter().ToJson()).ToArray(); + json["stack"] = appExec.Stack.Select(q => q.ToJson()).ToArray(); } catch (InvalidOperationException) { @@ -64,7 +64,7 @@ public void OnPersist(StoreView snapshot, IReadOnlyList Date: Thu, 7 May 2020 17:53:46 +0800 Subject: [PATCH 118/183] Override RpcServerPlugin's name (#235) --- src/RpcServer/RpcServerPlugin.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/RpcServer/RpcServerPlugin.cs b/src/RpcServer/RpcServerPlugin.cs index e2ff2d838..45e2ebd03 100644 --- a/src/RpcServer/RpcServerPlugin.cs +++ b/src/RpcServer/RpcServerPlugin.cs @@ -5,6 +5,7 @@ namespace Neo.Plugins public sealed class RpcServerPlugin : Plugin { static List handlers = new List(); + public override string Name => "RpcServer"; RpcServer server; RpcServerSettings settings; From 6b06c1f43998a2ae5fc9b5371303d391cf8724b8 Mon Sep 17 00:00:00 2001 From: ZhangHaoqiang Date: Mon, 11 May 2020 10:17:22 +0800 Subject: [PATCH 119/183] Fix RpcServer RegisterMethods (#239) * Fix RpcServer RegisterMethods * Update RpcServerPlugin.cs OnPluginsLoaded() will do RegisterMethods --- src/RpcServer/RpcServerPlugin.cs | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/RpcServer/RpcServerPlugin.cs b/src/RpcServer/RpcServerPlugin.cs index 45e2ebd03..ed62be904 100644 --- a/src/RpcServer/RpcServerPlugin.cs +++ b/src/RpcServer/RpcServerPlugin.cs @@ -47,17 +47,6 @@ protected override void OnPluginsLoaded() public static void RegisterMethods(object handler) { - // if RpcServerPlugin is already loaded, call RegisterMethods directly - foreach (var plugin in Plugin.Plugins) - { - if (plugin is RpcServerPlugin rpcServerPlugin) - { - rpcServerPlugin.server.RegisterMethods(handler); - return; - } - } - - // otherwise, save the handler for use during RpcServerPlugin load handlers.Add(handler); } } From 779a0b70690e74c4ac5993a70ddb852642df88ff Mon Sep 17 00:00:00 2001 From: Shargon Date: Mon, 11 May 2020 10:47:39 +0200 Subject: [PATCH 120/183] Update nugets (#233) * Close 232 * Sync to the latest neo. * Fix UT * Deal with exceptions * Use last version * Fix compilation * Fix RPC module UTs. Co-authored-by: superboyiii <573504781@qq.com> Co-authored-by: zhuoqian Co-authored-by: Owen Zhang <38493437+superboyiii@users.noreply.github.com> --- src/LevelDBStore/LevelDBStore.csproj | 2 +- src/RocksDBStore/RocksDBStore.csproj | 2 +- src/RpcClient/ContractClient.cs | 2 +- src/RpcClient/Models/RpcBlock.cs | 2 +- src/RpcClient/Models/RpcBlockHeader.cs | 2 +- src/RpcClient/Models/RpcTransaction.cs | 2 +- src/RpcClient/Nep5API.cs | 4 +- src/RpcClient/RpcClient.csproj | 2 +- src/RpcClient/TransactionManager.cs | 6 +- src/RpcClient/Utility.cs | 86 +++++++++++++++++++ src/RpcServer/RpcServer.csproj | 2 +- src/StatesDumper/StatesDumper.csproj | 2 +- src/SystemLog/Logger.cs | 29 ++++++- src/SystemLog/SystemLog.csproj | 2 +- tests/Neo.Network.RPC.Tests/RpcTestCases.json | 34 +++----- tests/Neo.Network.RPC.Tests/TestUtils.cs | 1 - .../UT_TransactionManager.cs | 33 +++---- 17 files changed, 154 insertions(+), 59 deletions(-) diff --git a/src/LevelDBStore/LevelDBStore.csproj b/src/LevelDBStore/LevelDBStore.csproj index 50333d3ad..d49d4f5c2 100644 --- a/src/LevelDBStore/LevelDBStore.csproj +++ b/src/LevelDBStore/LevelDBStore.csproj @@ -15,7 +15,7 @@ - + diff --git a/src/RocksDBStore/RocksDBStore.csproj b/src/RocksDBStore/RocksDBStore.csproj index 50cdd8140..11d92850a 100644 --- a/src/RocksDBStore/RocksDBStore.csproj +++ b/src/RocksDBStore/RocksDBStore.csproj @@ -14,7 +14,7 @@ - + diff --git a/src/RpcClient/ContractClient.cs b/src/RpcClient/ContractClient.cs index c00b799e0..67d4484c9 100644 --- a/src/RpcClient/ContractClient.cs +++ b/src/RpcClient/ContractClient.cs @@ -54,7 +54,7 @@ public Transaction CreateDeployContractTx(byte[] contractScript, ContractManifes UInt160 sender = Contract.CreateSignatureRedeemScript(key.PublicKey).ToScriptHash(); Transaction tx = new TransactionManager(rpcClient, sender) - .MakeTransaction(script, null, null) + .MakeTransaction(script, null) .AddSignature(key) .Sign() .Tx; diff --git a/src/RpcClient/Models/RpcBlock.cs b/src/RpcClient/Models/RpcBlock.cs index 6689572e5..3eab2a91a 100644 --- a/src/RpcClient/Models/RpcBlock.cs +++ b/src/RpcClient/Models/RpcBlock.cs @@ -22,7 +22,7 @@ public JObject ToJson() public static RpcBlock FromJson(JObject json) { RpcBlock block = new RpcBlock(); - block.Block = Block.FromJson(json); + block.Block = Utility.BlockFromJson(json); block.Confirmations = (uint)json["confirmations"].AsNumber(); block.NextBlockHash = json["nextblockhash"] is null ? null : UInt256.Parse(json["nextblockhash"].AsString()); return block; diff --git a/src/RpcClient/Models/RpcBlockHeader.cs b/src/RpcClient/Models/RpcBlockHeader.cs index 94def029f..5072827df 100644 --- a/src/RpcClient/Models/RpcBlockHeader.cs +++ b/src/RpcClient/Models/RpcBlockHeader.cs @@ -22,7 +22,7 @@ public JObject ToJson() public static RpcBlockHeader FromJson(JObject json) { RpcBlockHeader block = new RpcBlockHeader(); - block.Header = Header.FromJson(json); + block.Header = Utility.HeaderFromJson(json); block.Confirmations = (uint)json["confirmations"].AsNumber(); block.NextBlockHash = json["nextblockhash"] is null ? null : UInt256.Parse(json["nextblockhash"].AsString()); return block; diff --git a/src/RpcClient/Models/RpcTransaction.cs b/src/RpcClient/Models/RpcTransaction.cs index 6b5a0743c..b376c2cdb 100644 --- a/src/RpcClient/Models/RpcTransaction.cs +++ b/src/RpcClient/Models/RpcTransaction.cs @@ -35,7 +35,7 @@ public JObject ToJson() public static RpcTransaction FromJson(JObject json) { RpcTransaction transaction = new RpcTransaction(); - transaction.Transaction = Transaction.FromJson(json); + transaction.Transaction = Utility.TransactionFromJson(json); if (json["confirmations"] != null) { transaction.BlockHash = UInt256.Parse(json["blockhash"].AsString()); diff --git a/src/RpcClient/Nep5API.cs b/src/RpcClient/Nep5API.cs index c6ffe60c9..e111e4f99 100644 --- a/src/RpcClient/Nep5API.cs +++ b/src/RpcClient/Nep5API.cs @@ -112,7 +112,7 @@ public Transaction CreateTransferTx(UInt160 scriptHash, KeyPair fromKey, UInt160 byte[] script = scriptHash.MakeScript("transfer", sender, to, amount); Transaction tx = new TransactionManager(rpcClient, sender) - .MakeTransaction(script, null, cosigners) + .MakeTransaction(script, cosigners) .AddSignature(fromKey) .Sign() .Tx; @@ -139,7 +139,7 @@ public Transaction CreateTransferTx(UInt160 scriptHash, int m, ECPoint[] pubKeys byte[] script = scriptHash.MakeScript("transfer", sender, to, amount); Transaction tx = new TransactionManager(rpcClient, sender) - .MakeTransaction(script, null, cosigners) + .MakeTransaction(script, cosigners) .AddMultiSig(fromKeys, m, pubKeys) .Sign() .Tx; diff --git a/src/RpcClient/RpcClient.csproj b/src/RpcClient/RpcClient.csproj index 4e50acdb5..40c918937 100644 --- a/src/RpcClient/RpcClient.csproj +++ b/src/RpcClient/RpcClient.csproj @@ -14,7 +14,7 @@ - + diff --git a/src/RpcClient/TransactionManager.cs b/src/RpcClient/TransactionManager.cs index f71482400..39fd2da06 100644 --- a/src/RpcClient/TransactionManager.cs +++ b/src/RpcClient/TransactionManager.cs @@ -56,9 +56,8 @@ public TransactionManager(RpcClient rpc, UInt160 sender) /// /// Transaction Script /// Transaction Attributes - /// Transaction Cosigners /// - public TransactionManager MakeTransaction(byte[] script, TransactionAttribute[] attributes = null, Cosigner[] cosigners = null) + public TransactionManager MakeTransaction(byte[] script, TransactionAttribute[] attributes = null) { var random = new Random(); uint height = rpcClient.GetBlockCount() - 1; @@ -70,7 +69,6 @@ public TransactionManager MakeTransaction(byte[] script, TransactionAttribute[] Sender = sender, ValidUntilBlock = height + Transaction.MaxValidUntilBlockIncrement, Attributes = attributes ?? Array.Empty(), - Cosigners = cosigners ?? Array.Empty(), Witnesses = Array.Empty() }; @@ -92,7 +90,7 @@ private long CalculateNetworkFee() { long networkFee = 0; UInt160[] hashes = Tx.GetScriptHashesForVerifying(null); - int size = Transaction.HeaderSize + Tx.Attributes.GetVarSize() + Tx.Cosigners.GetVarSize() + Tx.Script.GetVarSize() + IO.Helper.GetVarSize(hashes.Length); + int size = Transaction.HeaderSize + Tx.Attributes.GetVarSize() + Tx.Script.GetVarSize() + IO.Helper.GetVarSize(hashes.Length); foreach (UInt160 hash in hashes) { byte[] witness_script = null; diff --git a/src/RpcClient/Utility.cs b/src/RpcClient/Utility.cs index e6a6aa847..ff65c9377 100644 --- a/src/RpcClient/Utility.cs +++ b/src/RpcClient/Utility.cs @@ -1,7 +1,11 @@ using Neo.Cryptography.ECC; +using Neo.IO.Json; +using Neo.Network.P2P.Payloads; using Neo.SmartContract; using Neo.Wallets; using System; +using System.Globalization; +using System.Linq; using System.Numerics; namespace Neo.Network.RPC @@ -88,5 +92,87 @@ public static BigInteger ToBigInteger(this decimal amount, uint decimals) BigInteger res = factor * numerator / denominator; return res; } + + public static Block BlockFromJson(JObject json) + { + Block block = new Block(); + BlockBase blockBase = block; + blockBase.FromJson(json); + block.ConsensusData = ConsensusDataFromJson(json["consensus_data"]); + block.Transactions = ((JArray)json["tx"]).Select(p => TransactionFromJson(p)).ToArray(); + return block; + } + + public static void FromJson(this BlockBase block, JObject json) + { + block.Version = (uint)json["version"].AsNumber(); + block.PrevHash = UInt256.Parse(json["previousblockhash"].AsString()); + block.MerkleRoot = UInt256.Parse(json["merkleroot"].AsString()); + block.Timestamp = (ulong)json["time"].AsNumber(); + block.Index = (uint)json["index"].AsNumber(); + block.NextConsensus = json["nextconsensus"].AsString().ToScriptHash(); + block.Witness = ((JArray)json["witnesses"]).Select(p => WitnessFromJson(p)).FirstOrDefault(); + } + + public static Transaction TransactionFromJson(JObject json) + { + Transaction tx = new Transaction(); + tx.Version = byte.Parse(json["version"].AsString()); + tx.Nonce = uint.Parse(json["nonce"].AsString()); + tx.Sender = json["sender"].AsString().ToScriptHash(); + tx.SystemFee = long.Parse(json["sys_fee"].AsString()); + tx.NetworkFee = long.Parse(json["net_fee"].AsString()); + tx.ValidUntilBlock = uint.Parse(json["valid_until_block"].AsString()); + tx.Attributes = ((JArray)json["attributes"]).Select(p => TransactionAttributeFromJson(p)).ToArray(); + tx.Script = Convert.FromBase64String(json["script"].AsString()); + tx.Witnesses = ((JArray)json["witnesses"]).Select(p => WitnessFromJson(p)).ToArray(); + return tx; + } + + public static Header HeaderFromJson(JObject json) + { + Header header = new Header(); + BlockBase blockBase = header; + blockBase.FromJson(json); + return header; + } + + public static Cosigner CosignerFromJson(JObject json) + { + return new Cosigner + { + Account = UInt160.Parse(json["account"].AsString()), + Scopes = (WitnessScope)Enum.Parse(typeof(WitnessScope), json["scopes"].AsString()), + AllowedContracts = ((JArray)json["allowedContracts"])?.Select(p => UInt160.Parse(p.AsString())).ToArray(), + AllowedGroups = ((JArray)json["allowedGroups"])?.Select(p => ECPoint.Parse(p.AsString(), ECCurve.Secp256r1)).ToArray() + }; + } + + public static ConsensusData ConsensusDataFromJson(JObject json) + { + ConsensusData block = new ConsensusData(); + block.PrimaryIndex = (uint)json["primary"].AsNumber(); + block.Nonce = ulong.Parse(json["nonce"].AsString(), NumberStyles.HexNumber); + return block; + } + + public static TransactionAttribute TransactionAttributeFromJson(JObject json) + { + TransactionAttributeType usage = Enum.Parse(json["type"].AsString()); + + switch (usage) + { + case TransactionAttributeType.Cosigner: return CosignerFromJson(json); + default: throw new FormatException(); + } + } + + public static Witness WitnessFromJson(JObject json) + { + Witness witness = new Witness(); + witness.InvocationScript = Convert.FromBase64String(json["invocation"].AsString()); + witness.VerificationScript = Convert.FromBase64String(json["verification"].AsString()); + return witness; + } } } diff --git a/src/RpcServer/RpcServer.csproj b/src/RpcServer/RpcServer.csproj index 147b24854..1bfb1be70 100644 --- a/src/RpcServer/RpcServer.csproj +++ b/src/RpcServer/RpcServer.csproj @@ -15,7 +15,7 @@ - + diff --git a/src/StatesDumper/StatesDumper.csproj b/src/StatesDumper/StatesDumper.csproj index d700a251e..228d217e0 100644 --- a/src/StatesDumper/StatesDumper.csproj +++ b/src/StatesDumper/StatesDumper.csproj @@ -14,7 +14,7 @@ - + diff --git a/src/SystemLog/Logger.cs b/src/SystemLog/Logger.cs index 0e759b2a2..f3d940f86 100644 --- a/src/SystemLog/Logger.cs +++ b/src/SystemLog/Logger.cs @@ -14,8 +14,35 @@ protected override void Configure() Settings.Load(GetConfiguration()); } - void ILogPlugin.Log(string source, LogLevel level, string message) + private static void GetErrorLogs(StringBuilder sb, Exception ex) { + sb.AppendLine(ex.GetType().ToString()); + sb.AppendLine(ex.Message); + sb.AppendLine(ex.StackTrace); + if (ex is AggregateException ex2) + { + foreach (Exception inner in ex2.InnerExceptions) + { + sb.AppendLine(); + GetErrorLogs(sb, inner); + } + } + else if (ex.InnerException != null) + { + sb.AppendLine(); + GetErrorLogs(sb, ex.InnerException); + } + } + + void ILogPlugin.Log(string source, LogLevel level, object message) + { + if (message is Exception ex) + { + var sb = new StringBuilder(); + GetErrorLogs(sb, ex); + message = sb.ToString(); + } + lock (typeof(Logger)) { DateTime now = DateTime.Now; diff --git a/src/SystemLog/SystemLog.csproj b/src/SystemLog/SystemLog.csproj index 6f4f0b309..8571f15fa 100644 --- a/src/SystemLog/SystemLog.csproj +++ b/src/SystemLog/SystemLog.csproj @@ -14,7 +14,7 @@ - + diff --git a/tests/Neo.Network.RPC.Tests/RpcTestCases.json b/tests/Neo.Network.RPC.Tests/RpcTestCases.json index b8505f2e3..86bf50c7d 100644 --- a/tests/Neo.Network.RPC.Tests/RpcTestCases.json +++ b/tests/Neo.Network.RPC.Tests/RpcTestCases.json @@ -4,7 +4,7 @@ "Request": { "jsonrpc": "2.0", "method": "sendrawtransaction", - "params": [ "00b5077e7bb8cef712d3f9b3ec90d36e7bf8d50ac81718a3b000e1f5050000000080778e0600000000e31420000001b8cef712d3f9b3ec90d36e7bf8d50ac81718a3b0015c0300e40b54020000000c1400000000000000000000000000000000000000000c14b8cef712d3f9b3ec90d36e7bf8d50ac81718a3b013c00c087472616e736665720c143b7d3711c6f0ccf9b1dca903d1bfa1d896f1238c41627d5b5201420c4077a5ffdc41dce3b06418879a26bac0fcea06af4a833446c90f63a3e80b85d13e07ca9084989e7c7e4535187409058dc7233ba8ee4638593605134e2c2c8f3c9f290c2102f9ec1fd0a98796cf75b586772a4ddd41a0af07a1dbdf86a7238f74fb725035750b410a906ad4" ], + "params": [ "00b5077e7bb8cef712d3f9b3ec90d36e7bf8d50ac81718a3b000e1f5050000000080778e0600000000e3142000005c0300e40b54020000000c1400000000000000000000000000000000000000000c14b8cef712d3f9b3ec90d36e7bf8d50ac81718a3b013c00c087472616e736665720c143b7d3711c6f0ccf9b1dca903d1bfa1d896f1238c41627d5b5201420c4077a5ffdc41dce3b06418879a26bac0fcea06af4a833446c90f63a3e80b85d13e07ca9084989e7c7e4535187409058dc7233ba8ee4638593605134e2c2c8f3c9f290c2102f9ec1fd0a98796cf75b586772a4ddd41a0af07a1dbdf86a7238f74fb725035750b410a906ad4" ], "id": 1 }, "Response": { @@ -72,7 +72,7 @@ "id": 1, "result": { "hash": "0xe191fe1aea732c3e23f20af8a95e09f95891176f8064a2fce8571d51f80619a8", - "size": 171, + "size": 170, "version": 0, "previousblockhash": "0x0000000000000000000000000000000000000000000000000000000000000000", "merkleroot": "0x735b68ca1bab490b8fd6166cba4c2ce76e97bedfe4d2df0c333970fc9862bb2b", @@ -91,8 +91,8 @@ }, "tx": [ { - "hash": "0x019befa728a371a08fb0f78330b3c697ebc9d8bbf252bd173b17cc2bd6e97e9c", - "size": 57, + "hash": "0x55808e2014b486a607a4617c81a6f5060ec363eff6cfc80210221b2e8a1f1013", + "size": 56, "version": 0, "nonce": 0, "sender": "NeN4xPMn4kHoj7G8Lciq9oorgLTvqt4qi1", @@ -100,7 +100,6 @@ "net_fee": "0", "valid_until_block": 0, "attributes": [], - "cosigners": [], "script": "QRI+f+g=", "witnesses": [ { @@ -128,7 +127,7 @@ "id": 1, "result": { "hash": "0xe191fe1aea732c3e23f20af8a95e09f95891176f8064a2fce8571d51f80619a8", - "size": 171, + "size": 170, "version": 0, "previousblockhash": "0x0000000000000000000000000000000000000000000000000000000000000000", "merkleroot": "0x735b68ca1bab490b8fd6166cba4c2ce76e97bedfe4d2df0c333970fc9862bb2b", @@ -147,8 +146,8 @@ }, "tx": [ { - "hash": "0x019befa728a371a08fb0f78330b3c697ebc9d8bbf252bd173b17cc2bd6e97e9c", - "size": 57, + "hash": "0x55808e2014b486a607a4617c81a6f5060ec363eff6cfc80210221b2e8a1f1013", + "size": 56, "version": 0, "nonce": 0, "sender": "NeN4xPMn4kHoj7G8Lciq9oorgLTvqt4qi1", @@ -156,7 +155,6 @@ "net_fee": "0", "valid_until_block": 0, "attributes": [], - "cosigners": [], "script": "QRI+f+g=", "witnesses": [ { @@ -489,7 +487,7 @@ "Response": { "jsonrpc": "2.0", "id": 1, - "result": "004cdec1396925aa554712439a9c613ba114efa3fac23ddbca00e1f50500000000466a130000000000311d200000016925aa554712439a9c613ba114efa3fac23ddbca015d030010a5d4e80000000c149903b0c3d292988febe5f306a02f654ea2eb16290c146925aa554712439a9c613ba114efa3fac23ddbca13c00c087472616e736665720c143b7d3711c6f0ccf9b1dca903d1bfa1d896f1238c41627d5b523901420c401f85b40d7fa12164aa1d4d18b06ca470f2c89572dc5b901ab1667faebb587cf536454b98a09018adac72376c5e7c5d164535155b763564347aa47b69aa01b3cc290c2103aa052fbcb8e5b33a4eefd662536f8684641f04109f1d5e69cdda6f084890286a0b410a906ad4" + "result": "004cdec1396925aa554712439a9c613ba114efa3fac23ddbca00e1f50500000000466a130000000000311d2000005d030010a5d4e80000000c149903b0c3d292988febe5f306a02f654ea2eb16290c146925aa554712439a9c613ba114efa3fac23ddbca13c00c087472616e736665720c143b7d3711c6f0ccf9b1dca903d1bfa1d896f1238c41627d5b523901420c401f85b40d7fa12164aa1d4d18b06ca470f2c89572dc5b901ab1667faebb587cf536454b98a09018adac72376c5e7c5d164535155b763564347aa47b69aa01b3cc290c2103aa052fbcb8e5b33a4eefd662536f8684641f04109f1d5e69cdda6f084890286a0b410a906ad4" } }, { @@ -497,15 +495,15 @@ "Request": { "jsonrpc": "2.0", "method": "getrawtransaction", - "params": [ "0x0cfd49c48306f9027dc71585589b6456bcc53567c359fb7858eabca482186b78", true ], + "params": [ "0x4d47255ff5564aaa73855068c3574f8f28e2bb18c7fb7256e58ae51fab44c9bc", true ], "id": 1 }, "Response": { "jsonrpc": "2.0", "id": 1, "result": { - "hash": "0x0cfd49c48306f9027dc71585589b6456bcc53567c359fb7858eabca482186b78", - "size": 272, + "hash": "0x4d47255ff5564aaa73855068c3574f8f28e2bb18c7fb7256e58ae51fab44c9bc", + "size": 250, "version": 0, "nonce": 969006668, "sender": "NVVwFw6XyhtRCFQ8SpUTMdPyYt4Vd9A1XQ", @@ -513,12 +511,6 @@ "net_fee": "1272390", "valid_until_block": 2104625, "attributes": [], - "cosigners": [ - { - "account": "0xcadb3dc2faa3ef14a13b619c9a43124755aa2569", - "scopes": "CalledByEntry" - } - ], "script": "AwAQpdToAAAADBSZA7DD0pKYj+vl8wagL2VOousWKQwUaSWqVUcSQ5qcYTuhFO+j+sI928oTwAwIdHJhbnNmZXIMFDt9NxHG8Mz5sdypA9G/odiW8SOMQWJ9W1I5", "witnesses": [ { @@ -667,14 +659,14 @@ "Request": { "jsonrpc": "2.0", "method": "sendrawtransaction", - "params": [ "00142449186925aa554712439a9c613ba114efa3fac23ddbca00e1f50500000000a65a1300000000001d20200000016925aa554712439a9c613ba114efa3fac23ddbca01590200e1f5050c149903b0c3d292988febe5f306a02f654ea2eb16290c146925aa554712439a9c613ba114efa3fac23ddbca13c00c087472616e736665720c143b7d3711c6f0ccf9b1dca903d1bfa1d896f1238c41627d5b523901420c4076507ef5922e84aac57f09cb699ecbb10bc3d9c06ef908bed812c35fd2651531de27091f1e6e81566454fcc1c5f129d1051b08704c3fec3f6ed793563cfd30bb290c2103aa052fbcb8e5b33a4eefd662536f8684641f04109f1d5e69cdda6f084890286a0b410a906ad4" ], + "params": [ "00142449186925aa554712439a9c613ba114efa3fac23ddbca00e1f50500000000a65a1300000000001d20200000590200e1f5050c149903b0c3d292988febe5f306a02f654ea2eb16290c146925aa554712439a9c613ba114efa3fac23ddbca13c00c087472616e736665720c143b7d3711c6f0ccf9b1dca903d1bfa1d896f1238c41627d5b523901420c4076507ef5922e84aac57f09cb699ecbb10bc3d9c06ef908bed812c35fd2651531de27091f1e6e81566454fcc1c5f129d1051b08704c3fec3f6ed793563cfd30bb290c2103aa052fbcb8e5b33a4eefd662536f8684641f04109f1d5e69cdda6f084890286a0b410a906ad4" ], "id": 1 }, "Response": { "jsonrpc": "2.0", "id": 1, "result": { - "hash": "0x32cda8771aca33da2f7a022b33468fd658abd2521b58dd6ba1ffb89883903405" + "hash": "0x4d47255ff5564aaa73855068c3574f8f28e2bb18c7fb7256e58ae51fab44c9bc" } } }, diff --git a/tests/Neo.Network.RPC.Tests/TestUtils.cs b/tests/Neo.Network.RPC.Tests/TestUtils.cs index 2c4128376..582715022 100644 --- a/tests/Neo.Network.RPC.Tests/TestUtils.cs +++ b/tests/Neo.Network.RPC.Tests/TestUtils.cs @@ -40,7 +40,6 @@ public static Transaction GetTransaction() Script = new byte[1], Sender = UInt160.Zero, Attributes = new TransactionAttribute[0], - Cosigners = new Cosigner[0], Witnesses = new Witness[] { new Witness diff --git a/tests/Neo.Network.RPC.Tests/UT_TransactionManager.cs b/tests/Neo.Network.RPC.Tests/UT_TransactionManager.cs index 976dbf0b9..cd1dcdad0 100644 --- a/tests/Neo.Network.RPC.Tests/UT_TransactionManager.cs +++ b/tests/Neo.Network.RPC.Tests/UT_TransactionManager.cs @@ -80,20 +80,20 @@ public void TestMakeTransaction() { txManager = new TransactionManager(rpcClientMock.Object, sender); - TransactionAttribute[] attributes = new TransactionAttribute[1] + var attributes = new TransactionAttribute[1] { - new TransactionAttribute + new Cosigner { - Usage = TransactionAttributeUsage.Url, - Data = "53616d706c6555726c".HexToBytes() // "SampleUrl" + Account = sender, + Scopes= WitnessScope.Global } }; byte[] script = new byte[1]; - txManager.MakeTransaction(script, attributes, null); + txManager.MakeTransaction(script, attributes); var tx = txManager.Tx; - Assert.AreEqual("53616d706c6555726c", tx.Attributes[0].Data.ToHexString()); + Assert.AreEqual(WitnessScope.Global, (tx.Attributes[0] as Cosigner).Scopes); } [TestMethod] @@ -101,24 +101,17 @@ public void TestSign() { txManager = new TransactionManager(rpcClientMock.Object, sender); - TransactionAttribute[] attributes = new TransactionAttribute[1] + var attributes = new TransactionAttribute[1] { - new TransactionAttribute + new Cosigner { - Usage = TransactionAttributeUsage.Url, - Data = "53616d706c6555726c".HexToBytes() // "SampleUrl" - } - }; - - Cosigner[] cosigners = new Cosigner[1] { - new Cosigner{ Account = sender, Scopes = WitnessScope.Global } }; byte[] script = new byte[1]; - txManager.MakeTransaction(script, attributes, cosigners) + txManager.MakeTransaction(script, attributes) .AddSignature(keyPair1) .Sign(); @@ -126,9 +119,9 @@ public void TestSign() var tx = txManager.Tx; byte[] signature = tx.Witnesses[0].InvocationScript.Skip(2).ToArray(); - Assert.IsTrue(Crypto.VerifySignature(tx.GetHashData(), signature, keyPair1.PublicKey.EncodePoint(false).Skip(1).ToArray())); + Assert.IsTrue(Crypto.VerifySignature(tx.GetHashData(), signature, keyPair1.PublicKey)); // verify network fee and system fee - long networkFee = tx.Size * (long)1000 + ApplicationEngine.OpCodePrices[OpCode.PUSHDATA1] + ApplicationEngine.OpCodePrices[OpCode.PUSHDATA1] + ApplicationEngine.OpCodePrices[OpCode.PUSHNULL] + InteropService.GetPrice(InteropService.Crypto.ECDsaVerify, null, null); + long networkFee = tx.Size * (long)1000 + ApplicationEngine.OpCodePrices[OpCode.PUSHDATA1] + ApplicationEngine.OpCodePrices[OpCode.PUSHDATA1] + ApplicationEngine.OpCodePrices[OpCode.PUSHNULL] + InteropService.GetPrice(InteropService.Crypto.VerifyWithECDsaSecp256r1, null, null); Assert.AreEqual(networkFee, tx.NetworkFee); Assert.AreEqual(100, tx.SystemFee); @@ -158,7 +151,7 @@ public void TestSignMulti() }; byte[] script = new byte[1]; - txManager.MakeTransaction(script, null, cosigners) + txManager.MakeTransaction(script, cosigners) .AddMultiSig(keyPair1, 2, keyPair1.PublicKey, keyPair2.PublicKey) .AddMultiSig(keyPair2, 2, keyPair1.PublicKey, keyPair2.PublicKey) .AddSignature(keyPair1) @@ -181,7 +174,7 @@ public void TestAddWitness() }; byte[] script = new byte[1]; - txManager.MakeTransaction(script, null, cosigners); + txManager.MakeTransaction(script, cosigners); txManager.AddWitness(UInt160.Zero); txManager.AddSignature(keyPair1); txManager.Sign(); From 3dcd2bdac59611ad5c71fcb4891f631919892d0a Mon Sep 17 00:00:00 2001 From: Shargon Date: Tue, 12 May 2020 04:17:50 +0200 Subject: [PATCH 121/183] Allow to share logs in read mode (#240) * Allow to share logs in read mode * Catch exception * Update Logger.cs * format format Co-authored-by: Owen Zhang <38493437+superboyiii@users.noreply.github.com> --- src/SystemLog/Logger.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/SystemLog/Logger.cs b/src/SystemLog/Logger.cs index f3d940f86..b8ef7d5e3 100644 --- a/src/SystemLog/Logger.cs +++ b/src/SystemLog/Logger.cs @@ -70,10 +70,19 @@ void ILogPlugin.Log(string source, LogLevel level, object message) StringBuilder sb = new StringBuilder(source); foreach (char c in GetInvalidFileNameChars()) sb.Replace(c, '-'); + var path = Combine(Settings.Default.Path, sb.ToString()); Directory.CreateDirectory(path); path = Combine(path, $"{now:yyyy-MM-dd}.log"); - File.AppendAllLines(path, new[] { $"[{level}]{log}" }); + try + { + File.AppendAllLines(path, new[] { $"[{level}]{log}" }); + } + catch (IOException) + { + Console.WriteLine("Error writing the log file: " + path); + + } } } } From a314f9ee66a0b529b63d62165a6a358cdceb7eaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vitor=20Naz=C3=A1rio=20Coelho?= Date: Mon, 25 May 2020 04:39:10 -0300 Subject: [PATCH 122/183] Create generic getunclaimedgas and rename wallet ones (#243) * Create generic getunclaimedgas and rename wallet ones * Throw exception --- src/RpcServer/RpcServer.SmartContract.cs | 26 ++++++++++++++++++++++++ src/RpcServer/RpcServer.Wallet.cs | 4 ++-- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/src/RpcServer/RpcServer.SmartContract.cs b/src/RpcServer/RpcServer.SmartContract.cs index 639288656..d9e2311a8 100644 --- a/src/RpcServer/RpcServer.SmartContract.cs +++ b/src/RpcServer/RpcServer.SmartContract.cs @@ -9,6 +9,10 @@ using System; using System.IO; using System.Linq; +using Neo.IO; +using Neo.Ledger; +using Neo.SmartContract.Native; +using Neo.Wallets; namespace Neo.Plugins { @@ -92,5 +96,27 @@ private JObject InvokeScript(JArray _params) CheckWitnessHashes checkWitnessHashes = _params.Count >= 2 ? new CheckWitnessHashes(((JArray)_params[1]).Select(u => UInt160.Parse(u.AsString())).ToArray()) : null; return GetInvokeResult(script, checkWitnessHashes); } + + [RpcMethod] + private JObject GetUnclaimedGas(JArray _params) + { + string address = _params[0].AsString(); + JObject json = new JObject(); + UInt160 script_hash; + try + { + script_hash = address.ToScriptHash(); + } + catch + { + script_hash = null; + } + if (script_hash == null) + throw new RpcException(-100, "Invalid address"); + SnapshotView snapshot = Blockchain.Singleton.GetSnapshot(); + json["unclaimed"] = NativeContract.NEO.UnclaimedGas(snapshot, script_hash, snapshot.Height + 1).ToString(); + json["address"] = script_hash.ToAddress(); + return json; + } } } diff --git a/src/RpcServer/RpcServer.Wallet.cs b/src/RpcServer/RpcServer.Wallet.cs index 0a47622ef..da087cdf7 100644 --- a/src/RpcServer/RpcServer.Wallet.cs +++ b/src/RpcServer/RpcServer.Wallet.cs @@ -48,7 +48,7 @@ private JObject DumpPrivKey(JArray _params) } [RpcMethod] - private JObject GetBalance(JArray _params) + private JObject GetWalletBalance(JArray _params) { CheckWallet(); UInt160 asset_id = UInt160.Parse(_params[0].AsString()); @@ -68,7 +68,7 @@ private JObject GetNewAddress(JArray _params) } [RpcMethod] - private JObject GetUnclaimedGas(JArray _params) + private JObject GetWalletUnclaimedGas(JArray _params) { CheckWallet(); BigInteger gas = BigInteger.Zero; From 2bcfb9d6b4050e0f1c6496702f2139b42f68ce4e Mon Sep 17 00:00:00 2001 From: Luchuan Date: Thu, 28 May 2020 02:34:44 +0800 Subject: [PATCH 123/183] fix relay tx (#249) --- src/RpcServer/RpcServer.Wallet.cs | 2 +- src/RpcServer/RpcServer.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/RpcServer/RpcServer.Wallet.cs b/src/RpcServer/RpcServer.Wallet.cs index da087cdf7..b0b0f4f74 100644 --- a/src/RpcServer/RpcServer.Wallet.cs +++ b/src/RpcServer/RpcServer.Wallet.cs @@ -285,7 +285,7 @@ private JObject SignAndRelay(Transaction tx) if (context.Completed) { tx.Witnesses = context.GetWitnesses(); - system.LocalNode.Tell(new LocalNode.Relay { Inventory = tx }); + system.Blockchain.Tell(tx); return tx.ToJson(); } else diff --git a/src/RpcServer/RpcServer.csproj b/src/RpcServer/RpcServer.csproj index 1bfb1be70..23b492203 100644 --- a/src/RpcServer/RpcServer.csproj +++ b/src/RpcServer/RpcServer.csproj @@ -15,7 +15,7 @@ - + From eb75e0d730ebe0e62eafd22b2b8859377936bca4 Mon Sep 17 00:00:00 2001 From: Luchuan Date: Mon, 1 Jun 2020 13:44:28 +0800 Subject: [PATCH 124/183] add issue template (#250) --- .github/ISSUE_TEMPLATE/bug_report.md | 31 +++++++++++++++++++ .../feature-or-enhancement-request.md | 27 ++++++++++++++++ .github/ISSUE_TEMPLATE/questions.md | 9 ++++++ 3 files changed, 67 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/feature-or-enhancement-request.md create mode 100644 .github/ISSUE_TEMPLATE/questions.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 000000000..f69eccca7 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,31 @@ +--- +name: Bug report +about: Create a report to detail an error or unexpected behavior +title: '' +labels: '' +assignees: '' +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Open the project, run '...' +2. Type '...' or do '...' +3. ... + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Platform:** + - OS: [e.g. Windows 10 x64] + - Version [e.g. neo-cli 2.10.2] + +**(Optional) Additional context** +Add any other context about the problem here. + +However, if your issue does not fit these aforementioned criteria, or it can be understood in another manner, feel free to open it in a different format. diff --git a/.github/ISSUE_TEMPLATE/feature-or-enhancement-request.md b/.github/ISSUE_TEMPLATE/feature-or-enhancement-request.md new file mode 100644 index 000000000..9b98d24f9 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature-or-enhancement-request.md @@ -0,0 +1,27 @@ +--- +name: Feature or enhancement request +about: Suggest an idea for Neo +title: '' +labels: discussion +assignees: '' +--- + +**Summary or problem description** +A summary of the problem you want to solve or metric you want to improve + +**Do you have any solution you want to propose?** +A clear and concise description of what you expect with this change. + +**Where in the software does this update applies to?** +- Compiler +- Consensus +- CLI +- Plugins +- Ledger +- Network Policy +- P2P (TCP) +- RPC (HTTP) +- SDK +- VM +- Other: + diff --git a/.github/ISSUE_TEMPLATE/questions.md b/.github/ISSUE_TEMPLATE/questions.md new file mode 100644 index 000000000..4d97925f8 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/questions.md @@ -0,0 +1,9 @@ +--- +name: Questions +about: Questions about Neo Platform +title: '' +labels: question +assignees: '' +--- + +**Delete this: We would like to use GitHub for bug reports and feature requests only however if you are unable to get support from our team in: our [Discord](https://discord.io/neo) server or in our [offical documentation](https://docs.neo.org/docs/en-us/index.html), feel encouraged to create an issue here on GitHub.** From bd7468ee6476621eb93edb66e8a7b019ebed4d2e Mon Sep 17 00:00:00 2001 From: Luchuan Date: Fri, 5 Jun 2020 13:56:46 +0800 Subject: [PATCH 125/183] delete systemlog plugin (#246) Co-authored-by: Shargon --- src/SystemLog/ConsoleColorSet.cs | 51 ---------------- src/SystemLog/Logger.cs | 90 ----------------------------- src/SystemLog/Settings.cs | 23 -------- src/SystemLog/SystemLog.csproj | 20 ------- src/SystemLog/SystemLog/config.json | 7 --- 5 files changed, 191 deletions(-) delete mode 100644 src/SystemLog/ConsoleColorSet.cs delete mode 100644 src/SystemLog/Logger.cs delete mode 100644 src/SystemLog/Settings.cs delete mode 100644 src/SystemLog/SystemLog.csproj delete mode 100644 src/SystemLog/SystemLog/config.json diff --git a/src/SystemLog/ConsoleColorSet.cs b/src/SystemLog/ConsoleColorSet.cs deleted file mode 100644 index 6ca6549bf..000000000 --- a/src/SystemLog/ConsoleColorSet.cs +++ /dev/null @@ -1,51 +0,0 @@ -using System; - -namespace Neo.Plugins -{ - internal class ConsoleColorSet - { - #region Constants - - public static readonly ConsoleColorSet Debug = new ConsoleColorSet(ConsoleColor.Cyan); - public static readonly ConsoleColorSet Info = new ConsoleColorSet(ConsoleColor.White); - public static readonly ConsoleColorSet Warning = new ConsoleColorSet(ConsoleColor.Yellow); - public static readonly ConsoleColorSet Error = new ConsoleColorSet(ConsoleColor.Red); - public static readonly ConsoleColorSet Fatal = new ConsoleColorSet(ConsoleColor.Red); - - #endregion - - public ConsoleColor Foreground; - public ConsoleColor Background; - - /// - /// Create a new color set with the current console colors - /// - public ConsoleColorSet() : this(Console.ForegroundColor, Console.BackgroundColor) { } - - /// - /// Create a new color set - /// - /// Foreground color - public ConsoleColorSet(ConsoleColor foreground) : this(foreground, Console.BackgroundColor) { } - - /// - /// Create a new color set - /// - /// Foreground color - /// Background color - public ConsoleColorSet(ConsoleColor foreground, ConsoleColor background) - { - Foreground = foreground; - Background = background; - } - - /// - /// Apply the current set - /// - public void Apply() - { - Console.ForegroundColor = Foreground; - Console.BackgroundColor = Background; - } - } -} diff --git a/src/SystemLog/Logger.cs b/src/SystemLog/Logger.cs deleted file mode 100644 index b8ef7d5e3..000000000 --- a/src/SystemLog/Logger.cs +++ /dev/null @@ -1,90 +0,0 @@ -using System; -using System.IO; -using System.Text; -using static System.IO.Path; - -namespace Neo.Plugins -{ - public class Logger : Plugin, ILogPlugin - { - public override string Name => "SystemLog"; - - protected override void Configure() - { - Settings.Load(GetConfiguration()); - } - - private static void GetErrorLogs(StringBuilder sb, Exception ex) - { - sb.AppendLine(ex.GetType().ToString()); - sb.AppendLine(ex.Message); - sb.AppendLine(ex.StackTrace); - if (ex is AggregateException ex2) - { - foreach (Exception inner in ex2.InnerExceptions) - { - sb.AppendLine(); - GetErrorLogs(sb, inner); - } - } - else if (ex.InnerException != null) - { - sb.AppendLine(); - GetErrorLogs(sb, ex.InnerException); - } - } - - void ILogPlugin.Log(string source, LogLevel level, object message) - { - if (message is Exception ex) - { - var sb = new StringBuilder(); - GetErrorLogs(sb, ex); - message = sb.ToString(); - } - - lock (typeof(Logger)) - { - DateTime now = DateTime.Now; - var log = $"[{now.TimeOfDay:hh\\:mm\\:ss\\.fff}] {message}"; - - if (Settings.Default.ConsoleOutput) - { - var currentColor = new ConsoleColorSet(); - - switch (level) - { - case LogLevel.Debug: ConsoleColorSet.Debug.Apply(); break; - case LogLevel.Error: ConsoleColorSet.Error.Apply(); break; - case LogLevel.Fatal: ConsoleColorSet.Fatal.Apply(); break; - case LogLevel.Info: ConsoleColorSet.Info.Apply(); break; - case LogLevel.Warning: ConsoleColorSet.Warning.Apply(); break; - } - - Console.WriteLine(log); - currentColor.Apply(); - } - - if (!string.IsNullOrEmpty(Settings.Default.Path)) - { - StringBuilder sb = new StringBuilder(source); - foreach (char c in GetInvalidFileNameChars()) - sb.Replace(c, '-'); - - var path = Combine(Settings.Default.Path, sb.ToString()); - Directory.CreateDirectory(path); - path = Combine(path, $"{now:yyyy-MM-dd}.log"); - try - { - File.AppendAllLines(path, new[] { $"[{level}]{log}" }); - } - catch (IOException) - { - Console.WriteLine("Error writing the log file: " + path); - - } - } - } - } - } -} diff --git a/src/SystemLog/Settings.cs b/src/SystemLog/Settings.cs deleted file mode 100644 index 242da4d5c..000000000 --- a/src/SystemLog/Settings.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Microsoft.Extensions.Configuration; - -namespace Neo.Plugins -{ - internal class Settings - { - public string Path { get; } - public bool ConsoleOutput { get; } - - public static Settings Default { get; private set; } - - private Settings(IConfigurationSection section) - { - this.Path = string.Format(section.GetSection("Path").Value, ProtocolSettings.Default.Magic.ToString("X8")); - this.ConsoleOutput = section.GetSection("ConsoleOutput").Get(); - } - - public static void Load(IConfigurationSection section) - { - Default = new Settings(section); - } - } -} diff --git a/src/SystemLog/SystemLog.csproj b/src/SystemLog/SystemLog.csproj deleted file mode 100644 index 8571f15fa..000000000 --- a/src/SystemLog/SystemLog.csproj +++ /dev/null @@ -1,20 +0,0 @@ - - - - 3.0.0-preview2 - netstandard2.1 - Neo.Plugins - - - - - PreserveNewest - PreserveNewest - - - - - - - - diff --git a/src/SystemLog/SystemLog/config.json b/src/SystemLog/SystemLog/config.json deleted file mode 100644 index 8164bf7ce..000000000 --- a/src/SystemLog/SystemLog/config.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "PluginConfiguration": - { - "Path": "SystemLogs_{0}", - "ConsoleOutput": true - } -} From c51b96bb8802f48a14e2677a027bed408a0a5b26 Mon Sep 17 00:00:00 2001 From: Luchuan Date: Sun, 7 Jun 2020 15:14:24 +0800 Subject: [PATCH 126/183] Add plugin desc and fix ut (#257) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add plugin desc and sync neo-core * format Co-authored-by: Vitor Nazário Coelho --- src/ApplicationLogs/LogReader.cs | 2 ++ src/LevelDBStore/LevelDBStore.csproj | 2 +- src/LevelDBStore/Plugins/Storage/LevelDBStore.cs | 2 ++ src/RocksDBStore/Plugins/Storage/RocksDBStore.cs | 2 ++ src/RocksDBStore/RocksDBStore.csproj | 2 +- src/RpcClient/ContractClient.cs | 2 +- src/RpcClient/RpcClient.csproj | 2 +- src/RpcNep5Tracker/RpcNep5Tracker.cs | 2 ++ src/RpcServer/RpcServer.csproj | 2 +- src/RpcServer/RpcServerPlugin.cs | 1 + src/StatesDumper/StatesDumper.cs | 2 ++ src/StatesDumper/StatesDumper.csproj | 2 +- tests/Neo.Network.RPC.Tests/UT_ContractClient.cs | 2 +- tests/Neo.Network.RPC.Tests/UT_TransactionManager.cs | 2 +- 14 files changed, 19 insertions(+), 8 deletions(-) diff --git a/src/ApplicationLogs/LogReader.cs b/src/ApplicationLogs/LogReader.cs index 5983b0fca..e66839890 100644 --- a/src/ApplicationLogs/LogReader.cs +++ b/src/ApplicationLogs/LogReader.cs @@ -18,6 +18,8 @@ public class LogReader : Plugin, IPersistencePlugin public override string Name => "ApplicationLogs"; + public override string Description => "Synchronizes the smart contract log with the NativeContract log (Notify)"; + public LogReader() { db = DB.Open(GetFullPath(Settings.Default.Path), new Options { CreateIfMissing = true }); diff --git a/src/LevelDBStore/LevelDBStore.csproj b/src/LevelDBStore/LevelDBStore.csproj index d49d4f5c2..835d492c5 100644 --- a/src/LevelDBStore/LevelDBStore.csproj +++ b/src/LevelDBStore/LevelDBStore.csproj @@ -15,7 +15,7 @@ - + diff --git a/src/LevelDBStore/Plugins/Storage/LevelDBStore.cs b/src/LevelDBStore/Plugins/Storage/LevelDBStore.cs index 265c4286b..dcb59c871 100644 --- a/src/LevelDBStore/Plugins/Storage/LevelDBStore.cs +++ b/src/LevelDBStore/Plugins/Storage/LevelDBStore.cs @@ -6,6 +6,8 @@ public class LevelDBStore : Plugin, IStoragePlugin { private string path; + public override string Description => "Uses LevelDB to store the blockchain data"; + protected override void Configure() { path = string.Format(GetConfiguration().GetSection("Path").Value ?? "Data_LevelDB_{0}", ProtocolSettings.Default.Magic.ToString("X8")); diff --git a/src/RocksDBStore/Plugins/Storage/RocksDBStore.cs b/src/RocksDBStore/Plugins/Storage/RocksDBStore.cs index d847da5d1..afd11757d 100644 --- a/src/RocksDBStore/Plugins/Storage/RocksDBStore.cs +++ b/src/RocksDBStore/Plugins/Storage/RocksDBStore.cs @@ -4,6 +4,8 @@ namespace Neo.Plugins.Storage { public class RocksDBStore : Plugin, IStoragePlugin { + public override string Description => "Uses RocksDBStore to store the blockchain data"; + /// /// Configure /// diff --git a/src/RocksDBStore/RocksDBStore.csproj b/src/RocksDBStore/RocksDBStore.csproj index 11d92850a..01d858435 100644 --- a/src/RocksDBStore/RocksDBStore.csproj +++ b/src/RocksDBStore/RocksDBStore.csproj @@ -14,7 +14,7 @@ - + diff --git a/src/RpcClient/ContractClient.cs b/src/RpcClient/ContractClient.cs index 67d4484c9..3ae7ec22d 100644 --- a/src/RpcClient/ContractClient.cs +++ b/src/RpcClient/ContractClient.cs @@ -48,7 +48,7 @@ public Transaction CreateDeployContractTx(byte[] contractScript, ContractManifes byte[] script; using (ScriptBuilder sb = new ScriptBuilder()) { - sb.EmitSysCall(InteropService.Contract.Create, contractScript, manifest.ToString()); + sb.EmitSysCall(ApplicationEngine.System_Contract_Create, contractScript, manifest.ToString()); script = sb.ToArray(); } diff --git a/src/RpcClient/RpcClient.csproj b/src/RpcClient/RpcClient.csproj index 40c918937..547e761ad 100644 --- a/src/RpcClient/RpcClient.csproj +++ b/src/RpcClient/RpcClient.csproj @@ -14,7 +14,7 @@ - + diff --git a/src/RpcNep5Tracker/RpcNep5Tracker.cs b/src/RpcNep5Tracker/RpcNep5Tracker.cs index 2406c344c..2b3a6e1af 100644 --- a/src/RpcNep5Tracker/RpcNep5Tracker.cs +++ b/src/RpcNep5Tracker/RpcNep5Tracker.cs @@ -33,6 +33,8 @@ public class RpcNep5Tracker : Plugin, IPersistencePlugin private uint _maxResults; private Snapshot _levelDbSnapshot; + public override string Description => "Enquiries NEP-5 balance and transactions history of accounts through RPC"; + public RpcNep5Tracker() { RpcServerPlugin.RegisterMethods(this); diff --git a/src/RpcServer/RpcServer.csproj b/src/RpcServer/RpcServer.csproj index 23b492203..f5dba907e 100644 --- a/src/RpcServer/RpcServer.csproj +++ b/src/RpcServer/RpcServer.csproj @@ -15,7 +15,7 @@ - + diff --git a/src/RpcServer/RpcServerPlugin.cs b/src/RpcServer/RpcServerPlugin.cs index ed62be904..2d662432f 100644 --- a/src/RpcServer/RpcServerPlugin.cs +++ b/src/RpcServer/RpcServerPlugin.cs @@ -6,6 +6,7 @@ public sealed class RpcServerPlugin : Plugin { static List handlers = new List(); public override string Name => "RpcServer"; + public override string Description => "Enables RPC for the node"; RpcServer server; RpcServerSettings settings; diff --git a/src/StatesDumper/StatesDumper.cs b/src/StatesDumper/StatesDumper.cs index 02f969d89..7abc10e3f 100644 --- a/src/StatesDumper/StatesDumper.cs +++ b/src/StatesDumper/StatesDumper.cs @@ -15,6 +15,8 @@ public class StatesDumper : Plugin, IPersistencePlugin { private readonly JArray bs_cache = new JArray(); + public override string Description => "Exports Neo-CLI status data"; + protected override void Configure() { Settings.Load(GetConfiguration()); diff --git a/src/StatesDumper/StatesDumper.csproj b/src/StatesDumper/StatesDumper.csproj index 228d217e0..c49646329 100644 --- a/src/StatesDumper/StatesDumper.csproj +++ b/src/StatesDumper/StatesDumper.csproj @@ -14,7 +14,7 @@ - + diff --git a/tests/Neo.Network.RPC.Tests/UT_ContractClient.cs b/tests/Neo.Network.RPC.Tests/UT_ContractClient.cs index 9d2a1fb2c..fafca52c4 100644 --- a/tests/Neo.Network.RPC.Tests/UT_ContractClient.cs +++ b/tests/Neo.Network.RPC.Tests/UT_ContractClient.cs @@ -56,7 +56,7 @@ public void TestDeployContract() manifest.Features = ContractFeatures.HasStorage | ContractFeatures.Payable; using (ScriptBuilder sb = new ScriptBuilder()) { - sb.EmitSysCall(InteropService.Contract.Create, new byte[1], manifest.ToString()); + sb.EmitSysCall(ApplicationEngine.System_Contract_Create, new byte[1], manifest.ToString()); script = sb.ToArray(); } diff --git a/tests/Neo.Network.RPC.Tests/UT_TransactionManager.cs b/tests/Neo.Network.RPC.Tests/UT_TransactionManager.cs index cd1dcdad0..d027b0790 100644 --- a/tests/Neo.Network.RPC.Tests/UT_TransactionManager.cs +++ b/tests/Neo.Network.RPC.Tests/UT_TransactionManager.cs @@ -121,7 +121,7 @@ public void TestSign() Assert.IsTrue(Crypto.VerifySignature(tx.GetHashData(), signature, keyPair1.PublicKey)); // verify network fee and system fee - long networkFee = tx.Size * (long)1000 + ApplicationEngine.OpCodePrices[OpCode.PUSHDATA1] + ApplicationEngine.OpCodePrices[OpCode.PUSHDATA1] + ApplicationEngine.OpCodePrices[OpCode.PUSHNULL] + InteropService.GetPrice(InteropService.Crypto.VerifyWithECDsaSecp256r1, null, null); + long networkFee = tx.Size * (long)1000 + ApplicationEngine.OpCodePrices[OpCode.PUSHDATA1] + ApplicationEngine.OpCodePrices[OpCode.PUSHDATA1] + ApplicationEngine.OpCodePrices[OpCode.PUSHNULL] + ApplicationEngine.ECDsaVerifyPrice * 1; Assert.AreEqual(networkFee, tx.NetworkFee); Assert.AreEqual(100, tx.SystemFee); From 15776e30c154ff28e2faf2fc99de02eaeb271380 Mon Sep 17 00:00:00 2001 From: joeqian Date: Thu, 18 Jun 2020 20:17:29 +0800 Subject: [PATCH 127/183] Convert StackItem directly to json (#264) --- src/RpcServer/RpcServer.SmartContract.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/RpcServer/RpcServer.SmartContract.cs b/src/RpcServer/RpcServer.SmartContract.cs index d9e2311a8..bffb524c2 100644 --- a/src/RpcServer/RpcServer.SmartContract.cs +++ b/src/RpcServer/RpcServer.SmartContract.cs @@ -64,7 +64,7 @@ private JObject GetInvokeResult(byte[] script, IVerifiable checkWitnessHashes = json["gas_consumed"] = engine.GasConsumed.ToString(); try { - json["stack"] = new JArray(engine.ResultStack.Select(p => p.ToParameter().ToJson())); + json["stack"] = new JArray(engine.ResultStack.Select(p => p.ToJson())); } catch (InvalidOperationException) { From eddcd2c1b803c00170d8b4611c2b901931bf3942 Mon Sep 17 00:00:00 2001 From: joeqian Date: Thu, 25 Jun 2020 17:55:13 +0800 Subject: [PATCH 128/183] Change json field names for GetVersion (#262) Co-authored-by: Shargon --- src/RpcServer/RpcServer.Node.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/RpcServer/RpcServer.Node.cs b/src/RpcServer/RpcServer.Node.cs index 0483f5ed1..f42fd96c6 100644 --- a/src/RpcServer/RpcServer.Node.cs +++ b/src/RpcServer/RpcServer.Node.cs @@ -60,10 +60,10 @@ private static JObject GetRelayResult(VerifyResult reason, UInt256 hash) private JObject GetVersion(JArray _params) { JObject json = new JObject(); - json["tcp_port"] = LocalNode.Singleton.ListenerTcpPort; - json["ws_port"] = LocalNode.Singleton.ListenerWsPort; + json["tcpPort"] = LocalNode.Singleton.ListenerTcpPort; + json["wsPort"] = LocalNode.Singleton.ListenerWsPort; json["nonce"] = LocalNode.Nonce; - json["user_agent"] = LocalNode.UserAgent; + json["userAgent"] = LocalNode.UserAgent; return json; } From 1bbce6aa33e5a5aa9ce08475683526446ef5d89b Mon Sep 17 00:00:00 2001 From: HaoqiangZhang Date: Sun, 28 Jun 2020 15:21:11 +0800 Subject: [PATCH 129/183] remove system log (#272) --- neo-modules.sln | 7 ------- 1 file changed, 7 deletions(-) diff --git a/neo-modules.sln b/neo-modules.sln index 1f5f32fbc..763a89627 100644 --- a/neo-modules.sln +++ b/neo-modules.sln @@ -12,8 +12,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StatesDumper", "src\StatesD EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RpcNep5Tracker", "src\RpcNep5Tracker\RpcNep5Tracker.csproj", "{BBE8AC15-12DF-4AF0-ABC1-F1557EB5DC8E}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SystemLog", "src\SystemLog\SystemLog.csproj", "{14DB62D5-0EA1-4A98-8656-1AA2D0345206}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LevelDBStore", "src\LevelDBStore\LevelDBStore.csproj", "{C66214CD-0B97-4EA5-B7A2-164F54346F19}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RocksDBStore", "src\RocksDBStore\RocksDBStore.csproj", "{0E2AAF05-C55A-4B36-8750-F55743FBE4B3}" @@ -44,10 +42,6 @@ Global {BBE8AC15-12DF-4AF0-ABC1-F1557EB5DC8E}.Debug|Any CPU.Build.0 = Debug|Any CPU {BBE8AC15-12DF-4AF0-ABC1-F1557EB5DC8E}.Release|Any CPU.ActiveCfg = Release|Any CPU {BBE8AC15-12DF-4AF0-ABC1-F1557EB5DC8E}.Release|Any CPU.Build.0 = Release|Any CPU - {14DB62D5-0EA1-4A98-8656-1AA2D0345206}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {14DB62D5-0EA1-4A98-8656-1AA2D0345206}.Debug|Any CPU.Build.0 = Debug|Any CPU - {14DB62D5-0EA1-4A98-8656-1AA2D0345206}.Release|Any CPU.ActiveCfg = Release|Any CPU - {14DB62D5-0EA1-4A98-8656-1AA2D0345206}.Release|Any CPU.Build.0 = Release|Any CPU {C66214CD-0B97-4EA5-B7A2-164F54346F19}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C66214CD-0B97-4EA5-B7A2-164F54346F19}.Debug|Any CPU.Build.0 = Debug|Any CPU {C66214CD-0B97-4EA5-B7A2-164F54346F19}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -80,7 +74,6 @@ Global {84DA8EA6-EF60-4FCD-B1C6-65C1A8323B3F} = {97E81C78-1637-481F-9485-DA1225E94C23} {86531DB1-A231-46C4-823F-BE60972F7523} = {97E81C78-1637-481F-9485-DA1225E94C23} {BBE8AC15-12DF-4AF0-ABC1-F1557EB5DC8E} = {97E81C78-1637-481F-9485-DA1225E94C23} - {14DB62D5-0EA1-4A98-8656-1AA2D0345206} = {97E81C78-1637-481F-9485-DA1225E94C23} {C66214CD-0B97-4EA5-B7A2-164F54346F19} = {97E81C78-1637-481F-9485-DA1225E94C23} {0E2AAF05-C55A-4B36-8750-F55743FBE4B3} = {97E81C78-1637-481F-9485-DA1225E94C23} {8DC57A45-A192-4953-81B1-6907FB7C28D2} = {97E81C78-1637-481F-9485-DA1225E94C23} From d55d88c5b6eb3f44026237d73ea001c535def334 Mon Sep 17 00:00:00 2001 From: Luchuan Date: Mon, 29 Jun 2020 16:11:59 +0800 Subject: [PATCH 130/183] Neo.VM.3.0.0-CI00958 (#274) * fix * fix event * CI00958 Co-authored-by: Luchuan Co-authored-by: Erik Zhang --- src/LevelDBStore/LevelDBStore.csproj | 2 +- src/RocksDBStore/RocksDBStore.csproj | 2 +- src/RpcClient/Nep5API.cs | 10 +++++----- src/RpcClient/PolicyAPI.cs | 6 +++--- src/RpcClient/RpcClient.csproj | 2 +- src/RpcClient/WalletAPI.cs | 2 +- src/RpcNep5Tracker/RpcNep5Tracker.cs | 4 ++-- src/RpcServer/RpcServer.csproj | 2 +- src/StatesDumper/StatesDumper.csproj | 2 +- tests/Neo.Network.RPC.Tests/RpcTestCases.json | 4 +--- tests/Neo.Network.RPC.Tests/UT_ContractClient.cs | 2 +- 11 files changed, 18 insertions(+), 20 deletions(-) diff --git a/src/LevelDBStore/LevelDBStore.csproj b/src/LevelDBStore/LevelDBStore.csproj index 835d492c5..e88f68d18 100644 --- a/src/LevelDBStore/LevelDBStore.csproj +++ b/src/LevelDBStore/LevelDBStore.csproj @@ -15,7 +15,7 @@ - + diff --git a/src/RocksDBStore/RocksDBStore.csproj b/src/RocksDBStore/RocksDBStore.csproj index 01d858435..7992330f8 100644 --- a/src/RocksDBStore/RocksDBStore.csproj +++ b/src/RocksDBStore/RocksDBStore.csproj @@ -14,7 +14,7 @@ - + diff --git a/src/RpcClient/Nep5API.cs b/src/RpcClient/Nep5API.cs index e111e4f99..da8bc59e0 100644 --- a/src/RpcClient/Nep5API.cs +++ b/src/RpcClient/Nep5API.cs @@ -30,7 +30,7 @@ public Nep5API(RpcClient rpcClient) : base(rpcClient) { } /// public BigInteger BalanceOf(UInt160 scriptHash, UInt160 account) { - BigInteger balance = TestInvoke(scriptHash, "balanceOf", account).Stack.Single().ToStackItem().GetBigInteger(); + BigInteger balance = TestInvoke(scriptHash, "balanceOf", account).Stack.Single().ToStackItem().GetInteger(); return balance; } @@ -61,7 +61,7 @@ public string Symbol(UInt160 scriptHash) /// public byte Decimals(UInt160 scriptHash) { - return (byte)TestInvoke(scriptHash, "decimals").Stack.Single().ToStackItem().GetBigInteger(); + return (byte)TestInvoke(scriptHash, "decimals").Stack.Single().ToStackItem().GetInteger(); } /// @@ -71,7 +71,7 @@ public byte Decimals(UInt160 scriptHash) /// public BigInteger TotalSupply(UInt160 scriptHash) { - return TestInvoke(scriptHash, "totalSupply").Stack.Single().ToStackItem().GetBigInteger(); + return TestInvoke(scriptHash, "totalSupply").Stack.Single().ToStackItem().GetInteger(); } /// @@ -92,8 +92,8 @@ public RpcNep5TokenInfo GetTokenInfo(UInt160 scriptHash) { Name = result[0].ToStackItem().GetString(), Symbol = result[1].ToStackItem().GetString(), - Decimals = (byte)result[2].ToStackItem().GetBigInteger(), - TotalSupply = result[3].ToStackItem().GetBigInteger() + Decimals = (byte)result[2].ToStackItem().GetInteger(), + TotalSupply = result[3].ToStackItem().GetInteger() }; } diff --git a/src/RpcClient/PolicyAPI.cs b/src/RpcClient/PolicyAPI.cs index 1b401cd7e..de078a8e3 100644 --- a/src/RpcClient/PolicyAPI.cs +++ b/src/RpcClient/PolicyAPI.cs @@ -23,7 +23,7 @@ public PolicyAPI(RpcClient rpcClient) : base(rpcClient) { } /// public uint GetMaxTransactionsPerBlock() { - return (uint)TestInvoke(scriptHash, "getMaxTransactionsPerBlock").Stack.Single().ToStackItem().GetBigInteger(); + return (uint)TestInvoke(scriptHash, "getMaxTransactionsPerBlock").Stack.Single().ToStackItem().GetInteger(); } /// @@ -32,7 +32,7 @@ public uint GetMaxTransactionsPerBlock() /// public uint GetMaxBlockSize() { - return (uint)TestInvoke(scriptHash, "getMaxBlockSize").Stack.Single().ToStackItem().GetBigInteger(); + return (uint)TestInvoke(scriptHash, "getMaxBlockSize").Stack.Single().ToStackItem().GetInteger(); } /// @@ -41,7 +41,7 @@ public uint GetMaxBlockSize() /// public long GetFeePerByte() { - return (long)TestInvoke(scriptHash, "getFeePerByte").Stack.Single().ToStackItem().GetBigInteger(); + return (long)TestInvoke(scriptHash, "getFeePerByte").Stack.Single().ToStackItem().GetInteger(); } /// diff --git a/src/RpcClient/RpcClient.csproj b/src/RpcClient/RpcClient.csproj index 547e761ad..532622216 100644 --- a/src/RpcClient/RpcClient.csproj +++ b/src/RpcClient/RpcClient.csproj @@ -14,7 +14,7 @@ - + diff --git a/src/RpcClient/WalletAPI.cs b/src/RpcClient/WalletAPI.cs index c00b6d188..3d9edaa83 100644 --- a/src/RpcClient/WalletAPI.cs +++ b/src/RpcClient/WalletAPI.cs @@ -52,7 +52,7 @@ public decimal GetUnclaimedGas(UInt160 account) { UInt160 scriptHash = NativeContract.NEO.Hash; BigInteger balance = nep5API.TestInvoke(scriptHash, "unclaimedGas", account, rpcClient.GetBlockCount() - 1) - .Stack.Single().ToStackItem().GetBigInteger(); + .Stack.Single().ToStackItem().GetInteger(); return ((decimal)balance) / (long)NativeContract.GAS.Factor; } diff --git a/src/RpcNep5Tracker/RpcNep5Tracker.cs b/src/RpcNep5Tracker/RpcNep5Tracker.cs index 2b3a6e1af..8499a02f2 100644 --- a/src/RpcNep5Tracker/RpcNep5Tracker.cs +++ b/src/RpcNep5Tracker/RpcNep5Tracker.cs @@ -143,7 +143,7 @@ private void HandleNotification(StoreView snapshot, IVerifiable scriptContainer, } if (scriptContainer is Transaction transaction) { - RecordTransferHistory(snapshot, scriptHash, from, to, amountItem.GetBigInteger(), transaction.Hash, ref transferIndex); + RecordTransferHistory(snapshot, scriptHash, from, to, amountItem.GetInteger(), transaction.Hash, ref transferIndex); } } @@ -182,7 +182,7 @@ public void OnPersist(StoreView snapshot, IReadOnlyList - + diff --git a/src/StatesDumper/StatesDumper.csproj b/src/StatesDumper/StatesDumper.csproj index c49646329..7429ea9f9 100644 --- a/src/StatesDumper/StatesDumper.csproj +++ b/src/StatesDumper/StatesDumper.csproj @@ -14,7 +14,7 @@ - + diff --git a/tests/Neo.Network.RPC.Tests/RpcTestCases.json b/tests/Neo.Network.RPC.Tests/RpcTestCases.json index 86bf50c7d..4bf9c9e2c 100644 --- a/tests/Neo.Network.RPC.Tests/RpcTestCases.json +++ b/tests/Neo.Network.RPC.Tests/RpcTestCases.json @@ -425,9 +425,7 @@ "name": "arg3", "type": "Integer" } - ], - "offset": 0, - "returnType": "Signature" + ] } ] }, diff --git a/tests/Neo.Network.RPC.Tests/UT_ContractClient.cs b/tests/Neo.Network.RPC.Tests/UT_ContractClient.cs index fafca52c4..6fa4feb7e 100644 --- a/tests/Neo.Network.RPC.Tests/UT_ContractClient.cs +++ b/tests/Neo.Network.RPC.Tests/UT_ContractClient.cs @@ -32,7 +32,7 @@ public void TestInvoke() ContractClient contractClient = new ContractClient(rpcClientMock.Object); var result = contractClient.TestInvoke(NativeContract.GAS.Hash, "balanceOf", UInt160.Zero); - Assert.AreEqual(30000000000000L, (long)result.Stack[0].ToStackItem().GetBigInteger()); + Assert.AreEqual(30000000000000L, (long)result.Stack[0].ToStackItem().GetInteger()); } [TestMethod] From 27aff25279f25830beef57a7bed4805c0c4f4d49 Mon Sep 17 00:00:00 2001 From: joeqian Date: Fri, 3 Jul 2020 15:20:44 +0800 Subject: [PATCH 131/183] Add EventName to NotifyEventArgs (#267) * Add EventName to NotifyEventArgs * Update UT cases * Change to all lower case * Fix UTs * Fix format * Fix format again --- src/ApplicationLogs/LogReader.cs | 3 ++- src/RpcClient/Models/RpcApplicationLog.cs | 8 +++++-- src/RpcNep5Tracker/RpcNep5Tracker.cs | 22 +++++++++---------- tests/Neo.Network.RPC.Tests/RpcTestCases.json | 12 +++------- 4 files changed, 21 insertions(+), 24 deletions(-) diff --git a/src/ApplicationLogs/LogReader.cs b/src/ApplicationLogs/LogReader.cs index e66839890..9f26ec9a0 100644 --- a/src/ApplicationLogs/LogReader.cs +++ b/src/ApplicationLogs/LogReader.cs @@ -51,7 +51,7 @@ public void OnPersist(StoreView snapshot, IReadOnlyList q.ToJson()).ToArray(); @@ -64,6 +64,7 @@ public void OnPersist(StoreView snapshot, IReadOnlyList q.ToJson()).ToArray(); json["notifications"] = Notifications.Select(q => q.ToJson()).ToArray(); return json; @@ -38,7 +38,7 @@ public static RpcApplicationLog FromJson(JObject json) log.TxId = json["txid"] is null ? null : UInt256.Parse(json["txid"].AsString()); log.Trigger = json["trigger"].TryGetEnum(); log.VMState = json["vmstate"].TryGetEnum(); - log.GasConsumed = long.Parse(json["gas_consumed"].AsString()); + log.GasConsumed = long.Parse(json["gasconsumed"].AsString()); log.Stack = ((JArray)json["stack"]).Select(p => ContractParameter.FromJson(p)).ToList(); log.Notifications = ((JArray)json["notifications"]).Select(p => RpcNotifyEventArgs.FromJson(p)).ToList(); return log; @@ -49,12 +49,15 @@ public class RpcNotifyEventArgs { public UInt160 Contract { get; set; } + public string EventName { get; set; } + public ContractParameter State { get; set; } public JObject ToJson() { JObject json = new JObject(); json["contract"] = Contract.ToString(); + json["eventname"] = EventName; json["state"] = State.ToJson(); return json; } @@ -64,6 +67,7 @@ public static RpcNotifyEventArgs FromJson(JObject json) return new RpcNotifyEventArgs { Contract = UInt160.Parse(json["contract"].AsString()), + EventName = json["eventname"].AsString(), State = ContractParameter.FromJson(json["state"]) }; } diff --git a/src/RpcNep5Tracker/RpcNep5Tracker.cs b/src/RpcNep5Tracker/RpcNep5Tracker.cs index 8499a02f2..c2c58c123 100644 --- a/src/RpcNep5Tracker/RpcNep5Tracker.cs +++ b/src/RpcNep5Tracker/RpcNep5Tracker.cs @@ -100,31 +100,29 @@ private void RecordTransferHistory(StoreView snapshot, UInt160 scriptHash, UInt1 transferIndex++; } - private void HandleNotification(StoreView snapshot, IVerifiable scriptContainer, UInt160 scriptHash, + private void HandleNotification(StoreView snapshot, IVerifiable scriptContainer, UInt160 scriptHash, string eventName, VM.Types.Array stateItems, Dictionary nep5BalancesChanged, ref ushort transferIndex) { if (stateItems.Count == 0) return; - // Event name should be encoded as a byte array. - if (!(stateItems[0] is VM.Types.ByteString)) return; - var eventName = stateItems[0].GetString(); if (eventName != "Transfer") return; - if (stateItems.Count < 4) return; + if (stateItems.Count < 3) return; - if (!(stateItems[1].IsNull) && !(stateItems[1] is VM.Types.ByteString)) + if (!(stateItems[0].IsNull) && !(stateItems[0] is VM.Types.ByteString)) return; - if (!(stateItems[2].IsNull) && !(stateItems[2] is VM.Types.ByteString)) + if (!(stateItems[1].IsNull) && !(stateItems[1] is VM.Types.ByteString)) return; - var amountItem = stateItems[3]; + var amountItem = stateItems[2]; if (!(amountItem is VM.Types.ByteString || amountItem is VM.Types.Integer)) return; - byte[] fromBytes = stateItems[1].IsNull ? null : stateItems[1].GetSpan().ToArray(); + byte[] fromBytes = stateItems[0].IsNull ? null : stateItems[0].GetSpan().ToArray(); if (fromBytes != null && fromBytes.Length != UInt160.Length) return; - byte[] toBytes = stateItems[2].IsNull ? null : stateItems[2].GetSpan().ToArray(); + byte[] toBytes = stateItems[1].IsNull ? null : stateItems[1].GetSpan().ToArray(); if (toBytes != null && toBytes.Length != UInt160.Length) return; if (fromBytes == null && toBytes == null) return; + var from = UInt160.Zero; var to = UInt160.Zero; @@ -162,8 +160,8 @@ public void OnPersist(StoreView snapshot, IReadOnlyList + diff --git a/src/LevelDBStore/Plugins/Storage/Snapshot.cs b/src/LevelDBStore/Plugins/Storage/Snapshot.cs index aaba9951c..b547f1108 100644 --- a/src/LevelDBStore/Plugins/Storage/Snapshot.cs +++ b/src/LevelDBStore/Plugins/Storage/Snapshot.cs @@ -1,3 +1,4 @@ +using Neo.IO.Caching; using Neo.IO.Data.LevelDB; using Neo.Persistence; using System.Collections.Generic; @@ -35,9 +36,9 @@ public void Dispose() snapshot.Dispose(); } - public IEnumerable<(byte[] Key, byte[] Value)> Find(byte table, byte[] prefix) + public IEnumerable<(byte[] Key, byte[] Value)> Seek(byte table, byte[] prefix, SeekDirection direction) { - return db.Find(options, Helper.CreateKey(table, prefix), (k, v) => (k[1..], v)); + return db.Seek(options, Helper.CreateKey(table, prefix), direction, (k, v) => (k[1..], v)); } public void Put(byte table, byte[] key, byte[] value) diff --git a/src/LevelDBStore/Plugins/Storage/Store.cs b/src/LevelDBStore/Plugins/Storage/Store.cs index fef486d27..48cb10018 100644 --- a/src/LevelDBStore/Plugins/Storage/Store.cs +++ b/src/LevelDBStore/Plugins/Storage/Store.cs @@ -1,3 +1,4 @@ +using Neo.IO.Caching; using Neo.IO.Data.LevelDB; using Neo.Persistence; using System; @@ -49,9 +50,9 @@ public void Dispose() db.Dispose(); } - public IEnumerable<(byte[], byte[])> Find(byte table, byte[] prefix) + public IEnumerable<(byte[], byte[])> Seek(byte table, byte[] prefix, SeekDirection direction) { - return db.Find(ReadOptions.Default, Helper.CreateKey(table, prefix), (k, v) => (k[1..], v)); + return db.Seek(ReadOptions.Default, Helper.CreateKey(table, prefix), direction, (k, v) => (k[1..], v)); } public ISnapshot GetSnapshot() diff --git a/src/RocksDBStore/Plugins/Storage/Snapshot.cs b/src/RocksDBStore/Plugins/Storage/Snapshot.cs index 163a8e661..c61bf460e 100644 --- a/src/RocksDBStore/Plugins/Storage/Snapshot.cs +++ b/src/RocksDBStore/Plugins/Storage/Snapshot.cs @@ -1,3 +1,4 @@ +using Neo.IO.Caching; using Neo.Persistence; using RocksDbSharp; using System; @@ -40,16 +41,17 @@ public void Put(byte table, byte[] key, byte[] value) batch.Put(key, value, store.GetFamily(table)); } - public IEnumerable<(byte[] Key, byte[] Value)> Find(byte table, byte[] prefix) + public IEnumerable<(byte[] Key, byte[] Value)> Seek(byte table, byte[] keyOrPrefix, SeekDirection direction) { using var it = db.NewIterator(store.GetFamily(table), options); - for (it.Seek(prefix); it.Valid(); it.Next()) + for (it.Seek(keyOrPrefix); it.Valid();) { - var key = it.Key(); - byte[] y = prefix; - if (key.Length < y.Length) break; - if (!key.AsSpan().StartsWith(y)) break; - yield return (key, it.Value()); + yield return (it.Key(), it.Value()); + + if (direction == SeekDirection.Forward) + it.Next(); + else + it.Prev(); } } diff --git a/src/RocksDBStore/Plugins/Storage/Store.cs b/src/RocksDBStore/Plugins/Storage/Store.cs index 97d0e2f2c..f0959a596 100644 --- a/src/RocksDBStore/Plugins/Storage/Store.cs +++ b/src/RocksDBStore/Plugins/Storage/Store.cs @@ -1,3 +1,4 @@ +using Neo.IO.Caching; using Neo.Persistence; using RocksDbSharp; using System; @@ -81,7 +82,7 @@ public ISnapshot GetSnapshot() return new Snapshot(this, db); } - public IEnumerable<(byte[] Key, byte[] Value)> Find(byte table, byte[] prefix) + public IEnumerable<(byte[] Key, byte[] Value)> Seek(byte table, byte[] prefix, SeekDirection direction) { using var it = db.NewIterator(GetFamily(table), Options.ReadDefault); for (it.Seek(prefix); it.Valid(); it.Next()) diff --git a/src/RocksDBStore/RocksDBStore.csproj b/src/RocksDBStore/RocksDBStore.csproj index 7992330f8..71964ff97 100644 --- a/src/RocksDBStore/RocksDBStore.csproj +++ b/src/RocksDBStore/RocksDBStore.csproj @@ -14,7 +14,7 @@ - + diff --git a/src/RpcNep5Tracker/DbCache.cs b/src/RpcNep5Tracker/DbCache.cs index 681b6404a..bd2ff3cba 100644 --- a/src/RpcNep5Tracker/DbCache.cs +++ b/src/RpcNep5Tracker/DbCache.cs @@ -47,9 +47,9 @@ protected override void DeleteInternal(TKey key) batch?.Delete(CreateKey(prefix, key)); } - protected override IEnumerable<(TKey, TValue)> FindInternal(byte[] key_prefix) + protected override IEnumerable<(TKey, TValue)> SeekInternal(byte[] key_prefix, SeekDirection direction) { - return db.Find(options, CreateKey(prefix, key_prefix), (k, v) => (k.AsSerializable(1), v.AsSerializable())); + return db.Seek(options, CreateKey(prefix, key_prefix), direction, (k, v) => (k.AsSerializable(1), v.AsSerializable())); } protected override TValue GetInternal(TKey key) From 50e245b8b49df852f36e34ede58fad0dabae5c5b Mon Sep 17 00:00:00 2001 From: joeqian Date: Tue, 7 Jul 2020 15:39:16 +0800 Subject: [PATCH 133/183] Add a generic GetUnclaimedGas() in RpcClient (#273) * Add GetUnclaimedGas() in RpcClient and UT * Fix format * Update tests/Neo.Network.RPC.Tests/RpcTestCases.json Co-authored-by: Luchuan Co-authored-by: Shargon --- src/RpcClient/Models/RpcUnclaimedGas.cs | 28 ++++++++++ src/RpcClient/RpcClient.cs | 31 ++++++----- src/RpcServer/RpcServer.Wallet.cs | 20 +++---- tests/Neo.Network.RPC.Tests/RpcTestCases.json | 54 ++++++++++++------- tests/Neo.Network.RPC.Tests/UT_RpcClient.cs | 30 +++++++---- 5 files changed, 110 insertions(+), 53 deletions(-) create mode 100644 src/RpcClient/Models/RpcUnclaimedGas.cs diff --git a/src/RpcClient/Models/RpcUnclaimedGas.cs b/src/RpcClient/Models/RpcUnclaimedGas.cs new file mode 100644 index 000000000..0702e7f97 --- /dev/null +++ b/src/RpcClient/Models/RpcUnclaimedGas.cs @@ -0,0 +1,28 @@ +using Neo.IO.Json; +using System.Numerics; + +namespace Neo.Network.RPC.Models +{ + public class RpcUnclaimedGas + { + public BigInteger Unclaimed { get; set; } + + public string Address { get; set; } + + public JObject ToJson() + { + JObject json = new JObject(); + json["unclaimed"] = Unclaimed.ToString(); + json["address"] = Address; + return json; + } + + public static RpcUnclaimedGas FromJson(JObject json) + { + RpcUnclaimedGas gas = new RpcUnclaimedGas(); + gas.Unclaimed = BigInteger.Parse(json["unclaimed"].AsString()); + gas.Address = json["address"].AsString(); + return gas; + } + } +} diff --git a/src/RpcClient/RpcClient.cs b/src/RpcClient/RpcClient.cs index ea1eebeaf..35f7500f4 100644 --- a/src/RpcClient/RpcClient.cs +++ b/src/RpcClient/RpcClient.cs @@ -340,6 +340,11 @@ public RpcInvokeResult InvokeScript(byte[] script, params UInt160[] scriptHashes return RpcInvokeResult.FromJson(RpcSend("invokescript", parameters.ToArray())); } + public RpcUnclaimedGas GetUnclaimedGas(string address) + { + return RpcUnclaimedGas.FromJson(RpcSend("getunclaimedgas", address)); + } + #endregion SmartContract #region Utilities @@ -381,31 +386,31 @@ public string DumpPrivKey(string address) } /// - /// Returns the balance of the corresponding asset in the wallet, based on the specified asset Id. - /// This method applies to assets that conform to NEP-5 standards. + /// Creates a new account in the wallet opened by RPC. /// - /// new address as string - public BigDecimal GetBalance(string assetId) + public string GetNewAddress() { - byte decimals = new Nep5API(this).Decimals(UInt160.Parse(assetId)); - BigInteger balance = BigInteger.Parse(RpcSend("getbalance", assetId)["balance"].AsString()); - return new BigDecimal(balance, decimals); + return RpcSend("getnewaddress").AsString(); } /// - /// Creates a new account in the wallet opened by RPC. + /// Returns the balance of the corresponding asset in the wallet, based on the specified asset Id. + /// This method applies to assets that conform to NEP-5 standards. /// - public string GetNewAddress() + /// new address as string + public BigDecimal GetWalletBalance(string assetId) { - return RpcSend("getnewaddress").AsString(); + byte decimals = new Nep5API(this).Decimals(UInt160.Parse(assetId)); + BigInteger balance = BigInteger.Parse(RpcSend("getwalletbalance", assetId)["balance"].AsString()); + return new BigDecimal(balance, decimals); } /// /// Gets the amount of unclaimed GAS in the wallet. /// - public BigInteger GetUnclaimedGas() + public BigInteger GetWalletUnclaimedGas() { - return BigInteger.Parse(RpcSend("getunclaimedgas").AsString()); + return BigInteger.Parse(RpcSend("getwalletunclaimedgas").AsString()); } /// @@ -467,7 +472,7 @@ public JObject SendToAddress(string assetId, string address, string amount) return RpcSend("sendtoaddress", assetId, address, amount); } - #endregion Utilities + #endregion Wallet #region Plugins diff --git a/src/RpcServer/RpcServer.Wallet.cs b/src/RpcServer/RpcServer.Wallet.cs index b0b0f4f74..f58c1472e 100644 --- a/src/RpcServer/RpcServer.Wallet.cs +++ b/src/RpcServer/RpcServer.Wallet.cs @@ -47,16 +47,6 @@ private JObject DumpPrivKey(JArray _params) return account.GetKey().Export(); } - [RpcMethod] - private JObject GetWalletBalance(JArray _params) - { - CheckWallet(); - UInt160 asset_id = UInt160.Parse(_params[0].AsString()); - JObject json = new JObject(); - json["balance"] = wallet.GetAvailable(asset_id).Value.ToString(); - return json; - } - [RpcMethod] private JObject GetNewAddress(JArray _params) { @@ -67,6 +57,16 @@ private JObject GetNewAddress(JArray _params) return account.Address; } + [RpcMethod] + private JObject GetWalletBalance(JArray _params) + { + CheckWallet(); + UInt160 asset_id = UInt160.Parse(_params[0].AsString()); + JObject json = new JObject(); + json["balance"] = wallet.GetAvailable(asset_id).Value.ToString(); + return json; + } + [RpcMethod] private JObject GetWalletUnclaimedGas(JArray _params) { diff --git a/tests/Neo.Network.RPC.Tests/RpcTestCases.json b/tests/Neo.Network.RPC.Tests/RpcTestCases.json index 48f1bd0d1..bd934923d 100644 --- a/tests/Neo.Network.RPC.Tests/RpcTestCases.json +++ b/tests/Neo.Network.RPC.Tests/RpcTestCases.json @@ -758,6 +758,23 @@ } }, + { + "Name": "getunclaimedgas", + "Request": { + "jsonrpc": "2.0", + "method": "getunclaimedgas", + "params": [ "NPvKVTGZapmFWABLsyvfreuqn73jCjJtN1" ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": { + "unclaimed": "735870007400", + "address": "NPvKVTGZapmFWABLsyvfreuqn73jCjJtN1" + } + } + }, { "Name": "listplugins", @@ -847,23 +864,6 @@ "result": "KyoYyZpoccbR6KZ25eLzhMTUxREwCpJzDsnuodGTKXSG8fDW9t7x" } }, - { - "Name": "getbalance", - "Request": { - "jsonrpc": "2.0", - "method": "getbalance", - "params": [ "0x8c23f196d8a1bfd103a9dcb1f9ccf0c611377d3b" ], - "id": 1 - }, - "Response": { - "jsonrpc": "2.0", - "id": 1, - "result": { - "balance": "3001101329992600" - } - } - }, - // mock decimals { "Name": "invokescript", "Request": { @@ -904,10 +904,26 @@ } }, { - "Name": "getunclaimedgas", + "Name": "getwalletbalance", "Request": { "jsonrpc": "2.0", - "method": "getunclaimedgas", + "method": "getwalletbalance", + "params": [ "0x8c23f196d8a1bfd103a9dcb1f9ccf0c611377d3b" ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": { + "balance": "3001101329992600" + } + } + }, + { + "Name": "getwalletunclaimedgas", + "Request": { + "jsonrpc": "2.0", + "method": "getwalletunclaimedgas", "params": [], "id": 1 }, diff --git a/tests/Neo.Network.RPC.Tests/UT_RpcClient.cs b/tests/Neo.Network.RPC.Tests/UT_RpcClient.cs index d4f9cca5e..302040e47 100644 --- a/tests/Neo.Network.RPC.Tests/UT_RpcClient.cs +++ b/tests/Neo.Network.RPC.Tests/UT_RpcClient.cs @@ -291,6 +291,14 @@ public void TestInvokeScript() Assert.AreEqual(test.Response.Result.ToString(), result.ToJson().ToString()); } + [TestMethod] + public void TestGetUnclaimedGas() + { + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetUnclaimedGas).ToLower()); + var result = rpc.GetUnclaimedGas(test.Request.Params[0].AsString()); + Assert.AreEqual(test.Response.Result["unclaimed"].AsString(), result.Unclaimed.ToString()); + } + #endregion SmartContract #region Utilities @@ -331,14 +339,6 @@ public void TestDumpPrivKey() Assert.AreEqual(test.Response.Result.AsString(), result); } - [TestMethod] - public void TestGetBalance() - { - var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetBalance).ToLower()); - var result = rpc.GetBalance(test.Request.Params[0].AsString()); - Assert.AreEqual(test.Response.Result["balance"].AsString(), result.Value.ToString()); - } - [TestMethod] public void TestGetNewAddress() { @@ -348,10 +348,18 @@ public void TestGetNewAddress() } [TestMethod] - public void TestGetUnclaimedGas() + public void TestGetWalletBalance() { - var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetUnclaimedGas).ToLower()); - var result = rpc.GetUnclaimedGas(); + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetWalletBalance).ToLower()); + var result = rpc.GetWalletBalance(test.Request.Params[0].AsString()); + Assert.AreEqual(test.Response.Result["balance"].AsString(), result.Value.ToString()); + } + + [TestMethod] + public void TestGetWalletUnclaimedGas() + { + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetWalletUnclaimedGas).ToLower()); + var result = rpc.GetWalletUnclaimedGas(); Assert.AreEqual(test.Response.Result.AsString(), result.ToString()); } From 1cf385dc6de647d9b44cf9016e5dea189943ed1f Mon Sep 17 00:00:00 2001 From: Luchuan Date: Tue, 7 Jul 2020 22:48:00 +0800 Subject: [PATCH 134/183] Fix seek (#281) * fix seek * move Helper method * Update Helper.cs Co-authored-by: Luchuan --- src/LevelDBStore/IO/Data/LevelDB/Helper.cs | 15 +++++++++++++-- src/LevelDBStore/Plugins/Storage/Helper.cs | 16 ---------------- src/LevelDBStore/Plugins/Storage/Snapshot.cs | 9 +++++---- src/LevelDBStore/Plugins/Storage/Store.cs | 15 ++++++++------- src/RocksDBStore/Plugins/Storage/Snapshot.cs | 1 - src/RocksDBStore/Plugins/Storage/Store.cs | 15 ++++++++------- src/RpcNep5Tracker/DbCache.cs | 2 +- 7 files changed, 35 insertions(+), 38 deletions(-) delete mode 100644 src/LevelDBStore/Plugins/Storage/Helper.cs diff --git a/src/LevelDBStore/IO/Data/LevelDB/Helper.cs b/src/LevelDBStore/IO/Data/LevelDB/Helper.cs index a2c28e769..0ed2f9543 100644 --- a/src/LevelDBStore/IO/Data/LevelDB/Helper.cs +++ b/src/LevelDBStore/IO/Data/LevelDB/Helper.cs @@ -7,11 +7,13 @@ namespace Neo.IO.Data.LevelDB { public static class Helper { - public static IEnumerable Seek(this DB db, ReadOptions options, byte[] keyOrPrefix, SeekDirection direction, Func resultSelector) + public static IEnumerable Seek(this DB db, ReadOptions options, byte table, byte[] prefix, SeekDirection direction, Func resultSelector) { using Iterator it = db.NewIterator(options); - for (it.Seek(keyOrPrefix); it.Valid();) + for (it.Seek(CreateKey(table, prefix)); it.Valid();) { + var key = it.Key(); + if (key.Length < 1 || key[0] != table) break; yield return resultSelector(it.Key(), it.Value()); if (direction == SeekDirection.Forward) @@ -39,5 +41,14 @@ internal static byte[] ToByteArray(this IntPtr data, UIntPtr length) Marshal.Copy(data, buffer, 0, (int)length); return buffer; } + + public static byte[] CreateKey(byte table, byte[] key = null) + { + if (key is null || key.Length == 0) return new[] { table }; + byte[] buffer = new byte[1 + key.Length]; + buffer[0] = table; + Buffer.BlockCopy(key, 0, buffer, 1, key.Length); + return buffer; + } } } diff --git a/src/LevelDBStore/Plugins/Storage/Helper.cs b/src/LevelDBStore/Plugins/Storage/Helper.cs deleted file mode 100644 index ff54faebe..000000000 --- a/src/LevelDBStore/Plugins/Storage/Helper.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; - -namespace Neo.Plugins.Storage -{ - internal static class Helper - { - public static byte[] CreateKey(byte table, byte[] key = null) - { - if (key is null) return new[] { table }; - byte[] buffer = new byte[1 + key.Length]; - buffer[0] = table; - Buffer.BlockCopy(key, 0, buffer, 1, key.Length); - return buffer; - } - } -} diff --git a/src/LevelDBStore/Plugins/Storage/Snapshot.cs b/src/LevelDBStore/Plugins/Storage/Snapshot.cs index b547f1108..aec33b8d1 100644 --- a/src/LevelDBStore/Plugins/Storage/Snapshot.cs +++ b/src/LevelDBStore/Plugins/Storage/Snapshot.cs @@ -3,6 +3,7 @@ using Neo.Persistence; using System.Collections.Generic; using LSnapshot = Neo.IO.Data.LevelDB.Snapshot; +using LHelper = Neo.IO.Data.LevelDB.Helper; namespace Neo.Plugins.Storage { @@ -28,7 +29,7 @@ public void Commit() public void Delete(byte table, byte[] key) { - batch.Delete(Helper.CreateKey(table, key)); + batch.Delete(LHelper.CreateKey(table, key)); } public void Dispose() @@ -38,17 +39,17 @@ public void Dispose() public IEnumerable<(byte[] Key, byte[] Value)> Seek(byte table, byte[] prefix, SeekDirection direction) { - return db.Seek(options, Helper.CreateKey(table, prefix), direction, (k, v) => (k[1..], v)); + return db.Seek(options, table, prefix, direction, (k, v) => (k[1..], v)); } public void Put(byte table, byte[] key, byte[] value) { - batch.Put(Helper.CreateKey(table, key), value); + batch.Put(LHelper.CreateKey(table, key), value); } public byte[] TryGet(byte table, byte[] key) { - return db.Get(options, Helper.CreateKey(table, key)); + return db.Get(options, LHelper.CreateKey(table, key)); } } } diff --git a/src/LevelDBStore/Plugins/Storage/Store.cs b/src/LevelDBStore/Plugins/Storage/Store.cs index 48cb10018..2d59258c7 100644 --- a/src/LevelDBStore/Plugins/Storage/Store.cs +++ b/src/LevelDBStore/Plugins/Storage/Store.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Reflection; using System.Text; +using LHelper = Neo.IO.Data.LevelDB.Helper; namespace Neo.Plugins.Storage { @@ -16,7 +17,7 @@ internal class Store : IStore public Store(string path) { this.db = DB.Open(path, new Options { CreateIfMissing = true }); - byte[] value = db.Get(ReadOptions.Default, Helper.CreateKey(SYS_Version)); + byte[] value = db.Get(ReadOptions.Default, LHelper.CreateKey(SYS_Version)); if (value != null && Version.TryParse(Encoding.ASCII.GetString(value), out Version version) && version >= Version.Parse("3.0.0")) return; @@ -36,13 +37,13 @@ public Store(string path) } } - db.Put(WriteOptions.Default, Helper.CreateKey(SYS_Version), Encoding.ASCII.GetBytes(Assembly.GetExecutingAssembly().GetName().Version.ToString())); + db.Put(WriteOptions.Default, LHelper.CreateKey(SYS_Version), Encoding.ASCII.GetBytes(Assembly.GetExecutingAssembly().GetName().Version.ToString())); db.Write(WriteOptions.Default, batch); } public void Delete(byte table, byte[] key) { - db.Delete(WriteOptions.Default, Helper.CreateKey(table, key)); + db.Delete(WriteOptions.Default, LHelper.CreateKey(table, key)); } public void Dispose() @@ -52,7 +53,7 @@ public void Dispose() public IEnumerable<(byte[], byte[])> Seek(byte table, byte[] prefix, SeekDirection direction) { - return db.Seek(ReadOptions.Default, Helper.CreateKey(table, prefix), direction, (k, v) => (k[1..], v)); + return db.Seek(ReadOptions.Default, table, prefix, direction, (k, v) => (k[1..], v)); } public ISnapshot GetSnapshot() @@ -62,17 +63,17 @@ public ISnapshot GetSnapshot() public void Put(byte table, byte[] key, byte[] value) { - db.Put(WriteOptions.Default, Helper.CreateKey(table, key), value); + db.Put(WriteOptions.Default, LHelper.CreateKey(table, key), value); } public void PutSync(byte table, byte[] key, byte[] value) { - db.Put(WriteOptions.SyncWrite, Helper.CreateKey(table, key), value); + db.Put(WriteOptions.SyncWrite, LHelper.CreateKey(table, key), value); } public byte[] TryGet(byte table, byte[] key) { - return db.Get(ReadOptions.Default, Helper.CreateKey(table, key)); + return db.Get(ReadOptions.Default, LHelper.CreateKey(table, key)); } } } diff --git a/src/RocksDBStore/Plugins/Storage/Snapshot.cs b/src/RocksDBStore/Plugins/Storage/Snapshot.cs index c61bf460e..fba384598 100644 --- a/src/RocksDBStore/Plugins/Storage/Snapshot.cs +++ b/src/RocksDBStore/Plugins/Storage/Snapshot.cs @@ -1,7 +1,6 @@ using Neo.IO.Caching; using Neo.Persistence; using RocksDbSharp; -using System; using System.Collections.Generic; namespace Neo.Plugins.Storage diff --git a/src/RocksDBStore/Plugins/Storage/Store.cs b/src/RocksDBStore/Plugins/Storage/Store.cs index f0959a596..3cad88249 100644 --- a/src/RocksDBStore/Plugins/Storage/Store.cs +++ b/src/RocksDBStore/Plugins/Storage/Store.cs @@ -82,16 +82,17 @@ public ISnapshot GetSnapshot() return new Snapshot(this, db); } - public IEnumerable<(byte[] Key, byte[] Value)> Seek(byte table, byte[] prefix, SeekDirection direction) + public IEnumerable<(byte[] Key, byte[] Value)> Seek(byte table, byte[] prefix, SeekDirection direction = SeekDirection.Forward) { using var it = db.NewIterator(GetFamily(table), Options.ReadDefault); - for (it.Seek(prefix); it.Valid(); it.Next()) + for (it.Seek(prefix); it.Valid();) { - var key = it.Key(); - byte[] y = prefix; - if (key.Length < y.Length) break; - if (!key.AsSpan().StartsWith(y)) break; - yield return (key, it.Value()); + yield return (it.Key(), it.Value()); + + if (direction == SeekDirection.Forward) + it.Next(); + else + it.Prev(); } } diff --git a/src/RpcNep5Tracker/DbCache.cs b/src/RpcNep5Tracker/DbCache.cs index bd2ff3cba..9cfd27e35 100644 --- a/src/RpcNep5Tracker/DbCache.cs +++ b/src/RpcNep5Tracker/DbCache.cs @@ -49,7 +49,7 @@ protected override void DeleteInternal(TKey key) protected override IEnumerable<(TKey, TValue)> SeekInternal(byte[] key_prefix, SeekDirection direction) { - return db.Seek(options, CreateKey(prefix, key_prefix), direction, (k, v) => (k.AsSerializable(1), v.AsSerializable())); + return db.Seek(options, prefix, key_prefix, direction, (k, v) => (k.AsSerializable(1), v.AsSerializable())); } protected override TValue GetInternal(TKey key) From bc6d38a882a26e9469cb3fef66fb139a6434143d Mon Sep 17 00:00:00 2001 From: joeqian Date: Wed, 8 Jul 2020 19:50:13 +0800 Subject: [PATCH 135/183] Change json fields to all lower case for consistency (#277) * Change json field names for GetVersion * Change json fields to snake case for consistency * Change json fields to all lower case * Fix UTs. * rename * Add back GetUnclaimedGas() * Remove "_" in RpcNep5Tracker.cs * Remove underscore line Co-authored-by: Shargon Co-authored-by: Luchuan --- src/LevelDBStore/Plugins/Storage/Snapshot.cs | 2 +- src/LevelDBStore/Plugins/Storage/Store.cs | 2 +- src/RpcClient/Models/RpcInvokeResult.cs | 4 +- src/RpcClient/Models/RpcNep5Balances.cs | 8 +- src/RpcClient/Models/RpcNep5Transfers.cs | 20 +-- src/RpcClient/Models/RpcTransaction.cs | 4 +- src/RpcClient/Models/RpcVersion.cs | 12 +- src/RpcClient/RpcClient.csproj | 2 +- src/RpcClient/Utility.cs | 8 +- src/RpcNep5Tracker/RpcNep5Tracker.cs | 16 +-- src/RpcServer/RpcServer.Blockchain.cs | 2 +- src/RpcServer/RpcServer.Node.cs | 6 +- src/RpcServer/RpcServer.SmartContract.cs | 9 +- src/RpcServer/RpcServer.csproj | 2 +- tests/Neo.Network.RPC.Tests/RpcTestCases.json | 114 +++++++++--------- 15 files changed, 105 insertions(+), 106 deletions(-) diff --git a/src/LevelDBStore/Plugins/Storage/Snapshot.cs b/src/LevelDBStore/Plugins/Storage/Snapshot.cs index aec33b8d1..46d70d6fb 100644 --- a/src/LevelDBStore/Plugins/Storage/Snapshot.cs +++ b/src/LevelDBStore/Plugins/Storage/Snapshot.cs @@ -37,7 +37,7 @@ public void Dispose() snapshot.Dispose(); } - public IEnumerable<(byte[] Key, byte[] Value)> Seek(byte table, byte[] prefix, SeekDirection direction) + public IEnumerable<(byte[] Key, byte[] Value)> Seek(byte table, byte[] prefix, SeekDirection direction = SeekDirection.Forward) { return db.Seek(options, table, prefix, direction, (k, v) => (k[1..], v)); } diff --git a/src/LevelDBStore/Plugins/Storage/Store.cs b/src/LevelDBStore/Plugins/Storage/Store.cs index 2d59258c7..5a6503e3d 100644 --- a/src/LevelDBStore/Plugins/Storage/Store.cs +++ b/src/LevelDBStore/Plugins/Storage/Store.cs @@ -51,7 +51,7 @@ public void Dispose() db.Dispose(); } - public IEnumerable<(byte[], byte[])> Seek(byte table, byte[] prefix, SeekDirection direction) + public IEnumerable<(byte[], byte[])> Seek(byte table, byte[] prefix, SeekDirection direction = SeekDirection.Forward) { return db.Seek(ReadOptions.Default, table, prefix, direction, (k, v) => (k[1..], v)); } diff --git a/src/RpcClient/Models/RpcInvokeResult.cs b/src/RpcClient/Models/RpcInvokeResult.cs index c58c0afe4..eeae4518c 100644 --- a/src/RpcClient/Models/RpcInvokeResult.cs +++ b/src/RpcClient/Models/RpcInvokeResult.cs @@ -22,7 +22,7 @@ public JObject ToJson() JObject json = new JObject(); json["script"] = Script; json["state"] = State; - json["gas_consumed"] = GasConsumed; + json["gasconsumed"] = GasConsumed; try { json["stack"] = new JArray(Stack.Select(p => p.ToJson())); @@ -41,7 +41,7 @@ public static RpcInvokeResult FromJson(JObject json) RpcInvokeResult invokeScriptResult = new RpcInvokeResult(); invokeScriptResult.Script = json["script"].AsString(); invokeScriptResult.State = json["state"].TryGetEnum(); - invokeScriptResult.GasConsumed = json["gas_consumed"].AsString(); + invokeScriptResult.GasConsumed = json["gasconsumed"].AsString(); try { invokeScriptResult.Stack = ((JArray)json["stack"]).Select(p => ContractParameter.FromJson(p)).ToArray(); diff --git a/src/RpcClient/Models/RpcNep5Balances.cs b/src/RpcClient/Models/RpcNep5Balances.cs index 0b8f79c17..0ebdc2840 100644 --- a/src/RpcClient/Models/RpcNep5Balances.cs +++ b/src/RpcClient/Models/RpcNep5Balances.cs @@ -42,9 +42,9 @@ public class RpcNep5Balance public JObject ToJson() { JObject json = new JObject(); - json["asset_hash"] = AssetHash.ToString(); + json["assethash"] = AssetHash.ToString(); json["amount"] = Amount.ToString(); - json["last_updated_block"] = LastUpdatedBlock; + json["lastupdatedblock"] = LastUpdatedBlock; return json; } @@ -52,9 +52,9 @@ public static RpcNep5Balance FromJson(JObject json) { RpcNep5Balance balance = new RpcNep5Balance { - AssetHash = UInt160.Parse(json["asset_hash"].AsString()), + AssetHash = UInt160.Parse(json["assethash"].AsString()), Amount = BigInteger.Parse(json["amount"].AsString()), - LastUpdatedBlock = (uint)json["last_updated_block"].AsNumber() + LastUpdatedBlock = (uint)json["lastupdatedblock"].AsNumber() }; return balance; } diff --git a/src/RpcClient/Models/RpcNep5Transfers.cs b/src/RpcClient/Models/RpcNep5Transfers.cs index f44180554..e2eb7d01e 100644 --- a/src/RpcClient/Models/RpcNep5Transfers.cs +++ b/src/RpcClient/Models/RpcNep5Transfers.cs @@ -56,12 +56,12 @@ public JObject ToJson() { JObject json = new JObject(); json["timestamp"] = TimestampMS; - json["asset_hash"] = AssetHash.ToString(); - json["transfer_address"] = UserScriptHash.ToAddress(); + json["assethash"] = AssetHash.ToString(); + json["transferaddress"] = UserScriptHash.ToAddress(); json["amount"] = Amount.ToString(); - json["block_index"] = BlockIndex; - json["transfer_notify_index"] = TransferNotifyIndex; - json["tx_hash"] = TxHash.ToString(); + json["blockindex"] = BlockIndex; + json["transfernotifyindex"] = TransferNotifyIndex; + json["txhash"] = TxHash.ToString(); return json; } @@ -69,12 +69,12 @@ public static RpcNep5Transfer FromJson(JObject json) { RpcNep5Transfer transfer = new RpcNep5Transfer(); transfer.TimestampMS = (ulong)json["timestamp"].AsNumber(); - transfer.AssetHash = UInt160.Parse(json["asset_hash"].AsString()); - transfer.UserScriptHash = json["transfer_address"].AsString().ToScriptHash(); + transfer.AssetHash = UInt160.Parse(json["assethash"].AsString()); + transfer.UserScriptHash = json["transferaddress"].AsString().ToScriptHash(); transfer.Amount = BigInteger.Parse(json["amount"].AsString()); - transfer.BlockIndex = (uint)json["block_index"].AsNumber(); - transfer.TransferNotifyIndex = (ushort)json["transfer_notify_index"].AsNumber(); - transfer.TxHash = UInt256.Parse(json["tx_hash"].AsString()); + transfer.BlockIndex = (uint)json["blockindex"].AsNumber(); + transfer.TransferNotifyIndex = (ushort)json["transfernotifyindex"].AsNumber(); + transfer.TxHash = UInt256.Parse(json["txhash"].AsString()); return transfer; } } diff --git a/src/RpcClient/Models/RpcTransaction.cs b/src/RpcClient/Models/RpcTransaction.cs index b376c2cdb..92a9f3290 100644 --- a/src/RpcClient/Models/RpcTransaction.cs +++ b/src/RpcClient/Models/RpcTransaction.cs @@ -26,7 +26,7 @@ public JObject ToJson() json["blocktime"] = BlockTime; if (VMState != null) { - json["vm_state"] = VMState; + json["vmstate"] = VMState; } } return json; @@ -41,7 +41,7 @@ public static RpcTransaction FromJson(JObject json) transaction.BlockHash = UInt256.Parse(json["blockhash"].AsString()); transaction.Confirmations = (uint)json["confirmations"].AsNumber(); transaction.BlockTime = (ulong)json["blocktime"].AsNumber(); - transaction.VMState = json["vm_state"]?.TryGetEnum(); + transaction.VMState = json["vmstate"]?.TryGetEnum(); } return transaction; } diff --git a/src/RpcClient/Models/RpcVersion.cs b/src/RpcClient/Models/RpcVersion.cs index 11d831d74..c66015218 100644 --- a/src/RpcClient/Models/RpcVersion.cs +++ b/src/RpcClient/Models/RpcVersion.cs @@ -15,20 +15,20 @@ public class RpcVersion public JObject ToJson() { JObject json = new JObject(); - json["tcp_port"] = TcpPort; - json["ws_port"] = WsPort; + json["tcpport"] = TcpPort; + json["wsport"] = WsPort; json["nonce"] = Nonce; - json["user_agent"] = UserAgent; + json["useragent"] = UserAgent; return json; } public static RpcVersion FromJson(JObject json) { RpcVersion version = new RpcVersion(); - version.TcpPort = (int)json["tcp_port"].AsNumber(); - version.WsPort = (int)json["ws_port"].AsNumber(); + version.TcpPort = (int)json["tcpport"].AsNumber(); + version.WsPort = (int)json["wsport"].AsNumber(); version.Nonce = (uint)json["nonce"].AsNumber(); - version.UserAgent = json["user_agent"].AsString(); + version.UserAgent = json["useragent"].AsString(); return version; } } diff --git a/src/RpcClient/RpcClient.csproj b/src/RpcClient/RpcClient.csproj index 532622216..f21d61127 100644 --- a/src/RpcClient/RpcClient.csproj +++ b/src/RpcClient/RpcClient.csproj @@ -14,7 +14,7 @@ - + diff --git a/src/RpcClient/Utility.cs b/src/RpcClient/Utility.cs index ff65c9377..beb4eb4f4 100644 --- a/src/RpcClient/Utility.cs +++ b/src/RpcClient/Utility.cs @@ -98,7 +98,7 @@ public static Block BlockFromJson(JObject json) Block block = new Block(); BlockBase blockBase = block; blockBase.FromJson(json); - block.ConsensusData = ConsensusDataFromJson(json["consensus_data"]); + block.ConsensusData = ConsensusDataFromJson(json["consensusdata"]); block.Transactions = ((JArray)json["tx"]).Select(p => TransactionFromJson(p)).ToArray(); return block; } @@ -120,9 +120,9 @@ public static Transaction TransactionFromJson(JObject json) tx.Version = byte.Parse(json["version"].AsString()); tx.Nonce = uint.Parse(json["nonce"].AsString()); tx.Sender = json["sender"].AsString().ToScriptHash(); - tx.SystemFee = long.Parse(json["sys_fee"].AsString()); - tx.NetworkFee = long.Parse(json["net_fee"].AsString()); - tx.ValidUntilBlock = uint.Parse(json["valid_until_block"].AsString()); + tx.SystemFee = long.Parse(json["sysfee"].AsString()); + tx.NetworkFee = long.Parse(json["netfee"].AsString()); + tx.ValidUntilBlock = uint.Parse(json["validuntilblock"].AsString()); tx.Attributes = ((JArray)json["attributes"]).Select(p => TransactionAttributeFromJson(p)).ToArray(); tx.Script = Convert.FromBase64String(json["script"].AsString()); tx.Witnesses = ((JArray)json["witnesses"]).Select(p => WitnessFromJson(p)).ToArray(); diff --git a/src/RpcNep5Tracker/RpcNep5Tracker.cs b/src/RpcNep5Tracker/RpcNep5Tracker.cs index c2c58c123..2f1788e85 100644 --- a/src/RpcNep5Tracker/RpcNep5Tracker.cs +++ b/src/RpcNep5Tracker/RpcNep5Tracker.cs @@ -33,7 +33,7 @@ public class RpcNep5Tracker : Plugin, IPersistencePlugin private uint _maxResults; private Snapshot _levelDbSnapshot; - public override string Description => "Enquiries NEP-5 balance and transactions history of accounts through RPC"; + public override string Description => "Enquiries NEP-5 balances and transaction history of accounts through RPC"; public RpcNep5Tracker() { @@ -233,12 +233,12 @@ private void AddTransfers(byte dbPrefix, UInt160 userScriptHash, ulong startTime if (++resultCount > _maxResults) break; JObject transfer = new JObject(); transfer["timestamp"] = key.TimestampMS; - transfer["asset_hash"] = key.AssetScriptHash.ToString(); - transfer["transfer_address"] = value.UserScriptHash.ToAddress(); + transfer["assethash"] = key.AssetScriptHash.ToString(); + transfer["transferaddress"] = value.UserScriptHash.ToAddress(); transfer["amount"] = value.Amount.ToString(); - transfer["block_index"] = value.BlockIndex; - transfer["transfer_notify_index"] = key.BlockXferNotificationIndex; - transfer["tx_hash"] = value.TxHash.ToString(); + transfer["blockindex"] = value.BlockIndex; + transfer["transfernotifyindex"] = key.BlockXferNotificationIndex; + transfer["txhash"] = value.TxHash.ToString(); parentJArray.Add(transfer); } } @@ -288,9 +288,9 @@ public JObject GetNep5Balances(JArray _params) JObject balance = new JObject(); if (Blockchain.Singleton.View.Contracts.TryGet(key.AssetScriptHash) is null) continue; - balance["asset_hash"] = key.AssetScriptHash.ToString(); + balance["assethash"] = key.AssetScriptHash.ToString(); balance["amount"] = value.Balance.ToString(); - balance["last_updated_block"] = value.LastUpdatedBlock; + balance["lastupdatedblock"] = value.LastUpdatedBlock; balances.Add(balance); } return json; diff --git a/src/RpcServer/RpcServer.Blockchain.cs b/src/RpcServer/RpcServer.Blockchain.cs index 0bb0b0371..60d736da4 100644 --- a/src/RpcServer/RpcServer.Blockchain.cs +++ b/src/RpcServer/RpcServer.Blockchain.cs @@ -145,7 +145,7 @@ private JObject GetRawTransaction(JArray _params) json["blockhash"] = header.Hash.ToString(); json["confirmations"] = Blockchain.Singleton.Height - header.Index + 1; json["blocktime"] = header.Timestamp; - json["vm_state"] = txState.VMState; + json["vmstate"] = txState.VMState; } return json; } diff --git a/src/RpcServer/RpcServer.Node.cs b/src/RpcServer/RpcServer.Node.cs index f42fd96c6..0696ab7f3 100644 --- a/src/RpcServer/RpcServer.Node.cs +++ b/src/RpcServer/RpcServer.Node.cs @@ -60,10 +60,10 @@ private static JObject GetRelayResult(VerifyResult reason, UInt256 hash) private JObject GetVersion(JArray _params) { JObject json = new JObject(); - json["tcpPort"] = LocalNode.Singleton.ListenerTcpPort; - json["wsPort"] = LocalNode.Singleton.ListenerWsPort; + json["tcpport"] = LocalNode.Singleton.ListenerTcpPort; + json["wsport"] = LocalNode.Singleton.ListenerWsPort; json["nonce"] = LocalNode.Nonce; - json["userAgent"] = LocalNode.UserAgent; + json["useragent"] = LocalNode.UserAgent; return json; } diff --git a/src/RpcServer/RpcServer.SmartContract.cs b/src/RpcServer/RpcServer.SmartContract.cs index bffb524c2..cb477f41a 100644 --- a/src/RpcServer/RpcServer.SmartContract.cs +++ b/src/RpcServer/RpcServer.SmartContract.cs @@ -2,17 +2,16 @@ #pragma warning disable IDE0060 using Neo.IO.Json; +using Neo.Ledger; using Neo.Network.P2P.Payloads; using Neo.Persistence; using Neo.SmartContract; +using Neo.SmartContract.Native; using Neo.VM; +using Neo.Wallets; using System; using System.IO; using System.Linq; -using Neo.IO; -using Neo.Ledger; -using Neo.SmartContract.Native; -using Neo.Wallets; namespace Neo.Plugins { @@ -61,7 +60,7 @@ private JObject GetInvokeResult(byte[] script, IVerifiable checkWitnessHashes = JObject json = new JObject(); json["script"] = script.ToHexString(); json["state"] = engine.State; - json["gas_consumed"] = engine.GasConsumed.ToString(); + json["gasconsumed"] = engine.GasConsumed.ToString(); try { json["stack"] = new JArray(engine.ResultStack.Select(p => p.ToJson())); diff --git a/src/RpcServer/RpcServer.csproj b/src/RpcServer/RpcServer.csproj index e3e8a3855..97a64275b 100644 --- a/src/RpcServer/RpcServer.csproj +++ b/src/RpcServer/RpcServer.csproj @@ -15,7 +15,7 @@ - + diff --git a/tests/Neo.Network.RPC.Tests/RpcTestCases.json b/tests/Neo.Network.RPC.Tests/RpcTestCases.json index bd934923d..644654b96 100644 --- a/tests/Neo.Network.RPC.Tests/RpcTestCases.json +++ b/tests/Neo.Network.RPC.Tests/RpcTestCases.json @@ -85,7 +85,7 @@ "verification": "EQ==" } ], - "consensus_data": { + "consensusdata": { "primary": 0, "nonce": "000000007c2bac1d" }, @@ -96,9 +96,9 @@ "version": 0, "nonce": 0, "sender": "NeN4xPMn4kHoj7G8Lciq9oorgLTvqt4qi1", - "sys_fee": "0", - "net_fee": "0", - "valid_until_block": 0, + "sysfee": "0", + "netfee": "0", + "validuntilblock": 0, "attributes": [], "script": "QRI+f+g=", "witnesses": [ @@ -140,7 +140,7 @@ "verification": "EQ==" } ], - "consensus_data": { + "consensusdata": { "primary": 0, "nonce": "000000007c2bac1d" }, @@ -151,9 +151,9 @@ "version": 0, "nonce": 0, "sender": "NeN4xPMn4kHoj7G8Lciq9oorgLTvqt4qi1", - "sys_fee": "0", - "net_fee": "0", - "valid_until_block": 0, + "sysfee": "0", + "netfee": "0", + "validuntilblock": 0, "attributes": [], "script": "QRI+f+g=", "witnesses": [ @@ -338,13 +338,13 @@ } ], "offset": 0, - "returnType": "ByteArray" + "returntype": "ByteArray" }, { "name": "Destroy", "parameters": [], "offset": 400, - "returnType": "Boolean" + "returntype": "Boolean" }, { "name": "Migrate", @@ -359,7 +359,7 @@ } ], "offset": 408, - "returnType": "Boolean" + "returntype": "Boolean" }, { "name": "BalanceOf", @@ -370,43 +370,43 @@ } ], "offset": 474, - "returnType": "Integer" + "returntype": "Integer" }, { "name": "Decimals", "parameters": [], "offset": 585, - "returnType": "Integer" + "returntype": "Integer" }, { "name": "Deploy", "parameters": [], "offset": 610, - "returnType": "Boolean" + "returntype": "Boolean" }, { "name": "Name", "parameters": [], "offset": 763, - "returnType": "String" + "returntype": "String" }, { "name": "Symbol", "parameters": [], "offset": 787, - "returnType": "String" + "returntype": "String" }, { "name": "SupportedStandards", "parameters": [], "offset": 793, - "returnType": "Array" + "returntype": "Array" }, { "name": "TotalSupply", "parameters": [], "offset": 827, - "returnType": "Integer" + "returntype": "Integer" } ], "events": [ @@ -436,7 +436,7 @@ } ], "trusts": [], - "safeMethods": [], + "safemethods": [], "extra": null } } @@ -505,9 +505,9 @@ "version": 0, "nonce": 969006668, "sender": "NVVwFw6XyhtRCFQ8SpUTMdPyYt4Vd9A1XQ", - "sys_fee": "100000000", - "net_fee": "1272390", - "valid_until_block": 2104625, + "sysfee": "100000000", + "netfee": "1272390", + "validuntilblock": 2104625, "attributes": [], "script": "AwAQpdToAAAADBSZA7DD0pKYj+vl8wagL2VOousWKQwUaSWqVUcSQ5qcYTuhFO+j+sI928oTwAwIdHJhbnNmZXIMFDt9NxHG8Mz5sdypA9G/odiW8SOMQWJ9W1I5", "witnesses": [ @@ -519,7 +519,7 @@ "blockhash": "0xc1ed259e394c9cd93c1e0eb1e0f144c0d10da64861a24c0084f0d98270b698f1", "confirmations": 643, "blocktime": 1579417249620, - "vm_state": "HALT" + "vmstate": "HALT" } } }, @@ -645,10 +645,10 @@ "jsonrpc": "2.0", "id": 1, "result": { - "tcp_port": 20333, - "ws_port": 20334, + "tcpport": 20333, + "wsport": 20334, "nonce": 592651621, - "user_agent": "/Neo:3.0.0-preview1/" + "useragent": "/Neo:3.0.0-preview1/" } } }, @@ -709,7 +709,7 @@ "result": { "script": "0c1426ae7c6c9861ec418468c1f0fdc4a7f2963eb89111c00c0962616c616e63654f660c143b7d3711c6f0ccf9b1dca903d1bfa1d896f1238c41627d5b52", "state": "HALT", - "gas_consumed": "2007570", + "gasconsumed": "2007570", "stack": [ { "type": "Integer", @@ -734,7 +734,7 @@ "result": { "script": "10c30c046e616d650c143b7d3711c6f0ccf9b1dca903d1bfa1d896f1238c41627d5b5210c30c0673796d626f6c0c143b7d3711c6f0ccf9b1dca903d1bfa1d896f1238c41627d5b5210c30c08646563696d616c730c143b7d3711c6f0ccf9b1dca903d1bfa1d896f1238c41627d5b5210c30c0b746f74616c537570706c790c143b7d3711c6f0ccf9b1dca903d1bfa1d896f1238c41627d5b52", "state": "HALT", - "gas_consumed": "5061560", + "gasconsumed": "5061560", "stack": [ { "type": "ByteArray", @@ -878,7 +878,7 @@ "result": { "script": "10c30c08646563696d616c730c143b7d3711c6f0ccf9b1dca903d1bfa1d896f1238c41627d5b52", "state": "HALT", - "gas_consumed": "5061560", + "gasconsumed": "5061560", "stack": [ { "type": "Integer", @@ -1010,9 +1010,9 @@ "version": 0, "nonce": 1553700339, "sender": "NVVwFw6XyhtRCFQ8SpUTMdPyYt4Vd9A1XQ", - "sys_fee": "100000000", - "net_fee": "1272390", - "valid_until_block": 2105487, + "sysfee": "100000000", + "netfee": "1272390", + "validuntilblock": 2105487, "attributes": [], "cosigners": [ { @@ -1061,9 +1061,9 @@ "version": 0, "nonce": 34429660, "sender": "NUMK37TV9yYKbJr1Gufh74nZiM623eBLqX", - "sys_fee": "100000000", - "net_fee": "2483780", - "valid_until_block": 2105494, + "sysfee": "100000000", + "netfee": "2483780", + "validuntilblock": 2105494, "attributes": [], "cosigners": [ { @@ -1106,9 +1106,9 @@ "version": 0, "nonce": 330056065, "sender": "NUMK37TV9yYKbJr1Gufh74nZiM623eBLqX", - "sys_fee": "100000000", - "net_fee": "2381780", - "valid_until_block": 2105500, + "sysfee": "100000000", + "netfee": "2381780", + "validuntilblock": 2105500, "attributes": [], "cosigners": [ { @@ -1210,32 +1210,32 @@ "sent": [ { "timestamp": 1579250114541, - "asset_hash": "0x8c23f196d8a1bfd103a9dcb1f9ccf0c611377d3b", - "transfer_address": "NVVwFw6XyhtRCFQ8SpUTMdPyYt4Vd9A1XQ", + "assethash": "0x8c23f196d8a1bfd103a9dcb1f9ccf0c611377d3b", + "transferaddress": "NVVwFw6XyhtRCFQ8SpUTMdPyYt4Vd9A1XQ", "amount": "1000000000", - "block_index": 603, - "transfer_notify_index": 0, - "tx_hash": "0x5e177b8d1dc33e9103c0cfd42f6dbf4efbe43029e2d6a18ea5ba0cb8437056b3" + "blockindex": 603, + "transfernotifyindex": 0, + "txhash": "0x5e177b8d1dc33e9103c0cfd42f6dbf4efbe43029e2d6a18ea5ba0cb8437056b3" }, { "timestamp": 1579406581635, - "asset_hash": "0x8c23f196d8a1bfd103a9dcb1f9ccf0c611377d3b", - "transfer_address": "NUMK37TV9yYKbJr1Gufh74nZiM623eBLqX", + "assethash": "0x8c23f196d8a1bfd103a9dcb1f9ccf0c611377d3b", + "transferaddress": "NUMK37TV9yYKbJr1Gufh74nZiM623eBLqX", "amount": "1000000000", - "block_index": 1525, - "transfer_notify_index": 0, - "tx_hash": "0xc9c618b48972b240e0058d97b8d79b807ad51015418c84012765298526aeb77d" + "blockindex": 1525, + "transfernotifyindex": 0, + "txhash": "0xc9c618b48972b240e0058d97b8d79b807ad51015418c84012765298526aeb77d" } ], "received": [ { "timestamp": 1579250114541, - "asset_hash": "0x8c23f196d8a1bfd103a9dcb1f9ccf0c611377d3b", - "transfer_address": "NVVwFw6XyhtRCFQ8SpUTMdPyYt4Vd9A1XQ", + "assethash": "0x8c23f196d8a1bfd103a9dcb1f9ccf0c611377d3b", + "transferaddress": "NVVwFw6XyhtRCFQ8SpUTMdPyYt4Vd9A1XQ", "amount": "1000000000", - "block_index": 603, - "transfer_notify_index": 0, - "tx_hash": "0x5e177b8d1dc33e9103c0cfd42f6dbf4efbe43029e2d6a18ea5ba0cb8437056b3" + "blockindex": 603, + "transfernotifyindex": 0, + "txhash": "0x5e177b8d1dc33e9103c0cfd42f6dbf4efbe43029e2d6a18ea5ba0cb8437056b3" } ], "address": "NVVwFw6XyhtRCFQ8SpUTMdPyYt4Vd9A1XQ" @@ -1256,14 +1256,14 @@ "result": { "balance": [ { - "asset_hash": "0x8c23f196d8a1bfd103a9dcb1f9ccf0c611377d3b", + "assethash": "0x8c23f196d8a1bfd103a9dcb1f9ccf0c611377d3b", "amount": "719978585420", - "last_updated_block": 3101 + "lastupdatedblock": 3101 }, { - "asset_hash": "0x9bde8f209c88dd0e7ca3bf0af0f476cdd8207789", + "assethash": "0x9bde8f209c88dd0e7ca3bf0af0f476cdd8207789", "amount": "89999810", - "last_updated_block": 3096 + "lastupdatedblock": 3096 } ], "address": "NVVwFw6XyhtRCFQ8SpUTMdPyYt4Vd9A1XQ" From f51432d4a58c78818f7bd1c1e174ba0e160b482b Mon Sep 17 00:00:00 2001 From: HaoqiangZhang Date: Thu, 9 Jul 2020 14:08:55 +0800 Subject: [PATCH 136/183] fix add signature in invokefunction and invokescript (#280) * fix add signature in invokefunction and invokescript * Update RpcServer.SmartContract.cs * rename * fix format * add exception if wallet or cosigners is null * Set the default tx to null Co-authored-by: Shargon --- src/RpcServer/RpcServer.SmartContract.cs | 29 ++++++++++++++---------- src/RpcServer/RpcServer.Wallet.cs | 26 +++++++++++++-------- 2 files changed, 33 insertions(+), 22 deletions(-) diff --git a/src/RpcServer/RpcServer.SmartContract.cs b/src/RpcServer/RpcServer.SmartContract.cs index cb477f41a..5bb258ea6 100644 --- a/src/RpcServer/RpcServer.SmartContract.cs +++ b/src/RpcServer/RpcServer.SmartContract.cs @@ -17,15 +17,15 @@ namespace Neo.Plugins { partial class RpcServer { - private class CheckWitnessHashes : IVerifiable + private class Cosigners : IVerifiable { - private readonly UInt160[] _scriptHashesForVerifying; + private readonly Cosigner[] _cosigners; public Witness[] Witnesses { get; set; } public int Size { get; } - public CheckWitnessHashes(UInt160[] scriptHashesForVerifying) + public Cosigners(Cosigner[] cosigners) { - _scriptHashesForVerifying = scriptHashesForVerifying; + _cosigners = cosigners; } public void Serialize(BinaryWriter writer) @@ -45,7 +45,12 @@ public void DeserializeUnsigned(BinaryReader reader) public UInt160[] GetScriptHashesForVerifying(StoreView snapshot) { - return _scriptHashesForVerifying; + return _cosigners.Select(p => p.Account).ToArray(); + } + + public Cosigner[] GetCosigners() + { + return _cosigners; } public void SerializeUnsigned(BinaryWriter writer) @@ -54,9 +59,9 @@ public void SerializeUnsigned(BinaryWriter writer) } } - private JObject GetInvokeResult(byte[] script, IVerifiable checkWitnessHashes = null) + private JObject GetInvokeResult(byte[] script, Cosigners cosigners = null) { - using ApplicationEngine engine = ApplicationEngine.Run(script, checkWitnessHashes, extraGAS: settings.MaxGasInvoke); + using ApplicationEngine engine = ApplicationEngine.Run(script, cosigners, extraGAS: settings.MaxGasInvoke); JObject json = new JObject(); json["script"] = script.ToHexString(); json["state"] = engine.State; @@ -69,7 +74,7 @@ private JObject GetInvokeResult(byte[] script, IVerifiable checkWitnessHashes = { json["stack"] = "error: recursive reference"; } - ProcessInvokeWithWallet(json); + ProcessInvokeWithWallet(json, cosigners); return json; } @@ -79,21 +84,21 @@ private JObject InvokeFunction(JArray _params) UInt160 script_hash = UInt160.Parse(_params[0].AsString()); string operation = _params[1].AsString(); ContractParameter[] args = _params.Count >= 3 ? ((JArray)_params[2]).Select(p => ContractParameter.FromJson(p)).ToArray() : new ContractParameter[0]; - CheckWitnessHashes checkWitnessHashes = _params.Count >= 4 ? new CheckWitnessHashes(((JArray)_params[3]).Select(u => UInt160.Parse(u.AsString())).ToArray()) : null; + Cosigners cosigners = _params.Count >= 4 ? new Cosigners(((JArray)_params[3]).Select(u => new Cosigner() { Account = UInt160.Parse(u["account"].AsString()), Scopes = (WitnessScope)Enum.Parse(typeof(WitnessScope), u["scopes"].AsString()) }).ToArray()) : null; byte[] script; using (ScriptBuilder sb = new ScriptBuilder()) { script = sb.EmitAppCall(script_hash, operation, args).ToArray(); } - return GetInvokeResult(script, checkWitnessHashes); + return GetInvokeResult(script, cosigners); } [RpcMethod] private JObject InvokeScript(JArray _params) { byte[] script = _params[0].AsString().HexToBytes(); - CheckWitnessHashes checkWitnessHashes = _params.Count >= 2 ? new CheckWitnessHashes(((JArray)_params[1]).Select(u => UInt160.Parse(u.AsString())).ToArray()) : null; - return GetInvokeResult(script, checkWitnessHashes); + Cosigners cosigners = _params.Count >= 2 ? new Cosigners(((JArray)_params[1]).Select(u => new Cosigner() { Account = UInt160.Parse(u["account"].AsString()), Scopes = (WitnessScope)Enum.Parse(typeof(WitnessScope), u["scopes"].AsString()) }).ToArray()) : null; + return GetInvokeResult(script, cosigners); } [RpcMethod] diff --git a/src/RpcServer/RpcServer.Wallet.cs b/src/RpcServer/RpcServer.Wallet.cs index f58c1472e..6af9cbc25 100644 --- a/src/RpcServer/RpcServer.Wallet.cs +++ b/src/RpcServer/RpcServer.Wallet.cs @@ -138,19 +138,25 @@ private JObject OpenWallet(JArray _params) return true; } - private void ProcessInvokeWithWallet(JObject result) + private void ProcessInvokeWithWallet(JObject result, Cosigners cosigners = null) { - if (wallet != null) + Transaction tx = null; + if (wallet != null && cosigners != null) { - Transaction tx = wallet.MakeTransaction(result["script"].AsString().HexToBytes()); - ContractParametersContext context = new ContractParametersContext(tx); - wallet.Sign(context); - if (context.Completed) - tx.Witnesses = context.GetWitnesses(); - else - tx = null; - result["tx"] = tx?.ToArray().ToHexString(); + UInt160[] accounts = wallet.GetAccounts().Where(p => !p.Lock && !p.WatchOnly).Select(p => p.ScriptHash).ToArray(); + Cosigner[] witnessCosigners = cosigners.GetCosigners().Where(p => accounts.Contains(p.Account)).ToArray(); + if (witnessCosigners.Count() > 0) + { + tx = wallet.MakeTransaction(result["script"].AsString().HexToBytes(), null, witnessCosigners); + ContractParametersContext context = new ContractParametersContext(tx); + wallet.Sign(context); + if (context.Completed) + tx.Witnesses = context.GetWitnesses(); + else + tx = null; + } } + result["tx"] = tx?.ToArray().ToHexString(); } [RpcMethod] From 40f9180d2b3e4e038d77ec8da9af27ec2ac34197 Mon Sep 17 00:00:00 2001 From: cloud8little <34291844+cloud8little@users.noreply.github.com> Date: Thu, 9 Jul 2020 14:40:31 +0800 Subject: [PATCH 137/183] update nuget (#283) * update nuget * remove GasFree * resolve conflict Co-authored-by: Owen Zhang <38493437+superboyiii@users.noreply.github.com> --- src/LevelDBStore/LevelDBStore.csproj | 2 +- src/RocksDBStore/RocksDBStore.csproj | 2 +- src/RpcClient/RpcClient.csproj | 2 +- src/RpcClient/TransactionManager.cs | 2 +- src/RpcNep5Tracker/RpcNep5Tracker.cs | 2 +- src/RpcServer/RpcServer.SmartContract.cs | 2 +- src/RpcServer/RpcServer.csproj | 2 +- src/StatesDumper/StatesDumper.csproj | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/LevelDBStore/LevelDBStore.csproj b/src/LevelDBStore/LevelDBStore.csproj index f1501ab71..73a707dba 100644 --- a/src/LevelDBStore/LevelDBStore.csproj +++ b/src/LevelDBStore/LevelDBStore.csproj @@ -15,7 +15,7 @@ - + diff --git a/src/RocksDBStore/RocksDBStore.csproj b/src/RocksDBStore/RocksDBStore.csproj index 71964ff97..57d6ff4eb 100644 --- a/src/RocksDBStore/RocksDBStore.csproj +++ b/src/RocksDBStore/RocksDBStore.csproj @@ -14,7 +14,7 @@ - + diff --git a/src/RpcClient/RpcClient.csproj b/src/RpcClient/RpcClient.csproj index f21d61127..2d520e052 100644 --- a/src/RpcClient/RpcClient.csproj +++ b/src/RpcClient/RpcClient.csproj @@ -14,7 +14,7 @@ - + diff --git a/src/RpcClient/TransactionManager.cs b/src/RpcClient/TransactionManager.cs index 39fd2da06..11e273b5e 100644 --- a/src/RpcClient/TransactionManager.cs +++ b/src/RpcClient/TransactionManager.cs @@ -75,7 +75,7 @@ public TransactionManager MakeTransaction(byte[] script, TransactionAttribute[] // Add witness hashes parameter to pass CheckWitness UInt160[] hashes = Tx.GetScriptHashesForVerifying(null); RpcInvokeResult result = rpcClient.InvokeScript(script, hashes); - Tx.SystemFee = Math.Max(long.Parse(result.GasConsumed) - ApplicationEngine.GasFree, 0); + Tx.SystemFee = long.Parse(result.GasConsumed); context = new ContractParametersContext(Tx); signStore = new List(); diff --git a/src/RpcNep5Tracker/RpcNep5Tracker.cs b/src/RpcNep5Tracker/RpcNep5Tracker.cs index 2f1788e85..535fd4410 100644 --- a/src/RpcNep5Tracker/RpcNep5Tracker.cs +++ b/src/RpcNep5Tracker/RpcNep5Tracker.cs @@ -176,7 +176,7 @@ public void OnPersist(StoreView snapshot, IReadOnlyList - + diff --git a/src/StatesDumper/StatesDumper.csproj b/src/StatesDumper/StatesDumper.csproj index 7429ea9f9..a5ca9871a 100644 --- a/src/StatesDumper/StatesDumper.csproj +++ b/src/StatesDumper/StatesDumper.csproj @@ -14,7 +14,7 @@ - + From 70f65d4e6745598ef4ee46ed04e170b965629005 Mon Sep 17 00:00:00 2001 From: HaoqiangZhang Date: Mon, 13 Jul 2020 21:38:27 +0800 Subject: [PATCH 138/183] update IStorageProvider (#285) --- src/LevelDBStore/LevelDBStore.csproj | 4 ++-- src/LevelDBStore/Plugins/Storage/LevelDBStore.cs | 2 +- src/RocksDBStore/Plugins/Storage/RocksDBStore.cs | 2 +- src/RocksDBStore/RocksDBStore.csproj | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/LevelDBStore/LevelDBStore.csproj b/src/LevelDBStore/LevelDBStore.csproj index 73a707dba..9e6e2a829 100644 --- a/src/LevelDBStore/LevelDBStore.csproj +++ b/src/LevelDBStore/LevelDBStore.csproj @@ -1,4 +1,4 @@ - + 3.0.0-preview2 @@ -15,7 +15,7 @@ - + diff --git a/src/LevelDBStore/Plugins/Storage/LevelDBStore.cs b/src/LevelDBStore/Plugins/Storage/LevelDBStore.cs index dcb59c871..09a526bcc 100644 --- a/src/LevelDBStore/Plugins/Storage/LevelDBStore.cs +++ b/src/LevelDBStore/Plugins/Storage/LevelDBStore.cs @@ -2,7 +2,7 @@ namespace Neo.Plugins.Storage { - public class LevelDBStore : Plugin, IStoragePlugin + public class LevelDBStore : Plugin, IStorageProvider { private string path; diff --git a/src/RocksDBStore/Plugins/Storage/RocksDBStore.cs b/src/RocksDBStore/Plugins/Storage/RocksDBStore.cs index afd11757d..6377845e6 100644 --- a/src/RocksDBStore/Plugins/Storage/RocksDBStore.cs +++ b/src/RocksDBStore/Plugins/Storage/RocksDBStore.cs @@ -2,7 +2,7 @@ namespace Neo.Plugins.Storage { - public class RocksDBStore : Plugin, IStoragePlugin + public class RocksDBStore : Plugin, IStorageProvider { public override string Description => "Uses RocksDBStore to store the blockchain data"; diff --git a/src/RocksDBStore/RocksDBStore.csproj b/src/RocksDBStore/RocksDBStore.csproj index 57d6ff4eb..fb9d1a700 100644 --- a/src/RocksDBStore/RocksDBStore.csproj +++ b/src/RocksDBStore/RocksDBStore.csproj @@ -1,4 +1,4 @@ - + 3.0.0-preview2 @@ -14,7 +14,7 @@ - + From 6dc340c0be3f20771094ce2bf39e498526b97372 Mon Sep 17 00:00:00 2001 From: HaoqiangZhang Date: Wed, 15 Jul 2020 21:42:36 +0800 Subject: [PATCH 139/183] update signers for invokefunction and invokescript (#286) * update signers for invokefunction and invokescript * fix format * Validate signer format Co-authored-by: Shargon --- src/RpcServer/RpcServer.SmartContract.cs | 47 +++++++++++++++++------- src/RpcServer/RpcServer.Wallet.cs | 6 +-- src/RpcServer/RpcServer.csproj | 2 +- src/StatesDumper/StatesDumper.csproj | 2 +- 4 files changed, 38 insertions(+), 19 deletions(-) diff --git a/src/RpcServer/RpcServer.SmartContract.cs b/src/RpcServer/RpcServer.SmartContract.cs index 929ab2d77..2b04ad013 100644 --- a/src/RpcServer/RpcServer.SmartContract.cs +++ b/src/RpcServer/RpcServer.SmartContract.cs @@ -1,6 +1,8 @@ #pragma warning disable IDE0051 #pragma warning disable IDE0060 +using Neo.Cryptography.ECC; +using Neo.IO; using Neo.IO.Json; using Neo.Ledger; using Neo.Network.P2P.Payloads; @@ -17,15 +19,15 @@ namespace Neo.Plugins { partial class RpcServer { - private class Cosigners : IVerifiable + private class Signers : IVerifiable { - private readonly Cosigner[] _cosigners; + private readonly Signer[] _signers; public Witness[] Witnesses { get; set; } public int Size { get; } - public Cosigners(Cosigner[] cosigners) + public Signers(Signer[] signers) { - _cosigners = cosigners; + _signers = signers; } public void Serialize(BinaryWriter writer) @@ -45,12 +47,12 @@ public void DeserializeUnsigned(BinaryReader reader) public UInt160[] GetScriptHashesForVerifying(StoreView snapshot) { - return _cosigners.Select(p => p.Account).ToArray(); + return _signers.Select(p => p.Account).ToArray(); } - public Cosigner[] GetCosigners() + public Signer[] GetSigners() { - return _cosigners; + return _signers; } public void SerializeUnsigned(BinaryWriter writer) @@ -59,9 +61,9 @@ public void SerializeUnsigned(BinaryWriter writer) } } - private JObject GetInvokeResult(byte[] script, Cosigners cosigners = null) + private JObject GetInvokeResult(byte[] script, Signers signers = null) { - using ApplicationEngine engine = ApplicationEngine.Run(script, cosigners, gas: settings.MaxGasInvoke); + using ApplicationEngine engine = ApplicationEngine.Run(script, signers, gas: settings.MaxGasInvoke); JObject json = new JObject(); json["script"] = script.ToHexString(); json["state"] = engine.State; @@ -74,31 +76,48 @@ private JObject GetInvokeResult(byte[] script, Cosigners cosigners = null) { json["stack"] = "error: recursive reference"; } - ProcessInvokeWithWallet(json, cosigners); + ProcessInvokeWithWallet(json, signers); return json; } + private static Signers SignersFromJson(JArray _params) + { + var ret = new Signers(_params.Select(u => new Signer() + { + Account = UInt160.Parse(u["account"].AsString()), + Scopes = (WitnessScope)Enum.Parse(typeof(WitnessScope), u["scopes"]?.AsString()), + AllowedContracts = ((JArray)u["contracts"])?.Select(p => UInt160.Parse(p.AsString())).ToArray(), + AllowedGroups = ((JArray)u["groups"])?.Select(p => ECPoint.Parse(p.AsString(), ECCurve.Secp256r1)).ToArray() + }).ToArray()); + + // Validate format + + _ = IO.Helper.ToByteArray(ret.GetSigners()).AsSerializableArray(); + + return ret; + } + [RpcMethod] private JObject InvokeFunction(JArray _params) { UInt160 script_hash = UInt160.Parse(_params[0].AsString()); string operation = _params[1].AsString(); ContractParameter[] args = _params.Count >= 3 ? ((JArray)_params[2]).Select(p => ContractParameter.FromJson(p)).ToArray() : new ContractParameter[0]; - Cosigners cosigners = _params.Count >= 4 ? new Cosigners(((JArray)_params[3]).Select(u => new Cosigner() { Account = UInt160.Parse(u["account"].AsString()), Scopes = (WitnessScope)Enum.Parse(typeof(WitnessScope), u["scopes"].AsString()) }).ToArray()) : null; + Signers signers = _params.Count >= 4 ? SignersFromJson((JArray)_params[3]) : null; byte[] script; using (ScriptBuilder sb = new ScriptBuilder()) { script = sb.EmitAppCall(script_hash, operation, args).ToArray(); } - return GetInvokeResult(script, cosigners); + return GetInvokeResult(script, signers); } [RpcMethod] private JObject InvokeScript(JArray _params) { byte[] script = _params[0].AsString().HexToBytes(); - Cosigners cosigners = _params.Count >= 2 ? new Cosigners(((JArray)_params[1]).Select(u => new Cosigner() { Account = UInt160.Parse(u["account"].AsString()), Scopes = (WitnessScope)Enum.Parse(typeof(WitnessScope), u["scopes"].AsString()) }).ToArray()) : null; - return GetInvokeResult(script, cosigners); + Signers signers = _params.Count >= 2 ? SignersFromJson((JArray)_params[1]) : null; + return GetInvokeResult(script, signers); } [RpcMethod] diff --git a/src/RpcServer/RpcServer.Wallet.cs b/src/RpcServer/RpcServer.Wallet.cs index 6af9cbc25..4db930130 100644 --- a/src/RpcServer/RpcServer.Wallet.cs +++ b/src/RpcServer/RpcServer.Wallet.cs @@ -138,13 +138,13 @@ private JObject OpenWallet(JArray _params) return true; } - private void ProcessInvokeWithWallet(JObject result, Cosigners cosigners = null) + private void ProcessInvokeWithWallet(JObject result, Signers signers = null) { Transaction tx = null; - if (wallet != null && cosigners != null) + if (wallet != null && signers != null) { UInt160[] accounts = wallet.GetAccounts().Where(p => !p.Lock && !p.WatchOnly).Select(p => p.ScriptHash).ToArray(); - Cosigner[] witnessCosigners = cosigners.GetCosigners().Where(p => accounts.Contains(p.Account)).ToArray(); + Signer[] witnessCosigners = signers.GetSigners().Where(p => accounts.Contains(p.Account)).ToArray(); if (witnessCosigners.Count() > 0) { tx = wallet.MakeTransaction(result["script"].AsString().HexToBytes(), null, witnessCosigners); diff --git a/src/RpcServer/RpcServer.csproj b/src/RpcServer/RpcServer.csproj index cc5318110..853edc38f 100644 --- a/src/RpcServer/RpcServer.csproj +++ b/src/RpcServer/RpcServer.csproj @@ -15,7 +15,7 @@ - + diff --git a/src/StatesDumper/StatesDumper.csproj b/src/StatesDumper/StatesDumper.csproj index a5ca9871a..5ae67e8ca 100644 --- a/src/StatesDumper/StatesDumper.csproj +++ b/src/StatesDumper/StatesDumper.csproj @@ -14,7 +14,7 @@ - + From dcd946a25b8f3e6365a42bfe3ecf68be990f8b6c Mon Sep 17 00:00:00 2001 From: Qiao Jin <43407364+Qiao-Jin@users.noreply.github.com> Date: Thu, 16 Jul 2020 15:50:45 +0800 Subject: [PATCH 140/183] Add BloomFilter to levelDB (#253) * Add BloomFilter to levelDB * Code optimization * Code optimization * Optimize bloomfilter bits per key value * Hard-code bloomfilter bitsPeyKey to 15 * Code optimization Co-authored-by: Jin Qiao Co-authored-by: Shargon Co-authored-by: Erik Zhang --- src/LevelDBStore/IO/Data/LevelDB/Native.cs | 3 +++ src/LevelDBStore/LevelDBStore/config.json | 2 +- src/LevelDBStore/Plugins/Storage/Store.cs | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/LevelDBStore/IO/Data/LevelDB/Native.cs b/src/LevelDBStore/IO/Data/LevelDB/Native.cs index f9991ff81..8959ae390 100644 --- a/src/LevelDBStore/IO/Data/LevelDB/Native.cs +++ b/src/LevelDBStore/IO/Data/LevelDB/Native.cs @@ -155,6 +155,9 @@ public static class Native [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] public static extern void leveldb_options_set_filter_policy(IntPtr /*Options*/ options, IntPtr /*FilterPolicy*/ policy); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr leveldb_filterpolicy_create_bloom(int bits_per_key); #endregion #region ReadOptions diff --git a/src/LevelDBStore/LevelDBStore/config.json b/src/LevelDBStore/LevelDBStore/config.json index e6683b8e4..f31d07fd6 100644 --- a/src/LevelDBStore/LevelDBStore/config.json +++ b/src/LevelDBStore/LevelDBStore/config.json @@ -1,4 +1,4 @@ -{ +{ "PluginConfiguration": { "Path": "Data_LevelDB_{0}" } diff --git a/src/LevelDBStore/Plugins/Storage/Store.cs b/src/LevelDBStore/Plugins/Storage/Store.cs index 5a6503e3d..6d9aba937 100644 --- a/src/LevelDBStore/Plugins/Storage/Store.cs +++ b/src/LevelDBStore/Plugins/Storage/Store.cs @@ -16,7 +16,7 @@ internal class Store : IStore public Store(string path) { - this.db = DB.Open(path, new Options { CreateIfMissing = true }); + this.db = DB.Open(path, new Options { CreateIfMissing = true, FilterPolicy = Native.leveldb_filterpolicy_create_bloom(15) }); byte[] value = db.Get(ReadOptions.Default, LHelper.CreateKey(SYS_Version)); if (value != null && Version.TryParse(Encoding.ASCII.GetString(value), out Version version) && version >= Version.Parse("3.0.0")) return; From 804181f7c2096df25fdeeb6036a845eb7be5517a Mon Sep 17 00:00:00 2001 From: Owen Zhang <38493437+superboyiii@users.noreply.github.com> Date: Fri, 17 Jul 2020 16:03:02 +0800 Subject: [PATCH 141/183] Solve workflow conflict (#294) * Solve workflow conflict Solve workflow conflict from master-2.x and master * Update main.yml Apply https://github.com/neo-project/neo/pull/1775 Co-authored-by: Shargon --- .github/workflows/main.yml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 0c57bda8d..989a033f7 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,7 +1,10 @@ name: .NET Core Test and Publish -on: pull_request - +on: + push: + branches: master + pull_request: + env: DOTNET_VERSION: 3.1.100 @@ -11,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v1 + uses: actions/checkout@v2 - name: Setup .NET Core uses: actions/setup-dotnet@v1 with: From d21b53790cb16103f67ba1d31c5f469387152669 Mon Sep 17 00:00:00 2001 From: HaoqiangZhang Date: Sat, 18 Jul 2020 16:54:52 +0800 Subject: [PATCH 142/183] update InvokeFunction (#295) --- src/RpcServer/RpcServer.SmartContract.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/RpcServer/RpcServer.SmartContract.cs b/src/RpcServer/RpcServer.SmartContract.cs index 2b04ad013..3bce967c7 100644 --- a/src/RpcServer/RpcServer.SmartContract.cs +++ b/src/RpcServer/RpcServer.SmartContract.cs @@ -86,8 +86,8 @@ private static Signers SignersFromJson(JArray _params) { Account = UInt160.Parse(u["account"].AsString()), Scopes = (WitnessScope)Enum.Parse(typeof(WitnessScope), u["scopes"]?.AsString()), - AllowedContracts = ((JArray)u["contracts"])?.Select(p => UInt160.Parse(p.AsString())).ToArray(), - AllowedGroups = ((JArray)u["groups"])?.Select(p => ECPoint.Parse(p.AsString(), ECCurve.Secp256r1)).ToArray() + AllowedContracts = ((JArray)u["allowedcontracts"])?.Select(p => UInt160.Parse(p.AsString())).ToArray(), + AllowedGroups = ((JArray)u["allowedgroups"])?.Select(p => ECPoint.Parse(p.AsString(), ECCurve.Secp256r1)).ToArray() }).ToArray()); // Validate format From 424a25a33a2da8fceaa91455c3702f784e36e409 Mon Sep 17 00:00:00 2001 From: Luchuan Date: Tue, 21 Jul 2020 14:12:52 +0800 Subject: [PATCH 143/183] Fix db.Seek (#291) * add db.seek ut * fix db.seek * remove ByteArrayCompare Co-authored-by: Luchuan Co-authored-by: Shargon --- src/LevelDBStore/IO/Data/LevelDB/Helper.cs | 30 ++++++++++--- src/RocksDBStore/Plugins/Storage/Snapshot.cs | 14 +++--- src/RocksDBStore/Plugins/Storage/Store.cs | 17 +++----- tests/Neo.Plugins.Storage.Tests/StoreTest.cs | 45 +++++++++++++++++++- 4 files changed, 80 insertions(+), 26 deletions(-) diff --git a/src/LevelDBStore/IO/Data/LevelDB/Helper.cs b/src/LevelDBStore/IO/Data/LevelDB/Helper.cs index 0ed2f9543..bd28be11c 100644 --- a/src/LevelDBStore/IO/Data/LevelDB/Helper.cs +++ b/src/LevelDBStore/IO/Data/LevelDB/Helper.cs @@ -10,16 +10,32 @@ public static class Helper public static IEnumerable Seek(this DB db, ReadOptions options, byte table, byte[] prefix, SeekDirection direction, Func resultSelector) { using Iterator it = db.NewIterator(options); - for (it.Seek(CreateKey(table, prefix)); it.Valid();) + byte[] target = CreateKey(table, prefix); + if (direction == SeekDirection.Forward) { - var key = it.Key(); - if (key.Length < 1 || key[0] != table) break; - yield return resultSelector(it.Key(), it.Value()); + for (it.Seek(target); it.Valid(); it.Next()) + { + var key = it.Key(); + if (key.Length < 1 || key[0] != table) break; + yield return resultSelector(it.Key(), it.Value()); + } + } + else + { + // SeekForPrev - if (direction == SeekDirection.Forward) - it.Next(); - else + it.Seek(target); + if (!it.Valid()) + it.SeekToLast(); + else if (it.Key().AsSpan().SequenceCompareTo(target) > 0) it.Prev(); + + for (; it.Valid(); it.Prev()) + { + var key = it.Key(); + if (key.Length < 1 || key[0] != table) break; + yield return resultSelector(it.Key(), it.Value()); + } } } diff --git a/src/RocksDBStore/Plugins/Storage/Snapshot.cs b/src/RocksDBStore/Plugins/Storage/Snapshot.cs index fba384598..834dbc0a3 100644 --- a/src/RocksDBStore/Plugins/Storage/Snapshot.cs +++ b/src/RocksDBStore/Plugins/Storage/Snapshot.cs @@ -43,15 +43,13 @@ public void Put(byte table, byte[] key, byte[] value) public IEnumerable<(byte[] Key, byte[] Value)> Seek(byte table, byte[] keyOrPrefix, SeekDirection direction) { using var it = db.NewIterator(store.GetFamily(table), options); - for (it.Seek(keyOrPrefix); it.Valid();) - { - yield return (it.Key(), it.Value()); - if (direction == SeekDirection.Forward) - it.Next(); - else - it.Prev(); - } + if (direction == SeekDirection.Forward) + for (it.Seek(keyOrPrefix); it.Valid(); it.Next()) + yield return (it.Key(), it.Value()); + else + for (it.SeekForPrev(keyOrPrefix); it.Valid(); it.Prev()) + yield return (it.Key(), it.Value()); } public byte[] TryGet(byte table, byte[] key) diff --git a/src/RocksDBStore/Plugins/Storage/Store.cs b/src/RocksDBStore/Plugins/Storage/Store.cs index 3cad88249..5fb255c11 100644 --- a/src/RocksDBStore/Plugins/Storage/Store.cs +++ b/src/RocksDBStore/Plugins/Storage/Store.cs @@ -82,18 +82,15 @@ public ISnapshot GetSnapshot() return new Snapshot(this, db); } - public IEnumerable<(byte[] Key, byte[] Value)> Seek(byte table, byte[] prefix, SeekDirection direction = SeekDirection.Forward) + public IEnumerable<(byte[] Key, byte[] Value)> Seek(byte table, byte[] keyOrPrefix, SeekDirection direction = SeekDirection.Forward) { using var it = db.NewIterator(GetFamily(table), Options.ReadDefault); - for (it.Seek(prefix); it.Valid();) - { - yield return (it.Key(), it.Value()); - - if (direction == SeekDirection.Forward) - it.Next(); - else - it.Prev(); - } + if (direction == SeekDirection.Forward) + for (it.Seek(keyOrPrefix); it.Valid(); it.Next()) + yield return (it.Key(), it.Value()); + else + for (it.SeekForPrev(keyOrPrefix); it.Valid(); it.Prev()) + yield return (it.Key(), it.Value()); } public byte[] TryGet(byte table, byte[] key) diff --git a/tests/Neo.Plugins.Storage.Tests/StoreTest.cs b/tests/Neo.Plugins.Storage.Tests/StoreTest.cs index ee83c8a42..d19290dc6 100644 --- a/tests/Neo.Plugins.Storage.Tests/StoreTest.cs +++ b/tests/Neo.Plugins.Storage.Tests/StoreTest.cs @@ -1,5 +1,6 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.Persistence; +using System; namespace Neo.Plugins.Storage.Tests { @@ -43,7 +44,7 @@ public void TestRocksDb() } /// - /// Test Put/Delete/TryGet + /// Test Put/Delete/TryGet/Seek /// /// Store private void TestStorage(IStore store) @@ -64,6 +65,48 @@ private void TestStorage(IStore store) ret = store.TryGet(0, new byte[] { 0x01, 0x02 }); Assert.IsNull(ret); + + // Test seek + + store.Put(1, new byte[] { 0x00, 0x00, 0x00 }, new byte[] { 0x00 }); + store.Put(1, new byte[] { 0x00, 0x00, 0x01 }, new byte[] { 0x01 }); + store.Put(1, new byte[] { 0x00, 0x00, 0x02 }, new byte[] { 0x02 }); + store.Put(1, new byte[] { 0x00, 0x00, 0x03 }, new byte[] { 0x03 }); + store.Put(1, new byte[] { 0x00, 0x00, 0x04 }, new byte[] { 0x04 }); + + // Seek Forward + + var enumerator = store.Seek(1, new byte[] { 0x00, 0x00, 0x02 }, IO.Caching.SeekDirection.Forward).GetEnumerator(); + Assert.IsTrue(enumerator.MoveNext()); + CollectionAssert.AreEqual(new byte[] { 0x00, 0x00, 0x02 }, enumerator.Current.Key); + CollectionAssert.AreEqual(new byte[] { 0x02 }, enumerator.Current.Value); + Assert.IsTrue(enumerator.MoveNext()); + CollectionAssert.AreEqual(new byte[] { 0x00, 0x00, 0x03 }, enumerator.Current.Key); + CollectionAssert.AreEqual(new byte[] { 0x03 }, enumerator.Current.Value); + + // Seek Backward + + enumerator = store.Seek(1, new byte[] { 0x00, 0x00, 0x02 }, IO.Caching.SeekDirection.Backward).GetEnumerator(); + Assert.IsTrue(enumerator.MoveNext()); + CollectionAssert.AreEqual(new byte[] { 0x00, 0x00, 0x02 }, enumerator.Current.Key); + CollectionAssert.AreEqual(new byte[] { 0x02 }, enumerator.Current.Value); + Assert.IsTrue(enumerator.MoveNext()); + CollectionAssert.AreEqual(new byte[] { 0x00, 0x00, 0x01 }, enumerator.Current.Key); + CollectionAssert.AreEqual(new byte[] { 0x01 }, enumerator.Current.Value); + + // Seek Backward + + store.Put(2, new byte[] { 0x00, 0x00, 0x00 }, new byte[] { 0x00 }); + store.Put(2, new byte[] { 0x00, 0x00, 0x01 }, new byte[] { 0x01 }); + store.Put(2, new byte[] { 0x00, 0x01, 0x02 }, new byte[] { 0x02 }); + + enumerator = store.Seek(2, new byte[] { 0x00, 0x00, 0x03 }, IO.Caching.SeekDirection.Backward).GetEnumerator(); + Assert.IsTrue(enumerator.MoveNext()); + CollectionAssert.AreEqual(new byte[] { 0x00, 0x00, 0x01 }, enumerator.Current.Key); + CollectionAssert.AreEqual(new byte[] { 0x01 }, enumerator.Current.Value); + Assert.IsTrue(enumerator.MoveNext()); + CollectionAssert.AreEqual(new byte[] { 0x00, 0x00, 0x00 }, enumerator.Current.Key); + CollectionAssert.AreEqual(new byte[] { 0x00 }, enumerator.Current.Value); } } From b0ed3f26dfb7ae466b0a033eb9fe80330c40cf76 Mon Sep 17 00:00:00 2001 From: HaoqiangZhang Date: Tue, 21 Jul 2020 15:11:53 +0800 Subject: [PATCH 144/183] update RpcClient (#296) * update RpcClient * fix sln * fix format * fix format Co-authored-by: Owen Zhang <38493437+superboyiii@users.noreply.github.com> --- src/RpcClient/ContractClient.cs | 7 +- src/RpcClient/Nep5API.cs | 12 +- src/RpcClient/RpcClient.cs | 12 +- src/RpcClient/RpcClient.csproj | 2 +- src/RpcClient/TransactionManager.cs | 19 +-- src/RpcClient/Utility.cs | 7 +- tests/Neo.Network.RPC.Tests/RpcTestCases.json | 125 ++++++++++-------- tests/Neo.Network.RPC.Tests/TestUtils.cs | 2 +- .../UT_ContractClient.cs | 1 + .../UT_TransactionManager.cs | 79 +++++++---- 10 files changed, 158 insertions(+), 108 deletions(-) diff --git a/src/RpcClient/ContractClient.cs b/src/RpcClient/ContractClient.cs index 3ae7ec22d..0aa3aff3b 100644 --- a/src/RpcClient/ContractClient.cs +++ b/src/RpcClient/ContractClient.cs @@ -51,10 +51,11 @@ public Transaction CreateDeployContractTx(byte[] contractScript, ContractManifes sb.EmitSysCall(ApplicationEngine.System_Contract_Create, contractScript, manifest.ToString()); script = sb.ToArray(); } - UInt160 sender = Contract.CreateSignatureRedeemScript(key.PublicKey).ToScriptHash(); - Transaction tx = new TransactionManager(rpcClient, sender) - .MakeTransaction(script, null) + Signer[] signers = new[] { new Signer { Scopes = WitnessScope.CalledByEntry, Account = sender } }; + + Transaction tx = new TransactionManager(rpcClient) + .MakeTransaction(script, signers) .AddSignature(key) .Sign() .Tx; diff --git a/src/RpcClient/Nep5API.cs b/src/RpcClient/Nep5API.cs index da8bc59e0..fc1616126 100644 --- a/src/RpcClient/Nep5API.cs +++ b/src/RpcClient/Nep5API.cs @@ -108,11 +108,11 @@ public RpcNep5TokenInfo GetTokenInfo(UInt160 scriptHash) public Transaction CreateTransferTx(UInt160 scriptHash, KeyPair fromKey, UInt160 to, BigInteger amount) { var sender = Contract.CreateSignatureRedeemScript(fromKey.PublicKey).ToScriptHash(); - Cosigner[] cosigners = new[] { new Cosigner { Scopes = WitnessScope.CalledByEntry, Account = sender } }; + Signer[] signers = new[] { new Signer { Scopes = WitnessScope.CalledByEntry, Account = sender } }; byte[] script = scriptHash.MakeScript("transfer", sender, to, amount); - Transaction tx = new TransactionManager(rpcClient, sender) - .MakeTransaction(script, cosigners) + Transaction tx = new TransactionManager(rpcClient) + .MakeTransaction(script, signers) .AddSignature(fromKey) .Sign() .Tx; @@ -135,11 +135,11 @@ public Transaction CreateTransferTx(UInt160 scriptHash, int m, ECPoint[] pubKeys if (m > fromKeys.Length) throw new ArgumentException($"Need at least {m} KeyPairs for signing!"); var sender = Contract.CreateMultiSigContract(m, pubKeys).ScriptHash; - Cosigner[] cosigners = new[] { new Cosigner { Scopes = WitnessScope.CalledByEntry, Account = sender } }; + Signer[] signers = new[] { new Signer { Scopes = WitnessScope.CalledByEntry, Account = sender } }; byte[] script = scriptHash.MakeScript("transfer", sender, to, amount); - Transaction tx = new TransactionManager(rpcClient, sender) - .MakeTransaction(script, cosigners) + Transaction tx = new TransactionManager(rpcClient) + .MakeTransaction(script, signers) .AddMultiSig(fromKeys, m, pubKeys) .Sign() .Tx; diff --git a/src/RpcClient/RpcClient.cs b/src/RpcClient/RpcClient.cs index 35f7500f4..6448178e2 100644 --- a/src/RpcClient/RpcClient.cs +++ b/src/RpcClient/RpcClient.cs @@ -316,12 +316,12 @@ public UInt256 SubmitBlock(byte[] block) /// Returns the result after calling a smart contract at scripthash with the given operation and parameters. /// This RPC call does not affect the blockchain in any way. /// - public RpcInvokeResult InvokeFunction(string scriptHash, string operation, RpcStack[] stacks, params UInt160[] scriptHashesForVerifying) + public RpcInvokeResult InvokeFunction(string scriptHash, string operation, RpcStack[] stacks, params Signer[] signer) { List parameters = new List { scriptHash, operation, stacks.Select(p => p.ToJson()).ToArray() }; - if (scriptHashesForVerifying.Length > 0) + if (signer.Length > 0) { - parameters.Add(scriptHashesForVerifying.Select(p => (JObject)p.ToString()).ToArray()); + parameters.Add(signer.Select(p => (JObject)p.ToJson()).ToArray()); } return RpcInvokeResult.FromJson(RpcSend("invokefunction", parameters.ToArray())); } @@ -330,12 +330,12 @@ public RpcInvokeResult InvokeFunction(string scriptHash, string operation, RpcSt /// Returns the result after passing a script through the VM. /// This RPC call does not affect the blockchain in any way. /// - public RpcInvokeResult InvokeScript(byte[] script, params UInt160[] scriptHashesForVerifying) + public RpcInvokeResult InvokeScript(byte[] script, params Signer[] signers) { List parameters = new List { script.ToHexString() }; - if (scriptHashesForVerifying.Length > 0) + if (signers.Length > 0) { - parameters.Add(scriptHashesForVerifying.Select(p => (JObject)p.ToString()).ToArray()); + parameters.Add(signers.Select(p => p.ToJson()).ToArray()); } return RpcInvokeResult.FromJson(RpcSend("invokescript", parameters.ToArray())); } diff --git a/src/RpcClient/RpcClient.csproj b/src/RpcClient/RpcClient.csproj index 2d520e052..a8b93604a 100644 --- a/src/RpcClient/RpcClient.csproj +++ b/src/RpcClient/RpcClient.csproj @@ -14,7 +14,7 @@ - + diff --git a/src/RpcClient/TransactionManager.cs b/src/RpcClient/TransactionManager.cs index 11e273b5e..cd7fe1e1f 100644 --- a/src/RpcClient/TransactionManager.cs +++ b/src/RpcClient/TransactionManager.cs @@ -19,7 +19,6 @@ public class TransactionManager private readonly RpcClient rpcClient; private readonly PolicyAPI policyAPI; private readonly Nep5API nep5API; - private readonly UInt160 sender; private class SignItem { public Contract Contract; public HashSet KeyPairs; } @@ -43,12 +42,11 @@ private class SignItem { public Contract Contract; public HashSet KeyPa /// /// the RPC client to call NEO RPC API /// the account script hash of sender - public TransactionManager(RpcClient rpc, UInt160 sender) + public TransactionManager(RpcClient rpc) { rpcClient = rpc; policyAPI = new PolicyAPI(rpc); nep5API = new Nep5API(rpc); - this.sender = sender; } /// @@ -57,7 +55,7 @@ public TransactionManager(RpcClient rpc, UInt160 sender) /// Transaction Script /// Transaction Attributes /// - public TransactionManager MakeTransaction(byte[] script, TransactionAttribute[] attributes = null) + public TransactionManager MakeTransaction(byte[] script, Signer[] signers = null, TransactionAttribute[] attributes = null) { var random = new Random(); uint height = rpcClient.GetBlockCount() - 1; @@ -66,15 +64,12 @@ public TransactionManager MakeTransaction(byte[] script, TransactionAttribute[] Version = 0, Nonce = (uint)random.Next(), Script = script, - Sender = sender, + Signers = signers, ValidUntilBlock = height + Transaction.MaxValidUntilBlockIncrement, Attributes = attributes ?? Array.Empty(), - Witnesses = Array.Empty() }; - // Add witness hashes parameter to pass CheckWitness - UInt160[] hashes = Tx.GetScriptHashesForVerifying(null); - RpcInvokeResult result = rpcClient.InvokeScript(script, hashes); + RpcInvokeResult result = rpcClient.InvokeScript(script, signers); Tx.SystemFee = long.Parse(result.GasConsumed); context = new ContractParametersContext(Tx); signStore = new List(); @@ -90,7 +85,7 @@ private long CalculateNetworkFee() { long networkFee = 0; UInt160[] hashes = Tx.GetScriptHashesForVerifying(null); - int size = Transaction.HeaderSize + Tx.Attributes.GetVarSize() + Tx.Script.GetVarSize() + IO.Helper.GetVarSize(hashes.Length); + int size = Transaction.HeaderSize + Tx.Signers.GetVarSize() + Tx.Attributes.GetVarSize() + Tx.Script.GetVarSize() + IO.Helper.GetVarSize(hashes.Length); foreach (UInt160 hash in hashes) { byte[] witness_script = null; @@ -203,9 +198,9 @@ public TransactionManager Sign() { // Calculate NetworkFee Tx.NetworkFee = CalculateNetworkFee(); - var gasBalance = nep5API.BalanceOf(NativeContract.GAS.Hash, sender); + var gasBalance = nep5API.BalanceOf(NativeContract.GAS.Hash, Tx.Sender); if (gasBalance < Tx.SystemFee + Tx.NetworkFee) - throw new InvalidOperationException($"Insufficient GAS in address: {sender.ToAddress()}"); + throw new InvalidOperationException($"Insufficient GAS in address: {Tx.Sender.ToAddress()}"); // Sign with signStore foreach (var item in signStore) diff --git a/src/RpcClient/Utility.cs b/src/RpcClient/Utility.cs index beb4eb4f4..cff72fd78 100644 --- a/src/RpcClient/Utility.cs +++ b/src/RpcClient/Utility.cs @@ -119,7 +119,7 @@ public static Transaction TransactionFromJson(JObject json) Transaction tx = new Transaction(); tx.Version = byte.Parse(json["version"].AsString()); tx.Nonce = uint.Parse(json["nonce"].AsString()); - tx.Sender = json["sender"].AsString().ToScriptHash(); + tx.Signers = ((JArray)json["signers"]).Select(p => SignerFromJson(p)).ToArray(); tx.SystemFee = long.Parse(json["sysfee"].AsString()); tx.NetworkFee = long.Parse(json["netfee"].AsString()); tx.ValidUntilBlock = uint.Parse(json["validuntilblock"].AsString()); @@ -137,9 +137,9 @@ public static Header HeaderFromJson(JObject json) return header; } - public static Cosigner CosignerFromJson(JObject json) + public static Signer SignerFromJson(JObject json) { - return new Cosigner + return new Signer { Account = UInt160.Parse(json["account"].AsString()), Scopes = (WitnessScope)Enum.Parse(typeof(WitnessScope), json["scopes"].AsString()), @@ -162,7 +162,6 @@ public static TransactionAttribute TransactionAttributeFromJson(JObject json) switch (usage) { - case TransactionAttributeType.Cosigner: return CosignerFromJson(json); default: throw new FormatException(); } } diff --git a/tests/Neo.Network.RPC.Tests/RpcTestCases.json b/tests/Neo.Network.RPC.Tests/RpcTestCases.json index 644654b96..d364a71d3 100644 --- a/tests/Neo.Network.RPC.Tests/RpcTestCases.json +++ b/tests/Neo.Network.RPC.Tests/RpcTestCases.json @@ -4,7 +4,7 @@ "Request": { "jsonrpc": "2.0", "method": "sendrawtransaction", - "params": [ "00b5077e7bb8cef712d3f9b3ec90d36e7bf8d50ac81718a3b000e1f5050000000080778e0600000000e3142000005c0300e40b54020000000c1400000000000000000000000000000000000000000c14b8cef712d3f9b3ec90d36e7bf8d50ac81718a3b013c00c087472616e736665720c143b7d3711c6f0ccf9b1dca903d1bfa1d896f1238c41627d5b5201420c4077a5ffdc41dce3b06418879a26bac0fcea06af4a833446c90f63a3e80b85d13e07ca9084989e7c7e4535187409058dc7233ba8ee4638593605134e2c2c8f3c9f290c2102f9ec1fd0a98796cf75b586772a4ddd41a0af07a1dbdf86a7238f74fb725035750b410a906ad4" ], + "params": [ "0089d9a541587389000000000046e71300000000007b212000011c0357464b777ecf6b5f3ac3893ace1f8b1621f6100325059ecb4878d3a875f91c51ceded330d4575fdee3137eddba5f6485cad334a79bdb67c43273171fbcaf41d684c7d4ad6ee0d99da9707b9d1f0c8e660054180c14e3137eddba5f6485cad334a79bdb67c43273171f0c141c0357464b777ecf6b5f3ac3893ace1f8b1621f613c00c087472616e736665720c14bcaf41d684c7d4ad6ee0d99da9707b9d1f0c8e6641627d5b5201420c40b90107fe5d251a9ef10b22c3bb0d329c0fa8f1d0d1aab8ad430837c069cc2818887c4c387319a55837d72c997f6112698acf80c346c9bb4638d78b0c2623778c290c210222d8515184c7d62ffa99b829aeb4938c4704ecb0dd7e340e842e9df1218263430b4195440d78" ], "id": 1 }, "Response": { @@ -64,53 +64,59 @@ "Request": { "jsonrpc": "2.0", "method": "getblock", - "params": [ 0, true ], + "params": [ 7, true ], "id": 1 }, "Response": { "jsonrpc": "2.0", "id": 1, "result": { - "hash": "0xe191fe1aea732c3e23f20af8a95e09f95891176f8064a2fce8571d51f80619a8", - "size": 170, + "hash": "0x78057f73c5755db691e690746dd76a6e370b426f18664cab3721897d72e72209", + "size": 470, "version": 0, - "previousblockhash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "merkleroot": "0x735b68ca1bab490b8fd6166cba4c2ce76e97bedfe4d2df0c333970fc9862bb2b", - "time": 1468595301000, - "index": 0, - "nextconsensus": "NZs2zXSPuuv9ZF6TDGSWT1RBmE8rfGj7UW", + "previousblockhash": "0xaae8867e9086afaf06fd02cc538e88a69b801abd6f9d3ae39ae630e29d5b39e2", + "merkleroot": "0xe95761f21c733ad53066786af24ee5d613b32bd5aae538df2d611492ec0cae82", + "time": 1594867377561, + "index": 7, + "nextconsensus": "NikvsLcNP1jWhrFPrfS3n4spEASgdNYTG2", "witnesses": [ { - "invocation": "", - "verification": "EQ==" + "invocation": "DEBs6hZDHUtL7KOJuF1m8/vITM8VeduwegKhBdbqcLKdBzXA1uZZiBl8jM/rhjXBaIGQSFIQuq8Er1Nb5y5/DWUx", + "verification": "EQwhAqnqaELMDLOw8jF7B8hQ3j0eKyQ6mO0tVqP/TKZqrzMLEQtBE43vrw==" } ], "consensusdata": { "primary": 0, - "nonce": "000000007c2bac1d" + "nonce": "83603a05111390a7" }, "tx": [ { - "hash": "0x55808e2014b486a607a4617c81a6f5060ec363eff6cfc80210221b2e8a1f1013", - "size": 56, + "hash": "0x0a76a72fb4958c7f3940410225a5d0f63b50153136cbf3015c38391b92034c5d", + "size": 248, "version": 0, - "nonce": 0, - "sender": "NeN4xPMn4kHoj7G8Lciq9oorgLTvqt4qi1", - "sysfee": "0", - "netfee": "0", - "validuntilblock": 0, + "nonce": 631973574, + "sender": "NikvsLcNP1jWhrFPrfS3n4spEASgdNYTG2", + "sysfee": "9007990", + "netfee": "1248450", + "validuntilblock": 2102405, + "signers": [ + { + "account": "0xe19de267a37a71734478f512b3e92c79fc3695fa", + "scopes": "CalledByEntry" + } + ], "attributes": [], - "script": "QRI+f+g=", + "script": "AccyDBQcA1dGS3d+z2tfOsOJOs4fixYh9gwU+pU2/Hks6bMS9XhEc3F6o2fineETwAwIdHJhbnNmZXIMFCUFnstIeNOodfkcUc7e0zDUV1/eQWJ9W1I4", "witnesses": [ { - "invocation": "", - "verification": "EQ==" + "invocation": "DEDZxkskUb1aH1I4EX5ja02xrYX4fCubAmQzBuPpfY7pDEb1n4Dzx+UB+qSdC/CGskGf5BuzJ0MWJJipsHuivKmU", + "verification": "EQwhAqnqaELMDLOw8jF7B8hQ3j0eKyQ6mO0tVqP/TKZqrzMLEQtBE43vrw==" } ] } ], - "confirmations": 2671, - "nextblockhash": "0x423173109798b038019b35129417b55cc4b5976ac79978dfab8ea2512d155f69" + "confirmations": 695, + "nextblockhash": "0xc4b986813396932a47d6823a9987ccee0148c6fca0150102f4b24ce05cfc9c6f" } } }, @@ -119,53 +125,59 @@ "Request": { "jsonrpc": "2.0", "method": "getblock", - "params": [ "0xe191fe1aea732c3e23f20af8a95e09f95891176f8064a2fce8571d51f80619a8", true ], + "params": [ "0x78057f73c5755db691e690746dd76a6e370b426f18664cab3721897d72e72209", true ], "id": 1 }, "Response": { "jsonrpc": "2.0", "id": 1, "result": { - "hash": "0xe191fe1aea732c3e23f20af8a95e09f95891176f8064a2fce8571d51f80619a8", - "size": 170, + "hash": "0x78057f73c5755db691e690746dd76a6e370b426f18664cab3721897d72e72209", + "size": 470, "version": 0, - "previousblockhash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "merkleroot": "0x735b68ca1bab490b8fd6166cba4c2ce76e97bedfe4d2df0c333970fc9862bb2b", - "time": 1468595301000, - "index": 0, - "nextconsensus": "NZs2zXSPuuv9ZF6TDGSWT1RBmE8rfGj7UW", + "previousblockhash": "0xaae8867e9086afaf06fd02cc538e88a69b801abd6f9d3ae39ae630e29d5b39e2", + "merkleroot": "0xe95761f21c733ad53066786af24ee5d613b32bd5aae538df2d611492ec0cae82", + "time": 1594867377561, + "index": 7, + "nextconsensus": "NikvsLcNP1jWhrFPrfS3n4spEASgdNYTG2", "witnesses": [ { - "invocation": "", - "verification": "EQ==" + "invocation": "DEBs6hZDHUtL7KOJuF1m8/vITM8VeduwegKhBdbqcLKdBzXA1uZZiBl8jM/rhjXBaIGQSFIQuq8Er1Nb5y5/DWUx", + "verification": "EQwhAqnqaELMDLOw8jF7B8hQ3j0eKyQ6mO0tVqP/TKZqrzMLEQtBE43vrw==" } ], "consensusdata": { "primary": 0, - "nonce": "000000007c2bac1d" + "nonce": "83603a05111390a7" }, "tx": [ { - "hash": "0x55808e2014b486a607a4617c81a6f5060ec363eff6cfc80210221b2e8a1f1013", - "size": 56, + "hash": "0x0a76a72fb4958c7f3940410225a5d0f63b50153136cbf3015c38391b92034c5d", + "size": 248, "version": 0, - "nonce": 0, - "sender": "NeN4xPMn4kHoj7G8Lciq9oorgLTvqt4qi1", - "sysfee": "0", - "netfee": "0", - "validuntilblock": 0, + "nonce": 631973574, + "sender": "NikvsLcNP1jWhrFPrfS3n4spEASgdNYTG2", + "sysfee": "9007990", + "netfee": "1248450", + "validuntilblock": 2102405, + "signers": [ + { + "account": "0xe19de267a37a71734478f512b3e92c79fc3695fa", + "scopes": "CalledByEntry" + } + ], "attributes": [], - "script": "QRI+f+g=", + "script": "AccyDBQcA1dGS3d+z2tfOsOJOs4fixYh9gwU+pU2/Hks6bMS9XhEc3F6o2fineETwAwIdHJhbnNmZXIMFCUFnstIeNOodfkcUc7e0zDUV1/eQWJ9W1I4", "witnesses": [ { - "invocation": "", - "verification": "EQ==" + "invocation": "DEDZxkskUb1aH1I4EX5ja02xrYX4fCubAmQzBuPpfY7pDEb1n4Dzx+UB+qSdC/CGskGf5BuzJ0MWJJipsHuivKmU", + "verification": "EQwhAqnqaELMDLOw8jF7B8hQ3j0eKyQ6mO0tVqP/TKZqrzMLEQtBE43vrw==" } ] } ], - "confirmations": 2671, - "nextblockhash": "0x423173109798b038019b35129417b55cc4b5976ac79978dfab8ea2512d155f69" + "confirmations": 695, + "nextblockhash": "0xc4b986813396932a47d6823a9987ccee0148c6fca0150102f4b24ce05cfc9c6f" } } }, @@ -322,6 +334,9 @@ "storage": true, "payable": true }, + "supportedstandards": [ + "NEP-5" + ], "abi": { "hash": "0x806b7fa0db3b46d6c42e1e1b0a7fd50db9d4a9b0", "methods": [ @@ -493,21 +508,27 @@ "Request": { "jsonrpc": "2.0", "method": "getrawtransaction", - "params": [ "0x4d47255ff5564aaa73855068c3574f8f28e2bb18c7fb7256e58ae51fab44c9bc", true ], + "params": [ "0xc97cc05c790a844f05f582d80952c4ced3894cbe6d96a74f3e5589d741372dd4", true ], "id": 1 }, "Response": { "jsonrpc": "2.0", "id": 1, "result": { - "hash": "0x4d47255ff5564aaa73855068c3574f8f28e2bb18c7fb7256e58ae51fab44c9bc", - "size": 250, + "hash": "0xc97cc05c790a844f05f582d80952c4ced3894cbe6d96a74f3e5589d741372dd4", + "size": 252, "version": 0, "nonce": 969006668, - "sender": "NVVwFw6XyhtRCFQ8SpUTMdPyYt4Vd9A1XQ", + "sender": "NikvsLcNP1jWhrFPrfS3n4spEASgdNYTG2", "sysfee": "100000000", "netfee": "1272390", "validuntilblock": 2104625, + "signers": [ + { + "account": "0xe19de267a37a71734478f512b3e92c79fc3695fa", + "scopes": "CalledByEntry" + } + ], "attributes": [], "script": "AwAQpdToAAAADBSZA7DD0pKYj+vl8wagL2VOousWKQwUaSWqVUcSQ5qcYTuhFO+j+sI928oTwAwIdHJhbnNmZXIMFDt9NxHG8Mz5sdypA9G/odiW8SOMQWJ9W1I5", "witnesses": [ @@ -657,7 +678,7 @@ "Request": { "jsonrpc": "2.0", "method": "sendrawtransaction", - "params": [ "00142449186925aa554712439a9c613ba114efa3fac23ddbca00e1f50500000000a65a1300000000001d20200000590200e1f5050c149903b0c3d292988febe5f306a02f654ea2eb16290c146925aa554712439a9c613ba114efa3fac23ddbca13c00c087472616e736665720c143b7d3711c6f0ccf9b1dca903d1bfa1d896f1238c41627d5b523901420c4076507ef5922e84aac57f09cb699ecbb10bc3d9c06ef908bed812c35fd2651531de27091f1e6e81566454fcc1c5f129d1051b08704c3fec3f6ed793563cfd30bb290c2103aa052fbcb8e5b33a4eefd662536f8684641f04109f1d5e69cdda6f084890286a0b410a906ad4" ], + "params": [ "0089d9a541587389000000000046e71300000000007b212000011c0357464b777ecf6b5f3ac3893ace1f8b1621f6100325059ecb4878d3a875f91c51ceded330d4575fdee3137eddba5f6485cad334a79bdb67c43273171fbcaf41d684c7d4ad6ee0d99da9707b9d1f0c8e660054180c14e3137eddba5f6485cad334a79bdb67c43273171f0c141c0357464b777ecf6b5f3ac3893ace1f8b1621f613c00c087472616e736665720c14bcaf41d684c7d4ad6ee0d99da9707b9d1f0c8e6641627d5b5201420c40b90107fe5d251a9ef10b22c3bb0d329c0fa8f1d0d1aab8ad430837c069cc2818887c4c387319a55837d72c997f6112698acf80c346c9bb4638d78b0c2623778c290c210222d8515184c7d62ffa99b829aeb4938c4704ecb0dd7e340e842e9df1218263430b4195440d78" ], "id": 1 }, "Response": { diff --git a/tests/Neo.Network.RPC.Tests/TestUtils.cs b/tests/Neo.Network.RPC.Tests/TestUtils.cs index 582715022..53893264a 100644 --- a/tests/Neo.Network.RPC.Tests/TestUtils.cs +++ b/tests/Neo.Network.RPC.Tests/TestUtils.cs @@ -38,7 +38,7 @@ public static Transaction GetTransaction() return new Transaction { Script = new byte[1], - Sender = UInt160.Zero, + Signers = new Signer[] { new Signer { Account = UInt160.Zero } }, Attributes = new TransactionAttribute[0], Witnesses = new Witness[] { diff --git a/tests/Neo.Network.RPC.Tests/UT_ContractClient.cs b/tests/Neo.Network.RPC.Tests/UT_ContractClient.cs index 6fa4feb7e..0e84afa3d 100644 --- a/tests/Neo.Network.RPC.Tests/UT_ContractClient.cs +++ b/tests/Neo.Network.RPC.Tests/UT_ContractClient.cs @@ -51,6 +51,7 @@ public void TestDeployContract() Groups = new ContractGroup[0], SafeMethods = WildcardContainer.Create(), Trusts = WildcardContainer.Create(), + SupportedStandards = new string[] { "NEP-10" }, Extra = null, }; manifest.Features = ContractFeatures.HasStorage | ContractFeatures.Payable; diff --git a/tests/Neo.Network.RPC.Tests/UT_TransactionManager.cs b/tests/Neo.Network.RPC.Tests/UT_TransactionManager.cs index d027b0790..1f4da3250 100644 --- a/tests/Neo.Network.RPC.Tests/UT_TransactionManager.cs +++ b/tests/Neo.Network.RPC.Tests/UT_TransactionManager.cs @@ -10,6 +10,7 @@ using Neo.SmartContract.Native; using Neo.VM; using Neo.Wallets; +using Neo.Wallets.NEP6; using System; using System.Linq; using System.Numerics; @@ -21,9 +22,11 @@ public class UT_TransactionManager { TransactionManager txManager; Mock rpcClientMock; + Mock multiSigMock; KeyPair keyPair1; KeyPair keyPair2; UInt160 sender; + UInt160 multiHash; [TestInitialize] public void TestSetup() @@ -31,7 +34,9 @@ public void TestSetup() keyPair1 = new KeyPair(Wallet.GetPrivateKeyFromWIF("KyXwTh1hB76RRMquSvnxZrJzQx7h9nQP2PCRL38v6VDb5ip3nf1p")); keyPair2 = new KeyPair(Wallet.GetPrivateKeyFromWIF("L2LGkrwiNmUAnWYb1XGd5mv7v2eDf6P4F3gHyXSrNJJR4ArmBp7Q")); sender = Contract.CreateSignatureRedeemScript(keyPair1.PublicKey).ToScriptHash(); + multiHash = Contract.CreateMultiSigContract(2, keyPair1.PublicKey, keyPair2.PublicKey).ScriptHash; rpcClientMock = MockRpcClient(sender, new byte[1]); + multiSigMock = MockMultiSig(multiHash, new byte[1]); } public static Mock MockRpcClient(UInt160 sender, byte[] script) @@ -60,6 +65,32 @@ public static Mock MockRpcClient(UInt160 sender, byte[] script) return mockRpc; } + public static Mock MockMultiSig(UInt160 multiHash, byte[] script) + { + var mockRpc = new Mock(MockBehavior.Strict, "http://seed1.neo.org:10331", null, null); + + // MockHeight + mockRpc.Setup(p => p.RpcSend("getblockcount")).Returns(100).Verifiable(); + + // MockGasBalance + byte[] balanceScript = NativeContract.GAS.Hash.MakeScript("balanceOf", multiHash); + var balanceResult = new ContractParameter() { Type = ContractParameterType.Integer, Value = BigInteger.Parse("10000000000000000") }; + + MockInvokeScript(mockRpc, balanceScript, balanceResult); + + // MockFeePerByte + byte[] policyScript = NativeContract.Policy.Hash.MakeScript("getFeePerByte"); + var policyResult = new ContractParameter() { Type = ContractParameterType.Integer, Value = BigInteger.Parse("1000") }; + + MockInvokeScript(mockRpc, policyScript, policyResult); + + // MockGasConsumed + var result = new ContractParameter(); + MockInvokeScript(mockRpc, script, result); + + return mockRpc; + } + public static void MockInvokeScript(Mock mockClient, byte[] script, params ContractParameter[] parameters) { var result = new RpcInvokeResult() @@ -78,11 +109,11 @@ public static void MockInvokeScript(Mock mockClient, byte[] script, p [TestMethod] public void TestMakeTransaction() { - txManager = new TransactionManager(rpcClientMock.Object, sender); + txManager = new TransactionManager(rpcClientMock.Object); - var attributes = new TransactionAttribute[1] + Signer[] signers = new Signer[1] { - new Cosigner + new Signer { Account = sender, Scopes= WitnessScope.Global @@ -90,20 +121,20 @@ public void TestMakeTransaction() }; byte[] script = new byte[1]; - txManager.MakeTransaction(script, attributes); + txManager.MakeTransaction(script, signers); var tx = txManager.Tx; - Assert.AreEqual(WitnessScope.Global, (tx.Attributes[0] as Cosigner).Scopes); + Assert.AreEqual(WitnessScope.Global, tx.Signers[0].Scopes); } [TestMethod] public void TestSign() { - txManager = new TransactionManager(rpcClientMock.Object, sender); + txManager = new TransactionManager(rpcClientMock.Object); - var attributes = new TransactionAttribute[1] + Signer[] signers = new Signer[1] { - new Cosigner + new Signer { Account = sender, Scopes = WitnessScope.Global @@ -111,7 +142,7 @@ public void TestSign() }; byte[] script = new byte[1]; - txManager.MakeTransaction(script, attributes) + txManager.MakeTransaction(script, signers) .AddSignature(keyPair1) .Sign(); @@ -136,37 +167,39 @@ public void TestSign() [TestMethod] public void TestSignMulti() { - txManager = new TransactionManager(rpcClientMock.Object, sender); - - var multiContract = Contract.CreateMultiSigContract(2, keyPair1.PublicKey, keyPair2.PublicKey); + txManager = new TransactionManager(multiSigMock.Object); // Cosigner needs multi signature - Cosigner[] cosigners = new Cosigner[1] + Signer[] signers = new Signer[1] { - new Cosigner + new Signer { - Account = multiContract.ScriptHash, + Account = multiHash, Scopes = WitnessScope.Global } }; byte[] script = new byte[1]; - txManager.MakeTransaction(script, cosigners) + txManager.MakeTransaction(script, signers) .AddMultiSig(keyPair1, 2, keyPair1.PublicKey, keyPair2.PublicKey) .AddMultiSig(keyPair2, 2, keyPair1.PublicKey, keyPair2.PublicKey) - .AddSignature(keyPair1) .Sign(); } [TestMethod] public void TestAddWitness() { - txManager = new TransactionManager(rpcClientMock.Object, sender); + txManager = new TransactionManager(rpcClientMock.Object); // Cosigner as contract scripthash - Cosigner[] cosigners = new Cosigner[1] + Signer[] signers = new Signer[2] { - new Cosigner + new Signer + { + Account = sender, + Scopes = WitnessScope.Global + }, + new Signer { Account = UInt160.Zero, Scopes = WitnessScope.Global @@ -174,15 +207,15 @@ public void TestAddWitness() }; byte[] script = new byte[1]; - txManager.MakeTransaction(script, cosigners); + txManager.MakeTransaction(script, signers); txManager.AddWitness(UInt160.Zero); txManager.AddSignature(keyPair1); txManager.Sign(); var tx = txManager.Tx; Assert.AreEqual(2, tx.Witnesses.Length); - Assert.AreEqual(0, tx.Witnesses[0].VerificationScript.Length); - Assert.AreEqual(0, tx.Witnesses[0].InvocationScript.Length); + Assert.AreEqual(41, tx.Witnesses[0].VerificationScript.Length); + Assert.AreEqual(66, tx.Witnesses[0].InvocationScript.Length); } } } From 612b4cbbc845e42536f41b58a2461a1d75bf61f9 Mon Sep 17 00:00:00 2001 From: Luchuan Date: Wed, 29 Jul 2020 10:43:04 +0800 Subject: [PATCH 145/183] Add Utility.StackItemFromJson (#302) * fix invoke tojson * add StackItemFromJson * optimize code * remove src/RpcClientTests/UtilityTests.cs Co-authored-by: Luchuan --- src/RpcClient/Models/RpcInvokeResult.cs | 7 +- src/RpcClient/Nep5API.cs | 18 ++--- src/RpcClient/PolicyAPI.cs | 8 +-- src/RpcClient/Utility.cs | 43 ++++++++++++ src/RpcClient/WalletAPI.cs | 2 +- tests/Neo.Network.RPC.Tests/RpcTestCases.json | 70 +++++++++++++++---- .../UT_ContractClient.cs | 2 +- .../UT_TransactionManager.cs | 2 +- 8 files changed, 119 insertions(+), 33 deletions(-) diff --git a/src/RpcClient/Models/RpcInvokeResult.cs b/src/RpcClient/Models/RpcInvokeResult.cs index eeae4518c..67fb81e9a 100644 --- a/src/RpcClient/Models/RpcInvokeResult.cs +++ b/src/RpcClient/Models/RpcInvokeResult.cs @@ -1,5 +1,6 @@ using Neo.IO.Json; -using Neo.SmartContract; +using Neo.VM; +using Neo.VM.Types; using System; using System.Linq; @@ -13,7 +14,7 @@ public class RpcInvokeResult public string GasConsumed { get; set; } - public ContractParameter[] Stack { get; set; } + public StackItem[] Stack { get; set; } public string Tx { get; set; } @@ -44,7 +45,7 @@ public static RpcInvokeResult FromJson(JObject json) invokeScriptResult.GasConsumed = json["gasconsumed"].AsString(); try { - invokeScriptResult.Stack = ((JArray)json["stack"]).Select(p => ContractParameter.FromJson(p)).ToArray(); + invokeScriptResult.Stack = ((JArray)json["stack"]).Select(p => Utility.StackItemFromJson(p)).ToArray(); } catch { } invokeScriptResult.Tx = json["tx"]?.AsString(); diff --git a/src/RpcClient/Nep5API.cs b/src/RpcClient/Nep5API.cs index fc1616126..c700d5c68 100644 --- a/src/RpcClient/Nep5API.cs +++ b/src/RpcClient/Nep5API.cs @@ -30,7 +30,7 @@ public Nep5API(RpcClient rpcClient) : base(rpcClient) { } /// public BigInteger BalanceOf(UInt160 scriptHash, UInt160 account) { - BigInteger balance = TestInvoke(scriptHash, "balanceOf", account).Stack.Single().ToStackItem().GetInteger(); + BigInteger balance = TestInvoke(scriptHash, "balanceOf", account).Stack.Single().GetInteger(); return balance; } @@ -41,7 +41,7 @@ public BigInteger BalanceOf(UInt160 scriptHash, UInt160 account) /// public string Name(UInt160 scriptHash) { - return TestInvoke(scriptHash, "name").Stack.Single().ToStackItem().GetString(); + return TestInvoke(scriptHash, "name").Stack.Single().GetString(); } /// @@ -51,7 +51,7 @@ public string Name(UInt160 scriptHash) /// public string Symbol(UInt160 scriptHash) { - return TestInvoke(scriptHash, "symbol").Stack.Single().ToStackItem().GetString(); + return TestInvoke(scriptHash, "symbol").Stack.Single().GetString(); } /// @@ -61,7 +61,7 @@ public string Symbol(UInt160 scriptHash) /// public byte Decimals(UInt160 scriptHash) { - return (byte)TestInvoke(scriptHash, "decimals").Stack.Single().ToStackItem().GetInteger(); + return (byte)TestInvoke(scriptHash, "decimals").Stack.Single().GetInteger(); } /// @@ -71,7 +71,7 @@ public byte Decimals(UInt160 scriptHash) /// public BigInteger TotalSupply(UInt160 scriptHash) { - return TestInvoke(scriptHash, "totalSupply").Stack.Single().ToStackItem().GetInteger(); + return TestInvoke(scriptHash, "totalSupply").Stack.Single().GetInteger(); } /// @@ -90,10 +90,10 @@ public RpcNep5TokenInfo GetTokenInfo(UInt160 scriptHash) return new RpcNep5TokenInfo { - Name = result[0].ToStackItem().GetString(), - Symbol = result[1].ToStackItem().GetString(), - Decimals = (byte)result[2].ToStackItem().GetInteger(), - TotalSupply = result[3].ToStackItem().GetInteger() + Name = result[0].GetString(), + Symbol = result[1].GetString(), + Decimals = (byte)result[2].GetInteger(), + TotalSupply = result[3].GetInteger() }; } diff --git a/src/RpcClient/PolicyAPI.cs b/src/RpcClient/PolicyAPI.cs index de078a8e3..073b105b3 100644 --- a/src/RpcClient/PolicyAPI.cs +++ b/src/RpcClient/PolicyAPI.cs @@ -23,7 +23,7 @@ public PolicyAPI(RpcClient rpcClient) : base(rpcClient) { } /// public uint GetMaxTransactionsPerBlock() { - return (uint)TestInvoke(scriptHash, "getMaxTransactionsPerBlock").Stack.Single().ToStackItem().GetInteger(); + return (uint)TestInvoke(scriptHash, "getMaxTransactionsPerBlock").Stack.Single().GetInteger(); } /// @@ -32,7 +32,7 @@ public uint GetMaxTransactionsPerBlock() /// public uint GetMaxBlockSize() { - return (uint)TestInvoke(scriptHash, "getMaxBlockSize").Stack.Single().ToStackItem().GetInteger(); + return (uint)TestInvoke(scriptHash, "getMaxBlockSize").Stack.Single().GetInteger(); } /// @@ -41,7 +41,7 @@ public uint GetMaxBlockSize() /// public long GetFeePerByte() { - return (long)TestInvoke(scriptHash, "getFeePerByte").Stack.Single().ToStackItem().GetInteger(); + return (long)TestInvoke(scriptHash, "getFeePerByte").Stack.Single().GetInteger(); } /// @@ -50,7 +50,7 @@ public long GetFeePerByte() /// public UInt160[] GetBlockedAccounts() { - var result = (VM.Types.Array)TestInvoke(scriptHash, "getBlockedAccounts").Stack.Single().ToStackItem(); + var result = (VM.Types.Array)TestInvoke(scriptHash, "getBlockedAccounts").Stack.Single(); return result.Select(p => new UInt160(p.GetSpan().ToArray())).ToArray(); } } diff --git a/src/RpcClient/Utility.cs b/src/RpcClient/Utility.cs index cff72fd78..6bca96b12 100644 --- a/src/RpcClient/Utility.cs +++ b/src/RpcClient/Utility.cs @@ -2,11 +2,15 @@ using Neo.IO.Json; using Neo.Network.P2P.Payloads; using Neo.SmartContract; +using Neo.VM.Types; using Neo.Wallets; using System; using System.Globalization; using System.Linq; using System.Numerics; +using Array = Neo.VM.Types.Array; +using Boolean = Neo.VM.Types.Boolean; +using Buffer = Neo.VM.Types.Buffer; namespace Neo.Network.RPC { @@ -173,5 +177,44 @@ public static Witness WitnessFromJson(JObject json) witness.VerificationScript = Convert.FromBase64String(json["verification"].AsString()); return witness; } + + public static StackItem StackItemFromJson(JObject json) + { + StackItemType type = json["type"].TryGetEnum(); + switch (type) + { + case StackItemType.Boolean: + return new Boolean(json["value"].AsBoolean()); + case StackItemType.Buffer: + return new Buffer(Convert.FromBase64String(json["value"].AsString())); + case StackItemType.ByteString: + return new ByteString(Convert.FromBase64String(json["value"].AsString())); + case StackItemType.Integer: + return new Integer(new BigInteger(json["value"].AsNumber())); + case StackItemType.Array: + Array array = new Array(); + foreach (var item in (JArray)json["value"]) + array.Add(StackItemFromJson(item)); + return array; + case StackItemType.Struct: + Struct @struct = new Struct(); + foreach (var item in (JArray)json["value"]) + @struct.Add(StackItemFromJson(item)); + return @struct; + case StackItemType.Map: + Map map = new Map(); + foreach (var item in (JArray)json["value"]) + { + PrimitiveType key = (PrimitiveType)StackItemFromJson(item["key"]); + map[key] = StackItemFromJson(item["value"]); + } + return map; + case StackItemType.Pointer: + return new Pointer(null, (int)json["value"].AsNumber()); + case StackItemType.InteropInterface: + return new InteropInterface(new object()); // See https://github.com/neo-project/neo/blob/master/src/neo/VM/Helper.cs#L194 + } + return null; + } } } diff --git a/src/RpcClient/WalletAPI.cs b/src/RpcClient/WalletAPI.cs index 3d9edaa83..014aba6ec 100644 --- a/src/RpcClient/WalletAPI.cs +++ b/src/RpcClient/WalletAPI.cs @@ -52,7 +52,7 @@ public decimal GetUnclaimedGas(UInt160 account) { UInt160 scriptHash = NativeContract.NEO.Hash; BigInteger balance = nep5API.TestInvoke(scriptHash, "unclaimedGas", account, rpcClient.GetBlockCount() - 1) - .Stack.Single().ToStackItem().GetInteger(); + .Stack.Single().GetInteger(); return ((decimal)balance) / (long)NativeContract.GAS.Factor; } diff --git a/tests/Neo.Network.RPC.Tests/RpcTestCases.json b/tests/Neo.Network.RPC.Tests/RpcTestCases.json index d364a71d3..33ee866d1 100644 --- a/tests/Neo.Network.RPC.Tests/RpcTestCases.json +++ b/tests/Neo.Network.RPC.Tests/RpcTestCases.json @@ -758,20 +758,62 @@ "gasconsumed": "5061560", "stack": [ { - "type": "ByteArray", - "value": "R0FT" - }, - { - "type": "ByteArray", - "value": "Z2Fz" - }, - { - "type": "Integer", - "value": "8" - }, - { - "type": "Integer", - "value": "3001101329992600" + "type": "Array", + "value": [ + { + "type": "ByteString", + "value": "dGVzdA==" + }, + { + "type": "InteropInterface" + }, + { + "type": "Integer", + "value": "1" + }, + { + "type": "Buffer", + "value": "CAwiNQw=" + }, + { + "type": "Array", + "value": [ + { + "type": "ByteString", + "value": "YmI=" + }, + { + "type": "ByteString", + "value": "Y2Mw" + } + ] + }, + { + "type": "Map", + "value": [ + { + "key": { + "type": "Integer", + "value": "2" + }, + "value": { + "type": "Integer", + "value": "12" + } + }, + { + "key": { + "type": "Integer", + "value": "0" + }, + "value": { + "type": "Integer", + "value": "24" + } + } + ] + } + ] } ], "tx": "00769d16556925aa554712439a9c613ba114efa3fac23ddbca00e1f505000000009e021400000000005620200000009910c30c046e616d650c143b7d3711c6f0ccf9b1dca903d1bfa1d896f1238c41627d5b5210c30c0673796d626f6c0c143b7d3711c6f0ccf9b1dca903d1bfa1d896f1238c41627d5b5210c30c08646563696d616c730c143b7d3711c6f0ccf9b1dca903d1bfa1d896f1238c41627d5b5210c30c0b746f74616c537570706c790c143b7d3711c6f0ccf9b1dca903d1bfa1d896f1238c41627d5b5201420c40c848d0fcbf5e6a820508242ea8b7ccbeed3caefeed5db570537279c2154f7cfd8b0d8f477f37f4e6ca912935b732684d57c455dff7aa525ad4ab000931f22208290c2103aa052fbcb8e5b33a4eefd662536f8684641f04109f1d5e69cdda6f084890286a0b410a906ad4" diff --git a/tests/Neo.Network.RPC.Tests/UT_ContractClient.cs b/tests/Neo.Network.RPC.Tests/UT_ContractClient.cs index 0e84afa3d..dfdbf9990 100644 --- a/tests/Neo.Network.RPC.Tests/UT_ContractClient.cs +++ b/tests/Neo.Network.RPC.Tests/UT_ContractClient.cs @@ -32,7 +32,7 @@ public void TestInvoke() ContractClient contractClient = new ContractClient(rpcClientMock.Object); var result = contractClient.TestInvoke(NativeContract.GAS.Hash, "balanceOf", UInt160.Zero); - Assert.AreEqual(30000000000000L, (long)result.Stack[0].ToStackItem().GetInteger()); + Assert.AreEqual(30000000000000L, (long)result.Stack[0].GetInteger()); } [TestMethod] diff --git a/tests/Neo.Network.RPC.Tests/UT_TransactionManager.cs b/tests/Neo.Network.RPC.Tests/UT_TransactionManager.cs index 1f4da3250..b1546a9c7 100644 --- a/tests/Neo.Network.RPC.Tests/UT_TransactionManager.cs +++ b/tests/Neo.Network.RPC.Tests/UT_TransactionManager.cs @@ -95,7 +95,7 @@ public static void MockInvokeScript(Mock mockClient, byte[] script, p { var result = new RpcInvokeResult() { - Stack = parameters, + Stack = parameters.Select(p => p.ToStackItem()).ToArray(), GasConsumed = "100", Script = script.ToHexString(), State = VMState.HALT From 981edd9c0259566216d4f1b6c0dd83ed85bf677b Mon Sep 17 00:00:00 2001 From: Owen Zhang <38493437+superboyiii@users.noreply.github.com> Date: Wed, 5 Aug 2020 16:19:48 +0800 Subject: [PATCH 146/183] Merge Preview3 to Master (#307) * Add Utility.StackItemFromJson (#302) (#303) * fix invoke tojson * add StackItemFromJson * optimize code * remove src/RpcClientTests/UtilityTests.cs Co-authored-by: Luchuan Co-authored-by: Luchuan Co-authored-by: Luchuan * update to preview3 (#305) Co-authored-by: Luchuan Co-authored-by: Luchuan --- src/ApplicationLogs/ApplicationLogs.csproj | 2 +- src/LevelDBStore/LevelDBStore.csproj | 6 +++--- src/RocksDBStore/RocksDBStore.csproj | 6 +++--- src/RpcClient/RpcClient.csproj | 4 ++-- src/RpcNep5Tracker/RpcNep5Tracker.csproj | 2 +- src/RpcServer/RpcServer.csproj | 4 ++-- src/StatesDumper/StatesDumper.csproj | 4 ++-- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/ApplicationLogs/ApplicationLogs.csproj b/src/ApplicationLogs/ApplicationLogs.csproj index c06947925..5318c84ca 100644 --- a/src/ApplicationLogs/ApplicationLogs.csproj +++ b/src/ApplicationLogs/ApplicationLogs.csproj @@ -1,7 +1,7 @@ - 3.0.0-preview2 + 3.0.0-preview3 netstandard2.1 Neo.Plugins diff --git a/src/LevelDBStore/LevelDBStore.csproj b/src/LevelDBStore/LevelDBStore.csproj index 9e6e2a829..9c57ece5c 100644 --- a/src/LevelDBStore/LevelDBStore.csproj +++ b/src/LevelDBStore/LevelDBStore.csproj @@ -1,7 +1,7 @@ - + - 3.0.0-preview2 + 3.0.0-preview3 netstandard2.1 Neo true @@ -15,7 +15,7 @@ - + diff --git a/src/RocksDBStore/RocksDBStore.csproj b/src/RocksDBStore/RocksDBStore.csproj index fb9d1a700..5f67e8f73 100644 --- a/src/RocksDBStore/RocksDBStore.csproj +++ b/src/RocksDBStore/RocksDBStore.csproj @@ -1,7 +1,7 @@ - + - 3.0.0-preview2 + 3.0.0-preview3 netstandard2.1 Neo.Plugins.Storage @@ -14,7 +14,7 @@ - + diff --git a/src/RpcClient/RpcClient.csproj b/src/RpcClient/RpcClient.csproj index a8b93604a..31e757d12 100644 --- a/src/RpcClient/RpcClient.csproj +++ b/src/RpcClient/RpcClient.csproj @@ -1,7 +1,7 @@ - 3.0.0-preview2 + 3.0.0-preview3 netstandard2.1 Neo.Network.RPC The Neo Project @@ -14,7 +14,7 @@ - + diff --git a/src/RpcNep5Tracker/RpcNep5Tracker.csproj b/src/RpcNep5Tracker/RpcNep5Tracker.csproj index 408ffed03..7a9a6764e 100644 --- a/src/RpcNep5Tracker/RpcNep5Tracker.csproj +++ b/src/RpcNep5Tracker/RpcNep5Tracker.csproj @@ -1,6 +1,6 @@ - 3.0.0-preview2 + 3.0.0-preview3 netstandard2.1 Neo.Plugins diff --git a/src/RpcServer/RpcServer.csproj b/src/RpcServer/RpcServer.csproj index 853edc38f..c337384ad 100644 --- a/src/RpcServer/RpcServer.csproj +++ b/src/RpcServer/RpcServer.csproj @@ -1,7 +1,7 @@ - 3.0.0-preview2 + 3.0.0-preview3 netstandard2.1 Neo.Plugins @@ -15,7 +15,7 @@ - + diff --git a/src/StatesDumper/StatesDumper.csproj b/src/StatesDumper/StatesDumper.csproj index 5ae67e8ca..9e695830a 100644 --- a/src/StatesDumper/StatesDumper.csproj +++ b/src/StatesDumper/StatesDumper.csproj @@ -1,7 +1,7 @@ - 3.0.0-preview2 + 3.0.0-preview3 netstandard2.1 Neo.Plugins @@ -14,7 +14,7 @@ - + From d7214ef4ee7bced71a857ceb89b2e31ef96833e8 Mon Sep 17 00:00:00 2001 From: cloud8little <34291844+cloud8little@users.noreply.github.com> Date: Thu, 13 Aug 2020 15:39:41 +0800 Subject: [PATCH 147/183] fix #312 (#319) --- src/RpcServer/RpcServer.SmartContract.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/RpcServer/RpcServer.SmartContract.cs b/src/RpcServer/RpcServer.SmartContract.cs index 3bce967c7..acb696b5d 100644 --- a/src/RpcServer/RpcServer.SmartContract.cs +++ b/src/RpcServer/RpcServer.SmartContract.cs @@ -63,7 +63,7 @@ public void SerializeUnsigned(BinaryWriter writer) private JObject GetInvokeResult(byte[] script, Signers signers = null) { - using ApplicationEngine engine = ApplicationEngine.Run(script, signers, gas: settings.MaxGasInvoke); + using ApplicationEngine engine = ApplicationEngine.Run(script, container: signers, gas: settings.MaxGasInvoke); JObject json = new JObject(); json["script"] = script.ToHexString(); json["state"] = engine.State; From 1fbe6f2cdabb63b42d8376b3f07eb2611809f8c3 Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Sun, 16 Aug 2020 14:08:53 +0800 Subject: [PATCH 148/183] Allow to try to repair leveldb before opening (#322) --- src/LevelDBStore/IO/Data/LevelDB/DB.cs | 6 ++++++ src/LevelDBStore/Plugins/Storage/LevelDBStore.cs | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/src/LevelDBStore/IO/Data/LevelDB/DB.cs b/src/LevelDBStore/IO/Data/LevelDB/DB.cs index 82ccf933b..75e8f018c 100644 --- a/src/LevelDBStore/IO/Data/LevelDB/DB.cs +++ b/src/LevelDBStore/IO/Data/LevelDB/DB.cs @@ -78,6 +78,12 @@ public void Put(WriteOptions options, byte[] key, byte[] value) NativeHelper.CheckError(error); } + public static void Repair(string name, Options options) + { + Native.leveldb_repair_db(options.handle, Path.GetFullPath(name), out IntPtr error); + NativeHelper.CheckError(error); + } + public void Write(WriteOptions options, WriteBatch write_batch) { // There's a bug in .Net Core. diff --git a/src/LevelDBStore/Plugins/Storage/LevelDBStore.cs b/src/LevelDBStore/Plugins/Storage/LevelDBStore.cs index 09a526bcc..61118a57a 100644 --- a/src/LevelDBStore/Plugins/Storage/LevelDBStore.cs +++ b/src/LevelDBStore/Plugins/Storage/LevelDBStore.cs @@ -1,4 +1,7 @@ +using Neo.IO.Data.LevelDB; using Neo.Persistence; +using System; +using System.Linq; namespace Neo.Plugins.Storage { @@ -15,6 +18,8 @@ protected override void Configure() public IStore GetStore() { + if (Environment.CommandLine.Split(' ').Any(p => p == "/repair" || p == "--repair")) + DB.Repair(path, Options.Default); return new Store(path); } } From c465029d2f80145416fe7a1ea67382857d04ffcc Mon Sep 17 00:00:00 2001 From: HaoqiangZhang Date: Tue, 18 Aug 2020 01:22:09 +0800 Subject: [PATCH 149/183] update applicationLogs serialization (#321) --- src/RpcClient/Models/RpcApplicationLog.cs | 9 +- tests/Neo.Network.RPC.Tests/RpcTestCases.json | 172 ++++++++++++++---- 2 files changed, 141 insertions(+), 40 deletions(-) diff --git a/src/RpcClient/Models/RpcApplicationLog.cs b/src/RpcClient/Models/RpcApplicationLog.cs index a3ee870f0..915a9e896 100644 --- a/src/RpcClient/Models/RpcApplicationLog.cs +++ b/src/RpcClient/Models/RpcApplicationLog.cs @@ -1,6 +1,7 @@ using Neo.IO.Json; using Neo.SmartContract; using Neo.VM; +using Neo.VM.Types; using System.Collections.Generic; using System.Linq; @@ -16,7 +17,7 @@ public class RpcApplicationLog public long GasConsumed { get; set; } - public List Stack { get; set; } + public List Stack { get; set; } public List Notifications { get; set; } @@ -39,7 +40,7 @@ public static RpcApplicationLog FromJson(JObject json) log.Trigger = json["trigger"].TryGetEnum(); log.VMState = json["vmstate"].TryGetEnum(); log.GasConsumed = long.Parse(json["gasconsumed"].AsString()); - log.Stack = ((JArray)json["stack"]).Select(p => ContractParameter.FromJson(p)).ToList(); + log.Stack = ((JArray)json["stack"]).Select(p => Utility.StackItemFromJson(p)).ToList(); log.Notifications = ((JArray)json["notifications"]).Select(p => RpcNotifyEventArgs.FromJson(p)).ToList(); return log; } @@ -51,7 +52,7 @@ public class RpcNotifyEventArgs public string EventName { get; set; } - public ContractParameter State { get; set; } + public StackItem State { get; set; } public JObject ToJson() { @@ -68,7 +69,7 @@ public static RpcNotifyEventArgs FromJson(JObject json) { Contract = UInt160.Parse(json["contract"].AsString()), EventName = json["eventname"].AsString(), - State = ContractParameter.FromJson(json["state"]) + State = Utility.StackItemFromJson(json["state"]) }; } } diff --git a/tests/Neo.Network.RPC.Tests/RpcTestCases.json b/tests/Neo.Network.RPC.Tests/RpcTestCases.json index 33ee866d1..5dccd0d73 100644 --- a/tests/Neo.Network.RPC.Tests/RpcTestCases.json +++ b/tests/Neo.Network.RPC.Tests/RpcTestCases.json @@ -1205,51 +1205,151 @@ }, "Response": { "jsonrpc": "2.0", - "id": 1, + "id": "1", "result": { - "txid": "0x183cd84359cd9f8b956afcd02403ec07361c1dba55f0800241b4ef2b28e88bbb", + "txid": "0xe36f62923deb64376e5e982e19b60afc65faca8d9e8eb71ac12f7298ce32ef7b", "trigger": "Application", "vmstate": "HALT", - "gasconsumed": "9007810", - "stack": [], - "notifications": [ + "gasconsumed": "5814860", + "stack": [ { - "contract": "0x8c23f196d8a1bfd103a9dcb1f9ccf0c611377d3b", - "eventname": "Transfer", - "state": { - "type": "Array", - "value": [ - { - "type": "Any" - }, - { - "type": "ByteArray", - "value": "eU9We10tADBFvus3caGe5hjcaNE=" - }, - { - "type": "Integer", - "value": "6321697534537" - } - ] - } - }, + "type": "Array", + "value": [ + { + "type": "Integer", + "value": "1" + }, + { + "type": "Integer", + "value": "1223" + }, + { + "type": "ByteString", + "value": "dGVzdHFxd2FzZGFz" + }, + { + "type": "Buffer", + "value": "CAwiNQw=" + }, + { + "type": "Array", + "value": [ + { + "type": "ByteString", + "value": "YWE=" + }, + { + "type": "ByteString", + "value": "YmI=" + }, + { + "type": "ByteString", + "value": "Y2Mw" + } + ] + }, + { + "type": "Map", + "value": [ + { + "key": { + "type": "Integer", + "value": "2" + }, + "value": { + "type": "Integer", + "value": "12" + } + }, + { + "key": { + "type": "Integer", + "value": "0" + }, + "value": { + "type": "Integer", + "value": "24" + } + } + ] + } + ] + } + ], + "notifications": [ { - "contract": "0x9bde8f209c88dd0e7ca3bf0af0f476cdd8207789", - "eventname": "Transfer", + "contract": "0xbfe215933f29b29dacf0e8383722a62974ac8aa6", + "eventname": "event_name", "state": { "type": "Array", "value": [ { - "type": "ByteArray", - "value": "eU9We10tADBFvus3caGe5hjcaNE=" - }, - { - "type": "ByteArray", - "value": "eU9We10tADBFvus3caGe5hjcaNE=" - }, - { - "type": "Integer", - "value": "99999961" + "type": "Array", + "value": [ + { + "type": "Array", + "value": [ + { + "type": "Integer", + "value": "1" + }, + { + "type": "Integer", + "value": "1223" + }, + { + "type": "ByteString", + "value": "dGVzdHFxd2FzZGFz" + }, + { + "type": "Buffer", + "value": "CAwiNQw=" + }, + { + "type": "Array", + "value": [ + { + "type": "ByteString", + "value": "YWE=" + }, + { + "type": "ByteString", + "value": "YmI=" + }, + { + "type": "ByteString", + "value": "Y2Mw" + } + ] + }, + { + "type": "Map", + "value": [ + { + "key": { + "type": "Integer", + "value": "2" + }, + "value": { + "type": "Integer", + "value": "12" + } + }, + { + "key": { + "type": "Integer", + "value": "0" + }, + "value": { + "type": "Integer", + "value": "24" + } + } + ] + } + ] + } + ] } ] } From 83b3a06f9501b63d79e2713092946102c706baa6 Mon Sep 17 00:00:00 2001 From: Shargon Date: Wed, 26 Aug 2020 12:08:16 +0200 Subject: [PATCH 150/183] Remove old bug (#331) --- src/LevelDBStore/IO/Data/LevelDB/DB.cs | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/src/LevelDBStore/IO/Data/LevelDB/DB.cs b/src/LevelDBStore/IO/Data/LevelDB/DB.cs index 75e8f018c..e8b1a33c1 100644 --- a/src/LevelDBStore/IO/Data/LevelDB/DB.cs +++ b/src/LevelDBStore/IO/Data/LevelDB/DB.cs @@ -86,25 +86,8 @@ public static void Repair(string name, Options options) public void Write(WriteOptions options, WriteBatch write_batch) { - // There's a bug in .Net Core. - // When calling DB.Write(), it will throw LevelDBException sometimes. - // But when you try to catch the exception, the bug disappears. - // We shall remove the "try...catch" clause when Microsoft fix the bug. - byte retry = 0; - while (true) - { - try - { - Native.leveldb_write(handle, options.handle, write_batch.handle, out IntPtr error); - NativeHelper.CheckError(error); - break; - } - catch (LevelDBException ex) - { - if (++retry >= 4) throw; - System.IO.File.AppendAllText("leveldb.log", ex.Message + "\r\n"); - } - } + Native.leveldb_write(handle, options.handle, write_batch.handle, out IntPtr error); + NativeHelper.CheckError(error); } } } From 4a77dfecae9a11cf5784b56e52c632a18f09e31a Mon Sep 17 00:00:00 2001 From: Shargon Date: Thu, 27 Aug 2020 12:18:41 +0200 Subject: [PATCH 151/183] Optimize RocksDb startup (#333) --- src/RocksDBStore/Plugins/Storage/Store.cs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/RocksDBStore/Plugins/Storage/Store.cs b/src/RocksDBStore/Plugins/Storage/Store.cs index 5fb255c11..0304cb12c 100644 --- a/src/RocksDBStore/Plugins/Storage/Store.cs +++ b/src/RocksDBStore/Plugins/Storage/Store.cs @@ -20,8 +20,16 @@ internal class Store : IStore public Store(string path) { var families = new ColumnFamilies(); - for (int x = 0; x <= byte.MaxValue; x++) - families.Add(new ColumnFamilies.Descriptor(x.ToString(), new ColumnFamilyOptions())); + + try + { + foreach (var family in RocksDb.ListColumnFamilies(Options.Default, Path.GetFullPath(path))) + { + families.Add(new ColumnFamilies.Descriptor(family, new ColumnFamilyOptions())); + } + } + catch { } + db = RocksDb.Open(Options.Default, Path.GetFullPath(path), families); ColumnFamilyHandle defaultFamily = db.GetDefaultColumnFamily(); From 01a1ba31bffc0ad92b355cbbb3973ccdc82933f2 Mon Sep 17 00:00:00 2001 From: Shargon Date: Wed, 2 Sep 2020 11:00:15 +0200 Subject: [PATCH 152/183] Fix RocksDb (#332) --- src/RocksDBStore/Plugins/Storage/Snapshot.cs | 9 ++++++--- src/RocksDBStore/Plugins/Storage/Store.cs | 10 ++++++---- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/RocksDBStore/Plugins/Storage/Snapshot.cs b/src/RocksDBStore/Plugins/Storage/Snapshot.cs index 834dbc0a3..9bc924e26 100644 --- a/src/RocksDBStore/Plugins/Storage/Snapshot.cs +++ b/src/RocksDBStore/Plugins/Storage/Snapshot.cs @@ -1,6 +1,7 @@ using Neo.IO.Caching; using Neo.Persistence; using RocksDbSharp; +using System; using System.Collections.Generic; namespace Neo.Plugins.Storage @@ -32,16 +33,18 @@ public void Commit() public void Delete(byte table, byte[] key) { - batch.Delete(key, store.GetFamily(table)); + batch.Delete(key ?? Array.Empty(), store.GetFamily(table)); } public void Put(byte table, byte[] key, byte[] value) { - batch.Put(key, value, store.GetFamily(table)); + batch.Put(key ?? Array.Empty(), value, store.GetFamily(table)); } public IEnumerable<(byte[] Key, byte[] Value)> Seek(byte table, byte[] keyOrPrefix, SeekDirection direction) { + if (keyOrPrefix == null) keyOrPrefix = Array.Empty(); + using var it = db.NewIterator(store.GetFamily(table), options); if (direction == SeekDirection.Forward) @@ -54,7 +57,7 @@ public void Put(byte table, byte[] key, byte[] value) public byte[] TryGet(byte table, byte[] key) { - return db.Get(key, store.GetFamily(table), options); + return db.Get(key ?? Array.Empty(), store.GetFamily(table), options); } public void Dispose() diff --git a/src/RocksDBStore/Plugins/Storage/Store.cs b/src/RocksDBStore/Plugins/Storage/Store.cs index 0304cb12c..ffdcba25f 100644 --- a/src/RocksDBStore/Plugins/Storage/Store.cs +++ b/src/RocksDBStore/Plugins/Storage/Store.cs @@ -92,6 +92,8 @@ public ISnapshot GetSnapshot() public IEnumerable<(byte[] Key, byte[] Value)> Seek(byte table, byte[] keyOrPrefix, SeekDirection direction = SeekDirection.Forward) { + if (keyOrPrefix == null) keyOrPrefix = Array.Empty(); + using var it = db.NewIterator(GetFamily(table), Options.ReadDefault); if (direction == SeekDirection.Forward) for (it.Seek(keyOrPrefix); it.Valid(); it.Next()) @@ -103,22 +105,22 @@ public ISnapshot GetSnapshot() public byte[] TryGet(byte table, byte[] key) { - return db.Get(key, GetFamily(table), Options.ReadDefault); + return db.Get(key ?? Array.Empty(), GetFamily(table), Options.ReadDefault); } public void Delete(byte table, byte[] key) { - db.Remove(key, GetFamily(table), Options.WriteDefault); + db.Remove(key ?? Array.Empty(), GetFamily(table), Options.WriteDefault); } public void Put(byte table, byte[] key, byte[] value) { - db.Put(key, value, GetFamily(table), Options.WriteDefault); + db.Put(key ?? Array.Empty(), value, GetFamily(table), Options.WriteDefault); } public void PutSync(byte table, byte[] key, byte[] value) { - db.Put(key, value, GetFamily(table), Options.WriteDefaultSync); + db.Put(key ?? Array.Empty(), value, GetFamily(table), Options.WriteDefaultSync); } } } From 435a68bf26959e4a811efdaa14b9ac82f35a9eae Mon Sep 17 00:00:00 2001 From: cloud8little <34291844+cloud8little@users.noreply.github.com> Date: Fri, 11 Sep 2020 16:35:14 +0800 Subject: [PATCH 153/183] Add Getcommittee (#342) --- src/RpcClient/RpcClient.cs | 8 ++++++++ src/RpcServer/RpcServer.Blockchain.cs | 7 +++++++ 2 files changed, 15 insertions(+) diff --git a/src/RpcClient/RpcClient.cs b/src/RpcClient/RpcClient.cs index 6448178e2..f418a0c6f 100644 --- a/src/RpcClient/RpcClient.cs +++ b/src/RpcClient/RpcClient.cs @@ -256,6 +256,14 @@ public RpcValidator[] GetValidators() return ((JArray)RpcSend("getvalidators")).Select(p => RpcValidator.FromJson(p)).ToArray(); } + /// + /// Returns the current NEO committee members. + /// + public string[] GetCommittee() + { + return ((JArray)RpcSend("getcommittee")).Select(p => p.AsString()).ToArray(); + } + #endregion Blockchain #region Node diff --git a/src/RpcServer/RpcServer.Blockchain.cs b/src/RpcServer/RpcServer.Blockchain.cs index 60d736da4..18000383a 100644 --- a/src/RpcServer/RpcServer.Blockchain.cs +++ b/src/RpcServer/RpcServer.Blockchain.cs @@ -194,5 +194,12 @@ private JObject GetValidators(JArray _params) return validator; }).ToArray(); } + + [RpcMethod] + private JObject GetCommittee(JArray _params) + { + using SnapshotView snapshot = Blockchain.Singleton.GetSnapshot(); + return new JArray(NativeContract.NEO.GetCommittee(snapshot).Select(p => (JObject)p.ToString())); + } } } From 294d9150202055d25992344996c137a75516867d Mon Sep 17 00:00:00 2001 From: HaoqiangZhang Date: Fri, 11 Sep 2020 16:48:17 +0800 Subject: [PATCH 154/183] update signers and add sender for rpc api (#309) --- src/RpcServer/RpcServer.SmartContract.cs | 18 +++++---- src/RpcServer/RpcServer.Utilities.cs | 4 +- src/RpcServer/RpcServer.Wallet.cs | 50 +++++++++++++++++------- src/RpcServer/RpcServer.csproj | 2 +- 4 files changed, 49 insertions(+), 25 deletions(-) diff --git a/src/RpcServer/RpcServer.SmartContract.cs b/src/RpcServer/RpcServer.SmartContract.cs index acb696b5d..31b956ff5 100644 --- a/src/RpcServer/RpcServer.SmartContract.cs +++ b/src/RpcServer/RpcServer.SmartContract.cs @@ -61,7 +61,7 @@ public void SerializeUnsigned(BinaryWriter writer) } } - private JObject GetInvokeResult(byte[] script, Signers signers = null) + private JObject GetInvokeResult(byte[] script, UInt160 sender = null, Signers signers = null) { using ApplicationEngine engine = ApplicationEngine.Run(script, container: signers, gas: settings.MaxGasInvoke); JObject json = new JObject(); @@ -76,7 +76,7 @@ private JObject GetInvokeResult(byte[] script, Signers signers = null) { json["stack"] = "error: recursive reference"; } - ProcessInvokeWithWallet(json, signers); + ProcessInvokeWithWallet(json, sender, signers); return json; } @@ -84,7 +84,7 @@ private static Signers SignersFromJson(JArray _params) { var ret = new Signers(_params.Select(u => new Signer() { - Account = UInt160.Parse(u["account"].AsString()), + Account = AddressToScriptHash(u["account"].AsString()), Scopes = (WitnessScope)Enum.Parse(typeof(WitnessScope), u["scopes"]?.AsString()), AllowedContracts = ((JArray)u["allowedcontracts"])?.Select(p => UInt160.Parse(p.AsString())).ToArray(), AllowedGroups = ((JArray)u["allowedgroups"])?.Select(p => ECPoint.Parse(p.AsString(), ECCurve.Secp256r1)).ToArray() @@ -103,21 +103,23 @@ private JObject InvokeFunction(JArray _params) UInt160 script_hash = UInt160.Parse(_params[0].AsString()); string operation = _params[1].AsString(); ContractParameter[] args = _params.Count >= 3 ? ((JArray)_params[2]).Select(p => ContractParameter.FromJson(p)).ToArray() : new ContractParameter[0]; - Signers signers = _params.Count >= 4 ? SignersFromJson((JArray)_params[3]) : null; + UInt160 sender = _params.Count >= 4 ? AddressToScriptHash(_params[3].AsString()) : null; + Signers signers = _params.Count >= 5 ? SignersFromJson((JArray)_params[4]) : null; byte[] script; using (ScriptBuilder sb = new ScriptBuilder()) { script = sb.EmitAppCall(script_hash, operation, args).ToArray(); } - return GetInvokeResult(script, signers); + return GetInvokeResult(script, sender, signers); } [RpcMethod] private JObject InvokeScript(JArray _params) { byte[] script = _params[0].AsString().HexToBytes(); - Signers signers = _params.Count >= 2 ? SignersFromJson((JArray)_params[1]) : null; - return GetInvokeResult(script, signers); + UInt160 sender = _params.Count >= 2 ? AddressToScriptHash(_params[1].AsString()) : null; + Signers signers = _params.Count >= 3 ? SignersFromJson((JArray)_params[2]) : null; + return GetInvokeResult(script, sender, signers); } [RpcMethod] @@ -128,7 +130,7 @@ private JObject GetUnclaimedGas(JArray _params) UInt160 script_hash; try { - script_hash = address.ToScriptHash(); + script_hash = AddressToScriptHash(address); } catch { diff --git a/src/RpcServer/RpcServer.Utilities.cs b/src/RpcServer/RpcServer.Utilities.cs index 41b22d741..7e4bf45db 100644 --- a/src/RpcServer/RpcServer.Utilities.cs +++ b/src/RpcServer/RpcServer.Utilities.cs @@ -12,7 +12,7 @@ partial class RpcServer [RpcMethod] private JObject ListPlugins(JArray _params) { - return new JArray(Neo.Plugins.Plugin.Plugins + return new JArray(Plugin.Plugins .OrderBy(u => u.Name) .Select(u => new JObject { @@ -33,7 +33,7 @@ private JObject ValidateAddress(JArray _params) UInt160 scriptHash; try { - scriptHash = address.ToScriptHash(); + scriptHash = AddressToScriptHash(address); } catch { diff --git a/src/RpcServer/RpcServer.Wallet.cs b/src/RpcServer/RpcServer.Wallet.cs index 4db930130..e55471c7e 100644 --- a/src/RpcServer/RpcServer.Wallet.cs +++ b/src/RpcServer/RpcServer.Wallet.cs @@ -42,7 +42,7 @@ private JObject CloseWallet(JArray _params) private JObject DumpPrivKey(JArray _params) { CheckWallet(); - UInt160 scriptHash = _params[0].AsString().ToScriptHash(); + UInt160 scriptHash = AddressToScriptHash(_params[0].AsString()); WalletAccount account = wallet.GetAccount(scriptHash); return account.GetKey().Export(); } @@ -138,16 +138,24 @@ private JObject OpenWallet(JArray _params) return true; } - private void ProcessInvokeWithWallet(JObject result, Signers signers = null) + private void ProcessInvokeWithWallet(JObject result, UInt160 sender = null, Signers signers = null) { Transaction tx = null; if (wallet != null && signers != null) { - UInt160[] accounts = wallet.GetAccounts().Where(p => !p.Lock && !p.WatchOnly).Select(p => p.ScriptHash).ToArray(); - Signer[] witnessCosigners = signers.GetSigners().Where(p => accounts.Contains(p.Account)).ToArray(); - if (witnessCosigners.Count() > 0) + Signer[] witnessSigners = signers.GetSigners().ToArray(); + UInt160[] signersAccounts = signers.GetScriptHashesForVerifying(null); + if (sender != null) { - tx = wallet.MakeTransaction(result["script"].AsString().HexToBytes(), null, witnessCosigners); + if (!signersAccounts.Contains(sender)) + witnessSigners = witnessSigners.Prepend(new Signer() { Account = sender, Scopes = WitnessScope.CalledByEntry }).ToArray(); + else if (signersAccounts[0] != sender) + throw new RpcException(-32602, "The sender must be the first element of signers."); + } + + if (witnessSigners.Count() > 0) + { + tx = wallet.MakeTransaction(result["script"].AsString().HexToBytes(), sender, witnessSigners); ContractParametersContext context = new ContractParametersContext(tx); wallet.Sign(context); if (context.Completed) @@ -164,12 +172,14 @@ private JObject SendFrom(JArray _params) { CheckWallet(); UInt160 assetId = UInt160.Parse(_params[0].AsString()); - UInt160 from = _params[1].AsString().ToScriptHash(); - UInt160 to = _params[2].AsString().ToScriptHash(); + UInt160 from = AddressToScriptHash(_params[1].AsString()); + UInt160 to = AddressToScriptHash(_params[2].AsString()); AssetDescriptor descriptor = new AssetDescriptor(assetId); BigDecimal amount = BigDecimal.Parse(_params[3].AsString(), descriptor.Decimals); if (amount.Sign <= 0) throw new RpcException(-32602, "Invalid params"); + Signer[] signers = _params.Count >= 5 ? ((JArray)_params[4]).Select(p => new Signer() { Account = AddressToScriptHash(p.AsString()), Scopes = WitnessScope.CalledByEntry }).ToArray() : null; + Transaction tx = wallet.MakeTransaction(new[] { new TransferOutput @@ -178,7 +188,7 @@ private JObject SendFrom(JArray _params) Value = amount, ScriptHash = to } - }, from); + }, from, signers); if (tx == null) throw new RpcException(-300, "Insufficient funds"); @@ -206,12 +216,14 @@ private JObject SendMany(JArray _params) UInt160 from = null; if (_params[0] is JString) { - from = _params[0].AsString().ToScriptHash(); + from = AddressToScriptHash(_params[0].AsString()); to_start = 1; } JArray to = (JArray)_params[to_start]; if (to.Count == 0) throw new RpcException(-32602, "Invalid params"); + Signer[] signers = _params.Count >= to_start + 2 ? ((JArray)_params[to_start + 1]).Select(p => new Signer() { Account = AddressToScriptHash(p.AsString()), Scopes = WitnessScope.CalledByEntry }).ToArray() : null; + TransferOutput[] outputs = new TransferOutput[to.Count]; for (int i = 0; i < to.Count; i++) { @@ -221,12 +233,12 @@ private JObject SendMany(JArray _params) { AssetId = asset_id, Value = BigDecimal.Parse(to[i]["value"].AsString(), descriptor.Decimals), - ScriptHash = to[i]["address"].AsString().ToScriptHash() + ScriptHash = AddressToScriptHash(to[i]["address"].AsString()) }; if (outputs[i].Value.Sign <= 0) throw new RpcException(-32602, "Invalid params"); } - Transaction tx = wallet.MakeTransaction(outputs, from); + Transaction tx = wallet.MakeTransaction(outputs, from, signers); if (tx == null) throw new RpcException(-300, "Insufficient funds"); @@ -251,7 +263,7 @@ private JObject SendToAddress(JArray _params) { CheckWallet(); UInt160 assetId = UInt160.Parse(_params[0].AsString()); - UInt160 scriptHash = _params[1].AsString().ToScriptHash(); + UInt160 to = AddressToScriptHash(_params[1].AsString()); AssetDescriptor descriptor = new AssetDescriptor(assetId); BigDecimal amount = BigDecimal.Parse(_params[2].AsString(), descriptor.Decimals); if (amount.Sign <= 0) @@ -262,7 +274,7 @@ private JObject SendToAddress(JArray _params) { AssetId = assetId, Value = amount, - ScriptHash = scriptHash + ScriptHash = to } }); if (tx == null) @@ -299,5 +311,15 @@ private JObject SignAndRelay(Transaction tx) return context.ToJson(); } } + + internal static UInt160 AddressToScriptHash(string address) + { + if (UInt160.TryParse(address, out var scriptHash)) + { + return scriptHash; + } + + return address.ToScriptHash(); + } } } diff --git a/src/RpcServer/RpcServer.csproj b/src/RpcServer/RpcServer.csproj index c337384ad..a9e4b71ad 100644 --- a/src/RpcServer/RpcServer.csproj +++ b/src/RpcServer/RpcServer.csproj @@ -15,7 +15,7 @@ - + From 19086b2bb733b48c06e7f2671be2321d111dd253 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=BF=97=E5=90=8C?= Date: Sat, 12 Sep 2020 05:10:15 -0500 Subject: [PATCH 155/183] Optimize the result of 'getnep5transfers' (#345) * Update RpcNep5Tracker.cs * Update RpcNep5Tracker.cs Co-authored-by: Erik Zhang --- src/RpcNep5Tracker/RpcNep5Tracker.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/RpcNep5Tracker/RpcNep5Tracker.cs b/src/RpcNep5Tracker/RpcNep5Tracker.cs index 535fd4410..2ad00b0d6 100644 --- a/src/RpcNep5Tracker/RpcNep5Tracker.cs +++ b/src/RpcNep5Tracker/RpcNep5Tracker.cs @@ -234,7 +234,7 @@ private void AddTransfers(byte dbPrefix, UInt160 userScriptHash, ulong startTime JObject transfer = new JObject(); transfer["timestamp"] = key.TimestampMS; transfer["assethash"] = key.AssetScriptHash.ToString(); - transfer["transferaddress"] = value.UserScriptHash.ToAddress(); + transfer["transferaddress"] = value.UserScriptHash == UInt160.Zero ? null : value.UserScriptHash.ToAddress(); transfer["amount"] = value.Amount.ToString(); transfer["blockindex"] = value.BlockIndex; transfer["transfernotifyindex"] = key.BlockXferNotificationIndex; From c4de92b463cdf9b5db67ccb4f82051847777d617 Mon Sep 17 00:00:00 2001 From: Shargon Date: Tue, 15 Sep 2020 06:04:24 +0200 Subject: [PATCH 156/183] Allow querying contracts by name (#340) --- src/RpcClient/Models/RpcApplicationLog.cs | 2 +- src/RpcClient/Models/RpcNep5Balances.cs | 4 ++-- src/RpcClient/Models/RpcNep5Transfers.cs | 6 ++--- src/RpcClient/Models/RpcTransferOut.cs | 4 ++-- src/RpcClient/RpcClient.cs | 16 ++++++------- src/RpcClient/Utility.cs | 28 ++++++++++++++++++++--- 6 files changed, 41 insertions(+), 19 deletions(-) diff --git a/src/RpcClient/Models/RpcApplicationLog.cs b/src/RpcClient/Models/RpcApplicationLog.cs index 915a9e896..83467f817 100644 --- a/src/RpcClient/Models/RpcApplicationLog.cs +++ b/src/RpcClient/Models/RpcApplicationLog.cs @@ -67,7 +67,7 @@ public static RpcNotifyEventArgs FromJson(JObject json) { return new RpcNotifyEventArgs { - Contract = UInt160.Parse(json["contract"].AsString()), + Contract = json["contract"].ToScriptHash(), EventName = json["eventname"].AsString(), State = Utility.StackItemFromJson(json["state"]) }; diff --git a/src/RpcClient/Models/RpcNep5Balances.cs b/src/RpcClient/Models/RpcNep5Balances.cs index 0ebdc2840..4cdc1ecc7 100644 --- a/src/RpcClient/Models/RpcNep5Balances.cs +++ b/src/RpcClient/Models/RpcNep5Balances.cs @@ -25,7 +25,7 @@ public static RpcNep5Balances FromJson(JObject json) RpcNep5Balances nep5Balance = new RpcNep5Balances { Balances = ((JArray)json["balance"]).Select(p => RpcNep5Balance.FromJson(p)).ToList(), - UserScriptHash = json["address"].AsString().ToScriptHash() + UserScriptHash = json["address"].ToScriptHash() }; return nep5Balance; } @@ -52,7 +52,7 @@ public static RpcNep5Balance FromJson(JObject json) { RpcNep5Balance balance = new RpcNep5Balance { - AssetHash = UInt160.Parse(json["assethash"].AsString()), + AssetHash = json["assethash"].ToScriptHash(), Amount = BigInteger.Parse(json["amount"].AsString()), LastUpdatedBlock = (uint)json["lastupdatedblock"].AsNumber() }; diff --git a/src/RpcClient/Models/RpcNep5Transfers.cs b/src/RpcClient/Models/RpcNep5Transfers.cs index e2eb7d01e..e166d41fe 100644 --- a/src/RpcClient/Models/RpcNep5Transfers.cs +++ b/src/RpcClient/Models/RpcNep5Transfers.cs @@ -30,7 +30,7 @@ public static RpcNep5Transfers FromJson(JObject json) { Sent = ((JArray)json["sent"]).Select(p => RpcNep5Transfer.FromJson(p)).ToList(), Received = ((JArray)json["received"]).Select(p => RpcNep5Transfer.FromJson(p)).ToList(), - UserScriptHash = json["address"].AsString().ToScriptHash() + UserScriptHash = json["address"].ToScriptHash() }; return transfers; } @@ -69,8 +69,8 @@ public static RpcNep5Transfer FromJson(JObject json) { RpcNep5Transfer transfer = new RpcNep5Transfer(); transfer.TimestampMS = (ulong)json["timestamp"].AsNumber(); - transfer.AssetHash = UInt160.Parse(json["assethash"].AsString()); - transfer.UserScriptHash = json["transferaddress"].AsString().ToScriptHash(); + transfer.AssetHash = json["assethash"].ToScriptHash(); + transfer.UserScriptHash = json["transferaddress"].ToScriptHash(); transfer.Amount = BigInteger.Parse(json["amount"].AsString()); transfer.BlockIndex = (uint)json["blockindex"].AsNumber(); transfer.TransferNotifyIndex = (ushort)json["transfernotifyindex"].AsNumber(); diff --git a/src/RpcClient/Models/RpcTransferOut.cs b/src/RpcClient/Models/RpcTransferOut.cs index 6f582dfe3..6e3ce9d47 100644 --- a/src/RpcClient/Models/RpcTransferOut.cs +++ b/src/RpcClient/Models/RpcTransferOut.cs @@ -25,9 +25,9 @@ public static RpcTransferOut FromJson(JObject json) { return new RpcTransferOut { - Asset = UInt160.Parse(json["asset"].AsString()), + Asset = json["asset"].ToScriptHash(), Value = json["value"].AsString(), - ScriptHash = json["address"].AsString().ToScriptHash(), + ScriptHash = json["address"].ToScriptHash(), }; } } diff --git a/src/RpcClient/RpcClient.cs b/src/RpcClient/RpcClient.cs index f418a0c6f..c43df5683 100644 --- a/src/RpcClient/RpcClient.cs +++ b/src/RpcClient/RpcClient.cs @@ -326,7 +326,7 @@ public UInt256 SubmitBlock(byte[] block) /// public RpcInvokeResult InvokeFunction(string scriptHash, string operation, RpcStack[] stacks, params Signer[] signer) { - List parameters = new List { scriptHash, operation, stacks.Select(p => p.ToJson()).ToArray() }; + List parameters = new List { scriptHash.AsScriptHash(), operation, stacks.Select(p => p.ToJson()).ToArray() }; if (signer.Length > 0) { parameters.Add(signer.Select(p => (JObject)p.ToJson()).ToArray()); @@ -350,7 +350,7 @@ public RpcInvokeResult InvokeScript(byte[] script, params Signer[] signers) public RpcUnclaimedGas GetUnclaimedGas(string address) { - return RpcUnclaimedGas.FromJson(RpcSend("getunclaimedgas", address)); + return RpcUnclaimedGas.FromJson(RpcSend("getunclaimedgas", address.AsScriptHash())); } #endregion SmartContract @@ -408,7 +408,7 @@ public string GetNewAddress() /// new address as string public BigDecimal GetWalletBalance(string assetId) { - byte decimals = new Nep5API(this).Decimals(UInt160.Parse(assetId)); + byte decimals = new Nep5API(this).Decimals(UInt160.Parse(assetId.AsScriptHash())); BigInteger balance = BigInteger.Parse(RpcSend("getwalletbalance", assetId)["balance"].AsString()); return new BigDecimal(balance, decimals); } @@ -452,7 +452,7 @@ public bool OpenWallet(string path, string password) /// This function returns Signed Transaction JSON if successful, ContractParametersContext JSON if signing failed. public JObject SendFrom(string assetId, string fromAddress, string toAddress, string amount) { - return RpcSend("sendfrom", assetId, fromAddress, toAddress, amount); + return RpcSend("sendfrom", assetId.AsScriptHash(), fromAddress.AsScriptHash(), toAddress.AsScriptHash(), amount); } /// @@ -464,7 +464,7 @@ public JObject SendMany(string fromAddress, IEnumerable outputs) var parameters = new List(); if (!string.IsNullOrEmpty(fromAddress)) { - parameters.Add(fromAddress); + parameters.Add(fromAddress.AsScriptHash()); } parameters.Add(outputs.Select(p => p.ToJson()).ToArray()); @@ -477,7 +477,7 @@ public JObject SendMany(string fromAddress, IEnumerable outputs) /// This function returns Signed Transaction JSON if successful, ContractParametersContext JSON if signing failed. public JObject SendToAddress(string assetId, string address, string amount) { - return RpcSend("sendtoaddress", assetId, address, amount); + return RpcSend("sendtoaddress", assetId.AsScriptHash(), address.AsScriptHash(), amount); } #endregion Wallet @@ -504,7 +504,7 @@ public RpcNep5Transfers GetNep5Transfers(string address, ulong? startTimestamp = { startTimestamp ??= 0; endTimestamp ??= DateTime.UtcNow.ToTimestampMS(); - return RpcNep5Transfers.FromJson(RpcSend("getnep5transfers", address, startTimestamp, endTimestamp)); + return RpcNep5Transfers.FromJson(RpcSend("getnep5transfers", address.AsScriptHash(), startTimestamp, endTimestamp)); } /// @@ -513,7 +513,7 @@ public RpcNep5Transfers GetNep5Transfers(string address, ulong? startTimestamp = /// public RpcNep5Balances GetNep5Balances(string address) { - return RpcNep5Balances.FromJson(RpcSend("getnep5balances", address)); + return RpcNep5Balances.FromJson(RpcSend("getnep5balances", address.AsScriptHash())); } #endregion Plugins diff --git a/src/RpcClient/Utility.cs b/src/RpcClient/Utility.cs index 6bca96b12..07a65ccff 100644 --- a/src/RpcClient/Utility.cs +++ b/src/RpcClient/Utility.cs @@ -2,6 +2,7 @@ using Neo.IO.Json; using Neo.Network.P2P.Payloads; using Neo.SmartContract; +using Neo.SmartContract.Native; using Neo.VM.Types; using Neo.Wallets; using System; @@ -27,6 +28,27 @@ private static (BigInteger numerator, BigInteger denominator) Fraction(decimal d return (numerator, denominator); } + public static UInt160 ToScriptHash(this JObject value) + { + var addressOrScriptHash = value.AsString(); + + return addressOrScriptHash.Length < 40 ? + addressOrScriptHash.ToScriptHash() : UInt160.Parse(addressOrScriptHash); + } + + public static string AsScriptHash(this string addressOrScriptHash) + { + foreach (var native in NativeContract.Contracts) + { + if (addressOrScriptHash.Equals(native.Name, StringComparison.InvariantCultureIgnoreCase) || + addressOrScriptHash == native.Id.ToString()) + return native.Hash.ToString(); + } + + return addressOrScriptHash.Length < 40 ? + addressOrScriptHash : UInt160.Parse(addressOrScriptHash).ToString(); + } + /// /// Parse WIF or private key hex string to KeyPair /// @@ -114,7 +136,7 @@ public static void FromJson(this BlockBase block, JObject json) block.MerkleRoot = UInt256.Parse(json["merkleroot"].AsString()); block.Timestamp = (ulong)json["time"].AsNumber(); block.Index = (uint)json["index"].AsNumber(); - block.NextConsensus = json["nextconsensus"].AsString().ToScriptHash(); + block.NextConsensus = json["nextconsensus"].ToScriptHash(); block.Witness = ((JArray)json["witnesses"]).Select(p => WitnessFromJson(p)).FirstOrDefault(); } @@ -145,9 +167,9 @@ public static Signer SignerFromJson(JObject json) { return new Signer { - Account = UInt160.Parse(json["account"].AsString()), + Account = json["account"].ToScriptHash(), Scopes = (WitnessScope)Enum.Parse(typeof(WitnessScope), json["scopes"].AsString()), - AllowedContracts = ((JArray)json["allowedContracts"])?.Select(p => UInt160.Parse(p.AsString())).ToArray(), + AllowedContracts = ((JArray)json["allowedContracts"])?.Select(p => p.ToScriptHash()).ToArray(), AllowedGroups = ((JArray)json["allowedGroups"])?.Select(p => ECPoint.Parse(p.AsString(), ECCurve.Secp256r1)).ToArray() }; } From a849d05d54a063ad6827f8d872d0d72f322e6107 Mon Sep 17 00:00:00 2001 From: Shargon Date: Wed, 16 Sep 2020 10:48:52 +0200 Subject: [PATCH 157/183] Update dependencies (#338) --- src/LevelDBStore/IO/Data/LevelDB/DB.cs | 20 ++++++-- src/LevelDBStore/IO/Data/LevelDB/Native.cs | 2 + src/LevelDBStore/LevelDBStore.csproj | 2 +- src/LevelDBStore/Plugins/Storage/Snapshot.cs | 5 ++ src/LevelDBStore/Plugins/Storage/Store.cs | 5 ++ src/RocksDBStore/Plugins/Storage/Snapshot.cs | 5 ++ src/RocksDBStore/Plugins/Storage/Store.cs | 5 ++ src/RocksDBStore/RocksDBStore.csproj | 2 +- src/RpcClient/RpcClient.cs | 11 ++++ src/RpcClient/RpcClient.csproj | 2 +- src/RpcClient/TransactionManager.cs | 51 +++++++------------ src/RpcClient/Utility.cs | 2 +- src/RpcNep5Tracker/DbCache.cs | 5 ++ src/RpcServer/RpcServer.Blockchain.cs | 4 +- src/RpcServer/RpcServer.Wallet.cs | 29 ++++++++++- src/RpcServer/RpcServer.csproj | 2 +- src/StatesDumper/StatesDumper.csproj | 2 +- .../UT_TransactionManager.cs | 17 ++++++- tests/Neo.Plugins.Storage.Tests/StoreTest.cs | 3 +- 19 files changed, 124 insertions(+), 50 deletions(-) diff --git a/src/LevelDBStore/IO/Data/LevelDB/DB.cs b/src/LevelDBStore/IO/Data/LevelDB/DB.cs index e8b1a33c1..56316ec7c 100644 --- a/src/LevelDBStore/IO/Data/LevelDB/DB.cs +++ b/src/LevelDBStore/IO/Data/LevelDB/DB.cs @@ -37,11 +37,7 @@ public byte[] Get(ReadOptions options, byte[] key) IntPtr value = Native.leveldb_get(handle, options.handle, key, (UIntPtr)key.Length, out UIntPtr length, out IntPtr error); try { - if (error != IntPtr.Zero) - { - Native.leveldb_free(error); - return null; - } + NativeHelper.CheckError(error); return value.ToByteArray(length); } finally @@ -50,6 +46,20 @@ public byte[] Get(ReadOptions options, byte[] key) } } + public bool Contains(ReadOptions options, byte[] key) + { + IntPtr value = Native.leveldb_get(handle, options.handle, key, (UIntPtr)key.Length, out _, out IntPtr error); + NativeHelper.CheckError(error); + + if (value != IntPtr.Zero) + { + Native.leveldb_free(value); + return true; + } + + return false; + } + public Snapshot GetSnapshot() { return new Snapshot(handle); diff --git a/src/LevelDBStore/IO/Data/LevelDB/Native.cs b/src/LevelDBStore/IO/Data/LevelDB/Native.cs index 8959ae390..1743989d7 100644 --- a/src/LevelDBStore/IO/Data/LevelDB/Native.cs +++ b/src/LevelDBStore/IO/Data/LevelDB/Native.cs @@ -1,4 +1,5 @@ using System; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; namespace Neo.IO.Data.LevelDB @@ -238,6 +239,7 @@ public static extern IntPtr /* leveldb_comparator_t* */ internal static class NativeHelper { + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void CheckError(IntPtr error) { if (error != IntPtr.Zero) diff --git a/src/LevelDBStore/LevelDBStore.csproj b/src/LevelDBStore/LevelDBStore.csproj index 9c57ece5c..f82c544ef 100644 --- a/src/LevelDBStore/LevelDBStore.csproj +++ b/src/LevelDBStore/LevelDBStore.csproj @@ -15,7 +15,7 @@ - + diff --git a/src/LevelDBStore/Plugins/Storage/Snapshot.cs b/src/LevelDBStore/Plugins/Storage/Snapshot.cs index 46d70d6fb..52c55dd60 100644 --- a/src/LevelDBStore/Plugins/Storage/Snapshot.cs +++ b/src/LevelDBStore/Plugins/Storage/Snapshot.cs @@ -47,6 +47,11 @@ public void Put(byte table, byte[] key, byte[] value) batch.Put(LHelper.CreateKey(table, key), value); } + public bool Contains(byte table, byte[] key) + { + return db.Contains(options, LHelper.CreateKey(table, key)); + } + public byte[] TryGet(byte table, byte[] key) { return db.Get(options, LHelper.CreateKey(table, key)); diff --git a/src/LevelDBStore/Plugins/Storage/Store.cs b/src/LevelDBStore/Plugins/Storage/Store.cs index 6d9aba937..c6f51092c 100644 --- a/src/LevelDBStore/Plugins/Storage/Store.cs +++ b/src/LevelDBStore/Plugins/Storage/Store.cs @@ -71,6 +71,11 @@ public void PutSync(byte table, byte[] key, byte[] value) db.Put(WriteOptions.SyncWrite, LHelper.CreateKey(table, key), value); } + public bool Contains(byte table, byte[] key) + { + return db.Contains(ReadOptions.Default, LHelper.CreateKey(table, key)); + } + public byte[] TryGet(byte table, byte[] key) { return db.Get(ReadOptions.Default, LHelper.CreateKey(table, key)); diff --git a/src/RocksDBStore/Plugins/Storage/Snapshot.cs b/src/RocksDBStore/Plugins/Storage/Snapshot.cs index 9bc924e26..d8159fef3 100644 --- a/src/RocksDBStore/Plugins/Storage/Snapshot.cs +++ b/src/RocksDBStore/Plugins/Storage/Snapshot.cs @@ -55,6 +55,11 @@ public void Put(byte table, byte[] key, byte[] value) yield return (it.Key(), it.Value()); } + public bool Contains(byte table, byte[] key) + { + return db.Get(key ?? Array.Empty(), store.GetFamily(table), options) != null; + } + public byte[] TryGet(byte table, byte[] key) { return db.Get(key ?? Array.Empty(), store.GetFamily(table), options); diff --git a/src/RocksDBStore/Plugins/Storage/Store.cs b/src/RocksDBStore/Plugins/Storage/Store.cs index ffdcba25f..c4eefe01b 100644 --- a/src/RocksDBStore/Plugins/Storage/Store.cs +++ b/src/RocksDBStore/Plugins/Storage/Store.cs @@ -103,6 +103,11 @@ public ISnapshot GetSnapshot() yield return (it.Key(), it.Value()); } + public bool Contains(byte table, byte[] key) + { + return db.Get(key ?? Array.Empty(), GetFamily(table), Options.ReadDefault) != null; + } + public byte[] TryGet(byte table, byte[] key) { return db.Get(key ?? Array.Empty(), GetFamily(table), Options.ReadDefault); diff --git a/src/RocksDBStore/RocksDBStore.csproj b/src/RocksDBStore/RocksDBStore.csproj index 5f67e8f73..b947a0132 100644 --- a/src/RocksDBStore/RocksDBStore.csproj +++ b/src/RocksDBStore/RocksDBStore.csproj @@ -14,7 +14,7 @@ - + diff --git a/src/RpcClient/RpcClient.cs b/src/RpcClient/RpcClient.cs index c43df5683..47605c2f4 100644 --- a/src/RpcClient/RpcClient.cs +++ b/src/RpcClient/RpcClient.cs @@ -227,6 +227,17 @@ public RpcTransaction GetRawTransaction(string txHash) return RpcTransaction.FromJson(RpcSend("getrawtransaction", txHash, true)); } + /// + /// Calculate network fee + /// + /// Transaction + /// NetworkFee + public long CalculateNetworkFee(Transaction tx) + { + var json = RpcSend("calculatenetworkfee", Convert.ToBase64String(tx.ToArray())); + return (long)json["networkfee"].AsNumber(); + } + /// /// Returns the stored value, according to the contract script hash (or Id) and the stored key. /// diff --git a/src/RpcClient/RpcClient.csproj b/src/RpcClient/RpcClient.csproj index 31e757d12..ae1f936f5 100644 --- a/src/RpcClient/RpcClient.csproj +++ b/src/RpcClient/RpcClient.csproj @@ -14,7 +14,7 @@ - + diff --git a/src/RpcClient/TransactionManager.cs b/src/RpcClient/TransactionManager.cs index cd7fe1e1f..ac38818de 100644 --- a/src/RpcClient/TransactionManager.cs +++ b/src/RpcClient/TransactionManager.cs @@ -1,5 +1,4 @@ using Neo.Cryptography.ECC; -using Neo.IO; using Neo.Network.P2P.Payloads; using Neo.Network.RPC.Models; using Neo.SmartContract; @@ -77,37 +76,6 @@ public TransactionManager MakeTransaction(byte[] script, Signer[] signers = null return this; } - /// - /// Calculate NetworkFee - /// - /// - private long CalculateNetworkFee() - { - long networkFee = 0; - UInt160[] hashes = Tx.GetScriptHashesForVerifying(null); - int size = Transaction.HeaderSize + Tx.Signers.GetVarSize() + Tx.Attributes.GetVarSize() + Tx.Script.GetVarSize() + IO.Helper.GetVarSize(hashes.Length); - foreach (UInt160 hash in hashes) - { - byte[] witness_script = null; - - // calculate NetworkFee - witness_script = signStore.FirstOrDefault(p => p.Contract.ScriptHash == hash)?.Contract?.Script; - if (witness_script is null || witness_script.Length == 0) - { - try - { - witness_script = rpcClient.GetContractState(hash.ToString())?.Script; - } - catch { } - } - - if (witness_script is null) continue; - networkFee += Wallet.CalculateNetworkFee(witness_script, ref size); - } - networkFee += size * policyAPI.GetFeePerByte(); - return networkFee; - } - /// /// Add Signature /// @@ -197,7 +165,14 @@ public TransactionManager AddWitness(UInt160 scriptHash, params object[] paramet public TransactionManager Sign() { // Calculate NetworkFee - Tx.NetworkFee = CalculateNetworkFee(); + Tx.Witnesses = Tx.GetScriptHashesForVerifying(null).Select(u => new Witness() + { + InvocationScript = Array.Empty(), + VerificationScript = GetVerificationScript(u) + }).ToArray(); + Tx.NetworkFee = rpcClient.CalculateNetworkFee(Tx); + Tx.Witnesses = null; + var gasBalance = nep5API.BalanceOf(NativeContract.GAS.Hash, Tx.Sender); if (gasBalance < Tx.SystemFee + Tx.NetworkFee) throw new InvalidOperationException($"Insufficient GAS in address: {Tx.Sender.ToAddress()}"); @@ -221,5 +196,15 @@ public TransactionManager Sign() Tx.Witnesses = context.GetWitnesses(); return this; } + + private byte[] GetVerificationScript(UInt160 hash) + { + foreach (var item in signStore) + { + if (item.Contract.ScriptHash == hash) return item.Contract.Script; + } + + return Array.Empty(); + } } } diff --git a/src/RpcClient/Utility.cs b/src/RpcClient/Utility.cs index 07a65ccff..8b1135249 100644 --- a/src/RpcClient/Utility.cs +++ b/src/RpcClient/Utility.cs @@ -177,7 +177,7 @@ public static Signer SignerFromJson(JObject json) public static ConsensusData ConsensusDataFromJson(JObject json) { ConsensusData block = new ConsensusData(); - block.PrimaryIndex = (uint)json["primary"].AsNumber(); + block.PrimaryIndex = (byte)json["primary"].AsNumber(); block.Nonce = ulong.Parse(json["nonce"].AsString(), NumberStyles.HexNumber); return block; } diff --git a/src/RpcNep5Tracker/DbCache.cs b/src/RpcNep5Tracker/DbCache.cs index 9cfd27e35..a16ab37ad 100644 --- a/src/RpcNep5Tracker/DbCache.cs +++ b/src/RpcNep5Tracker/DbCache.cs @@ -57,6 +57,11 @@ protected override TValue GetInternal(TKey key) return TryGetInternal(key) ?? throw new InvalidOperationException(); } + protected override bool ContainsInternal(TKey key) + { + return db.Contains(options, CreateKey(prefix, key)); + } + protected override TValue TryGetInternal(TKey key) { return db.Get(options, CreateKey(prefix, key))?.AsSerializable(); diff --git a/src/RpcServer/RpcServer.Blockchain.cs b/src/RpcServer/RpcServer.Blockchain.cs index 18000383a..25ae58acc 100644 --- a/src/RpcServer/RpcServer.Blockchain.cs +++ b/src/RpcServer/RpcServer.Blockchain.cs @@ -181,10 +181,10 @@ private JObject GetTransactionHeight(JArray _params) } [RpcMethod] - private JObject GetValidators(JArray _params) + private JObject GetNextBlockValidators(JArray _params) { using SnapshotView snapshot = Blockchain.Singleton.GetSnapshot(); - var validators = NativeContract.NEO.GetValidators(snapshot); + var validators = NativeContract.NEO.GetNextBlockValidators(snapshot); return NativeContract.NEO.GetCandidates(snapshot).Select(p => { JObject validator = new JObject(); diff --git a/src/RpcServer/RpcServer.Wallet.cs b/src/RpcServer/RpcServer.Wallet.cs index e55471c7e..5bcff2b39 100644 --- a/src/RpcServer/RpcServer.Wallet.cs +++ b/src/RpcServer/RpcServer.Wallet.cs @@ -5,7 +5,6 @@ using Neo.IO; using Neo.IO.Json; using Neo.Ledger; -using Neo.Network.P2P; using Neo.Network.P2P.Payloads; using Neo.Persistence; using Neo.SmartContract; @@ -14,6 +13,7 @@ using Neo.Wallets.NEP6; using Neo.Wallets.SQLite; using System; +using System.Collections.Generic; using System.IO; using System.Linq; using System.Numerics; @@ -23,6 +23,23 @@ namespace Neo.Plugins { partial class RpcServer { + private class DummyWallet : Wallet + { + public DummyWallet() : base("") { } + public override string Name => ""; + public override Version Version => new Version(); + + public override bool ChangePassword(string oldPassword, string newPassword) => false; + public override bool Contains(UInt160 scriptHash) => false; + public override WalletAccount CreateAccount(byte[] privateKey) => null; + public override WalletAccount CreateAccount(Contract contract, KeyPair key = null) => null; + public override WalletAccount CreateAccount(UInt160 scriptHash) => null; + public override bool DeleteAccount(UInt160 scriptHash) => false; + public override WalletAccount GetAccount(UInt160 scriptHash) => null; + public override IEnumerable GetAccounts() => Array.Empty(); + public override bool VerifyPassword(string password) => false; + } + private Wallet wallet; private void CheckWallet() @@ -97,6 +114,16 @@ private JObject ImportPrivKey(JArray _params) }; } + [RpcMethod] + private JObject CalculateNetworkFee(JArray _params) + { + byte[] tx = Convert.FromBase64String(_params[0].AsString()); + + JObject account = new JObject(); + account["networkfee"] = (wallet ?? new DummyWallet()).CalculateNetworkFee(Blockchain.Singleton.GetSnapshot(), tx.AsSerializable()); + return account; + } + [RpcMethod] private JObject ListAddress(JArray _params) { diff --git a/src/RpcServer/RpcServer.csproj b/src/RpcServer/RpcServer.csproj index a9e4b71ad..9a9129daf 100644 --- a/src/RpcServer/RpcServer.csproj +++ b/src/RpcServer/RpcServer.csproj @@ -15,7 +15,7 @@ - + diff --git a/src/StatesDumper/StatesDumper.csproj b/src/StatesDumper/StatesDumper.csproj index 9e695830a..2865673e4 100644 --- a/src/StatesDumper/StatesDumper.csproj +++ b/src/StatesDumper/StatesDumper.csproj @@ -14,7 +14,7 @@ - + diff --git a/tests/Neo.Network.RPC.Tests/UT_TransactionManager.cs b/tests/Neo.Network.RPC.Tests/UT_TransactionManager.cs index b1546a9c7..a9802fec0 100644 --- a/tests/Neo.Network.RPC.Tests/UT_TransactionManager.cs +++ b/tests/Neo.Network.RPC.Tests/UT_TransactionManager.cs @@ -46,6 +46,13 @@ public static Mock MockRpcClient(UInt160 sender, byte[] script) // MockHeight mockRpc.Setup(p => p.RpcSend("getblockcount")).Returns(100).Verifiable(); + // calculatenetworkfee + var networkfee = new JObject(); + networkfee["networkfee"] = 100000000; + mockRpc.Setup(p => p.RpcSend("calculatenetworkfee", It.Is(u => true))) + .Returns(networkfee) + .Verifiable(); + // MockGasBalance byte[] balanceScript = NativeContract.GAS.Hash.MakeScript("balanceOf", sender); var balanceResult = new ContractParameter() { Type = ContractParameterType.Integer, Value = BigInteger.Parse("10000000000000000") }; @@ -72,6 +79,13 @@ public static Mock MockMultiSig(UInt160 multiHash, byte[] script) // MockHeight mockRpc.Setup(p => p.RpcSend("getblockcount")).Returns(100).Verifiable(); + // calculatenetworkfee + var networkfee = new JObject(); + networkfee["networkfee"] = 100000000; + mockRpc.Setup(p => p.RpcSend("calculatenetworkfee", It.Is(u => true))) + .Returns(networkfee) + .Verifiable(); + // MockGasBalance byte[] balanceScript = NativeContract.GAS.Hash.MakeScript("balanceOf", multiHash); var balanceResult = new ContractParameter() { Type = ContractParameterType.Integer, Value = BigInteger.Parse("10000000000000000") }; @@ -152,8 +166,7 @@ public void TestSign() Assert.IsTrue(Crypto.VerifySignature(tx.GetHashData(), signature, keyPair1.PublicKey)); // verify network fee and system fee - long networkFee = tx.Size * (long)1000 + ApplicationEngine.OpCodePrices[OpCode.PUSHDATA1] + ApplicationEngine.OpCodePrices[OpCode.PUSHDATA1] + ApplicationEngine.OpCodePrices[OpCode.PUSHNULL] + ApplicationEngine.ECDsaVerifyPrice * 1; - Assert.AreEqual(networkFee, tx.NetworkFee); + Assert.AreEqual(100000000/*Mock*/, tx.NetworkFee); Assert.AreEqual(100, tx.SystemFee); // duplicate sign should not add new witness diff --git a/tests/Neo.Plugins.Storage.Tests/StoreTest.cs b/tests/Neo.Plugins.Storage.Tests/StoreTest.cs index d19290dc6..a09bedacb 100644 --- a/tests/Neo.Plugins.Storage.Tests/StoreTest.cs +++ b/tests/Neo.Plugins.Storage.Tests/StoreTest.cs @@ -1,6 +1,5 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.Persistence; -using System; namespace Neo.Plugins.Storage.Tests { @@ -57,9 +56,11 @@ private void TestStorage(IStore store) store.Put(0, new byte[] { 0x01, 0x02 }, new byte[] { 0x03, 0x04 }); ret = store.TryGet(0, new byte[] { 0x01, 0x02 }); CollectionAssert.AreEqual(new byte[] { 0x03, 0x04 }, ret); + Assert.IsTrue(store.Contains(0, new byte[] { 0x01, 0x02 })); ret = store.TryGet(1, new byte[] { 0x01, 0x02 }); Assert.IsNull(ret); + Assert.IsFalse(store.Contains(1, new byte[] { 0x01, 0x02 })); store.Delete(0, new byte[] { 0x01, 0x02 }); From fed3f7a87d65d91bbe4e42bce94734cc76571d5c Mon Sep 17 00:00:00 2001 From: Luchuan Date: Fri, 25 Sep 2020 17:47:57 +0800 Subject: [PATCH 158/183] Neo 3.0.0-CI01036 (#353) * upgrade neo-core * Add statesdumper Co-authored-by: Shargon --- src/LevelDBStore/LevelDBStore.csproj | 2 +- src/RocksDBStore/RocksDBStore.csproj | 2 +- src/RpcClient/RpcClient.csproj | 2 +- src/RpcServer/RpcServer.csproj | 2 +- src/StatesDumper/StatesDumper.csproj | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/LevelDBStore/LevelDBStore.csproj b/src/LevelDBStore/LevelDBStore.csproj index f82c544ef..b0fd1b983 100644 --- a/src/LevelDBStore/LevelDBStore.csproj +++ b/src/LevelDBStore/LevelDBStore.csproj @@ -15,7 +15,7 @@ - + diff --git a/src/RocksDBStore/RocksDBStore.csproj b/src/RocksDBStore/RocksDBStore.csproj index b947a0132..53ff6b564 100644 --- a/src/RocksDBStore/RocksDBStore.csproj +++ b/src/RocksDBStore/RocksDBStore.csproj @@ -14,7 +14,7 @@ - + diff --git a/src/RpcClient/RpcClient.csproj b/src/RpcClient/RpcClient.csproj index ae1f936f5..1aa80c1a3 100644 --- a/src/RpcClient/RpcClient.csproj +++ b/src/RpcClient/RpcClient.csproj @@ -14,7 +14,7 @@ - + diff --git a/src/RpcServer/RpcServer.csproj b/src/RpcServer/RpcServer.csproj index 9a9129daf..7bceda3c2 100644 --- a/src/RpcServer/RpcServer.csproj +++ b/src/RpcServer/RpcServer.csproj @@ -15,7 +15,7 @@ - + diff --git a/src/StatesDumper/StatesDumper.csproj b/src/StatesDumper/StatesDumper.csproj index 2865673e4..2d144d45b 100644 --- a/src/StatesDumper/StatesDumper.csproj +++ b/src/StatesDumper/StatesDumper.csproj @@ -14,7 +14,7 @@ - + From 81e07af27db214cca0f7287a81041ca79e201379 Mon Sep 17 00:00:00 2001 From: Luchuan Date: Mon, 12 Oct 2020 14:39:20 +0800 Subject: [PATCH 159/183] Replace getvalidators by getnextblockvalidators (#366) --- src/RpcClient/RpcClient.cs | 6 +++--- tests/Neo.Network.RPC.Tests/RpcTestCases.json | 4 ++-- tests/Neo.Network.RPC.Tests/UT_RpcClient.cs | 6 +++--- tests/Neo.Network.RPC.Tests/UT_RpcModels.cs | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/RpcClient/RpcClient.cs b/src/RpcClient/RpcClient.cs index 47605c2f4..d6f3411c7 100644 --- a/src/RpcClient/RpcClient.cs +++ b/src/RpcClient/RpcClient.cs @@ -260,11 +260,11 @@ public uint GetTransactionHeight(string txHash) } /// - /// Returns the current NEO consensus nodes information and voting status. + /// Returns the next NEO consensus nodes information and voting status. /// - public RpcValidator[] GetValidators() + public RpcValidator[] GetNextBlockValidators() { - return ((JArray)RpcSend("getvalidators")).Select(p => RpcValidator.FromJson(p)).ToArray(); + return ((JArray)RpcSend("getnextblockvalidators")).Select(p => RpcValidator.FromJson(p)).ToArray(); } /// diff --git a/tests/Neo.Network.RPC.Tests/RpcTestCases.json b/tests/Neo.Network.RPC.Tests/RpcTestCases.json index 5dccd0d73..845741690 100644 --- a/tests/Neo.Network.RPC.Tests/RpcTestCases.json +++ b/tests/Neo.Network.RPC.Tests/RpcTestCases.json @@ -587,10 +587,10 @@ } }, { - "Name": "getvalidators", + "Name": "getnextblockvalidators", "Request": { "jsonrpc": "2.0", - "method": "getvalidators", + "method": "getnextblockvalidators", "params": [], "id": 1 }, diff --git a/tests/Neo.Network.RPC.Tests/UT_RpcClient.cs b/tests/Neo.Network.RPC.Tests/UT_RpcClient.cs index 302040e47..1c4287d91 100644 --- a/tests/Neo.Network.RPC.Tests/UT_RpcClient.cs +++ b/tests/Neo.Network.RPC.Tests/UT_RpcClient.cs @@ -218,10 +218,10 @@ public void TestGetTransactionHeight() } [TestMethod] - public void TestGetValidators() + public void TestGetNextBlockValidators() { - var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetValidators).ToLower()); - var result = rpc.GetValidators(); + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetNextBlockValidators).ToLower()); + var result = rpc.GetNextBlockValidators(); Assert.AreEqual(test.Response.Result.ToString(), ((JArray)result.Select(p => p.ToJson()).ToArray()).ToString()); } diff --git a/tests/Neo.Network.RPC.Tests/UT_RpcModels.cs b/tests/Neo.Network.RPC.Tests/UT_RpcModels.cs index 313f757f6..559e1f748 100644 --- a/tests/Neo.Network.RPC.Tests/UT_RpcModels.cs +++ b/tests/Neo.Network.RPC.Tests/UT_RpcModels.cs @@ -123,7 +123,7 @@ public void TestRpcValidateAddressResult() [TestMethod()] public void TestRpcValidator() { - JObject json = TestUtils.RpcTestCases.Find(p => p.Name == nameof(RpcClient.GetValidators).ToLower()).Response.Result; + JObject json = TestUtils.RpcTestCases.Find(p => p.Name == nameof(RpcClient.GetNextBlockValidators).ToLower()).Response.Result; var item = ((JArray)json).Select(p => RpcValidator.FromJson(p)); Assert.AreEqual(json.ToString(), ((JArray)item.Select(p => p.ToJson()).ToArray()).ToString()); } From 65e8b9b37a227d0288035da402cbeb4ab5346983 Mon Sep 17 00:00:00 2001 From: Harry Pierson Date: Wed, 14 Oct 2020 19:30:29 -0700 Subject: [PATCH 160/183] Pure async RpcClient (#335) * compiling, some stuff stubbed out * more tests working * MakeTxContext * mistake in GetBlock/GetBlockHeader * rework TransactionManager to be closer to original * more unit tests (2 still failing) * remove assertEx * Add ThrowsAsync comment * ReturnsAsync * fixed last remaining test issues * minor TXManager cleanup * formatting * move tx contruction to MakeTransaction * discards * Async Suffixes (PR feedback) * GetCommitteeAsync * add custom magic support to tx manager * fix format * add magic param comment * CR Feedback * Clean enter Co-authored-by: Harry Co-authored-by: Shargon --- src/RpcClient/ContractClient.cs | 27 +- src/RpcClient/Nep5API.cs | 68 +++-- src/RpcClient/PolicyAPI.cs | 23 +- src/RpcClient/RpcClient.cs | 279 ++++++++++-------- src/RpcClient/TransactionManager.cs | 89 +++--- src/RpcClient/TransactionManagerFactory.cs | 57 ++++ src/RpcClient/WalletAPI.cs | 57 ++-- tests/Neo.Network.RPC.Tests/RpcTestCases.json | 94 +++--- .../UT_ContractClient.cs | 9 +- tests/Neo.Network.RPC.Tests/UT_Nep5API.cs | 29 +- tests/Neo.Network.RPC.Tests/UT_PolicyAPI.cs | 17 +- tests/Neo.Network.RPC.Tests/UT_RpcClient.cs | 248 ++++++++-------- tests/Neo.Network.RPC.Tests/UT_RpcModels.cs | 32 +- .../UT_TransactionManager.cs | 77 +++-- tests/Neo.Network.RPC.Tests/UT_WalletAPI.cs | 43 +-- 15 files changed, 633 insertions(+), 516 deletions(-) create mode 100644 src/RpcClient/TransactionManagerFactory.cs diff --git a/src/RpcClient/ContractClient.cs b/src/RpcClient/ContractClient.cs index 0aa3aff3b..a6ffb8f28 100644 --- a/src/RpcClient/ContractClient.cs +++ b/src/RpcClient/ContractClient.cs @@ -1,3 +1,5 @@ +using System; +using System.Threading.Tasks; using Neo.Network.P2P.Payloads; using Neo.Network.RPC.Models; using Neo.SmartContract; @@ -13,14 +15,21 @@ namespace Neo.Network.RPC public class ContractClient { protected readonly RpcClient rpcClient; + protected readonly uint? magic; + /// /// ContractClient Constructor /// /// the RPC client to call NEO RPC methods - public ContractClient(RpcClient rpc) + /// + /// the network Magic value to use when signing transactions. + /// Defaults to ProtocolSettings.Default.Magic if not specified. + /// + public ContractClient(RpcClient rpc, uint? magic = null) { rpcClient = rpc; + this.magic = magic; } /// @@ -30,10 +39,10 @@ public ContractClient(RpcClient rpc) /// contract operation /// operation arguments /// - public RpcInvokeResult TestInvoke(UInt160 scriptHash, string operation, params object[] args) + public Task TestInvokeAsync(UInt160 scriptHash, string operation, params object[] args) { byte[] script = scriptHash.MakeScript(operation, args); - return rpcClient.InvokeScript(script); + return rpcClient.InvokeScriptAsync(script); } /// @@ -43,7 +52,7 @@ public RpcInvokeResult TestInvoke(UInt160 scriptHash, string operation, params o /// contract manifest /// sender KeyPair /// - public Transaction CreateDeployContractTx(byte[] contractScript, ContractManifest manifest, KeyPair key) + public async Task CreateDeployContractTxAsync(byte[] contractScript, ContractManifest manifest, KeyPair key) { byte[] script; using (ScriptBuilder sb = new ScriptBuilder()) @@ -54,13 +63,11 @@ public Transaction CreateDeployContractTx(byte[] contractScript, ContractManifes UInt160 sender = Contract.CreateSignatureRedeemScript(key.PublicKey).ToScriptHash(); Signer[] signers = new[] { new Signer { Scopes = WitnessScope.CalledByEntry, Account = sender } }; - Transaction tx = new TransactionManager(rpcClient) - .MakeTransaction(script, signers) + TransactionManagerFactory factory = new TransactionManagerFactory(rpcClient, magic); + TransactionManager manager = await factory.MakeTransactionAsync(script, signers).ConfigureAwait(false); + return await manager .AddSignature(key) - .Sign() - .Tx; - - return tx; + .SignAsync().ConfigureAwait(false); } } } diff --git a/src/RpcClient/Nep5API.cs b/src/RpcClient/Nep5API.cs index c700d5c68..59cadd67e 100644 --- a/src/RpcClient/Nep5API.cs +++ b/src/RpcClient/Nep5API.cs @@ -7,6 +7,7 @@ using System; using System.Linq; using System.Numerics; +using System.Threading.Tasks; using static Neo.Helper; namespace Neo.Network.RPC @@ -28,9 +29,10 @@ public Nep5API(RpcClient rpcClient) : base(rpcClient) { } /// contract script hash /// account script hash /// - public BigInteger BalanceOf(UInt160 scriptHash, UInt160 account) + public async Task BalanceOfAsync(UInt160 scriptHash, UInt160 account) { - BigInteger balance = TestInvoke(scriptHash, "balanceOf", account).Stack.Single().GetInteger(); + var result = await TestInvokeAsync(scriptHash, "balanceOf", account).ConfigureAwait(false); + BigInteger balance = result.Stack.Single().GetInteger(); return balance; } @@ -39,9 +41,10 @@ public BigInteger BalanceOf(UInt160 scriptHash, UInt160 account) /// /// contract script hash /// - public string Name(UInt160 scriptHash) + public async Task NameAsync(UInt160 scriptHash) { - return TestInvoke(scriptHash, "name").Stack.Single().GetString(); + var result = await TestInvokeAsync(scriptHash, "name").ConfigureAwait(false); + return result.Stack.Single().GetString(); } /// @@ -49,9 +52,10 @@ public string Name(UInt160 scriptHash) /// /// contract script hash /// - public string Symbol(UInt160 scriptHash) + public async Task SymbolAsync(UInt160 scriptHash) { - return TestInvoke(scriptHash, "symbol").Stack.Single().GetString(); + var result = await TestInvokeAsync(scriptHash, "symbol").ConfigureAwait(false); + return result.Stack.Single().GetString(); } /// @@ -59,9 +63,10 @@ public string Symbol(UInt160 scriptHash) /// /// contract script hash /// - public byte Decimals(UInt160 scriptHash) + public async Task DecimalsAsync(UInt160 scriptHash) { - return (byte)TestInvoke(scriptHash, "decimals").Stack.Single().GetInteger(); + var result = await TestInvokeAsync(scriptHash, "decimals").ConfigureAwait(false); + return (byte)result.Stack.Single().GetInteger(); } /// @@ -69,9 +74,10 @@ public byte Decimals(UInt160 scriptHash) /// /// contract script hash /// - public BigInteger TotalSupply(UInt160 scriptHash) + public async Task TotalSupplyAsync(UInt160 scriptHash) { - return TestInvoke(scriptHash, "totalSupply").Stack.Single().GetInteger(); + var result = await TestInvokeAsync(scriptHash, "totalSupply").ConfigureAwait(false); + return result.Stack.Single().GetInteger(); } /// @@ -79,21 +85,23 @@ public BigInteger TotalSupply(UInt160 scriptHash) /// /// contract script hash /// - public RpcNep5TokenInfo GetTokenInfo(UInt160 scriptHash) + public async Task GetTokenInfoAsync(UInt160 scriptHash) { - byte[] script = Concat(scriptHash.MakeScript("name"), + byte[] script = Concat( + scriptHash.MakeScript("name"), scriptHash.MakeScript("symbol"), scriptHash.MakeScript("decimals"), scriptHash.MakeScript("totalSupply")); - var result = rpcClient.InvokeScript(script).Stack; + var result = await rpcClient.InvokeScriptAsync(script).ConfigureAwait(false); + var stack = result.Stack; return new RpcNep5TokenInfo { - Name = result[0].GetString(), - Symbol = result[1].GetString(), - Decimals = (byte)result[2].GetInteger(), - TotalSupply = result[3].GetInteger() + Name = stack[0].GetString(), + Symbol = stack[1].GetString(), + Decimals = (byte)stack[2].GetInteger(), + TotalSupply = stack[3].GetInteger() }; } @@ -105,19 +113,18 @@ public RpcNep5TokenInfo GetTokenInfo(UInt160 scriptHash) /// to account script hash /// transfer amount /// - public Transaction CreateTransferTx(UInt160 scriptHash, KeyPair fromKey, UInt160 to, BigInteger amount) + public async Task CreateTransferTxAsync(UInt160 scriptHash, KeyPair fromKey, UInt160 to, BigInteger amount) { var sender = Contract.CreateSignatureRedeemScript(fromKey.PublicKey).ToScriptHash(); Signer[] signers = new[] { new Signer { Scopes = WitnessScope.CalledByEntry, Account = sender } }; byte[] script = scriptHash.MakeScript("transfer", sender, to, amount); - Transaction tx = new TransactionManager(rpcClient) - .MakeTransaction(script, signers) - .AddSignature(fromKey) - .Sign() - .Tx; - return tx; + TransactionManagerFactory factory = new TransactionManagerFactory(rpcClient, magic); + TransactionManager manager = await factory.MakeTransactionAsync(script, signers).ConfigureAwait(false); + return await manager + .AddSignature(fromKey) + .SignAsync().ConfigureAwait(false); } /// @@ -130,7 +137,7 @@ public Transaction CreateTransferTx(UInt160 scriptHash, KeyPair fromKey, UInt160 /// to account /// transfer amount /// - public Transaction CreateTransferTx(UInt160 scriptHash, int m, ECPoint[] pubKeys, KeyPair[] fromKeys, UInt160 to, BigInteger amount) + public async Task CreateTransferTxAsync(UInt160 scriptHash, int m, ECPoint[] pubKeys, KeyPair[] fromKeys, UInt160 to, BigInteger amount) { if (m > fromKeys.Length) throw new ArgumentException($"Need at least {m} KeyPairs for signing!"); @@ -138,13 +145,12 @@ public Transaction CreateTransferTx(UInt160 scriptHash, int m, ECPoint[] pubKeys Signer[] signers = new[] { new Signer { Scopes = WitnessScope.CalledByEntry, Account = sender } }; byte[] script = scriptHash.MakeScript("transfer", sender, to, amount); - Transaction tx = new TransactionManager(rpcClient) - .MakeTransaction(script, signers) - .AddMultiSig(fromKeys, m, pubKeys) - .Sign() - .Tx; - return tx; + TransactionManagerFactory factory = new TransactionManagerFactory(rpcClient, magic); + TransactionManager manager = await factory.MakeTransactionAsync(script, signers).ConfigureAwait(false); + return await manager + .AddMultiSig(fromKeys, m, pubKeys) + .SignAsync().ConfigureAwait(false); } } } diff --git a/src/RpcClient/PolicyAPI.cs b/src/RpcClient/PolicyAPI.cs index 073b105b3..540f945da 100644 --- a/src/RpcClient/PolicyAPI.cs +++ b/src/RpcClient/PolicyAPI.cs @@ -1,6 +1,7 @@ using Neo.SmartContract.Native; using Neo.VM; using System.Linq; +using System.Threading.Tasks; namespace Neo.Network.RPC { @@ -21,37 +22,41 @@ public PolicyAPI(RpcClient rpcClient) : base(rpcClient) { } /// Get Max Transactions Count Per Block /// /// - public uint GetMaxTransactionsPerBlock() + public async Task GetMaxTransactionsPerBlockAsync() { - return (uint)TestInvoke(scriptHash, "getMaxTransactionsPerBlock").Stack.Single().GetInteger(); + var result = await TestInvokeAsync(scriptHash, "getMaxTransactionsPerBlock").ConfigureAwait(false); + return (uint)result.Stack.Single().GetInteger(); } /// /// Get Max Block Size /// /// - public uint GetMaxBlockSize() + public async Task GetMaxBlockSizeAsync() { - return (uint)TestInvoke(scriptHash, "getMaxBlockSize").Stack.Single().GetInteger(); + var result = await TestInvokeAsync(scriptHash, "getMaxBlockSize").ConfigureAwait(false); + return (uint)result.Stack.Single().GetInteger(); } /// /// Get Network Fee Per Byte /// /// - public long GetFeePerByte() + public async Task GetFeePerByteAsync() { - return (long)TestInvoke(scriptHash, "getFeePerByte").Stack.Single().GetInteger(); + var result = await TestInvokeAsync(scriptHash, "getFeePerByte").ConfigureAwait(false); + return (long)result.Stack.Single().GetInteger(); } /// /// Get Ploicy Blocked Accounts /// /// - public UInt160[] GetBlockedAccounts() + public async Task GetBlockedAccountsAsync() { - var result = (VM.Types.Array)TestInvoke(scriptHash, "getBlockedAccounts").Stack.Single(); - return result.Select(p => new UInt160(p.GetSpan().ToArray())).ToArray(); + var result = await TestInvokeAsync(scriptHash, "getBlockedAccounts").ConfigureAwait(false); + var array = (VM.Types.Array)result.Stack.Single(); + return array.Select(p => new UInt160(p.GetSpan().ToArray())).ToArray(); } } } diff --git a/src/RpcClient/RpcClient.cs b/src/RpcClient/RpcClient.cs index d6f3411c7..6d81f9b86 100644 --- a/src/RpcClient/RpcClient.cs +++ b/src/RpcClient/RpcClient.cs @@ -20,11 +20,13 @@ namespace Neo.Network.RPC /// public class RpcClient : IDisposable { - private HttpClient httpClient; + private readonly HttpClient httpClient; + private readonly string baseAddress; public RpcClient(string url, string rpcUser = default, string rpcPass = default) { - httpClient = new HttpClient() { BaseAddress = new Uri(url) }; + httpClient = new HttpClient(); + baseAddress = url; if (!string.IsNullOrEmpty(rpcUser) && !string.IsNullOrEmpty(rpcPass)) { string token = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{rpcUser}:{rpcPass}")); @@ -32,9 +34,10 @@ public RpcClient(string url, string rpcUser = default, string rpcPass = default) } } - public RpcClient(HttpClient client) + public RpcClient(HttpClient client, string url) { httpClient = client; + baseAddress = url; } #region IDisposable Support @@ -46,10 +49,9 @@ protected virtual void Dispose(bool disposing) { if (disposing) { - httpClient?.Dispose(); + httpClient.Dispose(); } - httpClient = null; disposedValue = true; } } @@ -62,8 +64,10 @@ public void Dispose() public async Task SendAsync(RpcRequest request) { + if (disposedValue) throw new ObjectDisposedException(nameof(RpcClient)); + var requestJson = request.ToJson().ToString(); - using var result = await httpClient.PostAsync(httpClient.BaseAddress, new StringContent(requestJson, Encoding.UTF8)); + using var result = await httpClient.PostAsync(baseAddress, new StringContent(requestJson, Encoding.UTF8)).ConfigureAwait(false); var content = await result.Content.ReadAsStringAsync(); var response = RpcResponse.FromJson(JObject.Parse(content)); response.RawResponse = content; @@ -76,19 +80,7 @@ public async Task SendAsync(RpcRequest request) return response; } - public RpcResponse Send(RpcRequest request) - { - try - { - return SendAsync(request).Result; - } - catch (AggregateException ex) - { - throw ex.GetBaseException(); - } - } - - public virtual JObject RpcSend(string method, params JObject[] paraArgs) + public virtual async Task RpcSendAsync(string method, params JObject[] paraArgs) { var request = new RpcRequest { @@ -97,7 +89,9 @@ public virtual JObject RpcSend(string method, params JObject[] paraArgs) Method = method, Params = paraArgs }; - return Send(request).Result; + + var response = await SendAsync(request).ConfigureAwait(false); + return response.Result; } #region Blockchain @@ -105,82 +99,84 @@ public virtual JObject RpcSend(string method, params JObject[] paraArgs) /// /// Returns the hash of the tallest block in the main chain. /// - public string GetBestBlockHash() + public async Task GetBestBlockHashAsync() { - return RpcSend("getbestblockhash").AsString(); + var result = await RpcSendAsync("getbestblockhash").ConfigureAwait(false); + return result.AsString(); } /// /// Returns the hash of the tallest block in the main chain. /// The serialized information of the block is returned, represented by a hexadecimal string. /// - public string GetBlockHex(string hashOrIndex) + public async Task GetBlockHexAsync(string hashOrIndex) { - if (int.TryParse(hashOrIndex, out int index)) - { - return RpcSend("getblock", index).AsString(); - } - return RpcSend("getblock", hashOrIndex).AsString(); + var result = int.TryParse(hashOrIndex, out int index) + ? await RpcSendAsync("getblock", index).ConfigureAwait(false) + : await RpcSendAsync("getblock", hashOrIndex).ConfigureAwait(false); + return result.AsString(); } /// /// Returns the hash of the tallest block in the main chain. /// - public RpcBlock GetBlock(string hashOrIndex) + public async Task GetBlockAsync(string hashOrIndex) { - if (int.TryParse(hashOrIndex, out int index)) - { - return RpcBlock.FromJson(RpcSend("getblock", index, true)); - } - return RpcBlock.FromJson(RpcSend("getblock", hashOrIndex, true)); + var result = int.TryParse(hashOrIndex, out int index) + ? await RpcSendAsync("getblock", index, true).ConfigureAwait(false) + : await RpcSendAsync("getblock", hashOrIndex, true).ConfigureAwait(false); + + return RpcBlock.FromJson(result); } /// /// Gets the number of blocks in the main chain. /// - public uint GetBlockCount() + public async Task GetBlockCountAsync() { - return (uint)RpcSend("getblockcount").AsNumber(); + var result = await RpcSendAsync("getblockcount").ConfigureAwait(false); + return (uint)result.AsNumber(); } /// /// Returns the hash value of the corresponding block, based on the specified index. /// - public string GetBlockHash(int index) + public async Task GetBlockHashAsync(int index) { - return RpcSend("getblockhash", index).AsString(); + var result = await RpcSendAsync("getblockhash", index).ConfigureAwait(false); + return result.AsString(); } /// /// Returns the corresponding block header information according to the specified script hash. /// - public string GetBlockHeaderHex(string hashOrIndex) + public async Task GetBlockHeaderHexAsync(string hashOrIndex) { - if (int.TryParse(hashOrIndex, out int index)) - { - return RpcSend("getblockheader", index).AsString(); - } - return RpcSend("getblockheader", hashOrIndex).AsString(); + var result = int.TryParse(hashOrIndex, out int index) + ? await RpcSendAsync("getblockheader", index).ConfigureAwait(false) + : await RpcSendAsync("getblockheader", hashOrIndex).ConfigureAwait(false); + return result.AsString(); } /// /// Returns the corresponding block header information according to the specified script hash. /// - public RpcBlockHeader GetBlockHeader(string hashOrIndex) + public async Task GetBlockHeaderAsync(string hashOrIndex) { - if (int.TryParse(hashOrIndex, out int index)) - { - return RpcBlockHeader.FromJson(RpcSend("getblockheader", index, true)); - } - return RpcBlockHeader.FromJson(RpcSend("getblockheader", hashOrIndex, true)); + var result = int.TryParse(hashOrIndex, out int index) + ? await RpcSendAsync("getblockheader", index, true).ConfigureAwait(false) + : await RpcSendAsync("getblockheader", hashOrIndex, true).ConfigureAwait(false); + + return RpcBlockHeader.FromJson(result); } /// /// Queries contract information, according to the contract script hash. /// - public ContractState GetContractState(string hash) + public async Task GetContractStateAsync(string hash) { - return ContractStateFromJson(RpcSend("getcontractstate", hash)); + var result = await RpcSendAsync("getcontractstate", hash).ConfigureAwait(false); + return ContractStateFromJson(result); } public static ContractState ContractStateFromJson(JObject json) @@ -196,35 +192,39 @@ public static ContractState ContractStateFromJson(JObject json) /// /// Obtains the list of unconfirmed transactions in memory. /// - public string[] GetRawMempool() + public async Task GetRawMempoolAsync() { - return ((JArray)RpcSend("getrawmempool")).Select(p => p.AsString()).ToArray(); + var result = await RpcSendAsync("getrawmempool").ConfigureAwait(false); + return ((JArray)result).Select(p => p.AsString()).ToArray(); } /// /// Obtains the list of unconfirmed transactions in memory. /// shouldGetUnverified = true /// - public RpcRawMemPool GetRawMempoolBoth() + public async Task GetRawMempoolBothAsync() { - return RpcRawMemPool.FromJson(RpcSend("getrawmempool", true)); + var result = await RpcSendAsync("getrawmempool", true).ConfigureAwait(false); + return RpcRawMemPool.FromJson(result); } /// /// Returns the corresponding transaction information, based on the specified hash value. /// - public string GetRawTransactionHex(string txHash) + public async Task GetRawTransactionHexAsync(string txHash) { - return RpcSend("getrawtransaction", txHash).AsString(); + var result = await RpcSendAsync("getrawtransaction", txHash).ConfigureAwait(false); + return result.AsString(); } /// /// Returns the corresponding transaction information, based on the specified hash value. /// verbose = true /// - public RpcTransaction GetRawTransaction(string txHash) + public async Task GetRawTransactionAsync(string txHash) { - return RpcTransaction.FromJson(RpcSend("getrawtransaction", txHash, true)); + var result = await RpcSendAsync("getrawtransaction", txHash, true).ConfigureAwait(false); + return RpcTransaction.FromJson(result); } /// @@ -232,47 +232,49 @@ public RpcTransaction GetRawTransaction(string txHash) /// /// Transaction /// NetworkFee - public long CalculateNetworkFee(Transaction tx) + public async Task CalculateNetworkFeeAsync(Transaction tx) { - var json = RpcSend("calculatenetworkfee", Convert.ToBase64String(tx.ToArray())); + var json = await RpcSendAsync("calculatenetworkfee", Convert.ToBase64String(tx.ToArray())) + .ConfigureAwait(false); return (long)json["networkfee"].AsNumber(); } /// /// Returns the stored value, according to the contract script hash (or Id) and the stored key. /// - public string GetStorage(string scriptHashOrId, string key) + public async Task GetStorageAsync(string scriptHashOrId, string key) { - if (int.TryParse(scriptHashOrId, out int id)) - { - return RpcSend("getstorage", id, key).AsString(); - } - - return RpcSend("getstorage", scriptHashOrId, key).AsString(); + var result = int.TryParse(scriptHashOrId, out int id) + ? await RpcSendAsync("getstorage", id, key).ConfigureAwait(false) + : await RpcSendAsync("getstorage", scriptHashOrId, key).ConfigureAwait(false); + return result.AsString(); } /// /// Returns the block index in which the transaction is found. /// - public uint GetTransactionHeight(string txHash) + public async Task GetTransactionHeightAsync(string txHash) { - return uint.Parse(RpcSend("gettransactionheight", txHash).AsString()); + var result = await RpcSendAsync("gettransactionheight", txHash).ConfigureAwait(false); + return uint.Parse(result.AsString()); } /// /// Returns the next NEO consensus nodes information and voting status. /// - public RpcValidator[] GetNextBlockValidators() + public async Task GetNextBlockValidatorsAsync() { - return ((JArray)RpcSend("getnextblockvalidators")).Select(p => RpcValidator.FromJson(p)).ToArray(); + var result = await RpcSendAsync("getnextblockvalidators").ConfigureAwait(false); + return ((JArray)result).Select(p => RpcValidator.FromJson(p)).ToArray(); } /// /// Returns the current NEO committee members. /// - public string[] GetCommittee() + public async Task GetCommitteeAsync() { - return ((JArray)RpcSend("getcommittee")).Select(p => p.AsString()).ToArray(); + var result = await RpcSendAsync("getcommittee").ConfigureAwait(false); + return ((JArray)result).Select(p => p.AsString()).ToArray(); } #endregion Blockchain @@ -282,49 +284,54 @@ public string[] GetCommittee() /// /// Gets the current number of connections for the node. /// - public int GetConnectionCount() + public async Task GetConnectionCountAsync() { - return (int)RpcSend("getconnectioncount").AsNumber(); + var result = await RpcSendAsync("getconnectioncount").ConfigureAwait(false); + return (int)result.AsNumber(); } /// /// Gets the list of nodes that the node is currently connected/disconnected from. /// - public RpcPeers GetPeers() + public async Task GetPeersAsync() { - return RpcPeers.FromJson(RpcSend("getpeers")); + var result = await RpcSendAsync("getpeers").ConfigureAwait(false); + return RpcPeers.FromJson(result); } /// /// Returns the version information about the queried node. /// - public RpcVersion GetVersion() + public async Task GetVersionAsync() { - return RpcVersion.FromJson(RpcSend("getversion")); + var result = await RpcSendAsync("getversion").ConfigureAwait(false); + return RpcVersion.FromJson(result); } /// /// Broadcasts a serialized transaction over the NEO network. /// - public UInt256 SendRawTransaction(byte[] rawTransaction) + public async Task SendRawTransactionAsync(byte[] rawTransaction) { - return UInt256.Parse(RpcSend("sendrawtransaction", rawTransaction.ToHexString())["hash"].AsString()); + var result = await RpcSendAsync("sendrawtransaction", rawTransaction.ToHexString()).ConfigureAwait(false); + return UInt256.Parse(result["hash"].AsString()); } /// /// Broadcasts a transaction over the NEO network. /// - public UInt256 SendRawTransaction(Transaction transaction) + public Task SendRawTransactionAsync(Transaction transaction) { - return SendRawTransaction(transaction.ToArray()); + return SendRawTransactionAsync(transaction.ToArray()); } /// /// Broadcasts a serialized block over the NEO network. /// - public UInt256 SubmitBlock(byte[] block) + public async Task SubmitBlockAsync(byte[] block) { - return UInt256.Parse(RpcSend("submitblock", block.ToHexString())["hash"].AsString()); + var result = await RpcSendAsync("submitblock", block.ToHexString()).ConfigureAwait(false); + return UInt256.Parse(result["hash"].AsString()); } #endregion Node @@ -335,33 +342,36 @@ public UInt256 SubmitBlock(byte[] block) /// Returns the result after calling a smart contract at scripthash with the given operation and parameters. /// This RPC call does not affect the blockchain in any way. /// - public RpcInvokeResult InvokeFunction(string scriptHash, string operation, RpcStack[] stacks, params Signer[] signer) + public async Task InvokeFunctionAsync(string scriptHash, string operation, RpcStack[] stacks, params Signer[] signer) { List parameters = new List { scriptHash.AsScriptHash(), operation, stacks.Select(p => p.ToJson()).ToArray() }; if (signer.Length > 0) { parameters.Add(signer.Select(p => (JObject)p.ToJson()).ToArray()); } - return RpcInvokeResult.FromJson(RpcSend("invokefunction", parameters.ToArray())); + var result = await RpcSendAsync("invokefunction", parameters.ToArray()).ConfigureAwait(false); + return RpcInvokeResult.FromJson(result); } /// /// Returns the result after passing a script through the VM. /// This RPC call does not affect the blockchain in any way. /// - public RpcInvokeResult InvokeScript(byte[] script, params Signer[] signers) + public async Task InvokeScriptAsync(byte[] script, params Signer[] signers) { List parameters = new List { script.ToHexString() }; if (signers.Length > 0) { parameters.Add(signers.Select(p => p.ToJson()).ToArray()); } - return RpcInvokeResult.FromJson(RpcSend("invokescript", parameters.ToArray())); + var result = await RpcSendAsync("invokescript", parameters.ToArray()).ConfigureAwait(false); + return RpcInvokeResult.FromJson(result); } - public RpcUnclaimedGas GetUnclaimedGas(string address) + public async Task GetUnclaimedGasAsync(string address) { - return RpcUnclaimedGas.FromJson(RpcSend("getunclaimedgas", address.AsScriptHash())); + var result = await RpcSendAsync("getunclaimedgas", address.AsScriptHash()).ConfigureAwait(false); + return RpcUnclaimedGas.FromJson(result); } #endregion SmartContract @@ -371,17 +381,19 @@ public RpcUnclaimedGas GetUnclaimedGas(string address) /// /// Returns a list of plugins loaded by the node. /// - public RpcPlugin[] ListPlugins() + public async Task ListPluginsAsync() { - return ((JArray)RpcSend("listplugins")).Select(p => RpcPlugin.FromJson(p)).ToArray(); + var result = await RpcSendAsync("listplugins").ConfigureAwait(false); + return ((JArray)result).Select(p => RpcPlugin.FromJson(p)).ToArray(); } /// /// Verifies that the address is a correct NEO address. /// - public RpcValidateAddressResult ValidateAddress(string address) + public async Task ValidateAddressAsync(string address) { - return RpcValidateAddressResult.FromJson(RpcSend("validateaddress", address)); + var result = await RpcSendAsync("validateaddress", address).ConfigureAwait(false); + return RpcValidateAddressResult.FromJson(result); } #endregion Utilities @@ -391,25 +403,28 @@ public RpcValidateAddressResult ValidateAddress(string address) /// /// Close the wallet opened by RPC. /// - public bool CloseWallet() + public async Task CloseWalletAsync() { - return RpcSend("closewallet").AsBoolean(); + var result = await RpcSendAsync("closewallet").ConfigureAwait(false); + return result.AsBoolean(); } /// /// Exports the private key of the specified address. /// - public string DumpPrivKey(string address) + public async Task DumpPrivKeyAsync(string address) { - return RpcSend("dumpprivkey", address).AsString(); + var result = await RpcSendAsync("dumpprivkey", address).ConfigureAwait(false); + return result.AsString(); } /// /// Creates a new account in the wallet opened by RPC. /// - public string GetNewAddress() + public async Task GetNewAddressAsync() { - return RpcSend("getnewaddress").AsString(); + var result = await RpcSendAsync("getnewaddress").ConfigureAwait(false); + return result.AsString(); } /// @@ -417,60 +432,66 @@ public string GetNewAddress() /// This method applies to assets that conform to NEP-5 standards. /// /// new address as string - public BigDecimal GetWalletBalance(string assetId) + public async Task GetWalletBalanceAsync(string assetId) { - byte decimals = new Nep5API(this).Decimals(UInt160.Parse(assetId.AsScriptHash())); - BigInteger balance = BigInteger.Parse(RpcSend("getwalletbalance", assetId)["balance"].AsString()); + byte decimals = await new Nep5API(this).DecimalsAsync(UInt160.Parse(assetId.AsScriptHash())).ConfigureAwait(false); + var result = await RpcSendAsync("getwalletbalance", assetId).ConfigureAwait(false); + BigInteger balance = BigInteger.Parse(result["balance"].AsString()); return new BigDecimal(balance, decimals); } /// /// Gets the amount of unclaimed GAS in the wallet. /// - public BigInteger GetWalletUnclaimedGas() + public async Task GetWalletUnclaimedGasAsync() { - return BigInteger.Parse(RpcSend("getwalletunclaimedgas").AsString()); + var result = await RpcSendAsync("getwalletunclaimedgas").ConfigureAwait(false); + return BigInteger.Parse(result.AsString()); } /// /// Imports the private key to the wallet. /// - public RpcAccount ImportPrivKey(string wif) + public async Task ImportPrivKeyAsync(string wif) { - return RpcAccount.FromJson(RpcSend("importprivkey", wif)); + var result = await RpcSendAsync("importprivkey", wif).ConfigureAwait(false); + return RpcAccount.FromJson(result); } /// /// Lists all the accounts in the current wallet. /// - public List ListAddress() + public async Task> ListAddressAsync() { - return ((JArray)RpcSend("listaddress")).Select(p => RpcAccount.FromJson(p)).ToList(); + var result = await RpcSendAsync("listaddress").ConfigureAwait(false); + return ((JArray)result).Select(p => RpcAccount.FromJson(p)).ToList(); } /// /// Open wallet file in the provider's machine. /// By default, this method is disabled by RpcServer config.json. /// - public bool OpenWallet(string path, string password) + public async Task OpenWalletAsync(string path, string password) { - return RpcSend("openwallet", path, password).AsBoolean(); + var result = await RpcSendAsync("openwallet", path, password).ConfigureAwait(false); + return result.AsBoolean(); } /// /// Transfer from the specified address to the destination address. /// /// This function returns Signed Transaction JSON if successful, ContractParametersContext JSON if signing failed. - public JObject SendFrom(string assetId, string fromAddress, string toAddress, string amount) + public async Task SendFromAsync(string assetId, string fromAddress, string toAddress, string amount) { - return RpcSend("sendfrom", assetId.AsScriptHash(), fromAddress.AsScriptHash(), toAddress.AsScriptHash(), amount); + return await RpcSendAsync("sendfrom", assetId.AsScriptHash(), fromAddress.AsScriptHash(), + toAddress.AsScriptHash(), amount).ConfigureAwait(false); } /// /// Bulk transfer order, and you can specify a sender address. /// /// This function returns Signed Transaction JSON if successful, ContractParametersContext JSON if signing failed. - public JObject SendMany(string fromAddress, IEnumerable outputs) + public async Task SendManyAsync(string fromAddress, IEnumerable outputs) { var parameters = new List(); if (!string.IsNullOrEmpty(fromAddress)) @@ -479,16 +500,17 @@ public JObject SendMany(string fromAddress, IEnumerable outputs) } parameters.Add(outputs.Select(p => p.ToJson()).ToArray()); - return RpcSend("sendmany", paraArgs: parameters.ToArray()); + return await RpcSendAsync("sendmany", paraArgs: parameters.ToArray()).ConfigureAwait(false); } /// /// Transfer asset from the wallet to the destination address. /// /// This function returns Signed Transaction JSON if successful, ContractParametersContext JSON if signing failed. - public JObject SendToAddress(string assetId, string address, string amount) + public async Task SendToAddressAsync(string assetId, string address, string amount) { - return RpcSend("sendtoaddress", assetId.AsScriptHash(), address.AsScriptHash(), amount); + return await RpcSendAsync("sendtoaddress", assetId.AsScriptHash(), address.AsScriptHash(), amount) + .ConfigureAwait(false); } #endregion Wallet @@ -499,9 +521,10 @@ public JObject SendToAddress(string assetId, string address, string amount) /// Returns the contract log based on the specified txHash. The complete contract logs are stored under the ApplicationLogs directory. /// This method is provided by the plugin ApplicationLogs. /// - public RpcApplicationLog GetApplicationLog(string txHash) + public async Task GetApplicationLogAsync(string txHash) { - return RpcApplicationLog.FromJson(RpcSend("getapplicationlog", txHash)); + var result = await RpcSendAsync("getapplicationlog", txHash).ConfigureAwait(false); + return RpcApplicationLog.FromJson(result); } /// @@ -511,20 +534,24 @@ public RpcApplicationLog GetApplicationLog(string txHash) /// The address to query the transaction information. /// The start block Timestamp, default to seven days before UtcNow /// The end block Timestamp, default to UtcNow - public RpcNep5Transfers GetNep5Transfers(string address, ulong? startTimestamp = default, ulong? endTimestamp = default) + public async Task GetNep5TransfersAsync(string address, ulong? startTimestamp = default, ulong? endTimestamp = default) { startTimestamp ??= 0; endTimestamp ??= DateTime.UtcNow.ToTimestampMS(); - return RpcNep5Transfers.FromJson(RpcSend("getnep5transfers", address.AsScriptHash(), startTimestamp, endTimestamp)); + var result = await RpcSendAsync("getnep5transfers", address.AsScriptHash(), startTimestamp, endTimestamp) + .ConfigureAwait(false); + return RpcNep5Transfers.FromJson(result); } /// /// Returns the balance of all NEP-5 assets in the specified address. /// This method is provided by the plugin RpcNep5Tracker. /// - public RpcNep5Balances GetNep5Balances(string address) + public async Task GetNep5BalancesAsync(string address) { - return RpcNep5Balances.FromJson(RpcSend("getnep5balances", address.AsScriptHash())); + var result = await RpcSendAsync("getnep5balances", address.AsScriptHash()) + .ConfigureAwait(false); + return RpcNep5Balances.FromJson(result); } #endregion Plugins diff --git a/src/RpcClient/TransactionManager.cs b/src/RpcClient/TransactionManager.cs index ac38818de..7e35e25f0 100644 --- a/src/RpcClient/TransactionManager.cs +++ b/src/RpcClient/TransactionManager.cs @@ -1,12 +1,13 @@ using Neo.Cryptography.ECC; +using Neo.IO; using Neo.Network.P2P.Payloads; -using Neo.Network.RPC.Models; using Neo.SmartContract; using Neo.SmartContract.Native; using Neo.Wallets; using System; using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; namespace Neo.Network.RPC { @@ -15,65 +16,56 @@ namespace Neo.Network.RPC /// public class TransactionManager { + private class SignItem { public Contract Contract; public HashSet KeyPairs; } + private readonly RpcClient rpcClient; - private readonly PolicyAPI policyAPI; - private readonly Nep5API nep5API; - private class SignItem { public Contract Contract; public HashSet KeyPairs; } + /// + /// protocol settings Magic value to use for hashing transactions. + /// + private readonly uint magic; /// /// The Transaction context to manage the witnesses /// - private ContractParametersContext context; + private readonly ContractParametersContext context; /// /// This container stores the keys for sign the transaction /// - private List signStore; + private readonly List signStore = new List(); /// - /// The Transaction managed by this class + /// The Transaction managed by this instance /// - public Transaction Tx { get; private set; } + private readonly Transaction tx; + + public Transaction Tx => tx; /// /// TransactionManager Constructor /// - /// the RPC client to call NEO RPC API - /// the account script hash of sender - public TransactionManager(RpcClient rpc) + /// the transaction to manage. Typically buildt + /// the RPC client to call NEO RPC API + /// + /// the network Magic value to use when signing transactions. + /// Defaults to ProtocolSettings.Default.Magic if not specified. + /// + public TransactionManager(Transaction tx, RpcClient rpcClient, uint magic) { - rpcClient = rpc; - policyAPI = new PolicyAPI(rpc); - nep5API = new Nep5API(rpc); + this.tx = tx; + this.context = new ContractParametersContext(tx); + this.rpcClient = rpcClient; + this.magic = magic; } /// - /// Create an unsigned Transaction object with given parameters. + /// Helper function for one-off TransactionManager creation /// - /// Transaction Script - /// Transaction Attributes - /// - public TransactionManager MakeTransaction(byte[] script, Signer[] signers = null, TransactionAttribute[] attributes = null) + public static Task MakeTransactionAsync(RpcClient rpcClient, byte[] script, Signer[] signers = null, TransactionAttribute[] attributes = null, uint? magic = null) { - var random = new Random(); - uint height = rpcClient.GetBlockCount() - 1; - Tx = new Transaction - { - Version = 0, - Nonce = (uint)random.Next(), - Script = script, - Signers = signers, - ValidUntilBlock = height + Transaction.MaxValidUntilBlockIncrement, - Attributes = attributes ?? Array.Empty(), - }; - - RpcInvokeResult result = rpcClient.InvokeScript(script, signers); - Tx.SystemFee = long.Parse(result.GasConsumed); - context = new ContractParametersContext(Tx); - signStore = new List(); - - return this; + var factory = new TransactionManagerFactory(rpcClient, magic); + return factory.MakeTransactionAsync(script, signers, attributes); } /// @@ -109,9 +101,10 @@ public TransactionManager AddMultiSig(KeyPair key, int m, params ECPoint[] publi /// The Public Keys construct the multiple signature contract public TransactionManager AddMultiSig(KeyPair[] keys, int m, params ECPoint[] publicKeys) { - foreach (var key in keys) + Contract contract = Contract.CreateMultiSigContract(m, publicKeys); + for (int i = 0; i < keys.Length; i++) { - AddMultiSig(key, m, publicKeys); + AddSignItem(contract, keys[i]); } return this; } @@ -162,7 +155,7 @@ public TransactionManager AddWitness(UInt160 scriptHash, params object[] paramet /// /// Verify Witness count and add witnesses /// - public TransactionManager Sign() + public async Task SignAsync() { // Calculate NetworkFee Tx.Witnesses = Tx.GetScriptHashesForVerifying(null).Select(u => new Witness() @@ -170,23 +163,25 @@ public TransactionManager Sign() InvocationScript = Array.Empty(), VerificationScript = GetVerificationScript(u) }).ToArray(); - Tx.NetworkFee = rpcClient.CalculateNetworkFee(Tx); + Tx.NetworkFee = await rpcClient.CalculateNetworkFeeAsync(Tx).ConfigureAwait(false); Tx.Witnesses = null; - var gasBalance = nep5API.BalanceOf(NativeContract.GAS.Hash, Tx.Sender); + var gasBalance = await new Nep5API(rpcClient).BalanceOfAsync(NativeContract.GAS.Hash, Tx.Sender).ConfigureAwait(false); if (gasBalance < Tx.SystemFee + Tx.NetworkFee) throw new InvalidOperationException($"Insufficient GAS in address: {Tx.Sender.ToAddress()}"); // Sign with signStore - foreach (var item in signStore) - foreach (var key in item.KeyPairs) + for (int i = 0; i < signStore.Count; i++) + { + foreach (var key in signStore[i].KeyPairs) { - byte[] signature = Tx.Sign(key); - if (!context.AddSignature(item.Contract, key.PublicKey, signature)) + byte[] signature = Tx.Sign(key, magic); + if (!context.AddSignature(signStore[i].Contract, key.PublicKey, signature)) { throw new Exception("AddSignature failed!"); } } + } // Verify witness count if (!context.Completed) @@ -194,7 +189,7 @@ public TransactionManager Sign() throw new Exception($"Please add signature or witness first!"); } Tx.Witnesses = context.GetWitnesses(); - return this; + return Tx; } private byte[] GetVerificationScript(UInt160 hash) diff --git a/src/RpcClient/TransactionManagerFactory.cs b/src/RpcClient/TransactionManagerFactory.cs new file mode 100644 index 000000000..0f7277a2c --- /dev/null +++ b/src/RpcClient/TransactionManagerFactory.cs @@ -0,0 +1,57 @@ +using Neo.Network.P2P.Payloads; +using Neo.Network.RPC.Models; +using System; +using System.Threading.Tasks; + +namespace Neo.Network.RPC +{ + public class TransactionManagerFactory + { + private readonly RpcClient rpcClient; + + /// + /// protocol settings Magic value to use for hashing transactions. + /// defaults to ProtocolSettings.Default.Magic if unspecified + /// + private readonly uint magic; + + /// + /// TransactionManagerFactory Constructor + /// + /// the RPC client to call NEO RPC API + /// + /// the network Magic value to use when signing transactions. + /// Defaults to ProtocolSettings.Default.Magic if not specified. + /// + public TransactionManagerFactory(RpcClient rpcClient, uint? magic = null) + { + this.rpcClient = rpcClient; + this.magic = magic ?? ProtocolSettings.Default.Magic; + } + + /// + /// Create an unsigned Transaction object with given parameters. + /// + /// Transaction Script + /// Transaction Attributes + /// + public async Task MakeTransactionAsync(byte[] script, Signer[] signers = null, TransactionAttribute[] attributes = null) + { + uint blockCount = await rpcClient.GetBlockCountAsync().ConfigureAwait(false) - 1; + RpcInvokeResult invokeResult = await rpcClient.InvokeScriptAsync(script, signers).ConfigureAwait(false); + + var tx = new Transaction + { + Version = 0, + Nonce = (uint)new Random().Next(), + Script = script, + Signers = signers ?? Array.Empty(), + ValidUntilBlock = blockCount - 1 + Transaction.MaxValidUntilBlockIncrement, + SystemFee = long.Parse(invokeResult.GasConsumed), + Attributes = attributes ?? Array.Empty(), + }; + + return new TransactionManager(tx, rpcClient, magic); + } + } +} diff --git a/src/RpcClient/WalletAPI.cs b/src/RpcClient/WalletAPI.cs index 014aba6ec..b4cef3c55 100644 --- a/src/RpcClient/WalletAPI.cs +++ b/src/RpcClient/WalletAPI.cs @@ -37,10 +37,10 @@ public WalletAPI(RpcClient rpc) /// address, scripthash or public key string /// Example: address ("Ncm9TEzrp8SSer6Wa3UCSLTRnqzwVhCfuE"), scripthash ("0xb0a31817c80ad5f87b6ed390ecb3f9d312f7ceb8"), public key ("02f9ec1fd0a98796cf75b586772a4ddd41a0af07a1dbdf86a7238f74fb72503575") /// - public decimal GetUnclaimedGas(string account) + public Task GetUnclaimedGasAsync(string account) { UInt160 accountHash = Utility.GetScriptHash(account); - return GetUnclaimedGas(accountHash); + return GetUnclaimedGasAsync(accountHash); } /// @@ -48,11 +48,12 @@ public decimal GetUnclaimedGas(string account) /// /// account scripthash /// - public decimal GetUnclaimedGas(UInt160 account) + public async Task GetUnclaimedGasAsync(UInt160 account) { UInt160 scriptHash = NativeContract.NEO.Hash; - BigInteger balance = nep5API.TestInvoke(scriptHash, "unclaimedGas", account, rpcClient.GetBlockCount() - 1) - .Stack.Single().GetInteger(); + var blockCount = await rpcClient.GetBlockCountAsync().ConfigureAwait(false); + var result = await nep5API.TestInvokeAsync(scriptHash, "unclaimedGas", account, blockCount - 1).ConfigureAwait(false); + BigInteger balance = result.Stack.Single().GetInteger(); return ((decimal)balance) / (long)NativeContract.GAS.Factor; } @@ -62,9 +63,9 @@ public decimal GetUnclaimedGas(UInt160 account) /// address, scripthash or public key string /// Example: address ("Ncm9TEzrp8SSer6Wa3UCSLTRnqzwVhCfuE"), scripthash ("0xb0a31817c80ad5f87b6ed390ecb3f9d312f7ceb8"), public key ("02f9ec1fd0a98796cf75b586772a4ddd41a0af07a1dbdf86a7238f74fb72503575") /// - public uint GetNeoBalance(string account) + public async Task GetNeoBalanceAsync(string account) { - BigInteger balance = GetTokenBalance(NativeContract.NEO.Hash.ToString(), account); + BigInteger balance = await GetTokenBalanceAsync(NativeContract.NEO.Hash.ToString(), account).ConfigureAwait(false); return (uint)balance; } @@ -74,9 +75,9 @@ public uint GetNeoBalance(string account) /// address, scripthash or public key string /// Example: address ("Ncm9TEzrp8SSer6Wa3UCSLTRnqzwVhCfuE"), scripthash ("0xb0a31817c80ad5f87b6ed390ecb3f9d312f7ceb8"), public key ("02f9ec1fd0a98796cf75b586772a4ddd41a0af07a1dbdf86a7238f74fb72503575") /// - public decimal GetGasBalance(string account) + public async Task GetGasBalanceAsync(string account) { - BigInteger balance = GetTokenBalance(NativeContract.GAS.Hash.ToString(), account); + BigInteger balance = await GetTokenBalanceAsync(NativeContract.GAS.Hash.ToString(), account).ConfigureAwait(false); return ((decimal)balance) / (long)NativeContract.GAS.Factor; } @@ -87,11 +88,11 @@ public decimal GetGasBalance(string account) /// address, scripthash or public key string /// Example: address ("Ncm9TEzrp8SSer6Wa3UCSLTRnqzwVhCfuE"), scripthash ("0xb0a31817c80ad5f87b6ed390ecb3f9d312f7ceb8"), public key ("02f9ec1fd0a98796cf75b586772a4ddd41a0af07a1dbdf86a7238f74fb72503575") /// - public BigInteger GetTokenBalance(string tokenHash, string account) + public Task GetTokenBalanceAsync(string tokenHash, string account) { UInt160 scriptHash = Utility.GetScriptHash(tokenHash); UInt160 accountHash = Utility.GetScriptHash(account); - return nep5API.BalanceOf(scriptHash, accountHash); + return nep5API.BalanceOfAsync(scriptHash, accountHash); } /// @@ -101,10 +102,10 @@ public BigInteger GetTokenBalance(string tokenHash, string account) /// wif or private key /// Example: WIF ("KyXwTh1hB76RRMquSvnxZrJzQx7h9nQP2PCRL38v6VDb5ip3nf1p"), PrivateKey ("450d6c2a04b5b470339a745427bae6828400cf048400837d73c415063835e005") /// The transaction sended - public Transaction ClaimGas(string key) + public Task ClaimGasAsync(string key) { KeyPair keyPair = Utility.GetKeyPair(key); - return ClaimGas(keyPair); + return ClaimGasAsync(keyPair); } /// @@ -113,12 +114,12 @@ public Transaction ClaimGas(string key) /// /// keyPair /// The transaction sended - public Transaction ClaimGas(KeyPair keyPair) + public async Task ClaimGasAsync(KeyPair keyPair) { UInt160 toHash = Contract.CreateSignatureRedeemScript(keyPair.PublicKey).ToScriptHash(); - BigInteger balance = nep5API.BalanceOf(NativeContract.NEO.Hash, toHash); - Transaction transaction = nep5API.CreateTransferTx(NativeContract.NEO.Hash, keyPair, toHash, balance); - rpcClient.SendRawTransaction(transaction); + BigInteger balance = await nep5API.BalanceOfAsync(NativeContract.NEO.Hash, toHash).ConfigureAwait(false); + Transaction transaction = await nep5API.CreateTransferTxAsync(NativeContract.NEO.Hash, keyPair, toHash, balance).ConfigureAwait(false); + await rpcClient.SendRawTransactionAsync(transaction).ConfigureAwait(false); return transaction; } @@ -131,15 +132,15 @@ public Transaction ClaimGas(KeyPair keyPair) /// address or account script hash /// token amount /// - public Transaction Transfer(string tokenHash, string fromKey, string toAddress, decimal amount) + public async Task TransferAsync(string tokenHash, string fromKey, string toAddress, decimal amount) { UInt160 scriptHash = Utility.GetScriptHash(tokenHash); - var decimals = nep5API.Decimals(scriptHash); + var decimals = await nep5API.DecimalsAsync(scriptHash).ConfigureAwait(false); KeyPair from = Utility.GetKeyPair(fromKey); UInt160 to = Utility.GetScriptHash(toAddress); BigInteger amountInteger = amount.ToBigInteger(decimals); - return Transfer(scriptHash, from, to, amountInteger); + return await TransferAsync(scriptHash, from, to, amountInteger).ConfigureAwait(false); } /// @@ -150,10 +151,10 @@ public Transaction Transfer(string tokenHash, string fromKey, string toAddress, /// to account script hash /// transfer amount /// - public Transaction Transfer(UInt160 scriptHash, KeyPair from, UInt160 to, BigInteger amountInteger) + public async Task TransferAsync(UInt160 scriptHash, KeyPair from, UInt160 to, BigInteger amountInteger) { - Transaction transaction = nep5API.CreateTransferTx(scriptHash, from, to, amountInteger); - rpcClient.SendRawTransaction(transaction); + Transaction transaction = await nep5API.CreateTransferTxAsync(scriptHash, from, to, amountInteger).ConfigureAwait(false); + await rpcClient.SendRawTransactionAsync(transaction).ConfigureAwait(false); return transaction; } @@ -167,10 +168,10 @@ public Transaction Transfer(UInt160 scriptHash, KeyPair from, UInt160 to, BigInt /// to account /// transfer amount /// - public Transaction Transfer(UInt160 scriptHash, int m, ECPoint[] pubKeys, KeyPair[] keys, UInt160 to, BigInteger amountInteger) + public async Task TransferAsync(UInt160 scriptHash, int m, ECPoint[] pubKeys, KeyPair[] keys, UInt160 to, BigInteger amountInteger) { - Transaction transaction = nep5API.CreateTransferTx(scriptHash, m, pubKeys, keys, to, amountInteger); - rpcClient.SendRawTransaction(transaction); + Transaction transaction = await nep5API.CreateTransferTxAsync(scriptHash, m, pubKeys, keys, to, amountInteger).ConfigureAwait(false); + await rpcClient.SendRawTransactionAsync(transaction).ConfigureAwait(false); return transaction; } @@ -180,7 +181,7 @@ public Transaction Transfer(UInt160 scriptHash, int m, ECPoint[] pubKeys, KeyPai /// the transaction to observe /// TimeoutException throws after "timeout" seconds /// the Transaction state, including vmState and blockhash - public async Task WaitTransaction(Transaction transaction, int timeout = 60) + public async Task WaitTransactionAsync(Transaction transaction, int timeout = 60) { DateTime deadline = DateTime.UtcNow.AddSeconds(timeout); RpcTransaction rpcTx = null; @@ -193,7 +194,7 @@ public async Task WaitTransaction(Transaction transaction, int t try { - rpcTx = rpcClient.GetRawTransaction(transaction.Hash.ToString()); + rpcTx = await rpcClient.GetRawTransactionAsync(transaction.Hash.ToString()).ConfigureAwait(false); if (rpcTx == null || rpcTx.Confirmations == null) { await Task.Delay((int)Blockchain.MillisecondsPerBlock / 2); diff --git a/tests/Neo.Network.RPC.Tests/RpcTestCases.json b/tests/Neo.Network.RPC.Tests/RpcTestCases.json index 845741690..f1a7b9e07 100644 --- a/tests/Neo.Network.RPC.Tests/RpcTestCases.json +++ b/tests/Neo.Network.RPC.Tests/RpcTestCases.json @@ -1,6 +1,6 @@ [ { - "Name": "sendrawtransactionerror", + "Name": "sendrawtransactionasyncerror", "Request": { "jsonrpc": "2.0", "method": "sendrawtransaction", @@ -18,7 +18,7 @@ } }, { - "Name": "getbestblockhash", + "Name": "getbestblockhashasync", "Request": { "jsonrpc": "2.0", "method": "getbestblockhash", @@ -32,7 +32,7 @@ } }, { - "Name": "getblockhex", + "Name": "getblockhexasync", "Request": { "jsonrpc": "2.0", "method": "getblock", @@ -46,7 +46,7 @@ } }, { - "Name": "getblockhex", + "Name": "getblockhexasync", "Request": { "jsonrpc": "2.0", "method": "getblock", @@ -60,7 +60,7 @@ } }, { - "Name": "getblock", + "Name": "getblockasync", "Request": { "jsonrpc": "2.0", "method": "getblock", @@ -121,7 +121,7 @@ } }, { - "Name": "getblock", + "Name": "getblockasync", "Request": { "jsonrpc": "2.0", "method": "getblock", @@ -182,7 +182,7 @@ } }, { - "Name": "getblockcount", + "Name": "getblockcountasync", "Request": { "jsonrpc": "2.0", "method": "getblockcount", @@ -196,7 +196,7 @@ } }, { - "Name": "getblockhash", + "Name": "getblockhashasync", "Request": { "jsonrpc": "2.0", "method": "getblockhash", @@ -210,7 +210,7 @@ } }, { - "Name": "getblockheaderhex", + "Name": "getblockheaderhexasync", "Request": { "jsonrpc": "2.0", "method": "getblockheader", @@ -224,7 +224,7 @@ } }, { - "Name": "getblockheaderhex", + "Name": "getblockheaderhexasync", "Request": { "jsonrpc": "2.0", "method": "getblockheader", @@ -238,7 +238,7 @@ } }, { - "Name": "getblockheader", + "Name": "getblockheaderasync", "Request": { "jsonrpc": "2.0", "method": "getblockheader", @@ -269,7 +269,7 @@ } }, { - "Name": "getblockheader", + "Name": "getblockheaderasync", "Request": { "jsonrpc": "2.0", "method": "getblockheader", @@ -300,7 +300,7 @@ } }, { - "Name": "getblocksysfee", + "Name": "getblocksysfeeasync", "Request": { "jsonrpc": "2.0", "method": "getblocksysfee", @@ -314,7 +314,7 @@ } }, { - "Name": "getcontractstate", + "Name": "getcontractstateasync", "Request": { "jsonrpc": "2.0", "method": "getcontractstate", @@ -458,7 +458,7 @@ } }, { - "Name": "getrawmempool", + "Name": "getrawmempoolasync", "Request": { "jsonrpc": "2.0", "method": "getrawmempool", @@ -472,7 +472,7 @@ } }, { - "Name": "getrawmempoolboth", + "Name": "getrawmempoolbothasync", "Request": { "jsonrpc": "2.0", "method": "getrawmempool", @@ -490,7 +490,7 @@ } }, { - "Name": "getrawtransactionhex", + "Name": "getrawtransactionhexasync", "Request": { "jsonrpc": "2.0", "method": "getrawtransaction", @@ -504,7 +504,7 @@ } }, { - "Name": "getrawtransaction", + "Name": "getrawtransactionasync", "Request": { "jsonrpc": "2.0", "method": "getrawtransaction", @@ -545,7 +545,7 @@ } }, { - "Name": "getstorage", + "Name": "getstorageasync", "Request": { "jsonrpc": "2.0", "method": "getstorage", @@ -559,7 +559,7 @@ } }, { - "Name": "getstorage", + "Name": "getstorageasync", "Request": { "jsonrpc": "2.0", "method": "getstorage", @@ -573,7 +573,7 @@ } }, { - "Name": "gettransactionheight", + "Name": "gettransactionheightasync", "Request": { "jsonrpc": "2.0", "method": "gettransactionheight", @@ -587,7 +587,7 @@ } }, { - "Name": "getnextblockvalidators", + "Name": "getnextblockvalidatorsasync", "Request": { "jsonrpc": "2.0", "method": "getnextblockvalidators", @@ -609,7 +609,7 @@ { - "Name": "getconnectioncount", + "Name": "getconnectioncountasync", "Request": { "jsonrpc": "2.0", "method": "getconnectioncount", @@ -623,7 +623,7 @@ } }, { - "Name": "getpeers", + "Name": "getpeersasync", "Request": { "jsonrpc": "2.0", "method": "getpeers", @@ -655,7 +655,7 @@ } }, { - "Name": "getversion", + "Name": "getversionasync", "Request": { "jsonrpc": "2.0", "method": "getversion", @@ -674,7 +674,7 @@ } }, { - "Name": "sendrawtransaction", + "Name": "sendrawtransactionasync", "Request": { "jsonrpc": "2.0", "method": "sendrawtransaction", @@ -690,7 +690,7 @@ } }, { - "Name": "submitblock", + "Name": "submitblockasync", "Request": { "jsonrpc": "2.0", "method": "submitblock", @@ -708,7 +708,7 @@ { - "Name": "invokefunction", + "Name": "invokefunctionasync", "Request": { "jsonrpc": "2.0", "method": "invokefunction", @@ -742,7 +742,7 @@ } }, { - "Name": "invokescript", + "Name": "invokescriptasync", "Request": { "jsonrpc": "2.0", "method": "invokescript", @@ -822,7 +822,7 @@ }, { - "Name": "getunclaimedgas", + "Name": "getunclaimedgasasync", "Request": { "jsonrpc": "2.0", "method": "getunclaimedgas", @@ -840,7 +840,7 @@ }, { - "Name": "listplugins", + "Name": "listpluginsasync", "Request": { "jsonrpc": "2.0", "method": "listplugins", @@ -881,7 +881,7 @@ } }, { - "Name": "validateaddress", + "Name": "validateaddressasync", "Request": { "jsonrpc": "2.0", "method": "validateaddress", @@ -900,7 +900,7 @@ { - "Name": "closewallet", + "Name": "closewalletasync", "Request": { "jsonrpc": "2.0", "method": "closewallet", @@ -914,7 +914,7 @@ } }, { - "Name": "dumpprivkey", + "Name": "dumpprivkeyasync", "Request": { "jsonrpc": "2.0", "method": "dumpprivkey", @@ -928,7 +928,7 @@ } }, { - "Name": "invokescript", + "Name": "invokescriptasync", "Request": { "jsonrpc": "2.0", "method": "invokescript", @@ -953,7 +953,7 @@ } }, { - "Name": "getnewaddress", + "Name": "getnewaddressasync", "Request": { "jsonrpc": "2.0", "method": "getnewaddress", @@ -967,7 +967,7 @@ } }, { - "Name": "getwalletbalance", + "Name": "getwalletbalanceasync", "Request": { "jsonrpc": "2.0", "method": "getwalletbalance", @@ -983,7 +983,7 @@ } }, { - "Name": "getwalletunclaimedgas", + "Name": "getwalletunclaimedgasasync", "Request": { "jsonrpc": "2.0", "method": "getwalletunclaimedgas", @@ -997,7 +997,7 @@ } }, { - "Name": "importprivkey", + "Name": "importprivkeyasync", "Request": { "jsonrpc": "2.0", "method": "importprivkey", @@ -1016,7 +1016,7 @@ } }, { - "Name": "listaddress", + "Name": "listaddressasync", "Request": { "jsonrpc": "2.0", "method": "listaddress", @@ -1043,7 +1043,7 @@ } }, { - "Name": "openwallet", + "Name": "openwalletasync", "Request": { "jsonrpc": "2.0", "method": "openwallet", @@ -1057,7 +1057,7 @@ } }, { - "Name": "sendfrom", + "Name": "sendfromasync", "Request": { "jsonrpc": "2.0", "method": "sendfrom", @@ -1094,7 +1094,7 @@ } }, { - "Name": "sendmany", + "Name": "sendmanyasync", "Request": { "jsonrpc": "2.0", "method": "sendmany", @@ -1153,7 +1153,7 @@ } }, { - "Name": "sendtoaddress", + "Name": "sendtoaddressasync", "Request": { "jsonrpc": "2.0", "method": "sendtoaddress", @@ -1196,7 +1196,7 @@ { - "Name": "getapplicationlog", + "Name": "getapplicationlogasync", "Request": { "jsonrpc": "2.0", "method": "getapplicationlog", @@ -1359,7 +1359,7 @@ } }, { - "Name": "getnep5transfers", + "Name": "getnep5transfersasync", "Request": { "jsonrpc": "2.0", "method": "getnep5transfers", @@ -1406,7 +1406,7 @@ } }, { - "Name": "getnep5balances", + "Name": "getnep5balancesasync", "Request": { "jsonrpc": "2.0", "method": "getnep5balances", diff --git a/tests/Neo.Network.RPC.Tests/UT_ContractClient.cs b/tests/Neo.Network.RPC.Tests/UT_ContractClient.cs index dfdbf9990..2a120fad4 100644 --- a/tests/Neo.Network.RPC.Tests/UT_ContractClient.cs +++ b/tests/Neo.Network.RPC.Tests/UT_ContractClient.cs @@ -1,3 +1,4 @@ +using System.Threading.Tasks; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; using Neo.SmartContract; @@ -24,19 +25,19 @@ public void TestSetup() } [TestMethod] - public void TestInvoke() + public async Task TestInvoke() { byte[] testScript = NativeContract.GAS.Hash.MakeScript("balanceOf", UInt160.Zero); UT_TransactionManager.MockInvokeScript(rpcClientMock, testScript, new ContractParameter { Type = ContractParameterType.ByteArray, Value = "00e057eb481b".HexToBytes() }); ContractClient contractClient = new ContractClient(rpcClientMock.Object); - var result = contractClient.TestInvoke(NativeContract.GAS.Hash, "balanceOf", UInt160.Zero); + var result = await contractClient.TestInvokeAsync(NativeContract.GAS.Hash, "balanceOf", UInt160.Zero); Assert.AreEqual(30000000000000L, (long)result.Stack[0].GetInteger()); } [TestMethod] - public void TestDeployContract() + public async Task TestDeployContract() { byte[] script; var manifest = new ContractManifest() @@ -64,7 +65,7 @@ public void TestDeployContract() UT_TransactionManager.MockInvokeScript(rpcClientMock, script, new ContractParameter()); ContractClient contractClient = new ContractClient(rpcClientMock.Object); - var result = contractClient.CreateDeployContractTx(new byte[1], manifest, keyPair1); + var result = await contractClient.CreateDeployContractTxAsync(new byte[1], manifest, keyPair1); Assert.IsNotNull(result); } diff --git a/tests/Neo.Network.RPC.Tests/UT_Nep5API.cs b/tests/Neo.Network.RPC.Tests/UT_Nep5API.cs index 8454d4afa..12f0142c9 100644 --- a/tests/Neo.Network.RPC.Tests/UT_Nep5API.cs +++ b/tests/Neo.Network.RPC.Tests/UT_Nep5API.cs @@ -6,6 +6,7 @@ using Neo.Wallets; using System.Linq; using System.Numerics; +using System.Threading.Tasks; namespace Neo.Network.RPC.Tests { @@ -27,57 +28,57 @@ public void TestSetup() } [TestMethod] - public void TestBalanceOf() + public async Task TestBalanceOf() { byte[] testScript = NativeContract.GAS.Hash.MakeScript("balanceOf", UInt160.Zero); UT_TransactionManager.MockInvokeScript(rpcClientMock, testScript, new ContractParameter { Type = ContractParameterType.Integer, Value = new BigInteger(10000) }); - var balance = nep5API.BalanceOf(NativeContract.GAS.Hash, UInt160.Zero); + var balance = await nep5API.BalanceOfAsync(NativeContract.GAS.Hash, UInt160.Zero); Assert.AreEqual(10000, (int)balance); } [TestMethod] - public void TestGetName() + public async Task TestGetName() { byte[] testScript = NativeContract.GAS.Hash.MakeScript("name"); UT_TransactionManager.MockInvokeScript(rpcClientMock, testScript, new ContractParameter { Type = ContractParameterType.String, Value = NativeContract.GAS.Name }); - var result = nep5API.Name(NativeContract.GAS.Hash); + var result = await nep5API.NameAsync(NativeContract.GAS.Hash); Assert.AreEqual(NativeContract.GAS.Name, result); } [TestMethod] - public void TestGetSymbol() + public async Task TestGetSymbol() { byte[] testScript = NativeContract.GAS.Hash.MakeScript("symbol"); UT_TransactionManager.MockInvokeScript(rpcClientMock, testScript, new ContractParameter { Type = ContractParameterType.String, Value = NativeContract.GAS.Symbol }); - var result = nep5API.Symbol(NativeContract.GAS.Hash); + var result = await nep5API.SymbolAsync(NativeContract.GAS.Hash); Assert.AreEqual(NativeContract.GAS.Symbol, result); } [TestMethod] - public void TestGetDecimals() + public async Task TestGetDecimals() { byte[] testScript = NativeContract.GAS.Hash.MakeScript("decimals"); UT_TransactionManager.MockInvokeScript(rpcClientMock, testScript, new ContractParameter { Type = ContractParameterType.Integer, Value = new BigInteger(NativeContract.GAS.Decimals) }); - var result = nep5API.Decimals(NativeContract.GAS.Hash); + var result = await nep5API.DecimalsAsync(NativeContract.GAS.Hash); Assert.AreEqual(NativeContract.GAS.Decimals, result); } [TestMethod] - public void TestGetTotalSupply() + public async Task TestGetTotalSupply() { byte[] testScript = NativeContract.GAS.Hash.MakeScript("totalSupply"); UT_TransactionManager.MockInvokeScript(rpcClientMock, testScript, new ContractParameter { Type = ContractParameterType.Integer, Value = new BigInteger(1_00000000) }); - var result = nep5API.TotalSupply(NativeContract.GAS.Hash); + var result = await nep5API.TotalSupplyAsync(NativeContract.GAS.Hash); Assert.AreEqual(1_00000000, (int)result); } [TestMethod] - public void TestGetTokenInfo() + public async Task TestGetTokenInfo() { UInt160 scriptHash = NativeContract.GAS.Hash; byte[] testScript = scriptHash.MakeScript("name") @@ -91,7 +92,7 @@ public void TestGetTokenInfo() new ContractParameter { Type = ContractParameterType.Integer, Value = new BigInteger(NativeContract.GAS.Decimals) }, new ContractParameter { Type = ContractParameterType.Integer, Value = new BigInteger(1_00000000) }); - var result = nep5API.GetTokenInfo(NativeContract.GAS.Hash); + var result = await nep5API.GetTokenInfoAsync(NativeContract.GAS.Hash); Assert.AreEqual(NativeContract.GAS.Name, result.Name); Assert.AreEqual(NativeContract.GAS.Symbol, result.Symbol); Assert.AreEqual(8, (int)result.Decimals); @@ -99,12 +100,12 @@ public void TestGetTokenInfo() } [TestMethod] - public void TestTransfer() + public async Task TestTransfer() { byte[] testScript = NativeContract.GAS.Hash.MakeScript("transfer", sender, UInt160.Zero, new BigInteger(1_00000000)); UT_TransactionManager.MockInvokeScript(rpcClientMock, testScript, new ContractParameter()); - var result = nep5API.CreateTransferTx(NativeContract.GAS.Hash, keyPair1, UInt160.Zero, new BigInteger(1_00000000)); + var result = await nep5API.CreateTransferTxAsync(NativeContract.GAS.Hash, keyPair1, UInt160.Zero, new BigInteger(1_00000000)); Assert.IsNotNull(result); } } diff --git a/tests/Neo.Network.RPC.Tests/UT_PolicyAPI.cs b/tests/Neo.Network.RPC.Tests/UT_PolicyAPI.cs index b6a8bdd01..546e250e1 100644 --- a/tests/Neo.Network.RPC.Tests/UT_PolicyAPI.cs +++ b/tests/Neo.Network.RPC.Tests/UT_PolicyAPI.cs @@ -5,6 +5,7 @@ using Neo.VM; using Neo.Wallets; using System.Numerics; +using System.Threading.Tasks; namespace Neo.Network.RPC.Tests { @@ -26,42 +27,42 @@ public void TestSetup() } [TestMethod] - public void TestGetMaxTransactionsPerBlock() + public async Task TestGetMaxTransactionsPerBlock() { byte[] testScript = NativeContract.Policy.Hash.MakeScript("getMaxTransactionsPerBlock"); UT_TransactionManager.MockInvokeScript(rpcClientMock, testScript, new ContractParameter { Type = ContractParameterType.Integer, Value = new BigInteger(512) }); - var result = policyAPI.GetMaxTransactionsPerBlock(); + var result = await policyAPI.GetMaxTransactionsPerBlockAsync(); Assert.AreEqual(512u, result); } [TestMethod] - public void TestGetMaxBlockSize() + public async Task TestGetMaxBlockSize() { byte[] testScript = NativeContract.Policy.Hash.MakeScript("getMaxBlockSize"); UT_TransactionManager.MockInvokeScript(rpcClientMock, testScript, new ContractParameter { Type = ContractParameterType.Integer, Value = new BigInteger(1024u * 256u) }); - var result = policyAPI.GetMaxBlockSize(); + var result = await policyAPI.GetMaxBlockSizeAsync(); Assert.AreEqual(1024u * 256u, result); } [TestMethod] - public void TestGetFeePerByte() + public async Task TestGetFeePerByte() { byte[] testScript = NativeContract.Policy.Hash.MakeScript("getFeePerByte"); UT_TransactionManager.MockInvokeScript(rpcClientMock, testScript, new ContractParameter { Type = ContractParameterType.Integer, Value = new BigInteger(1000) }); - var result = policyAPI.GetFeePerByte(); + var result = await policyAPI.GetFeePerByteAsync(); Assert.AreEqual(1000L, result); } [TestMethod] - public void TestGetBlockedAccounts() + public async Task TestGetBlockedAccounts() { byte[] testScript = NativeContract.Policy.Hash.MakeScript("getBlockedAccounts"); UT_TransactionManager.MockInvokeScript(rpcClientMock, testScript, new ContractParameter { Type = ContractParameterType.Array, Value = new[] { new ContractParameter { Type = ContractParameterType.Hash160, Value = UInt160.Zero } } }); - var result = policyAPI.GetBlockedAccounts(); + var result = await policyAPI.GetBlockedAccountsAsync(); Assert.AreEqual(UInt160.Zero, result[0]); } } diff --git a/tests/Neo.Network.RPC.Tests/UT_RpcClient.cs b/tests/Neo.Network.RPC.Tests/UT_RpcClient.cs index 1c4287d91..dd38fd9fe 100644 --- a/tests/Neo.Network.RPC.Tests/UT_RpcClient.cs +++ b/tests/Neo.Network.RPC.Tests/UT_RpcClient.cs @@ -27,12 +27,8 @@ public void TestSetup() handlerMock = new Mock(MockBehavior.Strict); // use real http client with mocked handler here - var httpClient = new HttpClient(handlerMock.Object) - { - BaseAddress = new Uri("http://seed1.neo.org:10331"), - }; - - rpc = new RpcClient(httpClient); + var httpClient = new HttpClient(handlerMock.Object); + rpc = new RpcClient(httpClient, "http://seed1.neo.org:10331"); foreach (var test in TestUtils.RpcTestCases) { MockResponse(test.Request, test.Response); @@ -58,12 +54,12 @@ private void MockResponse(RpcRequest request, RpcResponse response) } [TestMethod] - public void TestErrorResponse() + public async Task TestErrorResponse() { - var test = TestUtils.RpcTestCases.Find(p => p.Name == (nameof(rpc.SendRawTransaction) + "error").ToLower()); + var test = TestUtils.RpcTestCases.Find(p => p.Name == (nameof(rpc.SendRawTransactionAsync) + "error").ToLower()); try { - var result = rpc.SendRawTransaction(test.Request.Params[0].AsString().HexToBytes().AsSerializable()); + var result = await rpc.SendRawTransactionAsync(test.Request.Params[0].AsString().HexToBytes().AsSerializable()); } catch (RpcException ex) { @@ -91,137 +87,137 @@ public void TestConstructorWithBasicAuth() #region Blockchain [TestMethod] - public void TestGetBestBlockHash() + public async Task TestGetBestBlockHash() { - var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetBestBlockHash).ToLower()); - var result = rpc.GetBestBlockHash(); + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetBestBlockHashAsync).ToLower()); + var result = await rpc.GetBestBlockHashAsync(); Assert.AreEqual(test.Response.Result.AsString(), result); } [TestMethod] - public void TestGetBlockHex() + public async Task TestGetBlockHex() { - var tests = TestUtils.RpcTestCases.Where(p => p.Name == nameof(rpc.GetBlockHex).ToLower()); + var tests = TestUtils.RpcTestCases.Where(p => p.Name == nameof(rpc.GetBlockHexAsync).ToLower()); foreach (var test in tests) { - var result = rpc.GetBlockHex(test.Request.Params[0].AsString()); + var result = await rpc.GetBlockHexAsync(test.Request.Params[0].AsString()); Assert.AreEqual(test.Response.Result.AsString(), result); } } [TestMethod] - public void TestGetBlock() + public async Task TestGetBlock() { - var tests = TestUtils.RpcTestCases.Where(p => p.Name == nameof(rpc.GetBlock).ToLower()); + var tests = TestUtils.RpcTestCases.Where(p => p.Name == nameof(rpc.GetBlockAsync).ToLower()); foreach (var test in tests) { - var result = rpc.GetBlock(test.Request.Params[0].AsString()); + var result = await rpc.GetBlockAsync(test.Request.Params[0].AsString()); Assert.AreEqual(test.Response.Result.AsString(), result.ToJson().ToString()); } } [TestMethod] - public void TestGetBlockCount() + public async Task TestGetBlockCount() { - var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetBlockCount).ToLower()); - var result = rpc.GetBlockCount(); + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetBlockCountAsync).ToLower()); + var result = await rpc.GetBlockCountAsync(); Assert.AreEqual(test.Response.Result.AsString(), result.ToString()); } [TestMethod] - public void TestGetBlockHash() + public async Task TestGetBlockHash() { - var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetBlockHash).ToLower()); - var result = rpc.GetBlockHash((int)test.Request.Params[0].AsNumber()); + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetBlockHashAsync).ToLower()); + var result = await rpc.GetBlockHashAsync((int)test.Request.Params[0].AsNumber()); Assert.AreEqual(test.Response.Result.AsString(), result.ToString()); } [TestMethod] - public void TestGetBlockHeaderHex() + public async Task TestGetBlockHeaderHex() { - var tests = TestUtils.RpcTestCases.Where(p => p.Name == nameof(rpc.GetBlockHeaderHex).ToLower()); + var tests = TestUtils.RpcTestCases.Where(p => p.Name == nameof(rpc.GetBlockHeaderHexAsync).ToLower()); foreach (var test in tests) { - var result = rpc.GetBlockHeaderHex(test.Request.Params[0].AsString()); + var result = await rpc.GetBlockHeaderHexAsync(test.Request.Params[0].AsString()); Assert.AreEqual(test.Response.Result.AsString(), result); } } [TestMethod] - public void TestGetBlockHeader() + public async Task TestGetBlockHeader() { - var tests = TestUtils.RpcTestCases.Where(p => p.Name == nameof(rpc.GetBlockHeader).ToLower()); + var tests = TestUtils.RpcTestCases.Where(p => p.Name == nameof(rpc.GetBlockHeaderAsync).ToLower()); foreach (var test in tests) { - var result = rpc.GetBlockHeader(test.Request.Params[0].AsString()); + var result = await rpc.GetBlockHeaderAsync(test.Request.Params[0].AsString()); Assert.AreEqual(test.Response.Result.ToString(), result.ToJson().ToString()); } } [TestMethod] - public void TestGetContractState() + public async Task TestGetContractState() { - var tests = TestUtils.RpcTestCases.Where(p => p.Name == nameof(rpc.GetContractState).ToLower()); + var tests = TestUtils.RpcTestCases.Where(p => p.Name == nameof(rpc.GetContractStateAsync).ToLower()); foreach (var test in tests) { - var result = rpc.GetContractState(test.Request.Params[0].AsString()); + var result = await rpc.GetContractStateAsync(test.Request.Params[0].AsString()); Assert.AreEqual(test.Response.Result.ToString(), result.ToJson().ToString()); } } [TestMethod] - public void TestGetRawMempool() + public async Task TestGetRawMempool() { - var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetRawMempool).ToLower()); - var result = rpc.GetRawMempool(); + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetRawMempoolAsync).ToLower()); + var result = await rpc.GetRawMempoolAsync(); Assert.AreEqual(test.Response.Result.ToString(), ((JArray)result.Select(p => (JObject)p).ToArray()).ToString()); } [TestMethod] - public void TestGetRawMempoolBoth() + public async Task TestGetRawMempoolBoth() { - var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetRawMempoolBoth).ToLower()); - var result = rpc.GetRawMempoolBoth(); + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetRawMempoolBothAsync).ToLower()); + var result = await rpc.GetRawMempoolBothAsync(); Assert.AreEqual(test.Response.Result.ToString(), result.ToJson().ToString()); } [TestMethod] - public void TestGetRawTransactionHex() + public async Task TestGetRawTransactionHex() { - var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetRawTransactionHex).ToLower()); - var result = rpc.GetRawTransactionHex(test.Request.Params[0].AsString()); + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetRawTransactionHexAsync).ToLower()); + var result = await rpc.GetRawTransactionHexAsync(test.Request.Params[0].AsString()); Assert.AreEqual(test.Response.Result.AsString(), result); } [TestMethod] - public void TestGetRawTransaction() + public async Task TestGetRawTransaction() { - var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetRawTransaction).ToLower()); - var result = rpc.GetRawTransaction(test.Request.Params[0].AsString()); + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetRawTransactionAsync).ToLower()); + var result = await rpc.GetRawTransactionAsync(test.Request.Params[0].AsString()); Assert.AreEqual(test.Response.Result.ToString(), result.ToJson().ToString()); } [TestMethod] - public void TestGetStorage() + public async Task TestGetStorage() { - var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetStorage).ToLower()); - var result = rpc.GetStorage(test.Request.Params[0].AsString(), test.Request.Params[1].AsString()); + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetStorageAsync).ToLower()); + var result = await rpc.GetStorageAsync(test.Request.Params[0].AsString(), test.Request.Params[1].AsString()); Assert.AreEqual(test.Response.Result.AsString(), result); } [TestMethod] - public void TestGetTransactionHeight() + public async Task TestGetTransactionHeight() { - var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetTransactionHeight).ToLower()); - var result = rpc.GetTransactionHeight(test.Request.Params[0].AsString()); + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetTransactionHeightAsync).ToLower()); + var result = await rpc.GetTransactionHeightAsync(test.Request.Params[0].AsString()); Assert.AreEqual(test.Response.Result.ToString(), result.ToString()); } [TestMethod] - public void TestGetNextBlockValidators() + public async Task TestGetNextBlockValidators() { - var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetNextBlockValidators).ToLower()); - var result = rpc.GetNextBlockValidators(); + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetNextBlockValidatorsAsync).ToLower()); + var result = await rpc.GetNextBlockValidatorsAsync(); Assert.AreEqual(test.Response.Result.ToString(), ((JArray)result.Select(p => p.ToJson()).ToArray()).ToString()); } @@ -230,43 +226,43 @@ public void TestGetNextBlockValidators() #region Node [TestMethod] - public void TestGetConnectionCount() + public async Task TestGetConnectionCount() { - var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetConnectionCount).ToLower()); - var result = rpc.GetConnectionCount(); + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetConnectionCountAsync).ToLower()); + var result = await rpc.GetConnectionCountAsync(); Assert.AreEqual(test.Response.Result.ToString(), result.ToString()); } [TestMethod] - public void TestGetPeers() + public async Task TestGetPeers() { - var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetPeers).ToLower()); - var result = rpc.GetPeers(); + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetPeersAsync).ToLower()); + var result = await rpc.GetPeersAsync(); Assert.AreEqual(test.Response.Result.ToString(), result.ToJson().ToString()); } [TestMethod] - public void TestGetVersion() + public async Task TestGetVersion() { - var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetVersion).ToLower()); - var result = rpc.GetVersion(); + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetVersionAsync).ToLower()); + var result = await rpc.GetVersionAsync(); Assert.AreEqual(test.Response.Result.ToString(), result.ToJson().ToString()); } [TestMethod] - public void TestSendRawTransaction() + public async Task TestSendRawTransaction() { - var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.SendRawTransaction).ToLower()); - var result = rpc.SendRawTransaction(test.Request.Params[0].AsString().HexToBytes().AsSerializable()); + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.SendRawTransactionAsync).ToLower()); + var result = await rpc.SendRawTransactionAsync(test.Request.Params[0].AsString().HexToBytes().AsSerializable()); Assert.AreEqual(test.Response.Result["hash"].AsString(), result.ToString()); } [TestMethod] - public void TestSubmitBlock() + public async Task TestSubmitBlock() { - var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.SubmitBlock).ToLower()); + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.SubmitBlockAsync).ToLower()); var block = TestUtils.GetBlock(2).Hash; - var result = rpc.SubmitBlock(test.Request.Params[0].AsString().HexToBytes()); + var result = await rpc.SubmitBlockAsync(test.Request.Params[0].AsString().HexToBytes()); Assert.AreEqual(test.Response.Result["hash"].AsString(), result.ToString()); } @@ -275,27 +271,27 @@ public void TestSubmitBlock() #region SmartContract [TestMethod] - public void TestInvokeFunction() + public async Task TestInvokeFunction() { - var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.InvokeFunction).ToLower()); - var result = rpc.InvokeFunction(test.Request.Params[0].AsString(), test.Request.Params[1].AsString(), + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.InvokeFunctionAsync).ToLower()); + var result = await rpc.InvokeFunctionAsync(test.Request.Params[0].AsString(), test.Request.Params[1].AsString(), ((JArray)test.Request.Params[2]).Select(p => RpcStack.FromJson(p)).ToArray()); Assert.AreEqual(test.Response.Result.ToString(), result.ToJson().ToString()); } [TestMethod] - public void TestInvokeScript() + public async Task TestInvokeScript() { - var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.InvokeScript).ToLower()); - var result = rpc.InvokeScript(test.Request.Params[0].AsString().HexToBytes()); + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.InvokeScriptAsync).ToLower()); + var result = await rpc.InvokeScriptAsync(test.Request.Params[0].AsString().HexToBytes()); Assert.AreEqual(test.Response.Result.ToString(), result.ToJson().ToString()); } [TestMethod] - public void TestGetUnclaimedGas() + public async Task TestGetUnclaimedGas() { - var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetUnclaimedGas).ToLower()); - var result = rpc.GetUnclaimedGas(test.Request.Params[0].AsString()); + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetUnclaimedGasAsync).ToLower()); + var result = await rpc.GetUnclaimedGasAsync(test.Request.Params[0].AsString()); Assert.AreEqual(test.Response.Result["unclaimed"].AsString(), result.Unclaimed.ToString()); } @@ -304,18 +300,18 @@ public void TestGetUnclaimedGas() #region Utilities [TestMethod] - public void TestListPlugins() + public async Task TestListPlugins() { - var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.ListPlugins).ToLower()); - var result = rpc.ListPlugins(); + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.ListPluginsAsync).ToLower()); + var result = await rpc.ListPluginsAsync(); Assert.AreEqual(test.Response.Result.ToString(), ((JArray)result.Select(p => p.ToJson()).ToArray()).ToString()); } [TestMethod] - public void TestValidateAddress() + public async Task TestValidateAddress() { - var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.ValidateAddress).ToLower()); - var result = rpc.ValidateAddress(test.Request.Params[0].AsString()); + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.ValidateAddressAsync).ToLower()); + var result = await rpc.ValidateAddressAsync(test.Request.Params[0].AsString()); Assert.AreEqual(test.Response.Result.ToString(), result.ToJson().ToString()); } @@ -324,91 +320,91 @@ public void TestValidateAddress() #region Wallet [TestMethod] - public void TestCloseWallet() + public async Task TestCloseWallet() { - var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.CloseWallet).ToLower()); - var result = rpc.CloseWallet(); + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.CloseWalletAsync).ToLower()); + var result = await rpc.CloseWalletAsync(); Assert.AreEqual(test.Response.Result.AsBoolean(), result); } [TestMethod] - public void TestDumpPrivKey() + public async Task TestDumpPrivKey() { - var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.DumpPrivKey).ToLower()); - var result = rpc.DumpPrivKey(test.Request.Params[0].AsString()); + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.DumpPrivKeyAsync).ToLower()); + var result = await rpc.DumpPrivKeyAsync(test.Request.Params[0].AsString()); Assert.AreEqual(test.Response.Result.AsString(), result); } [TestMethod] - public void TestGetNewAddress() + public async Task TestGetNewAddress() { - var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetNewAddress).ToLower()); - var result = rpc.GetNewAddress(); + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetNewAddressAsync).ToLower()); + var result = await rpc.GetNewAddressAsync(); Assert.AreEqual(test.Response.Result.AsString(), result); } [TestMethod] - public void TestGetWalletBalance() + public async Task TestGetWalletBalance() { - var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetWalletBalance).ToLower()); - var result = rpc.GetWalletBalance(test.Request.Params[0].AsString()); + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetWalletBalanceAsync).ToLower()); + var result = await rpc.GetWalletBalanceAsync(test.Request.Params[0].AsString()); Assert.AreEqual(test.Response.Result["balance"].AsString(), result.Value.ToString()); } [TestMethod] - public void TestGetWalletUnclaimedGas() + public async Task TestGetWalletUnclaimedGas() { - var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetWalletUnclaimedGas).ToLower()); - var result = rpc.GetWalletUnclaimedGas(); + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetWalletUnclaimedGasAsync).ToLower()); + var result = await rpc.GetWalletUnclaimedGasAsync(); Assert.AreEqual(test.Response.Result.AsString(), result.ToString()); } [TestMethod] - public void TestImportPrivKey() + public async Task TestImportPrivKey() { - var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.ImportPrivKey).ToLower()); - var result = rpc.ImportPrivKey(test.Request.Params[0].AsString()); + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.ImportPrivKeyAsync).ToLower()); + var result = await rpc.ImportPrivKeyAsync(test.Request.Params[0].AsString()); Assert.AreEqual(test.Response.Result.ToString(), result.ToJson().ToString()); } [TestMethod] - public void TestListAddress() + public async Task TestListAddress() { - var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.ListAddress).ToLower()); - var result = rpc.ListAddress(); + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.ListAddressAsync).ToLower()); + var result = await rpc.ListAddressAsync(); Assert.AreEqual(test.Response.Result.ToString(), ((JArray)result.Select(p => p.ToJson()).ToArray()).ToString()); } [TestMethod] - public void TestOpenWallet() + public async Task TestOpenWallet() { - var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.OpenWallet).ToLower()); - var result = rpc.OpenWallet(test.Request.Params[0].AsString(), test.Request.Params[1].AsString()); + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.OpenWalletAsync).ToLower()); + var result = await rpc.OpenWalletAsync(test.Request.Params[0].AsString(), test.Request.Params[1].AsString()); Assert.AreEqual(test.Response.Result.AsBoolean(), result); } [TestMethod] - public void TestSendFrom() + public async Task TestSendFrom() { - var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.SendFrom).ToLower()); - var result = rpc.SendFrom(test.Request.Params[0].AsString(), test.Request.Params[1].AsString(), + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.SendFromAsync).ToLower()); + var result = await rpc.SendFromAsync(test.Request.Params[0].AsString(), test.Request.Params[1].AsString(), test.Request.Params[2].AsString(), test.Request.Params[3].AsString()); Assert.AreEqual(test.Response.Result.ToString(), result.ToString()); } [TestMethod] - public void TestSendMany() + public async Task TestSendMany() { - var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.SendMany).ToLower()); - var result = rpc.SendMany(test.Request.Params[0].AsString(), ((JArray)test.Request.Params[1]).Select(p => RpcTransferOut.FromJson(p))); + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.SendManyAsync).ToLower()); + var result = await rpc.SendManyAsync(test.Request.Params[0].AsString(), ((JArray)test.Request.Params[1]).Select(p => RpcTransferOut.FromJson(p))); Assert.AreEqual(test.Response.Result.ToString(), result.ToString()); } [TestMethod] - public void TestSendToAddress() + public async Task TestSendToAddress() { - var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.SendToAddress).ToLower()); - var result = rpc.SendToAddress(test.Request.Params[0].AsString(), test.Request.Params[1].AsString(), test.Request.Params[2].AsString()); + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.SendToAddressAsync).ToLower()); + var result = await rpc.SendToAddressAsync(test.Request.Params[0].AsString(), test.Request.Params[1].AsString(), test.Request.Params[2].AsString()); Assert.AreEqual(test.Response.Result.ToString(), result.ToString()); } @@ -417,27 +413,27 @@ public void TestSendToAddress() #region Plugins [TestMethod()] - public void GetApplicationLogTest() + public async Task GetApplicationLogTest() { - var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetApplicationLog).ToLower()); - var result = rpc.GetApplicationLog(test.Request.Params[0].AsString()); + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetApplicationLogAsync).ToLower()); + var result = await rpc.GetApplicationLogAsync(test.Request.Params[0].AsString()); Assert.AreEqual(test.Response.Result.ToString(), result.ToJson().ToString()); } [TestMethod()] - public void GetNep5TransfersTest() + public async Task GetNep5TransfersTest() { - var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetNep5Transfers).ToLower()); - var result = rpc.GetNep5Transfers(test.Request.Params[0].AsString(), (ulong)test.Request.Params[1].AsNumber(), + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetNep5TransfersAsync).ToLower()); + var result = await rpc.GetNep5TransfersAsync(test.Request.Params[0].AsString(), (ulong)test.Request.Params[1].AsNumber(), (ulong)test.Request.Params[2].AsNumber()); Assert.AreEqual(test.Response.Result.ToString(), result.ToJson().ToString()); } [TestMethod()] - public void GetNep5BalancesTest() + public async Task GetNep5BalancesTest() { - var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetNep5Balances).ToLower()); - var result = rpc.GetNep5Balances(test.Request.Params[0].AsString()); + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetNep5BalancesAsync).ToLower()); + var result = await rpc.GetNep5BalancesAsync(test.Request.Params[0].AsString()); Assert.AreEqual(test.Response.Result.ToString(), result.ToJson().ToString()); } diff --git a/tests/Neo.Network.RPC.Tests/UT_RpcModels.cs b/tests/Neo.Network.RPC.Tests/UT_RpcModels.cs index 559e1f748..04613dbc1 100644 --- a/tests/Neo.Network.RPC.Tests/UT_RpcModels.cs +++ b/tests/Neo.Network.RPC.Tests/UT_RpcModels.cs @@ -11,7 +11,7 @@ public class UT_RpcModels [TestMethod()] public void TestRpcAccount() { - JObject json = TestUtils.RpcTestCases.Find(p => p.Name == nameof(RpcClient.ImportPrivKey).ToLower()).Response.Result; + JObject json = TestUtils.RpcTestCases.Find(p => p.Name == nameof(RpcClient.ImportPrivKeyAsync).ToLower()).Response.Result; var item = RpcAccount.FromJson(json); Assert.AreEqual(json.ToString(), item.ToJson().ToString()); } @@ -19,7 +19,7 @@ public void TestRpcAccount() [TestMethod()] public void TestRpcApplicationLog() { - JObject json = TestUtils.RpcTestCases.Find(p => p.Name == nameof(RpcClient.GetApplicationLog).ToLower()).Response.Result; + JObject json = TestUtils.RpcTestCases.Find(p => p.Name == nameof(RpcClient.GetApplicationLogAsync).ToLower()).Response.Result; var item = RpcApplicationLog.FromJson(json); Assert.AreEqual(json.ToString(), item.ToJson().ToString()); } @@ -27,7 +27,7 @@ public void TestRpcApplicationLog() [TestMethod()] public void TestRpcBlock() { - JObject json = TestUtils.RpcTestCases.Find(p => p.Name == nameof(RpcClient.GetBlock).ToLower()).Response.Result; + JObject json = TestUtils.RpcTestCases.Find(p => p.Name == nameof(RpcClient.GetBlockAsync).ToLower()).Response.Result; var item = RpcBlock.FromJson(json); Assert.AreEqual(json.ToString(), item.ToJson().ToString()); } @@ -35,7 +35,7 @@ public void TestRpcBlock() [TestMethod()] public void TestRpcBlockHeader() { - JObject json = TestUtils.RpcTestCases.Find(p => p.Name == nameof(RpcClient.GetBlockHeader).ToLower()).Response.Result; + JObject json = TestUtils.RpcTestCases.Find(p => p.Name == nameof(RpcClient.GetBlockHeaderAsync).ToLower()).Response.Result; var item = RpcBlockHeader.FromJson(json); Assert.AreEqual(json.ToString(), item.ToJson().ToString()); } @@ -43,7 +43,7 @@ public void TestRpcBlockHeader() [TestMethod()] public void TestGetContractState() { - JObject json = TestUtils.RpcTestCases.Find(p => p.Name == nameof(RpcClient.GetContractState).ToLower()).Response.Result; + JObject json = TestUtils.RpcTestCases.Find(p => p.Name == nameof(RpcClient.GetContractStateAsync).ToLower()).Response.Result; var item = RpcContractState.FromJson(json); Assert.AreEqual(json.ToString(), item.ToJson().ToString()); } @@ -51,7 +51,7 @@ public void TestGetContractState() [TestMethod()] public void TestRpcInvokeResult() { - JObject json = TestUtils.RpcTestCases.Find(p => p.Name == nameof(RpcClient.InvokeFunction).ToLower()).Response.Result; + JObject json = TestUtils.RpcTestCases.Find(p => p.Name == nameof(RpcClient.InvokeFunctionAsync).ToLower()).Response.Result; var item = RpcInvokeResult.FromJson(json); Assert.AreEqual(json.ToString(), item.ToJson().ToString()); } @@ -59,7 +59,7 @@ public void TestRpcInvokeResult() [TestMethod()] public void TestRpcNep5Balances() { - JObject json = TestUtils.RpcTestCases.Find(p => p.Name == nameof(RpcClient.GetNep5Balances).ToLower()).Response.Result; + JObject json = TestUtils.RpcTestCases.Find(p => p.Name == nameof(RpcClient.GetNep5BalancesAsync).ToLower()).Response.Result; var item = RpcNep5Balances.FromJson(json); Assert.AreEqual(json.ToString(), item.ToJson().ToString()); } @@ -67,7 +67,7 @@ public void TestRpcNep5Balances() [TestMethod()] public void TestRpcNep5Transfers() { - JObject json = TestUtils.RpcTestCases.Find(p => p.Name == nameof(RpcClient.GetNep5Transfers).ToLower()).Response.Result; + JObject json = TestUtils.RpcTestCases.Find(p => p.Name == nameof(RpcClient.GetNep5TransfersAsync).ToLower()).Response.Result; var item = RpcNep5Transfers.FromJson(json); Assert.AreEqual(json.ToString(), item.ToJson().ToString()); } @@ -75,7 +75,7 @@ public void TestRpcNep5Transfers() [TestMethod()] public void TestRpcPeers() { - JObject json = TestUtils.RpcTestCases.Find(p => p.Name == nameof(RpcClient.GetPeers).ToLower()).Response.Result; + JObject json = TestUtils.RpcTestCases.Find(p => p.Name == nameof(RpcClient.GetPeersAsync).ToLower()).Response.Result; var item = RpcPeers.FromJson(json); Assert.AreEqual(json.ToString(), item.ToJson().ToString()); } @@ -83,7 +83,7 @@ public void TestRpcPeers() [TestMethod()] public void TestRpcPlugin() { - JObject json = TestUtils.RpcTestCases.Find(p => p.Name == nameof(RpcClient.ListPlugins).ToLower()).Response.Result; + JObject json = TestUtils.RpcTestCases.Find(p => p.Name == nameof(RpcClient.ListPluginsAsync).ToLower()).Response.Result; var item = ((JArray)json).Select(p => RpcPlugin.FromJson(p)); Assert.AreEqual(json.ToString(), ((JArray)item.Select(p => p.ToJson()).ToArray()).ToString()); } @@ -91,7 +91,7 @@ public void TestRpcPlugin() [TestMethod()] public void TestRpcRawMemPool() { - JObject json = TestUtils.RpcTestCases.Find(p => p.Name == nameof(RpcClient.GetRawMempoolBoth).ToLower()).Response.Result; + JObject json = TestUtils.RpcTestCases.Find(p => p.Name == nameof(RpcClient.GetRawMempoolBothAsync).ToLower()).Response.Result; var item = RpcRawMemPool.FromJson(json); Assert.AreEqual(json.ToString(), item.ToJson().ToString()); } @@ -99,7 +99,7 @@ public void TestRpcRawMemPool() [TestMethod()] public void TestRpcTransaction() { - JObject json = TestUtils.RpcTestCases.Find(p => p.Name == nameof(RpcClient.GetRawTransaction).ToLower()).Response.Result; + JObject json = TestUtils.RpcTestCases.Find(p => p.Name == nameof(RpcClient.GetRawTransactionAsync).ToLower()).Response.Result; var item = RpcTransaction.FromJson(json); Assert.AreEqual(json.ToString(), item.ToJson().ToString()); } @@ -107,7 +107,7 @@ public void TestRpcTransaction() [TestMethod()] public void TestRpcTransferOut() { - JObject json = TestUtils.RpcTestCases.Find(p => p.Name == nameof(RpcClient.SendMany).ToLower()).Request.Params[1]; + JObject json = TestUtils.RpcTestCases.Find(p => p.Name == nameof(RpcClient.SendManyAsync).ToLower()).Request.Params[1]; var item = ((JArray)json).Select(p => RpcTransferOut.FromJson(p)); Assert.AreEqual(json.ToString(), ((JArray)item.Select(p => p.ToJson()).ToArray()).ToString()); } @@ -115,7 +115,7 @@ public void TestRpcTransferOut() [TestMethod()] public void TestRpcValidateAddressResult() { - JObject json = TestUtils.RpcTestCases.Find(p => p.Name == nameof(RpcClient.ValidateAddress).ToLower()).Response.Result; + JObject json = TestUtils.RpcTestCases.Find(p => p.Name == nameof(RpcClient.ValidateAddressAsync).ToLower()).Response.Result; var item = RpcValidateAddressResult.FromJson(json); Assert.AreEqual(json.ToString(), item.ToJson().ToString()); } @@ -123,7 +123,7 @@ public void TestRpcValidateAddressResult() [TestMethod()] public void TestRpcValidator() { - JObject json = TestUtils.RpcTestCases.Find(p => p.Name == nameof(RpcClient.GetNextBlockValidators).ToLower()).Response.Result; + JObject json = TestUtils.RpcTestCases.Find(p => p.Name == nameof(RpcClient.GetNextBlockValidatorsAsync).ToLower()).Response.Result; var item = ((JArray)json).Select(p => RpcValidator.FromJson(p)); Assert.AreEqual(json.ToString(), ((JArray)item.Select(p => p.ToJson()).ToArray()).ToString()); } @@ -131,7 +131,7 @@ public void TestRpcValidator() [TestMethod()] public void TestRpcVersion() { - JObject json = TestUtils.RpcTestCases.Find(p => p.Name == nameof(RpcClient.GetVersion).ToLower()).Response.Result; + JObject json = TestUtils.RpcTestCases.Find(p => p.Name == nameof(RpcClient.GetVersionAsync).ToLower()).Response.Result; var item = RpcVersion.FromJson(json); Assert.AreEqual(json.ToString(), item.ToJson().ToString()); } diff --git a/tests/Neo.Network.RPC.Tests/UT_TransactionManager.cs b/tests/Neo.Network.RPC.Tests/UT_TransactionManager.cs index a9802fec0..c5d8a1d4b 100644 --- a/tests/Neo.Network.RPC.Tests/UT_TransactionManager.cs +++ b/tests/Neo.Network.RPC.Tests/UT_TransactionManager.cs @@ -14,6 +14,7 @@ using System; using System.Linq; using System.Numerics; +using System.Threading.Tasks; namespace Neo.Network.RPC.Tests { @@ -44,13 +45,13 @@ public static Mock MockRpcClient(UInt160 sender, byte[] script) var mockRpc = new Mock(MockBehavior.Strict, "http://seed1.neo.org:10331", null, null); // MockHeight - mockRpc.Setup(p => p.RpcSend("getblockcount")).Returns(100).Verifiable(); + mockRpc.Setup(p => p.RpcSendAsync("getblockcount")).ReturnsAsync(100).Verifiable(); // calculatenetworkfee var networkfee = new JObject(); networkfee["networkfee"] = 100000000; - mockRpc.Setup(p => p.RpcSend("calculatenetworkfee", It.Is(u => true))) - .Returns(networkfee) + mockRpc.Setup(p => p.RpcSendAsync("calculatenetworkfee", It.Is(u => true))) + .ReturnsAsync(networkfee) .Verifiable(); // MockGasBalance @@ -77,13 +78,13 @@ public static Mock MockMultiSig(UInt160 multiHash, byte[] script) var mockRpc = new Mock(MockBehavior.Strict, "http://seed1.neo.org:10331", null, null); // MockHeight - mockRpc.Setup(p => p.RpcSend("getblockcount")).Returns(100).Verifiable(); + mockRpc.Setup(p => p.RpcSendAsync("getblockcount")).ReturnsAsync(100).Verifiable(); // calculatenetworkfee var networkfee = new JObject(); networkfee["networkfee"] = 100000000; - mockRpc.Setup(p => p.RpcSend("calculatenetworkfee", It.Is(u => true))) - .Returns(networkfee) + mockRpc.Setup(p => p.RpcSendAsync("calculatenetworkfee", It.Is(u => true))) + .ReturnsAsync(networkfee) .Verifiable(); // MockGasBalance @@ -115,16 +116,14 @@ public static void MockInvokeScript(Mock mockClient, byte[] script, p State = VMState.HALT }; - mockClient.Setup(p => p.RpcSend("invokescript", It.Is(j => j[0].AsString() == script.ToHexString()))) - .Returns(result.ToJson()) + mockClient.Setup(p => p.RpcSendAsync("invokescript", It.Is(j => j[0].AsString() == script.ToHexString()))) + .ReturnsAsync(result.ToJson()) .Verifiable(); } [TestMethod] - public void TestMakeTransaction() + public async Task TestMakeTransaction() { - txManager = new TransactionManager(rpcClientMock.Object); - Signer[] signers = new Signer[1] { new Signer @@ -135,17 +134,15 @@ public void TestMakeTransaction() }; byte[] script = new byte[1]; - txManager.MakeTransaction(script, signers); + txManager = await TransactionManager.MakeTransactionAsync(rpcClientMock.Object, script, signers); var tx = txManager.Tx; Assert.AreEqual(WitnessScope.Global, tx.Signers[0].Scopes); } [TestMethod] - public void TestSign() + public async Task TestSign() { - txManager = new TransactionManager(rpcClientMock.Object); - Signer[] signers = new Signer[1] { new Signer @@ -156,9 +153,10 @@ public void TestSign() }; byte[] script = new byte[1]; - txManager.MakeTransaction(script, signers) + txManager = await TransactionManager.MakeTransactionAsync(rpcClientMock.Object, script, signers); + await txManager .AddSignature(keyPair1) - .Sign(); + .SignAsync(); // get signature from Witnesses var tx = txManager.Tx; @@ -170,18 +168,40 @@ public void TestSign() Assert.AreEqual(100, tx.SystemFee); // duplicate sign should not add new witness - txManager.AddSignature(keyPair1).Sign(); + await txManager.AddSignature(keyPair1).SignAsync(); Assert.AreEqual(1, txManager.Tx.Witnesses.Length); // throw exception when the KeyPair is wrong - Assert.ThrowsException(() => txManager.AddSignature(keyPair2).Sign()); + await ThrowsAsync(async () => await txManager.AddSignature(keyPair2).SignAsync()); } - [TestMethod] - public void TestSignMulti() + // https://docs.microsoft.com/en-us/archive/msdn-magazine/2014/november/async-programming-unit-testing-asynchronous-code#testing-exceptions + static async Task ThrowsAsync(Func action, bool allowDerivedTypes = true) + where TException : Exception { - txManager = new TransactionManager(multiSigMock.Object); + try + { + await action(); + } + catch (Exception ex) + { + if (allowDerivedTypes && !(ex is TException)) + throw new Exception("Delegate threw exception of type " + + ex.GetType().Name + ", but " + typeof(TException).Name + + " or a derived type was expected.", ex); + if (!allowDerivedTypes && ex.GetType() != typeof(TException)) + throw new Exception("Delegate threw exception of type " + + ex.GetType().Name + ", but " + typeof(TException).Name + + " was expected.", ex); + return (TException)ex; + } + throw new Exception("Delegate did not throw expected exception " + + typeof(TException).Name + "."); + } + [TestMethod] + public async Task TestSignMulti() + { // Cosigner needs multi signature Signer[] signers = new Signer[1] { @@ -193,17 +213,16 @@ public void TestSignMulti() }; byte[] script = new byte[1]; - txManager.MakeTransaction(script, signers) + txManager = await TransactionManager.MakeTransactionAsync(multiSigMock.Object, script, signers); + await txManager .AddMultiSig(keyPair1, 2, keyPair1.PublicKey, keyPair2.PublicKey) .AddMultiSig(keyPair2, 2, keyPair1.PublicKey, keyPair2.PublicKey) - .Sign(); + .SignAsync(); } [TestMethod] - public void TestAddWitness() + public async Task TestAddWitness() { - txManager = new TransactionManager(rpcClientMock.Object); - // Cosigner as contract scripthash Signer[] signers = new Signer[2] { @@ -220,10 +239,10 @@ public void TestAddWitness() }; byte[] script = new byte[1]; - txManager.MakeTransaction(script, signers); + txManager = await TransactionManager.MakeTransactionAsync(rpcClientMock.Object, script, signers); txManager.AddWitness(UInt160.Zero); txManager.AddSignature(keyPair1); - txManager.Sign(); + await txManager.SignAsync(); var tx = txManager.Tx; Assert.AreEqual(2, tx.Witnesses.Length); diff --git a/tests/Neo.Network.RPC.Tests/UT_WalletAPI.cs b/tests/Neo.Network.RPC.Tests/UT_WalletAPI.cs index 37a0cc181..ebfbcb51b 100644 --- a/tests/Neo.Network.RPC.Tests/UT_WalletAPI.cs +++ b/tests/Neo.Network.RPC.Tests/UT_WalletAPI.cs @@ -8,6 +8,7 @@ using Neo.VM; using Neo.Wallets; using System.Numerics; +using System.Threading.Tasks; namespace Neo.Network.RPC.Tests { @@ -33,47 +34,47 @@ public void TestSetup() } [TestMethod] - public void TestGetUnclaimedGas() + public async Task TestGetUnclaimedGas() { byte[] testScript = NativeContract.NEO.Hash.MakeScript("unclaimedGas", sender, 99); UT_TransactionManager.MockInvokeScript(rpcClientMock, testScript, new ContractParameter { Type = ContractParameterType.Integer, Value = new BigInteger(1_10000000) }); - var balance = walletAPI.GetUnclaimedGas(address1); + var balance = await walletAPI.GetUnclaimedGasAsync(address1); Assert.AreEqual(1.1m, balance); } [TestMethod] - public void TestGetNeoBalance() + public async Task TestGetNeoBalance() { byte[] testScript = NativeContract.NEO.Hash.MakeScript("balanceOf", sender); UT_TransactionManager.MockInvokeScript(rpcClientMock, testScript, new ContractParameter { Type = ContractParameterType.Integer, Value = new BigInteger(1_00000000) }); - var balance = walletAPI.GetNeoBalance(address1); + var balance = await walletAPI.GetNeoBalanceAsync(address1); Assert.AreEqual(1_00000000u, balance); } [TestMethod] - public void TestGetGasBalance() + public async Task TestGetGasBalance() { byte[] testScript = NativeContract.GAS.Hash.MakeScript("balanceOf", sender); UT_TransactionManager.MockInvokeScript(rpcClientMock, testScript, new ContractParameter { Type = ContractParameterType.Integer, Value = new BigInteger(1_10000000) }); - var balance = walletAPI.GetGasBalance(address1); + var balance = await walletAPI.GetGasBalanceAsync(address1); Assert.AreEqual(1.1m, balance); } [TestMethod] - public void TestGetTokenBalance() + public async Task TestGetTokenBalance() { byte[] testScript = UInt160.Zero.MakeScript("balanceOf", sender); UT_TransactionManager.MockInvokeScript(rpcClientMock, testScript, new ContractParameter { Type = ContractParameterType.Integer, Value = new BigInteger(1_10000000) }); - var balance = walletAPI.GetTokenBalance(UInt160.Zero.ToString(), address1); + var balance = await walletAPI.GetTokenBalanceAsync(UInt160.Zero.ToString(), address1); Assert.AreEqual(1_10000000, balance); } [TestMethod] - public void TestClaimGas() + public async Task TestClaimGas() { byte[] balanceScript = NativeContract.NEO.Hash.MakeScript("balanceOf", sender); UT_TransactionManager.MockInvokeScript(rpcClientMock, balanceScript, new ContractParameter { Type = ContractParameterType.Integer, Value = new BigInteger(1_00000000) }); @@ -83,14 +84,14 @@ public void TestClaimGas() var json = new JObject(); json["hash"] = UInt256.Zero.ToString(); - rpcClientMock.Setup(p => p.RpcSend("sendrawtransaction", It.IsAny())).Returns(json); + rpcClientMock.Setup(p => p.RpcSendAsync("sendrawtransaction", It.IsAny())).ReturnsAsync(json); - var tranaction = walletAPI.ClaimGas(keyPair1.Export()); + var tranaction = await walletAPI.ClaimGasAsync(keyPair1.Export()); Assert.AreEqual(testScript.ToHexString(), tranaction.Script.ToHexString()); } [TestMethod] - public void TestTransfer() + public async Task TestTransfer() { byte[] decimalsScript = NativeContract.GAS.Hash.MakeScript("decimals"); UT_TransactionManager.MockInvokeScript(rpcClientMock, decimalsScript, new ContractParameter { Type = ContractParameterType.Integer, Value = new BigInteger(8) }); @@ -100,14 +101,14 @@ public void TestTransfer() var json = new JObject(); json["hash"] = UInt256.Zero.ToString(); - rpcClientMock.Setup(p => p.RpcSend("sendrawtransaction", It.IsAny())).Returns(json); + rpcClientMock.Setup(p => p.RpcSendAsync("sendrawtransaction", It.IsAny())).ReturnsAsync(json); - var tranaction = walletAPI.Transfer(NativeContract.GAS.Hash.ToString(), keyPair1.Export(), UInt160.Zero.ToAddress(), 100); + var tranaction = await walletAPI.TransferAsync(NativeContract.GAS.Hash.ToString(), keyPair1.Export(), UInt160.Zero.ToAddress(), 100); Assert.AreEqual(testScript.ToHexString(), tranaction.Script.ToHexString()); } [TestMethod] - public void TestTransferfromMultiSigAccount() + public async Task TestTransferfromMultiSigAccount() { byte[] balanceScript = NativeContract.GAS.Hash.MakeScript("balanceOf", multiSender); var balanceResult = new ContractParameter() { Type = ContractParameterType.Integer, Value = BigInteger.Parse("10000000000000000") }; @@ -122,20 +123,20 @@ public void TestTransferfromMultiSigAccount() var json = new JObject(); json["hash"] = UInt256.Zero.ToString(); - rpcClientMock.Setup(p => p.RpcSend("sendrawtransaction", It.IsAny())).Returns(json); + rpcClientMock.Setup(p => p.RpcSendAsync("sendrawtransaction", It.IsAny())).ReturnsAsync(json); - var tranaction = walletAPI.Transfer(NativeContract.GAS.Hash, 1, new[] { keyPair1.PublicKey }, new[] { keyPair1 }, UInt160.Zero, NativeContract.GAS.Factor * 100); + var tranaction = await walletAPI.TransferAsync(NativeContract.GAS.Hash, 1, new[] { keyPair1.PublicKey }, new[] { keyPair1 }, UInt160.Zero, NativeContract.GAS.Factor * 100); Assert.AreEqual(testScript.ToHexString(), tranaction.Script.ToHexString()); } [TestMethod] - public void TestWaitTransaction() + public async Task TestWaitTransaction() { Transaction transaction = TestUtils.GetTransaction(); - rpcClientMock.Setup(p => p.RpcSend("getrawtransaction", It.Is(j => j[0].AsString() == transaction.Hash.ToString()))) - .Returns(new RpcTransaction { Transaction = transaction, VMState = VMState.HALT, BlockHash = UInt256.Zero, BlockTime = 100, Confirmations = 1 }.ToJson()); + rpcClientMock.Setup(p => p.RpcSendAsync("getrawtransaction", It.Is(j => j[0].AsString() == transaction.Hash.ToString()))) + .ReturnsAsync(new RpcTransaction { Transaction = transaction, VMState = VMState.HALT, BlockHash = UInt256.Zero, BlockTime = 100, Confirmations = 1 }.ToJson()); - var tx = walletAPI.WaitTransaction(transaction).Result; + var tx = await walletAPI.WaitTransactionAsync(transaction); Assert.AreEqual(VMState.HALT, tx.VMState); Assert.AreEqual(UInt256.Zero, tx.BlockHash); } From 10a237ccdf67cb6e1180f613af86c328b6ff2b34 Mon Sep 17 00:00:00 2001 From: Luchuan Date: Thu, 15 Oct 2020 10:37:50 +0800 Subject: [PATCH 161/183] Add `magic` field in getversion (#363) * add magic field in getversion * fix rpc client * fix --- src/RpcClient/Models/RpcVersion.cs | 5 +++++ src/RpcServer/RpcServer.Node.cs | 1 + tests/Neo.Network.RPC.Tests/RpcTestCases.json | 1 + 3 files changed, 7 insertions(+) diff --git a/src/RpcClient/Models/RpcVersion.cs b/src/RpcClient/Models/RpcVersion.cs index c66015218..34ca163dd 100644 --- a/src/RpcClient/Models/RpcVersion.cs +++ b/src/RpcClient/Models/RpcVersion.cs @@ -4,6 +4,8 @@ namespace Neo.Network.RPC.Models { public class RpcVersion { + public uint Magic { get; set; } + public int TcpPort { get; set; } public int WsPort { get; set; } @@ -12,9 +14,11 @@ public class RpcVersion public string UserAgent { get; set; } + public JObject ToJson() { JObject json = new JObject(); + json["magic"] = Magic; json["tcpport"] = TcpPort; json["wsport"] = WsPort; json["nonce"] = Nonce; @@ -25,6 +29,7 @@ public JObject ToJson() public static RpcVersion FromJson(JObject json) { RpcVersion version = new RpcVersion(); + version.Magic = (uint)json["magic"].AsNumber(); version.TcpPort = (int)json["tcpport"].AsNumber(); version.WsPort = (int)json["wsport"].AsNumber(); version.Nonce = (uint)json["nonce"].AsNumber(); diff --git a/src/RpcServer/RpcServer.Node.cs b/src/RpcServer/RpcServer.Node.cs index 0696ab7f3..fa6e601fb 100644 --- a/src/RpcServer/RpcServer.Node.cs +++ b/src/RpcServer/RpcServer.Node.cs @@ -64,6 +64,7 @@ private JObject GetVersion(JArray _params) json["wsport"] = LocalNode.Singleton.ListenerWsPort; json["nonce"] = LocalNode.Nonce; json["useragent"] = LocalNode.UserAgent; + json["magic"] = ProtocolSettings.Default.Magic; return json; } diff --git a/tests/Neo.Network.RPC.Tests/RpcTestCases.json b/tests/Neo.Network.RPC.Tests/RpcTestCases.json index f1a7b9e07..2a98356c9 100644 --- a/tests/Neo.Network.RPC.Tests/RpcTestCases.json +++ b/tests/Neo.Network.RPC.Tests/RpcTestCases.json @@ -666,6 +666,7 @@ "jsonrpc": "2.0", "id": 1, "result": { + "magic": 0, "tcpport": 20333, "wsport": 20334, "nonce": 592651621, From 20dfce9c812e0eb842b5c712146a1fe5fdf13a0a Mon Sep 17 00:00:00 2001 From: Luchuan Date: Thu, 15 Oct 2020 10:56:40 +0800 Subject: [PATCH 162/183] Fix validateaddress (#365) * fix validateaddress * apply recommendation Co-authored-by: Owen Zhang <38493437+superboyiii@users.noreply.github.com> --- src/RpcServer/RpcServer.Utilities.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/RpcServer/RpcServer.Utilities.cs b/src/RpcServer/RpcServer.Utilities.cs index 7e4bf45db..ee4a038d3 100644 --- a/src/RpcServer/RpcServer.Utilities.cs +++ b/src/RpcServer/RpcServer.Utilities.cs @@ -33,7 +33,7 @@ private JObject ValidateAddress(JArray _params) UInt160 scriptHash; try { - scriptHash = AddressToScriptHash(address); + scriptHash = address.ToScriptHash(); } catch { From 6069db452661f4c1c02d6e04fe32047662db4e74 Mon Sep 17 00:00:00 2001 From: Luchuan Date: Thu, 15 Oct 2020 11:06:10 +0800 Subject: [PATCH 163/183] Allow rpc method can be overrided (#367) * allow rpc method can be overrided * change to protected virtual * set DummyWallet private * Update src/RpcServer/RpcServer.SmartContract.cs Co-authored-by: Shargon Co-authored-by: Shargon Co-authored-by: Owen Zhang <38493437+superboyiii@users.noreply.github.com> --- src/RpcServer/RpcServer.Blockchain.cs | 26 +++++++++++------------- src/RpcServer/RpcServer.Node.cs | 10 ++++----- src/RpcServer/RpcServer.SmartContract.cs | 6 +++--- src/RpcServer/RpcServer.Utilities.cs | 5 ++--- src/RpcServer/RpcServer.Wallet.cs | 26 ++++++++++++------------ src/RpcServer/RpcServer.cs | 2 +- src/RpcServer/RpcServerPlugin.cs | 2 +- src/RpcServer/RpcServerSettings.cs | 1 - 8 files changed, 37 insertions(+), 41 deletions(-) diff --git a/src/RpcServer/RpcServer.Blockchain.cs b/src/RpcServer/RpcServer.Blockchain.cs index 25ae58acc..3adde1ac7 100644 --- a/src/RpcServer/RpcServer.Blockchain.cs +++ b/src/RpcServer/RpcServer.Blockchain.cs @@ -6,9 +6,7 @@ using Neo.Ledger; using Neo.Network.P2P.Payloads; using Neo.Persistence; -using Neo.SmartContract; using Neo.SmartContract.Native; -using Neo.VM; using System; using System.Collections.Generic; using System.Linq; @@ -18,13 +16,13 @@ namespace Neo.Plugins partial class RpcServer { [RpcMethod] - private JObject GetBestBlockHash(JArray _params) + protected virtual JObject GetBestBlockHash(JArray _params) { return Blockchain.Singleton.CurrentBlockHash.ToString(); } [RpcMethod] - private JObject GetBlock(JArray _params) + protected virtual JObject GetBlock(JArray _params) { JObject key = _params[0]; bool verbose = _params.Count >= 2 && _params[1].AsBoolean(); @@ -54,13 +52,13 @@ private JObject GetBlock(JArray _params) } [RpcMethod] - private JObject GetBlockCount(JArray _params) + protected virtual JObject GetBlockCount(JArray _params) { return Blockchain.Singleton.Height + 1; } [RpcMethod] - private JObject GetBlockHash(JArray _params) + protected virtual JObject GetBlockHash(JArray _params) { uint height = uint.Parse(_params[0].AsString()); if (height <= Blockchain.Singleton.Height) @@ -71,7 +69,7 @@ private JObject GetBlockHash(JArray _params) } [RpcMethod] - private JObject GetBlockHeader(JArray _params) + protected virtual JObject GetBlockHeader(JArray _params) { JObject key = _params[0]; bool verbose = _params.Count >= 2 && _params[1].AsBoolean(); @@ -103,7 +101,7 @@ private JObject GetBlockHeader(JArray _params) } [RpcMethod] - private JObject GetContractState(JArray _params) + protected virtual JObject GetContractState(JArray _params) { UInt160 script_hash = UInt160.Parse(_params[0].AsString()); ContractState contract = Blockchain.Singleton.View.Contracts.TryGet(script_hash); @@ -111,7 +109,7 @@ private JObject GetContractState(JArray _params) } [RpcMethod] - private JObject GetRawMemPool(JArray _params) + protected virtual JObject GetRawMemPool(JArray _params) { bool shouldGetUnverified = _params.Count >= 1 && _params[0].AsBoolean(); if (!shouldGetUnverified) @@ -128,7 +126,7 @@ private JObject GetRawMemPool(JArray _params) } [RpcMethod] - private JObject GetRawTransaction(JArray _params) + protected virtual JObject GetRawTransaction(JArray _params) { UInt256 hash = UInt256.Parse(_params[0].AsString()); bool verbose = _params.Count >= 2 && _params[1].AsBoolean(); @@ -153,7 +151,7 @@ private JObject GetRawTransaction(JArray _params) } [RpcMethod] - private JObject GetStorage(JArray _params) + protected virtual JObject GetStorage(JArray _params) { if (!int.TryParse(_params[0].AsString(), out int id)) { @@ -172,7 +170,7 @@ private JObject GetStorage(JArray _params) } [RpcMethod] - private JObject GetTransactionHeight(JArray _params) + protected virtual JObject GetTransactionHeight(JArray _params) { UInt256 hash = UInt256.Parse(_params[0].AsString()); uint? height = Blockchain.Singleton.View.Transactions.TryGet(hash)?.BlockIndex; @@ -181,7 +179,7 @@ private JObject GetTransactionHeight(JArray _params) } [RpcMethod] - private JObject GetNextBlockValidators(JArray _params) + protected virtual JObject GetNextBlockValidators(JArray _params) { using SnapshotView snapshot = Blockchain.Singleton.GetSnapshot(); var validators = NativeContract.NEO.GetNextBlockValidators(snapshot); @@ -196,7 +194,7 @@ private JObject GetNextBlockValidators(JArray _params) } [RpcMethod] - private JObject GetCommittee(JArray _params) + protected virtual JObject GetCommittee(JArray _params) { using SnapshotView snapshot = Blockchain.Singleton.GetSnapshot(); return new JArray(NativeContract.NEO.GetCommittee(snapshot).Select(p => (JObject)p.ToString())); diff --git a/src/RpcServer/RpcServer.Node.cs b/src/RpcServer/RpcServer.Node.cs index fa6e601fb..ccf06ee28 100644 --- a/src/RpcServer/RpcServer.Node.cs +++ b/src/RpcServer/RpcServer.Node.cs @@ -15,13 +15,13 @@ namespace Neo.Plugins partial class RpcServer { [RpcMethod] - private JObject GetConnectionCount(JArray _params) + protected virtual JObject GetConnectionCount(JArray _params) { return LocalNode.Singleton.ConnectedCount; } [RpcMethod] - private JObject GetPeers(JArray _params) + protected virtual JObject GetPeers(JArray _params) { JObject json = new JObject(); json["unconnected"] = new JArray(LocalNode.Singleton.GetUnconnectedPeers().Select(p => @@ -57,7 +57,7 @@ private static JObject GetRelayResult(VerifyResult reason, UInt256 hash) } [RpcMethod] - private JObject GetVersion(JArray _params) + protected virtual JObject GetVersion(JArray _params) { JObject json = new JObject(); json["tcpport"] = LocalNode.Singleton.ListenerTcpPort; @@ -69,7 +69,7 @@ private JObject GetVersion(JArray _params) } [RpcMethod] - private JObject SendRawTransaction(JArray _params) + protected virtual JObject SendRawTransaction(JArray _params) { Transaction tx = _params[0].AsString().HexToBytes().AsSerializable(); RelayResult reason = system.Blockchain.Ask(tx).Result; @@ -77,7 +77,7 @@ private JObject SendRawTransaction(JArray _params) } [RpcMethod] - private JObject SubmitBlock(JArray _params) + protected virtual JObject SubmitBlock(JArray _params) { Block block = _params[0].AsString().HexToBytes().AsSerializable(); RelayResult reason = system.Blockchain.Ask(block).Result; diff --git a/src/RpcServer/RpcServer.SmartContract.cs b/src/RpcServer/RpcServer.SmartContract.cs index 31b956ff5..2acec7012 100644 --- a/src/RpcServer/RpcServer.SmartContract.cs +++ b/src/RpcServer/RpcServer.SmartContract.cs @@ -98,7 +98,7 @@ private static Signers SignersFromJson(JArray _params) } [RpcMethod] - private JObject InvokeFunction(JArray _params) + protected virtual JObject InvokeFunction(JArray _params) { UInt160 script_hash = UInt160.Parse(_params[0].AsString()); string operation = _params[1].AsString(); @@ -114,7 +114,7 @@ private JObject InvokeFunction(JArray _params) } [RpcMethod] - private JObject InvokeScript(JArray _params) + protected virtual JObject InvokeScript(JArray _params) { byte[] script = _params[0].AsString().HexToBytes(); UInt160 sender = _params.Count >= 2 ? AddressToScriptHash(_params[1].AsString()) : null; @@ -123,7 +123,7 @@ private JObject InvokeScript(JArray _params) } [RpcMethod] - private JObject GetUnclaimedGas(JArray _params) + protected virtual JObject GetUnclaimedGas(JArray _params) { string address = _params[0].AsString(); JObject json = new JObject(); diff --git a/src/RpcServer/RpcServer.Utilities.cs b/src/RpcServer/RpcServer.Utilities.cs index ee4a038d3..52cf665e3 100644 --- a/src/RpcServer/RpcServer.Utilities.cs +++ b/src/RpcServer/RpcServer.Utilities.cs @@ -2,7 +2,6 @@ #pragma warning disable IDE0060 using Neo.IO.Json; -using Neo.Wallets; using System.Linq; namespace Neo.Plugins @@ -10,7 +9,7 @@ namespace Neo.Plugins partial class RpcServer { [RpcMethod] - private JObject ListPlugins(JArray _params) + protected virtual JObject ListPlugins(JArray _params) { return new JArray(Plugin.Plugins .OrderBy(u => u.Name) @@ -26,7 +25,7 @@ private JObject ListPlugins(JArray _params) } [RpcMethod] - private JObject ValidateAddress(JArray _params) + protected virtual JObject ValidateAddress(JArray _params) { string address = _params[0].AsString(); JObject json = new JObject(); diff --git a/src/RpcServer/RpcServer.Wallet.cs b/src/RpcServer/RpcServer.Wallet.cs index 5bcff2b39..021893d5a 100644 --- a/src/RpcServer/RpcServer.Wallet.cs +++ b/src/RpcServer/RpcServer.Wallet.cs @@ -40,7 +40,7 @@ public DummyWallet() : base("") { } public override bool VerifyPassword(string password) => false; } - private Wallet wallet; + protected Wallet wallet; private void CheckWallet() { @@ -49,14 +49,14 @@ private void CheckWallet() } [RpcMethod] - private JObject CloseWallet(JArray _params) + protected virtual JObject CloseWallet(JArray _params) { wallet = null; return true; } [RpcMethod] - private JObject DumpPrivKey(JArray _params) + protected virtual JObject DumpPrivKey(JArray _params) { CheckWallet(); UInt160 scriptHash = AddressToScriptHash(_params[0].AsString()); @@ -65,7 +65,7 @@ private JObject DumpPrivKey(JArray _params) } [RpcMethod] - private JObject GetNewAddress(JArray _params) + protected virtual JObject GetNewAddress(JArray _params) { CheckWallet(); WalletAccount account = wallet.CreateAccount(); @@ -75,7 +75,7 @@ private JObject GetNewAddress(JArray _params) } [RpcMethod] - private JObject GetWalletBalance(JArray _params) + protected virtual JObject GetWalletBalance(JArray _params) { CheckWallet(); UInt160 asset_id = UInt160.Parse(_params[0].AsString()); @@ -85,7 +85,7 @@ private JObject GetWalletBalance(JArray _params) } [RpcMethod] - private JObject GetWalletUnclaimedGas(JArray _params) + protected virtual JObject GetWalletUnclaimedGas(JArray _params) { CheckWallet(); BigInteger gas = BigInteger.Zero; @@ -98,7 +98,7 @@ private JObject GetWalletUnclaimedGas(JArray _params) } [RpcMethod] - private JObject ImportPrivKey(JArray _params) + protected virtual JObject ImportPrivKey(JArray _params) { CheckWallet(); string privkey = _params[0].AsString(); @@ -115,7 +115,7 @@ private JObject ImportPrivKey(JArray _params) } [RpcMethod] - private JObject CalculateNetworkFee(JArray _params) + protected virtual JObject CalculateNetworkFee(JArray _params) { byte[] tx = Convert.FromBase64String(_params[0].AsString()); @@ -125,7 +125,7 @@ private JObject CalculateNetworkFee(JArray _params) } [RpcMethod] - private JObject ListAddress(JArray _params) + protected virtual JObject ListAddress(JArray _params) { CheckWallet(); return wallet.GetAccounts().Select(p => @@ -140,7 +140,7 @@ private JObject ListAddress(JArray _params) } [RpcMethod] - private JObject OpenWallet(JArray _params) + protected virtual JObject OpenWallet(JArray _params) { string path = _params[0].AsString(); string password = _params[1].AsString(); @@ -195,7 +195,7 @@ private void ProcessInvokeWithWallet(JObject result, UInt160 sender = null, Sign } [RpcMethod] - private JObject SendFrom(JArray _params) + protected virtual JObject SendFrom(JArray _params) { CheckWallet(); UInt160 assetId = UInt160.Parse(_params[0].AsString()); @@ -236,7 +236,7 @@ private JObject SendFrom(JArray _params) } [RpcMethod] - private JObject SendMany(JArray _params) + protected virtual JObject SendMany(JArray _params) { CheckWallet(); int to_start = 0; @@ -286,7 +286,7 @@ private JObject SendMany(JArray _params) } [RpcMethod] - private JObject SendToAddress(JArray _params) + protected virtual JObject SendToAddress(JArray _params) { CheckWallet(); UInt160 assetId = UInt160.Parse(_params[0].AsString()); diff --git a/src/RpcServer/RpcServer.cs b/src/RpcServer/RpcServer.cs index e21755b5a..a17d51d22 100644 --- a/src/RpcServer/RpcServer.cs +++ b/src/RpcServer/RpcServer.cs @@ -19,7 +19,7 @@ namespace Neo.Plugins { - public sealed partial class RpcServer : IDisposable + public partial class RpcServer : IDisposable { private readonly Dictionary> methods = new Dictionary>(); diff --git a/src/RpcServer/RpcServerPlugin.cs b/src/RpcServer/RpcServerPlugin.cs index 2d662432f..bc30cba3a 100644 --- a/src/RpcServer/RpcServerPlugin.cs +++ b/src/RpcServer/RpcServerPlugin.cs @@ -2,7 +2,7 @@ namespace Neo.Plugins { - public sealed class RpcServerPlugin : Plugin + public class RpcServerPlugin : Plugin { static List handlers = new List(); public override string Name => "RpcServer"; diff --git a/src/RpcServer/RpcServerSettings.cs b/src/RpcServer/RpcServerSettings.cs index 93a23586c..4a61070ee 100644 --- a/src/RpcServer/RpcServerSettings.cs +++ b/src/RpcServer/RpcServerSettings.cs @@ -3,7 +3,6 @@ using System; using System.Linq; using System.Net; -using System.Numerics; namespace Neo.Plugins { From 388f44ddecdbf47172fb3936fae191d0da061420 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=BF=97=E5=90=8C?= Date: Fri, 16 Oct 2020 13:27:37 +0800 Subject: [PATCH 164/183] Update RpcServer.Utilities.cs (#374) --- src/RpcServer/RpcServer.Utilities.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/RpcServer/RpcServer.Utilities.cs b/src/RpcServer/RpcServer.Utilities.cs index 52cf665e3..d566ad90d 100644 --- a/src/RpcServer/RpcServer.Utilities.cs +++ b/src/RpcServer/RpcServer.Utilities.cs @@ -2,6 +2,7 @@ #pragma warning disable IDE0060 using Neo.IO.Json; +using Neo.Wallets; using System.Linq; namespace Neo.Plugins From b9b97c8a230b43443c16e88ba2bc4d80d72ab6d6 Mon Sep 17 00:00:00 2001 From: cloud8little <34291844+cloud8little@users.noreply.github.com> Date: Fri, 16 Oct 2020 13:53:29 +0800 Subject: [PATCH 165/183] add null check for transferaddress (#373) * add null check for transferaddress * add ut * fix ut * fix format * fix * merge master Co-authored-by: Owen Zhang <38493437+superboyiii@users.noreply.github.com> --- src/RpcClient/Models/RpcNep5Transfers.cs | 4 +- tests/Neo.Network.RPC.Tests/RpcTestCases.json | 47 +++++++++++++++++++ tests/Neo.Network.RPC.Tests/UT_RpcClient.cs | 8 ++-- 3 files changed, 54 insertions(+), 5 deletions(-) diff --git a/src/RpcClient/Models/RpcNep5Transfers.cs b/src/RpcClient/Models/RpcNep5Transfers.cs index e166d41fe..ee9abc18f 100644 --- a/src/RpcClient/Models/RpcNep5Transfers.cs +++ b/src/RpcClient/Models/RpcNep5Transfers.cs @@ -57,7 +57,7 @@ public JObject ToJson() JObject json = new JObject(); json["timestamp"] = TimestampMS; json["assethash"] = AssetHash.ToString(); - json["transferaddress"] = UserScriptHash.ToAddress(); + json["transferaddress"] = UserScriptHash?.ToAddress(); json["amount"] = Amount.ToString(); json["blockindex"] = BlockIndex; json["transfernotifyindex"] = TransferNotifyIndex; @@ -70,7 +70,7 @@ public static RpcNep5Transfer FromJson(JObject json) RpcNep5Transfer transfer = new RpcNep5Transfer(); transfer.TimestampMS = (ulong)json["timestamp"].AsNumber(); transfer.AssetHash = json["assethash"].ToScriptHash(); - transfer.UserScriptHash = json["transferaddress"].ToScriptHash(); + transfer.UserScriptHash = json["transferaddress"]?.ToScriptHash(); transfer.Amount = BigInteger.Parse(json["amount"].AsString()); transfer.BlockIndex = (uint)json["blockindex"].AsNumber(); transfer.TransferNotifyIndex = (ushort)json["transfernotifyindex"].AsNumber(); diff --git a/tests/Neo.Network.RPC.Tests/RpcTestCases.json b/tests/Neo.Network.RPC.Tests/RpcTestCases.json index 2a98356c9..e3f03d4df 100644 --- a/tests/Neo.Network.RPC.Tests/RpcTestCases.json +++ b/tests/Neo.Network.RPC.Tests/RpcTestCases.json @@ -1406,6 +1406,53 @@ } } }, + { + "Name": "getnep5transfersasync_with_null_transferaddress", + "Request": { + "jsonrpc": "2.0", + "method": "getnep5transfers", + "params": [ "Ncb7jVsYWBt1q5T5k3ZTP8bn5eK4DuanLd", 0, 1868595301000 ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": { + "sent": [ + { + "timestamp": 1579250114541, + "assethash": "0x8c23f196d8a1bfd103a9dcb1f9ccf0c611377d3b", + "transferaddress": null, + "amount": "1000000000", + "blockindex": 603, + "transfernotifyindex": 0, + "txhash": "0x5e177b8d1dc33e9103c0cfd42f6dbf4efbe43029e2d6a18ea5ba0cb8437056b3" + }, + { + "timestamp": 1579406581635, + "assethash": "0x8c23f196d8a1bfd103a9dcb1f9ccf0c611377d3b", + "transferaddress": "Ncb7jVsYWBt1q5T5k3ZTP8bn5eK4DuanLd", + "amount": "1000000000", + "blockindex": 1525, + "transfernotifyindex": 0, + "txhash": "0xc9c618b48972b240e0058d97b8d79b807ad51015418c84012765298526aeb77d" + } + ], + "received": [ + { + "timestamp": 1579250114541, + "assethash": "0x8c23f196d8a1bfd103a9dcb1f9ccf0c611377d3b", + "transferaddress": null, + "amount": "1000000000", + "blockindex": 603, + "transfernotifyindex": 0, + "txhash": "0x5e177b8d1dc33e9103c0cfd42f6dbf4efbe43029e2d6a18ea5ba0cb8437056b3" + } + ], + "address": "Ncb7jVsYWBt1q5T5k3ZTP8bn5eK4DuanLd" + } + } + }, { "Name": "getnep5balancesasync", "Request": { diff --git a/tests/Neo.Network.RPC.Tests/UT_RpcClient.cs b/tests/Neo.Network.RPC.Tests/UT_RpcClient.cs index dd38fd9fe..dd08d6024 100644 --- a/tests/Neo.Network.RPC.Tests/UT_RpcClient.cs +++ b/tests/Neo.Network.RPC.Tests/UT_RpcClient.cs @@ -44,7 +44,7 @@ private void MockResponse(RpcRequest request, RpcResponse response) ItExpr.Is(p => p.Content.ReadAsStringAsync().Result == request.ToJson().ToString()), ItExpr.IsAny() ) - // prepare the expected response of the mocked http call + // prepare the expected response of the mocked http call .ReturnsAsync(new HttpResponseMessage() { StatusCode = HttpStatusCode.OK, @@ -424,8 +424,10 @@ public async Task GetApplicationLogTest() public async Task GetNep5TransfersTest() { var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetNep5TransfersAsync).ToLower()); - var result = await rpc.GetNep5TransfersAsync(test.Request.Params[0].AsString(), (ulong)test.Request.Params[1].AsNumber(), - (ulong)test.Request.Params[2].AsNumber()); + var result = await rpc.GetNep5TransfersAsync(test.Request.Params[0].AsString(), (ulong)test.Request.Params[1].AsNumber(), (ulong)test.Request.Params[2].AsNumber()); + Assert.AreEqual(test.Response.Result.ToString(), result.ToJson().ToString()); + test = TestUtils.RpcTestCases.Find(p => p.Name == (nameof(rpc.GetNep5TransfersAsync).ToLower() + "_with_null_transferaddress")); + result = await rpc.GetNep5TransfersAsync(test.Request.Params[0].AsString(), (ulong)test.Request.Params[1].AsNumber(), (ulong)test.Request.Params[2].AsNumber()); Assert.AreEqual(test.Response.Result.ToString(), result.ToJson().ToString()); } From e61cfe2dfe71643d49b9afd0d85a3d72b905cd9f Mon Sep 17 00:00:00 2001 From: Luchuan Date: Fri, 16 Oct 2020 15:27:16 +0800 Subject: [PATCH 166/183] invoke* use base64 script (#362) * invoke* use base64 script * fix rpc client * fix ut * fix validateaddress * fix ut * revert * fix ProcessInvokeWithWallet Co-authored-by: Owen Zhang <38493437+superboyiii@users.noreply.github.com> --- src/RpcClient/RpcClient.cs | 2 +- src/RpcServer/RpcServer.SmartContract.cs | 4 ++-- src/RpcServer/RpcServer.Wallet.cs | 2 +- tests/Neo.Network.RPC.Tests/RpcTestCases.json | 8 ++++---- tests/Neo.Network.RPC.Tests/UT_RpcClient.cs | 2 +- tests/Neo.Network.RPC.Tests/UT_TransactionManager.cs | 5 ++--- 6 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/RpcClient/RpcClient.cs b/src/RpcClient/RpcClient.cs index 6d81f9b86..32442ba98 100644 --- a/src/RpcClient/RpcClient.cs +++ b/src/RpcClient/RpcClient.cs @@ -359,7 +359,7 @@ public async Task InvokeFunctionAsync(string scriptHash, string /// public async Task InvokeScriptAsync(byte[] script, params Signer[] signers) { - List parameters = new List { script.ToHexString() }; + List parameters = new List { Convert.ToBase64String(script) }; if (signers.Length > 0) { parameters.Add(signers.Select(p => p.ToJson()).ToArray()); diff --git a/src/RpcServer/RpcServer.SmartContract.cs b/src/RpcServer/RpcServer.SmartContract.cs index 2acec7012..2cc910851 100644 --- a/src/RpcServer/RpcServer.SmartContract.cs +++ b/src/RpcServer/RpcServer.SmartContract.cs @@ -65,7 +65,7 @@ private JObject GetInvokeResult(byte[] script, UInt160 sender = null, Signers si { using ApplicationEngine engine = ApplicationEngine.Run(script, container: signers, gas: settings.MaxGasInvoke); JObject json = new JObject(); - json["script"] = script.ToHexString(); + json["script"] = Convert.ToBase64String(script); json["state"] = engine.State; json["gasconsumed"] = engine.GasConsumed.ToString(); try @@ -116,7 +116,7 @@ protected virtual JObject InvokeFunction(JArray _params) [RpcMethod] protected virtual JObject InvokeScript(JArray _params) { - byte[] script = _params[0].AsString().HexToBytes(); + byte[] script = Convert.FromBase64String(_params[0].AsString()); UInt160 sender = _params.Count >= 2 ? AddressToScriptHash(_params[1].AsString()) : null; Signers signers = _params.Count >= 3 ? SignersFromJson((JArray)_params[2]) : null; return GetInvokeResult(script, sender, signers); diff --git a/src/RpcServer/RpcServer.Wallet.cs b/src/RpcServer/RpcServer.Wallet.cs index 021893d5a..21e07d0d8 100644 --- a/src/RpcServer/RpcServer.Wallet.cs +++ b/src/RpcServer/RpcServer.Wallet.cs @@ -182,7 +182,7 @@ private void ProcessInvokeWithWallet(JObject result, UInt160 sender = null, Sign if (witnessSigners.Count() > 0) { - tx = wallet.MakeTransaction(result["script"].AsString().HexToBytes(), sender, witnessSigners); + tx = wallet.MakeTransaction(Convert.FromBase64String(result["script"].AsString()), sender, witnessSigners); ContractParametersContext context = new ContractParametersContext(tx); wallet.Sign(context); if (context.Completed) diff --git a/tests/Neo.Network.RPC.Tests/RpcTestCases.json b/tests/Neo.Network.RPC.Tests/RpcTestCases.json index e3f03d4df..6c89e441f 100644 --- a/tests/Neo.Network.RPC.Tests/RpcTestCases.json +++ b/tests/Neo.Network.RPC.Tests/RpcTestCases.json @@ -747,14 +747,14 @@ "Request": { "jsonrpc": "2.0", "method": "invokescript", - "params": [ "10c30c046e616d650c143b7d3711c6f0ccf9b1dca903d1bfa1d896f1238c41627d5b5210c30c0673796d626f6c0c143b7d3711c6f0ccf9b1dca903d1bfa1d896f1238c41627d5b5210c30c08646563696d616c730c143b7d3711c6f0ccf9b1dca903d1bfa1d896f1238c41627d5b5210c30c0b746f74616c537570706c790c143b7d3711c6f0ccf9b1dca903d1bfa1d896f1238c41627d5b52" ], + "params": [ "EMMMBG5hbWUMFDt9NxHG8Mz5sdypA9G/odiW8SOMQWJ9W1IQwwwGc3ltYm9sDBQ7fTcRxvDM+bHcqQPRv6HYlvEjjEFifVtSEMMMCGRlY2ltYWxzDBQ7fTcRxvDM+bHcqQPRv6HYlvEjjEFifVtSEMMMC3RvdGFsU3VwcGx5DBQ7fTcRxvDM+bHcqQPRv6HYlvEjjEFifVtS" ], "id": 1 }, "Response": { "jsonrpc": "2.0", "id": 1, "result": { - "script": "10c30c046e616d650c143b7d3711c6f0ccf9b1dca903d1bfa1d896f1238c41627d5b5210c30c0673796d626f6c0c143b7d3711c6f0ccf9b1dca903d1bfa1d896f1238c41627d5b5210c30c08646563696d616c730c143b7d3711c6f0ccf9b1dca903d1bfa1d896f1238c41627d5b5210c30c0b746f74616c537570706c790c143b7d3711c6f0ccf9b1dca903d1bfa1d896f1238c41627d5b52", + "script": "EMMMBG5hbWUMFDt9NxHG8Mz5sdypA9G/odiW8SOMQWJ9W1IQwwwGc3ltYm9sDBQ7fTcRxvDM+bHcqQPRv6HYlvEjjEFifVtSEMMMCGRlY2ltYWxzDBQ7fTcRxvDM+bHcqQPRv6HYlvEjjEFifVtSEMMMC3RvdGFsU3VwcGx5DBQ7fTcRxvDM+bHcqQPRv6HYlvEjjEFifVtS", "state": "HALT", "gasconsumed": "5061560", "stack": [ @@ -933,14 +933,14 @@ "Request": { "jsonrpc": "2.0", "method": "invokescript", - "params": [ "10c30c08646563696d616c730c143b7d3711c6f0ccf9b1dca903d1bfa1d896f1238c41627d5b52" ], + "params": [ "EMMMCGRlY2ltYWxzDBQ7fTcRxvDM+bHcqQPRv6HYlvEjjEFifVtS" ], "id": 1 }, "Response": { "jsonrpc": "2.0", "id": 1, "result": { - "script": "10c30c08646563696d616c730c143b7d3711c6f0ccf9b1dca903d1bfa1d896f1238c41627d5b52", + "script": "EMMMCGRlY2ltYWxzDBQ7fTcRxvDM+bHcqQPRv6HYlvEjjEFifVtS", "state": "HALT", "gasconsumed": "5061560", "stack": [ diff --git a/tests/Neo.Network.RPC.Tests/UT_RpcClient.cs b/tests/Neo.Network.RPC.Tests/UT_RpcClient.cs index dd08d6024..bc95c6beb 100644 --- a/tests/Neo.Network.RPC.Tests/UT_RpcClient.cs +++ b/tests/Neo.Network.RPC.Tests/UT_RpcClient.cs @@ -283,7 +283,7 @@ public async Task TestInvokeFunction() public async Task TestInvokeScript() { var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.InvokeScriptAsync).ToLower()); - var result = await rpc.InvokeScriptAsync(test.Request.Params[0].AsString().HexToBytes()); + var result = await rpc.InvokeScriptAsync(Convert.FromBase64String(test.Request.Params[0].AsString())); Assert.AreEqual(test.Response.Result.ToString(), result.ToJson().ToString()); } diff --git a/tests/Neo.Network.RPC.Tests/UT_TransactionManager.cs b/tests/Neo.Network.RPC.Tests/UT_TransactionManager.cs index c5d8a1d4b..32744c2e2 100644 --- a/tests/Neo.Network.RPC.Tests/UT_TransactionManager.cs +++ b/tests/Neo.Network.RPC.Tests/UT_TransactionManager.cs @@ -10,7 +10,6 @@ using Neo.SmartContract.Native; using Neo.VM; using Neo.Wallets; -using Neo.Wallets.NEP6; using System; using System.Linq; using System.Numerics; @@ -112,11 +111,11 @@ public static void MockInvokeScript(Mock mockClient, byte[] script, p { Stack = parameters.Select(p => p.ToStackItem()).ToArray(), GasConsumed = "100", - Script = script.ToHexString(), + Script = Convert.ToBase64String(script), State = VMState.HALT }; - mockClient.Setup(p => p.RpcSendAsync("invokescript", It.Is(j => j[0].AsString() == script.ToHexString()))) + mockClient.Setup(p => p.RpcSendAsync("invokescript", It.Is(j => j[0].AsString() == Convert.ToBase64String(script)))) .ReturnsAsync(result.ToJson()) .Verifiable(); } From 039a28fbfea74ce6287b884b68b15077ef3b6922 Mon Sep 17 00:00:00 2001 From: Luchuan Date: Tue, 20 Oct 2020 02:14:31 +0800 Subject: [PATCH 167/183] Remove sender from invoke method (#368) * remove sender from invoke method * fix * format Co-authored-by: Owen Zhang <38493437+superboyiii@users.noreply.github.com> --- src/RpcServer/RpcServer.SmartContract.cs | 17 ++++++++--------- src/RpcServer/RpcServer.Wallet.cs | 12 ++---------- 2 files changed, 10 insertions(+), 19 deletions(-) diff --git a/src/RpcServer/RpcServer.SmartContract.cs b/src/RpcServer/RpcServer.SmartContract.cs index 2cc910851..de4099920 100644 --- a/src/RpcServer/RpcServer.SmartContract.cs +++ b/src/RpcServer/RpcServer.SmartContract.cs @@ -61,7 +61,7 @@ public void SerializeUnsigned(BinaryWriter writer) } } - private JObject GetInvokeResult(byte[] script, UInt160 sender = null, Signers signers = null) + private JObject GetInvokeResult(byte[] script, Signers signers = null) { using ApplicationEngine engine = ApplicationEngine.Run(script, container: signers, gas: settings.MaxGasInvoke); JObject json = new JObject(); @@ -76,7 +76,7 @@ private JObject GetInvokeResult(byte[] script, UInt160 sender = null, Signers si { json["stack"] = "error: recursive reference"; } - ProcessInvokeWithWallet(json, sender, signers); + ProcessInvokeWithWallet(json, signers); return json; } @@ -103,23 +103,22 @@ protected virtual JObject InvokeFunction(JArray _params) UInt160 script_hash = UInt160.Parse(_params[0].AsString()); string operation = _params[1].AsString(); ContractParameter[] args = _params.Count >= 3 ? ((JArray)_params[2]).Select(p => ContractParameter.FromJson(p)).ToArray() : new ContractParameter[0]; - UInt160 sender = _params.Count >= 4 ? AddressToScriptHash(_params[3].AsString()) : null; - Signers signers = _params.Count >= 5 ? SignersFromJson((JArray)_params[4]) : null; + Signers signers = _params.Count >= 4 ? SignersFromJson((JArray)_params[3]) : null; + byte[] script; using (ScriptBuilder sb = new ScriptBuilder()) { script = sb.EmitAppCall(script_hash, operation, args).ToArray(); } - return GetInvokeResult(script, sender, signers); + return GetInvokeResult(script, signers); } [RpcMethod] protected virtual JObject InvokeScript(JArray _params) { - byte[] script = Convert.FromBase64String(_params[0].AsString()); - UInt160 sender = _params.Count >= 2 ? AddressToScriptHash(_params[1].AsString()) : null; - Signers signers = _params.Count >= 3 ? SignersFromJson((JArray)_params[2]) : null; - return GetInvokeResult(script, sender, signers); + byte[] script = _params[0].AsString().HexToBytes(); + Signers signers = _params.Count >= 2 ? SignersFromJson((JArray)_params[1]) : null; + return GetInvokeResult(script, signers); } [RpcMethod] diff --git a/src/RpcServer/RpcServer.Wallet.cs b/src/RpcServer/RpcServer.Wallet.cs index 21e07d0d8..2b6ab6688 100644 --- a/src/RpcServer/RpcServer.Wallet.cs +++ b/src/RpcServer/RpcServer.Wallet.cs @@ -165,21 +165,13 @@ protected virtual JObject OpenWallet(JArray _params) return true; } - private void ProcessInvokeWithWallet(JObject result, UInt160 sender = null, Signers signers = null) + private void ProcessInvokeWithWallet(JObject result, Signers signers = null) { Transaction tx = null; if (wallet != null && signers != null) { Signer[] witnessSigners = signers.GetSigners().ToArray(); - UInt160[] signersAccounts = signers.GetScriptHashesForVerifying(null); - if (sender != null) - { - if (!signersAccounts.Contains(sender)) - witnessSigners = witnessSigners.Prepend(new Signer() { Account = sender, Scopes = WitnessScope.CalledByEntry }).ToArray(); - else if (signersAccounts[0] != sender) - throw new RpcException(-32602, "The sender must be the first element of signers."); - } - + UInt160 sender = signers.Size > 0 ? signers.GetSigners()[0].Account : null; if (witnessSigners.Count() > 0) { tx = wallet.MakeTransaction(Convert.FromBase64String(result["script"].AsString()), sender, witnessSigners); From 8f2185d9fd631cd7636d4b1a520be26a7806e1c1 Mon Sep 17 00:00:00 2001 From: Luchuan Date: Tue, 20 Oct 2020 15:37:42 +0800 Subject: [PATCH 168/183] Add `exception` field in invokeresult (#364) * add exception field in invokeresult * fix rpc client * fix * fix show exception message * fix * fix * fix: add try-catch for processInvokeWithWallet * fix * apply * trigger github action * Singers * fix Co-authored-by: Owen Zhang <38493437+superboyiii@users.noreply.github.com> --- src/RpcClient/Models/RpcInvokeResult.cs | 6 ++++++ src/RpcServer/RpcServer.SmartContract.cs | 20 ++++++++++++++++++-- src/RpcServer/RpcServer.Wallet.cs | 10 +++++++++- tests/Neo.Network.RPC.Tests/UT_RpcClient.cs | 2 ++ 4 files changed, 35 insertions(+), 3 deletions(-) diff --git a/src/RpcClient/Models/RpcInvokeResult.cs b/src/RpcClient/Models/RpcInvokeResult.cs index 67fb81e9a..c8ee3741d 100644 --- a/src/RpcClient/Models/RpcInvokeResult.cs +++ b/src/RpcClient/Models/RpcInvokeResult.cs @@ -18,12 +18,16 @@ public class RpcInvokeResult public string Tx { get; set; } + public string Exception { get; set; } + public JObject ToJson() { JObject json = new JObject(); json["script"] = Script; json["state"] = State; json["gasconsumed"] = GasConsumed; + if (!string.IsNullOrEmpty(Exception)) + json["exception"] = Exception; try { json["stack"] = new JArray(Stack.Select(p => p.ToJson())); @@ -43,6 +47,8 @@ public static RpcInvokeResult FromJson(JObject json) invokeScriptResult.Script = json["script"].AsString(); invokeScriptResult.State = json["state"].TryGetEnum(); invokeScriptResult.GasConsumed = json["gasconsumed"].AsString(); + if (json.ContainsProperty("exception")) + invokeScriptResult.Exception = json["exception"]?.AsString(); try { invokeScriptResult.Stack = ((JArray)json["stack"]).Select(p => Utility.StackItemFromJson(p)).ToArray(); diff --git a/src/RpcServer/RpcServer.SmartContract.cs b/src/RpcServer/RpcServer.SmartContract.cs index de4099920..f5cf6cbfc 100644 --- a/src/RpcServer/RpcServer.SmartContract.cs +++ b/src/RpcServer/RpcServer.SmartContract.cs @@ -23,7 +23,7 @@ private class Signers : IVerifiable { private readonly Signer[] _signers; public Witness[] Witnesses { get; set; } - public int Size { get; } + public int Size => _signers.Length; public Signers(Signer[] signers) { @@ -68,6 +68,7 @@ private JObject GetInvokeResult(byte[] script, Signers signers = null) json["script"] = Convert.ToBase64String(script); json["state"] = engine.State; json["gasconsumed"] = engine.GasConsumed.ToString(); + json["exception"] = GetExceptionMessage(engine.FaultException); try { json["stack"] = new JArray(engine.ResultStack.Select(p => p.ToJson())); @@ -76,7 +77,10 @@ private JObject GetInvokeResult(byte[] script, Signers signers = null) { json["stack"] = "error: recursive reference"; } - ProcessInvokeWithWallet(json, signers); + if (engine.State != VMState.FAULT) + { + ProcessInvokeWithWallet(json, signers); + } return json; } @@ -142,5 +146,17 @@ protected virtual JObject GetUnclaimedGas(JArray _params) json["address"] = script_hash.ToAddress(); return json; } + + static string GetExceptionMessage(Exception exception) + { + if (exception == null) return null; + + if (exception.InnerException != null) + { + return exception.InnerException.Message; + } + + return exception.Message; + } } } diff --git a/src/RpcServer/RpcServer.Wallet.cs b/src/RpcServer/RpcServer.Wallet.cs index 2b6ab6688..8b1131166 100644 --- a/src/RpcServer/RpcServer.Wallet.cs +++ b/src/RpcServer/RpcServer.Wallet.cs @@ -174,7 +174,15 @@ private void ProcessInvokeWithWallet(JObject result, Signers signers = null) UInt160 sender = signers.Size > 0 ? signers.GetSigners()[0].Account : null; if (witnessSigners.Count() > 0) { - tx = wallet.MakeTransaction(Convert.FromBase64String(result["script"].AsString()), sender, witnessSigners); + try + { + tx = wallet.MakeTransaction(result["script"].AsString().HexToBytes(), sender, witnessSigners); + } + catch (Exception e) + { + result["exception"] = GetExceptionMessage(e); + return; + } ContractParametersContext context = new ContractParametersContext(tx); wallet.Sign(context); if (context.Completed) diff --git a/tests/Neo.Network.RPC.Tests/UT_RpcClient.cs b/tests/Neo.Network.RPC.Tests/UT_RpcClient.cs index bc95c6beb..d2660aa4a 100644 --- a/tests/Neo.Network.RPC.Tests/UT_RpcClient.cs +++ b/tests/Neo.Network.RPC.Tests/UT_RpcClient.cs @@ -277,6 +277,8 @@ public async Task TestInvokeFunction() var result = await rpc.InvokeFunctionAsync(test.Request.Params[0].AsString(), test.Request.Params[1].AsString(), ((JArray)test.Request.Params[2]).Select(p => RpcStack.FromJson(p)).ToArray()); Assert.AreEqual(test.Response.Result.ToString(), result.ToJson().ToString()); + + // TODO test verify method } [TestMethod] From 328ca33dd73be3859c600ea509c7f2bfec9b2043 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=BF=97=E5=90=8C?= Date: Tue, 20 Oct 2020 17:44:32 +0800 Subject: [PATCH 169/183] [RpcClient] Optimization code. (#372) * optimization code * conflict resolution 2 * conflict resolution 3 * update * Update RpcApplicationLog.cs * Update RpcBlock.cs * Update RpcBlockHeader.cs * Optimize return Co-authored-by: Shargon Co-authored-by: Owen Zhang <38493437+superboyiii@users.noreply.github.com> --- src/RpcClient/Models/RpcApplicationLog.cs | 17 +-- src/RpcClient/Models/RpcBlock.cs | 11 +- src/RpcClient/Models/RpcBlockHeader.cs | 11 +- src/RpcClient/Models/RpcContractState.cs | 13 ++- src/RpcClient/Models/RpcInvokeResult.cs | 19 +-- src/RpcClient/Models/RpcNep5Transfers.cs | 19 +-- src/RpcClient/Models/RpcPeers.cs | 20 ++-- src/RpcClient/Models/RpcPlugin.cs | 11 +- src/RpcClient/Models/RpcRawMemPool.cs | 11 +- src/RpcClient/Models/RpcTransaction.cs | 6 +- src/RpcClient/Models/RpcUnclaimedGas.cs | 9 +- .../Models/RpcValidateAddressResult.cs | 9 +- src/RpcClient/Models/RpcValidator.cs | 11 +- src/RpcClient/Models/RpcVersion.cs | 15 +-- src/RpcClient/RpcClient.cs | 108 ++++++++++-------- src/RpcClient/TransactionManager.cs | 2 +- src/RpcClient/Utility.cs | 41 ++++--- 17 files changed, 185 insertions(+), 148 deletions(-) diff --git a/src/RpcClient/Models/RpcApplicationLog.cs b/src/RpcClient/Models/RpcApplicationLog.cs index 83467f817..205835e9c 100644 --- a/src/RpcClient/Models/RpcApplicationLog.cs +++ b/src/RpcClient/Models/RpcApplicationLog.cs @@ -35,14 +35,15 @@ public JObject ToJson() public static RpcApplicationLog FromJson(JObject json) { - RpcApplicationLog log = new RpcApplicationLog(); - log.TxId = json["txid"] is null ? null : UInt256.Parse(json["txid"].AsString()); - log.Trigger = json["trigger"].TryGetEnum(); - log.VMState = json["vmstate"].TryGetEnum(); - log.GasConsumed = long.Parse(json["gasconsumed"].AsString()); - log.Stack = ((JArray)json["stack"]).Select(p => Utility.StackItemFromJson(p)).ToList(); - log.Notifications = ((JArray)json["notifications"]).Select(p => RpcNotifyEventArgs.FromJson(p)).ToList(); - return log; + return new RpcApplicationLog + { + TxId = json["txid"] is null ? null : UInt256.Parse(json["txid"].AsString()), + Trigger = json["trigger"].TryGetEnum(), + VMState = json["vmstate"].TryGetEnum(), + GasConsumed = long.Parse(json["gasconsumed"].AsString()), + Stack = ((JArray)json["stack"]).Select(p => Utility.StackItemFromJson(p)).ToList(), + Notifications = ((JArray)json["notifications"]).Select(p => RpcNotifyEventArgs.FromJson(p)).ToList() + }; } } diff --git a/src/RpcClient/Models/RpcBlock.cs b/src/RpcClient/Models/RpcBlock.cs index 3eab2a91a..24687812f 100644 --- a/src/RpcClient/Models/RpcBlock.cs +++ b/src/RpcClient/Models/RpcBlock.cs @@ -21,11 +21,12 @@ public JObject ToJson() public static RpcBlock FromJson(JObject json) { - RpcBlock block = new RpcBlock(); - block.Block = Utility.BlockFromJson(json); - block.Confirmations = (uint)json["confirmations"].AsNumber(); - block.NextBlockHash = json["nextblockhash"] is null ? null : UInt256.Parse(json["nextblockhash"].AsString()); - return block; + return new RpcBlock + { + Block = Utility.BlockFromJson(json), + Confirmations = (uint)json["confirmations"].AsNumber(), + NextBlockHash = json["nextblockhash"] is null ? null : UInt256.Parse(json["nextblockhash"].AsString()) + }; } } } diff --git a/src/RpcClient/Models/RpcBlockHeader.cs b/src/RpcClient/Models/RpcBlockHeader.cs index 5072827df..368e237b0 100644 --- a/src/RpcClient/Models/RpcBlockHeader.cs +++ b/src/RpcClient/Models/RpcBlockHeader.cs @@ -21,11 +21,12 @@ public JObject ToJson() public static RpcBlockHeader FromJson(JObject json) { - RpcBlockHeader block = new RpcBlockHeader(); - block.Header = Utility.HeaderFromJson(json); - block.Confirmations = (uint)json["confirmations"].AsNumber(); - block.NextBlockHash = json["nextblockhash"] is null ? null : UInt256.Parse(json["nextblockhash"].AsString()); - return block; + return new RpcBlockHeader + { + Header = Utility.HeaderFromJson(json), + Confirmations = (uint)json["confirmations"].AsNumber(), + NextBlockHash = json["nextblockhash"] is null ? null : UInt256.Parse(json["nextblockhash"].AsString()) + }; } } } diff --git a/src/RpcClient/Models/RpcContractState.cs b/src/RpcClient/Models/RpcContractState.cs index b87351884..041cd97f8 100644 --- a/src/RpcClient/Models/RpcContractState.cs +++ b/src/RpcClient/Models/RpcContractState.cs @@ -14,13 +14,14 @@ public JObject ToJson() public static RpcContractState FromJson(JObject json) { - RpcContractState state = new RpcContractState(); - state.ContractState = new ContractState + return new RpcContractState { - Id = (int)json["id"].AsNumber(), - Script = Convert.FromBase64String(json["script"].AsString()), - Manifest = ContractManifest.FromJson(json["manifest"]) + ContractState = new ContractState + { + Id = (int)json["id"].AsNumber(), + Script = Convert.FromBase64String(json["script"].AsString()), + Manifest = ContractManifest.FromJson(json["manifest"]) + } }; - return state; } } diff --git a/src/RpcClient/Models/RpcInvokeResult.cs b/src/RpcClient/Models/RpcInvokeResult.cs index c8ee3741d..e57310894 100644 --- a/src/RpcClient/Models/RpcInvokeResult.cs +++ b/src/RpcClient/Models/RpcInvokeResult.cs @@ -43,10 +43,12 @@ public JObject ToJson() public static RpcInvokeResult FromJson(JObject json) { - RpcInvokeResult invokeScriptResult = new RpcInvokeResult(); - invokeScriptResult.Script = json["script"].AsString(); - invokeScriptResult.State = json["state"].TryGetEnum(); - invokeScriptResult.GasConsumed = json["gasconsumed"].AsString(); + RpcInvokeResult invokeScriptResult = new RpcInvokeResult + { + Script = json["script"].AsString(), + State = json["state"].TryGetEnum(), + GasConsumed = json["gasconsumed"].AsString() + }; if (json.ContainsProperty("exception")) invokeScriptResult.Exception = json["exception"]?.AsString(); try @@ -75,10 +77,11 @@ public JObject ToJson() public static RpcStack FromJson(JObject json) { - RpcStack stackJson = new RpcStack(); - stackJson.Type = json["type"].AsString(); - stackJson.Value = json["value"].AsString(); - return stackJson; + return new RpcStack + { + Type = json["type"].AsString(), + Value = json["value"].AsString() + }; } } } diff --git a/src/RpcClient/Models/RpcNep5Transfers.cs b/src/RpcClient/Models/RpcNep5Transfers.cs index ee9abc18f..d23ca7a41 100644 --- a/src/RpcClient/Models/RpcNep5Transfers.cs +++ b/src/RpcClient/Models/RpcNep5Transfers.cs @@ -67,15 +67,16 @@ public JObject ToJson() public static RpcNep5Transfer FromJson(JObject json) { - RpcNep5Transfer transfer = new RpcNep5Transfer(); - transfer.TimestampMS = (ulong)json["timestamp"].AsNumber(); - transfer.AssetHash = json["assethash"].ToScriptHash(); - transfer.UserScriptHash = json["transferaddress"]?.ToScriptHash(); - transfer.Amount = BigInteger.Parse(json["amount"].AsString()); - transfer.BlockIndex = (uint)json["blockindex"].AsNumber(); - transfer.TransferNotifyIndex = (ushort)json["transfernotifyindex"].AsNumber(); - transfer.TxHash = UInt256.Parse(json["txhash"].AsString()); - return transfer; + return new RpcNep5Transfer + { + TimestampMS = (ulong)json["timestamp"].AsNumber(), + AssetHash = json["assethash"].ToScriptHash(), + UserScriptHash = json["transferaddress"]?.ToScriptHash(), + Amount = BigInteger.Parse(json["amount"].AsString()), + BlockIndex = (uint)json["blockindex"].AsNumber(), + TransferNotifyIndex = (ushort)json["transfernotifyindex"].AsNumber(), + TxHash = UInt256.Parse(json["txhash"].AsString()) + }; } } } diff --git a/src/RpcClient/Models/RpcPeers.cs b/src/RpcClient/Models/RpcPeers.cs index fac73842d..b32359e78 100644 --- a/src/RpcClient/Models/RpcPeers.cs +++ b/src/RpcClient/Models/RpcPeers.cs @@ -22,11 +22,12 @@ public JObject ToJson() public static RpcPeers FromJson(JObject json) { - RpcPeers result = new RpcPeers(); - result.Unconnected = ((JArray)json["unconnected"]).Select(p => RpcPeer.FromJson(p)).ToArray(); - result.Bad = ((JArray)json["bad"]).Select(p => RpcPeer.FromJson(p)).ToArray(); - result.Connected = ((JArray)json["connected"]).Select(p => RpcPeer.FromJson(p)).ToArray(); - return result; + return new RpcPeers + { + Unconnected = ((JArray)json["unconnected"]).Select(p => RpcPeer.FromJson(p)).ToArray(), + Bad = ((JArray)json["bad"]).Select(p => RpcPeer.FromJson(p)).ToArray(), + Connected = ((JArray)json["connected"]).Select(p => RpcPeer.FromJson(p)).ToArray() + }; } } @@ -46,10 +47,11 @@ public JObject ToJson() public static RpcPeer FromJson(JObject json) { - RpcPeer peer = new RpcPeer(); - peer.Address = json["address"].AsString(); - peer.Port = int.Parse(json["port"].AsString()); - return peer; + return new RpcPeer + { + Address = json["address"].AsString(), + Port = int.Parse(json["port"].AsString()) + }; } } } diff --git a/src/RpcClient/Models/RpcPlugin.cs b/src/RpcClient/Models/RpcPlugin.cs index db03f70eb..281c7508e 100644 --- a/src/RpcClient/Models/RpcPlugin.cs +++ b/src/RpcClient/Models/RpcPlugin.cs @@ -22,11 +22,12 @@ public JObject ToJson() public static RpcPlugin FromJson(JObject json) { - RpcPlugin plugin = new RpcPlugin(); - plugin.Name = json["name"].AsString(); - plugin.Version = json["version"].AsString(); - plugin.Interfaces = ((JArray)json["interfaces"]).Select(p => p.AsString()).ToArray(); - return plugin; + return new RpcPlugin + { + Name = json["name"].AsString(), + Version = json["version"].AsString(), + Interfaces = ((JArray)json["interfaces"]).Select(p => p.AsString()).ToArray() + }; } } } diff --git a/src/RpcClient/Models/RpcRawMemPool.cs b/src/RpcClient/Models/RpcRawMemPool.cs index 61d8bcf99..e80dc8d10 100644 --- a/src/RpcClient/Models/RpcRawMemPool.cs +++ b/src/RpcClient/Models/RpcRawMemPool.cs @@ -23,11 +23,12 @@ public JObject ToJson() public static RpcRawMemPool FromJson(JObject json) { - RpcRawMemPool rawMemPool = new RpcRawMemPool(); - rawMemPool.Height = uint.Parse(json["height"].AsString()); - rawMemPool.Verified = ((JArray)json["verified"]).Select(p => UInt256.Parse(p.AsString())).ToList(); - rawMemPool.UnVerified = ((JArray)json["unverified"]).Select(p => UInt256.Parse(p.AsString())).ToList(); - return rawMemPool; + return new RpcRawMemPool + { + Height = uint.Parse(json["height"].AsString()), + Verified = ((JArray)json["verified"]).Select(p => UInt256.Parse(p.AsString())).ToList(), + UnVerified = ((JArray)json["unverified"]).Select(p => UInt256.Parse(p.AsString())).ToList() + }; } } } diff --git a/src/RpcClient/Models/RpcTransaction.cs b/src/RpcClient/Models/RpcTransaction.cs index 92a9f3290..74aae5566 100644 --- a/src/RpcClient/Models/RpcTransaction.cs +++ b/src/RpcClient/Models/RpcTransaction.cs @@ -34,8 +34,10 @@ public JObject ToJson() public static RpcTransaction FromJson(JObject json) { - RpcTransaction transaction = new RpcTransaction(); - transaction.Transaction = Utility.TransactionFromJson(json); + RpcTransaction transaction = new RpcTransaction + { + Transaction = Utility.TransactionFromJson(json) + }; if (json["confirmations"] != null) { transaction.BlockHash = UInt256.Parse(json["blockhash"].AsString()); diff --git a/src/RpcClient/Models/RpcUnclaimedGas.cs b/src/RpcClient/Models/RpcUnclaimedGas.cs index 0702e7f97..93e2c72fc 100644 --- a/src/RpcClient/Models/RpcUnclaimedGas.cs +++ b/src/RpcClient/Models/RpcUnclaimedGas.cs @@ -19,10 +19,11 @@ public JObject ToJson() public static RpcUnclaimedGas FromJson(JObject json) { - RpcUnclaimedGas gas = new RpcUnclaimedGas(); - gas.Unclaimed = BigInteger.Parse(json["unclaimed"].AsString()); - gas.Address = json["address"].AsString(); - return gas; + return new RpcUnclaimedGas + { + Unclaimed = BigInteger.Parse(json["unclaimed"].AsString()), + Address = json["address"].AsString() + }; } } } diff --git a/src/RpcClient/Models/RpcValidateAddressResult.cs b/src/RpcClient/Models/RpcValidateAddressResult.cs index 5e0a70479..239d4de23 100644 --- a/src/RpcClient/Models/RpcValidateAddressResult.cs +++ b/src/RpcClient/Models/RpcValidateAddressResult.cs @@ -18,10 +18,11 @@ public JObject ToJson() public static RpcValidateAddressResult FromJson(JObject json) { - RpcValidateAddressResult validateAddress = new RpcValidateAddressResult(); - validateAddress.Address = json["address"].AsString(); - validateAddress.IsValid = json["isvalid"].AsBoolean(); - return validateAddress; + return new RpcValidateAddressResult + { + Address = json["address"].AsString(), + IsValid = json["isvalid"].AsBoolean() + }; } } } diff --git a/src/RpcClient/Models/RpcValidator.cs b/src/RpcClient/Models/RpcValidator.cs index f3116ed2e..0c8d53d43 100644 --- a/src/RpcClient/Models/RpcValidator.cs +++ b/src/RpcClient/Models/RpcValidator.cs @@ -22,11 +22,12 @@ public JObject ToJson() public static RpcValidator FromJson(JObject json) { - RpcValidator validator = new RpcValidator(); - validator.PublicKey = json["publickey"].AsString(); - validator.Votes = BigInteger.Parse(json["votes"].AsString()); - validator.Active = json["active"].AsBoolean(); - return validator; + return new RpcValidator + { + PublicKey = json["publickey"].AsString(), + Votes = BigInteger.Parse(json["votes"].AsString()), + Active = json["active"].AsBoolean() + }; } } } diff --git a/src/RpcClient/Models/RpcVersion.cs b/src/RpcClient/Models/RpcVersion.cs index 34ca163dd..06e7d7056 100644 --- a/src/RpcClient/Models/RpcVersion.cs +++ b/src/RpcClient/Models/RpcVersion.cs @@ -28,13 +28,14 @@ public JObject ToJson() public static RpcVersion FromJson(JObject json) { - RpcVersion version = new RpcVersion(); - version.Magic = (uint)json["magic"].AsNumber(); - version.TcpPort = (int)json["tcpport"].AsNumber(); - version.WsPort = (int)json["wsport"].AsNumber(); - version.Nonce = (uint)json["nonce"].AsNumber(); - version.UserAgent = json["useragent"].AsString(); - return version; + return new RpcVersion + { + Magic = (uint)json["magic"].AsNumber(), + TcpPort = (int)json["tcpport"].AsNumber(), + WsPort = (int)json["wsport"].AsNumber(), + Nonce = (uint)json["nonce"].AsNumber(), + UserAgent = json["useragent"].AsString() + }; } } } diff --git a/src/RpcClient/RpcClient.cs b/src/RpcClient/RpcClient.cs index 32442ba98..ca43fc744 100644 --- a/src/RpcClient/RpcClient.cs +++ b/src/RpcClient/RpcClient.cs @@ -11,6 +11,7 @@ using System.Net.Http.Headers; using System.Numerics; using System.Text; +using System.Text.RegularExpressions; using System.Threading.Tasks; namespace Neo.Network.RPC @@ -94,6 +95,21 @@ public virtual async Task RpcSendAsync(string method, params JObject[] return response.Result; } + public static string GetRpcName() + { + var methodName = ""; + for (int i = 1; i < 5; i++) + { + var method = new System.Diagnostics.StackTrace(true).GetFrame(i).GetMethod(); + if (method.IsPublic && !method.IsGenericMethod) + { + methodName = method.Name; + break; + } + } + return new Regex("(.*?)(Hex|Both)?(Async)?").Replace(methodName, "$1").ToLower(); + } + #region Blockchain /// @@ -101,7 +117,7 @@ public virtual async Task RpcSendAsync(string method, params JObject[] /// public async Task GetBestBlockHashAsync() { - var result = await RpcSendAsync("getbestblockhash").ConfigureAwait(false); + var result = await RpcSendAsync(GetRpcName()).ConfigureAwait(false); return result.AsString(); } @@ -112,8 +128,8 @@ public async Task GetBestBlockHashAsync() public async Task GetBlockHexAsync(string hashOrIndex) { var result = int.TryParse(hashOrIndex, out int index) - ? await RpcSendAsync("getblock", index).ConfigureAwait(false) - : await RpcSendAsync("getblock", hashOrIndex).ConfigureAwait(false); + ? await RpcSendAsync(GetRpcName(), index).ConfigureAwait(false) + : await RpcSendAsync(GetRpcName(), hashOrIndex).ConfigureAwait(false); return result.AsString(); } @@ -123,8 +139,8 @@ public async Task GetBlockHexAsync(string hashOrIndex) public async Task GetBlockAsync(string hashOrIndex) { var result = int.TryParse(hashOrIndex, out int index) - ? await RpcSendAsync("getblock", index, true).ConfigureAwait(false) - : await RpcSendAsync("getblock", hashOrIndex, true).ConfigureAwait(false); + ? await RpcSendAsync(GetRpcName(), index, true).ConfigureAwait(false) + : await RpcSendAsync(GetRpcName(), hashOrIndex, true).ConfigureAwait(false); return RpcBlock.FromJson(result); } @@ -134,7 +150,7 @@ public async Task GetBlockAsync(string hashOrIndex) /// public async Task GetBlockCountAsync() { - var result = await RpcSendAsync("getblockcount").ConfigureAwait(false); + var result = await RpcSendAsync(GetRpcName()).ConfigureAwait(false); return (uint)result.AsNumber(); } @@ -143,7 +159,7 @@ public async Task GetBlockCountAsync() /// public async Task GetBlockHashAsync(int index) { - var result = await RpcSendAsync("getblockhash", index).ConfigureAwait(false); + var result = await RpcSendAsync(GetRpcName(), index).ConfigureAwait(false); return result.AsString(); } @@ -153,8 +169,8 @@ public async Task GetBlockHashAsync(int index) public async Task GetBlockHeaderHexAsync(string hashOrIndex) { var result = int.TryParse(hashOrIndex, out int index) - ? await RpcSendAsync("getblockheader", index).ConfigureAwait(false) - : await RpcSendAsync("getblockheader", hashOrIndex).ConfigureAwait(false); + ? await RpcSendAsync(GetRpcName(), index).ConfigureAwait(false) + : await RpcSendAsync(GetRpcName(), hashOrIndex).ConfigureAwait(false); return result.AsString(); } @@ -164,8 +180,8 @@ public async Task GetBlockHeaderHexAsync(string hashOrIndex) public async Task GetBlockHeaderAsync(string hashOrIndex) { var result = int.TryParse(hashOrIndex, out int index) - ? await RpcSendAsync("getblockheader", index, true).ConfigureAwait(false) - : await RpcSendAsync("getblockheader", hashOrIndex, true).ConfigureAwait(false); + ? await RpcSendAsync(GetRpcName(), index, true).ConfigureAwait(false) + : await RpcSendAsync(GetRpcName(), hashOrIndex, true).ConfigureAwait(false); return RpcBlockHeader.FromJson(result); } @@ -175,7 +191,7 @@ public async Task GetBlockHeaderAsync(string hashOrIndex) /// public async Task GetContractStateAsync(string hash) { - var result = await RpcSendAsync("getcontractstate", hash).ConfigureAwait(false); + var result = await RpcSendAsync(GetRpcName(), hash).ConfigureAwait(false); return ContractStateFromJson(result); } @@ -194,7 +210,7 @@ public static ContractState ContractStateFromJson(JObject json) /// public async Task GetRawMempoolAsync() { - var result = await RpcSendAsync("getrawmempool").ConfigureAwait(false); + var result = await RpcSendAsync(GetRpcName()).ConfigureAwait(false); return ((JArray)result).Select(p => p.AsString()).ToArray(); } @@ -204,7 +220,7 @@ public async Task GetRawMempoolAsync() /// public async Task GetRawMempoolBothAsync() { - var result = await RpcSendAsync("getrawmempool", true).ConfigureAwait(false); + var result = await RpcSendAsync(GetRpcName(), true).ConfigureAwait(false); return RpcRawMemPool.FromJson(result); } @@ -213,7 +229,7 @@ public async Task GetRawMempoolBothAsync() /// public async Task GetRawTransactionHexAsync(string txHash) { - var result = await RpcSendAsync("getrawtransaction", txHash).ConfigureAwait(false); + var result = await RpcSendAsync(GetRpcName(), txHash).ConfigureAwait(false); return result.AsString(); } @@ -223,7 +239,7 @@ public async Task GetRawTransactionHexAsync(string txHash) /// public async Task GetRawTransactionAsync(string txHash) { - var result = await RpcSendAsync("getrawtransaction", txHash, true).ConfigureAwait(false); + var result = await RpcSendAsync(GetRpcName(), txHash, true).ConfigureAwait(false); return RpcTransaction.FromJson(result); } @@ -234,7 +250,7 @@ public async Task GetRawTransactionAsync(string txHash) /// NetworkFee public async Task CalculateNetworkFeeAsync(Transaction tx) { - var json = await RpcSendAsync("calculatenetworkfee", Convert.ToBase64String(tx.ToArray())) + var json = await RpcSendAsync(GetRpcName(), Convert.ToBase64String(tx.ToArray())) .ConfigureAwait(false); return (long)json["networkfee"].AsNumber(); } @@ -245,8 +261,8 @@ public async Task CalculateNetworkFeeAsync(Transaction tx) public async Task GetStorageAsync(string scriptHashOrId, string key) { var result = int.TryParse(scriptHashOrId, out int id) - ? await RpcSendAsync("getstorage", id, key).ConfigureAwait(false) - : await RpcSendAsync("getstorage", scriptHashOrId, key).ConfigureAwait(false); + ? await RpcSendAsync(GetRpcName(), id, key).ConfigureAwait(false) + : await RpcSendAsync(GetRpcName(), scriptHashOrId, key).ConfigureAwait(false); return result.AsString(); } @@ -255,7 +271,7 @@ public async Task GetStorageAsync(string scriptHashOrId, string key) /// public async Task GetTransactionHeightAsync(string txHash) { - var result = await RpcSendAsync("gettransactionheight", txHash).ConfigureAwait(false); + var result = await RpcSendAsync(GetRpcName(), txHash).ConfigureAwait(false); return uint.Parse(result.AsString()); } @@ -264,7 +280,7 @@ public async Task GetTransactionHeightAsync(string txHash) /// public async Task GetNextBlockValidatorsAsync() { - var result = await RpcSendAsync("getnextblockvalidators").ConfigureAwait(false); + var result = await RpcSendAsync(GetRpcName()).ConfigureAwait(false); return ((JArray)result).Select(p => RpcValidator.FromJson(p)).ToArray(); } @@ -273,7 +289,7 @@ public async Task GetNextBlockValidatorsAsync() /// public async Task GetCommitteeAsync() { - var result = await RpcSendAsync("getcommittee").ConfigureAwait(false); + var result = await RpcSendAsync(GetRpcName()).ConfigureAwait(false); return ((JArray)result).Select(p => p.AsString()).ToArray(); } @@ -286,7 +302,7 @@ public async Task GetCommitteeAsync() /// public async Task GetConnectionCountAsync() { - var result = await RpcSendAsync("getconnectioncount").ConfigureAwait(false); + var result = await RpcSendAsync(GetRpcName()).ConfigureAwait(false); return (int)result.AsNumber(); } @@ -295,7 +311,7 @@ public async Task GetConnectionCountAsync() /// public async Task GetPeersAsync() { - var result = await RpcSendAsync("getpeers").ConfigureAwait(false); + var result = await RpcSendAsync(GetRpcName()).ConfigureAwait(false); return RpcPeers.FromJson(result); } @@ -304,7 +320,7 @@ public async Task GetPeersAsync() /// public async Task GetVersionAsync() { - var result = await RpcSendAsync("getversion").ConfigureAwait(false); + var result = await RpcSendAsync(GetRpcName()).ConfigureAwait(false); return RpcVersion.FromJson(result); } @@ -313,7 +329,7 @@ public async Task GetVersionAsync() /// public async Task SendRawTransactionAsync(byte[] rawTransaction) { - var result = await RpcSendAsync("sendrawtransaction", rawTransaction.ToHexString()).ConfigureAwait(false); + var result = await RpcSendAsync(GetRpcName(), rawTransaction.ToHexString()).ConfigureAwait(false); return UInt256.Parse(result["hash"].AsString()); } @@ -330,7 +346,7 @@ public Task SendRawTransactionAsync(Transaction transaction) /// public async Task SubmitBlockAsync(byte[] block) { - var result = await RpcSendAsync("submitblock", block.ToHexString()).ConfigureAwait(false); + var result = await RpcSendAsync(GetRpcName(), block.ToHexString()).ConfigureAwait(false); return UInt256.Parse(result["hash"].AsString()); } @@ -349,7 +365,7 @@ public async Task InvokeFunctionAsync(string scriptHash, string { parameters.Add(signer.Select(p => (JObject)p.ToJson()).ToArray()); } - var result = await RpcSendAsync("invokefunction", parameters.ToArray()).ConfigureAwait(false); + var result = await RpcSendAsync(GetRpcName(), parameters.ToArray()).ConfigureAwait(false); return RpcInvokeResult.FromJson(result); } @@ -364,13 +380,13 @@ public async Task InvokeScriptAsync(byte[] script, params Signe { parameters.Add(signers.Select(p => p.ToJson()).ToArray()); } - var result = await RpcSendAsync("invokescript", parameters.ToArray()).ConfigureAwait(false); + var result = await RpcSendAsync(GetRpcName(), parameters.ToArray()).ConfigureAwait(false); return RpcInvokeResult.FromJson(result); } public async Task GetUnclaimedGasAsync(string address) { - var result = await RpcSendAsync("getunclaimedgas", address.AsScriptHash()).ConfigureAwait(false); + var result = await RpcSendAsync(GetRpcName(), address.AsScriptHash()).ConfigureAwait(false); return RpcUnclaimedGas.FromJson(result); } @@ -383,7 +399,7 @@ public async Task GetUnclaimedGasAsync(string address) /// public async Task ListPluginsAsync() { - var result = await RpcSendAsync("listplugins").ConfigureAwait(false); + var result = await RpcSendAsync(GetRpcName()).ConfigureAwait(false); return ((JArray)result).Select(p => RpcPlugin.FromJson(p)).ToArray(); } @@ -392,7 +408,7 @@ public async Task ListPluginsAsync() /// public async Task ValidateAddressAsync(string address) { - var result = await RpcSendAsync("validateaddress", address).ConfigureAwait(false); + var result = await RpcSendAsync(GetRpcName(), address).ConfigureAwait(false); return RpcValidateAddressResult.FromJson(result); } @@ -405,7 +421,7 @@ public async Task ValidateAddressAsync(string address) /// public async Task CloseWalletAsync() { - var result = await RpcSendAsync("closewallet").ConfigureAwait(false); + var result = await RpcSendAsync(GetRpcName()).ConfigureAwait(false); return result.AsBoolean(); } @@ -414,7 +430,7 @@ public async Task CloseWalletAsync() /// public async Task DumpPrivKeyAsync(string address) { - var result = await RpcSendAsync("dumpprivkey", address).ConfigureAwait(false); + var result = await RpcSendAsync(GetRpcName(), address).ConfigureAwait(false); return result.AsString(); } @@ -423,7 +439,7 @@ public async Task DumpPrivKeyAsync(string address) /// public async Task GetNewAddressAsync() { - var result = await RpcSendAsync("getnewaddress").ConfigureAwait(false); + var result = await RpcSendAsync(GetRpcName()).ConfigureAwait(false); return result.AsString(); } @@ -435,7 +451,7 @@ public async Task GetNewAddressAsync() public async Task GetWalletBalanceAsync(string assetId) { byte decimals = await new Nep5API(this).DecimalsAsync(UInt160.Parse(assetId.AsScriptHash())).ConfigureAwait(false); - var result = await RpcSendAsync("getwalletbalance", assetId).ConfigureAwait(false); + var result = await RpcSendAsync(GetRpcName(), assetId).ConfigureAwait(false); BigInteger balance = BigInteger.Parse(result["balance"].AsString()); return new BigDecimal(balance, decimals); } @@ -445,7 +461,7 @@ public async Task GetWalletBalanceAsync(string assetId) /// public async Task GetWalletUnclaimedGasAsync() { - var result = await RpcSendAsync("getwalletunclaimedgas").ConfigureAwait(false); + var result = await RpcSendAsync(GetRpcName()).ConfigureAwait(false); return BigInteger.Parse(result.AsString()); } @@ -454,7 +470,7 @@ public async Task GetWalletUnclaimedGasAsync() /// public async Task ImportPrivKeyAsync(string wif) { - var result = await RpcSendAsync("importprivkey", wif).ConfigureAwait(false); + var result = await RpcSendAsync(GetRpcName(), wif).ConfigureAwait(false); return RpcAccount.FromJson(result); } @@ -463,7 +479,7 @@ public async Task ImportPrivKeyAsync(string wif) /// public async Task> ListAddressAsync() { - var result = await RpcSendAsync("listaddress").ConfigureAwait(false); + var result = await RpcSendAsync(GetRpcName()).ConfigureAwait(false); return ((JArray)result).Select(p => RpcAccount.FromJson(p)).ToList(); } @@ -473,7 +489,7 @@ public async Task> ListAddressAsync() /// public async Task OpenWalletAsync(string path, string password) { - var result = await RpcSendAsync("openwallet", path, password).ConfigureAwait(false); + var result = await RpcSendAsync(GetRpcName(), path, password).ConfigureAwait(false); return result.AsBoolean(); } @@ -483,7 +499,7 @@ public async Task OpenWalletAsync(string path, string password) /// This function returns Signed Transaction JSON if successful, ContractParametersContext JSON if signing failed. public async Task SendFromAsync(string assetId, string fromAddress, string toAddress, string amount) { - return await RpcSendAsync("sendfrom", assetId.AsScriptHash(), fromAddress.AsScriptHash(), + return await RpcSendAsync(GetRpcName(), assetId.AsScriptHash(), fromAddress.AsScriptHash(), toAddress.AsScriptHash(), amount).ConfigureAwait(false); } @@ -500,7 +516,7 @@ public async Task SendManyAsync(string fromAddress, IEnumerable p.ToJson()).ToArray()); - return await RpcSendAsync("sendmany", paraArgs: parameters.ToArray()).ConfigureAwait(false); + return await RpcSendAsync(GetRpcName(), paraArgs: parameters.ToArray()).ConfigureAwait(false); } /// @@ -509,7 +525,7 @@ public async Task SendManyAsync(string fromAddress, IEnumerableThis function returns Signed Transaction JSON if successful, ContractParametersContext JSON if signing failed. public async Task SendToAddressAsync(string assetId, string address, string amount) { - return await RpcSendAsync("sendtoaddress", assetId.AsScriptHash(), address.AsScriptHash(), amount) + return await RpcSendAsync(GetRpcName(), assetId.AsScriptHash(), address.AsScriptHash(), amount) .ConfigureAwait(false); } @@ -523,7 +539,7 @@ public async Task SendToAddressAsync(string assetId, string address, st /// public async Task GetApplicationLogAsync(string txHash) { - var result = await RpcSendAsync("getapplicationlog", txHash).ConfigureAwait(false); + var result = await RpcSendAsync(GetRpcName(), txHash).ConfigureAwait(false); return RpcApplicationLog.FromJson(result); } @@ -538,7 +554,7 @@ public async Task GetNep5TransfersAsync(string address, ulong? { startTimestamp ??= 0; endTimestamp ??= DateTime.UtcNow.ToTimestampMS(); - var result = await RpcSendAsync("getnep5transfers", address.AsScriptHash(), startTimestamp, endTimestamp) + var result = await RpcSendAsync(GetRpcName(), address.AsScriptHash(), startTimestamp, endTimestamp) .ConfigureAwait(false); return RpcNep5Transfers.FromJson(result); } @@ -549,7 +565,7 @@ public async Task GetNep5TransfersAsync(string address, ulong? /// public async Task GetNep5BalancesAsync(string address) { - var result = await RpcSendAsync("getnep5balances", address.AsScriptHash()) + var result = await RpcSendAsync(GetRpcName(), address.AsScriptHash()) .ConfigureAwait(false); return RpcNep5Balances.FromJson(result); } diff --git a/src/RpcClient/TransactionManager.cs b/src/RpcClient/TransactionManager.cs index 7e35e25f0..067fc2ff6 100644 --- a/src/RpcClient/TransactionManager.cs +++ b/src/RpcClient/TransactionManager.cs @@ -113,7 +113,7 @@ private void AddSignItem(Contract contract, KeyPair key) { if (!Tx.GetScriptHashesForVerifying(null).Contains(contract.ScriptHash)) { - throw new Exception($"Add SignItem error: Mismatch ScriptHash ({contract.ScriptHash.ToString()})"); + throw new Exception($"Add SignItem error: Mismatch ScriptHash ({contract.ScriptHash})"); } SignItem item = signStore.FirstOrDefault(p => p.Contract.ScriptHash == contract.ScriptHash); diff --git a/src/RpcClient/Utility.cs b/src/RpcClient/Utility.cs index 8b1135249..0c4332754 100644 --- a/src/RpcClient/Utility.cs +++ b/src/RpcClient/Utility.cs @@ -142,17 +142,18 @@ public static void FromJson(this BlockBase block, JObject json) public static Transaction TransactionFromJson(JObject json) { - Transaction tx = new Transaction(); - tx.Version = byte.Parse(json["version"].AsString()); - tx.Nonce = uint.Parse(json["nonce"].AsString()); - tx.Signers = ((JArray)json["signers"]).Select(p => SignerFromJson(p)).ToArray(); - tx.SystemFee = long.Parse(json["sysfee"].AsString()); - tx.NetworkFee = long.Parse(json["netfee"].AsString()); - tx.ValidUntilBlock = uint.Parse(json["validuntilblock"].AsString()); - tx.Attributes = ((JArray)json["attributes"]).Select(p => TransactionAttributeFromJson(p)).ToArray(); - tx.Script = Convert.FromBase64String(json["script"].AsString()); - tx.Witnesses = ((JArray)json["witnesses"]).Select(p => WitnessFromJson(p)).ToArray(); - return tx; + return new Transaction + { + Version = byte.Parse(json["version"].AsString()), + Nonce = uint.Parse(json["nonce"].AsString()), + Signers = ((JArray)json["signers"]).Select(p => SignerFromJson(p)).ToArray(), + SystemFee = long.Parse(json["sysfee"].AsString()), + NetworkFee = long.Parse(json["netfee"].AsString()), + ValidUntilBlock = uint.Parse(json["validuntilblock"].AsString()), + Attributes = ((JArray)json["attributes"]).Select(p => TransactionAttributeFromJson(p)).ToArray(), + Script = Convert.FromBase64String(json["script"].AsString()), + Witnesses = ((JArray)json["witnesses"]).Select(p => WitnessFromJson(p)).ToArray() + }; } public static Header HeaderFromJson(JObject json) @@ -176,10 +177,11 @@ public static Signer SignerFromJson(JObject json) public static ConsensusData ConsensusDataFromJson(JObject json) { - ConsensusData block = new ConsensusData(); - block.PrimaryIndex = (byte)json["primary"].AsNumber(); - block.Nonce = ulong.Parse(json["nonce"].AsString(), NumberStyles.HexNumber); - return block; + return new ConsensusData + { + PrimaryIndex = (byte)json["primary"].AsNumber(), + Nonce = ulong.Parse(json["nonce"].AsString(), NumberStyles.HexNumber) + }; } public static TransactionAttribute TransactionAttributeFromJson(JObject json) @@ -194,10 +196,11 @@ public static TransactionAttribute TransactionAttributeFromJson(JObject json) public static Witness WitnessFromJson(JObject json) { - Witness witness = new Witness(); - witness.InvocationScript = Convert.FromBase64String(json["invocation"].AsString()); - witness.VerificationScript = Convert.FromBase64String(json["verification"].AsString()); - return witness; + return new Witness + { + InvocationScript = Convert.FromBase64String(json["invocation"].AsString()), + VerificationScript = Convert.FromBase64String(json["verification"].AsString()) + }; } public static StackItem StackItemFromJson(JObject json) From ce24f59b8d22eab57de2eadc6edbc38429afba9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=BF=97=E5=90=8C?= Date: Wed, 21 Oct 2020 14:51:18 +0800 Subject: [PATCH 170/183] [RpcClient] Add processing of Any type to StackItemFromJson method. (#371) * Update Utility.cs * Update RpcTestCases.json * update Co-authored-by: Owen Zhang <38493437+superboyiii@users.noreply.github.com> --- src/RpcClient/Utility.cs | 2 +- tests/Neo.Network.RPC.Tests/RpcTestCases.json | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/RpcClient/Utility.cs b/src/RpcClient/Utility.cs index 0c4332754..dae537f2b 100644 --- a/src/RpcClient/Utility.cs +++ b/src/RpcClient/Utility.cs @@ -239,7 +239,7 @@ public static StackItem StackItemFromJson(JObject json) case StackItemType.InteropInterface: return new InteropInterface(new object()); // See https://github.com/neo-project/neo/blob/master/src/neo/VM/Helper.cs#L194 } - return null; + return json["value"] is null ? StackItem.Null : json["value"].AsString(); } } } diff --git a/tests/Neo.Network.RPC.Tests/RpcTestCases.json b/tests/Neo.Network.RPC.Tests/RpcTestCases.json index 6c89e441f..b9e0bd15c 100644 --- a/tests/Neo.Network.RPC.Tests/RpcTestCases.json +++ b/tests/Neo.Network.RPC.Tests/RpcTestCases.json @@ -1216,6 +1216,9 @@ { "type": "Array", "value": [ + { + "type": "Any" + }, { "type": "Integer", "value": "1" From e5c90f423da99f7e0fc7ee218f2591825fb174c5 Mon Sep 17 00:00:00 2001 From: Owen Zhang <38493437+superboyiii@users.noreply.github.com> Date: Fri, 30 Oct 2020 16:46:23 +0800 Subject: [PATCH 171/183] Fix script convert in MakeTransaction(). (#382) --- src/RpcServer/RpcServer.Wallet.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/RpcServer/RpcServer.Wallet.cs b/src/RpcServer/RpcServer.Wallet.cs index 8b1131166..158218550 100644 --- a/src/RpcServer/RpcServer.Wallet.cs +++ b/src/RpcServer/RpcServer.Wallet.cs @@ -176,7 +176,7 @@ private void ProcessInvokeWithWallet(JObject result, Signers signers = null) { try { - tx = wallet.MakeTransaction(result["script"].AsString().HexToBytes(), sender, witnessSigners); + tx = wallet.MakeTransaction(Convert.FromBase64String(result["script"].AsString()), sender, witnessSigners); } catch (Exception e) { From 23811189d2e8dc4fd81f3368a5c3e3331e60b737 Mon Sep 17 00:00:00 2001 From: Owen Zhang <38493437+superboyiii@users.noreply.github.com> Date: Mon, 2 Nov 2020 10:13:44 +0800 Subject: [PATCH 172/183] Use Base64String on response of getrawtransaction (#383) Use Base64String on response of getrawtransaction --- src/RpcServer/RpcServer.Blockchain.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/RpcServer/RpcServer.Blockchain.cs b/src/RpcServer/RpcServer.Blockchain.cs index 3adde1ac7..e851d5d0e 100644 --- a/src/RpcServer/RpcServer.Blockchain.cs +++ b/src/RpcServer/RpcServer.Blockchain.cs @@ -147,7 +147,7 @@ protected virtual JObject GetRawTransaction(JArray _params) } return json; } - return tx.ToArray().ToHexString(); + return Convert.ToBase64String(tx.ToArray().ToHexString().HexToBytes()); } [RpcMethod] From 9729f7e36ef544f1da967f28f7df71d93925f860 Mon Sep 17 00:00:00 2001 From: Owen Zhang <38493437+superboyiii@users.noreply.github.com> Date: Tue, 3 Nov 2020 17:33:13 +0800 Subject: [PATCH 173/183] Unify to base64 (#384) --- src/LevelDBStore/LevelDBStore.csproj | 2 +- src/RocksDBStore/RocksDBStore.csproj | 2 +- src/RpcClient/RpcClient.csproj | 2 +- src/RpcServer/RpcServer.Blockchain.cs | 6 +++--- src/RpcServer/RpcServer.csproj | 2 +- src/StatesDumper/StatesDumper.csproj | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/LevelDBStore/LevelDBStore.csproj b/src/LevelDBStore/LevelDBStore.csproj index b0fd1b983..af5907e30 100644 --- a/src/LevelDBStore/LevelDBStore.csproj +++ b/src/LevelDBStore/LevelDBStore.csproj @@ -15,7 +15,7 @@ - + diff --git a/src/RocksDBStore/RocksDBStore.csproj b/src/RocksDBStore/RocksDBStore.csproj index 53ff6b564..abe7a2172 100644 --- a/src/RocksDBStore/RocksDBStore.csproj +++ b/src/RocksDBStore/RocksDBStore.csproj @@ -14,7 +14,7 @@ - + diff --git a/src/RpcClient/RpcClient.csproj b/src/RpcClient/RpcClient.csproj index 1aa80c1a3..35fa82f23 100644 --- a/src/RpcClient/RpcClient.csproj +++ b/src/RpcClient/RpcClient.csproj @@ -14,7 +14,7 @@ - + diff --git a/src/RpcServer/RpcServer.Blockchain.cs b/src/RpcServer/RpcServer.Blockchain.cs index e851d5d0e..4ef57fc18 100644 --- a/src/RpcServer/RpcServer.Blockchain.cs +++ b/src/RpcServer/RpcServer.Blockchain.cs @@ -48,7 +48,7 @@ protected virtual JObject GetBlock(JArray _params) json["nextblockhash"] = hash.ToString(); return json; } - return block.ToArray().ToHexString(); + return Convert.ToBase64String(block.ToArray()); } [RpcMethod] @@ -97,7 +97,7 @@ protected virtual JObject GetBlockHeader(JArray _params) return json; } - return header.ToArray().ToHexString(); + return Convert.ToBase64String(header.ToArray()); } [RpcMethod] @@ -147,7 +147,7 @@ protected virtual JObject GetRawTransaction(JArray _params) } return json; } - return Convert.ToBase64String(tx.ToArray().ToHexString().HexToBytes()); + return Convert.ToBase64String(tx.ToArray()); } [RpcMethod] diff --git a/src/RpcServer/RpcServer.csproj b/src/RpcServer/RpcServer.csproj index 7bceda3c2..e1206da61 100644 --- a/src/RpcServer/RpcServer.csproj +++ b/src/RpcServer/RpcServer.csproj @@ -15,7 +15,7 @@ - + diff --git a/src/StatesDumper/StatesDumper.csproj b/src/StatesDumper/StatesDumper.csproj index 2d144d45b..6de4d295e 100644 --- a/src/StatesDumper/StatesDumper.csproj +++ b/src/StatesDumper/StatesDumper.csproj @@ -14,7 +14,7 @@ - + From f88961d0c1348b1d5f01fc0c2a1ae25532c83f59 Mon Sep 17 00:00:00 2001 From: HaoqiangZhang Date: Thu, 5 Nov 2020 20:17:08 +0800 Subject: [PATCH 174/183] Update RpcServer.SmartContract.cs (#386) According to https://github.com/neo-project/neo-modules/pull/368#discussion_r517824469 --- src/RpcServer/RpcServer.SmartContract.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/RpcServer/RpcServer.SmartContract.cs b/src/RpcServer/RpcServer.SmartContract.cs index f5cf6cbfc..cba590ba3 100644 --- a/src/RpcServer/RpcServer.SmartContract.cs +++ b/src/RpcServer/RpcServer.SmartContract.cs @@ -120,7 +120,7 @@ protected virtual JObject InvokeFunction(JArray _params) [RpcMethod] protected virtual JObject InvokeScript(JArray _params) { - byte[] script = _params[0].AsString().HexToBytes(); + byte[] script = Convert.FromBase64String(_params[0].AsString()); Signers signers = _params.Count >= 2 ? SignersFromJson((JArray)_params[1]) : null; return GetInvokeResult(script, signers); } From 3ab2871ab30a90e6dcb2b14ff2e59631f40fa59f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=BF=97=E5=90=8C?= Date: Tue, 10 Nov 2020 17:34:45 +0800 Subject: [PATCH 175/183] [RpcClient] Policy API mismatch (#388) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fixed-bug-1021 * Update src/RpcServer/RpcServer.SmartContract.cs * 😂 * NEO3: RPC client Policy API mismatch * update * update * update * UT * Format Co-authored-by: Shargon Co-authored-by: Owen Zhang <38493437+superboyiii@users.noreply.github.com> --- src/RpcClient/PolicyAPI.cs | 8 ++++---- tests/Neo.Network.RPC.Tests/UT_PolicyAPI.cs | 11 +++++------ 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/RpcClient/PolicyAPI.cs b/src/RpcClient/PolicyAPI.cs index 540f945da..808906a39 100644 --- a/src/RpcClient/PolicyAPI.cs +++ b/src/RpcClient/PolicyAPI.cs @@ -2,6 +2,7 @@ using Neo.VM; using System.Linq; using System.Threading.Tasks; +using Neo.IO.Json; namespace Neo.Network.RPC { @@ -52,11 +53,10 @@ public async Task GetFeePerByteAsync() /// Get Ploicy Blocked Accounts /// /// - public async Task GetBlockedAccountsAsync() + public async Task IsBlockedAsync(UInt160 account) { - var result = await TestInvokeAsync(scriptHash, "getBlockedAccounts").ConfigureAwait(false); - var array = (VM.Types.Array)result.Stack.Single(); - return array.Select(p => new UInt160(p.GetSpan().ToArray())).ToArray(); + var result = await TestInvokeAsync(scriptHash, "isBlocked", new object[] { account }).ConfigureAwait(false); + return result.Stack.Single().GetBoolean(); } } } diff --git a/tests/Neo.Network.RPC.Tests/UT_PolicyAPI.cs b/tests/Neo.Network.RPC.Tests/UT_PolicyAPI.cs index 546e250e1..245636e93 100644 --- a/tests/Neo.Network.RPC.Tests/UT_PolicyAPI.cs +++ b/tests/Neo.Network.RPC.Tests/UT_PolicyAPI.cs @@ -57,13 +57,12 @@ public async Task TestGetFeePerByte() } [TestMethod] - public async Task TestGetBlockedAccounts() + public async Task TestIsBlocked() { - byte[] testScript = NativeContract.Policy.Hash.MakeScript("getBlockedAccounts"); - UT_TransactionManager.MockInvokeScript(rpcClientMock, testScript, new ContractParameter { Type = ContractParameterType.Array, Value = new[] { new ContractParameter { Type = ContractParameterType.Hash160, Value = UInt160.Zero } } }); - - var result = await policyAPI.GetBlockedAccountsAsync(); - Assert.AreEqual(UInt160.Zero, result[0]); + byte[] testScript = NativeContract.Policy.Hash.MakeScript("isBlocked", UInt160.Zero); + UT_TransactionManager.MockInvokeScript(rpcClientMock, testScript, new ContractParameter { Type = ContractParameterType.Boolean, Value = true }); + var result = await policyAPI.IsBlockedAsync(UInt160.Zero); + Assert.AreEqual(true, result); } } } From fc7bbb05c01ad83521fe36e53462bd3c8f8cc5ba Mon Sep 17 00:00:00 2001 From: Owen Zhang <38493437+superboyiii@users.noreply.github.com> Date: Thu, 12 Nov 2020 16:57:22 +0800 Subject: [PATCH 176/183] [Sync to master] Unify base64 (#397) * Unify base64 in SendRawTransaction and SubmitBlock * fix GetRpcName() in GetWalletBalanceAsync * add SubmitBlock * add ProcessInvokeWithWallet --- src/LevelDBStore/LevelDBStore.csproj | 2 +- src/RocksDBStore/RocksDBStore.csproj | 2 +- src/RpcClient/RpcClient.cs | 6 +++--- src/RpcClient/RpcClient.csproj | 2 +- src/RpcServer/RpcServer.Node.cs | 5 +++-- src/RpcServer/RpcServer.Wallet.cs | 3 ++- src/RpcServer/RpcServer.csproj | 4 ++-- src/StatesDumper/StatesDumper.csproj | 2 +- tests/Neo.Network.RPC.Tests/RpcTestCases.json | 6 +++--- tests/Neo.Network.RPC.Tests/UT_RpcClient.cs | 7 +++---- 10 files changed, 20 insertions(+), 19 deletions(-) diff --git a/src/LevelDBStore/LevelDBStore.csproj b/src/LevelDBStore/LevelDBStore.csproj index af5907e30..2acba8102 100644 --- a/src/LevelDBStore/LevelDBStore.csproj +++ b/src/LevelDBStore/LevelDBStore.csproj @@ -15,7 +15,7 @@ - + diff --git a/src/RocksDBStore/RocksDBStore.csproj b/src/RocksDBStore/RocksDBStore.csproj index abe7a2172..8cace3405 100644 --- a/src/RocksDBStore/RocksDBStore.csproj +++ b/src/RocksDBStore/RocksDBStore.csproj @@ -14,7 +14,7 @@ - + diff --git a/src/RpcClient/RpcClient.cs b/src/RpcClient/RpcClient.cs index ca43fc744..deba207ef 100644 --- a/src/RpcClient/RpcClient.cs +++ b/src/RpcClient/RpcClient.cs @@ -329,7 +329,7 @@ public async Task GetVersionAsync() /// public async Task SendRawTransactionAsync(byte[] rawTransaction) { - var result = await RpcSendAsync(GetRpcName(), rawTransaction.ToHexString()).ConfigureAwait(false); + var result = await RpcSendAsync(GetRpcName(), Convert.ToBase64String(rawTransaction)).ConfigureAwait(false); return UInt256.Parse(result["hash"].AsString()); } @@ -346,7 +346,7 @@ public Task SendRawTransactionAsync(Transaction transaction) /// public async Task SubmitBlockAsync(byte[] block) { - var result = await RpcSendAsync(GetRpcName(), block.ToHexString()).ConfigureAwait(false); + var result = await RpcSendAsync(GetRpcName(), Convert.ToBase64String(block)).ConfigureAwait(false); return UInt256.Parse(result["hash"].AsString()); } @@ -450,9 +450,9 @@ public async Task GetNewAddressAsync() /// new address as string public async Task GetWalletBalanceAsync(string assetId) { - byte decimals = await new Nep5API(this).DecimalsAsync(UInt160.Parse(assetId.AsScriptHash())).ConfigureAwait(false); var result = await RpcSendAsync(GetRpcName(), assetId).ConfigureAwait(false); BigInteger balance = BigInteger.Parse(result["balance"].AsString()); + byte decimals = await new Nep5API(this).DecimalsAsync(UInt160.Parse(assetId.AsScriptHash())).ConfigureAwait(false); return new BigDecimal(balance, decimals); } diff --git a/src/RpcClient/RpcClient.csproj b/src/RpcClient/RpcClient.csproj index 35fa82f23..d687d0cce 100644 --- a/src/RpcClient/RpcClient.csproj +++ b/src/RpcClient/RpcClient.csproj @@ -14,7 +14,7 @@ - + diff --git a/src/RpcServer/RpcServer.Node.cs b/src/RpcServer/RpcServer.Node.cs index ccf06ee28..782544837 100644 --- a/src/RpcServer/RpcServer.Node.cs +++ b/src/RpcServer/RpcServer.Node.cs @@ -7,6 +7,7 @@ using Neo.Ledger; using Neo.Network.P2P; using Neo.Network.P2P.Payloads; +using System; using System.Linq; using static Neo.Ledger.Blockchain; @@ -71,7 +72,7 @@ protected virtual JObject GetVersion(JArray _params) [RpcMethod] protected virtual JObject SendRawTransaction(JArray _params) { - Transaction tx = _params[0].AsString().HexToBytes().AsSerializable(); + Transaction tx = Convert.FromBase64String(_params[0].AsString()).AsSerializable(); RelayResult reason = system.Blockchain.Ask(tx).Result; return GetRelayResult(reason.Result, tx.Hash); } @@ -79,7 +80,7 @@ protected virtual JObject SendRawTransaction(JArray _params) [RpcMethod] protected virtual JObject SubmitBlock(JArray _params) { - Block block = _params[0].AsString().HexToBytes().AsSerializable(); + Block block = Convert.FromBase64String(_params[0].AsString()).AsSerializable(); RelayResult reason = system.Blockchain.Ask(block).Result; return GetRelayResult(reason.Result, block.Hash); } diff --git a/src/RpcServer/RpcServer.Wallet.cs b/src/RpcServer/RpcServer.Wallet.cs index 158218550..2256c0a6d 100644 --- a/src/RpcServer/RpcServer.Wallet.cs +++ b/src/RpcServer/RpcServer.Wallet.cs @@ -191,7 +191,8 @@ private void ProcessInvokeWithWallet(JObject result, Signers signers = null) tx = null; } } - result["tx"] = tx?.ToArray().ToHexString(); + if (tx != null) + result["tx"] = Convert.ToBase64String(tx.ToArray()); } [RpcMethod] diff --git a/src/RpcServer/RpcServer.csproj b/src/RpcServer/RpcServer.csproj index e1206da61..eafe5d8d5 100644 --- a/src/RpcServer/RpcServer.csproj +++ b/src/RpcServer/RpcServer.csproj @@ -1,4 +1,4 @@ - + 3.0.0-preview3 @@ -15,7 +15,7 @@ - + diff --git a/src/StatesDumper/StatesDumper.csproj b/src/StatesDumper/StatesDumper.csproj index 6de4d295e..ee9be372a 100644 --- a/src/StatesDumper/StatesDumper.csproj +++ b/src/StatesDumper/StatesDumper.csproj @@ -14,7 +14,7 @@ - + diff --git a/tests/Neo.Network.RPC.Tests/RpcTestCases.json b/tests/Neo.Network.RPC.Tests/RpcTestCases.json index b9e0bd15c..ebe32c8a5 100644 --- a/tests/Neo.Network.RPC.Tests/RpcTestCases.json +++ b/tests/Neo.Network.RPC.Tests/RpcTestCases.json @@ -4,7 +4,7 @@ "Request": { "jsonrpc": "2.0", "method": "sendrawtransaction", - "params": [ "0089d9a541587389000000000046e71300000000007b212000011c0357464b777ecf6b5f3ac3893ace1f8b1621f6100325059ecb4878d3a875f91c51ceded330d4575fdee3137eddba5f6485cad334a79bdb67c43273171fbcaf41d684c7d4ad6ee0d99da9707b9d1f0c8e660054180c14e3137eddba5f6485cad334a79bdb67c43273171f0c141c0357464b777ecf6b5f3ac3893ace1f8b1621f613c00c087472616e736665720c14bcaf41d684c7d4ad6ee0d99da9707b9d1f0c8e6641627d5b5201420c40b90107fe5d251a9ef10b22c3bb0d329c0fa8f1d0d1aab8ad430837c069cc2818887c4c387319a55837d72c997f6112698acf80c346c9bb4638d78b0c2623778c290c210222d8515184c7d62ffa99b829aeb4938c4704ecb0dd7e340e842e9df1218263430b4195440d78" ], + "params": [ "ANIHn05ujtUAAAAAACYcEwAAAAAAQkEAAAEKo4e1Ppa3mJpjFDGgVt0fQKBC9gEAXQMAyBeoBAAAAAwUzViuz9M1vh6z0xHh3IAJY9/XLZ8MFAqjh7U+lreYmmMUMaBW3R9AoEL2E8AMCHRyYW5zZmVyDBSlB7dGdv/td+dUuG7NmQnwus08ukFifVtSOAFCDEDh8zgTrGUXyzVX60wBCMyajNRfzFRiEPAe8CgGQ10bA2C3fnVz68Gw+Amgn5gmvuNfYKgWQ/W68Km1bYUPlnEYKQwhA86j4vgfGvk1ItKe3k8kofC+3q1ykzkdM4gPVHXZeHjJC0GVRA14" ], "id": 1 }, "Response": { @@ -679,7 +679,7 @@ "Request": { "jsonrpc": "2.0", "method": "sendrawtransaction", - "params": [ "0089d9a541587389000000000046e71300000000007b212000011c0357464b777ecf6b5f3ac3893ace1f8b1621f6100325059ecb4878d3a875f91c51ceded330d4575fdee3137eddba5f6485cad334a79bdb67c43273171fbcaf41d684c7d4ad6ee0d99da9707b9d1f0c8e660054180c14e3137eddba5f6485cad334a79bdb67c43273171f0c141c0357464b777ecf6b5f3ac3893ace1f8b1621f613c00c087472616e736665720c14bcaf41d684c7d4ad6ee0d99da9707b9d1f0c8e6641627d5b5201420c40b90107fe5d251a9ef10b22c3bb0d329c0fa8f1d0d1aab8ad430837c069cc2818887c4c387319a55837d72c997f6112698acf80c346c9bb4638d78b0c2623778c290c210222d8515184c7d62ffa99b829aeb4938c4704ecb0dd7e340e842e9df1218263430b4195440d78" ], + "params": [ "ANIHn05ujtUAAAAAACYcEwAAAAAAQkEAAAEKo4e1Ppa3mJpjFDGgVt0fQKBC9gEAXQMAyBeoBAAAAAwUzViuz9M1vh6z0xHh3IAJY9/XLZ8MFAqjh7U+lreYmmMUMaBW3R9AoEL2E8AMCHRyYW5zZmVyDBSlB7dGdv/td+dUuG7NmQnwus08ukFifVtSOAFCDEDh8zgTrGUXyzVX60wBCMyajNRfzFRiEPAe8CgGQ10bA2C3fnVz68Gw+Amgn5gmvuNfYKgWQ/W68Km1bYUPlnEYKQwhA86j4vgfGvk1ItKe3k8kofC+3q1ykzkdM4gPVHXZeHjJC0GVRA14" ], "id": 1 }, "Response": { @@ -695,7 +695,7 @@ "Request": { "jsonrpc": "2.0", "method": "submitblock", - "params": [ "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100010000" ], + "params": [ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAI+JfEVZZd6cjX2qJADFSuzRR40IzeV3K1zS9Q2wqetqI6hnvVQEAAAAAAAD6lrDvowCyjK9dBALCmE1fvMuahQEAARECAB2sK3wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHKYeUuiB1BN05kD4Gc0RjMFTshpwAABUESPn/oAQABEQ==" ], "id": 1 }, "Response": { diff --git a/tests/Neo.Network.RPC.Tests/UT_RpcClient.cs b/tests/Neo.Network.RPC.Tests/UT_RpcClient.cs index d2660aa4a..4f0b398ca 100644 --- a/tests/Neo.Network.RPC.Tests/UT_RpcClient.cs +++ b/tests/Neo.Network.RPC.Tests/UT_RpcClient.cs @@ -59,7 +59,7 @@ public async Task TestErrorResponse() var test = TestUtils.RpcTestCases.Find(p => p.Name == (nameof(rpc.SendRawTransactionAsync) + "error").ToLower()); try { - var result = await rpc.SendRawTransactionAsync(test.Request.Params[0].AsString().HexToBytes().AsSerializable()); + var result = await rpc.SendRawTransactionAsync(Convert.FromBase64String(test.Request.Params[0].AsString()).AsSerializable()); } catch (RpcException ex) { @@ -253,7 +253,7 @@ public async Task TestGetVersion() public async Task TestSendRawTransaction() { var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.SendRawTransactionAsync).ToLower()); - var result = await rpc.SendRawTransactionAsync(test.Request.Params[0].AsString().HexToBytes().AsSerializable()); + var result = await rpc.SendRawTransactionAsync(Convert.FromBase64String(test.Request.Params[0].AsString()).AsSerializable()); Assert.AreEqual(test.Response.Result["hash"].AsString(), result.ToString()); } @@ -261,8 +261,7 @@ public async Task TestSendRawTransaction() public async Task TestSubmitBlock() { var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.SubmitBlockAsync).ToLower()); - var block = TestUtils.GetBlock(2).Hash; - var result = await rpc.SubmitBlockAsync(test.Request.Params[0].AsString().HexToBytes()); + var result = await rpc.SubmitBlockAsync(Convert.FromBase64String(test.Request.Params[0].AsString())); Assert.AreEqual(test.Response.Result["hash"].AsString(), result.ToString()); } From f43c5abfeafae49d8ed84f4112a8f3fdd0c69c10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=BF=97=E5=90=8C?= Date: Fri, 13 Nov 2020 14:15:59 +0800 Subject: [PATCH 177/183] Modify container in GetInvokeResult method (#390) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fixed-bug-1021 * Update src/RpcServer/RpcServer.SmartContract.cs * 😂 * Modify container in GetInvokeResult method * . * Update src/RpcServer/RpcServer.SmartContract.cs Co-authored-by: cloud8little <34291844+cloud8little@users.noreply.github.com> Co-authored-by: Shargon Co-authored-by: cloud8little <34291844+cloud8little@users.noreply.github.com> --- src/RpcServer/RpcServer.SmartContract.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/RpcServer/RpcServer.SmartContract.cs b/src/RpcServer/RpcServer.SmartContract.cs index cba590ba3..9146c91d1 100644 --- a/src/RpcServer/RpcServer.SmartContract.cs +++ b/src/RpcServer/RpcServer.SmartContract.cs @@ -63,7 +63,13 @@ public void SerializeUnsigned(BinaryWriter writer) private JObject GetInvokeResult(byte[] script, Signers signers = null) { - using ApplicationEngine engine = ApplicationEngine.Run(script, container: signers, gas: settings.MaxGasInvoke); + Transaction tx = new Transaction + { + Signers = signers.GetSigners(), + Attributes = Array.Empty(), + Witnesses = signers.Witnesses, + }; + using ApplicationEngine engine = ApplicationEngine.Run(script, container: tx, gas: settings.MaxGasInvoke); JObject json = new JObject(); json["script"] = Convert.ToBase64String(script); json["state"] = engine.State; From 7cee1a45e1856ad4f6ed9f4ed3082e588351d581 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=BF=97=E5=90=8C?= Date: Mon, 16 Nov 2020 10:10:56 +0800 Subject: [PATCH 178/183] trigger type for getapplicationlog (#380) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fixed-bug-1021 * Update src/RpcServer/RpcServer.SmartContract.cs * 😂 * Keeping up to date with neo * Keeping up to date with neo * Revert "Keeping up to date with neo" This reverts commit aa8e120d3e7f81fd1cfaf6c495b15eed3eb66a21. * Prevent create key if not null * dotnet format * Query application log via blockhash * update * Modifying the Json storage structure * Modifying the JSON storage structure 2 * Additional optional "trigger" parameter to getapplicationlog for clients to be able to get just one execution result for a block. * Re-run checks * StrictUTF8 * Update src/ApplicationLogs/LogReader.cs Co-authored-by: Luchuan * Optimize Co-authored-by: Shargon Co-authored-by: Luchuan Co-authored-by: Vitor Nazário Coelho Co-authored-by: Owen Zhang <38493437+superboyiii@users.noreply.github.com> --- src/ApplicationLogs/LogReader.cs | 86 +++++++++++++++++++++++++++----- 1 file changed, 74 insertions(+), 12 deletions(-) diff --git a/src/ApplicationLogs/LogReader.cs b/src/ApplicationLogs/LogReader.cs index 9f26ec9a0..60eb903f9 100644 --- a/src/ApplicationLogs/LogReader.cs +++ b/src/ApplicationLogs/LogReader.cs @@ -3,6 +3,7 @@ using Neo.IO.Json; using Neo.Ledger; using Neo.Persistence; +using Neo.SmartContract; using Neo.VM; using System; using System.Collections.Generic; @@ -37,30 +38,46 @@ public JObject GetApplicationLog(JArray _params) UInt256 hash = UInt256.Parse(_params[0].AsString()); byte[] value = db.Get(ReadOptions.Default, hash.ToArray()); if (value is null) - throw new RpcException(-100, "Unknown transaction"); - return JObject.Parse(Encoding.UTF8.GetString(value)); + throw new RpcException(-100, "Unknown transaction/blockhash"); + + var raw = JObject.Parse(Utility.StrictUTF8.GetString(value)); + //Additional optional "trigger" parameter to getapplicationlog for clients to be able to get just one execution result for a block. + if (_params.Count >= 2 && Enum.TryParse(_params[1].AsString(), true, out TriggerType trigger)) + { + var executions = raw["executions"] as JArray; + for (int i = 0; i < executions.Count;) + { + if (!executions[i]["trigger"].AsString().Equals(trigger.ToString(), StringComparison.OrdinalIgnoreCase)) + executions.RemoveAt(i); + else + i++; + } + } + return raw; } public void OnPersist(StoreView snapshot, IReadOnlyList applicationExecutedList) { WriteBatch writeBatch = new WriteBatch(); - foreach (var appExec in applicationExecutedList) + //processing log for transactions + foreach (var appExec in applicationExecutedList.Where(p => p.Transaction != null)) { - JObject json = new JObject(); - json["txid"] = appExec.Transaction?.Hash.ToString(); - json["trigger"] = appExec.Trigger; - json["vmstate"] = appExec.VMState; - json["gasconsumed"] = appExec.GasConsumed.ToString(); + var txJson = new JObject(); + txJson["txid"] = appExec.Transaction.Hash.ToString(); + JObject trigger = new JObject(); + trigger["trigger"] = appExec.Trigger; + trigger["vmstate"] = appExec.VMState; + trigger["gasconsumed"] = appExec.GasConsumed.ToString(); try { - json["stack"] = appExec.Stack.Select(q => q.ToJson()).ToArray(); + trigger["stack"] = appExec.Stack.Select(q => q.ToJson()).ToArray(); } catch (InvalidOperationException) { - json["stack"] = "error: recursive reference"; + trigger["stack"] = "error: recursive reference"; } - json["notifications"] = appExec.Notifications.Select(q => + trigger["notifications"] = appExec.Notifications.Select(q => { JObject notification = new JObject(); notification["contract"] = q.ScriptHash.ToString(); @@ -75,7 +92,52 @@ public void OnPersist(StoreView snapshot, IReadOnlyList() { trigger }.ToArray(); + writeBatch.Put(appExec.Transaction.Hash.ToArray(), Utility.StrictUTF8.GetBytes(txJson.ToString())); + } + + //processing log for block + var blocks = applicationExecutedList.Where(p => p.Transaction == null); + if (blocks.Count() > 0) + { + var blockJson = new JObject(); + var blockHash = snapshot.PersistingBlock.Hash.ToArray(); + blockJson["blockhash"] = snapshot.PersistingBlock.Hash.ToString(); + var triggerList = new List(); + foreach (var appExec in blocks) + { + JObject trigger = new JObject(); + trigger["trigger"] = appExec.Trigger; + trigger["vmstate"] = appExec.VMState; + trigger["gasconsumed"] = appExec.GasConsumed.ToString(); + try + { + trigger["stack"] = appExec.Stack.Select(q => q.ToJson()).ToArray(); + } + catch (InvalidOperationException) + { + trigger["stack"] = "error: recursive reference"; + } + trigger["notifications"] = appExec.Notifications.Select(q => + { + JObject notification = new JObject(); + notification["contract"] = q.ScriptHash.ToString(); + notification["eventname"] = q.EventName; + try + { + notification["state"] = q.State.ToJson(); + } + catch (InvalidOperationException) + { + notification["state"] = "error: recursive reference"; + } + return notification; + }).ToArray(); + triggerList.Add(trigger); + } + blockJson["executions"] = triggerList.ToArray(); + writeBatch.Put(blockHash, Utility.StrictUTF8.GetBytes(blockJson.ToString())); } db.Write(WriteOptions.Default, writeBatch); } From 2ae6a9722b7a6a031943f92866d53c89b18b3433 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=BF=97=E5=90=8C?= Date: Mon, 16 Nov 2020 10:13:39 +0800 Subject: [PATCH 179/183] Update RpcApplicationLog.cs in RpcClient (#395) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fixed-bug-1021 * Update src/RpcServer/RpcServer.SmartContract.cs * 😂 * Update RpcApplicationLog.cs in RpcClient * update * Fixed UT * ??? * update * UT Co-authored-by: Shargon Co-authored-by: Owen Zhang <38493437+superboyiii@users.noreply.github.com> Co-authored-by: superboyiii <573504781@qq.com> --- src/RpcClient/Models/RpcApplicationLog.cs | 34 ++- src/RpcClient/RpcClient.cs | 11 + tests/Neo.Network.RPC.Tests/RpcTestCases.json | 258 +++++++++--------- tests/Neo.Network.RPC.Tests/UT_RpcClient.cs | 9 + 4 files changed, 176 insertions(+), 136 deletions(-) diff --git a/src/RpcClient/Models/RpcApplicationLog.cs b/src/RpcClient/Models/RpcApplicationLog.cs index 205835e9c..cfdfbcc7e 100644 --- a/src/RpcClient/Models/RpcApplicationLog.cs +++ b/src/RpcClient/Models/RpcApplicationLog.cs @@ -11,6 +11,34 @@ public class RpcApplicationLog { public UInt256 TxId { get; set; } + public UInt256 BlockHash { get; set; } + + public List Executions { get; set; } + + public JObject ToJson() + { + JObject json = new JObject(); + if (TxId != null) + json["txid"] = TxId.ToString(); + if (BlockHash != null) + json["blockhash"] = BlockHash.ToString(); + json["executions"] = Executions.Select(p => p.ToJson()).ToArray(); + return json; + } + + public static RpcApplicationLog FromJson(JObject json) + { + return new RpcApplicationLog + { + TxId = json["txid"] is null ? null : UInt256.Parse(json["txid"].AsString()), + BlockHash = json["blockhash"] is null ? null : UInt256.Parse(json["blockhash"].AsString()), + Executions = ((JArray)json["executions"]).Select(p => Execution.FromJson(p)).ToList(), + }; + } + } + + public class Execution + { public TriggerType Trigger { get; set; } public VMState VMState { get; set; } @@ -24,7 +52,6 @@ public class RpcApplicationLog public JObject ToJson() { JObject json = new JObject(); - json["txid"] = TxId?.ToString(); json["trigger"] = Trigger; json["vmstate"] = VMState; json["gasconsumed"] = GasConsumed.ToString(); @@ -33,11 +60,10 @@ public JObject ToJson() return json; } - public static RpcApplicationLog FromJson(JObject json) + public static Execution FromJson(JObject json) { - return new RpcApplicationLog + return new Execution { - TxId = json["txid"] is null ? null : UInt256.Parse(json["txid"].AsString()), Trigger = json["trigger"].TryGetEnum(), VMState = json["vmstate"].TryGetEnum(), GasConsumed = long.Parse(json["gasconsumed"].AsString()), diff --git a/src/RpcClient/RpcClient.cs b/src/RpcClient/RpcClient.cs index deba207ef..b5d2cf430 100644 --- a/src/RpcClient/RpcClient.cs +++ b/src/RpcClient/RpcClient.cs @@ -3,6 +3,7 @@ using Neo.Ledger; using Neo.Network.P2P.Payloads; using Neo.Network.RPC.Models; +using Neo.SmartContract; using Neo.SmartContract.Manifest; using System; using System.Collections.Generic; @@ -543,6 +544,16 @@ public async Task GetApplicationLogAsync(string txHash) return RpcApplicationLog.FromJson(result); } + /// + /// Returns the contract log based on the specified txHash. The complete contract logs are stored under the ApplicationLogs directory. + /// This method is provided by the plugin ApplicationLogs. + /// + public async Task GetApplicationLogAsync(string txHash, TriggerType triggerType) + { + var result = await RpcSendAsync(GetRpcName(), txHash, triggerType).ConfigureAwait(false); + return RpcApplicationLog.FromJson(result); + } + /// /// Returns all the NEP-5 transaction information occurred in the specified address. /// This method is provided by the plugin RpcNep5Tracker. diff --git a/tests/Neo.Network.RPC.Tests/RpcTestCases.json b/tests/Neo.Network.RPC.Tests/RpcTestCases.json index ebe32c8a5..5de1433b6 100644 --- a/tests/Neo.Network.RPC.Tests/RpcTestCases.json +++ b/tests/Neo.Network.RPC.Tests/RpcTestCases.json @@ -666,7 +666,7 @@ "jsonrpc": "2.0", "id": 1, "result": { - "magic": 0, + "magic": 0, "tcpport": 20333, "wsport": 20334, "nonce": 592651621, @@ -1201,162 +1201,156 @@ "Request": { "jsonrpc": "2.0", "method": "getapplicationlog", - "params": [ "0x183cd84359cd9f8b956afcd02403ec07361c1dba55f0800241b4ef2b28e88bbb" ], + "params": [ "0x6ea186fe714b8168ede3b78461db8945c06d867da649852352dbe7cbf1ba3724" ], "id": 1 }, "Response": { "jsonrpc": "2.0", - "id": "1", + "id": 1, "result": { - "txid": "0xe36f62923deb64376e5e982e19b60afc65faca8d9e8eb71ac12f7298ce32ef7b", - "trigger": "Application", - "vmstate": "HALT", - "gasconsumed": "5814860", - "stack": [ + "blockhash": "0x6ea186fe714b8168ede3b78461db8945c06d867da649852352dbe7cbf1ba3724", + "executions": [ { - "type": "Array", - "value": [ - { - "type": "Any" - }, - { - "type": "Integer", - "value": "1" - }, - { - "type": "Integer", - "value": "1223" - }, - { - "type": "ByteString", - "value": "dGVzdHFxd2FzZGFz" - }, - { - "type": "Buffer", - "value": "CAwiNQw=" - }, + "trigger": "OnPersist", + "vmstate": "HALT", + "gasconsumed": "2031260", + "stack": [], + "notifications": [ { - "type": "Array", - "value": [ - { - "type": "ByteString", - "value": "YWE=" - }, - { - "type": "ByteString", - "value": "YmI=" - }, - { - "type": "ByteString", - "value": "Y2Mw" - } - ] + "contract": "0x668e0c1f9d7b70a99dd9e06eadd4c784d641afbc", + "eventname": "Transfer", + "state": { + "type": "Array", + "value": [ + { + "type": "ByteString", + "value": "CqOHtT6Wt5iaYxQxoFbdH0CgQvY=" + }, + { + "type": "Any" + }, + { + "type": "Integer", + "value": "18083410" + } + ] + } }, { - "type": "Map", - "value": [ - { - "key": { - "type": "Integer", - "value": "2" + "contract": "0x668e0c1f9d7b70a99dd9e06eadd4c784d641afbc", + "eventname": "Transfer", + "state": { + "type": "Array", + "value": [ + { + "type": "Any" }, - "value": { + { + "type": "ByteString", + "value": "z6LDQN4w1uEMToIZiPSxToNRPog=" + }, + { "type": "Integer", - "value": "12" + "value": "1252390" } - }, - { - "key": { - "type": "Integer", - "value": "0" + ] + } + } + ] + }, + { + "trigger": "PostPersist", + "vmstate": "HALT", + "gasconsumed": "2031260", + "stack": [], + "notifications": [ + { + "contract": "0x668e0c1f9d7b70a99dd9e06eadd4c784d641afbc", + "eventname": "Transfer", + "state": { + "type": "Array", + "value": [ + { + "type": "Any" }, - "value": { + { + "type": "ByteString", + "value": "z6LDQN4w1uEMToIZiPSxToNRPog=" + }, + { "type": "Integer", - "value": "24" + "value": "50000000" } - } - ] + ] + } } ] } - ], - "notifications": [ + ] + } + } + }, + { + "Name": "getapplicationlogasync_triggertype", + "Request": { + "jsonrpc": "2.0", + "method": "getapplicationlog", + "params": [ "0x6ea186fe714b8168ede3b78461db8945c06d867da649852352dbe7cbf1ba3724", "OnPersist" ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": { + "blockhash": "0x6ea186fe714b8168ede3b78461db8945c06d867da649852352dbe7cbf1ba3724", + "executions": [ { - "contract": "0xbfe215933f29b29dacf0e8383722a62974ac8aa6", - "eventname": "event_name", - "state": { - "type": "Array", - "value": [ - { + "trigger": "OnPersist", + "vmstate": "HALT", + "gasconsumed": "2031260", + "stack": [], + "notifications": [ + { + "contract": "0x668e0c1f9d7b70a99dd9e06eadd4c784d641afbc", + "eventname": "Transfer", + "state": { "type": "Array", "value": [ { - "type": "Array", - "value": [ - { - "type": "Integer", - "value": "1" - }, - { - "type": "Integer", - "value": "1223" - }, - { - "type": "ByteString", - "value": "dGVzdHFxd2FzZGFz" - }, - { - "type": "Buffer", - "value": "CAwiNQw=" - }, - { - "type": "Array", - "value": [ - { - "type": "ByteString", - "value": "YWE=" - }, - { - "type": "ByteString", - "value": "YmI=" - }, - { - "type": "ByteString", - "value": "Y2Mw" - } - ] - }, - { - "type": "Map", - "value": [ - { - "key": { - "type": "Integer", - "value": "2" - }, - "value": { - "type": "Integer", - "value": "12" - } - }, - { - "key": { - "type": "Integer", - "value": "0" - }, - "value": { - "type": "Integer", - "value": "24" - } - } - ] - } - ] + "type": "ByteString", + "value": "CqOHtT6Wt5iaYxQxoFbdH0CgQvY=" + }, + { + "type": "Any" + }, + { + "type": "Integer", + "value": "18083410" } ] } - ] - } + }, + { + "contract": "0x668e0c1f9d7b70a99dd9e06eadd4c784d641afbc", + "eventname": "Transfer", + "state": { + "type": "Array", + "value": [ + { + "type": "Any" + }, + { + "type": "ByteString", + "value": "z6LDQN4w1uEMToIZiPSxToNRPog=" + }, + { + "type": "Integer", + "value": "1252390" + } + ] + } + } + ] } ] } diff --git a/tests/Neo.Network.RPC.Tests/UT_RpcClient.cs b/tests/Neo.Network.RPC.Tests/UT_RpcClient.cs index 4f0b398ca..b558ef201 100644 --- a/tests/Neo.Network.RPC.Tests/UT_RpcClient.cs +++ b/tests/Neo.Network.RPC.Tests/UT_RpcClient.cs @@ -6,6 +6,7 @@ using Neo.IO.Json; using Neo.Network.P2P.Payloads; using Neo.Network.RPC.Models; +using Neo.SmartContract; using System; using System.Linq; using System.Net; @@ -421,6 +422,14 @@ public async Task GetApplicationLogTest() Assert.AreEqual(test.Response.Result.ToString(), result.ToJson().ToString()); } + [TestMethod()] + public async Task GetApplicationLogTest_TriggerType() + { + var test = TestUtils.RpcTestCases.Find(p => p.Name == (nameof(rpc.GetApplicationLogAsync) + "_triggertype").ToLower()); + var result = await rpc.GetApplicationLogAsync(test.Request.Params[0].AsString(), TriggerType.OnPersist); + Assert.AreEqual(test.Response.Result.ToString(), result.ToJson().ToString()); + } + [TestMethod()] public async Task GetNep5TransfersTest() { From f13d7c305f02f77aa48cc579f678a96e4f319a25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=BF=97=E5=90=8C?= Date: Wed, 18 Nov 2020 10:54:58 +0800 Subject: [PATCH 180/183] Update LogReader.cs (#401) * Update LogReader.cs * update --- src/ApplicationLogs/LogReader.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/ApplicationLogs/LogReader.cs b/src/ApplicationLogs/LogReader.cs index 60eb903f9..8e6f551d5 100644 --- a/src/ApplicationLogs/LogReader.cs +++ b/src/ApplicationLogs/LogReader.cs @@ -68,6 +68,7 @@ public void OnPersist(StoreView snapshot, IReadOnlyList Date: Fri, 20 Nov 2020 18:03:01 +0800 Subject: [PATCH 181/183] [RpcServer] Update RpcServer.SmartContract.cs (#400) * Update RpcServer.SmartContract.cs * Update src/RpcServer/RpcServer.SmartContract.cs Co-authored-by: Shargon * update Co-authored-by: Owen Zhang <38493437+superboyiii@users.noreply.github.com> Co-authored-by: Shargon --- src/RpcServer/RpcServer.SmartContract.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/RpcServer/RpcServer.SmartContract.cs b/src/RpcServer/RpcServer.SmartContract.cs index 9146c91d1..4fed465ad 100644 --- a/src/RpcServer/RpcServer.SmartContract.cs +++ b/src/RpcServer/RpcServer.SmartContract.cs @@ -63,7 +63,7 @@ public void SerializeUnsigned(BinaryWriter writer) private JObject GetInvokeResult(byte[] script, Signers signers = null) { - Transaction tx = new Transaction + Transaction tx = signers == null ? null : new Transaction { Signers = signers.GetSigners(), Attributes = Array.Empty(), From 85bd7c371324897a20f5a7cf73ac2ece10d9f10f Mon Sep 17 00:00:00 2001 From: Harry Pierson Date: Mon, 23 Nov 2020 02:15:58 -0800 Subject: [PATCH 182/183] use shared directory.build.props file (#403) * use shared directory.build.props file * Update src/LevelDBStore/LevelDBStore.csproj Co-authored-by: Erik Zhang * Update src/RocksDBStore/RocksDBStore.csproj Co-authored-by: Erik Zhang * Update src/RocksDBStore/RocksDBStore.csproj Co-authored-by: Erik Zhang * CR Feedback * Fix namespace Co-authored-by: Harry Co-authored-by: Erik Zhang Co-authored-by: Harry Pierson --- src/ApplicationLogs/ApplicationLogs.csproj | 3 +-- src/Directory.Build.props | 21 +++++++++++++++++++++ src/LevelDBStore/LevelDBStore.csproj | 9 ++------- src/RocksDBStore/RocksDBStore.csproj | 4 +--- src/RpcClient/RpcClient.csproj | 14 +------------- src/RpcNep5Tracker/RpcNep5Tracker.csproj | 3 +-- src/RpcServer/RpcServer.csproj | 4 +--- src/StatesDumper/StatesDumper.csproj | 5 +---- 8 files changed, 29 insertions(+), 34 deletions(-) create mode 100644 src/Directory.Build.props diff --git a/src/ApplicationLogs/ApplicationLogs.csproj b/src/ApplicationLogs/ApplicationLogs.csproj index 5318c84ca..007129f40 100644 --- a/src/ApplicationLogs/ApplicationLogs.csproj +++ b/src/ApplicationLogs/ApplicationLogs.csproj @@ -1,8 +1,7 @@ - 3.0.0-preview3 - netstandard2.1 + Neo.Plugins.ApplicationLogs Neo.Plugins diff --git a/src/Directory.Build.props b/src/Directory.Build.props new file mode 100644 index 000000000..44d252790 --- /dev/null +++ b/src/Directory.Build.props @@ -0,0 +1,21 @@ + + + + + 3.0.0 + preview3 + netstandard2.1 + Neo.Plugins + The Neo Project + NEO;Blockchain + https://github.com/neo-project/neo-modules + MIT + git + https://github.com/neo-project/neo-modules.git + + + + + + + \ No newline at end of file diff --git a/src/LevelDBStore/LevelDBStore.csproj b/src/LevelDBStore/LevelDBStore.csproj index 2acba8102..d49bce97d 100644 --- a/src/LevelDBStore/LevelDBStore.csproj +++ b/src/LevelDBStore/LevelDBStore.csproj @@ -1,9 +1,8 @@ - 3.0.0-preview3 - netstandard2.1 - Neo + Neo.Plugins.Storage.LevelDBStore + Neo.Plugins.Storage true @@ -14,8 +13,4 @@ - - - - diff --git a/src/RocksDBStore/RocksDBStore.csproj b/src/RocksDBStore/RocksDBStore.csproj index 8cace3405..e1f5bad60 100644 --- a/src/RocksDBStore/RocksDBStore.csproj +++ b/src/RocksDBStore/RocksDBStore.csproj @@ -1,8 +1,7 @@ - 3.0.0-preview3 - netstandard2.1 + Neo.Plugins.Storage.RocksDBStore Neo.Plugins.Storage @@ -14,7 +13,6 @@ - diff --git a/src/RpcClient/RpcClient.csproj b/src/RpcClient/RpcClient.csproj index d687d0cce..d2f535e5e 100644 --- a/src/RpcClient/RpcClient.csproj +++ b/src/RpcClient/RpcClient.csproj @@ -1,20 +1,8 @@ - 3.0.0-preview3 - netstandard2.1 - Neo.Network.RPC - The Neo Project Neo.Network.RPC.RpcClient - NEO;Blockchain - https://github.com/neo-project/neo-modules - MIT - git - https://github.com/neo-project/neo-modules.git + Neo.Network.RPC - - - - diff --git a/src/RpcNep5Tracker/RpcNep5Tracker.csproj b/src/RpcNep5Tracker/RpcNep5Tracker.csproj index 7a9a6764e..403f4a12a 100644 --- a/src/RpcNep5Tracker/RpcNep5Tracker.csproj +++ b/src/RpcNep5Tracker/RpcNep5Tracker.csproj @@ -1,7 +1,6 @@ - 3.0.0-preview3 - netstandard2.1 + Neo.Plugins.RpcNep5Tracker Neo.Plugins diff --git a/src/RpcServer/RpcServer.csproj b/src/RpcServer/RpcServer.csproj index eafe5d8d5..9ce3d9e1c 100644 --- a/src/RpcServer/RpcServer.csproj +++ b/src/RpcServer/RpcServer.csproj @@ -1,8 +1,7 @@  - 3.0.0-preview3 - netstandard2.1 + Neo.Plugins.RpcServer Neo.Plugins @@ -15,7 +14,6 @@ - diff --git a/src/StatesDumper/StatesDumper.csproj b/src/StatesDumper/StatesDumper.csproj index ee9be372a..c361bbf96 100644 --- a/src/StatesDumper/StatesDumper.csproj +++ b/src/StatesDumper/StatesDumper.csproj @@ -1,9 +1,7 @@ - 3.0.0-preview3 - netstandard2.1 - Neo.Plugins + Neo.Plugins.StatesDumper @@ -14,7 +12,6 @@ - From e8a69c460be235cd9f10de3d1a2667b150252a52 Mon Sep 17 00:00:00 2001 From: Harry Pierson Date: Tue, 24 Nov 2020 12:49:56 -0800 Subject: [PATCH 183/183] create helper applog JSON functions for reuse in neo-express (#402) * create helper applog JSON functions for reuse in neo-express * Update LogReader.cs (#401) * Update LogReader.cs * update Co-authored-by: Harry --- src/ApplicationLogs/LogReader.cs | 89 +++++++++++++++++++------------- 1 file changed, 54 insertions(+), 35 deletions(-) diff --git a/src/ApplicationLogs/LogReader.cs b/src/ApplicationLogs/LogReader.cs index 8e6f551d5..90c772691 100644 --- a/src/ApplicationLogs/LogReader.cs +++ b/src/ApplicationLogs/LogReader.cs @@ -56,49 +56,47 @@ public JObject GetApplicationLog(JArray _params) return raw; } - public void OnPersist(StoreView snapshot, IReadOnlyList applicationExecutedList) + public static JObject TxLogToJson(Blockchain.ApplicationExecuted appExec) { - WriteBatch writeBatch = new WriteBatch(); - - //processing log for transactions - foreach (var appExec in applicationExecutedList.Where(p => p.Transaction != null)) + global::System.Diagnostics.Debug.Assert(appExec.Transaction != null); + + var txJson = new JObject(); + txJson["txid"] = appExec.Transaction.Hash.ToString(); + JObject trigger = new JObject(); + trigger["trigger"] = appExec.Trigger; + trigger["vmstate"] = appExec.VMState; + trigger["exception"] = GetExceptionMessage(appExec.Exception); + trigger["gasconsumed"] = appExec.GasConsumed.ToString(); + try { - var txJson = new JObject(); - txJson["txid"] = appExec.Transaction.Hash.ToString(); - JObject trigger = new JObject(); - trigger["trigger"] = appExec.Trigger; - trigger["vmstate"] = appExec.VMState; - trigger["exception"] = GetExceptionMessage(appExec.Exception); - trigger["gasconsumed"] = appExec.GasConsumed.ToString(); + trigger["stack"] = appExec.Stack.Select(q => q.ToJson()).ToArray(); + } + catch (InvalidOperationException) + { + trigger["stack"] = "error: recursive reference"; + } + trigger["notifications"] = appExec.Notifications.Select(q => + { + JObject notification = new JObject(); + notification["contract"] = q.ScriptHash.ToString(); + notification["eventname"] = q.EventName; try { - trigger["stack"] = appExec.Stack.Select(q => q.ToJson()).ToArray(); + notification["state"] = q.State.ToJson(); } catch (InvalidOperationException) { - trigger["stack"] = "error: recursive reference"; + notification["state"] = "error: recursive reference"; } - trigger["notifications"] = appExec.Notifications.Select(q => - { - JObject notification = new JObject(); - notification["contract"] = q.ScriptHash.ToString(); - notification["eventname"] = q.EventName; - try - { - notification["state"] = q.State.ToJson(); - } - catch (InvalidOperationException) - { - notification["state"] = "error: recursive reference"; - } - return notification; - }).ToArray(); + return notification; + }).ToArray(); - txJson["executions"] = new List() { trigger }.ToArray(); - writeBatch.Put(appExec.Transaction.Hash.ToArray(), Utility.StrictUTF8.GetBytes(txJson.ToString())); - } + txJson["executions"] = new List() { trigger }.ToArray(); + return txJson; + } - //processing log for block + public static JObject BlockLogToJson(StoreView snapshot, IReadOnlyList applicationExecutedList) + { var blocks = applicationExecutedList.Where(p => p.Transaction == null); if (blocks.Count() > 0) { @@ -138,7 +136,28 @@ public void OnPersist(StoreView snapshot, IReadOnlyList applicationExecutedList) + { + WriteBatch writeBatch = new WriteBatch(); + + //processing log for transactions + foreach (var appExec in applicationExecutedList.Where(p => p.Transaction != null)) + { + var txJson = TxLogToJson(appExec); + writeBatch.Put(appExec.Transaction.Hash.ToArray(), Utility.StrictUTF8.GetBytes(txJson.ToString())); + } + + //processing log for block + var blockJson = BlockLogToJson(snapshot, applicationExecutedList); + if (blockJson != null) + { + writeBatch.Put(snapshot.PersistingBlock.Hash.ToArray(), Utility.StrictUTF8.GetBytes(blockJson.ToString())); } db.Write(WriteOptions.Default, writeBatch); } @@ -152,7 +171,7 @@ public bool ShouldThrowExceptionFromCommit(Exception ex) return false; } - string GetExceptionMessage(Exception exception) + static string GetExceptionMessage(Exception exception) { if (exception == null) return "Engine faulted.";