From 38cc0e9384a31f3b492225a190c38aba72d7c7f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=BF=97=E5=90=8C?= Date: Fri, 7 Jun 2024 15:31:45 +0000 Subject: [PATCH 01/71] Fix error when vc_redist is missing (#3293) * Update MainService.cs * Update src/Neo.CLI/CLI/MainService.cs --------- Co-authored-by: Jimmy --- src/Neo.CLI/CLI/MainService.cs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/Neo.CLI/CLI/MainService.cs b/src/Neo.CLI/CLI/MainService.cs index 1d349df320..7e96af9e85 100644 --- a/src/Neo.CLI/CLI/MainService.cs +++ b/src/Neo.CLI/CLI/MainService.cs @@ -375,7 +375,18 @@ public async void Start(CommandLineOptions options) ProtocolSettings protocol = ProtocolSettings.Load("config.json"); CustomProtocolSettings(options, protocol); CustomApplicationSettings(options, Settings.Default); - NeoSystem = new NeoSystem(protocol, Settings.Default.Storage.Engine, string.Format(Settings.Default.Storage.Path, protocol.Network.ToString("X8"))); + try + { + NeoSystem = new NeoSystem(protocol, Settings.Default.Storage.Engine, string.Format(Settings.Default.Storage.Path, protocol.Network.ToString("X8"))); + } + catch (DllNotFoundException) + { + ConsoleHelper.Error("DLL not found, please install Microsoft Visual C++ Redistributable." + Environment.NewLine + + "See https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist" + Environment.NewLine + + "Press any key to exit."); + Console.ReadKey(); + Environment.Exit(-1); + } NeoSystem.AddService(this); LocalNode = NeoSystem.LocalNode.Ask(new LocalNode.GetInstance()).Result; From b68ad5126ab20c7224fa023052947cf36b65d2a3 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Tue, 11 Jun 2024 11:13:57 +0800 Subject: [PATCH 02/71] [Neo Plugin Bug]fix 3296 (#3299) * fix 3296 * Update src/Plugins/ApplicationLogs/Store/LogStorageStore.cs * add exception message to the incorrect storeitem * optimize the code to apply Hecate suggestion * revert change to the exception info * clean using --------- Co-authored-by: Shargon --- src/Plugins/ApplicationLogs/Store/LogStorageStore.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Plugins/ApplicationLogs/Store/LogStorageStore.cs b/src/Plugins/ApplicationLogs/Store/LogStorageStore.cs index 249c5d3bd1..147a80034b 100644 --- a/src/Plugins/ApplicationLogs/Store/LogStorageStore.cs +++ b/src/Plugins/ApplicationLogs/Store/LogStorageStore.cs @@ -159,7 +159,7 @@ public Guid PutStackItemState(StackItem stackItem) { _snapshot.Put(key, BinarySerializer.Serialize(stackItem, ExecutionEngineLimits.Default with { MaxItemSize = (uint)Settings.Default.MaxStackSize })); } - catch (NotSupportedException) + catch { _snapshot.Put(key, BinarySerializer.Serialize(StackItem.Null, ExecutionEngineLimits.Default with { MaxItemSize = (uint)Settings.Default.MaxStackSize })); } From 5cf744632be95eedd2570a10999e129ea6168960 Mon Sep 17 00:00:00 2001 From: Anna Shaleva Date: Tue, 11 Jun 2024 06:42:58 +0300 Subject: [PATCH 03/71] SmartContract: use executing contract state to check permissions (#3290) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's not correct to use an updated contract state got from native Management to check for the allowed method call. We need to use manifest from the currently executing context for that. It may be critical for cases when executing contract is being updated firstly, and after that it calls another contract. So we need an old (executing) contract manifest for this check. This change is moved under D hardfork to avoid state diff issues on nodes update. Although it should be noted that it's hard to meet the trigger criteria. A port of https://github.com/nspcc-dev/neo-go/pull/3473. This bug was discovered during the similar problem described in https://github.com/nspcc-dev/neo-go/issues/3471 and fixed in https://github.com/nspcc-dev/neo-go/pull/3472. I've checked all other similar usages and the rest of them use proper contract state (executing one, not the Management's one). Signed-off-by: Anna Shaleva Co-authored-by: Shargon Co-authored-by: Jimmy Co-authored-by: Vitor Nazário Coelho --- src/Neo/Hardfork.cs | 3 +- src/Neo/SmartContract/ApplicationEngine.cs | 10 +- .../SmartContract/UT_ApplicationEngine.cs | 101 ++++++++++++++++++ .../SmartContract/UT_InteropService.cs | 26 ++++- .../SmartContract/UT_Syscalls.cs | 2 +- 5 files changed, 135 insertions(+), 7 deletions(-) diff --git a/src/Neo/Hardfork.cs b/src/Neo/Hardfork.cs index 9ef6a63c1c..7bd3cc0aef 100644 --- a/src/Neo/Hardfork.cs +++ b/src/Neo/Hardfork.cs @@ -15,6 +15,7 @@ public enum Hardfork : byte { HF_Aspidochelone, HF_Basilisk, - HF_Cockatrice + HF_Cockatrice, + HF_Domovoi } } diff --git a/src/Neo/SmartContract/ApplicationEngine.cs b/src/Neo/SmartContract/ApplicationEngine.cs index 8602eb054d..fab17a2bb1 100644 --- a/src/Neo/SmartContract/ApplicationEngine.cs +++ b/src/Neo/SmartContract/ApplicationEngine.cs @@ -286,14 +286,18 @@ private ExecutionContext CallContractInternal(ContractState contract, ContractMe if (NativeContract.Policy.IsBlocked(Snapshot, contract.Hash)) throw new InvalidOperationException($"The contract {contract.Hash} has been blocked."); + ExecutionContext currentContext = CurrentContext; + ExecutionContextState state = currentContext.GetState(); if (method.Safe) { flags &= ~(CallFlags.WriteStates | CallFlags.AllowNotify); } else { - ContractState currentContract = NativeContract.ContractManagement.GetContract(Snapshot, CurrentScriptHash); - if (currentContract?.CanCall(contract, method.Name) == false) + var executingContract = IsHardforkEnabled(Hardfork.HF_Domovoi) + ? state.Contract // use executing contract state to avoid possible contract update/destroy side-effects, ref. https://github.com/neo-project/neo/pull/3290. + : NativeContract.ContractManagement.GetContract(Snapshot, CurrentScriptHash); + if (executingContract?.CanCall(contract, method.Name) == false) throw new InvalidOperationException($"Cannot Call Method {method.Name} Of Contract {contract.Hash} From Contract {CurrentScriptHash}"); } @@ -306,8 +310,6 @@ private ExecutionContext CallContractInternal(ContractState contract, ContractMe invocationCounter[contract.Hash] = 1; } - ExecutionContext currentContext = CurrentContext; - ExecutionContextState state = currentContext.GetState(); CallFlags callingFlags = state.CallFlags; if (args.Count != method.Parameters.Length) throw new InvalidOperationException($"Method {method} Expects {method.Parameters.Length} Arguments But Receives {args.Count} Arguments"); diff --git a/tests/Neo.UnitTests/SmartContract/UT_ApplicationEngine.cs b/tests/Neo.UnitTests/SmartContract/UT_ApplicationEngine.cs index 7639377fe1..0969e12776 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_ApplicationEngine.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_ApplicationEngine.cs @@ -12,6 +12,9 @@ using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.SmartContract; +using Neo.SmartContract.Manifest; +using Neo.UnitTests.Extensions; +using Neo.VM; using System; using System.Collections.Immutable; using System.Linq; @@ -103,5 +106,103 @@ public void TestCheckingHardfork() (setting[sortedHardforks[i]] > setting[sortedHardforks[i + 1]]).Should().Be(false); } } + + [TestMethod] + public void TestSystem_Contract_Call_Permissions() + { + UInt160 scriptHash; + var snapshot = TestBlockchain.GetTestSnapshot(); + + // Setup: put a simple contract to the storage. + using (var script = new ScriptBuilder()) + { + // Push True on stack and return. + script.EmitPush(true); + script.Emit(OpCode.RET); + + // Mock contract and put it to the Managemant's storage. + scriptHash = script.ToArray().ToScriptHash(); + + snapshot.DeleteContract(scriptHash); + var contract = TestUtils.GetContract(script.ToArray(), TestUtils.CreateManifest("test", ContractParameterType.Any)); + contract.Manifest.Abi.Methods = new[] + { + new ContractMethodDescriptor + { + Name = "disallowed", + Parameters = new ContractParameterDefinition[]{} + }, + new ContractMethodDescriptor + { + Name = "test", + Parameters = new ContractParameterDefinition[]{} + } + }; + snapshot.AddContract(scriptHash, contract); + } + + // Disallowed method call. + using (var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, null, ProtocolSettings.Default)) + using (var script = new ScriptBuilder()) + { + // Build call script calling disallowed method. + script.EmitDynamicCall(scriptHash, "disallowed"); + + // Mock executing state to be a contract-based. + engine.LoadScript(script.ToArray()); + engine.CurrentContext.GetState().Contract = new() + { + Manifest = new() + { + Abi = new() { }, + Permissions = new ContractPermission[] + { + new ContractPermission + { + Contract = ContractPermissionDescriptor.Create(scriptHash), + Methods = WildcardContainer.Create(new string[]{"test"}) // allowed to call only "test" method of the target contract. + } + } + } + }; + var currentScriptHash = engine.EntryScriptHash; + + Assert.AreEqual(VMState.FAULT, engine.Execute()); + Assert.IsTrue(engine.FaultException.ToString().Contains($"Cannot Call Method disallowed Of Contract {scriptHash.ToString()}")); + } + + // Allowed method call. + using (var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, null, ProtocolSettings.Default)) + using (var script = new ScriptBuilder()) + { + // Build call script. + script.EmitDynamicCall(scriptHash, "test"); + + // Mock executing state to be a contract-based. + engine.LoadScript(script.ToArray()); + engine.CurrentContext.GetState().Contract = new() + { + Manifest = new() + { + Abi = new() { }, + Permissions = new ContractPermission[] + { + new ContractPermission + { + Contract = ContractPermissionDescriptor.Create(scriptHash), + Methods = WildcardContainer.Create(new string[]{"test"}) // allowed to call only "test" method of the target contract. + } + } + } + }; + var currentScriptHash = engine.EntryScriptHash; + + Assert.AreEqual(VMState.HALT, engine.Execute()); + Assert.AreEqual(1, engine.ResultStack.Count); + Assert.IsInstanceOfType(engine.ResultStack.Peek(), typeof(VM.Types.Boolean)); + var res = (VM.Types.Boolean)engine.ResultStack.Pop(); + Assert.IsTrue(res.GetBoolean()); + } + } } } diff --git a/tests/Neo.UnitTests/SmartContract/UT_InteropService.cs b/tests/Neo.UnitTests/SmartContract/UT_InteropService.cs index 0e9916b7d5..51f26d22eb 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_InteropService.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_InteropService.cs @@ -71,6 +71,14 @@ public void Runtime_GetNotifications_Test() } } }; + contract.Manifest.Permissions = new ContractPermission[] + { + new ContractPermission + { + Contract = ContractPermissionDescriptor.Create(scriptHash2), + Methods = WildcardContainer.Create(new string[]{"test"}) + } + }; snapshot.AddContract(scriptHash2, contract); } @@ -133,6 +141,14 @@ public void Runtime_GetNotifications_Test() Parameters = System.Array.Empty() } } + }, + Permissions = new ContractPermission[] + { + new ContractPermission + { + Contract = ContractPermissionDescriptor.Create(scriptHash2), + Methods = WildcardContainer.Create(new string[]{"test"}) + } } } }; @@ -202,6 +218,14 @@ public void Runtime_GetNotifications_Test() Parameters = System.Array.Empty() } } + }, + Permissions = new ContractPermission[] + { + new ContractPermission + { + Contract = ContractPermissionDescriptor.Create(scriptHash2), + Methods = WildcardContainer.Create(new string[]{"test"}) + } } } }; @@ -642,7 +666,7 @@ public void TestContract_Call() var args = new VM.Types.Array { 0, 1 }; var state = TestUtils.GetContract(method, args.Count); - var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot); + var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, null, ProtocolSettings.Default); engine.LoadScript(new byte[] { 0x01 }); engine.Snapshot.AddContract(state.Hash, state); diff --git a/tests/Neo.UnitTests/SmartContract/UT_Syscalls.cs b/tests/Neo.UnitTests/SmartContract/UT_Syscalls.cs index 0a98b5fd66..7791b8acef 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_Syscalls.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_Syscalls.cs @@ -257,7 +257,7 @@ public void System_Runtime_GetInvocationCounter() // Execute - var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot); + var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, null, ProtocolSettings.Default); engine.LoadScript(script.ToArray()); Assert.AreEqual(VMState.HALT, engine.Execute()); From b1d27f0189861167b8005a7e40e6d8500fb48cc4 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Tue, 11 Jun 2024 12:19:21 +0800 Subject: [PATCH 04/71] [Neo Core Bug]fix 3300 (#3301) * fix 3300 * update format * add state subitems to ref counter, with suggestion from DuSmart * apply hardfork * format * my mistake * fix hardfork * remove negative check * add unit test * apply anna's suggestion --------- Co-authored-by: Shargon Co-authored-by: NGD Admin <154295625+NGDAdmin@users.noreply.github.com> --- .../ApplicationEngine.Runtime.cs | 11 ++++-- src/Neo/SmartContract/NotifyEventArgs.cs | 28 ++++++++++++--- .../SmartContract/UT_NotifyEventArgs.cs | 34 +++++++++++++++++++ 3 files changed, 66 insertions(+), 7 deletions(-) diff --git a/src/Neo/SmartContract/ApplicationEngine.Runtime.cs b/src/Neo/SmartContract/ApplicationEngine.Runtime.cs index b39fd55a01..e54529f6d1 100644 --- a/src/Neo/SmartContract/ApplicationEngine.Runtime.cs +++ b/src/Neo/SmartContract/ApplicationEngine.Runtime.cs @@ -407,14 +407,19 @@ protected internal void SendNotification(UInt160 hash, string eventName, Array s /// /// The hash of the specified contract. It can be set to to get all notifications. /// The notifications sent during the execution. - protected internal NotifyEventArgs[] GetNotifications(UInt160 hash) + protected internal Array GetNotifications(UInt160 hash) { IEnumerable notifications = Notifications; if (hash != null) // must filter by scriptHash notifications = notifications.Where(p => p.ScriptHash == hash); - NotifyEventArgs[] array = notifications.ToArray(); + var array = notifications.ToArray(); if (array.Length > Limits.MaxStackSize) throw new InvalidOperationException(); - return array; + Array notifyArray = new(ReferenceCounter); + foreach (var notify in array) + { + notifyArray.Add(notify.ToStackItem(ReferenceCounter, this)); + } + return notifyArray; } /// diff --git a/src/Neo/SmartContract/NotifyEventArgs.cs b/src/Neo/SmartContract/NotifyEventArgs.cs index 93c124ea88..257efb3a66 100644 --- a/src/Neo/SmartContract/NotifyEventArgs.cs +++ b/src/Neo/SmartContract/NotifyEventArgs.cs @@ -66,11 +66,31 @@ public void FromStackItem(StackItem stackItem) public StackItem ToStackItem(ReferenceCounter referenceCounter) { return new Array(referenceCounter) + { + ScriptHash.ToArray(), + EventName, + State + }; + } + + public StackItem ToStackItem(ReferenceCounter referenceCounter, ApplicationEngine engine) + { + if (engine.IsHardforkEnabled(Hardfork.HF_Domovoi)) { - ScriptHash.ToArray(), - EventName, - State - }; + return new Array(referenceCounter) + { + ScriptHash.ToArray(), + EventName, + State.OnStack ? State : State.DeepCopy(true) + }; + } + + return new Array(referenceCounter) + { + ScriptHash.ToArray(), + EventName, + State + }; } } } diff --git a/tests/Neo.UnitTests/SmartContract/UT_NotifyEventArgs.cs b/tests/Neo.UnitTests/SmartContract/UT_NotifyEventArgs.cs index fdaeb9106e..59afbbb760 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_NotifyEventArgs.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_NotifyEventArgs.cs @@ -13,6 +13,8 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.Network.P2P.Payloads; using Neo.SmartContract; +using Neo.VM; +using Neo.VM.Types; namespace Neo.UnitTests.SmartContract { @@ -27,5 +29,37 @@ public void TestGetScriptContainer() NotifyEventArgs args = new NotifyEventArgs(container, script_hash, "Test", null); args.ScriptContainer.Should().Be(container); } + + + [TestMethod] + public void TestIssue3300() // https://github.com/neo-project/neo/issues/3300 + { + using var engine = ApplicationEngine.Create(TriggerType.Application, null, null, settings: TestProtocolSettings.Default, gas: 1100_00000000); + using (var script = new ScriptBuilder()) + { + // Build call script calling disallowed method. + script.Emit(OpCode.NOP); + // Mock executing state to be a contract-based. + engine.LoadScript(script.ToArray()); + } + + var ns = new Array(engine.ReferenceCounter); + for (var i = 0; i < 500; i++) + { + ns.Add(""); + }; + + var hash = UInt160.Parse("0x179ab5d297fd34ecd48643894242fc3527f42853"); + engine.SendNotification(hash, "Test", ns); + // This should have being 0, but we have optimized the vm to not clean the reference counter + // unless it is necessary, so the reference counter will be 1000. + // Same reason why its 1504 instead of 504. + Assert.AreEqual(1000, engine.ReferenceCounter.Count); + // This will make a deepcopy for the notification, along with the 500 state items. + engine.GetNotifications(hash); + // With the fix of issue 3300, the reference counter calculates not only + // the notifaction items, but also the subitems of the notification state. + Assert.AreEqual(1504, engine.ReferenceCounter.Count); + } } } From ef77a4c43ffe29e6c3439eed071d8b43224ce4d5 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Fri, 14 Jun 2024 06:13:43 +0300 Subject: [PATCH 05/71] fix plugin download url (#3329) --- src/Neo.CLI/Settings.cs | 2 +- src/Neo.CLI/config.fs.mainnet.json | 2 +- src/Neo.CLI/config.fs.testnet.json | 2 +- src/Neo.CLI/config.json | 2 +- src/Neo.CLI/config.mainnet.json | 2 +- src/Neo.CLI/config.testnet.json | 2 +- tests/Neo.Plugins.OracleService.Tests/config.json | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Neo.CLI/Settings.cs b/src/Neo.CLI/Settings.cs index ecc38115c3..7687b8cbda 100644 --- a/src/Neo.CLI/Settings.cs +++ b/src/Neo.CLI/Settings.cs @@ -165,7 +165,7 @@ public ContractsSettings() { } public class PluginsSettings { - public Uri DownloadUrl { get; init; } = new("https://api.github.com/repos/neo-project/neo-modules/releases"); + public Uri DownloadUrl { get; init; } = new("https://api.github.com/repos/neo-project/neo/releases"); public bool Prerelease { get; init; } = false; public Version Version { get; init; } = Assembly.GetExecutingAssembly().GetName().Version!; diff --git a/src/Neo.CLI/config.fs.mainnet.json b/src/Neo.CLI/config.fs.mainnet.json index 6adb47eb03..f629dc3aac 100644 --- a/src/Neo.CLI/config.fs.mainnet.json +++ b/src/Neo.CLI/config.fs.mainnet.json @@ -24,7 +24,7 @@ "NeoNameService": "0x7061fbd31562664b58f422c3dee4acfd70dba8af" }, "Plugins": { - "DownloadUrl": "https://api.github.com/repos/neo-project/neo-modules/releases" + "DownloadUrl": "https://api.github.com/repos/neo-project/neo/releases" } }, "ProtocolConfiguration": { diff --git a/src/Neo.CLI/config.fs.testnet.json b/src/Neo.CLI/config.fs.testnet.json index ca0f0225e6..4e9468e2c6 100644 --- a/src/Neo.CLI/config.fs.testnet.json +++ b/src/Neo.CLI/config.fs.testnet.json @@ -24,7 +24,7 @@ "NeoNameService": "0xfb08ccf30ab534a871b7b092a49fe70c154ed678" }, "Plugins": { - "DownloadUrl": "https://api.github.com/repos/neo-project/neo-modules/releases" + "DownloadUrl": "https://api.github.com/repos/neo-project/neo/releases" } }, "ProtocolConfiguration": { diff --git a/src/Neo.CLI/config.json b/src/Neo.CLI/config.json index c9544a337f..87e38b2efe 100644 --- a/src/Neo.CLI/config.json +++ b/src/Neo.CLI/config.json @@ -24,7 +24,7 @@ "NeoNameService": "0x50ac1c37690cc2cfc594472833cf57505d5f46de" }, "Plugins": { - "DownloadUrl": "https://api.github.com/repos/neo-project/neo-modules/releases" + "DownloadUrl": "https://api.github.com/repos/neo-project/neo/releases" } }, "ProtocolConfiguration": { diff --git a/src/Neo.CLI/config.mainnet.json b/src/Neo.CLI/config.mainnet.json index a32cad5ad5..821eb364f5 100644 --- a/src/Neo.CLI/config.mainnet.json +++ b/src/Neo.CLI/config.mainnet.json @@ -24,7 +24,7 @@ "NeoNameService": "0x50ac1c37690cc2cfc594472833cf57505d5f46de" }, "Plugins": { - "DownloadUrl": "https://api.github.com/repos/neo-project/neo-modules/releases" + "DownloadUrl": "https://api.github.com/repos/neo-project/neo/releases" } }, "ProtocolConfiguration": { diff --git a/src/Neo.CLI/config.testnet.json b/src/Neo.CLI/config.testnet.json index 4350fc62f2..ee28108c3e 100644 --- a/src/Neo.CLI/config.testnet.json +++ b/src/Neo.CLI/config.testnet.json @@ -24,7 +24,7 @@ "NeoNameService": "0x50ac1c37690cc2cfc594472833cf57505d5f46de" }, "Plugins": { - "DownloadUrl": "https://api.github.com/repos/neo-project/neo-modules/releases" + "DownloadUrl": "https://api.github.com/repos/neo-project/neo/releases" } }, "ProtocolConfiguration": { diff --git a/tests/Neo.Plugins.OracleService.Tests/config.json b/tests/Neo.Plugins.OracleService.Tests/config.json index b4800b80ea..67bc3a62fa 100644 --- a/tests/Neo.Plugins.OracleService.Tests/config.json +++ b/tests/Neo.Plugins.OracleService.Tests/config.json @@ -24,7 +24,7 @@ "NeoNameService": "0x50ac1c37690cc2cfc594472833cf57505d5f46de" }, "Plugins": { - "DownloadUrl": "https://api.github.com/repos/neo-project/neo-modules/releases" + "DownloadUrl": "https://api.github.com/repos/neo-project/neo/releases" } }, "ProtocolConfiguration": { From 4c1194f3c47c3d673605b6e1913f12af9a807711 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Fri, 14 Jun 2024 06:22:14 +0300 Subject: [PATCH 06/71] [Neo CLI Optimization] fix exception message (#3314) * fix exception message * add detailed check * Update src/Neo.CLI/CLI/MainService.cs * directly send them to release page * update msg. * fix its readibility * fix issue * use shared library to replace DLL on macos --------- Co-authored-by: Shargon Co-authored-by: NGD Admin <154295625+NGDAdmin@users.noreply.github.com> --- src/Neo.CLI/CLI/MainService.cs | 49 +++++++++++++++++++++++++++++----- 1 file changed, 43 insertions(+), 6 deletions(-) diff --git a/src/Neo.CLI/CLI/MainService.cs b/src/Neo.CLI/CLI/MainService.cs index 7e96af9e85..88967c82ea 100644 --- a/src/Neo.CLI/CLI/MainService.cs +++ b/src/Neo.CLI/CLI/MainService.cs @@ -33,6 +33,7 @@ using System.Net; using System.Numerics; using System.Reflection; +using System.Runtime.InteropServices; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; @@ -377,16 +378,41 @@ public async void Start(CommandLineOptions options) CustomApplicationSettings(options, Settings.Default); try { - NeoSystem = new NeoSystem(protocol, Settings.Default.Storage.Engine, string.Format(Settings.Default.Storage.Path, protocol.Network.ToString("X8"))); + NeoSystem = new NeoSystem(protocol, Settings.Default.Storage.Engine, + string.Format(Settings.Default.Storage.Path, protocol.Network.ToString("X8"))); + } + catch (DllNotFoundException ex) when (ex.Message.Contains("libleveldb")) + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + if (File.Exists("libleveldb.dll")) + { + DisplayError("Dependency DLL not found, please install Microsoft Visual C++ Redistributable.", + "See https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist"); + } + else + { + DisplayError("DLL not found, please get libleveldb.dll."); + } + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + DisplayError("Shared library libleveldb.dylib not found, please get libleveldb.dylib.", + "From https://github.com/neo-project/neo/releases"); + } + else + { + DisplayError("Neo CLI is broken, please reinstall it.", + "From https://github.com/neo-project/neo/releases"); + } + } catch (DllNotFoundException) { - ConsoleHelper.Error("DLL not found, please install Microsoft Visual C++ Redistributable." + Environment.NewLine + - "See https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist" + Environment.NewLine + - "Press any key to exit."); - Console.ReadKey(); - Environment.Exit(-1); + DisplayError("Neo CLI is broken, please reinstall it.", + "From https://github.com/neo-project/neo/releases"); } + NeoSystem.AddService(this); LocalNode = NeoSystem.LocalNode.Ask(new LocalNode.GetInstance()).Result; @@ -459,6 +485,17 @@ public async void Start(CommandLineOptions options) ConsoleHelper.Error(ex.GetBaseException().Message); } } + + return; + + void DisplayError(string primaryMessage, string? secondaryMessage = null) + { + ConsoleHelper.Error(primaryMessage + Environment.NewLine + + (secondaryMessage != null ? secondaryMessage + Environment.NewLine : "") + + "Press any key to exit."); + Console.ReadKey(); + Environment.Exit(-1); + } } public void Stop() From a6dff238742e7c43fbee6f85120c0ae7fb22d48f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vitor=20Naz=C3=A1rio=20Coelho?= Date: Fri, 14 Jun 2024 00:40:25 -0300 Subject: [PATCH 07/71] Return expect to verify neo-cli (#3318) * Return expect to verify neo-cli * Create test-neo-cli.expect * Organize * Update test-neo-cli.expect * Update test-neo-cli.expect * Update main.yml * Update main.yml * Try to improve path and dependencies install * Depencies are needed for each task * Break lines * Script path * Organize script folder --------- Co-authored-by: NGD Admin <154295625+NGDAdmin@users.noreply.github.com> --- .github/workflows/main.yml | 38 ++++++++++++- scripts/Neo.CLI/test-neo-cli.expect | 86 +++++++++++++++++++++++++++++ 2 files changed, 122 insertions(+), 2 deletions(-) create mode 100644 scripts/Neo.CLI/test-neo-cli.expect diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index dca46dbbd6..e12760e019 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -24,11 +24,30 @@ jobs: - name: Check Format (*.cs) run: dotnet format --verify-no-changes --verbosity diagnostic + Build-Test-Neo-Cli: + needs: [Format] + timeout-minutes: 15 + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: ${{ env.DOTNET_VERSION }} + - name: Build (Neo.CLI) + run: dotnet build ./src/Neo.CLI --output ./out/Neo.CLI + + - name: Install dependencies run: | - dotnet build ./src/Neo.CLI \ - --output ./out/Neo.CLI + sudo apt-get install libleveldb-dev expect + find ./out -name 'config.json' | xargs perl -pi -e 's|LevelDBStore|MemoryStore|g' + - name: Run tests with expect + run: expect ./scripts/Neo.CLI/test-neo-cli.expect + Test: needs: [Format] timeout-minutes: 15 @@ -39,15 +58,18 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4 + - name: Setup .NET uses: actions/setup-dotnet@v4 with: dotnet-version: ${{ env.DOTNET_VERSION }} + - name: Test if: matrix.os != 'ubuntu-latest' run: | dotnet sln neo.sln remove ./tests/Neo.Plugins.Storage.Tests/Neo.Plugins.Storage.Tests.csproj dotnet test + - name: Test for coverall if: matrix.os == 'ubuntu-latest' run: | @@ -139,14 +161,17 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4 + - name: Get version id: get_version run: | sudo apt install xmlstarlet find src -name Directory.Build.props | xargs xmlstarlet sel -N i=http://schemas.microsoft.com/developer/msbuild/2003 -t -v "concat('::set-output name=version::v',//i:VersionPrefix/text())" | xargs echo + - name: Check tag id: check_tag run: curl -s -I ${{ format('https://github.com/{0}/releases/tag/{1}', github.repository, steps.get_version.outputs.version) }} | head -n 1 | cut -d$' ' -f2 | xargs printf "::set-output name=statusCode::%s" | xargs echo + - name: Create release if: steps.check_tag.outputs.statusCode == '404' id: create_release @@ -157,53 +182,62 @@ jobs: tag_name: ${{ steps.get_version.outputs.version }} release_name: ${{ steps.get_version.outputs.version }} prerelease: ${{ contains(steps.get_version.outputs.version, '-') }} + - name: Setup .NET if: steps.check_tag.outputs.statusCode == '404' uses: actions/setup-dotnet@v4 with: dotnet-version: ${{ env.DOTNET_VERSION }} + - name : Pack (Neo) if: steps.check_tag.outputs.statusCode == '404' run: | dotnet pack ./src/Neo \ --configuration Release \ --output ./out + - name : Pack (Neo.IO) if: steps.check_tag.outputs.statusCode == '404' run: | dotnet pack ./src/Neo.IO \ --configuration Release \ --output ./out + - name : Pack (Neo.Extensions) if: steps.check_tag.outputs.statusCode == '404' run: | dotnet pack ./src/Neo.Extensions \ --configuration Release \ --output ./out + - name : Pack (Neo.Json) if: steps.check_tag.outputs.statusCode == '404' run: | dotnet pack ./src/Neo.Json \ --configuration Release \ --output ./out + - name : Pack (Neo.VM) if: steps.check_tag.outputs.statusCode == '404' run: | dotnet pack ./src/Neo.VM \ --configuration Release \ --output ./out + - name : Pack (Neo.ConsoleService) if: steps.check_tag.outputs.statusCode == '404' run: | dotnet pack ./src/Neo.ConsoleService \ --configuration Release \ --output ./out + - name : Pack (Neo.Cryptography.BLS12_381) if: steps.check_tag.outputs.statusCode == '404' run: | dotnet pack ./src/Neo.Cryptography.BLS12_381 \ --configuration Release \ --output ./out + - name: Publish to NuGet if: steps.check_tag.outputs.statusCode == '404' run: | diff --git a/scripts/Neo.CLI/test-neo-cli.expect b/scripts/Neo.CLI/test-neo-cli.expect new file mode 100644 index 0000000000..8319c18f8e --- /dev/null +++ b/scripts/Neo.CLI/test-neo-cli.expect @@ -0,0 +1,86 @@ +#!/usr/bin/expect -f +# +# This script uses expect to test neo-cli +# +set timeout 10 + + +# Start neo-cli +spawn dotnet out/Neo.CLI/neo-cli.dll + +# Expect the main input prompt +expect { + "neo> " { } + "error" { exit 2 } + timeout { exit 1 } +} + +# +# Test 'create wallet' +# +send "create wallet test-wallet1.json\n" + +expect { + "password:" { send "asd\n" } + "error" { exit 2 } + timeout { exit 1 } +} + +expect { + "password:" { send "asd\n" } + "error" { exit 2 } + timeout { exit 1 } +} + +expect { + " Address:" { } + "error" { exit 2 } + timeout { exit 1 } +} + + +# +# Test 'create wallet' +# +send "create wallet test-wallet2.json L2ArHTuiDL4FHu4nfyhamrG8XVYB4QyRbmhj7vD6hFMB5iAMSTf6\n" + +expect { + "password:" { send "abcd\n" } + "error" { exit 2 } + timeout { exit 1 } +} + +expect { + "password:" { send "abcd\n" } + "error" { exit 2 } + timeout { exit 1 } +} + +expect { + "NUj249PQg9EMJfAuxKizdJwMG7GSBzYX2Y" { } + "error" { exit 2 } + timeout { exit 1 } +} + +# +# Test 'list address' +# +send "list address\n" + +expect { + "neo> " { } + "error" { exit 2 } + timeout { exit 1 } +} + +# +# Test 'create address' +# +send "create address\n" + +expect { + "neo> " { } + "error" { exit 2 } + timeout { exit 1 } +} +exit 0 From e0ba8974fe0cf76e8d2b4916557503e924fefa83 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Fri, 14 Jun 2024 09:41:00 +0300 Subject: [PATCH 08/71] [Neo CLI New Feature] Allow custom plugins (#3295) * allow custom plugins * use command instead. --------- Co-authored-by: Shargon Co-authored-by: NGD Admin <154295625+NGDAdmin@users.noreply.github.com> --- src/Neo.CLI/CLI/MainService.Plugins.cs | 23 ++++++++++++++--------- src/Neo.CLI/Settings.cs | 1 + src/Neo.CLI/config.json | 4 ++-- src/Neo.CLI/config.json.md | 10 +++++----- 4 files changed, 22 insertions(+), 16 deletions(-) diff --git a/src/Neo.CLI/CLI/MainService.Plugins.cs b/src/Neo.CLI/CLI/MainService.Plugins.cs index a73cdcb31e..761dd386d2 100644 --- a/src/Neo.CLI/CLI/MainService.Plugins.cs +++ b/src/Neo.CLI/CLI/MainService.Plugins.cs @@ -32,8 +32,9 @@ partial class MainService /// Process "install" command /// /// Plugin name + /// Custom plugins download url, this is optional. [ConsoleCommand("install", Category = "Plugin Commands")] - private void OnInstallCommand(string pluginName) + private void OnInstallCommand(string pluginName, string? downloadUrl = null) { if (PluginExists(pluginName)) { @@ -41,7 +42,7 @@ private void OnInstallCommand(string pluginName) return; } - var result = InstallPluginAsync(pluginName).GetAwaiter().GetResult(); + var result = InstallPluginAsync(pluginName, downloadUrl).GetAwaiter().GetResult(); if (result) { var asmName = Assembly.GetExecutingAssembly().GetName().Name; @@ -74,16 +75,17 @@ private void OnReinstallCommand(string pluginName) /// /// name of the plugin /// + /// Custom plugin download url. /// /// Downloaded content - private static async Task DownloadPluginAsync(string pluginName, Version pluginVersion, bool prerelease = false) + private static async Task DownloadPluginAsync(string pluginName, Version pluginVersion, string? customDownloadUrl = null, bool prerelease = false) { using var httpClient = new HttpClient(); var asmName = Assembly.GetExecutingAssembly().GetName(); httpClient.DefaultRequestHeaders.UserAgent.Add(new(asmName.Name!, asmName.Version!.ToString(3))); - - var json = await httpClient.GetFromJsonAsync(Settings.Default.Plugins.DownloadUrl) ?? throw new HttpRequestException($"Failed: {Settings.Default.Plugins.DownloadUrl}"); + var url = customDownloadUrl == null ? Settings.Default.Plugins.DownloadUrl : new Uri(customDownloadUrl); + var json = await httpClient.GetFromJsonAsync(url) ?? throw new HttpRequestException($"Failed: {url}"); var jsonRelease = json.AsArray() .SingleOrDefault(s => s != null && @@ -110,10 +112,12 @@ private static async Task DownloadPluginAsync(string pluginName, Version /// Install plugin from stream /// /// Name of the plugin + /// Custom plugins download url. /// Dependency set /// Install by force for `update` private async Task InstallPluginAsync( string pluginName, + string? downloadUrl = null, HashSet? installed = null, bool overWrite = false) { @@ -124,14 +128,14 @@ private async Task InstallPluginAsync( try { - using var stream = await DownloadPluginAsync(pluginName, Settings.Default.Plugins.Version, Settings.Default.Plugins.Prerelease); + using var stream = await DownloadPluginAsync(pluginName, Settings.Default.Plugins.Version, downloadUrl, Settings.Default.Plugins.Prerelease); using var zip = new ZipArchive(stream, ZipArchiveMode.Read); var entry = zip.Entries.FirstOrDefault(p => p.Name == "config.json"); if (entry is not null) { await using var es = entry.Open(); - await InstallDependenciesAsync(es, installed); + await InstallDependenciesAsync(es, installed, downloadUrl); } zip.ExtractToDirectory("./", true); return true; @@ -148,7 +152,8 @@ private async Task InstallPluginAsync( /// /// plugin config path in temp /// Dependency set - private async Task InstallDependenciesAsync(Stream config, HashSet installed) + /// Custom plugin download url. + private async Task InstallDependenciesAsync(Stream config, HashSet installed, string? downloadUrl = null) { var dependency = new ConfigurationBuilder() .AddJsonStream(config) @@ -162,7 +167,7 @@ private async Task InstallDependenciesAsync(Stream config, HashSet insta foreach (var plugin in dependencies.Where(p => p is not null && !PluginExists(p))) { ConsoleHelper.Info($"Installing dependency: {plugin}"); - await InstallPluginAsync(plugin!, installed); + await InstallPluginAsync(plugin!, downloadUrl, installed); } } diff --git a/src/Neo.CLI/Settings.cs b/src/Neo.CLI/Settings.cs index 7687b8cbda..e831d15ebd 100644 --- a/src/Neo.CLI/Settings.cs +++ b/src/Neo.CLI/Settings.cs @@ -13,6 +13,7 @@ using Neo.Network.P2P; using Neo.Persistence; using System; +using System.Linq; using System.Reflection; using System.Threading; diff --git a/src/Neo.CLI/config.json b/src/Neo.CLI/config.json index 87e38b2efe..821eb364f5 100644 --- a/src/Neo.CLI/config.json +++ b/src/Neo.CLI/config.json @@ -6,8 +6,8 @@ "Active": false }, "Storage": { - "Engine": "LevelDBStore", // Candidates [MemoryStore, LevelDBStore, RocksDBStore] - "Path": "Data_LevelDB_{0}" // {0} is a placeholder for the network id + "Engine": "LevelDBStore", + "Path": "Data_LevelDB_{0}" }, "P2P": { "Port": 10333, diff --git a/src/Neo.CLI/config.json.md b/src/Neo.CLI/config.json.md index da3bbaec6e..b32b1f2f8f 100644 --- a/src/Neo.CLI/config.json.md +++ b/src/Neo.CLI/config.json.md @@ -1,6 +1,6 @@ # README for Application and Protocol Configuration JSON File -This README provides an explanation for each field in the JSON configuration file for a NEO node. +This README provides an explanation for each field in the JSON configuration file for a Neo node. ## ApplicationConfiguration @@ -31,15 +31,15 @@ This README provides an explanation for each field in the JSON configuration fil - **NeoNameService**: Script hash of the Neo Name Service contract. MainNet is `0x50ac1c37690cc2cfc594472833cf57505d5f46de`, TestNet is `0x50ac1c37690cc2cfc594472833cf57505d5f46de`. ### Plugins -- **DownloadUrl**: URL to download plugins, typically from the NEO project's GitHub releases. Default is `https://api.github.com/repos/neo-project/neo/releases`. +- **DownloadUrl**: URL to download plugins, typically from the Neo project's GitHub releases. Default is `https://api.github.com/repos/neo-project/neo/releases`. ## ProtocolConfiguration ### Network -- **Network**: Network ID for the NEO network. MainNet is `860833102`, TestNet is `894710606` +- **Network**: Network ID for the Neo network. MainNet is `860833102`, TestNet is `894710606` ### AddressVersion -- **AddressVersion**: Version byte used in NEO address generation. Default is `53`. +- **AddressVersion**: Version byte used in Neo address generation. Default is `53`. ### MillisecondsPerBlock - **MillisecondsPerBlock**: Time interval between blocks in milliseconds. Default is `15000` (15 seconds). @@ -82,4 +82,4 @@ This README provides an explanation for each field in the JSON configuration fil - `seed4t5.neo.org:20333` - `seed5t5.neo.org:20333` -This configuration file is essential for setting up and running a NEO node, ensuring proper logging, storage, network connectivity, and consensus protocol parameters. +This configuration file is essential for setting up and running a Neo node, ensuring proper logging, storage, network connectivity, and consensus protocol parameters. From efbdc94c541ccc70c09e5dd745bb73e2160e6312 Mon Sep 17 00:00:00 2001 From: Christopher Schuchardt Date: Fri, 14 Jun 2024 03:28:38 -0400 Subject: [PATCH 09/71] Fixed pathing and Property (#3306) Co-authored-by: Shargon Co-authored-by: NGD Admin <154295625+NGDAdmin@users.noreply.github.com> --- src/Neo.CLI/Neo.CLI.csproj | 2 +- src/Neo.ConsoleService/Neo.ConsoleService.csproj | 2 +- .../Neo.Cryptography.BLS12_381.csproj | 2 +- src/Neo.Extensions/Neo.Extensions.csproj | 2 +- src/Neo.GUI/Neo.GUI.csproj | 2 +- src/Neo.IO/Neo.IO.csproj | 2 +- src/Neo.Json/Neo.Json.csproj | 2 +- src/Neo.VM/Neo.VM.csproj | 2 +- src/Neo/Neo.csproj | 2 +- src/Plugins/ApplicationLogs/ApplicationLogs.csproj | 2 +- src/Plugins/DBFTPlugin/DBFTPlugin.csproj | 2 +- src/Plugins/LevelDBStore/LevelDBStore.csproj | 2 +- src/Plugins/MPTTrie/MPTTrie.csproj | 2 +- src/Plugins/OracleService/OracleService.csproj | 2 +- src/Plugins/RocksDBStore/RocksDBStore.csproj | 2 +- src/Plugins/RpcClient/RpcClient.csproj | 2 +- src/Plugins/RpcServer/RpcServer.csproj | 2 +- src/Plugins/SQLiteWallet/SQLiteWallet.csproj | 2 +- src/Plugins/StateService/StateService.csproj | 2 +- src/Plugins/StorageDumper/StorageDumper.csproj | 2 +- src/Plugins/TokensTracker/TokensTracker.csproj | 2 +- 21 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/Neo.CLI/Neo.CLI.csproj b/src/Neo.CLI/Neo.CLI.csproj index a9d4c9919e..f3f319d358 100644 --- a/src/Neo.CLI/Neo.CLI.csproj +++ b/src/Neo.CLI/Neo.CLI.csproj @@ -10,7 +10,7 @@ Neo.CLI neo.ico enable - $(SolutionDir)/bin/$(AssemblyTitle) + ../../bin/$(AssemblyTitle) diff --git a/src/Neo.ConsoleService/Neo.ConsoleService.csproj b/src/Neo.ConsoleService/Neo.ConsoleService.csproj index 9b3ad32dfe..b4254a4cad 100644 --- a/src/Neo.ConsoleService/Neo.ConsoleService.csproj +++ b/src/Neo.ConsoleService/Neo.ConsoleService.csproj @@ -4,7 +4,7 @@ netstandard2.1;net8.0 Neo.ConsoleService enable - $(SolutionDir)/bin/$(PackageId) + ../../bin/$(PackageId) diff --git a/src/Neo.Cryptography.BLS12_381/Neo.Cryptography.BLS12_381.csproj b/src/Neo.Cryptography.BLS12_381/Neo.Cryptography.BLS12_381.csproj index d5313d9eab..f74c9f1ec0 100644 --- a/src/Neo.Cryptography.BLS12_381/Neo.Cryptography.BLS12_381.csproj +++ b/src/Neo.Cryptography.BLS12_381/Neo.Cryptography.BLS12_381.csproj @@ -6,7 +6,7 @@ enable enable Neo.Cryptography.BLS12_381 - $(SolutionDir)/bin/$(PackageId) + ../../bin/$(PackageId) diff --git a/src/Neo.Extensions/Neo.Extensions.csproj b/src/Neo.Extensions/Neo.Extensions.csproj index c6d549be6a..a7f4870568 100644 --- a/src/Neo.Extensions/Neo.Extensions.csproj +++ b/src/Neo.Extensions/Neo.Extensions.csproj @@ -5,7 +5,7 @@ enable Neo.Extensions NEO;Blockchain;Extensions - $(SolutionDir)/bin/$(PackageId) + ../../bin/$(PackageId) diff --git a/src/Neo.GUI/Neo.GUI.csproj b/src/Neo.GUI/Neo.GUI.csproj index 014459be4c..078434fc13 100644 --- a/src/Neo.GUI/Neo.GUI.csproj +++ b/src/Neo.GUI/Neo.GUI.csproj @@ -11,7 +11,7 @@ Neo.GUI neo.ico false - $(SolutionDir)/bin/$(AssemblyTitle) + ../../bin/$(AssemblyTitle) diff --git a/src/Neo.IO/Neo.IO.csproj b/src/Neo.IO/Neo.IO.csproj index a1a0a9ea2e..a51ec1110a 100644 --- a/src/Neo.IO/Neo.IO.csproj +++ b/src/Neo.IO/Neo.IO.csproj @@ -6,7 +6,7 @@ enable Neo.IO NEO;Blockchain;IO - $(SolutionDir)/bin/$(PackageId) + ../../bin/$(PackageId) diff --git a/src/Neo.Json/Neo.Json.csproj b/src/Neo.Json/Neo.Json.csproj index 3d75276dec..15924436e7 100644 --- a/src/Neo.Json/Neo.Json.csproj +++ b/src/Neo.Json/Neo.Json.csproj @@ -6,7 +6,7 @@ enable Neo.Json NEO;JSON - $(SolutionDir)/bin/$(PackageId) + ../../bin/$(PackageId) diff --git a/src/Neo.VM/Neo.VM.csproj b/src/Neo.VM/Neo.VM.csproj index 9315a850df..eb137b623a 100644 --- a/src/Neo.VM/Neo.VM.csproj +++ b/src/Neo.VM/Neo.VM.csproj @@ -5,7 +5,7 @@ true enable Neo.VM - $(SolutionDir)/bin/$(PackageId) + ../../bin/$(PackageId) diff --git a/src/Neo/Neo.csproj b/src/Neo/Neo.csproj index 707b94fa4c..835224eddd 100644 --- a/src/Neo/Neo.csproj +++ b/src/Neo/Neo.csproj @@ -5,7 +5,7 @@ true Neo NEO;AntShares;Blockchain;Smart Contract - $(SolutionDir)/bin/$(PackageId) + ../../bin/$(PackageId) diff --git a/src/Plugins/ApplicationLogs/ApplicationLogs.csproj b/src/Plugins/ApplicationLogs/ApplicationLogs.csproj index 4529b946af..0d01281c6a 100644 --- a/src/Plugins/ApplicationLogs/ApplicationLogs.csproj +++ b/src/Plugins/ApplicationLogs/ApplicationLogs.csproj @@ -4,7 +4,7 @@ Neo.Plugins.ApplicationLogs Neo.Plugins enable - $(SolutionDir)/bin/$(PackageId) + ../../../bin/$(PackageId) diff --git a/src/Plugins/DBFTPlugin/DBFTPlugin.csproj b/src/Plugins/DBFTPlugin/DBFTPlugin.csproj index 68595be53a..93c77ad1f8 100644 --- a/src/Plugins/DBFTPlugin/DBFTPlugin.csproj +++ b/src/Plugins/DBFTPlugin/DBFTPlugin.csproj @@ -4,7 +4,7 @@ net8.0 Neo.Consensus.DBFT Neo.Consensus - $(SolutionDir)/bin/$(PackageId) + ../../../bin/$(PackageId) diff --git a/src/Plugins/LevelDBStore/LevelDBStore.csproj b/src/Plugins/LevelDBStore/LevelDBStore.csproj index ef605a7afe..23cf469640 100644 --- a/src/Plugins/LevelDBStore/LevelDBStore.csproj +++ b/src/Plugins/LevelDBStore/LevelDBStore.csproj @@ -5,7 +5,7 @@ Neo.Plugins.Storage.LevelDBStore Neo.Plugins.Storage true - $(SolutionDir)/bin/$(PackageId) + ../../../bin/$(PackageId) diff --git a/src/Plugins/MPTTrie/MPTTrie.csproj b/src/Plugins/MPTTrie/MPTTrie.csproj index ef9e45cc51..3134f7ae5b 100644 --- a/src/Plugins/MPTTrie/MPTTrie.csproj +++ b/src/Plugins/MPTTrie/MPTTrie.csproj @@ -5,7 +5,7 @@ Neo.Cryptography.MPT Neo.Cryptography true - $(SolutionDir)/bin/$(PackageId) + ../../../bin/$(PackageId) diff --git a/src/Plugins/OracleService/OracleService.csproj b/src/Plugins/OracleService/OracleService.csproj index 1fa5c5602f..bb5cde6754 100644 --- a/src/Plugins/OracleService/OracleService.csproj +++ b/src/Plugins/OracleService/OracleService.csproj @@ -3,7 +3,7 @@ net8.0 Neo.Plugins.OracleService - $(SolutionDir)/bin/$(PackageId) + ../../../bin/$(PackageId) diff --git a/src/Plugins/RocksDBStore/RocksDBStore.csproj b/src/Plugins/RocksDBStore/RocksDBStore.csproj index 441b17306e..d23f089160 100644 --- a/src/Plugins/RocksDBStore/RocksDBStore.csproj +++ b/src/Plugins/RocksDBStore/RocksDBStore.csproj @@ -4,7 +4,7 @@ net8.0 Neo.Plugins.Storage.RocksDBStore Neo.Plugins.Storage - $(SolutionDir)/bin/$(PackageId) + ../../../bin/$(PackageId) diff --git a/src/Plugins/RpcClient/RpcClient.csproj b/src/Plugins/RpcClient/RpcClient.csproj index c43c71ef8a..bc6161e3cb 100644 --- a/src/Plugins/RpcClient/RpcClient.csproj +++ b/src/Plugins/RpcClient/RpcClient.csproj @@ -4,7 +4,7 @@ net8.0 Neo.Network.RPC.RpcClient Neo.Network.RPC - $(SolutionDir)/bin/$(PackageId) + ../../../bin/$(PackageId) diff --git a/src/Plugins/RpcServer/RpcServer.csproj b/src/Plugins/RpcServer/RpcServer.csproj index 3fb7a7bb9a..c5b72e7a61 100644 --- a/src/Plugins/RpcServer/RpcServer.csproj +++ b/src/Plugins/RpcServer/RpcServer.csproj @@ -3,7 +3,7 @@ net8.0 Neo.Plugins.RpcServer - $(SolutionDir)/bin/$(PackageId) + ../../../bin/$(PackageId) diff --git a/src/Plugins/SQLiteWallet/SQLiteWallet.csproj b/src/Plugins/SQLiteWallet/SQLiteWallet.csproj index 4c9029040f..041233af79 100644 --- a/src/Plugins/SQLiteWallet/SQLiteWallet.csproj +++ b/src/Plugins/SQLiteWallet/SQLiteWallet.csproj @@ -5,7 +5,7 @@ Neo.Wallets.SQLite Neo.Wallets.SQLite enable - $(SolutionDir)/bin/$(PackageId) + ../../../bin/$(PackageId) diff --git a/src/Plugins/StateService/StateService.csproj b/src/Plugins/StateService/StateService.csproj index 2bf85f1465..58c18ac498 100644 --- a/src/Plugins/StateService/StateService.csproj +++ b/src/Plugins/StateService/StateService.csproj @@ -4,7 +4,7 @@ net8.0 Neo.Plugins.StateService true - $(SolutionDir)/bin/$(PackageId) + ../../../bin/$(PackageId) diff --git a/src/Plugins/StorageDumper/StorageDumper.csproj b/src/Plugins/StorageDumper/StorageDumper.csproj index 7805140f3e..ebadda6136 100644 --- a/src/Plugins/StorageDumper/StorageDumper.csproj +++ b/src/Plugins/StorageDumper/StorageDumper.csproj @@ -5,7 +5,7 @@ Neo.Plugins.StorageDumper enable enable - $(SolutionDir)/bin/$(PackageId) + ../../../bin/$(PackageId) diff --git a/src/Plugins/TokensTracker/TokensTracker.csproj b/src/Plugins/TokensTracker/TokensTracker.csproj index bdacd3839c..5f17120159 100644 --- a/src/Plugins/TokensTracker/TokensTracker.csproj +++ b/src/Plugins/TokensTracker/TokensTracker.csproj @@ -3,7 +3,7 @@ net8.0 Neo.Plugins.TokensTracker - $(SolutionDir)/bin/$(PackageId) + ../../../bin/$(PackageId) From cf6c46d58291cff3b9c40d9eb076f44239a45cf4 Mon Sep 17 00:00:00 2001 From: Owen <38493437+superboyiii@users.noreply.github.com> Date: Tue, 18 Jun 2024 10:20:12 +0800 Subject: [PATCH 10/71] sync v3.7.5 (#3342) --- src/Neo.CLI/config.fs.mainnet.json | 3 ++- src/Neo.CLI/config.json | 3 ++- src/Neo.CLI/config.mainnet.json | 3 ++- src/Neo.CLI/config.testnet.json | 3 ++- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/Neo.CLI/config.fs.mainnet.json b/src/Neo.CLI/config.fs.mainnet.json index f629dc3aac..3ec4eda871 100644 --- a/src/Neo.CLI/config.fs.mainnet.json +++ b/src/Neo.CLI/config.fs.mainnet.json @@ -39,7 +39,8 @@ "Hardforks": { "HF_Aspidochelone": 3000000, "HF_Basilisk": 4500000, - "HF_Cockatrice": 5800000 + "HF_Cockatrice": 5800000, + "HF_Domovoi": 5800000 }, "StandbyCommittee": [ "026fa34ec057d74c2fdf1a18e336d0bd597ea401a0b2ad57340d5c220d09f44086", diff --git a/src/Neo.CLI/config.json b/src/Neo.CLI/config.json index 821eb364f5..772a221714 100644 --- a/src/Neo.CLI/config.json +++ b/src/Neo.CLI/config.json @@ -37,7 +37,8 @@ "Hardforks": { "HF_Aspidochelone": 1730000, "HF_Basilisk": 4120000, - "HF_Cockatrice": 5450000 + "HF_Cockatrice": 5450000, + "HF_Domovoi": 5570000 }, "InitialGasDistribution": 5200000000000000, "ValidatorsCount": 7, diff --git a/src/Neo.CLI/config.mainnet.json b/src/Neo.CLI/config.mainnet.json index 821eb364f5..772a221714 100644 --- a/src/Neo.CLI/config.mainnet.json +++ b/src/Neo.CLI/config.mainnet.json @@ -37,7 +37,8 @@ "Hardforks": { "HF_Aspidochelone": 1730000, "HF_Basilisk": 4120000, - "HF_Cockatrice": 5450000 + "HF_Cockatrice": 5450000, + "HF_Domovoi": 5570000 }, "InitialGasDistribution": 5200000000000000, "ValidatorsCount": 7, diff --git a/src/Neo.CLI/config.testnet.json b/src/Neo.CLI/config.testnet.json index ee28108c3e..dc102be54b 100644 --- a/src/Neo.CLI/config.testnet.json +++ b/src/Neo.CLI/config.testnet.json @@ -37,7 +37,8 @@ "Hardforks": { "HF_Aspidochelone": 210000, "HF_Basilisk": 2680000, - "HF_Cockatrice": 3967000 + "HF_Cockatrice": 3967000, + "HF_Domovoi": 4144000 }, "InitialGasDistribution": 5200000000000000, "ValidatorsCount": 7, From 379ce75aaac7e2d3604f596abde15d33483c924e Mon Sep 17 00:00:00 2001 From: Jimmy Date: Tue, 18 Jun 2024 10:29:11 +0800 Subject: [PATCH 11/71] catch format exception (#3341) Co-authored-by: NGD Admin <154295625+NGDAdmin@users.noreply.github.com> --- src/Plugins/RpcServer/RpcServer.Blockchain.cs | 12 ++++++------ src/Plugins/RpcServer/RpcServer.Wallet.cs | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Plugins/RpcServer/RpcServer.Blockchain.cs b/src/Plugins/RpcServer/RpcServer.Blockchain.cs index 1c8eecb99f..7898dd9d9b 100644 --- a/src/Plugins/RpcServer/RpcServer.Blockchain.cs +++ b/src/Plugins/RpcServer/RpcServer.Blockchain.cs @@ -44,7 +44,7 @@ protected virtual JToken GetBlock(JArray _params) } else { - UInt256 hash = UInt256.Parse(key.AsString()); + UInt256 hash = Result.Ok_Or(() => UInt256.Parse(key.AsString()), RpcError.InvalidParams.WithData($"Invalid block hash {_params[0]}")); block = NativeContract.Ledger.GetBlock(snapshot, hash); } block.NotNull_Or(RpcError.UnknownBlock); @@ -98,7 +98,7 @@ protected virtual JToken GetBlockHeader(JArray _params) } else { - UInt256 hash = UInt256.Parse(key.AsString()); + UInt256 hash = Result.Ok_Or(() => UInt256.Parse(key.AsString()), RpcError.InvalidParams.WithData($"Invalid block hash {_params[0]}")); header = NativeContract.Ledger.GetHeader(snapshot, hash).NotNull_Or(RpcError.UnknownBlock); } if (verbose) @@ -123,7 +123,7 @@ protected virtual JToken GetContractState(JArray _params) return contractState.NotNull_Or(RpcError.UnknownContract).ToJson(); } - var scriptHash = ToScriptHash(_params[0].AsString()); + var scriptHash = Result.Ok_Or(() => ToScriptHash(_params[0].AsString()), RpcError.InvalidParams.WithData($"Invalid contract hash {_params[0]}")); var contract = NativeContract.ContractManagement.GetContract(system.StoreView, scriptHash); return contract.NotNull_Or(RpcError.UnknownContract).ToJson(); } @@ -185,7 +185,7 @@ protected virtual JToken GetStorage(JArray _params) using var snapshot = system.GetSnapshot(); if (!int.TryParse(_params[0].AsString(), out int id)) { - UInt160 hash = UInt160.Parse(_params[0].AsString()); + UInt160 hash = Result.Ok_Or(() => UInt160.Parse(_params[0].AsString()), RpcError.InvalidParams.WithData($"Invalid contract hash {_params[0]}")); ContractState contract = NativeContract.ContractManagement.GetContract(snapshot, hash).NotNull_Or(RpcError.UnknownContract); id = contract.Id; } @@ -204,12 +204,12 @@ protected virtual JToken FindStorage(JArray _params) using var snapshot = system.GetSnapshot(); if (!int.TryParse(_params[0].AsString(), out int id)) { - UInt160 hash = UInt160.Parse(_params[0].AsString()); + UInt160 hash = Result.Ok_Or(() => UInt160.Parse(_params[0].AsString()), RpcError.InvalidParams.WithData($"Invalid contract hash {_params[0]}")); ContractState contract = NativeContract.ContractManagement.GetContract(snapshot, hash).NotNull_Or(RpcError.UnknownContract); id = contract.Id; } - byte[] prefix = Convert.FromBase64String(_params[1].AsString()); + byte[] prefix = Result.Ok_Or(() => Convert.FromBase64String(_params[1].AsString()), RpcError.InvalidParams.WithData($"Invalid Base64 string{_params[1]}")); byte[] prefix_key = StorageKey.CreateSearchPrefix(id, prefix); if (!int.TryParse(_params[2].AsString(), out int start)) diff --git a/src/Plugins/RpcServer/RpcServer.Wallet.cs b/src/Plugins/RpcServer/RpcServer.Wallet.cs index f1adb277ce..9083f916c6 100644 --- a/src/Plugins/RpcServer/RpcServer.Wallet.cs +++ b/src/Plugins/RpcServer/RpcServer.Wallet.cs @@ -85,7 +85,7 @@ protected virtual JToken GetNewAddress(JArray _params) protected virtual JToken GetWalletBalance(JArray _params) { CheckWallet(); - UInt160 asset_id = UInt160.Parse(_params[0].AsString()); + UInt160 asset_id = Result.Ok_Or(() => UInt160.Parse(_params[0].AsString()), RpcError.InvalidParams.WithData($"Invalid asset id: {_params[0]}")); JObject json = new(); json["balance"] = wallet.GetAvailable(system.StoreView, asset_id).Value.ToString(); return json; @@ -193,7 +193,7 @@ private void ProcessInvokeWithWallet(JObject result, Signer[] signers = null) protected virtual JToken SendFrom(JArray _params) { CheckWallet(); - UInt160 assetId = UInt160.Parse(_params[0].AsString()); + UInt160 assetId = Result.Ok_Or(() => UInt160.Parse(_params[0].AsString()), RpcError.InvalidParams.WithData($"Invalid asset id: {_params[0]}")); UInt160 from = AddressToScriptHash(_params[1].AsString(), system.Settings.AddressVersion); UInt160 to = AddressToScriptHash(_params[2].AsString(), system.Settings.AddressVersion); using var snapshot = system.GetSnapshot(); From d9ae4a67781bb9858c4b5f189c0d158c14a8d289 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Tue, 18 Jun 2024 11:00:37 +0800 Subject: [PATCH 12/71] [Neo Core Optimization] Organize core events. (#3332) * organize core events. * add event handler interfaces * add missing using * complete comments for params --------- Co-authored-by: Shargon Co-authored-by: NGD Admin <154295625+NGDAdmin@users.noreply.github.com> --- src/Neo.CLI/CLI/MainService.Logger.cs | 9 ++- src/Neo/IEventHandlers/ICommittedHandler.cs | 26 +++++++ src/Neo/IEventHandlers/ICommittingHandler.cs | 30 ++++++++ src/Neo/IEventHandlers/ILogHandler.cs | 25 +++++++ src/Neo/IEventHandlers/ILoggingHandler.cs | 24 ++++++ .../IEventHandlers/IMessageReceivedHandler.cs | 25 +++++++ src/Neo/IEventHandlers/INotifyHandler.cs | 25 +++++++ .../IEventHandlers/IServiceAddedHandler.cs | 23 ++++++ .../ITransactionAddedHandler.cs | 26 +++++++ .../ITransactionRemovedHandler.cs | 25 +++++++ .../IEventHandlers/IWalletChangedHandler.cs | 25 +++++++ src/Neo/IEventHandlers/handlers.md | 73 +++++++++++++++++++ src/Plugins/ApplicationLogs/LogReader.cs | 21 +++--- src/Plugins/DBFTPlugin/DBFTPlugin.cs | 22 +++--- src/Plugins/OracleService/OracleService.cs | 22 +++--- src/Plugins/StateService/StatePlugin.cs | 27 +++---- src/Plugins/StorageDumper/StorageDumper.cs | 15 ++-- src/Plugins/TokensTracker/TokensTracker.cs | 15 ++-- 18 files changed, 396 insertions(+), 62 deletions(-) create mode 100644 src/Neo/IEventHandlers/ICommittedHandler.cs create mode 100644 src/Neo/IEventHandlers/ICommittingHandler.cs create mode 100644 src/Neo/IEventHandlers/ILogHandler.cs create mode 100644 src/Neo/IEventHandlers/ILoggingHandler.cs create mode 100644 src/Neo/IEventHandlers/IMessageReceivedHandler.cs create mode 100644 src/Neo/IEventHandlers/INotifyHandler.cs create mode 100644 src/Neo/IEventHandlers/IServiceAddedHandler.cs create mode 100644 src/Neo/IEventHandlers/ITransactionAddedHandler.cs create mode 100644 src/Neo/IEventHandlers/ITransactionRemovedHandler.cs create mode 100644 src/Neo/IEventHandlers/IWalletChangedHandler.cs create mode 100644 src/Neo/IEventHandlers/handlers.md diff --git a/src/Neo.CLI/CLI/MainService.Logger.cs b/src/Neo.CLI/CLI/MainService.Logger.cs index 80624779c7..b54bbefa2c 100644 --- a/src/Neo.CLI/CLI/MainService.Logger.cs +++ b/src/Neo.CLI/CLI/MainService.Logger.cs @@ -10,6 +10,7 @@ // modifications are permitted. using Neo.ConsoleService; +using Neo.IEventHandlers; using System; using System.Collections.Generic; using System.IO; @@ -19,7 +20,7 @@ namespace Neo.CLI { - partial class MainService + partial class MainService : ILoggingHandler { private static readonly ConsoleColorSet DebugColor = new(ConsoleColor.Cyan); private static readonly ConsoleColorSet InfoColor = new(ConsoleColor.White); @@ -32,12 +33,12 @@ partial class MainService private void Initialize_Logger() { - Utility.Logging += OnLog; + Utility.Logging += ((ILoggingHandler)this).Utility_Logging_Handler; } private void Dispose_Logger() { - Utility.Logging -= OnLog; + Utility.Logging -= ((ILoggingHandler)this).Utility_Logging_Handler; } /// @@ -78,7 +79,7 @@ private static void GetErrorLogs(StringBuilder sb, Exception ex) } } - private void OnLog(string source, LogLevel level, object message) + void ILoggingHandler.Utility_Logging_Handler(string source, LogLevel level, object message) { if (!Settings.Default.Logger.Active) return; diff --git a/src/Neo/IEventHandlers/ICommittedHandler.cs b/src/Neo/IEventHandlers/ICommittedHandler.cs new file mode 100644 index 0000000000..632e88916b --- /dev/null +++ b/src/Neo/IEventHandlers/ICommittedHandler.cs @@ -0,0 +1,26 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// ICommittedHandler.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using Neo.Ledger; +using Neo.Network.P2P.Payloads; + +namespace Neo.IEventHandlers; + +public interface ICommittedHandler +{ + /// + /// This is the handler of Commited event from + /// Triggered after a new block is Commited, and state has being updated. + /// + /// The object. + /// The committed . + void Blockchain_Committed_Handler(NeoSystem system, Block block); +} diff --git a/src/Neo/IEventHandlers/ICommittingHandler.cs b/src/Neo/IEventHandlers/ICommittingHandler.cs new file mode 100644 index 0000000000..3fcccccda2 --- /dev/null +++ b/src/Neo/IEventHandlers/ICommittingHandler.cs @@ -0,0 +1,30 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// ICommittingHandler.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using Neo.Ledger; +using Neo.Network.P2P.Payloads; +using Neo.Persistence; +using System.Collections.Generic; + +namespace Neo.IEventHandlers; + +public interface ICommittingHandler +{ + /// + /// This is the handler of Committing event from + /// Triggered when a new block is committing, and the state is still in the cache. + /// + /// The instance associated with the event. + /// The block that is being committed. + /// The current data snapshot. + /// A list of executed applications associated with the block. + void Blockchain_Committing_Handler(NeoSystem system, Block block, DataCache snapshot, IReadOnlyList applicationExecutedList); +} diff --git a/src/Neo/IEventHandlers/ILogHandler.cs b/src/Neo/IEventHandlers/ILogHandler.cs new file mode 100644 index 0000000000..ae0a1f9773 --- /dev/null +++ b/src/Neo/IEventHandlers/ILogHandler.cs @@ -0,0 +1,25 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// ILogHandler.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using Neo.SmartContract; + +namespace Neo.IEventHandlers; + +public interface ILogHandler +{ + /// + /// The handler of Log event from the . + /// Triggered when a contract calls System.Runtime.Log. + /// + /// The source of the event. + /// The arguments of the log. + void ApplicationEngine_Log_Handler(object sender, LogEventArgs logEventArgs); +} diff --git a/src/Neo/IEventHandlers/ILoggingHandler.cs b/src/Neo/IEventHandlers/ILoggingHandler.cs new file mode 100644 index 0000000000..7ec03d4751 --- /dev/null +++ b/src/Neo/IEventHandlers/ILoggingHandler.cs @@ -0,0 +1,24 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// ILoggingHandler.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +namespace Neo.IEventHandlers; + +public interface ILoggingHandler +{ + /// + /// The handler of Logging event from + /// Triggered when a new log is added by calling + /// + /// The source of the log. Used to identify the producer of the log. + /// The level of the log. + /// The message of the log. + void Utility_Logging_Handler(string source, LogLevel level, object message); +} diff --git a/src/Neo/IEventHandlers/IMessageReceivedHandler.cs b/src/Neo/IEventHandlers/IMessageReceivedHandler.cs new file mode 100644 index 0000000000..e4e15a4f3f --- /dev/null +++ b/src/Neo/IEventHandlers/IMessageReceivedHandler.cs @@ -0,0 +1,25 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// IMessageReceivedHandler.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using Neo.Network.P2P; + +namespace Neo.IEventHandlers; + +public interface IMessageReceivedHandler +{ + /// + /// The handler of MessageReceived event from + /// Triggered when a new message is received from a peer + /// + /// The object + /// The current node received from a peer + bool RemoteNode_MessageReceived_Handler(NeoSystem system, Message message); +} diff --git a/src/Neo/IEventHandlers/INotifyHandler.cs b/src/Neo/IEventHandlers/INotifyHandler.cs new file mode 100644 index 0000000000..36b9c4abe4 --- /dev/null +++ b/src/Neo/IEventHandlers/INotifyHandler.cs @@ -0,0 +1,25 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// INotifyHandler.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using Neo.SmartContract; + +namespace Neo.IEventHandlers; + +public interface INotifyHandler +{ + /// + /// The handler of Notify event from + /// Triggered when a contract calls System.Runtime.Notify. + /// + /// The source of the event. + /// The arguments of the notification. + void ApplicationEngine_Notify_Handler(object sender, NotifyEventArgs notifyEventArgs); +} diff --git a/src/Neo/IEventHandlers/IServiceAddedHandler.cs b/src/Neo/IEventHandlers/IServiceAddedHandler.cs new file mode 100644 index 0000000000..7c3b66a471 --- /dev/null +++ b/src/Neo/IEventHandlers/IServiceAddedHandler.cs @@ -0,0 +1,23 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// IServiceAddedHandler.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +namespace Neo.IEventHandlers; + +public interface IServiceAddedHandler +{ + /// + /// The handler of ServiceAdded event from the . + /// Triggered when a service is added to the . + /// + /// The source of the event. + /// The service added. + void NeoSystem_ServiceAdded_Handler(object sender, object service); +} diff --git a/src/Neo/IEventHandlers/ITransactionAddedHandler.cs b/src/Neo/IEventHandlers/ITransactionAddedHandler.cs new file mode 100644 index 0000000000..e120170c3d --- /dev/null +++ b/src/Neo/IEventHandlers/ITransactionAddedHandler.cs @@ -0,0 +1,26 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// ITransactionAddedHandler.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using Neo.Ledger; +using Neo.Network.P2P.Payloads; + +namespace Neo.IEventHandlers; + +public interface ITransactionAddedHandler +{ + /// + /// The handler of TransactionAdded event from the . + /// Triggered when a transaction is added to the . + /// + /// The source of the event + /// The transaction added to the memory pool . + void MemoryPool_TransactionAdded_Handler(object sender, Transaction tx); +} diff --git a/src/Neo/IEventHandlers/ITransactionRemovedHandler.cs b/src/Neo/IEventHandlers/ITransactionRemovedHandler.cs new file mode 100644 index 0000000000..077aa3eccb --- /dev/null +++ b/src/Neo/IEventHandlers/ITransactionRemovedHandler.cs @@ -0,0 +1,25 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// ITransactionRemovedHandler.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using Neo.Ledger; + +namespace Neo.IEventHandlers; + +public interface ITransactionRemovedHandler +{ + /// + /// Handler of TransactionRemoved event from + /// Triggered when a transaction is removed to the . + /// + /// The source of the event + /// The arguments of event that removes a transaction from the + void MemoryPool_TransactionRemoved_Handler(object sender, TransactionRemovedEventArgs tx); +} diff --git a/src/Neo/IEventHandlers/IWalletChangedHandler.cs b/src/Neo/IEventHandlers/IWalletChangedHandler.cs new file mode 100644 index 0000000000..32986e6e15 --- /dev/null +++ b/src/Neo/IEventHandlers/IWalletChangedHandler.cs @@ -0,0 +1,25 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// IWalletChangedHandler.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using Neo.Wallets; + +namespace Neo.IEventHandlers; + +public interface IWalletChangedHandler +{ + /// + /// The handler of WalletChanged event from the . + /// Triggered when a new wallet is assigned to the node. + /// + /// The source of the event + /// The new wallet being assigned to the system. + void IWalletProvider_WalletChanged_Handler(object sender, Wallet wallet); +} diff --git a/src/Neo/IEventHandlers/handlers.md b/src/Neo/IEventHandlers/handlers.md new file mode 100644 index 0000000000..43d864b209 --- /dev/null +++ b/src/Neo/IEventHandlers/handlers.md @@ -0,0 +1,73 @@ +## Neo Core Events + +### 1. Block Committing Event + +**Event Name** `Committing` + +**Handler Interface:** `ICommittingHandler` + +This event is triggered when a transaction is in the process of being committed to the blockchain. Implementing the `ICommittingHandler` interface allows you to define custom actions that should be executed during this phase. + +### 2. Block Committed Event + +**Event Name** `Committed` + +**Handler Interface:** `ICommittedHandler` + +This event occurs after a transaction has been successfully committed to the blockchain. By implementing the `ICommittedHandler` interface, you can specify custom actions to be performed after the transaction is committed. + +### 3. Logging Event +**Event Name** `Logging` + +**Handler Interface:** `ILoggingHandler` + +This event is related to logging within the blockchain system. Implement the `ILoggingHandler` interface to define custom logging behaviors for different events and actions that occur in the blockchain. + +### 4. General Log Event +**Event Name** `Log` + +**Handler Interface:** `ILogHandler` + +This event pertains to general logging activities. The `ILogHandler` interface allows you to handle logging for specific actions or errors within the blockchain system. + +### 5. Notification Event +**Event Name** `Notify` + +**Handler Interface:** `INotifyHandler` + +This event is triggered when a notification needs to be sent. By implementing the `INotifyHandler` interface, you can specify custom actions for sending notifications when certain events occur within the blockchain system. + +### 6. Service Added Event +**Event Name** `ServiceAdded` + +**Handler Interface:** `IServiceAddedHandler` + +This event occurs when a new service is added to the blockchain system. Implement the `IServiceAddedHandler` interface to define custom actions that should be executed when a new service is added. + +### 7. Transaction Added Event +**Event Name** `TransactionAdded` + +**Handler Interface:** `ITransactionAddedHandler` + +This event is triggered when a new transaction is added to the blockchain system. By implementing the `ITransactionAddedHandler` interface, you can specify custom actions to be performed when a new transaction is added. + +### 8. Transaction Removed Event +**Event Name** `TransactionRemoved` + +**Handler Interface:** `ITransactionRemovedHandler` + +This event occurs when a transaction is removed from the blockchain system. Implement the `ITransactionRemovedHandler` interface to define custom actions that should be taken when a transaction is removed. + +### 9. Wallet Changed Event +**Event Name** `WalletChanged` + +**Handler Interface:** `IWalletChangedHandler` + +This event is triggered when changes occur in the wallet, such as balance updates or new transactions. By implementing the `IWalletChangedHandler` interface, you can specify custom actions to be taken when there are changes in the wallet. + +### 10. Remote Node MessageReceived Event +**Event Name** `MessageReceived` + +**Handler Interface:** `IMessageReceivedHandler` + +This event is triggered when a new message is received from a peer remote node. diff --git a/src/Plugins/ApplicationLogs/LogReader.cs b/src/Plugins/ApplicationLogs/LogReader.cs index 6a8682ab5e..3155ecea1f 100644 --- a/src/Plugins/ApplicationLogs/LogReader.cs +++ b/src/Plugins/ApplicationLogs/LogReader.cs @@ -10,6 +10,7 @@ // modifications are permitted. using Neo.ConsoleService; +using Neo.IEventHandlers; using Neo.Json; using Neo.Ledger; using Neo.Network.P2P.Payloads; @@ -25,7 +26,7 @@ namespace Neo.Plugins.ApplicationLogs { - public class LogReader : Plugin + public class LogReader : Plugin, ICommittingHandler, ICommittedHandler, ILogHandler { #region Globals @@ -43,8 +44,8 @@ public class LogReader : Plugin public LogReader() { _logEvents = new(); - Blockchain.Committing += OnCommitting; - Blockchain.Committed += OnCommitted; + Blockchain.Committing += ((ICommittingHandler)this).Blockchain_Committing_Handler; + Blockchain.Committed += ((ICommittedHandler)this).Blockchain_Committed_Handler; } #endregion @@ -55,10 +56,10 @@ public LogReader() public override void Dispose() { - Blockchain.Committing -= OnCommitting; - Blockchain.Committed -= OnCommitted; + Blockchain.Committing -= ((ICommittingHandler)this).Blockchain_Committing_Handler; + Blockchain.Committed -= ((ICommittedHandler)this).Blockchain_Committed_Handler; if (Settings.Default.Debug) - ApplicationEngine.Log -= OnApplicationEngineLog; + ApplicationEngine.Log -= ((ILogHandler)this).ApplicationEngine_Log_Handler; GC.SuppressFinalize(this); } @@ -78,7 +79,7 @@ protected override void OnSystemLoaded(NeoSystem system) RpcServerPlugin.RegisterMethods(this, Settings.Default.Network); if (Settings.Default.Debug) - ApplicationEngine.Log += OnApplicationEngineLog; + ApplicationEngine.Log += ((ILogHandler)this).ApplicationEngine_Log_Handler; } #endregion @@ -195,7 +196,7 @@ private void OnGetContractCommand(UInt160 scripthash, uint page = 1, uint pageSi #region Blockchain Events - private void OnCommitting(NeoSystem system, Block block, DataCache snapshot, IReadOnlyList applicationExecutedList) + void ICommittingHandler.Blockchain_Committing_Handler(NeoSystem system, Block block, DataCache snapshot, IReadOnlyList applicationExecutedList) { if (system.Settings.Network != Settings.Default.Network) return; @@ -216,7 +217,7 @@ private void OnCommitting(NeoSystem system, Block block, DataCache snapshot, IRe } } - private void OnCommitted(NeoSystem system, Block block) + void ICommittedHandler.Blockchain_Committed_Handler(NeoSystem system, Block block) { if (system.Settings.Network != Settings.Default.Network) return; @@ -225,7 +226,7 @@ private void OnCommitted(NeoSystem system, Block block) _neostore.CommitBlockLog(); } - private void OnApplicationEngineLog(object sender, LogEventArgs e) + void ILogHandler.ApplicationEngine_Log_Handler(object sender, LogEventArgs e) { if (Settings.Default.Debug == false) return; diff --git a/src/Plugins/DBFTPlugin/DBFTPlugin.cs b/src/Plugins/DBFTPlugin/DBFTPlugin.cs index 9ca44adc74..f09be9d291 100644 --- a/src/Plugins/DBFTPlugin/DBFTPlugin.cs +++ b/src/Plugins/DBFTPlugin/DBFTPlugin.cs @@ -11,15 +11,15 @@ using Akka.Actor; using Neo.ConsoleService; +using Neo.IEventHandlers; using Neo.Network.P2P; using Neo.Network.P2P.Payloads; -using Neo.Plugins; using Neo.Plugins.DBFTPlugin.Consensus; using Neo.Wallets; namespace Neo.Plugins.DBFTPlugin { - public class DBFTPlugin : Plugin + public class DBFTPlugin : Plugin, IServiceAddedHandler, IMessageReceivedHandler, IWalletChangedHandler { private IWalletProvider walletProvider; private IActorRef consensus; @@ -33,7 +33,7 @@ public class DBFTPlugin : Plugin public DBFTPlugin() { - RemoteNode.MessageReceived += RemoteNode_MessageReceived; + RemoteNode.MessageReceived += ((IMessageReceivedHandler)this).RemoteNode_MessageReceived_Handler; } public DBFTPlugin(Settings settings) : this() @@ -43,7 +43,7 @@ public DBFTPlugin(Settings settings) : this() public override void Dispose() { - RemoteNode.MessageReceived -= RemoteNode_MessageReceived; + RemoteNode.MessageReceived -= ((IMessageReceivedHandler)this).RemoteNode_MessageReceived_Handler; } protected override void Configure() @@ -55,23 +55,23 @@ protected override void OnSystemLoaded(NeoSystem system) { if (system.Settings.Network != settings.Network) return; neoSystem = system; - neoSystem.ServiceAdded += NeoSystem_ServiceAdded; + neoSystem.ServiceAdded += ((IServiceAddedHandler)this).NeoSystem_ServiceAdded_Handler; } - private void NeoSystem_ServiceAdded(object sender, object service) + void IServiceAddedHandler.NeoSystem_ServiceAdded_Handler(object sender, object service) { if (service is not IWalletProvider provider) return; walletProvider = provider; - neoSystem.ServiceAdded -= NeoSystem_ServiceAdded; + neoSystem.ServiceAdded -= ((IServiceAddedHandler)this).NeoSystem_ServiceAdded_Handler; if (settings.AutoStart) { - walletProvider.WalletChanged += WalletProvider_WalletChanged; + walletProvider.WalletChanged += ((IWalletChangedHandler)this).IWalletProvider_WalletChanged_Handler; } } - private void WalletProvider_WalletChanged(object sender, Wallet wallet) + void IWalletChangedHandler.IWalletProvider_WalletChanged_Handler(object sender, Wallet wallet) { - walletProvider.WalletChanged -= WalletProvider_WalletChanged; + walletProvider.WalletChanged -= ((IWalletChangedHandler)this).IWalletProvider_WalletChanged_Handler; Start(wallet); } @@ -89,7 +89,7 @@ public void Start(Wallet wallet) consensus.Tell(new ConsensusService.Start()); } - private bool RemoteNode_MessageReceived(NeoSystem system, Message message) + bool IMessageReceivedHandler.RemoteNode_MessageReceived_Handler(NeoSystem system, Message message) { if (message.Command == MessageCommand.Transaction) { diff --git a/src/Plugins/OracleService/OracleService.cs b/src/Plugins/OracleService/OracleService.cs index e9787b3d4c..6041bbb0ca 100644 --- a/src/Plugins/OracleService/OracleService.cs +++ b/src/Plugins/OracleService/OracleService.cs @@ -14,6 +14,7 @@ using Neo.ConsoleService; using Neo.Cryptography; using Neo.Cryptography.ECC; +using Neo.IEventHandlers; using Neo.IO; using Neo.Json; using Neo.Ledger; @@ -37,7 +38,7 @@ namespace Neo.Plugins.OracleService { - public class OracleService : Plugin + public class OracleService : Plugin, ICommittingHandler, IServiceAddedHandler, IWalletChangedHandler { private const int RefreshIntervalMilliSeconds = 1000 * 60 * 3; @@ -65,7 +66,7 @@ public class OracleService : Plugin public OracleService() { - Blockchain.Committing += OnCommitting; + Blockchain.Committing += ((ICommittingHandler)this).Blockchain_Committing_Handler; } protected override void Configure() @@ -79,32 +80,33 @@ protected override void OnSystemLoaded(NeoSystem system) { if (system.Settings.Network != Settings.Default.Network) return; _system = system; - _system.ServiceAdded += NeoSystem_ServiceAdded; + _system.ServiceAdded += ((IServiceAddedHandler)this).NeoSystem_ServiceAdded_Handler; RpcServerPlugin.RegisterMethods(this, Settings.Default.Network); } - private void NeoSystem_ServiceAdded(object sender, object service) + + void IServiceAddedHandler.NeoSystem_ServiceAdded_Handler(object sender, object service) { if (service is IWalletProvider) { walletProvider = service as IWalletProvider; - _system.ServiceAdded -= NeoSystem_ServiceAdded; + _system.ServiceAdded -= ((IServiceAddedHandler)this).NeoSystem_ServiceAdded_Handler; if (Settings.Default.AutoStart) { - walletProvider.WalletChanged += WalletProvider_WalletChanged; + walletProvider.WalletChanged += ((IWalletChangedHandler)this).IWalletProvider_WalletChanged_Handler; } } } - private void WalletProvider_WalletChanged(object sender, Wallet wallet) + void IWalletChangedHandler.IWalletProvider_WalletChanged_Handler(object sender, Wallet wallet) { - walletProvider.WalletChanged -= WalletProvider_WalletChanged; + walletProvider.WalletChanged -= ((IWalletChangedHandler)this).IWalletProvider_WalletChanged_Handler; Start(wallet); } public override void Dispose() { - Blockchain.Committing -= OnCommitting; + Blockchain.Committing -= ((ICommittingHandler)this).Blockchain_Committing_Handler; OnStop(); while (status != OracleStatus.Stopped) Thread.Sleep(100); @@ -166,7 +168,7 @@ private void OnShow() ConsoleHelper.Info($"Oracle status: ", $"{status}"); } - private void OnCommitting(NeoSystem system, Block block, DataCache snapshot, IReadOnlyList applicationExecutedList) + void ICommittingHandler.Blockchain_Committing_Handler(NeoSystem system, Block block, DataCache snapshot, IReadOnlyList applicationExecutedList) { if (system.Settings.Network != Settings.Default.Network) return; diff --git a/src/Plugins/StateService/StatePlugin.cs b/src/Plugins/StateService/StatePlugin.cs index 1c28e92193..5f6e1ef1d8 100644 --- a/src/Plugins/StateService/StatePlugin.cs +++ b/src/Plugins/StateService/StatePlugin.cs @@ -12,6 +12,7 @@ using Akka.Actor; using Neo.ConsoleService; using Neo.Cryptography.MPTTrie; +using Neo.IEventHandlers; using Neo.IO; using Neo.Json; using Neo.Ledger; @@ -33,7 +34,7 @@ namespace Neo.Plugins.StateService { - public class StatePlugin : Plugin + public class StatePlugin : Plugin, ICommittingHandler, ICommittedHandler, IWalletChangedHandler, IServiceAddedHandler { public const string StatePayloadCategory = "StateService"; public override string Name => "StateService"; @@ -48,8 +49,8 @@ public class StatePlugin : Plugin public StatePlugin() { - Blockchain.Committing += OnCommitting; - Blockchain.Committed += OnCommitted; + Blockchain.Committing += ((ICommittingHandler)this).Blockchain_Committing_Handler; + Blockchain.Committed += ((ICommittedHandler)this).Blockchain_Committed_Handler; } protected override void Configure() @@ -62,45 +63,45 @@ protected override void OnSystemLoaded(NeoSystem system) if (system.Settings.Network != Settings.Default.Network) return; _system = system; Store = _system.ActorSystem.ActorOf(StateStore.Props(this, string.Format(Settings.Default.Path, system.Settings.Network.ToString("X8")))); - _system.ServiceAdded += NeoSystem_ServiceAdded; + _system.ServiceAdded += ((IServiceAddedHandler)this).NeoSystem_ServiceAdded_Handler; RpcServerPlugin.RegisterMethods(this, Settings.Default.Network); } - private void NeoSystem_ServiceAdded(object sender, object service) + void IServiceAddedHandler.NeoSystem_ServiceAdded_Handler(object sender, object service) { if (service is IWalletProvider) { walletProvider = service as IWalletProvider; - _system.ServiceAdded -= NeoSystem_ServiceAdded; + _system.ServiceAdded -= ((IServiceAddedHandler)this).NeoSystem_ServiceAdded_Handler; if (Settings.Default.AutoVerify) { - walletProvider.WalletChanged += WalletProvider_WalletChanged; + walletProvider.WalletChanged += ((IWalletChangedHandler)this).IWalletProvider_WalletChanged_Handler; } } } - private void WalletProvider_WalletChanged(object sender, Wallet wallet) + void IWalletChangedHandler.IWalletProvider_WalletChanged_Handler(object sender, Wallet wallet) { - walletProvider.WalletChanged -= WalletProvider_WalletChanged; + walletProvider.WalletChanged -= ((IWalletChangedHandler)this).IWalletProvider_WalletChanged_Handler; Start(wallet); } public override void Dispose() { base.Dispose(); - Blockchain.Committing -= OnCommitting; - Blockchain.Committed -= OnCommitted; + Blockchain.Committing -= ((ICommittingHandler)this).Blockchain_Committing_Handler; + Blockchain.Committed -= ((ICommittedHandler)this).Blockchain_Committed_Handler; if (Store is not null) _system.EnsureStopped(Store); if (Verifier is not null) _system.EnsureStopped(Verifier); } - private void OnCommitting(NeoSystem system, Block block, DataCache snapshot, IReadOnlyList applicationExecutedList) + void ICommittingHandler.Blockchain_Committing_Handler(NeoSystem system, Block block, DataCache snapshot, IReadOnlyList applicationExecutedList) { if (system.Settings.Network != Settings.Default.Network) return; StateStore.Singleton.UpdateLocalStateRootSnapshot(block.Index, snapshot.GetChangeSet().Where(p => p.State != TrackState.None).Where(p => p.Key.Id != NativeContract.Ledger.Id).ToList()); } - private void OnCommitted(NeoSystem system, Block block) + void ICommittedHandler.Blockchain_Committed_Handler(NeoSystem system, Block block) { if (system.Settings.Network != Settings.Default.Network) return; StateStore.Singleton.UpdateLocalStateRoot(block.Index); diff --git a/src/Plugins/StorageDumper/StorageDumper.cs b/src/Plugins/StorageDumper/StorageDumper.cs index d8987cdcaa..c47df9ac1d 100644 --- a/src/Plugins/StorageDumper/StorageDumper.cs +++ b/src/Plugins/StorageDumper/StorageDumper.cs @@ -10,6 +10,7 @@ // modifications are permitted. using Neo.ConsoleService; +using Neo.IEventHandlers; using Neo.IO; using Neo.Json; using Neo.Ledger; @@ -19,7 +20,7 @@ namespace Neo.Plugins.StorageDumper { - public class StorageDumper : Plugin + public class StorageDumper : Plugin, ICommittingHandler, ICommittedHandler { private readonly Dictionary systems = new Dictionary(); @@ -37,14 +38,14 @@ public class StorageDumper : Plugin public StorageDumper() { - Blockchain.Committing += OnCommitting; - Blockchain.Committed += OnCommitted; + Blockchain.Committing += ((ICommittingHandler)this).Blockchain_Committing_Handler; + Blockchain.Committed += ((ICommittedHandler)this).Blockchain_Committed_Handler; } public override void Dispose() { - Blockchain.Committing -= OnCommitting; - Blockchain.Committed -= OnCommitted; + Blockchain.Committing -= ((ICommittingHandler)this).Blockchain_Committing_Handler; + Blockchain.Committed -= ((ICommittedHandler)this).Blockchain_Committed_Handler; } protected override void Configure() @@ -85,7 +86,7 @@ private void OnDumpStorage(uint network, UInt160? contractHash = null) $"{path}"); } - private void OnCommitting(NeoSystem system, Block block, DataCache snapshot, IReadOnlyList applicationExecutedList) + void ICommittingHandler.Blockchain_Committing_Handler(NeoSystem system, Block block, DataCache snapshot, IReadOnlyList applicationExecutedList) { InitFileWriter(system.Settings.Network, snapshot); OnPersistStorage(system.Settings.Network, snapshot); @@ -132,7 +133,7 @@ private void OnPersistStorage(uint network, DataCache snapshot) } - private void OnCommitted(NeoSystem system, Block block) + void ICommittedHandler.Blockchain_Committed_Handler(NeoSystem system, Block block) { OnCommitStorage(system.Settings.Network, system.StoreView); } diff --git a/src/Plugins/TokensTracker/TokensTracker.cs b/src/Plugins/TokensTracker/TokensTracker.cs index eacd0de6e4..e5ffdce3f4 100644 --- a/src/Plugins/TokensTracker/TokensTracker.cs +++ b/src/Plugins/TokensTracker/TokensTracker.cs @@ -10,6 +10,7 @@ // modifications are permitted. using Microsoft.Extensions.Configuration; +using Neo.IEventHandlers; using Neo.Ledger; using Neo.Network.P2P.Payloads; using Neo.Persistence; @@ -21,7 +22,7 @@ namespace Neo.Plugins { - public class TokensTracker : Plugin + public class TokensTracker : Plugin, ICommittingHandler, ICommittedHandler { private string _dbPath; private bool _shouldTrackHistory; @@ -38,14 +39,14 @@ public class TokensTracker : Plugin public TokensTracker() { - Blockchain.Committing += OnCommitting; - Blockchain.Committed += OnCommitted; + Blockchain.Committing += ((ICommittingHandler)this).Blockchain_Committing_Handler; + Blockchain.Committed += ((ICommittedHandler)this).Blockchain_Committed_Handler; } public override void Dispose() { - Blockchain.Committing -= OnCommitting; - Blockchain.Committed -= OnCommitted; + Blockchain.Committing -= ((ICommittingHandler)this).Blockchain_Committing_Handler; + Blockchain.Committed -= ((ICommittedHandler)this).Blockchain_Committed_Handler; } protected override void Configure() @@ -80,7 +81,7 @@ private void ResetBatch() } } - private void OnCommitting(NeoSystem system, Block block, DataCache snapshot, IReadOnlyList applicationExecutedList) + void ICommittingHandler.Blockchain_Committing_Handler(NeoSystem system, Block block, DataCache snapshot, IReadOnlyList applicationExecutedList) { if (system.Settings.Network != _network) return; // Start freshly with a new DBCache for each block. @@ -91,7 +92,7 @@ private void OnCommitting(NeoSystem system, Block block, DataCache snapshot, IRe } } - private void OnCommitted(NeoSystem system, Block block) + void ICommittedHandler.Blockchain_Committed_Handler(NeoSystem system, Block block) { if (system.Settings.Network != _network) return; foreach (var tracker in trackers) From 12c3b8989a57c46fbd8977c48eb5d4b950019ea9 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Tue, 18 Jun 2024 11:09:38 +0800 Subject: [PATCH 13/71] [Neo VM Optimization]Print stack exception (#3326) * print stack exception * Move and use Error --------- Co-authored-by: Fernando Diaz Toledano Co-authored-by: NGD Admin <154295625+NGDAdmin@users.noreply.github.com> --- src/Neo.VM/ExecutionEngine.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Neo.VM/ExecutionEngine.cs b/src/Neo.VM/ExecutionEngine.cs index c7c3f86ce9..bec60c4348 100644 --- a/src/Neo.VM/ExecutionEngine.cs +++ b/src/Neo.VM/ExecutionEngine.cs @@ -235,6 +235,13 @@ public ExecutionContext LoadScript(Script script, int rvcount = -1, int initialP protected virtual void OnFault(Exception ex) { State = VMState.FAULT; + +#if VMPERF + if (ex != null) + { + Console.Error.WriteLine(ex); + } +#endif } /// From 2ca8467046b56038ba87947ce8957bf7dd2bbf52 Mon Sep 17 00:00:00 2001 From: Christopher Schuchardt Date: Mon, 17 Jun 2024 23:23:02 -0400 Subject: [PATCH 14/71] Fixed `version` display in `neo-cli` (#3307) * fixed version display in `neo-cli` * Remove `hash` from `UserAgent` * Fixed version string for format `0.0.0` --------- Co-authored-by: NGD Admin <154295625+NGDAdmin@users.noreply.github.com> --- src/Neo.CLI/CLI/MainService.cs | 8 ++++---- src/Neo/Network/P2P/LocalNode.cs | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Neo.CLI/CLI/MainService.cs b/src/Neo.CLI/CLI/MainService.cs index 88967c82ea..19ea5d9334 100644 --- a/src/Neo.CLI/CLI/MainService.cs +++ b/src/Neo.CLI/CLI/MainService.cs @@ -132,10 +132,10 @@ public override void RunConsole() { Console.ForegroundColor = ConsoleColor.DarkGreen; - var cliV = Assembly.GetAssembly(typeof(Program))!.GetVersion(); - var neoV = Assembly.GetAssembly(typeof(NeoSystem))!.GetVersion(); - var vmV = Assembly.GetAssembly(typeof(ExecutionEngine))!.GetVersion(); - Console.WriteLine($"{ServiceName} v{cliV} - NEO v{neoV} - NEO-VM v{vmV}"); + var cliV = Assembly.GetAssembly(typeof(Program))!.GetName().Version; + var neoV = Assembly.GetAssembly(typeof(NeoSystem))!.GetName().Version; + var vmV = Assembly.GetAssembly(typeof(ExecutionEngine))!.GetName().Version; + Console.WriteLine($"{ServiceName} v{cliV?.ToString(3)} - NEO v{neoV?.ToString(3)} - NEO-VM v{vmV?.ToString(3)}"); Console.WriteLine(); base.RunConsole(); diff --git a/src/Neo/Network/P2P/LocalNode.cs b/src/Neo/Network/P2P/LocalNode.cs index 78a967047c..313e7afd16 100644 --- a/src/Neo/Network/P2P/LocalNode.cs +++ b/src/Neo/Network/P2P/LocalNode.cs @@ -78,7 +78,7 @@ static LocalNode() { Random rand = new(); Nonce = (uint)rand.Next(); - UserAgent = $"/{Assembly.GetExecutingAssembly().GetName().Name}:{Assembly.GetExecutingAssembly().GetVersion()}/"; + UserAgent = $"/{Assembly.GetExecutingAssembly().GetName().Name}:{Assembly.GetExecutingAssembly().GetName().Version?.ToString(3)}/"; } /// From 2bd2a4522f365fb314f9b49aeef866b60da986c6 Mon Sep 17 00:00:00 2001 From: Christopher Schuchardt Date: Mon, 17 Jun 2024 23:41:28 -0400 Subject: [PATCH 15/71] Fixed Props paths for `*.csproj` builds (#3320) * Fixed Props paths * Removed unwanted files * Removed unwanted project files --------- Co-authored-by: Jimmy Co-authored-by: NGD Admin <154295625+NGDAdmin@users.noreply.github.com> --- src/Directory.Build.props | 4 ++-- src/Plugins/Directory.Build.props | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Directory.Build.props b/src/Directory.Build.props index c211ee34aa..ba6b9f24c2 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -19,8 +19,8 @@ - - + + diff --git a/src/Plugins/Directory.Build.props b/src/Plugins/Directory.Build.props index 72e96f0300..e7cfbdeb1e 100644 --- a/src/Plugins/Directory.Build.props +++ b/src/Plugins/Directory.Build.props @@ -4,12 +4,12 @@ - - + + - + From 90468e8fc7b4b5c8e6f7b9c023c9c64b44690167 Mon Sep 17 00:00:00 2001 From: Christopher Schuchardt Date: Tue, 18 Jun 2024 23:09:57 -0400 Subject: [PATCH 16/71] [**Fixed**] `NuGet` Release (#3338) * Added Nuget release when new published release * Added some comments * Removed current nuget release * Added forgotten slashes --- .github/workflows/main.yml | 95 +------------------ .github/workflows/nuget.yml | 46 +++++++++ benchmarks/Directory.Build.props | 8 ++ .../Neo.Benchmarks/Neo.Benchmarks.csproj | 1 - .../Neo.VM.Benchmarks.csproj | 1 - src/Directory.Build.props | 2 +- src/Neo.CLI/Neo.CLI.csproj | 1 + src/Neo.GUI/Neo.GUI.csproj | 1 + 8 files changed, 59 insertions(+), 96 deletions(-) create mode 100644 .github/workflows/nuget.yml create mode 100644 benchmarks/Directory.Build.props diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index e12760e019..5294cd09f4 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -143,7 +143,7 @@ jobs: --source https://nuget.pkg.github.com/neo-project/index.json \ --api-key "${{ secrets.GITHUB_TOKEN }}" \ --disable-buffering \ - --no-service-endpoint; + --no-service-endpoint - name: Publish to myGet working-directory: ./out @@ -152,95 +152,4 @@ jobs: --source https://www.myget.org/F/neo/api/v3/index.json \ --api-key "${{ secrets.MYGET_TOKEN }}" \ --disable-buffering \ - --no-service-endpoint; - - Release: - if: github.ref == 'refs/heads/master' && startsWith(github.repository, 'neo-project/') - needs: [Test] - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Get version - id: get_version - run: | - sudo apt install xmlstarlet - find src -name Directory.Build.props | xargs xmlstarlet sel -N i=http://schemas.microsoft.com/developer/msbuild/2003 -t -v "concat('::set-output name=version::v',//i:VersionPrefix/text())" | xargs echo - - - name: Check tag - id: check_tag - run: curl -s -I ${{ format('https://github.com/{0}/releases/tag/{1}', github.repository, steps.get_version.outputs.version) }} | head -n 1 | cut -d$' ' -f2 | xargs printf "::set-output name=statusCode::%s" | xargs echo - - - name: Create release - if: steps.check_tag.outputs.statusCode == '404' - id: create_release - uses: actions/create-release@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - tag_name: ${{ steps.get_version.outputs.version }} - release_name: ${{ steps.get_version.outputs.version }} - prerelease: ${{ contains(steps.get_version.outputs.version, '-') }} - - - name: Setup .NET - if: steps.check_tag.outputs.statusCode == '404' - uses: actions/setup-dotnet@v4 - with: - dotnet-version: ${{ env.DOTNET_VERSION }} - - - name : Pack (Neo) - if: steps.check_tag.outputs.statusCode == '404' - run: | - dotnet pack ./src/Neo \ - --configuration Release \ - --output ./out - - - name : Pack (Neo.IO) - if: steps.check_tag.outputs.statusCode == '404' - run: | - dotnet pack ./src/Neo.IO \ - --configuration Release \ - --output ./out - - - name : Pack (Neo.Extensions) - if: steps.check_tag.outputs.statusCode == '404' - run: | - dotnet pack ./src/Neo.Extensions \ - --configuration Release \ - --output ./out - - - name : Pack (Neo.Json) - if: steps.check_tag.outputs.statusCode == '404' - run: | - dotnet pack ./src/Neo.Json \ - --configuration Release \ - --output ./out - - - name : Pack (Neo.VM) - if: steps.check_tag.outputs.statusCode == '404' - run: | - dotnet pack ./src/Neo.VM \ - --configuration Release \ - --output ./out - - - name : Pack (Neo.ConsoleService) - if: steps.check_tag.outputs.statusCode == '404' - run: | - dotnet pack ./src/Neo.ConsoleService \ - --configuration Release \ - --output ./out - - - name : Pack (Neo.Cryptography.BLS12_381) - if: steps.check_tag.outputs.statusCode == '404' - run: | - dotnet pack ./src/Neo.Cryptography.BLS12_381 \ - --configuration Release \ - --output ./out - - - name: Publish to NuGet - if: steps.check_tag.outputs.statusCode == '404' - run: | - dotnet nuget push out/*.nupkg -s https://api.nuget.org/v3/index.json -k ${NUGET_TOKEN} --skip-duplicate - env: - NUGET_TOKEN: ${{ secrets.NUGET_TOKEN }} + --no-service-endpoint diff --git a/.github/workflows/nuget.yml b/.github/workflows/nuget.yml new file mode 100644 index 0000000000..61ff1e3408 --- /dev/null +++ b/.github/workflows/nuget.yml @@ -0,0 +1,46 @@ +name: Release (nuget) + +# Trigger the workflow on a release event when a new release is published +on: + release: + types: [published] + +# Define environment variables +env: + DOTNET_VERSION: 8.0.x + CONFIGURATION: Release + +jobs: + nuget-release: + runs-on: ubuntu-latest + steps: + # Step to set the application version from the release tag + - name: Set Application Version (Environment Variable) + run: | + APP_VERSION=$(echo '${{ github.event.release.tag_name }}' | cut -d 'v' -f 2) + echo "APP_VERSION=$APP_VERSION" >> $GITHUB_ENV + + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: ${{ env.DOTNET_VERSION }} + + - name: Pack NuGet Packages + run: | + dotnet pack ./neo.sln \ + --configuration Release \ + --output ./sbin \ + --verbosity normal \ # Normal verbosity level + -p:VersionPrefix=${{ env.APP_VERSION }} # Set the version prefix from tag_name + + - name: Publish to NuGet.org + run: | + dotnet nuget push ./sbin/*.nupkg \ + --source https://api.nuget.org/v3/index.json \ + --api-key ${{ secrets.NUGET_TOKEN }} \ + --skip-duplicate diff --git a/benchmarks/Directory.Build.props b/benchmarks/Directory.Build.props new file mode 100644 index 0000000000..8ef2d9e6bb --- /dev/null +++ b/benchmarks/Directory.Build.props @@ -0,0 +1,8 @@ + + + + + false + + + diff --git a/benchmarks/Neo.Benchmarks/Neo.Benchmarks.csproj b/benchmarks/Neo.Benchmarks/Neo.Benchmarks.csproj index 476ef93060..22b90aeb03 100644 --- a/benchmarks/Neo.Benchmarks/Neo.Benchmarks.csproj +++ b/benchmarks/Neo.Benchmarks/Neo.Benchmarks.csproj @@ -5,7 +5,6 @@ net8.0 Neo enable - false diff --git a/benchmarks/Neo.VM.Benchmarks/Neo.VM.Benchmarks.csproj b/benchmarks/Neo.VM.Benchmarks/Neo.VM.Benchmarks.csproj index 7737c3ec0c..4c3c3d6057 100644 --- a/benchmarks/Neo.VM.Benchmarks/Neo.VM.Benchmarks.csproj +++ b/benchmarks/Neo.VM.Benchmarks/Neo.VM.Benchmarks.csproj @@ -6,7 +6,6 @@ Neo.VM enable enable - false diff --git a/src/Directory.Build.props b/src/Directory.Build.props index ba6b9f24c2..e751a3b92c 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -3,9 +3,9 @@ 2015-2024 The Neo Project - 3.7.4 12.0 The Neo Project + true neo.png https://github.com/neo-project/neo MIT diff --git a/src/Neo.CLI/Neo.CLI.csproj b/src/Neo.CLI/Neo.CLI.csproj index f3f319d358..eaa2cb3067 100644 --- a/src/Neo.CLI/Neo.CLI.csproj +++ b/src/Neo.CLI/Neo.CLI.csproj @@ -11,6 +11,7 @@ neo.ico enable ../../bin/$(AssemblyTitle) + false diff --git a/src/Neo.GUI/Neo.GUI.csproj b/src/Neo.GUI/Neo.GUI.csproj index 078434fc13..28c7d841a5 100644 --- a/src/Neo.GUI/Neo.GUI.csproj +++ b/src/Neo.GUI/Neo.GUI.csproj @@ -12,6 +12,7 @@ neo.ico false ../../bin/$(AssemblyTitle) + false From 60bb9c6d4f08df5087849fb977367bc5c9487dc3 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Thu, 20 Jun 2024 23:58:47 +0100 Subject: [PATCH 17/71] [Neo Core UT] Test memory store (#3336) * test memory store * Update tests/Neo.UnitTests/Neo.UnitTests.csproj Co-authored-by: Shargon --------- Co-authored-by: Shargon Co-authored-by: NGD Admin <154295625+NGDAdmin@users.noreply.github.com> --- .../Persistence/TestMemoryStoreProvider.cs | 21 ++++++ .../Persistence/UT_MemoryStore.cs | 66 ++++++++++++++++++- 2 files changed, 84 insertions(+), 3 deletions(-) create mode 100644 tests/Neo.UnitTests/Persistence/TestMemoryStoreProvider.cs diff --git a/tests/Neo.UnitTests/Persistence/TestMemoryStoreProvider.cs b/tests/Neo.UnitTests/Persistence/TestMemoryStoreProvider.cs new file mode 100644 index 0000000000..59b8ac885d --- /dev/null +++ b/tests/Neo.UnitTests/Persistence/TestMemoryStoreProvider.cs @@ -0,0 +1,21 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// TestMemoryStoreProvider.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using Neo.Persistence; + +namespace Neo.UnitTests.Persistence; + +public class TestMemoryStoreProvider(MemoryStore memoryStore) : IStoreProvider +{ + public MemoryStore MemoryStore { get; set; } = memoryStore; + public string Name => nameof(MemoryStore); + public IStore GetStore(string path) => MemoryStore; +} diff --git a/tests/Neo.UnitTests/Persistence/UT_MemoryStore.cs b/tests/Neo.UnitTests/Persistence/UT_MemoryStore.cs index b0f61791f6..4cddf07e65 100644 --- a/tests/Neo.UnitTests/Persistence/UT_MemoryStore.cs +++ b/tests/Neo.UnitTests/Persistence/UT_MemoryStore.cs @@ -10,6 +10,7 @@ // modifications are permitted. using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.IO; using Neo.Persistence; using Neo.SmartContract; using System; @@ -21,6 +22,22 @@ namespace Neo.UnitTests.Persistence [TestClass] public class UT_MemoryStore { + private NeoSystem _neoSystem; + private MemoryStore _memoryStore; + + [TestInitialize] + public void Setup() + { + _memoryStore = new MemoryStore(); + _neoSystem = new NeoSystem(TestProtocolSettings.Default, new TestMemoryStoreProvider(_memoryStore)); + } + + [TestCleanup] + public void CleanUp() + { + _memoryStore.Reset(); + } + [TestMethod] public void LoadStoreTest() { @@ -58,16 +75,59 @@ public void StoreTest() [TestMethod] public void NeoSystemStoreViewTest() { - var neoSystem = new NeoSystem(TestProtocolSettings.Default, new MemoryStoreProvider()); - Assert.IsNotNull(neoSystem.StoreView); - var store = neoSystem.StoreView; + Assert.IsNotNull(_neoSystem.StoreView); + var store = _neoSystem.StoreView; var key = new StorageKey(Encoding.UTF8.GetBytes("testKey")); var value = new StorageItem(Encoding.UTF8.GetBytes("testValue")); store.Add(key, value); store.Commit(); var result = store.TryGet(key); + // The StoreView is a readonly view of the store, here it will have value in the cache Assert.AreEqual("testValue", Encoding.UTF8.GetString(result.Value.ToArray())); + // But the value will not be written to the underlying store even its committed. + Assert.IsNull(_memoryStore.TryGet(key.ToArray())); } + [TestMethod] + public void NeoSystemStoreAddTest() + { + var storeCache = _neoSystem.GetSnapshot(); + var key = new KeyBuilder(0, 0); + storeCache.Add(key, new StorageItem(UInt256.Zero.ToArray())); + storeCache.Commit(); + + CollectionAssert.AreEqual(UInt256.Zero.ToArray(), storeCache.TryGet(key).ToArray()); + } + + [TestMethod] + public void NeoSystemStoreGetAndChange() + { + var storeView = _neoSystem.GetSnapshot(); + var key = new KeyBuilder(1, 1); + var item = new StorageItem([1, 2, 3]); + storeView.Delete(key); + Assert.AreEqual(null, storeView.TryGet(key)); + storeView.Add(key, item); + CollectionAssert.AreEqual(new byte[] { 1, 2, 3 }, storeView.TryGet(key).ToArray()); + + var key2 = new KeyBuilder(1, 2); + var item2 = new StorageItem([4, 5, 6]); + storeView.Add(key2, item2); + CollectionAssert.AreEqual(key2.ToArray(), storeView.Seek(key2.ToArray(), SeekDirection.Backward).Select(u => u.Key).First().ToArray()); + CollectionAssert.AreEqual(key.ToArray(), storeView.Seek(key.ToArray(), SeekDirection.Backward).Select(u => u.Key).First().ToArray()); + + storeView.Delete(key); + storeView.Delete(key2); + + storeView.Add(new KeyBuilder(1, 0x000000), new StorageItem([0x00])); + storeView.Add(new KeyBuilder(1, 0x000001), new StorageItem([0x01])); + storeView.Add(new KeyBuilder(1, 0x000002), new StorageItem([0x02])); + storeView.Add(new KeyBuilder(1, 0x000003), new StorageItem([0x03])); + storeView.Add(new KeyBuilder(1, 0x000004), new StorageItem([0x04])); + + var entries = storeView.Seek([], SeekDirection.Backward).ToArray(); + // Memory store has different seek behavior than the snapshot + Assert.AreEqual(entries.Length, 37); + } } } From f379dabead4a28917518fdb5014a87439c5df918 Mon Sep 17 00:00:00 2001 From: Christopher Schuchardt Date: Fri, 21 Jun 2024 04:50:04 -0400 Subject: [PATCH 18/71] Fixed `ApplicationLogs` `GetMethodParameterName` method (#3348) Co-authored-by: Jimmy Co-authored-by: NGD Admin <154295625+NGDAdmin@users.noreply.github.com> --- src/Plugins/ApplicationLogs/LogReader.cs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/Plugins/ApplicationLogs/LogReader.cs b/src/Plugins/ApplicationLogs/LogReader.cs index 3155ecea1f..3c1b5ecb94 100644 --- a/src/Plugins/ApplicationLogs/LogReader.cs +++ b/src/Plugins/ApplicationLogs/LogReader.cs @@ -272,8 +272,9 @@ private void PrintExecutionToConsole(BlockchainExecutionModel model) ConsoleHelper.Info(" ScriptHash: ", $"{notifyItem.ScriptHash}"); ConsoleHelper.Info(" Event Name: ", $"{notifyItem.EventName}"); ConsoleHelper.Info(" State Parameters:"); - for (int i = 0; i < notifyItem.State.Length; i++) - ConsoleHelper.Info($" {GetMethodParameterName(notifyItem.ScriptHash, notifyItem.EventName, i)}: ", $"{notifyItem.State[i].ToJson()}"); + var ncount = (uint)notifyItem.State.Length; + for (var i = 0; i < ncount; i++) + ConsoleHelper.Info($" {GetMethodParameterName(notifyItem.ScriptHash, notifyItem.EventName, ncount, i)}: ", $"{notifyItem.State[i].ToJson()}"); } } if (Settings.Default.Debug) @@ -301,18 +302,21 @@ private void PrintEventModelToConsole(IReadOnlyCollection<(BlockchainEventModel ConsoleHelper.Info(); ConsoleHelper.Info(" Event Name: ", $"{notifyItem.EventName}"); ConsoleHelper.Info(" State Parameters:"); - for (int i = 0; i < notifyItem.State.Length; i++) - ConsoleHelper.Info($" {GetMethodParameterName(notifyItem.ScriptHash, notifyItem.EventName, i)}: ", $"{notifyItem.State[i].ToJson()}"); + var ncount = (uint)notifyItem.State.Length; + for (var i = 0; i < ncount; i++) + ConsoleHelper.Info($" {GetMethodParameterName(notifyItem.ScriptHash, notifyItem.EventName, ncount, i)}: ", $"{notifyItem.State[i].ToJson()}"); ConsoleHelper.Info("--------------------------------"); } } - private string GetMethodParameterName(UInt160 scriptHash, string methodName, int parameterIndex) + private string GetMethodParameterName(UInt160 scriptHash, string methodName, uint ncount, int parameterIndex) { var contract = NativeContract.ContractManagement.GetContract(_neosystem.StoreView, scriptHash); if (contract == null) return $"{parameterIndex}"; - var contractEvent = contract.Manifest.Abi.Events.SingleOrDefault(s => s.Name == methodName); + var contractEvent = contract.Manifest.Abi.Events.SingleOrDefault(s => s.Name == methodName && (uint)s.Parameters.Length == ncount); + if (contractEvent == null) + return $"{parameterIndex}"; return contractEvent.Parameters[parameterIndex].Name; } From b2f060f11f5ac5713fc30255467100f0ff4c409d Mon Sep 17 00:00:00 2001 From: Jimmy Date: Fri, 21 Jun 2024 10:18:36 +0100 Subject: [PATCH 19/71] Plugin unhandled exception (#3349) * [Neo Core] Part 1. Isolate Plugins Exceptions from the Node. (#3309) * catch plugin exceptions. * add UT test * udpate format * make the test more complete * complete the ut test * format * complete UT tests with NonPlugin case * async invoke * Update src/Neo/Ledger/Blockchain.cs Co-authored-by: Christopher Schuchardt --------- Co-authored-by: Christopher Schuchardt * [Neo Plugin New feature] UnhandledExceptionPolicy on Plugin Unhandled Exception (#3311) * catch plugin exceptions. * add UT test * udpate format * make the test more complete * complete the ut test * format * complete UT tests with NonPlugin case * async invoke * stop plugin on exception * remove watcher from blockchain if uint test is done to avoid cross test data pollution. * add missing file * 3 different policy on handling plugin exception * add missing file * fix null warning * format * Apply suggestions from code review Clean * Update src/Neo/Plugins/PluginSettings.cs Co-authored-by: Shargon * Update src/Neo/Plugins/PluginSettings.cs Co-authored-by: Christopher Schuchardt * Update src/Plugins/TokensTracker/TokensTracker.cs Co-authored-by: Christopher Schuchardt * Update src/Plugins/TokensTracker/TokensTracker.json --------- Co-authored-by: Shargon Co-authored-by: Christopher Schuchardt * make the exception message clear --------- Co-authored-by: Christopher Schuchardt Co-authored-by: Shargon Co-authored-by: NGD Admin <154295625+NGDAdmin@users.noreply.github.com> --- src/Neo/Ledger/Blockchain.cs | 66 +++++++- src/Neo/Plugins/Plugin.cs | 56 ++++++- src/Neo/Plugins/PluginSettings.cs | 33 ++++ src/Neo/Plugins/UnhandledExceptionPolicy.cs | 20 +++ .../ApplicationLogs/ApplicationLogs.json | 3 +- src/Plugins/ApplicationLogs/LogReader.cs | 1 + src/Plugins/ApplicationLogs/Settings.cs | 4 +- src/Plugins/DBFTPlugin/DBFTPlugin.cs | 2 + src/Plugins/DBFTPlugin/DBFTPlugin.json | 3 +- src/Plugins/DBFTPlugin/Settings.cs | 4 +- src/Plugins/OracleService/OracleService.cs | 2 + src/Plugins/OracleService/OracleService.json | 1 + src/Plugins/OracleService/Settings.cs | 4 +- src/Plugins/RpcServer/RpcServer.json | 1 + src/Plugins/RpcServer/RpcServerPlugin.cs | 1 + src/Plugins/RpcServer/Settings.cs | 4 +- src/Plugins/StateService/Settings.cs | 4 +- src/Plugins/StateService/StatePlugin.cs | 2 + src/Plugins/StateService/StateService.json | 3 +- src/Plugins/StorageDumper/Settings.cs | 4 +- src/Plugins/StorageDumper/StorageDumper.cs | 2 +- src/Plugins/StorageDumper/StorageDumper.json | 3 +- src/Plugins/TokensTracker/TokensTracker.cs | 8 + src/Plugins/TokensTracker/TokensTracker.json | 3 +- tests/Neo.UnitTests/Plugins/TestPlugin.cs | 61 ++++++- tests/Neo.UnitTests/Plugins/UT_Plugin.cs | 151 ++++++++++++++++++ 26 files changed, 417 insertions(+), 29 deletions(-) create mode 100644 src/Neo/Plugins/PluginSettings.cs create mode 100644 src/Neo/Plugins/UnhandledExceptionPolicy.cs diff --git a/src/Neo/Ledger/Blockchain.cs b/src/Neo/Ledger/Blockchain.cs index ff9c8e29d8..b35dd069e3 100644 --- a/src/Neo/Ledger/Blockchain.cs +++ b/src/Neo/Ledger/Blockchain.cs @@ -12,18 +12,22 @@ using Akka.Actor; using Akka.Configuration; using Akka.IO; +using Akka.Util.Internal; using Neo.IO.Actors; using Neo.Network.P2P; using Neo.Network.P2P.Payloads; using Neo.Persistence; +using Neo.Plugins; using Neo.SmartContract; using Neo.SmartContract.Native; using Neo.VM; using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; using System.Linq; +using System.Threading.Tasks; namespace Neo.Ledger { @@ -468,10 +472,10 @@ private void Persist(Block block) Context.System.EventStream.Publish(application_executed); all_application_executed.Add(application_executed); } - Committing?.Invoke(system, block, snapshot, all_application_executed); + _ = InvokeCommittingAsync(system, block, snapshot, all_application_executed); snapshot.Commit(); } - Committed?.Invoke(system, block); + _ = InvokeCommittedAsync(system, block); system.MemPool.UpdatePoolForBlockPersisted(block, system.StoreView); extensibleWitnessWhiteList = null; block_cache.Remove(block.PrevHash); @@ -480,6 +484,64 @@ private void Persist(Block block) Debug.Assert(header.Index == block.Index); } + internal static async Task InvokeCommittingAsync(NeoSystem system, Block block, DataCache snapshot, IReadOnlyList applicationExecutedList) + { + await InvokeHandlersAsync(Committing?.GetInvocationList(), h => ((CommittingHandler)h)(system, block, snapshot, applicationExecutedList)); + } + + internal static async Task InvokeCommittedAsync(NeoSystem system, Block block) + { + await InvokeHandlersAsync(Committed?.GetInvocationList(), h => ((CommittedHandler)h)(system, block)); + } + + private static async Task InvokeHandlersAsync(Delegate[] handlers, Action handlerAction) + { + if (handlers == null) return; + + var exceptions = new ConcurrentBag(); + var tasks = handlers.Select(handler => Task.Run(() => + { + try + { + // skip stopped plugin. + if (handler.Target is Plugin { IsStopped: true }) + { + return; + } + + handlerAction(handler); + } + catch (Exception ex) when (handler.Target is Plugin plugin) + { + switch (plugin.ExceptionPolicy) + { + case UnhandledExceptionPolicy.StopNode: + exceptions.Add(ex); + throw; + case UnhandledExceptionPolicy.StopPlugin: + //Stop plugin on exception + plugin.IsStopped = true; + break; + case UnhandledExceptionPolicy.Ignore: + // Log the exception and continue with the next handler + break; + default: + throw new InvalidCastException($"The exception policy {plugin.ExceptionPolicy} is not valid."); + } + + Utility.Log(nameof(plugin), LogLevel.Error, ex); + } + catch (Exception ex) + { + exceptions.Add(ex); + } + })).ToList(); + + await Task.WhenAll(tasks); + + exceptions.ForEach(e => throw e); + } + /// /// Gets a object used for creating the actor. /// diff --git a/src/Neo/Plugins/Plugin.cs b/src/Neo/Plugins/Plugin.cs index 248301af56..9feee25d57 100644 --- a/src/Neo/Plugins/Plugin.cs +++ b/src/Neo/Plugins/Plugin.cs @@ -33,7 +33,8 @@ public abstract class Plugin : IDisposable /// /// The directory containing the plugin folders. Files can be contained in any subdirectory. /// - public static readonly string PluginsDirectory = Combine(GetDirectoryName(System.AppContext.BaseDirectory), "Plugins"); + public static readonly string PluginsDirectory = + Combine(GetDirectoryName(System.AppContext.BaseDirectory), "Plugins"); private static readonly FileSystemWatcher configWatcher; @@ -67,6 +68,18 @@ public abstract class Plugin : IDisposable /// public virtual Version Version => GetType().Assembly.GetName().Version; + /// + /// If the plugin should be stopped when an exception is thrown. + /// Default is . + /// + protected internal virtual UnhandledExceptionPolicy ExceptionPolicy { get; init; } = UnhandledExceptionPolicy.StopNode; + + /// + /// The plugin will be stopped if an exception is thrown. + /// But it also depends on . + /// + internal bool IsStopped { get; set; } + static Plugin() { if (!Directory.Exists(PluginsDirectory)) return; @@ -74,7 +87,8 @@ static Plugin() { EnableRaisingEvents = true, IncludeSubdirectories = true, - NotifyFilter = NotifyFilters.FileName | NotifyFilters.DirectoryName | NotifyFilters.CreationTime | NotifyFilters.LastWrite | NotifyFilters.Size, + NotifyFilter = NotifyFilters.FileName | NotifyFilters.DirectoryName | NotifyFilters.CreationTime | + NotifyFilters.LastWrite | NotifyFilters.Size, }; configWatcher.Changed += ConfigWatcher_Changed; configWatcher.Created += ConfigWatcher_Changed; @@ -106,7 +120,8 @@ private static void ConfigWatcher_Changed(object sender, FileSystemEventArgs e) { case ".json": case ".dll": - Utility.Log(nameof(Plugin), LogLevel.Warning, $"File {e.Name} is {e.ChangeType}, please restart node."); + Utility.Log(nameof(Plugin), LogLevel.Warning, + $"File {e.Name} is {e.ChangeType}, please restart node."); break; } } @@ -119,7 +134,8 @@ private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEven AssemblyName an = new(args.Name); Assembly assembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(a => a.FullName == args.Name) ?? - AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(a => a.GetName().Name == an.Name); + AppDomain.CurrentDomain.GetAssemblies() + .FirstOrDefault(a => a.GetName().Name == an.Name); if (assembly != null) return assembly; string filename = an.Name + ".dll"; @@ -150,7 +166,8 @@ public virtual void Dispose() /// The content of the configuration file read. protected IConfigurationSection GetConfiguration() { - return new ConfigurationBuilder().AddJsonFile(ConfigFile, optional: true).Build().GetSection("PluginConfiguration"); + return new ConfigurationBuilder().AddJsonFile(ConfigFile, optional: true).Build() + .GetSection("PluginConfiguration"); } private static void LoadPlugin(Assembly assembly) @@ -187,6 +204,7 @@ internal static void LoadPlugins() catch { } } } + foreach (Assembly assembly in assemblies) { LoadPlugin(assembly); @@ -229,7 +247,33 @@ protected internal virtual void OnSystemLoaded(NeoSystem system) /// if the is handled by a plugin; otherwise, . public static bool SendMessage(object message) { - return Plugins.Any(plugin => plugin.OnMessage(message)); + + return Plugins.Any(plugin => + { + try + { + return !plugin.IsStopped && + plugin.OnMessage(message); + } + catch (Exception ex) + { + switch (plugin.ExceptionPolicy) + { + case UnhandledExceptionPolicy.StopNode: + throw; + case UnhandledExceptionPolicy.StopPlugin: + plugin.IsStopped = true; + break; + case UnhandledExceptionPolicy.Ignore: + break; + default: + throw new InvalidCastException($"The exception policy {plugin.ExceptionPolicy} is not valid."); + } + Utility.Log(nameof(Plugin), LogLevel.Error, ex); + return false; + } + } + ); } } } diff --git a/src/Neo/Plugins/PluginSettings.cs b/src/Neo/Plugins/PluginSettings.cs new file mode 100644 index 0000000000..af33e44eea --- /dev/null +++ b/src/Neo/Plugins/PluginSettings.cs @@ -0,0 +1,33 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// PluginSettings.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using Microsoft.Extensions.Configuration; +using Org.BouncyCastle.Security; +using System; + +namespace Neo.Plugins; + +public abstract class PluginSettings(IConfigurationSection section) +{ + public UnhandledExceptionPolicy ExceptionPolicy + { + get + { + var policyString = section.GetValue(nameof(UnhandledExceptionPolicy), nameof(UnhandledExceptionPolicy.StopNode)); + if (Enum.TryParse(policyString, out UnhandledExceptionPolicy policy)) + { + return policy; + } + + throw new InvalidParameterException($"{policyString} is not a valid UnhandledExceptionPolicy"); + } + } +} diff --git a/src/Neo/Plugins/UnhandledExceptionPolicy.cs b/src/Neo/Plugins/UnhandledExceptionPolicy.cs new file mode 100644 index 0000000000..035e173aa3 --- /dev/null +++ b/src/Neo/Plugins/UnhandledExceptionPolicy.cs @@ -0,0 +1,20 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UnhandledExceptionPolicy.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +namespace Neo.Plugins +{ + public enum UnhandledExceptionPolicy + { + Ignore = 0, + StopPlugin = 1, + StopNode = 2, + } +} diff --git a/src/Plugins/ApplicationLogs/ApplicationLogs.json b/src/Plugins/ApplicationLogs/ApplicationLogs.json index af601bc81e..2664665dd2 100644 --- a/src/Plugins/ApplicationLogs/ApplicationLogs.json +++ b/src/Plugins/ApplicationLogs/ApplicationLogs.json @@ -3,7 +3,8 @@ "Path": "ApplicationLogs_{0}", "Network": 860833102, "MaxStackSize": 65535, - "Debug": false + "Debug": false, + "UnhandledExceptionPolicy": "StopPlugin" }, "Dependency": [ "RpcServer" diff --git a/src/Plugins/ApplicationLogs/LogReader.cs b/src/Plugins/ApplicationLogs/LogReader.cs index 3c1b5ecb94..f9d1470f03 100644 --- a/src/Plugins/ApplicationLogs/LogReader.cs +++ b/src/Plugins/ApplicationLogs/LogReader.cs @@ -38,6 +38,7 @@ public class LogReader : Plugin, ICommittingHandler, ICommittedHandler, ILogHand public override string Name => "ApplicationLogs"; public override string Description => "Synchronizes smart contract VM executions and notifications (NotifyLog) on blockchain."; + protected override UnhandledExceptionPolicy ExceptionPolicy => Settings.Default.ExceptionPolicy; #region Ctor diff --git a/src/Plugins/ApplicationLogs/Settings.cs b/src/Plugins/ApplicationLogs/Settings.cs index 8f2a0da1e1..6a5f238272 100644 --- a/src/Plugins/ApplicationLogs/Settings.cs +++ b/src/Plugins/ApplicationLogs/Settings.cs @@ -13,7 +13,7 @@ namespace Neo.Plugins.ApplicationLogs { - internal class Settings + internal class Settings : PluginSettings { public string Path { get; } public uint Network { get; } @@ -23,7 +23,7 @@ internal class Settings public static Settings Default { get; private set; } - private Settings(IConfigurationSection section) + private Settings(IConfigurationSection section) : base(section) { Path = section.GetValue("Path", "ApplicationLogs_{0}"); Network = section.GetValue("Network", 5195086u); diff --git a/src/Plugins/DBFTPlugin/DBFTPlugin.cs b/src/Plugins/DBFTPlugin/DBFTPlugin.cs index f09be9d291..65fc5011dc 100644 --- a/src/Plugins/DBFTPlugin/DBFTPlugin.cs +++ b/src/Plugins/DBFTPlugin/DBFTPlugin.cs @@ -31,6 +31,8 @@ public class DBFTPlugin : Plugin, IServiceAddedHandler, IMessageReceivedHandler, public override string ConfigFile => System.IO.Path.Combine(RootPath, "DBFTPlugin.json"); + protected override UnhandledExceptionPolicy ExceptionPolicy => settings.ExceptionPolicy; + public DBFTPlugin() { RemoteNode.MessageReceived += ((IMessageReceivedHandler)this).RemoteNode_MessageReceived_Handler; diff --git a/src/Plugins/DBFTPlugin/DBFTPlugin.json b/src/Plugins/DBFTPlugin/DBFTPlugin.json index 2e2b710ba3..705b2b77cb 100644 --- a/src/Plugins/DBFTPlugin/DBFTPlugin.json +++ b/src/Plugins/DBFTPlugin/DBFTPlugin.json @@ -5,6 +5,7 @@ "AutoStart": false, "Network": 860833102, "MaxBlockSize": 2097152, - "MaxBlockSystemFee": 150000000000 + "MaxBlockSystemFee": 150000000000, + "UnhandledExceptionPolicy": "StopNode" } } diff --git a/src/Plugins/DBFTPlugin/Settings.cs b/src/Plugins/DBFTPlugin/Settings.cs index 28ad21f37a..1f37feaf16 100644 --- a/src/Plugins/DBFTPlugin/Settings.cs +++ b/src/Plugins/DBFTPlugin/Settings.cs @@ -13,7 +13,7 @@ namespace Neo.Plugins.DBFTPlugin { - public class Settings + public class Settings : PluginSettings { public string RecoveryLogs { get; } public bool IgnoreRecoveryLogs { get; } @@ -22,7 +22,7 @@ public class Settings public uint MaxBlockSize { get; } public long MaxBlockSystemFee { get; } - public Settings(IConfigurationSection section) + public Settings(IConfigurationSection section) : base(section) { RecoveryLogs = section.GetValue("RecoveryLogs", "ConsensusState"); IgnoreRecoveryLogs = section.GetValue("IgnoreRecoveryLogs", false); diff --git a/src/Plugins/OracleService/OracleService.cs b/src/Plugins/OracleService/OracleService.cs index 6041bbb0ca..a1a3e92eae 100644 --- a/src/Plugins/OracleService/OracleService.cs +++ b/src/Plugins/OracleService/OracleService.cs @@ -62,6 +62,8 @@ public class OracleService : Plugin, ICommittingHandler, IServiceAddedHandler, I public override string Description => "Built-in oracle plugin"; + protected override UnhandledExceptionPolicy ExceptionPolicy => Settings.Default.ExceptionPolicy; + public override string ConfigFile => System.IO.Path.Combine(RootPath, "OracleService.json"); public OracleService() diff --git a/src/Plugins/OracleService/OracleService.json b/src/Plugins/OracleService/OracleService.json index 1ab0d93399..49bf1153b3 100644 --- a/src/Plugins/OracleService/OracleService.json +++ b/src/Plugins/OracleService/OracleService.json @@ -6,6 +6,7 @@ "MaxOracleTimeout": 10000, "AllowPrivateHost": false, "AllowedContentTypes": [ "application/json" ], + "UnhandledExceptionPolicy": "Ignore", "Https": { "Timeout": 5000 }, diff --git a/src/Plugins/OracleService/Settings.cs b/src/Plugins/OracleService/Settings.cs index 952ea0c27b..db93c1c400 100644 --- a/src/Plugins/OracleService/Settings.cs +++ b/src/Plugins/OracleService/Settings.cs @@ -37,7 +37,7 @@ public NeoFSSettings(IConfigurationSection section) } } - class Settings + class Settings : PluginSettings { public uint Network { get; } public Uri[] Nodes { get; } @@ -51,7 +51,7 @@ class Settings public static Settings Default { get; private set; } - private Settings(IConfigurationSection section) + private Settings(IConfigurationSection section) : base(section) { Network = section.GetValue("Network", 5195086u); Nodes = section.GetSection("Nodes").GetChildren().Select(p => new Uri(p.Get(), UriKind.Absolute)).ToArray(); diff --git a/src/Plugins/RpcServer/RpcServer.json b/src/Plugins/RpcServer/RpcServer.json index 8f6905dead..dc9c25b8da 100644 --- a/src/Plugins/RpcServer/RpcServer.json +++ b/src/Plugins/RpcServer/RpcServer.json @@ -1,5 +1,6 @@ { "PluginConfiguration": { + "UnhandledExceptionPolicy": "Ignore", "Servers": [ { "Network": 860833102, diff --git a/src/Plugins/RpcServer/RpcServerPlugin.cs b/src/Plugins/RpcServer/RpcServerPlugin.cs index c22462d139..03416c1be5 100644 --- a/src/Plugins/RpcServer/RpcServerPlugin.cs +++ b/src/Plugins/RpcServer/RpcServerPlugin.cs @@ -24,6 +24,7 @@ public class RpcServerPlugin : Plugin private static readonly Dictionary> handlers = new(); public override string ConfigFile => System.IO.Path.Combine(RootPath, "RpcServer.json"); + protected override UnhandledExceptionPolicy ExceptionPolicy => settings.ExceptionPolicy; protected override void Configure() { diff --git a/src/Plugins/RpcServer/Settings.cs b/src/Plugins/RpcServer/Settings.cs index ad624d9082..2cf7b72fb8 100644 --- a/src/Plugins/RpcServer/Settings.cs +++ b/src/Plugins/RpcServer/Settings.cs @@ -18,11 +18,11 @@ namespace Neo.Plugins.RpcServer { - class Settings + class Settings : PluginSettings { public IReadOnlyList Servers { get; init; } - public Settings(IConfigurationSection section) + public Settings(IConfigurationSection section) : base(section) { Servers = section.GetSection(nameof(Servers)).GetChildren().Select(p => RpcServerSettings.Load(p)).ToArray(); } diff --git a/src/Plugins/StateService/Settings.cs b/src/Plugins/StateService/Settings.cs index 8557866bc1..a425b57d7e 100644 --- a/src/Plugins/StateService/Settings.cs +++ b/src/Plugins/StateService/Settings.cs @@ -13,7 +13,7 @@ namespace Neo.Plugins.StateService { - internal class Settings + internal class Settings : PluginSettings { public string Path { get; } public bool FullState { get; } @@ -23,7 +23,7 @@ internal class Settings public static Settings Default { get; private set; } - private Settings(IConfigurationSection section) + private Settings(IConfigurationSection section) : base(section) { Path = section.GetValue("Path", "Data_MPT_{0}"); FullState = section.GetValue("FullState", false); diff --git a/src/Plugins/StateService/StatePlugin.cs b/src/Plugins/StateService/StatePlugin.cs index 5f6e1ef1d8..03dcc55aac 100644 --- a/src/Plugins/StateService/StatePlugin.cs +++ b/src/Plugins/StateService/StatePlugin.cs @@ -41,6 +41,8 @@ public class StatePlugin : Plugin, ICommittingHandler, ICommittedHandler, IWalle public override string Description => "Enables MPT for the node"; public override string ConfigFile => System.IO.Path.Combine(RootPath, "StateService.json"); + protected override UnhandledExceptionPolicy ExceptionPolicy => Settings.Default.ExceptionPolicy; + internal IActorRef Store; internal IActorRef Verifier; diff --git a/src/Plugins/StateService/StateService.json b/src/Plugins/StateService/StateService.json index 265436fc30..cadd2da5fd 100644 --- a/src/Plugins/StateService/StateService.json +++ b/src/Plugins/StateService/StateService.json @@ -4,7 +4,8 @@ "FullState": false, "Network": 860833102, "AutoVerify": false, - "MaxFindResultItems": 100 + "MaxFindResultItems": 100, + "UnhandledExceptionPolicy": "StopPlugin" }, "Dependency": [ "RpcServer" diff --git a/src/Plugins/StorageDumper/Settings.cs b/src/Plugins/StorageDumper/Settings.cs index c2761ce6b9..e645cd7074 100644 --- a/src/Plugins/StorageDumper/Settings.cs +++ b/src/Plugins/StorageDumper/Settings.cs @@ -14,7 +14,7 @@ namespace Neo.Plugins.StorageDumper { - internal class Settings + internal class Settings : PluginSettings { /// /// Amount of storages states (heights) to be dump in a given json file @@ -32,7 +32,7 @@ internal class Settings public static Settings? Default { get; private set; } - private Settings(IConfigurationSection section) + private Settings(IConfigurationSection section) : base(section) { // Geting settings for storage changes state dumper BlockCacheSize = section.GetValue("BlockCacheSize", 1000u); diff --git a/src/Plugins/StorageDumper/StorageDumper.cs b/src/Plugins/StorageDumper/StorageDumper.cs index c47df9ac1d..6f5498b3a2 100644 --- a/src/Plugins/StorageDumper/StorageDumper.cs +++ b/src/Plugins/StorageDumper/StorageDumper.cs @@ -30,7 +30,7 @@ public class StorageDumper : Plugin, ICommittingHandler, ICommittedHandler /// private JObject? _currentBlock; private string? _lastCreateDirectory; - + protected override UnhandledExceptionPolicy ExceptionPolicy => Settings.Default?.ExceptionPolicy ?? UnhandledExceptionPolicy.Ignore; public override string Description => "Exports Neo-CLI status data"; diff --git a/src/Plugins/StorageDumper/StorageDumper.json b/src/Plugins/StorageDumper/StorageDumper.json index b327c37e0c..0c314cf262 100644 --- a/src/Plugins/StorageDumper/StorageDumper.json +++ b/src/Plugins/StorageDumper/StorageDumper.json @@ -3,6 +3,7 @@ "BlockCacheSize": 1000, "HeightToBegin": 0, "StoragePerFolder": 100000, - "Exclude": [ -4 ] + "Exclude": [ -4 ], + "UnhandledExceptionPolicy": "Ignore" } } diff --git a/src/Plugins/TokensTracker/TokensTracker.cs b/src/Plugins/TokensTracker/TokensTracker.cs index e5ffdce3f4..a7ab075245 100644 --- a/src/Plugins/TokensTracker/TokensTracker.cs +++ b/src/Plugins/TokensTracker/TokensTracker.cs @@ -16,6 +16,7 @@ using Neo.Persistence; using Neo.Plugins.RpcServer; using Neo.Plugins.Trackers; +using System; using System.Collections.Generic; using System.Linq; using static System.IO.Path; @@ -30,8 +31,10 @@ public class TokensTracker : Plugin, ICommittingHandler, ICommittedHandler private uint _network; private string[] _enabledTrackers; private IStore _db; + private UnhandledExceptionPolicy _exceptionPolicy; private NeoSystem neoSystem; private readonly List trackers = new(); + protected override UnhandledExceptionPolicy ExceptionPolicy => _exceptionPolicy; public override string Description => "Enquiries balances and transaction history of accounts through RPC"; @@ -57,6 +60,11 @@ protected override void Configure() _maxResults = config.GetValue("MaxResults", 1000u); _network = config.GetValue("Network", 860833102u); _enabledTrackers = config.GetSection("EnabledTrackers").GetChildren().Select(p => p.Value).ToArray(); + var policyString = config.GetValue(nameof(UnhandledExceptionPolicy), nameof(UnhandledExceptionPolicy.StopNode)); + if (Enum.TryParse(policyString, out UnhandledExceptionPolicy policy)) + { + _exceptionPolicy = policy; + } } protected override void OnSystemLoaded(NeoSystem system) diff --git a/src/Plugins/TokensTracker/TokensTracker.json b/src/Plugins/TokensTracker/TokensTracker.json index ca63183b68..dbdbecfd40 100644 --- a/src/Plugins/TokensTracker/TokensTracker.json +++ b/src/Plugins/TokensTracker/TokensTracker.json @@ -4,7 +4,8 @@ "TrackHistory": true, "MaxResults": 1000, "Network": 860833102, - "EnabledTrackers": [ "NEP-11", "NEP-17" ] + "EnabledTrackers": [ "NEP-11", "NEP-17" ], + "UnhandledExceptionPolicy": "StopPlugin" }, "Dependency": [ "RpcServer" diff --git a/tests/Neo.UnitTests/Plugins/TestPlugin.cs b/tests/Neo.UnitTests/Plugins/TestPlugin.cs index dde500b927..5e51220c7f 100644 --- a/tests/Neo.UnitTests/Plugins/TestPlugin.cs +++ b/tests/Neo.UnitTests/Plugins/TestPlugin.cs @@ -10,15 +10,60 @@ // modifications are permitted. using Microsoft.Extensions.Configuration; +using Neo.Ledger; +using Neo.Network.P2P.Payloads; +using Neo.Persistence; using Neo.Plugins; +using System; +using System.Collections.Generic; namespace Neo.UnitTests.Plugins { - public class TestPlugin : Plugin + + internal class TestPluginSettings(IConfigurationSection section) : PluginSettings(section) + { + public static TestPluginSettings Default { get; private set; } + public static void Load(IConfigurationSection section) + { + Default = new TestPluginSettings(section); + } + } + internal class TestNonPlugin + { + public TestNonPlugin() + { + Blockchain.Committing += OnCommitting; + Blockchain.Committed += OnCommitted; + } + + private void OnCommitting(NeoSystem system, Block block, DataCache snapshot, IReadOnlyList applicationExecutedList) + { + throw new NotImplementedException("Test exception from OnCommitting"); + } + + private void OnCommitted(NeoSystem system, Block block) + { + throw new NotImplementedException("Test exception from OnCommitted"); + } + } + + + internal class TestPlugin : Plugin { - public TestPlugin() : base() { } + private readonly UnhandledExceptionPolicy _exceptionPolicy; + protected internal override UnhandledExceptionPolicy ExceptionPolicy => _exceptionPolicy; - protected override void Configure() { } + public TestPlugin(UnhandledExceptionPolicy exceptionPolicy = UnhandledExceptionPolicy.StopPlugin) : base() + { + Blockchain.Committing += OnCommitting; + Blockchain.Committed += OnCommitted; + _exceptionPolicy = exceptionPolicy; + } + + protected override void Configure() + { + TestPluginSettings.Load(GetConfiguration()); + } public void LogMessage(string message) { @@ -36,5 +81,15 @@ public IConfigurationSection TestGetConfiguration() } protected override bool OnMessage(object message) => true; + + private void OnCommitting(NeoSystem system, Block block, DataCache snapshot, IReadOnlyList applicationExecutedList) + { + throw new NotImplementedException(); + } + + private void OnCommitted(NeoSystem system, Block block) + { + throw new NotImplementedException(); + } } } diff --git a/tests/Neo.UnitTests/Plugins/UT_Plugin.cs b/tests/Neo.UnitTests/Plugins/UT_Plugin.cs index e5e8cb6e49..c48d32563f 100644 --- a/tests/Neo.UnitTests/Plugins/UT_Plugin.cs +++ b/tests/Neo.UnitTests/Plugins/UT_Plugin.cs @@ -11,8 +11,11 @@ using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Ledger; using Neo.Plugins; using System; +using System.Reflection; +using System.Threading.Tasks; namespace Neo.UnitTests.Plugins { @@ -21,6 +24,50 @@ public class UT_Plugin { private static readonly object locker = new(); + [TestInitialize] + public void TestInitialize() + { + ClearEventHandlers(); + } + + [TestCleanup] + public void TestCleanup() + { + ClearEventHandlers(); + } + + private static void ClearEventHandlers() + { + ClearEventHandler("Committing"); + ClearEventHandler("Committed"); + } + + private static void ClearEventHandler(string eventName) + { + var eventInfo = typeof(Blockchain).GetEvent(eventName, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); + if (eventInfo == null) + { + return; + } + + var fields = typeof(Blockchain).GetFields(BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public); + foreach (var field in fields) + { + if (field.FieldType == typeof(MulticastDelegate) || field.FieldType.BaseType == typeof(MulticastDelegate)) + { + var eventDelegate = (MulticastDelegate)field.GetValue(null); + if (eventDelegate != null && field.Name.Contains(eventName)) + { + foreach (var handler in eventDelegate.GetInvocationList()) + { + eventInfo.RemoveEventHandler(null, handler); + } + break; + } + } + } + } + [TestMethod] public void TestGetConfigFile() { @@ -63,5 +110,109 @@ public void TestGetConfiguration() var pp = new TestPlugin(); pp.TestGetConfiguration().Key.Should().Be("PluginConfiguration"); } + + [TestMethod] + public async Task TestOnException() + { + _ = new TestPlugin(); + // Ensure no exception is thrown + try + { + await Blockchain.InvokeCommittingAsync(null, null, null, null); + await Blockchain.InvokeCommittedAsync(null, null); + } + catch (Exception ex) + { + Assert.Fail($"InvokeCommitting or InvokeCommitted threw an exception: {ex.Message}"); + } + + // Register TestNonPlugin that throws exceptions + _ = new TestNonPlugin(); + + // Ensure exception is thrown + await Assert.ThrowsExceptionAsync(async () => + { + await Blockchain.InvokeCommittingAsync(null, null, null, null); + }); + + await Assert.ThrowsExceptionAsync(async () => + { + await Blockchain.InvokeCommittedAsync(null, null); + }); + } + + [TestMethod] + public async Task TestOnPluginStopped() + { + var pp = new TestPlugin(); + Assert.AreEqual(false, pp.IsStopped); + // Ensure no exception is thrown + try + { + await Blockchain.InvokeCommittingAsync(null, null, null, null); + await Blockchain.InvokeCommittedAsync(null, null); + } + catch (Exception ex) + { + Assert.Fail($"InvokeCommitting or InvokeCommitted threw an exception: {ex.Message}"); + } + + Assert.AreEqual(true, pp.IsStopped); + } + + [TestMethod] + public async Task TestOnPluginStopOnException() + { + // pp will stop on exception. + var pp = new TestPlugin(); + Assert.AreEqual(false, pp.IsStopped); + // Ensure no exception is thrown + try + { + await Blockchain.InvokeCommittingAsync(null, null, null, null); + await Blockchain.InvokeCommittedAsync(null, null); + } + catch (Exception ex) + { + Assert.Fail($"InvokeCommitting or InvokeCommitted threw an exception: {ex.Message}"); + } + + Assert.AreEqual(true, pp.IsStopped); + + // pp2 will not stop on exception. + var pp2 = new TestPlugin(UnhandledExceptionPolicy.Ignore); + Assert.AreEqual(false, pp2.IsStopped); + // Ensure no exception is thrown + try + { + await Blockchain.InvokeCommittingAsync(null, null, null, null); + await Blockchain.InvokeCommittedAsync(null, null); + } + catch (Exception ex) + { + Assert.Fail($"InvokeCommitting or InvokeCommitted threw an exception: {ex.Message}"); + } + + Assert.AreEqual(false, pp2.IsStopped); + } + + [TestMethod] + public async Task TestOnNodeStopOnPluginException() + { + // node will stop on pp exception. + var pp = new TestPlugin(UnhandledExceptionPolicy.StopNode); + Assert.AreEqual(false, pp.IsStopped); + await Assert.ThrowsExceptionAsync(async () => + { + await Blockchain.InvokeCommittingAsync(null, null, null, null); + }); + + await Assert.ThrowsExceptionAsync(async () => + { + await Blockchain.InvokeCommittedAsync(null, null); + }); + + Assert.AreEqual(false, pp.IsStopped); + } } } From 2d0395ffcf9116d3f48a7158cbd3e006e9259e77 Mon Sep 17 00:00:00 2001 From: Christopher Schuchardt Date: Tue, 25 Jun 2024 22:15:51 -0400 Subject: [PATCH 20/71] Revert "Fixed Props paths for `*.csproj` builds (#3320)" (#3352) This reverts commit 2bd2a4522f365fb314f9b49aeef866b60da986c6. --- src/Directory.Build.props | 4 ++-- src/Plugins/Directory.Build.props | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Directory.Build.props b/src/Directory.Build.props index e751a3b92c..b2a79557e2 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -19,8 +19,8 @@ - - + + diff --git a/src/Plugins/Directory.Build.props b/src/Plugins/Directory.Build.props index e7cfbdeb1e..72e96f0300 100644 --- a/src/Plugins/Directory.Build.props +++ b/src/Plugins/Directory.Build.props @@ -4,12 +4,12 @@ - - + + - + From aaf5ef694be5c9fb663acc15bbb892c6046d3515 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Wed, 26 Jun 2024 12:24:18 +1000 Subject: [PATCH 21/71] [Neo VM Style] Add comments and document to reference counter (#3331) * add comments * fix doc * Update src/Neo.VM/Types/Array.cs * Update ReferenceCounter.md * Update src/Neo.VM/ReferenceCounter.md --------- Co-authored-by: NGD Admin <154295625+NGDAdmin@users.noreply.github.com> --- src/Neo.VM/ReferenceCounter.cs | 211 +++++++++++++++++++---- src/Neo.VM/ReferenceCounter.md | 241 +++++++++++++++++++++++++++ src/Neo.VM/Types/StackItem.Vertex.cs | 86 ++++++++++ 3 files changed, 503 insertions(+), 35 deletions(-) create mode 100644 src/Neo.VM/ReferenceCounter.md diff --git a/src/Neo.VM/ReferenceCounter.cs b/src/Neo.VM/ReferenceCounter.cs index be7844dac8..f9ea08a2e2 100644 --- a/src/Neo.VM/ReferenceCounter.cs +++ b/src/Neo.VM/ReferenceCounter.cs @@ -22,86 +22,180 @@ namespace Neo.VM /// public sealed class ReferenceCounter { + // If set to true, all items will be tracked regardless of their type. private const bool TrackAllItems = false; - private readonly HashSet tracked_items = new(ReferenceEqualityComparer.Instance); - private readonly HashSet zero_referred = new(ReferenceEqualityComparer.Instance); - private LinkedList>? cached_components; - private int references_count = 0; + // Stores items that are being tracked for references. + // Only CompoundType and Buffer items are tracked. + private readonly HashSet _trackedItems = new(ReferenceEqualityComparer.Instance); + + // Stores items that have zero references. + private readonly HashSet _zeroReferred = new(ReferenceEqualityComparer.Instance); + + // Caches strongly connected components for optimization. + private LinkedList>? _cachedComponents; + + // Keeps the total count of references. + private int _referencesCount = 0; /// - /// Indicates the number of this counter. + /// Gets the count of references. /// - public int Count => references_count; + public int Count => _referencesCount; + /// + /// Determines if an item needs to be tracked based on its type. + /// + /// The item to check. + /// True if the item needs to be tracked, otherwise false. [MethodImpl(MethodImplOptions.AggressiveInlining)] private static bool NeedTrack(StackItem item) { + // Track all items if TrackAllItems is true. #pragma warning disable CS0162 if (TrackAllItems) return true; #pragma warning restore CS0162 + + // Track the item if it is a CompoundType or Buffer. if (item is CompoundType or Buffer) return true; return false; } + /// + /// Adds a reference to a specified item with a parent compound type. + /// + /// This method is used when an item gains a new reference through a parent compound type. + /// It increments the reference count and updates the tracking structures if necessary. + /// + /// Use this method when you need to add a reference from a compound type to a stack item. + /// + /// The item to add a reference to. + /// The parent compound type. internal void AddReference(StackItem item, CompoundType parent) { - references_count++; + // Increment the reference count. + _referencesCount++; + + // If the item doesn't need to be tracked, return early. + // Only track CompoundType and Buffer items. if (!NeedTrack(item)) return; - cached_components = null; - tracked_items.Add(item); - item.ObjectReferences ??= new(ReferenceEqualityComparer.Instance); + + // Invalidate the cached components since the tracked items are changing. + _cachedComponents = null; + + // Add the item to the set of tracked items. + _trackedItems.Add(item); + + // Initialize the ObjectReferences dictionary if it is null. + item.ObjectReferences ??= new Dictionary(ReferenceEqualityComparer.Instance); + + // Add the parent to the item's ObjectReferences dictionary and increment its reference count. if (!item.ObjectReferences.TryGetValue(parent, out var pEntry)) { - pEntry = new(parent); + pEntry = new StackItem.ObjectReferenceEntry(parent); item.ObjectReferences.Add(parent, pEntry); } pEntry.References++; } + /// + /// Adds a stack reference to a specified item with a count. + /// + /// This method is used when an item gains a new stack reference, usually due to being pushed onto the evaluation stack. + /// It increments the reference count and updates the tracking structures if necessary. + /// + /// Use this method when you need to add one or more stack references to a stack item. + /// + /// The item to add a stack reference to. + /// The number of references to add. internal void AddStackReference(StackItem item, int count = 1) { - references_count += count; + // Increment the reference count by the specified count. + _referencesCount += count; + + // If the item doesn't need to be tracked, return early. if (!NeedTrack(item)) return; - if (tracked_items.Add(item)) - cached_components?.AddLast(new HashSet(ReferenceEqualityComparer.Instance) { item }); + + // Add the item to the set of tracked items and to the cached components if needed. + if (_trackedItems.Add(item)) + _cachedComponents?.AddLast(new HashSet(ReferenceEqualityComparer.Instance) { item }); + + // Increment the item's stack references by the specified count. item.StackReferences += count; - zero_referred.Remove(item); + + // Remove the item from the _zeroReferred set since it now has references. + _zeroReferred.Remove(item); } + /// + /// Adds an item to the zero-referred list. + /// + /// This method is used when an item has no remaining references. + /// It adds the item to the zero-referred list to be checked for cleanup later. + /// + /// Use this method when you detect that an item has zero references and may need to be cleaned up. + /// + /// The item to add. internal void AddZeroReferred(StackItem item) { - zero_referred.Add(item); + // Add the item to the _zeroReferred set. + _zeroReferred.Add(item); + + // If the item doesn't need to be tracked, return early. if (!NeedTrack(item)) return; - cached_components?.AddLast(new HashSet(ReferenceEqualityComparer.Instance) { item }); - tracked_items.Add(item); + + // Add the item to the cached components and the set of tracked items. + _cachedComponents?.AddLast(new HashSet(ReferenceEqualityComparer.Instance) { item }); + _trackedItems.Add(item); } + /// + /// Checks and processes items that have zero references. + /// + /// This method is used to check items in the zero-referred list and clean up those that are no longer needed. + /// It uses Tarjan's algorithm to find strongly connected components and remove those with no references. + /// + /// Use this method periodically to clean up items with zero references and free up memory. + /// + /// The current reference count. internal int CheckZeroReferred() { - if (zero_referred.Count > 0) + // If there are items with zero references, process them. + if (_zeroReferred.Count > 0) { - zero_referred.Clear(); - if (cached_components is null) + // Clear the zero_referred set since we are going to process all of them. + _zeroReferred.Clear(); + + // If cached components are null, we need to recompute the strongly connected components (SCCs). + if (_cachedComponents is null) { - //Tarjan tarjan = new(tracked_items.Where(p => p.StackReferences == 0)); - Tarjan tarjan = new(tracked_items); - cached_components = tarjan.Invoke(); + // Create a new Tarjan object and invoke it to find all SCCs in the tracked_items graph. + Tarjan tarjan = new(_trackedItems); + _cachedComponents = tarjan.Invoke(); } - foreach (StackItem item in tracked_items) + + // Reset all tracked items' Tarjan algorithm-related fields (DFN, LowLink, and OnStack). + foreach (StackItem item in _trackedItems) item.Reset(); - for (var node = cached_components.First; node != null;) + + // Process each SCC in the cached_components list. + for (var node = _cachedComponents.First; node != null;) { var component = node.Value; bool on_stack = false; + + // Check if any item in the SCC is still on the stack. foreach (StackItem item in component) { + // An item is considered 'on stack' if it has stack references or if its parent items are still on stack. if (item.StackReferences > 0 || item.ObjectReferences?.Values.Any(p => p.References > 0 && p.Item.OnStack) == true) { on_stack = true; break; } } + + // If any item in the component is on stack, mark all items in the component as on stack. if (on_stack) { foreach (StackItem item in component) @@ -110,46 +204,93 @@ internal int CheckZeroReferred() } else { + // Otherwise, remove the component and clean up the items. foreach (StackItem item in component) { - tracked_items.Remove(item); + _trackedItems.Remove(item); + + // If the item is a CompoundType, adjust the reference count and clean up its sub-items. if (item is CompoundType compound) { - references_count -= compound.SubItemsCount; + // Decrease the reference count by the number of sub-items. + _referencesCount -= compound.SubItemsCount; foreach (StackItem subitem in compound.SubItems) { + // Skip sub-items that are in the same component or don't need tracking. if (component.Contains(subitem)) continue; if (!NeedTrack(subitem)) continue; + + // Remove the parent reference from the sub-item. subitem.ObjectReferences!.Remove(compound); } } + + // Perform cleanup for the item. item.Cleanup(); } + + // Move to the next component and remove the current one from the cached_components list. var nodeToRemove = node; node = node.Next; - cached_components.Remove(nodeToRemove); + _cachedComponents.Remove(nodeToRemove); } } } - return references_count; + + // Return the current total reference count. + return _referencesCount; } + + /// + /// Removes a reference from a specified item with a parent compound type. + /// + /// This method is used when an item loses a reference from a parent compound type. + /// It decrements the reference count and updates the tracking structures if necessary. + /// + /// Use this method when you need to remove a reference from a compound type to a stack item. + /// + /// The item to remove a reference from. + /// The parent compound type. internal void RemoveReference(StackItem item, CompoundType parent) { - references_count--; + // Decrement the reference count. + _referencesCount--; + + // If the item doesn't need to be tracked, return early. if (!NeedTrack(item)) return; - cached_components = null; + + // Invalidate the cached components since the tracked items are changing. + _cachedComponents = null; + + // Decrement the reference count for the parent in the item's ObjectReferences dictionary. item.ObjectReferences![parent].References--; + + // If the item has no stack references, add it to the zero_referred set. if (item.StackReferences == 0) - zero_referred.Add(item); + _zeroReferred.Add(item); } + /// + /// Removes a stack reference from a specified item. + /// + /// This method is used when an item loses a stack reference, usually due to being popped off the evaluation stack. + /// It decrements the reference count and updates the tracking structures if necessary. + /// + /// Use this method when you need to remove one or more stack references from a stack item. + /// + /// The item to remove a stack reference from. internal void RemoveStackReference(StackItem item) { - references_count--; + // Decrement the reference count. + _referencesCount--; + + // If the item doesn't need to be tracked, return early. if (!NeedTrack(item)) return; + + // Decrement the item's stack references and add it to the zero_referred set if it has no references. if (--item.StackReferences == 0) - zero_referred.Add(item); + _zeroReferred.Add(item); } } } diff --git a/src/Neo.VM/ReferenceCounter.md b/src/Neo.VM/ReferenceCounter.md new file mode 100644 index 0000000000..87c9bd489e --- /dev/null +++ b/src/Neo.VM/ReferenceCounter.md @@ -0,0 +1,241 @@ +# ReferenceCounter + +`ReferenceCounter` is a reference counting manager for use in a virtual machine (VM). It is designed to track and manage the reference counts of objects to ensure they are correctly cleaned up when no longer referenced, thereby preventing memory leaks. + +## Purpose + +In a virtual machine, managing object memory is crucial. The main purposes of `ReferenceCounter` are: + +1. **Tracking Object References**: Manage and track the reference relationships between objects. +2. **Memory Management**: Ensure that objects are correctly released when they are no longer referenced. +3. **Preventing Memory Leaks**: Avoid memory leaks by using reference counting and detecting circular references. + +## Technical Principles + +### Reference Counting + +Reference counting is a memory management technique used to track the number of references to each object. When an object's reference count drops to zero, it indicates that the object is no longer in use and can be safely cleaned up. `ReferenceCounter` uses the principles of reference counting to manage the lifecycle of objects: + +- **Increment Reference Count**: Increase the reference count when an object is referenced. +- **Decrement Reference Count**: Decrease the reference count when a reference is removed. +- **Cleanup Object**: Cleanup the object when its reference count drops to zero. + +### What is Tracked + +In the Neo VM, the `ReferenceCounter` class is used to count references to objects to track and manage `StackItem` references. The `reference_count` calculates the total number of current references, including stack references and object references. Specifically, the `reference_count` increases or decreases in the following situations: + +#### Increment Reference + +Use the `AddReference` method to increment the reference count of an object: + +```csharp +internal void AddReference(StackItem item, CompoundType parent) +{ + references_count++; + if (!NeedTrack(item)) return; + cached_components = null; + tracked_items.Add(item); + item.ObjectReferences ??= new(ReferenceEqualityComparer.Instance); + if (!item.ObjectReferences.TryGetValue(parent, out var pEntry)) + { + pEntry = new(parent); + item.ObjectReferences.Add(parent, pEntry); + } + pEntry.References++; +} +``` + +#### Decrement Reference + +Use the `RemoveReference` method to decrement the reference count of an object: + +```csharp +internal void RemoveReference(StackItem item, CompoundType parent) +{ + references_count--; + if (!NeedTrack(item)) return; + cached_components = null; + item.ObjectReferences![parent].References--; + if (item.StackReferences == 0) + zero_referred.Add(item); +} +``` + +#### Increment Stack Reference + +Use the `AddStackReference` method to increment the stack reference count of an object: + +```csharp +internal void AddStackReference(StackItem item, int count = 1) +{ + references_count += count; + if (!NeedTrack(item)) return; + if (tracked_items.Add(item)) + cached_components?.AddLast(new HashSet(ReferenceEqualityComparer.Instance) { item }); + item.StackReferences += count; + zero_referred.Remove(item); +} +``` + +#### Decrement Stack Reference + +Use the `RemoveStackReference` method to decrement the stack reference count of an object: + +```csharp +internal void RemoveStackReference(StackItem item) +{ + references_count--; + if (!NeedTrack(item)) return; + if (--item.StackReferences == 0) + zero_referred.Add(item); +} +``` + +### Circular References + +Circular references occur when objects reference each other, preventing their reference counts from dropping to zero, which can lead to memory leaks. `ReferenceCounter` addresses circular references using the following methods: + +1. **Mark and Sweep**: Detect and clean up strongly connected components when circular references are identified using algorithms like Tarjan's algorithm. +2. **Recursive Reference Management**: Recursively manage the reference counts of nested objects to ensure all reference relationships are correctly handled. + +### Tarjan's Algorithm + +Tarjan's algorithm is a graph theory algorithm for finding strongly connected components (SCCs) in a directed graph. An SCC is a maximal subgraph where every vertex is reachable from every other vertex in the subgraph. In the context of `ReferenceCounter`, Tarjan's algorithm is used to detect circular references, allowing for efficient memory management and cleanup of objects that are no longer reachable. + +#### How Tarjan's Algorithm Works + +1. **Initialization**: + - Each node (object) in the graph is initially unvisited. The algorithm uses a stack to keep track of the current path and arrays (or lists) to store the discovery time (`DFN`) and the lowest point reachable (`LowLink`) for each node. + +2. **Depth-First Search (DFS)**: + - Starting from an unvisited node, the algorithm performs a DFS. Each node visited is assigned a discovery time and a `LowLink` value, both initially set to the node's discovery time. + +3. **Update LowLink**: + - For each node, the algorithm updates the `LowLink` value based on the nodes reachable from its descendants. If a descendant node points back to an ancestor in the current path (stack), the `LowLink` value of the current node is updated to the minimum of its own `LowLink` and the descendant's `LowLink`. + +4. **Identify SCCs**: + - When a node's `LowLink` value is equal to its discovery time, it indicates the root of an SCC. The algorithm then pops nodes from the stack until it reaches the current node, forming an SCC. + +5. **Cleanup**: + - Once SCCs are identified, nodes that have no remaining references are cleaned up, preventing memory leaks caused by circular references. + +### Tarjan's Algorithm in `ReferenceCounter` + +The `CheckZeroReferred` method in `ReferenceCounter` uses Tarjan's algorithm to detect and handle circular references. Here’s a detailed breakdown of the algorithm as used in `CheckZeroReferred`: + +```csharp +internal int CheckZeroReferred() +{ + // If there are items with zero references, process them. + if (zero_referred.Count > 0) + { + // Clear the zero_referred set since we are going to process all of them. + zero_referred.Clear(); + + // If cached components are null, we need to recompute the strongly connected components (SCCs). + if (cached_components is null) + { + // Create a new Tarjan object and invoke it to find all SCCs in the tracked_items graph. + Tarjan tarjan = new(tracked_items); + cached_components = tarjan.Invoke(); + } + + // Reset all tracked items' Tarjan algorithm-related fields (DFN, LowLink, and OnStack). + foreach (StackItem item in tracked_items) + item.Reset(); + + // Process each SCC in the cached_components list. + for (var node = cached_components.First; node != null;) + { + var component = node.Value; + bool on_stack = false; + + // Check if any item in the SCC is still on the stack. + foreach (StackItem item in component) + { + // An item is considered 'on stack' if it has stack references or if its parent items are still on stack. + if (item.StackReferences > 0 || item.ObjectReferences?.Values.Any(p => p.References > 0 && p.Item.OnStack) == true) + { + on_stack = true; + break; + } + } + + // If any item in the component is on stack, mark all items in the component as on stack. + if (on_stack) + { + foreach (StackItem item in component) + item.OnStack = true; + node = node.Next; + } + else + { + // Otherwise, remove the component and clean up the items. + foreach (StackItem item in component) + { + tracked_items.Remove(item); + + // If the item is a CompoundType, adjust the reference count and clean up its sub-items. + if (item is CompoundType compound) + { + // Decrease the reference count by the number of sub-items. + references_count -= compound.SubItemsCount; + foreach (StackItem subitem in compound.SubItems) + { + // Skip sub-items that are in the same component or don't need tracking. + if (component.Contains(subitem)) continue; + if (!NeedTrack(subitem)) continue; + + // Remove the parent reference from the sub-item. + subitem.ObjectReferences!.Remove(compound); + } + } + + // Perform cleanup for the item. + item.Cleanup(); + } + + // Move to the next component and remove the current one from the cached_components list. + var nodeToRemove = node; + node = node.Next; + cached_components.Remove(nodeToRemove); + } + } + } + + // Return the current total reference count. + return references_count; +} +``` + +### Detailed Explanation + +1. **Initialization and Check for Zero References**: + - The method starts by checking if there are any items in `zero_referred`. If there are, it clears the `zero_referred` set. + +2. **Compute Strongly Connected Components (SCCs)**: + - If there are no cached SCCs, it recomputes them using Tarjan's algorithm. This involves creating a `Tarjan` object, passing the `tracked_items` to it, and invoking the algorithm to get the SCCs. + +3. **Reset Tarjan-related Fields**: + - It resets the Tarjan-related fields (`DFN`, `LowLink`, `OnStack`) of all tracked items to prepare for processing SCCs. + +4. **Process Each SCC**: + - It iterates through each SCC (component) in the cached components list. For each component, it checks if any item is still on the stack by looking at its `StackReferences` or if any of its parent items are on the stack. + +5. **Mark Items as On Stack**: + - If any item in the component is still on the stack, it marks all items in the component as on the stack and moves to the next component. + +6. **Remove and Clean Up Items**: + - If no items in the component are on the stack, it removes the component and cleans up all items within it. For `CompoundType` items, it adjusts the reference count and removes parent references from their sub-items. It then performs cleanup on each item and removes the component from the cached components list. + +7. **Return Reference Count**: + - Finally, it returns the current total reference count. + +## Features + +`ReferenceCounter` provides the following features: + +1. **Increment Reference Count**: Increment the reference count of objects. +2. **Decrement Reference Count**: Decrement the reference count of objects. +3. **Check Zero-Referenced Objects**: Detect and clean up objects with a reference count of zero. +4. **Manage Nested References**: Recursively manage the reference counts of nested objects, supporting nested arrays of arbitrary depth. diff --git a/src/Neo.VM/Types/StackItem.Vertex.cs b/src/Neo.VM/Types/StackItem.Vertex.cs index a988d5db32..d3e9ed4dbd 100644 --- a/src/Neo.VM/Types/StackItem.Vertex.cs +++ b/src/Neo.VM/Types/StackItem.Vertex.cs @@ -17,23 +17,109 @@ namespace Neo.VM.Types { partial class StackItem { + /// + /// Represents an entry for an object reference. + /// + /// This class is used to keep track of references from compound types to other or . + /// It contains the referenced item and the number of references to it. + /// + /// Use this class to manage references from compound types to their child items. + /// + /// This is used to track references numbers from the same parent to the same child. + /// This is used for the purpose of determining strongly connect components. + /// + /// internal class ObjectReferenceEntry { + /// + /// The referenced StackItem. + /// public StackItem Item; + + /// + /// The number of references to the StackItem. + /// public int References; + + /// + /// Initializes a new instance of the ObjectReferenceEntry class with the specified StackItem. + /// + /// The referenced StackItem. public ObjectReferenceEntry(StackItem item) => Item = item; } + /// + /// The number of references to this StackItem from the evaluation stack. + /// + /// This field tracks how many times this item is referenced by the evaluation stack. + /// It is incremented when the item is pushed onto the stack and decremented when it is popped off. + /// + /// Use this field to manage stack references and determine when an item is no longer needed. + /// internal int StackReferences = 0; + + /// + /// A dictionary mapping compound types to their object reference entries. + /// + /// This dictionary is used to track references from compound types to their child items. + /// It allows efficient lookup and management of references. + /// + /// Use this dictionary to manage references from compound types to their children. + /// Only and will be assigned an , + /// other types will be null. + /// internal Dictionary? ObjectReferences; + + /// + /// Depth-First Number for Tarjan's algorithm. + /// internal int DFN = -1; + + /// + /// Low-link value for Tarjan's algorithm. + /// internal int LowLink = 0; + + /// + /// Indicates whether the item is currently on the stack for Tarjan's algorithm. + /// + /// + /// This should only be used for Tarjan algorithm, it can not be used to indicate + /// whether an item is on the stack or not since it can still be false if a value is + /// on the stack but the algorithm is not yet running. + /// + /// internal bool OnStack = false; + /// + /// Returns the successors of the current item based on object references. + /// + /// This property provides an enumerable of StackItems that are referenced by this item. + /// It is used by Tarjan's algorithm to find strongly connected components. + /// + /// Use this property when you need to iterate over the successors of a StackItem. + /// internal IEnumerable Successors => ObjectReferences?.Values.Where(p => p.References > 0).Select(p => p.Item) ?? System.Array.Empty(); + /// + /// Resets the strongly connected components-related fields. + /// + /// This method resets the DFN, LowLink, and OnStack fields to their default values. + /// It is used before running Tarjan's algorithm to ensure a clean state. + /// + /// Use this method to reset the state of a StackItem for strongly connected components analysis. + /// internal void Reset() => (DFN, LowLink, OnStack) = (-1, 0, false); + /// + /// Generates a hash code based on the item's span. + /// + /// This method provides a hash code for the StackItem based on its byte span. + /// It is used for efficient storage and retrieval in hash-based collections. + /// + /// Use this method when you need a hash code for a StackItem. + /// + /// The hash code for the StackItem. public override int GetHashCode() => HashCode.Combine(GetSpan().ToArray()); } From e281dcd00ae4b98a4ce538a63f94f205d10d391d Mon Sep 17 00:00:00 2001 From: Jimmy Date: Wed, 26 Jun 2024 18:33:52 +1000 Subject: [PATCH 22/71] fix https://github.com/neo-project/neo/issues/3357 (#3358) Co-authored-by: NGD Admin <154295625+NGDAdmin@users.noreply.github.com> --- src/Directory.Build.props | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Directory.Build.props b/src/Directory.Build.props index b2a79557e2..fe43e16b3c 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -16,6 +16,7 @@ snupkg The Neo Project true + 3.7.5 From 07fb5ce167aaac60fa0d30edc1942386157f250b Mon Sep 17 00:00:00 2001 From: Jimmy Date: Fri, 28 Jun 2024 13:35:06 +0800 Subject: [PATCH 23/71] [Neo Plugins UT] Add RpcServer Unit Tests Part Blockchain. (#3339) * try mock * not use mock * test * fix test * use neo testutils * complete rpcserver blockchain tests. * revert change to ByteArrayComparer * revert cache change * add more detail to comments * add more exception test cases * fix warning * Apply suggestions from code review * update TODO mark * Update src/Plugins/RpcServer/RpcServer.Blockchain.cs Co-authored-by: Anna Shaleva * Update src/Plugins/RpcServer/RpcServer.Blockchain.cs Co-authored-by: Anna Shaleva * Update src/Plugins/RpcServer/RpcServer.Blockchain.cs Co-authored-by: Anna Shaleva * Update src/Plugins/RpcServer/RpcServer.Blockchain.cs Co-authored-by: Anna Shaleva * Update src/Plugins/RpcServer/RpcServer.Blockchain.cs Co-authored-by: Anna Shaleva --------- Co-authored-by: Shargon Co-authored-by: Anna Shaleva Co-authored-by: Christopher Schuchardt --- src/Neo/SmartContract/Native/NeoToken.cs | 2 +- src/Plugins/RpcServer/RpcServer.Blockchain.cs | 127 +++- .../MockNeoSystem.cs | 34 - .../Neo.Plugins.RpcServer.Tests.csproj | 2 + .../TestMemoryStoreProvider.cs | 21 + .../UT_RpcServer.Blockchain.cs | 620 ++++++++++++++++++ .../UT_RpcServer.cs | 55 +- tests/Neo.UnitTests/Ledger/UT_Blockchain.cs | 32 +- tests/Neo.UnitTests/Ledger/UT_TrimmedBlock.cs | 4 +- .../Network/P2P/Payloads/UT_Header.cs | 2 +- .../SmartContract/UT_InteropService.cs | 2 +- .../SmartContract/UT_SmartContractHelper.cs | 31 +- .../SmartContract/UT_Syscalls.cs | 2 +- tests/Neo.UnitTests/TestUtils.Block.cs | 144 ++++ tests/Neo.UnitTests/TestUtils.cs | 100 +-- 15 files changed, 1003 insertions(+), 175 deletions(-) delete mode 100644 tests/Neo.Plugins.RpcServer.Tests/MockNeoSystem.cs create mode 100644 tests/Neo.Plugins.RpcServer.Tests/TestMemoryStoreProvider.cs create mode 100644 tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Blockchain.cs create mode 100644 tests/Neo.UnitTests/TestUtils.Block.cs diff --git a/src/Neo/SmartContract/Native/NeoToken.cs b/src/Neo/SmartContract/Native/NeoToken.cs index 99ecd41e29..f43a0d6079 100644 --- a/src/Neo/SmartContract/Native/NeoToken.cs +++ b/src/Neo/SmartContract/Native/NeoToken.cs @@ -421,7 +421,7 @@ private async ContractTask Vote(ApplicationEngine engine, UInt160 account, /// The snapshot used to read data. /// All the registered candidates. [ContractMethod(CpuFee = 1 << 22, RequiredCallFlags = CallFlags.ReadStates)] - private (ECPoint PublicKey, BigInteger Votes)[] GetCandidates(DataCache snapshot) + internal (ECPoint PublicKey, BigInteger Votes)[] GetCandidates(DataCache snapshot) { return GetCandidatesInternal(snapshot) .Select(p => (p.PublicKey, p.State.Votes)) diff --git a/src/Plugins/RpcServer/RpcServer.Blockchain.cs b/src/Plugins/RpcServer/RpcServer.Blockchain.cs index 7898dd9d9b..4abddbc183 100644 --- a/src/Plugins/RpcServer/RpcServer.Blockchain.cs +++ b/src/Plugins/RpcServer/RpcServer.Blockchain.cs @@ -24,14 +24,28 @@ namespace Neo.Plugins.RpcServer { partial class RpcServer { + /// + /// Gets the hash of the best (most recent) block. + /// + /// An empty array; no parameters are required. + /// The hash of the best block as a . [RpcMethod] - protected virtual JToken GetBestBlockHash(JArray _params) + protected internal virtual JToken GetBestBlockHash(JArray _params) { return NativeContract.Ledger.CurrentHash(system.StoreView).ToString(); } + /// + /// Gets a block by its hash or index. + /// + /// + /// An array containing the block hash or index as the first element, + /// and an optional boolean indicating whether to return verbose information. + /// + /// The block data as a . If the second item of _params is true, then + /// block data is json format, otherwise, the return type is Base64-encoded byte array. [RpcMethod] - protected virtual JToken GetBlock(JArray _params) + protected internal virtual JToken GetBlock(JArray _params) { JToken key = Result.Ok_Or(() => _params[0], RpcError.InvalidParams.WithData($"Invalid Block Hash or Index: {_params[0]}")); bool verbose = _params.Count >= 2 && _params[1].AsBoolean(); @@ -60,20 +74,35 @@ protected virtual JToken GetBlock(JArray _params) return Convert.ToBase64String(block.ToArray()); } + /// + /// Gets the number of block headers in the blockchain. + /// + /// An empty array; no parameters are required. + /// The count of block headers as a . [RpcMethod] internal virtual JToken GetBlockHeaderCount(JArray _params) { return (system.HeaderCache.Last?.Index ?? NativeContract.Ledger.CurrentIndex(system.StoreView)) + 1; } + /// + /// Gets the number of blocks in the blockchain. + /// + /// An empty array; no parameters are required. + /// The count of blocks as a . [RpcMethod] - protected virtual JToken GetBlockCount(JArray _params) + protected internal virtual JToken GetBlockCount(JArray _params) { return NativeContract.Ledger.CurrentIndex(system.StoreView) + 1; } + /// + /// Gets the hash of the block at the specified height. + /// + /// An array containing the block height as the first element. + /// The hash of the block at the specified height as a . [RpcMethod] - protected virtual JToken GetBlockHash(JArray _params) + protected internal virtual JToken GetBlockHash(JArray _params) { uint height = Result.Ok_Or(() => uint.Parse(_params[0].AsString()), RpcError.InvalidParams.WithData($"Invalid Height: {_params[0]}")); var snapshot = system.StoreView; @@ -84,8 +113,16 @@ protected virtual JToken GetBlockHash(JArray _params) throw new RpcException(RpcError.UnknownHeight); } + /// + /// Gets a block header by its hash or index. + /// + /// + /// An array containing the block header hash or index as the first element, + /// and an optional boolean indicating whether to return verbose information. + /// + /// The block header data as a . In json format if the second item of _params is true, otherwise Base64-encoded byte array. [RpcMethod] - protected virtual JToken GetBlockHeader(JArray _params) + protected internal virtual JToken GetBlockHeader(JArray _params) { JToken key = _params[0]; bool verbose = _params.Count >= 2 && _params[1].AsBoolean(); @@ -114,8 +151,13 @@ protected virtual JToken GetBlockHeader(JArray _params) return Convert.ToBase64String(header.ToArray()); } + /// + /// Gets the state of a contract by its ID or script hash or (only for native contracts) by case-insensitive name. + /// + /// An array containing the contract ID or script hash or case-insensitive native contract name as the first element. + /// The contract state in json format as a . [RpcMethod] - protected virtual JToken GetContractState(JArray _params) + protected internal virtual JToken GetContractState(JArray _params) { if (int.TryParse(_params[0].AsString(), out int contractId)) { @@ -139,8 +181,13 @@ private static UInt160 ToScriptHash(string keyword) return UInt160.Parse(keyword); } + /// + /// Gets the current memory pool transactions. + /// + /// An array containing an optional boolean indicating whether to include unverified transactions. + /// The memory pool transactions in json format as a . [RpcMethod] - protected virtual JToken GetRawMemPool(JArray _params) + protected internal virtual JToken GetRawMemPool(JArray _params) { bool shouldGetUnverified = _params.Count >= 1 && _params[0].AsBoolean(); if (!shouldGetUnverified) @@ -156,8 +203,16 @@ protected virtual JToken GetRawMemPool(JArray _params) return json; } + /// + /// Gets a transaction by its hash. + /// + /// + /// An array containing the transaction hash as the first element, + /// and an optional boolean indicating whether to return verbose information. + /// + /// The transaction data as a . In json format if the second item of _params is true, otherwise base64string. [RpcMethod] - protected virtual JToken GetRawTransaction(JArray _params) + protected internal virtual JToken GetRawTransaction(JArray _params) { UInt256 hash = Result.Ok_Or(() => UInt256.Parse(_params[0].AsString()), RpcError.InvalidParams.WithData($"Invalid Transaction Hash: {_params[0]}")); bool verbose = _params.Count >= 2 && _params[1].AsBoolean(); @@ -179,8 +234,16 @@ protected virtual JToken GetRawTransaction(JArray _params) return json; } + /// + /// Gets the storage item by contract ID or script hash and key. + /// + /// + /// An array containing the contract ID or script hash as the first element, + /// and the storage key as the second element. + /// + /// The storage item as a . [RpcMethod] - protected virtual JToken GetStorage(JArray _params) + protected internal virtual JToken GetStorage(JArray _params) { using var snapshot = system.GetSnapshot(); if (!int.TryParse(_params[0].AsString(), out int id)) @@ -198,8 +261,17 @@ protected virtual JToken GetStorage(JArray _params) return Convert.ToBase64String(item.Value.Span); } + /// + /// Finds storage items by contract ID or script hash and prefix. + /// + /// + /// An array containing the contract ID or script hash as the first element, + /// the Base64-encoded storage key prefix as the second element, + /// and an optional start index as the third element. + /// + /// The found storage items as a . [RpcMethod] - protected virtual JToken FindStorage(JArray _params) + protected internal virtual JToken FindStorage(JArray _params) { using var snapshot = system.GetSnapshot(); if (!int.TryParse(_params[0].AsString(), out int id)) @@ -247,8 +319,13 @@ protected virtual JToken FindStorage(JArray _params) return json; } + /// + /// Gets the height of a transaction by its hash. + /// + /// An array containing the transaction hash as the first element. + /// The height of the transaction as a . [RpcMethod] - protected virtual JToken GetTransactionHeight(JArray _params) + protected internal virtual JToken GetTransactionHeight(JArray _params) { UInt256 hash = Result.Ok_Or(() => UInt256.Parse(_params[0].AsString()), RpcError.InvalidParams.WithData($"Invalid Transaction Hash: {_params[0]}")); uint? height = NativeContract.Ledger.GetTransactionState(system.StoreView, hash)?.BlockIndex; @@ -256,8 +333,13 @@ protected virtual JToken GetTransactionHeight(JArray _params) throw new RpcException(RpcError.UnknownTransaction); } + /// + /// Gets the next block validators. + /// + /// An empty array; no parameters are required. + /// The next block validators as a . [RpcMethod] - protected virtual JToken GetNextBlockValidators(JArray _params) + protected internal virtual JToken GetNextBlockValidators(JArray _params) { using var snapshot = system.GetSnapshot(); var validators = NativeContract.NEO.GetNextBlockValidators(snapshot, system.Settings.ValidatorsCount); @@ -270,8 +352,13 @@ protected virtual JToken GetNextBlockValidators(JArray _params) }).ToArray(); } + /// + /// Gets the list of candidates for the next block validators. + /// + /// An empty array; no parameters are required. + /// The candidates public key list as a JToken. [RpcMethod] - protected virtual JToken GetCandidates(JArray _params) + protected internal virtual JToken GetCandidates(JArray _params) { using var snapshot = system.GetSnapshot(); byte[] script; @@ -322,14 +409,24 @@ protected virtual JToken GetCandidates(JArray _params) return json; } + /// + /// Gets the list of committee members. + /// + /// An empty array; no parameters are required. + /// The committee members publickeys as a . [RpcMethod] - protected virtual JToken GetCommittee(JArray _params) + protected internal virtual JToken GetCommittee(JArray _params) { return new JArray(NativeContract.NEO.GetCommittee(system.StoreView).Select(p => (JToken)p.ToString())); } + /// + /// Gets the list of native contracts. + /// + /// An empty array; no parameters are required. + /// The native contract states as a . [RpcMethod] - protected virtual JToken GetNativeContracts(JArray _params) + protected internal virtual JToken GetNativeContracts(JArray _params) { return new JArray(NativeContract.Contracts.Select(p => NativeContract.ContractManagement.GetContract(system.StoreView, p.Hash).ToJson())); } diff --git a/tests/Neo.Plugins.RpcServer.Tests/MockNeoSystem.cs b/tests/Neo.Plugins.RpcServer.Tests/MockNeoSystem.cs deleted file mode 100644 index 0f45a63d98..0000000000 --- a/tests/Neo.Plugins.RpcServer.Tests/MockNeoSystem.cs +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright (C) 2015-2024 The Neo Project. -// -// MockNeoSystem.cs file belongs to the neo project and is free -// software distributed under the MIT software license, see the -// accompanying file LICENSE in the main directory of the -// repository or http://www.opensource.org/licenses/mit-license.php -// for more details. -// -// Redistribution and use in source and binary forms with or without -// modifications are permitted. - -using Neo.Ledger; -using Neo.Persistence; - -namespace Neo.Plugins.RpcServer.Tests -{ - public class MockNeoSystem : NeoSystem - { - public SnapshotCache SnapshotCache { get; } - public MemoryPool MemoryPool { get; } - - public MockNeoSystem(SnapshotCache snapshotCache, MemoryPool memoryPool) - : base(TestProtocolSettings.Default, new TestBlockchain.StoreProvider()) - { - SnapshotCache = snapshotCache; - MemoryPool = memoryPool; - } - - public SnapshotCache GetSnapshot() - { - return SnapshotCache; - } - } -} diff --git a/tests/Neo.Plugins.RpcServer.Tests/Neo.Plugins.RpcServer.Tests.csproj b/tests/Neo.Plugins.RpcServer.Tests/Neo.Plugins.RpcServer.Tests.csproj index 5b693c96b8..1586b9753d 100644 --- a/tests/Neo.Plugins.RpcServer.Tests/Neo.Plugins.RpcServer.Tests.csproj +++ b/tests/Neo.Plugins.RpcServer.Tests/Neo.Plugins.RpcServer.Tests.csproj @@ -4,6 +4,7 @@ net8.0 Neo.Plugins.RpcServer.Tests Neo.Plugins.RpcServer.Tests + true @@ -16,6 +17,7 @@ + \ No newline at end of file diff --git a/tests/Neo.Plugins.RpcServer.Tests/TestMemoryStoreProvider.cs b/tests/Neo.Plugins.RpcServer.Tests/TestMemoryStoreProvider.cs new file mode 100644 index 0000000000..b39b4aeae5 --- /dev/null +++ b/tests/Neo.Plugins.RpcServer.Tests/TestMemoryStoreProvider.cs @@ -0,0 +1,21 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// TestMemoryStoreProvider.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using Neo.Persistence; + +namespace Neo.Plugins.RpcServer.Tests; + +public class TestMemoryStoreProvider(MemoryStore memoryStore) : IStoreProvider +{ + public MemoryStore MemoryStore { get; init; } = memoryStore; + public string Name => nameof(MemoryStore); + public IStore GetStore(string path) => MemoryStore; +} diff --git a/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Blockchain.cs b/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Blockchain.cs new file mode 100644 index 0000000000..5fd37b2bc3 --- /dev/null +++ b/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Blockchain.cs @@ -0,0 +1,620 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_RpcServer.Blockchain.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using Akka.Util.Internal; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.IO; +using Neo.Json; +using Neo.Ledger; +using Neo.Network.P2P.Payloads; +using Neo.SmartContract; +using Neo.SmartContract.Native; +using Neo.UnitTests; +using Neo.UnitTests.Extensions; +using System; +using System.Linq; + +namespace Neo.Plugins.RpcServer.Tests +{ + public partial class UT_RpcServer + { + + [TestMethod] + public void TestGetBestBlockHash() + { + var key = NativeContract.Ledger.CreateStorageKey(12); + var expectedHash = UInt256.Zero; + + var snapshot = _neoSystem.GetSnapshot(); + var b = snapshot.GetAndChange(key, () => new StorageItem(new HashIndexState())).GetInteroperable(); + b.Hash = UInt256.Zero; + b.Index = 100; + snapshot.Commit(); + + var result = _rpcServer.GetBestBlockHash([]); + // Assert + Assert.AreEqual(expectedHash.ToString(), result.AsString()); + } + + [TestMethod] + public void TestGetBlockByHash() + { + var snapshot = _neoSystem.GetSnapshot(); + var block = TestUtils.CreateBlockWithValidTransactions(snapshot, _wallet, _walletAccount, 3); + TestUtils.BlocksAdd(snapshot, block.Hash, block); + snapshot.Commit(); + + var parameters = new JArray(block.Hash.ToString(), false); + var result = _rpcServer.GetBlock(parameters); + var blockArr = Convert.FromBase64String(result.AsString()); + var block2 = blockArr.AsSerializable(); + block2.Transactions.ForEach(tx => + { + Assert.AreEqual(VerifyResult.Succeed, tx.VerifyStateIndependent(UnitTests.TestProtocolSettings.Default)); + }); + } + + [TestMethod] + public void TestGetBlockByIndex() + { + var snapshot = _neoSystem.GetSnapshot(); + var block = TestUtils.CreateBlockWithValidTransactions(snapshot, _wallet, _walletAccount, 3); + TestUtils.BlocksAdd(snapshot, block.Hash, block); + snapshot.Commit(); + + var parameters = new JArray(block.Index, false); + var result = _rpcServer.GetBlock(parameters); + var blockArr = Convert.FromBase64String(result.AsString()); + var block2 = blockArr.AsSerializable(); + block2.Transactions.ForEach(tx => + { + Assert.AreEqual(VerifyResult.Succeed, tx.VerifyStateIndependent(UnitTests.TestProtocolSettings.Default)); + }); + } + + [TestMethod] + public void TestGetBlockCount() + { + var expectedCount = 1; + var result = _rpcServer.GetBlockCount(new JArray()); + Assert.AreEqual(expectedCount, result.AsNumber()); + } + + [TestMethod] + public void TestGetBlockHeaderCount() + { + var expectedCount = 1; + var result = _rpcServer.GetBlockHeaderCount(new JArray()); + Assert.AreEqual(expectedCount, result.AsNumber()); + } + + [TestMethod] + public void TestGetBlockHash() + { + var snapshot = _neoSystem.GetSnapshot(); + var block = TestUtils.CreateBlockWithValidTransactions(snapshot, _wallet, _walletAccount, 3); + TestUtils.BlocksAdd(snapshot, block.Hash, block); + snapshot.Commit(); + var expectedHash = block.Hash.ToString(); + var result = _rpcServer.GetBlockHash(new JArray(block.Index)); + Assert.AreEqual(expectedHash, result.AsString()); + } + + [TestMethod] + public void TestGetBlockHeader() + { + var snapshot = _neoSystem.GetSnapshot(); + var block = TestUtils.CreateBlockWithValidTransactions(snapshot, _wallet, _walletAccount, 3); + TestUtils.BlocksAdd(snapshot, block.Hash, block); + snapshot.Commit(); + var parameters = new JArray(block.Hash.ToString(), true); + var result = _rpcServer.GetBlockHeader(parameters); + var header = block.Header.ToJson(_neoSystem.Settings); + header["confirmations"] = NativeContract.Ledger.CurrentIndex(snapshot) - block.Index + 1; + Assert.AreEqual(header.ToString(), result.ToString()); + } + + [TestMethod] + public void TestGetContractState() + { + var snapshot = _neoSystem.GetSnapshot(); + var contractState = TestUtils.GetContract(); + snapshot.AddContract(contractState.Hash, contractState); + snapshot.Commit(); + var result = _rpcServer.GetContractState(new JArray(contractState.Hash.ToString())); + + Assert.AreEqual(contractState.ToJson().ToString(), result.ToString()); + } + + [TestMethod] + public void TestGetRawMemPool() + { + var snapshot = _neoSystem.GetSnapshot(); + var tx = TestUtils.CreateValidTx(snapshot, _wallet, _walletAccount); + snapshot.Commit(); + _neoSystem.MemPool.TryAdd(tx, snapshot); + + var result = _rpcServer.GetRawMemPool(new JArray()); + + Assert.IsTrue(((JArray)result).Any(p => p.AsString() == tx.Hash.ToString())); + } + + [TestMethod] + public void TestGetRawTransaction() + { + var snapshot = _neoSystem.GetSnapshot(); + var tx = TestUtils.CreateValidTx(snapshot, _wallet, _walletAccount); + _neoSystem.MemPool.TryAdd(tx, snapshot); + var parameters = new JArray(tx.Hash.ToString(), true); + snapshot.Commit(); + var result = _rpcServer.GetRawTransaction(parameters); + + var json = Utility.TransactionToJson(tx, _neoSystem.Settings); + Assert.AreEqual(json.ToString(), result.ToString()); + } + + [TestMethod] + public void TestGetStorage() + { + var snapshot = _neoSystem.GetSnapshot(); + var contractState = TestUtils.GetContract(); + snapshot.AddContract(contractState.Hash, contractState); + var key = new byte[] { 0x01 }; + var value = new byte[] { 0x02 }; + TestUtils.StorageItemAdd(snapshot, contractState.Id, key, value); + snapshot.Commit(); + + var result = _rpcServer.GetStorage(new JArray(contractState.Hash.ToString(), Convert.ToBase64String(key))); + Assert.AreEqual(Convert.ToBase64String(value), result.AsString()); + } + + [TestMethod] + public void TestFindStorage() + { + var snapshot = _neoSystem.GetSnapshot(); + var contractState = TestUtils.GetContract(); + snapshot.AddContract(contractState.Hash, contractState); + var key = new byte[] { 0x01 }; + var value = new byte[] { 0x02 }; + TestUtils.StorageItemAdd(snapshot, contractState.Id, key, value); + snapshot.Commit(); + var result = _rpcServer.FindStorage(new JArray(contractState.Hash.ToString(), Convert.ToBase64String(key), 0)); + + var json = new JObject(); + var jarr = new JArray(); + var j = new JObject(); + j["key"] = Convert.ToBase64String(key); + j["value"] = Convert.ToBase64String(value); + jarr.Add(j); + json["truncated"] = false; + json["next"] = 1; + json["results"] = jarr; + Assert.AreEqual(json.ToString(), result.ToString()); + } + + [TestMethod] + public void TestGetTransactionHeight() + { + var snapshot = _neoSystem.GetSnapshot(); + var block = TestUtils.CreateBlockWithValidTransactions(snapshot, _wallet, _walletAccount, 1); + TestUtils.BlocksAdd(snapshot, block.Hash, block); + snapshot.Commit(); + var tx = block.Transactions[0]; + var result = _rpcServer.GetTransactionHeight(new JArray(tx.Hash.ToString())); + Assert.AreEqual(block.Index, result.AsNumber()); + } + + [TestMethod] + public void TestGetNextBlockValidators() + { + var snapshot = _neoSystem.GetSnapshot(); + var result = _rpcServer.GetNextBlockValidators(new JArray()); + + var validators = NativeContract.NEO.GetNextBlockValidators(snapshot, _neoSystem.Settings.ValidatorsCount); + var expected = validators.Select(p => + { + var validator = new JObject(); + validator["publickey"] = p.ToString(); + validator["votes"] = (int)NativeContract.NEO.GetCandidateVote(snapshot, p); + return validator; + }).ToArray(); + Assert.AreEqual(new JArray(expected).ToString(), result.ToString()); + } + + [TestMethod] + public void TestGetCandidates() + { + var snapshot = _neoSystem.GetSnapshot(); + var result = _rpcServer.GetCandidates(new JArray()); + var json = new JArray(); + var validators = NativeContract.NEO.GetNextBlockValidators(snapshot, _neoSystem.Settings.ValidatorsCount); + snapshot.Commit(); + var candidates = NativeContract.NEO.GetCandidates(_neoSystem.GetSnapshot()); + + foreach (var candidate in candidates) + { + var item = new JObject(); + item["publickey"] = candidate.PublicKey.ToString(); + item["votes"] = candidate.Votes.ToString(); + item["active"] = validators.Contains(candidate.PublicKey); + json.Add(item); + } + Assert.AreEqual(json.ToString(), result.ToString()); + } + + [TestMethod] + public void TestGetCommittee() + { + var snapshot = _neoSystem.GetSnapshot(); + var result = _rpcServer.GetCommittee(new JArray()); + var committee = NativeContract.NEO.GetCommittee(snapshot); + var expected = new JArray(committee.Select(p => (JToken)p.ToString())); + Assert.AreEqual(expected.ToString(), result.ToString()); + } + + [TestMethod] + public void TestGetNativeContracts() + { + var result = _rpcServer.GetNativeContracts(new JArray()); + var contracts = new JArray(NativeContract.Contracts.Select(p => NativeContract.ContractManagement.GetContract(_neoSystem.GetSnapshot(), p.Hash).ToJson())); + Assert.AreEqual(contracts.ToString(), result.ToString()); + } + + [TestMethod] + public void TestGetBlockByUnknownIndex() + { + var snapshot = _neoSystem.GetSnapshot(); + var block = TestUtils.CreateBlockWithValidTransactions(snapshot, _wallet, _walletAccount, 3); + TestUtils.BlocksAdd(snapshot, block.Hash, block); + snapshot.Commit(); + + var parameters = new JArray(int.MaxValue, false); + try + { + _rpcServer.GetBlock(parameters); + Assert.Fail("Expected RpcException was not thrown."); + } + catch (RpcException ex) + { + Assert.AreEqual(RpcError.UnknownBlock.Code, ex.HResult); + } + } + + [TestMethod] + public void TestGetBlockByUnknownHash() + { + var snapshot = _neoSystem.GetSnapshot(); + var block = TestUtils.CreateBlockWithValidTransactions(snapshot, _wallet, _walletAccount, 3); + TestUtils.BlocksAdd(snapshot, block.Hash, block); + snapshot.Commit(); + + var parameters = new JArray(TestUtils.RandomUInt256().ToString(), false); + try + { + _rpcServer.GetBlock(parameters); + Assert.Fail("Expected RpcException was not thrown."); + } + catch (RpcException ex) + { + Assert.AreEqual(RpcError.UnknownBlock.Code, ex.HResult); + } + } + + [TestMethod] + public void TestGetBlockByUnKnownIndex() + { + var snapshot = _neoSystem.GetSnapshot(); + var block = TestUtils.CreateBlockWithValidTransactions(snapshot, _wallet, _walletAccount, 3); + TestUtils.BlocksAdd(snapshot, block.Hash, block); + snapshot.Commit(); + + var parameters = new JArray(int.MaxValue, false); + try + { + _rpcServer.GetBlock(parameters); + Assert.Fail("Expected RpcException was not thrown."); + } + catch (RpcException ex) + { + Assert.AreEqual(RpcError.UnknownBlock.Code, ex.HResult); + } + } + + [TestMethod] + public void TestGetBlockByUnKnownHash() + { + var snapshot = _neoSystem.GetSnapshot(); + var block = TestUtils.CreateBlockWithValidTransactions(snapshot, _wallet, _walletAccount, 3); + TestUtils.BlocksAdd(snapshot, block.Hash, block); + snapshot.Commit(); + + var parameters = new JArray(TestUtils.RandomUInt256().ToString(), false); + try + { + _rpcServer.GetBlock(parameters); + Assert.Fail("Expected RpcException was not thrown."); + } + catch (RpcException ex) + { + Assert.AreEqual(RpcError.UnknownBlock.Code, ex.HResult); + } + } + + [TestMethod] + public void TestGetBlockHashInvalidIndex() + { + var snapshot = _neoSystem.GetSnapshot(); + var block = TestUtils.CreateBlockWithValidTransactions(snapshot, _wallet, _walletAccount, 3); + TestUtils.BlocksAdd(snapshot, block.Hash, block); + snapshot.Commit(); + Assert.ThrowsException(() => _rpcServer.GetBlockHash(new JArray(block.Index + 1))); + } + + [TestMethod] + public void TestGetContractStateUnknownContract() + { + var snapshot = _neoSystem.GetSnapshot(); + var randomHash = TestUtils.RandomUInt160(); + try + { + _rpcServer.GetContractState(new JArray(randomHash.ToString())); + Assert.Fail("Expected RpcException was not thrown."); + } + catch (RpcException ex) + { + Assert.AreEqual(RpcError.UnknownContract.Code, ex.HResult); + } + } + + [TestMethod] + public void TestGetStorageUnknownContract() + { + var snapshot = _neoSystem.GetSnapshot(); + var randomHash = TestUtils.RandomUInt160(); + var key = new byte[] { 0x01 }; + try + { + _rpcServer.GetStorage(new JArray(randomHash.ToString(), Convert.ToBase64String(key))); + Assert.Fail("Expected RpcException was not thrown."); + } + catch (RpcException ex) + { + Assert.AreEqual(RpcError.UnknownContract.Code, ex.HResult); + } + } + + [TestMethod] + public void TestGetStorageUnknownStorageItem() + { + var snapshot = _neoSystem.GetSnapshot(); + var contractState = TestUtils.GetContract(); + snapshot.AddContract(contractState.Hash, contractState); + snapshot.Commit(); + + var key = new byte[] { 0x01 }; + try + { + _rpcServer.GetStorage(new JArray(contractState.Hash.ToString(), Convert.ToBase64String(key))); + Assert.Fail("Expected RpcException was not thrown."); + } + catch (RpcException ex) + { + Assert.AreEqual(RpcError.UnknownStorageItem.Code, ex.HResult); + } + } + + [TestMethod] + public void TestGetTransactionHeightUnknownTransaction() + { + var randomHash = TestUtils.RandomUInt256(); + try + { + _rpcServer.GetTransactionHeight(new JArray(randomHash.ToString())); + Assert.Fail("Expected RpcException was not thrown."); + } + catch (RpcException ex) + { + Assert.AreEqual(RpcError.UnknownTransaction.Code, ex.HResult); + } + } + + [TestMethod] + public void TestGetRawTransactionUnknownTransaction() + { + var randomHash = TestUtils.RandomUInt256(); + try + { + _rpcServer.GetRawTransaction(new JArray(randomHash.ToString(), true)); + Assert.Fail("Expected RpcException was not thrown."); + } + catch (RpcException ex) + { + Assert.AreEqual(RpcError.UnknownTransaction.Code, ex.HResult); + } + } + + [TestMethod] + public void TestGetBlockInvalidParams() + { + try + { + _rpcServer.GetBlock(new JArray("invalid_hash", false)); + Assert.Fail("Expected RpcException was not thrown."); + } + catch (RpcException ex) + { + Assert.AreEqual(RpcError.InvalidParams.Code, ex.HResult); + } + catch (FormatException) + { + } + catch + { + Assert.Fail("Unexpected exception"); + } + } + + [TestMethod] + public void TestGetBlockHashInvalidParams() + { + try + { + _rpcServer.GetBlockHash(new JArray("invalid_index")); + Assert.Fail("Expected RpcException was not thrown."); + } + catch (RpcException ex) + { + Assert.AreEqual(RpcError.InvalidParams.Code, ex.HResult); + } + } + + [TestMethod] + public void TestGetBlockHeaderInvalidParams() + { + try + { + _rpcServer.GetBlockHeader(new JArray("invalid_hash", true)); + Assert.Fail("Expected RpcException was not thrown."); + } + catch (RpcException ex) + { + Assert.AreEqual(RpcError.InvalidParams.Code, ex.HResult); + } + catch (FormatException) + { + } + catch + { + Assert.Fail("Unexpected exception"); + } + } + + [TestMethod] + public void TestGetContractStateInvalidParams() + { + try + { + _rpcServer.GetContractState(new JArray("invalid_hash")); + Assert.Fail("Expected RpcException was not thrown."); + } + catch (RpcException ex) + { + Assert.AreEqual(RpcError.InvalidParams.Code, ex.HResult); + } + catch (FormatException) + { + } + catch + { + Assert.Fail("Unexpected exception"); + } + } + + [TestMethod] + public void TestGetStorageInvalidParams() + { + try + { + _rpcServer.GetStorage(new JArray("invalid_hash", "invalid_key")); + Assert.Fail("Expected RpcException was not thrown."); + } + catch (RpcException ex) + { + Assert.AreEqual(RpcError.InvalidParams.Code, ex.HResult); + } + catch (FormatException) + { + } + catch + { + Assert.Fail("Unexpected exception"); + } + } + + [TestMethod] + public void TestFindStorageInvalidParams() + { + try + { + _rpcServer.FindStorage(new JArray("invalid_hash", "invalid_prefix", "invalid_start")); + Assert.Fail("Expected RpcException was not thrown."); + } + catch (RpcException ex) + { + Assert.AreEqual(RpcError.InvalidParams.Code, ex.HResult); + } + catch (FormatException) + { + } + catch + { + Assert.Fail("Unexpected exception"); + } + } + + [TestMethod] + public void TestGetTransactionHeightInvalidParams() + { + try + { + _rpcServer.GetTransactionHeight(new JArray("invalid_hash")); + Assert.Fail("Expected RpcException was not thrown."); + } + catch (RpcException ex) + { + Assert.AreEqual(RpcError.InvalidParams.Code, ex.HResult); + } + } + + [TestMethod] + public void TestGetRawTransactionInvalidParams() + { + try + { + _rpcServer.GetRawTransaction(new JArray("invalid_hash", true)); + Assert.Fail("Expected RpcException was not thrown."); + } + catch (RpcException ex) + { + Assert.AreEqual(RpcError.InvalidParams.Code, ex.HResult); + } + } + + [TestMethod] + public void TestInternalServerError() + { + _memoryStore.Reset(); + try + { + _rpcServer.GetCandidates(new JArray()); + Assert.Fail("Expected RpcException was not thrown."); + } + catch (RpcException ex) + { + Assert.AreEqual(RpcError.InternalServerError.Code, ex.HResult); + } + } + + [TestMethod] + public void TestUnknownHeight() + { + try + { + _rpcServer.GetBlockHash(new JArray(int.MaxValue)); + Assert.Fail("Expected RpcException was not thrown."); + } + catch (RpcException ex) + { + Assert.AreEqual(RpcError.UnknownHeight.Code, ex.HResult); + } + } + } +} diff --git a/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.cs b/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.cs index 7bca550b83..4ba95b7798 100644 --- a/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.cs +++ b/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.cs @@ -11,9 +11,12 @@ using Microsoft.AspNetCore.Http; using Microsoft.VisualStudio.TestTools.UnitTesting; -using Moq; -using Neo.Ledger; using Neo.Persistence; +using Neo.SmartContract; +using Neo.SmartContract.Native; +using Neo.UnitTests; +using Neo.Wallets; +using Neo.Wallets.NEP6; using System; using System.Text; @@ -22,39 +25,49 @@ namespace Neo.Plugins.RpcServer.Tests [TestClass] public partial class UT_RpcServer { - private Mock _systemMock; - private SnapshotCache _snapshotCache; - private MemoryPool _memoryPool; - private RpcServerSettings _settings; + private NeoSystem _neoSystem; private RpcServer _rpcServer; + private TestMemoryStoreProvider _memoryStoreProvider; + private MemoryStore _memoryStore; + private readonly NEP6Wallet _wallet = TestUtils.GenerateTestWallet("123"); + private WalletAccount _walletAccount; [TestInitialize] public void TestSetup() { - // Mock IReadOnlyStore - var mockStore = new Mock(); - - // Initialize SnapshotCache with the mock IReadOnlyStore - _snapshotCache = new SnapshotCache(mockStore.Object); - - // Initialize NeoSystem - var neoSystem = new NeoSystem(TestProtocolSettings.Default, new TestBlockchain.StoreProvider()); - - // Initialize MemoryPool with the NeoSystem - _memoryPool = new MemoryPool(neoSystem); - - // Set up the mock system with the correct constructor arguments - _systemMock = new Mock(_snapshotCache, _memoryPool); + _memoryStore = new MemoryStore(); + _memoryStoreProvider = new TestMemoryStoreProvider(_memoryStore); + var protocolSettings = TestProtocolSettings.Default; + _neoSystem = new NeoSystem(protocolSettings, _memoryStoreProvider); + _rpcServer = new RpcServer(_neoSystem, RpcServerSettings.Default); + _walletAccount = _wallet.CreateAccount(); + var key = new KeyBuilder(NativeContract.GAS.Id, 20).Add(_walletAccount.ScriptHash); + var snapshot = _neoSystem.GetSnapshot(); + var entry = snapshot.GetAndChange(key, () => new StorageItem(new AccountState())); + entry.GetInteroperable().Balance = 100_000_000 * NativeContract.GAS.Factor; + snapshot.Commit(); + } - _rpcServer = new RpcServer(_systemMock.Object, RpcServerSettings.Default); + [TestCleanup] + public void TestCleanup() + { + _memoryStore.Reset(); + var snapshot = _neoSystem.GetSnapshot(); + var key = new KeyBuilder(NativeContract.GAS.Id, 20).Add(_walletAccount.ScriptHash); + var entry = snapshot.GetAndChange(key, () => new StorageItem(new AccountState())); + entry.GetInteroperable().Balance = 100_000_000 * NativeContract.GAS.Factor; + snapshot.Commit(); } [TestMethod] public void TestCheckAuth_ValidCredentials_ReturnsTrue() { + // Arrange var context = new DefaultHttpContext(); context.Request.Headers["Authorization"] = "Basic " + Convert.ToBase64String(Encoding.UTF8.GetBytes("testuser:testpass")); + // Act var result = _rpcServer.CheckAuth(context); + // Assert Assert.IsTrue(result); } } diff --git a/tests/Neo.UnitTests/Ledger/UT_Blockchain.cs b/tests/Neo.UnitTests/Ledger/UT_Blockchain.cs index 491b4fe21e..cedc68bb4d 100644 --- a/tests/Neo.UnitTests/Ledger/UT_Blockchain.cs +++ b/tests/Neo.UnitTests/Ledger/UT_Blockchain.cs @@ -70,7 +70,7 @@ public void TestValidTransaction() // Make transaction - var tx = CreateValidTx(snapshot, walletA, acc.ScriptHash, 0); + var tx = TestUtils.CreateValidTx(snapshot, walletA, acc.ScriptHash, 0); senderProbe.Send(system.Blockchain, tx); senderProbe.ExpectMsg(p => p.Result == VerifyResult.Succeed); @@ -91,30 +91,6 @@ internal static StorageKey CreateStorageKey(byte prefix, byte[] key = null) }; } - private static Transaction CreateValidTx(DataCache snapshot, NEP6Wallet wallet, UInt160 account, uint nonce) - { - var tx = wallet.MakeTransaction(snapshot, new TransferOutput[] - { - new TransferOutput() - { - AssetId = NativeContract.GAS.Hash, - ScriptHash = account, - Value = new BigDecimal(BigInteger.One,8) - } - }, - account); - - tx.Nonce = nonce; - - var data = new ContractParametersContext(snapshot, tx, TestProtocolSettings.Default.Network); - Assert.IsNull(data.GetSignatures(tx.Sender)); - Assert.IsTrue(wallet.Sign(data)); - Assert.IsTrue(data.Completed); - Assert.AreEqual(1, data.GetSignatures(tx.Sender).Count()); - - tx.Witnesses = data.GetWitnesses(); - return tx; - } [TestMethod] public void TestMaliciousOnChainConflict() @@ -141,9 +117,9 @@ public void TestMaliciousOnChainConflict() // Create transactions: // tx1 conflicts with tx2 and has the same sender (thus, it's a valid conflict and must prevent tx2 from entering the chain); // tx2 conflicts with tx3 and has different sender (thus, this conflict is invalid and must not prevent tx3 from entering the chain). - var tx1 = CreateValidTx(snapshot, walletA, accA.ScriptHash, 0); - var tx2 = CreateValidTx(snapshot, walletA, accA.ScriptHash, 1); - var tx3 = CreateValidTx(snapshot, walletB, accB.ScriptHash, 2); + var tx1 = TestUtils.CreateValidTx(snapshot, walletA, accA.ScriptHash, 0); + var tx2 = TestUtils.CreateValidTx(snapshot, walletA, accA.ScriptHash, 1); + var tx3 = TestUtils.CreateValidTx(snapshot, walletB, accB.ScriptHash, 2); tx1.Attributes = new TransactionAttribute[] { new Conflicts() { Hash = tx2.Hash }, new Conflicts() { Hash = tx3.Hash } }; diff --git a/tests/Neo.UnitTests/Ledger/UT_TrimmedBlock.cs b/tests/Neo.UnitTests/Ledger/UT_TrimmedBlock.cs index 7942847f94..ea797f8be3 100644 --- a/tests/Neo.UnitTests/Ledger/UT_TrimmedBlock.cs +++ b/tests/Neo.UnitTests/Ledger/UT_TrimmedBlock.cs @@ -69,11 +69,11 @@ public void TestGetBlock() Transaction = tx2, BlockIndex = 1 }; - UT_SmartContractHelper.TransactionAdd(snapshot, state1, state2); + TestUtils.TransactionAdd(snapshot, state1, state2); TrimmedBlock tblock = GetTrimmedBlockWithNoTransaction(); tblock.Hashes = new UInt256[] { tx1.Hash, tx2.Hash }; - UT_SmartContractHelper.BlocksAdd(snapshot, tblock.Hash, tblock); + TestUtils.BlocksAdd(snapshot, tblock.Hash, tblock); Block block = NativeContract.Ledger.GetBlock(snapshot, tblock.Hash); diff --git a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Header.cs b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Header.cs index df33505965..a597c88cb6 100644 --- a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Header.cs +++ b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Header.cs @@ -56,7 +56,7 @@ public void TrimTest() TestUtils.SetupHeaderWithValues(uut, val256, out _, out _, out _, out _, out _, out _); uut.Witness = new Witness() { InvocationScript = Array.Empty(), VerificationScript = Array.Empty() }; - UT_SmartContractHelper.BlocksAdd(snapshot, uut.Hash, new TrimmedBlock() + TestUtils.BlocksAdd(snapshot, uut.Hash, new TrimmedBlock() { Header = new Header { diff --git a/tests/Neo.UnitTests/SmartContract/UT_InteropService.cs b/tests/Neo.UnitTests/SmartContract/UT_InteropService.cs index 51f26d22eb..06290922da 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_InteropService.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_InteropService.cs @@ -476,7 +476,7 @@ public void TestBlockchain_GetTransactionHeight() BlockIndex = 0, Transaction = TestUtils.CreateRandomHashTransaction() }; - UT_SmartContractHelper.TransactionAdd(engine.Snapshot, state); + TestUtils.TransactionAdd(engine.Snapshot, state); using var script = new ScriptBuilder(); script.EmitDynamicCall(NativeContract.Ledger.Hash, "getTransactionHeight", state.Transaction.Hash); diff --git a/tests/Neo.UnitTests/SmartContract/UT_SmartContractHelper.cs b/tests/Neo.UnitTests/SmartContract/UT_SmartContractHelper.cs index c14b15c241..c1161213ce 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_SmartContractHelper.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_SmartContractHelper.cs @@ -27,9 +27,6 @@ namespace Neo.UnitTests.SmartContract [TestClass] public class UT_SmartContractHelper { - const byte Prefix_Block = 5; - const byte Prefix_BlockHash = 9; - const byte Prefix_Transaction = 11; [TestMethod] public void TestIsMultiSigContract() @@ -129,7 +126,7 @@ public void TestVerifyWitnesses() { var snapshot1 = TestBlockchain.GetTestSnapshot().CreateSnapshot(); UInt256 index1 = UInt256.Parse("0xa400ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff01"); - BlocksAdd(snapshot1, index1, new TrimmedBlock() + TestUtils.BlocksAdd(snapshot1, index1, new TrimmedBlock() { Header = new Header { @@ -141,7 +138,7 @@ public void TestVerifyWitnesses() }, Hashes = new UInt256[1] { UInt256.Zero }, }); - BlocksDelete(snapshot1, index1); + TestUtils.BlocksDelete(snapshot1, index1); Assert.AreEqual(false, Neo.SmartContract.Helper.VerifyWitnesses(new Header() { PrevHash = index1 }, TestProtocolSettings.Default, snapshot1, 100)); var snapshot2 = TestBlockchain.GetTestSnapshot(); @@ -158,7 +155,7 @@ public void TestVerifyWitnesses() }, Hashes = new UInt256[1] { UInt256.Zero }, }; - BlocksAdd(snapshot2, index2, block2); + TestUtils.BlocksAdd(snapshot2, index2, block2); Header header2 = new() { PrevHash = index2, Witness = new Witness { InvocationScript = Array.Empty(), VerificationScript = Array.Empty() } }; snapshot2.AddContract(UInt160.Zero, new ContractState()); @@ -179,7 +176,7 @@ public void TestVerifyWitnesses() }, Hashes = new UInt256[1] { UInt256.Zero }, }; - BlocksAdd(snapshot3, index3, block3); + TestUtils.BlocksAdd(snapshot3, index3, block3); Header header3 = new() { PrevHash = index3, @@ -213,25 +210,5 @@ public void TestVerifyWitnesses() Assert.AreEqual(true, Neo.SmartContract.Helper.VerifyWitnesses(tx, TestProtocolSettings.Default, snapshot3, 1000)); } - - private static void BlocksDelete(DataCache snapshot, UInt256 hash) - { - snapshot.Delete(NativeContract.Ledger.CreateStorageKey(Prefix_BlockHash, hash)); - snapshot.Delete(NativeContract.Ledger.CreateStorageKey(Prefix_Block, hash)); - } - - public static void TransactionAdd(DataCache snapshot, params TransactionState[] txs) - { - foreach (TransactionState tx in txs) - { - snapshot.Add(NativeContract.Ledger.CreateStorageKey(Prefix_Transaction, tx.Transaction.Hash), new StorageItem(tx)); - } - } - - public static void BlocksAdd(DataCache snapshot, UInt256 hash, TrimmedBlock block) - { - snapshot.Add(NativeContract.Ledger.CreateStorageKey(Prefix_BlockHash, block.Index), new StorageItem(hash.ToArray())); - snapshot.Add(NativeContract.Ledger.CreateStorageKey(Prefix_Block, hash), new StorageItem(block.ToArray())); - } } } diff --git a/tests/Neo.UnitTests/SmartContract/UT_Syscalls.cs b/tests/Neo.UnitTests/SmartContract/UT_Syscalls.cs index 7791b8acef..76448855d7 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_Syscalls.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_Syscalls.cs @@ -84,7 +84,7 @@ public void System_Blockchain_GetBlock() var height = snapshot[NativeContract.Ledger.CreateStorageKey(Prefix_CurrentBlock)].GetInteroperable(); height.Index = block.Index + TestProtocolSettings.Default.MaxTraceableBlocks; - UT_SmartContractHelper.BlocksAdd(snapshot, block.Hash, block); + TestUtils.BlocksAdd(snapshot, block.Hash, block); snapshot.Add(NativeContract.Ledger.CreateStorageKey(Prefix_Transaction, tx.Hash), new StorageItem(new TransactionState { BlockIndex = block.Index, diff --git a/tests/Neo.UnitTests/TestUtils.Block.cs b/tests/Neo.UnitTests/TestUtils.Block.cs new file mode 100644 index 0000000000..4f663fec2d --- /dev/null +++ b/tests/Neo.UnitTests/TestUtils.Block.cs @@ -0,0 +1,144 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// TestUtils.Block.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using Akka.Util.Internal; +using Neo.Cryptography; +using Neo.IO; +using Neo.Network.P2P.Payloads; +using Neo.Persistence; +using Neo.SmartContract; +using Neo.SmartContract.Native; +using Neo.VM; +using Neo.Wallets; +using Neo.Wallets.NEP6; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Neo.UnitTests; + +public partial class TestUtils +{ + const byte Prefix_Block = 5; + const byte Prefix_BlockHash = 9; + const byte Prefix_Transaction = 11; + + /// + /// Test Util function SetupHeaderWithValues + /// + /// The header to be assigned + /// PrevHash + /// MerkleRoot + /// NextConsensus + /// Timestamp + /// Index + /// Nonce + /// Witness + public static void SetupHeaderWithValues(Header header, UInt256 val256, out UInt256 merkRootVal, out UInt160 val160, out ulong timestampVal, out ulong nonceVal, out uint indexVal, out Witness scriptVal) + { + header.PrevHash = val256; + header.MerkleRoot = merkRootVal = UInt256.Parse("0x6226416a0e5aca42b5566f5a19ab467692688ba9d47986f6981a7f747bba2772"); + header.Timestamp = timestampVal = new DateTime(1980, 06, 01, 0, 0, 1, 001, DateTimeKind.Utc).ToTimestampMS(); // GMT: Sunday, June 1, 1980 12:00:01.001 AM + header.Index = indexVal = 0; + header.Nonce = nonceVal = 0; + header.NextConsensus = val160 = UInt160.Zero; + header.Witness = scriptVal = new Witness + { + InvocationScript = Array.Empty(), + VerificationScript = new[] { (byte)OpCode.PUSH1 } + }; + } + + public static void SetupBlockWithValues(Block block, UInt256 val256, out UInt256 merkRootVal, out UInt160 val160, out ulong timestampVal, out ulong nonceVal, out uint indexVal, out Witness scriptVal, out Transaction[] transactionsVal, int numberOfTransactions) + { + Header header = new Header(); + SetupHeaderWithValues(header, val256, out merkRootVal, out val160, out timestampVal, out nonceVal, out indexVal, out scriptVal); + + transactionsVal = new Transaction[numberOfTransactions]; + if (numberOfTransactions > 0) + { + for (int i = 0; i < numberOfTransactions; i++) + { + transactionsVal[i] = GetTransaction(UInt160.Zero); + } + } + + block.Header = header; + block.Transactions = transactionsVal; + + header.MerkleRoot = merkRootVal = MerkleTree.ComputeRoot(block.Transactions.Select(p => p.Hash).ToArray()); + } + + public static Block CreateBlockWithValidTransactions(DataCache snapshot, NEP6Wallet wallet, WalletAccount account, int numberOfTransactions) + { + var block = new Block(); + + var transactions = new List(); + for (var i = 0; i < numberOfTransactions; i++) + { + transactions.Add(CreateValidTx(snapshot, wallet, account)); + } + + var header = new Header(); + SetupHeaderWithValues(header, RandomUInt256(), out _, out _, out _, out _, out _, out _); + + block.Header = header; + block.Transactions = transactions.ToArray(); + + header.MerkleRoot = MerkleTree.ComputeRoot(block.Transactions.Select(p => p.Hash).ToArray()); + return block; + } + + public static void BlocksDelete(DataCache snapshot, UInt256 hash) + { + snapshot.Delete(NativeContract.Ledger.CreateStorageKey(Prefix_BlockHash, hash)); + snapshot.Delete(NativeContract.Ledger.CreateStorageKey(Prefix_Block, hash)); + } + + public static void TransactionAdd(DataCache snapshot, params TransactionState[] txs) + { + foreach (var tx in txs) + { + snapshot.Add(NativeContract.Ledger.CreateStorageKey(Prefix_Transaction, tx.Transaction.Hash), new StorageItem(tx)); + } + } + + public static void BlocksAdd(DataCache snapshot, UInt256 hash, TrimmedBlock block) + { + snapshot.Add(NativeContract.Ledger.CreateStorageKey(Prefix_BlockHash, block.Index), new StorageItem(hash.ToArray())); + snapshot.Add(NativeContract.Ledger.CreateStorageKey(Prefix_Block, hash), new StorageItem(block.ToArray())); + } + + public static void BlocksAdd(DataCache snapshot, UInt256 hash, Block block) + { + + block.Transactions.ForEach(tx => + { + var state = new TransactionState + { + BlockIndex = block.Index, + Transaction = tx + }; + TransactionAdd(snapshot, state); + }); + snapshot.Add(NativeContract.Ledger.CreateStorageKey(Prefix_BlockHash, block.Index), new StorageItem(hash.ToArray())); + snapshot.Add(NativeContract.Ledger.CreateStorageKey(Prefix_Block, hash), new StorageItem(block.ToTrimmedBlock().ToArray())); + } + + public static TrimmedBlock ToTrimmedBlock(this Block block) + { + return new TrimmedBlock + { + Header = block.Header, + Hashes = block.Transactions.Select(p => p.Hash).ToArray() + }; + } +} diff --git a/tests/Neo.UnitTests/TestUtils.cs b/tests/Neo.UnitTests/TestUtils.cs index f8f63de53a..55492d882c 100644 --- a/tests/Neo.UnitTests/TestUtils.cs +++ b/tests/Neo.UnitTests/TestUtils.cs @@ -10,25 +10,43 @@ // modifications are permitted. using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.Cryptography; using Neo.Cryptography.ECC; using Neo.IO; using Neo.Json; using Neo.Network.P2P.Payloads; +using Neo.Persistence; using Neo.SmartContract; using Neo.SmartContract.Manifest; using Neo.SmartContract.Native; using Neo.VM; +using Neo.Wallets; using Neo.Wallets.NEP6; using System; using System.Linq; +using System.Numerics; namespace Neo.UnitTests { - public static class TestUtils + public static partial class TestUtils { public static readonly Random TestRandom = new Random(1337); // use fixed seed for guaranteed determinism + public static UInt256 RandomUInt256() + { + byte[] data = new byte[32]; + TestRandom.NextBytes(data); + return new UInt256(data); + } + + public static UInt160 RandomUInt160() + { + byte[] data = new byte[20]; + TestRandom.NextBytes(data); + return new UInt160(data); + } + public static ContractManifest CreateDefaultManifest() { return new ContractManifest() @@ -111,6 +129,37 @@ public static NEP6Wallet GenerateTestWallet(string password) return new NEP6Wallet(null, password, TestProtocolSettings.Default, wallet); } + public static Transaction CreateValidTx(DataCache snapshot, NEP6Wallet wallet, WalletAccount account) + { + return CreateValidTx(snapshot, wallet, account.ScriptHash, (uint)new Random().Next()); + } + + public static Transaction CreateValidTx(DataCache snapshot, NEP6Wallet wallet, UInt160 account, uint nonce) + { + var tx = wallet.MakeTransaction(snapshot, new TransferOutput[] + { + new TransferOutput() + { + AssetId = NativeContract.GAS.Hash, + ScriptHash = account, + Value = new BigDecimal(BigInteger.One,8) + } + }, + account); + + tx.Nonce = nonce; + + var data = new ContractParametersContext(snapshot, tx, TestProtocolSettings.Default.Network); + Assert.IsNull(data.GetSignatures(tx.Sender)); + Assert.IsTrue(wallet.Sign(data)); + Assert.IsTrue(data.Completed); + Assert.AreEqual(1, data.GetSignatures(tx.Sender).Count()); + + tx.Witnesses = data.GetWitnesses(); + return tx; + } + + public static Transaction GetTransaction(UInt160 sender) { return new Transaction @@ -133,7 +182,7 @@ public static Transaction GetTransaction(UInt160 sender) }; } - internal static ContractState GetContract(string method = "test", int parametersCount = 0) + public static ContractState GetContract(string method = "test", int parametersCount = 0) { NefFile nef = new() { @@ -188,50 +237,13 @@ internal static StorageKey GetStorageKey(int id, byte[] keyValue) }; } - /// - /// Test Util function SetupHeaderWithValues - /// - /// The header to be assigned - /// PrevHash - /// MerkleRoot - /// NextConsensus - /// Timestamp - /// Index - /// Nonce - /// Witness - public static void SetupHeaderWithValues(Header header, UInt256 val256, out UInt256 merkRootVal, out UInt160 val160, out ulong timestampVal, out ulong nonceVal, out uint indexVal, out Witness scriptVal) - { - header.PrevHash = val256; - header.MerkleRoot = merkRootVal = UInt256.Parse("0x6226416a0e5aca42b5566f5a19ab467692688ba9d47986f6981a7f747bba2772"); - header.Timestamp = timestampVal = new DateTime(1980, 06, 01, 0, 0, 1, 001, DateTimeKind.Utc).ToTimestampMS(); // GMT: Sunday, June 1, 1980 12:00:01.001 AM - header.Index = indexVal = 0; - header.Nonce = nonceVal = 0; - header.NextConsensus = val160 = UInt160.Zero; - header.Witness = scriptVal = new Witness - { - InvocationScript = new byte[0], - VerificationScript = new[] { (byte)OpCode.PUSH1 } - }; - } - - public static void SetupBlockWithValues(Block block, UInt256 val256, out UInt256 merkRootVal, out UInt160 val160, out ulong timestampVal, out ulong nonceVal, out uint indexVal, out Witness scriptVal, out Transaction[] transactionsVal, int numberOfTransactions) + public static void StorageItemAdd(DataCache snapshot, int id, byte[] keyValue, byte[] value) { - Header header = new Header(); - SetupHeaderWithValues(header, val256, out merkRootVal, out val160, out timestampVal, out nonceVal, out indexVal, out scriptVal); - - transactionsVal = new Transaction[numberOfTransactions]; - if (numberOfTransactions > 0) + snapshot.Add(new StorageKey { - for (int i = 0; i < numberOfTransactions; i++) - { - transactionsVal[i] = GetTransaction(UInt160.Zero); - } - } - - block.Header = header; - block.Transactions = transactionsVal; - - header.MerkleRoot = merkRootVal = MerkleTree.ComputeRoot(block.Transactions.Select(p => p.Hash).ToArray()); + Id = id, + Key = keyValue + }, new StorageItem(value)); } public static Transaction CreateRandomHashTransaction() From ae998ee3a5730530970b9053b2fa67c0d5f5efdc Mon Sep 17 00:00:00 2001 From: Christopher Schuchardt Date: Mon, 1 Jul 2024 12:45:30 -0400 Subject: [PATCH 24/71] Remove comments in `nuget.yml` (#3359) * Fixed Typo in `nuget.yml` * reverted for path --- .github/workflows/nuget.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/nuget.yml b/.github/workflows/nuget.yml index 61ff1e3408..3fa6cc4f5e 100644 --- a/.github/workflows/nuget.yml +++ b/.github/workflows/nuget.yml @@ -35,8 +35,8 @@ jobs: dotnet pack ./neo.sln \ --configuration Release \ --output ./sbin \ - --verbosity normal \ # Normal verbosity level - -p:VersionPrefix=${{ env.APP_VERSION }} # Set the version prefix from tag_name + --verbosity normal \ + -p:VersionPrefix=${{ env.APP_VERSION }} - name: Publish to NuGet.org run: | From 5f66404f6ef0fcad301a14a177b8a3ad4d000d5c Mon Sep 17 00:00:00 2001 From: Shargon Date: Mon, 1 Jul 2024 22:44:51 +0200 Subject: [PATCH 25/71] Fix: `MemPool` null checks (#3367) * Fix null error * Add [MaybeNullWhen(false)] * Update MemoryPool.cs --- src/Neo/Ledger/MemoryPool.cs | 44 ++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/src/Neo/Ledger/MemoryPool.cs b/src/Neo/Ledger/MemoryPool.cs index 23eb711e87..7f59bc6e92 100644 --- a/src/Neo/Ledger/MemoryPool.cs +++ b/src/Neo/Ledger/MemoryPool.cs @@ -9,6 +9,7 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +#nullable enable using Akka.Util.Internal; using Neo.Network.P2P; using Neo.Network.P2P.Payloads; @@ -16,6 +17,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Runtime.CompilerServices; using System.Threading; @@ -27,8 +29,8 @@ namespace Neo.Ledger /// public class MemoryPool : IReadOnlyCollection { - public event EventHandler TransactionAdded; - public event EventHandler TransactionRemoved; + public event EventHandler? TransactionAdded; + public event EventHandler? TransactionRemoved; // Allow a reverified transaction to be rebroadcast if it has been this many block times since last broadcast. private const int BlocksTillRebroadcast = 10; @@ -157,15 +159,15 @@ public bool ContainsKey(UInt256 hash) /// The hash of the to get. /// When this method returns, contains the associated with the specified hash, if the hash is found; otherwise, . /// if the contains a with the specified hash; otherwise, . - public bool TryGetValue(UInt256 hash, out Transaction tx) + public bool TryGetValue(UInt256 hash, [MaybeNullWhen(false)] out Transaction? tx) { _txRwLock.EnterReadLock(); try { - bool ret = _unsortedTransactions.TryGetValue(hash, out PoolItem item) - || _unverifiedTransactions.TryGetValue(hash, out item); - tx = ret ? item.Tx : null; - return ret; + _ = _unsortedTransactions.TryGetValue(hash, out var item) + || _unverifiedTransactions.TryGetValue(hash, out item); + tx = item?.Tx; + return tx != null; } finally { @@ -247,13 +249,13 @@ public IEnumerable GetSortedVerifiedTransactions() } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static PoolItem GetLowestFeeTransaction(SortedSet verifiedTxSorted, - SortedSet unverifiedTxSorted, out SortedSet sortedPool) + private static PoolItem? GetLowestFeeTransaction(SortedSet verifiedTxSorted, + SortedSet unverifiedTxSorted, out SortedSet? sortedPool) { - PoolItem minItem = unverifiedTxSorted.Min; + var minItem = unverifiedTxSorted.Min; sortedPool = minItem != null ? unverifiedTxSorted : null; - PoolItem verifiedMin = verifiedTxSorted.Min; + var verifiedMin = verifiedTxSorted.Min; if (verifiedMin == null) return minItem; if (minItem != null && verifiedMin.CompareTo(minItem) >= 0) @@ -265,7 +267,7 @@ private static PoolItem GetLowestFeeTransaction(SortedSet verifiedTxSo return minItem; } - private PoolItem GetLowestFeeTransaction(out Dictionary unsortedTxPool, out SortedSet sortedPool) + private PoolItem? GetLowestFeeTransaction(out Dictionary unsortedTxPool, out SortedSet? sortedPool) { sortedPool = null; @@ -286,7 +288,10 @@ internal bool CanTransactionFitInPool(Transaction tx) { if (Count < Capacity) return true; - return GetLowestFeeTransaction(out _, out _).CompareTo(tx) <= 0; + var item = GetLowestFeeTransaction(out _, out _); + if (item == null) return false; + + return item.CompareTo(tx) <= 0; } internal VerifyResult TryAdd(Transaction tx, DataCache snapshot) @@ -295,7 +300,7 @@ internal VerifyResult TryAdd(Transaction tx, DataCache snapshot) if (_unsortedTransactions.ContainsKey(tx.Hash)) return VerifyResult.AlreadyInPool; - List removedTransactions = null; + List? removedTransactions = null; _txRwLock.EnterWriteLock(); try { @@ -368,7 +373,7 @@ private bool CheckConflicts(Transaction tx, out List conflictsList) // Step 2: check if unsorted transactions were in `tx`'s Conflicts attributes. foreach (var hash in tx.GetAttributes().Select(p => p.Hash)) { - if (_unsortedTransactions.TryGetValue(hash, out PoolItem unsortedTx)) + if (_unsortedTransactions.TryGetValue(hash, out var unsortedTx)) { if (!tx.Signers.Select(p => p.Account).Intersect(unsortedTx.Tx.Signers.Select(p => p.Account)).Any()) return false; conflictsFeeSum += unsortedTx.Tx.NetworkFee; @@ -390,7 +395,8 @@ private List RemoveOverCapacity() List removedTransactions = new(); do { - PoolItem minItem = GetLowestFeeTransaction(out var unsortedPool, out var sortedPool); + var minItem = GetLowestFeeTransaction(out var unsortedPool, out var sortedPool); + if (minItem == null || sortedPool == null) break; unsortedPool.Remove(minItem.Tx.Hash); sortedPool.Remove(minItem); @@ -407,7 +413,7 @@ private List RemoveOverCapacity() } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private bool TryRemoveVerified(UInt256 hash, out PoolItem item) + private bool TryRemoveVerified(UInt256 hash, [MaybeNullWhen(false)] out PoolItem? item) { if (!_unsortedTransactions.TryGetValue(hash, out item)) return false; @@ -425,7 +431,7 @@ private void RemoveConflictsOfVerified(PoolItem item) { foreach (var h in item.Tx.GetAttributes().Select(attr => attr.Hash)) { - if (_conflicts.TryGetValue(h, out HashSet conflicts)) + if (_conflicts.TryGetValue(h, out var conflicts)) { conflicts.Remove(item.Tx.Hash); if (conflicts.Count() == 0) @@ -437,7 +443,7 @@ private void RemoveConflictsOfVerified(PoolItem item) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal bool TryRemoveUnVerified(UInt256 hash, out PoolItem item) + internal bool TryRemoveUnVerified(UInt256 hash, [MaybeNullWhen(false)] out PoolItem? item) { if (!_unverifiedTransactions.TryGetValue(hash, out item)) return false; From 96c9e771a9c7587cdb85867878909dd29dc03663 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=BF=97=E5=90=8C?= Date: Wed, 3 Jul 2024 17:02:58 +0000 Subject: [PATCH 26/71] plugins: remove expressions that are always true (#3393) * this expression is always true * Improve --------- Co-authored-by: Shargon --- src/Plugins/ApplicationLogs/LogReader.cs | 7 +++---- src/Plugins/OracleService/OracleService.cs | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/Plugins/ApplicationLogs/LogReader.cs b/src/Plugins/ApplicationLogs/LogReader.cs index f9d1470f03..b3f767fecb 100644 --- a/src/Plugins/ApplicationLogs/LogReader.cs +++ b/src/Plugins/ApplicationLogs/LogReader.cs @@ -143,12 +143,11 @@ private void OnGetBlockCommand(string blockHashOrIndex, string eventName = null) _neostore.GetBlockLog(blockhash, TriggerType.PostPersist) : _neostore.GetBlockLog(blockhash, TriggerType.PostPersist, eventName); - if (blockOnPersist == null && blockOnPersist == null) + if (blockOnPersist == null) ConsoleHelper.Error($"No logs."); - if (blockOnPersist != null) - PrintExecutionToConsole(blockOnPersist); - if (blockPostPersist != null) + else { + PrintExecutionToConsole(blockOnPersist); ConsoleHelper.Info("--------------------------------"); PrintExecutionToConsole(blockPostPersist); } diff --git a/src/Plugins/OracleService/OracleService.cs b/src/Plugins/OracleService/OracleService.cs index a1a3e92eae..6f291e763d 100644 --- a/src/Plugins/OracleService/OracleService.cs +++ b/src/Plugins/OracleService/OracleService.cs @@ -532,7 +532,7 @@ private bool CheckTxSign(DataCache snapshot, Transaction tx, ConcurrentDictionar } ECPoint[] oraclesNodes = NativeContract.RoleManagement.GetDesignatedByRole(snapshot, Role.Oracle, height); int neededThreshold = oraclesNodes.Length - (oraclesNodes.Length - 1) / 3; - if (OracleSigns.Count >= neededThreshold && tx != null) + if (OracleSigns.Count >= neededThreshold) { var contract = Contract.CreateMultiSigContract(neededThreshold, oraclesNodes); ScriptBuilder sb = new ScriptBuilder(); From 20b7409eac25f54e2ac42d85b190991b48a7c59d Mon Sep 17 00:00:00 2001 From: Christopher Schuchardt Date: Wed, 3 Jul 2024 23:01:53 -0400 Subject: [PATCH 27/71] [**Part-1] Add `github` Release Workflow (#3308) * Added `release.yml` * Fixed `release.yml` * Remove `VersionPrefix` * Added macos leveldb * Fixed * Remove comments on the command-line * Fixed `CodeSign` `neo-cli` * Added steps for `codesign` in `release.yml` --------- Co-authored-by: Jimmy Co-authored-by: NGD Admin <154295625+NGDAdmin@users.noreply.github.com> --- .github/workflows/release.yml | 348 ++++++++++++++++++++++++++++++++++ 1 file changed, 348 insertions(+) create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000000..bcfddc1185 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,348 @@ +name: Release (neo-cli) + +# Trigger the workflow on a release event when a new release is published +on: + release: + types: [published] + +# Define environment variables +env: + DOTNET_VERSION: 8.0.x + CONFIGURATION: Release + DIST_PATH: /tmp/dist + OUTPUT_PATH: /tmp/out + +jobs: + build-leveldb: + name: Build leveldb win-${{ matrix.arch }} + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [windows-latest] + arch: [x64, arm64] + + steps: + # Step to lookup cache for the LevelDB build distribution + - name: Lookup Cache Distribution + id: cache-leveldb + uses: actions/cache@v4 + with: + path: ./leveldb/build/Release/* + key: leveldb-${{ matrix.os }}-${{ matrix.arch }} + enableCrossOsArchive: true + lookup-only: true + + # Conditionally checkout LevelDB repository if cache is not found + - if: ${{ steps.cache-leveldb.outputs.cache-hit != 'true' }} + name: Checkout Repository Code (leveldb) + uses: actions/checkout@v4 + with: + repository: google/leveldb + path: leveldb + submodules: true + fetch-depth: 0 + + # Conditionally setup MSBuild if cache is not found + - if: ${{ matrix.os == 'windows-latest' && steps.cache-leveldb.outputs.cache-hit != 'true' }} + name: Setup MSBuild + uses: microsoft/setup-msbuild@v2 + + # Conditionally setup LevelDB build directory if cache is not found + - if: ${{ steps.cache-leveldb.outputs.cache-hit != 'true' }} + name: Setup LevelDb + working-directory: ./leveldb + run: mkdir -p ./build/Release + + # Conditionally create build files for LevelDB if cache is not found + - if: ${{ steps.cache-leveldb.outputs.cache-hit != 'true' }} + name: Create Build Files (win-${{ matrix.arch }}) + working-directory: ./leveldb/build + run: cmake -DBUILD_SHARED_LIBS=ON -A ${{ matrix.arch }} .. + + # Conditionally build LevelDB using MSBuild if cache is not found + - if: ${{ matrix.os == 'windows-latest' && steps.cache-leveldb.outputs.cache-hit != 'true' }} + name: Build (MSBuild) + working-directory: ./leveldb/build + run: msbuild ./leveldb.sln /p:Configuration=Release + + # Conditionally cache the LevelDB distribution if it was built + - if: ${{ steps.cache-leveldb.outputs.cache-hit != 'true' }} + name: Cache Distribution + uses: actions/cache/save@v4 + with: + path: ./leveldb/build/Release/* + key: leveldb-${{ matrix.os }}-${{ matrix.arch }} + enableCrossOsArchive: true + + build-neo-cli: + needs: [build-leveldb] + name: ${{ matrix.runtime }} + runs-on: ubuntu-latest + strategy: + matrix: + runtime: [linux-x64, linux-arm64, win-x64, win-arm64, osx-x64, osx-arm64] + + steps: + # Step to set the application version from the release tag + - name: Set Application Version (Environment Variable) + run: | + APP_VERSION=$(echo '${{ github.event.release.tag_name }}' | cut -d 'v' -f 2) + echo "APP_VERSION=$APP_VERSION" >> $GITHUB_ENV + + # Checkout the neo-cli repository code + - name: Checkout Repository Code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + # Setup .NET environment + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: ${{ env.DOTNET_VERSION }} + + # Publish the neo-cli project + - name: .NET Publish (neo-cli) + run: | + dotnet publish ./src/Neo.CLI \ + --version-suffix ${{ matrix.runtime }} \ + --framework net8.0 \ + --configuration ${{ env.CONFIGURATION }} \ + --runtime ${{ matrix.runtime }} \ + --self-contained true \ + --output ${{ env.OUTPUT_PATH }}/${{ matrix.runtime }} \ + --verbosity normal \ + -p:VersionPrefix=${{ env.APP_VERSION }} \ + -p:RuntimeIdentifier=${{ matrix.runtime }} \ + -p:SelfContained=true \ + -p:IncludeNativeLibrariesForSelfExtract=false \ + -p:PublishTrimmed=false \ + -p:PublishSingleFile=true \ + -p:PublishReadyToRun=true \ + -p:EnableCompressionInSingleFile=true \ + -p:DebugType=embedded \ + -p:ServerGarbageCollection=true + + # Build the LevelDBStore plugin + - name: .NET Build (LevelDBStore) + run: | + dotnet build ./src/Plugins/LevelDBStore \ + --version-suffix ${{ matrix.runtime }} \ + --framework net8.0 \ + --configuration ${{ env.CONFIGURATION }} \ + --output ${{ env.OUTPUT_PATH }}/${{ matrix.runtime }}/Plugins/LevelDBStore \ + --verbosity normal \ + -p:VersionPrefix=${{ env.APP_VERSION }} + + # Remove unnecessary files from the LevelDBStore plugin output + - name: Remove files (junk) + working-directory: ${{ env.OUTPUT_PATH }}/${{ matrix.runtime }}/Plugins/LevelDBStore + run: | + rm -v Neo* + rm -v *.pdb + rm -v *.xml + + # Remove XML comment files from the neo-cli output + - name: Remove Xml Comment Files + working-directory: ${{ env.OUTPUT_PATH }}/${{ matrix.runtime }} + run: rm -v *.xml + + # Get cached LevelDB distribution for Windows x64 if applicable + - if: ${{ startsWith(matrix.runtime, 'win-x64') }} + name: Get Distribution Caches (win-x64) + uses: actions/cache@v4 + with: + path: ./leveldb/build/Release/* + key: leveldb-windows-latest-x64 + enableCrossOsArchive: true + fail-on-cache-miss: true + + # Get cached LevelDB distribution for Windows arm64 if applicable + - if: ${{ startsWith(matrix.runtime, 'win-arm64') }} + name: Get Distribution Caches (win-arm64) + uses: actions/cache@v4 + with: + path: ./leveldb/build/Release/* + key: leveldb-windows-latest-arm64 + enableCrossOsArchive: true + fail-on-cache-miss: true + + # Copy LevelDB files to the output directory for Windows + - if: ${{ startsWith(matrix.runtime, 'win') }} + name: Copy Files (leveldb) (win) + run: cp -v ./leveldb/build/Release/leveldb.dll ${{ env.OUTPUT_PATH }}/${{ matrix.runtime }}/libleveldb.dll + + # Create the distribution directory + - name: Create Distribution Directory + run: mkdir -p ${{ env.DIST_PATH }} + + # Create a tarball file for Linux distributions + - name: Create Tarball File (linux) + if: ${{ startsWith(matrix.runtime, 'linux') }} + working-directory: ${{ env.OUTPUT_PATH }}/${{ matrix.runtime }} + run: tar -czvf ${{ env.DIST_PATH }}/neo-cli.v${{ env.APP_VERSION }}-${{ matrix.runtime }}.tar.gz . + + # Create a tarball file for macOS distributions + - name: Cache Distribution + uses: actions/cache/save@v4 + with: + path: ${{ env.OUTPUT_PATH }}/${{ matrix.runtime }}/* + key: neo-${{ matrix.runtime }} + enableCrossOsArchive: true + + # Create a zip file for Windows distributions + - name: Create Zip File (win) + if: ${{ startsWith(matrix.runtime, 'win') }} + working-directory: ${{ env.OUTPUT_PATH }}/${{ matrix.runtime }} + run: zip ${{ env.DIST_PATH }}/neo-cli.v${{ env.APP_VERSION }}-${{ matrix.runtime }}.zip -r * + + # Create checksum files for Linux distributions + - name: Create Checksum Files (linux) + if: ${{ startsWith(matrix.runtime, 'linux') }} + working-directory: ${{ env.DIST_PATH }} + env: + FILENAME: neo-cli.v${{ env.APP_VERSION }}-${{ matrix.runtime }} + run: | + sha256sum ${{ env.FILENAME }}.tar.gz > ${{ env.FILENAME }}.sha256 + + # Create checksum files for Windows distributions + - name: Create Checksum Files (win) + if: ${{ startsWith(matrix.runtime, 'win') }} + working-directory: ${{ env.DIST_PATH }} + env: + FILENAME: neo-cli.v${{ env.APP_VERSION }}-${{ matrix.runtime }} + run: | + sha256sum ${{ env.FILENAME }}.zip > ${{ env.FILENAME }}.sha256 + + # List the contents of the distribution and output directories + - name: Output/Distribution Directory Contents + run: | + ls -la ${{ env.DIST_PATH }} + ls -la ${{ env.OUTPUT_PATH }}/${{ matrix.runtime }} + + # Upload tarball files for Linux distributions + - name: Upload Tarball File (linux) + if: ${{ startsWith(matrix.runtime, 'linux') }} + uses: actions/upload-release-asset@latest + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ github.event.release.upload_url }} + asset_path: ${{ env.DIST_PATH }}/neo-cli.v${{ env.APP_VERSION }}-${{ matrix.runtime }}.tar.gz + asset_name: neo-cli.v${{ env.APP_VERSION }}-${{ matrix.runtime }}.tar.gz + asset_content_type: application/x-gtar + + # Upload zip files for Windows distributions + - name: Upload Zip File (win) + if: ${{ startsWith(matrix.runtime, 'win') }} + uses: actions/upload-release-asset@latest + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ github.event.release.upload_url }} + asset_path: ${{ env.DIST_PATH }}/neo-cli.v${{ env.APP_VERSION }}-${{ matrix.runtime }}.zip + asset_name: neo-cli.v${{ env.APP_VERSION }}-${{ matrix.runtime }}.zip + asset_content_type: application/zip + + # Upload checksum files for all distributions + - name: Upload Checksum File (all) + if: ${{ startsWith(matrix.runtime, 'osx') == false }} + uses: actions/upload-release-asset@latest + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ github.event.release.upload_url }} + asset_path: ${{ env.DIST_PATH }}/neo-cli.v${{ env.APP_VERSION }}-${{ matrix.runtime }}.sha256 + asset_name: neo-cli.v${{ env.APP_VERSION }}-${{ matrix.runtime }}.sha256 + asset_content_type: text/plain + + code-sign: + needs: [build-neo-cli] + name: CodeSign & Publish (neo-cli) ${{ matrix.arch }} + runs-on: macos-latest + strategy: + matrix: + arch: [x64, arm64] + + steps: + # Step to set the application version from the release tag + - name: Set Application Version (Environment Variable) + run: | + APP_VERSION=$(echo '${{ github.event.release.tag_name }}' | cut -d 'v' -f 2) + echo "APP_VERSION=$APP_VERSION" >> $GITHUB_ENV + + - name: Get Distribution Caches (win-${{ matrix.arch}}) + uses: actions/cache@v4 + with: + path: ${{ env.OUTPUT_PATH }}/osx-${{ matrix.arch }}/* + key: neo-osx-${{ matrix.arch }} + enableCrossOsArchive: true + fail-on-cache-miss: true + + - name: Sign (neo-cli) + working-directory: ${{ env.OUTPUT_PATH }}/osx-${{ matrix.arch }} + run: codesign --force --deep -s - neo-cli + + # Create the distribution directory + - name: Create Distribution Directory + run: mkdir -p ${{ env.DIST_PATH }} + + # Create a tarball file for macOS distributions + - name: Create Tarball File (osx) + working-directory: ${{ env.OUTPUT_PATH }}/osx-${{ matrix.arch }} + run: tar -cJf ${{ env.DIST_PATH }}/neo-cli.v${{ env.APP_VERSION }}-osx-${{ matrix.arch }}.tar.xz . + + # Create checksum files for macOS distributions + - name: Create Checksum Files (osx) + working-directory: ${{ env.DIST_PATH }} + env: + FILENAME: neo-cli.v${{ env.APP_VERSION }}-osx-${{ matrix.arch }} + run: | + shasum -a 256 ${{ env.FILENAME }}.tar.xz > ${{ env.FILENAME }}.sha256 + + # Upload tarball files for macOS distributions + - name: Upload Tarball File (osx) + uses: actions/upload-release-asset@latest + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ github.event.release.upload_url }} + asset_path: ${{ env.DIST_PATH }}/neo-cli.v${{ env.APP_VERSION }}-osx-${{ matrix.arch }}.tar.xz + asset_name: neo-cli.v${{ env.APP_VERSION }}-osx-${{ matrix.arch }}.tar.xz + asset_content_type: application/x-gtar + + # Upload checksum files for all distributions + - name: Upload Checksum File (all) + uses: actions/upload-release-asset@latest + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ github.event.release.upload_url }} + asset_path: ${{ env.DIST_PATH }}/neo-cli.v${{ env.APP_VERSION }}-osx-${{ matrix.arch }}.sha256 + asset_name: neo-cli.v${{ env.APP_VERSION }}-osx-${{ matrix.arch }}.sha256 + asset_content_type: text/plain + + cleanup: + needs: [build-neo-cli, code-sign] + runs-on: ubuntu-latest + steps: + # Cleanup step to delete old caches + - name: Cleanup + run: | + gh extension install actions/gh-actions-cache + + echo "Fetching list of cache key" + cacheKeysForPR=$(gh actions-cache list -R $REPO -B $BRANCH -L 100 | cut -f 1 ) + + ## Setting this to not fail the workflow while deleting cache keys. + set +e + echo "Deleting caches..." + for cacheKey in $cacheKeysForPR + do + gh actions-cache delete $cacheKey -R $REPO -B $BRANCH --confirm + done + echo "Done" + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + REPO: ${{ github.repository }} + BRANCH: ${{ github.ref }} From a80fca637f6bf407de1a04f89c1a18f94c6ae646 Mon Sep 17 00:00:00 2001 From: Shargon Date: Thu, 4 Jul 2024 09:53:39 +0200 Subject: [PATCH 28/71] cli: Fix `plugins` command (#3394) * Fix plugin list * Update src/Neo.CLI/CLI/MainService.Plugins.cs --------- Co-authored-by: NGD Admin <154295625+NGDAdmin@users.noreply.github.com> --- src/Neo.CLI/CLI/MainService.Plugins.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Neo.CLI/CLI/MainService.Plugins.cs b/src/Neo.CLI/CLI/MainService.Plugins.cs index 761dd386d2..77fb73f8f8 100644 --- a/src/Neo.CLI/CLI/MainService.Plugins.cs +++ b/src/Neo.CLI/CLI/MainService.Plugins.cs @@ -269,13 +269,15 @@ private async Task> GetPluginListAsync() var asmName = Assembly.GetExecutingAssembly().GetName(); httpClient.DefaultRequestHeaders.UserAgent.Add(new(asmName.Name!, asmName.Version!.ToString(3))); - var json = await httpClient.GetFromJsonAsync(Settings.Default.Plugins.DownloadUrl) ?? throw new HttpRequestException($"Failed: {Settings.Default.Plugins.DownloadUrl}"); + var json = await httpClient.GetFromJsonAsync(Settings.Default.Plugins.DownloadUrl) + ?? throw new HttpRequestException($"Failed: {Settings.Default.Plugins.DownloadUrl}"); return json.AsArray() .Where(w => w != null && w["tag_name"]!.GetValue() == $"v{Settings.Default.Plugins.Version.ToString(3)}") .SelectMany(s => s!["assets"]!.AsArray()) - .Select(s => Path.GetFileNameWithoutExtension(s!["name"]!.GetValue())); + .Select(s => Path.GetFileNameWithoutExtension(s!["name"]!.GetValue())) + .Where(s => !s.StartsWith("neo-cli", StringComparison.InvariantCultureIgnoreCase)); } } } From 188028ba2b633bcda9d9e13775957635e0a81920 Mon Sep 17 00:00:00 2001 From: Christopher Schuchardt Date: Thu, 4 Jul 2024 03:59:39 -0400 Subject: [PATCH 29/71] Added blame logging for `dotnet test` (#3384) Co-authored-by: Jimmy Co-authored-by: Shargon --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 5294cd09f4..458ff0e80a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -68,7 +68,7 @@ jobs: if: matrix.os != 'ubuntu-latest' run: | dotnet sln neo.sln remove ./tests/Neo.Plugins.Storage.Tests/Neo.Plugins.Storage.Tests.csproj - dotnet test + dotnet test --blame-hang --blame-crash - name: Test for coverall if: matrix.os == 'ubuntu-latest' From 5a14bf207febf88925b2c9bbfca99d487a785a59 Mon Sep 17 00:00:00 2001 From: Owen <38493437+superboyiii@users.noreply.github.com> Date: Fri, 5 Jul 2024 10:36:38 +0800 Subject: [PATCH 30/71] Fix download tips (#3395) * Added `release.yml` * Fixed `release.yml` * Remove `VersionPrefix` * Added macos leveldb * Fixed * Remove comments on the command-line * Fixed `CodeSign` `neo-cli` * Added steps for `codesign` in `release.yml` * Add downloading plugin tips * Change to ConsoleHelper * Move before first download --------- Co-authored-by: Christopher Schuchardt Co-authored-by: Jimmy Co-authored-by: NGD Admin <154295625+NGDAdmin@users.noreply.github.com> Co-authored-by: Shargon --- src/Neo.CLI/CLI/MainService.Plugins.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Neo.CLI/CLI/MainService.Plugins.cs b/src/Neo.CLI/CLI/MainService.Plugins.cs index 77fb73f8f8..a3974d5e48 100644 --- a/src/Neo.CLI/CLI/MainService.Plugins.cs +++ b/src/Neo.CLI/CLI/MainService.Plugins.cs @@ -80,6 +80,7 @@ private void OnReinstallCommand(string pluginName) /// Downloaded content private static async Task DownloadPluginAsync(string pluginName, Version pluginVersion, string? customDownloadUrl = null, bool prerelease = false) { + ConsoleHelper.Info($"Downloading {pluginName} {pluginVersion}..."); using var httpClient = new HttpClient(); var asmName = Assembly.GetExecutingAssembly().GetName(); @@ -104,7 +105,6 @@ private static async Task DownloadPluginAsync(string pluginName, Version ?? throw new Exception($"Could not find {pluginName}"); var downloadUrl = jsonPlugin["browser_download_url"]!.GetValue(); - return await httpClient.GetStreamAsync(downloadUrl); } From b7bc07bb964fa171984a7749e3e2e0f81e8bbf1d Mon Sep 17 00:00:00 2001 From: Shargon Date: Fri, 5 Jul 2024 04:55:32 +0200 Subject: [PATCH 31/71] `DeprecatedIn` for events (#3362) * DeprecatedIn for events * Added UT * Remove using --------- Co-authored-by: Jimmy Co-authored-by: NGD Admin <154295625+NGDAdmin@users.noreply.github.com> --- .../Native/ContractEventAttribute.cs | 54 ++++++++++++++----- .../Native/ContractMethodAttribute.cs | 7 ++- .../Native/ContractMethodMetadata.cs | 2 +- .../Native/IHardforkActivable.cs | 19 +++++++ .../SmartContract/Native/NativeContract.cs | 23 ++++---- .../SmartContract/Native/UT_NativeContract.cs | 22 ++++++++ 6 files changed, 102 insertions(+), 25 deletions(-) create mode 100644 src/Neo/SmartContract/Native/IHardforkActivable.cs diff --git a/src/Neo/SmartContract/Native/ContractEventAttribute.cs b/src/Neo/SmartContract/Native/ContractEventAttribute.cs index 656ecef725..b2ff30891a 100644 --- a/src/Neo/SmartContract/Native/ContractEventAttribute.cs +++ b/src/Neo/SmartContract/Native/ContractEventAttribute.cs @@ -17,11 +17,12 @@ namespace Neo.SmartContract.Native { [DebuggerDisplay("{Descriptor.Name}")] [AttributeUsage(AttributeTargets.Constructor, AllowMultiple = true)] - internal class ContractEventAttribute : Attribute + internal class ContractEventAttribute : Attribute, IHardforkActivable { public int Order { get; init; } public ContractEventDescriptor Descriptor { get; set; } public Hardfork? ActiveIn { get; init; } = null; + public Hardfork? DeprecatedIn { get; init; } = null; public ContractEventAttribute(Hardfork activeIn, int order, string name, string arg1Name, ContractParameterType arg1Value) : this(order, name, arg1Name, arg1Value) @@ -29,23 +30,35 @@ public ContractEventAttribute(Hardfork activeIn, int order, string name, ActiveIn = activeIn; } + public ContractEventAttribute(Hardfork activeIn, int order, string name, + string arg1Name, ContractParameterType arg1Value, Hardfork deprecatedIn) : this(activeIn, order, name, arg1Name, arg1Value) + { + DeprecatedIn = deprecatedIn; + } + public ContractEventAttribute(int order, string name, string arg1Name, ContractParameterType arg1Value) { Order = order; Descriptor = new ContractEventDescriptor() { Name = name, - Parameters = new ContractParameterDefinition[] - { + Parameters = + [ new ContractParameterDefinition() { Name = arg1Name, Type = arg1Value } - } + ] }; } + public ContractEventAttribute(int order, string name, string arg1Name, ContractParameterType arg1Value, Hardfork deprecatedIn) + : this(order, name, arg1Name, arg1Value) + { + DeprecatedIn = deprecatedIn; + } + public ContractEventAttribute(Hardfork activeIn, int order, string name, string arg1Name, ContractParameterType arg1Value, string arg2Name, ContractParameterType arg2Value) : this(order, name, arg1Name, arg1Value, arg2Name, arg2Value) @@ -53,6 +66,13 @@ public ContractEventAttribute(Hardfork activeIn, int order, string name, ActiveIn = activeIn; } + public ContractEventAttribute(Hardfork activeIn, int order, string name, + string arg1Name, ContractParameterType arg1Value, + string arg2Name, ContractParameterType arg2Value, Hardfork deprecatedIn) : this(activeIn, order, name, arg1Name, arg1Value, arg2Name, arg2Value) + { + DeprecatedIn = deprecatedIn; + } + public ContractEventAttribute(int order, string name, string arg1Name, ContractParameterType arg1Value, string arg2Name, ContractParameterType arg2Value) @@ -61,8 +81,8 @@ public ContractEventAttribute(int order, string name, Descriptor = new ContractEventDescriptor() { Name = name, - Parameters = new ContractParameterDefinition[] - { + Parameters = + [ new ContractParameterDefinition() { Name = arg1Name, @@ -73,10 +93,18 @@ public ContractEventAttribute(int order, string name, Name = arg2Name, Type = arg2Value } - } + ] }; } + public ContractEventAttribute(int order, string name, + string arg1Name, ContractParameterType arg1Value, + string arg2Name, ContractParameterType arg2Value, Hardfork deprecatedIn) : this(order, name, arg1Name, arg1Value, arg2Name, arg2Value) + { + DeprecatedIn = deprecatedIn; + } + + public ContractEventAttribute(Hardfork activeIn, int order, string name, string arg1Name, ContractParameterType arg1Value, string arg2Name, ContractParameterType arg2Value, @@ -95,8 +123,8 @@ public ContractEventAttribute(int order, string name, Descriptor = new ContractEventDescriptor() { Name = name, - Parameters = new ContractParameterDefinition[] - { + Parameters = + [ new ContractParameterDefinition() { Name = arg1Name, @@ -112,7 +140,7 @@ public ContractEventAttribute(int order, string name, Name = arg3Name, Type = arg3Value } - } + ] }; } @@ -136,8 +164,8 @@ public ContractEventAttribute(int order, string name, Descriptor = new ContractEventDescriptor() { Name = name, - Parameters = new ContractParameterDefinition[] - { + Parameters = + [ new ContractParameterDefinition() { Name = arg1Name, @@ -158,7 +186,7 @@ public ContractEventAttribute(int order, string name, Name = arg4Name, Type = arg4Value } - } + ] }; } } diff --git a/src/Neo/SmartContract/Native/ContractMethodAttribute.cs b/src/Neo/SmartContract/Native/ContractMethodAttribute.cs index 7caa27c8b0..38bc065533 100644 --- a/src/Neo/SmartContract/Native/ContractMethodAttribute.cs +++ b/src/Neo/SmartContract/Native/ContractMethodAttribute.cs @@ -16,7 +16,7 @@ namespace Neo.SmartContract.Native { [DebuggerDisplay("{Name}")] [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, AllowMultiple = false)] - internal class ContractMethodAttribute : Attribute + internal class ContractMethodAttribute : Attribute, IHardforkActivable { public string Name { get; init; } public CallFlags RequiredCallFlags { get; init; } @@ -32,6 +32,11 @@ public ContractMethodAttribute(Hardfork activeIn) ActiveIn = activeIn; } + public ContractMethodAttribute(Hardfork activeIn, Hardfork deprecatedIn) : this(activeIn) + { + DeprecatedIn = deprecatedIn; + } + public ContractMethodAttribute(bool isDeprecated, Hardfork deprecatedIn) { if (!isDeprecated) throw new ArgumentException("isDeprecated must be true", nameof(isDeprecated)); diff --git a/src/Neo/SmartContract/Native/ContractMethodMetadata.cs b/src/Neo/SmartContract/Native/ContractMethodMetadata.cs index 30874efb47..fd5a02be6a 100644 --- a/src/Neo/SmartContract/Native/ContractMethodMetadata.cs +++ b/src/Neo/SmartContract/Native/ContractMethodMetadata.cs @@ -24,7 +24,7 @@ namespace Neo.SmartContract.Native { [DebuggerDisplay("{Name}")] - internal class ContractMethodMetadata + internal class ContractMethodMetadata : IHardforkActivable { public string Name { get; } public MethodInfo Handler { get; } diff --git a/src/Neo/SmartContract/Native/IHardforkActivable.cs b/src/Neo/SmartContract/Native/IHardforkActivable.cs new file mode 100644 index 0000000000..7794d03f25 --- /dev/null +++ b/src/Neo/SmartContract/Native/IHardforkActivable.cs @@ -0,0 +1,19 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// IHardforkActivable.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +namespace Neo.SmartContract.Native +{ + internal interface IHardforkActivable + { + public Hardfork? ActiveIn { get; } + public Hardfork? DeprecatedIn { get; } + } +} diff --git a/src/Neo/SmartContract/Native/NativeContract.cs b/src/Neo/SmartContract/Native/NativeContract.cs index 1cc244408d..b030f06c9b 100644 --- a/src/Neo/SmartContract/Native/NativeContract.cs +++ b/src/Neo/SmartContract/Native/NativeContract.cs @@ -161,6 +161,7 @@ protected NativeContract() _usedHardforks = _methodDescriptors.Select(u => u.ActiveIn) .Concat(_methodDescriptors.Select(u => u.DeprecatedIn)) + .Concat(_eventsDescriptors.Select(u => u.DeprecatedIn)) .Concat(_eventsDescriptors.Select(u => u.ActiveIn)) .Concat([ActiveIn]) .Where(u => u is not null) @@ -184,15 +185,7 @@ private NativeContractsCache.CacheEntry GetAllowedMethods(IsHardforkEnabledDeleg byte[] script; using (ScriptBuilder sb = new()) { - foreach (ContractMethodMetadata method in _methodDescriptors.Where(u - => - // no hardfork is involved - u.ActiveIn is null && u.DeprecatedIn is null || - // deprecated method hardfork is involved - u.DeprecatedIn is not null && hfChecker(u.DeprecatedIn.Value, blockHeight) == false || - // active method hardfork is involved - u.ActiveIn is not null && hfChecker(u.ActiveIn.Value, blockHeight)) - ) + foreach (ContractMethodMetadata method in _methodDescriptors.Where(u => IsActive(u, hfChecker, blockHeight))) { method.Descriptor.Offset = sb.Length; sb.EmitPush(0); //version @@ -215,6 +208,16 @@ u.ActiveIn is null && u.DeprecatedIn is null || [MethodImpl(MethodImplOptions.AggressiveInlining)] public ContractState GetContractState(ProtocolSettings settings, uint blockHeight) => GetContractState(settings.IsHardforkEnabled, blockHeight); + internal static bool IsActive(IHardforkActivable u, IsHardforkEnabledDelegate hfChecker, uint blockHeight) + { + return // no hardfork is involved + u.ActiveIn is null && u.DeprecatedIn is null || + // deprecated method hardfork is involved + u.DeprecatedIn is not null && hfChecker(u.DeprecatedIn.Value, blockHeight) == false || + // active method hardfork is involved + u.ActiveIn is not null && hfChecker(u.ActiveIn.Value, blockHeight); + } + /// /// The of the native contract. /// @@ -245,7 +248,7 @@ public ContractState GetContractState(IsHardforkEnabledDelegate hfChecker, uint Abi = new ContractAbi { Events = _eventsDescriptors - .Where(u => u.ActiveIn is null || hfChecker(u.ActiveIn.Value, blockHeight)) + .Where(u => IsActive(u, hfChecker, blockHeight)) .Select(p => p.Descriptor).ToArray(), Methods = allowedMethods.Methods.Values .Select(p => p.Descriptor).ToArray() diff --git a/tests/Neo.UnitTests/SmartContract/Native/UT_NativeContract.cs b/tests/Neo.UnitTests/SmartContract/Native/UT_NativeContract.cs index 1989b4323b..61e6e67f48 100644 --- a/tests/Neo.UnitTests/SmartContract/Native/UT_NativeContract.cs +++ b/tests/Neo.UnitTests/SmartContract/Native/UT_NativeContract.cs @@ -58,6 +58,28 @@ public void Clean() TestBlockchain.ResetStore(); } + class active : IHardforkActivable + { + public Hardfork? ActiveIn { get; init; } + public Hardfork? DeprecatedIn { get; init; } + } + + [TestMethod] + public void TestActiveDeprecatedIn() + { + string json = UT_ProtocolSettings.CreateHKSettings("\"HF_Cockatrice\": 20"); + var file = Path.GetTempFileName(); + File.WriteAllText(file, json); + ProtocolSettings settings = ProtocolSettings.Load(file, false); + File.Delete(file); + + Assert.IsFalse(NativeContract.IsActive(new active() { ActiveIn = Hardfork.HF_Cockatrice, DeprecatedIn = null }, settings.IsHardforkEnabled, 1)); + Assert.IsTrue(NativeContract.IsActive(new active() { ActiveIn = Hardfork.HF_Cockatrice, DeprecatedIn = null }, settings.IsHardforkEnabled, 20)); + + Assert.IsTrue(NativeContract.IsActive(new active() { ActiveIn = null, DeprecatedIn = Hardfork.HF_Cockatrice }, settings.IsHardforkEnabled, 1)); + Assert.IsFalse(NativeContract.IsActive(new active() { ActiveIn = null, DeprecatedIn = Hardfork.HF_Cockatrice }, settings.IsHardforkEnabled, 20)); + } + [TestMethod] public void TestGetContract() { From 2c2082084e705d148221281d5dbc65ef72f426e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=BF=97=E5=90=8C?= Date: Fri, 5 Jul 2024 03:26:30 +0000 Subject: [PATCH 32/71] Fix crash when comparing ContractPermissionDescriptor (#3396) * Update ContractPermissionDescriptor.cs * Add UT --------- Co-authored-by: Fernando Diaz Toledano Co-authored-by: Christopher Schuchardt Co-authored-by: NGD Admin <154295625+NGDAdmin@users.noreply.github.com> --- .../Manifest/ContractPermissionDescriptor.cs | 3 ++- .../Manifest/UT_ContractPermissionDescriptor.cs | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/Neo/SmartContract/Manifest/ContractPermissionDescriptor.cs b/src/Neo/SmartContract/Manifest/ContractPermissionDescriptor.cs index f1f22d99d8..d950d25c62 100644 --- a/src/Neo/SmartContract/Manifest/ContractPermissionDescriptor.cs +++ b/src/Neo/SmartContract/Manifest/ContractPermissionDescriptor.cs @@ -114,7 +114,8 @@ public bool Equals(ContractPermissionDescriptor other) if (this == other) return true; if (IsWildcard == other.IsWildcard) return true; if (IsHash) return Hash.Equals(other.Hash); - else return Group.Equals(other.Group); + if (IsGroup) return Group.Equals(other.Group); + return false; } public override int GetHashCode() diff --git a/tests/Neo.UnitTests/SmartContract/Manifest/UT_ContractPermissionDescriptor.cs b/tests/Neo.UnitTests/SmartContract/Manifest/UT_ContractPermissionDescriptor.cs index 0dee8b0f67..1ef2397d69 100644 --- a/tests/Neo.UnitTests/SmartContract/Manifest/UT_ContractPermissionDescriptor.cs +++ b/tests/Neo.UnitTests/SmartContract/Manifest/UT_ContractPermissionDescriptor.cs @@ -11,6 +11,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.SmartContract.Manifest; +using Neo.SmartContract.Native; using Neo.Wallets; using System.Security.Cryptography; @@ -44,5 +45,18 @@ public void TestFromAndToJson() Assert.AreEqual(null, result.Hash); Assert.AreEqual(result.Group, result.Group); } + + [TestMethod] + public void TestEquals() + { + var descriptor1 = ContractPermissionDescriptor.CreateWildcard(); + var descriptor2 = ContractPermissionDescriptor.Create(LedgerContract.NEO.Hash); + + Assert.AreNotEqual(descriptor1, descriptor2); + + var descriptor3 = ContractPermissionDescriptor.Create(LedgerContract.NEO.Hash); + + Assert.AreEqual(descriptor2, descriptor3); + } } } From c537f87959fbe355f5b05bed4cf113d81563f039 Mon Sep 17 00:00:00 2001 From: Christopher Schuchardt Date: Thu, 4 Jul 2024 23:48:49 -0400 Subject: [PATCH 33/71] `[neo-cli]` Error Message and Warning - LevelDb (#3380) * Fixed warnings and error message for `libleveldb` missing * Update src/Neo.CLI/CLI/MainService.cs Co-authored-by: lingyido --------- Co-authored-by: Shargon Co-authored-by: lingyido Co-authored-by: NGD Admin <154295625+NGDAdmin@users.noreply.github.com> --- src/Neo.CLI/CLI/MainService.cs | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/Neo.CLI/CLI/MainService.cs b/src/Neo.CLI/CLI/MainService.cs index 19ea5d9334..de667bc63d 100644 --- a/src/Neo.CLI/CLI/MainService.cs +++ b/src/Neo.CLI/CLI/MainService.cs @@ -33,7 +33,6 @@ using System.Net; using System.Numerics; using System.Reflection; -using System.Runtime.InteropServices; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; @@ -383,7 +382,7 @@ public async void Start(CommandLineOptions options) } catch (DllNotFoundException ex) when (ex.Message.Contains("libleveldb")) { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + if (OperatingSystem.IsWindows()) { if (File.Exists("libleveldb.dll")) { @@ -392,25 +391,32 @@ public async void Start(CommandLineOptions options) } else { - DisplayError("DLL not found, please get libleveldb.dll."); + DisplayError("DLL not found, please get libleveldb.dll.", + "Download from https://github.com/neo-ngd/leveldb/releases"); } } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + else if (OperatingSystem.IsLinux()) + { + DisplayError("Shared library libleveldb.so not found, please get libleveldb.so.", + "Use command \"sudo apt-get install libleveldb-dev\" in terminal or download from https://github.com/neo-ngd/leveldb/releases"); + } + else if (OperatingSystem.IsMacOS() || OperatingSystem.IsMacCatalyst()) { DisplayError("Shared library libleveldb.dylib not found, please get libleveldb.dylib.", - "From https://github.com/neo-project/neo/releases"); + "Use command \"brew install leveldb\" in terminal or download from https://github.com/neo-ngd/leveldb/releases"); } else { DisplayError("Neo CLI is broken, please reinstall it.", - "From https://github.com/neo-project/neo/releases"); + "Download from https://github.com/neo-project/neo/releases"); } - + return; } catch (DllNotFoundException) { DisplayError("Neo CLI is broken, please reinstall it.", - "From https://github.com/neo-project/neo/releases"); + "Download from https://github.com/neo-project/neo/releases"); + return; } NeoSystem.AddService(this); From 8e1e6619130088f8a184df48c5bf766a7e92ab9a Mon Sep 17 00:00:00 2001 From: Christopher Schuchardt Date: Fri, 5 Jul 2024 02:28:44 -0400 Subject: [PATCH 34/71] Fixed Props Pathing for `dotnet pack` with `nuget` (#3379) Co-authored-by: NGD Admin <154295625+NGDAdmin@users.noreply.github.com> --- src/Plugins/Directory.Build.props | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/Plugins/Directory.Build.props b/src/Plugins/Directory.Build.props index 72e96f0300..ecd9a2735f 100644 --- a/src/Plugins/Directory.Build.props +++ b/src/Plugins/Directory.Build.props @@ -3,11 +3,6 @@ - - - - - From 15d36b7672b003bf678009977a5e2d26cf110a64 Mon Sep 17 00:00:00 2001 From: Christopher Schuchardt Date: Fri, 5 Jul 2024 03:04:50 -0400 Subject: [PATCH 35/71] Part-1 `Neo.IO` - move (#3387) Co-authored-by: Shargon Co-authored-by: NGD Admin <154295625+NGDAdmin@users.noreply.github.com> --- src/{Neo/IO => Neo.IO}/Caching/Cache.cs | 56 ++++++++----------- src/{Neo/IO => Neo.IO}/Caching/FIFOCache.cs | 9 +-- .../IO => Neo.IO}/Caching/HashSetCache.cs | 36 ++++++------ .../IO => Neo.IO}/Caching/IndexedQueue.cs | 16 +++--- .../Caching/KeyedCollectionSlim.cs | 23 ++++---- src/Neo/Cryptography/Crypto.cs | 2 +- src/Neo/IO/Caching/ECDsaCache.cs | 5 +- .../Network/P2P/RemoteNode.ProtocolHandler.cs | 6 +- 8 files changed, 72 insertions(+), 81 deletions(-) rename src/{Neo/IO => Neo.IO}/Caching/Cache.cs (80%) rename src/{Neo/IO => Neo.IO}/Caching/FIFOCache.cs (72%) rename src/{Neo/IO => Neo.IO}/Caching/HashSetCache.cs (76%) rename src/{Neo/IO => Neo.IO}/Caching/IndexedQueue.cs (95%) rename src/{Neo/IO => Neo.IO}/Caching/KeyedCollectionSlim.cs (61%) diff --git a/src/Neo/IO/Caching/Cache.cs b/src/Neo.IO/Caching/Cache.cs similarity index 80% rename from src/Neo/IO/Caching/Cache.cs rename to src/Neo.IO/Caching/Cache.cs index 7895a8ca2d..1a66e6dca5 100644 --- a/src/Neo/IO/Caching/Cache.cs +++ b/src/Neo.IO/Caching/Cache.cs @@ -17,25 +17,21 @@ namespace Neo.IO.Caching { - internal abstract class Cache : ICollection, IDisposable + internal abstract class Cache + (int max_capacity, IEqualityComparer? comparer = null) : ICollection, IDisposable + where TKey : notnull { protected class CacheItem + (TKey key, TValue value) { - public readonly TKey Key; - public readonly TValue Value; - public readonly DateTime Time; - - public CacheItem(TKey key, TValue value) - { - Key = key; - Value = value; - Time = TimeProvider.Current.UtcNow; - } + public readonly TKey Key = key; + public readonly TValue Value = value; + public readonly DateTime Time = DateTime.UtcNow; } protected readonly ReaderWriterLockSlim RwSyncRootLock = new(LockRecursionPolicy.SupportsRecursion); - protected readonly Dictionary InnerDictionary; - private readonly int max_capacity; + protected readonly Dictionary InnerDictionary = new Dictionary(comparer); + private readonly int _max_capacity = max_capacity; public TValue this[TKey key] { @@ -44,7 +40,7 @@ public TValue this[TKey key] RwSyncRootLock.EnterReadLock(); try { - if (!InnerDictionary.TryGetValue(key, out CacheItem item)) throw new KeyNotFoundException(); + if (!InnerDictionary.TryGetValue(key, out CacheItem? item)) throw new KeyNotFoundException(); OnAccess(item); return item.Value; } @@ -73,15 +69,9 @@ public int Count public bool IsReadOnly => false; - public Cache(int max_capacity, IEqualityComparer comparer = null) - { - this.max_capacity = max_capacity; - InnerDictionary = new Dictionary(comparer); - } - public void Add(TValue item) { - TKey key = GetKeyForItem(item); + var key = GetKeyForItem(item); RwSyncRootLock.EnterWriteLock(); try { @@ -95,16 +85,16 @@ public void Add(TValue item) private void AddInternal(TKey key, TValue item) { - if (InnerDictionary.TryGetValue(key, out CacheItem cacheItem)) + if (InnerDictionary.TryGetValue(key, out CacheItem? cacheItem)) { OnAccess(cacheItem); } else { - if (InnerDictionary.Count >= max_capacity) + if (InnerDictionary.Count >= _max_capacity) { //TODO: Perform a performance test on the PLINQ query to determine which algorithm is better here (parallel or not) - foreach (CacheItem item_del in InnerDictionary.Values.AsParallel().OrderBy(p => p.Time).Take(InnerDictionary.Count - max_capacity + 1)) + foreach (var item_del in InnerDictionary.Values.AsParallel().OrderBy(p => p.Time).Take(InnerDictionary.Count - _max_capacity + 1)) { RemoveInternal(item_del); } @@ -118,9 +108,9 @@ public void AddRange(IEnumerable items) RwSyncRootLock.EnterWriteLock(); try { - foreach (TValue item in items) + foreach (var item in items) { - TKey key = GetKeyForItem(item); + var key = GetKeyForItem(item); AddInternal(key, item); } } @@ -135,7 +125,7 @@ public void Clear() RwSyncRootLock.EnterWriteLock(); try { - foreach (CacheItem item_del in InnerDictionary.Values.ToArray()) + foreach (var item_del in InnerDictionary.Values.ToArray()) { RemoveInternal(item_del); } @@ -151,7 +141,7 @@ public bool Contains(TKey key) RwSyncRootLock.EnterReadLock(); try { - if (!InnerDictionary.TryGetValue(key, out CacheItem cacheItem)) return false; + if (!InnerDictionary.TryGetValue(key, out CacheItem? cacheItem)) return false; OnAccess(cacheItem); return true; } @@ -171,7 +161,7 @@ public void CopyTo(TValue[] array, int arrayIndex) if (array == null) throw new ArgumentNullException(); if (arrayIndex < 0) throw new ArgumentOutOfRangeException(); if (arrayIndex + InnerDictionary.Count > array.Length) throw new ArgumentException(); - foreach (TValue item in this) + foreach (var item in this) { array[arrayIndex++] = item; } @@ -188,7 +178,7 @@ public IEnumerator GetEnumerator() RwSyncRootLock.EnterReadLock(); try { - foreach (TValue item in InnerDictionary.Values.Select(p => p.Value)) + foreach (var item in InnerDictionary.Values.Select(p => p.Value)) { yield return item; } @@ -211,7 +201,7 @@ public bool Remove(TKey key) RwSyncRootLock.EnterWriteLock(); try { - if (!InnerDictionary.TryGetValue(key, out CacheItem cacheItem)) return false; + if (!InnerDictionary.TryGetValue(key, out CacheItem? cacheItem)) return false; RemoveInternal(cacheItem); return true; } @@ -242,7 +232,7 @@ public bool TryGet(TKey key, out TValue item) RwSyncRootLock.EnterReadLock(); try { - if (InnerDictionary.TryGetValue(key, out CacheItem cacheItem)) + if (InnerDictionary.TryGetValue(key, out CacheItem? cacheItem)) { OnAccess(cacheItem); item = cacheItem.Value; @@ -253,7 +243,7 @@ public bool TryGet(TKey key, out TValue item) { RwSyncRootLock.ExitReadLock(); } - item = default; + item = default!; return false; } } diff --git a/src/Neo/IO/Caching/FIFOCache.cs b/src/Neo.IO/Caching/FIFOCache.cs similarity index 72% rename from src/Neo/IO/Caching/FIFOCache.cs rename to src/Neo.IO/Caching/FIFOCache.cs index af3e5e469d..b7e9f39e98 100644 --- a/src/Neo/IO/Caching/FIFOCache.cs +++ b/src/Neo.IO/Caching/FIFOCache.cs @@ -13,13 +13,10 @@ namespace Neo.IO.Caching { - internal abstract class FIFOCache : Cache + internal abstract class FIFOCache + (int max_capacity, IEqualityComparer? comparer = null) : Cache(max_capacity, comparer) + where TKey : notnull { - public FIFOCache(int max_capacity, IEqualityComparer comparer = null) - : base(max_capacity, comparer) - { - } - protected override void OnAccess(CacheItem item) { } diff --git a/src/Neo/IO/Caching/HashSetCache.cs b/src/Neo.IO/Caching/HashSetCache.cs similarity index 76% rename from src/Neo/IO/Caching/HashSetCache.cs rename to src/Neo.IO/Caching/HashSetCache.cs index bdef1c5e3a..577893e924 100644 --- a/src/Neo/IO/Caching/HashSetCache.cs +++ b/src/Neo.IO/Caching/HashSetCache.cs @@ -20,17 +20,17 @@ class HashSetCache : IReadOnlyCollection where T : IEquatable /// /// Sets where the Hashes are stored /// - private readonly LinkedList> sets = new(); + private readonly LinkedList> _sets = new(); /// - /// Maximum capacity of each bucket inside each HashSet of . + /// Maximum capacity of each bucket inside each HashSet of . /// - private readonly int bucketCapacity; + private readonly int _bucketCapacity; /// /// Maximum number of buckets for the LinkedList, meaning its maximum cardinality. /// - private readonly int maxBucketCount; + private readonly int _maxBucketCount; /// /// Entry count @@ -43,32 +43,32 @@ public HashSetCache(int bucketCapacity, int maxBucketCount = 10) if (maxBucketCount <= 0) throw new ArgumentOutOfRangeException($"{nameof(maxBucketCount)} should be greater than 0"); Count = 0; - this.bucketCapacity = bucketCapacity; - this.maxBucketCount = maxBucketCount; - sets.AddFirst(new HashSet()); + _bucketCapacity = bucketCapacity; + _maxBucketCount = maxBucketCount; + _sets.AddFirst([]); } public bool Add(T item) { if (Contains(item)) return false; Count++; - if (sets.First.Value.Count < bucketCapacity) return sets.First.Value.Add(item); + if (_sets.First?.Value.Count < _bucketCapacity) return _sets.First.Value.Add(item); var newSet = new HashSet { item }; - sets.AddFirst(newSet); - if (sets.Count > maxBucketCount) + _sets.AddFirst(newSet); + if (_sets.Count > _maxBucketCount) { - Count -= sets.Last.Value.Count; - sets.RemoveLast(); + Count -= _sets.Last?.Value.Count ?? 0; + _sets.RemoveLast(); } return true; } public bool Contains(T item) { - foreach (var set in sets) + foreach (var set in _sets) { if (set.Contains(item)) return true; } @@ -77,17 +77,17 @@ public bool Contains(T item) public void ExceptWith(IEnumerable items) { - List> removeList = null; + List> removeList = default!; foreach (var item in items) { - foreach (var set in sets) + foreach (var set in _sets) { if (set.Remove(item)) { Count--; if (set.Count == 0) { - removeList ??= new List>(); + removeList ??= []; removeList.Add(set); } break; @@ -97,13 +97,13 @@ public void ExceptWith(IEnumerable items) if (removeList == null) return; foreach (var set in removeList) { - sets.Remove(set); + _sets.Remove(set); } } public IEnumerator GetEnumerator() { - foreach (var set in sets) + foreach (var set in _sets) { foreach (var item in set) { diff --git a/src/Neo/IO/Caching/IndexedQueue.cs b/src/Neo.IO/Caching/IndexedQueue.cs similarity index 95% rename from src/Neo/IO/Caching/IndexedQueue.cs rename to src/Neo.IO/Caching/IndexedQueue.cs index 54440a871b..29b39a4947 100644 --- a/src/Neo/IO/Caching/IndexedQueue.cs +++ b/src/Neo.IO/Caching/IndexedQueue.cs @@ -89,14 +89,14 @@ public void Enqueue(T item) { if (_array.Length == _count) { - int newSize = _array.Length * GrowthFactor; + var newSize = _array.Length * GrowthFactor; if (_head == 0) { Array.Resize(ref _array, newSize); } else { - T[] buffer = new T[newSize]; + var buffer = new T[newSize]; Array.Copy(_array, _head, buffer, 0, _array.Length - _head); Array.Copy(_array, 0, buffer, _array.Length - _head, _head); _array = buffer; @@ -127,7 +127,7 @@ public bool TryPeek(out T item) { if (_count == 0) { - item = default; + item = default!; return false; } else @@ -145,7 +145,7 @@ public T Dequeue() { if (_count == 0) throw new InvalidOperationException("The queue is empty"); - T result = _array[_head]; + var result = _array[_head]; ++_head; _head %= _array.Length; --_count; @@ -161,7 +161,7 @@ public bool TryDequeue(out T item) { if (_count == 0) { - item = default; + item = default!; return false; } else @@ -194,7 +194,7 @@ public void TrimExcess() } else if (_array.Length * TrimThreshold >= _count) { - T[] arr = new T[_count]; + var arr = new T[_count]; CopyTo(arr, 0); _array = arr; _head = 0; @@ -228,14 +228,14 @@ public void CopyTo(T[] array, int arrayIndex) /// An array containing the queue's items public T[] ToArray() { - T[] result = new T[_count]; + var result = new T[_count]; CopyTo(result, 0); return result; } public IEnumerator GetEnumerator() { - for (int i = 0; i < _count; i++) + for (var i = 0; i < _count; i++) yield return _array[(_head + i) % _array.Length]; } diff --git a/src/Neo/IO/Caching/KeyedCollectionSlim.cs b/src/Neo.IO/Caching/KeyedCollectionSlim.cs similarity index 61% rename from src/Neo/IO/Caching/KeyedCollectionSlim.cs rename to src/Neo.IO/Caching/KeyedCollectionSlim.cs index a24dd87e4c..f632dc0927 100644 --- a/src/Neo/IO/Caching/KeyedCollectionSlim.cs +++ b/src/Neo.IO/Caching/KeyedCollectionSlim.cs @@ -10,43 +10,46 @@ // modifications are permitted. using System; +using System.Collections; using System.Collections.Generic; namespace Neo.IO.Caching; -abstract class KeyedCollectionSlim where TKey : notnull +abstract class KeyedCollectionSlim + where TKey : notnull + where TItem : class, IStructuralEquatable, IStructuralComparable, IComparable { private readonly LinkedList _items = new(); - private readonly Dictionary> dict = new(); + private readonly Dictionary> _dict = []; - public int Count => dict.Count; - public TItem First => _items.First.Value; + public int Count => _dict.Count; + public TItem? First => _items.First?.Value; - protected abstract TKey GetKeyForItem(TItem item); + protected abstract TKey GetKeyForItem(TItem? item); public void Add(TItem item) { var key = GetKeyForItem(item); var node = _items.AddLast(item); - if (!dict.TryAdd(key, node)) + if (!_dict.TryAdd(key, node)) { _items.RemoveLast(); throw new ArgumentException("An element with the same key already exists in the collection."); } } - public bool Contains(TKey key) => dict.ContainsKey(key); + public bool Contains(TKey key) => _dict.ContainsKey(key); public void Remove(TKey key) { - if (dict.Remove(key, out var node)) + if (_dict.Remove(key, out var node)) _items.Remove(node); } public void RemoveFirst() { - var key = GetKeyForItem(_items.First.Value); - dict.Remove(key); + var key = GetKeyForItem(_items.First?.Value); + _dict.Remove(key); _items.RemoveFirst(); } } diff --git a/src/Neo/Cryptography/Crypto.cs b/src/Neo/Cryptography/Crypto.cs index 85ed0411a8..a2e89dc787 100644 --- a/src/Neo/Cryptography/Crypto.cs +++ b/src/Neo/Cryptography/Crypto.cs @@ -170,7 +170,7 @@ public static ECDsa CreateECDsa(ECC.ECPoint pubkey) { if (CacheECDsa.TryGet(pubkey, out var cache)) { - return cache.value; + return cache.Value; } var curve = pubkey.Curve == ECC.ECCurve.Secp256r1 ? ECCurve.NamedCurves.nistP256 : diff --git a/src/Neo/IO/Caching/ECDsaCache.cs b/src/Neo/IO/Caching/ECDsaCache.cs index b25f29da8e..b41a058b61 100644 --- a/src/Neo/IO/Caching/ECDsaCache.cs +++ b/src/Neo/IO/Caching/ECDsaCache.cs @@ -14,7 +14,8 @@ namespace Neo.IO.Caching { - record ECDsaCacheItem(Cryptography.ECC.ECPoint key, ECDsa value); + record ECDsaCacheItem(Cryptography.ECC.ECPoint Key, ECDsa Value); + internal class ECDsaCache : FIFOCache { public ECDsaCache(int max_capacity = 20000) : base(max_capacity, EqualityComparer.Default) @@ -23,7 +24,7 @@ public ECDsaCache(int max_capacity = 20000) : base(max_capacity, EqualityCompare protected override Cryptography.ECC.ECPoint GetKeyForItem(ECDsaCacheItem item) { - return item.key; + return item.Key; } } } diff --git a/src/Neo/Network/P2P/RemoteNode.ProtocolHandler.cs b/src/Neo/Network/P2P/RemoteNode.ProtocolHandler.cs index 4606723cd0..4e7861a562 100644 --- a/src/Neo/Network/P2P/RemoteNode.ProtocolHandler.cs +++ b/src/Neo/Network/P2P/RemoteNode.ProtocolHandler.cs @@ -30,9 +30,9 @@ namespace Neo.Network.P2P partial class RemoteNode { private class Timer { } - private class PendingKnownHashesCollection : KeyedCollectionSlim + private class PendingKnownHashesCollection : KeyedCollectionSlim> { - protected override UInt256 GetKeyForItem((UInt256, DateTime) item) + protected override UInt256 GetKeyForItem(Tuple item) { return item.Item1; } @@ -354,7 +354,7 @@ private void OnInvMessageReceived(InvPayload payload) } if (hashes.Length == 0) return; foreach (UInt256 hash in hashes) - pendingKnownHashes.Add((hash, TimeProvider.Current.UtcNow)); + pendingKnownHashes.Add(Tuple.Create(hash, TimeProvider.Current.UtcNow)); system.TaskManager.Tell(new TaskManager.NewTasks { Payload = InvPayload.Create(payload.Type, hashes) }); } From 94f1a72fd016a73fd95dd3c5aef4fa4070d9caae Mon Sep 17 00:00:00 2001 From: Christopher Schuchardt Date: Fri, 5 Jul 2024 03:42:43 -0400 Subject: [PATCH 36/71] `[Fix]` Test Problems (#3398) * Fix Test crashes * disable Build servers * Fixed Building problem with tests * Fixed command line * Removed disable build servers --------- Co-authored-by: Shargon --- .github/workflows/main.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 458ff0e80a..c5f315dd27 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -68,7 +68,8 @@ jobs: if: matrix.os != 'ubuntu-latest' run: | dotnet sln neo.sln remove ./tests/Neo.Plugins.Storage.Tests/Neo.Plugins.Storage.Tests.csproj - dotnet test --blame-hang --blame-crash + dotnet build + dotnet test --blame-hang --blame-crash --no-build - name: Test for coverall if: matrix.os == 'ubuntu-latest' From e5abfa17641065e99293ac512141a053ec97c32f Mon Sep 17 00:00:00 2001 From: Christopher Schuchardt Date: Sun, 7 Jul 2024 08:26:55 -0400 Subject: [PATCH 37/71] `[Typo]` Unit Tests - UT_ProtocolSettings.CreateHKSettings (#3383) * Typeo with `CreateHKSettings` * fix ut --------- Co-authored-by: Shargon Co-authored-by: NGD Admin <154295625+NGDAdmin@users.noreply.github.com> --- .../SmartContract/Native/UT_NativeContract.cs | 4 ++-- tests/Neo.UnitTests/UT_ProtocolSettings.cs | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/Neo.UnitTests/SmartContract/Native/UT_NativeContract.cs b/tests/Neo.UnitTests/SmartContract/Native/UT_NativeContract.cs index 61e6e67f48..1cce9ef32a 100644 --- a/tests/Neo.UnitTests/SmartContract/Native/UT_NativeContract.cs +++ b/tests/Neo.UnitTests/SmartContract/Native/UT_NativeContract.cs @@ -67,7 +67,7 @@ class active : IHardforkActivable [TestMethod] public void TestActiveDeprecatedIn() { - string json = UT_ProtocolSettings.CreateHKSettings("\"HF_Cockatrice\": 20"); + string json = UT_ProtocolSettings.CreateHFSettings("\"HF_Cockatrice\": 20"); var file = Path.GetTempFileName(); File.WriteAllText(file, json); ProtocolSettings settings = ProtocolSettings.Load(file, false); @@ -89,7 +89,7 @@ public void TestGetContract() [TestMethod] public void TestIsInitializeBlock() { - string json = UT_ProtocolSettings.CreateHKSettings("\"HF_Cockatrice\": 20"); + string json = UT_ProtocolSettings.CreateHFSettings("\"HF_Cockatrice\": 20"); var file = Path.GetTempFileName(); File.WriteAllText(file, json); diff --git a/tests/Neo.UnitTests/UT_ProtocolSettings.cs b/tests/Neo.UnitTests/UT_ProtocolSettings.cs index e5d829ef8b..97a36e5907 100644 --- a/tests/Neo.UnitTests/UT_ProtocolSettings.cs +++ b/tests/Neo.UnitTests/UT_ProtocolSettings.cs @@ -52,7 +52,7 @@ public void TestGetMillisecondsPerBlock() [TestMethod] public void HardForkTestBAndNotA() { - string json = CreateHKSettings("\"HF_Basilisk\": 4120000"); + string json = CreateHFSettings("\"HF_Basilisk\": 4120000"); var file = Path.GetTempFileName(); File.WriteAllText(file, json); @@ -74,7 +74,7 @@ public void HardForkTestBAndNotA() [TestMethod] public void HardForkTestAAndNotB() { - string json = CreateHKSettings("\"HF_Aspidochelone\": 0"); + string json = CreateHFSettings("\"HF_Aspidochelone\": 0"); var file = Path.GetTempFileName(); File.WriteAllText(file, json); @@ -96,7 +96,7 @@ public void HardForkTestAAndNotB() [TestMethod] public void HardForkTestNone() { - string json = CreateHKSettings(""); + string json = CreateHFSettings(""); var file = Path.GetTempFileName(); File.WriteAllText(file, json); @@ -117,14 +117,14 @@ public void HardForkTestNone() [TestMethod] public void HardForkTestAMoreThanB() { - string json = CreateHKSettings("\"HF_Aspidochelone\": 4120001, \"HF_Basilisk\": 4120000"); + string json = CreateHFSettings("\"HF_Aspidochelone\": 4120001, \"HF_Basilisk\": 4120000"); var file = Path.GetTempFileName(); File.WriteAllText(file, json); Assert.ThrowsException(() => ProtocolSettings.Load(file, false)); File.Delete(file); } - internal static string CreateHKSettings(string hf) + internal static string CreateHFSettings(string hf) { return @" { From c54c2043d8f78c5877bbcb53331b147a3f28440f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 10 Jul 2024 02:44:45 -0700 Subject: [PATCH 38/71] Bump System.Text.Json from 8.0.3 to 8.0.4 in /src/Neo.Json (#3416) Bumps System.Text.Json from 8.0.3 to 8.0.4. --- updated-dependencies: - dependency-name: System.Text.Json dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/Neo.Json/Neo.Json.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Neo.Json/Neo.Json.csproj b/src/Neo.Json/Neo.Json.csproj index 15924436e7..8d8fd33ac9 100644 --- a/src/Neo.Json/Neo.Json.csproj +++ b/src/Neo.Json/Neo.Json.csproj @@ -10,7 +10,7 @@ - + From 1c458325447152e7a86f1a4ae71a256b0887cb11 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Thu, 11 Jul 2024 10:47:51 +0800 Subject: [PATCH 39/71] [Neo Plugin Store] Unit test (#3399) * test * fix snapshot issue and add tests * fix test * apply old snapshot * remove duplicate * Remove method --------- Co-authored-by: Christopher Schuchardt Co-authored-by: NGD Admin <154295625+NGDAdmin@users.noreply.github.com> Co-authored-by: Shargon --- tests/Neo.Plugins.Storage.Tests/StoreTest.cs | 141 +++++++++++++++++-- 1 file changed, 127 insertions(+), 14 deletions(-) diff --git a/tests/Neo.Plugins.Storage.Tests/StoreTest.cs b/tests/Neo.Plugins.Storage.Tests/StoreTest.cs index 2773f92e80..189e212bc2 100644 --- a/tests/Neo.Plugins.Storage.Tests/StoreTest.cs +++ b/tests/Neo.Plugins.Storage.Tests/StoreTest.cs @@ -21,9 +21,19 @@ public class StoreTest { private const string path_leveldb = "Data_LevelDB_UT"; private const string path_rocksdb = "Data_RocksDB_UT"; + private static LevelDBStore levelDbStore; + private static RocksDBStore rocksDBStore; [TestInitialize] public void OnStart() + { + levelDbStore ??= new LevelDBStore(); + rocksDBStore ??= new RocksDBStore(); + OnEnd(); + } + + [TestCleanup] + public void OnEnd() { if (Directory.Exists(path_leveldb)) Directory.Delete(path_leveldb, true); if (Directory.Exists(path_rocksdb)) Directory.Delete(path_rocksdb, true); @@ -49,35 +59,138 @@ public void TestMemory() [TestMethod] public void TestLevelDb() { - using var plugin = new LevelDBStore(); - TestPersistenceDelete(plugin.GetStore(path_leveldb)); + TestPersistenceDelete(levelDbStore.GetStore(path_leveldb)); // Test all with the same store - TestStorage(plugin.GetStore(path_leveldb)); + TestStorage(levelDbStore.GetStore(path_leveldb)); // Test with different storages - TestPersistenceWrite(plugin.GetStore(path_leveldb)); - TestPersistenceRead(plugin.GetStore(path_leveldb), true); - TestPersistenceDelete(plugin.GetStore(path_leveldb)); - TestPersistenceRead(plugin.GetStore(path_leveldb), false); + TestPersistenceWrite(levelDbStore.GetStore(path_leveldb)); + TestPersistenceRead(levelDbStore.GetStore(path_leveldb), true); + TestPersistenceDelete(levelDbStore.GetStore(path_leveldb)); + TestPersistenceRead(levelDbStore.GetStore(path_leveldb), false); + } + + [TestMethod] + public void TestLevelDbSnapshot() + { + using var store = levelDbStore.GetStore(path_leveldb); + + var snapshot = store.GetSnapshot(); + + var testKey = new byte[] { 0x01, 0x02, 0x03 }; + var testValue = new byte[] { 0x04, 0x05, 0x06 }; + + snapshot.Put(testKey, testValue); + // Data saved to the leveldb snapshot shall not be visible to the store + Assert.IsNull(snapshot.TryGet(testKey)); + + // Value is in the write batch, not visible to the store and snapshot + Assert.AreEqual(false, snapshot.Contains(testKey)); + Assert.AreEqual(false, store.Contains(testKey)); + + snapshot.Commit(); + + // After commit, the data shall be visible to the store but not to the snapshot + Assert.IsNull(snapshot.TryGet(testKey)); + CollectionAssert.AreEqual(testValue, store.TryGet(testKey)); + Assert.AreEqual(false, snapshot.Contains(testKey)); + Assert.AreEqual(true, store.Contains(testKey)); + + snapshot.Dispose(); + } + + [TestMethod] + public void TestLevelDbMultiSnapshot() + { + using var store = levelDbStore.GetStore(path_leveldb); + + var snapshot = store.GetSnapshot(); + + var testKey = new byte[] { 0x01, 0x02, 0x03 }; + var testValue = new byte[] { 0x04, 0x05, 0x06 }; + + snapshot.Put(testKey, testValue); + snapshot.Commit(); + CollectionAssert.AreEqual(testValue, store.TryGet(testKey)); + + var snapshot2 = store.GetSnapshot(); + + // Data saved to the leveldb from snapshot1 shall be visible to snapshot2 but not visible to snapshot1 + CollectionAssert.AreEqual(testValue, snapshot2.TryGet(testKey)); + Assert.IsNull(snapshot.TryGet(testKey)); + + snapshot.Dispose(); + snapshot2.Dispose(); } [TestMethod] public void TestRocksDb() { - using var plugin = new RocksDBStore(); - TestPersistenceDelete(plugin.GetStore(path_rocksdb)); + TestPersistenceDelete(rocksDBStore.GetStore(path_rocksdb)); // Test all with the same store - TestStorage(plugin.GetStore(path_rocksdb)); + TestStorage(rocksDBStore.GetStore(path_rocksdb)); // Test with different storages - TestPersistenceWrite(plugin.GetStore(path_rocksdb)); - TestPersistenceRead(plugin.GetStore(path_rocksdb), true); - TestPersistenceDelete(plugin.GetStore(path_rocksdb)); - TestPersistenceRead(plugin.GetStore(path_rocksdb), false); + TestPersistenceWrite(rocksDBStore.GetStore(path_rocksdb)); + TestPersistenceRead(rocksDBStore.GetStore(path_rocksdb), true); + TestPersistenceDelete(rocksDBStore.GetStore(path_rocksdb)); + TestPersistenceRead(rocksDBStore.GetStore(path_rocksdb), false); + } + + [TestMethod] + public void TestRocksDbSnapshot() + { + using var store = rocksDBStore.GetStore(path_leveldb); + + var snapshot = store.GetSnapshot(); + + var testKey = new byte[] { 0x01, 0x02, 0x03 }; + var testValue = new byte[] { 0x04, 0x05, 0x06 }; + + snapshot.Put(testKey, testValue); + // Data saved to the leveldb snapshot shall not be visible + Assert.IsNull(snapshot.TryGet(testKey)); + Assert.IsNull(store.TryGet(testKey)); + + // Value is in the write batch, not visible to the store and snapshot + Assert.AreEqual(false, snapshot.Contains(testKey)); + Assert.AreEqual(false, store.Contains(testKey)); + + snapshot.Commit(); + + // After commit, the data shall be visible to the store but not to the snapshot + Assert.IsNull(snapshot.TryGet(testKey)); + CollectionAssert.AreEqual(testValue, store.TryGet(testKey)); + Assert.AreEqual(false, snapshot.Contains(testKey)); + Assert.AreEqual(true, store.Contains(testKey)); + + snapshot.Dispose(); + } + + [TestMethod] + public void TestRocksDbMultiSnapshot() + { + using var store = rocksDBStore.GetStore(path_leveldb); + + var snapshot = store.GetSnapshot(); + + var testKey = new byte[] { 0x01, 0x02, 0x03 }; + var testValue = new byte[] { 0x04, 0x05, 0x06 }; + + snapshot.Put(testKey, testValue); + snapshot.Commit(); + CollectionAssert.AreEqual(testValue, store.TryGet(testKey)); + + var snapshot2 = store.GetSnapshot(); + // Data saved to the leveldb from snapshot1 shall only be visible to snapshot2 + CollectionAssert.AreEqual(testValue, snapshot2.TryGet(testKey)); + + snapshot.Dispose(); + snapshot2.Dispose(); } /// From 97e24edb4c35362e919cf41c788c0fac49db328d Mon Sep 17 00:00:00 2001 From: Christopher Schuchardt Date: Wed, 10 Jul 2024 22:57:39 -0400 Subject: [PATCH 40/71] `[Add]` Debug Output to `Expect` (#3407) * Added Debug to Expect * Update file paths --------- Co-authored-by: Shargon Co-authored-by: NGD Admin <154295625+NGDAdmin@users.noreply.github.com> --- .github/workflows/main.yml | 10 +++++----- .../Neo.CLI/{test-neo-cli.expect => test-neo-cli.exp} | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) rename scripts/Neo.CLI/{test-neo-cli.expect => test-neo-cli.exp} (80%) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c5f315dd27..754b879b0e 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -24,7 +24,7 @@ jobs: - name: Check Format (*.cs) run: dotnet format --verify-no-changes --verbosity diagnostic - Build-Test-Neo-Cli: + Test-Everything: needs: [Format] timeout-minutes: 15 runs-on: ubuntu-latest @@ -37,16 +37,16 @@ jobs: with: dotnet-version: ${{ env.DOTNET_VERSION }} - - name: Build (Neo.CLI) - run: dotnet build ./src/Neo.CLI --output ./out/Neo.CLI + - name: Build (Everything) + run: dotnet build - name: Install dependencies run: | sudo apt-get install libleveldb-dev expect - find ./out -name 'config.json' | xargs perl -pi -e 's|LevelDBStore|MemoryStore|g' + find ./bin -name 'config.json' | xargs perl -pi -e 's|LevelDBStore|MemoryStore|g' - name: Run tests with expect - run: expect ./scripts/Neo.CLI/test-neo-cli.expect + run: expect ./scripts/Neo.CLI/test-neo-cli.exp Test: needs: [Format] diff --git a/scripts/Neo.CLI/test-neo-cli.expect b/scripts/Neo.CLI/test-neo-cli.exp similarity index 80% rename from scripts/Neo.CLI/test-neo-cli.expect rename to scripts/Neo.CLI/test-neo-cli.exp index 8319c18f8e..e7124402c3 100644 --- a/scripts/Neo.CLI/test-neo-cli.expect +++ b/scripts/Neo.CLI/test-neo-cli.exp @@ -1,12 +1,12 @@ -#!/usr/bin/expect -f +#!/usr/bin/expect -d -f # # This script uses expect to test neo-cli # set timeout 10 - +exp_internal true # Start neo-cli -spawn dotnet out/Neo.CLI/neo-cli.dll +spawn dotnet ./bin/Neo.CLI/net8.0/neo-cli.dll # Expect the main input prompt expect { @@ -18,7 +18,7 @@ expect { # # Test 'create wallet' # -send "create wallet test-wallet1.json\n" +send "create wallet ./bin/Neo.CLI/test-wallet1.json\n" expect { "password:" { send "asd\n" } @@ -42,7 +42,7 @@ expect { # # Test 'create wallet' # -send "create wallet test-wallet2.json L2ArHTuiDL4FHu4nfyhamrG8XVYB4QyRbmhj7vD6hFMB5iAMSTf6\n" +send "create wallet ./bin/Neo.CLI/test-wallet2.json L2ArHTuiDL4FHu4nfyhamrG8XVYB4QyRbmhj7vD6hFMB5iAMSTf6\n" expect { "password:" { send "abcd\n" } From bfb34409900d9269e89b93e008f3ff06db236cd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=BF=97=E5=90=8C?= Date: Thu, 11 Jul 2024 12:55:46 +0800 Subject: [PATCH 41/71] Improve code coverage (#3354) * update * remove binary file * Add UT and fixed bug * Add UT and fixed bug * Add UT * Add UT * Add UT * Update src/Neo/SmartContract/Manifest/ContractManifest.cs Co-authored-by: Christopher Schuchardt * Update src/Neo/SmartContract/Manifest/ContractManifest.cs Co-authored-by: Christopher Schuchardt * Update src/Neo/SmartContract/Manifest/ContractManifest.cs Co-authored-by: Christopher Schuchardt * Update Base58.cs * Update UT_Cryptography_Helper.cs * Update Base58.cs * update * Update ContractManifest.cs * Revert change that affect a syscall * Revert try * Remove using * Update src/Neo/SmartContract/Manifest/ContractManifest.cs Co-authored-by: Christopher Schuchardt * Update src/Neo/SmartContract/Manifest/ContractAbi.cs Co-authored-by: Christopher Schuchardt * Update src/Neo/SmartContract/Manifest/ContractManifest.cs Co-authored-by: Christopher Schuchardt --------- Co-authored-by: Christopher Schuchardt Co-authored-by: Jimmy Co-authored-by: Fernando Diaz Toledano Co-authored-by: NGD Admin <154295625+NGDAdmin@users.noreply.github.com> --- src/Neo/SmartContract/Manifest/ContractAbi.cs | 4 +- .../Manifest/ContractManifest.cs | 11 +- tests/Neo.Json.UnitTests/UT_JArray.cs | 13 ++ tests/Neo.Json.UnitTests/UT_JBoolean.cs | 2 + tests/Neo.Json.UnitTests/UT_JNumber.cs | 23 ++++ tests/Neo.Json.UnitTests/UT_JString.cs | 16 ++- .../Cryptography/UT_BloomFilter.cs | 2 + .../Cryptography/UT_Cryptography_Helper.cs | 24 ++++ tests/Neo.UnitTests/Neo.UnitTests.csproj | 3 + .../Network/P2P/Payloads/UT_Block.cs | 21 +++ .../TestFile/SampleContractCall.manifest.json | 1 + .../TestFile/SampleEvent.manifest.json | 1 + .../TestFile/SampleException.manifest.json | 1 + .../TestFile/SampleHelloWorld.manifest.json | 1 + .../TestFile/SampleNep17Token.manifest.json | 1 + .../TestFile/SampleOracle.manifest.json | 1 + .../UT_ContractPermissionDescriptor.cs | 19 ++- .../SmartContract/Native/UT_StdLib.cs | 4 + .../SmartContract/UT_InteropService.cs | 123 ++++++++++++++++++ 19 files changed, 261 insertions(+), 10 deletions(-) create mode 100644 tests/Neo.UnitTests/SmartContract/Manifest/TestFile/SampleContractCall.manifest.json create mode 100644 tests/Neo.UnitTests/SmartContract/Manifest/TestFile/SampleEvent.manifest.json create mode 100644 tests/Neo.UnitTests/SmartContract/Manifest/TestFile/SampleException.manifest.json create mode 100644 tests/Neo.UnitTests/SmartContract/Manifest/TestFile/SampleHelloWorld.manifest.json create mode 100644 tests/Neo.UnitTests/SmartContract/Manifest/TestFile/SampleNep17Token.manifest.json create mode 100644 tests/Neo.UnitTests/SmartContract/Manifest/TestFile/SampleOracle.manifest.json diff --git a/src/Neo/SmartContract/Manifest/ContractAbi.cs b/src/Neo/SmartContract/Manifest/ContractAbi.cs index 3660d1a99e..cedd431d62 100644 --- a/src/Neo/SmartContract/Manifest/ContractAbi.cs +++ b/src/Neo/SmartContract/Manifest/ContractAbi.cs @@ -62,8 +62,8 @@ public static ContractAbi FromJson(JObject json) { ContractAbi abi = new() { - Methods = ((JArray)json["methods"]).Select(u => ContractMethodDescriptor.FromJson((JObject)u)).ToArray(), - Events = ((JArray)json["events"]).Select(u => ContractEventDescriptor.FromJson((JObject)u)).ToArray() + Methods = ((JArray)json!["methods"])?.Select(u => ContractMethodDescriptor.FromJson((JObject)u)).ToArray() ?? [], + Events = ((JArray)json!["events"])?.Select(u => ContractEventDescriptor.FromJson((JObject)u)).ToArray() ?? [] }; if (abi.Methods.Length == 0) throw new FormatException(); return abi; diff --git a/src/Neo/SmartContract/Manifest/ContractManifest.cs b/src/Neo/SmartContract/Manifest/ContractManifest.cs index 078e8fd35e..b1bd317e41 100644 --- a/src/Neo/SmartContract/Manifest/ContractManifest.cs +++ b/src/Neo/SmartContract/Manifest/ContractManifest.cs @@ -112,20 +112,21 @@ public static ContractManifest FromJson(JObject json) { ContractManifest manifest = new() { - Name = json["name"].GetString(), - Groups = ((JArray)json["groups"]).Select(u => ContractGroup.FromJson((JObject)u)).ToArray(), - SupportedStandards = ((JArray)json["supportedstandards"]).Select(u => u.GetString()).ToArray(), + Name = json["name"]!.GetString(), + Groups = ((JArray)json["groups"])?.Select(u => ContractGroup.FromJson((JObject)u)).ToArray() ?? [], + SupportedStandards = ((JArray)json["supportedstandards"])?.Select(u => u.GetString()).ToArray() ?? [], Abi = ContractAbi.FromJson((JObject)json["abi"]), - Permissions = ((JArray)json["permissions"]).Select(u => ContractPermission.FromJson((JObject)u)).ToArray(), + Permissions = ((JArray)json["permissions"])?.Select(u => ContractPermission.FromJson((JObject)u)).ToArray() ?? [], Trusts = WildcardContainer.FromJson(json["trusts"], u => ContractPermissionDescriptor.FromJson((JString)u)), Extra = (JObject)json["extra"] }; + if (string.IsNullOrEmpty(manifest.Name)) throw new FormatException(); _ = manifest.Groups.ToDictionary(p => p.PubKey); if (json["features"] is not JObject features || features.Count != 0) throw new FormatException(); - if (manifest.SupportedStandards.Any(p => string.IsNullOrEmpty(p))) + if (manifest.SupportedStandards.Any(string.IsNullOrEmpty)) throw new FormatException(); _ = manifest.SupportedStandards.ToDictionary(p => p); _ = manifest.Permissions.ToDictionary(p => p.Contract); diff --git a/tests/Neo.Json.UnitTests/UT_JArray.cs b/tests/Neo.Json.UnitTests/UT_JArray.cs index 40388d11fc..b6c603ca2a 100644 --- a/tests/Neo.Json.UnitTests/UT_JArray.cs +++ b/tests/Neo.Json.UnitTests/UT_JArray.cs @@ -254,5 +254,18 @@ public void TestAsString() var s = jArray.AsString(); Assert.AreEqual(s, "{\"name\":\"alice\",\"age\":30,\"score\":100.001,\"gender\":\"female\",\"isMarried\":true,\"pet\":{\"name\":\"Tom\",\"type\":\"cat\"}},{\"name\":\"bob\",\"age\":100000,\"score\":0.001,\"gender\":\"male\",\"isMarried\":false,\"pet\":{\"name\":\"Paul\",\"type\":\"dog\"}}"); } + + [TestMethod] + public void TestClone() + { + var jArray = new JArray + { + alice, + bob, + }; + var a = jArray.AsString(); + var b = jArray.Clone().AsString(); + a.Should().Be(b); + } } } diff --git a/tests/Neo.Json.UnitTests/UT_JBoolean.cs b/tests/Neo.Json.UnitTests/UT_JBoolean.cs index 3ab19bd1b3..0e81e99c35 100644 --- a/tests/Neo.Json.UnitTests/UT_JBoolean.cs +++ b/tests/Neo.Json.UnitTests/UT_JBoolean.cs @@ -36,8 +36,10 @@ public void TestEqual() { Assert.IsTrue(jTrue.Equals(new JBoolean(true))); Assert.IsTrue(jTrue == new JBoolean(true)); + Assert.IsTrue(jTrue != new JBoolean(false)); Assert.IsTrue(jFalse.Equals(new JBoolean())); Assert.IsTrue(jFalse == new JBoolean()); + Assert.IsTrue(jFalse.GetBoolean().ToString().ToLowerInvariant() == jFalse.ToString()); } } } diff --git a/tests/Neo.Json.UnitTests/UT_JNumber.cs b/tests/Neo.Json.UnitTests/UT_JNumber.cs index 6eb0598fd3..df8bdca619 100644 --- a/tests/Neo.Json.UnitTests/UT_JNumber.cs +++ b/tests/Neo.Json.UnitTests/UT_JNumber.cs @@ -9,6 +9,8 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using System.Numerics; + namespace Neo.Json.UnitTests { enum Woo @@ -72,6 +74,27 @@ public void TestEqual() Assert.IsTrue(minInt.Equals(JNumber.MIN_SAFE_INTEGER)); Assert.IsTrue(minInt == JNumber.MIN_SAFE_INTEGER); Assert.IsTrue(zero == new JNumber()); + Assert.IsFalse(zero != new JNumber()); + Assert.IsTrue(zero.AsNumber() == zero.GetNumber()); + Assert.IsFalse(zero == null); + + var jnum = new JNumber(1); + jnum.Equals(new JNumber(1)).Should().BeTrue(); + jnum.Equals((uint)1).Should().BeTrue(); + jnum.Equals((int)1).Should().BeTrue(); + jnum.Equals((ulong)1).Should().BeTrue(); + jnum.Equals((long)1).Should().BeTrue(); + jnum.Equals((byte)1).Should().BeTrue(); + jnum.Equals((sbyte)1).Should().BeTrue(); + jnum.Equals((short)1).Should().BeTrue(); + jnum.Equals((ushort)1).Should().BeTrue(); + jnum.Equals((decimal)1).Should().BeTrue(); + jnum.Equals((float)1).Should().BeTrue(); + jnum.Equals((double)1).Should().BeTrue(); + jnum.Equals(null).Should().BeFalse(); + var x = jnum; + jnum.Equals(x).Should().BeTrue(); + Assert.ThrowsException(() => jnum.Equals(new BigInteger(1))); } } } diff --git a/tests/Neo.Json.UnitTests/UT_JString.cs b/tests/Neo.Json.UnitTests/UT_JString.cs index 7e2bec9834..3f0ca159ab 100644 --- a/tests/Neo.Json.UnitTests/UT_JString.cs +++ b/tests/Neo.Json.UnitTests/UT_JString.cs @@ -63,10 +63,22 @@ public void TestGetEnum() public void TestEqual() { var str = "hello world"; + var str2 = "hello world2"; var jString = new JString(str); - Assert.IsTrue(jString.Equals(str)); + var jString2 = new JString(str2); + Assert.IsTrue(jString == str); - Assert.IsTrue(jString != "hello world2"); + Assert.IsFalse(jString == null); + Assert.IsTrue(jString != str2); + Assert.IsFalse(jString == str2); + + Assert.AreEqual(str, jString.GetString()); + Assert.IsTrue(jString.Equals(str)); + Assert.IsFalse(jString.Equals(jString2)); + Assert.IsFalse(jString.Equals(null)); + Assert.IsFalse(jString.Equals(123)); + var reference = jString; + Assert.IsTrue(jString.Equals(reference)); } } } diff --git a/tests/Neo.UnitTests/Cryptography/UT_BloomFilter.cs b/tests/Neo.UnitTests/Cryptography/UT_BloomFilter.cs index 907a5df2b9..f7bc1789dd 100644 --- a/tests/Neo.UnitTests/Cryptography/UT_BloomFilter.cs +++ b/tests/Neo.UnitTests/Cryptography/UT_BloomFilter.cs @@ -39,6 +39,8 @@ public void TestBloomFIlterConstructorGetKMTweak() uint nTweak = 123456; Action action = () => new BloomFilter(m, n, nTweak); action.Should().Throw(); + action = () => new BloomFilter(m, n, nTweak, new byte[] { 0, 1, 2, 3, 4 }); + action.Should().Throw(); m = 7; n = -10; diff --git a/tests/Neo.UnitTests/Cryptography/UT_Cryptography_Helper.cs b/tests/Neo.UnitTests/Cryptography/UT_Cryptography_Helper.cs index 01022baab9..4bfde89ba2 100644 --- a/tests/Neo.UnitTests/Cryptography/UT_Cryptography_Helper.cs +++ b/tests/Neo.UnitTests/Cryptography/UT_Cryptography_Helper.cs @@ -41,6 +41,17 @@ public void TestBase58CheckDecode() input = "3vQB7B6MrGQZaxCuFg4og"; action = () => input.Base58CheckDecode(); action.Should().Throw(); + + Assert.ThrowsException(() => string.Empty.Base58CheckDecode()); + } + + [TestMethod] + public void TestMurmurReadOnlySpan() + { + ReadOnlySpan input = "Hello, world!"u8; + byte[] input2 = input.ToArray(); + input.Murmur32(0).Should().Be(input2.Murmur32(0)); + input.Murmur128(0).Should().Equal(input2.Murmur128(0)); } [TestMethod] @@ -50,6 +61,19 @@ public void TestSha256() byte[] result = value.Sha256(0, value.Length); string resultStr = result.ToHexString(); resultStr.Should().Be("b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9"); + value.Sha256().Should().Equal(result); + ((Span)value).Sha256().Should().Equal(result); + ((ReadOnlySpan)value).Sha256().Should().Equal(result); + } + + [TestMethod] + public void TestKeccak256() + { + var input = "Hello, world!"u8.ToArray(); + var result = input.Keccak256(); + result.ToHexString().Should().Be("b6e16d27ac5ab427a7f68900ac5559ce272dc6c37c82b3e052246c82244c50e4"); + ((Span)input).Keccak256().Should().Equal(result); + ((ReadOnlySpan)input).Keccak256().Should().Equal(result); } [TestMethod] diff --git a/tests/Neo.UnitTests/Neo.UnitTests.csproj b/tests/Neo.UnitTests/Neo.UnitTests.csproj index fb246cbdc3..ce6d3b41a4 100644 --- a/tests/Neo.UnitTests/Neo.UnitTests.csproj +++ b/tests/Neo.UnitTests/Neo.UnitTests.csproj @@ -12,6 +12,9 @@ + + PreserveNewest + PreserveNewest PreserveNewest diff --git a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Block.cs b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Block.cs index 2021e5a187..075c083df2 100644 --- a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Block.cs +++ b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Block.cs @@ -13,7 +13,10 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.IO; using Neo.Json; +using Neo.Ledger; using Neo.Network.P2P.Payloads; +using Neo.SmartContract; +using Neo.SmartContract.Native; namespace Neo.UnitTests.Network.P2P.Payloads { @@ -21,6 +24,15 @@ namespace Neo.UnitTests.Network.P2P.Payloads public class UT_Block { Block uut; + private static ApplicationEngine GetEngine(bool hasContainer = false, bool hasSnapshot = false, bool hasBlock = false, bool addScript = true, long gas = 20_00000000) + { + var tx = hasContainer ? TestUtils.GetTransaction(UInt160.Zero) : null; + var snapshot = hasSnapshot ? TestBlockchain.GetTestSnapshot() : null; + var block = hasBlock ? new Block { Header = new Header() } : null; + var engine = ApplicationEngine.Create(TriggerType.Application, tx, snapshot, block, TestBlockchain.TheNeoSystem.Settings, gas: gas); + if (addScript) engine.LoadScript(new byte[] { 0x01 }); + return engine; + } [TestInitialize] public void TestSetup() @@ -136,6 +148,15 @@ private void AssertStandardBlockTestVals(UInt256 val256, UInt256 merkRoot, UInt1 public void Equals_SameObj() { uut.Equals(uut).Should().BeTrue(); + var obj = uut as object; + uut.Equals(obj).Should().BeTrue(); + } + + [TestMethod] + public void TestGetHashCode() + { + var snapshot = GetEngine(true, true).Snapshot; + NativeContract.Ledger.GetBlock(snapshot, 0).GetHashCode().Should().Be(-626492395); } [TestMethod] diff --git a/tests/Neo.UnitTests/SmartContract/Manifest/TestFile/SampleContractCall.manifest.json b/tests/Neo.UnitTests/SmartContract/Manifest/TestFile/SampleContractCall.manifest.json new file mode 100644 index 0000000000..bfbee88473 --- /dev/null +++ b/tests/Neo.UnitTests/SmartContract/Manifest/TestFile/SampleContractCall.manifest.json @@ -0,0 +1 @@ +{"name":"SampleContractCall","groups":[],"features":{},"supportedstandards":[],"abi":{"methods":[{"name":"onNEP17Payment","parameters":[{"name":"from","type":"Hash160"},{"name":"amount","type":"Integer"},{"name":"data","type":"Integer"}],"returntype":"Void","offset":0,"safe":false},{"name":"_initialize","parameters":[],"returntype":"Void","offset":91,"safe":false}],"events":[]},"permissions":[],"trusts":[],"extra":{"Author":"core-dev","Version":"0.0.1","Description":"A sample contract to demonstrate how to call a contract","Sourcecode":"https://github.com/neo-project/neo-devpack-dotnet/tree/master/examples/"}} \ No newline at end of file diff --git a/tests/Neo.UnitTests/SmartContract/Manifest/TestFile/SampleEvent.manifest.json b/tests/Neo.UnitTests/SmartContract/Manifest/TestFile/SampleEvent.manifest.json new file mode 100644 index 0000000000..7e71a2f2a5 --- /dev/null +++ b/tests/Neo.UnitTests/SmartContract/Manifest/TestFile/SampleEvent.manifest.json @@ -0,0 +1 @@ +{"name":"SampleEvent","groups":[],"features":{},"supportedstandards":[],"abi":{"methods":[{"name":"main","parameters":[],"returntype":"Boolean","offset":0,"safe":false}],"events":[{"name":"new_event_name","parameters":[{"name":"arg1","type":"ByteArray"},{"name":"arg2","type":"String"},{"name":"arg3","type":"Integer"}]},{"name":"event2","parameters":[{"name":"arg1","type":"ByteArray"},{"name":"arg2","type":"Integer"}]}]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"extra":{"Author":"code-dev","Description":"A sample contract that demonstrates how to use Events","Version":"0.0.1","Sourcecode":"https://github.com/neo-project/neo-devpack-dotnet/tree/master/examples/"}} \ No newline at end of file diff --git a/tests/Neo.UnitTests/SmartContract/Manifest/TestFile/SampleException.manifest.json b/tests/Neo.UnitTests/SmartContract/Manifest/TestFile/SampleException.manifest.json new file mode 100644 index 0000000000..5d916af0f3 --- /dev/null +++ b/tests/Neo.UnitTests/SmartContract/Manifest/TestFile/SampleException.manifest.json @@ -0,0 +1 @@ +{"name":"SampleException","groups":[],"features":{},"supportedstandards":[],"abi":{"methods":[{"name":"try01","parameters":[],"returntype":"Any","offset":0,"safe":false},{"name":"try02","parameters":[],"returntype":"Any","offset":77,"safe":false},{"name":"try03","parameters":[],"returntype":"Any","offset":166,"safe":false},{"name":"tryNest","parameters":[],"returntype":"Any","offset":259,"safe":false},{"name":"tryFinally","parameters":[],"returntype":"Any","offset":404,"safe":false},{"name":"tryFinallyAndRethrow","parameters":[],"returntype":"Any","offset":474,"safe":false},{"name":"tryCatch","parameters":[],"returntype":"Any","offset":550,"safe":false},{"name":"tryWithTwoFinally","parameters":[],"returntype":"Any","offset":628,"safe":false},{"name":"tryecpointCast","parameters":[],"returntype":"Any","offset":920,"safe":false},{"name":"tryvalidByteString2Ecpoint","parameters":[],"returntype":"Any","offset":1010,"safe":false},{"name":"tryinvalidByteArray2UInt160","parameters":[],"returntype":"Any","offset":1100,"safe":false},{"name":"tryvalidByteArray2UInt160","parameters":[],"returntype":"Any","offset":1190,"safe":false},{"name":"tryinvalidByteArray2UInt256","parameters":[],"returntype":"Any","offset":1280,"safe":false},{"name":"tryvalidByteArray2UInt256","parameters":[],"returntype":"Any","offset":1370,"safe":false},{"name":"tryNULL2Ecpoint_1","parameters":[],"returntype":"Array","offset":1476,"safe":false},{"name":"tryNULL2Uint160_1","parameters":[],"returntype":"Array","offset":1652,"safe":false},{"name":"tryNULL2Uint256_1","parameters":[],"returntype":"Array","offset":1828,"safe":false},{"name":"tryNULL2Bytestring_1","parameters":[],"returntype":"Array","offset":1990,"safe":false},{"name":"tryUncatchableException","parameters":[],"returntype":"Any","offset":2141,"safe":false},{"name":"_initialize","parameters":[],"returntype":"Void","offset":2219,"safe":false}],"events":[]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"extra":{"Author":"core-dev","Description":"A sample contract to demonstrate how to handle exception","Version":"0.0.1","Sourcecode":"https://github.com/neo-project/neo-devpack-dotnet/tree/master/examples/"}} \ No newline at end of file diff --git a/tests/Neo.UnitTests/SmartContract/Manifest/TestFile/SampleHelloWorld.manifest.json b/tests/Neo.UnitTests/SmartContract/Manifest/TestFile/SampleHelloWorld.manifest.json new file mode 100644 index 0000000000..4c7c4b9605 --- /dev/null +++ b/tests/Neo.UnitTests/SmartContract/Manifest/TestFile/SampleHelloWorld.manifest.json @@ -0,0 +1 @@ +{"name":"SampleHelloWorld","groups":[],"features":{},"supportedstandards":[],"abi":{"methods":[{"name":"sayHello","parameters":[],"returntype":"String","offset":0,"safe":true}],"events":[]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"extra":{"Description":"A simple \u0060hello world\u0060 contract","E-mail":"dev@neo.org","Version":"0.0.1","Sourcecode":"https://github.com/neo-project/neo-devpack-dotnet/tree/master/examples/"}} \ No newline at end of file diff --git a/tests/Neo.UnitTests/SmartContract/Manifest/TestFile/SampleNep17Token.manifest.json b/tests/Neo.UnitTests/SmartContract/Manifest/TestFile/SampleNep17Token.manifest.json new file mode 100644 index 0000000000..bb9cf1682f --- /dev/null +++ b/tests/Neo.UnitTests/SmartContract/Manifest/TestFile/SampleNep17Token.manifest.json @@ -0,0 +1 @@ +{"name":"SampleNep17Token","groups":[],"features":{},"supportedstandards":["NEP-17"],"abi":{"methods":[{"name":"symbol","parameters":[],"returntype":"String","offset":1333,"safe":true},{"name":"decimals","parameters":[],"returntype":"Integer","offset":1348,"safe":true},{"name":"totalSupply","parameters":[],"returntype":"Integer","offset":52,"safe":true},{"name":"balanceOf","parameters":[{"name":"owner","type":"Hash160"}],"returntype":"Integer","offset":98,"safe":true},{"name":"transfer","parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"},{"name":"data","type":"Any"}],"returntype":"Boolean","offset":362,"safe":false},{"name":"getOwner","parameters":[],"returntype":"Hash160","offset":808,"safe":true},{"name":"setOwner","parameters":[{"name":"newOwner","type":"Any"}],"returntype":"Void","offset":877,"safe":false},{"name":"getMinter","parameters":[],"returntype":"Hash160","offset":980,"safe":true},{"name":"setMinter","parameters":[{"name":"newMinter","type":"Hash160"}],"returntype":"Void","offset":1025,"safe":false},{"name":"mint","parameters":[{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"}],"returntype":"Void","offset":1103,"safe":false},{"name":"burn","parameters":[{"name":"account","type":"Hash160"},{"name":"amount","type":"Integer"}],"returntype":"Void","offset":1158,"safe":false},{"name":"verify","parameters":[],"returntype":"Boolean","offset":1216,"safe":true},{"name":"update","parameters":[{"name":"nefFile","type":"ByteArray"},{"name":"manifest","type":"String"}],"returntype":"Boolean","offset":1222,"safe":false},{"name":"_initialize","parameters":[],"returntype":"Void","offset":1271,"safe":false}],"events":[{"name":"Transfer","parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"}]},{"name":"SetOwner","parameters":[{"name":"newOwner","type":"Hash160"}]},{"name":"SetMinter","parameters":[{"name":"newMinter","type":"Hash160"}]}]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"extra":{"Author":"core-dev","Version":"0.0.1","Description":"A sample NEP-17 token","Sourcecode":"https://github.com/neo-project/neo-devpack-dotnet/tree/master/examples/"}} \ No newline at end of file diff --git a/tests/Neo.UnitTests/SmartContract/Manifest/TestFile/SampleOracle.manifest.json b/tests/Neo.UnitTests/SmartContract/Manifest/TestFile/SampleOracle.manifest.json new file mode 100644 index 0000000000..8570ccb3fb --- /dev/null +++ b/tests/Neo.UnitTests/SmartContract/Manifest/TestFile/SampleOracle.manifest.json @@ -0,0 +1 @@ +{"name":"SampleOracle","groups":[],"features":{},"supportedstandards":[],"abi":{"methods":[{"name":"getResponse","parameters":[],"returntype":"String","offset":0,"safe":true},{"name":"doRequest","parameters":[],"returntype":"Void","offset":35,"safe":false},{"name":"onOracleResponse","parameters":[{"name":"requestedUrl","type":"String"},{"name":"userData","type":"Any"},{"name":"oracleResponse","type":"Integer"},{"name":"jsonString","type":"String"}],"returntype":"Void","offset":333,"safe":false}],"events":[]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"extra":{"Author":"code-dev","Description":"A sample contract to demonstrate how to use Example.SmartContract.Oracle Service","Version":"0.0.1","Sourcecode":"https://github.com/neo-project/neo-devpack-dotnet/tree/master/examples/"}} \ No newline at end of file diff --git a/tests/Neo.UnitTests/SmartContract/Manifest/UT_ContractPermissionDescriptor.cs b/tests/Neo.UnitTests/SmartContract/Manifest/UT_ContractPermissionDescriptor.cs index 1ef2397d69..cfcd9baf1e 100644 --- a/tests/Neo.UnitTests/SmartContract/Manifest/UT_ContractPermissionDescriptor.cs +++ b/tests/Neo.UnitTests/SmartContract/Manifest/UT_ContractPermissionDescriptor.cs @@ -9,10 +9,13 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Json; using Neo.SmartContract.Manifest; using Neo.SmartContract.Native; using Neo.Wallets; +using System; using System.Security.Cryptography; namespace Neo.UnitTests.SmartContract.Manifest @@ -34,7 +37,7 @@ public void TestCreateByECPointAndIsWildcard() } [TestMethod] - public void TestFromAndToJson() + public void TestContractPermissionDescriptorFromAndToJson() { byte[] privateKey = new byte[32]; RandomNumberGenerator rng = RandomNumberGenerator.Create(); @@ -44,6 +47,20 @@ public void TestFromAndToJson() ContractPermissionDescriptor result = ContractPermissionDescriptor.FromJson(temp.ToJson()); Assert.AreEqual(null, result.Hash); Assert.AreEqual(result.Group, result.Group); + Assert.ThrowsException(() => ContractPermissionDescriptor.FromJson(string.Empty)); + } + + [TestMethod] + public void TestContractManifestFromJson() + { + Assert.ThrowsException(() => ContractManifest.FromJson(new Json.JObject())); + var jsonFiles = System.IO.Directory.GetFiles(System.IO.Path.Combine("SmartContract", "Manifest", "TestFile")); + foreach (var item in jsonFiles) + { + var json = JObject.Parse(System.IO.File.ReadAllText(item)) as JObject; + var manifest = ContractManifest.FromJson(json); + manifest.ToJson().ToString().Should().Be(json.ToString()); + } } [TestMethod] diff --git a/tests/Neo.UnitTests/SmartContract/Native/UT_StdLib.cs b/tests/Neo.UnitTests/SmartContract/Native/UT_StdLib.cs index f36fa2cfa4..b5c9c198ec 100644 --- a/tests/Neo.UnitTests/SmartContract/Native/UT_StdLib.cs +++ b/tests/Neo.UnitTests/SmartContract/Native/UT_StdLib.cs @@ -9,6 +9,7 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.SmartContract; using Neo.SmartContract.Native; @@ -53,6 +54,9 @@ public void TestItoaAtoi() Assert.ThrowsException(() => StdLib.Atoi("a", 10)); Assert.ThrowsException(() => StdLib.Atoi("g", 16)); Assert.ThrowsException(() => StdLib.Atoi("a", 11)); + + StdLib.Atoi(StdLib.Itoa(BigInteger.One, 10)).Should().Be(BigInteger.One); + StdLib.Atoi(StdLib.Itoa(BigInteger.MinusOne, 10)).Should().Be(BigInteger.MinusOne); } [TestMethod] diff --git a/tests/Neo.UnitTests/SmartContract/UT_InteropService.cs b/tests/Neo.UnitTests/SmartContract/UT_InteropService.cs index 06290922da..1edcfbd9ca 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_InteropService.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_InteropService.cs @@ -10,6 +10,7 @@ // modifications are permitted. using Akka.TestKit.Xunit2; +using Akka.Util.Internal; using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.Cryptography; @@ -507,6 +508,41 @@ public void TestBlockchain_GetContract() NativeContract.ContractManagement.GetContract(engine.Snapshot, state.Hash).Hash.Should().Be(state.Hash); } + [TestMethod] + public void TestBlockchain_GetContractById() + { + var engine = GetEngine(true, true); + var contract = NativeContract.ContractManagement.GetContractById(engine.Snapshot, -1); + contract.Id.Should().Be(-1); + contract.Manifest.Name.Should().Be(nameof(ContractManagement)); + } + + [TestMethod] + public void TestBlockchain_HasMethod() + { + var engine = GetEngine(true, true); + NativeContract.ContractManagement.HasMethod(engine.Snapshot, NativeContract.NEO.Hash, "symbol", 0).Should().Be(true); + NativeContract.ContractManagement.HasMethod(engine.Snapshot, NativeContract.NEO.Hash, "transfer", 4).Should().Be(true); + } + + [TestMethod] + public void TestBlockchain_ListContracts() + { + var engine = GetEngine(true, true); + var list = NativeContract.ContractManagement.ListContracts(engine.Snapshot); + list.ForEach(p => p.Id.Should().BeLessThan(0)); + + var snapshot = TestBlockchain.GetTestSnapshot(); + var state = TestUtils.GetContract(); + snapshot.AddContract(state.Hash, state); + engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot); + engine.LoadScript(new byte[] { 0x01 }); + NativeContract.ContractManagement.GetContract(engine.Snapshot, state.Hash).Hash.Should().Be(state.Hash); + + var list2 = NativeContract.ContractManagement.ListContracts(engine.Snapshot); + list2.Count().Should().Be(list.Count() + 1); + } + [TestMethod] public void TestStorage_GetContext() { @@ -739,5 +775,92 @@ private static ApplicationEngine GetEngine(bool hasContainer = false, bool hasSn if (addScript) engine.LoadScript(new byte[] { 0x01 }); return engine; } + + [TestMethod] + public void TestVerifyWithECDsaV0() + { + var privateKey = new byte[32]; + using var rng = System.Security.Cryptography.RandomNumberGenerator.Create(); + rng.GetBytes(privateKey); + var publicKeyR1 = new KeyPair(privateKey).PublicKey.ToArray(); + var publicKeyK1 = (Neo.Cryptography.ECC.ECCurve.Secp256k1.G * privateKey).ToArray(); + var hexMessage = "Hello, world!"u8.ToArray(); + var signatureR1 = Crypto.Sign(hexMessage, privateKey, Neo.Cryptography.ECC.ECCurve.Secp256r1); + var signatureK1 = Crypto.Sign(hexMessage, privateKey, Neo.Cryptography.ECC.ECCurve.Secp256k1); + + var result = CryptoLib.VerifyWithECDsaV0(hexMessage, publicKeyR1, signatureR1, NamedCurveHash.secp256r1SHA256); + result.Should().BeTrue(); + result = CryptoLib.VerifyWithECDsaV0(hexMessage, publicKeyK1, signatureK1, NamedCurveHash.secp256k1SHA256); + result.Should().BeTrue(); + result = CryptoLib.VerifyWithECDsaV0(hexMessage, publicKeyK1, new byte[0], NamedCurveHash.secp256k1SHA256); + result.Should().BeFalse(); + Assert.ThrowsException(() => CryptoLib.VerifyWithECDsaV0(hexMessage, publicKeyK1, new byte[64], NamedCurveHash.secp256r1Keccak256)); + } + + [TestMethod] + public void TestSha256() + { + var input = "Hello, world!"u8.ToArray(); + var actualHash = CryptoLib.Sha256(input); + var expectedHash = "315f5bdb76d078c43b8ac0064e4a0164612b1fce77c869345bfc94c75894edd3"; + actualHash.ToHexString().Should().Be(expectedHash); + } + + [TestMethod] + public void TestRIPEMD160() + { + var input = "Hello, world!"u8.ToArray(); + var actualHash = CryptoLib.RIPEMD160(input); + var expectedHash = "58262d1fbdbe4530d8865d3518c6d6e41002610f"; + actualHash.ToHexString().Should().Be(expectedHash); + } + + [TestMethod] + public void TestMurmur32() + { + var input = "Hello, world!"u8.ToArray(); + var actualHash = CryptoLib.Murmur32(input, 0); + var expectedHash = "433e36c0"; + actualHash.ToHexString().Should().Be(expectedHash); + } + + [TestMethod] + public void TestGetBlockHash() + { + var snapshot = GetEngine(true, true).Snapshot; + var hash = LedgerContract.Ledger.GetBlockHash(snapshot, 0); + var hash2 = LedgerContract.Ledger.GetBlock(snapshot, 0).Hash; + var hash3 = LedgerContract.Ledger.GetHeader(snapshot, 0).Hash; + hash.ToString().Should().Be(hash2.ToString()); + hash.ToString().Should().Be(hash3.ToString()); + hash.ToString().Should().Be("0x1f4d1defa46faa5e7b9b8d3f79a06bec777d7c26c4aa5f6f5899a291daa87c15"); + LedgerContract.Ledger.ContainsBlock(snapshot, hash).Should().BeTrue(); + } + + [TestMethod] + public void TestGetCandidateVote() + { + var snapshot = GetEngine(true, true).Snapshot; + var vote = LedgerContract.NEO.GetCandidateVote(snapshot, new ECPoint()); + vote.Should().Be(-1); + } + + [TestMethod] + public void TestContractPermissionDescriptorEquals() + { + var descriptor1 = ContractPermissionDescriptor.CreateWildcard(); + descriptor1.Equals(null).Should().BeFalse(); + descriptor1.Equals(null as object).Should().BeFalse(); + var descriptor2 = ContractPermissionDescriptor.Create(LedgerContract.NEO.Hash); + var descriptor3 = ContractPermissionDescriptor.Create(hash: null); + descriptor1.Equals(descriptor3).Should().BeTrue(); + descriptor1.Equals(descriptor3 as object).Should().BeTrue(); + var descriptor4 = ContractPermissionDescriptor.Create(group: null); + var descriptor5 = ContractPermissionDescriptor.Create(group: new ECPoint()); + descriptor1.Equals(descriptor4).Should().BeTrue(); + descriptor2.Equals(descriptor3).Should().BeFalse(); + descriptor5.Equals(descriptor3).Should().BeFalse(); + descriptor5.Equals(descriptor5).Should().BeTrue(); + } } } From 3351533e806d83cad68c93cd3593f34c16223b1b Mon Sep 17 00:00:00 2001 From: Jimmy Date: Thu, 11 Jul 2024 13:32:01 +0800 Subject: [PATCH 42/71] [Neo Plugin UT] Rpcserver unit test on node (#3353) * try mock * not use mock * test * fix test * use neo testutils * complete rpcserver blockchain tests. * revert change to ByteArrayComparer * revert cache change * add more detail to comments * add more exception test cases * fix warning * Apply suggestions from code review * update TODO mark * add node rpc tests * fix build error * set the mempool to 5. * remove memory pool test. * fix tests * fix test issue * Update tests/Neo.UnitTests/TestUtils.Transaction.cs --------- Co-authored-by: Shargon Co-authored-by: NGD Admin <154295625+NGDAdmin@users.noreply.github.com> --- src/Neo/Ledger/MemoryPool.cs | 21 ++ src/Plugins/RpcServer/RpcServer.Node.cs | 6 +- .../TestBlockchain.cs | 49 --- .../TestProtocolSettings.cs | 65 ---- .../UT_RpcServer.Blockchain.cs | 6 +- .../UT_RpcServer.Node.cs | 291 ++++++++++++++++++ .../UT_RpcServer.cs | 8 +- .../Network/P2P/Payloads/UT_Block.cs | 28 +- .../Network/P2P/Payloads/UT_Header.cs | 18 +- .../Network/P2P/Payloads/UT_HeadersPayload.cs | 4 +- .../SmartContract/UT_Syscalls.cs | 3 +- tests/Neo.UnitTests/TestProtocolSettings.cs | 40 ++- tests/Neo.UnitTests/TestUtils.Block.cs | 72 ++++- tests/Neo.UnitTests/TestUtils.Transaction.cs | 129 ++++++++ tests/Neo.UnitTests/TestUtils.cs | 41 ++- 15 files changed, 612 insertions(+), 169 deletions(-) delete mode 100644 tests/Neo.Plugins.RpcServer.Tests/TestBlockchain.cs delete mode 100644 tests/Neo.Plugins.RpcServer.Tests/TestProtocolSettings.cs create mode 100644 tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Node.cs create mode 100644 tests/Neo.UnitTests/TestUtils.Transaction.cs diff --git a/src/Neo/Ledger/MemoryPool.cs b/src/Neo/Ledger/MemoryPool.cs index 7f59bc6e92..2e1adb1a47 100644 --- a/src/Neo/Ledger/MemoryPool.cs +++ b/src/Neo/Ledger/MemoryPool.cs @@ -659,5 +659,26 @@ internal bool ReVerifyTopUnverifiedTransactionsIfNeeded(int maxToVerify, DataCac return _unverifiedTransactions.Count > 0; } + +#if DEBUG + // This method is only for test purpose + // Do not remove it from the DEBUG build + internal void Clear() + { + _txRwLock.EnterReadLock(); + try + { + _unsortedTransactions.Clear(); + _conflicts.Clear(); + _sortedTransactions.Clear(); + _unverifiedTransactions.Clear(); + _unverifiedSortedTransactions.Clear(); + } + finally + { + _txRwLock.ExitReadLock(); + } + } +#endif } } diff --git a/src/Plugins/RpcServer/RpcServer.Node.cs b/src/Plugins/RpcServer/RpcServer.Node.cs index 79a8884a0f..21ca583090 100644 --- a/src/Plugins/RpcServer/RpcServer.Node.cs +++ b/src/Plugins/RpcServer/RpcServer.Node.cs @@ -110,7 +110,7 @@ private static JObject GetRelayResult(VerifyResult reason, UInt256 hash) } [RpcMethod] - protected virtual JToken GetVersion(JArray _params) + protected internal virtual JToken GetVersion(JArray _params) { JObject json = new(); json["tcpport"] = localNode.ListenerTcpPort; @@ -150,7 +150,7 @@ private static string StripPrefix(string s, string prefix) } [RpcMethod] - protected virtual JToken SendRawTransaction(JArray _params) + protected internal virtual JToken SendRawTransaction(JArray _params) { Transaction tx = Result.Ok_Or(() => Convert.FromBase64String(_params[0].AsString()).AsSerializable(), RpcError.InvalidParams.WithData($"Invalid Transaction Format: {_params[0]}")); RelayResult reason = system.Blockchain.Ask(tx).Result; @@ -158,7 +158,7 @@ protected virtual JToken SendRawTransaction(JArray _params) } [RpcMethod] - protected virtual JToken SubmitBlock(JArray _params) + protected internal virtual JToken SubmitBlock(JArray _params) { Block block = Result.Ok_Or(() => Convert.FromBase64String(_params[0].AsString()).AsSerializable(), RpcError.InvalidParams.WithData($"Invalid Block Format: {_params[0]}")); RelayResult reason = system.Blockchain.Ask(block).Result; diff --git a/tests/Neo.Plugins.RpcServer.Tests/TestBlockchain.cs b/tests/Neo.Plugins.RpcServer.Tests/TestBlockchain.cs deleted file mode 100644 index f6e35cf695..0000000000 --- a/tests/Neo.Plugins.RpcServer.Tests/TestBlockchain.cs +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (C) 2015-2024 The Neo Project. -// -// TestBlockchain.cs file belongs to the neo project and is free -// software distributed under the MIT software license, see the -// accompanying file LICENSE in the main directory of the -// repository or http://www.opensource.org/licenses/mit-license.php -// for more details. -// -// Redistribution and use in source and binary forms with or without -// modifications are permitted. - -using Akka.Actor; -using Neo.Ledger; -using Neo.Persistence; -using System; - -namespace Neo.Plugins.RpcServer.Tests -{ - public static class TestBlockchain - { - public static readonly NeoSystem TheNeoSystem; - public static readonly UInt160[] DefaultExtensibleWitnessWhiteList; - private static readonly MemoryStore Store = new(); - - internal class StoreProvider : IStoreProvider - { - public string Name => "TestProvider"; - - public IStore GetStore(string path) => Store; - } - - static TestBlockchain() - { - Console.WriteLine("initialize NeoSystem"); - TheNeoSystem = new NeoSystem(TestProtocolSettings.Default, new StoreProvider()); - } - - internal static void ResetStore() - { - Store.Reset(); - TheNeoSystem.Blockchain.Ask(new Blockchain.Initialize()).Wait(); - } - - internal static DataCache GetTestSnapshot() - { - return TheNeoSystem.GetSnapshot().CreateSnapshot(); - } - } -} diff --git a/tests/Neo.Plugins.RpcServer.Tests/TestProtocolSettings.cs b/tests/Neo.Plugins.RpcServer.Tests/TestProtocolSettings.cs deleted file mode 100644 index edf2df39fb..0000000000 --- a/tests/Neo.Plugins.RpcServer.Tests/TestProtocolSettings.cs +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (C) 2015-2024 The Neo Project. -// -// TestProtocolSettings.cs file belongs to the neo project and is free -// software distributed under the MIT software license, see the -// accompanying file LICENSE in the main directory of the -// repository or http://www.opensource.org/licenses/mit-license.php -// for more details. -// -// Redistribution and use in source and binary forms with or without -// modifications are permitted. - -using Neo.Cryptography.ECC; - -namespace Neo.Plugins.RpcServer.Tests -{ - public static class TestProtocolSettings - { - public static readonly ProtocolSettings Default = new() - { - Network = 0x334F454Eu, - AddressVersion = ProtocolSettings.Default.AddressVersion, - StandbyCommittee = new[] - { - //Validators - ECPoint.Parse("03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c", ECCurve.Secp256r1), - ECPoint.Parse("02df48f60e8f3e01c48ff40b9b7f1310d7a8b2a193188befe1c2e3df740e895093", ECCurve.Secp256r1), - ECPoint.Parse("03b8d9d5771d8f513aa0869b9cc8d50986403b78c6da36890638c3d46a5adce04a", ECCurve.Secp256r1), - ECPoint.Parse("02ca0e27697b9c248f6f16e085fd0061e26f44da85b58ee835c110caa5ec3ba554", ECCurve.Secp256r1), - ECPoint.Parse("024c7b7fb6c310fccf1ba33b082519d82964ea93868d676662d4a59ad548df0e7d", ECCurve.Secp256r1), - ECPoint.Parse("02aaec38470f6aad0042c6e877cfd8087d2676b0f516fddd362801b9bd3936399e", ECCurve.Secp256r1), - ECPoint.Parse("02486fd15702c4490a26703112a5cc1d0923fd697a33406bd5a1c00e0013b09a70", ECCurve.Secp256r1), - //Other Members - ECPoint.Parse("023a36c72844610b4d34d1968662424011bf783ca9d984efa19a20babf5582f3fe", ECCurve.Secp256r1), - ECPoint.Parse("03708b860c1de5d87f5b151a12c2a99feebd2e8b315ee8e7cf8aa19692a9e18379", ECCurve.Secp256r1), - ECPoint.Parse("03c6aa6e12638b36e88adc1ccdceac4db9929575c3e03576c617c49cce7114a050", ECCurve.Secp256r1), - ECPoint.Parse("03204223f8c86b8cd5c89ef12e4f0dbb314172e9241e30c9ef2293790793537cf0", ECCurve.Secp256r1), - ECPoint.Parse("02a62c915cf19c7f19a50ec217e79fac2439bbaad658493de0c7d8ffa92ab0aa62", ECCurve.Secp256r1), - ECPoint.Parse("03409f31f0d66bdc2f70a9730b66fe186658f84a8018204db01c106edc36553cd0", ECCurve.Secp256r1), - ECPoint.Parse("0288342b141c30dc8ffcde0204929bb46aed5756b41ef4a56778d15ada8f0c6654", ECCurve.Secp256r1), - ECPoint.Parse("020f2887f41474cfeb11fd262e982051c1541418137c02a0f4961af911045de639", ECCurve.Secp256r1), - ECPoint.Parse("0222038884bbd1d8ff109ed3bdef3542e768eef76c1247aea8bc8171f532928c30", ECCurve.Secp256r1), - ECPoint.Parse("03d281b42002647f0113f36c7b8efb30db66078dfaaa9ab3ff76d043a98d512fde", ECCurve.Secp256r1), - ECPoint.Parse("02504acbc1f4b3bdad1d86d6e1a08603771db135a73e61c9d565ae06a1938cd2ad", ECCurve.Secp256r1), - ECPoint.Parse("0226933336f1b75baa42d42b71d9091508b638046d19abd67f4e119bf64a7cfb4d", ECCurve.Secp256r1), - ECPoint.Parse("03cdcea66032b82f5c30450e381e5295cae85c5e6943af716cc6b646352a6067dc", ECCurve.Secp256r1), - ECPoint.Parse("02cd5a5547119e24feaa7c2a0f37b8c9366216bab7054de0065c9be42084003c8a", ECCurve.Secp256r1) - }, - ValidatorsCount = 7, - SeedList = new[] - { - "seed1.neo.org:10333", - "seed2.neo.org:10333", - "seed3.neo.org:10333", - "seed4.neo.org:10333", - "seed5.neo.org:10333" - }, - MillisecondsPerBlock = ProtocolSettings.Default.MillisecondsPerBlock, - MaxTransactionsPerBlock = ProtocolSettings.Default.MaxTransactionsPerBlock, - MemoryPoolMaxTransactions = ProtocolSettings.Default.MemoryPoolMaxTransactions, - MaxTraceableBlocks = ProtocolSettings.Default.MaxTraceableBlocks, - InitialGasDistribution = ProtocolSettings.Default.InitialGasDistribution, - Hardforks = ProtocolSettings.Default.Hardforks - }; - } -} diff --git a/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Blockchain.cs b/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Blockchain.cs index 5fd37b2bc3..f62c4258ab 100644 --- a/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Blockchain.cs +++ b/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Blockchain.cs @@ -9,6 +9,7 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using Akka.Actor; using Akka.Util.Internal; using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.IO; @@ -101,8 +102,9 @@ public void TestGetBlockHash() { var snapshot = _neoSystem.GetSnapshot(); var block = TestUtils.CreateBlockWithValidTransactions(snapshot, _wallet, _walletAccount, 3); - TestUtils.BlocksAdd(snapshot, block.Hash, block); - snapshot.Commit(); + // TestUtils.BlocksAdd(snapshot, block.Hash, block); + // snapshot.Commit(); + var reason = _neoSystem.Blockchain.Ask(block).Result; var expectedHash = block.Hash.ToString(); var result = _rpcServer.GetBlockHash(new JArray(block.Index)); Assert.AreEqual(expectedHash, result.AsString()); diff --git a/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Node.cs b/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Node.cs new file mode 100644 index 0000000000..b75706e001 --- /dev/null +++ b/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Node.cs @@ -0,0 +1,291 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_RpcServer.Node.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.IO; +using Neo.Json; +using Neo.Network.P2P.Payloads; +using Neo.SmartContract.Native; +using Neo.UnitTests; +using System; + +namespace Neo.Plugins.RpcServer.Tests +{ + partial class UT_RpcServer + { + [TestMethod] + public void TestGetVersion() + { + var result = _rpcServer.GetVersion(new JArray()); + Assert.IsInstanceOfType(result, typeof(JObject)); + + var json = (JObject)result; + Assert.IsTrue(json.ContainsProperty("tcpport")); + Assert.IsTrue(json.ContainsProperty("nonce")); + Assert.IsTrue(json.ContainsProperty("useragent")); + + Assert.IsTrue(json.ContainsProperty("protocol")); + var protocol = (JObject)json["protocol"]; + Assert.IsTrue(protocol.ContainsProperty("addressversion")); + Assert.IsTrue(protocol.ContainsProperty("network")); + Assert.IsTrue(protocol.ContainsProperty("validatorscount")); + Assert.IsTrue(protocol.ContainsProperty("msperblock")); + Assert.IsTrue(protocol.ContainsProperty("maxtraceableblocks")); + Assert.IsTrue(protocol.ContainsProperty("maxvaliduntilblockincrement")); + Assert.IsTrue(protocol.ContainsProperty("maxtransactionsperblock")); + Assert.IsTrue(protocol.ContainsProperty("memorypoolmaxtransactions")); + } + + #region SendRawTransaction Tests + + [TestMethod] + public void TestSendRawTransaction_Normal() + { + var snapshot = _neoSystem.GetSnapshot(); + var tx = TestUtils.CreateValidTx(snapshot, _wallet, _walletAccount); + var txString = Convert.ToBase64String(tx.ToArray()); + + var result = _rpcServer.SendRawTransaction(new JArray(txString)); + Assert.IsInstanceOfType(result, typeof(JObject)); + Assert.IsTrue(((JObject)result).ContainsProperty("hash")); + } + + [TestMethod] + public void TestSendRawTransaction_InvalidTransactionFormat() + { + Assert.ThrowsException(() => + _rpcServer.SendRawTransaction(new JArray("invalid_transaction_string")), + "Should throw RpcException for invalid transaction format"); + } + + [TestMethod] + public void TestSendRawTransaction_InsufficientBalance() + { + var snapshot = _neoSystem.GetSnapshot(); + var tx = TestUtils.CreateInvalidTransaction(snapshot, _wallet, _walletAccount, TestUtils.InvalidTransactionType.InsufficientBalance); + var txString = Convert.ToBase64String(tx.ToArray()); + + var exception = Assert.ThrowsException(() => + _rpcServer.SendRawTransaction(new JArray(txString)), + "Should throw RpcException for insufficient balance"); + Assert.AreEqual(RpcError.InsufficientFunds.Code, exception.HResult); + } + + [TestMethod] + public void TestSendRawTransaction_InvalidSignature() + { + var snapshot = _neoSystem.GetSnapshot(); + var tx = TestUtils.CreateInvalidTransaction(snapshot, _wallet, _walletAccount, TestUtils.InvalidTransactionType.InvalidSignature); + var txString = Convert.ToBase64String(tx.ToArray()); + + var exception = Assert.ThrowsException(() => + _rpcServer.SendRawTransaction(new JArray(txString)), + "Should throw RpcException for invalid signature"); + Assert.AreEqual(RpcError.InvalidSignature.Code, exception.HResult); + } + + [TestMethod] + public void TestSendRawTransaction_InvalidScript() + { + var snapshot = _neoSystem.GetSnapshot(); + var tx = TestUtils.CreateInvalidTransaction(snapshot, _wallet, _walletAccount, TestUtils.InvalidTransactionType.InvalidScript); + var txString = Convert.ToBase64String(tx.ToArray()); + + var exception = Assert.ThrowsException(() => + _rpcServer.SendRawTransaction(new JArray(txString)), + "Should throw RpcException for invalid script"); + Assert.AreEqual(RpcError.InvalidScript.Code, exception.HResult); + } + + [TestMethod] + public void TestSendRawTransaction_InvalidAttribute() + { + var snapshot = _neoSystem.GetSnapshot(); + var tx = TestUtils.CreateInvalidTransaction(snapshot, _wallet, _walletAccount, TestUtils.InvalidTransactionType.InvalidAttribute); + var txString = Convert.ToBase64String(tx.ToArray()); + + var exception = Assert.ThrowsException(() => + _rpcServer.SendRawTransaction(new JArray(txString)), + "Should throw RpcException for invalid attribute"); + // Transaction with invalid attribute can not pass the Transaction deserialization + // and will throw invalid params exception. + Assert.AreEqual(RpcError.InvalidParams.Code, exception.HResult); + } + + [TestMethod] + public void TestSendRawTransaction_Oversized() + { + var snapshot = _neoSystem.GetSnapshot(); + var tx = TestUtils.CreateInvalidTransaction(snapshot, _wallet, _walletAccount, TestUtils.InvalidTransactionType.Oversized); + var txString = Convert.ToBase64String(tx.ToArray()); + + var exception = Assert.ThrowsException(() => + _rpcServer.SendRawTransaction(new JArray(txString)), + "Should throw RpcException for invalid format transaction"); + // Oversized transaction will not pass the deserialization. + Assert.AreEqual(RpcError.InvalidParams.Code, exception.HResult); + } + + [TestMethod] + public void TestSendRawTransaction_Expired() + { + var snapshot = _neoSystem.GetSnapshot(); + var tx = TestUtils.CreateInvalidTransaction(snapshot, _wallet, _walletAccount, TestUtils.InvalidTransactionType.Expired); + var txString = Convert.ToBase64String(tx.ToArray()); + + var exception = Assert.ThrowsException(() => + _rpcServer.SendRawTransaction(new JArray(txString)), + "Should throw RpcException for expired transaction"); + Assert.AreEqual(RpcError.ExpiredTransaction.Code, exception.HResult); + } + + [TestMethod] + public void TestSendRawTransaction_PolicyFailed() + { + var snapshot = _neoSystem.GetSnapshot(); + var tx = TestUtils.CreateValidTx(snapshot, _wallet, _walletAccount); + var txString = Convert.ToBase64String(tx.ToArray()); + NativeContract.Policy.BlockAccount(snapshot, _walletAccount.ScriptHash); + snapshot.Commit(); + + var exception = Assert.ThrowsException(() => + _rpcServer.SendRawTransaction(new JArray(txString)), + "Should throw RpcException for conflicting transaction"); + Assert.AreEqual(RpcError.PolicyFailed.Code, exception.HResult); + } + + [TestMethod] + public void TestSendRawTransaction_AlreadyInPool() + { + var snapshot = _neoSystem.GetSnapshot(); + var tx = TestUtils.CreateValidTx(snapshot, _wallet, _walletAccount); + _neoSystem.MemPool.TryAdd(tx, snapshot); + var txString = Convert.ToBase64String(tx.ToArray()); + + var exception = Assert.ThrowsException(() => + _rpcServer.SendRawTransaction(new JArray(txString)), + "Should throw RpcException for transaction already in memory pool"); + Assert.AreEqual(RpcError.AlreadyInPool.Code, exception.HResult); + } + + [TestMethod] + public void TestSendRawTransaction_AlreadyInBlockchain() + { + var snapshot = _neoSystem.GetSnapshot(); + var tx = TestUtils.CreateValidTx(snapshot, _wallet, _walletAccount); + TestUtils.AddTransactionToBlockchain(snapshot, tx); + snapshot.Commit(); + var txString = Convert.ToBase64String(tx.ToArray()); + var exception = Assert.ThrowsException(() => _rpcServer.SendRawTransaction(new JArray(txString))); + Assert.AreEqual(RpcError.AlreadyExists.Code, exception.HResult); + } + + #endregion + + #region SubmitBlock Tests + + [TestMethod] + public void TestSubmitBlock_Normal() + { + var snapshot = _neoSystem.GetSnapshot(); + var block = TestUtils.CreateBlockWithValidTransactions(snapshot, _wallet, _walletAccount, 1); + var blockString = Convert.ToBase64String(block.ToArray()); + + var result = _rpcServer.SubmitBlock(new JArray(blockString)); + Assert.IsInstanceOfType(result, typeof(JObject)); + Assert.IsTrue(((JObject)result).ContainsProperty("hash")); + } + + [TestMethod] + public void TestSubmitBlock_InvalidBlockFormat() + { + string invalidBlockString = TestUtils.CreateInvalidBlockFormat(); + + var exception = Assert.ThrowsException(() => + _rpcServer.SubmitBlock(new JArray(invalidBlockString)), + "Should throw RpcException for invalid block format"); + + Assert.AreEqual(RpcError.InvalidParams.Code, exception.HResult); + StringAssert.Contains(exception.Message, "Invalid Block Format"); + } + + [TestMethod] + public void TestSubmitBlock_AlreadyExists() + { + var snapshot = _neoSystem.GetSnapshot(); + var block = TestUtils.CreateBlockWithValidTransactions(snapshot, _wallet, _walletAccount, 1); + TestUtils.BlocksAdd(snapshot, block.Hash, block); + snapshot.Commit(); + var blockString = Convert.ToBase64String(block.ToArray()); + + var exception = Assert.ThrowsException(() => + _rpcServer.SubmitBlock(new JArray(blockString)), + "Should throw RpcException when block already exists"); + Assert.AreEqual(RpcError.AlreadyExists.Code, exception.HResult); + } + + [TestMethod] + public void TestSubmitBlock_InvalidBlock() + { + var snapshot = _neoSystem.GetSnapshot(); + var block = TestUtils.CreateBlockWithValidTransactions(snapshot, _wallet, _walletAccount, 1); + block.Header.Witness = new Witness(); + var blockString = Convert.ToBase64String(block.ToArray()); + + var exception = Assert.ThrowsException(() => + _rpcServer.SubmitBlock(new JArray(blockString)), + "Should throw RpcException for invalid block"); + Assert.AreEqual(RpcError.VerificationFailed.Code, exception.HResult); + } + + #endregion + + #region Edge Cases and Error Handling + + [TestMethod] + public void TestSendRawTransaction_NullInput() + { + var exception = Assert.ThrowsException(() => + _rpcServer.SendRawTransaction(new JArray((string)null)), + "Should throw RpcException for null input"); + Assert.AreEqual(RpcError.InvalidParams.Code, exception.HResult); + } + + [TestMethod] + public void TestSendRawTransaction_EmptyInput() + { + var exception = Assert.ThrowsException(() => + _rpcServer.SendRawTransaction(new JArray(string.Empty)), + "Should throw RpcException for empty input"); + Assert.AreEqual(RpcError.InvalidParams.Code, exception.HResult); + } + + [TestMethod] + public void TestSubmitBlock_NullInput() + { + var exception = Assert.ThrowsException(() => + _rpcServer.SubmitBlock(new JArray((string)null)), + "Should throw RpcException for null input"); + Assert.AreEqual(RpcError.InvalidParams.Code, exception.HResult); + } + + [TestMethod] + public void TestSubmitBlock_EmptyInput() + { + var exception = Assert.ThrowsException(() => + _rpcServer.SubmitBlock(new JArray(string.Empty)), + "Should throw RpcException for empty input"); + Assert.AreEqual(RpcError.InvalidParams.Code, exception.HResult); + } + + #endregion + } +} diff --git a/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.cs b/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.cs index 4ba95b7798..96de838ba8 100644 --- a/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.cs +++ b/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.cs @@ -11,6 +11,7 @@ using Microsoft.AspNetCore.Http; using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Ledger; using Neo.Persistence; using Neo.SmartContract; using Neo.SmartContract.Native; @@ -37,10 +38,9 @@ public void TestSetup() { _memoryStore = new MemoryStore(); _memoryStoreProvider = new TestMemoryStoreProvider(_memoryStore); - var protocolSettings = TestProtocolSettings.Default; - _neoSystem = new NeoSystem(protocolSettings, _memoryStoreProvider); + _neoSystem = new NeoSystem(TestProtocolSettings.SoleNode, _memoryStoreProvider); _rpcServer = new RpcServer(_neoSystem, RpcServerSettings.Default); - _walletAccount = _wallet.CreateAccount(); + _walletAccount = _wallet.Import("KxuRSsHgJMb3AMSN6B9P3JHNGMFtxmuimqgR9MmXPcv3CLLfusTd"); var key = new KeyBuilder(NativeContract.GAS.Id, 20).Add(_walletAccount.ScriptHash); var snapshot = _neoSystem.GetSnapshot(); var entry = snapshot.GetAndChange(key, () => new StorageItem(new AccountState())); @@ -51,6 +51,8 @@ public void TestSetup() [TestCleanup] public void TestCleanup() { + // Please build and test in debug mode + _neoSystem.MemPool.Clear(); _memoryStore.Reset(); var snapshot = _neoSystem.GetSnapshot(); var key = new KeyBuilder(NativeContract.GAS.Id, 20).Add(_walletAccount.ScriptHash); diff --git a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Block.cs b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Block.cs index 075c083df2..7793e27597 100644 --- a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Block.cs +++ b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Block.cs @@ -50,7 +50,7 @@ public void Transactions_Get() public void Header_Get() { UInt256 val256 = UInt256.Zero; - TestUtils.SetupBlockWithValues(uut, val256, out var merkRootVal, out _, out var timestampVal, out var nonceVal, out var indexVal, out var scriptVal, out _, 0); + TestUtils.SetupBlockWithValues(null, uut, val256, out var merkRootVal, out _, out var timestampVal, out var nonceVal, out var indexVal, out var scriptVal, out _, 0); uut.Header.Should().NotBeNull(); uut.Header.PrevHash.Should().Be(val256); @@ -65,7 +65,7 @@ public void Header_Get() public void Size_Get() { UInt256 val256 = UInt256.Zero; - TestUtils.SetupBlockWithValues(uut, val256, out var _, out var _, out var _, out var _, out var _, out var _, out var _, 0); + TestUtils.SetupBlockWithValues(null, uut, val256, out var _, out var _, out var _, out var _, out var _, out var _, out var _, 0); // header 4 + 32 + 32 + 8 + 4 + 1 + 20 + 4 // tx 1 uut.Size.Should().Be(114); // 106 + nonce @@ -75,7 +75,7 @@ public void Size_Get() public void Size_Get_1_Transaction() { UInt256 val256 = UInt256.Zero; - TestUtils.SetupBlockWithValues(uut, val256, out var _, out var _, out var _, out var _, out var _, out var _, out var _, 0); + TestUtils.SetupBlockWithValues(null, uut, val256, out var _, out var _, out var _, out var _, out var _, out var _, out var _, 0); uut.Transactions = new[] { @@ -89,7 +89,7 @@ public void Size_Get_1_Transaction() public void Size_Get_3_Transaction() { UInt256 val256 = UInt256.Zero; - TestUtils.SetupBlockWithValues(uut, val256, out var _, out var _, out var _, out var _, out var _, out var _, out var _, 0); + TestUtils.SetupBlockWithValues(null, uut, val256, out var _, out var _, out var _, out var _, out var _, out var _, out var _, 0); uut.Transactions = new[] { @@ -105,9 +105,9 @@ public void Size_Get_3_Transaction() public void Serialize() { UInt256 val256 = UInt256.Zero; - TestUtils.SetupBlockWithValues(uut, val256, out var _, out var _, out var _, out var _, out var _, out var _, out var _, 1); + TestUtils.SetupBlockWithValues(null, uut, val256, out var _, out var _, out var _, out var _, out var _, out var _, out var _, 1); - var hex = "0000000000000000000000000000000000000000000000000000000000000000000000006c23be5d32679baa9c5c2aa0d329fd2a2441d7875d0f34d42f58f70428fbbbb9e913ff854c00000000000000000000000000000000000000000000000000000000000000000000000001000111010000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000001000112010000"; + var hex = "0000000000000000000000000000000000000000000000000000000000000000000000006c23be5d32679baa9c5c2aa0d329fd2a2441d7875d0f34d42f58f70428fbbbb9493ed0e58f01000000000000000000000000000000000000000000000000000000000000000000000001000111010000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000001000112010000"; uut.ToArray().ToHexString().Should().Be(hex); } @@ -115,9 +115,9 @@ public void Serialize() public void Deserialize() { UInt256 val256 = UInt256.Zero; - TestUtils.SetupBlockWithValues(new Block(), val256, out _, out var val160, out var timestampVal, out var indexVal, out var nonceVal, out var scriptVal, out var transactionsVal, 1); + TestUtils.SetupBlockWithValues(null, new Block(), val256, out _, out var val160, out var timestampVal, out var indexVal, out var nonceVal, out var scriptVal, out var transactionsVal, 1); - var hex = "0000000000000000000000000000000000000000000000000000000000000000000000006c23be5d32679baa9c5c2aa0d329fd2a2441d7875d0f34d42f58f70428fbbbb9e913ff854c00000000000000000000000000000000000000000000000000000000000000000000000001000111010000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000001000112010000"; + var hex = "0000000000000000000000000000000000000000000000000000000000000000000000006c23be5d32679baa9c5c2aa0d329fd2a2441d7875d0f34d42f58f70428fbbbb9493ed0e58f01000000000000000000000000000000000000000000000000000000000000000000000001000111010000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000001000112010000"; MemoryReader reader = new(hex.HexToBytes()); uut.Deserialize(ref reader); @@ -165,8 +165,8 @@ public void Equals_DiffObj() Block newBlock = new(); UInt256 val256 = UInt256.Zero; UInt256 prevHash = new(TestUtils.GetByteArray(32, 0x42)); - TestUtils.SetupBlockWithValues(newBlock, val256, out _, out _, out _, out ulong _, out uint _, out _, out _, 1); - TestUtils.SetupBlockWithValues(uut, prevHash, out _, out _, out _, out _, out _, out _, out _, 0); + TestUtils.SetupBlockWithValues(null, newBlock, val256, out _, out _, out _, out ulong _, out uint _, out _, out _, 1); + TestUtils.SetupBlockWithValues(null, uut, prevHash, out _, out _, out _, out _, out _, out _, out _, 0); uut.Equals(newBlock).Should().BeFalse(); } @@ -182,8 +182,8 @@ public void Equals_SameHash() { Block newBlock = new(); UInt256 prevHash = new(TestUtils.GetByteArray(32, 0x42)); - TestUtils.SetupBlockWithValues(newBlock, prevHash, out _, out _, out _, out _, out _, out _, out _, 1); - TestUtils.SetupBlockWithValues(uut, prevHash, out _, out _, out _, out _, out _, out _, out _, 1); + TestUtils.SetupBlockWithValues(null, newBlock, prevHash, out _, out _, out _, out _, out _, out _, out _, 1); + TestUtils.SetupBlockWithValues(null, uut, prevHash, out _, out _, out _, out _, out _, out _, out _, 1); uut.Equals(newBlock).Should().BeTrue(); } @@ -192,11 +192,11 @@ public void Equals_SameHash() public void ToJson() { UInt256 val256 = UInt256.Zero; - TestUtils.SetupBlockWithValues(uut, val256, out _, out _, out var timeVal, out var indexVal, out var nonceVal, out _, out _, 1); + TestUtils.SetupBlockWithValues(null, uut, val256, out _, out _, out var timeVal, out var indexVal, out var nonceVal, out _, out _, 1); JObject jObj = uut.ToJson(TestProtocolSettings.Default); jObj.Should().NotBeNull(); - jObj["hash"].AsString().Should().Be("0x60193a05005c433787d8a9b95da332bbeebb311e904525e9fb1bacc34ff1ead7"); + jObj["hash"].AsString().Should().Be("0x942065e93848732c2e7844061fa92d20c5d9dc0bc71d420a1ea71b3431fc21b4"); jObj["size"].AsNumber().Should().Be(167); // 159 + nonce jObj["version"].AsNumber().Should().Be(0); jObj["previousblockhash"].AsString().Should().Be("0x0000000000000000000000000000000000000000000000000000000000000000"); diff --git a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Header.cs b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Header.cs index a597c88cb6..17e0cb894f 100644 --- a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Header.cs +++ b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Header.cs @@ -34,7 +34,7 @@ public void TestSetup() public void Size_Get() { UInt256 val256 = UInt256.Zero; - TestUtils.SetupHeaderWithValues(uut, val256, out _, out _, out _, out _, out _, out _); + TestUtils.SetupHeaderWithValues(null, uut, val256, out _, out _, out _, out _, out _, out _); // blockbase 4 + 64 + 1 + 32 + 4 + 4 + 20 + 4 // header 1 uut.Size.Should().Be(113); // 105 + nonce @@ -44,7 +44,7 @@ public void Size_Get() public void GetHashCodeTest() { UInt256 val256 = UInt256.Zero; - TestUtils.SetupHeaderWithValues(uut, val256, out _, out _, out _, out _, out _, out _); + TestUtils.SetupHeaderWithValues(null, uut, val256, out _, out _, out _, out _, out _, out _); uut.GetHashCode().Should().Be(uut.Hash.GetHashCode()); } @@ -53,7 +53,7 @@ public void TrimTest() { UInt256 val256 = UInt256.Zero; var snapshot = TestBlockchain.GetTestSnapshot().CreateSnapshot(); - TestUtils.SetupHeaderWithValues(uut, val256, out _, out _, out _, out _, out _, out _); + TestUtils.SetupHeaderWithValues(null, uut, val256, out _, out _, out _, out _, out _, out _); uut.Witness = new Witness() { InvocationScript = Array.Empty(), VerificationScript = Array.Empty() }; TestUtils.BlocksAdd(snapshot, uut.Hash, new TrimmedBlock() @@ -87,11 +87,11 @@ public void TrimTest() public void Deserialize() { UInt256 val256 = UInt256.Zero; - TestUtils.SetupHeaderWithValues(new Header(), val256, out UInt256 merkRoot, out UInt160 val160, out ulong timestampVal, out ulong nonceVal, out uint indexVal, out Witness scriptVal); + TestUtils.SetupHeaderWithValues(null, new Header(), val256, out UInt256 merkRoot, out UInt160 val160, out ulong timestampVal, out ulong nonceVal, out uint indexVal, out Witness scriptVal); uut.MerkleRoot = merkRoot; // need to set for deserialise to be valid - var hex = "0000000000000000000000000000000000000000000000000000000000000000000000007227ba7b747f1a98f68679d4a98b68927646ab195a6f56b542ca5a0e6a412662e913ff854c00000000000000000000000000000000000000000000000000000000000000000000000001000111"; + var hex = "0000000000000000000000000000000000000000000000000000000000000000000000007227ba7b747f1a98f68679d4a98b68927646ab195a6f56b542ca5a0e6a412662493ed0e58f01000000000000000000000000000000000000000000000000000000000000000000000001000111"; MemoryReader reader = new(hex.HexToBytes()); uut.Deserialize(ref reader); @@ -130,8 +130,8 @@ public void Equals_SameHash() { Header newHeader = new(); UInt256 prevHash = new(TestUtils.GetByteArray(32, 0x42)); - TestUtils.SetupHeaderWithValues(newHeader, prevHash, out _, out _, out _, out _, out _, out _); - TestUtils.SetupHeaderWithValues(uut, prevHash, out _, out _, out _, out _, out _, out _); + TestUtils.SetupHeaderWithValues(null, newHeader, prevHash, out _, out _, out _, out _, out _, out _); + TestUtils.SetupHeaderWithValues(null, uut, prevHash, out _, out _, out _, out _, out _, out _); uut.Equals(newHeader).Should().BeTrue(); } @@ -146,9 +146,9 @@ public void Equals_SameObject() public void Serialize() { UInt256 val256 = UInt256.Zero; - TestUtils.SetupHeaderWithValues(uut, val256, out _, out _, out _, out _, out _, out _); + TestUtils.SetupHeaderWithValues(null, uut, val256, out _, out _, out _, out _, out _, out _); - var hex = "0000000000000000000000000000000000000000000000000000000000000000000000007227ba7b747f1a98f68679d4a98b68927646ab195a6f56b542ca5a0e6a412662e913ff854c00000000000000000000000000000000000000000000000000000000000000000000000001000111"; + var hex = "0000000000000000000000000000000000000000000000000000000000000000000000007227ba7b747f1a98f68679d4a98b68927646ab195a6f56b542ca5a0e6a412662493ed0e58f01000000000000000000000000000000000000000000000000000000000000000000000001000111"; uut.ToArray().ToHexString().Should().Be(hex); } } diff --git a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_HeadersPayload.cs b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_HeadersPayload.cs index 2ac486ef06..9ecdd7f5e4 100644 --- a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_HeadersPayload.cs +++ b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_HeadersPayload.cs @@ -23,7 +23,7 @@ public class UT_HeadersPayload public void Size_Get() { var header = new Header(); - TestUtils.SetupHeaderWithValues(header, UInt256.Zero, out _, out _, out _, out _, out _, out _); + TestUtils.SetupHeaderWithValues(null, header, UInt256.Zero, out _, out _, out _, out _, out _, out _); var test = HeadersPayload.Create(); test.Size.Should().Be(1); @@ -35,7 +35,7 @@ public void Size_Get() public void DeserializeAndSerialize() { var header = new Header(); - TestUtils.SetupHeaderWithValues(header, UInt256.Zero, out _, out _, out _, out _, out _, out _); + TestUtils.SetupHeaderWithValues(null, header, UInt256.Zero, out _, out _, out _, out _, out _, out _); var test = HeadersPayload.Create(header); var clone = test.ToArray().AsSerializable(); diff --git a/tests/Neo.UnitTests/SmartContract/UT_Syscalls.cs b/tests/Neo.UnitTests/SmartContract/UT_Syscalls.cs index 76448855d7..e027fa4d88 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_Syscalls.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_Syscalls.cs @@ -81,10 +81,11 @@ public void System_Blockchain_GetBlock() const byte Prefix_Transaction = 11; const byte Prefix_CurrentBlock = 12; + TestUtils.BlocksAdd(snapshot, block.Hash, block); + var height = snapshot[NativeContract.Ledger.CreateStorageKey(Prefix_CurrentBlock)].GetInteroperable(); height.Index = block.Index + TestProtocolSettings.Default.MaxTraceableBlocks; - TestUtils.BlocksAdd(snapshot, block.Hash, block); snapshot.Add(NativeContract.Ledger.CreateStorageKey(Prefix_Transaction, tx.Hash), new StorageItem(new TransactionState { BlockIndex = block.Index, diff --git a/tests/Neo.UnitTests/TestProtocolSettings.cs b/tests/Neo.UnitTests/TestProtocolSettings.cs index b12f5c9a85..3f89fdd5f9 100644 --- a/tests/Neo.UnitTests/TestProtocolSettings.cs +++ b/tests/Neo.UnitTests/TestProtocolSettings.cs @@ -15,12 +15,12 @@ namespace Neo.UnitTests { public static class TestProtocolSettings { - public static ProtocolSettings Default = new() + public static readonly ProtocolSettings Default = new() { Network = 0x334F454Eu, AddressVersion = ProtocolSettings.Default.AddressVersion, - StandbyCommittee = new[] - { + StandbyCommittee = + [ //Validators ECPoint.Parse("03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c", ECCurve.Secp256r1), ECPoint.Parse("02df48f60e8f3e01c48ff40b9b7f1310d7a8b2a193188befe1c2e3df740e895093", ECCurve.Secp256r1), @@ -44,16 +44,42 @@ public static class TestProtocolSettings ECPoint.Parse("0226933336f1b75baa42d42b71d9091508b638046d19abd67f4e119bf64a7cfb4d", ECCurve.Secp256r1), ECPoint.Parse("03cdcea66032b82f5c30450e381e5295cae85c5e6943af716cc6b646352a6067dc", ECCurve.Secp256r1), ECPoint.Parse("02cd5a5547119e24feaa7c2a0f37b8c9366216bab7054de0065c9be42084003c8a", ECCurve.Secp256r1) - }, + ], ValidatorsCount = 7, - SeedList = new[] - { + SeedList = + [ "seed1.neo.org:10333", "seed2.neo.org:10333", "seed3.neo.org:10333", "seed4.neo.org:10333", "seed5.neo.org:10333" - }, + ], + MillisecondsPerBlock = ProtocolSettings.Default.MillisecondsPerBlock, + MaxTransactionsPerBlock = ProtocolSettings.Default.MaxTransactionsPerBlock, + MemoryPoolMaxTransactions = ProtocolSettings.Default.MemoryPoolMaxTransactions, + MaxTraceableBlocks = ProtocolSettings.Default.MaxTraceableBlocks, + InitialGasDistribution = ProtocolSettings.Default.InitialGasDistribution, + Hardforks = ProtocolSettings.Default.Hardforks + }; + + public static readonly ProtocolSettings SoleNode = new() + { + Network = 0x334F454Eu, + AddressVersion = ProtocolSettings.Default.AddressVersion, + StandbyCommittee = + [ + //Validators + ECPoint.Parse("0278ed78c917797b637a7ed6e7a9d94e8c408444c41ee4c0a0f310a256b9271eda", ECCurve.Secp256r1) + ], + ValidatorsCount = 1, + SeedList = + [ + "seed1.neo.org:10333", + "seed2.neo.org:10333", + "seed3.neo.org:10333", + "seed4.neo.org:10333", + "seed5.neo.org:10333" + ], MillisecondsPerBlock = ProtocolSettings.Default.MillisecondsPerBlock, MaxTransactionsPerBlock = ProtocolSettings.Default.MaxTransactionsPerBlock, MemoryPoolMaxTransactions = ProtocolSettings.Default.MemoryPoolMaxTransactions, diff --git a/tests/Neo.UnitTests/TestUtils.Block.cs b/tests/Neo.UnitTests/TestUtils.Block.cs index 4f663fec2d..bed85131e6 100644 --- a/tests/Neo.UnitTests/TestUtils.Block.cs +++ b/tests/Neo.UnitTests/TestUtils.Block.cs @@ -30,10 +30,12 @@ public partial class TestUtils const byte Prefix_Block = 5; const byte Prefix_BlockHash = 9; const byte Prefix_Transaction = 11; + const byte Prefix_CurrentBlock = 12; /// /// Test Util function SetupHeaderWithValues /// + /// The snapshot of the current storage provider. Can be null. /// The header to be assigned /// PrevHash /// MerkleRoot @@ -42,12 +44,15 @@ public partial class TestUtils /// Index /// Nonce /// Witness - public static void SetupHeaderWithValues(Header header, UInt256 val256, out UInt256 merkRootVal, out UInt160 val160, out ulong timestampVal, out ulong nonceVal, out uint indexVal, out Witness scriptVal) + public static void SetupHeaderWithValues(DataCache snapshot, Header header, UInt256 val256, out UInt256 merkRootVal, out UInt160 val160, out ulong timestampVal, out ulong nonceVal, out uint indexVal, out Witness scriptVal) { header.PrevHash = val256; header.MerkleRoot = merkRootVal = UInt256.Parse("0x6226416a0e5aca42b5566f5a19ab467692688ba9d47986f6981a7f747bba2772"); - header.Timestamp = timestampVal = new DateTime(1980, 06, 01, 0, 0, 1, 001, DateTimeKind.Utc).ToTimestampMS(); // GMT: Sunday, June 1, 1980 12:00:01.001 AM - header.Index = indexVal = 0; + header.Timestamp = timestampVal = new DateTime(2024, 06, 05, 0, 33, 1, 001, DateTimeKind.Utc).ToTimestampMS(); + if (snapshot != null) + header.Index = indexVal = NativeContract.Ledger.CurrentIndex(snapshot) + 1; + else + header.Index = indexVal = 0; header.Nonce = nonceVal = 0; header.NextConsensus = val160 = UInt160.Zero; header.Witness = scriptVal = new Witness @@ -57,10 +62,10 @@ public static void SetupHeaderWithValues(Header header, UInt256 val256, out UInt }; } - public static void SetupBlockWithValues(Block block, UInt256 val256, out UInt256 merkRootVal, out UInt160 val160, out ulong timestampVal, out ulong nonceVal, out uint indexVal, out Witness scriptVal, out Transaction[] transactionsVal, int numberOfTransactions) + public static void SetupBlockWithValues(DataCache snapshot, Block block, UInt256 val256, out UInt256 merkRootVal, out UInt160 val160, out ulong timestampVal, out ulong nonceVal, out uint indexVal, out Witness scriptVal, out Transaction[] transactionsVal, int numberOfTransactions) { Header header = new Header(); - SetupHeaderWithValues(header, val256, out merkRootVal, out val160, out timestampVal, out nonceVal, out indexVal, out scriptVal); + SetupHeaderWithValues(snapshot, header, val256, out merkRootVal, out val160, out timestampVal, out nonceVal, out indexVal, out scriptVal); transactionsVal = new Transaction[numberOfTransactions]; if (numberOfTransactions > 0) @@ -79,21 +84,32 @@ public static void SetupBlockWithValues(Block block, UInt256 val256, out UInt256 public static Block CreateBlockWithValidTransactions(DataCache snapshot, NEP6Wallet wallet, WalletAccount account, int numberOfTransactions) { - var block = new Block(); - var transactions = new List(); for (var i = 0; i < numberOfTransactions; i++) { transactions.Add(CreateValidTx(snapshot, wallet, account)); } + return CreateBlockWithValidTransactions(snapshot, account, transactions.ToArray()); + } + + public static Block CreateBlockWithValidTransactions(DataCache snapshot, WalletAccount account, Transaction[] transactions) + { + var block = new Block(); var header = new Header(); - SetupHeaderWithValues(header, RandomUInt256(), out _, out _, out _, out _, out _, out _); + var state = snapshot.TryGet(NativeContract.Ledger.CreateStorageKey(Prefix_CurrentBlock)).GetInteroperable(); + SetupHeaderWithValues(snapshot, header, state.Hash, out _, out _, out _, out _, out _, out _); block.Header = header; - block.Transactions = transactions.ToArray(); + block.Transactions = transactions; header.MerkleRoot = MerkleTree.ComputeRoot(block.Transactions.Select(p => p.Hash).ToArray()); + var contract = Contract.CreateMultiSigContract(1, TestProtocolSettings.SoleNode.StandbyCommittee); + var sc = new ContractParametersContext(snapshot, header, TestProtocolSettings.SoleNode.Network); + var signature = header.Sign(account.GetKey(), TestProtocolSettings.SoleNode.Network); + sc.AddSignature(contract, TestProtocolSettings.SoleNode.StandbyCommittee[0], signature.ToArray()); + block.Header.Witness = sc.GetWitnesses()[0]; + return block; } @@ -115,6 +131,10 @@ public static void BlocksAdd(DataCache snapshot, UInt256 hash, TrimmedBlock bloc { snapshot.Add(NativeContract.Ledger.CreateStorageKey(Prefix_BlockHash, block.Index), new StorageItem(hash.ToArray())); snapshot.Add(NativeContract.Ledger.CreateStorageKey(Prefix_Block, hash), new StorageItem(block.ToArray())); + + var state = snapshot.GetAndChange(NativeContract.Ledger.CreateStorageKey(Prefix_CurrentBlock), () => new StorageItem(new HashIndexState())).GetInteroperable(); + state.Hash = hash; + state.Index = block.Index; } public static void BlocksAdd(DataCache snapshot, UInt256 hash, Block block) @@ -129,8 +149,42 @@ public static void BlocksAdd(DataCache snapshot, UInt256 hash, Block block) }; TransactionAdd(snapshot, state); }); + snapshot.Add(NativeContract.Ledger.CreateStorageKey(Prefix_BlockHash, block.Index), new StorageItem(hash.ToArray())); snapshot.Add(NativeContract.Ledger.CreateStorageKey(Prefix_Block, hash), new StorageItem(block.ToTrimmedBlock().ToArray())); + var state = snapshot.GetAndChange(NativeContract.Ledger.CreateStorageKey(Prefix_CurrentBlock), () => new StorageItem(new HashIndexState())).GetInteroperable(); + state.Hash = hash; + state.Index = block.Index; + } + + public static string CreateInvalidBlockFormat() + { + // Create a valid block + var validBlock = new Block + { + Header = new Header + { + Version = 0, + PrevHash = UInt256.Zero, + MerkleRoot = UInt256.Zero, + Timestamp = 0, + Index = 0, + NextConsensus = UInt160.Zero, + Witness = new Witness { InvocationScript = Array.Empty(), VerificationScript = Array.Empty() } + }, + Transactions = [] + }; + + // Serialize the valid block + byte[] validBlockBytes = validBlock.ToArray(); + + // Corrupt the serialized data + // For example, we can truncate the data by removing the last few bytes + byte[] invalidBlockBytes = new byte[validBlockBytes.Length - 5]; + Array.Copy(validBlockBytes, invalidBlockBytes, invalidBlockBytes.Length); + + // Convert the corrupted data to a Base64 string + return Convert.ToBase64String(invalidBlockBytes); } public static TrimmedBlock ToTrimmedBlock(this Block block) diff --git a/tests/Neo.UnitTests/TestUtils.Transaction.cs b/tests/Neo.UnitTests/TestUtils.Transaction.cs new file mode 100644 index 0000000000..f96ac8ec74 --- /dev/null +++ b/tests/Neo.UnitTests/TestUtils.Transaction.cs @@ -0,0 +1,129 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// TestUtils.Transaction.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Cryptography; +using Neo.IO; +using Neo.Network.P2P.Payloads; +using Neo.Persistence; +using Neo.SmartContract; +using Neo.SmartContract.Native; +using Neo.VM; +using Neo.Wallets; +using Neo.Wallets.NEP6; +using System; +using System.IO; +using System.Linq; + +namespace Neo.UnitTests; + +public partial class TestUtils +{ + public static Transaction CreateInvalidTransaction(DataCache snapshot, NEP6Wallet wallet, WalletAccount account, InvalidTransactionType type, UInt256 conflict = null) + { + var rand = new Random(); + var sender = account.ScriptHash; + + var tx = new Transaction + { + Version = 0, + Nonce = (uint)rand.Next(), + ValidUntilBlock = NativeContract.Ledger.CurrentIndex(snapshot) + wallet.ProtocolSettings.MaxValidUntilBlockIncrement, + Signers = [new Signer { Account = sender, Scopes = WitnessScope.CalledByEntry }], + Attributes = [], + Script = new[] { (byte)OpCode.RET } + }; + + switch (type) + { + case InvalidTransactionType.InsufficientBalance: + // Set an unrealistically high system fee + tx.SystemFee = long.MaxValue; + break; + case InvalidTransactionType.InvalidScript: + // Use an invalid script + tx.Script = new byte[] { 0xFF }; + break; + case InvalidTransactionType.InvalidAttribute: + // Add an invalid attribute + tx.Attributes = [new InvalidAttribute()]; + break; + case InvalidTransactionType.Oversized: + // Make the transaction oversized + tx.Script = new byte[Transaction.MaxTransactionSize]; + break; + case InvalidTransactionType.Expired: + // Set an expired ValidUntilBlock + tx.ValidUntilBlock = NativeContract.Ledger.CurrentIndex(snapshot) - 1; + break; + case InvalidTransactionType.Conflicting: + // To create a conflicting transaction, we'd need another valid transaction. + // For simplicity, we'll just add a Conflicts attribute with a random hash. + tx.Attributes = [new Conflicts { Hash = conflict }]; + break; + } + + var data = new ContractParametersContext(snapshot, tx, TestProtocolSettings.Default.Network); + Assert.IsNull(data.GetSignatures(tx.Sender)); + Assert.IsTrue(wallet.Sign(data)); + Assert.IsTrue(data.Completed); + Assert.AreEqual(1, data.GetSignatures(tx.Sender).Count); + tx.Witnesses = data.GetWitnesses(); + if (type == InvalidTransactionType.InvalidSignature) + { + tx.Witnesses[0] = new Witness + { + InvocationScript = new byte[] { (byte)OpCode.PUSHDATA1, 64 }.Concat(new byte[64]).ToArray(), + VerificationScript = data.GetWitnesses()[0].VerificationScript + }; + } + + return tx; + } + + public enum InvalidTransactionType + { + InsufficientBalance, + InvalidSignature, + InvalidScript, + InvalidAttribute, + Oversized, + Expired, + Conflicting + } + + class InvalidAttribute : TransactionAttribute + { + public override TransactionAttributeType Type => (TransactionAttributeType)0xFF; + public override bool AllowMultiple { get; } + protected override void DeserializeWithoutType(ref MemoryReader reader) { } + protected override void SerializeWithoutType(BinaryWriter writer) { } + } + + public static void AddTransactionToBlockchain(DataCache snapshot, Transaction tx) + { + var block = new Block + { + Header = new Header + { + Index = NativeContract.Ledger.CurrentIndex(snapshot) + 1, + PrevHash = NativeContract.Ledger.CurrentHash(snapshot), + MerkleRoot = new UInt256(Crypto.Hash256(tx.Hash.ToArray())), + Timestamp = TimeProvider.Current.UtcNow.ToTimestampMS(), + NextConsensus = UInt160.Zero, + Witness = new Witness { InvocationScript = Array.Empty(), VerificationScript = Array.Empty() } + }, + Transactions = [tx] + }; + + BlocksAdd(snapshot, block.Hash, block); + } +} diff --git a/tests/Neo.UnitTests/TestUtils.cs b/tests/Neo.UnitTests/TestUtils.cs index 55492d882c..c1694347a7 100644 --- a/tests/Neo.UnitTests/TestUtils.cs +++ b/tests/Neo.UnitTests/TestUtils.cs @@ -24,6 +24,7 @@ using Neo.Wallets; using Neo.Wallets.NEP6; using System; +using System.Collections.Generic; using System.Linq; using System.Numerics; @@ -136,15 +137,14 @@ public static Transaction CreateValidTx(DataCache snapshot, NEP6Wallet wallet, W public static Transaction CreateValidTx(DataCache snapshot, NEP6Wallet wallet, UInt160 account, uint nonce) { - var tx = wallet.MakeTransaction(snapshot, new TransferOutput[] - { - new TransferOutput() + var tx = wallet.MakeTransaction(snapshot, [ + new TransferOutput { AssetId = NativeContract.GAS.Hash, ScriptHash = account, - Value = new BigDecimal(BigInteger.One,8) + Value = new BigDecimal(BigInteger.One, 8) } - }, + ], account); tx.Nonce = nonce; @@ -159,6 +159,28 @@ public static Transaction CreateValidTx(DataCache snapshot, NEP6Wallet wallet, U return tx; } + public static Transaction CreateValidTx(DataCache snapshot, NEP6Wallet wallet, UInt160 account, uint nonce, UInt256[] conflicts) + { + var tx = wallet.MakeTransaction(snapshot, [ + new TransferOutput + { + AssetId = NativeContract.GAS.Hash, + ScriptHash = account, + Value = new BigDecimal(BigInteger.One, 8) + } + ], + account); + tx.Attributes = conflicts.Select(conflict => new Conflicts { Hash = conflict }).ToArray(); + tx.Nonce = nonce; + + var data = new ContractParametersContext(snapshot, tx, TestProtocolSettings.Default.Network); + Assert.IsNull(data.GetSignatures(tx.Sender)); + Assert.IsTrue(wallet.Sign(data)); + Assert.IsTrue(data.Completed); + Assert.AreEqual(1, data.GetSignatures(tx.Sender).Count); + tx.Witnesses = data.GetWitnesses(); + return tx; + } public static Transaction GetTransaction(UInt160 sender) { @@ -266,6 +288,15 @@ public static Transaction CreateRandomHashTransaction() }; } + public static void FillMemoryPool(DataCache snapshot, NeoSystem system, NEP6Wallet wallet, WalletAccount account) + { + for (int i = 0; i < system.Settings.MemoryPoolMaxTransactions; i++) + { + var tx = CreateValidTx(snapshot, wallet, account); + system.MemPool.TryAdd(tx, snapshot); + } + } + public static T CopyMsgBySerialization(T serializableObj, T newObj) where T : ISerializable { MemoryReader reader = new(serializableObj.ToArray()); From 06e087fb80bbfeaa494e9ddd2efe2b2bd75ade0b Mon Sep 17 00:00:00 2001 From: Shargon Date: Fri, 12 Jul 2024 08:09:39 +0200 Subject: [PATCH 43/71] Fix release compilation (#3417) * Fix release * typo --- src/Neo/Ledger/MemoryPool.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Neo/Ledger/MemoryPool.cs b/src/Neo/Ledger/MemoryPool.cs index 2e1adb1a47..ff9c6b1069 100644 --- a/src/Neo/Ledger/MemoryPool.cs +++ b/src/Neo/Ledger/MemoryPool.cs @@ -660,9 +660,8 @@ internal bool ReVerifyTopUnverifiedTransactionsIfNeeded(int maxToVerify, DataCac return _unverifiedTransactions.Count > 0; } -#if DEBUG // This method is only for test purpose - // Do not remove it from the DEBUG build + // Do not use this method outside of unit tests internal void Clear() { _txRwLock.EnterReadLock(); @@ -679,6 +678,5 @@ internal void Clear() _txRwLock.ExitReadLock(); } } -#endif } } From 53eaa396e2a6c1542b5e7f08086a28c04e18477b Mon Sep 17 00:00:00 2001 From: Christopher Schuchardt Date: Fri, 12 Jul 2024 02:39:38 -0400 Subject: [PATCH 44/71] Fixed Publish Step (#3411) Co-authored-by: NGD Admin <154295625+NGDAdmin@users.noreply.github.com> --- .github/workflows/main.yml | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 754b879b0e..71602a6df2 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -124,19 +124,13 @@ jobs: - name: Set Version run: git rev-list --count HEAD | xargs printf 'CI%05d' | xargs -I{} echo 'VERSION_SUFFIX={}' >> $GITHUB_ENV - - name : Pack (Neo) + - name : Pack (Everything) run: | dotnet pack \ --configuration Release \ --output ./out \ --version-suffix ${{ env.VERSION_SUFFIX }} - - name: Remove Unwanted Files - working-directory: ./out - run: | - rm -v Neo.CLI* - rm -v Neo.GUI* - - name: Publish to Github Packages working-directory: ./out run: | From bf508238bca58a8d4d45ad9c10fe704e74c55c1a Mon Sep 17 00:00:00 2001 From: Jimmy Date: Mon, 15 Jul 2024 10:25:25 +0800 Subject: [PATCH 45/71] [Neo Core MemoryStore] MemoryStore Unit Tests. (#3404) * test * fix snapshot issue and add tests * fix test * apply old snapshot * memory snapshot tests * memory test * add more tests * make it more clear * revert storetest --------- Co-authored-by: Christopher Schuchardt Co-authored-by: NGD Admin <154295625+NGDAdmin@users.noreply.github.com> Co-authored-by: Shargon --- .../Persistence/UT_MemoryClonedCache.cs | 127 +++++++++++++++++ .../Persistence/UT_MemorySnapshot.cs | 121 ++++++++++++++++ .../Persistence/UT_MemorySnapshotCache.cs | 134 ++++++++++++++++++ 3 files changed, 382 insertions(+) create mode 100644 tests/Neo.UnitTests/Persistence/UT_MemoryClonedCache.cs create mode 100644 tests/Neo.UnitTests/Persistence/UT_MemorySnapshot.cs create mode 100644 tests/Neo.UnitTests/Persistence/UT_MemorySnapshotCache.cs diff --git a/tests/Neo.UnitTests/Persistence/UT_MemoryClonedCache.cs b/tests/Neo.UnitTests/Persistence/UT_MemoryClonedCache.cs new file mode 100644 index 0000000000..56afdc31f1 --- /dev/null +++ b/tests/Neo.UnitTests/Persistence/UT_MemoryClonedCache.cs @@ -0,0 +1,127 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_MemoryClonedCache.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Persistence; +using Neo.SmartContract; + +namespace Neo.UnitTests.Persistence; + +/// +/// When adding data to `datacache` , +/// it gets passed to `snapshotcache` during commit. +/// If `snapshotcache` commits, the data is then passed +/// to the underlying store . +/// However, because snapshots are immutable, the new data +/// cannot be retrieved from the snapshot . +/// +/// When deleting data from `datacache` , +/// it won't exist in `datacache` upon commit, and therefore will be removed from `snapshotcache` . +/// Upon `snapshotcache` commit, the data is deleted from the store . +/// However, since the snapshot remains unchanged, the data still exists in the snapshot. +/// If you attempt to read this data from `datacache` or `snapshotcache` , +/// which do not have the data, they will retrieve it from the snapshot instead of the store. +/// Thus, they can still access data that has been deleted. +/// +[TestClass] +public class UT_MemoryClonedCache +{ + private MemoryStore _memoryStore; + private MemorySnapshot _snapshot; + private SnapshotCache _snapshotCache; + private DataCache _dataCache; + + [TestInitialize] + public void Setup() + { + _memoryStore = new MemoryStore(); + _snapshot = _memoryStore.GetSnapshot() as MemorySnapshot; + _snapshotCache = new SnapshotCache(_snapshot); + _dataCache = _snapshotCache.CreateSnapshot(); + } + + [TestCleanup] + public void CleanUp() + { + _dataCache.Commit(); + _snapshotCache.Commit(); + _memoryStore.Reset(); + } + + [TestMethod] + public void SingleSnapshotCacheTest() + { + var key1 = new KeyBuilder(0, 1); + var value1 = new StorageItem([0x03, 0x04]); + + Assert.IsFalse(_dataCache.Contains(key1)); + _dataCache.Add(key1, value1); + + Assert.IsTrue(_dataCache.Contains(key1)); + Assert.IsFalse(_snapshotCache.Contains(key1)); + Assert.IsFalse(_snapshot.Contains(key1.ToArray())); + Assert.IsFalse(_memoryStore.Contains(key1.ToArray())); + + // After the data cache is committed, it should be dropped + // so its value after the commit is meaningless and should not be used. + _dataCache.Commit(); + + Assert.IsTrue(_dataCache.Contains(key1)); + Assert.IsTrue(_snapshotCache.Contains(key1)); + Assert.IsFalse(_snapshot.Contains(key1.ToArray())); + Assert.IsFalse(_memoryStore.Contains(key1.ToArray())); + + // After the snapshot is committed, it should be dropped + // so its value after the commit is meaningless and should not be used. + _snapshotCache.Commit(); + + Assert.IsTrue(_dataCache.Contains(key1)); + Assert.IsTrue(_snapshotCache.Contains(key1)); + Assert.IsFalse(_snapshot.Contains(key1.ToArray())); + Assert.IsTrue(_memoryStore.Contains(key1.ToArray())); + + // Test delete + + // Reset the snapshot to make it accessible to the new value. + _snapshot = _memoryStore.GetSnapshot() as MemorySnapshot; + _snapshotCache = new SnapshotCache(_snapshot); + _dataCache = _snapshotCache.CreateSnapshot(); + + Assert.IsTrue(_dataCache.Contains(key1)); + _dataCache.Delete(key1); + + Assert.IsFalse(_dataCache.Contains(key1)); + Assert.IsTrue(_snapshotCache.Contains(key1)); + Assert.IsTrue(_snapshot.Contains(key1.ToArray())); + Assert.IsTrue(_memoryStore.Contains(key1.ToArray())); + + // After the data cache is committed, it should be dropped + // so its value after the commit is meaningless and should not be used. + _dataCache.Commit(); + + Assert.IsFalse(_dataCache.Contains(key1)); + Assert.IsFalse(_snapshotCache.Contains(key1)); + Assert.IsTrue(_snapshot.Contains(key1.ToArray())); + Assert.IsTrue(_memoryStore.Contains(key1.ToArray())); + + + // After the snapshot cache is committed, it should be dropped + // so its value after the commit is meaningless and should not be used. + _snapshotCache.Commit(); + + // The reason that datacache, snapshotcache still contains key1 is because + // they can not find the value from its cache, so they fetch it from the snapshot of the store. + Assert.IsTrue(_dataCache.Contains(key1)); + Assert.IsTrue(_snapshotCache.Contains(key1)); + Assert.IsTrue(_snapshot.Contains(key1.ToArray())); + Assert.IsFalse(_memoryStore.Contains(key1.ToArray())); + } +} diff --git a/tests/Neo.UnitTests/Persistence/UT_MemorySnapshot.cs b/tests/Neo.UnitTests/Persistence/UT_MemorySnapshot.cs new file mode 100644 index 0000000000..629e2bc374 --- /dev/null +++ b/tests/Neo.UnitTests/Persistence/UT_MemorySnapshot.cs @@ -0,0 +1,121 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_MemorySnapshot.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Persistence; +using System.Linq; + +namespace Neo.UnitTests.Persistence; + +[TestClass] +public class UT_MemorySnapshot +{ + private MemoryStore _memoryStore; + private MemorySnapshot _snapshot; + + [TestInitialize] + public void Setup() + { + _memoryStore = new MemoryStore(); + _snapshot = _memoryStore.GetSnapshot() as MemorySnapshot; + } + + [TestCleanup] + public void CleanUp() + { + _memoryStore.Reset(); + } + + [TestMethod] + public void SingleSnapshotTest() + { + var key1 = new byte[] { 0x01, 0x02 }; + var value1 = new byte[] { 0x03, 0x04 }; + + _snapshot.Delete(key1); + Assert.IsNull(_snapshot.TryGet(key1)); + + // Both Store and Snapshot can not get the value that are cached in the snapshot + _snapshot.Put(key1, value1); + Assert.IsNull(_snapshot.TryGet(key1)); + Assert.IsNull(_memoryStore.TryGet(key1)); + + _snapshot.Commit(); + + // After commit the snapshot, the value can be get from the store but still can not get from the snapshot + CollectionAssert.AreEqual(value1, _memoryStore.TryGet(key1)); + Assert.IsNull(_snapshot.TryGet(key1)); + + _snapshot.Delete(key1); + + // Deleted value can not be found from the snapshot but can still get from the store + // This is because snapshot has no key1 at all. + Assert.IsFalse(_snapshot.Contains(key1)); + Assert.IsTrue(_memoryStore.Contains(key1)); + + _snapshot.Commit(); + + // After commit the snapshot, the value can not be found from the store + Assert.IsFalse(_memoryStore.Contains(key1)); + + // Test seek in order + _snapshot.Put([0x00, 0x00, 0x04], [0x04]); + _snapshot.Put([0x00, 0x00, 0x00], [0x00]); + _snapshot.Put([0x00, 0x00, 0x01], [0x01]); + _snapshot.Put([0x00, 0x00, 0x02], [0x02]); + _snapshot.Put([0x00, 0x00, 0x03], [0x03]); + + // Can not get anything from the snapshot + var entries = _snapshot.Seek([0x00, 0x00, 0x02]).ToArray(); + Assert.AreEqual(0, entries.Length); + } + + [TestMethod] + public void MultiSnapshotTest() + { + var key1 = new byte[] { 0x01, 0x02 }; + var value1 = new byte[] { 0x03, 0x04 }; + + _snapshot.Delete(key1); + Assert.IsNull(_snapshot.TryGet(key1)); + + // Both Store and Snapshot can not get the value that are cached in the snapshot + _snapshot.Put(key1, value1); + // After commit the snapshot, the value can be get from the store but still can not get from the snapshot + // But can get the value from a new snapshot + _snapshot.Commit(); + var snapshot2 = _memoryStore.GetSnapshot(); + CollectionAssert.AreEqual(value1, _memoryStore.TryGet(key1)); + Assert.IsNull(_snapshot.TryGet(key1)); + CollectionAssert.AreEqual(value1, snapshot2.TryGet(key1)); + + _snapshot.Delete(key1); + + // Deleted value can not being found from the snapshot but can still get from the store and snapshot2 + Assert.IsFalse(_snapshot.Contains(key1)); + Assert.IsTrue(_memoryStore.Contains(key1)); + Assert.IsTrue(snapshot2.Contains(key1)); + + _snapshot.Commit(); + + // After commit the snapshot, the value can not be found from the store, but can be found in snapshots + // Cause snapshot1 or store can not change the status of snapshot2. + Assert.IsFalse(_memoryStore.Contains(key1)); + Assert.IsTrue(snapshot2.Contains(key1)); + Assert.IsFalse(_snapshot.Contains(key1)); + + // Add value via snapshot2 will not affect snapshot1 at all + snapshot2.Put(key1, value1); + snapshot2.Commit(); + Assert.IsNull(_snapshot.TryGet(key1)); + CollectionAssert.AreEqual(value1, snapshot2.TryGet(key1)); + } +} diff --git a/tests/Neo.UnitTests/Persistence/UT_MemorySnapshotCache.cs b/tests/Neo.UnitTests/Persistence/UT_MemorySnapshotCache.cs new file mode 100644 index 0000000000..8c4843c3f3 --- /dev/null +++ b/tests/Neo.UnitTests/Persistence/UT_MemorySnapshotCache.cs @@ -0,0 +1,134 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_MemorySnapshotCache.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Persistence; +using Neo.SmartContract; +using System.Linq; + +namespace Neo.UnitTests.Persistence; + +[TestClass] +public class UT_MemorySnapshotCache +{ + private MemoryStore _memoryStore; + private MemorySnapshot _snapshot; + private SnapshotCache _snapshotCache; + + [TestInitialize] + public void Setup() + { + _memoryStore = new MemoryStore(); + _snapshot = _memoryStore.GetSnapshot() as MemorySnapshot; + _snapshotCache = new SnapshotCache(_snapshot); + } + + [TestCleanup] + public void CleanUp() + { + _snapshotCache.Commit(); + _memoryStore.Reset(); + } + + [TestMethod] + public void SingleSnapshotCacheTest() + { + var key1 = new KeyBuilder(0, 1); + var value1 = new StorageItem([0x03, 0x04]); + + _snapshotCache.Delete(key1); + Assert.IsNull(_snapshotCache.TryGet(key1)); + + // Adding value to the snapshot cache will not affect the snapshot or the store + // But the snapshot cache itself can see the added item right after it is added. + _snapshotCache.Add(key1, value1); + + Assert.AreEqual(value1.Value, _snapshotCache.TryGet(key1).Value); + Assert.IsNull(_snapshot.TryGet(key1.ToArray())); + Assert.IsNull(_memoryStore.TryGet(key1.ToArray())); + + // After commit the snapshot cache, it works the same as commit the snapshot. + // the value can be get from the snapshot cache and store but still can not get from the snapshot + _snapshotCache.Commit(); + + Assert.AreEqual(value1.Value, _snapshotCache.TryGet(key1).Value); + Assert.IsFalse(_snapshot.Contains(key1.ToArray())); + Assert.IsTrue(_memoryStore.Contains(key1.ToArray())); + + // Test delete + + // Reset the snapshot to make it accessible to the new value. + _snapshot = _memoryStore.GetSnapshot() as MemorySnapshot; + _snapshotCache = new SnapshotCache(_snapshot); + + // Delete value to the snapshot cache will not affect the snapshot or the store + // But the snapshot cache itself can not see the added item. + _snapshotCache.Delete(key1); + + // Value is removed from the snapshot cache immediately + Assert.IsNull(_snapshotCache.TryGet(key1)); + // But the underline snapshot will not be changed. + Assert.IsTrue(_snapshot.Contains(key1.ToArray())); + // And the store is also not affected. + Assert.IsNotNull(_memoryStore.TryGet(key1.ToArray())); + + // commit the snapshot cache + _snapshotCache.Commit(); + + // Value is removed from both the store, but the snapshot and snapshot cache remains the same. + Assert.IsTrue(_snapshotCache.Contains(key1)); + Assert.IsTrue(_snapshot.Contains(key1.ToArray())); + Assert.IsFalse(_memoryStore.Contains(key1.ToArray())); + } + + [TestMethod] + public void MultiSnapshotCacheTest() + { + var key1 = new KeyBuilder(0, 1); + var value1 = new StorageItem([0x03, 0x04]); + + _snapshotCache.Delete(key1); + Assert.IsNull(_snapshotCache.TryGet(key1)); + + // Adding value to the snapshot cache will not affect the snapshot or the store + // But the snapshot cache itself can see the added item. + _snapshotCache.Add(key1, value1); + + // After commit the snapshot cache, it works the same as commit the snapshot. + // the value can be get from the snapshot cache but still can not get from the snapshot + _snapshotCache.Commit(); + + // Get a new snapshot cache to test if the value can be seen from the new snapshot cache + var snapshotCache2 = new SnapshotCache(_snapshot); + Assert.IsNull(snapshotCache2.TryGet(key1)); + Assert.IsFalse(_snapshot.Contains(key1.ToArray())); + + // Test delete + + // Reset the snapshot to make it accessible to the new value. + _snapshot = _memoryStore.GetSnapshot() as MemorySnapshot; + _snapshotCache = new SnapshotCache(_snapshot); + + // Delete value to the snapshot cache will affect the snapshot + // But the snapshot and store itself can still see the item. + _snapshotCache.Delete(key1); + + // Commiting the snapshot cache will change the store, but the existing snapshot remains same. + _snapshotCache.Commit(); + + // reset the snapshotcache2 to snapshot + snapshotCache2 = new SnapshotCache(_snapshot); + // Value is removed from the store, but the snapshot remains the same. + // thus the snapshot cache from the snapshot will remain the same. + Assert.IsNotNull(snapshotCache2.TryGet(key1)); + Assert.IsNull(_memoryStore.TryGet(key1.ToArray())); + } +} From 6c29bde583d2ba210bb9971359b7e5458fc37d4b Mon Sep 17 00:00:00 2001 From: Jimmy Date: Tue, 16 Jul 2024 10:33:02 +0800 Subject: [PATCH 46/71] [Neo Core Storage] Implicit methods and tests (#3403) * implicit methods and tests * udpate --------- Co-authored-by: Shargon --- src/Neo/SmartContract/StorageItem.cs | 10 +++ src/Neo/SmartContract/StorageKey.cs | 10 +++ .../Neo.UnitTests/SmartContract/UT_Storage.cs | 74 +++++++++++++++++++ 3 files changed, 94 insertions(+) create mode 100644 tests/Neo.UnitTests/SmartContract/UT_Storage.cs diff --git a/src/Neo/SmartContract/StorageItem.cs b/src/Neo/SmartContract/StorageItem.cs index 133a8fa1dd..84d3cc6354 100644 --- a/src/Neo/SmartContract/StorageItem.cs +++ b/src/Neo/SmartContract/StorageItem.cs @@ -193,5 +193,15 @@ public static implicit operator BigInteger(StorageItem item) item.cache ??= new BigInteger(item.value.Span); return (BigInteger)item.cache; } + + public static implicit operator StorageItem(BigInteger value) + { + return new StorageItem(value); + } + + public static implicit operator StorageItem(byte[] value) + { + return new StorageItem(value); + } } } diff --git a/src/Neo/SmartContract/StorageKey.cs b/src/Neo/SmartContract/StorageKey.cs index a0136e4456..9c5e37827f 100644 --- a/src/Neo/SmartContract/StorageKey.cs +++ b/src/Neo/SmartContract/StorageKey.cs @@ -12,6 +12,7 @@ using Neo.Cryptography; using System; using System.Buffers.Binary; +using System.Runtime.CompilerServices; namespace Neo.SmartContract { @@ -79,5 +80,14 @@ public byte[] ToArray() } return cache; } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator StorageKey(byte[] value) => new StorageKey(value); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator StorageKey(ReadOnlyMemory value) => new StorageKey(value.Span.ToArray()); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator StorageKey(ReadOnlySpan value) => new StorageKey(value.ToArray()); } } diff --git a/tests/Neo.UnitTests/SmartContract/UT_Storage.cs b/tests/Neo.UnitTests/SmartContract/UT_Storage.cs new file mode 100644 index 0000000000..b52ea3046b --- /dev/null +++ b/tests/Neo.UnitTests/SmartContract/UT_Storage.cs @@ -0,0 +1,74 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_Storage.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.SmartContract; +using Neo.VM; +using Neo.VM.Types; +using System; +using System.Linq; +using System.Numerics; + +namespace Neo.UnitTests.SmartContract +{ + [TestClass] + public class UT_Storage + { + [TestMethod] + public void TestStorageKey() + { + // Test data + byte[] keyData = [0x00, 0x00, 0x00, 0x00, 0x12]; + var keyMemory = new ReadOnlyMemory(keyData); + + // Test implicit conversion from byte[] to StorageKey + StorageKey storageKeyFromArray = keyData; + Assert.AreEqual(0, storageKeyFromArray.Id); + Assert.IsTrue(keyMemory.Span.ToArray().Skip(sizeof(int)).SequenceEqual(storageKeyFromArray.Key.Span.ToArray())); + + // Test implicit conversion from ReadOnlyMemory to StorageKey + StorageKey storageKeyFromMemory = keyMemory; + Assert.AreEqual(0, storageKeyFromMemory.Id); + Assert.IsTrue(keyMemory.Span.ToArray().Skip(sizeof(int)).SequenceEqual(storageKeyFromMemory.Key.Span.ToArray())); + + // Test CreateSearchPrefix method + byte[] prefix = { 0xAA }; + var searchPrefix = StorageKey.CreateSearchPrefix(0, prefix); + var expectedPrefix = BitConverter.GetBytes(0).Concat(prefix).ToArray(); + Assert.IsTrue(expectedPrefix.SequenceEqual(searchPrefix)); + + // Test Equals method + var storageKey1 = new StorageKey { Id = 0, Key = keyMemory }; + var storageKey2 = new StorageKey { Id = 0, Key = keyMemory }; + var storageKeyDifferentId = new StorageKey { Id = 0 + 1, Key = keyMemory }; + var storageKeyDifferentKey = new StorageKey { Id = 0, Key = new ReadOnlyMemory([0x04]) }; + Assert.AreEqual(storageKey1, storageKey2); + Assert.AreNotEqual(storageKey1, storageKeyDifferentId); + Assert.AreNotEqual(storageKey1, storageKeyDifferentKey); + } + + [TestMethod] + public void TestStorageItem() + { + // Test data + byte[] keyData = [0x00, 0x00, 0x00, 0x00, 0x12]; + BigInteger bigInteger = new BigInteger(1234567890); + + // Test implicit conversion from byte[] to StorageItem + StorageItem storageItemFromArray = keyData; + Assert.IsTrue(keyData.SequenceEqual(storageItemFromArray.Value.Span.ToArray())); + + // Test implicit conversion from BigInteger to StorageItem + StorageItem storageItemFromBigInteger = bigInteger; + Assert.AreEqual(bigInteger, (BigInteger)storageItemFromBigInteger); + } + } +} From 096f4727a52a732e9400114a4874ca44fc071ffd Mon Sep 17 00:00:00 2001 From: Jimmy Date: Tue, 16 Jul 2024 11:15:44 +0800 Subject: [PATCH 47/71] [Neo Core Store] Rename various snapshots. (#3406) * rename snapshot * Remove warning --------- Co-authored-by: Shargon Co-authored-by: NGD Admin <154295625+NGDAdmin@users.noreply.github.com> --- benchmarks/Neo.Benchmarks/Benchmarks.cs | 2 +- src/Neo.GUI/GUI/MainForm.cs | 2 +- src/Neo/Ledger/Blockchain.cs | 6 +-- src/Neo/NeoSystem.cs | 14 +++++- src/Neo/Persistence/DataCache.cs | 10 ++++ src/Neo/SmartContract/ApplicationEngine.cs | 2 +- src/Neo/SmartContract/Helper.cs | 2 +- src/Neo/Wallets/Helper.cs | 2 +- src/Neo/Wallets/Wallet.cs | 2 +- .../DBFTPlugin/Consensus/ConsensusContext.cs | 2 +- src/Plugins/OracleService/OracleService.cs | 2 +- src/Plugins/RpcServer/RpcServer.Blockchain.cs | 10 ++-- src/Plugins/RpcServer/RpcServer.Wallet.cs | 10 ++-- src/Plugins/RpcServer/Session.cs | 2 +- .../TestBlockchain.cs | 2 +- .../TestBlockchain.cs | 50 +++++++++++++++++++ .../UT_RpcServer.Blockchain.cs | 44 ++++++++-------- .../UT_RpcServer.cs | 4 +- .../Neo.UnitTests/IO/Caching/UT_CloneCache.cs | 2 +- .../Neo.UnitTests/IO/Caching/UT_DataCache.cs | 2 +- tests/Neo.UnitTests/Ledger/UT_Blockchain.cs | 4 +- tests/Neo.UnitTests/Ledger/UT_MemoryPool.cs | 2 +- .../Persistence/UT_MemoryStore.cs | 4 +- .../SmartContract/Native/UT_GasToken.cs | 2 +- .../SmartContract/Native/UT_NativeContract.cs | 4 +- .../SmartContract/Native/UT_NeoToken.cs | 46 ++++++++--------- .../SmartContract/Native/UT_PolicyContract.cs | 14 +++--- .../SmartContract/Native/UT_RoleManagement.cs | 4 +- .../SmartContract/UT_SmartContractHelper.cs | 2 +- tests/Neo.UnitTests/TestBlockchain.cs | 2 +- tests/Neo.UnitTests/UT_DataCache.cs | 6 +-- 31 files changed, 167 insertions(+), 95 deletions(-) create mode 100644 tests/Neo.Plugins.RpcServer.Tests/TestBlockchain.cs diff --git a/benchmarks/Neo.Benchmarks/Benchmarks.cs b/benchmarks/Neo.Benchmarks/Benchmarks.cs index 081f806622..52eec04d44 100644 --- a/benchmarks/Neo.Benchmarks/Benchmarks.cs +++ b/benchmarks/Neo.Benchmarks/Benchmarks.cs @@ -67,7 +67,7 @@ private static void Run(string name, string poc) Script = Convert.FromBase64String(poc), Witnesses = Array.Empty() }; - using var snapshot = system.GetSnapshot(); + using var snapshot = system.GetSnapshotCache(); using var engine = ApplicationEngine.Create(TriggerType.Application, tx, snapshot, system.GenesisBlock, protocol, tx.SystemFee); engine.LoadScript(tx.Script); Stopwatch stopwatch = Stopwatch.StartNew(); diff --git a/src/Neo.GUI/GUI/MainForm.cs b/src/Neo.GUI/GUI/MainForm.cs index 3114e542b6..fc1a3e8d99 100644 --- a/src/Neo.GUI/GUI/MainForm.cs +++ b/src/Neo.GUI/GUI/MainForm.cs @@ -201,7 +201,7 @@ private void timer1_Tick(object sender, EventArgs e) check_nep5_balance = false; UInt160[] addresses = Service.CurrentWallet.GetAccounts().Select(p => p.ScriptHash).ToArray(); if (addresses.Length == 0) return; - using var snapshot = Service.NeoSystem.GetSnapshot(); + using var snapshot = Service.NeoSystem.GetSnapshotCache(); foreach (UInt160 assetId in NEP5Watched) { byte[] script; diff --git a/src/Neo/Ledger/Blockchain.cs b/src/Neo/Ledger/Blockchain.cs index b35dd069e3..e9e3cb0020 100644 --- a/src/Neo/Ledger/Blockchain.cs +++ b/src/Neo/Ledger/Blockchain.cs @@ -421,7 +421,7 @@ private void OnTransaction(Transaction tx) private void Persist(Block block) { - using (SnapshotCache snapshot = system.GetSnapshot()) + using (SnapshotCache snapshot = system.GetSnapshotCache()) { List all_application_executed = new(); TransactionState[] transactionStates; @@ -439,7 +439,7 @@ private void Persist(Block block) all_application_executed.Add(application_executed); transactionStates = engine.GetState(); } - DataCache clonedSnapshot = snapshot.CreateSnapshot(); + DataCache clonedSnapshot = snapshot.CloneCache(); // Warning: Do not write into variable snapshot directly. Write into variable clonedSnapshot and commit instead. foreach (TransactionState transactionState in transactionStates) { @@ -453,7 +453,7 @@ private void Persist(Block block) } else { - clonedSnapshot = snapshot.CreateSnapshot(); + clonedSnapshot = snapshot.CloneCache(); } ApplicationExecuted application_executed = new(engine); Context.System.EventStream.Publish(application_executed); diff --git a/src/Neo/NeoSystem.cs b/src/Neo/NeoSystem.cs index b752f16712..3121432db5 100644 --- a/src/Neo/NeoSystem.cs +++ b/src/Neo/NeoSystem.cs @@ -275,12 +275,24 @@ public void SuspendNodeStartup() /// /// Gets a snapshot of the blockchain storage. /// - /// + /// An instance of + [Obsolete("This method is obsolete, use GetSnapshotCache instead.")] public SnapshotCache GetSnapshot() { return new SnapshotCache(store.GetSnapshot()); } + /// + /// Gets a snapshot of the blockchain storage with an execution cache. + /// With the snapshot, we have the latest state of the blockchain, with the cache, + /// we can run transactions in a sandboxed environment. + /// + /// An instance of + public SnapshotCache GetSnapshotCache() + { + return new SnapshotCache(store.GetSnapshot()); + } + /// /// Determines whether the specified transaction exists in the memory pool or storage. /// diff --git a/src/Neo/Persistence/DataCache.cs b/src/Neo/Persistence/DataCache.cs index 86fbd69961..29c610c6c8 100644 --- a/src/Neo/Persistence/DataCache.cs +++ b/src/Neo/Persistence/DataCache.cs @@ -152,11 +152,21 @@ public virtual void Commit() /// Creates a snapshot, which uses this instance as the underlying storage. /// /// The snapshot of this instance. + [Obsolete("CreateSnapshot is deprecated, please use CloneCache instead.")] public DataCache CreateSnapshot() { return new ClonedCache(this); } + /// + /// Creates a clone of the snapshot cache, which uses this instance as the underlying storage. + /// + /// The of this instance. + public DataCache CloneCache() + { + return new ClonedCache(this); + } + /// /// Deletes an entry from the cache. /// diff --git a/src/Neo/SmartContract/ApplicationEngine.cs b/src/Neo/SmartContract/ApplicationEngine.cs index fab17a2bb1..6fd69439ab 100644 --- a/src/Neo/SmartContract/ApplicationEngine.cs +++ b/src/Neo/SmartContract/ApplicationEngine.cs @@ -460,7 +460,7 @@ public ExecutionContext LoadScript(Script script, int rvcount = -1, int initialP // Create and configure context ExecutionContext context = CreateContext(script, rvcount, initialPosition); ExecutionContextState state = context.GetState(); - state.Snapshot = Snapshot?.CreateSnapshot(); + state.Snapshot = Snapshot?.CloneCache(); configureState?.Invoke(state); // Load context diff --git a/src/Neo/SmartContract/Helper.cs b/src/Neo/SmartContract/Helper.cs index ae31d66a50..d0bc3c939b 100644 --- a/src/Neo/SmartContract/Helper.cs +++ b/src/Neo/SmartContract/Helper.cs @@ -326,7 +326,7 @@ internal static bool VerifyWitness(this IVerifiable verifiable, ProtocolSettings { return false; } - using (ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Verification, verifiable, snapshot?.CreateSnapshot(), null, settings, datoshi)) + using (ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Verification, verifiable, snapshot?.CloneCache(), null, settings, datoshi)) { if (witness.VerificationScript.Length == 0) { diff --git a/src/Neo/Wallets/Helper.cs b/src/Neo/Wallets/Helper.cs index 1273bafc50..b8427d078d 100644 --- a/src/Neo/Wallets/Helper.cs +++ b/src/Neo/Wallets/Helper.cs @@ -133,7 +133,7 @@ public static long CalculateNetworkFee(this Transaction tx, DataCache snapshot, size += Array.Empty().GetVarSize() + invSize; // Check verify cost - using ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Verification, tx, snapshot.CreateSnapshot(), settings: settings, gas: maxExecutionCost); + using ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Verification, tx, snapshot.CloneCache(), settings: settings, gas: maxExecutionCost); engine.LoadContract(contract, md, CallFlags.ReadOnly); if (invocationScript != null) engine.LoadScript(invocationScript, configureState: p => p.CallFlags = CallFlags.None); if (engine.Execute() == VMState.FAULT) throw new ArgumentException($"Smart contract {contract.Hash} verification fault."); diff --git a/src/Neo/Wallets/Wallet.cs b/src/Neo/Wallets/Wallet.cs index aca30b008f..dabe6049c6 100644 --- a/src/Neo/Wallets/Wallet.cs +++ b/src/Neo/Wallets/Wallet.cs @@ -574,7 +574,7 @@ private Transaction MakeTransaction(DataCache snapshot, ReadOnlyMemory scr }; // will try to execute 'transfer' script to check if it works - using (ApplicationEngine engine = ApplicationEngine.Run(script, snapshot.CreateSnapshot(), tx, settings: ProtocolSettings, gas: maxGas, persistingBlock: persistingBlock)) + using (ApplicationEngine engine = ApplicationEngine.Run(script, snapshot.CloneCache(), tx, settings: ProtocolSettings, gas: maxGas, persistingBlock: persistingBlock)) { if (engine.State == VMState.FAULT) { diff --git a/src/Plugins/DBFTPlugin/Consensus/ConsensusContext.cs b/src/Plugins/DBFTPlugin/Consensus/ConsensusContext.cs index abd0309783..2e6a3a19a6 100644 --- a/src/Plugins/DBFTPlugin/Consensus/ConsensusContext.cs +++ b/src/Plugins/DBFTPlugin/Consensus/ConsensusContext.cs @@ -192,7 +192,7 @@ public void Reset(byte viewNumber) if (viewNumber == 0) { Snapshot?.Dispose(); - Snapshot = neoSystem.GetSnapshot(); + Snapshot = neoSystem.GetSnapshotCache(); uint height = NativeContract.Ledger.CurrentIndex(Snapshot); Block = new Block { diff --git a/src/Plugins/OracleService/OracleService.cs b/src/Plugins/OracleService/OracleService.cs index 6f291e763d..bb5da83654 100644 --- a/src/Plugins/OracleService/OracleService.cs +++ b/src/Plugins/OracleService/OracleService.cs @@ -431,7 +431,7 @@ public static Transaction CreateResponseTx(DataCache snapshot, OracleRequest req // Calculate network fee var oracleContract = NativeContract.ContractManagement.GetContract(snapshot, NativeContract.Oracle.Hash); - var engine = ApplicationEngine.Create(TriggerType.Verification, tx, snapshot.CreateSnapshot(), settings: settings); + var engine = ApplicationEngine.Create(TriggerType.Verification, tx, snapshot.CloneCache(), settings: settings); ContractMethodDescriptor md = oracleContract.Manifest.Abi.GetMethod(ContractBasicMethod.Verify, ContractBasicMethod.VerifyPCount); engine.LoadContract(oracleContract, md, CallFlags.None); if (engine.Execute() != VMState.HALT) return null; diff --git a/src/Plugins/RpcServer/RpcServer.Blockchain.cs b/src/Plugins/RpcServer/RpcServer.Blockchain.cs index 4abddbc183..7bc4711f1c 100644 --- a/src/Plugins/RpcServer/RpcServer.Blockchain.cs +++ b/src/Plugins/RpcServer/RpcServer.Blockchain.cs @@ -49,7 +49,7 @@ protected internal virtual JToken GetBlock(JArray _params) { JToken key = Result.Ok_Or(() => _params[0], RpcError.InvalidParams.WithData($"Invalid Block Hash or Index: {_params[0]}")); bool verbose = _params.Count >= 2 && _params[1].AsBoolean(); - using var snapshot = system.GetSnapshot(); + using var snapshot = system.GetSnapshotCache(); Block block; if (key is JNumber) { @@ -245,7 +245,7 @@ protected internal virtual JToken GetRawTransaction(JArray _params) [RpcMethod] protected internal virtual JToken GetStorage(JArray _params) { - using var snapshot = system.GetSnapshot(); + using var snapshot = system.GetSnapshotCache(); if (!int.TryParse(_params[0].AsString(), out int id)) { UInt160 hash = Result.Ok_Or(() => UInt160.Parse(_params[0].AsString()), RpcError.InvalidParams.WithData($"Invalid contract hash {_params[0]}")); @@ -273,7 +273,7 @@ protected internal virtual JToken GetStorage(JArray _params) [RpcMethod] protected internal virtual JToken FindStorage(JArray _params) { - using var snapshot = system.GetSnapshot(); + using var snapshot = system.GetSnapshotCache(); if (!int.TryParse(_params[0].AsString(), out int id)) { UInt160 hash = Result.Ok_Or(() => UInt160.Parse(_params[0].AsString()), RpcError.InvalidParams.WithData($"Invalid contract hash {_params[0]}")); @@ -341,7 +341,7 @@ protected internal virtual JToken GetTransactionHeight(JArray _params) [RpcMethod] protected internal virtual JToken GetNextBlockValidators(JArray _params) { - using var snapshot = system.GetSnapshot(); + using var snapshot = system.GetSnapshotCache(); var validators = NativeContract.NEO.GetNextBlockValidators(snapshot, system.Settings.ValidatorsCount); return validators.Select(p => { @@ -360,7 +360,7 @@ protected internal virtual JToken GetNextBlockValidators(JArray _params) [RpcMethod] protected internal virtual JToken GetCandidates(JArray _params) { - using var snapshot = system.GetSnapshot(); + using var snapshot = system.GetSnapshotCache(); byte[] script; using (ScriptBuilder sb = new()) { diff --git a/src/Plugins/RpcServer/RpcServer.Wallet.cs b/src/Plugins/RpcServer/RpcServer.Wallet.cs index 9083f916c6..ab5724e588 100644 --- a/src/Plugins/RpcServer/RpcServer.Wallet.cs +++ b/src/Plugins/RpcServer/RpcServer.Wallet.cs @@ -196,7 +196,7 @@ protected virtual JToken SendFrom(JArray _params) UInt160 assetId = Result.Ok_Or(() => UInt160.Parse(_params[0].AsString()), RpcError.InvalidParams.WithData($"Invalid asset id: {_params[0]}")); UInt160 from = AddressToScriptHash(_params[1].AsString(), system.Settings.AddressVersion); UInt160 to = AddressToScriptHash(_params[2].AsString(), system.Settings.AddressVersion); - using var snapshot = system.GetSnapshot(); + using var snapshot = system.GetSnapshotCache(); AssetDescriptor descriptor = new(snapshot, system.Settings, assetId); BigDecimal amount = new(BigInteger.Parse(_params[3].AsString()), descriptor.Decimals); (amount.Sign > 0).True_Or(RpcErrorFactory.InvalidParams("Amount can't be negative.")); @@ -243,7 +243,7 @@ protected virtual JToken SendMany(JArray _params) Signer[] signers = _params.Count >= to_start + 2 ? ((JArray)_params[to_start + 1]).Select(p => new Signer() { Account = AddressToScriptHash(p.AsString(), system.Settings.AddressVersion), Scopes = WitnessScope.CalledByEntry }).ToArray() : null; TransferOutput[] outputs = new TransferOutput[to.Count]; - using var snapshot = system.GetSnapshot(); + using var snapshot = system.GetSnapshotCache(); for (int i = 0; i < to.Count; i++) { UInt160 asset_id = UInt160.Parse(to[i]["asset"].AsString()); @@ -279,7 +279,7 @@ protected virtual JToken SendToAddress(JArray _params) CheckWallet(); UInt160 assetId = Result.Ok_Or(() => UInt160.Parse(_params[0].AsString()), RpcError.InvalidParams.WithData($"Invalid asset hash: {_params[0]}")); UInt160 to = AddressToScriptHash(_params[1].AsString(), system.Settings.AddressVersion); - using var snapshot = system.GetSnapshot(); + using var snapshot = system.GetSnapshotCache(); AssetDescriptor descriptor = new(snapshot, system.Settings, assetId); BigDecimal amount = new(BigInteger.Parse(_params[2].AsString()), descriptor.Decimals); (amount.Sign > 0).True_Or(RpcError.InvalidParams); @@ -354,7 +354,7 @@ protected virtual JToken InvokeContractVerify(JArray _params) private JObject GetVerificationResult(UInt160 scriptHash, ContractParameter[] args, Signer[] signers = null, Witness[] witnesses = null) { - using var snapshot = system.GetSnapshot(); + using var snapshot = system.GetSnapshotCache(); var contract = NativeContract.ContractManagement.GetContract(snapshot, scriptHash).NotNull_Or(RpcError.UnknownContract); var md = contract.Manifest.Abi.GetMethod(ContractBasicMethod.Verify, ContractBasicMethod.VerifyPCount).NotNull_Or(RpcErrorFactory.InvalidContractVerification(contract.Hash)); (md.ReturnType == ContractParameterType.Boolean).True_Or(RpcErrorFactory.InvalidContractVerification("The verify method doesn't return boolean value.")); @@ -365,7 +365,7 @@ private JObject GetVerificationResult(UInt160 scriptHash, ContractParameter[] ar Witnesses = witnesses, Script = new[] { (byte)OpCode.RET } }; - using ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Verification, tx, snapshot.CreateSnapshot(), settings: system.Settings); + using ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Verification, tx, snapshot.CloneCache(), settings: system.Settings); engine.LoadContract(contract, md, CallFlags.ReadOnly); var invocationScript = Array.Empty(); diff --git a/src/Plugins/RpcServer/Session.cs b/src/Plugins/RpcServer/Session.cs index 1dd8808dde..60be3e19b1 100644 --- a/src/Plugins/RpcServer/Session.cs +++ b/src/Plugins/RpcServer/Session.cs @@ -29,7 +29,7 @@ class Session : IDisposable public Session(NeoSystem system, byte[] script, Signer[] signers, Witness[] witnesses, long datoshi, Diagnostic diagnostic) { Random random = new(); - Snapshot = system.GetSnapshot(); + Snapshot = system.GetSnapshotCache(); Transaction tx = signers == null ? null : new Transaction { Version = 0, diff --git a/tests/Neo.Plugins.OracleService.Tests/TestBlockchain.cs b/tests/Neo.Plugins.OracleService.Tests/TestBlockchain.cs index d689578e22..bc6be0d8bf 100644 --- a/tests/Neo.Plugins.OracleService.Tests/TestBlockchain.cs +++ b/tests/Neo.Plugins.OracleService.Tests/TestBlockchain.cs @@ -30,7 +30,7 @@ public static void InitializeMockNeoSystem() internal static DataCache GetTestSnapshot() { - return TheNeoSystem.GetSnapshot().CreateSnapshot(); + return TheNeoSystem.GetSnapshotCache().CloneCache(); } } } diff --git a/tests/Neo.Plugins.RpcServer.Tests/TestBlockchain.cs b/tests/Neo.Plugins.RpcServer.Tests/TestBlockchain.cs new file mode 100644 index 0000000000..3ed48e982c --- /dev/null +++ b/tests/Neo.Plugins.RpcServer.Tests/TestBlockchain.cs @@ -0,0 +1,50 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// TestBlockchain.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using Akka.Actor; +using Neo.Ledger; +using Neo.Persistence; +using Neo.UnitTests; +using System; + +namespace Neo.Plugins.RpcServer.Tests +{ + public static class TestBlockchain + { + public static readonly NeoSystem TheNeoSystem; + public static readonly UInt160[] DefaultExtensibleWitnessWhiteList; + private static readonly MemoryStore Store = new(); + + internal class StoreProvider : IStoreProvider + { + public string Name => "TestProvider"; + + public IStore GetStore(string path) => Store; + } + + static TestBlockchain() + { + Console.WriteLine("initialize NeoSystem"); + TheNeoSystem = new NeoSystem(TestProtocolSettings.Default, new StoreProvider()); + } + + internal static void ResetStore() + { + Store.Reset(); + TheNeoSystem.Blockchain.Ask(new Blockchain.Initialize()).Wait(); + } + + internal static DataCache GetTestSnapshot() + { + return TheNeoSystem.GetSnapshotCache().CloneCache(); + } + } +} diff --git a/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Blockchain.cs b/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Blockchain.cs index f62c4258ab..c9007f6580 100644 --- a/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Blockchain.cs +++ b/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Blockchain.cs @@ -34,7 +34,7 @@ public void TestGetBestBlockHash() var key = NativeContract.Ledger.CreateStorageKey(12); var expectedHash = UInt256.Zero; - var snapshot = _neoSystem.GetSnapshot(); + var snapshot = _neoSystem.GetSnapshotCache(); var b = snapshot.GetAndChange(key, () => new StorageItem(new HashIndexState())).GetInteroperable(); b.Hash = UInt256.Zero; b.Index = 100; @@ -48,7 +48,7 @@ public void TestGetBestBlockHash() [TestMethod] public void TestGetBlockByHash() { - var snapshot = _neoSystem.GetSnapshot(); + var snapshot = _neoSystem.GetSnapshotCache(); var block = TestUtils.CreateBlockWithValidTransactions(snapshot, _wallet, _walletAccount, 3); TestUtils.BlocksAdd(snapshot, block.Hash, block); snapshot.Commit(); @@ -66,7 +66,7 @@ public void TestGetBlockByHash() [TestMethod] public void TestGetBlockByIndex() { - var snapshot = _neoSystem.GetSnapshot(); + var snapshot = _neoSystem.GetSnapshotCache(); var block = TestUtils.CreateBlockWithValidTransactions(snapshot, _wallet, _walletAccount, 3); TestUtils.BlocksAdd(snapshot, block.Hash, block); snapshot.Commit(); @@ -100,7 +100,7 @@ public void TestGetBlockHeaderCount() [TestMethod] public void TestGetBlockHash() { - var snapshot = _neoSystem.GetSnapshot(); + var snapshot = _neoSystem.GetSnapshotCache(); var block = TestUtils.CreateBlockWithValidTransactions(snapshot, _wallet, _walletAccount, 3); // TestUtils.BlocksAdd(snapshot, block.Hash, block); // snapshot.Commit(); @@ -113,7 +113,7 @@ public void TestGetBlockHash() [TestMethod] public void TestGetBlockHeader() { - var snapshot = _neoSystem.GetSnapshot(); + var snapshot = _neoSystem.GetSnapshotCache(); var block = TestUtils.CreateBlockWithValidTransactions(snapshot, _wallet, _walletAccount, 3); TestUtils.BlocksAdd(snapshot, block.Hash, block); snapshot.Commit(); @@ -127,7 +127,7 @@ public void TestGetBlockHeader() [TestMethod] public void TestGetContractState() { - var snapshot = _neoSystem.GetSnapshot(); + var snapshot = _neoSystem.GetSnapshotCache(); var contractState = TestUtils.GetContract(); snapshot.AddContract(contractState.Hash, contractState); snapshot.Commit(); @@ -139,7 +139,7 @@ public void TestGetContractState() [TestMethod] public void TestGetRawMemPool() { - var snapshot = _neoSystem.GetSnapshot(); + var snapshot = _neoSystem.GetSnapshotCache(); var tx = TestUtils.CreateValidTx(snapshot, _wallet, _walletAccount); snapshot.Commit(); _neoSystem.MemPool.TryAdd(tx, snapshot); @@ -152,7 +152,7 @@ public void TestGetRawMemPool() [TestMethod] public void TestGetRawTransaction() { - var snapshot = _neoSystem.GetSnapshot(); + var snapshot = _neoSystem.GetSnapshotCache(); var tx = TestUtils.CreateValidTx(snapshot, _wallet, _walletAccount); _neoSystem.MemPool.TryAdd(tx, snapshot); var parameters = new JArray(tx.Hash.ToString(), true); @@ -166,7 +166,7 @@ public void TestGetRawTransaction() [TestMethod] public void TestGetStorage() { - var snapshot = _neoSystem.GetSnapshot(); + var snapshot = _neoSystem.GetSnapshotCache(); var contractState = TestUtils.GetContract(); snapshot.AddContract(contractState.Hash, contractState); var key = new byte[] { 0x01 }; @@ -181,7 +181,7 @@ public void TestGetStorage() [TestMethod] public void TestFindStorage() { - var snapshot = _neoSystem.GetSnapshot(); + var snapshot = _neoSystem.GetSnapshotCache(); var contractState = TestUtils.GetContract(); snapshot.AddContract(contractState.Hash, contractState); var key = new byte[] { 0x01 }; @@ -205,7 +205,7 @@ public void TestFindStorage() [TestMethod] public void TestGetTransactionHeight() { - var snapshot = _neoSystem.GetSnapshot(); + var snapshot = _neoSystem.GetSnapshotCache(); var block = TestUtils.CreateBlockWithValidTransactions(snapshot, _wallet, _walletAccount, 1); TestUtils.BlocksAdd(snapshot, block.Hash, block); snapshot.Commit(); @@ -217,7 +217,7 @@ public void TestGetTransactionHeight() [TestMethod] public void TestGetNextBlockValidators() { - var snapshot = _neoSystem.GetSnapshot(); + var snapshot = _neoSystem.GetSnapshotCache(); var result = _rpcServer.GetNextBlockValidators(new JArray()); var validators = NativeContract.NEO.GetNextBlockValidators(snapshot, _neoSystem.Settings.ValidatorsCount); @@ -234,7 +234,7 @@ public void TestGetNextBlockValidators() [TestMethod] public void TestGetCandidates() { - var snapshot = _neoSystem.GetSnapshot(); + var snapshot = _neoSystem.GetSnapshotCache(); var result = _rpcServer.GetCandidates(new JArray()); var json = new JArray(); var validators = NativeContract.NEO.GetNextBlockValidators(snapshot, _neoSystem.Settings.ValidatorsCount); @@ -255,7 +255,7 @@ public void TestGetCandidates() [TestMethod] public void TestGetCommittee() { - var snapshot = _neoSystem.GetSnapshot(); + var snapshot = _neoSystem.GetSnapshotCache(); var result = _rpcServer.GetCommittee(new JArray()); var committee = NativeContract.NEO.GetCommittee(snapshot); var expected = new JArray(committee.Select(p => (JToken)p.ToString())); @@ -273,7 +273,7 @@ public void TestGetNativeContracts() [TestMethod] public void TestGetBlockByUnknownIndex() { - var snapshot = _neoSystem.GetSnapshot(); + var snapshot = _neoSystem.GetSnapshotCache(); var block = TestUtils.CreateBlockWithValidTransactions(snapshot, _wallet, _walletAccount, 3); TestUtils.BlocksAdd(snapshot, block.Hash, block); snapshot.Commit(); @@ -293,7 +293,7 @@ public void TestGetBlockByUnknownIndex() [TestMethod] public void TestGetBlockByUnknownHash() { - var snapshot = _neoSystem.GetSnapshot(); + var snapshot = _neoSystem.GetSnapshotCache(); var block = TestUtils.CreateBlockWithValidTransactions(snapshot, _wallet, _walletAccount, 3); TestUtils.BlocksAdd(snapshot, block.Hash, block); snapshot.Commit(); @@ -313,7 +313,7 @@ public void TestGetBlockByUnknownHash() [TestMethod] public void TestGetBlockByUnKnownIndex() { - var snapshot = _neoSystem.GetSnapshot(); + var snapshot = _neoSystem.GetSnapshotCache(); var block = TestUtils.CreateBlockWithValidTransactions(snapshot, _wallet, _walletAccount, 3); TestUtils.BlocksAdd(snapshot, block.Hash, block); snapshot.Commit(); @@ -333,7 +333,7 @@ public void TestGetBlockByUnKnownIndex() [TestMethod] public void TestGetBlockByUnKnownHash() { - var snapshot = _neoSystem.GetSnapshot(); + var snapshot = _neoSystem.GetSnapshotCache(); var block = TestUtils.CreateBlockWithValidTransactions(snapshot, _wallet, _walletAccount, 3); TestUtils.BlocksAdd(snapshot, block.Hash, block); snapshot.Commit(); @@ -353,7 +353,7 @@ public void TestGetBlockByUnKnownHash() [TestMethod] public void TestGetBlockHashInvalidIndex() { - var snapshot = _neoSystem.GetSnapshot(); + var snapshot = _neoSystem.GetSnapshotCache(); var block = TestUtils.CreateBlockWithValidTransactions(snapshot, _wallet, _walletAccount, 3); TestUtils.BlocksAdd(snapshot, block.Hash, block); snapshot.Commit(); @@ -363,7 +363,7 @@ public void TestGetBlockHashInvalidIndex() [TestMethod] public void TestGetContractStateUnknownContract() { - var snapshot = _neoSystem.GetSnapshot(); + var snapshot = _neoSystem.GetSnapshotCache(); var randomHash = TestUtils.RandomUInt160(); try { @@ -379,7 +379,7 @@ public void TestGetContractStateUnknownContract() [TestMethod] public void TestGetStorageUnknownContract() { - var snapshot = _neoSystem.GetSnapshot(); + var snapshot = _neoSystem.GetSnapshotCache(); var randomHash = TestUtils.RandomUInt160(); var key = new byte[] { 0x01 }; try @@ -396,7 +396,7 @@ public void TestGetStorageUnknownContract() [TestMethod] public void TestGetStorageUnknownStorageItem() { - var snapshot = _neoSystem.GetSnapshot(); + var snapshot = _neoSystem.GetSnapshotCache(); var contractState = TestUtils.GetContract(); snapshot.AddContract(contractState.Hash, contractState); snapshot.Commit(); diff --git a/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.cs b/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.cs index 96de838ba8..2561171c81 100644 --- a/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.cs +++ b/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.cs @@ -42,7 +42,7 @@ public void TestSetup() _rpcServer = new RpcServer(_neoSystem, RpcServerSettings.Default); _walletAccount = _wallet.Import("KxuRSsHgJMb3AMSN6B9P3JHNGMFtxmuimqgR9MmXPcv3CLLfusTd"); var key = new KeyBuilder(NativeContract.GAS.Id, 20).Add(_walletAccount.ScriptHash); - var snapshot = _neoSystem.GetSnapshot(); + var snapshot = _neoSystem.GetSnapshotCache(); var entry = snapshot.GetAndChange(key, () => new StorageItem(new AccountState())); entry.GetInteroperable().Balance = 100_000_000 * NativeContract.GAS.Factor; snapshot.Commit(); @@ -54,7 +54,7 @@ public void TestCleanup() // Please build and test in debug mode _neoSystem.MemPool.Clear(); _memoryStore.Reset(); - var snapshot = _neoSystem.GetSnapshot(); + var snapshot = _neoSystem.GetSnapshotCache(); var key = new KeyBuilder(NativeContract.GAS.Id, 20).Add(_walletAccount.ScriptHash); var entry = snapshot.GetAndChange(key, () => new StorageItem(new AccountState())); entry.GetInteroperable().Balance = 100_000_000 * NativeContract.GAS.Factor; diff --git a/tests/Neo.UnitTests/IO/Caching/UT_CloneCache.cs b/tests/Neo.UnitTests/IO/Caching/UT_CloneCache.cs index 4d57da62b9..3dd3d2dd67 100644 --- a/tests/Neo.UnitTests/IO/Caching/UT_CloneCache.cs +++ b/tests/Neo.UnitTests/IO/Caching/UT_CloneCache.cs @@ -156,7 +156,7 @@ public void TestUpdateInternal() public void TestCacheOverrideIssue2572() { var snapshot = TestBlockchain.GetTestSnapshot(); - var storages = snapshot.CreateSnapshot(); + var storages = snapshot.CloneCache(); storages.Add ( diff --git a/tests/Neo.UnitTests/IO/Caching/UT_DataCache.cs b/tests/Neo.UnitTests/IO/Caching/UT_DataCache.cs index 5235b99c70..242905a13a 100644 --- a/tests/Neo.UnitTests/IO/Caching/UT_DataCache.cs +++ b/tests/Neo.UnitTests/IO/Caching/UT_DataCache.cs @@ -133,7 +133,7 @@ public void TestCommit() [TestMethod] public void TestCreateSnapshot() { - myDataCache.CreateSnapshot().Should().NotBeNull(); + myDataCache.CloneCache().Should().NotBeNull(); } [TestMethod] diff --git a/tests/Neo.UnitTests/Ledger/UT_Blockchain.cs b/tests/Neo.UnitTests/Ledger/UT_Blockchain.cs index cedc68bb4d..2c5ed88ef8 100644 --- a/tests/Neo.UnitTests/Ledger/UT_Blockchain.cs +++ b/tests/Neo.UnitTests/Ledger/UT_Blockchain.cs @@ -57,7 +57,7 @@ public void Clean() [TestMethod] public void TestValidTransaction() { - var snapshot = TestBlockchain.TheNeoSystem.GetSnapshot(); + var snapshot = TestBlockchain.TheNeoSystem.GetSnapshotCache(); var walletA = TestUtils.GenerateTestWallet("123"); var acc = walletA.CreateAccount(); @@ -95,7 +95,7 @@ internal static StorageKey CreateStorageKey(byte prefix, byte[] key = null) [TestMethod] public void TestMaliciousOnChainConflict() { - var snapshot = TestBlockchain.TheNeoSystem.GetSnapshot(); + var snapshot = TestBlockchain.TheNeoSystem.GetSnapshotCache(); var walletA = TestUtils.GenerateTestWallet("123"); var accA = walletA.CreateAccount(); var walletB = TestUtils.GenerateTestWallet("456"); diff --git a/tests/Neo.UnitTests/Ledger/UT_MemoryPool.cs b/tests/Neo.UnitTests/Ledger/UT_MemoryPool.cs index 1063413073..73cbb37dc9 100644 --- a/tests/Neo.UnitTests/Ledger/UT_MemoryPool.cs +++ b/tests/Neo.UnitTests/Ledger/UT_MemoryPool.cs @@ -47,7 +47,7 @@ public static void TestSetup(TestContext ctx) private static DataCache GetSnapshot() { - return testBlockchain.StoreView.CreateSnapshot(); + return testBlockchain.StoreView.CloneCache(); } [TestInitialize] diff --git a/tests/Neo.UnitTests/Persistence/UT_MemoryStore.cs b/tests/Neo.UnitTests/Persistence/UT_MemoryStore.cs index 4cddf07e65..133d9eb66c 100644 --- a/tests/Neo.UnitTests/Persistence/UT_MemoryStore.cs +++ b/tests/Neo.UnitTests/Persistence/UT_MemoryStore.cs @@ -91,7 +91,7 @@ public void NeoSystemStoreViewTest() [TestMethod] public void NeoSystemStoreAddTest() { - var storeCache = _neoSystem.GetSnapshot(); + var storeCache = _neoSystem.GetSnapshotCache(); var key = new KeyBuilder(0, 0); storeCache.Add(key, new StorageItem(UInt256.Zero.ToArray())); storeCache.Commit(); @@ -102,7 +102,7 @@ public void NeoSystemStoreAddTest() [TestMethod] public void NeoSystemStoreGetAndChange() { - var storeView = _neoSystem.GetSnapshot(); + var storeView = _neoSystem.GetSnapshotCache(); var key = new KeyBuilder(1, 1); var item = new StorageItem([1, 2, 3]); storeView.Delete(key); diff --git a/tests/Neo.UnitTests/SmartContract/Native/UT_GasToken.cs b/tests/Neo.UnitTests/SmartContract/Native/UT_GasToken.cs index 51617b6744..1557f9778d 100644 --- a/tests/Neo.UnitTests/SmartContract/Native/UT_GasToken.cs +++ b/tests/Neo.UnitTests/SmartContract/Native/UT_GasToken.cs @@ -49,7 +49,7 @@ public void TestSetup() [TestMethod] public async Task Check_BalanceOfTransferAndBurn() { - var snapshot = _snapshot.CreateSnapshot(); + var snapshot = _snapshot.CloneCache(); var persistingBlock = new Block { Header = new Header { Index = 1000 } }; byte[] from = Contract.GetBFTAddress(TestProtocolSettings.Default.StandbyValidators).ToArray(); byte[] to = new byte[20]; diff --git a/tests/Neo.UnitTests/SmartContract/Native/UT_NativeContract.cs b/tests/Neo.UnitTests/SmartContract/Native/UT_NativeContract.cs index 1cce9ef32a..707f8e6754 100644 --- a/tests/Neo.UnitTests/SmartContract/Native/UT_NativeContract.cs +++ b/tests/Neo.UnitTests/SmartContract/Native/UT_NativeContract.cs @@ -123,7 +123,7 @@ public void TestGenesisNEP17Manifest() }, Transactions = [] }; - var snapshot = _snapshot.CreateSnapshot(); + var snapshot = _snapshot.CloneCache(); // Ensure that native NEP17 contracts contain proper supported standards and events declared // in the manifest constructed for all hardforks enabled. Ref. https://github.com/neo-project/neo/pull/3195. @@ -150,7 +150,7 @@ public void TestGenesisNativeState() }, Transactions = [] }; - var snapshot = _snapshot.CreateSnapshot(); + var snapshot = _snapshot.CloneCache(); // Ensure that all native contracts have proper state generated with an assumption that // all hardforks enabled. diff --git a/tests/Neo.UnitTests/SmartContract/Native/UT_NeoToken.cs b/tests/Neo.UnitTests/SmartContract/Native/UT_NeoToken.cs index 0a19314153..92f1e0e5f2 100644 --- a/tests/Neo.UnitTests/SmartContract/Native/UT_NeoToken.cs +++ b/tests/Neo.UnitTests/SmartContract/Native/UT_NeoToken.cs @@ -56,7 +56,7 @@ public void TestSetup() [TestMethod] public void Check_Vote() { - var snapshot = _snapshot.CreateSnapshot(); + var snapshot = _snapshot.CloneCache(); var persistingBlock = new Block { Header = new Header { Index = 1000 } }; var storageKey = new KeyBuilder(NativeContract.Ledger.Id, 12); @@ -114,7 +114,7 @@ public void Check_Vote() [TestMethod] public void Check_Vote_Sameaccounts() { - var snapshot = _snapshot.CreateSnapshot(); + var snapshot = _snapshot.CloneCache(); var persistingBlock = new Block { Header = new Header { Index = 1000 } }; var storageKey = new KeyBuilder(NativeContract.Ledger.Id, 12); @@ -147,7 +147,7 @@ public void Check_Vote_Sameaccounts() [TestMethod] public void Check_Vote_ChangeVote() { - var snapshot = _snapshot.CreateSnapshot(); + var snapshot = _snapshot.CloneCache(); var persistingBlock = new Block { Header = new Header { Index = 1000 } }; var storageKey = new KeyBuilder(NativeContract.Ledger.Id, 12); snapshot.Add(storageKey, new StorageItem(new HashIndexState { Hash = UInt256.Zero, Index = persistingBlock.Index - 1 })); @@ -182,7 +182,7 @@ public void Check_Vote_ChangeVote() [TestMethod] public void Check_Vote_VoteToNull() { - var snapshot = _snapshot.CreateSnapshot(); + var snapshot = _snapshot.CloneCache(); var persistingBlock = new Block { Header = new Header { Index = 1000 } }; var storageKey = new KeyBuilder(NativeContract.Ledger.Id, 12); snapshot.Add(storageKey, new StorageItem(new HashIndexState { Hash = UInt256.Zero, Index = persistingBlock.Index - 1 })); @@ -219,7 +219,7 @@ public void Check_Vote_VoteToNull() [TestMethod] public void Check_UnclaimedGas() { - var snapshot = _snapshot.CreateSnapshot(); + var snapshot = _snapshot.CloneCache(); var persistingBlock = new Block { Header = new Header { Index = 1000 } }; var storageKey = new KeyBuilder(NativeContract.Ledger.Id, 12); @@ -239,7 +239,7 @@ public void Check_UnclaimedGas() [TestMethod] public void Check_RegisterValidator() { - var snapshot = _snapshot.CreateSnapshot(); + var snapshot = _snapshot.CloneCache(); var keyCount = snapshot.GetChangeSet().Count(); var point = TestProtocolSettings.Default.StandbyValidators[0].EncodePoint(true).Clone() as byte[]; @@ -267,7 +267,7 @@ public void Check_RegisterValidator() [TestMethod] public void Check_UnregisterCandidate() { - var snapshot = _snapshot.CreateSnapshot(); + var snapshot = _snapshot.CloneCache(); _persistingBlock.Header.Index = 1; var keyCount = snapshot.GetChangeSet().Count(); var point = TestProtocolSettings.Default.StandbyValidators[0].EncodePoint(true); @@ -328,7 +328,7 @@ public void Check_UnregisterCandidate() [TestMethod] public void Check_GetCommittee() { - var snapshot = _snapshot.CreateSnapshot(); + var snapshot = _snapshot.CloneCache(); var keyCount = snapshot.GetChangeSet().Count(); var point = TestProtocolSettings.Default.StandbyValidators[0].EncodePoint(true); var persistingBlock = _persistingBlock; @@ -388,7 +388,7 @@ public void Check_GetCommittee() [TestMethod] public void Check_Transfer() { - var snapshot = _snapshot.CreateSnapshot(); + var snapshot = _snapshot.CloneCache(); var persistingBlock = new Block { Header = new Header { Index = 1000 } }; byte[] from = Contract.GetBFTAddress(TestProtocolSettings.Default.StandbyValidators).ToArray(); @@ -447,7 +447,7 @@ public void Check_Transfer() [TestMethod] public void Check_BalanceOf() { - var snapshot = _snapshot.CreateSnapshot(); + var snapshot = _snapshot.CloneCache(); byte[] account = Contract.GetBFTAddress(TestProtocolSettings.Default.StandbyValidators).ToArray(); NativeContract.NEO.BalanceOf(snapshot, account).Should().Be(100_000_000); @@ -460,7 +460,7 @@ public void Check_BalanceOf() [TestMethod] public void Check_CommitteeBonus() { - var snapshot = _snapshot.CreateSnapshot(); + var snapshot = _snapshot.CloneCache(); var persistingBlock = new Block { Header = new Header @@ -485,7 +485,7 @@ public void Check_CommitteeBonus() [TestMethod] public void Check_Initialize() { - var snapshot = _snapshot.CreateSnapshot(); + var snapshot = _snapshot.CloneCache(); // StandbyValidators @@ -495,7 +495,7 @@ public void Check_Initialize() [TestMethod] public void TestCalculateBonus() { - var snapshot = _snapshot.CreateSnapshot(); + var snapshot = _snapshot.CloneCache(); var persistingBlock = new Block(); StorageKey key = CreateStorageKey(20, UInt160.Zero.ToArray()); @@ -584,7 +584,7 @@ public void TestGetNextBlockValidators1() [TestMethod] public void TestGetNextBlockValidators2() { - var snapshot = _snapshot.CreateSnapshot(); + var snapshot = _snapshot.CloneCache(); var result = NativeContract.NEO.GetNextBlockValidators(snapshot, 7); result.Length.Should().Be(7); result[0].ToArray().ToHexString().Should().Be("02486fd15702c4490a26703112a5cc1d0923fd697a33406bd5a1c00e0013b09a70"); @@ -607,7 +607,7 @@ public void TestGetCandidates1() [TestMethod] public void TestGetCandidates2() { - var snapshot = _snapshot.CreateSnapshot(); + var snapshot = _snapshot.CloneCache(); var result = NativeContract.NEO.GetCandidatesInternal(snapshot); result.Count().Should().Be(0); @@ -619,7 +619,7 @@ public void TestGetCandidates2() [TestMethod] public void TestCheckCandidate() { - var snapshot = _snapshot.CreateSnapshot(); + var snapshot = _snapshot.CloneCache(); var committee = NativeContract.NEO.GetCommittee(snapshot); var point = committee[0].EncodePoint(true); @@ -700,7 +700,7 @@ public void TestGetCommittee() [TestMethod] public void TestGetValidators() { - var snapshot = _snapshot.CreateSnapshot(); + var snapshot = _snapshot.CloneCache(); var result = NativeContract.NEO.ComputeNextBlockValidators(snapshot, TestProtocolSettings.Default); result[0].ToArray().ToHexString().Should().Be("02486fd15702c4490a26703112a5cc1d0923fd697a33406bd5a1c00e0013b09a70"); result[1].ToArray().ToHexString().Should().Be("024c7b7fb6c310fccf1ba33b082519d82964ea93868d676662d4a59ad548df0e7d"); @@ -730,7 +730,7 @@ public void TestOnBalanceChanging() [TestMethod] public void TestTotalSupply() { - var snapshot = _snapshot.CreateSnapshot(); + var snapshot = _snapshot.CloneCache(); NativeContract.NEO.TotalSupply(snapshot).Should().Be(new BigInteger(100000000)); } @@ -738,7 +738,7 @@ public void TestTotalSupply() public void TestEconomicParameter() { const byte Prefix_CurrentBlock = 12; - var snapshot = _snapshot.CreateSnapshot(); + var snapshot = _snapshot.CloneCache(); var persistingBlock = new Block { Header = new Header() }; (BigInteger, bool) result = Check_GetGasPerBlock(snapshot, persistingBlock); @@ -768,7 +768,7 @@ public void TestEconomicParameter() [TestMethod] public void TestClaimGas() { - var snapshot = _snapshot.CreateSnapshot(); + var snapshot = _snapshot.CloneCache(); // Initialize block snapshot.Add(CreateStorageKey(1), new StorageItem(new BigInteger(30000000))); @@ -877,7 +877,7 @@ public void TestClaimGas() [TestMethod] public void TestUnclaimedGas() { - var snapshot = _snapshot.CreateSnapshot(); + var snapshot = _snapshot.CloneCache(); NativeContract.NEO.UnclaimedGas(snapshot, UInt160.Zero, 10).Should().Be(new BigInteger(0)); snapshot.Add(CreateStorageKey(20, UInt160.Zero.ToArray()), new StorageItem(new NeoAccountState())); NativeContract.NEO.UnclaimedGas(snapshot, UInt160.Zero, 10).Should().Be(new BigInteger(0)); @@ -886,7 +886,7 @@ public void TestUnclaimedGas() [TestMethod] public void TestVote() { - var snapshot = _snapshot.CreateSnapshot(); + var snapshot = _snapshot.CloneCache(); UInt160 account = UInt160.Parse("01ff00ff00ff00ff00ff00ff00ff00ff00ff00a4"); StorageKey keyAccount = CreateStorageKey(20, account.ToArray()); StorageKey keyValidator = CreateStorageKey(33, ECCurve.Secp256r1.G.ToArray()); @@ -924,7 +924,7 @@ public void TestVote() internal (bool State, bool Result) Transfer4TesingOnBalanceChanging(BigInteger amount, bool addVotes) { - var snapshot = _snapshot.CreateSnapshot(); + var snapshot = _snapshot.CloneCache(); _persistingBlock.Header.Index = 1; var engine = ApplicationEngine.Create(TriggerType.Application, TestBlockchain.TheNeoSystem.GenesisBlock, snapshot, _persistingBlock, settings: TestBlockchain.TheNeoSystem.Settings); ScriptBuilder sb = new(); diff --git a/tests/Neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs b/tests/Neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs index 703253364c..a8d9495b5c 100644 --- a/tests/Neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs +++ b/tests/Neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs @@ -40,7 +40,7 @@ public void TestSetup() [TestMethod] public void Check_Default() { - var snapshot = _snapshot.CreateSnapshot(); + var snapshot = _snapshot.CloneCache(); var ret = NativeContract.Policy.Call(snapshot, "getFeePerByte"); ret.Should().BeOfType(); @@ -56,7 +56,7 @@ public void Check_Default() [TestMethod] public void Check_SetAttributeFee() { - var snapshot = _snapshot.CreateSnapshot(); + var snapshot = _snapshot.CloneCache(); // Fake blockchain Block block = new() @@ -115,7 +115,7 @@ public void Check_SetAttributeFee() [TestMethod] public void Check_SetFeePerByte() { - var snapshot = _snapshot.CreateSnapshot(); + var snapshot = _snapshot.CloneCache(); // Fake blockchain @@ -154,7 +154,7 @@ public void Check_SetFeePerByte() [TestMethod] public void Check_SetBaseExecFee() { - var snapshot = _snapshot.CreateSnapshot(); + var snapshot = _snapshot.CloneCache(); // Fake blockchain @@ -204,7 +204,7 @@ public void Check_SetBaseExecFee() [TestMethod] public void Check_SetStoragePrice() { - var snapshot = _snapshot.CreateSnapshot(); + var snapshot = _snapshot.CloneCache(); // Fake blockchain @@ -254,7 +254,7 @@ public void Check_SetStoragePrice() [TestMethod] public void Check_BlockAccount() { - var snapshot = _snapshot.CreateSnapshot(); + var snapshot = _snapshot.CloneCache(); // Fake blockchain @@ -310,7 +310,7 @@ public void Check_BlockAccount() [TestMethod] public void Check_Block_UnblockAccount() { - var snapshot = _snapshot.CreateSnapshot(); + var snapshot = _snapshot.CloneCache(); // Fake blockchain diff --git a/tests/Neo.UnitTests/SmartContract/Native/UT_RoleManagement.cs b/tests/Neo.UnitTests/SmartContract/Native/UT_RoleManagement.cs index 25ca7ee0d6..7db5ce4e01 100644 --- a/tests/Neo.UnitTests/SmartContract/Native/UT_RoleManagement.cs +++ b/tests/Neo.UnitTests/SmartContract/Native/UT_RoleManagement.cs @@ -62,7 +62,7 @@ public void TestSetAndGet() List roles = new List() { Role.StateValidator, Role.Oracle, Role.NeoFSAlphabetNode, Role.P2PNotary }; foreach (var role in roles) { - var snapshot1 = _snapshot.CreateSnapshot(); + var snapshot1 = _snapshot.CloneCache(); UInt160 committeeMultiSigAddr = NativeContract.NEO.GetCommitteeAddress(snapshot1); List notifications = new List(); EventHandler ev = (o, e) => notifications.Add(e); @@ -79,7 +79,7 @@ public void TestSetAndGet() ApplicationEngine.Notify -= ev; notifications.Count.Should().Be(1); notifications[0].EventName.Should().Be("Designation"); - var snapshot2 = _snapshot.CreateSnapshot(); + var snapshot2 = _snapshot.CloneCache(); ret = NativeContract.RoleManagement.Call( snapshot2, "getDesignatedByRole", diff --git a/tests/Neo.UnitTests/SmartContract/UT_SmartContractHelper.cs b/tests/Neo.UnitTests/SmartContract/UT_SmartContractHelper.cs index c1161213ce..f864fbe749 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_SmartContractHelper.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_SmartContractHelper.cs @@ -124,7 +124,7 @@ public void TestIsStandardContract() [TestMethod] public void TestVerifyWitnesses() { - var snapshot1 = TestBlockchain.GetTestSnapshot().CreateSnapshot(); + var snapshot1 = TestBlockchain.GetTestSnapshot().CloneCache(); UInt256 index1 = UInt256.Parse("0xa400ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff01"); TestUtils.BlocksAdd(snapshot1, index1, new TrimmedBlock() { diff --git a/tests/Neo.UnitTests/TestBlockchain.cs b/tests/Neo.UnitTests/TestBlockchain.cs index f7e06d0595..7bf26edbd7 100644 --- a/tests/Neo.UnitTests/TestBlockchain.cs +++ b/tests/Neo.UnitTests/TestBlockchain.cs @@ -43,7 +43,7 @@ internal static void ResetStore() internal static DataCache GetTestSnapshot() { - return TheNeoSystem.GetSnapshot().CreateSnapshot(); + return TheNeoSystem.GetSnapshotCache().CloneCache(); } } } diff --git a/tests/Neo.UnitTests/UT_DataCache.cs b/tests/Neo.UnitTests/UT_DataCache.cs index 008f166b6f..01bd84c949 100644 --- a/tests/Neo.UnitTests/UT_DataCache.cs +++ b/tests/Neo.UnitTests/UT_DataCache.cs @@ -23,7 +23,7 @@ public class UT_DataCache public void TestCachedFind_Between() { var snapshot = TestBlockchain.GetTestSnapshot(); - var storages = snapshot.CreateSnapshot(); + var storages = snapshot.CloneCache(); var cache = new ClonedCache(storages); storages.Add @@ -62,7 +62,7 @@ public void TestCachedFind_Between() public void TestCachedFind_Last() { var snapshot = TestBlockchain.GetTestSnapshot(); - var storages = snapshot.CreateSnapshot(); + var storages = snapshot.CloneCache(); var cache = new ClonedCache(storages); storages.Add @@ -94,7 +94,7 @@ public void TestCachedFind_Last() public void TestCachedFind_Empty() { var snapshot = TestBlockchain.GetTestSnapshot(); - var storages = snapshot.CreateSnapshot(); + var storages = snapshot.CloneCache(); var cache = new ClonedCache(storages); cache.Add From 03fc303d5b3392a6b59effbd48843e372d98fe2e Mon Sep 17 00:00:00 2001 From: Christopher Schuchardt Date: Tue, 16 Jul 2024 12:05:00 -0400 Subject: [PATCH 48/71] `[Move]` Part-2 Classes into Different Library - `Neo.IO` (#3388) * Part-1 `Neo.IO` - move * Part-2 * Added `BigInteger` to `Neo.Extensions` * Found more `BigInteger` * Added Tests * Update tests/Neo.Extensions.Tests/UT_BigIntegerExtensions.cs --------- Co-authored-by: Shargon Co-authored-by: Jimmy --- .github/workflows/main.yml | 2 + neo.sln | 7 ++ src/Neo.Extensions/BigIntegerExtensions.cs | 91 +++++++++++++++++++ src/Neo.Extensions/Neo.Extensions.csproj | 2 +- src/Neo.GUI/GUI/MainForm.cs | 1 + src/{Neo/IO => Neo.IO}/Actors/Idle.cs | 2 +- .../Caching/ReflectionCacheAttribute.cs | 18 ++-- src/Neo/Cryptography/ECC/ECFieldElement.cs | 1 + src/Neo/Cryptography/ECC/ECPoint.cs | 1 + src/Neo/Helper.cs | 70 -------------- src/Neo/IO/Actors/PriorityMailbox.cs | 14 +-- src/Neo/IO/Actors/PriorityMessageQueue.cs | 35 +++---- src/Neo/IO/Caching/ReflectionCache.cs | 17 ++-- src/Neo/IO/Caching/RelayCache.cs | 8 +- src/Neo/SmartContract/StorageItem.cs | 1 + src/Neo/Wallets/Wallet.cs | 1 + .../Neo.Extensions.Tests.csproj | 23 +++++ .../UT_BigIntegerExtensions.cs | 47 ++++++++++ tests/Neo.UnitTests/Neo.UnitTests.csproj | 1 + tests/Neo.UnitTests/UT_Helper.cs | 11 +-- 20 files changed, 216 insertions(+), 137 deletions(-) create mode 100644 src/Neo.Extensions/BigIntegerExtensions.cs rename src/{Neo/IO => Neo.IO}/Actors/Idle.cs (89%) rename src/{Neo/IO => Neo.IO}/Caching/ReflectionCacheAttribute.cs (67%) create mode 100644 tests/Neo.Extensions.Tests/Neo.Extensions.Tests.csproj create mode 100644 tests/Neo.Extensions.Tests/UT_BigIntegerExtensions.cs diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 71602a6df2..30939152a7 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -81,6 +81,7 @@ jobs: dotnet test ./tests/Neo.UnitTests --output ./bin/tests/Neo.UnitTests dotnet test ./tests/Neo.VM.Tests --output ./bin/tests/Neo.VM.Tests dotnet test ./tests/Neo.Json.UnitTests --output ./bin/tests/Neo.Json.UnitTests + dotnet test ./tests/Neo.Extensions.Tests --output ./bin/tests/Neo.Extensions.Tests # Plugins dotnet test ./tests/Neo.Cryptography.MPTTrie.Tests --output ./bin/tests/Neo.Cryptography.MPTTrie.Tests @@ -105,6 +106,7 @@ jobs: ${{ github.workspace }}/tests/Neo.Plugins.OracleService.Tests/TestResults/coverage.info ${{ github.workspace }}/tests/Neo.Plugins.RpcServer.Tests/TestResults/coverage.info ${{ github.workspace }}/tests/Neo.Plugins.Storage.Tests/TestResults/coverage.info + ${{ github.workspace }}/tests/Neo.Extensions.Tests/TestResults/coverage.info PublishPackage: if: github.ref == 'refs/heads/master' && startsWith(github.repository, 'neo-project/') diff --git a/neo.sln b/neo.sln index b0de1c27b1..5d55b0d785 100644 --- a/neo.sln +++ b/neo.sln @@ -78,6 +78,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TokensTracker", "src\Plugin EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RpcClient", "src\Plugins\RpcClient\RpcClient.csproj", "{185ADAFC-BFC6-413D-BC2E-97F9FB0A8AF0}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Neo.Extensions.Tests", "tests\Neo.Extensions.Tests\Neo.Extensions.Tests.csproj", "{77FDEE2E-9381-4BFC-B9E6-741EDBD6B90F}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -216,6 +218,10 @@ Global {185ADAFC-BFC6-413D-BC2E-97F9FB0A8AF0}.Debug|Any CPU.Build.0 = Debug|Any CPU {185ADAFC-BFC6-413D-BC2E-97F9FB0A8AF0}.Release|Any CPU.ActiveCfg = Release|Any CPU {185ADAFC-BFC6-413D-BC2E-97F9FB0A8AF0}.Release|Any CPU.Build.0 = Release|Any CPU + {77FDEE2E-9381-4BFC-B9E6-741EDBD6B90F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {77FDEE2E-9381-4BFC-B9E6-741EDBD6B90F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {77FDEE2E-9381-4BFC-B9E6-741EDBD6B90F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {77FDEE2E-9381-4BFC-B9E6-741EDBD6B90F}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -255,6 +261,7 @@ Global {FF76D8A4-356B-461A-8471-BC1B83E57BBC} = {C2DC830A-327A-42A7-807D-295216D30DBB} {5E4947F3-05D3-4806-B0F3-30DAC71B5986} = {C2DC830A-327A-42A7-807D-295216D30DBB} {185ADAFC-BFC6-413D-BC2E-97F9FB0A8AF0} = {C2DC830A-327A-42A7-807D-295216D30DBB} + {77FDEE2E-9381-4BFC-B9E6-741EDBD6B90F} = {EDE05FA8-8E73-4924-BC63-DD117127EEE1} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {BCBA19D9-F868-4C6D-8061-A2B91E06E3EC} diff --git a/src/Neo.Extensions/BigIntegerExtensions.cs b/src/Neo.Extensions/BigIntegerExtensions.cs new file mode 100644 index 0000000000..38a0e60bb5 --- /dev/null +++ b/src/Neo.Extensions/BigIntegerExtensions.cs @@ -0,0 +1,91 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// BigIntegerExtensions.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using System; +using System.Collections.Generic; +using System.Numerics; +using System.Runtime.CompilerServices; + +namespace Neo.Extensions +{ + public static class BigIntegerExtensions + { + public static int GetLowestSetBit(this BigInteger i) + { + if (i.Sign == 0) + return -1; + var b = i.ToByteArray(); + var w = 0; + while (b[w] == 0) + w++; + for (var x = 0; x < 8; x++) + if ((b[w] & 1 << x) > 0) + return x + w * 8; + throw new Exception(); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static BigInteger Mod(this BigInteger x, BigInteger y) + { + x %= y; + if (x.Sign < 0) + x += y; + return x; + } + + public static BigInteger ModInverse(this BigInteger a, BigInteger n) + { + BigInteger i = n, v = 0, d = 1; + while (a > 0) + { + BigInteger t = i / a, x = a; + a = i % x; + i = x; + x = d; + d = v - t * x; + v = x; + } + v %= n; + if (v < 0) v = (v + n) % n; + return v; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool TestBit(this BigInteger i, int index) + { + return (i & (BigInteger.One << index)) > BigInteger.Zero; + } + + /// + /// Finds the sum of the specified integers. + /// + /// The specified integers. + /// The sum of the integers. + public static BigInteger Sum(this IEnumerable source) + { + var sum = BigInteger.Zero; + foreach (var bi in source) sum += bi; + return sum; + } + + /// + /// Converts a to byte array and eliminates all the leading zeros. + /// + /// The to convert. + /// The converted byte array. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static byte[] ToByteArrayStandard(this BigInteger i) + { + if (i.IsZero) return Array.Empty(); + return i.ToByteArray(); + } + } +} diff --git a/src/Neo.Extensions/Neo.Extensions.csproj b/src/Neo.Extensions/Neo.Extensions.csproj index a7f4870568..aa79170ddb 100644 --- a/src/Neo.Extensions/Neo.Extensions.csproj +++ b/src/Neo.Extensions/Neo.Extensions.csproj @@ -15,7 +15,7 @@ - + diff --git a/src/Neo.GUI/GUI/MainForm.cs b/src/Neo.GUI/GUI/MainForm.cs index fc1a3e8d99..5269d992bd 100644 --- a/src/Neo.GUI/GUI/MainForm.cs +++ b/src/Neo.GUI/GUI/MainForm.cs @@ -10,6 +10,7 @@ // modifications are permitted. using Akka.Actor; +using Neo.Extensions; using Neo.IO.Actors; using Neo.Ledger; using Neo.Network.P2P.Payloads; diff --git a/src/Neo/IO/Actors/Idle.cs b/src/Neo.IO/Actors/Idle.cs similarity index 89% rename from src/Neo/IO/Actors/Idle.cs rename to src/Neo.IO/Actors/Idle.cs index e722d057ee..c372062783 100644 --- a/src/Neo/IO/Actors/Idle.cs +++ b/src/Neo.IO/Actors/Idle.cs @@ -13,6 +13,6 @@ namespace Neo.IO.Actors { internal sealed class Idle { - public static Idle Instance { get; } = new Idle(); + public static Idle Instance { get; } = new(); } } diff --git a/src/Neo/IO/Caching/ReflectionCacheAttribute.cs b/src/Neo.IO/Caching/ReflectionCacheAttribute.cs similarity index 67% rename from src/Neo/IO/Caching/ReflectionCacheAttribute.cs rename to src/Neo.IO/Caching/ReflectionCacheAttribute.cs index 20aeb91320..7071e879e4 100644 --- a/src/Neo/IO/Caching/ReflectionCacheAttribute.cs +++ b/src/Neo.IO/Caching/ReflectionCacheAttribute.cs @@ -13,21 +13,17 @@ namespace Neo.IO.Caching { + /// + /// Constructor + /// + /// Type [AttributeUsage(AttributeTargets.Field, AllowMultiple = false)] - internal class ReflectionCacheAttribute : Attribute + internal class ReflectionCacheAttribute + (Type type) : Attribute { /// /// Type /// - public Type Type { get; } - - /// - /// Constructor - /// - /// Type - public ReflectionCacheAttribute(Type type) - { - Type = type; - } + public Type Type { get; } = type; } } diff --git a/src/Neo/Cryptography/ECC/ECFieldElement.cs b/src/Neo/Cryptography/ECC/ECFieldElement.cs index 47d8bfa274..d77a8b0451 100644 --- a/src/Neo/Cryptography/ECC/ECFieldElement.cs +++ b/src/Neo/Cryptography/ECC/ECFieldElement.cs @@ -9,6 +9,7 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using Neo.Extensions; using System; using System.Numerics; diff --git a/src/Neo/Cryptography/ECC/ECPoint.cs b/src/Neo/Cryptography/ECC/ECPoint.cs index 3b7bdcc885..77d01b90ea 100644 --- a/src/Neo/Cryptography/ECC/ECPoint.cs +++ b/src/Neo/Cryptography/ECC/ECPoint.cs @@ -9,6 +9,7 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using Neo.Extensions; using Neo.IO; using Neo.IO.Caching; using System; diff --git a/src/Neo/Helper.cs b/src/Neo/Helper.cs index 00099bc148..7acf69b0e9 100644 --- a/src/Neo/Helper.cs +++ b/src/Neo/Helper.cs @@ -82,20 +82,6 @@ public static byte[] Concat(ReadOnlySpan a, ReadOnlySpan b) return buffer; } - internal static int GetLowestSetBit(this BigInteger i) - { - if (i.Sign == 0) - return -1; - byte[] b = i.ToByteArray(); - int w = 0; - while (b[w] == 0) - w++; - for (int x = 0; x < 8; x++) - if ((b[w] & 1 << x) > 0) - return x + w * 8; - throw new Exception(); - } - internal static void Remove(this HashSet set, ISet other) { if (set.Count > other.Count) @@ -157,32 +143,6 @@ public static byte[] HexToBytes(this string value) return result; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static BigInteger Mod(this BigInteger x, BigInteger y) - { - x %= y; - if (x.Sign < 0) - x += y; - return x; - } - - internal static BigInteger ModInverse(this BigInteger a, BigInteger n) - { - BigInteger i = n, v = 0, d = 1; - while (a > 0) - { - BigInteger t = i / a, x = a; - a = i % x; - i = x; - x = d; - d = v - t * x; - v = x; - } - v %= n; - if (v < 0) v = (v + n) % n; - return v; - } - internal static BigInteger NextBigInteger(this Random rand, int sizeInBits) { if (sizeInBits < 0) @@ -198,36 +158,6 @@ internal static BigInteger NextBigInteger(this Random rand, int sizeInBits) return new BigInteger(b); } - /// - /// Finds the sum of the specified integers. - /// - /// The specified integers. - /// The sum of the integers. - public static BigInteger Sum(this IEnumerable source) - { - var sum = BigInteger.Zero; - foreach (var bi in source) sum += bi; - return sum; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static bool TestBit(this BigInteger i, int index) - { - return (i & (BigInteger.One << index)) > BigInteger.Zero; - } - - /// - /// Converts a to byte array and eliminates all the leading zeros. - /// - /// The to convert. - /// The converted byte array. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static byte[] ToByteArrayStandard(this BigInteger i) - { - if (i.IsZero) return Array.Empty(); - return i.ToByteArray(); - } - /// /// Converts a byte array to hex . /// diff --git a/src/Neo/IO/Actors/PriorityMailbox.cs b/src/Neo/IO/Actors/PriorityMailbox.cs index 0b08c04d70..b51d5ee861 100644 --- a/src/Neo/IO/Actors/PriorityMailbox.cs +++ b/src/Neo/IO/Actors/PriorityMailbox.cs @@ -17,17 +17,11 @@ namespace Neo.IO.Actors { - internal abstract class PriorityMailbox : MailboxType, IProducesMessageQueue + internal abstract class PriorityMailbox + (Settings settings, Config config) : MailboxType(settings, config), IProducesMessageQueue { - public PriorityMailbox(Akka.Actor.Settings settings, Config config) - : base(settings, config) - { - } - - public override IMessageQueue Create(IActorRef owner, ActorSystem system) - { - return new PriorityMessageQueue(ShallDrop, IsHighPriority); - } + public override IMessageQueue Create(IActorRef owner, ActorSystem system) => + new PriorityMessageQueue(ShallDrop, IsHighPriority); internal protected virtual bool IsHighPriority(object message) => false; internal protected virtual bool ShallDrop(object message, IEnumerable queue) => false; diff --git a/src/Neo/IO/Actors/PriorityMessageQueue.cs b/src/Neo/IO/Actors/PriorityMessageQueue.cs index 225720ec97..8723416adf 100644 --- a/src/Neo/IO/Actors/PriorityMessageQueue.cs +++ b/src/Neo/IO/Actors/PriorityMessageQueue.cs @@ -20,22 +20,17 @@ namespace Neo.IO.Actors { - internal class PriorityMessageQueue : IMessageQueue, IUnboundedMessageQueueSemantics + internal class PriorityMessageQueue + (Func dropper, Func priority_generator) : IMessageQueue, IUnboundedMessageQueueSemantics { - private readonly ConcurrentQueue high = new(); - private readonly ConcurrentQueue low = new(); - private readonly Func dropper; - private readonly Func priority_generator; - private int idle = 1; + private readonly ConcurrentQueue _high = new(); + private readonly ConcurrentQueue _low = new(); + private readonly Func _dropper = dropper; + private readonly Func _priority_generator = priority_generator; + private int _idle = 1; - public bool HasMessages => !high.IsEmpty || !low.IsEmpty; - public int Count => high.Count + low.Count; - - public PriorityMessageQueue(Func dropper, Func priority_generator) - { - this.dropper = dropper; - this.priority_generator = priority_generator; - } + public bool HasMessages => !_high.IsEmpty || !_low.IsEmpty; + public int Count => _high.Count + _low.Count; public void CleanUp(IActorRef owner, IMessageQueue deadletters) { @@ -43,19 +38,19 @@ public void CleanUp(IActorRef owner, IMessageQueue deadletters) public void Enqueue(IActorRef receiver, Envelope envelope) { - Interlocked.Increment(ref idle); + Interlocked.Increment(ref _idle); if (envelope.Message is Idle) return; - if (dropper(envelope.Message, high.Concat(low).Select(p => p.Message))) + if (_dropper(envelope.Message, _high.Concat(_low).Select(p => p.Message))) return; - ConcurrentQueue queue = priority_generator(envelope.Message) ? high : low; + var queue = _priority_generator(envelope.Message) ? _high : _low; queue.Enqueue(envelope); } public bool TryDequeue(out Envelope envelope) { - if (high.TryDequeue(out envelope)) return true; - if (low.TryDequeue(out envelope)) return true; - if (Interlocked.Exchange(ref idle, 0) > 0) + if (_high.TryDequeue(out envelope)) return true; + if (_low.TryDequeue(out envelope)) return true; + if (Interlocked.Exchange(ref _idle, 0) > 0) { envelope = new Envelope(Idle.Instance, ActorRefs.NoSender); return true; diff --git a/src/Neo/IO/Caching/ReflectionCache.cs b/src/Neo/IO/Caching/ReflectionCache.cs index 2fd8f5fceb..5007b67740 100644 --- a/src/Neo/IO/Caching/ReflectionCache.cs +++ b/src/Neo/IO/Caching/ReflectionCache.cs @@ -15,29 +15,30 @@ namespace Neo.IO.Caching { - internal static class ReflectionCache where T : Enum + internal static class ReflectionCache + where T : Enum { - private static readonly Dictionary dictionary = new(); + private static readonly Dictionary s_dictionary = []; - public static int Count => dictionary.Count; + public static int Count => s_dictionary.Count; static ReflectionCache() { - foreach (FieldInfo field in typeof(T).GetFields(BindingFlags.Public | BindingFlags.Static)) + foreach (var field in typeof(T).GetFields(BindingFlags.Public | BindingFlags.Static)) { // Get attribute - ReflectionCacheAttribute attribute = field.GetCustomAttribute(); + var attribute = field.GetCustomAttribute(); if (attribute == null) continue; // Append to cache - dictionary.Add((T)field.GetValue(null), attribute.Type); + s_dictionary.Add((T)field.GetValue(null), attribute.Type); } } public static object CreateInstance(T key, object def = null) { // Get Type from cache - if (dictionary.TryGetValue(key, out Type t)) + if (s_dictionary.TryGetValue(key, out var t)) return Activator.CreateInstance(t); // return null @@ -46,7 +47,7 @@ public static object CreateInstance(T key, object def = null) public static ISerializable CreateSerializable(T key, ReadOnlyMemory data) { - if (dictionary.TryGetValue(key, out Type t)) + if (s_dictionary.TryGetValue(key, out var t)) return data.AsSerializable(t); return null; } diff --git a/src/Neo/IO/Caching/RelayCache.cs b/src/Neo/IO/Caching/RelayCache.cs index 0f617f4d24..56466d9a7f 100644 --- a/src/Neo/IO/Caching/RelayCache.cs +++ b/src/Neo/IO/Caching/RelayCache.cs @@ -13,13 +13,9 @@ namespace Neo.IO.Caching { - internal class RelayCache : FIFOCache + internal class RelayCache + (int max_capacity) : FIFOCache(max_capacity) { - public RelayCache(int max_capacity) - : base(max_capacity) - { - } - protected override UInt256 GetKeyForItem(IInventory item) { return item.Hash; diff --git a/src/Neo/SmartContract/StorageItem.cs b/src/Neo/SmartContract/StorageItem.cs index 84d3cc6354..199b31c7ec 100644 --- a/src/Neo/SmartContract/StorageItem.cs +++ b/src/Neo/SmartContract/StorageItem.cs @@ -9,6 +9,7 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using Neo.Extensions; using Neo.IO; using Neo.VM; using System; diff --git a/src/Neo/Wallets/Wallet.cs b/src/Neo/Wallets/Wallet.cs index dabe6049c6..d23bdcfb9f 100644 --- a/src/Neo/Wallets/Wallet.cs +++ b/src/Neo/Wallets/Wallet.cs @@ -10,6 +10,7 @@ // modifications are permitted. using Neo.Cryptography; +using Neo.Extensions; using Neo.IO; using Neo.Network.P2P.Payloads; using Neo.Persistence; diff --git a/tests/Neo.Extensions.Tests/Neo.Extensions.Tests.csproj b/tests/Neo.Extensions.Tests/Neo.Extensions.Tests.csproj new file mode 100644 index 0000000000..a2b2b20daf --- /dev/null +++ b/tests/Neo.Extensions.Tests/Neo.Extensions.Tests.csproj @@ -0,0 +1,23 @@ + + + + net8.0 + enable + + + + + + + + + + + + + + + + + + diff --git a/tests/Neo.Extensions.Tests/UT_BigIntegerExtensions.cs b/tests/Neo.Extensions.Tests/UT_BigIntegerExtensions.cs new file mode 100644 index 0000000000..b887d1c973 --- /dev/null +++ b/tests/Neo.Extensions.Tests/UT_BigIntegerExtensions.cs @@ -0,0 +1,47 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_BigIntegerExtensions.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using FluentAssertions; +using Neo.Extensions; +using System.Numerics; + +namespace Neo.Extensions.Tests +{ + [TestClass] + public class UT_BigIntegerExtensions + { + [TestMethod] + public void TestGetLowestSetBit() + { + var big1 = new BigInteger(0); + big1.GetLowestSetBit().Should().Be(-1); + + var big2 = new BigInteger(512); + big2.GetLowestSetBit().Should().Be(9); + + var big3 = new BigInteger(int.MinValue); + big3.GetLowestSetBit().Should().Be(31); + + var big4 = new BigInteger(long.MinValue); + big4.GetLowestSetBit().Should().Be(63); + } + + [TestMethod] + public void TestToByteArrayStandard() + { + BigInteger number = BigInteger.Zero; + Assert.AreEqual("", number.ToByteArrayStandard().ToHexString()); + + number = BigInteger.One; + Assert.AreEqual("01", number.ToByteArrayStandard().ToHexString()); + } + } +} diff --git a/tests/Neo.UnitTests/Neo.UnitTests.csproj b/tests/Neo.UnitTests/Neo.UnitTests.csproj index ce6d3b41a4..04be767fb7 100644 --- a/tests/Neo.UnitTests/Neo.UnitTests.csproj +++ b/tests/Neo.UnitTests/Neo.UnitTests.csproj @@ -22,6 +22,7 @@ + diff --git a/tests/Neo.UnitTests/UT_Helper.cs b/tests/Neo.UnitTests/UT_Helper.cs index b7dc4f1681..7fa3902cba 100644 --- a/tests/Neo.UnitTests/UT_Helper.cs +++ b/tests/Neo.UnitTests/UT_Helper.cs @@ -11,6 +11,7 @@ using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Extensions; using Neo.IO.Caching; using Neo.Network.P2P; using Neo.SmartContract; @@ -190,16 +191,6 @@ public void TestGetVersion() version.Should().Be("0.0.0"); } - [TestMethod] - public void TestToByteArrayStandard() - { - BigInteger number = BigInteger.Zero; - Assert.AreEqual("", number.ToByteArrayStandard().ToHexString()); - - number = BigInteger.One; - Assert.AreEqual("01", number.ToByteArrayStandard().ToHexString()); - } - [TestMethod] public void TestNextBigIntegerForRandom() { From f307a31cee4ba6d7a97c43058b73ba194efab9ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vitor=20Naz=C3=A1rio=20Coelho?= Date: Wed, 17 Jul 2024 03:35:12 -0300 Subject: [PATCH 49/71] Revert "Plugin unhandled exception (#3349)" (#3366) This reverts commit b2f060f11f5ac5713fc30255467100f0ff4c409d. Co-authored-by: Christopher Schuchardt --- src/Neo/Ledger/Blockchain.cs | 66 +------- src/Neo/Plugins/Plugin.cs | 56 +------ src/Neo/Plugins/PluginSettings.cs | 33 ---- src/Neo/Plugins/UnhandledExceptionPolicy.cs | 20 --- .../ApplicationLogs/ApplicationLogs.json | 3 +- src/Plugins/ApplicationLogs/LogReader.cs | 1 - src/Plugins/ApplicationLogs/Settings.cs | 4 +- src/Plugins/DBFTPlugin/DBFTPlugin.cs | 2 - src/Plugins/DBFTPlugin/DBFTPlugin.json | 3 +- src/Plugins/DBFTPlugin/Settings.cs | 4 +- src/Plugins/OracleService/OracleService.cs | 2 - src/Plugins/OracleService/OracleService.json | 1 - src/Plugins/OracleService/Settings.cs | 4 +- src/Plugins/RpcServer/RpcServer.json | 1 - src/Plugins/RpcServer/RpcServerPlugin.cs | 1 - src/Plugins/RpcServer/Settings.cs | 4 +- src/Plugins/StateService/Settings.cs | 4 +- src/Plugins/StateService/StatePlugin.cs | 2 - src/Plugins/StateService/StateService.json | 3 +- src/Plugins/StorageDumper/Settings.cs | 4 +- src/Plugins/StorageDumper/StorageDumper.cs | 2 +- src/Plugins/StorageDumper/StorageDumper.json | 3 +- src/Plugins/TokensTracker/TokensTracker.cs | 8 - src/Plugins/TokensTracker/TokensTracker.json | 3 +- tests/Neo.UnitTests/Plugins/TestPlugin.cs | 61 +------ tests/Neo.UnitTests/Plugins/UT_Plugin.cs | 151 ------------------ 26 files changed, 29 insertions(+), 417 deletions(-) delete mode 100644 src/Neo/Plugins/PluginSettings.cs delete mode 100644 src/Neo/Plugins/UnhandledExceptionPolicy.cs diff --git a/src/Neo/Ledger/Blockchain.cs b/src/Neo/Ledger/Blockchain.cs index e9e3cb0020..ca27bb2124 100644 --- a/src/Neo/Ledger/Blockchain.cs +++ b/src/Neo/Ledger/Blockchain.cs @@ -12,22 +12,18 @@ using Akka.Actor; using Akka.Configuration; using Akka.IO; -using Akka.Util.Internal; using Neo.IO.Actors; using Neo.Network.P2P; using Neo.Network.P2P.Payloads; using Neo.Persistence; -using Neo.Plugins; using Neo.SmartContract; using Neo.SmartContract.Native; using Neo.VM; using System; -using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; using System.Linq; -using System.Threading.Tasks; namespace Neo.Ledger { @@ -472,10 +468,10 @@ private void Persist(Block block) Context.System.EventStream.Publish(application_executed); all_application_executed.Add(application_executed); } - _ = InvokeCommittingAsync(system, block, snapshot, all_application_executed); + Committing?.Invoke(system, block, snapshot, all_application_executed); snapshot.Commit(); } - _ = InvokeCommittedAsync(system, block); + Committed?.Invoke(system, block); system.MemPool.UpdatePoolForBlockPersisted(block, system.StoreView); extensibleWitnessWhiteList = null; block_cache.Remove(block.PrevHash); @@ -484,64 +480,6 @@ private void Persist(Block block) Debug.Assert(header.Index == block.Index); } - internal static async Task InvokeCommittingAsync(NeoSystem system, Block block, DataCache snapshot, IReadOnlyList applicationExecutedList) - { - await InvokeHandlersAsync(Committing?.GetInvocationList(), h => ((CommittingHandler)h)(system, block, snapshot, applicationExecutedList)); - } - - internal static async Task InvokeCommittedAsync(NeoSystem system, Block block) - { - await InvokeHandlersAsync(Committed?.GetInvocationList(), h => ((CommittedHandler)h)(system, block)); - } - - private static async Task InvokeHandlersAsync(Delegate[] handlers, Action handlerAction) - { - if (handlers == null) return; - - var exceptions = new ConcurrentBag(); - var tasks = handlers.Select(handler => Task.Run(() => - { - try - { - // skip stopped plugin. - if (handler.Target is Plugin { IsStopped: true }) - { - return; - } - - handlerAction(handler); - } - catch (Exception ex) when (handler.Target is Plugin plugin) - { - switch (plugin.ExceptionPolicy) - { - case UnhandledExceptionPolicy.StopNode: - exceptions.Add(ex); - throw; - case UnhandledExceptionPolicy.StopPlugin: - //Stop plugin on exception - plugin.IsStopped = true; - break; - case UnhandledExceptionPolicy.Ignore: - // Log the exception and continue with the next handler - break; - default: - throw new InvalidCastException($"The exception policy {plugin.ExceptionPolicy} is not valid."); - } - - Utility.Log(nameof(plugin), LogLevel.Error, ex); - } - catch (Exception ex) - { - exceptions.Add(ex); - } - })).ToList(); - - await Task.WhenAll(tasks); - - exceptions.ForEach(e => throw e); - } - /// /// Gets a object used for creating the actor. /// diff --git a/src/Neo/Plugins/Plugin.cs b/src/Neo/Plugins/Plugin.cs index 9feee25d57..248301af56 100644 --- a/src/Neo/Plugins/Plugin.cs +++ b/src/Neo/Plugins/Plugin.cs @@ -33,8 +33,7 @@ public abstract class Plugin : IDisposable /// /// The directory containing the plugin folders. Files can be contained in any subdirectory. /// - public static readonly string PluginsDirectory = - Combine(GetDirectoryName(System.AppContext.BaseDirectory), "Plugins"); + public static readonly string PluginsDirectory = Combine(GetDirectoryName(System.AppContext.BaseDirectory), "Plugins"); private static readonly FileSystemWatcher configWatcher; @@ -68,18 +67,6 @@ public abstract class Plugin : IDisposable /// public virtual Version Version => GetType().Assembly.GetName().Version; - /// - /// If the plugin should be stopped when an exception is thrown. - /// Default is . - /// - protected internal virtual UnhandledExceptionPolicy ExceptionPolicy { get; init; } = UnhandledExceptionPolicy.StopNode; - - /// - /// The plugin will be stopped if an exception is thrown. - /// But it also depends on . - /// - internal bool IsStopped { get; set; } - static Plugin() { if (!Directory.Exists(PluginsDirectory)) return; @@ -87,8 +74,7 @@ static Plugin() { EnableRaisingEvents = true, IncludeSubdirectories = true, - NotifyFilter = NotifyFilters.FileName | NotifyFilters.DirectoryName | NotifyFilters.CreationTime | - NotifyFilters.LastWrite | NotifyFilters.Size, + NotifyFilter = NotifyFilters.FileName | NotifyFilters.DirectoryName | NotifyFilters.CreationTime | NotifyFilters.LastWrite | NotifyFilters.Size, }; configWatcher.Changed += ConfigWatcher_Changed; configWatcher.Created += ConfigWatcher_Changed; @@ -120,8 +106,7 @@ private static void ConfigWatcher_Changed(object sender, FileSystemEventArgs e) { case ".json": case ".dll": - Utility.Log(nameof(Plugin), LogLevel.Warning, - $"File {e.Name} is {e.ChangeType}, please restart node."); + Utility.Log(nameof(Plugin), LogLevel.Warning, $"File {e.Name} is {e.ChangeType}, please restart node."); break; } } @@ -134,8 +119,7 @@ private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEven AssemblyName an = new(args.Name); Assembly assembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(a => a.FullName == args.Name) ?? - AppDomain.CurrentDomain.GetAssemblies() - .FirstOrDefault(a => a.GetName().Name == an.Name); + AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(a => a.GetName().Name == an.Name); if (assembly != null) return assembly; string filename = an.Name + ".dll"; @@ -166,8 +150,7 @@ public virtual void Dispose() /// The content of the configuration file read. protected IConfigurationSection GetConfiguration() { - return new ConfigurationBuilder().AddJsonFile(ConfigFile, optional: true).Build() - .GetSection("PluginConfiguration"); + return new ConfigurationBuilder().AddJsonFile(ConfigFile, optional: true).Build().GetSection("PluginConfiguration"); } private static void LoadPlugin(Assembly assembly) @@ -204,7 +187,6 @@ internal static void LoadPlugins() catch { } } } - foreach (Assembly assembly in assemblies) { LoadPlugin(assembly); @@ -247,33 +229,7 @@ protected internal virtual void OnSystemLoaded(NeoSystem system) /// if the is handled by a plugin; otherwise, . public static bool SendMessage(object message) { - - return Plugins.Any(plugin => - { - try - { - return !plugin.IsStopped && - plugin.OnMessage(message); - } - catch (Exception ex) - { - switch (plugin.ExceptionPolicy) - { - case UnhandledExceptionPolicy.StopNode: - throw; - case UnhandledExceptionPolicy.StopPlugin: - plugin.IsStopped = true; - break; - case UnhandledExceptionPolicy.Ignore: - break; - default: - throw new InvalidCastException($"The exception policy {plugin.ExceptionPolicy} is not valid."); - } - Utility.Log(nameof(Plugin), LogLevel.Error, ex); - return false; - } - } - ); + return Plugins.Any(plugin => plugin.OnMessage(message)); } } } diff --git a/src/Neo/Plugins/PluginSettings.cs b/src/Neo/Plugins/PluginSettings.cs deleted file mode 100644 index af33e44eea..0000000000 --- a/src/Neo/Plugins/PluginSettings.cs +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (C) 2015-2024 The Neo Project. -// -// PluginSettings.cs file belongs to the neo project and is free -// software distributed under the MIT software license, see the -// accompanying file LICENSE in the main directory of the -// repository or http://www.opensource.org/licenses/mit-license.php -// for more details. -// -// Redistribution and use in source and binary forms with or without -// modifications are permitted. - -using Microsoft.Extensions.Configuration; -using Org.BouncyCastle.Security; -using System; - -namespace Neo.Plugins; - -public abstract class PluginSettings(IConfigurationSection section) -{ - public UnhandledExceptionPolicy ExceptionPolicy - { - get - { - var policyString = section.GetValue(nameof(UnhandledExceptionPolicy), nameof(UnhandledExceptionPolicy.StopNode)); - if (Enum.TryParse(policyString, out UnhandledExceptionPolicy policy)) - { - return policy; - } - - throw new InvalidParameterException($"{policyString} is not a valid UnhandledExceptionPolicy"); - } - } -} diff --git a/src/Neo/Plugins/UnhandledExceptionPolicy.cs b/src/Neo/Plugins/UnhandledExceptionPolicy.cs deleted file mode 100644 index 035e173aa3..0000000000 --- a/src/Neo/Plugins/UnhandledExceptionPolicy.cs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (C) 2015-2024 The Neo Project. -// -// UnhandledExceptionPolicy.cs file belongs to the neo project and is free -// software distributed under the MIT software license, see the -// accompanying file LICENSE in the main directory of the -// repository or http://www.opensource.org/licenses/mit-license.php -// for more details. -// -// Redistribution and use in source and binary forms with or without -// modifications are permitted. - -namespace Neo.Plugins -{ - public enum UnhandledExceptionPolicy - { - Ignore = 0, - StopPlugin = 1, - StopNode = 2, - } -} diff --git a/src/Plugins/ApplicationLogs/ApplicationLogs.json b/src/Plugins/ApplicationLogs/ApplicationLogs.json index 2664665dd2..af601bc81e 100644 --- a/src/Plugins/ApplicationLogs/ApplicationLogs.json +++ b/src/Plugins/ApplicationLogs/ApplicationLogs.json @@ -3,8 +3,7 @@ "Path": "ApplicationLogs_{0}", "Network": 860833102, "MaxStackSize": 65535, - "Debug": false, - "UnhandledExceptionPolicy": "StopPlugin" + "Debug": false }, "Dependency": [ "RpcServer" diff --git a/src/Plugins/ApplicationLogs/LogReader.cs b/src/Plugins/ApplicationLogs/LogReader.cs index b3f767fecb..e0e886d93b 100644 --- a/src/Plugins/ApplicationLogs/LogReader.cs +++ b/src/Plugins/ApplicationLogs/LogReader.cs @@ -38,7 +38,6 @@ public class LogReader : Plugin, ICommittingHandler, ICommittedHandler, ILogHand public override string Name => "ApplicationLogs"; public override string Description => "Synchronizes smart contract VM executions and notifications (NotifyLog) on blockchain."; - protected override UnhandledExceptionPolicy ExceptionPolicy => Settings.Default.ExceptionPolicy; #region Ctor diff --git a/src/Plugins/ApplicationLogs/Settings.cs b/src/Plugins/ApplicationLogs/Settings.cs index 6a5f238272..8f2a0da1e1 100644 --- a/src/Plugins/ApplicationLogs/Settings.cs +++ b/src/Plugins/ApplicationLogs/Settings.cs @@ -13,7 +13,7 @@ namespace Neo.Plugins.ApplicationLogs { - internal class Settings : PluginSettings + internal class Settings { public string Path { get; } public uint Network { get; } @@ -23,7 +23,7 @@ internal class Settings : PluginSettings public static Settings Default { get; private set; } - private Settings(IConfigurationSection section) : base(section) + private Settings(IConfigurationSection section) { Path = section.GetValue("Path", "ApplicationLogs_{0}"); Network = section.GetValue("Network", 5195086u); diff --git a/src/Plugins/DBFTPlugin/DBFTPlugin.cs b/src/Plugins/DBFTPlugin/DBFTPlugin.cs index 65fc5011dc..f09be9d291 100644 --- a/src/Plugins/DBFTPlugin/DBFTPlugin.cs +++ b/src/Plugins/DBFTPlugin/DBFTPlugin.cs @@ -31,8 +31,6 @@ public class DBFTPlugin : Plugin, IServiceAddedHandler, IMessageReceivedHandler, public override string ConfigFile => System.IO.Path.Combine(RootPath, "DBFTPlugin.json"); - protected override UnhandledExceptionPolicy ExceptionPolicy => settings.ExceptionPolicy; - public DBFTPlugin() { RemoteNode.MessageReceived += ((IMessageReceivedHandler)this).RemoteNode_MessageReceived_Handler; diff --git a/src/Plugins/DBFTPlugin/DBFTPlugin.json b/src/Plugins/DBFTPlugin/DBFTPlugin.json index 705b2b77cb..2e2b710ba3 100644 --- a/src/Plugins/DBFTPlugin/DBFTPlugin.json +++ b/src/Plugins/DBFTPlugin/DBFTPlugin.json @@ -5,7 +5,6 @@ "AutoStart": false, "Network": 860833102, "MaxBlockSize": 2097152, - "MaxBlockSystemFee": 150000000000, - "UnhandledExceptionPolicy": "StopNode" + "MaxBlockSystemFee": 150000000000 } } diff --git a/src/Plugins/DBFTPlugin/Settings.cs b/src/Plugins/DBFTPlugin/Settings.cs index 1f37feaf16..28ad21f37a 100644 --- a/src/Plugins/DBFTPlugin/Settings.cs +++ b/src/Plugins/DBFTPlugin/Settings.cs @@ -13,7 +13,7 @@ namespace Neo.Plugins.DBFTPlugin { - public class Settings : PluginSettings + public class Settings { public string RecoveryLogs { get; } public bool IgnoreRecoveryLogs { get; } @@ -22,7 +22,7 @@ public class Settings : PluginSettings public uint MaxBlockSize { get; } public long MaxBlockSystemFee { get; } - public Settings(IConfigurationSection section) : base(section) + public Settings(IConfigurationSection section) { RecoveryLogs = section.GetValue("RecoveryLogs", "ConsensusState"); IgnoreRecoveryLogs = section.GetValue("IgnoreRecoveryLogs", false); diff --git a/src/Plugins/OracleService/OracleService.cs b/src/Plugins/OracleService/OracleService.cs index bb5da83654..d7a54c5c9d 100644 --- a/src/Plugins/OracleService/OracleService.cs +++ b/src/Plugins/OracleService/OracleService.cs @@ -62,8 +62,6 @@ public class OracleService : Plugin, ICommittingHandler, IServiceAddedHandler, I public override string Description => "Built-in oracle plugin"; - protected override UnhandledExceptionPolicy ExceptionPolicy => Settings.Default.ExceptionPolicy; - public override string ConfigFile => System.IO.Path.Combine(RootPath, "OracleService.json"); public OracleService() diff --git a/src/Plugins/OracleService/OracleService.json b/src/Plugins/OracleService/OracleService.json index 49bf1153b3..1ab0d93399 100644 --- a/src/Plugins/OracleService/OracleService.json +++ b/src/Plugins/OracleService/OracleService.json @@ -6,7 +6,6 @@ "MaxOracleTimeout": 10000, "AllowPrivateHost": false, "AllowedContentTypes": [ "application/json" ], - "UnhandledExceptionPolicy": "Ignore", "Https": { "Timeout": 5000 }, diff --git a/src/Plugins/OracleService/Settings.cs b/src/Plugins/OracleService/Settings.cs index db93c1c400..952ea0c27b 100644 --- a/src/Plugins/OracleService/Settings.cs +++ b/src/Plugins/OracleService/Settings.cs @@ -37,7 +37,7 @@ public NeoFSSettings(IConfigurationSection section) } } - class Settings : PluginSettings + class Settings { public uint Network { get; } public Uri[] Nodes { get; } @@ -51,7 +51,7 @@ class Settings : PluginSettings public static Settings Default { get; private set; } - private Settings(IConfigurationSection section) : base(section) + private Settings(IConfigurationSection section) { Network = section.GetValue("Network", 5195086u); Nodes = section.GetSection("Nodes").GetChildren().Select(p => new Uri(p.Get(), UriKind.Absolute)).ToArray(); diff --git a/src/Plugins/RpcServer/RpcServer.json b/src/Plugins/RpcServer/RpcServer.json index dc9c25b8da..8f6905dead 100644 --- a/src/Plugins/RpcServer/RpcServer.json +++ b/src/Plugins/RpcServer/RpcServer.json @@ -1,6 +1,5 @@ { "PluginConfiguration": { - "UnhandledExceptionPolicy": "Ignore", "Servers": [ { "Network": 860833102, diff --git a/src/Plugins/RpcServer/RpcServerPlugin.cs b/src/Plugins/RpcServer/RpcServerPlugin.cs index 03416c1be5..c22462d139 100644 --- a/src/Plugins/RpcServer/RpcServerPlugin.cs +++ b/src/Plugins/RpcServer/RpcServerPlugin.cs @@ -24,7 +24,6 @@ public class RpcServerPlugin : Plugin private static readonly Dictionary> handlers = new(); public override string ConfigFile => System.IO.Path.Combine(RootPath, "RpcServer.json"); - protected override UnhandledExceptionPolicy ExceptionPolicy => settings.ExceptionPolicy; protected override void Configure() { diff --git a/src/Plugins/RpcServer/Settings.cs b/src/Plugins/RpcServer/Settings.cs index 2cf7b72fb8..ad624d9082 100644 --- a/src/Plugins/RpcServer/Settings.cs +++ b/src/Plugins/RpcServer/Settings.cs @@ -18,11 +18,11 @@ namespace Neo.Plugins.RpcServer { - class Settings : PluginSettings + class Settings { public IReadOnlyList Servers { get; init; } - public Settings(IConfigurationSection section) : base(section) + public Settings(IConfigurationSection section) { Servers = section.GetSection(nameof(Servers)).GetChildren().Select(p => RpcServerSettings.Load(p)).ToArray(); } diff --git a/src/Plugins/StateService/Settings.cs b/src/Plugins/StateService/Settings.cs index a425b57d7e..8557866bc1 100644 --- a/src/Plugins/StateService/Settings.cs +++ b/src/Plugins/StateService/Settings.cs @@ -13,7 +13,7 @@ namespace Neo.Plugins.StateService { - internal class Settings : PluginSettings + internal class Settings { public string Path { get; } public bool FullState { get; } @@ -23,7 +23,7 @@ internal class Settings : PluginSettings public static Settings Default { get; private set; } - private Settings(IConfigurationSection section) : base(section) + private Settings(IConfigurationSection section) { Path = section.GetValue("Path", "Data_MPT_{0}"); FullState = section.GetValue("FullState", false); diff --git a/src/Plugins/StateService/StatePlugin.cs b/src/Plugins/StateService/StatePlugin.cs index 03dcc55aac..5f6e1ef1d8 100644 --- a/src/Plugins/StateService/StatePlugin.cs +++ b/src/Plugins/StateService/StatePlugin.cs @@ -41,8 +41,6 @@ public class StatePlugin : Plugin, ICommittingHandler, ICommittedHandler, IWalle public override string Description => "Enables MPT for the node"; public override string ConfigFile => System.IO.Path.Combine(RootPath, "StateService.json"); - protected override UnhandledExceptionPolicy ExceptionPolicy => Settings.Default.ExceptionPolicy; - internal IActorRef Store; internal IActorRef Verifier; diff --git a/src/Plugins/StateService/StateService.json b/src/Plugins/StateService/StateService.json index cadd2da5fd..265436fc30 100644 --- a/src/Plugins/StateService/StateService.json +++ b/src/Plugins/StateService/StateService.json @@ -4,8 +4,7 @@ "FullState": false, "Network": 860833102, "AutoVerify": false, - "MaxFindResultItems": 100, - "UnhandledExceptionPolicy": "StopPlugin" + "MaxFindResultItems": 100 }, "Dependency": [ "RpcServer" diff --git a/src/Plugins/StorageDumper/Settings.cs b/src/Plugins/StorageDumper/Settings.cs index e645cd7074..c2761ce6b9 100644 --- a/src/Plugins/StorageDumper/Settings.cs +++ b/src/Plugins/StorageDumper/Settings.cs @@ -14,7 +14,7 @@ namespace Neo.Plugins.StorageDumper { - internal class Settings : PluginSettings + internal class Settings { /// /// Amount of storages states (heights) to be dump in a given json file @@ -32,7 +32,7 @@ internal class Settings : PluginSettings public static Settings? Default { get; private set; } - private Settings(IConfigurationSection section) : base(section) + private Settings(IConfigurationSection section) { // Geting settings for storage changes state dumper BlockCacheSize = section.GetValue("BlockCacheSize", 1000u); diff --git a/src/Plugins/StorageDumper/StorageDumper.cs b/src/Plugins/StorageDumper/StorageDumper.cs index 6f5498b3a2..c47df9ac1d 100644 --- a/src/Plugins/StorageDumper/StorageDumper.cs +++ b/src/Plugins/StorageDumper/StorageDumper.cs @@ -30,7 +30,7 @@ public class StorageDumper : Plugin, ICommittingHandler, ICommittedHandler /// private JObject? _currentBlock; private string? _lastCreateDirectory; - protected override UnhandledExceptionPolicy ExceptionPolicy => Settings.Default?.ExceptionPolicy ?? UnhandledExceptionPolicy.Ignore; + public override string Description => "Exports Neo-CLI status data"; diff --git a/src/Plugins/StorageDumper/StorageDumper.json b/src/Plugins/StorageDumper/StorageDumper.json index 0c314cf262..b327c37e0c 100644 --- a/src/Plugins/StorageDumper/StorageDumper.json +++ b/src/Plugins/StorageDumper/StorageDumper.json @@ -3,7 +3,6 @@ "BlockCacheSize": 1000, "HeightToBegin": 0, "StoragePerFolder": 100000, - "Exclude": [ -4 ], - "UnhandledExceptionPolicy": "Ignore" + "Exclude": [ -4 ] } } diff --git a/src/Plugins/TokensTracker/TokensTracker.cs b/src/Plugins/TokensTracker/TokensTracker.cs index a7ab075245..e5ffdce3f4 100644 --- a/src/Plugins/TokensTracker/TokensTracker.cs +++ b/src/Plugins/TokensTracker/TokensTracker.cs @@ -16,7 +16,6 @@ using Neo.Persistence; using Neo.Plugins.RpcServer; using Neo.Plugins.Trackers; -using System; using System.Collections.Generic; using System.Linq; using static System.IO.Path; @@ -31,10 +30,8 @@ public class TokensTracker : Plugin, ICommittingHandler, ICommittedHandler private uint _network; private string[] _enabledTrackers; private IStore _db; - private UnhandledExceptionPolicy _exceptionPolicy; private NeoSystem neoSystem; private readonly List trackers = new(); - protected override UnhandledExceptionPolicy ExceptionPolicy => _exceptionPolicy; public override string Description => "Enquiries balances and transaction history of accounts through RPC"; @@ -60,11 +57,6 @@ protected override void Configure() _maxResults = config.GetValue("MaxResults", 1000u); _network = config.GetValue("Network", 860833102u); _enabledTrackers = config.GetSection("EnabledTrackers").GetChildren().Select(p => p.Value).ToArray(); - var policyString = config.GetValue(nameof(UnhandledExceptionPolicy), nameof(UnhandledExceptionPolicy.StopNode)); - if (Enum.TryParse(policyString, out UnhandledExceptionPolicy policy)) - { - _exceptionPolicy = policy; - } } protected override void OnSystemLoaded(NeoSystem system) diff --git a/src/Plugins/TokensTracker/TokensTracker.json b/src/Plugins/TokensTracker/TokensTracker.json index dbdbecfd40..ca63183b68 100644 --- a/src/Plugins/TokensTracker/TokensTracker.json +++ b/src/Plugins/TokensTracker/TokensTracker.json @@ -4,8 +4,7 @@ "TrackHistory": true, "MaxResults": 1000, "Network": 860833102, - "EnabledTrackers": [ "NEP-11", "NEP-17" ], - "UnhandledExceptionPolicy": "StopPlugin" + "EnabledTrackers": [ "NEP-11", "NEP-17" ] }, "Dependency": [ "RpcServer" diff --git a/tests/Neo.UnitTests/Plugins/TestPlugin.cs b/tests/Neo.UnitTests/Plugins/TestPlugin.cs index 5e51220c7f..dde500b927 100644 --- a/tests/Neo.UnitTests/Plugins/TestPlugin.cs +++ b/tests/Neo.UnitTests/Plugins/TestPlugin.cs @@ -10,60 +10,15 @@ // modifications are permitted. using Microsoft.Extensions.Configuration; -using Neo.Ledger; -using Neo.Network.P2P.Payloads; -using Neo.Persistence; using Neo.Plugins; -using System; -using System.Collections.Generic; namespace Neo.UnitTests.Plugins { - - internal class TestPluginSettings(IConfigurationSection section) : PluginSettings(section) - { - public static TestPluginSettings Default { get; private set; } - public static void Load(IConfigurationSection section) - { - Default = new TestPluginSettings(section); - } - } - internal class TestNonPlugin - { - public TestNonPlugin() - { - Blockchain.Committing += OnCommitting; - Blockchain.Committed += OnCommitted; - } - - private void OnCommitting(NeoSystem system, Block block, DataCache snapshot, IReadOnlyList applicationExecutedList) - { - throw new NotImplementedException("Test exception from OnCommitting"); - } - - private void OnCommitted(NeoSystem system, Block block) - { - throw new NotImplementedException("Test exception from OnCommitted"); - } - } - - - internal class TestPlugin : Plugin + public class TestPlugin : Plugin { - private readonly UnhandledExceptionPolicy _exceptionPolicy; - protected internal override UnhandledExceptionPolicy ExceptionPolicy => _exceptionPolicy; + public TestPlugin() : base() { } - public TestPlugin(UnhandledExceptionPolicy exceptionPolicy = UnhandledExceptionPolicy.StopPlugin) : base() - { - Blockchain.Committing += OnCommitting; - Blockchain.Committed += OnCommitted; - _exceptionPolicy = exceptionPolicy; - } - - protected override void Configure() - { - TestPluginSettings.Load(GetConfiguration()); - } + protected override void Configure() { } public void LogMessage(string message) { @@ -81,15 +36,5 @@ public IConfigurationSection TestGetConfiguration() } protected override bool OnMessage(object message) => true; - - private void OnCommitting(NeoSystem system, Block block, DataCache snapshot, IReadOnlyList applicationExecutedList) - { - throw new NotImplementedException(); - } - - private void OnCommitted(NeoSystem system, Block block) - { - throw new NotImplementedException(); - } } } diff --git a/tests/Neo.UnitTests/Plugins/UT_Plugin.cs b/tests/Neo.UnitTests/Plugins/UT_Plugin.cs index c48d32563f..e5e8cb6e49 100644 --- a/tests/Neo.UnitTests/Plugins/UT_Plugin.cs +++ b/tests/Neo.UnitTests/Plugins/UT_Plugin.cs @@ -11,11 +11,8 @@ using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; -using Neo.Ledger; using Neo.Plugins; using System; -using System.Reflection; -using System.Threading.Tasks; namespace Neo.UnitTests.Plugins { @@ -24,50 +21,6 @@ public class UT_Plugin { private static readonly object locker = new(); - [TestInitialize] - public void TestInitialize() - { - ClearEventHandlers(); - } - - [TestCleanup] - public void TestCleanup() - { - ClearEventHandlers(); - } - - private static void ClearEventHandlers() - { - ClearEventHandler("Committing"); - ClearEventHandler("Committed"); - } - - private static void ClearEventHandler(string eventName) - { - var eventInfo = typeof(Blockchain).GetEvent(eventName, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); - if (eventInfo == null) - { - return; - } - - var fields = typeof(Blockchain).GetFields(BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public); - foreach (var field in fields) - { - if (field.FieldType == typeof(MulticastDelegate) || field.FieldType.BaseType == typeof(MulticastDelegate)) - { - var eventDelegate = (MulticastDelegate)field.GetValue(null); - if (eventDelegate != null && field.Name.Contains(eventName)) - { - foreach (var handler in eventDelegate.GetInvocationList()) - { - eventInfo.RemoveEventHandler(null, handler); - } - break; - } - } - } - } - [TestMethod] public void TestGetConfigFile() { @@ -110,109 +63,5 @@ public void TestGetConfiguration() var pp = new TestPlugin(); pp.TestGetConfiguration().Key.Should().Be("PluginConfiguration"); } - - [TestMethod] - public async Task TestOnException() - { - _ = new TestPlugin(); - // Ensure no exception is thrown - try - { - await Blockchain.InvokeCommittingAsync(null, null, null, null); - await Blockchain.InvokeCommittedAsync(null, null); - } - catch (Exception ex) - { - Assert.Fail($"InvokeCommitting or InvokeCommitted threw an exception: {ex.Message}"); - } - - // Register TestNonPlugin that throws exceptions - _ = new TestNonPlugin(); - - // Ensure exception is thrown - await Assert.ThrowsExceptionAsync(async () => - { - await Blockchain.InvokeCommittingAsync(null, null, null, null); - }); - - await Assert.ThrowsExceptionAsync(async () => - { - await Blockchain.InvokeCommittedAsync(null, null); - }); - } - - [TestMethod] - public async Task TestOnPluginStopped() - { - var pp = new TestPlugin(); - Assert.AreEqual(false, pp.IsStopped); - // Ensure no exception is thrown - try - { - await Blockchain.InvokeCommittingAsync(null, null, null, null); - await Blockchain.InvokeCommittedAsync(null, null); - } - catch (Exception ex) - { - Assert.Fail($"InvokeCommitting or InvokeCommitted threw an exception: {ex.Message}"); - } - - Assert.AreEqual(true, pp.IsStopped); - } - - [TestMethod] - public async Task TestOnPluginStopOnException() - { - // pp will stop on exception. - var pp = new TestPlugin(); - Assert.AreEqual(false, pp.IsStopped); - // Ensure no exception is thrown - try - { - await Blockchain.InvokeCommittingAsync(null, null, null, null); - await Blockchain.InvokeCommittedAsync(null, null); - } - catch (Exception ex) - { - Assert.Fail($"InvokeCommitting or InvokeCommitted threw an exception: {ex.Message}"); - } - - Assert.AreEqual(true, pp.IsStopped); - - // pp2 will not stop on exception. - var pp2 = new TestPlugin(UnhandledExceptionPolicy.Ignore); - Assert.AreEqual(false, pp2.IsStopped); - // Ensure no exception is thrown - try - { - await Blockchain.InvokeCommittingAsync(null, null, null, null); - await Blockchain.InvokeCommittedAsync(null, null); - } - catch (Exception ex) - { - Assert.Fail($"InvokeCommitting or InvokeCommitted threw an exception: {ex.Message}"); - } - - Assert.AreEqual(false, pp2.IsStopped); - } - - [TestMethod] - public async Task TestOnNodeStopOnPluginException() - { - // node will stop on pp exception. - var pp = new TestPlugin(UnhandledExceptionPolicy.StopNode); - Assert.AreEqual(false, pp.IsStopped); - await Assert.ThrowsExceptionAsync(async () => - { - await Blockchain.InvokeCommittingAsync(null, null, null, null); - }); - - await Assert.ThrowsExceptionAsync(async () => - { - await Blockchain.InvokeCommittedAsync(null, null); - }); - - Assert.AreEqual(false, pp.IsStopped); - } } } From e73fc009786d856b91f5cfa887f5692c3d984e24 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Mon, 22 Jul 2024 10:55:42 +0800 Subject: [PATCH 50/71] fix obsolete warning (#3428) --- src/Neo.CLI/CLI/MainService.Blockchain.cs | 2 +- src/Plugins/OracleService/OracleService.cs | 4 +-- src/Plugins/RpcServer/RpcServer.Wallet.cs | 2 +- .../Trackers/NEP-11/Nep11Tracker.cs | 2 +- .../UT_RpcServer.Blockchain.cs | 4 +-- .../UT_RpcServer.Node.cs | 26 +++++++++---------- 6 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/Neo.CLI/CLI/MainService.Blockchain.cs b/src/Neo.CLI/CLI/MainService.Blockchain.cs index 090939de49..2ac9c46ea4 100644 --- a/src/Neo.CLI/CLI/MainService.Blockchain.cs +++ b/src/Neo.CLI/CLI/MainService.Blockchain.cs @@ -82,7 +82,7 @@ private void OnShowBlockCommand(string indexOrHash) ConsoleHelper.Info("", " PrevHash: ", $"{block.PrevHash}"); ConsoleHelper.Info("", " NextConsensus: ", $"{block.NextConsensus}"); ConsoleHelper.Info("", " PrimaryIndex: ", $"{block.PrimaryIndex}"); - ConsoleHelper.Info("", " PrimaryPubKey: ", $"{NativeContract.NEO.GetCommittee(NeoSystem.GetSnapshot())[block.PrimaryIndex]}"); + ConsoleHelper.Info("", " PrimaryPubKey: ", $"{NativeContract.NEO.GetCommittee(NeoSystem.GetSnapshotCache())[block.PrimaryIndex]}"); ConsoleHelper.Info("", " Version: ", $"{block.Version}"); ConsoleHelper.Info("", " Size: ", $"{block.Size} Byte(s)"); ConsoleHelper.Info(); diff --git a/src/Plugins/OracleService/OracleService.cs b/src/Plugins/OracleService/OracleService.cs index d7a54c5c9d..3f14c8eab8 100644 --- a/src/Plugins/OracleService/OracleService.cs +++ b/src/Plugins/OracleService/OracleService.cs @@ -234,7 +234,7 @@ public JObject SubmitOracleResponse(JArray _params) finishedCache.ContainsKey(requestId).False_Or(RpcError.OracleRequestFinished); - using (var snapshot = _system.GetSnapshot()) + using (var snapshot = _system.GetSnapshotCache()) { uint height = NativeContract.Ledger.CurrentIndex(snapshot) + 1; var oracles = NativeContract.RoleManagement.GetDesignatedByRole(snapshot, Role.Oracle, height); @@ -326,7 +326,7 @@ private async void ProcessRequestsAsync() { while (!cancelSource.IsCancellationRequested) { - using (var snapshot = _system.GetSnapshot()) + using (var snapshot = _system.GetSnapshotCache()) { SyncPendingQueue(snapshot); foreach (var (id, request) in NativeContract.Oracle.GetRequests(snapshot)) diff --git a/src/Plugins/RpcServer/RpcServer.Wallet.cs b/src/Plugins/RpcServer/RpcServer.Wallet.cs index ab5724e588..155c56d91b 100644 --- a/src/Plugins/RpcServer/RpcServer.Wallet.cs +++ b/src/Plugins/RpcServer/RpcServer.Wallet.cs @@ -97,7 +97,7 @@ protected virtual JToken GetWalletUnclaimedGas(JArray _params) CheckWallet(); // Datoshi is the smallest unit of GAS, 1 GAS = 10^8 Datoshi BigInteger datoshi = BigInteger.Zero; - using (var snapshot = system.GetSnapshot()) + using (var snapshot = system.GetSnapshotCache()) { uint height = NativeContract.Ledger.CurrentIndex(snapshot) + 1; foreach (UInt160 account in wallet.GetAccounts().Select(p => p.ScriptHash)) diff --git a/src/Plugins/TokensTracker/Trackers/NEP-11/Nep11Tracker.cs b/src/Plugins/TokensTracker/Trackers/NEP-11/Nep11Tracker.cs index 12d3c208bc..a799e79a7a 100644 --- a/src/Plugins/TokensTracker/Trackers/NEP-11/Nep11Tracker.cs +++ b/src/Plugins/TokensTracker/Trackers/NEP-11/Nep11Tracker.cs @@ -283,7 +283,7 @@ public JToken GetNep11Properties(JArray _params) using ScriptBuilder sb = new(); sb.EmitDynamicCall(nep11Hash, "properties", CallFlags.ReadOnly, tokenId); - using var snapshot = _neoSystem.GetSnapshot(); + using var snapshot = _neoSystem.GetSnapshotCache(); using var engine = ApplicationEngine.Run(sb.ToArray(), snapshot, settings: _neoSystem.Settings); JObject json = new(); diff --git a/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Blockchain.cs b/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Blockchain.cs index c9007f6580..ab5693937f 100644 --- a/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Blockchain.cs +++ b/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Blockchain.cs @@ -239,7 +239,7 @@ public void TestGetCandidates() var json = new JArray(); var validators = NativeContract.NEO.GetNextBlockValidators(snapshot, _neoSystem.Settings.ValidatorsCount); snapshot.Commit(); - var candidates = NativeContract.NEO.GetCandidates(_neoSystem.GetSnapshot()); + var candidates = NativeContract.NEO.GetCandidates(_neoSystem.GetSnapshotCache()); foreach (var candidate in candidates) { @@ -266,7 +266,7 @@ public void TestGetCommittee() public void TestGetNativeContracts() { var result = _rpcServer.GetNativeContracts(new JArray()); - var contracts = new JArray(NativeContract.Contracts.Select(p => NativeContract.ContractManagement.GetContract(_neoSystem.GetSnapshot(), p.Hash).ToJson())); + var contracts = new JArray(NativeContract.Contracts.Select(p => NativeContract.ContractManagement.GetContract(_neoSystem.GetSnapshotCache(), p.Hash).ToJson())); Assert.AreEqual(contracts.ToString(), result.ToString()); } diff --git a/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Node.cs b/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Node.cs index b75706e001..413df59441 100644 --- a/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Node.cs +++ b/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Node.cs @@ -49,7 +49,7 @@ public void TestGetVersion() [TestMethod] public void TestSendRawTransaction_Normal() { - var snapshot = _neoSystem.GetSnapshot(); + var snapshot = _neoSystem.GetSnapshotCache(); var tx = TestUtils.CreateValidTx(snapshot, _wallet, _walletAccount); var txString = Convert.ToBase64String(tx.ToArray()); @@ -69,7 +69,7 @@ public void TestSendRawTransaction_InvalidTransactionFormat() [TestMethod] public void TestSendRawTransaction_InsufficientBalance() { - var snapshot = _neoSystem.GetSnapshot(); + var snapshot = _neoSystem.GetSnapshotCache(); var tx = TestUtils.CreateInvalidTransaction(snapshot, _wallet, _walletAccount, TestUtils.InvalidTransactionType.InsufficientBalance); var txString = Convert.ToBase64String(tx.ToArray()); @@ -82,7 +82,7 @@ public void TestSendRawTransaction_InsufficientBalance() [TestMethod] public void TestSendRawTransaction_InvalidSignature() { - var snapshot = _neoSystem.GetSnapshot(); + var snapshot = _neoSystem.GetSnapshotCache(); var tx = TestUtils.CreateInvalidTransaction(snapshot, _wallet, _walletAccount, TestUtils.InvalidTransactionType.InvalidSignature); var txString = Convert.ToBase64String(tx.ToArray()); @@ -95,7 +95,7 @@ public void TestSendRawTransaction_InvalidSignature() [TestMethod] public void TestSendRawTransaction_InvalidScript() { - var snapshot = _neoSystem.GetSnapshot(); + var snapshot = _neoSystem.GetSnapshotCache(); var tx = TestUtils.CreateInvalidTransaction(snapshot, _wallet, _walletAccount, TestUtils.InvalidTransactionType.InvalidScript); var txString = Convert.ToBase64String(tx.ToArray()); @@ -108,7 +108,7 @@ public void TestSendRawTransaction_InvalidScript() [TestMethod] public void TestSendRawTransaction_InvalidAttribute() { - var snapshot = _neoSystem.GetSnapshot(); + var snapshot = _neoSystem.GetSnapshotCache(); var tx = TestUtils.CreateInvalidTransaction(snapshot, _wallet, _walletAccount, TestUtils.InvalidTransactionType.InvalidAttribute); var txString = Convert.ToBase64String(tx.ToArray()); @@ -123,7 +123,7 @@ public void TestSendRawTransaction_InvalidAttribute() [TestMethod] public void TestSendRawTransaction_Oversized() { - var snapshot = _neoSystem.GetSnapshot(); + var snapshot = _neoSystem.GetSnapshotCache(); var tx = TestUtils.CreateInvalidTransaction(snapshot, _wallet, _walletAccount, TestUtils.InvalidTransactionType.Oversized); var txString = Convert.ToBase64String(tx.ToArray()); @@ -137,7 +137,7 @@ public void TestSendRawTransaction_Oversized() [TestMethod] public void TestSendRawTransaction_Expired() { - var snapshot = _neoSystem.GetSnapshot(); + var snapshot = _neoSystem.GetSnapshotCache(); var tx = TestUtils.CreateInvalidTransaction(snapshot, _wallet, _walletAccount, TestUtils.InvalidTransactionType.Expired); var txString = Convert.ToBase64String(tx.ToArray()); @@ -150,7 +150,7 @@ public void TestSendRawTransaction_Expired() [TestMethod] public void TestSendRawTransaction_PolicyFailed() { - var snapshot = _neoSystem.GetSnapshot(); + var snapshot = _neoSystem.GetSnapshotCache(); var tx = TestUtils.CreateValidTx(snapshot, _wallet, _walletAccount); var txString = Convert.ToBase64String(tx.ToArray()); NativeContract.Policy.BlockAccount(snapshot, _walletAccount.ScriptHash); @@ -165,7 +165,7 @@ public void TestSendRawTransaction_PolicyFailed() [TestMethod] public void TestSendRawTransaction_AlreadyInPool() { - var snapshot = _neoSystem.GetSnapshot(); + var snapshot = _neoSystem.GetSnapshotCache(); var tx = TestUtils.CreateValidTx(snapshot, _wallet, _walletAccount); _neoSystem.MemPool.TryAdd(tx, snapshot); var txString = Convert.ToBase64String(tx.ToArray()); @@ -179,7 +179,7 @@ public void TestSendRawTransaction_AlreadyInPool() [TestMethod] public void TestSendRawTransaction_AlreadyInBlockchain() { - var snapshot = _neoSystem.GetSnapshot(); + var snapshot = _neoSystem.GetSnapshotCache(); var tx = TestUtils.CreateValidTx(snapshot, _wallet, _walletAccount); TestUtils.AddTransactionToBlockchain(snapshot, tx); snapshot.Commit(); @@ -195,7 +195,7 @@ public void TestSendRawTransaction_AlreadyInBlockchain() [TestMethod] public void TestSubmitBlock_Normal() { - var snapshot = _neoSystem.GetSnapshot(); + var snapshot = _neoSystem.GetSnapshotCache(); var block = TestUtils.CreateBlockWithValidTransactions(snapshot, _wallet, _walletAccount, 1); var blockString = Convert.ToBase64String(block.ToArray()); @@ -220,7 +220,7 @@ public void TestSubmitBlock_InvalidBlockFormat() [TestMethod] public void TestSubmitBlock_AlreadyExists() { - var snapshot = _neoSystem.GetSnapshot(); + var snapshot = _neoSystem.GetSnapshotCache(); var block = TestUtils.CreateBlockWithValidTransactions(snapshot, _wallet, _walletAccount, 1); TestUtils.BlocksAdd(snapshot, block.Hash, block); snapshot.Commit(); @@ -235,7 +235,7 @@ public void TestSubmitBlock_AlreadyExists() [TestMethod] public void TestSubmitBlock_InvalidBlock() { - var snapshot = _neoSystem.GetSnapshot(); + var snapshot = _neoSystem.GetSnapshotCache(); var block = TestUtils.CreateBlockWithValidTransactions(snapshot, _wallet, _walletAccount, 1); block.Header.Witness = new Witness(); var blockString = Convert.ToBase64String(block.ToArray()); From 79a539f3928f656b37b4a24a92546ae2ca39cf6d Mon Sep 17 00:00:00 2001 From: Anna Shaleva Date: Mon, 22 Jul 2024 09:52:26 +0300 Subject: [PATCH 51/71] Neo.CLI: update MaxTraceableBlocks setting for NeoFS networks (#3424) We don't need long tails for NeoFS networks, 3 days is enough for now. It's checked that this change does not affect the network states. Port https://github.com/nspcc-dev/neo-go/pull/3518. Signed-off-by: Anna Shaleva Co-authored-by: NGD Admin <154295625+NGDAdmin@users.noreply.github.com> --- src/Neo.CLI/config.fs.mainnet.json | 2 +- src/Neo.CLI/config.fs.testnet.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Neo.CLI/config.fs.mainnet.json b/src/Neo.CLI/config.fs.mainnet.json index 3ec4eda871..6879232732 100644 --- a/src/Neo.CLI/config.fs.mainnet.json +++ b/src/Neo.CLI/config.fs.mainnet.json @@ -33,7 +33,7 @@ "MillisecondsPerBlock": 15000, "MaxTransactionsPerBlock": 512, "MemoryPoolMaxTransactions": 50000, - "MaxTraceableBlocks": 2102400, + "MaxTraceableBlocks": 17280, "InitialGasDistribution": 5200000000000000, "ValidatorsCount": 7, "Hardforks": { diff --git a/src/Neo.CLI/config.fs.testnet.json b/src/Neo.CLI/config.fs.testnet.json index 4e9468e2c6..9dc2d3b72f 100644 --- a/src/Neo.CLI/config.fs.testnet.json +++ b/src/Neo.CLI/config.fs.testnet.json @@ -33,7 +33,7 @@ "MillisecondsPerBlock": 15000, "MaxTransactionsPerBlock": 512, "MemoryPoolMaxTransactions": 50000, - "MaxTraceableBlocks": 2102400, + "MaxTraceableBlocks": 17280, "InitialGasDistribution": 5200000000000000, "ValidatorsCount": 7, "StandbyCommittee": [ From d0a202879af0b88f44095e9d48ee50216b5cdf64 Mon Sep 17 00:00:00 2001 From: Christopher Schuchardt Date: Mon, 22 Jul 2024 02:59:00 -0400 Subject: [PATCH 52/71] Upgrade `nuget` packages (#3421) Co-authored-by: NGD Admin <154295625+NGDAdmin@users.noreply.github.com> --- src/Neo.Extensions/Neo.Extensions.csproj | 2 +- src/Neo/Neo.csproj | 4 ++-- src/Plugins/RocksDBStore/RocksDBStore.csproj | 2 +- src/Plugins/SQLiteWallet/SQLiteWallet.csproj | 2 +- .../Neo.ConsoleService.Tests.csproj | 6 +++--- .../Neo.Cryptography.BLS12_381.Tests.csproj | 6 +++--- .../Neo.Cryptography.MPTTrie.Tests.csproj | 6 +++--- tests/Neo.Extensions.Tests/Neo.Extensions.Tests.csproj | 6 +++--- tests/Neo.Json.UnitTests/Neo.Json.UnitTests.csproj | 6 +++--- .../Neo.Network.RPC.Tests/Neo.Network.RPC.Tests.csproj | 6 +++--- .../Neo.Plugins.OracleService.Tests.csproj | 10 +++++----- .../Neo.Plugins.RpcServer.Tests.csproj | 6 +++--- .../Neo.Plugins.Storage.Tests.csproj | 6 +++--- tests/Neo.UnitTests/Neo.UnitTests.csproj | 10 +++++----- tests/Neo.VM.Tests/Neo.VM.Tests.csproj | 6 +++--- 15 files changed, 42 insertions(+), 42 deletions(-) diff --git a/src/Neo.Extensions/Neo.Extensions.csproj b/src/Neo.Extensions/Neo.Extensions.csproj index aa79170ddb..cc5325843a 100644 --- a/src/Neo.Extensions/Neo.Extensions.csproj +++ b/src/Neo.Extensions/Neo.Extensions.csproj @@ -9,7 +9,7 @@ - + diff --git a/src/Neo/Neo.csproj b/src/Neo/Neo.csproj index 835224eddd..238333372b 100644 --- a/src/Neo/Neo.csproj +++ b/src/Neo/Neo.csproj @@ -9,12 +9,12 @@ - + - + diff --git a/src/Plugins/RocksDBStore/RocksDBStore.csproj b/src/Plugins/RocksDBStore/RocksDBStore.csproj index d23f089160..90ed2e841a 100644 --- a/src/Plugins/RocksDBStore/RocksDBStore.csproj +++ b/src/Plugins/RocksDBStore/RocksDBStore.csproj @@ -8,7 +8,7 @@ - + diff --git a/src/Plugins/SQLiteWallet/SQLiteWallet.csproj b/src/Plugins/SQLiteWallet/SQLiteWallet.csproj index 041233af79..b8a1646e65 100644 --- a/src/Plugins/SQLiteWallet/SQLiteWallet.csproj +++ b/src/Plugins/SQLiteWallet/SQLiteWallet.csproj @@ -9,7 +9,7 @@ - + diff --git a/tests/Neo.ConsoleService.Tests/Neo.ConsoleService.Tests.csproj b/tests/Neo.ConsoleService.Tests/Neo.ConsoleService.Tests.csproj index 6562480859..469a49e548 100644 --- a/tests/Neo.ConsoleService.Tests/Neo.ConsoleService.Tests.csproj +++ b/tests/Neo.ConsoleService.Tests/Neo.ConsoleService.Tests.csproj @@ -10,9 +10,9 @@ - - - + + + diff --git a/tests/Neo.Cryptography.BLS12_381.Tests/Neo.Cryptography.BLS12_381.Tests.csproj b/tests/Neo.Cryptography.BLS12_381.Tests/Neo.Cryptography.BLS12_381.Tests.csproj index 999bc1c5f4..827c547041 100644 --- a/tests/Neo.Cryptography.BLS12_381.Tests/Neo.Cryptography.BLS12_381.Tests.csproj +++ b/tests/Neo.Cryptography.BLS12_381.Tests/Neo.Cryptography.BLS12_381.Tests.csproj @@ -11,9 +11,9 @@ - - - + + + diff --git a/tests/Neo.Cryptography.MPTTrie.Tests/Neo.Cryptography.MPTTrie.Tests.csproj b/tests/Neo.Cryptography.MPTTrie.Tests/Neo.Cryptography.MPTTrie.Tests.csproj index 3691fba90a..ed23c8a909 100644 --- a/tests/Neo.Cryptography.MPTTrie.Tests/Neo.Cryptography.MPTTrie.Tests.csproj +++ b/tests/Neo.Cryptography.MPTTrie.Tests/Neo.Cryptography.MPTTrie.Tests.csproj @@ -6,9 +6,9 @@ - - - + + + diff --git a/tests/Neo.Extensions.Tests/Neo.Extensions.Tests.csproj b/tests/Neo.Extensions.Tests/Neo.Extensions.Tests.csproj index a2b2b20daf..3c13dd0953 100644 --- a/tests/Neo.Extensions.Tests/Neo.Extensions.Tests.csproj +++ b/tests/Neo.Extensions.Tests/Neo.Extensions.Tests.csproj @@ -6,9 +6,9 @@ - - - + + + diff --git a/tests/Neo.Json.UnitTests/Neo.Json.UnitTests.csproj b/tests/Neo.Json.UnitTests/Neo.Json.UnitTests.csproj index 81e70ebbe1..c931c287a4 100644 --- a/tests/Neo.Json.UnitTests/Neo.Json.UnitTests.csproj +++ b/tests/Neo.Json.UnitTests/Neo.Json.UnitTests.csproj @@ -10,9 +10,9 @@ - - - + + + 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 13a13f5c98..fc632685b4 100644 --- a/tests/Neo.Network.RPC.Tests/Neo.Network.RPC.Tests.csproj +++ b/tests/Neo.Network.RPC.Tests/Neo.Network.RPC.Tests.csproj @@ -7,9 +7,9 @@ - - - + + + diff --git a/tests/Neo.Plugins.OracleService.Tests/Neo.Plugins.OracleService.Tests.csproj b/tests/Neo.Plugins.OracleService.Tests/Neo.Plugins.OracleService.Tests.csproj index 4dd4abbfa4..d192f37ea7 100644 --- a/tests/Neo.Plugins.OracleService.Tests/Neo.Plugins.OracleService.Tests.csproj +++ b/tests/Neo.Plugins.OracleService.Tests/Neo.Plugins.OracleService.Tests.csproj @@ -7,11 +7,11 @@ - - - - - + + + + + diff --git a/tests/Neo.Plugins.RpcServer.Tests/Neo.Plugins.RpcServer.Tests.csproj b/tests/Neo.Plugins.RpcServer.Tests/Neo.Plugins.RpcServer.Tests.csproj index 1586b9753d..b7e2ec91ac 100644 --- a/tests/Neo.Plugins.RpcServer.Tests/Neo.Plugins.RpcServer.Tests.csproj +++ b/tests/Neo.Plugins.RpcServer.Tests/Neo.Plugins.RpcServer.Tests.csproj @@ -8,10 +8,10 @@ - + - - + + 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 3e06cf32ca..3d2031e4d5 100644 --- a/tests/Neo.Plugins.Storage.Tests/Neo.Plugins.Storage.Tests.csproj +++ b/tests/Neo.Plugins.Storage.Tests/Neo.Plugins.Storage.Tests.csproj @@ -6,9 +6,9 @@ - - - + + + diff --git a/tests/Neo.UnitTests/Neo.UnitTests.csproj b/tests/Neo.UnitTests/Neo.UnitTests.csproj index 04be767fb7..54320cd223 100644 --- a/tests/Neo.UnitTests/Neo.UnitTests.csproj +++ b/tests/Neo.UnitTests/Neo.UnitTests.csproj @@ -6,8 +6,8 @@ - - + + @@ -27,9 +27,9 @@ - - - + + + diff --git a/tests/Neo.VM.Tests/Neo.VM.Tests.csproj b/tests/Neo.VM.Tests/Neo.VM.Tests.csproj index 53c16ed4af..2766ce05d2 100644 --- a/tests/Neo.VM.Tests/Neo.VM.Tests.csproj +++ b/tests/Neo.VM.Tests/Neo.VM.Tests.csproj @@ -17,9 +17,9 @@ - - - + + + From d8a4564444a7c9ae9fce4319c47f48fb95a2483d Mon Sep 17 00:00:00 2001 From: Jimmy Date: Mon, 22 Jul 2024 16:53:35 +0800 Subject: [PATCH 53/71] [Neo Core Fix]use strong randomness (#3432) * use strong randomness * Update src/Plugins/DBFTPlugin/Consensus/ConsensusContext.MakePayload.cs --------- Co-authored-by: Shargon Co-authored-by: NGD Admin <154295625+NGDAdmin@users.noreply.github.com> --- .../Consensus/ConsensusContext.MakePayload.cs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/Plugins/DBFTPlugin/Consensus/ConsensusContext.MakePayload.cs b/src/Plugins/DBFTPlugin/Consensus/ConsensusContext.MakePayload.cs index ee3b8a7747..f68f004c3c 100644 --- a/src/Plugins/DBFTPlugin/Consensus/ConsensusContext.MakePayload.cs +++ b/src/Plugins/DBFTPlugin/Consensus/ConsensusContext.MakePayload.cs @@ -166,11 +166,20 @@ public ExtensiblePayload MakePrepareResponse() }); } + // Related to issue https://github.com/neo-project/neo/issues/3431 + // Ref. https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.randomnumbergenerator?view=net-8.0 + // + //The System.Random class relies on a seed value that can be predictable, + //especially if the seed is based on the system clock or other low-entropy sources. + //RandomNumberGenerator, however, uses sources of entropy provided by the operating + //system, which are designed to be unpredictable. private static ulong GetNonce() { - Random _random = new(); Span buffer = stackalloc byte[8]; - _random.NextBytes(buffer); + using (var rng = System.Security.Cryptography.RandomNumberGenerator.Create()) + { + rng.GetBytes(buffer); + } return BinaryPrimitives.ReadUInt64LittleEndian(buffer); } } From 677b1fad8c1c782e05d22586bb009058578c2e2f Mon Sep 17 00:00:00 2001 From: Christopher Schuchardt Date: Tue, 23 Jul 2024 02:21:36 -0400 Subject: [PATCH 54/71] Fixed warning (#3430) Co-authored-by: Shargon --- src/Neo.CLI/CLI/MainService.Network.cs | 2 +- src/Neo.CLI/CLI/MainService.Wallet.cs | 2 +- src/Neo/Ledger/MemoryPool.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Neo.CLI/CLI/MainService.Network.cs b/src/Neo.CLI/CLI/MainService.Network.cs index 38d6fd1d28..c579b8323e 100644 --- a/src/Neo.CLI/CLI/MainService.Network.cs +++ b/src/Neo.CLI/CLI/MainService.Network.cs @@ -117,7 +117,7 @@ private void OnBroadcastInvCommand(InventoryType type, UInt256[] payload) [ConsoleCommand("broadcast transaction", Category = "Network Commands")] private void OnBroadcastTransactionCommand(UInt256 hash) { - if (NeoSystem.MemPool.TryGetValue(hash, out Transaction tx)) + if (NeoSystem.MemPool.TryGetValue(hash, out var tx)) OnBroadcastCommand(MessageCommand.Transaction, tx); } diff --git a/src/Neo.CLI/CLI/MainService.Wallet.cs b/src/Neo.CLI/CLI/MainService.Wallet.cs index db33e89564..f1390612bc 100644 --- a/src/Neo.CLI/CLI/MainService.Wallet.cs +++ b/src/Neo.CLI/CLI/MainService.Wallet.cs @@ -618,7 +618,7 @@ private void OnCancelCommand(UInt256 txid, UInt160? sender = null, UInt160[]? si return; } - if (NeoSystem.MemPool.TryGetValue(txid, out Transaction conflictTx)) + if (NeoSystem.MemPool.TryGetValue(txid, out var conflictTx)) { tx.NetworkFee = Math.Max(tx.NetworkFee, conflictTx.NetworkFee) + 1; } diff --git a/src/Neo/Ledger/MemoryPool.cs b/src/Neo/Ledger/MemoryPool.cs index ff9c6b1069..8f9437641b 100644 --- a/src/Neo/Ledger/MemoryPool.cs +++ b/src/Neo/Ledger/MemoryPool.cs @@ -159,7 +159,7 @@ public bool ContainsKey(UInt256 hash) /// The hash of the to get. /// When this method returns, contains the associated with the specified hash, if the hash is found; otherwise, . /// if the contains a with the specified hash; otherwise, . - public bool TryGetValue(UInt256 hash, [MaybeNullWhen(false)] out Transaction? tx) + public bool TryGetValue(UInt256 hash, [NotNullWhen(true)] out Transaction? tx) { _txRwLock.EnterReadLock(); try From 21765dc863d2cebf054dd0fc131e3beed10104ca Mon Sep 17 00:00:00 2001 From: Jimmy Date: Tue, 23 Jul 2024 15:20:03 +0800 Subject: [PATCH 55/71] [Neo Core UT] Fix ut and style (#3413) * fix ut and style * clean * update test * Update tests/Neo.UnitTests/IO/Caching/UT_DataCache.cs Co-authored-by: Hecate2 --------- Co-authored-by: Shargon Co-authored-by: Hecate2 Co-authored-by: Hecate2 <2474101468@qq.com> Co-authored-by: NGD Admin <154295625+NGDAdmin@users.noreply.github.com> --- src/Neo/Neo.csproj | 1 + .../TestBlockchain.cs | 25 +- .../UT_OracleService.cs | 4 +- .../Neo.UnitTests/IO/Caching/UT_CloneCache.cs | 4 +- .../Neo.UnitTests/IO/Caching/UT_DataCache.cs | 6 + tests/Neo.UnitTests/Ledger/UT_Blockchain.cs | 10 +- .../UT_TransactionVerificationContext.cs | 6 +- tests/Neo.UnitTests/Ledger/UT_TrimmedBlock.cs | 2 +- .../Network/P2P/Payloads/UT_Block.cs | 2 +- .../Network/P2P/Payloads/UT_Conflicts.cs | 2 +- .../Network/P2P/Payloads/UT_Header.cs | 2 +- .../P2P/Payloads/UT_HighPriorityAttribute.cs | 2 +- .../Network/P2P/Payloads/UT_NotValidBefore.cs | 2 +- .../Network/P2P/Payloads/UT_Transaction.cs | 272 +++++++++--------- .../Network/P2P/Payloads/UT_Witness.cs | 2 +- .../SmartContract/Native/UT_CryptoLib.cs | 170 +++++------ .../SmartContract/Native/UT_FungibleToken.cs | 2 +- .../SmartContract/Native/UT_GasToken.cs | 2 +- .../SmartContract/Native/UT_NativeContract.cs | 2 +- .../SmartContract/Native/UT_NeoToken.cs | 8 +- .../SmartContract/Native/UT_PolicyContract.cs | 2 +- .../SmartContract/Native/UT_RoleManagement.cs | 2 +- .../SmartContract/Native/UT_StdLib.cs | 20 +- .../SmartContract/UT_ApplicationEngine.cs | 6 +- .../UT_ContractParameterContext.cs | 16 +- .../SmartContract/UT_InteropPrices.cs | 8 +- .../SmartContract/UT_InteropService.NEO.cs | 8 +- .../SmartContract/UT_InteropService.cs | 18 +- .../SmartContract/UT_SmartContractHelper.cs | 6 +- .../SmartContract/UT_Syscalls.cs | 8 +- tests/Neo.UnitTests/TestBlockchain.cs | 6 +- tests/Neo.UnitTests/UT_DataCache.cs | 12 +- .../Wallets/NEP6/UT_NEP6Wallet.cs | 4 +- .../Wallets/UT_AssetDescriptor.cs | 6 +- tests/Neo.UnitTests/Wallets/UT_Wallet.cs | 8 +- 35 files changed, 342 insertions(+), 314 deletions(-) diff --git a/src/Neo/Neo.csproj b/src/Neo/Neo.csproj index 238333372b..7c6478c33e 100644 --- a/src/Neo/Neo.csproj +++ b/src/Neo/Neo.csproj @@ -30,6 +30,7 @@ + diff --git a/tests/Neo.Plugins.OracleService.Tests/TestBlockchain.cs b/tests/Neo.Plugins.OracleService.Tests/TestBlockchain.cs index bc6be0d8bf..a4cc2f6fbf 100644 --- a/tests/Neo.Plugins.OracleService.Tests/TestBlockchain.cs +++ b/tests/Neo.Plugins.OracleService.Tests/TestBlockchain.cs @@ -9,6 +9,8 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using Akka.Actor; +using Neo.Ledger; using Neo.Persistence; using System; @@ -16,21 +18,36 @@ namespace Neo.Plugins.OracleService.Tests { public static class TestBlockchain { - public static readonly NeoSystem TheNeoSystem; + private static readonly NeoSystem s_theNeoSystem; + private static readonly MemoryStore s_store = new(); + + private class StoreProvider : IStoreProvider + { + public string Name => "TestProvider"; + + public IStore GetStore(string path) => s_store; + } static TestBlockchain() { Console.WriteLine("initialize NeoSystem"); - TheNeoSystem = new NeoSystem(ProtocolSettings.Load("config.json"), new MemoryStoreProvider()); + s_theNeoSystem = new NeoSystem(ProtocolSettings.Load("config.json"), new StoreProvider()); } public static void InitializeMockNeoSystem() { } - internal static DataCache GetTestSnapshot() + internal static void ResetStore() + { + s_store.Reset(); + s_theNeoSystem.Blockchain.Ask(new Blockchain.Initialize()).Wait(); + } + + internal static SnapshotCache GetTestSnapshotCache() { - return TheNeoSystem.GetSnapshotCache().CloneCache(); + ResetStore(); + return s_theNeoSystem.GetSnapshot(); } } } diff --git a/tests/Neo.Plugins.OracleService.Tests/UT_OracleService.cs b/tests/Neo.Plugins.OracleService.Tests/UT_OracleService.cs index 9622ceb9e2..79771ee796 100644 --- a/tests/Neo.Plugins.OracleService.Tests/UT_OracleService.cs +++ b/tests/Neo.Plugins.OracleService.Tests/UT_OracleService.cs @@ -70,7 +70,7 @@ public void TestFilter() [TestMethod] public void TestCreateOracleResponseTx() { - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); var executionFactor = NativeContract.Policy.GetExecFeeFactor(snapshot); Assert.AreEqual(executionFactor, (uint)30); @@ -85,7 +85,7 @@ public void TestCreateOracleResponseTx() Filter = "", CallbackContract = UInt160.Zero, CallbackMethod = "callback", - UserData = System.Array.Empty() + UserData = [] }; byte Prefix_Transaction = 11; snapshot.Add(NativeContract.Ledger.CreateStorageKey(Prefix_Transaction, request.OriginalTxid), new StorageItem(new TransactionState() diff --git a/tests/Neo.UnitTests/IO/Caching/UT_CloneCache.cs b/tests/Neo.UnitTests/IO/Caching/UT_CloneCache.cs index 3dd3d2dd67..71eeb4ac25 100644 --- a/tests/Neo.UnitTests/IO/Caching/UT_CloneCache.cs +++ b/tests/Neo.UnitTests/IO/Caching/UT_CloneCache.cs @@ -155,8 +155,8 @@ public void TestUpdateInternal() [TestMethod] public void TestCacheOverrideIssue2572() { - var snapshot = TestBlockchain.GetTestSnapshot(); - var storages = snapshot.CloneCache(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); + var storages = snapshot.CreateSnapshot(); storages.Add ( diff --git a/tests/Neo.UnitTests/IO/Caching/UT_DataCache.cs b/tests/Neo.UnitTests/IO/Caching/UT_DataCache.cs index 242905a13a..224b1cc3f6 100644 --- a/tests/Neo.UnitTests/IO/Caching/UT_DataCache.cs +++ b/tests/Neo.UnitTests/IO/Caching/UT_DataCache.cs @@ -122,12 +122,18 @@ public void TestCommit() myDataCache.Add(key3, value4); Assert.AreEqual(TrackState.Changed, myDataCache.GetChangeSet().Where(u => u.Key.Equals(key3)).Select(u => u.State).FirstOrDefault()); + // If we use myDataCache after it is committed, it will return wrong result. myDataCache.Commit(); Assert.AreEqual(0, myDataCache.GetChangeSet().Count()); store.TryGet(key1.ToArray()).SequenceEqual(value1.ToArray()).Should().BeTrue(); store.TryGet(key2.ToArray()).Should().BeNull(); store.TryGet(key3.ToArray()).SequenceEqual(value4.ToArray()).Should().BeTrue(); + + myDataCache.TryGet(key1).Value.ToArray().SequenceEqual(value1.ToArray()).Should().BeTrue(); + // Though value is deleted from the store, the value can still be gotten from the snapshot cache. + myDataCache.TryGet(key2).Value.ToArray().SequenceEqual(value2.ToArray()).Should().BeTrue(); + myDataCache.TryGet(key3).Value.ToArray().SequenceEqual(value4.ToArray()).Should().BeTrue(); } [TestMethod] diff --git a/tests/Neo.UnitTests/Ledger/UT_Blockchain.cs b/tests/Neo.UnitTests/Ledger/UT_Blockchain.cs index 2c5ed88ef8..1ccfabbe92 100644 --- a/tests/Neo.UnitTests/Ledger/UT_Blockchain.cs +++ b/tests/Neo.UnitTests/Ledger/UT_Blockchain.cs @@ -38,14 +38,14 @@ public void Initialize() { system = TestBlockchain.TheNeoSystem; senderProbe = CreateTestProbe(); - txSample = new Transaction() + txSample = new Transaction { - Attributes = Array.Empty(), + Attributes = [], Script = Array.Empty(), - Signers = new Signer[] { new Signer() { Account = UInt160.Zero } }, - Witnesses = Array.Empty() + Signers = [new Signer { Account = UInt160.Zero }], + Witnesses = [] }; - system.MemPool.TryAdd(txSample, TestBlockchain.GetTestSnapshot()); + system.MemPool.TryAdd(txSample, TestBlockchain.GetTestSnapshotCache()); } [TestCleanup] diff --git a/tests/Neo.UnitTests/Ledger/UT_TransactionVerificationContext.cs b/tests/Neo.UnitTests/Ledger/UT_TransactionVerificationContext.cs index 32a0bd6237..7805da64b1 100644 --- a/tests/Neo.UnitTests/Ledger/UT_TransactionVerificationContext.cs +++ b/tests/Neo.UnitTests/Ledger/UT_TransactionVerificationContext.cs @@ -61,7 +61,7 @@ private Transaction CreateTransactionWithFee(long networkFee, long systemFee) public async Task TestDuplicateOracle() { // Fake balance - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, settings: TestBlockchain.TheNeoSystem.Settings, gas: long.MaxValue); BigInteger balance = NativeContract.GAS.BalanceOf(snapshot, UInt160.Zero); @@ -84,7 +84,7 @@ public async Task TestDuplicateOracle() [TestMethod] public async Task TestTransactionSenderFee() { - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, settings: TestBlockchain.TheNeoSystem.Settings, gas: long.MaxValue); BigInteger balance = NativeContract.GAS.BalanceOf(snapshot, UInt160.Zero); await NativeContract.GAS.Burn(engine, UInt160.Zero, balance); @@ -107,7 +107,7 @@ public async Task TestTransactionSenderFee() [TestMethod] public async Task TestTransactionSenderFeeWithConflicts() { - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, settings: TestBlockchain.TheNeoSystem.Settings, gas: long.MaxValue); BigInteger balance = NativeContract.GAS.BalanceOf(snapshot, UInt160.Zero); await NativeContract.GAS.Burn(engine, UInt160.Zero, balance); diff --git a/tests/Neo.UnitTests/Ledger/UT_TrimmedBlock.cs b/tests/Neo.UnitTests/Ledger/UT_TrimmedBlock.cs index ea797f8be3..12b56048c8 100644 --- a/tests/Neo.UnitTests/Ledger/UT_TrimmedBlock.cs +++ b/tests/Neo.UnitTests/Ledger/UT_TrimmedBlock.cs @@ -48,7 +48,7 @@ public static TrimmedBlock GetTrimmedBlockWithNoTransaction() [TestMethod] public void TestGetBlock() { - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); var tx1 = TestUtils.GetTransaction(UInt160.Zero); tx1.Script = new byte[] { 0x01,0x01,0x01,0x01, 0x01,0x01,0x01,0x01, diff --git a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Block.cs b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Block.cs index 7793e27597..4a7b0262f6 100644 --- a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Block.cs +++ b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Block.cs @@ -27,7 +27,7 @@ public class UT_Block private static ApplicationEngine GetEngine(bool hasContainer = false, bool hasSnapshot = false, bool hasBlock = false, bool addScript = true, long gas = 20_00000000) { var tx = hasContainer ? TestUtils.GetTransaction(UInt160.Zero) : null; - var snapshot = hasSnapshot ? TestBlockchain.GetTestSnapshot() : null; + var snapshot = hasSnapshot ? TestBlockchain.GetTestSnapshotCache() : null; var block = hasBlock ? new Block { Header = new Header() } : null; var engine = ApplicationEngine.Create(TriggerType.Application, tx, snapshot, block, TestBlockchain.TheNeoSystem.Settings, gas: gas); if (addScript) engine.LoadScript(new byte[] { 0x01 }); diff --git a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Conflicts.cs b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Conflicts.cs index ce46c5106d..b024fed808 100644 --- a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Conflicts.cs +++ b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Conflicts.cs @@ -73,7 +73,7 @@ public void DeserializeAndSerialize() public void Verify() { var test = new Conflicts() { Hash = _u }; - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); var key = Ledger.UT_MemoryPool.CreateStorageKey(NativeContract.Ledger.Id, Prefix_Transaction, _u.ToArray()); // Conflicting transaction is in the Conflicts attribute of some other on-chain transaction. diff --git a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Header.cs b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Header.cs index 17e0cb894f..0b32ffd656 100644 --- a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Header.cs +++ b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Header.cs @@ -52,7 +52,7 @@ public void GetHashCodeTest() public void TrimTest() { UInt256 val256 = UInt256.Zero; - var snapshot = TestBlockchain.GetTestSnapshot().CreateSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache().CreateSnapshot(); TestUtils.SetupHeaderWithValues(null, uut, val256, out _, out _, out _, out _, out _, out _); uut.Witness = new Witness() { InvocationScript = Array.Empty(), VerificationScript = Array.Empty() }; diff --git a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_HighPriorityAttribute.cs b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_HighPriorityAttribute.cs index 76808072d5..e5222e33de 100644 --- a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_HighPriorityAttribute.cs +++ b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_HighPriorityAttribute.cs @@ -74,7 +74,7 @@ public void DeserializeAndSerialize() public void Verify() { var test = new HighPriorityAttribute(); - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); Assert.IsFalse(test.Verify(snapshot, new Transaction() { Signers = Array.Empty() })); Assert.IsFalse(test.Verify(snapshot, new Transaction() { Signers = new Signer[] { new Signer() { Account = UInt160.Parse("0xa400ff00ff00ff00ff00ff00ff00ff00ff00ff01") } } })); diff --git a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_NotValidBefore.cs b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_NotValidBefore.cs index 8e7ad9087b..e44d4f3636 100644 --- a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_NotValidBefore.cs +++ b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_NotValidBefore.cs @@ -77,7 +77,7 @@ public void DeserializeAndSerialize() public void Verify() { var test = new NotValidBefore(); - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); test.Height = NativeContract.Ledger.CurrentIndex(snapshot) + 1; Assert.IsFalse(test.Verify(snapshot, new Transaction())); diff --git a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs index 56d9a66bec..1739f1b830 100644 --- a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs +++ b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs @@ -100,16 +100,16 @@ public void Gas_Set() public void Size_Get() { uut.Script = TestUtils.GetByteArray(32, 0x42); - uut.Signers = Array.Empty(); - uut.Attributes = Array.Empty(); - uut.Witnesses = new[] - { + uut.Signers = []; + uut.Attributes = []; + uut.Witnesses = + [ new Witness { InvocationScript = Array.Empty(), VerificationScript = Array.Empty() } - }; + ]; uut.Version.Should().Be(0); uut.Script.Length.Should().Be(32); @@ -122,17 +122,16 @@ public void FeeIsMultiSigContract() { var walletA = TestUtils.GenerateTestWallet("123"); var walletB = TestUtils.GenerateTestWallet("123"); - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); var a = walletA.CreateAccount(); var b = walletB.CreateAccount(); var multiSignContract = Contract.CreateMultiSigContract(2, - new ECPoint[] - { - a.GetKey().PublicKey, - b.GetKey().PublicKey - }); + [ + a.GetKey().PublicKey, + b.GetKey().PublicKey + ]); walletA.CreateAccount(multiSignContract, a.GetKey()); var acc = walletB.CreateAccount(multiSignContract, b.GetKey()); @@ -148,15 +147,14 @@ public void FeeIsMultiSigContract() // Make transaction - var tx = walletA.MakeTransaction(snapshot, new TransferOutput[] - { - new TransferOutput() - { - AssetId = NativeContract.GAS.Hash, - ScriptHash = acc.ScriptHash, - Value = new BigDecimal(BigInteger.One,8) - } - }, acc.ScriptHash); + var tx = walletA.MakeTransaction(snapshot, [ + new TransferOutput + { + AssetId = NativeContract.GAS.Hash, + ScriptHash = acc.ScriptHash, + Value = new BigDecimal(BigInteger.One, 8) + } + ], acc.ScriptHash); Assert.IsNotNull(tx); @@ -200,7 +198,7 @@ public void FeeIsMultiSigContract() public void FeeIsSignatureContractDetailed() { var wallet = TestUtils.GenerateTestWallet("123"); - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); var acc = wallet.CreateAccount(); // Fake balance @@ -216,15 +214,14 @@ public void FeeIsSignatureContractDetailed() // Make transaction // self-transfer of 1e-8 GAS - var tx = wallet.MakeTransaction(snapshot, new TransferOutput[] - { - new TransferOutput() - { - AssetId = NativeContract.GAS.Hash, - ScriptHash = acc.ScriptHash, - Value = new BigDecimal(BigInteger.One,8) - } - }, acc.ScriptHash); + var tx = wallet.MakeTransaction(snapshot, [ + new TransferOutput + { + AssetId = NativeContract.GAS.Hash, + ScriptHash = acc.ScriptHash, + Value = new BigDecimal(BigInteger.One, 8) + } + ], acc.ScriptHash); Assert.IsNotNull(tx); Assert.IsNull(tx.Witnesses); @@ -257,7 +254,7 @@ public void FeeIsSignatureContractDetailed() long verificationGas = 0; foreach (var witness in tx.Witnesses) { - using ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Verification, tx, snapshot, settings: TestBlockchain.TheNeoSystem.Settings, gas: tx.NetworkFee); + using var engine = ApplicationEngine.Create(TriggerType.Verification, tx, snapshot, settings: TestBlockchain.TheNeoSystem.Settings, gas: tx.NetworkFee); engine.LoadScript(witness.VerificationScript); engine.LoadScript(witness.InvocationScript); Assert.AreEqual(VMState.HALT, engine.Execute()); @@ -303,7 +300,7 @@ public void FeeIsSignatureContractDetailed() public void FeeIsSignatureContract_TestScope_Global() { var wallet = TestUtils.GenerateTestWallet(""); - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); var acc = wallet.CreateAccount(); // Fake balance @@ -323,14 +320,14 @@ public void FeeIsSignatureContract_TestScope_Global() using (ScriptBuilder sb = new()) { // self-transfer of 1e-8 GAS - BigInteger value = new BigDecimal(BigInteger.One, 8).Value; + var value = new BigDecimal(BigInteger.One, 8).Value; sb.EmitDynamicCall(NativeContract.GAS.Hash, "transfer", acc.ScriptHash, acc.ScriptHash, value, null); sb.Emit(OpCode.ASSERT); script = sb.ToArray(); } // trying global scope - var signers = new Signer[]{ new Signer + var signers = new[]{ new Signer { Account = acc.ScriptHash, Scopes = WitnessScope.Global @@ -382,7 +379,7 @@ public void FeeIsSignatureContract_TestScope_Global() public void FeeIsSignatureContract_TestScope_CurrentHash_GAS() { var wallet = TestUtils.GenerateTestWallet(""); - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); var acc = wallet.CreateAccount(); // Fake balance @@ -409,11 +406,11 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_GAS() } // trying global scope - var signers = new Signer[]{ new Signer + var signers = new[]{ new Signer { Account = acc.ScriptHash, Scopes = WitnessScope.CustomContracts, - AllowedContracts = new[] { NativeContract.GAS.Hash } + AllowedContracts = [NativeContract.GAS.Hash] } }; // using this... @@ -462,7 +459,7 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_GAS() public void FeeIsSignatureContract_TestScope_CalledByEntry_Plus_GAS() { var wallet = TestUtils.GenerateTestWallet(""); - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); var acc = wallet.CreateAccount(); // Fake balance @@ -482,21 +479,21 @@ public void FeeIsSignatureContract_TestScope_CalledByEntry_Plus_GAS() using (ScriptBuilder sb = new()) { // self-transfer of 1e-8 GAS - BigInteger value = new BigDecimal(BigInteger.One, 8).Value; + var value = new BigDecimal(BigInteger.One, 8).Value; sb.EmitDynamicCall(NativeContract.GAS.Hash, "transfer", acc.ScriptHash, acc.ScriptHash, value, null); sb.Emit(OpCode.ASSERT); script = sb.ToArray(); } // trying CalledByEntry together with GAS - var signers = new Signer[]{ new Signer + var signers = new[]{ new Signer { Account = acc.ScriptHash, // This combination is supposed to actually be an OR, // where it's valid in both Entry and also for Custom hash provided (in any execution level) // it would be better to test this in the future including situations where a deeper call level uses this custom witness successfully Scopes = WitnessScope.CustomContracts | WitnessScope.CalledByEntry, - AllowedContracts = new[] { NativeContract.GAS.Hash } + AllowedContracts = [NativeContract.GAS.Hash] } }; // using this... @@ -545,7 +542,7 @@ public void FeeIsSignatureContract_TestScope_CalledByEntry_Plus_GAS() public void FeeIsSignatureContract_TestScope_CurrentHash_NEO_FAULT() { var wallet = TestUtils.GenerateTestWallet(""); - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); var acc = wallet.CreateAccount(); // Fake balance @@ -570,11 +567,11 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_NEO_FAULT() } // trying global scope - var signers = new Signer[]{ new Signer + var signers = new[]{ new Signer { Account = acc.ScriptHash, Scopes = WitnessScope.CustomContracts, - AllowedContracts = new[] { NativeContract.NEO.Hash } + AllowedContracts = [NativeContract.NEO.Hash] } }; // using this... @@ -590,7 +587,7 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_NEO_FAULT() public void FeeIsSignatureContract_TestScope_CurrentHash_NEO_GAS() { var wallet = TestUtils.GenerateTestWallet(""); - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); var acc = wallet.CreateAccount(); // Fake balance @@ -617,11 +614,11 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_NEO_GAS() } // trying two custom hashes, for same target account - var signers = new Signer[]{ new Signer + var signers = new[]{ new Signer { Account = acc.ScriptHash, Scopes = WitnessScope.CustomContracts, - AllowedContracts = new[] { NativeContract.NEO.Hash, NativeContract.GAS.Hash } + AllowedContracts = [NativeContract.NEO.Hash, NativeContract.GAS.Hash] } }; // using this... @@ -675,7 +672,7 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_NEO_GAS() public void FeeIsSignatureContract_TestScope_NoScopeFAULT() { var wallet = TestUtils.GenerateTestWallet(""); - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); var acc = wallet.CreateAccount(); // Fake balance @@ -701,11 +698,11 @@ public void FeeIsSignatureContract_TestScope_NoScopeFAULT() // trying with no scope var attributes = Array.Empty(); - var signers = new Signer[]{ new Signer + var signers = new[]{ new Signer { Account = acc.ScriptHash, Scopes = WitnessScope.CustomContracts, - AllowedContracts = new[] { NativeContract.NEO.Hash, NativeContract.GAS.Hash } + AllowedContracts = [NativeContract.NEO.Hash, NativeContract.GAS.Hash] } }; // using this... @@ -721,7 +718,7 @@ public void FeeIsSignatureContract_TestScope_NoScopeFAULT() public void FeeIsSignatureContract_UnexistingVerificationContractFAULT() { var wallet = TestUtils.GenerateTestWallet(""); - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); var acc = wallet.CreateAccount(); // Fake balance @@ -770,7 +767,7 @@ public void FeeIsSignatureContract_UnexistingVerificationContractFAULT() [TestMethod] public void Transaction_Reverify_Hashes_Length_Unequal_To_Witnesses_Length() { - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); Transaction txSimple = new() { Version = 0x00, @@ -805,10 +802,11 @@ public void Transaction_Serialize_Deserialize_Simple() SystemFee = (long)BigInteger.Pow(10, 8), // 1 GAS NetworkFee = 0x0000000000000001, ValidUntilBlock = 0x01020304, - Signers = new Signer[] { new Signer() { Account = UInt160.Zero } }, - Attributes = Array.Empty(), - Script = new byte[] { (byte)OpCode.PUSH1 }, - Witnesses = new Witness[] { new Witness() { InvocationScript = Array.Empty(), VerificationScript = Array.Empty() } } + Signers = [new Signer() { Account = UInt160.Zero }], + Attributes = [], + Script = new[] { (byte)OpCode.PUSH1 }, + Witnesses = [new Witness { InvocationScript = Array.Empty(), VerificationScript = Array.Empty() } + ] }; byte[] sTx = txSimple.ToArray(); @@ -826,7 +824,7 @@ public void Transaction_Serialize_Deserialize_Simple() "010000"); // empty witnesses // try to deserialize - Transaction tx2 = Neo.IO.Helper.AsSerializable(sTx); + var tx2 = sTx.AsSerializable(); tx2.Version.Should().Be(0x00); tx2.Nonce.Should().Be(0x01020304); @@ -835,17 +833,16 @@ public void Transaction_Serialize_Deserialize_Simple() tx2.NetworkFee.Should().Be(0x0000000000000001); tx2.ValidUntilBlock.Should().Be(0x01020304); tx2.Attributes.Should().BeEquivalentTo(Array.Empty()); - tx2.Signers.Should().BeEquivalentTo(new[] - { + tx2.Signers.Should().BeEquivalentTo([ new Signer { Account = UInt160.Zero, - AllowedContracts = Array.Empty(), - AllowedGroups = Array.Empty(), - Rules = Array.Empty() + AllowedContracts = [], + AllowedGroups = [], + Rules = [] } - }); - tx2.Script.Span.SequenceEqual(new byte[] { (byte)OpCode.PUSH1 }).Should().BeTrue(); + ]); + tx2.Script.Span.SequenceEqual([(byte)OpCode.PUSH1]).Should().BeTrue(); tx2.Witnesses[0].InvocationScript.Span.IsEmpty.Should().BeTrue(); tx2.Witnesses[0].VerificationScript.Span.IsEmpty.Should().BeTrue(); } @@ -862,25 +859,26 @@ public void Transaction_Serialize_Deserialize_DistinctCosigners() SystemFee = (long)BigInteger.Pow(10, 8), // 1 GAS NetworkFee = 0x0000000000000001, ValidUntilBlock = 0x01020304, - Attributes = Array.Empty(), - Signers = new Signer[] - { - new Signer() + Attributes = [], + Signers = + [ + new Signer { Account = UInt160.Parse("0x0001020304050607080900010203040506070809"), Scopes = WitnessScope.Global }, - new Signer() + new Signer { Account = UInt160.Parse("0x0001020304050607080900010203040506070809"), // same account as above Scopes = WitnessScope.CalledByEntry // different scope, but still, same account (cannot do that) } - }, - Script = new byte[] { (byte)OpCode.PUSH1 }, - Witnesses = new Witness[] { new Witness() { InvocationScript = Array.Empty(), VerificationScript = Array.Empty() } } + ], + Script = new[] { (byte)OpCode.PUSH1 }, + Witnesses = [new Witness { InvocationScript = Array.Empty(), VerificationScript = Array.Empty() } + ] }; - byte[] sTx = txDoubleCosigners.ToArray(); + var sTx = txDoubleCosigners.ToArray(); // no need for detailed hexstring here (see basic tests for it) sTx.ToHexString().Should().Be("000403020100e1f5050000000001000000000000000403020102090807060504030201000908070605040302010080090807060504030201000908070605040302010001000111010000"); @@ -924,16 +922,17 @@ public void Transaction_Serialize_Deserialize_MaxSizeCosigners() SystemFee = (long)BigInteger.Pow(10, 8), // 1 GAS NetworkFee = 0x0000000000000001, ValidUntilBlock = 0x01020304, - Attributes = Array.Empty(), + Attributes = [], Signers = cosigners1, // max + 1 (should fail) - Script = new byte[] { (byte)OpCode.PUSH1 }, - Witnesses = new Witness[] { new Witness() { InvocationScript = Array.Empty(), VerificationScript = Array.Empty() } } + Script = new[] { (byte)OpCode.PUSH1 }, + Witnesses = [new Witness { InvocationScript = Array.Empty(), VerificationScript = Array.Empty() } + ] }; byte[] sTx1 = txCosigners1.ToArray(); // back to transaction (should fail, due to non-distinct cosigners) - Assert.ThrowsException(() => Neo.IO.Helper.AsSerializable(sTx1)); + Assert.ThrowsException(() => sTx1.AsSerializable()); // ---------------------------- // this should fail (max + 1) @@ -941,7 +940,7 @@ public void Transaction_Serialize_Deserialize_MaxSizeCosigners() var cosigners = new Signer[maxCosigners + 1]; for (var i = 0; i < maxCosigners + 1; i++) { - string hex = i.ToString("X4"); + var hex = i.ToString("X4"); while (hex.Length < 40) hex = hex.Insert(0, "0"); cosigners[i] = new Signer @@ -957,10 +956,11 @@ public void Transaction_Serialize_Deserialize_MaxSizeCosigners() SystemFee = (long)BigInteger.Pow(10, 8), // 1 GAS NetworkFee = 0x0000000000000001, ValidUntilBlock = 0x01020304, - Attributes = Array.Empty(), + Attributes = [], Signers = cosigners, // max + 1 (should fail) - Script = new byte[] { (byte)OpCode.PUSH1 }, - Witnesses = new Witness[] { new Witness() { InvocationScript = Array.Empty(), VerificationScript = Array.Empty() } } + Script = new[] { (byte)OpCode.PUSH1 }, + Witnesses = [new Witness { InvocationScript = Array.Empty(), VerificationScript = Array.Empty() } + ] }; byte[] sTx2 = txCosigners.ToArray(); @@ -968,7 +968,7 @@ public void Transaction_Serialize_Deserialize_MaxSizeCosigners() // back to transaction (should fail, due to non-distinct cosigners) Transaction tx2 = null; Assert.ThrowsException(() => - tx2 = Neo.IO.Helper.AsSerializable(sTx2) + tx2 = sTx2.AsSerializable() ); Assert.IsNull(tx2); } @@ -982,7 +982,7 @@ public void FeeIsSignatureContract_TestScope_FeeOnly_Default() cosigner.Scopes.Should().Be(WitnessScope.None); var wallet = TestUtils.GenerateTestWallet(""); - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); var acc = wallet.CreateAccount(); // Fake balance @@ -1009,7 +1009,7 @@ public void FeeIsSignatureContract_TestScope_FeeOnly_Default() } // try to use fee only inside the smart contract - var signers = new Signer[]{ new Signer + var signers = new[]{ new Signer { Account = acc.ScriptHash, Scopes = WitnessScope.None @@ -1065,16 +1065,16 @@ public void ToJson() { uut.Script = TestUtils.GetByteArray(32, 0x42); uut.SystemFee = 4200000000; - uut.Signers = new Signer[] { new Signer() { Account = UInt160.Zero } }; - uut.Attributes = Array.Empty(); - uut.Witnesses = new[] - { + uut.Signers = [new Signer { Account = UInt160.Zero }]; + uut.Attributes = []; + uut.Witnesses = + [ new Witness { InvocationScript = Array.Empty(), VerificationScript = Array.Empty() } - }; + ]; JObject jObj = uut.ToJson(ProtocolSettings.Default); jObj.Should().NotBeNull(); @@ -1090,23 +1090,23 @@ public void ToJson() [TestMethod] public void Test_GetAttribute() { - var tx = new Transaction() + var tx = new Transaction { - Attributes = Array.Empty(), + Attributes = [], NetworkFee = 0, Nonce = (uint)Environment.TickCount, Script = new byte[Transaction.MaxTransactionSize], - Signers = new Signer[] { new Signer() { Account = UInt160.Zero } }, + Signers = [new Signer { Account = UInt160.Zero }], SystemFee = 0, ValidUntilBlock = 0, Version = 0, - Witnesses = Array.Empty(), + Witnesses = [], }; Assert.IsNull(tx.GetAttribute()); Assert.IsNull(tx.GetAttribute()); - tx.Attributes = new TransactionAttribute[] { new HighPriorityAttribute() }; + tx.Attributes = [new HighPriorityAttribute()]; Assert.IsNull(tx.GetAttribute()); Assert.IsNotNull(tx.GetAttribute()); @@ -1115,24 +1115,24 @@ public void Test_GetAttribute() [TestMethod] public void Test_VerifyStateIndependent() { - var tx = new Transaction() + var tx = new Transaction { - Attributes = Array.Empty(), + Attributes = [], NetworkFee = 0, Nonce = (uint)Environment.TickCount, Script = new byte[Transaction.MaxTransactionSize], - Signers = new Signer[] { new Signer() { Account = UInt160.Zero } }, + Signers = [new Signer { Account = UInt160.Zero }], SystemFee = 0, ValidUntilBlock = 0, Version = 0, - Witnesses = new[] - { + Witnesses = + [ new Witness { InvocationScript = Array.Empty(), VerificationScript = Array.Empty() } - } + ] }; tx.VerifyStateIndependent(TestProtocolSettings.Default).Should().Be(VerifyResult.OverSize); tx.Script = Array.Empty(); @@ -1140,17 +1140,16 @@ public void Test_VerifyStateIndependent() var walletA = TestUtils.GenerateTestWallet("123"); var walletB = TestUtils.GenerateTestWallet("123"); - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); var a = walletA.CreateAccount(); var b = walletB.CreateAccount(); var multiSignContract = Contract.CreateMultiSigContract(2, - new ECPoint[] - { - a.GetKey().PublicKey, - b.GetKey().PublicKey - }); + [ + a.GetKey().PublicKey, + b.GetKey().PublicKey + ]); walletA.CreateAccount(multiSignContract, a.GetKey()); var acc = walletB.CreateAccount(multiSignContract, b.GetKey()); @@ -1166,15 +1165,14 @@ public void Test_VerifyStateIndependent() // Make transaction - tx = walletA.MakeTransaction(snapshot, new TransferOutput[] - { - new TransferOutput() - { - AssetId = NativeContract.GAS.Hash, - ScriptHash = acc.ScriptHash, - Value = new BigDecimal(BigInteger.One,8) - } - }, acc.ScriptHash); + tx = walletA.MakeTransaction(snapshot, [ + new TransferOutput + { + AssetId = NativeContract.GAS.Hash, + ScriptHash = acc.ScriptHash, + Value = new BigDecimal(BigInteger.One, 8) + } + ], acc.ScriptHash); // Sign @@ -1199,35 +1197,36 @@ public void Test_VerifyStateIndependent() [TestMethod] public void Test_VerifyStateDependent() { - var snapshot = TestBlockchain.GetTestSnapshot(); - var height = NativeContract.Ledger.CurrentIndex(snapshot); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); + var height = NativeContract.Ledger.CurrentIndex(snapshotCache); var tx = new Transaction() { - Attributes = Array.Empty(), + Attributes = [], NetworkFee = 55000, Nonce = (uint)Environment.TickCount, Script = Array.Empty(), - Signers = new Signer[] { new Signer() { Account = UInt160.Zero } }, + Signers = [new Signer() { Account = UInt160.Zero }], SystemFee = 0, ValidUntilBlock = height + 1, Version = 0, - Witnesses = new Witness[] { - new Witness() { InvocationScript = Array.Empty(), VerificationScript = Array.Empty() }, - new Witness() { InvocationScript = Array.Empty(), VerificationScript = new byte[1] } - } + Witnesses = + [ + new Witness { InvocationScript = Array.Empty(), VerificationScript = Array.Empty() }, + new Witness { InvocationScript = Array.Empty(), VerificationScript = new byte[1] } + ] }; // Fake balance var key = NativeContract.GAS.CreateStorageKey(20, tx.Sender); - var balance = snapshot.GetAndChange(key, () => new StorageItem(new AccountState())); + var balance = snapshotCache.GetAndChange(key, () => new StorageItem(new AccountState())); balance.GetInteroperable().Balance = tx.NetworkFee; var conflicts = new List(); - tx.VerifyStateDependent(ProtocolSettings.Default, snapshot, new TransactionVerificationContext(), conflicts).Should().Be(VerifyResult.Invalid); + tx.VerifyStateDependent(ProtocolSettings.Default, snapshotCache, new TransactionVerificationContext(), conflicts).Should().Be(VerifyResult.Invalid); balance.GetInteroperable().Balance = 0; tx.SystemFee = 10; - tx.VerifyStateDependent(ProtocolSettings.Default, snapshot, new TransactionVerificationContext(), conflicts).Should().Be(VerifyResult.InsufficientFunds); + tx.VerifyStateDependent(ProtocolSettings.Default, snapshotCache, new TransactionVerificationContext(), conflicts).Should().Be(VerifyResult.InsufficientFunds); var walletA = TestUtils.GenerateTestWallet("123"); var walletB = TestUtils.GenerateTestWallet("123"); @@ -1236,26 +1235,25 @@ public void Test_VerifyStateDependent() var b = walletB.CreateAccount(); var multiSignContract = Contract.CreateMultiSigContract(2, - new ECPoint[] - { - a.GetKey().PublicKey, - b.GetKey().PublicKey - }); + [ + a.GetKey().PublicKey, + b.GetKey().PublicKey + ]); walletA.CreateAccount(multiSignContract, a.GetKey()); var acc = walletB.CreateAccount(multiSignContract, b.GetKey()); // Fake balance - snapshot = TestBlockchain.GetTestSnapshot(); + snapshotCache = TestBlockchain.GetTestSnapshotCache(); key = NativeContract.GAS.CreateStorageKey(20, acc.ScriptHash); - balance = snapshot.GetAndChange(key, () => new StorageItem(new AccountState())); + balance = snapshotCache.GetAndChange(key, () => new StorageItem(new AccountState())); balance.GetInteroperable().Balance = 10000 * NativeContract.GAS.Factor; // Make transaction - snapshot.Commit(); - tx = walletA.MakeTransaction(snapshot, new TransferOutput[] + snapshotCache.Commit(); + tx = walletA.MakeTransaction(snapshotCache, new[] { new TransferOutput() { @@ -1267,13 +1265,13 @@ public void Test_VerifyStateDependent() // Sign - var data = new ContractParametersContext(snapshot, tx, TestProtocolSettings.Default.Network); + var data = new ContractParametersContext(snapshotCache, tx, TestProtocolSettings.Default.Network); Assert.IsTrue(walletA.Sign(data)); Assert.IsTrue(walletB.Sign(data)); Assert.IsTrue(data.Completed); tx.Witnesses = data.GetWitnesses(); - tx.VerifyStateDependent(TestProtocolSettings.Default, snapshot, new TransactionVerificationContext(), new List()).Should().Be(VerifyResult.Succeed); + tx.VerifyStateDependent(TestProtocolSettings.Default, snapshotCache, new TransactionVerificationContext(), new List()).Should().Be(VerifyResult.Succeed); } [TestMethod] diff --git a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Witness.cs b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Witness.cs index 74898eb4fb..6c4f066008 100644 --- a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Witness.cs +++ b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Witness.cs @@ -43,7 +43,7 @@ private static Witness PrepareDummyWitness(int pubKeys, int m) { var address = new WalletAccount[pubKeys]; var wallets = new NEP6Wallet[pubKeys]; - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); for (int x = 0; x < pubKeys; x++) { diff --git a/tests/Neo.UnitTests/SmartContract/Native/UT_CryptoLib.cs b/tests/Neo.UnitTests/SmartContract/Native/UT_CryptoLib.cs index f65e061093..00ababb416 100644 --- a/tests/Neo.UnitTests/SmartContract/Native/UT_CryptoLib.cs +++ b/tests/Neo.UnitTests/SmartContract/Native/UT_CryptoLib.cs @@ -45,7 +45,7 @@ public class UT_CryptoLib [TestMethod] public void TestG1() { - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); using ScriptBuilder script = new(); script.EmitDynamicCall(NativeContract.CryptoLib.Hash, "bls12381Deserialize", g1); @@ -59,7 +59,7 @@ public void TestG1() [TestMethod] public void TestG2() { - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); using ScriptBuilder script = new(); script.EmitDynamicCall(NativeContract.CryptoLib.Hash, "bls12381Deserialize", g2); @@ -73,7 +73,7 @@ public void TestG2() [TestMethod] public void TestNotG1() { - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); using ScriptBuilder script = new(); script.EmitDynamicCall(NativeContract.CryptoLib.Hash, "bls12381Deserialize", not_g1); @@ -85,7 +85,7 @@ public void TestNotG1() [TestMethod] public void TestNotG2() { - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); using ScriptBuilder script = new(); script.EmitDynamicCall(NativeContract.CryptoLib.Hash, "bls12381Deserialize", not_g2); @@ -96,7 +96,7 @@ public void TestNotG2() [TestMethod] public void TestBls12381Add() { - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); using ScriptBuilder script = new(); script.EmitDynamicCall(NativeContract.CryptoLib.Hash, "bls12381Deserialize", gt); script.EmitDynamicCall(NativeContract.CryptoLib.Hash, "bls12381Deserialize", gt); @@ -119,7 +119,7 @@ public void TestBls12381Mul() { var data = new byte[32]; data[0] = 0x03; - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); using (ScriptBuilder script = new()) { script.EmitPush(false); @@ -161,7 +161,7 @@ public void TestBls12381Mul() [TestMethod] public void TestBls12381Pairing() { - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); using ScriptBuilder script = new(); script.EmitDynamicCall(NativeContract.CryptoLib.Hash, "bls12381Deserialize", g2); script.EmitDynamicCall(NativeContract.CryptoLib.Hash, "bls12381Deserialize", g1); @@ -182,7 +182,7 @@ public void TestBls12381Pairing() [TestMethod] public void Bls12381Equal() { - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); using ScriptBuilder script = new(); script.EmitDynamicCall(NativeContract.CryptoLib.Hash, "bls12381Deserialize", g1); script.EmitDynamicCall(NativeContract.CryptoLib.Hash, "bls12381Deserialize", g1); @@ -211,7 +211,7 @@ private void CheckBls12381ScalarMul_Compat(string point, string mul, bool negati { var data = new byte[32]; data[0] = 0x03; - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); using (ScriptBuilder script = new()) { script.EmitPush(negative); @@ -506,7 +506,7 @@ public void TestVerifyWithECDsa_CustomTxWitness_SingleSig() tx.VerifyStateIndependent(TestProtocolSettings.Default).Should().Be(VerifyResult.Succeed); - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); // Create fake balance to pay the fees. ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, settings: TestBlockchain.TheNeoSystem.Settings, gas: long.MaxValue); @@ -534,19 +534,19 @@ public void TestVerifyWithECDsa_CustomTxWitness_SingleSig() // NEO-VM 0 > ops // INDEX OPCODE PARAMETER // 0 PUSHINT8 122 (7a) << - // 2 SWAP + // 2 SWAP // 3 PUSHDATA1 02fd0a8c1ce5ae5570fdd46e7599c16b175bf0ebdfe9c178f1ab848fb16dac74a5 // 38 SYSCALL System.Runtime.GetNetwork (c5fba0e0) // 43 PUSHINT64 4294967296 (0000000001000000) - // 52 ADD - // 53 PUSH4 - // 54 LEFT + // 52 ADD + // 53 PUSH4 + // 54 LEFT // 55 SYSCALL System.Runtime.GetScriptContainer (2d510830) - // 60 PUSH0 - // 61 PICKITEM - // 62 CAT - // 63 PUSH4 - // 64 PACK + // 60 PUSH0 + // 61 PICKITEM + // 62 CAT + // 63 PUSH4 + // 64 PACK // 65 PUSH0 // 66 PUSHDATA1 766572696679576974684543447361 ("verifyWithECDsa") // 83 PUSHDATA1 1bf575ab1189688413610a35a12886cde0b66c72 ("NNToUmdQBe5n8o53BTzjTFAnSEcpouyy3B", "0x726cb6e0cd8628a1350a611384688911ab75f51b") @@ -563,17 +563,17 @@ public void TestVerifyWithECDsa_CustomTxWitness_SingleSig() [TestMethod] public void TestVerifyWithECDsa_CustomTxWitness_MultiSig() { - byte[] privkey1 = "b2dde592bfce654ef03f1ceea452d2b0112e90f9f52099bcd86697a2bd0a2b60".HexToBytes(); - ECPoint pubKey1 = ECPoint.Parse("040486468683c112125978ffe876245b2006bfe739aca8539b67335079262cb27ad0dedc9e5583f99b61c6f46bf80b97eaec3654b87add0e5bd7106c69922a229d", ECCurve.Secp256k1); - byte[] privkey2 = "b9879e26941872ee6c9e6f01045681496d8170ed2cc4a54ce617b39ae1891b3a".HexToBytes(); - ECPoint pubKey2 = ECPoint.Parse("040d26fc2ad3b1aae20f040b5f83380670f8ef5c2b2ac921ba3bdd79fd0af0525177715fd4370b1012ddd10579698d186ab342c223da3e884ece9cab9b6638c7bb", ECCurve.Secp256k1); - byte[] privkey3 = "4e1fe2561a6da01ee030589d504d62b23c26bfd56c5e07dfc9b8b74e4602832a".HexToBytes(); - ECPoint pubKey3 = ECPoint.Parse("047b4e72ae854b6a0955b3e02d92651ab7fa641a936066776ad438f95bb674a269a63ff98544691663d91a6cfcd215831f01bfb7a226363a6c5c67ef14541dba07", ECCurve.Secp256k1); - byte[] privkey4 = "6dfd066bb989d3786043aa5c1f0476215d6f5c44f5fc3392dd15e2599b67a728".HexToBytes(); - ECPoint pubKey4 = ECPoint.Parse("04b62ac4c8a352a892feceb18d7e2e3a62c8c1ecbaae5523d89d747b0219276e225be2556a137e0e806e4915762d816cdb43f572730d23bb1b1cba750011c4edc6", ECCurve.Secp256k1); - - // Public keys must be sorted, exactly like for standard CreateMultiSigRedeemScript. - var keys = new List<(byte[], ECPoint)>() + var privkey1 = "b2dde592bfce654ef03f1ceea452d2b0112e90f9f52099bcd86697a2bd0a2b60".HexToBytes(); + var pubKey1 = ECPoint.Parse("040486468683c112125978ffe876245b2006bfe739aca8539b67335079262cb27ad0dedc9e5583f99b61c6f46bf80b97eaec3654b87add0e5bd7106c69922a229d", ECCurve.Secp256k1); + var privkey2 = "b9879e26941872ee6c9e6f01045681496d8170ed2cc4a54ce617b39ae1891b3a".HexToBytes(); + var pubKey2 = ECPoint.Parse("040d26fc2ad3b1aae20f040b5f83380670f8ef5c2b2ac921ba3bdd79fd0af0525177715fd4370b1012ddd10579698d186ab342c223da3e884ece9cab9b6638c7bb", ECCurve.Secp256k1); + var privkey3 = "4e1fe2561a6da01ee030589d504d62b23c26bfd56c5e07dfc9b8b74e4602832a".HexToBytes(); + var pubKey3 = ECPoint.Parse("047b4e72ae854b6a0955b3e02d92651ab7fa641a936066776ad438f95bb674a269a63ff98544691663d91a6cfcd215831f01bfb7a226363a6c5c67ef14541dba07", ECCurve.Secp256k1); + var privkey4 = "6dfd066bb989d3786043aa5c1f0476215d6f5c44f5fc3392dd15e2599b67a728".HexToBytes(); + var pubKey4 = ECPoint.Parse("04b62ac4c8a352a892feceb18d7e2e3a62c8c1ecbaae5523d89d747b0219276e225be2556a137e0e806e4915762d816cdb43f572730d23bb1b1cba750011c4edc6", ECCurve.Secp256k1); + + // Public keys must be sorted, exactly like for standard CreateMultiSigRedeemScript. + var keys = new List<(byte[], ECPoint)> { (privkey1, pubKey1), (privkey2, pubKey2), @@ -583,7 +583,7 @@ public void TestVerifyWithECDsa_CustomTxWitness_MultiSig() // Consider 4 users willing to sign 3/4 multisignature transaction with their Secp256k1 private keys. var m = 3; - var n = keys.Count(); + var n = keys.Count; // Must ensure the following conditions are met before verification script construction: n.Should().BeGreaterThan(0); @@ -607,7 +607,7 @@ public void TestVerifyWithECDsa_CustomTxWitness_MultiSig() // return sigCnt == m // } - // vrf is a builder of M out of N multisig witness verification script corresponding to the public keys. + // vrf is a builder of M out of N multisig witness verification script corresponding to the public keys. using ScriptBuilder vrf = new(); // Start the same way as regular multisig script. @@ -747,12 +747,16 @@ public void TestVerifyWithECDsa_CustomTxWitness_MultiSig() tx.VerifyStateIndependent(TestProtocolSettings.Default).Should().Be(VerifyResult.Succeed); - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); // Create fake balance to pay the fees. - ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, settings: TestBlockchain.TheNeoSystem.Settings, gas: long.MaxValue); + var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, settings: TestBlockchain.TheNeoSystem.Settings, gas: long.MaxValue); _ = NativeContract.GAS.Mint(engine, acc, 5_0000_0000, false); - snapshot.Commit(); + + // We should not use commit here cause once its committed, the value we get from the snapshot can be different + // from the underline storage. Thought there isn't any issue triggered here, its wrong to use it this way. + // We should either ignore the commit, or get a new snapshot of the store after the commit. + // snapshot.Commit(); // Check that witness verification passes. var txVrfContext = new TransactionVerificationContext(); @@ -780,65 +784,65 @@ public void TestVerifyWithECDsa_CustomTxWitness_MultiSig() // 36 PUSHDATA1 030d26fc2ad3b1aae20f040b5f83380670f8ef5c2b2ac921ba3bdd79fd0af05251 // 71 PUSHDATA1 037b4e72ae854b6a0955b3e02d92651ab7fa641a936066776ad438f95bb674a269 // 106 PUSHDATA1 02b62ac4c8a352a892feceb18d7e2e3a62c8c1ecbaae5523d89d747b0219276e22 - // 141 PUSH4 + // 141 PUSH4 // 142 INITSLOT 7 local, 0 arg - // 145 STLOC5 - // 146 LDLOC5 - // 147 PACK - // 148 STLOC1 - // 149 STLOC6 - // 150 DEPTH - // 151 LDLOC6 + // 145 STLOC5 + // 146 LDLOC5 + // 147 PACK + // 148 STLOC1 + // 149 STLOC6 + // 150 DEPTH + // 151 LDLOC6 // 152 JMPEQ 155 (3/03) - // 154 ABORT - // 155 LDLOC6 - // 156 PACK - // 157 STLOC0 + // 154 ABORT + // 155 LDLOC6 + // 156 PACK + // 157 STLOC0 // 158 SYSCALL System.Runtime.GetNetwork (c5fba0e0) // 163 PUSHINT64 4294967296 (0000000001000000) - // 172 ADD - // 173 PUSH4 - // 174 LEFT + // 172 ADD + // 173 PUSH4 + // 174 LEFT // 175 SYSCALL System.Runtime.GetScriptContainer (2d510830) - // 180 PUSH0 - // 181 PICKITEM - // 182 CAT - // 183 STLOC2 - // 184 PUSH0 - // 185 STLOC3 - // 186 PUSH0 - // 187 STLOC4 - // 188 LDLOC3 - // 189 LDLOC6 - // 190 GE - // 191 LDLOC4 - // 192 LDLOC5 - // 193 GE - // 194 OR + // 180 PUSH0 + // 181 PICKITEM + // 182 CAT + // 183 STLOC2 + // 184 PUSH0 + // 185 STLOC3 + // 186 PUSH0 + // 187 STLOC4 + // 188 LDLOC3 + // 189 LDLOC6 + // 190 GE + // 191 LDLOC4 + // 192 LDLOC5 + // 193 GE + // 194 OR // 195 JMPIF 261 (66/42) // 197 PUSHINT8 122 (7a) - // 199 LDLOC0 - // 200 LDLOC3 - // 201 PICKITEM - // 202 LDLOC1 - // 203 LDLOC4 - // 204 PICKITEM - // 205 LDLOC2 - // 206 PUSH4 - // 207 PACK + // 199 LDLOC0 + // 200 LDLOC3 + // 201 PICKITEM + // 202 LDLOC1 + // 203 LDLOC4 + // 204 PICKITEM + // 205 LDLOC2 + // 206 PUSH4 + // 207 PACK // 208 PUSH0 // 209 PUSHDATA1 766572696679576974684543447361 ("verifyWithECDsa") // 226 PUSHDATA1 1bf575ab1189688413610a35a12886cde0b66c72 ("NNToUmdQBe5n8o53BTzjTFAnSEcpouyy3B", "0x726cb6e0cd8628a1350a611384688911ab75f51b") // 248 SYSCALL System.Contract.Call (627d5b52) - // 253 LDLOC3 - // 254 ADD - // 255 STLOC3 - // 256 LDLOC4 - // 257 INC - // 258 STLOC4 + // 253 LDLOC3 + // 254 ADD + // 255 STLOC3 + // 256 LDLOC4 + // 257 INC + // 258 STLOC4 // 259 JMP 188 (-71/b9) - // 261 LDLOC3 - // 262 LDLOC6 + // 261 LDLOC3 + // 262 LDLOC6 // 263 NUMEQUAL } @@ -885,7 +889,7 @@ public void TestVerifyWithECDsa() private bool CallVerifyWithECDsa(byte[] message, ECPoint pub, byte[] signature, NamedCurveHash curveHash) { - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); using (ScriptBuilder script = new()) { script.EmitPush((int)curveHash); diff --git a/tests/Neo.UnitTests/SmartContract/Native/UT_FungibleToken.cs b/tests/Neo.UnitTests/SmartContract/Native/UT_FungibleToken.cs index 5d6d00986e..6e3c18999a 100644 --- a/tests/Neo.UnitTests/SmartContract/Native/UT_FungibleToken.cs +++ b/tests/Neo.UnitTests/SmartContract/Native/UT_FungibleToken.cs @@ -22,7 +22,7 @@ public class UT_FungibleToken : TestKit [TestMethod] public void TestTotalSupply() { - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); NativeContract.GAS.TotalSupply(snapshot).Should().Be(5200000050000000); } } diff --git a/tests/Neo.UnitTests/SmartContract/Native/UT_GasToken.cs b/tests/Neo.UnitTests/SmartContract/Native/UT_GasToken.cs index 1557f9778d..ebb66f0dff 100644 --- a/tests/Neo.UnitTests/SmartContract/Native/UT_GasToken.cs +++ b/tests/Neo.UnitTests/SmartContract/Native/UT_GasToken.cs @@ -33,7 +33,7 @@ public class UT_GasToken [TestInitialize] public void TestSetup() { - _snapshot = TestBlockchain.GetTestSnapshot(); + _snapshot = TestBlockchain.GetTestSnapshotCache(); _persistingBlock = new Block { Header = new Header() }; } diff --git a/tests/Neo.UnitTests/SmartContract/Native/UT_NativeContract.cs b/tests/Neo.UnitTests/SmartContract/Native/UT_NativeContract.cs index 707f8e6754..7c1d874b1b 100644 --- a/tests/Neo.UnitTests/SmartContract/Native/UT_NativeContract.cs +++ b/tests/Neo.UnitTests/SmartContract/Native/UT_NativeContract.cs @@ -37,7 +37,7 @@ public class UT_NativeContract [TestInitialize] public void TestSetup() { - _snapshot = TestBlockchain.GetTestSnapshot(); + _snapshot = TestBlockchain.GetTestSnapshotCache(); _nativeStates = new Dictionary { {"ContractManagement", """{"id":-1,"updatecounter":0,"hash":"0xfffdc93764dbaddd97c48f252a53ea4643faa3fd","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0A=","checksum":1094259016},"manifest":{"name":"ContractManagement","groups":[],"features":{},"supportedstandards":[],"abi":{"methods":[{"name":"deploy","parameters":[{"name":"nefFile","type":"ByteArray"},{"name":"manifest","type":"ByteArray"}],"returntype":"Array","offset":0,"safe":false},{"name":"deploy","parameters":[{"name":"nefFile","type":"ByteArray"},{"name":"manifest","type":"ByteArray"},{"name":"data","type":"Any"}],"returntype":"Array","offset":7,"safe":false},{"name":"destroy","parameters":[],"returntype":"Void","offset":14,"safe":false},{"name":"getContract","parameters":[{"name":"hash","type":"Hash160"}],"returntype":"Array","offset":21,"safe":true},{"name":"getContractById","parameters":[{"name":"id","type":"Integer"}],"returntype":"Array","offset":28,"safe":true},{"name":"getContractHashes","parameters":[],"returntype":"InteropInterface","offset":35,"safe":true},{"name":"getMinimumDeploymentFee","parameters":[],"returntype":"Integer","offset":42,"safe":true},{"name":"hasMethod","parameters":[{"name":"hash","type":"Hash160"},{"name":"method","type":"String"},{"name":"pcount","type":"Integer"}],"returntype":"Boolean","offset":49,"safe":true},{"name":"setMinimumDeploymentFee","parameters":[{"name":"value","type":"Integer"}],"returntype":"Void","offset":56,"safe":false},{"name":"update","parameters":[{"name":"nefFile","type":"ByteArray"},{"name":"manifest","type":"ByteArray"}],"returntype":"Void","offset":63,"safe":false},{"name":"update","parameters":[{"name":"nefFile","type":"ByteArray"},{"name":"manifest","type":"ByteArray"},{"name":"data","type":"Any"}],"returntype":"Void","offset":70,"safe":false}],"events":[{"name":"Deploy","parameters":[{"name":"Hash","type":"Hash160"}]},{"name":"Update","parameters":[{"name":"Hash","type":"Hash160"}]},{"name":"Destroy","parameters":[{"name":"Hash","type":"Hash160"}]}]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"extra":null}}""" }, diff --git a/tests/Neo.UnitTests/SmartContract/Native/UT_NeoToken.cs b/tests/Neo.UnitTests/SmartContract/Native/UT_NeoToken.cs index 92f1e0e5f2..b08898aad5 100644 --- a/tests/Neo.UnitTests/SmartContract/Native/UT_NeoToken.cs +++ b/tests/Neo.UnitTests/SmartContract/Native/UT_NeoToken.cs @@ -36,7 +36,7 @@ public class UT_NeoToken [TestInitialize] public void TestSetup() { - _snapshot = TestBlockchain.GetTestSnapshot(); + _snapshot = TestBlockchain.GetTestSnapshotCache(); _persistingBlock = new Block { Header = new Header(), @@ -569,7 +569,7 @@ public void TestCalculateBonus() [TestMethod] public void TestGetNextBlockValidators1() { - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); var result = (VM.Types.Array)NativeContract.NEO.Call(snapshot, "getNextBlockValidators"); result.Count.Should().Be(7); result[0].GetSpan().ToHexString().Should().Be("02486fd15702c4490a26703112a5cc1d0923fd697a33406bd5a1c00e0013b09a70"); @@ -599,7 +599,7 @@ public void TestGetNextBlockValidators2() [TestMethod] public void TestGetCandidates1() { - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); var array = (VM.Types.Array)NativeContract.NEO.Call(snapshot, "getCandidates"); array.Count.Should().Be(0); } @@ -671,7 +671,7 @@ public void TestCheckCandidate() [TestMethod] public void TestGetCommittee() { - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); var result = (VM.Types.Array)NativeContract.NEO.Call(snapshot, "getCommittee"); result.Count.Should().Be(21); result[0].GetSpan().ToHexString().Should().Be("020f2887f41474cfeb11fd262e982051c1541418137c02a0f4961af911045de639"); diff --git a/tests/Neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs b/tests/Neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs index a8d9495b5c..62052ad4bf 100644 --- a/tests/Neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs +++ b/tests/Neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs @@ -31,7 +31,7 @@ public class UT_PolicyContract [TestInitialize] public void TestSetup() { - _snapshot = TestBlockchain.GetTestSnapshot(); + _snapshot = TestBlockchain.GetTestSnapshotCache(); ApplicationEngine engine = ApplicationEngine.Create(TriggerType.OnPersist, null, _snapshot, new Block { Header = new Header() }, settings: TestBlockchain.TheNeoSystem.Settings, gas: 0); NativeContract.ContractManagement.OnPersistAsync(engine); diff --git a/tests/Neo.UnitTests/SmartContract/Native/UT_RoleManagement.cs b/tests/Neo.UnitTests/SmartContract/Native/UT_RoleManagement.cs index 7db5ce4e01..1fbb2a47a0 100644 --- a/tests/Neo.UnitTests/SmartContract/Native/UT_RoleManagement.cs +++ b/tests/Neo.UnitTests/SmartContract/Native/UT_RoleManagement.cs @@ -34,7 +34,7 @@ public class UT_RoleManagement [TestInitialize] public void TestSetup() { - _snapshot = TestBlockchain.GetTestSnapshot(); + _snapshot = TestBlockchain.GetTestSnapshotCache(); } [TestCleanup] diff --git a/tests/Neo.UnitTests/SmartContract/Native/UT_StdLib.cs b/tests/Neo.UnitTests/SmartContract/Native/UT_StdLib.cs index b5c9c198ec..28835aa55e 100644 --- a/tests/Neo.UnitTests/SmartContract/Native/UT_StdLib.cs +++ b/tests/Neo.UnitTests/SmartContract/Native/UT_StdLib.cs @@ -62,7 +62,7 @@ public void TestItoaAtoi() [TestMethod] public void MemoryCompare() { - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); using (var script = new ScriptBuilder()) { @@ -87,7 +87,7 @@ public void MemoryCompare() [TestMethod] public void CheckDecodeEncode() { - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); using (ScriptBuilder script = new()) { @@ -141,7 +141,7 @@ public void CheckDecodeEncode() [TestMethod] public void MemorySearch() { - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); using (var script = new ScriptBuilder()) { @@ -207,7 +207,7 @@ public void MemorySearch() [TestMethod] public void StringSplit() { - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); using var script = new ScriptBuilder(); script.EmitDynamicCall(NativeContract.StdLib.Hash, "stringSplit", "a,b", ","); @@ -227,7 +227,7 @@ public void StringSplit() [TestMethod] public void StringElementLength() { - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); using var script = new ScriptBuilder(); script.EmitDynamicCall(NativeContract.StdLib.Hash, "strLen", "🦆"); @@ -250,7 +250,7 @@ public void TestInvalidUtf8Sequence() // Simulating invalid UTF-8 byte (0xff) decoded as a UTF-16 char const char badChar = (char)0xff; var badStr = badChar.ToString(); - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); using var script = new ScriptBuilder(); script.EmitDynamicCall(NativeContract.StdLib.Hash, "strLen", badStr); @@ -268,7 +268,7 @@ public void TestInvalidUtf8Sequence() [TestMethod] public void Json_Deserialize() { - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); // Good @@ -317,7 +317,7 @@ public void Json_Deserialize() [TestMethod] public void Json_Serialize() { - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); // Good @@ -367,7 +367,7 @@ public void Json_Serialize() [TestMethod] public void TestRuntime_Serialize() { - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); // Good @@ -388,7 +388,7 @@ public void TestRuntime_Serialize() [TestMethod] public void TestRuntime_Deserialize() { - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); // Good diff --git a/tests/Neo.UnitTests/SmartContract/UT_ApplicationEngine.cs b/tests/Neo.UnitTests/SmartContract/UT_ApplicationEngine.cs index 0969e12776..9a150c2b22 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_ApplicationEngine.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_ApplicationEngine.cs @@ -30,7 +30,7 @@ public partial class UT_ApplicationEngine [TestMethod] public void TestNotify() { - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); using var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, settings: TestBlockchain.TheNeoSystem.Settings); engine.LoadScript(System.Array.Empty()); ApplicationEngine.Notify += Test_Notify1; @@ -66,7 +66,7 @@ private void Test_Notify2(object sender, NotifyEventArgs e) [TestMethod] public void TestCreateDummyBlock() { - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); byte[] SyscallSystemRuntimeCheckWitnessHash = new byte[] { 0x68, 0xf8, 0x27, 0xec, 0x8c }; ApplicationEngine engine = ApplicationEngine.Run(SyscallSystemRuntimeCheckWitnessHash, snapshot, settings: TestProtocolSettings.Default); engine.PersistingBlock.Version.Should().Be(0); @@ -111,7 +111,7 @@ public void TestCheckingHardfork() public void TestSystem_Contract_Call_Permissions() { UInt160 scriptHash; - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); // Setup: put a simple contract to the storage. using (var script = new ScriptBuilder()) diff --git a/tests/Neo.UnitTests/SmartContract/UT_ContractParameterContext.cs b/tests/Neo.UnitTests/SmartContract/UT_ContractParameterContext.cs index aba90cc6f0..8d22a0391c 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_ContractParameterContext.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_ContractParameterContext.cs @@ -43,7 +43,7 @@ public static void ClassSetUp(TestContext ctx) [TestMethod] public void TestGetComplete() { - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); Transaction tx = TestUtils.GetTransaction(UInt160.Parse("0x1bd5c777ec35768892bd3daab60fb7a1cb905066")); var context = new ContractParametersContext(snapshot, tx, TestProtocolSettings.Default.Network); context.Completed.Should().BeFalse(); @@ -52,7 +52,7 @@ public void TestGetComplete() [TestMethod] public void TestToString() { - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); Transaction tx = TestUtils.GetTransaction(UInt160.Parse("0x1bd5c777ec35768892bd3daab60fb7a1cb905066")); var context = new ContractParametersContext(snapshot, tx, TestProtocolSettings.Default.Network); context.Add(contract, 0, new byte[] { 0x01 }); @@ -63,7 +63,7 @@ public void TestToString() [TestMethod] public void TestParse() { - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); var ret = ContractParametersContext.Parse("{\"type\":\"Neo.Network.P2P.Payloads.Transaction\",\"data\":\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFmUJDLobcPtqo9vZKIdjXsd8fVGwEAARI=\",\"items\":{\"0xbecaad15c0ea585211faf99738a4354014f177f2\":{\"script\":\"IQJv8DuUkkHOHa3UNRnmlg4KhbQaaaBcMoEDqivOFZTKFmh0dHaq\",\"parameters\":[{\"type\":\"Signature\",\"value\":\"AQ==\"}],\"signatures\":{\"03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c\":\"AQ==\"}}},\"network\":" + TestProtocolSettings.Default.Network + "}", snapshot); ret.ScriptHashes[0].ToString().Should().Be("0x1bd5c777ec35768892bd3daab60fb7a1cb905066"); ((Transaction)ret.Verifiable).Script.Span.ToHexString().Should().Be(new byte[] { 18 }.ToHexString()); @@ -72,7 +72,7 @@ public void TestParse() [TestMethod] public void TestFromJson() { - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); Action action = () => ContractParametersContext.Parse("{\"type\":\"wrongType\",\"data\":\"00000000007c97764845172d827d3c863743293931a691271a0000000000000000000000000000000000000000000100\",\"items\":{\"0x1bd5c777ec35768892bd3daab60fb7a1cb905066\":{\"script\":\"21026ff03b949241ce1dadd43519e6960e0a85b41a69a05c328103aa2bce1594ca1650680a906ad4\",\"parameters\":[{\"type\":\"Signature\",\"value\":\"01\"}]}}}", snapshot); action.Should().Throw(); } @@ -80,7 +80,7 @@ public void TestFromJson() [TestMethod] public void TestAdd() { - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); Transaction tx = TestUtils.GetTransaction(UInt160.Zero); var context1 = new ContractParametersContext(snapshot, tx, TestProtocolSettings.Default.Network); context1.Add(contract, 0, new byte[] { 0x01 }).Should().BeFalse(); @@ -95,7 +95,7 @@ public void TestAdd() [TestMethod] public void TestGetParameter() { - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); Transaction tx = TestUtils.GetTransaction(UInt160.Parse("0x902e0d38da5e513b6d07c1c55b85e77d3dce8063")); var context = new ContractParametersContext(snapshot, tx, TestProtocolSettings.Default.Network); context.GetParameter(tx.Sender, 0).Should().BeNull(); @@ -108,7 +108,7 @@ public void TestGetParameter() [TestMethod] public void TestGetWitnesses() { - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); Transaction tx = TestUtils.GetTransaction(UInt160.Parse("0x902e0d38da5e513b6d07c1c55b85e77d3dce8063")); var context = new ContractParametersContext(snapshot, tx, TestProtocolSettings.Default.Network); context.Add(contract, 0, new byte[] { 0x01 }); @@ -121,7 +121,7 @@ public void TestGetWitnesses() [TestMethod] public void TestAddSignature() { - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); var singleSender = UInt160.Parse("0x902e0d38da5e513b6d07c1c55b85e77d3dce8063"); Transaction tx = TestUtils.GetTransaction(singleSender); diff --git a/tests/Neo.UnitTests/SmartContract/UT_InteropPrices.cs b/tests/Neo.UnitTests/SmartContract/UT_InteropPrices.cs index 581bf42751..fff5ef1877 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_InteropPrices.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_InteropPrices.cs @@ -64,7 +64,7 @@ public void ApplicationEngineRegularPut() StorageKey skey = TestUtils.GetStorageKey(contractState.Id, key); StorageItem sItem = TestUtils.GetStorageItem(System.Array.Empty()); - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); snapshot.Add(skey, sItem); snapshot.AddContract(script.ToScriptHash(), contractState); @@ -95,7 +95,7 @@ public void ApplicationEngineReusedStorage_FullReuse() StorageKey skey = TestUtils.GetStorageKey(contractState.Id, key); StorageItem sItem = TestUtils.GetStorageItem(value); - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); snapshot.Add(skey, sItem); snapshot.AddContract(script.ToScriptHash(), contractState); @@ -128,7 +128,7 @@ public void ApplicationEngineReusedStorage_PartialReuse() StorageKey skey = TestUtils.GetStorageKey(contractState.Id, key); StorageItem sItem = TestUtils.GetStorageItem(oldValue); - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); snapshot.Add(skey, sItem); snapshot.AddContract(script.ToScriptHash(), contractState); @@ -162,7 +162,7 @@ public void ApplicationEngineReusedStorage_PartialReuseTwice() StorageKey skey = TestUtils.GetStorageKey(contractState.Id, key); StorageItem sItem = TestUtils.GetStorageItem(oldValue); - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); snapshot.Add(skey, sItem); snapshot.AddContract(script.ToScriptHash(), contractState); diff --git a/tests/Neo.UnitTests/SmartContract/UT_InteropService.NEO.cs b/tests/Neo.UnitTests/SmartContract/UT_InteropService.NEO.cs index 4f0767bf2c..a2e22dbff3 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_InteropService.NEO.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_InteropService.NEO.cs @@ -113,7 +113,7 @@ public void TestCrypto_CheckMultiSig() [TestMethod] public void TestContract_Create() { - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); var nef = new NefFile() { Script = Enumerable.Repeat((byte)OpCode.RET, byte.MaxValue).ToArray(), @@ -160,7 +160,7 @@ public void TestContract_Create() [TestMethod] public void TestContract_Update() { - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); var nef = new NefFile() { Script = new[] { (byte)OpCode.RET }, @@ -221,7 +221,7 @@ public void TestContract_Update_Invalid() }; nefFile.CheckSum = NefFile.ComputeChecksum(nefFile); - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); Assert.ThrowsException(() => snapshot.UpdateContract(null, null, new byte[] { 0x01 })); Assert.ThrowsException(() => snapshot.UpdateContract(null, nefFile.ToArray(), null)); @@ -243,7 +243,7 @@ public void TestContract_Update_Invalid() [TestMethod] public void TestStorage_Find() { - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); var state = TestUtils.GetContract(); var storageItem = new StorageItem diff --git a/tests/Neo.UnitTests/SmartContract/UT_InteropService.cs b/tests/Neo.UnitTests/SmartContract/UT_InteropService.cs index 1edcfbd9ca..48203a644a 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_InteropService.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_InteropService.cs @@ -38,7 +38,7 @@ public partial class UT_InteropService : TestKit public void Runtime_GetNotifications_Test() { UInt160 scriptHash2; - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); using (var script = new ScriptBuilder()) { @@ -500,7 +500,7 @@ public void TestBlockchain_GetContract() 0x01, 0x01, 0x01, 0x01, 0x01 }; NativeContract.ContractManagement.GetContract(engine.Snapshot, new UInt160(data1)).Should().BeNull(); - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); var state = TestUtils.GetContract(); snapshot.AddContract(state.Hash, state); engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot); @@ -532,7 +532,7 @@ public void TestBlockchain_ListContracts() var list = NativeContract.ContractManagement.ListContracts(engine.Snapshot); list.ForEach(p => p.Id.Should().BeLessThan(0)); - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); var state = TestUtils.GetContract(); snapshot.AddContract(state.Hash, state); engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot); @@ -566,7 +566,7 @@ public void TestStorage_GetReadOnlyContext() [TestMethod] public void TestStorage_Get() { - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); var state = TestUtils.GetContract(); var storageKey = new StorageKey @@ -624,7 +624,7 @@ public void TestStorage_Put() Assert.ThrowsException(() => engine.Put(storageContext, key, value)); //storage value is constant - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); var storageKey = new StorageKey { @@ -654,7 +654,7 @@ public void TestStorage_Put() public void TestStorage_Delete() { var engine = GetEngine(false, true); - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); var state = TestUtils.GetContract(); var storageKey = new StorageKey { @@ -697,7 +697,7 @@ public void TestStorageContext_AsReadOnly() [TestMethod] public void TestContract_Call() { - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); var method = "method"; var args = new VM.Types.Array { 0, 1 }; var state = TestUtils.GetContract(method, args.Count); @@ -728,7 +728,7 @@ public void TestContract_Call() [TestMethod] public void TestContract_Destroy() { - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); var state = TestUtils.GetContract(); var scriptHash = UInt160.Parse("0xcb9f3b7c6fb1cf2c13a40637c189bdd066a272b4"); var storageItem = new StorageItem @@ -769,7 +769,7 @@ public static void LogEvent(object sender, LogEventArgs args) private static ApplicationEngine GetEngine(bool hasContainer = false, bool hasSnapshot = false, bool hasBlock = false, bool addScript = true, long gas = 20_00000000) { var tx = hasContainer ? TestUtils.GetTransaction(UInt160.Zero) : null; - var snapshot = hasSnapshot ? TestBlockchain.GetTestSnapshot() : null; + var snapshot = hasSnapshot ? TestBlockchain.GetTestSnapshotCache() : null; var block = hasBlock ? new Block { Header = new Header() } : null; var engine = ApplicationEngine.Create(TriggerType.Application, tx, snapshot, block, TestBlockchain.TheNeoSystem.Settings, gas: gas); if (addScript) engine.LoadScript(new byte[] { 0x01 }); diff --git a/tests/Neo.UnitTests/SmartContract/UT_SmartContractHelper.cs b/tests/Neo.UnitTests/SmartContract/UT_SmartContractHelper.cs index f864fbe749..ceb13a2a64 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_SmartContractHelper.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_SmartContractHelper.cs @@ -124,7 +124,7 @@ public void TestIsStandardContract() [TestMethod] public void TestVerifyWitnesses() { - var snapshot1 = TestBlockchain.GetTestSnapshot().CloneCache(); + var snapshot1 = TestBlockchain.GetTestSnapshotCache().CreateSnapshot(); UInt256 index1 = UInt256.Parse("0xa400ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff01"); TestUtils.BlocksAdd(snapshot1, index1, new TrimmedBlock() { @@ -141,7 +141,7 @@ public void TestVerifyWitnesses() TestUtils.BlocksDelete(snapshot1, index1); Assert.AreEqual(false, Neo.SmartContract.Helper.VerifyWitnesses(new Header() { PrevHash = index1 }, TestProtocolSettings.Default, snapshot1, 100)); - var snapshot2 = TestBlockchain.GetTestSnapshot(); + var snapshot2 = TestBlockchain.GetTestSnapshotCache(); UInt256 index2 = UInt256.Parse("0xa400ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff01"); TrimmedBlock block2 = new() { @@ -162,7 +162,7 @@ public void TestVerifyWitnesses() snapshot2.DeleteContract(UInt160.Zero); Assert.AreEqual(false, Neo.SmartContract.Helper.VerifyWitnesses(header2, TestProtocolSettings.Default, snapshot2, 100)); - var snapshot3 = TestBlockchain.GetTestSnapshot(); + var snapshot3 = TestBlockchain.GetTestSnapshotCache(); UInt256 index3 = UInt256.Parse("0xa400ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff01"); TrimmedBlock block3 = new() { diff --git a/tests/Neo.UnitTests/SmartContract/UT_Syscalls.cs b/tests/Neo.UnitTests/SmartContract/UT_Syscalls.cs index e027fa4d88..43448ef218 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_Syscalls.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_Syscalls.cs @@ -62,7 +62,7 @@ public void System_Blockchain_GetBlock() Hashes = new[] { tx.Hash } }; - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); using ScriptBuilder script = new(); script.EmitDynamicCall(NativeContract.Ledger.Hash, "getBlock", block.Hash.ToArray()); @@ -117,7 +117,7 @@ public void System_Blockchain_GetBlock() [TestMethod] public void System_ExecutionEngine_GetScriptContainer() { - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); using ScriptBuilder script = new(); script.EmitSysCall(ApplicationEngine.System_Runtime_GetScriptContainer); @@ -166,7 +166,7 @@ public void System_ExecutionEngine_GetScriptContainer() [TestMethod] public void System_Runtime_GasLeft() { - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); using (var script = new ScriptBuilder()) { @@ -218,7 +218,7 @@ public void System_Runtime_GasLeft() public void System_Runtime_GetInvocationCounter() { ContractState contractA, contractB, contractC; - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); // Create dummy contracts diff --git a/tests/Neo.UnitTests/TestBlockchain.cs b/tests/Neo.UnitTests/TestBlockchain.cs index 7bf26edbd7..0596c629d2 100644 --- a/tests/Neo.UnitTests/TestBlockchain.cs +++ b/tests/Neo.UnitTests/TestBlockchain.cs @@ -41,9 +41,11 @@ internal static void ResetStore() TheNeoSystem.Blockchain.Ask(new Blockchain.Initialize()).Wait(); } - internal static DataCache GetTestSnapshot() + internal static SnapshotCache GetTestSnapshotCache(bool reset = true) { - return TheNeoSystem.GetSnapshotCache().CloneCache(); + if (reset) + ResetStore(); + return TheNeoSystem.GetSnapshot(); } } } diff --git a/tests/Neo.UnitTests/UT_DataCache.cs b/tests/Neo.UnitTests/UT_DataCache.cs index 01bd84c949..5271d446ff 100644 --- a/tests/Neo.UnitTests/UT_DataCache.cs +++ b/tests/Neo.UnitTests/UT_DataCache.cs @@ -22,8 +22,8 @@ public class UT_DataCache [TestMethod] public void TestCachedFind_Between() { - var snapshot = TestBlockchain.GetTestSnapshot(); - var storages = snapshot.CloneCache(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); + var storages = snapshot.CreateSnapshot(); var cache = new ClonedCache(storages); storages.Add @@ -61,8 +61,8 @@ public void TestCachedFind_Between() [TestMethod] public void TestCachedFind_Last() { - var snapshot = TestBlockchain.GetTestSnapshot(); - var storages = snapshot.CloneCache(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); + var storages = snapshotCache.CreateSnapshot(); var cache = new ClonedCache(storages); storages.Add @@ -93,8 +93,8 @@ public void TestCachedFind_Last() [TestMethod] public void TestCachedFind_Empty() { - var snapshot = TestBlockchain.GetTestSnapshot(); - var storages = snapshot.CloneCache(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); + var storages = snapshot.CreateSnapshot(); var cache = new ClonedCache(storages); cache.Add diff --git a/tests/Neo.UnitTests/Wallets/NEP6/UT_NEP6Wallet.cs b/tests/Neo.UnitTests/Wallets/NEP6/UT_NEP6Wallet.cs index 71914c86f0..a914b235b7 100644 --- a/tests/Neo.UnitTests/Wallets/NEP6/UT_NEP6Wallet.cs +++ b/tests/Neo.UnitTests/Wallets/NEP6/UT_NEP6Wallet.cs @@ -89,10 +89,10 @@ public void TestCreateAccount() Script = new byte[1], Signers = new Signer[] { new Signer() { Account = acc.ScriptHash } }, }; - var ctx = new ContractParametersContext(TestBlockchain.GetTestSnapshot(), tx, TestProtocolSettings.Default.Network); + var ctx = new ContractParametersContext(TestBlockchain.GetTestSnapshotCache(), tx, TestProtocolSettings.Default.Network); Assert.IsTrue(uut.Sign(ctx)); tx.Witnesses = ctx.GetWitnesses(); - Assert.IsTrue(tx.VerifyWitnesses(TestProtocolSettings.Default, TestBlockchain.GetTestSnapshot(), long.MaxValue)); + Assert.IsTrue(tx.VerifyWitnesses(TestProtocolSettings.Default, TestBlockchain.GetTestSnapshotCache(), long.MaxValue)); Assert.ThrowsException(() => uut.CreateAccount((byte[])null)); Assert.ThrowsException(() => uut.CreateAccount("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551".HexToBytes())); } diff --git a/tests/Neo.UnitTests/Wallets/UT_AssetDescriptor.cs b/tests/Neo.UnitTests/Wallets/UT_AssetDescriptor.cs index 8d938492bc..427af290b1 100644 --- a/tests/Neo.UnitTests/Wallets/UT_AssetDescriptor.cs +++ b/tests/Neo.UnitTests/Wallets/UT_AssetDescriptor.cs @@ -22,7 +22,7 @@ public class UT_AssetDescriptor [TestMethod] public void TestConstructorWithNonexistAssetId() { - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); Action action = () => { var descriptor = new Neo.Wallets.AssetDescriptor(snapshot, TestProtocolSettings.Default, UInt160.Parse("01ff00ff00ff00ff00ff00ff00ff00ff00ff00a4")); @@ -33,7 +33,7 @@ public void TestConstructorWithNonexistAssetId() [TestMethod] public void Check_GAS() { - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); var descriptor = new Neo.Wallets.AssetDescriptor(snapshot, TestProtocolSettings.Default, NativeContract.GAS.Hash); descriptor.AssetId.Should().Be(NativeContract.GAS.Hash); descriptor.AssetName.Should().Be(nameof(GasToken)); @@ -45,7 +45,7 @@ public void Check_GAS() [TestMethod] public void Check_NEO() { - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); var descriptor = new Neo.Wallets.AssetDescriptor(snapshot, TestProtocolSettings.Default, NativeContract.NEO.Hash); descriptor.AssetId.Should().Be(NativeContract.NEO.Hash); descriptor.AssetName.Should().Be(nameof(NeoToken)); diff --git a/tests/Neo.UnitTests/Wallets/UT_Wallet.cs b/tests/Neo.UnitTests/Wallets/UT_Wallet.cs index d134c6aed3..06619d74f5 100644 --- a/tests/Neo.UnitTests/Wallets/UT_Wallet.cs +++ b/tests/Neo.UnitTests/Wallets/UT_Wallet.cs @@ -217,7 +217,7 @@ public void TestGetAvailable() account.Lock = false; // Fake balance - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); var key = NativeContract.GAS.CreateStorageKey(20, account.ScriptHash); var entry = snapshot.GetAndChange(key, () => new StorageItem(new AccountState())); entry.GetInteroperable().Balance = 10000 * NativeContract.GAS.Factor; @@ -237,7 +237,7 @@ public void TestGetBalance() account.Lock = false; // Fake balance - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); var key = NativeContract.GAS.CreateStorageKey(20, account.ScriptHash); var entry = snapshot.GetAndChange(key, () => new StorageItem(new AccountState())); entry.GetInteroperable().Balance = 10000 * NativeContract.GAS.Factor; @@ -290,7 +290,7 @@ public void TestImport2() [TestMethod] public void TestMakeTransaction1() { - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); MyWallet wallet = new(); Contract contract = Contract.Create(new ContractParameterType[] { ContractParameterType.Boolean }, new byte[] { 1 }); WalletAccount account = wallet.CreateAccount(contract, glkey.PrivateKey); @@ -373,7 +373,7 @@ public void TestMakeTransaction1() [TestMethod] public void TestMakeTransaction2() { - var snapshot = TestBlockchain.GetTestSnapshot(); + var snapshot = TestBlockchain.GetTestSnapshotCache(); MyWallet wallet = new(); Action action = () => wallet.MakeTransaction(snapshot, Array.Empty(), null, null, Array.Empty()); action.Should().Throw(); From e9e71553385bb6ee2f6735bfb7135ee04758a9b9 Mon Sep 17 00:00:00 2001 From: Christopher Schuchardt Date: Tue, 23 Jul 2024 06:27:17 -0400 Subject: [PATCH 56/71] [**Added**] Build `neo-cli` Docker Image (#3355) * Added `devcontrainer` test for `neo-cli` * Basic contrainer setup * Updated version of `checkout` action job's step. * Changed to `neo-cli` * Update `dockerfile` * Updated `PostCreateCommand` * Changed to `bookworm-slim` * Reverted to `Jammy` * Added `sudo` command for `PostCreateCommand` * Added permissions * Removed `screen` command * Added to `bin` and `PostCreateCommand` * Changed `devcontainer` files * Reverted builds * Added `neo` repo to devcontainer * Changed to docker-image for github registry * Fixed Bugs in `docker` support for `neo-cli` image * Added type `container` * Revert `.devcontainer` folder * format * Changed workflow to `docker` for `pkgs-delete.yml` since we use `v4` * Deleted `Dockerfile` from `src\Neo.CLI` * Revert "Deleted `Dockerfile` from `src\Neo.CLI`" This reverts commit b877de06629dbad8b42726ff42113a991d5eb4b2. --------- Co-authored-by: Jimmy --- .github/workflows/docker.yml | 77 +++++++++++++++++++++++++++++++ .github/workflows/pkgs-delete.yml | 13 +++++- .neo/docker/neo-cli/Dockerfile | 8 ++++ 3 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/docker.yml create mode 100644 .neo/docker/neo-cli/Dockerfile diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml new file mode 100644 index 0000000000..3d8e7d0d6c --- /dev/null +++ b/.github/workflows/docker.yml @@ -0,0 +1,77 @@ +name: Publish (docker-image) + +on: + release: + types: [published] + +env: + DOTNET_VERSION: 8.0.x + DIST_DIR: ./dist + +jobs: + neo-cli-build: + runs-on: ubuntu-latest + + steps: + - name: Set Application Version (Environment Variable) + run: | + APP_VERSION=$(echo '${{ github.event.release.tag_name }}' | cut -d 'v' -f 2) + echo "APP_VERSION=$APP_VERSION" >> $GITHUB_ENV + + - name: Checkout (GitHub) + uses: actions/checkout@v4 + + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: ${{ env.DOTNET_VERSION }} + + - name: Build (neo-cli) + run: | + dotnet publish ./src/Neo.CLI \ + --framework net8.0 \ + --configuration Release \ + --runtime linux-x64 \ + --self-contained true \ + --output ${{ env.DIST_DIR }} \ + --verbosity normal \ + -p:VersionPrefix=${{ env.APP_VERSION }} \ + -p:RuntimeIdentifier=linux-x64 \ + -p:SelfContained=true \ + -p:IncludeNativeLibrariesForSelfExtract=false \ + -p:PublishTrimmed=false \ + -p:PublishSingleFile=true \ + -p:PublishReadyToRun=true \ + -p:EnableCompressionInSingleFile=true \ + -p:DebugType=embedded \ + -p:ServerGarbageCollection=true + + - name: Build (LevelDbStore) + run: | + dotnet build ./src/Plugins/LevelDBStore \ + --framework net8.0 \ + --configuration Release \ + --output ${{ env.DIST_DIR }}/Plugins/LevelDBStore \ + --verbosity normal \ + -p:VersionPrefix=${{ env.APP_VERSION }} + + - name: Remove (junk) + run: | + rm -v ${{ env.DIST_DIR }}/Plugins/LevelDBStore/Neo* + rm -v ${{ env.DIST_DIR }}/Plugins/LevelDBStore/*.pdb + rm -v ${{ env.DIST_DIR }}/Plugins/LevelDBStore/*.xml + rm -v ${{ env.DIST_DIR }}/*.xml + + - name: Docker Login + run: | + docker login ghcr.io \ + --username ${{ github.repository_owner }} \ + --password ${{ secrets.GITHUB_TOKEN }} + + - name: Docker Build + run: | + docker build . \ + --file ./.neo/docker/neo-cli/Dockerfile \ + --tag ghcr.io/${{ github.repository_owner }}/neo-cli:latest \ + --tag ghcr.io/${{ github.repository_owner }}/neo-cli:${{ env.APP_VERSION }} \ + --push diff --git a/.github/workflows/pkgs-delete.yml b/.github/workflows/pkgs-delete.yml index cf3471b551..2dc580953d 100644 --- a/.github/workflows/pkgs-delete.yml +++ b/.github/workflows/pkgs-delete.yml @@ -102,7 +102,7 @@ jobs: delete-only-pre-release-versions: "true" token: "${{ secrets.GITHUB_TOKEN }}" - - name: Delete Neo Package + - name: Delete Neo Package (nuget) uses: actions/delete-package-versions@v4 with: package-name: Neo @@ -110,6 +110,16 @@ jobs: min-versions-to-keep: 3 delete-only-pre-release-versions: "true" token: "${{ secrets.GITHUB_TOKEN }}" + + - name: Delete Neo Package (docker) + uses: actions/delete-package-versions@v4 + with: + package-name: Neo + package-type: docker + min-versions-to-keep: 1 + delete-only-pre-release-versions: "true" + token: "${{ secrets.GITHUB_TOKEN }}" + - name: Delete Neo.ConsoleService Package uses: actions/delete-package-versions@v4 with: @@ -118,6 +128,7 @@ jobs: min-versions-to-keep: 3 delete-only-pre-release-versions: "true" token: "${{ secrets.GITHUB_TOKEN }}" + - name: Delete Neo.Extensions Package uses: actions/delete-package-versions@v4 with: diff --git a/.neo/docker/neo-cli/Dockerfile b/.neo/docker/neo-cli/Dockerfile new file mode 100644 index 0000000000..afdd97e597 --- /dev/null +++ b/.neo/docker/neo-cli/Dockerfile @@ -0,0 +1,8 @@ +FROM debian:stable-slim + +# Install the apt-get packages +RUN apt-get update +RUN apt-get install -y libicu-dev libleveldb-dev screen + +COPY ./dist /opt/neo-cli +RUN ln -s /opt/neo-cli/neo-cli /usr/bin From f8b090b30f74d493b2611795f7ee27f45fa7d810 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Wed, 24 Jul 2024 14:36:58 +0800 Subject: [PATCH 57/71] [Neo Core Doc]create a docs folder and move existing doc to it. (#3435) * create a docs folder and move existing doc to it. * move neocli config md --- {src/Neo.VM => docs}/ReferenceCounter.md | 0 {src/Neo.CLI => docs}/config.json.md | 0 {src/Neo/IEventHandlers => docs}/handlers.md | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename {src/Neo.VM => docs}/ReferenceCounter.md (100%) rename {src/Neo.CLI => docs}/config.json.md (100%) rename {src/Neo/IEventHandlers => docs}/handlers.md (100%) diff --git a/src/Neo.VM/ReferenceCounter.md b/docs/ReferenceCounter.md similarity index 100% rename from src/Neo.VM/ReferenceCounter.md rename to docs/ReferenceCounter.md diff --git a/src/Neo.CLI/config.json.md b/docs/config.json.md similarity index 100% rename from src/Neo.CLI/config.json.md rename to docs/config.json.md diff --git a/src/Neo/IEventHandlers/handlers.md b/docs/handlers.md similarity index 100% rename from src/Neo/IEventHandlers/handlers.md rename to docs/handlers.md From e73f533147eeb2745b4be4aa94974d3d5acee8a5 Mon Sep 17 00:00:00 2001 From: Christopher Schuchardt Date: Wed, 24 Jul 2024 03:46:19 -0400 Subject: [PATCH 58/71] [**Part-1**] Added `ApplicationLogs` Unit Tests (#3346) * Added ApplicationLogs Tests * Fixed pathing and naming * Merged `Part-2` * Fixed Test for `Test_Put_Get_NotifyState_Storage` --------- Co-authored-by: NGD Admin <154295625+NGDAdmin@users.noreply.github.com> Co-authored-by: Shargon Co-authored-by: Jimmy --- .github/workflows/main.yml | 2 + neo.sln | 7 + .../ApplicationLogs/ApplicationLogs.csproj | 5 + .../Neo.Plugins.ApplicationLogs.Tests.csproj | 19 +++ .../Setup/TestStorage.cs | 31 ++++ .../UT_LogStorageStore.cs | 156 ++++++++++++++++++ 6 files changed, 220 insertions(+) create mode 100644 tests/Neo.Plugins.ApplicationLogs.Tests/Neo.Plugins.ApplicationLogs.Tests.csproj create mode 100644 tests/Neo.Plugins.ApplicationLogs.Tests/Setup/TestStorage.cs create mode 100644 tests/Neo.Plugins.ApplicationLogs.Tests/UT_LogStorageStore.cs diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 30939152a7..22cf4d08df 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -89,6 +89,7 @@ jobs: dotnet test ./tests/Neo.Plugins.OracleService.Tests --output ./bin/tests/Neo.Plugins.OracleService.Tests dotnet test ./tests/Neo.Plugins.RpcServer.Tests --output ./bin/tests/Neo.Plugins.RpcServer.Tests dotnet test ./tests/Neo.Plugins.Storage.Tests --output ./bin/tests/Neo.Plugins.Storage.Tests + dotnet test ./tests/Neo.Plugins.ApplicationLogs.Tests --output ./bin/tests/Neo.Plugins.ApplicationLogs.Tests - name: Coveralls if: matrix.os == 'ubuntu-latest' @@ -106,6 +107,7 @@ jobs: ${{ github.workspace }}/tests/Neo.Plugins.OracleService.Tests/TestResults/coverage.info ${{ github.workspace }}/tests/Neo.Plugins.RpcServer.Tests/TestResults/coverage.info ${{ github.workspace }}/tests/Neo.Plugins.Storage.Tests/TestResults/coverage.info + ${{ github.workspace }}/tests/Neo.Plugins.ApplicationLogs.Tests/TestResults/coverage.info ${{ github.workspace }}/tests/Neo.Extensions.Tests/TestResults/coverage.info PublishPackage: diff --git a/neo.sln b/neo.sln index 5d55b0d785..5e7f8c7dda 100644 --- a/neo.sln +++ b/neo.sln @@ -78,6 +78,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TokensTracker", "src\Plugin EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RpcClient", "src\Plugins\RpcClient\RpcClient.csproj", "{185ADAFC-BFC6-413D-BC2E-97F9FB0A8AF0}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.Plugins.ApplicationLogs.Tests", "tests\Neo.Plugins.ApplicationLogs.Tests\Neo.Plugins.ApplicationLogs.Tests.csproj", "{8C866DC8-2E55-4399-9563-2F47FD4602EC}" +EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Neo.Extensions.Tests", "tests\Neo.Extensions.Tests\Neo.Extensions.Tests.csproj", "{77FDEE2E-9381-4BFC-B9E6-741EDBD6B90F}" EndProject Global @@ -218,6 +220,10 @@ Global {185ADAFC-BFC6-413D-BC2E-97F9FB0A8AF0}.Debug|Any CPU.Build.0 = Debug|Any CPU {185ADAFC-BFC6-413D-BC2E-97F9FB0A8AF0}.Release|Any CPU.ActiveCfg = Release|Any CPU {185ADAFC-BFC6-413D-BC2E-97F9FB0A8AF0}.Release|Any CPU.Build.0 = Release|Any CPU + {8C866DC8-2E55-4399-9563-2F47FD4602EC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8C866DC8-2E55-4399-9563-2F47FD4602EC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8C866DC8-2E55-4399-9563-2F47FD4602EC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8C866DC8-2E55-4399-9563-2F47FD4602EC}.Release|Any CPU.Build.0 = Release|Any CPU {77FDEE2E-9381-4BFC-B9E6-741EDBD6B90F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {77FDEE2E-9381-4BFC-B9E6-741EDBD6B90F}.Debug|Any CPU.Build.0 = Debug|Any CPU {77FDEE2E-9381-4BFC-B9E6-741EDBD6B90F}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -261,6 +267,7 @@ Global {FF76D8A4-356B-461A-8471-BC1B83E57BBC} = {C2DC830A-327A-42A7-807D-295216D30DBB} {5E4947F3-05D3-4806-B0F3-30DAC71B5986} = {C2DC830A-327A-42A7-807D-295216D30DBB} {185ADAFC-BFC6-413D-BC2E-97F9FB0A8AF0} = {C2DC830A-327A-42A7-807D-295216D30DBB} + {8C866DC8-2E55-4399-9563-2F47FD4602EC} = {7F257712-D033-47FF-B439-9D4320D06599} {77FDEE2E-9381-4BFC-B9E6-741EDBD6B90F} = {EDE05FA8-8E73-4924-BC63-DD117127EEE1} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution diff --git a/src/Plugins/ApplicationLogs/ApplicationLogs.csproj b/src/Plugins/ApplicationLogs/ApplicationLogs.csproj index 0d01281c6a..b0c31a7180 100644 --- a/src/Plugins/ApplicationLogs/ApplicationLogs.csproj +++ b/src/Plugins/ApplicationLogs/ApplicationLogs.csproj @@ -14,9 +14,14 @@ runtime + PreserveNewest + + + + diff --git a/tests/Neo.Plugins.ApplicationLogs.Tests/Neo.Plugins.ApplicationLogs.Tests.csproj b/tests/Neo.Plugins.ApplicationLogs.Tests/Neo.Plugins.ApplicationLogs.Tests.csproj new file mode 100644 index 0000000000..e8a46d3022 --- /dev/null +++ b/tests/Neo.Plugins.ApplicationLogs.Tests/Neo.Plugins.ApplicationLogs.Tests.csproj @@ -0,0 +1,19 @@ + + + + net8.0 + Neo.Plugins.ApplicationsLogs.Tests + + + + + + + + + + + + + + diff --git a/tests/Neo.Plugins.ApplicationLogs.Tests/Setup/TestStorage.cs b/tests/Neo.Plugins.ApplicationLogs.Tests/Setup/TestStorage.cs new file mode 100644 index 0000000000..17498d64e4 --- /dev/null +++ b/tests/Neo.Plugins.ApplicationLogs.Tests/Setup/TestStorage.cs @@ -0,0 +1,31 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// StorageFixture.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using Neo.Persistence; +using Neo.Plugins.ApplicationLogs.Store; +using Neo.Plugins.Storage; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Xunit; + +namespace Neo.Plugins.ApplicationsLogs.Tests.Setup +{ + public class TestStorage + { + private static readonly string s_dirPath = Path.GetRandomFileName(); + private static readonly RocksDBStore rocksDbStore = new RocksDBStore(); + public static readonly IStore Store = rocksDbStore.GetStore(s_dirPath); + } +} diff --git a/tests/Neo.Plugins.ApplicationLogs.Tests/UT_LogStorageStore.cs b/tests/Neo.Plugins.ApplicationLogs.Tests/UT_LogStorageStore.cs new file mode 100644 index 0000000000..5cb6fd2d6e --- /dev/null +++ b/tests/Neo.Plugins.ApplicationLogs.Tests/UT_LogStorageStore.cs @@ -0,0 +1,156 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_LogStorageStore.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using Microsoft.AspNetCore.Authorization; +using Neo.Persistence; +using Neo.Plugins.ApplicationLogs.Store; +using Neo.Plugins.ApplicationLogs.Store.States; +using Neo.Plugins.ApplicationsLogs.Tests.Setup; +using Neo.SmartContract; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Xunit; + +namespace Neo.Plugins.ApplicationsLogs.Tests +{ + public class UT_LogStorageStore + { + [Theory] + [InlineData(TriggerType.OnPersist, "0x0000000000000000000000000000000000000000000000000000000000000001")] + [InlineData(TriggerType.Application, "0x0000000000000000000000000000000000000000000000000000000000000002")] + [InlineData(TriggerType.PostPersist, "0x0000000000000000000000000000000000000000000000000000000000000003")] + public void Test_Put_Get_BlockState_Storage(TriggerType expectedAppTrigger, string expectedBlockHashString) + { + var expectedGuid = Guid.NewGuid(); + var expectedHash = UInt256.Parse(expectedBlockHashString); + + using (var snapshot = TestStorage.Store.GetSnapshot()) + { + using (var lss = new LogStorageStore(snapshot)) + { + // Put Block States in Storage for each Trigger + lss.PutBlockState(expectedHash, expectedAppTrigger, BlockLogState.Create([expectedGuid])); + // Commit Data to "Store" Storage for Lookup + snapshot.Commit(); + } + } + + // The Current way that ISnapshot Works we need to Create New Instance of LogStorageStore + using (var lss = new LogStorageStore(TestStorage.Store.GetSnapshot())) + { + // Get OnPersist Block State from Storage + var actualFound = lss.TryGetBlockState(expectedHash, expectedAppTrigger, out var actualState); + + Assert.True(actualFound); + Assert.NotNull(actualState); + Assert.NotNull(actualState.NotifyLogIds); + Assert.Single(actualState.NotifyLogIds); + Assert.Equal(expectedGuid, actualState.NotifyLogIds[0]); + } + } + + [Theory] + [InlineData("00000000-0000-0000-0000-000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000")] + [InlineData("00000000-0000-0000-0000-000000000001", "0x0000000000000000000000000000000000000000000000000000000000000001")] + public void Test_Put_Get_TransactionEngineState_Storage(string expectedLogId, string expectedHashString) + { + var expectedGuid = Guid.Parse(expectedLogId); + var expectedTxHash = UInt256.Parse(expectedHashString); + + using (var snapshot = TestStorage.Store.GetSnapshot()) + { + using (var lss = new LogStorageStore(snapshot)) + { + // Put Block States in Storage for each Trigger + lss.PutTransactionEngineState(expectedTxHash, TransactionEngineLogState.Create([expectedGuid])); + // Commit Data to "Store" Storage for Lookup + snapshot.Commit(); + } + } + + using (var lss = new LogStorageStore(TestStorage.Store.GetSnapshot())) + { + // Get OnPersist Block State from Storage + var actualFound = lss.TryGetTransactionEngineState(expectedTxHash, out var actualState); + + Assert.True(actualFound); + Assert.NotNull(actualState); + Assert.NotNull(actualState.LogIds); + Assert.Single(actualState.LogIds); + Assert.Equal(expectedGuid, actualState.LogIds[0]); + } + } + + [Theory] + [InlineData("0x0000000000000000000000000000000000000000", "Hello World")] + [InlineData("0x0000000000000000000000000000000000000001", "Hello Again")] + public void Test_Put_Get_EngineState_Storage(string expectedScriptHashString, string expectedMessage) + { + var expectedScriptHash = UInt160.Parse(expectedScriptHashString); + var expectedGuid = Guid.Empty; + + using (var snapshot = TestStorage.Store.GetSnapshot()) + { + using (var lss = new LogStorageStore(snapshot)) + { + expectedGuid = lss.PutEngineState(EngineLogState.Create(expectedScriptHash, expectedMessage)); + snapshot.Commit(); + } + } + + using (var lss = new LogStorageStore(TestStorage.Store.GetSnapshot())) + { + var actualFound = lss.TryGetEngineState(expectedGuid, out var actualState); + + Assert.True(actualFound); + Assert.NotNull(actualState); + Assert.Equal(expectedScriptHash, actualState.ScriptHash); + Assert.Equal(expectedMessage, actualState.Message); + } + } + + [Theory] + [InlineData("0x0000000000000000000000000000000000000000", "SayHello", "00000000-0000-0000-0000-000000000000")] + [InlineData("0x0000000000000000000000000000000000000001", "SayGoodBye", "00000000-0000-0000-0000-000000000001")] + public void Test_Put_Get_NotifyState_Storage(string expectedScriptHashString, string expectedEventName, string expectedItemGuidString) + { + var expectedScriptHash = UInt160.Parse(expectedScriptHashString); + var expectedNotifyEventArgs = new NotifyEventArgs(null, expectedScriptHash, expectedEventName, []); + var expectedItemGuid = Guid.Parse(expectedItemGuidString); + var expectedGuid = Guid.Empty; + + using (var snapshot = TestStorage.Store.GetSnapshot()) + { + using (var lss = new LogStorageStore(snapshot)) + { + expectedGuid = lss.PutNotifyState(NotifyLogState.Create(expectedNotifyEventArgs, [expectedItemGuid])); + snapshot.Commit(); + } + } + + using (var lss = new LogStorageStore(TestStorage.Store.GetSnapshot())) + { + var actualFound = lss.TryGetNotifyState(expectedGuid, out var actualState); + + Assert.True(actualFound); + Assert.NotNull(actualState); + Assert.Equal(expectedScriptHash, actualState.ScriptHash); + Assert.Equal(expectedEventName, actualState.EventName); + Assert.NotNull(actualState.StackItemIds); + Assert.Single(actualState.StackItemIds); + Assert.Equal(expectedItemGuid, actualState.StackItemIds[0]); + } + } + } +} From 31f837402a2aa811ed8b47d3e725d8144af18a71 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Sat, 27 Jul 2024 12:22:29 +0800 Subject: [PATCH 59/71] add unit tests for json (#2993) * add unit tests for json * fix ut * add ut cases for JString. * add invalid jpath tests * behavior of jboolean is kinda weird. i have: Assert.AreEqual failed. Expected:. Actual:. * fix test error * add more test --------- Co-authored-by: Shargon --- tests/Neo.Json.UnitTests/UT_JArray.cs | 66 +++- tests/Neo.Json.UnitTests/UT_JBoolean.cs | 45 +++ tests/Neo.Json.UnitTests/UT_JPath.cs | 69 +++++ tests/Neo.Json.UnitTests/UT_JString.cs | 394 ++++++++++++++++++++++-- 4 files changed, 550 insertions(+), 24 deletions(-) diff --git a/tests/Neo.Json.UnitTests/UT_JArray.cs b/tests/Neo.Json.UnitTests/UT_JArray.cs index b6c603ca2a..1538dfe558 100644 --- a/tests/Neo.Json.UnitTests/UT_JArray.cs +++ b/tests/Neo.Json.UnitTests/UT_JArray.cs @@ -255,17 +255,75 @@ public void TestAsString() Assert.AreEqual(s, "{\"name\":\"alice\",\"age\":30,\"score\":100.001,\"gender\":\"female\",\"isMarried\":true,\"pet\":{\"name\":\"Tom\",\"type\":\"cat\"}},{\"name\":\"bob\",\"age\":100000,\"score\":0.001,\"gender\":\"male\",\"isMarried\":false,\"pet\":{\"name\":\"Paul\",\"type\":\"dog\"}}"); } + [TestMethod] + public void TestCount() + { + var jArray = new JArray { alice, bob }; + jArray.Count.Should().Be(2); + } + + [TestMethod] + public void TestInvalidIndexAccess() + { + var jArray = new JArray { alice }; + Action action = () => { var item = jArray[1]; }; + action.Should().Throw(); + } + + [TestMethod] + public void TestEmptyEnumeration() + { + var jArray = new JArray(); + foreach (var item in jArray) + { + Assert.Fail("Enumeration should not occur on an empty JArray"); + } + } + + [TestMethod] + public void TestImplicitConversionFromJTokenArray() + { + JToken[] jTokens = { alice, bob }; + JArray jArray = jTokens; + + jArray.Count.Should().Be(2); + jArray[0].Should().Be(alice); + jArray[1].Should().Be(bob); + } + + [TestMethod] + public void TestAddNullValues() + { + var jArray = new JArray(); + jArray.Add(null); + jArray.Count.Should().Be(1); + jArray[0].Should().BeNull(); + } + [TestMethod] public void TestClone() { - var jArray = new JArray + var jArray = new JArray { alice, bob }; + var clone = (JArray)jArray.Clone(); + + clone.Should().NotBeSameAs(jArray); + clone.Count.Should().Be(jArray.Count); + + for (int i = 0; i < jArray.Count; i++) { - alice, - bob, - }; + clone[i]?.AsString().Should().Be(jArray[i]?.AsString()); + } + var a = jArray.AsString(); var b = jArray.Clone().AsString(); a.Should().Be(b); } + + [TestMethod] + public void TestReadOnlyBehavior() + { + var jArray = new JArray(); + jArray.IsReadOnly.Should().BeFalse(); + } } } diff --git a/tests/Neo.Json.UnitTests/UT_JBoolean.cs b/tests/Neo.Json.UnitTests/UT_JBoolean.cs index 0e81e99c35..4c5ed6f263 100644 --- a/tests/Neo.Json.UnitTests/UT_JBoolean.cs +++ b/tests/Neo.Json.UnitTests/UT_JBoolean.cs @@ -9,6 +9,8 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using Newtonsoft.Json; + namespace Neo.Json.UnitTests { [TestClass] @@ -31,6 +33,49 @@ public void TestAsNumber() jTrue.AsNumber().Should().Be(1); } + [TestMethod] + public void TestDefaultConstructor() + { + var defaultJBoolean = new JBoolean(); + defaultJBoolean.AsNumber().Should().Be(0); + } + + [TestMethod] + public void TestExplicitFalse() + { + var explicitFalse = new JBoolean(false); + explicitFalse.AsNumber().Should().Be(0); + } + + [TestMethod] + public void TestNullJBoolean() + { + JBoolean nullJBoolean = null; + Assert.ThrowsException(() => nullJBoolean.AsNumber()); + } + + [TestMethod] + public void TestConversionToOtherTypes() + { + Assert.AreEqual("true", jTrue.ToString()); + Assert.AreEqual("false", jFalse.ToString()); + } + + [TestMethod] + public void TestComparisonsWithOtherBooleans() + { + Assert.IsTrue(jTrue.Equals(new JBoolean(true))); + Assert.IsTrue(jFalse.Equals(new JBoolean())); + } + + [TestMethod] + public void TestSerializationAndDeserialization() + { + string serialized = JsonConvert.SerializeObject(jTrue); + var deserialized = JsonConvert.DeserializeObject(serialized); + Assert.AreEqual(jTrue, deserialized); + } + [TestMethod] public void TestEqual() { diff --git a/tests/Neo.Json.UnitTests/UT_JPath.cs b/tests/Neo.Json.UnitTests/UT_JPath.cs index 9d958b1cde..68e204a030 100644 --- a/tests/Neo.Json.UnitTests/UT_JPath.cs +++ b/tests/Neo.Json.UnitTests/UT_JPath.cs @@ -99,6 +99,75 @@ public void TestInvalidFormat() Assert.ThrowsException(() => json.JsonPath("$..*")); Assert.ThrowsException(() => json.JsonPath("..book")); Assert.ThrowsException(() => json.JsonPath("$..")); + + // Test with an empty JSON Path + // Assert.ThrowsException(() => json.JsonPath("")); + + // Test with only special characters + Assert.ThrowsException(() => json.JsonPath("@#$%^&*()")); + + // Test with unmatched brackets + Assert.ThrowsException(() => json.JsonPath("$.store.book[")); + Assert.ThrowsException(() => json.JsonPath("$.store.book)]")); + + // Test with invalid operators + Assert.ThrowsException(() => json.JsonPath("$.store.book=>2")); + + // Test with incorrect field syntax + Assert.ThrowsException(() => json.JsonPath("$.store.'book'")); + Assert.ThrowsException(() => json.JsonPath("$.store.[book]")); + + // Test with unexpected end of expression + Assert.ThrowsException(() => json.JsonPath("$.store.book[?(@.price<")); + + // Test with invalid array indexing + // Assert.ThrowsException(() => json.JsonPath("$.store.book['one']")); + // Assert.ThrowsException(() => json.JsonPath("$.store.book[999]")); + + // Test with invalid recursive descent + Assert.ThrowsException(() => json.JsonPath("$..*..author")); + + // Test with nonexistent functions + Assert.ThrowsException(() => json.JsonPath("$.store.book.length()")); + + // Test with incorrect use of wildcards + // Assert.ThrowsException(() => json.JsonPath("$.*.store")); + + // Test with improper use of filters + Assert.ThrowsException(() => json.JsonPath("$.store.book[?(@.price)]")); + + // Test with mixing of valid and invalid syntax + Assert.ThrowsException(() => json.JsonPath("$.store.book[*],$.invalid")); + + // Test with invalid escape sequences + Assert.ThrowsException(() => json.JsonPath("$.store.book[\\]")); + + // Test with incorrect property access + Assert.ThrowsException(() => json.JsonPath("$.store.'b?ook'")); + + // Test with invalid use of wildcard in array index + // Assert.ThrowsException(() => json.JsonPath("$.store.book[*]")); + + // Test with missing operators in filter expressions + Assert.ThrowsException(() => json.JsonPath("$.store.book[?(@.price)]")); + + // Test with incorrect boolean logic in filters + Assert.ThrowsException(() => json.JsonPath("$.store.book[?(@.price AND @.title)]")); + + // Test with nested filters without proper closure + Assert.ThrowsException(() => json.JsonPath("$.store.book[?(@.price[?(@ < 10)])]")); + + // Test with misplaced recursive descent operator + // Assert.ThrowsException(() => json.JsonPath("$..store..book")); + + // Test with using JSONPath reserved keywords incorrectly + Assert.ThrowsException(() => json.JsonPath("$..@.book")); + + // Test with incorrect combinations of valid operators + Assert.ThrowsException(() => json.JsonPath("$.store.book..[0]")); + + // Test with invalid script expressions (if supported) + Assert.ThrowsException(() => json.JsonPath("$.store.book[(@.length-1)]")); } } } diff --git a/tests/Neo.Json.UnitTests/UT_JString.cs b/tests/Neo.Json.UnitTests/UT_JString.cs index 3f0ca159ab..a80920ee51 100644 --- a/tests/Neo.Json.UnitTests/UT_JString.cs +++ b/tests/Neo.Json.UnitTests/UT_JString.cs @@ -9,11 +9,50 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using System.Text; +using System.Text.Json; + namespace Neo.Json.UnitTests { [TestClass] public class UT_JString { + private static readonly JString AsicString = "hello world"; + private static readonly JString EscapeString = "\n\t\'\""; + private static readonly JString BadChar = ((char)0xff).ToString(); + private static readonly JString IntegerString = "123"; + private static readonly JString EmptyString = ""; + private static readonly JString SpaceString = " "; + private static readonly JString DoubleString = "123.456"; + private static readonly JString UnicodeString = "\ud83d\ude03\ud83d\ude01"; + private static readonly JString EmojString = "ã🦆"; + private static readonly JString MixedString = "abc123!@# "; + private static readonly JString LongString = new String('x', 5000); // 5000 + private static readonly JString MultiLangString = "Hello 你好 مرحبا"; + private static readonly JString JsonString = "{\"key\": \"value\"}"; + private static readonly JString HtmlEntityString = "& < >"; + private static readonly JString ControlCharString = "\t\n\r"; + private static readonly JString SingleCharString = "a"; + private static readonly JString LongWordString = "Supercalifragilisticexpialidocious"; + private static readonly JString ConcatenatedString = new JString("Hello" + "123" + "!@#"); + private static readonly JString WhiteSpaceString = new JString(" leading and trailing spaces "); + private static readonly JString FilePathString = new JString(@"C:\Users\Example\file.txt"); + private static readonly JString LargeNumberString = new JString("12345678901234567890"); + private static readonly JString HexadecimalString = new JString("0x1A3F"); + private static readonly JString PalindromeString = new JString("racecar"); + private static readonly JString SqlInjectionString = new JString("SELECT * FROM users WHERE name = 'a'; DROP TABLE users;"); + private static readonly JString RegexString = new JString(@"^\d{3}-\d{2}-\d{4}$"); + private static readonly JString DateTimeString = new JString("2023-01-01T00:00:00"); + private static readonly JString SpecialCharString = new JString("!?@#$%^&*()"); + private static readonly JString SubstringString = new JString("Hello world".Substring(0, 5)); + private static readonly JString CaseSensitiveString1 = new JString("TestString"); + private static readonly JString CaseSensitiveString2 = new JString("teststring"); + private static readonly JString BooleanString = new JString("true"); + private static readonly JString FormatSpecifierString = new JString("{0:C}"); + private static readonly JString EmojiSequenceString = new JString("👨‍👩‍👦"); + private static readonly JString NullCharString = new JString("Hello\0World"); + private static readonly JString RepeatingPatternString = new JString("abcabcabc"); + [TestMethod] public void TestConstructor() { @@ -23,42 +62,284 @@ public void TestConstructor() Assert.ThrowsException(() => new JString(null)); } + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void TestConstructorNull() + { + string s = null; + JString jstring = new JString(s); + Assert.AreEqual(s, jstring.Value); + Assert.ThrowsException(() => new JString(null!)); + } + + [TestMethod] + public void TestConstructorEmpty() + { + string s = ""; + JString jstring = new JString(s); + Assert.AreEqual(s, jstring.Value); + } + + [TestMethod] + public void TestConstructorSpace() + { + string s = " "; + JString jstring = new JString(s); + Assert.AreEqual(s, jstring.Value); + Assert.ThrowsException(() => new JString(null)); + } + [TestMethod] public void TestAsBoolean() { - string s1 = "hello world"; - string s2 = ""; - JString jstring1 = new JString(s1); - JString jstring2 = new JString(s2); - Assert.AreEqual(true, jstring1.AsBoolean()); - Assert.AreEqual(false, jstring2.AsBoolean()); + Assert.AreEqual(true, AsicString.AsBoolean()); + Assert.AreEqual(true, EscapeString.AsBoolean()); + Assert.AreEqual(true, BadChar.AsBoolean()); + Assert.AreEqual(true, IntegerString.AsBoolean()); + Assert.AreEqual(false, EmptyString.AsBoolean()); + Assert.AreEqual(true, SpaceString.AsBoolean()); + Assert.AreEqual(true, DoubleString.AsBoolean()); + Assert.AreEqual(true, UnicodeString.AsBoolean()); + Assert.AreEqual(true, EmojString.AsBoolean()); + Assert.AreEqual(true, MixedString.AsBoolean()); + Assert.AreEqual(true, LongString.AsBoolean()); + Assert.AreEqual(true, MultiLangString.AsBoolean()); + Assert.AreEqual(true, JsonString.AsBoolean()); + Assert.AreEqual(true, HtmlEntityString.AsBoolean()); + Assert.AreEqual(true, ControlCharString.AsBoolean()); + Assert.AreEqual(true, SingleCharString.AsBoolean()); + Assert.AreEqual(true, LongWordString.AsBoolean()); + Assert.AreEqual(true, ConcatenatedString.AsBoolean()); + Assert.AreEqual(true, WhiteSpaceString.AsBoolean()); + Assert.AreEqual(true, FilePathString.AsBoolean()); + Assert.AreEqual(true, LargeNumberString.AsBoolean()); + Assert.AreEqual(true, HexadecimalString.AsBoolean()); + Assert.AreEqual(true, PalindromeString.AsBoolean()); + Assert.AreEqual(true, SqlInjectionString.AsBoolean()); + Assert.AreEqual(true, RegexString.AsBoolean()); + Assert.AreEqual(true, DateTimeString.AsBoolean()); + Assert.AreEqual(true, SpecialCharString.AsBoolean()); + Assert.AreEqual(true, SubstringString.AsBoolean()); + Assert.AreEqual(true, CaseSensitiveString1.AsBoolean()); + Assert.AreEqual(true, CaseSensitiveString2.AsBoolean()); + Assert.AreEqual(true, BooleanString.AsBoolean()); + Assert.AreEqual(true, FormatSpecifierString.AsBoolean()); + Assert.AreEqual(true, EmojiSequenceString.AsBoolean()); + Assert.AreEqual(true, NullCharString.AsBoolean()); + Assert.AreEqual(true, RepeatingPatternString.AsBoolean()); } [TestMethod] public void TestAsNumber() { - string s1 = "hello world"; - string s2 = "123"; - string s3 = ""; - JString jstring1 = new JString(s1); - JString jstring2 = new JString(s2); - JString jstring3 = new JString(s3); - Assert.AreEqual(double.NaN, jstring1.AsNumber()); - Assert.AreEqual(123, jstring2.AsNumber()); - Assert.AreEqual(0, jstring3.AsNumber()); + Assert.AreEqual(double.NaN, AsicString.AsNumber()); + Assert.AreEqual(double.NaN, EscapeString.AsNumber()); + Assert.AreEqual(double.NaN, BadChar.AsNumber()); + Assert.AreEqual(123, IntegerString.AsNumber()); + Assert.AreEqual(0, EmptyString.AsNumber()); + Assert.AreEqual(double.NaN, SpaceString.AsNumber()); + Assert.AreEqual(123.456, DoubleString.AsNumber()); + Assert.AreEqual(double.NaN, UnicodeString.AsNumber()); + Assert.AreEqual(double.NaN, EmojString.AsNumber()); + Assert.AreEqual(double.NaN, MixedString.AsNumber()); + Assert.AreEqual(double.NaN, LongString.AsNumber()); + Assert.AreEqual(double.NaN, MultiLangString.AsNumber()); + Assert.AreEqual(double.NaN, JsonString.AsNumber()); + Assert.AreEqual(double.NaN, HtmlEntityString.AsNumber()); + Assert.AreEqual(double.NaN, ControlCharString.AsNumber()); + Assert.AreEqual(double.NaN, SingleCharString.AsNumber()); + Assert.AreEqual(double.NaN, LongWordString.AsNumber()); + Assert.AreEqual(double.NaN, ConcatenatedString.AsNumber()); + Assert.AreEqual(double.NaN, WhiteSpaceString.AsNumber()); + Assert.AreEqual(double.NaN, FilePathString.AsNumber()); + Assert.AreEqual(12345678901234567890d, LargeNumberString.AsNumber()); + Assert.AreEqual(double.NaN, HexadecimalString.AsNumber()); // Depending on how hexadecimal strings are handled + Assert.AreEqual(double.NaN, PalindromeString.AsNumber()); + Assert.AreEqual(double.NaN, SqlInjectionString.AsNumber()); + Assert.AreEqual(double.NaN, RegexString.AsNumber()); + Assert.AreEqual(double.NaN, DateTimeString.AsNumber()); + Assert.AreEqual(double.NaN, SpecialCharString.AsNumber()); + Assert.AreEqual(double.NaN, SubstringString.AsNumber()); + Assert.AreEqual(double.NaN, CaseSensitiveString1.AsNumber()); + Assert.AreEqual(double.NaN, CaseSensitiveString2.AsNumber()); + Assert.AreEqual(double.NaN, BooleanString.AsNumber()); + Assert.AreEqual(double.NaN, FormatSpecifierString.AsNumber()); + Assert.AreEqual(double.NaN, EmojiSequenceString.AsNumber()); + Assert.AreEqual(double.NaN, NullCharString.AsNumber()); + Assert.AreEqual(double.NaN, RepeatingPatternString.AsNumber()); } [TestMethod] - public void TestGetEnum() + public void TestValidGetEnum() { - JString s = "James"; - Woo woo = s.GetEnum(); + JString validEnum = "James"; + + Woo woo = validEnum.GetEnum(); Assert.AreEqual(Woo.James, woo); - s = ""; - woo = s.AsEnum(Woo.Jerry, false); + validEnum = ""; + woo = validEnum.AsEnum(Woo.Jerry, false); Assert.AreEqual(Woo.Jerry, woo); } + + [TestMethod] + [ExpectedException(typeof(ArgumentException))] + public void TestInValidGetEnum() + { + JString validEnum = "_James"; + Woo woo = validEnum.GetEnum(); + } + + [TestMethod] + public void TestMixedString() + { + Assert.AreEqual("abc123!@# ", MixedString.Value); + } + + [TestMethod] + public void TestLongString() + { + Assert.AreEqual(new String('x', 5000), LongString.Value); + } + + [TestMethod] + public void TestMultiLangString() + { + Assert.AreEqual("Hello 你好 مرحبا", MultiLangString.Value); + } + + [TestMethod] + public void TestJsonString() + { + Assert.AreEqual("{\"key\": \"value\"}", JsonString.Value); + } + + [TestMethod] + public void TestHtmlEntityString() + { + Assert.AreEqual("& < >", HtmlEntityString.Value); + } + + [TestMethod] + public void TestControlCharString() + { + Assert.AreEqual("\t\n\r", ControlCharString.Value); + } + + [TestMethod] + public void TestSingleCharString() + { + Assert.AreEqual("a", SingleCharString.Value); + } + + [TestMethod] + public void TestLongWordString() + { + Assert.AreEqual("Supercalifragilisticexpialidocious", LongWordString.Value); + } + + [TestMethod] + public void TestConcatenatedString() + { + Assert.AreEqual("Hello123!@#", ConcatenatedString.Value); + } + + [TestMethod] + public void TestWhiteSpaceString() + { + Assert.AreEqual(" leading and trailing spaces ", WhiteSpaceString.Value); + } + + [TestMethod] + public void TestFilePathString() + { + Assert.AreEqual(@"C:\Users\Example\file.txt", FilePathString.Value); + } + + [TestMethod] + public void TestLargeNumberString() + { + Assert.AreEqual("12345678901234567890", LargeNumberString.Value); + } + + [TestMethod] + public void TestHexadecimalString() + { + Assert.AreEqual("0x1A3F", HexadecimalString.Value); + } + + [TestMethod] + public void TestPalindromeString() + { + Assert.AreEqual("racecar", PalindromeString.Value); + } + + [TestMethod] + public void TestSqlInjectionString() + { + Assert.AreEqual("SELECT * FROM users WHERE name = 'a'; DROP TABLE users;", SqlInjectionString.Value); + } + + [TestMethod] + public void TestRegexString() + { + Assert.AreEqual(@"^\d{3}-\d{2}-\d{4}$", RegexString.Value); + } + + [TestMethod] + public void TestDateTimeString() + { + Assert.AreEqual("2023-01-01T00:00:00", DateTimeString.Value); + } + + [TestMethod] + public void TestSpecialCharString() + { + Assert.AreEqual("!?@#$%^&*()", SpecialCharString.Value); + } + + [TestMethod] + public void TestSubstringString() + { + Assert.AreEqual("Hello", SubstringString.Value); + } + + [TestMethod] + public void TestCaseSensitiveStrings() + { + Assert.AreNotEqual(CaseSensitiveString1.Value, CaseSensitiveString2.Value); + } + + [TestMethod] + public void TestBooleanString() + { + Assert.AreEqual("true", BooleanString.Value); + } + + [TestMethod] + public void TestFormatSpecifierString() + { + Assert.AreEqual("{0:C}", FormatSpecifierString.Value); + } + + [TestMethod] + public void TestEmojiSequenceString() + { + Assert.AreEqual("👨‍👩‍👦", EmojiSequenceString.Value); + } + + [TestMethod] + public void TestNullCharString() + { + Assert.AreEqual("Hello\0World", NullCharString.Value); + } + + [TestMethod] + public void TestRepeatingPatternString() + { + Assert.AreEqual("abcabcabc", RepeatingPatternString.Value); + } + [TestMethod] public void TestEqual() { @@ -80,5 +361,78 @@ public void TestEqual() var reference = jString; Assert.IsTrue(jString.Equals(reference)); } + + [TestMethod] + public void TestWrite() + { + var jString = new JString("hello world"); + using (var stream = new MemoryStream()) + using (var writer = new Utf8JsonWriter(stream)) + { + jString.Write(writer); + writer.Flush(); + var json = Encoding.UTF8.GetString(stream.ToArray()); + Assert.AreEqual("\"hello world\"", json); + } + } + + [TestMethod] + public void TestClone() + { + var jString = new JString("hello world"); + var clone = jString.Clone(); + Assert.AreEqual(jString, clone); + Assert.AreSame(jString, clone); // Cloning should return the same instance for immutable objects + } + + [TestMethod] + public void TestEqualityWithDifferentTypes() + { + var jString = new JString("hello world"); + Assert.IsFalse(jString.Equals(123)); + Assert.IsFalse(jString.Equals(new object())); + Assert.IsFalse(jString.Equals(new JBoolean())); + } + + [TestMethod] + public void TestImplicitOperators() + { + JString fromEnum = EnumExample.Value; + Assert.AreEqual("Value", fromEnum.Value); + + JString fromString = "test string"; + Assert.AreEqual("test string", fromString.Value); + + JString nullString = (string)null; + Assert.IsNull(nullString); + } + + [TestMethod] + public void TestBoundaryAndSpecialCases() + { + JString largeString = new string('a', ushort.MaxValue); + Assert.AreEqual(ushort.MaxValue, largeString.Value.Length); + + JString specialUnicode = "\uD83D\uDE00"; // 😀 emoji + Assert.AreEqual("\uD83D\uDE00", specialUnicode.Value); + + JString complexJson = "{\"nested\":{\"key\":\"value\"}}"; + Assert.AreEqual("{\"nested\":{\"key\":\"value\"}}", complexJson.Value); + } + + [TestMethod] + public void TestExceptionHandling() + { + JString invalidEnum = "invalid_value"; + + var result = invalidEnum.AsEnum(Woo.Jerry); + Assert.AreEqual(Woo.Jerry, result); + + Assert.ThrowsException(() => invalidEnum.GetEnum()); + } + } + public enum EnumExample + { + Value } } From 97a4417e5503fe819530a3001630f4f37fb474a2 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Mon, 29 Jul 2024 14:59:03 +0800 Subject: [PATCH 60/71] [Neo Core VM] complete opcode comments (#3437) * complete opcode comments * Apply suggestions from code review * Update src/Neo.VM/OpCode.cs --------- Co-authored-by: Shargon --- src/Neo.VM/JumpTable/JumpTable.Compound.cs | 3 +- src/Neo.VM/JumpTable/JumpTable.Numeric.cs | 6 +- src/Neo.VM/JumpTable/JumpTable.Splice.cs | 1 + src/Neo.VM/JumpTable/JumpTable.Stack.cs | 4 +- src/Neo.VM/OpCode.cs | 1215 +++++++++++++++++++- 5 files changed, 1215 insertions(+), 14 deletions(-) diff --git a/src/Neo.VM/JumpTable/JumpTable.Compound.cs b/src/Neo.VM/JumpTable/JumpTable.Compound.cs index aeb2047825..197cc1952a 100644 --- a/src/Neo.VM/JumpTable/JumpTable.Compound.cs +++ b/src/Neo.VM/JumpTable/JumpTable.Compound.cs @@ -239,6 +239,7 @@ public virtual void NewMap(ExecutionEngine engine, Instruction instruction) [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Size(ExecutionEngine engine, Instruction instruction) { + // TODO: we should be able to optimize by using peek instead of dup and pop var x = engine.Pop(); switch (x) { @@ -410,7 +411,7 @@ public virtual void PickItem(ExecutionEngine engine, Instruction instruction) /// /// The execution engine. /// The instruction being executed. - /// Pop 1, Push 1 + /// Pop 2, Push 0 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Append(ExecutionEngine engine, Instruction instruction) { diff --git a/src/Neo.VM/JumpTable/JumpTable.Numeric.cs b/src/Neo.VM/JumpTable/JumpTable.Numeric.cs index 989991a07c..06533e293a 100644 --- a/src/Neo.VM/JumpTable/JumpTable.Numeric.cs +++ b/src/Neo.VM/JumpTable/JumpTable.Numeric.cs @@ -155,7 +155,7 @@ public virtual void Div(ExecutionEngine engine, Instruction instruction) } /// - /// Computes the result of raising a number to the specified power. + /// Computes the remainder after dividing a by b. /// /// /// The execution engine. @@ -170,7 +170,7 @@ public virtual void Mod(ExecutionEngine engine, Instruction instruction) } /// - /// Computes the square root of the specified integer. + /// Computes the result of raising a number to the specified power. /// /// /// The execution engine. @@ -186,7 +186,7 @@ public virtual void Pow(ExecutionEngine engine, Instruction instruction) } /// - /// + /// Returns the square root of a specified number. /// /// /// The execution engine. diff --git a/src/Neo.VM/JumpTable/JumpTable.Splice.cs b/src/Neo.VM/JumpTable/JumpTable.Splice.cs index 2f49ea0107..f04d045988 100644 --- a/src/Neo.VM/JumpTable/JumpTable.Splice.cs +++ b/src/Neo.VM/JumpTable/JumpTable.Splice.cs @@ -59,6 +59,7 @@ public virtual void Memcpy(ExecutionEngine engine, Instruction instruction) Types.Buffer dst = engine.Pop(); if (checked(di + count) > dst.Size) throw new InvalidOperationException($"The value {count} is out of range."); + // TODO: check if we can optimize the memcpy by using peek instead of dup then pop src.Slice(si, count).CopyTo(dst.InnerBuffer.Span[di..]); } diff --git a/src/Neo.VM/JumpTable/JumpTable.Stack.cs b/src/Neo.VM/JumpTable/JumpTable.Stack.cs index 45ee5565a7..68094470fe 100644 --- a/src/Neo.VM/JumpTable/JumpTable.Stack.cs +++ b/src/Neo.VM/JumpTable/JumpTable.Stack.cs @@ -47,7 +47,7 @@ public virtual void Drop(ExecutionEngine engine, Instruction instruction) } /// - /// + /// Removes the second-to-top stack item. /// /// /// The execution engine. @@ -59,7 +59,7 @@ public virtual void Nip(ExecutionEngine engine, Instruction instruction) } /// - /// Removes the nth item from the top of the evaluation stack. + /// Removes the n-th item from the top of the evaluation stack. /// /// /// The execution engine. diff --git a/src/Neo.VM/OpCode.cs b/src/Neo.VM/OpCode.cs index dd5f1574ea..8ef5c0e538 100644 --- a/src/Neo.VM/OpCode.cs +++ b/src/Neo.VM/OpCode.cs @@ -22,136 +22,321 @@ public enum OpCode : byte /// /// Pushes a 1-byte signed integer onto the stack. + /// + /// + /// Push: 1 item(s) + /// Pop: 0 item(s) + /// /// [OperandSize(Size = 1)] PUSHINT8 = 0x00, + /// /// Pushes a 2-bytes signed integer onto the stack. + /// + /// + /// Push: 1 item(s) + /// Pop: 0 item(s) + /// /// [OperandSize(Size = 2)] PUSHINT16 = 0x01, + /// /// Pushes a 4-bytes signed integer onto the stack. + /// + /// + /// Push: 1 item(s) + /// Pop: 0 item(s) + /// /// [OperandSize(Size = 4)] PUSHINT32 = 0x02, + /// - /// Pushes a 8-bytes signed integer onto the stack. + /// Pushes an 8-bytes signed integer onto the stack. + /// + /// + /// Push: 1 item(s) + /// Pop: 0 item(s) + /// /// [OperandSize(Size = 8)] PUSHINT64 = 0x03, + /// /// Pushes a 16-bytes signed integer onto the stack. + /// + /// + /// Push: 1 item(s) + /// Pop: 0 item(s) + /// /// [OperandSize(Size = 16)] PUSHINT128 = 0x04, + /// /// Pushes a 32-bytes signed integer onto the stack. + /// + /// + /// Push: 1 item(s) + /// Pop: 0 item(s) + /// /// [OperandSize(Size = 32)] PUSHINT256 = 0x05, + /// /// Pushes the boolean value onto the stack. + /// + /// + /// Push: 1 item(s) + /// Pop: 0 item(s) + /// /// PUSHT = 0x08, + /// /// Pushes the boolean value onto the stack. + /// + /// + /// Push: 1 item(s) + /// Pop: 0 item(s) + /// /// PUSHF = 0x09, + /// /// Converts the 4-bytes offset to an , and pushes it onto the stack. + /// + /// + /// Push: 1 item(s) + /// Pop: 0 item(s) + /// /// [OperandSize(Size = 4)] PUSHA = 0x0A, + /// /// The item is pushed onto the stack. + /// + /// + /// Push: 1 item(s) + /// Pop: 0 item(s) + /// /// PUSHNULL = 0x0B, + /// /// The next byte contains the number of bytes to be pushed onto the stack. + /// + /// + /// Push: 1 item(s) + /// Pop: 0 item(s) + /// /// [OperandSize(SizePrefix = 1)] PUSHDATA1 = 0x0C, + /// /// The next two bytes contain the number of bytes to be pushed onto the stack. + /// + /// + /// Push: 1 item(s) + /// Pop: 0 item(s) + /// /// [OperandSize(SizePrefix = 2)] PUSHDATA2 = 0x0D, + /// /// The next four bytes contain the number of bytes to be pushed onto the stack. + /// + /// + /// Push: 1 item(s) + /// Pop: 0 item(s) + /// /// [OperandSize(SizePrefix = 4)] PUSHDATA4 = 0x0E, + /// /// The number -1 is pushed onto the stack. + /// + /// + /// Push: 1 item(s) + /// Pop: 0 item(s) + /// /// PUSHM1 = 0x0F, + /// /// The number 0 is pushed onto the stack. + /// + /// + /// Push: 1 item(s) + /// Pop: 0 item(s) + /// /// PUSH0 = 0x10, + /// /// The number 1 is pushed onto the stack. + /// + /// + /// Push: 1 item(s) + /// Pop: 0 item(s) + /// /// PUSH1 = 0x11, + /// /// The number 2 is pushed onto the stack. + /// + /// + /// Push: 1 item(s) + /// Pop: 0 item(s) + /// /// PUSH2 = 0x12, + /// /// The number 3 is pushed onto the stack. + /// + /// + /// Push: 1 item(s) + /// Pop: 0 item(s) + /// /// PUSH3 = 0x13, + /// /// The number 4 is pushed onto the stack. + /// + /// + /// Push: 1 item(s) + /// Pop: 0 item(s) + /// /// PUSH4 = 0x14, + /// /// The number 5 is pushed onto the stack. + /// + /// + /// Push: 1 item(s) + /// Pop: 0 item(s) + /// /// PUSH5 = 0x15, + /// /// The number 6 is pushed onto the stack. + /// + /// + /// Push: 1 item(s) + /// Pop: 0 item(s) + /// /// PUSH6 = 0x16, + /// /// The number 7 is pushed onto the stack. + /// + /// + /// Push: 1 item(s) + /// Pop: 0 item(s) + /// /// PUSH7 = 0x17, + /// /// The number 8 is pushed onto the stack. + /// + /// + /// Push: 1 item(s) + /// Pop: 0 item(s) + /// /// PUSH8 = 0x18, + /// /// The number 9 is pushed onto the stack. + /// + /// + /// Push: 1 item(s) + /// Pop: 0 item(s) + /// /// PUSH9 = 0x19, + /// /// The number 10 is pushed onto the stack. + /// + /// + /// Push: 1 item(s) + /// Pop: 0 item(s) + /// /// PUSH10 = 0x1A, + /// /// The number 11 is pushed onto the stack. + /// + /// + /// Push: 1 item(s) + /// Pop: 0 item(s) + /// /// PUSH11 = 0x1B, + /// /// The number 12 is pushed onto the stack. + /// + /// + /// Push: 1 item(s) + /// Pop: 0 item(s) + /// /// PUSH12 = 0x1C, + /// /// The number 13 is pushed onto the stack. + /// + /// + /// Push: 1 item(s) + /// Pop: 0 item(s) + /// /// PUSH13 = 0x1D, + /// /// The number 14 is pushed onto the stack. + /// + /// + /// Push: 1 item(s) + /// Pop: 0 item(s) + /// /// PUSH14 = 0x1E, + /// /// The number 15 is pushed onto the stack. + /// + /// + /// Push: 1 item(s) + /// Pop: 0 item(s) + /// /// PUSH15 = 0x1F, + /// /// The number 16 is pushed onto the stack. + /// + /// + /// Push: 1 item(s) + /// Pop: 0 item(s) + /// /// PUSH16 = 0x20, @@ -161,157 +346,299 @@ public enum OpCode : byte /// /// The operation does nothing. It is intended to fill in space if opcodes are patched. + /// + /// + /// Push: 0 item(s) + /// Pop: 0 item(s) + /// /// NOP = 0x21, + /// /// Unconditionally transfers control to a target instruction. The target instruction is represented as a 1-byte signed offset from the beginning of the current instruction. + /// + /// + /// Push: 0 item(s) + /// Pop: 0 item(s) + /// /// [OperandSize(Size = 1)] JMP = 0x22, + /// /// Unconditionally transfers control to a target instruction. The target instruction is represented as a 4-bytes signed offset from the beginning of the current instruction. + /// + /// + /// Push: 0 item(s) + /// Pop: 0 item(s) + /// /// [OperandSize(Size = 4)] JMP_L = 0x23, + /// /// Transfers control to a target instruction if the value is , not , or non-zero. The target instruction is represented as a 1-byte signed offset from the beginning of the current instruction. + /// + /// + /// Push: 0 item(s) + /// Pop: 1 item(s) + /// /// [OperandSize(Size = 1)] JMPIF = 0x24, + /// /// Transfers control to a target instruction if the value is , not , or non-zero. The target instruction is represented as a 4-bytes signed offset from the beginning of the current instruction. + /// + /// + /// Push: 0 item(s) + /// Pop: 1 item(s) + /// /// [OperandSize(Size = 4)] JMPIF_L = 0x25, + /// /// Transfers control to a target instruction if the value is , a reference, or zero. The target instruction is represented as a 1-byte signed offset from the beginning of the current instruction. + /// + /// + /// Push: 0 item(s) + /// Pop: 1 item(s) + /// /// [OperandSize(Size = 1)] JMPIFNOT = 0x26, + /// /// Transfers control to a target instruction if the value is , a reference, or zero. The target instruction is represented as a 4-bytes signed offset from the beginning of the current instruction. + /// + /// + /// Push: 0 item(s) + /// Pop: 1 item(s) + /// /// [OperandSize(Size = 4)] JMPIFNOT_L = 0x27, + /// /// Transfers control to a target instruction if two values are equal. The target instruction is represented as a 1-byte signed offset from the beginning of the current instruction. + /// + /// + /// Push: 0 item(s) + /// Pop: 2 item(s) + /// /// [OperandSize(Size = 1)] JMPEQ = 0x28, + /// /// Transfers control to a target instruction if two values are equal. The target instruction is represented as a 4-bytes signed offset from the beginning of the current instruction. + /// + /// + /// Push: 0 item(s) + /// Pop: 2 item(s) + /// /// [OperandSize(Size = 4)] JMPEQ_L = 0x29, + /// /// Transfers control to a target instruction when two values are not equal. The target instruction is represented as a 1-byte signed offset from the beginning of the current instruction. + /// + /// + /// Push: 0 item(s) + /// Pop: 2 item(s) + /// /// [OperandSize(Size = 1)] JMPNE = 0x2A, + /// /// Transfers control to a target instruction when two values are not equal. The target instruction is represented as a 4-bytes signed offset from the beginning of the current instruction. + /// + /// + /// Push: 0 item(s) + /// Pop: 2 item(s) + /// /// [OperandSize(Size = 4)] JMPNE_L = 0x2B, + /// /// Transfers control to a target instruction if the first value is greater than the second value. The target instruction is represented as a 1-byte signed offset from the beginning of the current instruction. + /// + /// + /// Push: 0 item(s) + /// Pop: 2 item(s) + /// /// [OperandSize(Size = 1)] JMPGT = 0x2C, + /// /// Transfers control to a target instruction if the first value is greater than the second value. The target instruction is represented as a 4-bytes signed offset from the beginning of the current instruction. + /// + /// + /// Push: 0 item(s) + /// Pop: 2 item(s) + /// /// [OperandSize(Size = 4)] JMPGT_L = 0x2D, + /// /// Transfers control to a target instruction if the first value is greater than or equal to the second value. The target instruction is represented as a 1-byte signed offset from the beginning of the current instruction. + /// + /// + /// Push: 0 item(s) + /// Pop: 2 item(s) + /// /// [OperandSize(Size = 1)] JMPGE = 0x2E, + /// /// Transfers control to a target instruction if the first value is greater than or equal to the second value. The target instruction is represented as a 4-bytes signed offset from the beginning of the current instruction. + /// + /// + /// Push: 0 item(s) + /// Pop: 2 item(s) + /// /// [OperandSize(Size = 4)] JMPGE_L = 0x2F, + /// /// Transfers control to a target instruction if the first value is less than the second value. The target instruction is represented as a 1-byte signed offset from the beginning of the current instruction. + /// + /// + /// Push: 0 item(s) + /// Pop: 2 item(s) + /// /// [OperandSize(Size = 1)] JMPLT = 0x30, + /// /// Transfers control to a target instruction if the first value is less than the second value. The target instruction is represented as a 4-bytes signed offset from the beginning of the current instruction. + /// + /// + /// Push: 0 item(s) + /// Pop: 2 item(s) + /// /// [OperandSize(Size = 4)] JMPLT_L = 0x31, + /// /// Transfers control to a target instruction if the first value is less than or equal to the second value. The target instruction is represented as a 1-byte signed offset from the beginning of the current instruction. + /// + /// + /// Push: 0 item(s) + /// Pop: 2 item(s) + /// /// [OperandSize(Size = 1)] JMPLE = 0x32, + /// /// Transfers control to a target instruction if the first value is less than or equal to the second value. The target instruction is represented as a 4-bytes signed offset from the beginning of the current instruction. + /// + /// + /// Push: 0 item(s) + /// Pop: 2 item(s) + /// /// [OperandSize(Size = 4)] JMPLE_L = 0x33, + /// /// Calls the function at the target address which is represented as a 1-byte signed offset from the beginning of the current instruction. /// [OperandSize(Size = 1)] CALL = 0x34, + /// /// Calls the function at the target address which is represented as a 4-bytes signed offset from the beginning of the current instruction. /// [OperandSize(Size = 4)] CALL_L = 0x35, + /// /// Pop the address of a function from the stack, and call the function. /// CALLA = 0x36, + /// /// Calls the function which is described by the token. /// [OperandSize(Size = 2)] CALLT = 0x37, + /// /// It turns the vm state to FAULT immediately, and cannot be caught. + /// + /// + /// Push: 0 item(s) + /// Pop: 0 item(s) + /// /// ABORT = 0x38, + /// /// Pop the top value of the stack. If it's false, exit vm execution and set vm state to FAULT. + /// + /// + /// Push: 0 item(s) + /// Pop: 1 item(s) + /// /// ASSERT = 0x39, + /// /// Pop the top value of the stack, and throw it. + /// + /// + /// Push: 0 item(s) + /// Pop: 1 item(s) + /// /// THROW = 0x3A, + /// /// TRY CatchOffset(sbyte) FinallyOffset(sbyte). If there's no catch body, set CatchOffset 0. If there's no finally body, set FinallyOffset 0. /// [OperandSize(Size = 2)] TRY = 0x3B, + /// /// TRY_L CatchOffset(int) FinallyOffset(int). If there's no catch body, set CatchOffset 0. If there's no finally body, set FinallyOffset 0. /// [OperandSize(Size = 8)] TRY_L = 0x3C, + /// /// Ensures that the appropriate surrounding finally blocks are executed. And then unconditionally transfers control to the specific target instruction, represented as a 1-byte signed offset from the beginning of the current instruction. /// [OperandSize(Size = 1)] ENDTRY = 0x3D, + /// /// Ensures that the appropriate surrounding finally blocks are executed. And then unconditionally transfers control to the specific target instruction, represented as a 4-byte signed offset from the beginning of the current instruction. /// [OperandSize(Size = 4)] ENDTRY_L = 0x3E, + /// - /// End finally, If no exception happen or be catched, vm will jump to the target instruction of ENDTRY/ENDTRY_L. Otherwise vm will rethrow the exception to upper layer. + /// End finally, If no exception happen or be catched, vm will jump to the target instruction of ENDTRY/ENDTRY_L. Otherwise, vm will rethrow the exception to upper layer. /// ENDFINALLY = 0x3F, + /// /// Returns from the current method. /// RET = 0x40, + /// /// Calls to an interop service. /// @@ -324,62 +651,164 @@ public enum OpCode : byte /// /// Puts the number of stack items onto the stack. + /// + /// + /// Push: 1 item(s) + /// Pop: 0 item(s) + /// /// DEPTH = 0x43, + /// /// Removes the top stack item. + /// + /// a b c -> a b + /// + /// + /// Push: 0 item(s) + /// Pop: 1 item(s) + /// /// DROP = 0x45, + /// /// Removes the second-to-top stack item. + /// + /// a b c -> a c + /// + /// + /// Push: 0 item(s) + /// Pop: 1 item(s) + /// /// NIP = 0x46, + /// /// The item n back in the main stack is removed. + /// + /// + /// Push: 0 item(s) + /// Pop: n+1 item(s) + /// /// XDROP = 0x48, + /// /// Clear the stack /// CLEAR = 0x49, + /// /// Duplicates the top stack item. + /// + /// a b c -> a b c c + /// + /// + /// Push: 1 item(s) + /// Pop: 0 item(s) + /// /// DUP = 0x4A, + /// /// Copies the second-to-top stack item to the top. + /// + /// a b c -> a b c b + /// + /// + /// Push: 1 item(s) + /// Pop: 0 item(s) + /// /// OVER = 0x4B, + /// /// The item n back in the stack is copied to the top. + /// + /// + /// Push: 1 item(s) + /// Pop: 0 item(s) + /// /// PICK = 0x4D, + /// /// The item at the top of the stack is copied and inserted before the second-to-top item. + /// + /// + /// Push: 1 item(s) + /// Pop: 0 item(s) + /// /// TUCK = 0x4E, + /// /// The top two items on the stack are swapped. + /// + /// a b -> b a + /// + /// + /// Push: 0 item(s) + /// Pop: 0 item(s) + /// /// SWAP = 0x50, + /// /// The top three items on the stack are rotated to the left. + /// + /// a b c -> b c a + /// + /// + /// Push: 0 item(s) + /// Pop: 0 item(s) + /// /// ROT = 0x51, + /// /// The item n back in the stack is moved to the top. + /// + /// + /// Push: 0 item(s) + /// Pop: 1 item(s) + /// /// ROLL = 0x52, + /// /// Reverse the order of the top 3 items on the stack. + /// + /// a b c -> c b a + /// + /// + /// Push: 0 item(s) + /// Pop: 0 item(s) + /// /// REVERSE3 = 0x53, + /// /// Reverse the order of the top 4 items on the stack. + /// + /// a b c d -> d c b a + /// + /// + /// + /// Push: 0 item(s) + /// Pop: 0 item(s) + /// /// REVERSE4 = 0x54, + /// /// Pop the number N on the stack, and reverse the order of the top N items on the stack. + /// + /// + /// + /// Push: 0 item(s) + /// Pop: 1 item(s) + /// /// REVERSEN = 0x55, @@ -389,209 +818,503 @@ public enum OpCode : byte /// /// Initialize the static field list for the current execution context. + /// + /// + /// Push: 0 item(s) + /// Pop: 0 item(s) + /// /// [OperandSize(Size = 1)] INITSSLOT = 0x56, + /// /// Initialize the argument slot and the local variable list for the current execution context. /// [OperandSize(Size = 2)] INITSLOT = 0x57, + /// /// Loads the static field at index 0 onto the evaluation stack. + /// + /// + /// Push: 1 item(s) + /// Pop: 0 item(s) + /// /// LDSFLD0 = 0x58, + /// /// Loads the static field at index 1 onto the evaluation stack. + /// + /// + /// Push: 1 item(s) + /// Pop: 0 item(s) + /// /// LDSFLD1 = 0x59, + /// /// Loads the static field at index 2 onto the evaluation stack. + /// + /// + /// Push: 1 item(s) + /// Pop: 0 item(s) + /// /// LDSFLD2 = 0x5A, + /// /// Loads the static field at index 3 onto the evaluation stack. + /// + /// + /// Push: 1 item(s) + /// Pop: 0 item(s) + /// /// LDSFLD3 = 0x5B, + /// /// Loads the static field at index 4 onto the evaluation stack. + /// + /// + /// Push: 1 item(s) + /// Pop: 0 item(s) + /// /// LDSFLD4 = 0x5C, + /// /// Loads the static field at index 5 onto the evaluation stack. + /// + /// + /// Push: 1 item(s) + /// Pop: 0 item(s) + /// /// LDSFLD5 = 0x5D, + /// /// Loads the static field at index 6 onto the evaluation stack. + /// + /// + /// Push: 1 item(s) + /// Pop: 0 item(s) + /// /// LDSFLD6 = 0x5E, + /// /// Loads the static field at a specified index onto the evaluation stack. The index is represented as a 1-byte unsigned integer. + /// + /// + /// Push: 1 item(s) + /// Pop: 0 item(s) + /// /// [OperandSize(Size = 1)] LDSFLD = 0x5F, + /// /// Stores the value on top of the evaluation stack in the static field list at index 0. + /// + /// + /// Push: 0 item(s) + /// Pop: 1 item(s) + /// /// STSFLD0 = 0x60, + /// /// Stores the value on top of the evaluation stack in the static field list at index 1. + /// + /// + /// Push: 0 item(s) + /// Pop: 1 item(s) + /// /// STSFLD1 = 0x61, + /// /// Stores the value on top of the evaluation stack in the static field list at index 2. + /// + /// + /// Push: 0 item(s) + /// Pop: 1 item(s) + /// /// STSFLD2 = 0x62, + /// /// Stores the value on top of the evaluation stack in the static field list at index 3. + /// + /// + /// Push: 0 item(s) + /// Pop: 1 item(s) + /// /// STSFLD3 = 0x63, + /// /// Stores the value on top of the evaluation stack in the static field list at index 4. + /// + /// + /// Push: 0 item(s) + /// Pop: 1 item(s) + /// /// STSFLD4 = 0x64, + /// /// Stores the value on top of the evaluation stack in the static field list at index 5. + /// + /// + /// Push: 0 item(s) + /// Pop: 1 item(s) + /// /// STSFLD5 = 0x65, + /// /// Stores the value on top of the evaluation stack in the static field list at index 6. + /// + /// + /// Push: 0 item(s) + /// Pop: 1 item(s) + /// /// STSFLD6 = 0x66, + /// /// Stores the value on top of the evaluation stack in the static field list at a specified index. The index is represented as a 1-byte unsigned integer. + /// + /// + /// Push: 0 item(s) + /// Pop: 1 item(s) + /// /// [OperandSize(Size = 1)] STSFLD = 0x67, + /// /// Loads the local variable at index 0 onto the evaluation stack. + /// + /// + /// Push: 1 item(s) + /// Pop: 0 item(s) + /// /// LDLOC0 = 0x68, + /// /// Loads the local variable at index 1 onto the evaluation stack. + /// + /// + /// Push: 1 item(s) + /// Pop: 0 item(s) + /// /// LDLOC1 = 0x69, + /// /// Loads the local variable at index 2 onto the evaluation stack. + /// + /// + /// Push: 1 item(s) + /// Pop: 0 item(s) + /// /// LDLOC2 = 0x6A, + /// /// Loads the local variable at index 3 onto the evaluation stack. + /// + /// + /// Push: 1 item(s) + /// Pop: 0 item(s) + /// /// LDLOC3 = 0x6B, + /// /// Loads the local variable at index 4 onto the evaluation stack. + /// + /// + /// Push: 1 item(s) + /// Pop: 0 item(s) + /// /// LDLOC4 = 0x6C, + /// /// Loads the local variable at index 5 onto the evaluation stack. + /// + /// + /// Push: 1 item(s) + /// Pop: 0 item(s) + /// /// LDLOC5 = 0x6D, + /// /// Loads the local variable at index 6 onto the evaluation stack. + /// + /// + /// Push: 1 item(s) + /// Pop: 0 item(s) + /// /// LDLOC6 = 0x6E, + /// /// Loads the local variable at a specified index onto the evaluation stack. The index is represented as a 1-byte unsigned integer. + /// + /// + /// Push: 1 item(s) + /// Pop: 0 item(s) + /// /// [OperandSize(Size = 1)] LDLOC = 0x6F, + /// /// Stores the value on top of the evaluation stack in the local variable list at index 0. + /// + /// + /// Push: 0 item(s) + /// Pop: 1 item(s) + /// /// STLOC0 = 0x70, + /// /// Stores the value on top of the evaluation stack in the local variable list at index 1. + /// + /// + /// Push: 0 item(s) + /// Pop: 1 item(s) + /// /// STLOC1 = 0x71, + /// /// Stores the value on top of the evaluation stack in the local variable list at index 2. + /// + /// + /// Push: 0 item(s) + /// Pop: 1 item(s) + /// /// STLOC2 = 0x72, + /// /// Stores the value on top of the evaluation stack in the local variable list at index 3. + /// + /// + /// Push: 0 item(s) + /// Pop: 1 item(s) + /// /// STLOC3 = 0x73, + /// /// Stores the value on top of the evaluation stack in the local variable list at index 4. + /// + /// + /// Push: 0 item(s) + /// Pop: 1 item(s) + /// /// STLOC4 = 0x74, + /// /// Stores the value on top of the evaluation stack in the local variable list at index 5. + /// + /// + /// Push: 0 item(s) + /// Pop: 1 item(s) + /// /// STLOC5 = 0x75, + /// /// Stores the value on top of the evaluation stack in the local variable list at index 6. + /// + /// + /// Push: 0 item(s) + /// Pop: 1 item(s) + /// /// STLOC6 = 0x76, + /// /// Stores the value on top of the evaluation stack in the local variable list at a specified index. The index is represented as a 1-byte unsigned integer. + /// + /// + /// Push: 0 item(s) + /// Pop: 1 item(s) + /// /// [OperandSize(Size = 1)] STLOC = 0x77, + /// /// Loads the argument at index 0 onto the evaluation stack. + /// + /// + /// Push: 1 item(s) + /// Pop: 0 item(s) + /// /// LDARG0 = 0x78, + /// /// Loads the argument at index 1 onto the evaluation stack. + /// + /// + /// Push: 1 item(s) + /// Pop: 0 item(s) + /// /// LDARG1 = 0x79, + /// /// Loads the argument at index 2 onto the evaluation stack. + /// + /// + /// Push: 1 item(s) + /// Pop: 0 item(s) + /// /// LDARG2 = 0x7A, + /// /// Loads the argument at index 3 onto the evaluation stack. + /// + /// + /// Push: 1 item(s) + /// Pop: 0 item(s) + /// /// LDARG3 = 0x7B, + /// /// Loads the argument at index 4 onto the evaluation stack. + /// + /// + /// Push: 1 item(s) + /// Pop: 0 item(s) + /// /// LDARG4 = 0x7C, + /// /// Loads the argument at index 5 onto the evaluation stack. + /// + /// + /// Push: 1 item(s) + /// Pop: 0 item(s) + /// /// LDARG5 = 0x7D, + /// /// Loads the argument at index 6 onto the evaluation stack. + /// + /// + /// Push: 1 item(s) + /// Pop: 0 item(s) + /// /// LDARG6 = 0x7E, + /// /// Loads the argument at a specified index onto the evaluation stack. The index is represented as a 1-byte unsigned integer. + /// + /// + /// Push: 1 item(s) + /// Pop: 0 item(s) + /// /// [OperandSize(Size = 1)] LDARG = 0x7F, + /// /// Stores the value on top of the evaluation stack in the argument slot at index 0. + /// + /// + /// Push: 0 item(s) + /// Pop: 1 item(s) + /// /// STARG0 = 0x80, + /// /// Stores the value on top of the evaluation stack in the argument slot at index 1. + /// + /// + /// Push: 0 item(s) + /// Pop: 1 item(s) + /// /// STARG1 = 0x81, + /// /// Stores the value on top of the evaluation stack in the argument slot at index 2. + /// + /// + /// Push: 0 item(s) + /// Pop: 1 item(s) + /// /// STARG2 = 0x82, + /// /// Stores the value on top of the evaluation stack in the argument slot at index 3. + /// + /// + /// Push: 0 item(s) + /// Pop: 1 item(s) + /// /// STARG3 = 0x83, + /// /// Stores the value on top of the evaluation stack in the argument slot at index 4. + /// + /// + /// Push: 0 item(s) + /// Pop: 1 item(s) + /// /// STARG4 = 0x84, + /// /// Stores the value on top of the evaluation stack in the argument slot at index 5. + /// + /// + /// Push: 0 item(s) + /// Pop: 1 item(s) + /// /// STARG5 = 0x85, + /// /// Stores the value on top of the evaluation stack in the argument slot at index 6. + /// + /// + /// Push: 0 item(s) + /// Pop: 1 item(s) + /// /// STARG6 = 0x86, + /// /// Stores the value on top of the evaluation stack in the argument slot at a specified index. The index is represented as a 1-byte unsigned integer. + /// + /// + /// Push: 0 item(s) + /// Pop: 1 item(s) + /// /// [OperandSize(Size = 1)] STARG = 0x87, @@ -602,26 +1325,74 @@ public enum OpCode : byte /// /// Creates a new and pushes it onto the stack. + /// + /// new Buffer(a) + /// + /// + /// Push: 1 item(s) + /// Pop: 0 item(s) + /// /// NEWBUFFER = 0x88, + /// /// Copies a range of bytes from one to another. + /// Using this opcode will require to dup the destination buffer. + /// + /// c.Slice(d, e).CopyTo(a.InnerBuffer.Span[b..]); + /// + /// + /// Push: 0 item(s) + /// Pop: 5 item(s) + /// /// MEMCPY = 0x89, + /// /// Concatenates two strings. + /// + /// a.concat(b) + /// + /// + /// Push: 1 item(s) + /// Pop: 2 item(s) + /// /// CAT = 0x8B, + /// /// Returns a section of a string. + /// + /// a.Slice(b, c) + /// + /// + /// Push: 1 item(s) + /// Pop: 3 item(s) + /// /// SUBSTR = 0x8C, + /// /// Keeps only characters left of the specified point in a string. + /// + /// a[..b] + /// + /// + /// Push: 1 item(s) + /// Pop: 2 item(s) + /// /// LEFT = 0x8D, + /// /// Keeps only characters right of the specified point in a string. + /// + /// a[^b..^0] + /// + /// + /// Push: 1 item(s) + /// Pop: 2 item(s) + /// /// RIGHT = 0x8E, @@ -630,27 +1401,74 @@ public enum OpCode : byte #region Bitwise logic /// - /// Flips all of the bits in the input. + /// Flips all the bits in the input. + /// + /// ~a + /// + /// + /// Push: 1 item(s) + /// Pop: 1 item(s) + /// /// INVERT = 0x90, + /// /// Boolean and between each bit in the inputs. + /// + /// a&b + /// + /// + /// Push: 1 item(s) + /// Pop: 2 item(s) + /// /// AND = 0x91, + /// /// Boolean or between each bit in the inputs. + /// + /// a|b + /// + /// + /// Push: 1 item(s) + /// Pop: 2 item(s) + /// /// OR = 0x92, + /// /// Boolean exclusive or between each bit in the inputs. + /// + /// a^b + /// + /// + /// Push: 1 item(s) + /// Pop: 2 item(s) + /// /// XOR = 0x93, + /// /// Returns 1 if the inputs are exactly equal, 0 otherwise. + /// + /// a.Equals(b) + /// + /// + /// Push: 1 item(s) + /// Pop: 2 item(s) + /// /// EQUAL = 0x97, + /// /// Returns 1 if the inputs are not equal, 0 otherwise. + /// + /// !a.Equals(b) + /// + /// + /// Push: 1 item(s) + /// Pop: 2 item(s) + /// /// NOTEQUAL = 0x98, @@ -660,118 +1478,339 @@ public enum OpCode : byte /// /// Puts the sign of top stack item on top of the main stack. If value is negative, put -1; if positive, put 1; if value is zero, put 0. + /// + /// a.Sign + /// + /// + /// Push: 1 item(s) + /// Pop: 1 item(s) + /// /// SIGN = 0x99, + /// /// The input is made positive. + /// + /// abs(a) + /// + /// + /// Push: 1 item(s) + /// Pop: 1 item(s) + /// /// ABS = 0x9A, + /// /// The sign of the input is flipped. + /// + /// -a + /// + /// + /// Push: 1 item(s) + /// Pop: 1 item(s) + /// /// NEGATE = 0x9B, + /// /// 1 is added to the input. + /// + /// a+1 + /// + /// + /// Push: 1 item(s) + /// Pop: 1 item(s) + /// /// INC = 0x9C, + /// /// 1 is subtracted from the input. + /// + /// a-1 + /// + /// + /// Push: 1 item(s) + /// Pop: 1 item(s) + /// /// DEC = 0x9D, + /// /// a is added to b. + /// + /// a+b + /// + /// + /// Push: 1 item(s) + /// Pop: 2 item(s) + /// /// ADD = 0x9E, + /// /// b is subtracted from a. + /// + /// a-b + /// + /// + /// Push: 1 item(s) + /// Pop: 2 item(s) + /// /// SUB = 0x9F, + /// /// a is multiplied by b. + /// + /// a*b + /// + /// + /// Push: 1 item(s) + /// Pop: 2 item(s) + /// /// MUL = 0xA0, + /// /// a is divided by b. + /// + /// a/b + /// + /// + /// Push: 1 item(s) + /// Pop: 2 item(s) + /// /// DIV = 0xA1, + /// /// Returns the remainder after dividing a by b. + /// + /// a%b + /// + /// + /// Push: 1 item(s) + /// Pop: 2 item(s) + /// /// MOD = 0xA2, + /// /// The result of raising value to the exponent power. + /// + /// a^b + /// + /// + /// Push: 1 item(s) + /// Pop: 2 item(s) + /// /// POW = 0xA3, + /// /// Returns the square root of a specified number. + /// + /// sqrt(a) + /// + /// + /// Push: 1 item(s) + /// Pop: 1 item(s) + /// /// SQRT = 0xA4, + /// /// Performs modulus division on a number multiplied by another number. + /// + /// a*b%c + /// + /// + /// Push: 1 item(s) + /// Pop: 3 item(s) + /// /// MODMUL = 0xA5, + /// /// Performs modulus division on a number raised to the power of another number. If the exponent is -1, it will have the calculation of the modular inverse. + /// + /// modpow(a, b, c) + /// + /// + /// Push: 1 item(s) + /// Pop: 3 item(s) + /// /// MODPOW = 0xA6, + /// /// Shifts a left b bits, preserving sign. + /// + /// a<<b + /// + /// + /// Push: 1 item(s) + /// Pop: 2 item(s) + /// /// SHL = 0xA8, + /// /// Shifts a right b bits, preserving sign. + /// + /// a>>b + /// + /// + /// Push: 1 item(s) + /// Pop: 2 item(s) + /// /// SHR = 0xA9, + /// - /// If the input is 0 or 1, it is flipped. Otherwise the output will be 0. + /// If the input is 0 or 1, it is flipped. Otherwise, the output will be 0. + /// + /// !a + /// + /// + /// Push: 1 item(s) + /// Pop: 1 item(s) + /// /// NOT = 0xAA, + /// - /// If both a and b are not 0, the output is 1. Otherwise 0. + /// If both a and b are not 0, the output is 1. Otherwise, 0. + /// + /// b && a + /// + /// + /// Push: 1 item(s) + /// Pop: 2 item(s) + /// /// BOOLAND = 0xAB, + /// - /// If a or b is not 0, the output is 1. Otherwise 0. + /// If a or b is not 0, the output is 1. Otherwise, 0. + /// + /// b || a + /// + /// + /// Push: 1 item(s) + /// Pop: 2 item(s) + /// /// BOOLOR = 0xAC, + /// /// Returns 0 if the input is 0. 1 otherwise. + /// + /// a != 0 + /// + /// + /// Push: 1 item(s) + /// Pop: 1 item(s) + /// /// NZ = 0xB1, + /// /// Returns 1 if the numbers are equal, 0 otherwise. + /// + /// b == a + /// + /// + /// Push: 1 item(s) + /// Pop: 2 item(s) + /// /// NUMEQUAL = 0xB3, + /// /// Returns 1 if the numbers are not equal, 0 otherwise. + /// + /// b != a + /// + /// + /// Push: 1 item(s) + /// Pop: 2 item(s) + /// /// NUMNOTEQUAL = 0xB4, + /// /// Returns 1 if a is less than b, 0 otherwise. + /// + /// b>a + /// + /// + /// Push: 1 item(s) + /// Pop: 2 item(s) + /// /// LT = 0xB5, + /// /// Returns 1 if a is less than or equal to b, 0 otherwise. + /// + /// b>=a + /// + /// + /// Push: 1 item(s) + /// Pop: 2 item(s) + /// /// LE = 0xB6, + /// /// Returns 1 if a is greater than b, 0 otherwise. + /// + /// + /// Push: 1 item(s) + /// Pop: 2 item(s) + /// /// GT = 0xB7, + /// /// Returns 1 if a is greater than or equal to b, 0 otherwise. + /// + /// + /// Push: 1 item(s) + /// Pop: 2 item(s) + /// /// GE = 0xB8, + /// - /// Returns the smaller of a and b. + /// Returns the smallest of a and b. + /// + /// + /// Push: 1 item(s) + /// Pop: 2 item(s) + /// /// MIN = 0xB9, + /// - /// Returns the larger of a and b. + /// Returns the largest of a and b. + /// + /// + /// Push: 1 item(s) + /// Pop: 2 item(s) + /// /// MAX = 0xBA, + /// /// Returns 1 if x is within the specified range (left-inclusive), 0 otherwise. + /// + /// + /// Push: 1 item(s) + /// Pop: 3 item(s) + /// /// WITHIN = 0xBB, @@ -781,87 +1820,217 @@ public enum OpCode : byte /// /// A value n is taken from top of main stack. The next n*2 items on main stack are removed, put inside n-sized map and this map is put on top of the main stack. + /// + /// + /// Push: 1 item(s) + /// Pop: 2n+1 item(s) + /// /// PACKMAP = 0xBE, + /// /// A value n is taken from top of main stack. The next n items on main stack are removed, put inside n-sized struct and this struct is put on top of the main stack. + /// + /// + /// Push: 1 item(s) + /// Pop: n+1 item(s) + /// /// PACKSTRUCT = 0xBF, + /// /// A value n is taken from top of main stack. The next n items on main stack are removed, put inside n-sized array and this array is put on top of the main stack. + /// + /// + /// Push: 1 item(s) + /// Pop: n+1 item(s) + /// /// PACK = 0xC0, + /// /// A collection is removed from top of the main stack. Its elements are put on top of the main stack (in reverse order) and the collection size is also put on main stack. + /// + /// + /// Push: 2n+1 or n+1 item(s) + /// Pop: 1 item(s) + /// /// UNPACK = 0xC1, + /// /// An empty array (with size 0) is put on top of the main stack. + /// + /// + /// Push: 1 item(s) + /// Pop: 0 item(s) + /// /// NEWARRAY0 = 0xC2, + /// /// A value n is taken from top of main stack. A null-filled array with size n is put on top of the main stack. + /// + /// + /// Push: 1 item(s) + /// Pop: 1 item(s) + /// /// NEWARRAY = 0xC3, + /// /// A value n is taken from top of main stack. An array of type T with size n is put on top of the main stack. + /// + /// + /// Push: 1 item(s) + /// Pop: 1 item(s) + /// /// [OperandSize(Size = 1)] NEWARRAY_T = 0xC4, + /// /// An empty struct (with size 0) is put on top of the main stack. + /// + /// + /// Push: 1 item(s) + /// Pop: 0 item(s) + /// /// NEWSTRUCT0 = 0xC5, + /// /// A value n is taken from top of main stack. A zero-filled struct with size n is put on top of the main stack. + /// + /// + /// Push: 1 item(s) + /// Pop: 1 item(s) + /// /// NEWSTRUCT = 0xC6, + /// /// A Map is created and put on top of the main stack. + /// + /// + /// Push: 1 item(s) + /// Pop: 0 item(s) + /// /// NEWMAP = 0xC8, + /// /// An array is removed from top of the main stack. Its size is put on top of the main stack. + /// + /// + /// Push: 1 item(s) + /// Pop: 1 item(s) + /// /// SIZE = 0xCA, + /// /// An input index n (or key) and an array (or map) are removed from the top of the main stack. Puts True on top of main stack if array[n] (or map[n]) exist, and False otherwise. + /// + /// + /// Push: 1 item(s) + /// Pop: 2 item(s) + /// /// HASKEY = 0xCB, + /// /// A map is taken from top of the main stack. The keys of this map are put on top of the main stack. + /// + /// + /// Push: 1 item(s) + /// Pop: 1 item(s) + /// /// KEYS = 0xCC, + /// /// A map is taken from top of the main stack. The values of this map are put on top of the main stack. + /// + /// + /// Push: 1 item(s) + /// Pop: 1 item(s) + /// /// VALUES = 0xCD, + /// /// An input index n (or key) and an array (or map) are taken from main stack. Element array[n] (or map[n]) is put on top of the main stack. + /// + /// + /// Push: 1 item(s) + /// Pop: 2 item(s) + /// /// PICKITEM = 0xCE, + /// /// The item on top of main stack is removed and appended to the second item on top of the main stack. + /// When we use this opcode, we should dup the second item on top of the main stack before using it. + /// + /// a a b -> a.concat(b) + /// + /// + /// Push: 0 item(s) + /// Pop: 2 item(s) + /// /// APPEND = 0xCF, + /// /// A value v, index n (or key) and an array (or map) are taken from main stack. Attribution array[n]=v (or map[n]=v) is performed. + /// + /// + /// Push: 1 item(s) + /// Pop: 3 item(s) + /// /// SETITEM = 0xD0, + /// /// An array is removed from the top of the main stack and its elements are reversed. + /// + /// + /// Push: 0 item(s) + /// Pop: 1 item(s) + /// /// REVERSEITEMS = 0xD1, + /// /// An input index n (or key) and an array (or map) are removed from the top of the main stack. Element array[n] (or map[n]) is removed. + /// + /// + /// Push: 0 item(s) + /// Pop: 2 item(s) + /// /// REMOVE = 0xD2, + /// /// Remove all the items from the compound-type. + /// Using this opcode will need to dup the compound-type before using it. + /// + /// + /// Push: 0 item(s) + /// Pop: 1 item(s) + /// /// CLEARITEMS = 0xD3, + /// /// Remove the last element from an array, and push it onto the stack. + /// Using this opcode will need to dup the array before using it. + /// + /// + /// Push: 0 item(s) + /// Pop: 1 item(s) + /// /// POPITEM = 0xD4, @@ -872,16 +2041,33 @@ public enum OpCode : byte /// /// Returns if the input is ; /// otherwise. + /// + /// + /// Push: 1 item(s) + /// Pop: 1 item(s) + /// /// ISNULL = 0xD8, + /// /// Returns if the top item of the stack is of the specified type; /// otherwise. + /// + /// + /// Push: 1 item(s) + /// Pop: 1 item(s) + /// /// [OperandSize(Size = 1)] ISTYPE = 0xD9, + /// /// Converts the top item of the stack to the specified type. + /// + /// + /// Push: 1 item(s) + /// Pop: 1 item(s) + /// /// [OperandSize(Size = 1)] CONVERT = 0xDB, @@ -893,11 +2079,24 @@ public enum OpCode : byte /// /// Pops the top stack item. Then, turns the vm state to FAULT immediately, and cannot be caught. The top stack /// value is used as reason. + /// + /// new Exception(a) + /// + /// + /// Push: 0 item(s) + /// Pop: 1 item(s) + /// /// ABORTMSG = 0xE0, + /// /// Pops the top two stack items. If the second-to-top stack value is false, exits the vm execution and sets the /// vm state to FAULT. In this case, the top stack value is used as reason for the exit. Otherwise, it is ignored. + /// + /// + /// Push: 0 item(s) + /// Pop: 2 item(s) + /// /// ASSERTMSG = 0xE1 From eb167b34c1a9f83e18175ad1f46d70e91845b51f Mon Sep 17 00:00:00 2001 From: Jimmy Date: Mon, 29 Jul 2024 15:46:55 +0800 Subject: [PATCH 61/71] [Neo Core] Obsolete applicationengine snapshot (#3436) * Obsolete applicationengine snapshot * fix UT names * fix executioncontextstate --------- Co-authored-by: Shargon Co-authored-by: NGD Admin <154295625+NGDAdmin@users.noreply.github.com> --- .../Conditions/CalledByGroupCondition.cs | 2 +- .../P2P/Payloads/Conditions/GroupCondition.cs | 2 +- .../ApplicationEngine.Contract.cs | 4 +- .../ApplicationEngine.Runtime.cs | 6 +- .../ApplicationEngine.Storage.cs | 14 +- src/Neo/SmartContract/ApplicationEngine.cs | 30 +- .../ContractParametersContext.cs | 21 +- .../SmartContract/ExecutionContextState.cs | 6 +- .../Native/ContractManagement.cs | 38 +- src/Neo/SmartContract/Native/FungibleToken.cs | 18 +- src/Neo/SmartContract/Native/GasToken.cs | 2 +- .../SmartContract/Native/LedgerContract.cs | 42 +- .../SmartContract/Native/NativeContract.cs | 6 +- src/Neo/SmartContract/Native/NeoToken.cs | 58 +-- .../SmartContract/Native/OracleContract.cs | 32 +- .../SmartContract/Native/PolicyContract.cs | 20 +- .../SmartContract/Native/RoleManagement.cs | 4 +- src/Neo/Wallets/Wallet.cs | 2 +- .../RpcServer/RpcServer.SmartContract.cs | 2 +- .../UT_OracleService.cs | 12 +- .../Neo.UnitTests/IO/Caching/UT_CloneCache.cs | 8 +- tests/Neo.UnitTests/Ledger/UT_Blockchain.cs | 4 +- tests/Neo.UnitTests/Ledger/UT_MemoryPool.cs | 58 +-- .../UT_TransactionVerificationContext.cs | 40 +- tests/Neo.UnitTests/Ledger/UT_TrimmedBlock.cs | 8 +- .../Network/P2P/Payloads/UT_Block.cs | 6 +- .../Network/P2P/Payloads/UT_Conflicts.cs | 16 +- .../Network/P2P/Payloads/UT_Header.cs | 6 +- .../P2P/Payloads/UT_HighPriorityAttribute.cs | 8 +- .../Network/P2P/Payloads/UT_NotValidBefore.cs | 8 +- .../Network/P2P/Payloads/UT_Transaction.cs | 155 +++--- .../Network/P2P/Payloads/UT_Witness.cs | 4 +- .../SmartContract/Native/UT_CryptoLib.cs | 52 +- .../SmartContract/Native/UT_FungibleToken.cs | 4 +- .../SmartContract/Native/UT_GasToken.cs | 22 +- .../SmartContract/Native/UT_NativeContract.cs | 8 +- .../SmartContract/Native/UT_NeoToken.cs | 486 +++++++++--------- .../SmartContract/Native/UT_PolicyContract.cs | 20 +- .../SmartContract/Native/UT_RoleManagement.cs | 8 +- .../SmartContract/Native/UT_StdLib.cs | 56 +- .../SmartContract/UT_ApplicationEngine.cs | 18 +- .../UT_ApplicationEngineProvider.cs | 4 +- .../UT_ContractParameterContext.cs | 42 +- .../SmartContract/UT_InteropPrices.cs | 32 +- .../SmartContract/UT_InteropService.NEO.cs | 56 +- .../SmartContract/UT_InteropService.cs | 136 ++--- .../SmartContract/UT_SmartContractHelper.cs | 30 +- .../SmartContract/UT_Syscalls.cs | 44 +- tests/Neo.UnitTests/UT_DataCache.cs | 8 +- .../Wallets/UT_AssetDescriptor.cs | 12 +- tests/Neo.UnitTests/Wallets/UT_Wallet.cs | 50 +- 51 files changed, 875 insertions(+), 855 deletions(-) diff --git a/src/Neo/Network/P2P/Payloads/Conditions/CalledByGroupCondition.cs b/src/Neo/Network/P2P/Payloads/Conditions/CalledByGroupCondition.cs index 82dab60fcf..d28cd9f8bf 100644 --- a/src/Neo/Network/P2P/Payloads/Conditions/CalledByGroupCondition.cs +++ b/src/Neo/Network/P2P/Payloads/Conditions/CalledByGroupCondition.cs @@ -39,7 +39,7 @@ protected override void DeserializeWithoutType(ref MemoryReader reader, int maxN public override bool Match(ApplicationEngine engine) { engine.ValidateCallFlags(CallFlags.ReadStates); - ContractState contract = NativeContract.ContractManagement.GetContract(engine.Snapshot, engine.CallingScriptHash); + ContractState contract = NativeContract.ContractManagement.GetContract(engine.SnapshotCache, engine.CallingScriptHash); return contract is not null && contract.Manifest.Groups.Any(p => p.PubKey.Equals(Group)); } diff --git a/src/Neo/Network/P2P/Payloads/Conditions/GroupCondition.cs b/src/Neo/Network/P2P/Payloads/Conditions/GroupCondition.cs index ee937aff8b..3187b62988 100644 --- a/src/Neo/Network/P2P/Payloads/Conditions/GroupCondition.cs +++ b/src/Neo/Network/P2P/Payloads/Conditions/GroupCondition.cs @@ -39,7 +39,7 @@ protected override void DeserializeWithoutType(ref MemoryReader reader, int maxN public override bool Match(ApplicationEngine engine) { engine.ValidateCallFlags(CallFlags.ReadStates); - ContractState contract = NativeContract.ContractManagement.GetContract(engine.Snapshot, engine.CurrentScriptHash); + ContractState contract = NativeContract.ContractManagement.GetContract(engine.SnapshotCache, engine.CurrentScriptHash); return contract is not null && contract.Manifest.Groups.Any(p => p.PubKey.Equals(Group)); } diff --git a/src/Neo/SmartContract/ApplicationEngine.Contract.cs b/src/Neo/SmartContract/ApplicationEngine.Contract.cs index e5c1c762a7..889ec0e07d 100644 --- a/src/Neo/SmartContract/ApplicationEngine.Contract.cs +++ b/src/Neo/SmartContract/ApplicationEngine.Contract.cs @@ -76,7 +76,7 @@ protected internal void CallContract(UInt160 contractHash, string method, CallFl if ((callFlags & ~CallFlags.All) != 0) throw new ArgumentOutOfRangeException(nameof(callFlags)); - ContractState contract = NativeContract.ContractManagement.GetContract(Snapshot, contractHash); + ContractState contract = NativeContract.ContractManagement.GetContract(SnapshotCache, contractHash); if (contract is null) throw new InvalidOperationException($"Called Contract Does Not Exist: {contractHash}.{method}"); ContractMethodDescriptor md = contract.Manifest.Abi.GetMethod(method, args.Count); if (md is null) throw new InvalidOperationException($"Method \"{method}\" with {args.Count} parameter(s) doesn't exist in the contract {contractHash}."); @@ -96,7 +96,7 @@ protected internal void CallNativeContract(byte version) NativeContract contract = NativeContract.GetContract(CurrentScriptHash); if (contract is null) throw new InvalidOperationException("It is not allowed to use \"System.Contract.CallNative\" directly."); - if (!contract.IsActive(ProtocolSettings, NativeContract.Ledger.CurrentIndex(Snapshot))) + if (!contract.IsActive(ProtocolSettings, NativeContract.Ledger.CurrentIndex(SnapshotCache))) throw new InvalidOperationException($"The native contract {contract.Name} is not active."); contract.Invoke(this, version); } diff --git a/src/Neo/SmartContract/ApplicationEngine.Runtime.cs b/src/Neo/SmartContract/ApplicationEngine.Runtime.cs index e54529f6d1..3771278839 100644 --- a/src/Neo/SmartContract/ApplicationEngine.Runtime.cs +++ b/src/Neo/SmartContract/ApplicationEngine.Runtime.cs @@ -260,8 +260,8 @@ protected internal bool CheckWitnessInternal(UInt160 hash) } else { - OracleRequest request = NativeContract.Oracle.GetRequest(Snapshot, response.Id); - signers = NativeContract.Ledger.GetTransaction(Snapshot, request.OriginalTxid).Signers; + OracleRequest request = NativeContract.Oracle.GetRequest(SnapshotCache, response.Id); + signers = NativeContract.Ledger.GetTransaction(SnapshotCache, request.OriginalTxid).Signers; } Signer signer = signers.FirstOrDefault(p => p.Account.Equals(hash)); if (signer is null) return false; @@ -280,7 +280,7 @@ protected internal bool CheckWitnessInternal(UInt160 hash) ValidateCallFlags(CallFlags.ReadStates); // only for non-Transaction types (Block, etc) - return ScriptContainer.GetScriptHashesForVerifying(Snapshot).Contains(hash); + return ScriptContainer.GetScriptHashesForVerifying(SnapshotCache).Contains(hash); } /// diff --git a/src/Neo/SmartContract/ApplicationEngine.Storage.cs b/src/Neo/SmartContract/ApplicationEngine.Storage.cs index fbd452d6cc..5550835975 100644 --- a/src/Neo/SmartContract/ApplicationEngine.Storage.cs +++ b/src/Neo/SmartContract/ApplicationEngine.Storage.cs @@ -77,7 +77,7 @@ partial class ApplicationEngine /// The storage context for the current contract. protected internal StorageContext GetStorageContext() { - ContractState contract = NativeContract.ContractManagement.GetContract(Snapshot, CurrentScriptHash); + ContractState contract = NativeContract.ContractManagement.GetContract(SnapshotCache, CurrentScriptHash); return new StorageContext { Id = contract.Id, @@ -92,7 +92,7 @@ protected internal StorageContext GetStorageContext() /// The storage context for the current contract. protected internal StorageContext GetReadOnlyContext() { - ContractState contract = NativeContract.ContractManagement.GetContract(Snapshot, CurrentScriptHash); + ContractState contract = NativeContract.ContractManagement.GetContract(SnapshotCache, CurrentScriptHash); return new StorageContext { Id = contract.Id, @@ -126,7 +126,7 @@ protected internal static StorageContext AsReadOnly(StorageContext context) /// The value of the entry. Or if the entry doesn't exist. protected internal ReadOnlyMemory? Get(StorageContext context, byte[] key) { - return Snapshot.TryGet(new StorageKey + return SnapshotCache.TryGet(new StorageKey { Id = context.Id, Key = key @@ -155,7 +155,7 @@ protected internal IIterator Find(StorageContext context, byte[] prefix, FindOpt throw new ArgumentException(null, nameof(options)); byte[] prefix_key = StorageKey.CreateSearchPrefix(context.Id, prefix); SeekDirection direction = options.HasFlag(FindOptions.Backwards) ? SeekDirection.Backward : SeekDirection.Forward; - return new StorageIterator(Snapshot.Find(prefix_key, direction).GetEnumerator(), prefix.Length, options); + return new StorageIterator(SnapshotCache.Find(prefix_key, direction).GetEnumerator(), prefix.Length, options); } /// @@ -177,11 +177,11 @@ protected internal void Put(StorageContext context, byte[] key, byte[] value) Id = context.Id, Key = key }; - StorageItem item = Snapshot.GetAndChange(skey); + StorageItem item = SnapshotCache.GetAndChange(skey); if (item is null) { newDataSize = key.Length + value.Length; - Snapshot.Add(skey, item = new StorageItem()); + SnapshotCache.Add(skey, item = new StorageItem()); } else { @@ -208,7 +208,7 @@ protected internal void Put(StorageContext context, byte[] key, byte[] value) protected internal void Delete(StorageContext context, byte[] key) { if (context.IsReadOnly) throw new ArgumentException(null, nameof(context)); - Snapshot.Delete(new StorageKey + SnapshotCache.Delete(new StorageKey { Id = context.Id, Key = key diff --git a/src/Neo/SmartContract/ApplicationEngine.cs b/src/Neo/SmartContract/ApplicationEngine.cs index 6fd69439ab..38430f3632 100644 --- a/src/Neo/SmartContract/ApplicationEngine.cs +++ b/src/Neo/SmartContract/ApplicationEngine.cs @@ -55,7 +55,7 @@ public partial class ApplicationEngine : ExecutionEngine // In the unit of datoshi, 1 datoshi = 1e-8 GAS, 1 GAS = 1e8 datoshi private readonly long _feeAmount; private Dictionary states; - private readonly DataCache originalSnapshot; + private readonly DataCache originalSnapshotCache; private List notifications; private List disposables; private readonly Dictionary invocationCounter = new(); @@ -95,7 +95,13 @@ public partial class ApplicationEngine : ExecutionEngine /// /// The snapshot used to read or write data. /// - public DataCache Snapshot => CurrentContext?.GetState().Snapshot ?? originalSnapshot; + [Obsolete("This property is deprecated. Use SnapshotCache instead.")] + public DataCache Snapshot => CurrentContext?.GetState().SnapshotCache ?? originalSnapshotCache; + + /// + /// The snapshotcache used to read or write data. + /// + public DataCache SnapshotCache => CurrentContext?.GetState().SnapshotCache ?? originalSnapshotCache; /// /// The block being persisted. This field could be if the is . @@ -164,26 +170,26 @@ public virtual UInt160 CallingScriptHash /// /// The trigger of the execution. /// The container of the script. - /// The snapshot used by the engine during execution. + /// The snapshot used by the engine during execution. /// The block being persisted. It should be if the is . /// The used by the engine. /// The maximum gas, in the unit of datoshi, used in this execution. The execution will fail when the gas is exhausted. /// The diagnostic to be used by the . /// The jump table to be used by the . protected unsafe ApplicationEngine( - TriggerType trigger, IVerifiable container, DataCache snapshot, Block persistingBlock, + TriggerType trigger, IVerifiable container, DataCache snapshotCache, Block persistingBlock, ProtocolSettings settings, long gas, IDiagnostic diagnostic, JumpTable jumpTable = null) : base(jumpTable ?? DefaultJumpTable) { Trigger = trigger; ScriptContainer = container; - originalSnapshot = snapshot; + originalSnapshotCache = snapshotCache; PersistingBlock = persistingBlock; ProtocolSettings = settings; _feeAmount = gas; Diagnostic = diagnostic; - ExecFeeFactor = snapshot is null || persistingBlock?.Index == 0 ? PolicyContract.DefaultExecFeeFactor : NativeContract.Policy.GetExecFeeFactor(snapshot); - StoragePrice = snapshot is null || persistingBlock?.Index == 0 ? PolicyContract.DefaultStoragePrice : NativeContract.Policy.GetStoragePrice(snapshot); + ExecFeeFactor = snapshotCache is null || persistingBlock?.Index == 0 ? PolicyContract.DefaultExecFeeFactor : NativeContract.Policy.GetExecFeeFactor(snapshotCache); + StoragePrice = snapshotCache is null || persistingBlock?.Index == 0 ? PolicyContract.DefaultStoragePrice : NativeContract.Policy.GetStoragePrice(snapshotCache); nonceData = container is Transaction tx ? tx.Hash.ToArray()[..16] : new byte[16]; if (persistingBlock is not null) { @@ -274,7 +280,7 @@ internal void Throw(Exception ex) private ExecutionContext CallContractInternal(UInt160 contractHash, string method, CallFlags flags, bool hasReturnValue, StackItem[] args) { - ContractState contract = NativeContract.ContractManagement.GetContract(Snapshot, contractHash); + ContractState contract = NativeContract.ContractManagement.GetContract(SnapshotCache, contractHash); if (contract is null) throw new InvalidOperationException($"Called Contract Does Not Exist: {contractHash}"); ContractMethodDescriptor md = contract.Manifest.Abi.GetMethod(method, args.Length); if (md is null) throw new InvalidOperationException($"Method \"{method}\" with {args.Length} parameter(s) doesn't exist in the contract {contractHash}."); @@ -283,7 +289,7 @@ private ExecutionContext CallContractInternal(UInt160 contractHash, string metho private ExecutionContext CallContractInternal(ContractState contract, ContractMethodDescriptor method, CallFlags flags, bool hasReturnValue, IReadOnlyList args) { - if (NativeContract.Policy.IsBlocked(Snapshot, contract.Hash)) + if (NativeContract.Policy.IsBlocked(SnapshotCache, contract.Hash)) throw new InvalidOperationException($"The contract {contract.Hash} has been blocked."); ExecutionContext currentContext = CurrentContext; @@ -296,7 +302,7 @@ private ExecutionContext CallContractInternal(ContractState contract, ContractMe { var executingContract = IsHardforkEnabled(Hardfork.HF_Domovoi) ? state.Contract // use executing contract state to avoid possible contract update/destroy side-effects, ref. https://github.com/neo-project/neo/pull/3290. - : NativeContract.ContractManagement.GetContract(Snapshot, CurrentScriptHash); + : NativeContract.ContractManagement.GetContract(SnapshotCache, CurrentScriptHash); if (executingContract?.CanCall(contract, method.Name) == false) throw new InvalidOperationException($"Cannot Call Method {method.Name} Of Contract {contract.Hash} From Contract {CurrentScriptHash}"); } @@ -352,7 +358,7 @@ internal override void UnloadContext(ExecutionContext context) ExecutionContextState state = context.GetState(); if (UncaughtException is null) { - state.Snapshot?.Commit(); + state.SnapshotCache?.Commit(); if (CurrentContext != null) { ExecutionContextState contextState = CurrentContext.GetState(); @@ -460,7 +466,7 @@ public ExecutionContext LoadScript(Script script, int rvcount = -1, int initialP // Create and configure context ExecutionContext context = CreateContext(script, rvcount, initialPosition); ExecutionContextState state = context.GetState(); - state.Snapshot = Snapshot?.CloneCache(); + state.SnapshotCache = SnapshotCache?.CloneCache(); configureState?.Invoke(state); // Load context diff --git a/src/Neo/SmartContract/ContractParametersContext.cs b/src/Neo/SmartContract/ContractParametersContext.cs index e8bf3ceec9..c4129f0ad1 100644 --- a/src/Neo/SmartContract/ContractParametersContext.cs +++ b/src/Neo/SmartContract/ContractParametersContext.cs @@ -73,7 +73,18 @@ public JObject ToJson() /// /// The snapshot used to read data. /// - public readonly DataCache Snapshot; + [Obsolete("Use SnapshotCache instead")] + public DataCache Snapshot => SnapshotCache; + + /// + /// The snapshotcache used to read data. + /// + public readonly DataCache SnapshotCache; + + // /// + // /// The snapshot used to read data. + // /// + // public readonly DataCache Snapshot; /// /// The magic number of the network. @@ -99,18 +110,18 @@ public bool Completed /// /// Gets the script hashes to be verified for the . /// - public IReadOnlyList ScriptHashes => _ScriptHashes ??= Verifiable.GetScriptHashesForVerifying(Snapshot); + public IReadOnlyList ScriptHashes => _ScriptHashes ??= Verifiable.GetScriptHashesForVerifying(SnapshotCache); /// /// Initializes a new instance of the class. /// - /// The snapshot used to read data. + /// The snapshot used to read data. /// The to add witnesses. /// The magic number of the network. - public ContractParametersContext(DataCache snapshot, IVerifiable verifiable, uint network) + public ContractParametersContext(DataCache snapshotCache, IVerifiable verifiable, uint network) { Verifiable = verifiable; - Snapshot = snapshot; + SnapshotCache = snapshotCache; ContextItems = new Dictionary(); Network = network; } diff --git a/src/Neo/SmartContract/ExecutionContextState.cs b/src/Neo/SmartContract/ExecutionContextState.cs index 8b61ff1197..993015df13 100644 --- a/src/Neo/SmartContract/ExecutionContextState.cs +++ b/src/Neo/SmartContract/ExecutionContextState.cs @@ -11,6 +11,7 @@ using Neo.Persistence; using Neo.VM; +using System; namespace Neo.SmartContract { @@ -44,7 +45,10 @@ public class ExecutionContextState /// public CallFlags CallFlags { get; set; } = CallFlags.All; - public DataCache Snapshot { get; set; } + [Obsolete("Use SnapshotCache instead")] + public DataCache Snapshot => SnapshotCache; + + public DataCache SnapshotCache { get; set; } public int NotificationCount { get; set; } diff --git a/src/Neo/SmartContract/Native/ContractManagement.cs b/src/Neo/SmartContract/Native/ContractManagement.cs index c533f029a6..6fefd2d05f 100644 --- a/src/Neo/SmartContract/Native/ContractManagement.cs +++ b/src/Neo/SmartContract/Native/ContractManagement.cs @@ -52,8 +52,8 @@ internal override ContractTask InitializeAsync(ApplicationEngine engine, Hardfor { if (hardfork == ActiveIn) { - engine.Snapshot.Add(CreateStorageKey(Prefix_MinimumDeploymentFee), new StorageItem(10_00000000)); - engine.Snapshot.Add(CreateStorageKey(Prefix_NextAvailableId), new StorageItem(1)); + engine.SnapshotCache.Add(CreateStorageKey(Prefix_MinimumDeploymentFee), new StorageItem(10_00000000)); + engine.SnapshotCache.Add(CreateStorageKey(Prefix_NextAvailableId), new StorageItem(1)); } return ContractTask.CompletedTask; } @@ -73,13 +73,13 @@ internal override async ContractTask OnPersistAsync(ApplicationEngine engine) if (contract.IsInitializeBlock(engine.ProtocolSettings, engine.PersistingBlock.Index, out var hfs)) { ContractState contractState = contract.GetContractState(engine.ProtocolSettings, engine.PersistingBlock.Index); - StorageItem state = engine.Snapshot.GetAndChange(CreateStorageKey(Prefix_Contract).Add(contract.Hash)); + StorageItem state = engine.SnapshotCache.GetAndChange(CreateStorageKey(Prefix_Contract).Add(contract.Hash)); if (state is null) { // Create the contract state - engine.Snapshot.Add(CreateStorageKey(Prefix_Contract).Add(contract.Hash), new StorageItem(contractState)); - engine.Snapshot.Add(CreateStorageKey(Prefix_ContractHash).AddBigEndian(contract.Id), new StorageItem(contract.Hash.ToArray())); + engine.SnapshotCache.Add(CreateStorageKey(Prefix_Contract).Add(contract.Hash), new StorageItem(contractState)); + engine.SnapshotCache.Add(CreateStorageKey(Prefix_ContractHash).AddBigEndian(contract.Id), new StorageItem(contract.Hash.ToArray())); // Initialize the native smart contract if it's active starting from the genesis. // If it's not the case, then hardfork-based initialization will be performed down below. @@ -127,7 +127,7 @@ private void SetMinimumDeploymentFee(ApplicationEngine engine, BigInteger value/ { if (value < 0) throw new ArgumentOutOfRangeException(nameof(value)); if (!CheckCommittee(engine)) throw new InvalidOperationException(); - engine.Snapshot.GetAndChange(CreateStorageKey(Prefix_MinimumDeploymentFee)).Set(value); + engine.SnapshotCache.GetAndChange(CreateStorageKey(Prefix_MinimumDeploymentFee)).Set(value); } /// @@ -221,7 +221,7 @@ private async ContractTask Deploy(ApplicationEngine engine, byte[ engine.AddFee(Math.Max( engine.StoragePrice * (nefFile.Length + manifest.Length), - GetMinimumDeploymentFee(engine.Snapshot) + GetMinimumDeploymentFee(engine.SnapshotCache) )); NefFile nef = nefFile.AsSerializable(); @@ -229,15 +229,15 @@ private async ContractTask Deploy(ApplicationEngine engine, byte[ Helper.Check(new VM.Script(nef.Script, engine.IsHardforkEnabled(Hardfork.HF_Basilisk)), parsedManifest.Abi); UInt160 hash = Helper.GetContractHash(tx.Sender, nef.CheckSum, parsedManifest.Name); - if (Policy.IsBlocked(engine.Snapshot, hash)) + if (Policy.IsBlocked(engine.SnapshotCache, hash)) throw new InvalidOperationException($"The contract {hash} has been blocked."); StorageKey key = CreateStorageKey(Prefix_Contract).Add(hash); - if (engine.Snapshot.Contains(key)) + if (engine.SnapshotCache.Contains(key)) throw new InvalidOperationException($"Contract Already Exists: {hash}"); ContractState contract = new() { - Id = GetNextAvailableId(engine.Snapshot), + Id = GetNextAvailableId(engine.SnapshotCache), UpdateCounter = 0, Nef = nef, Hash = hash, @@ -246,8 +246,8 @@ private async ContractTask Deploy(ApplicationEngine engine, byte[ if (!contract.Manifest.IsValid(engine.Limits, hash)) throw new InvalidOperationException($"Invalid Manifest: {hash}"); - engine.Snapshot.Add(key, new StorageItem(contract)); - engine.Snapshot.Add(CreateStorageKey(Prefix_ContractHash).AddBigEndian(contract.Id), new StorageItem(hash.ToArray())); + engine.SnapshotCache.Add(key, new StorageItem(contract)); + engine.SnapshotCache.Add(CreateStorageKey(Prefix_ContractHash).AddBigEndian(contract.Id), new StorageItem(hash.ToArray())); await OnDeployAsync(engine, contract, data, false); @@ -267,7 +267,7 @@ private ContractTask Update(ApplicationEngine engine, byte[] nefFile, byte[] man engine.AddFee(engine.StoragePrice * ((nefFile?.Length ?? 0) + (manifest?.Length ?? 0))); - var contract = engine.Snapshot.GetAndChange(CreateStorageKey(Prefix_Contract).Add(engine.CallingScriptHash))?.GetInteroperable(false); + var contract = engine.SnapshotCache.GetAndChange(CreateStorageKey(Prefix_Contract).Add(engine.CallingScriptHash))?.GetInteroperable(false); if (contract is null) throw new InvalidOperationException($"Updating Contract Does Not Exist: {engine.CallingScriptHash}"); if (contract.UpdateCounter == ushort.MaxValue) throw new InvalidOperationException($"The contract reached the maximum number of updates."); @@ -300,14 +300,14 @@ private void Destroy(ApplicationEngine engine) { UInt160 hash = engine.CallingScriptHash; StorageKey ckey = CreateStorageKey(Prefix_Contract).Add(hash); - ContractState contract = engine.Snapshot.TryGet(ckey)?.GetInteroperable(false); + ContractState contract = engine.SnapshotCache.TryGet(ckey)?.GetInteroperable(false); if (contract is null) return; - engine.Snapshot.Delete(ckey); - engine.Snapshot.Delete(CreateStorageKey(Prefix_ContractHash).AddBigEndian(contract.Id)); - foreach (var (key, _) in engine.Snapshot.Find(StorageKey.CreateSearchPrefix(contract.Id, ReadOnlySpan.Empty))) - engine.Snapshot.Delete(key); + engine.SnapshotCache.Delete(ckey); + engine.SnapshotCache.Delete(CreateStorageKey(Prefix_ContractHash).AddBigEndian(contract.Id)); + foreach (var (key, _) in engine.SnapshotCache.Find(StorageKey.CreateSearchPrefix(contract.Id, ReadOnlySpan.Empty))) + engine.SnapshotCache.Delete(key); // lock contract - Policy.BlockAccount(engine.Snapshot, hash); + Policy.BlockAccount(engine.SnapshotCache, hash); // emit event engine.SendNotification(Hash, "Destroy", new VM.Types.Array(engine.ReferenceCounter) { hash.ToArray() }); } diff --git a/src/Neo/SmartContract/Native/FungibleToken.cs b/src/Neo/SmartContract/Native/FungibleToken.cs index 4ab0f01589..21de0a5644 100644 --- a/src/Neo/SmartContract/Native/FungibleToken.cs +++ b/src/Neo/SmartContract/Native/FungibleToken.cs @@ -74,11 +74,11 @@ internal async ContractTask Mint(ApplicationEngine engine, UInt160 account, BigI { if (amount.Sign < 0) throw new ArgumentOutOfRangeException(nameof(amount)); if (amount.IsZero) return; - StorageItem storage = engine.Snapshot.GetAndChange(CreateStorageKey(Prefix_Account).Add(account), () => new StorageItem(new TState())); + StorageItem storage = engine.SnapshotCache.GetAndChange(CreateStorageKey(Prefix_Account).Add(account), () => new StorageItem(new TState())); TState state = storage.GetInteroperable(); OnBalanceChanging(engine, account, state, amount); state.Balance += amount; - storage = engine.Snapshot.GetAndChange(CreateStorageKey(Prefix_TotalSupply), () => new StorageItem(BigInteger.Zero)); + storage = engine.SnapshotCache.GetAndChange(CreateStorageKey(Prefix_TotalSupply), () => new StorageItem(BigInteger.Zero)); storage.Add(amount); await PostTransferAsync(engine, null, account, amount, StackItem.Null, callOnPayment); } @@ -88,15 +88,15 @@ internal async ContractTask Burn(ApplicationEngine engine, UInt160 account, BigI if (amount.Sign < 0) throw new ArgumentOutOfRangeException(nameof(amount)); if (amount.IsZero) return; StorageKey key = CreateStorageKey(Prefix_Account).Add(account); - StorageItem storage = engine.Snapshot.GetAndChange(key); + StorageItem storage = engine.SnapshotCache.GetAndChange(key); TState state = storage.GetInteroperable(); if (state.Balance < amount) throw new InvalidOperationException(); OnBalanceChanging(engine, account, state, -amount); if (state.Balance == amount) - engine.Snapshot.Delete(key); + engine.SnapshotCache.Delete(key); else state.Balance -= amount; - storage = engine.Snapshot.GetAndChange(CreateStorageKey(Prefix_TotalSupply)); + storage = engine.SnapshotCache.GetAndChange(CreateStorageKey(Prefix_TotalSupply)); storage.Add(-amount); await PostTransferAsync(engine, account, null, amount, StackItem.Null, false); } @@ -137,7 +137,7 @@ private protected async ContractTask Transfer(ApplicationEngine engine, UI if (!from.Equals(engine.CallingScriptHash) && !engine.CheckWitnessInternal(from)) return false; StorageKey key_from = CreateStorageKey(Prefix_Account).Add(from); - StorageItem storage_from = engine.Snapshot.GetAndChange(key_from); + StorageItem storage_from = engine.SnapshotCache.GetAndChange(key_from); if (amount.IsZero) { if (storage_from != null) @@ -159,11 +159,11 @@ private protected async ContractTask Transfer(ApplicationEngine engine, UI { OnBalanceChanging(engine, from, state_from, -amount); if (state_from.Balance == amount) - engine.Snapshot.Delete(key_from); + engine.SnapshotCache.Delete(key_from); else state_from.Balance -= amount; StorageKey key_to = CreateStorageKey(Prefix_Account).Add(to); - StorageItem storage_to = engine.Snapshot.GetAndChange(key_to, () => new StorageItem(new TState())); + StorageItem storage_to = engine.SnapshotCache.GetAndChange(key_to, () => new StorageItem(new TState())); TState state_to = storage_to.GetInteroperable(); OnBalanceChanging(engine, to, state_to, amount); state_to.Balance += amount; @@ -186,7 +186,7 @@ private protected virtual async ContractTask PostTransferAsync(ApplicationEngine // Check if it's a wallet or smart contract - if (!callOnPayment || to is null || ContractManagement.GetContract(engine.Snapshot, to) is null) return; + if (!callOnPayment || to is null || ContractManagement.GetContract(engine.SnapshotCache, to) is null) return; // Call onNEP17Payment method diff --git a/src/Neo/SmartContract/Native/GasToken.cs b/src/Neo/SmartContract/Native/GasToken.cs index b8a185b6f1..42eb16c1e5 100644 --- a/src/Neo/SmartContract/Native/GasToken.cs +++ b/src/Neo/SmartContract/Native/GasToken.cs @@ -44,7 +44,7 @@ internal override async ContractTask OnPersistAsync(ApplicationEngine engine) await Burn(engine, tx.Sender, tx.SystemFee + tx.NetworkFee); totalNetworkFee += tx.NetworkFee; } - ECPoint[] validators = NEO.GetNextBlockValidators(engine.Snapshot, engine.ProtocolSettings.ValidatorsCount); + ECPoint[] validators = NEO.GetNextBlockValidators(engine.SnapshotCache, engine.ProtocolSettings.ValidatorsCount); UInt160 primary = Contract.CreateSignatureRedeemScript(validators[engine.PersistingBlock.PrimaryIndex]).ToScriptHash(); await Mint(engine, primary, totalNetworkFee, false); } diff --git a/src/Neo/SmartContract/Native/LedgerContract.cs b/src/Neo/SmartContract/Native/LedgerContract.cs index ea757ba348..329e0565d5 100644 --- a/src/Neo/SmartContract/Native/LedgerContract.cs +++ b/src/Neo/SmartContract/Native/LedgerContract.cs @@ -42,22 +42,22 @@ internal override ContractTask OnPersistAsync(ApplicationEngine engine) Transaction = p, State = VMState.NONE }).ToArray(); - engine.Snapshot.Add(CreateStorageKey(Prefix_BlockHash).AddBigEndian(engine.PersistingBlock.Index), new StorageItem(engine.PersistingBlock.Hash.ToArray())); - engine.Snapshot.Add(CreateStorageKey(Prefix_Block).Add(engine.PersistingBlock.Hash), new StorageItem(Trim(engine.PersistingBlock).ToArray())); + engine.SnapshotCache.Add(CreateStorageKey(Prefix_BlockHash).AddBigEndian(engine.PersistingBlock.Index), new StorageItem(engine.PersistingBlock.Hash.ToArray())); + engine.SnapshotCache.Add(CreateStorageKey(Prefix_Block).Add(engine.PersistingBlock.Hash), new StorageItem(Trim(engine.PersistingBlock).ToArray())); foreach (TransactionState tx in transactions) { // It's possible that there are previously saved malicious conflict records for this transaction. // If so, then remove it and store the relevant transaction itself. - engine.Snapshot.GetAndChange(CreateStorageKey(Prefix_Transaction).Add(tx.Transaction.Hash), () => new StorageItem(new TransactionState())).FromReplica(new StorageItem(tx)); + engine.SnapshotCache.GetAndChange(CreateStorageKey(Prefix_Transaction).Add(tx.Transaction.Hash), () => new StorageItem(new TransactionState())).FromReplica(new StorageItem(tx)); // Store transaction's conflicits. var conflictingSigners = tx.Transaction.Signers.Select(s => s.Account); foreach (var attr in tx.Transaction.GetAttributes()) { - engine.Snapshot.GetAndChange(CreateStorageKey(Prefix_Transaction).Add(attr.Hash), () => new StorageItem(new TransactionState())).FromReplica(new StorageItem(new TransactionState() { BlockIndex = engine.PersistingBlock.Index })); + engine.SnapshotCache.GetAndChange(CreateStorageKey(Prefix_Transaction).Add(attr.Hash), () => new StorageItem(new TransactionState())).FromReplica(new StorageItem(new TransactionState() { BlockIndex = engine.PersistingBlock.Index })); foreach (var signer in conflictingSigners) { - engine.Snapshot.GetAndChange(CreateStorageKey(Prefix_Transaction).Add(attr.Hash).Add(signer), () => new StorageItem(new TransactionState())).FromReplica(new StorageItem(new TransactionState() { BlockIndex = engine.PersistingBlock.Index })); + engine.SnapshotCache.GetAndChange(CreateStorageKey(Prefix_Transaction).Add(attr.Hash).Add(signer), () => new StorageItem(new TransactionState())).FromReplica(new StorageItem(new TransactionState() { BlockIndex = engine.PersistingBlock.Index })); } } } @@ -67,7 +67,7 @@ internal override ContractTask OnPersistAsync(ApplicationEngine engine) internal override ContractTask PostPersistAsync(ApplicationEngine engine) { - HashIndexState state = engine.Snapshot.GetAndChange(CreateStorageKey(Prefix_CurrentBlock), () => new StorageItem(new HashIndexState())).GetInteroperable(); + HashIndexState state = engine.SnapshotCache.GetAndChange(CreateStorageKey(Prefix_CurrentBlock), () => new StorageItem(new HashIndexState())).GetInteroperable(); state.Hash = engine.PersistingBlock.Hash; state.Index = engine.PersistingBlock.Index; return ContractTask.CompletedTask; @@ -188,14 +188,14 @@ private TrimmedBlock GetBlock(ApplicationEngine engine, byte[] indexOrHash) { UInt256 hash; if (indexOrHash.Length < UInt256.Length) - hash = GetBlockHash(engine.Snapshot, (uint)new BigInteger(indexOrHash)); + hash = GetBlockHash(engine.SnapshotCache, (uint)new BigInteger(indexOrHash)); else if (indexOrHash.Length == UInt256.Length) hash = new UInt256(indexOrHash); else throw new ArgumentException(null, nameof(indexOrHash)); if (hash is null) return null; - TrimmedBlock block = GetTrimmedBlock(engine.Snapshot, hash); - if (block is null || !IsTraceableBlock(engine.Snapshot, block.Index, engine.ProtocolSettings.MaxTraceableBlocks)) return null; + TrimmedBlock block = GetTrimmedBlock(engine.SnapshotCache, hash); + if (block is null || !IsTraceableBlock(engine.SnapshotCache, block.Index, engine.ProtocolSettings.MaxTraceableBlocks)) return null; return block; } @@ -280,32 +280,32 @@ public Transaction GetTransaction(DataCache snapshot, UInt256 hash) [ContractMethod(CpuFee = 1 << 15, RequiredCallFlags = CallFlags.ReadStates, Name = "getTransaction")] private Transaction GetTransactionForContract(ApplicationEngine engine, UInt256 hash) { - TransactionState state = GetTransactionState(engine.Snapshot, hash); - if (state is null || !IsTraceableBlock(engine.Snapshot, state.BlockIndex, engine.ProtocolSettings.MaxTraceableBlocks)) return null; + TransactionState state = GetTransactionState(engine.SnapshotCache, hash); + if (state is null || !IsTraceableBlock(engine.SnapshotCache, state.BlockIndex, engine.ProtocolSettings.MaxTraceableBlocks)) return null; return state.Transaction; } [ContractMethod(CpuFee = 1 << 15, RequiredCallFlags = CallFlags.ReadStates)] private Signer[] GetTransactionSigners(ApplicationEngine engine, UInt256 hash) { - TransactionState state = GetTransactionState(engine.Snapshot, hash); - if (state is null || !IsTraceableBlock(engine.Snapshot, state.BlockIndex, engine.ProtocolSettings.MaxTraceableBlocks)) return null; + TransactionState state = GetTransactionState(engine.SnapshotCache, hash); + if (state is null || !IsTraceableBlock(engine.SnapshotCache, state.BlockIndex, engine.ProtocolSettings.MaxTraceableBlocks)) return null; return state.Transaction.Signers; } [ContractMethod(CpuFee = 1 << 15, RequiredCallFlags = CallFlags.ReadStates)] private VMState GetTransactionVMState(ApplicationEngine engine, UInt256 hash) { - TransactionState state = GetTransactionState(engine.Snapshot, hash); - if (state is null || !IsTraceableBlock(engine.Snapshot, state.BlockIndex, engine.ProtocolSettings.MaxTraceableBlocks)) return VMState.NONE; + TransactionState state = GetTransactionState(engine.SnapshotCache, hash); + if (state is null || !IsTraceableBlock(engine.SnapshotCache, state.BlockIndex, engine.ProtocolSettings.MaxTraceableBlocks)) return VMState.NONE; return state.State; } [ContractMethod(CpuFee = 1 << 15, RequiredCallFlags = CallFlags.ReadStates)] private int GetTransactionHeight(ApplicationEngine engine, UInt256 hash) { - TransactionState state = GetTransactionState(engine.Snapshot, hash); - if (state is null || !IsTraceableBlock(engine.Snapshot, state.BlockIndex, engine.ProtocolSettings.MaxTraceableBlocks)) return -1; + TransactionState state = GetTransactionState(engine.SnapshotCache, hash); + if (state is null || !IsTraceableBlock(engine.SnapshotCache, state.BlockIndex, engine.ProtocolSettings.MaxTraceableBlocks)) return -1; return (int)state.BlockIndex; } @@ -314,17 +314,17 @@ private Transaction GetTransactionFromBlock(ApplicationEngine engine, byte[] blo { UInt256 hash; if (blockIndexOrHash.Length < UInt256.Length) - hash = GetBlockHash(engine.Snapshot, (uint)new BigInteger(blockIndexOrHash)); + hash = GetBlockHash(engine.SnapshotCache, (uint)new BigInteger(blockIndexOrHash)); else if (blockIndexOrHash.Length == UInt256.Length) hash = new UInt256(blockIndexOrHash); else throw new ArgumentException(null, nameof(blockIndexOrHash)); if (hash is null) return null; - TrimmedBlock block = GetTrimmedBlock(engine.Snapshot, hash); - if (block is null || !IsTraceableBlock(engine.Snapshot, block.Index, engine.ProtocolSettings.MaxTraceableBlocks)) return null; + TrimmedBlock block = GetTrimmedBlock(engine.SnapshotCache, hash); + if (block is null || !IsTraceableBlock(engine.SnapshotCache, block.Index, engine.ProtocolSettings.MaxTraceableBlocks)) return null; if (txIndex < 0 || txIndex >= block.Hashes.Length) throw new ArgumentOutOfRangeException(nameof(txIndex)); - return GetTransaction(engine.Snapshot, block.Hashes[txIndex]); + return GetTransaction(engine.SnapshotCache, block.Hashes[txIndex]); } private static TrimmedBlock Trim(Block block) diff --git a/src/Neo/SmartContract/Native/NativeContract.cs b/src/Neo/SmartContract/Native/NativeContract.cs index b030f06c9b..97bb0ab69a 100644 --- a/src/Neo/SmartContract/Native/NativeContract.cs +++ b/src/Neo/SmartContract/Native/NativeContract.cs @@ -41,7 +41,7 @@ public CacheEntry GetAllowedMethods(NativeContract native, ApplicationEngine eng { if (NativeContracts.TryGetValue(native.Id, out var value)) return value; - uint index = engine.PersistingBlock is null ? Ledger.CurrentIndex(engine.Snapshot) : engine.PersistingBlock.Index; + uint index = engine.PersistingBlock is null ? Ledger.CurrentIndex(engine.SnapshotCache) : engine.PersistingBlock.Index; CacheEntry methods = native.GetAllowedMethods(engine.ProtocolSettings.IsHardforkEnabled, index); NativeContracts[native.Id] = methods; return methods; @@ -343,7 +343,7 @@ internal bool IsActive(ProtocolSettings settings, uint blockHeight) /// if the committee has witnessed the current transaction; otherwise, . protected static bool CheckCommittee(ApplicationEngine engine) { - UInt160 committeeMultiSigAddr = NEO.GetCommitteeAddress(engine.Snapshot); + UInt160 committeeMultiSigAddr = NEO.GetCommitteeAddress(engine.SnapshotCache); return engine.CheckWitnessInternal(committeeMultiSigAddr); } @@ -386,7 +386,7 @@ internal async void Invoke(ApplicationEngine engine, byte version) engine.AddFee(method.CpuFee * engine.ExecFeeFactor + method.StorageFee * engine.StoragePrice); List parameters = new(); if (method.NeedApplicationEngine) parameters.Add(engine); - if (method.NeedSnapshot) parameters.Add(engine.Snapshot); + if (method.NeedSnapshot) parameters.Add(engine.SnapshotCache); for (int i = 0; i < method.Parameters.Length; i++) parameters.Add(engine.Convert(context.EvaluationStack.Peek(i), method.Parameters[i])); object returnValue = method.Handler.Invoke(this, parameters.ToArray()); diff --git a/src/Neo/SmartContract/Native/NeoToken.cs b/src/Neo/SmartContract/Native/NeoToken.cs index f43a0d6079..40f63355df 100644 --- a/src/Neo/SmartContract/Native/NeoToken.cs +++ b/src/Neo/SmartContract/Native/NeoToken.cs @@ -86,11 +86,11 @@ internal override void OnBalanceChanging(ApplicationEngine engine, UInt160 accou } if (amount.IsZero) return; if (state.VoteTo is null) return; - engine.Snapshot.GetAndChange(CreateStorageKey(Prefix_VotersCount)).Add(amount); + engine.SnapshotCache.GetAndChange(CreateStorageKey(Prefix_VotersCount)).Add(amount); StorageKey key = CreateStorageKey(Prefix_Candidate).Add(state.VoteTo); - CandidateState candidate = engine.Snapshot.GetAndChange(key).GetInteroperable(); + CandidateState candidate = engine.SnapshotCache.GetAndChange(key).GetInteroperable(); candidate.Votes += amount; - CheckCandidate(engine.Snapshot, state.VoteTo, candidate); + CheckCandidate(engine.SnapshotCache, state.VoteTo, candidate); } private protected override async ContractTask PostTransferAsync(ApplicationEngine engine, UInt160 from, UInt160 to, BigInteger amount, StackItem data, bool callOnPayment) @@ -107,12 +107,12 @@ private GasDistribution DistributeGas(ApplicationEngine engine, UInt160 account, if (engine.PersistingBlock is null) return null; // In the unit of datoshi, 1 datoshi = 1e-8 GAS - BigInteger datoshi = CalculateBonus(engine.Snapshot, state, engine.PersistingBlock.Index); + BigInteger datoshi = CalculateBonus(engine.SnapshotCache, state, engine.PersistingBlock.Index); state.BalanceHeight = engine.PersistingBlock.Index; if (state.VoteTo is not null) { var keyLastest = CreateStorageKey(Prefix_VoterRewardPerCommittee).Add(state.VoteTo); - var latestGasPerVote = engine.Snapshot.TryGet(keyLastest) ?? BigInteger.Zero; + var latestGasPerVote = engine.SnapshotCache.TryGet(keyLastest) ?? BigInteger.Zero; state.LastGasPerVote = latestGasPerVote; } if (datoshi == 0) return null; @@ -184,10 +184,10 @@ internal override ContractTask InitializeAsync(ApplicationEngine engine, Hardfor if (hardfork == ActiveIn) { var cachedCommittee = new CachedCommittee(engine.ProtocolSettings.StandbyCommittee.Select(p => (p, BigInteger.Zero))); - engine.Snapshot.Add(CreateStorageKey(Prefix_Committee), new StorageItem(cachedCommittee)); - engine.Snapshot.Add(CreateStorageKey(Prefix_VotersCount), new StorageItem(System.Array.Empty())); - engine.Snapshot.Add(CreateStorageKey(Prefix_GasPerBlock).AddBigEndian(0u), new StorageItem(5 * GAS.Factor)); - engine.Snapshot.Add(CreateStorageKey(Prefix_RegisterPrice), new StorageItem(1000 * GAS.Factor)); + engine.SnapshotCache.Add(CreateStorageKey(Prefix_Committee), new StorageItem(cachedCommittee)); + engine.SnapshotCache.Add(CreateStorageKey(Prefix_VotersCount), new StorageItem(System.Array.Empty())); + engine.SnapshotCache.Add(CreateStorageKey(Prefix_GasPerBlock).AddBigEndian(0u), new StorageItem(5 * GAS.Factor)); + engine.SnapshotCache.Add(CreateStorageKey(Prefix_RegisterPrice), new StorageItem(1000 * GAS.Factor)); return Mint(engine, Contract.GetBFTAddress(engine.ProtocolSettings.StandbyValidators), TotalAmount, false); } return ContractTask.CompletedTask; @@ -198,17 +198,17 @@ internal override ContractTask OnPersistAsync(ApplicationEngine engine) // Set next committee if (ShouldRefreshCommittee(engine.PersistingBlock.Index, engine.ProtocolSettings.CommitteeMembersCount)) { - var storageItem = engine.Snapshot.GetAndChange(CreateStorageKey(Prefix_Committee)); + var storageItem = engine.SnapshotCache.GetAndChange(CreateStorageKey(Prefix_Committee)); var cachedCommittee = storageItem.GetInteroperable(); var prevCommittee = cachedCommittee.Select(u => u.PublicKey).ToArray(); cachedCommittee.Clear(); - cachedCommittee.AddRange(ComputeCommitteeMembers(engine.Snapshot, engine.ProtocolSettings)); + cachedCommittee.AddRange(ComputeCommitteeMembers(engine.SnapshotCache, engine.ProtocolSettings)); // Hardfork check for https://github.com/neo-project/neo/pull/3158 // New notification will case 3.7.0 and 3.6.0 have different behavior - var index = engine.PersistingBlock?.Index ?? Ledger.CurrentIndex(engine.Snapshot); + var index = engine.PersistingBlock?.Index ?? Ledger.CurrentIndex(engine.SnapshotCache); if (engine.ProtocolSettings.IsHardforkEnabled(Hardfork.HF_Cockatrice, index)) { var newCommittee = cachedCommittee.Select(u => u.PublicKey).ToArray(); @@ -232,8 +232,8 @@ internal override async ContractTask PostPersistAsync(ApplicationEngine engine) int m = engine.ProtocolSettings.CommitteeMembersCount; int n = engine.ProtocolSettings.ValidatorsCount; int index = (int)(engine.PersistingBlock.Index % (uint)m); - var gasPerBlock = GetGasPerBlock(engine.Snapshot); - var committee = GetCommitteeFromCache(engine.Snapshot); + var gasPerBlock = GetGasPerBlock(engine.SnapshotCache); + var committee = GetCommitteeFromCache(engine.SnapshotCache); var pubkey = committee[index].PublicKey; var account = Contract.CreateSignatureRedeemScript(pubkey).ToScriptHash(); await GAS.Mint(engine, account, gasPerBlock * CommitteeRewardRatio / 100, false); @@ -251,7 +251,7 @@ internal override async ContractTask PostPersistAsync(ApplicationEngine engine) { BigInteger voterSumRewardPerNEO = factor * voterRewardOfEachCommittee / Votes; StorageKey voterRewardKey = CreateStorageKey(Prefix_VoterRewardPerCommittee).Add(PublicKey); - StorageItem lastRewardPerNeo = engine.Snapshot.GetAndChange(voterRewardKey, () => new StorageItem(BigInteger.Zero)); + StorageItem lastRewardPerNeo = engine.SnapshotCache.GetAndChange(voterRewardKey, () => new StorageItem(BigInteger.Zero)); lastRewardPerNeo.Add(voterSumRewardPerNEO); } } @@ -266,7 +266,7 @@ private void SetGasPerBlock(ApplicationEngine engine, BigInteger gasPerBlock) if (!CheckCommittee(engine)) throw new InvalidOperationException(); uint index = engine.PersistingBlock.Index + 1; - StorageItem entry = engine.Snapshot.GetAndChange(CreateStorageKey(Prefix_GasPerBlock).AddBigEndian(index), () => new StorageItem(gasPerBlock)); + StorageItem entry = engine.SnapshotCache.GetAndChange(CreateStorageKey(Prefix_GasPerBlock).AddBigEndian(index), () => new StorageItem(gasPerBlock)); entry.Set(gasPerBlock); } @@ -287,7 +287,7 @@ private void SetRegisterPrice(ApplicationEngine engine, long registerPrice) if (registerPrice <= 0) throw new ArgumentOutOfRangeException(nameof(registerPrice)); if (!CheckCommittee(engine)) throw new InvalidOperationException(); - engine.Snapshot.GetAndChange(CreateStorageKey(Prefix_RegisterPrice)).Set(registerPrice); + engine.SnapshotCache.GetAndChange(CreateStorageKey(Prefix_RegisterPrice)).Set(registerPrice); } /// @@ -332,9 +332,9 @@ private bool RegisterCandidate(ApplicationEngine engine, ECPoint pubkey) if (!engine.CheckWitnessInternal(Contract.CreateSignatureRedeemScript(pubkey).ToScriptHash())) return false; // In the unit of datoshi, 1 datoshi = 1e-8 GAS - engine.AddFee(GetRegisterPrice(engine.Snapshot)); + engine.AddFee(GetRegisterPrice(engine.SnapshotCache)); StorageKey key = CreateStorageKey(Prefix_Candidate).Add(pubkey); - StorageItem item = engine.Snapshot.GetAndChange(key, () => new StorageItem(new CandidateState())); + StorageItem item = engine.SnapshotCache.GetAndChange(key, () => new StorageItem(new CandidateState())); CandidateState state = item.GetInteroperable(); if (state.Registered) return true; state.Registered = true; @@ -349,12 +349,12 @@ private bool UnregisterCandidate(ApplicationEngine engine, ECPoint pubkey) if (!engine.CheckWitnessInternal(Contract.CreateSignatureRedeemScript(pubkey).ToScriptHash())) return false; StorageKey key = CreateStorageKey(Prefix_Candidate).Add(pubkey); - if (engine.Snapshot.TryGet(key) is null) return true; - StorageItem item = engine.Snapshot.GetAndChange(key); + if (engine.SnapshotCache.TryGet(key) is null) return true; + StorageItem item = engine.SnapshotCache.GetAndChange(key); CandidateState state = item.GetInteroperable(); if (!state.Registered) return true; state.Registered = false; - CheckCandidate(engine.Snapshot, pubkey, state); + CheckCandidate(engine.SnapshotCache, pubkey, state); engine.SendNotification(Hash, "CandidateStateChanged", new VM.Types.Array(engine.ReferenceCounter) { pubkey.ToArray(), false, state.Votes }); return true; @@ -364,19 +364,19 @@ private bool UnregisterCandidate(ApplicationEngine engine, ECPoint pubkey) private async ContractTask Vote(ApplicationEngine engine, UInt160 account, ECPoint voteTo) { if (!engine.CheckWitnessInternal(account)) return false; - NeoAccountState state_account = engine.Snapshot.GetAndChange(CreateStorageKey(Prefix_Account).Add(account))?.GetInteroperable(); + NeoAccountState state_account = engine.SnapshotCache.GetAndChange(CreateStorageKey(Prefix_Account).Add(account))?.GetInteroperable(); if (state_account is null) return false; if (state_account.Balance == 0) return false; CandidateState validator_new = null; if (voteTo != null) { - validator_new = engine.Snapshot.GetAndChange(CreateStorageKey(Prefix_Candidate).Add(voteTo))?.GetInteroperable(); + validator_new = engine.SnapshotCache.GetAndChange(CreateStorageKey(Prefix_Candidate).Add(voteTo))?.GetInteroperable(); if (validator_new is null) return false; if (!validator_new.Registered) return false; } if (state_account.VoteTo is null ^ voteTo is null) { - StorageItem item = engine.Snapshot.GetAndChange(CreateStorageKey(Prefix_VotersCount)); + StorageItem item = engine.SnapshotCache.GetAndChange(CreateStorageKey(Prefix_VotersCount)); if (state_account.VoteTo is null) item.Add(state_account.Balance); else @@ -386,15 +386,15 @@ private async ContractTask Vote(ApplicationEngine engine, UInt160 account, if (state_account.VoteTo != null) { StorageKey key = CreateStorageKey(Prefix_Candidate).Add(state_account.VoteTo); - StorageItem storage_validator = engine.Snapshot.GetAndChange(key); + StorageItem storage_validator = engine.SnapshotCache.GetAndChange(key); CandidateState state_validator = storage_validator.GetInteroperable(); state_validator.Votes -= state_account.Balance; - CheckCandidate(engine.Snapshot, state_account.VoteTo, state_validator); + CheckCandidate(engine.SnapshotCache, state_account.VoteTo, state_validator); } if (voteTo != null && voteTo != state_account.VoteTo) { StorageKey voterRewardKey = CreateStorageKey(Prefix_VoterRewardPerCommittee).Add(voteTo); - var latestGasPerVote = engine.Snapshot.TryGet(voterRewardKey) ?? BigInteger.Zero; + var latestGasPerVote = engine.SnapshotCache.TryGet(voterRewardKey) ?? BigInteger.Zero; state_account.LastGasPerVote = latestGasPerVote; } ECPoint from = state_account.VoteTo; @@ -536,7 +536,7 @@ public ECPoint[] ComputeNextBlockValidators(DataCache snapshot, ProtocolSettings [ContractMethod(CpuFee = 1 << 16, RequiredCallFlags = CallFlags.ReadStates)] private ECPoint[] GetNextBlockValidators(ApplicationEngine engine) { - return GetNextBlockValidators(engine.Snapshot, engine.ProtocolSettings.ValidatorsCount); + return GetNextBlockValidators(engine.SnapshotCache, engine.ProtocolSettings.ValidatorsCount); } /// diff --git a/src/Neo/SmartContract/Native/OracleContract.cs b/src/Neo/SmartContract/Native/OracleContract.cs index 13a7264660..be4765581a 100644 --- a/src/Neo/SmartContract/Native/OracleContract.cs +++ b/src/Neo/SmartContract/Native/OracleContract.cs @@ -56,7 +56,7 @@ private void SetPrice(ApplicationEngine engine, long price) if (price <= 0) throw new ArgumentOutOfRangeException(nameof(price)); if (!CheckCommittee(engine)) throw new InvalidOperationException(); - engine.Snapshot.GetAndChange(CreateStorageKey(Prefix_Price)).Set(price); + engine.SnapshotCache.GetAndChange(CreateStorageKey(Prefix_Price)).Set(price); } /// @@ -78,7 +78,7 @@ private ContractTask Finish(ApplicationEngine engine) Transaction tx = (Transaction)engine.ScriptContainer; OracleResponse response = tx.GetAttribute(); if (response == null) throw new ArgumentException("Oracle response was not found"); - OracleRequest request = GetRequest(engine.Snapshot, response.Id); + OracleRequest request = GetRequest(engine.SnapshotCache, response.Id); if (request == null) throw new ArgumentException("Oracle request was not found"); engine.SendNotification(Hash, "OracleResponse", new VM.Types.Array(engine.ReferenceCounter) { response.Id, request.OriginalTxid.ToArray() }); StackItem userData = BinarySerializer.Deserialize(request.UserData, engine.Limits, engine.ReferenceCounter); @@ -90,7 +90,7 @@ private UInt256 GetOriginalTxid(ApplicationEngine engine) Transaction tx = (Transaction)engine.ScriptContainer; OracleResponse response = tx.GetAttribute(); if (response is null) return tx.Hash; - OracleRequest request = GetRequest(engine.Snapshot, response.Id); + OracleRequest request = GetRequest(engine.SnapshotCache, response.Id); return request.OriginalTxid; } @@ -138,8 +138,8 @@ internal override ContractTask InitializeAsync(ApplicationEngine engine, Hardfor { if (hardfork == ActiveIn) { - engine.Snapshot.Add(CreateStorageKey(Prefix_RequestId), new StorageItem(BigInteger.Zero)); - engine.Snapshot.Add(CreateStorageKey(Prefix_Price), new StorageItem(0_50000000)); + engine.SnapshotCache.Add(CreateStorageKey(Prefix_RequestId), new StorageItem(BigInteger.Zero)); + engine.SnapshotCache.Add(CreateStorageKey(Prefix_Price), new StorageItem(0_50000000)); } return ContractTask.CompletedTask; } @@ -155,22 +155,22 @@ internal override async ContractTask PostPersistAsync(ApplicationEngine engine) //Remove the request from storage StorageKey key = CreateStorageKey(Prefix_Request).AddBigEndian(response.Id); - OracleRequest request = engine.Snapshot.TryGet(key)?.GetInteroperable(); + OracleRequest request = engine.SnapshotCache.TryGet(key)?.GetInteroperable(); if (request == null) continue; - engine.Snapshot.Delete(key); + engine.SnapshotCache.Delete(key); //Remove the id from IdList key = CreateStorageKey(Prefix_IdList).Add(GetUrlHash(request.Url)); - IdList list = engine.Snapshot.GetAndChange(key).GetInteroperable(); + IdList list = engine.SnapshotCache.GetAndChange(key).GetInteroperable(); if (!list.Remove(response.Id)) throw new InvalidOperationException(); - if (list.Count == 0) engine.Snapshot.Delete(key); + if (list.Count == 0) engine.SnapshotCache.Delete(key); //Mint GAS for oracle nodes - nodes ??= RoleManagement.GetDesignatedByRole(engine.Snapshot, Role.Oracle, engine.PersistingBlock.Index).Select(p => (Contract.CreateSignatureRedeemScript(p).ToScriptHash(), BigInteger.Zero)).ToArray(); + nodes ??= RoleManagement.GetDesignatedByRole(engine.SnapshotCache, Role.Oracle, engine.PersistingBlock.Index).Select(p => (Contract.CreateSignatureRedeemScript(p).ToScriptHash(), BigInteger.Zero)).ToArray(); if (nodes.Length > 0) { int index = (int)(response.Id % (ulong)nodes.Length); - nodes[index].GAS += GetPrice(engine.Snapshot); + nodes[index].GAS += GetPrice(engine.SnapshotCache); } } if (nodes != null) @@ -193,21 +193,21 @@ private async ContractTask Request(ApplicationEngine engine, string url, string || gasForResponse < 0_10000000) throw new ArgumentException(); - engine.AddFee(GetPrice(engine.Snapshot)); + engine.AddFee(GetPrice(engine.SnapshotCache)); //Mint gas for the response engine.AddFee(gasForResponse); await GAS.Mint(engine, Hash, gasForResponse, false); //Increase the request id - StorageItem item_id = engine.Snapshot.GetAndChange(CreateStorageKey(Prefix_RequestId)); + StorageItem item_id = engine.SnapshotCache.GetAndChange(CreateStorageKey(Prefix_RequestId)); ulong id = (ulong)(BigInteger)item_id; item_id.Add(1); //Put the request to storage - if (ContractManagement.GetContract(engine.Snapshot, engine.CallingScriptHash) is null) + if (ContractManagement.GetContract(engine.SnapshotCache, engine.CallingScriptHash) is null) throw new InvalidOperationException(); - engine.Snapshot.Add(CreateStorageKey(Prefix_Request).AddBigEndian(id), new StorageItem(new OracleRequest + engine.SnapshotCache.Add(CreateStorageKey(Prefix_Request).AddBigEndian(id), new StorageItem(new OracleRequest { OriginalTxid = GetOriginalTxid(engine), GasForResponse = gasForResponse, @@ -219,7 +219,7 @@ private async ContractTask Request(ApplicationEngine engine, string url, string })); //Add the id to the IdList - var list = engine.Snapshot.GetAndChange(CreateStorageKey(Prefix_IdList).Add(GetUrlHash(url)), () => new StorageItem(new IdList())).GetInteroperable(); + var list = engine.SnapshotCache.GetAndChange(CreateStorageKey(Prefix_IdList).Add(GetUrlHash(url)), () => new StorageItem(new IdList())).GetInteroperable(); if (list.Count >= 256) throw new InvalidOperationException("There are too many pending responses for this url"); list.Add(id); diff --git a/src/Neo/SmartContract/Native/PolicyContract.cs b/src/Neo/SmartContract/Native/PolicyContract.cs index 2da6255094..744b7b3ab6 100644 --- a/src/Neo/SmartContract/Native/PolicyContract.cs +++ b/src/Neo/SmartContract/Native/PolicyContract.cs @@ -71,9 +71,9 @@ internal override ContractTask InitializeAsync(ApplicationEngine engine, Hardfor { if (hardfork == ActiveIn) { - engine.Snapshot.Add(CreateStorageKey(Prefix_FeePerByte), new StorageItem(DefaultFeePerByte)); - engine.Snapshot.Add(CreateStorageKey(Prefix_ExecFeeFactor), new StorageItem(DefaultExecFeeFactor)); - engine.Snapshot.Add(CreateStorageKey(Prefix_StoragePrice), new StorageItem(DefaultStoragePrice)); + engine.SnapshotCache.Add(CreateStorageKey(Prefix_FeePerByte), new StorageItem(DefaultFeePerByte)); + engine.SnapshotCache.Add(CreateStorageKey(Prefix_ExecFeeFactor), new StorageItem(DefaultExecFeeFactor)); + engine.SnapshotCache.Add(CreateStorageKey(Prefix_StoragePrice), new StorageItem(DefaultStoragePrice)); } return ContractTask.CompletedTask; } @@ -146,7 +146,7 @@ private void SetAttributeFee(ApplicationEngine engine, byte attributeType, uint if (value > MaxAttributeFee) throw new ArgumentOutOfRangeException(nameof(value)); if (!CheckCommittee(engine)) throw new InvalidOperationException(); - engine.Snapshot.GetAndChange(CreateStorageKey(Prefix_AttributeFee).Add(attributeType), () => new StorageItem(DefaultAttributeFee)).Set(value); + engine.SnapshotCache.GetAndChange(CreateStorageKey(Prefix_AttributeFee).Add(attributeType), () => new StorageItem(DefaultAttributeFee)).Set(value); } [ContractMethod(CpuFee = 1 << 15, RequiredCallFlags = CallFlags.States)] @@ -154,7 +154,7 @@ private void SetFeePerByte(ApplicationEngine engine, long value) { if (value < 0 || value > 1_00000000) throw new ArgumentOutOfRangeException(nameof(value)); if (!CheckCommittee(engine)) throw new InvalidOperationException(); - engine.Snapshot.GetAndChange(CreateStorageKey(Prefix_FeePerByte)).Set(value); + engine.SnapshotCache.GetAndChange(CreateStorageKey(Prefix_FeePerByte)).Set(value); } [ContractMethod(CpuFee = 1 << 15, RequiredCallFlags = CallFlags.States)] @@ -162,7 +162,7 @@ private void SetExecFeeFactor(ApplicationEngine engine, uint value) { if (value == 0 || value > MaxExecFeeFactor) throw new ArgumentOutOfRangeException(nameof(value)); if (!CheckCommittee(engine)) throw new InvalidOperationException(); - engine.Snapshot.GetAndChange(CreateStorageKey(Prefix_ExecFeeFactor)).Set(value); + engine.SnapshotCache.GetAndChange(CreateStorageKey(Prefix_ExecFeeFactor)).Set(value); } [ContractMethod(CpuFee = 1 << 15, RequiredCallFlags = CallFlags.States)] @@ -170,14 +170,14 @@ private void SetStoragePrice(ApplicationEngine engine, uint value) { if (value == 0 || value > MaxStoragePrice) throw new ArgumentOutOfRangeException(nameof(value)); if (!CheckCommittee(engine)) throw new InvalidOperationException(); - engine.Snapshot.GetAndChange(CreateStorageKey(Prefix_StoragePrice)).Set(value); + engine.SnapshotCache.GetAndChange(CreateStorageKey(Prefix_StoragePrice)).Set(value); } [ContractMethod(CpuFee = 1 << 15, RequiredCallFlags = CallFlags.States)] private bool BlockAccount(ApplicationEngine engine, UInt160 account) { if (!CheckCommittee(engine)) throw new InvalidOperationException(); - return BlockAccount(engine.Snapshot, account); + return BlockAccount(engine.SnapshotCache, account); } internal bool BlockAccount(DataCache snapshot, UInt160 account) @@ -197,9 +197,9 @@ private bool UnblockAccount(ApplicationEngine engine, UInt160 account) if (!CheckCommittee(engine)) throw new InvalidOperationException(); var key = CreateStorageKey(Prefix_BlockedAccount).Add(account); - if (!engine.Snapshot.Contains(key)) return false; + if (!engine.SnapshotCache.Contains(key)) return false; - engine.Snapshot.Delete(key); + engine.SnapshotCache.Delete(key); return true; } } diff --git a/src/Neo/SmartContract/Native/RoleManagement.cs b/src/Neo/SmartContract/Native/RoleManagement.cs index 6e989b78cf..d0437594c9 100644 --- a/src/Neo/SmartContract/Native/RoleManagement.cs +++ b/src/Neo/SmartContract/Native/RoleManagement.cs @@ -63,12 +63,12 @@ private void DesignateAsRole(ApplicationEngine engine, Role role, ECPoint[] node throw new InvalidOperationException(nameof(DesignateAsRole)); uint index = engine.PersistingBlock.Index + 1; var key = CreateStorageKey((byte)role).AddBigEndian(index); - if (engine.Snapshot.Contains(key)) + if (engine.SnapshotCache.Contains(key)) throw new InvalidOperationException(); NodeList list = new(); list.AddRange(nodes); list.Sort(); - engine.Snapshot.Add(key, new StorageItem(list)); + engine.SnapshotCache.Add(key, new StorageItem(list)); engine.SendNotification(Hash, "Designation", new VM.Types.Array(engine.ReferenceCounter, new StackItem[] { (int)role, engine.PersistingBlock.Index })); } diff --git a/src/Neo/Wallets/Wallet.cs b/src/Neo/Wallets/Wallet.cs index d23bdcfb9f..fc71a9135c 100644 --- a/src/Neo/Wallets/Wallet.cs +++ b/src/Neo/Wallets/Wallet.cs @@ -636,7 +636,7 @@ public bool Sign(ContractParametersContext context) // Try Smart contract verification - var contract = NativeContract.ContractManagement.GetContract(context.Snapshot, scriptHash); + var contract = NativeContract.ContractManagement.GetContract(context.SnapshotCache, scriptHash); if (contract != null) { diff --git a/src/Plugins/RpcServer/RpcServer.SmartContract.cs b/src/Plugins/RpcServer/RpcServer.SmartContract.cs index 2fe49d4965..473ae0cb5d 100644 --- a/src/Plugins/RpcServer/RpcServer.SmartContract.cs +++ b/src/Plugins/RpcServer/RpcServer.SmartContract.cs @@ -92,7 +92,7 @@ private JObject GetInvokeResult(byte[] script, Signer[] signers = null, Witness[ json["diagnostics"] = new JObject() { ["invokedcontracts"] = ToJson(diagnostic.InvocationTree.Root), - ["storagechanges"] = ToJson(session.Engine.Snapshot.GetChangeSet()) + ["storagechanges"] = ToJson(session.Engine.SnapshotCache.GetChangeSet()) }; } var stack = new JArray(); diff --git a/tests/Neo.Plugins.OracleService.Tests/UT_OracleService.cs b/tests/Neo.Plugins.OracleService.Tests/UT_OracleService.cs index 79771ee796..33d82c618c 100644 --- a/tests/Neo.Plugins.OracleService.Tests/UT_OracleService.cs +++ b/tests/Neo.Plugins.OracleService.Tests/UT_OracleService.cs @@ -70,11 +70,11 @@ public void TestFilter() [TestMethod] public void TestCreateOracleResponseTx() { - var snapshot = TestBlockchain.GetTestSnapshotCache(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); - var executionFactor = NativeContract.Policy.GetExecFeeFactor(snapshot); + var executionFactor = NativeContract.Policy.GetExecFeeFactor(snapshotCache); Assert.AreEqual(executionFactor, (uint)30); - var feePerByte = NativeContract.Policy.GetFeePerByte(snapshot); + var feePerByte = NativeContract.Policy.GetFeePerByte(snapshotCache); Assert.AreEqual(feePerByte, 1000); OracleRequest request = new OracleRequest @@ -88,7 +88,7 @@ public void TestCreateOracleResponseTx() UserData = [] }; byte Prefix_Transaction = 11; - snapshot.Add(NativeContract.Ledger.CreateStorageKey(Prefix_Transaction, request.OriginalTxid), new StorageItem(new TransactionState() + snapshotCache.Add(NativeContract.Ledger.CreateStorageKey(Prefix_Transaction, request.OriginalTxid), new StorageItem(new TransactionState() { BlockIndex = 1, Transaction = new Transaction() @@ -98,7 +98,7 @@ public void TestCreateOracleResponseTx() })); OracleResponse response = new OracleResponse() { Id = 1, Code = OracleResponseCode.Success, Result = new byte[] { 0x00 } }; ECPoint[] oracleNodes = new ECPoint[] { ECCurve.Secp256r1.G }; - var tx = OracleService.CreateResponseTx(snapshot, request, response, oracleNodes, ProtocolSettings.Default); + var tx = OracleService.CreateResponseTx(snapshotCache, request, response, oracleNodes, ProtocolSettings.Default); Assert.AreEqual(166, tx.Size); Assert.AreEqual(2198650, tx.NetworkFee); @@ -108,7 +108,7 @@ public void TestCreateOracleResponseTx() request.GasForResponse = 0_10000000; response.Result = new byte[10250]; - tx = OracleService.CreateResponseTx(snapshot, request, response, oracleNodes, ProtocolSettings.Default); + tx = OracleService.CreateResponseTx(snapshotCache, request, response, oracleNodes, ProtocolSettings.Default); Assert.AreEqual(165, tx.Size); Assert.AreEqual(OracleResponseCode.InsufficientFunds, response.Code); Assert.AreEqual(2197650, tx.NetworkFee); diff --git a/tests/Neo.UnitTests/IO/Caching/UT_CloneCache.cs b/tests/Neo.UnitTests/IO/Caching/UT_CloneCache.cs index 71eeb4ac25..e5fea8130a 100644 --- a/tests/Neo.UnitTests/IO/Caching/UT_CloneCache.cs +++ b/tests/Neo.UnitTests/IO/Caching/UT_CloneCache.cs @@ -155,8 +155,8 @@ public void TestUpdateInternal() [TestMethod] public void TestCacheOverrideIssue2572() { - var snapshot = TestBlockchain.GetTestSnapshotCache(); - var storages = snapshot.CreateSnapshot(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); + var storages = snapshotCache.CreateSnapshot(); storages.Add ( @@ -174,10 +174,10 @@ public void TestCacheOverrideIssue2572() var item = storages.GetAndChange(new StorageKey() { Key = new byte[] { 0x01, 0x01 }, Id = 0 }); item.Value = new byte[] { 0x06 }; - var res = snapshot.TryGet(new StorageKey() { Key = new byte[] { 0x01, 0x01 }, Id = 0 }); + var res = snapshotCache.TryGet(new StorageKey() { Key = new byte[] { 0x01, 0x01 }, Id = 0 }); Assert.AreEqual("05", res.Value.Span.ToHexString()); storages.Commit(); - res = snapshot.TryGet(new StorageKey() { Key = new byte[] { 0x01, 0x01 }, Id = 0 }); + res = snapshotCache.TryGet(new StorageKey() { Key = new byte[] { 0x01, 0x01 }, Id = 0 }); Assert.AreEqual("06", res.Value.Span.ToHexString()); } } diff --git a/tests/Neo.UnitTests/Ledger/UT_Blockchain.cs b/tests/Neo.UnitTests/Ledger/UT_Blockchain.cs index 1ccfabbe92..9ee5dd6929 100644 --- a/tests/Neo.UnitTests/Ledger/UT_Blockchain.cs +++ b/tests/Neo.UnitTests/Ledger/UT_Blockchain.cs @@ -146,7 +146,7 @@ public void TestMaliciousOnChainConflict() { engine2.LoadScript(onPersistScript); if (engine2.Execute() != VMState.HALT) throw engine2.FaultException; - engine2.Snapshot.Commit(); + engine2.SnapshotCache.Commit(); } snapshot.Commit(); @@ -162,7 +162,7 @@ public void TestMaliciousOnChainConflict() { engine2.LoadScript(postPersistScript); if (engine2.Execute() != VMState.HALT) throw engine2.FaultException; - engine2.Snapshot.Commit(); + engine2.SnapshotCache.Commit(); } snapshot.Commit(); diff --git a/tests/Neo.UnitTests/Ledger/UT_MemoryPool.cs b/tests/Neo.UnitTests/Ledger/UT_MemoryPool.cs index 73cbb37dc9..45cdee05c7 100644 --- a/tests/Neo.UnitTests/Ledger/UT_MemoryPool.cs +++ b/tests/Neo.UnitTests/Ledger/UT_MemoryPool.cs @@ -225,7 +225,7 @@ public async Task BlockPersistAndReverificationWillAbandonTxAsBalanceTransfered( _ = NativeContract.GAS.Mint(engine, UInt160.Zero, 70, true); long txFee = 1; - AddTransactionsWithBalanceVerify(70, txFee, engine.Snapshot); + AddTransactionsWithBalanceVerify(70, txFee, engine.SnapshotCache); _unit.SortedTxCount.Should().Be(70); @@ -244,7 +244,7 @@ public async Task BlockPersistAndReverificationWillAbandonTxAsBalanceTransfered( _ = NativeContract.GAS.Mint(applicationEngine, sender, txFee * 30, true); // Set the balance to meet 30 txs only // Persist block and reverify all the txs in mempool, but half of the txs will be discarded - _unit.UpdatePoolForBlockPersisted(block, applicationEngine.Snapshot); + _unit.UpdatePoolForBlockPersisted(block, applicationEngine.SnapshotCache); _unit.SortedTxCount.Should().Be(30); _unit.UnverifiedSortedTxCount.Should().Be(0); @@ -266,30 +266,30 @@ public async Task UpdatePoolForBlockPersisted_RemoveBlockConflicts() _ = NativeContract.GAS.Mint(engine, UInt160.Zero, 7, true); // balance enough for 7 mempooled txs var mp1 = CreateTransactionWithFeeAndBalanceVerify(txFee); // mp1 doesn't conflict with anyone - _unit.TryAdd(mp1, engine.Snapshot).Should().Be(VerifyResult.Succeed); + _unit.TryAdd(mp1, engine.SnapshotCache).Should().Be(VerifyResult.Succeed); var tx1 = CreateTransactionWithFeeAndBalanceVerify(txFee); // but in-block tx1 conflicts with mempooled mp1 => mp1 should be removed from pool after persist tx1.Attributes = new TransactionAttribute[] { new Conflicts() { Hash = mp1.Hash } }; var mp2 = CreateTransactionWithFeeAndBalanceVerify(txFee); // mp1 and mp2 don't conflict with anyone - _unit.TryAdd(mp2, engine.Snapshot); + _unit.TryAdd(mp2, engine.SnapshotCache); var mp3 = CreateTransactionWithFeeAndBalanceVerify(txFee); - _unit.TryAdd(mp3, engine.Snapshot); + _unit.TryAdd(mp3, engine.SnapshotCache); var tx2 = CreateTransactionWithFeeAndBalanceVerify(txFee); // in-block tx2 conflicts with mempooled mp2 and mp3 => mp2 and mp3 should be removed from pool after persist tx2.Attributes = new TransactionAttribute[] { new Conflicts() { Hash = mp2.Hash }, new Conflicts() { Hash = mp3.Hash } }; var tx3 = CreateTransactionWithFeeAndBalanceVerify(txFee); // in-block tx3 doesn't conflict with anyone var mp4 = CreateTransactionWithFeeAndBalanceVerify(txFee); // mp4 conflicts with in-block tx3 => mp4 should be removed from pool after persist mp4.Attributes = new TransactionAttribute[] { new Conflicts() { Hash = tx3.Hash } }; - _unit.TryAdd(mp4, engine.Snapshot); + _unit.TryAdd(mp4, engine.SnapshotCache); var tx4 = CreateTransactionWithFeeAndBalanceVerify(txFee); // in-block tx4 and tx5 don't conflict with anyone var tx5 = CreateTransactionWithFeeAndBalanceVerify(txFee); var mp5 = CreateTransactionWithFeeAndBalanceVerify(txFee); // mp5 conflicts with in-block tx4 and tx5 => mp5 should be removed from pool after persist mp5.Attributes = new TransactionAttribute[] { new Conflicts() { Hash = tx4.Hash }, new Conflicts() { Hash = tx5.Hash } }; - _unit.TryAdd(mp5, engine.Snapshot); + _unit.TryAdd(mp5, engine.SnapshotCache); var mp6 = CreateTransactionWithFeeAndBalanceVerify(txFee); // mp6 doesn't conflict with anyone and noone conflicts with mp6 => mp6 should be left in the pool after persist - _unit.TryAdd(mp6, engine.Snapshot); + _unit.TryAdd(mp6, engine.SnapshotCache); _unit.SortedTxCount.Should().Be(6); _unit.UnverifiedSortedTxCount.Should().Be(0); @@ -298,7 +298,7 @@ public async Task UpdatePoolForBlockPersisted_RemoveBlockConflicts() var tx6 = CreateTransactionWithFeeAndBalanceVerify(txFee); // in-block tx6 conflicts with mp7, but doesn't include sender of mp7 into signers list => even if tx6 is included into block, mp7 shouldn't be removed from the pool tx6.Signers = new Signer[] { new Signer() { Account = new UInt160(Crypto.Hash160(new byte[] { 1, 2, 3 })) }, new Signer() { Account = new UInt160(Crypto.Hash160(new byte[] { 4, 5, 6 })) } }; tx6.Attributes = new TransactionAttribute[] { new Conflicts() { Hash = mp7.Hash } }; - _unit.TryAdd(mp7, engine.Snapshot); + _unit.TryAdd(mp7, engine.SnapshotCache); // Act: persist block and reverify all mempooled txs. var block = new Block @@ -306,7 +306,7 @@ public async Task UpdatePoolForBlockPersisted_RemoveBlockConflicts() Header = new Header(), Transactions = new Transaction[] { tx1, tx2, tx3, tx4, tx5, tx6 }, }; - _unit.UpdatePoolForBlockPersisted(block, engine.Snapshot); + _unit.UpdatePoolForBlockPersisted(block, engine.SnapshotCache); // Assert: conflicting txs should be removed from the pool; the only mp6 that doesn't conflict with anyone should be left. _unit.SortedTxCount.Should().Be(2); @@ -337,14 +337,14 @@ public async Task TryAdd_AddRangeOfConflictingTransactions() var mp2_1 = CreateTransactionWithFeeAndBalanceVerify(txFee); // mp2_1 conflicts with mp1 and has the same network fee mp2_1.Attributes = new TransactionAttribute[] { new Conflicts() { Hash = mp1.Hash } }; - _unit.TryAdd(mp2_1, engine.Snapshot); + _unit.TryAdd(mp2_1, engine.SnapshotCache); var mp2_2 = CreateTransactionWithFeeAndBalanceVerify(txFee); // mp2_2 also conflicts with mp1 and has the same network fee as mp1 and mp2_1 mp2_2.Attributes = new TransactionAttribute[] { new Conflicts() { Hash = mp1.Hash } }; - _unit.TryAdd(mp2_2, engine.Snapshot); + _unit.TryAdd(mp2_2, engine.SnapshotCache); var mp3 = CreateTransactionWithFeeAndBalanceVerify(2 * txFee); // mp3 conflicts with mp1 and has larger network fee mp3.Attributes = new TransactionAttribute[] { new Conflicts() { Hash = mp1.Hash } }; - _unit.TryAdd(mp3, engine.Snapshot); + _unit.TryAdd(mp3, engine.SnapshotCache); var mp4 = CreateTransactionWithFeeAndBalanceVerify(3 * txFee); // mp4 conflicts with mp3 and has larger network fee mp4.Attributes = new TransactionAttribute[] { new Conflicts() { Hash = mp3.Hash } }; @@ -372,44 +372,44 @@ public async Task TryAdd_AddRangeOfConflictingTransactions() _unit.UnverifiedSortedTxCount.Should().Be(0); // Act & Assert: try to add conlflicting transactions to the pool. - _unit.TryAdd(mp1, engine.Snapshot).Should().Be(VerifyResult.HasConflicts); // mp1 conflicts with mp2_1, mp2_2 and mp3 but has lower network fee than mp3 => mp1 fails to be added + _unit.TryAdd(mp1, engine.SnapshotCache).Should().Be(VerifyResult.HasConflicts); // mp1 conflicts with mp2_1, mp2_2 and mp3 but has lower network fee than mp3 => mp1 fails to be added _unit.SortedTxCount.Should().Be(3); _unit.GetVerifiedTransactions().Should().Contain(new List() { mp2_1, mp2_2, mp3 }); - _unit.TryAdd(malicious, engine.Snapshot).Should().Be(VerifyResult.HasConflicts); // malicious conflicts with mp3, has larger network fee but malicious (different) sender => mp3 shoould be left in pool + _unit.TryAdd(malicious, engine.SnapshotCache).Should().Be(VerifyResult.HasConflicts); // malicious conflicts with mp3, has larger network fee but malicious (different) sender => mp3 shoould be left in pool _unit.SortedTxCount.Should().Be(3); _unit.GetVerifiedTransactions().Should().Contain(new List() { mp2_1, mp2_2, mp3 }); - _unit.TryAdd(mp4, engine.Snapshot).Should().Be(VerifyResult.Succeed); // mp4 conflicts with mp3 and has larger network fee => mp3 shoould be removed from pool + _unit.TryAdd(mp4, engine.SnapshotCache).Should().Be(VerifyResult.Succeed); // mp4 conflicts with mp3 and has larger network fee => mp3 shoould be removed from pool _unit.SortedTxCount.Should().Be(3); _unit.GetVerifiedTransactions().Should().Contain(new List() { mp2_1, mp2_2, mp4 }); - _unit.TryAdd(mp1, engine.Snapshot).Should().Be(VerifyResult.HasConflicts); // mp1 conflicts with mp2_1 and mp2_2 and has same network fee => mp2_1 and mp2_2 should be left in pool. + _unit.TryAdd(mp1, engine.SnapshotCache).Should().Be(VerifyResult.HasConflicts); // mp1 conflicts with mp2_1 and mp2_2 and has same network fee => mp2_1 and mp2_2 should be left in pool. _unit.SortedTxCount.Should().Be(3); _unit.GetVerifiedTransactions().Should().Contain(new List() { mp2_1, mp2_2, mp4 }); - _unit.TryAdd(mp6, engine.Snapshot).Should().Be(VerifyResult.Succeed); // mp6 conflicts with mp2_1 and mp2_2 and has larger network fee than the sum of mp2_1 and mp2_2 fees => mp6 should be added. + _unit.TryAdd(mp6, engine.SnapshotCache).Should().Be(VerifyResult.Succeed); // mp6 conflicts with mp2_1 and mp2_2 and has larger network fee than the sum of mp2_1 and mp2_2 fees => mp6 should be added. _unit.SortedTxCount.Should().Be(2); _unit.GetVerifiedTransactions().Should().Contain(new List() { mp6, mp4 }); - _unit.TryAdd(mp1, engine.Snapshot).Should().Be(VerifyResult.Succeed); // mp1 conflicts with mp2_1 and mp2_2, but they are not in the pool now => mp1 should be added. + _unit.TryAdd(mp1, engine.SnapshotCache).Should().Be(VerifyResult.Succeed); // mp1 conflicts with mp2_1 and mp2_2, but they are not in the pool now => mp1 should be added. _unit.SortedTxCount.Should().Be(3); _unit.GetVerifiedTransactions().Should().Contain(new List() { mp1, mp6, mp4 }); - _unit.TryAdd(mp2_1, engine.Snapshot).Should().Be(VerifyResult.HasConflicts); // mp2_1 conflicts with mp1 and has same network fee => mp2_1 shouldn't be added to the pool. + _unit.TryAdd(mp2_1, engine.SnapshotCache).Should().Be(VerifyResult.HasConflicts); // mp2_1 conflicts with mp1 and has same network fee => mp2_1 shouldn't be added to the pool. _unit.SortedTxCount.Should().Be(3); _unit.GetVerifiedTransactions().Should().Contain(new List() { mp1, mp6, mp4 }); - _unit.TryAdd(mp5, engine.Snapshot).Should().Be(VerifyResult.HasConflicts); // mp5 conflicts with mp4 and has smaller network fee => mp5 fails to be added. + _unit.TryAdd(mp5, engine.SnapshotCache).Should().Be(VerifyResult.HasConflicts); // mp5 conflicts with mp4 and has smaller network fee => mp5 fails to be added. _unit.SortedTxCount.Should().Be(3); _unit.GetVerifiedTransactions().Should().Contain(new List() { mp1, mp6, mp4 }); - _unit.TryAdd(mp8, engine.Snapshot).Should().Be(VerifyResult.Succeed); // mp8, mp9 and mp10malicious conflict with mp7, but mo7 is not in the pool yet. - _unit.TryAdd(mp9, engine.Snapshot).Should().Be(VerifyResult.Succeed); - _unit.TryAdd(mp10malicious, engine.Snapshot).Should().Be(VerifyResult.Succeed); + _unit.TryAdd(mp8, engine.SnapshotCache).Should().Be(VerifyResult.Succeed); // mp8, mp9 and mp10malicious conflict with mp7, but mo7 is not in the pool yet. + _unit.TryAdd(mp9, engine.SnapshotCache).Should().Be(VerifyResult.Succeed); + _unit.TryAdd(mp10malicious, engine.SnapshotCache).Should().Be(VerifyResult.Succeed); _unit.SortedTxCount.Should().Be(6); _unit.GetVerifiedTransactions().Should().Contain(new List() { mp1, mp6, mp4, mp8, mp9, mp10malicious }); - _unit.TryAdd(mp7, engine.Snapshot).Should().Be(VerifyResult.Succeed); // mp7 has larger network fee than the sum of mp8 and mp9 fees => should be added to the pool. + _unit.TryAdd(mp7, engine.SnapshotCache).Should().Be(VerifyResult.Succeed); // mp7 has larger network fee than the sum of mp8 and mp9 fees => should be added to the pool. _unit.SortedTxCount.Should().Be(4); _unit.GetVerifiedTransactions().Should().Contain(new List() { mp1, mp6, mp4, mp7 }); @@ -436,18 +436,18 @@ public async Task TryRemoveVerified_RemoveVerifiedTxWithConflicts() var mp2 = CreateTransactionWithFeeAndBalanceVerify(2 * txFee); // mp2 conflicts with mp1 and has larger same network fee mp2.Attributes = new TransactionAttribute[] { new Conflicts() { Hash = mp1.Hash } }; - _unit.TryAdd(mp2, engine.Snapshot); + _unit.TryAdd(mp2, engine.SnapshotCache); _unit.SortedTxCount.Should().Be(1); _unit.UnverifiedSortedTxCount.Should().Be(0); - _unit.TryAdd(mp1, engine.Snapshot).Should().Be(VerifyResult.HasConflicts); // mp1 conflicts with mp2 but has lower network fee + _unit.TryAdd(mp1, engine.SnapshotCache).Should().Be(VerifyResult.HasConflicts); // mp1 conflicts with mp2 but has lower network fee _unit.SortedTxCount.Should().Be(1); _unit.GetVerifiedTransactions().Should().Contain(new List() { mp2 }); // Act & Assert: try to invalidate verified transactions and push conflicting one. _unit.InvalidateVerifiedTransactions(); - _unit.TryAdd(mp1, engine.Snapshot).Should().Be(VerifyResult.Succeed); // mp1 conflicts with mp2 but mp2 is not verified anymore + _unit.TryAdd(mp1, engine.SnapshotCache).Should().Be(VerifyResult.Succeed); // mp1 conflicts with mp2 but mp2 is not verified anymore _unit.SortedTxCount.Should().Be(1); _unit.GetVerifiedTransactions().Should().Contain(new List() { mp1 }); @@ -457,7 +457,7 @@ public async Task TryRemoveVerified_RemoveVerifiedTxWithConflicts() Header = new Header(), Transactions = new Transaction[] { tx1 }, }; - _unit.UpdatePoolForBlockPersisted(block, engine.Snapshot); + _unit.UpdatePoolForBlockPersisted(block, engine.SnapshotCache); _unit.SortedTxCount.Should().Be(1); _unit.GetVerifiedTransactions().Should().Contain(new List() { mp2 }); // after reverificaion mp2 should be back at verified list; mp1 should be completely kicked off } diff --git a/tests/Neo.UnitTests/Ledger/UT_TransactionVerificationContext.cs b/tests/Neo.UnitTests/Ledger/UT_TransactionVerificationContext.cs index 7805da64b1..57cf996acd 100644 --- a/tests/Neo.UnitTests/Ledger/UT_TransactionVerificationContext.cs +++ b/tests/Neo.UnitTests/Ledger/UT_TransactionVerificationContext.cs @@ -61,10 +61,10 @@ private Transaction CreateTransactionWithFee(long networkFee, long systemFee) public async Task TestDuplicateOracle() { // Fake balance - var snapshot = TestBlockchain.GetTestSnapshotCache(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); - ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, settings: TestBlockchain.TheNeoSystem.Settings, gas: long.MaxValue); - BigInteger balance = NativeContract.GAS.BalanceOf(snapshot, UInt160.Zero); + ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Application, null, snapshotCache, settings: TestBlockchain.TheNeoSystem.Settings, gas: long.MaxValue); + BigInteger balance = NativeContract.GAS.BalanceOf(snapshotCache, UInt160.Zero); await NativeContract.GAS.Burn(engine, UInt160.Zero, balance); _ = NativeContract.GAS.Mint(engine, UInt160.Zero, 8, false); @@ -73,43 +73,43 @@ public async Task TestDuplicateOracle() var tx = CreateTransactionWithFee(1, 2); tx.Attributes = new TransactionAttribute[] { new OracleResponse() { Code = OracleResponseCode.ConsensusUnreachable, Id = 1, Result = Array.Empty() } }; var conflicts = new List(); - verificationContext.CheckTransaction(tx, conflicts, snapshot).Should().BeTrue(); + verificationContext.CheckTransaction(tx, conflicts, snapshotCache).Should().BeTrue(); verificationContext.AddTransaction(tx); tx = CreateTransactionWithFee(2, 1); tx.Attributes = new TransactionAttribute[] { new OracleResponse() { Code = OracleResponseCode.ConsensusUnreachable, Id = 1, Result = Array.Empty() } }; - verificationContext.CheckTransaction(tx, conflicts, snapshot).Should().BeFalse(); + verificationContext.CheckTransaction(tx, conflicts, snapshotCache).Should().BeFalse(); } [TestMethod] public async Task TestTransactionSenderFee() { - var snapshot = TestBlockchain.GetTestSnapshotCache(); - ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, settings: TestBlockchain.TheNeoSystem.Settings, gas: long.MaxValue); - BigInteger balance = NativeContract.GAS.BalanceOf(snapshot, UInt160.Zero); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); + ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Application, null, snapshotCache, settings: TestBlockchain.TheNeoSystem.Settings, gas: long.MaxValue); + BigInteger balance = NativeContract.GAS.BalanceOf(snapshotCache, UInt160.Zero); await NativeContract.GAS.Burn(engine, UInt160.Zero, balance); _ = NativeContract.GAS.Mint(engine, UInt160.Zero, 8, true); TransactionVerificationContext verificationContext = new(); var tx = CreateTransactionWithFee(1, 2); var conflicts = new List(); - verificationContext.CheckTransaction(tx, conflicts, snapshot).Should().BeTrue(); + verificationContext.CheckTransaction(tx, conflicts, snapshotCache).Should().BeTrue(); verificationContext.AddTransaction(tx); - verificationContext.CheckTransaction(tx, conflicts, snapshot).Should().BeTrue(); + verificationContext.CheckTransaction(tx, conflicts, snapshotCache).Should().BeTrue(); verificationContext.AddTransaction(tx); - verificationContext.CheckTransaction(tx, conflicts, snapshot).Should().BeFalse(); + verificationContext.CheckTransaction(tx, conflicts, snapshotCache).Should().BeFalse(); verificationContext.RemoveTransaction(tx); - verificationContext.CheckTransaction(tx, conflicts, snapshot).Should().BeTrue(); + verificationContext.CheckTransaction(tx, conflicts, snapshotCache).Should().BeTrue(); verificationContext.AddTransaction(tx); - verificationContext.CheckTransaction(tx, conflicts, snapshot).Should().BeFalse(); + verificationContext.CheckTransaction(tx, conflicts, snapshotCache).Should().BeFalse(); } [TestMethod] public async Task TestTransactionSenderFeeWithConflicts() { - var snapshot = TestBlockchain.GetTestSnapshotCache(); - ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, settings: TestBlockchain.TheNeoSystem.Settings, gas: long.MaxValue); - BigInteger balance = NativeContract.GAS.BalanceOf(snapshot, UInt160.Zero); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); + ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Application, null, snapshotCache, settings: TestBlockchain.TheNeoSystem.Settings, gas: long.MaxValue); + BigInteger balance = NativeContract.GAS.BalanceOf(snapshotCache, UInt160.Zero); await NativeContract.GAS.Burn(engine, UInt160.Zero, balance); _ = NativeContract.GAS.Mint(engine, UInt160.Zero, 3 + 3 + 1, true); // balance is enough for 2 transactions and 1 GAS is left. @@ -118,14 +118,14 @@ public async Task TestTransactionSenderFeeWithConflicts() var conflictingTx = CreateTransactionWithFee(1, 1); // costs 2 GAS var conflicts = new List(); - verificationContext.CheckTransaction(tx, conflicts, snapshot).Should().BeTrue(); + verificationContext.CheckTransaction(tx, conflicts, snapshotCache).Should().BeTrue(); verificationContext.AddTransaction(tx); - verificationContext.CheckTransaction(tx, conflicts, snapshot).Should().BeTrue(); + verificationContext.CheckTransaction(tx, conflicts, snapshotCache).Should().BeTrue(); verificationContext.AddTransaction(tx); - verificationContext.CheckTransaction(tx, conflicts, snapshot).Should().BeFalse(); + verificationContext.CheckTransaction(tx, conflicts, snapshotCache).Should().BeFalse(); conflicts.Add(conflictingTx); - verificationContext.CheckTransaction(tx, conflicts, snapshot).Should().BeTrue(); // 1 GAS is left on the balance + 2 GAS is free after conflicts removal => enough for one more trasnaction. + verificationContext.CheckTransaction(tx, conflicts, snapshotCache).Should().BeTrue(); // 1 GAS is left on the balance + 2 GAS is free after conflicts removal => enough for one more trasnaction. } } } diff --git a/tests/Neo.UnitTests/Ledger/UT_TrimmedBlock.cs b/tests/Neo.UnitTests/Ledger/UT_TrimmedBlock.cs index 12b56048c8..e65bfba843 100644 --- a/tests/Neo.UnitTests/Ledger/UT_TrimmedBlock.cs +++ b/tests/Neo.UnitTests/Ledger/UT_TrimmedBlock.cs @@ -48,7 +48,7 @@ public static TrimmedBlock GetTrimmedBlockWithNoTransaction() [TestMethod] public void TestGetBlock() { - var snapshot = TestBlockchain.GetTestSnapshotCache(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); var tx1 = TestUtils.GetTransaction(UInt160.Zero); tx1.Script = new byte[] { 0x01,0x01,0x01,0x01, 0x01,0x01,0x01,0x01, @@ -69,13 +69,13 @@ public void TestGetBlock() Transaction = tx2, BlockIndex = 1 }; - TestUtils.TransactionAdd(snapshot, state1, state2); + TestUtils.TransactionAdd(snapshotCache, state1, state2); TrimmedBlock tblock = GetTrimmedBlockWithNoTransaction(); tblock.Hashes = new UInt256[] { tx1.Hash, tx2.Hash }; - TestUtils.BlocksAdd(snapshot, tblock.Hash, tblock); + TestUtils.BlocksAdd(snapshotCache, tblock.Hash, tblock); - Block block = NativeContract.Ledger.GetBlock(snapshot, tblock.Hash); + Block block = NativeContract.Ledger.GetBlock(snapshotCache, tblock.Hash); block.Index.Should().Be(1); block.MerkleRoot.Should().Be(UInt256.Parse("0xa400ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff02")); diff --git a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Block.cs b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Block.cs index 4a7b0262f6..1c31e3483c 100644 --- a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Block.cs +++ b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Block.cs @@ -27,9 +27,9 @@ public class UT_Block private static ApplicationEngine GetEngine(bool hasContainer = false, bool hasSnapshot = false, bool hasBlock = false, bool addScript = true, long gas = 20_00000000) { var tx = hasContainer ? TestUtils.GetTransaction(UInt160.Zero) : null; - var snapshot = hasSnapshot ? TestBlockchain.GetTestSnapshotCache() : null; + var snapshotCache = hasSnapshot ? TestBlockchain.GetTestSnapshotCache() : null; var block = hasBlock ? new Block { Header = new Header() } : null; - var engine = ApplicationEngine.Create(TriggerType.Application, tx, snapshot, block, TestBlockchain.TheNeoSystem.Settings, gas: gas); + var engine = ApplicationEngine.Create(TriggerType.Application, tx, snapshotCache, block, TestBlockchain.TheNeoSystem.Settings, gas: gas); if (addScript) engine.LoadScript(new byte[] { 0x01 }); return engine; } @@ -155,7 +155,7 @@ public void Equals_SameObj() [TestMethod] public void TestGetHashCode() { - var snapshot = GetEngine(true, true).Snapshot; + var snapshot = GetEngine(true, true).SnapshotCache; NativeContract.Ledger.GetBlock(snapshot, 0).GetHashCode().Should().Be(-626492395); } diff --git a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Conflicts.cs b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Conflicts.cs index b024fed808..a0dac53fbe 100644 --- a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Conflicts.cs +++ b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Conflicts.cs @@ -73,28 +73,28 @@ public void DeserializeAndSerialize() public void Verify() { var test = new Conflicts() { Hash = _u }; - var snapshot = TestBlockchain.GetTestSnapshotCache(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); var key = Ledger.UT_MemoryPool.CreateStorageKey(NativeContract.Ledger.Id, Prefix_Transaction, _u.ToArray()); // Conflicting transaction is in the Conflicts attribute of some other on-chain transaction. var conflict = new TransactionState(); - snapshot.Add(key, new StorageItem(conflict)); - Assert.IsTrue(test.Verify(snapshot, new Transaction())); + snapshotCache.Add(key, new StorageItem(conflict)); + Assert.IsTrue(test.Verify(snapshotCache, new Transaction())); // Conflicting transaction is on-chain. - snapshot.Delete(key); + snapshotCache.Delete(key); conflict = new TransactionState { BlockIndex = 123, Transaction = new Transaction(), State = VMState.NONE }; - snapshot.Add(key, new StorageItem(conflict)); - Assert.IsFalse(test.Verify(snapshot, new Transaction())); + snapshotCache.Add(key, new StorageItem(conflict)); + Assert.IsFalse(test.Verify(snapshotCache, new Transaction())); // There's no conflicting transaction at all. - snapshot.Delete(key); - Assert.IsTrue(test.Verify(snapshot, new Transaction())); + snapshotCache.Delete(key); + Assert.IsTrue(test.Verify(snapshotCache, new Transaction())); } } } diff --git a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Header.cs b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Header.cs index 0b32ffd656..0291b6f7c6 100644 --- a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Header.cs +++ b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Header.cs @@ -52,11 +52,11 @@ public void GetHashCodeTest() public void TrimTest() { UInt256 val256 = UInt256.Zero; - var snapshot = TestBlockchain.GetTestSnapshotCache().CreateSnapshot(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache().CreateSnapshot(); TestUtils.SetupHeaderWithValues(null, uut, val256, out _, out _, out _, out _, out _, out _); uut.Witness = new Witness() { InvocationScript = Array.Empty(), VerificationScript = Array.Empty() }; - TestUtils.BlocksAdd(snapshot, uut.Hash, new TrimmedBlock() + TestUtils.BlocksAdd(snapshotCache, uut.Hash, new TrimmedBlock() { Header = new Header { @@ -69,7 +69,7 @@ public void TrimTest() Hashes = Array.Empty() }); - var trim = NativeContract.Ledger.GetTrimmedBlock(snapshot, uut.Hash); + var trim = NativeContract.Ledger.GetTrimmedBlock(snapshotCache, uut.Hash); var header = trim.Header; header.Version.Should().Be(uut.Version); diff --git a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_HighPriorityAttribute.cs b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_HighPriorityAttribute.cs index e5222e33de..09454d298f 100644 --- a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_HighPriorityAttribute.cs +++ b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_HighPriorityAttribute.cs @@ -74,11 +74,11 @@ public void DeserializeAndSerialize() public void Verify() { var test = new HighPriorityAttribute(); - var snapshot = TestBlockchain.GetTestSnapshotCache(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); - Assert.IsFalse(test.Verify(snapshot, new Transaction() { Signers = Array.Empty() })); - Assert.IsFalse(test.Verify(snapshot, new Transaction() { Signers = new Signer[] { new Signer() { Account = UInt160.Parse("0xa400ff00ff00ff00ff00ff00ff00ff00ff00ff01") } } })); - Assert.IsTrue(test.Verify(snapshot, new Transaction() { Signers = new Signer[] { new Signer() { Account = NativeContract.NEO.GetCommitteeAddress(snapshot) } } })); + Assert.IsFalse(test.Verify(snapshotCache, new Transaction() { Signers = Array.Empty() })); + Assert.IsFalse(test.Verify(snapshotCache, new Transaction() { Signers = new Signer[] { new Signer() { Account = UInt160.Parse("0xa400ff00ff00ff00ff00ff00ff00ff00ff00ff01") } } })); + Assert.IsTrue(test.Verify(snapshotCache, new Transaction() { Signers = new Signer[] { new Signer() { Account = NativeContract.NEO.GetCommitteeAddress(snapshotCache) } } })); } } } diff --git a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_NotValidBefore.cs b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_NotValidBefore.cs index e44d4f3636..bff21a4e5e 100644 --- a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_NotValidBefore.cs +++ b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_NotValidBefore.cs @@ -77,12 +77,12 @@ public void DeserializeAndSerialize() public void Verify() { var test = new NotValidBefore(); - var snapshot = TestBlockchain.GetTestSnapshotCache(); - test.Height = NativeContract.Ledger.CurrentIndex(snapshot) + 1; + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); + test.Height = NativeContract.Ledger.CurrentIndex(snapshotCache) + 1; - Assert.IsFalse(test.Verify(snapshot, new Transaction())); + Assert.IsFalse(test.Verify(snapshotCache, new Transaction())); test.Height--; - Assert.IsTrue(test.Verify(snapshot, new Transaction())); + Assert.IsTrue(test.Verify(snapshotCache, new Transaction())); } } } diff --git a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs index 1739f1b830..a483ecf0d6 100644 --- a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs +++ b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs @@ -11,7 +11,6 @@ using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; -using Neo.Cryptography.ECC; using Neo.IO; using Neo.Json; using Neo.Ledger; @@ -122,7 +121,7 @@ public void FeeIsMultiSigContract() { var walletA = TestUtils.GenerateTestWallet("123"); var walletB = TestUtils.GenerateTestWallet("123"); - var snapshot = TestBlockchain.GetTestSnapshotCache(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); var a = walletA.CreateAccount(); var b = walletB.CreateAccount(); @@ -139,15 +138,15 @@ public void FeeIsMultiSigContract() // Fake balance var key = NativeContract.GAS.CreateStorageKey(20, acc.ScriptHash); - var entry = snapshot.GetAndChange(key, () => new StorageItem(new AccountState())); + var entry = snapshotCache.GetAndChange(key, () => new StorageItem(new AccountState())); entry.GetInteroperable().Balance = 10000 * NativeContract.GAS.Factor; - snapshot.Commit(); + snapshotCache.Commit(); // Make transaction - var tx = walletA.MakeTransaction(snapshot, [ + var tx = walletA.MakeTransaction(snapshotCache, [ new TransferOutput { AssetId = NativeContract.GAS.Hash, @@ -160,10 +159,10 @@ public void FeeIsMultiSigContract() // Sign - var wrongData = new ContractParametersContext(snapshot, tx, TestProtocolSettings.Default.Network + 1); + var wrongData = new ContractParametersContext(snapshotCache, tx, TestProtocolSettings.Default.Network + 1); Assert.IsFalse(walletA.Sign(wrongData)); - var data = new ContractParametersContext(snapshot, tx, TestProtocolSettings.Default.Network); + var data = new ContractParametersContext(snapshotCache, tx, TestProtocolSettings.Default.Network); Assert.IsTrue(walletA.Sign(data)); Assert.IsTrue(walletB.Sign(data)); Assert.IsTrue(data.Completed); @@ -172,14 +171,14 @@ public void FeeIsMultiSigContract() // Fast check - Assert.IsTrue(tx.VerifyWitnesses(TestProtocolSettings.Default, snapshot, tx.NetworkFee)); + Assert.IsTrue(tx.VerifyWitnesses(TestProtocolSettings.Default, snapshotCache, tx.NetworkFee)); // Check long verificationGas = 0; foreach (var witness in tx.Witnesses) { - using ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Verification, tx, snapshot, settings: TestBlockchain.TheNeoSystem.Settings, gas: tx.NetworkFee); + using ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Verification, tx, snapshotCache, settings: TestBlockchain.TheNeoSystem.Settings, gas: tx.NetworkFee); engine.LoadScript(witness.VerificationScript); engine.LoadScript(witness.InvocationScript); Assert.AreEqual(VMState.HALT, engine.Execute()); @@ -188,7 +187,7 @@ public void FeeIsMultiSigContract() verificationGas += engine.FeeConsumed; } - var sizeGas = tx.Size * NativeContract.Policy.GetFeePerByte(snapshot); + var sizeGas = tx.Size * NativeContract.Policy.GetFeePerByte(snapshotCache); Assert.AreEqual(1967100, verificationGas); Assert.AreEqual(348000, sizeGas); Assert.AreEqual(2315100, tx.NetworkFee); @@ -198,23 +197,23 @@ public void FeeIsMultiSigContract() public void FeeIsSignatureContractDetailed() { var wallet = TestUtils.GenerateTestWallet("123"); - var snapshot = TestBlockchain.GetTestSnapshotCache(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); var acc = wallet.CreateAccount(); // Fake balance var key = NativeContract.GAS.CreateStorageKey(20, acc.ScriptHash); - var entry = snapshot.GetAndChange(key, () => new StorageItem(new AccountState())); + var entry = snapshotCache.GetAndChange(key, () => new StorageItem(new AccountState())); entry.GetInteroperable().Balance = 10000 * NativeContract.GAS.Factor; - snapshot.Commit(); + snapshotCache.Commit(); // Make transaction // self-transfer of 1e-8 GAS - var tx = wallet.MakeTransaction(snapshot, [ + var tx = wallet.MakeTransaction(snapshotCache, [ new TransferOutput { AssetId = NativeContract.GAS.Hash, @@ -233,7 +232,7 @@ public void FeeIsSignatureContractDetailed() // Sign // ---- - var data = new ContractParametersContext(snapshot, tx, TestProtocolSettings.Default.Network); + var data = new ContractParametersContext(snapshotCache, tx, TestProtocolSettings.Default.Network); // 'from' is always required as witness // if not included on cosigner with a scope, its scope should be considered 'CalledByEntry' data.ScriptHashes.Count.Should().Be(1); @@ -247,14 +246,14 @@ public void FeeIsSignatureContractDetailed() // Fast check - Assert.IsTrue(tx.VerifyWitnesses(TestProtocolSettings.Default, snapshot, tx.NetworkFee)); + Assert.IsTrue(tx.VerifyWitnesses(TestProtocolSettings.Default, snapshotCache, tx.NetworkFee)); // Check long verificationGas = 0; foreach (var witness in tx.Witnesses) { - using var engine = ApplicationEngine.Create(TriggerType.Verification, tx, snapshot, settings: TestBlockchain.TheNeoSystem.Settings, gas: tx.NetworkFee); + using var engine = ApplicationEngine.Create(TriggerType.Verification, tx, snapshotCache, settings: TestBlockchain.TheNeoSystem.Settings, gas: tx.NetworkFee); engine.LoadScript(witness.VerificationScript); engine.LoadScript(witness.InvocationScript); Assert.AreEqual(VMState.HALT, engine.Execute()); @@ -285,8 +284,8 @@ public void FeeIsSignatureContractDetailed() // I + II + III + IV Assert.AreEqual(25 + 22 + 1 + 88 + 109, tx.Size); - Assert.AreEqual(1000, NativeContract.Policy.GetFeePerByte(snapshot)); - var sizeGas = tx.Size * NativeContract.Policy.GetFeePerByte(snapshot); + Assert.AreEqual(1000, NativeContract.Policy.GetFeePerByte(snapshotCache)); + var sizeGas = tx.Size * NativeContract.Policy.GetFeePerByte(snapshotCache); // final check: verification_cost and tx_size Assert.AreEqual(245000, sizeGas); @@ -300,18 +299,18 @@ public void FeeIsSignatureContractDetailed() public void FeeIsSignatureContract_TestScope_Global() { var wallet = TestUtils.GenerateTestWallet(""); - var snapshot = TestBlockchain.GetTestSnapshotCache(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); var acc = wallet.CreateAccount(); // Fake balance var key = NativeContract.GAS.CreateStorageKey(20, acc.ScriptHash); - var entry = snapshot.GetAndChange(key, () => new StorageItem(new AccountState())); + var entry = snapshotCache.GetAndChange(key, () => new StorageItem(new AccountState())); entry.GetInteroperable().Balance = 10000 * NativeContract.GAS.Factor; - snapshot.Commit(); + snapshotCache.Commit(); // Make transaction // Manually creating script @@ -335,7 +334,7 @@ public void FeeIsSignatureContract_TestScope_Global() // using this... - var tx = wallet.MakeTransaction(snapshot, script, acc.ScriptHash, signers); + var tx = wallet.MakeTransaction(snapshotCache, script, acc.ScriptHash, signers); Assert.IsNotNull(tx); Assert.IsNull(tx.Witnesses); @@ -344,7 +343,7 @@ public void FeeIsSignatureContract_TestScope_Global() // Sign // ---- - var data = new ContractParametersContext(snapshot, tx, TestProtocolSettings.Default.Network); + var data = new ContractParametersContext(snapshotCache, tx, TestProtocolSettings.Default.Network); bool signed = wallet.Sign(data); Assert.IsTrue(signed); @@ -353,13 +352,13 @@ public void FeeIsSignatureContract_TestScope_Global() tx.Witnesses.Length.Should().Be(1); // Fast check - Assert.IsTrue(tx.VerifyWitnesses(TestProtocolSettings.Default, snapshot, tx.NetworkFee)); + Assert.IsTrue(tx.VerifyWitnesses(TestProtocolSettings.Default, snapshotCache, tx.NetworkFee)); // Check long verificationGas = 0; foreach (var witness in tx.Witnesses) { - using ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Verification, tx, snapshot, settings: TestBlockchain.TheNeoSystem.Settings, gas: tx.NetworkFee); + using ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Verification, tx, snapshotCache, settings: TestBlockchain.TheNeoSystem.Settings, gas: tx.NetworkFee); engine.LoadScript(witness.VerificationScript); engine.LoadScript(witness.InvocationScript); Assert.AreEqual(VMState.HALT, engine.Execute()); @@ -368,7 +367,7 @@ public void FeeIsSignatureContract_TestScope_Global() verificationGas += engine.FeeConsumed; } // get sizeGas - var sizeGas = tx.Size * NativeContract.Policy.GetFeePerByte(snapshot); + var sizeGas = tx.Size * NativeContract.Policy.GetFeePerByte(snapshotCache); // final check on sum: verification_cost + tx_size Assert.AreEqual(1228520, verificationGas + sizeGas); // final assert @@ -379,18 +378,18 @@ public void FeeIsSignatureContract_TestScope_Global() public void FeeIsSignatureContract_TestScope_CurrentHash_GAS() { var wallet = TestUtils.GenerateTestWallet(""); - var snapshot = TestBlockchain.GetTestSnapshotCache(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); var acc = wallet.CreateAccount(); // Fake balance var key = NativeContract.GAS.CreateStorageKey(20, acc.ScriptHash); - var entry = snapshot.GetAndChange(key, () => new StorageItem(new AccountState())); + var entry = snapshotCache.GetAndChange(key, () => new StorageItem(new AccountState())); entry.GetInteroperable().Balance = 10000 * NativeContract.GAS.Factor; - snapshot.Commit(); + snapshotCache.Commit(); // Make transaction // Manually creating script @@ -415,7 +414,7 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_GAS() // using this... - var tx = wallet.MakeTransaction(snapshot, script, acc.ScriptHash, signers); + var tx = wallet.MakeTransaction(snapshotCache, script, acc.ScriptHash, signers); Assert.IsNotNull(tx); Assert.IsNull(tx.Witnesses); @@ -424,7 +423,7 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_GAS() // Sign // ---- - var data = new ContractParametersContext(snapshot, tx, TestProtocolSettings.Default.Network); + var data = new ContractParametersContext(snapshotCache, tx, TestProtocolSettings.Default.Network); bool signed = wallet.Sign(data); Assert.IsTrue(signed); @@ -433,13 +432,13 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_GAS() tx.Witnesses.Length.Should().Be(1); // Fast check - Assert.IsTrue(tx.VerifyWitnesses(TestProtocolSettings.Default, snapshot, tx.NetworkFee)); + Assert.IsTrue(tx.VerifyWitnesses(TestProtocolSettings.Default, snapshotCache, tx.NetworkFee)); // Check long verificationGas = 0; foreach (var witness in tx.Witnesses) { - using ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Verification, tx, snapshot, settings: TestBlockchain.TheNeoSystem.Settings, gas: tx.NetworkFee); + using ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Verification, tx, snapshotCache, settings: TestBlockchain.TheNeoSystem.Settings, gas: tx.NetworkFee); engine.LoadScript(witness.VerificationScript); engine.LoadScript(witness.InvocationScript); Assert.AreEqual(VMState.HALT, engine.Execute()); @@ -448,7 +447,7 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_GAS() verificationGas += engine.FeeConsumed; } // get sizeGas - var sizeGas = tx.Size * NativeContract.Policy.GetFeePerByte(snapshot); + var sizeGas = tx.Size * NativeContract.Policy.GetFeePerByte(snapshotCache); // final check on sum: verification_cost + tx_size Assert.AreEqual(1249520, verificationGas + sizeGas); // final assert @@ -459,18 +458,18 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_GAS() public void FeeIsSignatureContract_TestScope_CalledByEntry_Plus_GAS() { var wallet = TestUtils.GenerateTestWallet(""); - var snapshot = TestBlockchain.GetTestSnapshotCache(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); var acc = wallet.CreateAccount(); // Fake balance var key = NativeContract.GAS.CreateStorageKey(20, acc.ScriptHash); - var entry = snapshot.GetAndChange(key, () => new StorageItem(new AccountState())); + var entry = snapshotCache.GetAndChange(key, () => new StorageItem(new AccountState())); entry.GetInteroperable().Balance = 10000 * NativeContract.GAS.Factor; - snapshot.Commit(); + snapshotCache.Commit(); // Make transaction // Manually creating script @@ -498,7 +497,7 @@ public void FeeIsSignatureContract_TestScope_CalledByEntry_Plus_GAS() // using this... - var tx = wallet.MakeTransaction(snapshot, script, acc.ScriptHash, signers); + var tx = wallet.MakeTransaction(snapshotCache, script, acc.ScriptHash, signers); Assert.IsNotNull(tx); Assert.IsNull(tx.Witnesses); @@ -507,7 +506,7 @@ public void FeeIsSignatureContract_TestScope_CalledByEntry_Plus_GAS() // Sign // ---- - var data = new ContractParametersContext(snapshot, tx, TestProtocolSettings.Default.Network); + var data = new ContractParametersContext(snapshotCache, tx, TestProtocolSettings.Default.Network); bool signed = wallet.Sign(data); Assert.IsTrue(signed); @@ -516,13 +515,13 @@ public void FeeIsSignatureContract_TestScope_CalledByEntry_Plus_GAS() tx.Witnesses.Length.Should().Be(1); // Fast check - Assert.IsTrue(tx.VerifyWitnesses(TestProtocolSettings.Default, snapshot, tx.NetworkFee)); + Assert.IsTrue(tx.VerifyWitnesses(TestProtocolSettings.Default, snapshotCache, tx.NetworkFee)); // Check long verificationGas = 0; foreach (var witness in tx.Witnesses) { - using ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Verification, tx, snapshot, settings: TestBlockchain.TheNeoSystem.Settings, gas: tx.NetworkFee); + using ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Verification, tx, snapshotCache, settings: TestBlockchain.TheNeoSystem.Settings, gas: tx.NetworkFee); engine.LoadScript(witness.VerificationScript); engine.LoadScript(witness.InvocationScript); Assert.AreEqual(VMState.HALT, engine.Execute()); @@ -531,7 +530,7 @@ public void FeeIsSignatureContract_TestScope_CalledByEntry_Plus_GAS() verificationGas += engine.FeeConsumed; } // get sizeGas - var sizeGas = tx.Size * NativeContract.Policy.GetFeePerByte(snapshot); + var sizeGas = tx.Size * NativeContract.Policy.GetFeePerByte(snapshotCache); // final check on sum: verification_cost + tx_size Assert.AreEqual(1249520, verificationGas + sizeGas); // final assert @@ -542,14 +541,14 @@ public void FeeIsSignatureContract_TestScope_CalledByEntry_Plus_GAS() public void FeeIsSignatureContract_TestScope_CurrentHash_NEO_FAULT() { var wallet = TestUtils.GenerateTestWallet(""); - var snapshot = TestBlockchain.GetTestSnapshotCache(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); var acc = wallet.CreateAccount(); // Fake balance var key = NativeContract.GAS.CreateStorageKey(20, acc.ScriptHash); - var entry = snapshot.GetAndChange(key, () => new StorageItem(new AccountState())); + var entry = snapshotCache.GetAndChange(key, () => new StorageItem(new AccountState())); entry.GetInteroperable().Balance = 10000 * NativeContract.GAS.Factor; @@ -579,7 +578,7 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_NEO_FAULT() // expects FAULT on execution of 'transfer' Application script // due to lack of a valid witness validation Transaction tx = null; - Assert.ThrowsException(() => tx = wallet.MakeTransaction(snapshot, script, acc.ScriptHash, signers)); + Assert.ThrowsException(() => tx = wallet.MakeTransaction(snapshotCache, script, acc.ScriptHash, signers)); Assert.IsNull(tx); } @@ -587,18 +586,18 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_NEO_FAULT() public void FeeIsSignatureContract_TestScope_CurrentHash_NEO_GAS() { var wallet = TestUtils.GenerateTestWallet(""); - var snapshot = TestBlockchain.GetTestSnapshotCache(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); var acc = wallet.CreateAccount(); // Fake balance var key = NativeContract.GAS.CreateStorageKey(20, acc.ScriptHash); - var entry = snapshot.GetAndChange(key, () => new StorageItem(new AccountState())); + var entry = snapshotCache.GetAndChange(key, () => new StorageItem(new AccountState())); entry.GetInteroperable().Balance = 10000 * NativeContract.GAS.Factor; - snapshot.Commit(); + snapshotCache.Commit(); // Make transaction // Manually creating script @@ -623,7 +622,7 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_NEO_GAS() // using this... - var tx = wallet.MakeTransaction(snapshot, script, acc.ScriptHash, signers); + var tx = wallet.MakeTransaction(snapshotCache, script, acc.ScriptHash, signers); Assert.IsNotNull(tx); Assert.IsNull(tx.Witnesses); @@ -632,7 +631,7 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_NEO_GAS() // Sign // ---- - var data = new ContractParametersContext(snapshot, tx, TestProtocolSettings.Default.Network); + var data = new ContractParametersContext(snapshotCache, tx, TestProtocolSettings.Default.Network); bool signed = wallet.Sign(data); Assert.IsTrue(signed); @@ -646,13 +645,13 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_NEO_GAS() tx.Signers.Length.Should().Be(1); // Fast check - Assert.IsTrue(tx.VerifyWitnesses(TestProtocolSettings.Default, snapshot, tx.NetworkFee)); + Assert.IsTrue(tx.VerifyWitnesses(TestProtocolSettings.Default, snapshotCache, tx.NetworkFee)); // Check long verificationGas = 0; foreach (var witness in tx.Witnesses) { - using ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Verification, tx, snapshot, settings: TestBlockchain.TheNeoSystem.Settings, gas: tx.NetworkFee); + using ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Verification, tx, snapshotCache, settings: TestBlockchain.TheNeoSystem.Settings, gas: tx.NetworkFee); engine.LoadScript(witness.VerificationScript); engine.LoadScript(witness.InvocationScript); Assert.AreEqual(VMState.HALT, engine.Execute()); @@ -661,7 +660,7 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_NEO_GAS() verificationGas += engine.FeeConsumed; } // get sizeGas - var sizeGas = tx.Size * NativeContract.Policy.GetFeePerByte(snapshot); + var sizeGas = tx.Size * NativeContract.Policy.GetFeePerByte(snapshotCache); // final check on sum: verification_cost + tx_size Assert.AreEqual(1269520, verificationGas + sizeGas); // final assert @@ -672,14 +671,14 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_NEO_GAS() public void FeeIsSignatureContract_TestScope_NoScopeFAULT() { var wallet = TestUtils.GenerateTestWallet(""); - var snapshot = TestBlockchain.GetTestSnapshotCache(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); var acc = wallet.CreateAccount(); // Fake balance var key = NativeContract.GAS.CreateStorageKey(20, acc.ScriptHash); - var entry = snapshot.GetAndChange(key, () => new StorageItem(new AccountState())); + var entry = snapshotCache.GetAndChange(key, () => new StorageItem(new AccountState())); entry.GetInteroperable().Balance = 10000 * NativeContract.GAS.Factor; @@ -710,7 +709,7 @@ public void FeeIsSignatureContract_TestScope_NoScopeFAULT() // expects FAULT on execution of 'transfer' Application script // due to lack of a valid witness validation Transaction tx = null; - Assert.ThrowsException(() => tx = wallet.MakeTransaction(snapshot, script, acc.ScriptHash, signers, attributes)); + Assert.ThrowsException(() => tx = wallet.MakeTransaction(snapshotCache, script, acc.ScriptHash, signers, attributes)); Assert.IsNull(tx); } @@ -718,18 +717,18 @@ public void FeeIsSignatureContract_TestScope_NoScopeFAULT() public void FeeIsSignatureContract_UnexistingVerificationContractFAULT() { var wallet = TestUtils.GenerateTestWallet(""); - var snapshot = TestBlockchain.GetTestSnapshotCache(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); var acc = wallet.CreateAccount(); // Fake balance var key = NativeContract.GAS.CreateStorageKey(20, acc.ScriptHash); - var entry = snapshot.GetAndChange(key, () => new StorageItem(new AccountState())); + var entry = snapshotCache.GetAndChange(key, () => new StorageItem(new AccountState())); entry.GetInteroperable().Balance = 10000 * NativeContract.GAS.Factor; - snapshot.Commit(); + snapshotCache.Commit(); // Make transaction // Manually creating script @@ -760,14 +759,14 @@ public void FeeIsSignatureContract_UnexistingVerificationContractFAULT() // expects ArgumentException on execution of 'CalculateNetworkFee' due to // null witness_script (no account in the wallet, no corresponding witness // and no verification contract for the signer) - Assert.ThrowsException(() => walletWithoutAcc.MakeTransaction(snapshot, script, acc.ScriptHash, signers)); + Assert.ThrowsException(() => walletWithoutAcc.MakeTransaction(snapshotCache, script, acc.ScriptHash, signers)); Assert.IsNull(tx); } [TestMethod] public void Transaction_Reverify_Hashes_Length_Unequal_To_Witnesses_Length() { - var snapshot = TestBlockchain.GetTestSnapshotCache(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); Transaction txSimple = new() { Version = 0x00, @@ -786,9 +785,9 @@ public void Transaction_Reverify_Hashes_Length_Unequal_To_Witnesses_Length() Script = new byte[] { (byte)OpCode.PUSH1 }, Witnesses = Array.Empty() }; - UInt160[] hashes = txSimple.GetScriptHashesForVerifying(snapshot); + UInt160[] hashes = txSimple.GetScriptHashesForVerifying(snapshotCache); Assert.AreEqual(1, hashes.Length); - Assert.AreNotEqual(VerifyResult.Succeed, txSimple.VerifyStateDependent(TestProtocolSettings.Default, snapshot, new TransactionVerificationContext(), new List())); + Assert.AreNotEqual(VerifyResult.Succeed, txSimple.VerifyStateDependent(TestProtocolSettings.Default, snapshotCache, new TransactionVerificationContext(), new List())); } [TestMethod] @@ -982,18 +981,18 @@ public void FeeIsSignatureContract_TestScope_FeeOnly_Default() cosigner.Scopes.Should().Be(WitnessScope.None); var wallet = TestUtils.GenerateTestWallet(""); - var snapshot = TestBlockchain.GetTestSnapshotCache(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); var acc = wallet.CreateAccount(); // Fake balance var key = NativeContract.GAS.CreateStorageKey(20, acc.ScriptHash); - var entry = snapshot.GetAndChange(key, () => new StorageItem(new AccountState())); + var entry = snapshotCache.GetAndChange(key, () => new StorageItem(new AccountState())); entry.GetInteroperable().Balance = 10000 * NativeContract.GAS.Factor; - snapshot.Commit(); + snapshotCache.Commit(); // Make transaction // Manually creating script @@ -1015,12 +1014,12 @@ public void FeeIsSignatureContract_TestScope_FeeOnly_Default() Scopes = WitnessScope.None } }; - Assert.ThrowsException(() => wallet.MakeTransaction(snapshot, script, acc.ScriptHash, signers)); + Assert.ThrowsException(() => wallet.MakeTransaction(snapshotCache, script, acc.ScriptHash, signers)); // change to global scope signers[0].Scopes = WitnessScope.Global; - var tx = wallet.MakeTransaction(snapshot, script, acc.ScriptHash, signers); + var tx = wallet.MakeTransaction(snapshotCache, script, acc.ScriptHash, signers); Assert.IsNotNull(tx); Assert.IsNull(tx.Witnesses); @@ -1029,7 +1028,7 @@ public void FeeIsSignatureContract_TestScope_FeeOnly_Default() // Sign // ---- - var data = new ContractParametersContext(snapshot, tx, TestProtocolSettings.Default.Network); + var data = new ContractParametersContext(snapshotCache, tx, TestProtocolSettings.Default.Network); bool signed = wallet.Sign(data); Assert.IsTrue(signed); @@ -1038,13 +1037,13 @@ public void FeeIsSignatureContract_TestScope_FeeOnly_Default() tx.Witnesses.Length.Should().Be(1); // Fast check - Assert.IsTrue(tx.VerifyWitnesses(TestProtocolSettings.Default, snapshot, tx.NetworkFee)); + Assert.IsTrue(tx.VerifyWitnesses(TestProtocolSettings.Default, snapshotCache, tx.NetworkFee)); // Check long verificationGas = 0; foreach (var witness in tx.Witnesses) { - using ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Verification, tx, snapshot, settings: TestBlockchain.TheNeoSystem.Settings, gas: tx.NetworkFee); + using ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Verification, tx, snapshotCache, settings: TestBlockchain.TheNeoSystem.Settings, gas: tx.NetworkFee); engine.LoadScript(witness.VerificationScript); engine.LoadScript(witness.InvocationScript); Assert.AreEqual(VMState.HALT, engine.Execute()); @@ -1053,7 +1052,7 @@ public void FeeIsSignatureContract_TestScope_FeeOnly_Default() verificationGas += engine.FeeConsumed; } // get sizeGas - var sizeGas = tx.Size * NativeContract.Policy.GetFeePerByte(snapshot); + var sizeGas = tx.Size * NativeContract.Policy.GetFeePerByte(snapshotCache); // final check on sum: verification_cost + tx_size Assert.AreEqual(1228520, verificationGas + sizeGas); // final assert @@ -1140,7 +1139,7 @@ public void Test_VerifyStateIndependent() var walletA = TestUtils.GenerateTestWallet("123"); var walletB = TestUtils.GenerateTestWallet("123"); - var snapshot = TestBlockchain.GetTestSnapshotCache(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); var a = walletA.CreateAccount(); var b = walletB.CreateAccount(); @@ -1157,15 +1156,15 @@ public void Test_VerifyStateIndependent() // Fake balance var key = NativeContract.GAS.CreateStorageKey(20, acc.ScriptHash); - var entry = snapshot.GetAndChange(key, () => new StorageItem(new AccountState())); + var entry = snapshotCache.GetAndChange(key, () => new StorageItem(new AccountState())); entry.GetInteroperable().Balance = 10000 * NativeContract.GAS.Factor; - snapshot.Commit(); + snapshotCache.Commit(); // Make transaction - tx = walletA.MakeTransaction(snapshot, [ + tx = walletA.MakeTransaction(snapshotCache, [ new TransferOutput { AssetId = NativeContract.GAS.Hash, @@ -1176,7 +1175,7 @@ public void Test_VerifyStateIndependent() // Sign - var data = new ContractParametersContext(snapshot, tx, TestProtocolSettings.Default.Network); + var data = new ContractParametersContext(snapshotCache, tx, TestProtocolSettings.Default.Network); Assert.IsTrue(walletA.Sign(data)); Assert.IsTrue(walletB.Sign(data)); Assert.IsTrue(data.Completed); diff --git a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Witness.cs b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Witness.cs index 6c4f066008..cf765365c9 100644 --- a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Witness.cs +++ b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Witness.cs @@ -43,7 +43,7 @@ private static Witness PrepareDummyWitness(int pubKeys, int m) { var address = new WalletAccount[pubKeys]; var wallets = new NEP6Wallet[pubKeys]; - var snapshot = TestBlockchain.GetTestSnapshotCache(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); for (int x = 0; x < pubKeys; x++) { @@ -62,7 +62,7 @@ private static Witness PrepareDummyWitness(int pubKeys, int m) // Sign - var data = new ContractParametersContext(snapshot, new Transaction() + var data = new ContractParametersContext(snapshotCache, new Transaction() { Attributes = Array.Empty(), Signers = new[] {new Signer() diff --git a/tests/Neo.UnitTests/SmartContract/Native/UT_CryptoLib.cs b/tests/Neo.UnitTests/SmartContract/Native/UT_CryptoLib.cs index 00ababb416..cdca35a69e 100644 --- a/tests/Neo.UnitTests/SmartContract/Native/UT_CryptoLib.cs +++ b/tests/Neo.UnitTests/SmartContract/Native/UT_CryptoLib.cs @@ -45,11 +45,11 @@ public class UT_CryptoLib [TestMethod] public void TestG1() { - var snapshot = TestBlockchain.GetTestSnapshotCache(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); using ScriptBuilder script = new(); script.EmitDynamicCall(NativeContract.CryptoLib.Hash, "bls12381Deserialize", g1); - using var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, settings: TestBlockchain.TheNeoSystem.Settings); + using var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshotCache, settings: TestBlockchain.TheNeoSystem.Settings); engine.LoadScript(script.ToArray()); Assert.AreEqual(VMState.HALT, engine.Execute()); var result = engine.ResultStack.Pop(); @@ -59,11 +59,11 @@ public void TestG1() [TestMethod] public void TestG2() { - var snapshot = TestBlockchain.GetTestSnapshotCache(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); using ScriptBuilder script = new(); script.EmitDynamicCall(NativeContract.CryptoLib.Hash, "bls12381Deserialize", g2); - using var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, settings: TestBlockchain.TheNeoSystem.Settings); + using var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshotCache, settings: TestBlockchain.TheNeoSystem.Settings); engine.LoadScript(script.ToArray()); Assert.AreEqual(VMState.HALT, engine.Execute()); var result = engine.ResultStack.Pop(); @@ -73,11 +73,11 @@ public void TestG2() [TestMethod] public void TestNotG1() { - var snapshot = TestBlockchain.GetTestSnapshotCache(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); using ScriptBuilder script = new(); script.EmitDynamicCall(NativeContract.CryptoLib.Hash, "bls12381Deserialize", not_g1); - using var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, settings: TestBlockchain.TheNeoSystem.Settings); + using var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshotCache, settings: TestBlockchain.TheNeoSystem.Settings); engine.LoadScript(script.ToArray()); Assert.AreEqual(VMState.FAULT, engine.Execute()); } @@ -85,18 +85,18 @@ public void TestNotG1() [TestMethod] public void TestNotG2() { - var snapshot = TestBlockchain.GetTestSnapshotCache(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); using ScriptBuilder script = new(); script.EmitDynamicCall(NativeContract.CryptoLib.Hash, "bls12381Deserialize", not_g2); - using var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, settings: TestBlockchain.TheNeoSystem.Settings); + using var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshotCache, settings: TestBlockchain.TheNeoSystem.Settings); engine.LoadScript(script.ToArray()); Assert.AreEqual(VMState.FAULT, engine.Execute()); } [TestMethod] public void TestBls12381Add() { - var snapshot = TestBlockchain.GetTestSnapshotCache(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); using ScriptBuilder script = new(); script.EmitDynamicCall(NativeContract.CryptoLib.Hash, "bls12381Deserialize", gt); script.EmitDynamicCall(NativeContract.CryptoLib.Hash, "bls12381Deserialize", gt); @@ -107,7 +107,7 @@ public void TestBls12381Add() script.EmitPush(NativeContract.CryptoLib.Hash); script.EmitSysCall(ApplicationEngine.System_Contract_Call); - using var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, settings: TestBlockchain.TheNeoSystem.Settings); + using var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshotCache, settings: TestBlockchain.TheNeoSystem.Settings); engine.LoadScript(script.ToArray()); Assert.AreEqual(VMState.HALT, engine.Execute()); var result = engine.ResultStack.Pop(); @@ -119,7 +119,7 @@ public void TestBls12381Mul() { var data = new byte[32]; data[0] = 0x03; - var snapshot = TestBlockchain.GetTestSnapshotCache(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); using (ScriptBuilder script = new()) { script.EmitPush(false); @@ -132,7 +132,7 @@ public void TestBls12381Mul() script.EmitPush(NativeContract.CryptoLib.Hash); script.EmitSysCall(ApplicationEngine.System_Contract_Call); - using var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, settings: TestBlockchain.TheNeoSystem.Settings); + using var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshotCache, settings: TestBlockchain.TheNeoSystem.Settings); engine.LoadScript(script.ToArray()); Assert.AreEqual(VMState.HALT, engine.Execute()); var result = engine.ResultStack.Pop(); @@ -150,7 +150,7 @@ public void TestBls12381Mul() script.EmitPush(NativeContract.CryptoLib.Hash); script.EmitSysCall(ApplicationEngine.System_Contract_Call); - using var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, settings: TestBlockchain.TheNeoSystem.Settings); + using var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshotCache, settings: TestBlockchain.TheNeoSystem.Settings); engine.LoadScript(script.ToArray()); Assert.AreEqual(VMState.HALT, engine.Execute()); var result = engine.ResultStack.Pop(); @@ -161,7 +161,7 @@ public void TestBls12381Mul() [TestMethod] public void TestBls12381Pairing() { - var snapshot = TestBlockchain.GetTestSnapshotCache(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); using ScriptBuilder script = new(); script.EmitDynamicCall(NativeContract.CryptoLib.Hash, "bls12381Deserialize", g2); script.EmitDynamicCall(NativeContract.CryptoLib.Hash, "bls12381Deserialize", g1); @@ -172,7 +172,7 @@ public void TestBls12381Pairing() script.EmitPush(NativeContract.CryptoLib.Hash); script.EmitSysCall(ApplicationEngine.System_Contract_Call); - using var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, settings: TestBlockchain.TheNeoSystem.Settings); + using var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshotCache, settings: TestBlockchain.TheNeoSystem.Settings); engine.LoadScript(script.ToArray()); Assert.AreEqual(VMState.HALT, engine.Execute()); var result = engine.ResultStack.Pop(); @@ -182,7 +182,7 @@ public void TestBls12381Pairing() [TestMethod] public void Bls12381Equal() { - var snapshot = TestBlockchain.GetTestSnapshotCache(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); using ScriptBuilder script = new(); script.EmitDynamicCall(NativeContract.CryptoLib.Hash, "bls12381Deserialize", g1); script.EmitDynamicCall(NativeContract.CryptoLib.Hash, "bls12381Deserialize", g1); @@ -193,7 +193,7 @@ public void Bls12381Equal() script.EmitPush(NativeContract.CryptoLib.Hash); script.EmitSysCall(ApplicationEngine.System_Contract_Call); - using var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, settings: TestBlockchain.TheNeoSystem.Settings); + using var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshotCache, settings: TestBlockchain.TheNeoSystem.Settings); engine.LoadScript(script.ToArray()); Assert.AreEqual(VMState.HALT, engine.Execute()); var result = engine.ResultStack.Pop(); @@ -211,7 +211,7 @@ private void CheckBls12381ScalarMul_Compat(string point, string mul, bool negati { var data = new byte[32]; data[0] = 0x03; - var snapshot = TestBlockchain.GetTestSnapshotCache(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); using (ScriptBuilder script = new()) { script.EmitPush(negative); @@ -224,7 +224,7 @@ private void CheckBls12381ScalarMul_Compat(string point, string mul, bool negati script.EmitPush(NativeContract.CryptoLib.Hash); script.EmitSysCall(ApplicationEngine.System_Contract_Call); - using var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, settings: TestBlockchain.TheNeoSystem.Settings); + using var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshotCache, settings: TestBlockchain.TheNeoSystem.Settings); engine.LoadScript(script.ToArray()); Assert.AreEqual(VMState.HALT, engine.Execute()); var result = engine.ResultStack.Pop(); @@ -506,16 +506,16 @@ public void TestVerifyWithECDsa_CustomTxWitness_SingleSig() tx.VerifyStateIndependent(TestProtocolSettings.Default).Should().Be(VerifyResult.Succeed); - var snapshot = TestBlockchain.GetTestSnapshotCache(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); // Create fake balance to pay the fees. - ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, settings: TestBlockchain.TheNeoSystem.Settings, gas: long.MaxValue); + ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Application, null, snapshotCache, settings: TestBlockchain.TheNeoSystem.Settings, gas: long.MaxValue); _ = NativeContract.GAS.Mint(engine, acc, 5_0000_0000, false); - snapshot.Commit(); + snapshotCache.Commit(); var txVrfContext = new TransactionVerificationContext(); var conflicts = new List(); - tx.VerifyStateDependent(TestProtocolSettings.Default, snapshot, txVrfContext, conflicts).Should().Be(VerifyResult.Succeed); + tx.VerifyStateDependent(TestProtocolSettings.Default, snapshotCache, txVrfContext, conflicts).Should().Be(VerifyResult.Succeed); // The resulting witness verification cost is 2154270 * 10e-8GAS. // The resulting witness Invocation script (66 bytes length): @@ -747,10 +747,10 @@ public void TestVerifyWithECDsa_CustomTxWitness_MultiSig() tx.VerifyStateIndependent(TestProtocolSettings.Default).Should().Be(VerifyResult.Succeed); - var snapshot = TestBlockchain.GetTestSnapshotCache(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); // Create fake balance to pay the fees. - var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, settings: TestBlockchain.TheNeoSystem.Settings, gas: long.MaxValue); + var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshotCache, settings: TestBlockchain.TheNeoSystem.Settings, gas: long.MaxValue); _ = NativeContract.GAS.Mint(engine, acc, 5_0000_0000, false); // We should not use commit here cause once its committed, the value we get from the snapshot can be different @@ -761,7 +761,7 @@ public void TestVerifyWithECDsa_CustomTxWitness_MultiSig() // Check that witness verification passes. var txVrfContext = new TransactionVerificationContext(); var conflicts = new List(); - tx.VerifyStateDependent(TestProtocolSettings.Default, snapshot, txVrfContext, conflicts).Should().Be(VerifyResult.Succeed); + tx.VerifyStateDependent(TestProtocolSettings.Default, snapshotCache, txVrfContext, conflicts).Should().Be(VerifyResult.Succeed); // The resulting witness verification cost for 3/4 multisig is 8389470 * 10e-8GAS. Cost depends on M/N. // The resulting witness Invocation script (198 bytes for 3 signatures): diff --git a/tests/Neo.UnitTests/SmartContract/Native/UT_FungibleToken.cs b/tests/Neo.UnitTests/SmartContract/Native/UT_FungibleToken.cs index 6e3c18999a..7e7e27084c 100644 --- a/tests/Neo.UnitTests/SmartContract/Native/UT_FungibleToken.cs +++ b/tests/Neo.UnitTests/SmartContract/Native/UT_FungibleToken.cs @@ -22,8 +22,8 @@ public class UT_FungibleToken : TestKit [TestMethod] public void TestTotalSupply() { - var snapshot = TestBlockchain.GetTestSnapshotCache(); - NativeContract.GAS.TotalSupply(snapshot).Should().Be(5200000050000000); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); + NativeContract.GAS.TotalSupply(snapshotCache).Should().Be(5200000050000000); } } } diff --git a/tests/Neo.UnitTests/SmartContract/Native/UT_GasToken.cs b/tests/Neo.UnitTests/SmartContract/Native/UT_GasToken.cs index ebb66f0dff..a7d087fa86 100644 --- a/tests/Neo.UnitTests/SmartContract/Native/UT_GasToken.cs +++ b/tests/Neo.UnitTests/SmartContract/Native/UT_GasToken.cs @@ -27,13 +27,13 @@ namespace Neo.UnitTests.SmartContract.Native [TestClass] public class UT_GasToken { - private DataCache _snapshot; + private DataCache _snapshotCache; private Block _persistingBlock; [TestInitialize] public void TestSetup() { - _snapshot = TestBlockchain.GetTestSnapshotCache(); + _snapshotCache = TestBlockchain.GetTestSnapshotCache(); _persistingBlock = new Block { Header = new Header() }; } @@ -41,15 +41,15 @@ public void TestSetup() public void Check_Name() => NativeContract.GAS.Name.Should().Be(nameof(GasToken)); [TestMethod] - public void Check_Symbol() => NativeContract.GAS.Symbol(_snapshot).Should().Be("GAS"); + public void Check_Symbol() => NativeContract.GAS.Symbol(_snapshotCache).Should().Be("GAS"); [TestMethod] - public void Check_Decimals() => NativeContract.GAS.Decimals(_snapshot).Should().Be(8); + public void Check_Decimals() => NativeContract.GAS.Decimals(_snapshotCache).Should().Be(8); [TestMethod] public async Task Check_BalanceOfTransferAndBurn() { - var snapshot = _snapshot.CloneCache(); + var snapshot = _snapshotCache.CloneCache(); var persistingBlock = new Block { Header = new Header { Index = 1000 } }; byte[] from = Contract.GetBFTAddress(TestProtocolSettings.Default.StandbyValidators).ToArray(); byte[] to = new byte[20]; @@ -119,20 +119,20 @@ await Assert.ThrowsExceptionAsync(async () => await NativeContract.GAS.Burn(engine, new UInt160(to), new BigInteger(1)); - NativeContract.GAS.BalanceOf(engine.Snapshot, to).Should().Be(5200049999999999); + NativeContract.GAS.BalanceOf(engine.SnapshotCache, to).Should().Be(5200049999999999); - engine.Snapshot.GetChangeSet().Count().Should().Be(2); + engine.SnapshotCache.GetChangeSet().Count().Should().Be(2); // Burn all await NativeContract.GAS.Burn(engine, new UInt160(to), new BigInteger(5200049999999999)); - (keyCount - 2).Should().Be(engine.Snapshot.GetChangeSet().Count()); + (keyCount - 2).Should().Be(engine.SnapshotCache.GetChangeSet().Count()); // Bad inputs - Assert.ThrowsException(() => NativeContract.GAS.Transfer(engine.Snapshot, from, to, BigInteger.MinusOne, true, persistingBlock)); - Assert.ThrowsException(() => NativeContract.GAS.Transfer(engine.Snapshot, new byte[19], to, BigInteger.One, false, persistingBlock)); - Assert.ThrowsException(() => NativeContract.GAS.Transfer(engine.Snapshot, from, new byte[19], BigInteger.One, false, persistingBlock)); + Assert.ThrowsException(() => NativeContract.GAS.Transfer(engine.SnapshotCache, from, to, BigInteger.MinusOne, true, persistingBlock)); + Assert.ThrowsException(() => NativeContract.GAS.Transfer(engine.SnapshotCache, new byte[19], to, BigInteger.One, false, persistingBlock)); + Assert.ThrowsException(() => NativeContract.GAS.Transfer(engine.SnapshotCache, from, new byte[19], BigInteger.One, false, persistingBlock)); } internal static StorageKey CreateStorageKey(byte prefix, uint key) diff --git a/tests/Neo.UnitTests/SmartContract/Native/UT_NativeContract.cs b/tests/Neo.UnitTests/SmartContract/Native/UT_NativeContract.cs index 7c1d874b1b..f9a3089f9d 100644 --- a/tests/Neo.UnitTests/SmartContract/Native/UT_NativeContract.cs +++ b/tests/Neo.UnitTests/SmartContract/Native/UT_NativeContract.cs @@ -27,7 +27,7 @@ namespace Neo.UnitTests.SmartContract.Native [TestClass] public class UT_NativeContract { - private DataCache _snapshot; + private DataCache _snapshotCache; /// /// _nativeStates contains a mapping from native contract name to expected native contract state /// constructed with all hardforks enabled and marshalled in JSON. @@ -37,7 +37,7 @@ public class UT_NativeContract [TestInitialize] public void TestSetup() { - _snapshot = TestBlockchain.GetTestSnapshotCache(); + _snapshotCache = TestBlockchain.GetTestSnapshotCache(); _nativeStates = new Dictionary { {"ContractManagement", """{"id":-1,"updatecounter":0,"hash":"0xfffdc93764dbaddd97c48f252a53ea4643faa3fd","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0A=","checksum":1094259016},"manifest":{"name":"ContractManagement","groups":[],"features":{},"supportedstandards":[],"abi":{"methods":[{"name":"deploy","parameters":[{"name":"nefFile","type":"ByteArray"},{"name":"manifest","type":"ByteArray"}],"returntype":"Array","offset":0,"safe":false},{"name":"deploy","parameters":[{"name":"nefFile","type":"ByteArray"},{"name":"manifest","type":"ByteArray"},{"name":"data","type":"Any"}],"returntype":"Array","offset":7,"safe":false},{"name":"destroy","parameters":[],"returntype":"Void","offset":14,"safe":false},{"name":"getContract","parameters":[{"name":"hash","type":"Hash160"}],"returntype":"Array","offset":21,"safe":true},{"name":"getContractById","parameters":[{"name":"id","type":"Integer"}],"returntype":"Array","offset":28,"safe":true},{"name":"getContractHashes","parameters":[],"returntype":"InteropInterface","offset":35,"safe":true},{"name":"getMinimumDeploymentFee","parameters":[],"returntype":"Integer","offset":42,"safe":true},{"name":"hasMethod","parameters":[{"name":"hash","type":"Hash160"},{"name":"method","type":"String"},{"name":"pcount","type":"Integer"}],"returntype":"Boolean","offset":49,"safe":true},{"name":"setMinimumDeploymentFee","parameters":[{"name":"value","type":"Integer"}],"returntype":"Void","offset":56,"safe":false},{"name":"update","parameters":[{"name":"nefFile","type":"ByteArray"},{"name":"manifest","type":"ByteArray"}],"returntype":"Void","offset":63,"safe":false},{"name":"update","parameters":[{"name":"nefFile","type":"ByteArray"},{"name":"manifest","type":"ByteArray"},{"name":"data","type":"Any"}],"returntype":"Void","offset":70,"safe":false}],"events":[{"name":"Deploy","parameters":[{"name":"Hash","type":"Hash160"}]},{"name":"Update","parameters":[{"name":"Hash","type":"Hash160"}]},{"name":"Destroy","parameters":[{"name":"Hash","type":"Hash160"}]}]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"extra":null}}""" }, @@ -123,7 +123,7 @@ public void TestGenesisNEP17Manifest() }, Transactions = [] }; - var snapshot = _snapshot.CloneCache(); + var snapshot = _snapshotCache.CloneCache(); // Ensure that native NEP17 contracts contain proper supported standards and events declared // in the manifest constructed for all hardforks enabled. Ref. https://github.com/neo-project/neo/pull/3195. @@ -150,7 +150,7 @@ public void TestGenesisNativeState() }, Transactions = [] }; - var snapshot = _snapshot.CloneCache(); + var snapshot = _snapshotCache.CloneCache(); // Ensure that all native contracts have proper state generated with an assumption that // all hardforks enabled. diff --git a/tests/Neo.UnitTests/SmartContract/Native/UT_NeoToken.cs b/tests/Neo.UnitTests/SmartContract/Native/UT_NeoToken.cs index b08898aad5..cff1eb12b0 100644 --- a/tests/Neo.UnitTests/SmartContract/Native/UT_NeoToken.cs +++ b/tests/Neo.UnitTests/SmartContract/Native/UT_NeoToken.cs @@ -30,13 +30,13 @@ namespace Neo.UnitTests.SmartContract.Native [TestClass] public class UT_NeoToken { - private DataCache _snapshot; + private DataCache _snapshotCache; private Block _persistingBlock; [TestInitialize] public void TestSetup() { - _snapshot = TestBlockchain.GetTestSnapshotCache(); + _snapshotCache = TestBlockchain.GetTestSnapshotCache(); _persistingBlock = new Block { Header = new Header(), @@ -48,37 +48,37 @@ public void TestSetup() public void Check_Name() => NativeContract.NEO.Name.Should().Be(nameof(NeoToken)); [TestMethod] - public void Check_Symbol() => NativeContract.NEO.Symbol(_snapshot).Should().Be("NEO"); + public void Check_Symbol() => NativeContract.NEO.Symbol(_snapshotCache).Should().Be("NEO"); [TestMethod] - public void Check_Decimals() => NativeContract.NEO.Decimals(_snapshot).Should().Be(0); + public void Check_Decimals() => NativeContract.NEO.Decimals(_snapshotCache).Should().Be(0); [TestMethod] public void Check_Vote() { - var snapshot = _snapshot.CloneCache(); + var clonedCache = _snapshotCache.CloneCache(); var persistingBlock = new Block { Header = new Header { Index = 1000 } }; var storageKey = new KeyBuilder(NativeContract.Ledger.Id, 12); - snapshot.Add(storageKey, new StorageItem(new HashIndexState { Hash = UInt256.Zero, Index = persistingBlock.Index - 1 })); + clonedCache.Add(storageKey, new StorageItem(new HashIndexState { Hash = UInt256.Zero, Index = persistingBlock.Index - 1 })); byte[] from = Contract.GetBFTAddress(TestProtocolSettings.Default.StandbyValidators).ToArray(); // No signature - var ret = Check_Vote(snapshot, from, null, false, persistingBlock); + var ret = Check_Vote(clonedCache, from, null, false, persistingBlock); ret.Result.Should().BeFalse(); ret.State.Should().BeTrue(); // Wrong address - ret = Check_Vote(snapshot, new byte[19], null, false, persistingBlock); + ret = Check_Vote(clonedCache, new byte[19], null, false, persistingBlock); ret.Result.Should().BeFalse(); ret.State.Should().BeFalse(); // Wrong ec - ret = Check_Vote(snapshot, from, new byte[19], true, persistingBlock); + ret = Check_Vote(clonedCache, from, new byte[19], true, persistingBlock); ret.Result.Should().BeFalse(); ret.State.Should().BeFalse(); @@ -88,130 +88,130 @@ public void Check_Vote() fakeAddr[0] = 0x5F; fakeAddr[5] = 0xFF; - ret = Check_Vote(snapshot, fakeAddr, null, true, persistingBlock); + ret = Check_Vote(clonedCache, fakeAddr, null, true, persistingBlock); ret.Result.Should().BeFalse(); ret.State.Should().BeTrue(); // no registered - var accountState = snapshot.TryGet(CreateStorageKey(20, from)).GetInteroperable(); + var accountState = clonedCache.TryGet(CreateStorageKey(20, from)).GetInteroperable(); accountState.VoteTo = null; - ret = Check_Vote(snapshot, from, ECCurve.Secp256r1.G.ToArray(), true, persistingBlock); + ret = Check_Vote(clonedCache, from, ECCurve.Secp256r1.G.ToArray(), true, persistingBlock); ret.Result.Should().BeFalse(); ret.State.Should().BeTrue(); accountState.VoteTo.Should().BeNull(); // normal case - snapshot.Add(CreateStorageKey(33, ECCurve.Secp256r1.G.ToArray()), new StorageItem(new CandidateState() { Registered = true })); - ret = Check_Vote(snapshot, from, ECCurve.Secp256r1.G.ToArray(), true, persistingBlock); + clonedCache.Add(CreateStorageKey(33, ECCurve.Secp256r1.G.ToArray()), new StorageItem(new CandidateState() { Registered = true })); + ret = Check_Vote(clonedCache, from, ECCurve.Secp256r1.G.ToArray(), true, persistingBlock); ret.Result.Should().BeTrue(); ret.State.Should().BeTrue(); - accountState = snapshot.TryGet(CreateStorageKey(20, from)).GetInteroperable(); + accountState = clonedCache.TryGet(CreateStorageKey(20, from)).GetInteroperable(); accountState.VoteTo.Should().Be(ECCurve.Secp256r1.G); } [TestMethod] public void Check_Vote_Sameaccounts() { - var snapshot = _snapshot.CloneCache(); + var clonedCache = _snapshotCache.CloneCache(); var persistingBlock = new Block { Header = new Header { Index = 1000 } }; var storageKey = new KeyBuilder(NativeContract.Ledger.Id, 12); - snapshot.Add(storageKey, new StorageItem(new HashIndexState { Hash = UInt256.Zero, Index = persistingBlock.Index - 1 })); + clonedCache.Add(storageKey, new StorageItem(new HashIndexState { Hash = UInt256.Zero, Index = persistingBlock.Index - 1 })); byte[] from = Contract.GetBFTAddress(TestProtocolSettings.Default.StandbyValidators).ToArray(); - var accountState = snapshot.TryGet(CreateStorageKey(20, from)).GetInteroperable(); + var accountState = clonedCache.TryGet(CreateStorageKey(20, from)).GetInteroperable(); accountState.Balance = 100; - snapshot.Add(CreateStorageKey(33, ECCurve.Secp256r1.G.ToArray()), new StorageItem(new CandidateState() { Registered = true })); - var ret = Check_Vote(snapshot, from, ECCurve.Secp256r1.G.ToArray(), true, persistingBlock); + clonedCache.Add(CreateStorageKey(33, ECCurve.Secp256r1.G.ToArray()), new StorageItem(new CandidateState() { Registered = true })); + var ret = Check_Vote(clonedCache, from, ECCurve.Secp256r1.G.ToArray(), true, persistingBlock); ret.Result.Should().BeTrue(); ret.State.Should().BeTrue(); - accountState = snapshot.TryGet(CreateStorageKey(20, from)).GetInteroperable(); + accountState = clonedCache.TryGet(CreateStorageKey(20, from)).GetInteroperable(); accountState.VoteTo.Should().Be(ECCurve.Secp256r1.G); //two account vote for the same account - var stateValidator = snapshot.GetAndChange(CreateStorageKey(33, ECCurve.Secp256r1.G.ToArray())).GetInteroperable(); + var stateValidator = clonedCache.GetAndChange(CreateStorageKey(33, ECCurve.Secp256r1.G.ToArray())).GetInteroperable(); stateValidator.Votes.Should().Be(100); var G_Account = Contract.CreateSignatureContract(ECCurve.Secp256r1.G).ScriptHash.ToArray(); - snapshot.Add(CreateStorageKey(20, G_Account), new StorageItem(new NeoAccountState { Balance = 200 })); - var secondAccount = snapshot.TryGet(CreateStorageKey(20, G_Account)).GetInteroperable(); + clonedCache.Add(CreateStorageKey(20, G_Account), new StorageItem(new NeoAccountState { Balance = 200 })); + var secondAccount = clonedCache.TryGet(CreateStorageKey(20, G_Account)).GetInteroperable(); secondAccount.Balance.Should().Be(200); - ret = Check_Vote(snapshot, G_Account, ECCurve.Secp256r1.G.ToArray(), true, persistingBlock); + ret = Check_Vote(clonedCache, G_Account, ECCurve.Secp256r1.G.ToArray(), true, persistingBlock); ret.Result.Should().BeTrue(); ret.State.Should().BeTrue(); - stateValidator = snapshot.GetAndChange(CreateStorageKey(33, ECCurve.Secp256r1.G.ToArray())).GetInteroperable(); + stateValidator = clonedCache.GetAndChange(CreateStorageKey(33, ECCurve.Secp256r1.G.ToArray())).GetInteroperable(); stateValidator.Votes.Should().Be(300); } [TestMethod] public void Check_Vote_ChangeVote() { - var snapshot = _snapshot.CloneCache(); + var clonedCache = _snapshotCache.CloneCache(); var persistingBlock = new Block { Header = new Header { Index = 1000 } }; var storageKey = new KeyBuilder(NativeContract.Ledger.Id, 12); - snapshot.Add(storageKey, new StorageItem(new HashIndexState { Hash = UInt256.Zero, Index = persistingBlock.Index - 1 })); + clonedCache.Add(storageKey, new StorageItem(new HashIndexState { Hash = UInt256.Zero, Index = persistingBlock.Index - 1 })); //from vote to G byte[] from = TestProtocolSettings.Default.StandbyValidators[0].ToArray(); var from_Account = Contract.CreateSignatureContract(TestProtocolSettings.Default.StandbyValidators[0]).ScriptHash.ToArray(); - snapshot.Add(CreateStorageKey(20, from_Account), new StorageItem(new NeoAccountState())); - var accountState = snapshot.TryGet(CreateStorageKey(20, from_Account)).GetInteroperable(); + clonedCache.Add(CreateStorageKey(20, from_Account), new StorageItem(new NeoAccountState())); + var accountState = clonedCache.TryGet(CreateStorageKey(20, from_Account)).GetInteroperable(); accountState.Balance = 100; - snapshot.Add(CreateStorageKey(33, ECCurve.Secp256r1.G.ToArray()), new StorageItem(new CandidateState() { Registered = true })); - var ret = Check_Vote(snapshot, from_Account, ECCurve.Secp256r1.G.ToArray(), true, persistingBlock); + clonedCache.Add(CreateStorageKey(33, ECCurve.Secp256r1.G.ToArray()), new StorageItem(new CandidateState() { Registered = true })); + var ret = Check_Vote(clonedCache, from_Account, ECCurve.Secp256r1.G.ToArray(), true, persistingBlock); ret.Result.Should().BeTrue(); ret.State.Should().BeTrue(); - accountState = snapshot.TryGet(CreateStorageKey(20, from_Account)).GetInteroperable(); + accountState = clonedCache.TryGet(CreateStorageKey(20, from_Account)).GetInteroperable(); accountState.VoteTo.Should().Be(ECCurve.Secp256r1.G); //from change vote to itself - var G_stateValidator = snapshot.GetAndChange(CreateStorageKey(33, ECCurve.Secp256r1.G.ToArray())).GetInteroperable(); + var G_stateValidator = clonedCache.GetAndChange(CreateStorageKey(33, ECCurve.Secp256r1.G.ToArray())).GetInteroperable(); G_stateValidator.Votes.Should().Be(100); var G_Account = Contract.CreateSignatureContract(ECCurve.Secp256r1.G).ScriptHash.ToArray(); - snapshot.Add(CreateStorageKey(20, G_Account), new StorageItem(new NeoAccountState { Balance = 200 })); - snapshot.Add(CreateStorageKey(33, from), new StorageItem(new CandidateState() { Registered = true })); - ret = Check_Vote(snapshot, from_Account, from, true, persistingBlock); + clonedCache.Add(CreateStorageKey(20, G_Account), new StorageItem(new NeoAccountState { Balance = 200 })); + clonedCache.Add(CreateStorageKey(33, from), new StorageItem(new CandidateState() { Registered = true })); + ret = Check_Vote(clonedCache, from_Account, from, true, persistingBlock); ret.Result.Should().BeTrue(); ret.State.Should().BeTrue(); - G_stateValidator = snapshot.GetAndChange(CreateStorageKey(33, ECCurve.Secp256r1.G.ToArray())).GetInteroperable(); + G_stateValidator = clonedCache.GetAndChange(CreateStorageKey(33, ECCurve.Secp256r1.G.ToArray())).GetInteroperable(); G_stateValidator.Votes.Should().Be(0); - var from_stateValidator = snapshot.GetAndChange(CreateStorageKey(33, from)).GetInteroperable(); + var from_stateValidator = clonedCache.GetAndChange(CreateStorageKey(33, from)).GetInteroperable(); from_stateValidator.Votes.Should().Be(100); } [TestMethod] public void Check_Vote_VoteToNull() { - var snapshot = _snapshot.CloneCache(); + var clonedCache = _snapshotCache.CloneCache(); var persistingBlock = new Block { Header = new Header { Index = 1000 } }; var storageKey = new KeyBuilder(NativeContract.Ledger.Id, 12); - snapshot.Add(storageKey, new StorageItem(new HashIndexState { Hash = UInt256.Zero, Index = persistingBlock.Index - 1 })); + clonedCache.Add(storageKey, new StorageItem(new HashIndexState { Hash = UInt256.Zero, Index = persistingBlock.Index - 1 })); byte[] from = TestProtocolSettings.Default.StandbyValidators[0].ToArray(); var from_Account = Contract.CreateSignatureContract(TestProtocolSettings.Default.StandbyValidators[0]).ScriptHash.ToArray(); - snapshot.Add(CreateStorageKey(20, from_Account), new StorageItem(new NeoAccountState())); - var accountState = snapshot.TryGet(CreateStorageKey(20, from_Account)).GetInteroperable(); + clonedCache.Add(CreateStorageKey(20, from_Account), new StorageItem(new NeoAccountState())); + var accountState = clonedCache.TryGet(CreateStorageKey(20, from_Account)).GetInteroperable(); accountState.Balance = 100; - snapshot.Add(CreateStorageKey(33, ECCurve.Secp256r1.G.ToArray()), new StorageItem(new CandidateState() { Registered = true })); - snapshot.Add(CreateStorageKey(23, ECCurve.Secp256r1.G.ToArray()), new StorageItem(new BigInteger(100500))); - var ret = Check_Vote(snapshot, from_Account, ECCurve.Secp256r1.G.ToArray(), true, persistingBlock); + clonedCache.Add(CreateStorageKey(33, ECCurve.Secp256r1.G.ToArray()), new StorageItem(new CandidateState() { Registered = true })); + clonedCache.Add(CreateStorageKey(23, ECCurve.Secp256r1.G.ToArray()), new StorageItem(new BigInteger(100500))); + var ret = Check_Vote(clonedCache, from_Account, ECCurve.Secp256r1.G.ToArray(), true, persistingBlock); ret.Result.Should().BeTrue(); ret.State.Should().BeTrue(); - accountState = snapshot.TryGet(CreateStorageKey(20, from_Account)).GetInteroperable(); + accountState = clonedCache.TryGet(CreateStorageKey(20, from_Account)).GetInteroperable(); accountState.VoteTo.Should().Be(ECCurve.Secp256r1.G); accountState.LastGasPerVote.Should().Be(100500); //from vote to null account G votes becomes 0 - var G_stateValidator = snapshot.GetAndChange(CreateStorageKey(33, ECCurve.Secp256r1.G.ToArray())).GetInteroperable(); + var G_stateValidator = clonedCache.GetAndChange(CreateStorageKey(33, ECCurve.Secp256r1.G.ToArray())).GetInteroperable(); G_stateValidator.Votes.Should().Be(100); var G_Account = Contract.CreateSignatureContract(ECCurve.Secp256r1.G).ScriptHash.ToArray(); - snapshot.Add(CreateStorageKey(20, G_Account), new StorageItem(new NeoAccountState { Balance = 200 })); - snapshot.Add(CreateStorageKey(33, from), new StorageItem(new CandidateState() { Registered = true })); - ret = Check_Vote(snapshot, from_Account, null, true, persistingBlock); + clonedCache.Add(CreateStorageKey(20, G_Account), new StorageItem(new NeoAccountState { Balance = 200 })); + clonedCache.Add(CreateStorageKey(33, from), new StorageItem(new CandidateState() { Registered = true })); + ret = Check_Vote(clonedCache, from_Account, null, true, persistingBlock); ret.Result.Should().BeTrue(); ret.State.Should().BeTrue(); - G_stateValidator = snapshot.GetAndChange(CreateStorageKey(33, ECCurve.Secp256r1.G.ToArray())).GetInteroperable(); + G_stateValidator = clonedCache.GetAndChange(CreateStorageKey(33, ECCurve.Secp256r1.G.ToArray())).GetInteroperable(); G_stateValidator.Votes.Should().Be(0); - accountState = snapshot.TryGet(CreateStorageKey(20, from_Account)).GetInteroperable(); + accountState = clonedCache.TryGet(CreateStorageKey(20, from_Account)).GetInteroperable(); accountState.VoteTo.Should().Be(null); accountState.LastGasPerVote.Should().Be(0); } @@ -219,19 +219,19 @@ public void Check_Vote_VoteToNull() [TestMethod] public void Check_UnclaimedGas() { - var snapshot = _snapshot.CloneCache(); + var clonedCache = _snapshotCache.CloneCache(); var persistingBlock = new Block { Header = new Header { Index = 1000 } }; var storageKey = new KeyBuilder(NativeContract.Ledger.Id, 12); - snapshot.Add(storageKey, new StorageItem(new HashIndexState { Hash = UInt256.Zero, Index = persistingBlock.Index - 1 })); + clonedCache.Add(storageKey, new StorageItem(new HashIndexState { Hash = UInt256.Zero, Index = persistingBlock.Index - 1 })); byte[] from = Contract.GetBFTAddress(TestProtocolSettings.Default.StandbyValidators).ToArray(); - var unclaim = Check_UnclaimedGas(snapshot, from, persistingBlock); + var unclaim = Check_UnclaimedGas(clonedCache, from, persistingBlock); unclaim.Value.Should().Be(new BigInteger(0.5 * 1000 * 100000000L)); unclaim.State.Should().BeTrue(); - unclaim = Check_UnclaimedGas(snapshot, new byte[19], persistingBlock); + unclaim = Check_UnclaimedGas(clonedCache, new byte[19], persistingBlock); unclaim.Value.Should().Be(BigInteger.Zero); unclaim.State.Should().BeFalse(); } @@ -239,113 +239,113 @@ public void Check_UnclaimedGas() [TestMethod] public void Check_RegisterValidator() { - var snapshot = _snapshot.CloneCache(); + var clonedCache = _snapshotCache.CloneCache(); - var keyCount = snapshot.GetChangeSet().Count(); + var keyCount = clonedCache.GetChangeSet().Count(); var point = TestProtocolSettings.Default.StandbyValidators[0].EncodePoint(true).Clone() as byte[]; - var ret = Check_RegisterValidator(snapshot, point, _persistingBlock); // Exists + var ret = Check_RegisterValidator(clonedCache, point, _persistingBlock); // Exists ret.State.Should().BeTrue(); ret.Result.Should().BeTrue(); - snapshot.GetChangeSet().Count().Should().Be(++keyCount); // No changes + clonedCache.GetChangeSet().Count().Should().Be(++keyCount); // No changes point[20]++; // fake point - ret = Check_RegisterValidator(snapshot, point, _persistingBlock); // New + ret = Check_RegisterValidator(clonedCache, point, _persistingBlock); // New ret.State.Should().BeTrue(); ret.Result.Should().BeTrue(); - snapshot.GetChangeSet().Count().Should().Be(keyCount + 1); // New validator + clonedCache.GetChangeSet().Count().Should().Be(keyCount + 1); // New validator // Check GetRegisteredValidators - var members = NativeContract.NEO.GetCandidatesInternal(snapshot); + var members = NativeContract.NEO.GetCandidatesInternal(clonedCache); Assert.AreEqual(2, members.Count()); } [TestMethod] public void Check_UnregisterCandidate() { - var snapshot = _snapshot.CloneCache(); + var clonedCache = _snapshotCache.CloneCache(); _persistingBlock.Header.Index = 1; - var keyCount = snapshot.GetChangeSet().Count(); + var keyCount = clonedCache.GetChangeSet().Count(); var point = TestProtocolSettings.Default.StandbyValidators[0].EncodePoint(true); //without register - var ret = Check_UnregisterCandidate(snapshot, point, _persistingBlock); + var ret = Check_UnregisterCandidate(clonedCache, point, _persistingBlock); ret.State.Should().BeTrue(); ret.Result.Should().BeTrue(); - snapshot.GetChangeSet().Count().Should().Be(keyCount); + clonedCache.GetChangeSet().Count().Should().Be(keyCount); //register and then unregister - ret = Check_RegisterValidator(snapshot, point, _persistingBlock); - StorageItem item = snapshot.GetAndChange(CreateStorageKey(33, point)); + ret = Check_RegisterValidator(clonedCache, point, _persistingBlock); + StorageItem item = clonedCache.GetAndChange(CreateStorageKey(33, point)); item.Size.Should().Be(7); ret.State.Should().BeTrue(); ret.Result.Should().BeTrue(); - var members = NativeContract.NEO.GetCandidatesInternal(snapshot); + var members = NativeContract.NEO.GetCandidatesInternal(clonedCache); Assert.AreEqual(1, members.Count()); - snapshot.GetChangeSet().Count().Should().Be(keyCount + 1); + clonedCache.GetChangeSet().Count().Should().Be(keyCount + 1); StorageKey key = CreateStorageKey(33, point); - snapshot.TryGet(key).Should().NotBeNull(); + clonedCache.TryGet(key).Should().NotBeNull(); - ret = Check_UnregisterCandidate(snapshot, point, _persistingBlock); + ret = Check_UnregisterCandidate(clonedCache, point, _persistingBlock); ret.State.Should().BeTrue(); ret.Result.Should().BeTrue(); - snapshot.GetChangeSet().Count().Should().Be(keyCount); + clonedCache.GetChangeSet().Count().Should().Be(keyCount); - members = NativeContract.NEO.GetCandidatesInternal(snapshot); + members = NativeContract.NEO.GetCandidatesInternal(clonedCache); Assert.AreEqual(0, members.Count()); - snapshot.TryGet(key).Should().BeNull(); + clonedCache.TryGet(key).Should().BeNull(); //register with votes, then unregister - ret = Check_RegisterValidator(snapshot, point, _persistingBlock); + ret = Check_RegisterValidator(clonedCache, point, _persistingBlock); ret.State.Should().BeTrue(); var G_Account = Contract.CreateSignatureContract(ECCurve.Secp256r1.G).ScriptHash.ToArray(); - snapshot.Add(CreateStorageKey(20, G_Account), new StorageItem(new NeoAccountState())); - var accountState = snapshot.TryGet(CreateStorageKey(20, G_Account)).GetInteroperable(); + clonedCache.Add(CreateStorageKey(20, G_Account), new StorageItem(new NeoAccountState())); + var accountState = clonedCache.TryGet(CreateStorageKey(20, G_Account)).GetInteroperable(); accountState.Balance = 100; - Check_Vote(snapshot, G_Account, TestProtocolSettings.Default.StandbyValidators[0].ToArray(), true, _persistingBlock); - ret = Check_UnregisterCandidate(snapshot, point, _persistingBlock); + Check_Vote(clonedCache, G_Account, TestProtocolSettings.Default.StandbyValidators[0].ToArray(), true, _persistingBlock); + ret = Check_UnregisterCandidate(clonedCache, point, _persistingBlock); ret.State.Should().BeTrue(); ret.Result.Should().BeTrue(); - snapshot.TryGet(key).Should().NotBeNull(); - StorageItem pointItem = snapshot.TryGet(key); + clonedCache.TryGet(key).Should().NotBeNull(); + StorageItem pointItem = clonedCache.TryGet(key); CandidateState pointState = pointItem.GetInteroperable(); pointState.Registered.Should().BeFalse(); pointState.Votes.Should().Be(100); //vote fail - ret = Check_Vote(snapshot, G_Account, TestProtocolSettings.Default.StandbyValidators[0].ToArray(), true, _persistingBlock); + ret = Check_Vote(clonedCache, G_Account, TestProtocolSettings.Default.StandbyValidators[0].ToArray(), true, _persistingBlock); ret.State.Should().BeTrue(); ret.Result.Should().BeFalse(); - accountState = snapshot.TryGet(CreateStorageKey(20, G_Account)).GetInteroperable(); + accountState = clonedCache.TryGet(CreateStorageKey(20, G_Account)).GetInteroperable(); accountState.VoteTo.Should().Be(TestProtocolSettings.Default.StandbyValidators[0]); } [TestMethod] public void Check_GetCommittee() { - var snapshot = _snapshot.CloneCache(); - var keyCount = snapshot.GetChangeSet().Count(); + var clonedCache = _snapshotCache.CloneCache(); + var keyCount = clonedCache.GetChangeSet().Count(); var point = TestProtocolSettings.Default.StandbyValidators[0].EncodePoint(true); var persistingBlock = _persistingBlock; persistingBlock.Header.Index = 1; //register with votes with 20000000 var G_Account = Contract.CreateSignatureContract(ECCurve.Secp256r1.G).ScriptHash.ToArray(); - snapshot.Add(CreateStorageKey(20, G_Account), new StorageItem(new NeoAccountState())); - var accountState = snapshot.TryGet(CreateStorageKey(20, G_Account)).GetInteroperable(); + clonedCache.Add(CreateStorageKey(20, G_Account), new StorageItem(new NeoAccountState())); + var accountState = clonedCache.TryGet(CreateStorageKey(20, G_Account)).GetInteroperable(); accountState.Balance = 20000000; - var ret = Check_RegisterValidator(snapshot, ECCurve.Secp256r1.G.ToArray(), persistingBlock); + var ret = Check_RegisterValidator(clonedCache, ECCurve.Secp256r1.G.ToArray(), persistingBlock); ret.State.Should().BeTrue(); ret.Result.Should().BeTrue(); - ret = Check_Vote(snapshot, G_Account, ECCurve.Secp256r1.G.ToArray(), true, persistingBlock); + ret = Check_Vote(clonedCache, G_Account, ECCurve.Secp256r1.G.ToArray(), true, persistingBlock); ret.State.Should().BeTrue(); ret.Result.Should().BeTrue(); - var committeemembers = NativeContract.NEO.GetCommittee(snapshot); + var committeemembers = NativeContract.NEO.GetCommittee(clonedCache); var defaultCommittee = TestProtocolSettings.Default.StandbyCommittee.OrderBy(p => p).ToArray(); committeemembers.GetType().Should().Be(typeof(ECPoint[])); for (int i = 0; i < TestProtocolSettings.Default.CommitteeMembersCount; i++) @@ -368,14 +368,14 @@ public void Check_GetCommittee() }; for (int i = 0; i < TestProtocolSettings.Default.CommitteeMembersCount - 1; i++) { - ret = Check_RegisterValidator(snapshot, TestProtocolSettings.Default.StandbyCommittee[i].ToArray(), persistingBlock); + ret = Check_RegisterValidator(clonedCache, TestProtocolSettings.Default.StandbyCommittee[i].ToArray(), persistingBlock); ret.State.Should().BeTrue(); ret.Result.Should().BeTrue(); } - Check_OnPersist(snapshot, persistingBlock).Should().BeTrue(); + Check_OnPersist(clonedCache, persistingBlock).Should().BeTrue(); - committeemembers = NativeContract.NEO.GetCommittee(snapshot); + committeemembers = NativeContract.NEO.GetCommittee(clonedCache); committeemembers.Length.Should().Be(TestProtocolSettings.Default.CommitteeMembersCount); committeemembers.Contains(ECCurve.Secp256r1.G).Should().BeTrue(); for (int i = 0; i < TestProtocolSettings.Default.CommitteeMembersCount - 1; i++) @@ -388,79 +388,79 @@ public void Check_GetCommittee() [TestMethod] public void Check_Transfer() { - var snapshot = _snapshot.CloneCache(); + var clonedCache = _snapshotCache.CloneCache(); var persistingBlock = new Block { Header = new Header { Index = 1000 } }; byte[] from = Contract.GetBFTAddress(TestProtocolSettings.Default.StandbyValidators).ToArray(); byte[] to = new byte[20]; var storageKey = new KeyBuilder(NativeContract.Ledger.Id, 12); - snapshot.Add(storageKey, new StorageItem(new HashIndexState { Hash = UInt256.Zero, Index = persistingBlock.Index - 1 })); - var keyCount = snapshot.GetChangeSet().Count(); + clonedCache.Add(storageKey, new StorageItem(new HashIndexState { Hash = UInt256.Zero, Index = persistingBlock.Index - 1 })); + var keyCount = clonedCache.GetChangeSet().Count(); // Check unclaim - var unclaim = Check_UnclaimedGas(snapshot, from, persistingBlock); + var unclaim = Check_UnclaimedGas(clonedCache, from, persistingBlock); unclaim.Value.Should().Be(new BigInteger(0.5 * 1000 * 100000000L)); unclaim.State.Should().BeTrue(); // Transfer - NativeContract.NEO.Transfer(snapshot, from, to, BigInteger.One, false, persistingBlock).Should().BeFalse(); // Not signed - NativeContract.NEO.Transfer(snapshot, from, to, BigInteger.One, true, persistingBlock).Should().BeTrue(); - NativeContract.NEO.BalanceOf(snapshot, from).Should().Be(99999999); - NativeContract.NEO.BalanceOf(snapshot, to).Should().Be(1); + NativeContract.NEO.Transfer(clonedCache, from, to, BigInteger.One, false, persistingBlock).Should().BeFalse(); // Not signed + NativeContract.NEO.Transfer(clonedCache, from, to, BigInteger.One, true, persistingBlock).Should().BeTrue(); + NativeContract.NEO.BalanceOf(clonedCache, from).Should().Be(99999999); + NativeContract.NEO.BalanceOf(clonedCache, to).Should().Be(1); - var (from_balance, _, _) = GetAccountState(snapshot, new UInt160(from)); - var (to_balance, _, _) = GetAccountState(snapshot, new UInt160(to)); + var (from_balance, _, _) = GetAccountState(clonedCache, new UInt160(from)); + var (to_balance, _, _) = GetAccountState(clonedCache, new UInt160(to)); from_balance.Should().Be(99999999); to_balance.Should().Be(1); // Check unclaim - unclaim = Check_UnclaimedGas(snapshot, from, persistingBlock); + unclaim = Check_UnclaimedGas(clonedCache, from, persistingBlock); unclaim.Value.Should().Be(new BigInteger(0)); unclaim.State.Should().BeTrue(); - snapshot.GetChangeSet().Count().Should().Be(keyCount + 4); // Gas + new balance + clonedCache.GetChangeSet().Count().Should().Be(keyCount + 4); // Gas + new balance // Return balance - keyCount = snapshot.GetChangeSet().Count(); + keyCount = clonedCache.GetChangeSet().Count(); - NativeContract.NEO.Transfer(snapshot, to, from, BigInteger.One, true, persistingBlock).Should().BeTrue(); - NativeContract.NEO.BalanceOf(snapshot, to).Should().Be(0); - snapshot.GetChangeSet().Count().Should().Be(keyCount - 1); // Remove neo balance from address two + NativeContract.NEO.Transfer(clonedCache, to, from, BigInteger.One, true, persistingBlock).Should().BeTrue(); + NativeContract.NEO.BalanceOf(clonedCache, to).Should().Be(0); + clonedCache.GetChangeSet().Count().Should().Be(keyCount - 1); // Remove neo balance from address two // Bad inputs - Assert.ThrowsException(() => NativeContract.NEO.Transfer(snapshot, from, to, BigInteger.MinusOne, true, persistingBlock)); - Assert.ThrowsException(() => NativeContract.NEO.Transfer(snapshot, new byte[19], to, BigInteger.One, false, persistingBlock)); - Assert.ThrowsException(() => NativeContract.NEO.Transfer(snapshot, from, new byte[19], BigInteger.One, false, persistingBlock)); + Assert.ThrowsException(() => NativeContract.NEO.Transfer(clonedCache, from, to, BigInteger.MinusOne, true, persistingBlock)); + Assert.ThrowsException(() => NativeContract.NEO.Transfer(clonedCache, new byte[19], to, BigInteger.One, false, persistingBlock)); + Assert.ThrowsException(() => NativeContract.NEO.Transfer(clonedCache, from, new byte[19], BigInteger.One, false, persistingBlock)); // More than balance - NativeContract.NEO.Transfer(snapshot, to, from, new BigInteger(2), true, persistingBlock).Should().BeFalse(); + NativeContract.NEO.Transfer(clonedCache, to, from, new BigInteger(2), true, persistingBlock).Should().BeFalse(); } [TestMethod] public void Check_BalanceOf() { - var snapshot = _snapshot.CloneCache(); + var clonedCache = _snapshotCache.CloneCache(); byte[] account = Contract.GetBFTAddress(TestProtocolSettings.Default.StandbyValidators).ToArray(); - NativeContract.NEO.BalanceOf(snapshot, account).Should().Be(100_000_000); + NativeContract.NEO.BalanceOf(clonedCache, account).Should().Be(100_000_000); account[5]++; // Without existing balance - NativeContract.NEO.BalanceOf(snapshot, account).Should().Be(0); + NativeContract.NEO.BalanceOf(clonedCache, account).Should().Be(0); } [TestMethod] public void Check_CommitteeBonus() { - var snapshot = _snapshot.CloneCache(); + var clonedCache = _snapshotCache.CloneCache(); var persistingBlock = new Block { Header = new Header @@ -474,103 +474,103 @@ public void Check_CommitteeBonus() Transactions = Array.Empty() }; - Check_PostPersist(snapshot, persistingBlock).Should().BeTrue(); + Check_PostPersist(clonedCache, persistingBlock).Should().BeTrue(); var committee = TestProtocolSettings.Default.StandbyCommittee; - NativeContract.GAS.BalanceOf(snapshot, Contract.CreateSignatureContract(committee[0]).ScriptHash.ToArray()).Should().Be(50000000); - NativeContract.GAS.BalanceOf(snapshot, Contract.CreateSignatureContract(committee[1]).ScriptHash.ToArray()).Should().Be(50000000); - NativeContract.GAS.BalanceOf(snapshot, Contract.CreateSignatureContract(committee[2]).ScriptHash.ToArray()).Should().Be(0); + NativeContract.GAS.BalanceOf(clonedCache, Contract.CreateSignatureContract(committee[0]).ScriptHash.ToArray()).Should().Be(50000000); + NativeContract.GAS.BalanceOf(clonedCache, Contract.CreateSignatureContract(committee[1]).ScriptHash.ToArray()).Should().Be(50000000); + NativeContract.GAS.BalanceOf(clonedCache, Contract.CreateSignatureContract(committee[2]).ScriptHash.ToArray()).Should().Be(0); } [TestMethod] public void Check_Initialize() { - var snapshot = _snapshot.CloneCache(); + var clonedCache = _snapshotCache.CloneCache(); // StandbyValidators - Check_GetCommittee(snapshot, null); + Check_GetCommittee(clonedCache, null); } [TestMethod] public void TestCalculateBonus() { - var snapshot = _snapshot.CloneCache(); + var clonedCache = _snapshotCache.CloneCache(); var persistingBlock = new Block(); StorageKey key = CreateStorageKey(20, UInt160.Zero.ToArray()); // Fault: balance < 0 - snapshot.Add(key, new StorageItem(new NeoAccountState + clonedCache.Add(key, new StorageItem(new NeoAccountState { Balance = -100 })); - Action action = () => NativeContract.NEO.UnclaimedGas(snapshot, UInt160.Zero, 10).Should().Be(new BigInteger(0)); + Action action = () => NativeContract.NEO.UnclaimedGas(clonedCache, UInt160.Zero, 10).Should().Be(new BigInteger(0)); action.Should().Throw(); - snapshot.Delete(key); + clonedCache.Delete(key); // Fault range: start >= end - snapshot.GetAndChange(key, () => new StorageItem(new NeoAccountState + clonedCache.GetAndChange(key, () => new StorageItem(new NeoAccountState { Balance = 100, BalanceHeight = 100 })); - action = () => NativeContract.NEO.UnclaimedGas(snapshot, UInt160.Zero, 10).Should().Be(new BigInteger(0)); - snapshot.Delete(key); + action = () => NativeContract.NEO.UnclaimedGas(clonedCache, UInt160.Zero, 10).Should().Be(new BigInteger(0)); + clonedCache.Delete(key); // Fault range: start >= end - snapshot.GetAndChange(key, () => new StorageItem(new NeoAccountState + clonedCache.GetAndChange(key, () => new StorageItem(new NeoAccountState { Balance = 100, BalanceHeight = 100 })); - action = () => NativeContract.NEO.UnclaimedGas(snapshot, UInt160.Zero, 10).Should().Be(new BigInteger(0)); - snapshot.Delete(key); + action = () => NativeContract.NEO.UnclaimedGas(clonedCache, UInt160.Zero, 10).Should().Be(new BigInteger(0)); + clonedCache.Delete(key); // Normal 1) votee is non exist - snapshot.GetAndChange(key, () => new StorageItem(new NeoAccountState + clonedCache.GetAndChange(key, () => new StorageItem(new NeoAccountState { Balance = 100 })); var storageKey = new KeyBuilder(NativeContract.Ledger.Id, 12); - var item = snapshot.GetAndChange(storageKey).GetInteroperable(); + var item = clonedCache.GetAndChange(storageKey).GetInteroperable(); item.Index = 99; - NativeContract.NEO.UnclaimedGas(snapshot, UInt160.Zero, 100).Should().Be(new BigInteger(0.5 * 100 * 100)); - snapshot.Delete(key); + NativeContract.NEO.UnclaimedGas(clonedCache, UInt160.Zero, 100).Should().Be(new BigInteger(0.5 * 100 * 100)); + clonedCache.Delete(key); // Normal 2) votee is not committee - snapshot.GetAndChange(key, () => new StorageItem(new NeoAccountState + clonedCache.GetAndChange(key, () => new StorageItem(new NeoAccountState { Balance = 100, VoteTo = ECCurve.Secp256r1.G })); - NativeContract.NEO.UnclaimedGas(snapshot, UInt160.Zero, 100).Should().Be(new BigInteger(0.5 * 100 * 100)); - snapshot.Delete(key); + NativeContract.NEO.UnclaimedGas(clonedCache, UInt160.Zero, 100).Should().Be(new BigInteger(0.5 * 100 * 100)); + clonedCache.Delete(key); // Normal 3) votee is committee - snapshot.GetAndChange(key, () => new StorageItem(new NeoAccountState + clonedCache.GetAndChange(key, () => new StorageItem(new NeoAccountState { Balance = 100, VoteTo = TestProtocolSettings.Default.StandbyCommittee[0] })); - snapshot.Add(new KeyBuilder(NativeContract.NEO.Id, 23).Add(TestProtocolSettings.Default.StandbyCommittee[0]).AddBigEndian(uint.MaxValue - 50), new StorageItem() { Value = new BigInteger(50 * 10000L).ToByteArray() }); - NativeContract.NEO.UnclaimedGas(snapshot, UInt160.Zero, 100).Should().Be(new BigInteger(50 * 100)); - snapshot.Delete(key); + clonedCache.Add(new KeyBuilder(NativeContract.NEO.Id, 23).Add(TestProtocolSettings.Default.StandbyCommittee[0]).AddBigEndian(uint.MaxValue - 50), new StorageItem() { Value = new BigInteger(50 * 10000L).ToByteArray() }); + NativeContract.NEO.UnclaimedGas(clonedCache, UInt160.Zero, 100).Should().Be(new BigInteger(50 * 100)); + clonedCache.Delete(key); } [TestMethod] public void TestGetNextBlockValidators1() { - var snapshot = TestBlockchain.GetTestSnapshotCache(); - var result = (VM.Types.Array)NativeContract.NEO.Call(snapshot, "getNextBlockValidators"); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); + var result = (VM.Types.Array)NativeContract.NEO.Call(snapshotCache, "getNextBlockValidators"); result.Count.Should().Be(7); result[0].GetSpan().ToHexString().Should().Be("02486fd15702c4490a26703112a5cc1d0923fd697a33406bd5a1c00e0013b09a70"); result[1].GetSpan().ToHexString().Should().Be("024c7b7fb6c310fccf1ba33b082519d82964ea93868d676662d4a59ad548df0e7d"); @@ -584,8 +584,8 @@ public void TestGetNextBlockValidators1() [TestMethod] public void TestGetNextBlockValidators2() { - var snapshot = _snapshot.CloneCache(); - var result = NativeContract.NEO.GetNextBlockValidators(snapshot, 7); + var clonedCache = _snapshotCache.CloneCache(); + var result = NativeContract.NEO.GetNextBlockValidators(clonedCache, 7); result.Length.Should().Be(7); result[0].ToArray().ToHexString().Should().Be("02486fd15702c4490a26703112a5cc1d0923fd697a33406bd5a1c00e0013b09a70"); result[1].ToArray().ToHexString().Should().Be("024c7b7fb6c310fccf1ba33b082519d82964ea93868d676662d4a59ad548df0e7d"); @@ -599,40 +599,40 @@ public void TestGetNextBlockValidators2() [TestMethod] public void TestGetCandidates1() { - var snapshot = TestBlockchain.GetTestSnapshotCache(); - var array = (VM.Types.Array)NativeContract.NEO.Call(snapshot, "getCandidates"); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); + var array = (VM.Types.Array)NativeContract.NEO.Call(snapshotCache, "getCandidates"); array.Count.Should().Be(0); } [TestMethod] public void TestGetCandidates2() { - var snapshot = _snapshot.CloneCache(); - var result = NativeContract.NEO.GetCandidatesInternal(snapshot); + var clonedCache = _snapshotCache.CloneCache(); + var result = NativeContract.NEO.GetCandidatesInternal(clonedCache); result.Count().Should().Be(0); StorageKey key = NativeContract.NEO.CreateStorageKey(33, ECCurve.Secp256r1.G); - snapshot.Add(key, new StorageItem(new CandidateState() { Registered = true })); - NativeContract.NEO.GetCandidatesInternal(snapshot).Count().Should().Be(1); + clonedCache.Add(key, new StorageItem(new CandidateState() { Registered = true })); + NativeContract.NEO.GetCandidatesInternal(clonedCache).Count().Should().Be(1); } [TestMethod] public void TestCheckCandidate() { - var snapshot = _snapshot.CloneCache(); - var committee = NativeContract.NEO.GetCommittee(snapshot); + var cloneCache = _snapshotCache.CloneCache(); + var committee = NativeContract.NEO.GetCommittee(cloneCache); var point = committee[0].EncodePoint(true); // Prepare Prefix_VoterRewardPerCommittee var storageKey = new KeyBuilder(NativeContract.NEO.Id, 23).Add(committee[0]); - snapshot.Add(storageKey, new StorageItem(new BigInteger(1000))); + cloneCache.Add(storageKey, new StorageItem(new BigInteger(1000))); // Prepare Candidate storageKey = new KeyBuilder(NativeContract.NEO.Id, 33).Add(committee[0]); - snapshot.Add(storageKey, new StorageItem(new CandidateState { Registered = true, Votes = BigInteger.One })); + cloneCache.Add(storageKey, new StorageItem(new CandidateState { Registered = true, Votes = BigInteger.One })); storageKey = new KeyBuilder(NativeContract.NEO.Id, 23).Add(committee[0]); - snapshot.Find(storageKey.ToArray()).ToArray().Length.Should().Be(1); + cloneCache.Find(storageKey.ToArray()).ToArray().Length.Should().Be(1); // Pre-persist var persistingBlock = new Block @@ -647,32 +647,32 @@ public void TestCheckCandidate() }, Transactions = Array.Empty() }; - Check_OnPersist(snapshot, persistingBlock).Should().BeTrue(); + Check_OnPersist(cloneCache, persistingBlock).Should().BeTrue(); // Clear votes storageKey = new KeyBuilder(NativeContract.NEO.Id, 33).Add(committee[0]); - snapshot.GetAndChange(storageKey).GetInteroperable().Votes = BigInteger.Zero; + cloneCache.GetAndChange(storageKey).GetInteroperable().Votes = BigInteger.Zero; // Unregister candidate, remove - var ret = Check_UnregisterCandidate(snapshot, point, persistingBlock); + var ret = Check_UnregisterCandidate(cloneCache, point, persistingBlock); ret.State.Should().BeTrue(); ret.Result.Should().BeTrue(); storageKey = new KeyBuilder(NativeContract.NEO.Id, 23).Add(committee[0]); - snapshot.Find(storageKey.ToArray()).ToArray().Length.Should().Be(0); + cloneCache.Find(storageKey.ToArray()).ToArray().Length.Should().Be(0); // Post-persist - Check_PostPersist(snapshot, persistingBlock).Should().BeTrue(); + Check_PostPersist(cloneCache, persistingBlock).Should().BeTrue(); storageKey = new KeyBuilder(NativeContract.NEO.Id, 23).Add(committee[0]); - snapshot.Find(storageKey.ToArray()).ToArray().Length.Should().Be(1); + cloneCache.Find(storageKey.ToArray()).ToArray().Length.Should().Be(1); } [TestMethod] public void TestGetCommittee() { - var snapshot = TestBlockchain.GetTestSnapshotCache(); - var result = (VM.Types.Array)NativeContract.NEO.Call(snapshot, "getCommittee"); + var clonedCache = TestBlockchain.GetTestSnapshotCache(); + var result = (VM.Types.Array)NativeContract.NEO.Call(clonedCache, "getCommittee"); result.Count.Should().Be(21); result[0].GetSpan().ToHexString().Should().Be("020f2887f41474cfeb11fd262e982051c1541418137c02a0f4961af911045de639"); result[1].GetSpan().ToHexString().Should().Be("03204223f8c86b8cd5c89ef12e4f0dbb314172e9241e30c9ef2293790793537cf0"); @@ -700,8 +700,8 @@ public void TestGetCommittee() [TestMethod] public void TestGetValidators() { - var snapshot = _snapshot.CloneCache(); - var result = NativeContract.NEO.ComputeNextBlockValidators(snapshot, TestProtocolSettings.Default); + var clonedCache = _snapshotCache.CloneCache(); + var result = NativeContract.NEO.ComputeNextBlockValidators(clonedCache, TestProtocolSettings.Default); result[0].ToArray().ToHexString().Should().Be("02486fd15702c4490a26703112a5cc1d0923fd697a33406bd5a1c00e0013b09a70"); result[1].ToArray().ToHexString().Should().Be("024c7b7fb6c310fccf1ba33b082519d82964ea93868d676662d4a59ad548df0e7d"); result[2].ToArray().ToHexString().Should().Be("02aaec38470f6aad0042c6e877cfd8087d2676b0f516fddd362801b9bd3936399e"); @@ -730,64 +730,64 @@ public void TestOnBalanceChanging() [TestMethod] public void TestTotalSupply() { - var snapshot = _snapshot.CloneCache(); - NativeContract.NEO.TotalSupply(snapshot).Should().Be(new BigInteger(100000000)); + var clonedCache = _snapshotCache.CloneCache(); + NativeContract.NEO.TotalSupply(clonedCache).Should().Be(new BigInteger(100000000)); } [TestMethod] public void TestEconomicParameter() { const byte Prefix_CurrentBlock = 12; - var snapshot = _snapshot.CloneCache(); + var clonedCache = _snapshotCache.CloneCache(); var persistingBlock = new Block { Header = new Header() }; - (BigInteger, bool) result = Check_GetGasPerBlock(snapshot, persistingBlock); + (BigInteger, bool) result = Check_GetGasPerBlock(clonedCache, persistingBlock); result.Item2.Should().BeTrue(); result.Item1.Should().Be(5 * NativeContract.GAS.Factor); persistingBlock = new Block { Header = new Header { Index = 10 } }; - (VM.Types.Boolean, bool) result1 = Check_SetGasPerBlock(snapshot, 10 * NativeContract.GAS.Factor, persistingBlock); + (VM.Types.Boolean, bool) result1 = Check_SetGasPerBlock(clonedCache, 10 * NativeContract.GAS.Factor, persistingBlock); result1.Item2.Should().BeTrue(); result1.Item1.GetBoolean().Should().BeTrue(); - var height = snapshot[NativeContract.Ledger.CreateStorageKey(Prefix_CurrentBlock)].GetInteroperable(); + var height = clonedCache[NativeContract.Ledger.CreateStorageKey(Prefix_CurrentBlock)].GetInteroperable(); height.Index = persistingBlock.Index + 1; - result = Check_GetGasPerBlock(snapshot, persistingBlock); + result = Check_GetGasPerBlock(clonedCache, persistingBlock); result.Item2.Should().BeTrue(); result.Item1.Should().Be(10 * NativeContract.GAS.Factor); // Check calculate bonus - StorageItem storage = snapshot.GetOrAdd(CreateStorageKey(20, UInt160.Zero.ToArray()), () => new StorageItem(new NeoAccountState())); + StorageItem storage = clonedCache.GetOrAdd(CreateStorageKey(20, UInt160.Zero.ToArray()), () => new StorageItem(new NeoAccountState())); NeoAccountState state = storage.GetInteroperable(); state.Balance = 1000; state.BalanceHeight = 0; height.Index = persistingBlock.Index + 1; - NativeContract.NEO.UnclaimedGas(snapshot, UInt160.Zero, persistingBlock.Index + 2).Should().Be(6500); + NativeContract.NEO.UnclaimedGas(clonedCache, UInt160.Zero, persistingBlock.Index + 2).Should().Be(6500); } [TestMethod] public void TestClaimGas() { - var snapshot = _snapshot.CloneCache(); + var clonedCache = _snapshotCache.CloneCache(); // Initialize block - snapshot.Add(CreateStorageKey(1), new StorageItem(new BigInteger(30000000))); + clonedCache.Add(CreateStorageKey(1), new StorageItem(new BigInteger(30000000))); ECPoint[] standbyCommittee = TestProtocolSettings.Default.StandbyCommittee.OrderBy(p => p).ToArray(); CachedCommittee cachedCommittee = new(); for (var i = 0; i < TestProtocolSettings.Default.CommitteeMembersCount; i++) { ECPoint member = standbyCommittee[i]; - snapshot.Add(new KeyBuilder(NativeContract.NEO.Id, 33).Add(member), new StorageItem(new CandidateState() + clonedCache.Add(new KeyBuilder(NativeContract.NEO.Id, 33).Add(member), new StorageItem(new CandidateState() { Registered = true, Votes = 200 * 10000 })); cachedCommittee.Add((member, 200 * 10000)); } - snapshot.GetOrAdd(new KeyBuilder(NativeContract.NEO.Id, 14), () => new StorageItem()).Value = BinarySerializer.Serialize(cachedCommittee.ToStackItem(null), ExecutionEngineLimits.Default); + clonedCache.GetOrAdd(new KeyBuilder(NativeContract.NEO.Id, 14), () => new StorageItem()).Value = BinarySerializer.Serialize(cachedCommittee.ToStackItem(null), ExecutionEngineLimits.Default); - var item = snapshot.GetAndChange(new KeyBuilder(NativeContract.NEO.Id, 1), () => new StorageItem()); + var item = clonedCache.GetAndChange(new KeyBuilder(NativeContract.NEO.Id, 1), () => new StorageItem()); item.Value = ((BigInteger)2100 * 10000L).ToByteArray(); var persistingBlock = new Block @@ -802,17 +802,17 @@ public void TestClaimGas() }, Transactions = Array.Empty() }; - Check_PostPersist(snapshot, persistingBlock).Should().BeTrue(); + Check_PostPersist(clonedCache, persistingBlock).Should().BeTrue(); var committee = TestProtocolSettings.Default.StandbyCommittee.OrderBy(p => p).ToArray(); var accountA = committee[0]; var accountB = committee[TestProtocolSettings.Default.CommitteeMembersCount - 1]; - NativeContract.NEO.BalanceOf(snapshot, Contract.CreateSignatureContract(accountA).ScriptHash).Should().Be(0); + NativeContract.NEO.BalanceOf(clonedCache, Contract.CreateSignatureContract(accountA).ScriptHash).Should().Be(0); - StorageItem storageItem = snapshot.TryGet(new KeyBuilder(NativeContract.NEO.Id, 23).Add(accountA)); + StorageItem storageItem = clonedCache.TryGet(new KeyBuilder(NativeContract.NEO.Id, 23).Add(accountA)); ((BigInteger)storageItem).Should().Be(30000000000); - snapshot.TryGet(new KeyBuilder(NativeContract.NEO.Id, 23).Add(accountB).AddBigEndian(uint.MaxValue - 1)).Should().BeNull(); + clonedCache.TryGet(new KeyBuilder(NativeContract.NEO.Id, 23).Add(accountB).AddBigEndian(uint.MaxValue - 1)).Should().BeNull(); // Next block @@ -828,11 +828,11 @@ public void TestClaimGas() }, Transactions = Array.Empty() }; - Check_PostPersist(snapshot, persistingBlock).Should().BeTrue(); + Check_PostPersist(clonedCache, persistingBlock).Should().BeTrue(); - NativeContract.NEO.BalanceOf(snapshot, Contract.CreateSignatureContract(committee[1]).ScriptHash).Should().Be(0); + NativeContract.NEO.BalanceOf(clonedCache, Contract.CreateSignatureContract(committee[1]).ScriptHash).Should().Be(0); - storageItem = snapshot.TryGet(new KeyBuilder(NativeContract.NEO.Id, 23).Add(committee[1])); + storageItem = clonedCache.TryGet(new KeyBuilder(NativeContract.NEO.Id, 23).Add(committee[1])); ((BigInteger)storageItem).Should().Be(30000000000); // Next block @@ -849,99 +849,99 @@ public void TestClaimGas() }, Transactions = Array.Empty() }; - Check_PostPersist(snapshot, persistingBlock).Should().BeTrue(); + Check_PostPersist(clonedCache, persistingBlock).Should().BeTrue(); accountA = TestProtocolSettings.Default.StandbyCommittee.OrderBy(p => p).ToArray()[2]; - NativeContract.NEO.BalanceOf(snapshot, Contract.CreateSignatureContract(committee[2]).ScriptHash).Should().Be(0); + NativeContract.NEO.BalanceOf(clonedCache, Contract.CreateSignatureContract(committee[2]).ScriptHash).Should().Be(0); - storageItem = snapshot.TryGet(new KeyBuilder(NativeContract.NEO.Id, 23).Add(committee[2])); + storageItem = clonedCache.TryGet(new KeyBuilder(NativeContract.NEO.Id, 23).Add(committee[2])); ((BigInteger)storageItem).Should().Be(30000000000 * 2); // Claim GAS var account = Contract.CreateSignatureContract(committee[2]).ScriptHash; - snapshot.Add(new KeyBuilder(NativeContract.NEO.Id, 20).Add(account), new StorageItem(new NeoAccountState + clonedCache.Add(new KeyBuilder(NativeContract.NEO.Id, 20).Add(account), new StorageItem(new NeoAccountState { BalanceHeight = 3, Balance = 200 * 10000 - 2 * 100, VoteTo = committee[2], LastGasPerVote = 30000000000, })); - NativeContract.NEO.BalanceOf(snapshot, account).Should().Be(1999800); + NativeContract.NEO.BalanceOf(clonedCache, account).Should().Be(1999800); var storageKey = new KeyBuilder(NativeContract.Ledger.Id, 12); - snapshot.GetAndChange(storageKey).GetInteroperable().Index = 29 + 2; - BigInteger value = NativeContract.NEO.UnclaimedGas(snapshot, account, 29 + 3); + clonedCache.GetAndChange(storageKey).GetInteroperable().Index = 29 + 2; + BigInteger value = NativeContract.NEO.UnclaimedGas(clonedCache, account, 29 + 3); value.Should().Be(1999800 * 30000000000 / 100000000L + (1999800L * 10 * 5 * 29 / 100)); } [TestMethod] public void TestUnclaimedGas() { - var snapshot = _snapshot.CloneCache(); - NativeContract.NEO.UnclaimedGas(snapshot, UInt160.Zero, 10).Should().Be(new BigInteger(0)); - snapshot.Add(CreateStorageKey(20, UInt160.Zero.ToArray()), new StorageItem(new NeoAccountState())); - NativeContract.NEO.UnclaimedGas(snapshot, UInt160.Zero, 10).Should().Be(new BigInteger(0)); + var clonedCache = _snapshotCache.CloneCache(); + NativeContract.NEO.UnclaimedGas(clonedCache, UInt160.Zero, 10).Should().Be(new BigInteger(0)); + clonedCache.Add(CreateStorageKey(20, UInt160.Zero.ToArray()), new StorageItem(new NeoAccountState())); + NativeContract.NEO.UnclaimedGas(clonedCache, UInt160.Zero, 10).Should().Be(new BigInteger(0)); } [TestMethod] public void TestVote() { - var snapshot = _snapshot.CloneCache(); + var clonedCache = _snapshotCache.CloneCache(); UInt160 account = UInt160.Parse("01ff00ff00ff00ff00ff00ff00ff00ff00ff00a4"); StorageKey keyAccount = CreateStorageKey(20, account.ToArray()); StorageKey keyValidator = CreateStorageKey(33, ECCurve.Secp256r1.G.ToArray()); _persistingBlock.Header.Index = 1; - var ret = Check_Vote(snapshot, account.ToArray(), ECCurve.Secp256r1.G.ToArray(), false, _persistingBlock); + var ret = Check_Vote(clonedCache, account.ToArray(), ECCurve.Secp256r1.G.ToArray(), false, _persistingBlock); ret.State.Should().BeTrue(); ret.Result.Should().BeFalse(); - ret = Check_Vote(snapshot, account.ToArray(), ECCurve.Secp256r1.G.ToArray(), true, _persistingBlock); + ret = Check_Vote(clonedCache, account.ToArray(), ECCurve.Secp256r1.G.ToArray(), true, _persistingBlock); ret.State.Should().BeTrue(); ret.Result.Should().BeFalse(); - snapshot.Add(keyAccount, new StorageItem(new NeoAccountState())); - ret = Check_Vote(snapshot, account.ToArray(), ECCurve.Secp256r1.G.ToArray(), true, _persistingBlock); + clonedCache.Add(keyAccount, new StorageItem(new NeoAccountState())); + ret = Check_Vote(clonedCache, account.ToArray(), ECCurve.Secp256r1.G.ToArray(), true, _persistingBlock); ret.State.Should().BeTrue(); ret.Result.Should().BeFalse(); - var (_, _, vote_to_null) = GetAccountState(snapshot, account); + var (_, _, vote_to_null) = GetAccountState(clonedCache, account); vote_to_null.Should().BeNull(); - snapshot.Delete(keyAccount); - snapshot.GetAndChange(keyAccount, () => new StorageItem(new NeoAccountState + clonedCache.Delete(keyAccount); + clonedCache.GetAndChange(keyAccount, () => new StorageItem(new NeoAccountState { Balance = 1, VoteTo = ECCurve.Secp256r1.G })); - snapshot.Add(keyValidator, new StorageItem(new CandidateState() { Registered = true })); - ret = Check_Vote(snapshot, account.ToArray(), ECCurve.Secp256r1.G.ToArray(), true, _persistingBlock); + clonedCache.Add(keyValidator, new StorageItem(new CandidateState() { Registered = true })); + ret = Check_Vote(clonedCache, account.ToArray(), ECCurve.Secp256r1.G.ToArray(), true, _persistingBlock); ret.State.Should().BeTrue(); ret.Result.Should().BeTrue(); - var (_, _, voteto) = GetAccountState(snapshot, account); + var (_, _, voteto) = GetAccountState(clonedCache, account); voteto.ToHexString().Should().Be(ECCurve.Secp256r1.G.ToArray().ToHexString()); } internal (bool State, bool Result) Transfer4TesingOnBalanceChanging(BigInteger amount, bool addVotes) { - var snapshot = _snapshot.CloneCache(); + var clonedCache = _snapshotCache.CloneCache(); _persistingBlock.Header.Index = 1; - var engine = ApplicationEngine.Create(TriggerType.Application, TestBlockchain.TheNeoSystem.GenesisBlock, snapshot, _persistingBlock, settings: TestBlockchain.TheNeoSystem.Settings); + var engine = ApplicationEngine.Create(TriggerType.Application, TestBlockchain.TheNeoSystem.GenesisBlock, clonedCache, _persistingBlock, settings: TestBlockchain.TheNeoSystem.Settings); ScriptBuilder sb = new(); - var tmp = engine.ScriptContainer.GetScriptHashesForVerifying(engine.Snapshot); - UInt160 from = engine.ScriptContainer.GetScriptHashesForVerifying(engine.Snapshot)[0]; + var tmp = engine.ScriptContainer.GetScriptHashesForVerifying(engine.SnapshotCache); + UInt160 from = engine.ScriptContainer.GetScriptHashesForVerifying(engine.SnapshotCache)[0]; if (addVotes) { - snapshot.Add(CreateStorageKey(20, from.ToArray()), new StorageItem(new NeoAccountState + clonedCache.Add(CreateStorageKey(20, from.ToArray()), new StorageItem(new NeoAccountState { VoteTo = ECCurve.Secp256r1.G, Balance = new BigInteger(1000) })); - snapshot.Add(NativeContract.NEO.CreateStorageKey(33, ECCurve.Secp256r1.G), new StorageItem(new CandidateState())); + clonedCache.Add(NativeContract.NEO.CreateStorageKey(33, ECCurve.Secp256r1.G), new StorageItem(new CandidateState())); } else { - snapshot.Add(CreateStorageKey(20, from.ToArray()), new StorageItem(new NeoAccountState + clonedCache.Add(CreateStorageKey(20, from.ToArray()), new StorageItem(new NeoAccountState { Balance = new BigInteger(1000) })); @@ -956,29 +956,29 @@ public void TestVote() return (true, result.GetBoolean()); } - internal static bool Check_OnPersist(DataCache snapshot, Block persistingBlock) + internal static bool Check_OnPersist(DataCache clonedCache, Block persistingBlock) { var script = new ScriptBuilder(); script.EmitSysCall(ApplicationEngine.System_Contract_NativeOnPersist); - var engine = ApplicationEngine.Create(TriggerType.OnPersist, null, snapshot, persistingBlock, settings: TestBlockchain.TheNeoSystem.Settings); + var engine = ApplicationEngine.Create(TriggerType.OnPersist, null, clonedCache, persistingBlock, settings: TestBlockchain.TheNeoSystem.Settings); engine.LoadScript(script.ToArray()); return engine.Execute() == VMState.HALT; } - internal static bool Check_PostPersist(DataCache snapshot, Block persistingBlock) + internal static bool Check_PostPersist(DataCache clonedCache, Block persistingBlock) { using var script = new ScriptBuilder(); script.EmitSysCall(ApplicationEngine.System_Contract_NativePostPersist); - using var engine = ApplicationEngine.Create(TriggerType.PostPersist, null, snapshot, persistingBlock, settings: TestBlockchain.TheNeoSystem.Settings); + using var engine = ApplicationEngine.Create(TriggerType.PostPersist, null, clonedCache, persistingBlock, settings: TestBlockchain.TheNeoSystem.Settings); engine.LoadScript(script.ToArray()); return engine.Execute() == VMState.HALT; } - internal static (BigInteger Value, bool State) Check_GetGasPerBlock(DataCache snapshot, Block persistingBlock) + internal static (BigInteger Value, bool State) Check_GetGasPerBlock(DataCache clonedCache, Block persistingBlock) { - using var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, persistingBlock, settings: TestBlockchain.TheNeoSystem.Settings); + using var engine = ApplicationEngine.Create(TriggerType.Application, null, clonedCache, persistingBlock, settings: TestBlockchain.TheNeoSystem.Settings); using var script = new ScriptBuilder(); script.EmitDynamicCall(NativeContract.NEO.Hash, "getGasPerBlock"); @@ -995,10 +995,10 @@ internal static (BigInteger Value, bool State) Check_GetGasPerBlock(DataCache sn return (((VM.Types.Integer)result).GetInteger(), true); } - internal static (VM.Types.Boolean Value, bool State) Check_SetGasPerBlock(DataCache snapshot, BigInteger gasPerBlock, Block persistingBlock) + internal static (VM.Types.Boolean Value, bool State) Check_SetGasPerBlock(DataCache clonedCache, BigInteger gasPerBlock, Block persistingBlock) { - UInt160 committeeMultiSigAddr = NativeContract.NEO.GetCommitteeAddress(snapshot); - using var engine = ApplicationEngine.Create(TriggerType.Application, new Nep17NativeContractExtensions.ManualWitness(committeeMultiSigAddr), snapshot, persistingBlock, settings: TestBlockchain.TheNeoSystem.Settings); + UInt160 committeeMultiSigAddr = NativeContract.NEO.GetCommitteeAddress(clonedCache); + using var engine = ApplicationEngine.Create(TriggerType.Application, new Nep17NativeContractExtensions.ManualWitness(committeeMultiSigAddr), clonedCache, persistingBlock, settings: TestBlockchain.TheNeoSystem.Settings); var script = new ScriptBuilder(); script.EmitDynamicCall(NativeContract.NEO.Hash, "setGasPerBlock", gasPerBlock); @@ -1012,10 +1012,10 @@ internal static (VM.Types.Boolean Value, bool State) Check_SetGasPerBlock(DataCa return (true, true); } - internal static (bool State, bool Result) Check_Vote(DataCache snapshot, byte[] account, byte[] pubkey, bool signAccount, Block persistingBlock) + internal static (bool State, bool Result) Check_Vote(DataCache clonedCache, byte[] account, byte[] pubkey, bool signAccount, Block persistingBlock) { using var engine = ApplicationEngine.Create(TriggerType.Application, - new Nep17NativeContractExtensions.ManualWitness(signAccount ? new UInt160(account) : UInt160.Zero), snapshot, persistingBlock, settings: TestBlockchain.TheNeoSystem.Settings); + new Nep17NativeContractExtensions.ManualWitness(signAccount ? new UInt160(account) : UInt160.Zero), clonedCache, persistingBlock, settings: TestBlockchain.TheNeoSystem.Settings); using var script = new ScriptBuilder(); script.EmitDynamicCall(NativeContract.NEO.Hash, "vote", account, pubkey); @@ -1033,10 +1033,10 @@ internal static (bool State, bool Result) Check_Vote(DataCache snapshot, byte[] return (true, result.GetBoolean()); } - internal static (bool State, bool Result) Check_RegisterValidator(DataCache snapshot, byte[] pubkey, Block persistingBlock) + internal static (bool State, bool Result) Check_RegisterValidator(DataCache clonedCache, byte[] pubkey, Block persistingBlock) { using var engine = ApplicationEngine.Create(TriggerType.Application, - new Nep17NativeContractExtensions.ManualWitness(Contract.CreateSignatureRedeemScript(ECPoint.DecodePoint(pubkey, ECCurve.Secp256r1)).ToScriptHash()), snapshot, persistingBlock, settings: TestBlockchain.TheNeoSystem.Settings, gas: 1100_00000000); + new Nep17NativeContractExtensions.ManualWitness(Contract.CreateSignatureRedeemScript(ECPoint.DecodePoint(pubkey, ECCurve.Secp256r1)).ToScriptHash()), clonedCache, persistingBlock, settings: TestBlockchain.TheNeoSystem.Settings, gas: 1100_00000000); using var script = new ScriptBuilder(); script.EmitDynamicCall(NativeContract.NEO.Hash, "registerCandidate", pubkey); @@ -1053,9 +1053,9 @@ internal static (bool State, bool Result) Check_RegisterValidator(DataCache snap return (true, result.GetBoolean()); } - internal static ECPoint[] Check_GetCommittee(DataCache snapshot, Block persistingBlock) + internal static ECPoint[] Check_GetCommittee(DataCache clonedCache, Block persistingBlock) { - using var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, persistingBlock, settings: TestBlockchain.TheNeoSystem.Settings); + using var engine = ApplicationEngine.Create(TriggerType.Application, null, clonedCache, persistingBlock, settings: TestBlockchain.TheNeoSystem.Settings); using var script = new ScriptBuilder(); script.EmitDynamicCall(NativeContract.NEO.Hash, "getCommittee"); @@ -1069,9 +1069,9 @@ internal static ECPoint[] Check_GetCommittee(DataCache snapshot, Block persistin return (result as VM.Types.Array).Select(u => ECPoint.DecodePoint(u.GetSpan(), ECCurve.Secp256r1)).ToArray(); } - internal static (BigInteger Value, bool State) Check_UnclaimedGas(DataCache snapshot, byte[] address, Block persistingBlock) + internal static (BigInteger Value, bool State) Check_UnclaimedGas(DataCache clonedCache, byte[] address, Block persistingBlock) { - using var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, persistingBlock, settings: TestBlockchain.TheNeoSystem.Settings); + using var engine = ApplicationEngine.Create(TriggerType.Application, null, clonedCache, persistingBlock, settings: TestBlockchain.TheNeoSystem.Settings); using var script = new ScriptBuilder(); script.EmitDynamicCall(NativeContract.NEO.Hash, "unclaimedGas", address, persistingBlock.Index); @@ -1123,10 +1123,10 @@ internal static StorageKey CreateStorageKey(byte prefix, byte[] key = null) }; } - internal static (bool State, bool Result) Check_UnregisterCandidate(DataCache snapshot, byte[] pubkey, Block persistingBlock) + internal static (bool State, bool Result) Check_UnregisterCandidate(DataCache clonedCache, byte[] pubkey, Block persistingBlock) { using var engine = ApplicationEngine.Create(TriggerType.Application, - new Nep17NativeContractExtensions.ManualWitness(Contract.CreateSignatureRedeemScript(ECPoint.DecodePoint(pubkey, ECCurve.Secp256r1)).ToScriptHash()), snapshot, persistingBlock, settings: TestBlockchain.TheNeoSystem.Settings); + new Nep17NativeContractExtensions.ManualWitness(Contract.CreateSignatureRedeemScript(ECPoint.DecodePoint(pubkey, ECCurve.Secp256r1)).ToScriptHash()), clonedCache, persistingBlock, settings: TestBlockchain.TheNeoSystem.Settings); using var script = new ScriptBuilder(); script.EmitDynamicCall(NativeContract.NEO.Hash, "unregisterCandidate", pubkey); @@ -1143,9 +1143,9 @@ internal static (bool State, bool Result) Check_UnregisterCandidate(DataCache sn return (true, result.GetBoolean()); } - internal static (BigInteger balance, BigInteger height, byte[] voteto) GetAccountState(DataCache snapshot, UInt160 account) + internal static (BigInteger balance, BigInteger height, byte[] voteto) GetAccountState(DataCache clonedCache, UInt160 account) { - using var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, settings: TestBlockchain.TheNeoSystem.Settings); + using var engine = ApplicationEngine.Create(TriggerType.Application, null, clonedCache, settings: TestBlockchain.TheNeoSystem.Settings); using var script = new ScriptBuilder(); script.EmitDynamicCall(NativeContract.NEO.Hash, "getAccountState", account); diff --git a/tests/Neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs b/tests/Neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs index 62052ad4bf..745670977e 100644 --- a/tests/Neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs +++ b/tests/Neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs @@ -26,21 +26,21 @@ namespace Neo.UnitTests.SmartContract.Native [TestClass] public class UT_PolicyContract { - private DataCache _snapshot; + private DataCache _snapshotCache; [TestInitialize] public void TestSetup() { - _snapshot = TestBlockchain.GetTestSnapshotCache(); + _snapshotCache = TestBlockchain.GetTestSnapshotCache(); - ApplicationEngine engine = ApplicationEngine.Create(TriggerType.OnPersist, null, _snapshot, new Block { Header = new Header() }, settings: TestBlockchain.TheNeoSystem.Settings, gas: 0); + ApplicationEngine engine = ApplicationEngine.Create(TriggerType.OnPersist, null, _snapshotCache, new Block { Header = new Header() }, settings: TestBlockchain.TheNeoSystem.Settings, gas: 0); NativeContract.ContractManagement.OnPersistAsync(engine); } [TestMethod] public void Check_Default() { - var snapshot = _snapshot.CloneCache(); + var snapshot = _snapshotCache.CloneCache(); var ret = NativeContract.Policy.Call(snapshot, "getFeePerByte"); ret.Should().BeOfType(); @@ -56,7 +56,7 @@ public void Check_Default() [TestMethod] public void Check_SetAttributeFee() { - var snapshot = _snapshot.CloneCache(); + var snapshot = _snapshotCache.CloneCache(); // Fake blockchain Block block = new() @@ -115,7 +115,7 @@ public void Check_SetAttributeFee() [TestMethod] public void Check_SetFeePerByte() { - var snapshot = _snapshot.CloneCache(); + var snapshot = _snapshotCache.CloneCache(); // Fake blockchain @@ -154,7 +154,7 @@ public void Check_SetFeePerByte() [TestMethod] public void Check_SetBaseExecFee() { - var snapshot = _snapshot.CloneCache(); + var snapshot = _snapshotCache.CloneCache(); // Fake blockchain @@ -204,7 +204,7 @@ public void Check_SetBaseExecFee() [TestMethod] public void Check_SetStoragePrice() { - var snapshot = _snapshot.CloneCache(); + var snapshot = _snapshotCache.CloneCache(); // Fake blockchain @@ -254,7 +254,7 @@ public void Check_SetStoragePrice() [TestMethod] public void Check_BlockAccount() { - var snapshot = _snapshot.CloneCache(); + var snapshot = _snapshotCache.CloneCache(); // Fake blockchain @@ -310,7 +310,7 @@ public void Check_BlockAccount() [TestMethod] public void Check_Block_UnblockAccount() { - var snapshot = _snapshot.CloneCache(); + var snapshot = _snapshotCache.CloneCache(); // Fake blockchain diff --git a/tests/Neo.UnitTests/SmartContract/Native/UT_RoleManagement.cs b/tests/Neo.UnitTests/SmartContract/Native/UT_RoleManagement.cs index 1fbb2a47a0..ad3cb4b6c8 100644 --- a/tests/Neo.UnitTests/SmartContract/Native/UT_RoleManagement.cs +++ b/tests/Neo.UnitTests/SmartContract/Native/UT_RoleManagement.cs @@ -29,12 +29,12 @@ namespace Neo.UnitTests.SmartContract.Native [TestClass] public class UT_RoleManagement { - private DataCache _snapshot; + private DataCache _snapshotCache; [TestInitialize] public void TestSetup() { - _snapshot = TestBlockchain.GetTestSnapshotCache(); + _snapshotCache = TestBlockchain.GetTestSnapshotCache(); } [TestCleanup] @@ -62,7 +62,7 @@ public void TestSetAndGet() List roles = new List() { Role.StateValidator, Role.Oracle, Role.NeoFSAlphabetNode, Role.P2PNotary }; foreach (var role in roles) { - var snapshot1 = _snapshot.CloneCache(); + var snapshot1 = _snapshotCache.CloneCache(); UInt160 committeeMultiSigAddr = NativeContract.NEO.GetCommitteeAddress(snapshot1); List notifications = new List(); EventHandler ev = (o, e) => notifications.Add(e); @@ -79,7 +79,7 @@ public void TestSetAndGet() ApplicationEngine.Notify -= ev; notifications.Count.Should().Be(1); notifications[0].EventName.Should().Be("Designation"); - var snapshot2 = _snapshot.CloneCache(); + var snapshot2 = _snapshotCache.CloneCache(); ret = NativeContract.RoleManagement.Call( snapshot2, "getDesignatedByRole", diff --git a/tests/Neo.UnitTests/SmartContract/Native/UT_StdLib.cs b/tests/Neo.UnitTests/SmartContract/Native/UT_StdLib.cs index 28835aa55e..a13d2659ce 100644 --- a/tests/Neo.UnitTests/SmartContract/Native/UT_StdLib.cs +++ b/tests/Neo.UnitTests/SmartContract/Native/UT_StdLib.cs @@ -62,7 +62,7 @@ public void TestItoaAtoi() [TestMethod] public void MemoryCompare() { - var snapshot = TestBlockchain.GetTestSnapshotCache(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); using (var script = new ScriptBuilder()) { @@ -71,7 +71,7 @@ public void MemoryCompare() script.EmitDynamicCall(NativeContract.StdLib.Hash, "memoryCompare", "abc", "abc"); script.EmitDynamicCall(NativeContract.StdLib.Hash, "memoryCompare", "abc", "abcd"); - using var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, settings: TestBlockchain.TheNeoSystem.Settings); + using var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshotCache, settings: TestBlockchain.TheNeoSystem.Settings); engine.LoadScript(script.ToArray()); Assert.AreEqual(engine.Execute(), VMState.HALT); @@ -87,13 +87,13 @@ public void MemoryCompare() [TestMethod] public void CheckDecodeEncode() { - var snapshot = TestBlockchain.GetTestSnapshotCache(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); using (ScriptBuilder script = new()) { script.EmitDynamicCall(NativeContract.StdLib.Hash, "base58CheckEncode", new byte[] { 1, 2, 3 }); - using var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, settings: TestBlockchain.TheNeoSystem.Settings); + using var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshotCache, settings: TestBlockchain.TheNeoSystem.Settings); engine.LoadScript(script.ToArray()); Assert.AreEqual(engine.Execute(), VMState.HALT); @@ -106,7 +106,7 @@ public void CheckDecodeEncode() { script.EmitDynamicCall(NativeContract.StdLib.Hash, "base58CheckDecode", "3DUz7ncyT"); - using var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, settings: TestBlockchain.TheNeoSystem.Settings); + using var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshotCache, settings: TestBlockchain.TheNeoSystem.Settings); engine.LoadScript(script.ToArray()); Assert.AreEqual(engine.Execute(), VMState.HALT); @@ -121,7 +121,7 @@ public void CheckDecodeEncode() { script.EmitDynamicCall(NativeContract.StdLib.Hash, "base58CheckDecode", "AA"); - using var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, settings: TestBlockchain.TheNeoSystem.Settings); + using var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshotCache, settings: TestBlockchain.TheNeoSystem.Settings); engine.LoadScript(script.ToArray()); Assert.AreEqual(engine.Execute(), VMState.FAULT); @@ -131,7 +131,7 @@ public void CheckDecodeEncode() { script.EmitDynamicCall(NativeContract.StdLib.Hash, "base58CheckDecode", null); - using var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, settings: TestBlockchain.TheNeoSystem.Settings); + using var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshotCache, settings: TestBlockchain.TheNeoSystem.Settings); engine.LoadScript(script.ToArray()); Assert.AreEqual(engine.Execute(), VMState.FAULT); @@ -141,7 +141,7 @@ public void CheckDecodeEncode() [TestMethod] public void MemorySearch() { - var snapshot = TestBlockchain.GetTestSnapshotCache(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); using (var script = new ScriptBuilder()) { @@ -151,7 +151,7 @@ public void MemorySearch() script.EmitDynamicCall(NativeContract.StdLib.Hash, "memorySearch", "abc", "c", 3); script.EmitDynamicCall(NativeContract.StdLib.Hash, "memorySearch", "abc", "d", 0); - using var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, settings: TestBlockchain.TheNeoSystem.Settings); + using var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshotCache, settings: TestBlockchain.TheNeoSystem.Settings); engine.LoadScript(script.ToArray()); Assert.AreEqual(engine.Execute(), VMState.HALT); @@ -171,7 +171,7 @@ public void MemorySearch() script.EmitDynamicCall(NativeContract.StdLib.Hash, "memorySearch", "abc", "c", 3, false); script.EmitDynamicCall(NativeContract.StdLib.Hash, "memorySearch", "abc", "d", 0, false); - using var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, settings: TestBlockchain.TheNeoSystem.Settings); + using var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshotCache, settings: TestBlockchain.TheNeoSystem.Settings); engine.LoadScript(script.ToArray()); Assert.AreEqual(engine.Execute(), VMState.HALT); @@ -191,7 +191,7 @@ public void MemorySearch() script.EmitDynamicCall(NativeContract.StdLib.Hash, "memorySearch", "abc", "c", 3, true); script.EmitDynamicCall(NativeContract.StdLib.Hash, "memorySearch", "abc", "d", 0, true); - using var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, settings: TestBlockchain.TheNeoSystem.Settings); + using var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshotCache, settings: TestBlockchain.TheNeoSystem.Settings); engine.LoadScript(script.ToArray()); Assert.AreEqual(engine.Execute(), VMState.HALT); @@ -207,12 +207,12 @@ public void MemorySearch() [TestMethod] public void StringSplit() { - var snapshot = TestBlockchain.GetTestSnapshotCache(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); using var script = new ScriptBuilder(); script.EmitDynamicCall(NativeContract.StdLib.Hash, "stringSplit", "a,b", ","); - using var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, settings: TestBlockchain.TheNeoSystem.Settings); + using var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshotCache, settings: TestBlockchain.TheNeoSystem.Settings); engine.LoadScript(script.ToArray()); Assert.AreEqual(engine.Execute(), VMState.HALT); @@ -227,14 +227,14 @@ public void StringSplit() [TestMethod] public void StringElementLength() { - var snapshot = TestBlockchain.GetTestSnapshotCache(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); using var script = new ScriptBuilder(); script.EmitDynamicCall(NativeContract.StdLib.Hash, "strLen", "🦆"); script.EmitDynamicCall(NativeContract.StdLib.Hash, "strLen", "ã"); script.EmitDynamicCall(NativeContract.StdLib.Hash, "strLen", "a"); - using var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, settings: TestBlockchain.TheNeoSystem.Settings); + using var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshotCache, settings: TestBlockchain.TheNeoSystem.Settings); engine.LoadScript(script.ToArray()); Assert.AreEqual(engine.Execute(), VMState.HALT); @@ -250,13 +250,13 @@ public void TestInvalidUtf8Sequence() // Simulating invalid UTF-8 byte (0xff) decoded as a UTF-16 char const char badChar = (char)0xff; var badStr = badChar.ToString(); - var snapshot = TestBlockchain.GetTestSnapshotCache(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); using var script = new ScriptBuilder(); script.EmitDynamicCall(NativeContract.StdLib.Hash, "strLen", badStr); script.EmitDynamicCall(NativeContract.StdLib.Hash, "strLen", badStr + "ab"); - using var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, settings: TestBlockchain.TheNeoSystem.Settings); + using var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshotCache, settings: TestBlockchain.TheNeoSystem.Settings); engine.LoadScript(script.ToArray()); Assert.AreEqual(engine.Execute(), VMState.HALT); @@ -268,7 +268,7 @@ public void TestInvalidUtf8Sequence() [TestMethod] public void Json_Deserialize() { - var snapshot = TestBlockchain.GetTestSnapshotCache(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); // Good @@ -277,7 +277,7 @@ public void Json_Deserialize() script.EmitDynamicCall(NativeContract.StdLib.Hash, "jsonDeserialize", "123"); script.EmitDynamicCall(NativeContract.StdLib.Hash, "jsonDeserialize", "null"); - using var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, settings: TestBlockchain.TheNeoSystem.Settings); + using var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshotCache, settings: TestBlockchain.TheNeoSystem.Settings); engine.LoadScript(script.ToArray()); Assert.AreEqual(engine.Execute(), VMState.HALT); @@ -293,7 +293,7 @@ public void Json_Deserialize() { script.EmitDynamicCall(NativeContract.StdLib.Hash, "jsonDeserialize", "***"); - using var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, settings: TestBlockchain.TheNeoSystem.Settings); + using var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshotCache, settings: TestBlockchain.TheNeoSystem.Settings); engine.LoadScript(script.ToArray()); Assert.AreEqual(engine.Execute(), VMState.FAULT); @@ -306,7 +306,7 @@ public void Json_Deserialize() { script.EmitDynamicCall(NativeContract.StdLib.Hash, "jsonDeserialize", "123.45"); - using var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, settings: TestBlockchain.TheNeoSystem.Settings); + using var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshotCache, settings: TestBlockchain.TheNeoSystem.Settings); engine.LoadScript(script.ToArray()); Assert.AreEqual(engine.Execute(), VMState.FAULT); @@ -317,7 +317,7 @@ public void Json_Deserialize() [TestMethod] public void Json_Serialize() { - var snapshot = TestBlockchain.GetTestSnapshotCache(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); // Good @@ -337,7 +337,7 @@ public void Json_Serialize() } }); - using var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, settings: TestBlockchain.TheNeoSystem.Settings); + using var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshotCache, settings: TestBlockchain.TheNeoSystem.Settings); engine.LoadScript(script.ToArray()); Assert.AreEqual(engine.Execute(), VMState.HALT); @@ -356,7 +356,7 @@ public void Json_Serialize() { script.EmitDynamicCall(NativeContract.StdLib.Hash, "jsonSerialize"); - using var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, settings: TestBlockchain.TheNeoSystem.Settings); + using var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshotCache, settings: TestBlockchain.TheNeoSystem.Settings); engine.LoadScript(script.ToArray()); Assert.AreEqual(engine.Execute(), VMState.FAULT); @@ -367,7 +367,7 @@ public void Json_Serialize() [TestMethod] public void TestRuntime_Serialize() { - var snapshot = TestBlockchain.GetTestSnapshotCache(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); // Good @@ -375,7 +375,7 @@ public void TestRuntime_Serialize() script.EmitDynamicCall(NativeContract.StdLib.Hash, "serialize", 100); script.EmitDynamicCall(NativeContract.StdLib.Hash, "serialize", "test"); - using var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, settings: TestBlockchain.TheNeoSystem.Settings); + using var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshotCache, settings: TestBlockchain.TheNeoSystem.Settings); engine.LoadScript(script.ToArray()); Assert.AreEqual(engine.Execute(), VMState.HALT); @@ -388,7 +388,7 @@ public void TestRuntime_Serialize() [TestMethod] public void TestRuntime_Deserialize() { - var snapshot = TestBlockchain.GetTestSnapshotCache(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); // Good @@ -396,7 +396,7 @@ public void TestRuntime_Deserialize() script.EmitDynamicCall(NativeContract.StdLib.Hash, "deserialize", "280474657374".HexToBytes()); script.EmitDynamicCall(NativeContract.StdLib.Hash, "deserialize", "210164".HexToBytes()); - using var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, settings: TestBlockchain.TheNeoSystem.Settings); + using var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshotCache, settings: TestBlockchain.TheNeoSystem.Settings); engine.LoadScript(script.ToArray()); Assert.AreEqual(engine.Execute(), VMState.HALT); diff --git a/tests/Neo.UnitTests/SmartContract/UT_ApplicationEngine.cs b/tests/Neo.UnitTests/SmartContract/UT_ApplicationEngine.cs index 9a150c2b22..a670e3b4b7 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_ApplicationEngine.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_ApplicationEngine.cs @@ -30,8 +30,8 @@ public partial class UT_ApplicationEngine [TestMethod] public void TestNotify() { - var snapshot = TestBlockchain.GetTestSnapshotCache(); - using var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, settings: TestBlockchain.TheNeoSystem.Settings); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); + using var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshotCache, settings: TestBlockchain.TheNeoSystem.Settings); engine.LoadScript(System.Array.Empty()); ApplicationEngine.Notify += Test_Notify1; const string notifyEvent = "TestEvent"; @@ -66,9 +66,9 @@ private void Test_Notify2(object sender, NotifyEventArgs e) [TestMethod] public void TestCreateDummyBlock() { - var snapshot = TestBlockchain.GetTestSnapshotCache(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); byte[] SyscallSystemRuntimeCheckWitnessHash = new byte[] { 0x68, 0xf8, 0x27, 0xec, 0x8c }; - ApplicationEngine engine = ApplicationEngine.Run(SyscallSystemRuntimeCheckWitnessHash, snapshot, settings: TestProtocolSettings.Default); + ApplicationEngine engine = ApplicationEngine.Run(SyscallSystemRuntimeCheckWitnessHash, snapshotCache, settings: TestProtocolSettings.Default); engine.PersistingBlock.Version.Should().Be(0); engine.PersistingBlock.PrevHash.Should().Be(TestBlockchain.TheNeoSystem.GenesisBlock.Hash); engine.PersistingBlock.MerkleRoot.Should().Be(new UInt256()); @@ -111,7 +111,7 @@ public void TestCheckingHardfork() public void TestSystem_Contract_Call_Permissions() { UInt160 scriptHash; - var snapshot = TestBlockchain.GetTestSnapshotCache(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); // Setup: put a simple contract to the storage. using (var script = new ScriptBuilder()) @@ -123,7 +123,7 @@ public void TestSystem_Contract_Call_Permissions() // Mock contract and put it to the Managemant's storage. scriptHash = script.ToArray().ToScriptHash(); - snapshot.DeleteContract(scriptHash); + snapshotCache.DeleteContract(scriptHash); var contract = TestUtils.GetContract(script.ToArray(), TestUtils.CreateManifest("test", ContractParameterType.Any)); contract.Manifest.Abi.Methods = new[] { @@ -138,11 +138,11 @@ public void TestSystem_Contract_Call_Permissions() Parameters = new ContractParameterDefinition[]{} } }; - snapshot.AddContract(scriptHash, contract); + snapshotCache.AddContract(scriptHash, contract); } // Disallowed method call. - using (var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, null, ProtocolSettings.Default)) + using (var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshotCache, null, ProtocolSettings.Default)) using (var script = new ScriptBuilder()) { // Build call script calling disallowed method. @@ -172,7 +172,7 @@ public void TestSystem_Contract_Call_Permissions() } // Allowed method call. - using (var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, null, ProtocolSettings.Default)) + using (var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshotCache, null, ProtocolSettings.Default)) using (var script = new ScriptBuilder()) { // Build call script. diff --git a/tests/Neo.UnitTests/SmartContract/UT_ApplicationEngineProvider.cs b/tests/Neo.UnitTests/SmartContract/UT_ApplicationEngineProvider.cs index 75fc558669..1d9da111e1 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_ApplicationEngineProvider.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_ApplicationEngineProvider.cs @@ -59,8 +59,8 @@ public ApplicationEngine Create(TriggerType trigger, IVerifiable container, Data class TestEngine : ApplicationEngine { - public TestEngine(TriggerType trigger, IVerifiable container, DataCache snapshot, Block persistingBlock, ProtocolSettings settings, long gas, IDiagnostic diagnostic, JumpTable jumpTable) - : base(trigger, container, snapshot, persistingBlock, settings, gas, diagnostic, jumpTable) + public TestEngine(TriggerType trigger, IVerifiable container, DataCache snapshotCache, Block persistingBlock, ProtocolSettings settings, long gas, IDiagnostic diagnostic, JumpTable jumpTable) + : base(trigger, container, snapshotCache, persistingBlock, settings, gas, diagnostic, jumpTable) { } } diff --git a/tests/Neo.UnitTests/SmartContract/UT_ContractParameterContext.cs b/tests/Neo.UnitTests/SmartContract/UT_ContractParameterContext.cs index 8d22a0391c..9523c41be4 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_ContractParameterContext.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_ContractParameterContext.cs @@ -43,18 +43,18 @@ public static void ClassSetUp(TestContext ctx) [TestMethod] public void TestGetComplete() { - var snapshot = TestBlockchain.GetTestSnapshotCache(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); Transaction tx = TestUtils.GetTransaction(UInt160.Parse("0x1bd5c777ec35768892bd3daab60fb7a1cb905066")); - var context = new ContractParametersContext(snapshot, tx, TestProtocolSettings.Default.Network); + var context = new ContractParametersContext(snapshotCache, tx, TestProtocolSettings.Default.Network); context.Completed.Should().BeFalse(); } [TestMethod] public void TestToString() { - var snapshot = TestBlockchain.GetTestSnapshotCache(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); Transaction tx = TestUtils.GetTransaction(UInt160.Parse("0x1bd5c777ec35768892bd3daab60fb7a1cb905066")); - var context = new ContractParametersContext(snapshot, tx, TestProtocolSettings.Default.Network); + var context = new ContractParametersContext(snapshotCache, tx, TestProtocolSettings.Default.Network); context.Add(contract, 0, new byte[] { 0x01 }); string str = context.ToString(); str.Should().Be(@"{""type"":""Neo.Network.P2P.Payloads.Transaction"",""hash"":""0x602c1fa1c08b041e4e6b87aa9a9f9c643166cd34bdd5215a3dd85778c59cce88"",""data"":""AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFmUJDLobcPtqo9vZKIdjXsd8fVGwEAARI="",""items"":{},""network"":" + TestProtocolSettings.Default.Network + "}"); @@ -63,8 +63,8 @@ public void TestToString() [TestMethod] public void TestParse() { - var snapshot = TestBlockchain.GetTestSnapshotCache(); - var ret = ContractParametersContext.Parse("{\"type\":\"Neo.Network.P2P.Payloads.Transaction\",\"data\":\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFmUJDLobcPtqo9vZKIdjXsd8fVGwEAARI=\",\"items\":{\"0xbecaad15c0ea585211faf99738a4354014f177f2\":{\"script\":\"IQJv8DuUkkHOHa3UNRnmlg4KhbQaaaBcMoEDqivOFZTKFmh0dHaq\",\"parameters\":[{\"type\":\"Signature\",\"value\":\"AQ==\"}],\"signatures\":{\"03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c\":\"AQ==\"}}},\"network\":" + TestProtocolSettings.Default.Network + "}", snapshot); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); + var ret = ContractParametersContext.Parse("{\"type\":\"Neo.Network.P2P.Payloads.Transaction\",\"data\":\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFmUJDLobcPtqo9vZKIdjXsd8fVGwEAARI=\",\"items\":{\"0xbecaad15c0ea585211faf99738a4354014f177f2\":{\"script\":\"IQJv8DuUkkHOHa3UNRnmlg4KhbQaaaBcMoEDqivOFZTKFmh0dHaq\",\"parameters\":[{\"type\":\"Signature\",\"value\":\"AQ==\"}],\"signatures\":{\"03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c\":\"AQ==\"}}},\"network\":" + TestProtocolSettings.Default.Network + "}", snapshotCache); ret.ScriptHashes[0].ToString().Should().Be("0x1bd5c777ec35768892bd3daab60fb7a1cb905066"); ((Transaction)ret.Verifiable).Script.Span.ToHexString().Should().Be(new byte[] { 18 }.ToHexString()); } @@ -72,21 +72,21 @@ public void TestParse() [TestMethod] public void TestFromJson() { - var snapshot = TestBlockchain.GetTestSnapshotCache(); - Action action = () => ContractParametersContext.Parse("{\"type\":\"wrongType\",\"data\":\"00000000007c97764845172d827d3c863743293931a691271a0000000000000000000000000000000000000000000100\",\"items\":{\"0x1bd5c777ec35768892bd3daab60fb7a1cb905066\":{\"script\":\"21026ff03b949241ce1dadd43519e6960e0a85b41a69a05c328103aa2bce1594ca1650680a906ad4\",\"parameters\":[{\"type\":\"Signature\",\"value\":\"01\"}]}}}", snapshot); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); + Action action = () => ContractParametersContext.Parse("{\"type\":\"wrongType\",\"data\":\"00000000007c97764845172d827d3c863743293931a691271a0000000000000000000000000000000000000000000100\",\"items\":{\"0x1bd5c777ec35768892bd3daab60fb7a1cb905066\":{\"script\":\"21026ff03b949241ce1dadd43519e6960e0a85b41a69a05c328103aa2bce1594ca1650680a906ad4\",\"parameters\":[{\"type\":\"Signature\",\"value\":\"01\"}]}}}", snapshotCache); action.Should().Throw(); } [TestMethod] public void TestAdd() { - var snapshot = TestBlockchain.GetTestSnapshotCache(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); Transaction tx = TestUtils.GetTransaction(UInt160.Zero); - var context1 = new ContractParametersContext(snapshot, tx, TestProtocolSettings.Default.Network); + var context1 = new ContractParametersContext(snapshotCache, tx, TestProtocolSettings.Default.Network); context1.Add(contract, 0, new byte[] { 0x01 }).Should().BeFalse(); tx = TestUtils.GetTransaction(UInt160.Parse("0x902e0d38da5e513b6d07c1c55b85e77d3dce8063")); - var context2 = new ContractParametersContext(snapshot, tx, TestProtocolSettings.Default.Network); + var context2 = new ContractParametersContext(snapshotCache, tx, TestProtocolSettings.Default.Network); context2.Add(contract, 0, new byte[] { 0x01 }).Should().BeTrue(); //test repeatlly createItem context2.Add(contract, 0, new byte[] { 0x01 }).Should().BeTrue(); @@ -95,9 +95,9 @@ public void TestAdd() [TestMethod] public void TestGetParameter() { - var snapshot = TestBlockchain.GetTestSnapshotCache(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); Transaction tx = TestUtils.GetTransaction(UInt160.Parse("0x902e0d38da5e513b6d07c1c55b85e77d3dce8063")); - var context = new ContractParametersContext(snapshot, tx, TestProtocolSettings.Default.Network); + var context = new ContractParametersContext(snapshotCache, tx, TestProtocolSettings.Default.Network); context.GetParameter(tx.Sender, 0).Should().BeNull(); context.Add(contract, 0, new byte[] { 0x01 }); @@ -108,9 +108,9 @@ public void TestGetParameter() [TestMethod] public void TestGetWitnesses() { - var snapshot = TestBlockchain.GetTestSnapshotCache(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); Transaction tx = TestUtils.GetTransaction(UInt160.Parse("0x902e0d38da5e513b6d07c1c55b85e77d3dce8063")); - var context = new ContractParametersContext(snapshot, tx, TestProtocolSettings.Default.Network); + var context = new ContractParametersContext(snapshotCache, tx, TestProtocolSettings.Default.Network); context.Add(contract, 0, new byte[] { 0x01 }); Witness[] witnesses = context.GetWitnesses(); witnesses.Length.Should().Be(1); @@ -121,18 +121,18 @@ public void TestGetWitnesses() [TestMethod] public void TestAddSignature() { - var snapshot = TestBlockchain.GetTestSnapshotCache(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); var singleSender = UInt160.Parse("0x902e0d38da5e513b6d07c1c55b85e77d3dce8063"); Transaction tx = TestUtils.GetTransaction(singleSender); //singleSign - var context = new ContractParametersContext(snapshot, tx, TestProtocolSettings.Default.Network); + var context = new ContractParametersContext(snapshotCache, tx, TestProtocolSettings.Default.Network); context.AddSignature(contract, key.PublicKey, new byte[] { 0x01 }).Should().BeTrue(); var contract1 = Contract.CreateSignatureContract(key.PublicKey); contract1.ParameterList = Array.Empty(); - context = new ContractParametersContext(snapshot, tx, TestProtocolSettings.Default.Network); + context = new ContractParametersContext(snapshotCache, tx, TestProtocolSettings.Default.Network); context.AddSignature(contract1, key.PublicKey, new byte[] { 0x01 }).Should().BeFalse(); contract1.ParameterList = new[] { ContractParameterType.Signature, ContractParameterType.Signature }; @@ -154,16 +154,16 @@ public void TestAddSignature() }); var multiSender = UInt160.Parse("0xf76b51bc6605ac3cfcd188173af0930507f51210"); tx = TestUtils.GetTransaction(multiSender); - context = new ContractParametersContext(snapshot, tx, TestProtocolSettings.Default.Network); + context = new ContractParametersContext(snapshotCache, tx, TestProtocolSettings.Default.Network); context.AddSignature(multiSignContract, key.PublicKey, new byte[] { 0x01 }).Should().BeTrue(); context.AddSignature(multiSignContract, key2.PublicKey, new byte[] { 0x01 }).Should().BeTrue(); tx = TestUtils.GetTransaction(singleSender); - context = new ContractParametersContext(snapshot, tx, TestProtocolSettings.Default.Network); + context = new ContractParametersContext(snapshotCache, tx, TestProtocolSettings.Default.Network); context.AddSignature(multiSignContract, key.PublicKey, new byte[] { 0x01 }).Should().BeFalse(); tx = TestUtils.GetTransaction(multiSender); - context = new ContractParametersContext(snapshot, tx, TestProtocolSettings.Default.Network); + context = new ContractParametersContext(snapshotCache, tx, TestProtocolSettings.Default.Network); byte[] privateKey3 = new byte[] { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, diff --git a/tests/Neo.UnitTests/SmartContract/UT_InteropPrices.cs b/tests/Neo.UnitTests/SmartContract/UT_InteropPrices.cs index fff5ef1877..dfc685f335 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_InteropPrices.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_InteropPrices.cs @@ -64,11 +64,11 @@ public void ApplicationEngineRegularPut() StorageKey skey = TestUtils.GetStorageKey(contractState.Id, key); StorageItem sItem = TestUtils.GetStorageItem(System.Array.Empty()); - var snapshot = TestBlockchain.GetTestSnapshotCache(); - snapshot.Add(skey, sItem); - snapshot.AddContract(script.ToScriptHash(), contractState); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); + snapshotCache.Add(skey, sItem); + snapshotCache.AddContract(script.ToScriptHash(), contractState); - using ApplicationEngine ae = ApplicationEngine.Create(TriggerType.Application, null, snapshot); + using ApplicationEngine ae = ApplicationEngine.Create(TriggerType.Application, null, snapshotCache); Debugger debugger = new(ae); ae.LoadScript(script); debugger.StepInto(); @@ -95,11 +95,11 @@ public void ApplicationEngineReusedStorage_FullReuse() StorageKey skey = TestUtils.GetStorageKey(contractState.Id, key); StorageItem sItem = TestUtils.GetStorageItem(value); - var snapshot = TestBlockchain.GetTestSnapshotCache(); - snapshot.Add(skey, sItem); - snapshot.AddContract(script.ToScriptHash(), contractState); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); + snapshotCache.Add(skey, sItem); + snapshotCache.AddContract(script.ToScriptHash(), contractState); - using ApplicationEngine applicationEngine = ApplicationEngine.Create(TriggerType.Application, null, snapshot); + using ApplicationEngine applicationEngine = ApplicationEngine.Create(TriggerType.Application, null, snapshotCache); Debugger debugger = new(applicationEngine); applicationEngine.LoadScript(script); debugger.StepInto(); @@ -128,11 +128,11 @@ public void ApplicationEngineReusedStorage_PartialReuse() StorageKey skey = TestUtils.GetStorageKey(contractState.Id, key); StorageItem sItem = TestUtils.GetStorageItem(oldValue); - var snapshot = TestBlockchain.GetTestSnapshotCache(); - snapshot.Add(skey, sItem); - snapshot.AddContract(script.ToScriptHash(), contractState); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); + snapshotCache.Add(skey, sItem); + snapshotCache.AddContract(script.ToScriptHash(), contractState); - using ApplicationEngine ae = ApplicationEngine.Create(TriggerType.Application, null, snapshot); + using ApplicationEngine ae = ApplicationEngine.Create(TriggerType.Application, null, snapshotCache); Debugger debugger = new(ae); ae.LoadScript(script); debugger.StepInto(); @@ -162,11 +162,11 @@ public void ApplicationEngineReusedStorage_PartialReuseTwice() StorageKey skey = TestUtils.GetStorageKey(contractState.Id, key); StorageItem sItem = TestUtils.GetStorageItem(oldValue); - var snapshot = TestBlockchain.GetTestSnapshotCache(); - snapshot.Add(skey, sItem); - snapshot.AddContract(script.ToScriptHash(), contractState); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); + snapshotCache.Add(skey, sItem); + snapshotCache.AddContract(script.ToScriptHash(), contractState); - using ApplicationEngine ae = ApplicationEngine.Create(TriggerType.Application, null, snapshot); + using ApplicationEngine ae = ApplicationEngine.Create(TriggerType.Application, null, snapshotCache); Debugger debugger = new(ae); ae.LoadScript(script); debugger.StepInto(); //push value diff --git a/tests/Neo.UnitTests/SmartContract/UT_InteropService.NEO.cs b/tests/Neo.UnitTests/SmartContract/UT_InteropService.NEO.cs index a2e22dbff3..657206ab57 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_InteropService.NEO.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_InteropService.NEO.cs @@ -113,7 +113,7 @@ public void TestCrypto_CheckMultiSig() [TestMethod] public void TestContract_Create() { - var snapshot = TestBlockchain.GetTestSnapshotCache(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); var nef = new NefFile() { Script = Enumerable.Repeat((byte)OpCode.RET, byte.MaxValue).ToArray(), @@ -124,9 +124,9 @@ public void TestContract_Create() nef.CheckSum = NefFile.ComputeChecksum(nef); var nefFile = nef.ToArray(); var manifest = TestUtils.CreateDefaultManifest(); - Assert.ThrowsException(() => snapshot.DeployContract(null, nefFile, manifest.ToJson().ToByteArray(false))); - Assert.ThrowsException(() => snapshot.DeployContract(UInt160.Zero, nefFile, new byte[ContractManifest.MaxLength + 1])); - Assert.ThrowsException(() => snapshot.DeployContract(UInt160.Zero, nefFile, manifest.ToJson().ToByteArray(true), 10000000)); + Assert.ThrowsException(() => snapshotCache.DeployContract(null, nefFile, manifest.ToJson().ToByteArray(false))); + Assert.ThrowsException(() => snapshotCache.DeployContract(UInt160.Zero, nefFile, new byte[ContractManifest.MaxLength + 1])); + Assert.ThrowsException(() => snapshotCache.DeployContract(UInt160.Zero, nefFile, manifest.ToJson().ToByteArray(true), 10000000)); var script_exceedMaxLength = new NefFile() { @@ -138,29 +138,29 @@ public void TestContract_Create() script_exceedMaxLength.CheckSum = NefFile.ComputeChecksum(script_exceedMaxLength); Assert.ThrowsException(() => script_exceedMaxLength.ToArray().AsSerializable()); - Assert.ThrowsException(() => snapshot.DeployContract(UInt160.Zero, script_exceedMaxLength.ToArray(), manifest.ToJson().ToByteArray(true))); + Assert.ThrowsException(() => snapshotCache.DeployContract(UInt160.Zero, script_exceedMaxLength.ToArray(), manifest.ToJson().ToByteArray(true))); var script_zeroLength = System.Array.Empty(); - Assert.ThrowsException(() => snapshot.DeployContract(UInt160.Zero, script_zeroLength, manifest.ToJson().ToByteArray(true))); + Assert.ThrowsException(() => snapshotCache.DeployContract(UInt160.Zero, script_zeroLength, manifest.ToJson().ToByteArray(true))); var manifest_zeroLength = System.Array.Empty(); - Assert.ThrowsException(() => snapshot.DeployContract(UInt160.Zero, nefFile, manifest_zeroLength)); + Assert.ThrowsException(() => snapshotCache.DeployContract(UInt160.Zero, nefFile, manifest_zeroLength)); manifest = TestUtils.CreateDefaultManifest(); - var ret = snapshot.DeployContract(UInt160.Zero, nefFile, manifest.ToJson().ToByteArray(false)); + var ret = snapshotCache.DeployContract(UInt160.Zero, nefFile, manifest.ToJson().ToByteArray(false)); ret.Hash.ToString().Should().Be("0x7b37d4bd3d87f53825c3554bd1a617318235a685"); - Assert.ThrowsException(() => snapshot.DeployContract(UInt160.Zero, nefFile, manifest.ToJson().ToByteArray(false))); + Assert.ThrowsException(() => snapshotCache.DeployContract(UInt160.Zero, nefFile, manifest.ToJson().ToByteArray(false))); var state = TestUtils.GetContract(); - snapshot.AddContract(state.Hash, state); + snapshotCache.AddContract(state.Hash, state); - Assert.ThrowsException(() => snapshot.DeployContract(UInt160.Zero, nefFile, manifest.ToJson().ToByteArray(false))); + Assert.ThrowsException(() => snapshotCache.DeployContract(UInt160.Zero, nefFile, manifest.ToJson().ToByteArray(false))); } [TestMethod] public void TestContract_Update() { - var snapshot = TestBlockchain.GetTestSnapshotCache(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); var nef = new NefFile() { Script = new[] { (byte)OpCode.RET }, @@ -169,7 +169,7 @@ public void TestContract_Update() Tokens = Array.Empty() }; nef.CheckSum = NefFile.ComputeChecksum(nef); - Assert.ThrowsException(() => snapshot.UpdateContract(null, nef.ToArray(), new byte[0])); + Assert.ThrowsException(() => snapshotCache.UpdateContract(null, nef.ToArray(), new byte[0])); var manifest = TestUtils.CreateDefaultManifest(); byte[] privkey = { 0x01,0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, @@ -197,12 +197,12 @@ public void TestContract_Update() Id = state.Id, Key = new byte[] { 0x01 } }; - snapshot.AddContract(state.Hash, state); - snapshot.Add(storageKey, storageItem); + snapshotCache.AddContract(state.Hash, state); + snapshotCache.Add(storageKey, storageItem); state.UpdateCounter.Should().Be(0); - snapshot.UpdateContract(state.Hash, nef.ToArray(), manifest.ToJson().ToByteArray(false)); - var ret = NativeContract.ContractManagement.GetContract(snapshot, state.Hash); - snapshot.Find(BitConverter.GetBytes(state.Id)).ToList().Count().Should().Be(1); + snapshotCache.UpdateContract(state.Hash, nef.ToArray(), manifest.ToJson().ToByteArray(false)); + var ret = NativeContract.ContractManagement.GetContract(snapshotCache, state.Hash); + snapshotCache.Find(BitConverter.GetBytes(state.Id)).ToList().Count().Should().Be(1); ret.UpdateCounter.Should().Be(1); ret.Id.Should().Be(state.Id); ret.Manifest.ToJson().ToString().Should().Be(manifest.ToJson().ToString()); @@ -221,11 +221,11 @@ public void TestContract_Update_Invalid() }; nefFile.CheckSum = NefFile.ComputeChecksum(nefFile); - var snapshot = TestBlockchain.GetTestSnapshotCache(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); - Assert.ThrowsException(() => snapshot.UpdateContract(null, null, new byte[] { 0x01 })); - Assert.ThrowsException(() => snapshot.UpdateContract(null, nefFile.ToArray(), null)); - Assert.ThrowsException(() => snapshot.UpdateContract(null, null, null)); + Assert.ThrowsException(() => snapshotCache.UpdateContract(null, null, new byte[] { 0x01 })); + Assert.ThrowsException(() => snapshotCache.UpdateContract(null, nefFile.ToArray(), null)); + Assert.ThrowsException(() => snapshotCache.UpdateContract(null, null, null)); nefFile = new NefFile() { @@ -236,14 +236,14 @@ public void TestContract_Update_Invalid() }; nefFile.CheckSum = NefFile.ComputeChecksum(nefFile); - Assert.ThrowsException(() => snapshot.UpdateContract(null, nefFile.ToArray(), new byte[] { 0x01 })); - Assert.ThrowsException(() => snapshot.UpdateContract(null, nefFile.ToArray(), new byte[0])); + Assert.ThrowsException(() => snapshotCache.UpdateContract(null, nefFile.ToArray(), new byte[] { 0x01 })); + Assert.ThrowsException(() => snapshotCache.UpdateContract(null, nefFile.ToArray(), new byte[0])); } [TestMethod] public void TestStorage_Find() { - var snapshot = TestBlockchain.GetTestSnapshotCache(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); var state = TestUtils.GetContract(); var storageItem = new StorageItem @@ -255,9 +255,9 @@ public void TestStorage_Find() Id = state.Id, Key = new byte[] { 0x01 } }; - snapshot.AddContract(state.Hash, state); - snapshot.Add(storageKey, storageItem); - var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot); + snapshotCache.AddContract(state.Hash, state); + snapshotCache.Add(storageKey, storageItem); + var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshotCache); engine.LoadScript(new byte[] { 0x01 }); var iterator = engine.Find(new StorageContext diff --git a/tests/Neo.UnitTests/SmartContract/UT_InteropService.cs b/tests/Neo.UnitTests/SmartContract/UT_InteropService.cs index 48203a644a..972f8dc0d1 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_InteropService.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_InteropService.cs @@ -38,7 +38,7 @@ public partial class UT_InteropService : TestKit public void Runtime_GetNotifications_Test() { UInt160 scriptHash2; - var snapshot = TestBlockchain.GetTestSnapshotCache(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); using (var script = new ScriptBuilder()) { @@ -56,7 +56,7 @@ public void Runtime_GetNotifications_Test() scriptHash2 = script.ToArray().ToScriptHash(); - snapshot.DeleteContract(scriptHash2); + snapshotCache.DeleteContract(scriptHash2); var contract = TestUtils.GetContract(script.ToArray(), TestUtils.CreateManifest("test", ContractParameterType.Any, ContractParameterType.Integer, ContractParameterType.Integer)); contract.Manifest.Abi.Events = new[] { @@ -80,12 +80,12 @@ public void Runtime_GetNotifications_Test() Methods = WildcardContainer.Create(new string[]{"test"}) } }; - snapshot.AddContract(scriptHash2, contract); + snapshotCache.AddContract(scriptHash2, contract); } // Wrong length - using (var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, null, ProtocolSettings.Default)) + using (var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshotCache, null, ProtocolSettings.Default)) using (var script = new ScriptBuilder()) { // Retrive @@ -102,7 +102,7 @@ public void Runtime_GetNotifications_Test() // All test - using (var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, null, ProtocolSettings.Default)) + using (var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshotCache, null, ProtocolSettings.Default)) using (var script = new ScriptBuilder()) { // Notification @@ -179,7 +179,7 @@ public void Runtime_GetNotifications_Test() // Script notifications - using (var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, null, ProtocolSettings.Default)) + using (var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshotCache, null, ProtocolSettings.Default)) using (var script = new ScriptBuilder()) { // Notification @@ -255,7 +255,7 @@ public void Runtime_GetNotifications_Test() // Clean storage - snapshot.DeleteContract(scriptHash2); + snapshotCache.DeleteContract(scriptHash2); } private static void AssertNotification(StackItem stackItem, UInt160 scriptHash, string notification) @@ -291,7 +291,7 @@ public void TestExecutionEngine_GetCallingScriptHash() var contract = TestUtils.GetContract(scriptA.ToArray(), TestUtils.CreateManifest("test", ContractParameterType.Any, ContractParameterType.String, ContractParameterType.Integer)); engine = GetEngine(true, true, addScript: false); - engine.Snapshot.AddContract(contract.Hash, contract); + engine.SnapshotCache.AddContract(contract.Hash, contract); using ScriptBuilder scriptB = new(); scriptB.EmitDynamicCall(contract.Hash, "test", "0", 1); @@ -439,7 +439,7 @@ public void TestCrypto_Verify() public void TestBlockchain_GetHeight() { var engine = GetEngine(true, true); - NativeContract.Ledger.CurrentIndex(engine.Snapshot).Should().Be(0); + NativeContract.Ledger.CurrentIndex(engine.SnapshotCache).Should().Be(0); } [TestMethod] @@ -447,14 +447,14 @@ public void TestBlockchain_GetBlock() { var engine = GetEngine(true, true); - NativeContract.Ledger.GetBlock(engine.Snapshot, UInt256.Zero).Should().BeNull(); + NativeContract.Ledger.GetBlock(engine.SnapshotCache, UInt256.Zero).Should().BeNull(); var data1 = new byte[] { 0x01, 0x01, 0x01 ,0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}; - NativeContract.Ledger.GetBlock(engine.Snapshot, new UInt256(data1)).Should().BeNull(); - NativeContract.Ledger.GetBlock(engine.Snapshot, TestBlockchain.TheNeoSystem.GenesisBlock.Hash).Should().NotBeNull(); + NativeContract.Ledger.GetBlock(engine.SnapshotCache, new UInt256(data1)).Should().BeNull(); + NativeContract.Ledger.GetBlock(engine.SnapshotCache, TestBlockchain.TheNeoSystem.GenesisBlock.Hash).Should().NotBeNull(); } [TestMethod] @@ -465,7 +465,7 @@ public void TestBlockchain_GetTransaction() 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}; - NativeContract.Ledger.GetTransaction(engine.Snapshot, new UInt256(data1)).Should().BeNull(); + NativeContract.Ledger.GetTransaction(engine.SnapshotCache, new UInt256(data1)).Should().BeNull(); } [TestMethod] @@ -477,7 +477,7 @@ public void TestBlockchain_GetTransactionHeight() BlockIndex = 0, Transaction = TestUtils.CreateRandomHashTransaction() }; - TestUtils.TransactionAdd(engine.Snapshot, state); + TestUtils.TransactionAdd(engine.SnapshotCache, state); using var script = new ScriptBuilder(); script.EmitDynamicCall(NativeContract.Ledger.Hash, "getTransactionHeight", state.Transaction.Hash); @@ -498,21 +498,21 @@ public void TestBlockchain_GetContract() 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }; - NativeContract.ContractManagement.GetContract(engine.Snapshot, new UInt160(data1)).Should().BeNull(); + NativeContract.ContractManagement.GetContract(engine.SnapshotCache, new UInt160(data1)).Should().BeNull(); - var snapshot = TestBlockchain.GetTestSnapshotCache(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); var state = TestUtils.GetContract(); - snapshot.AddContract(state.Hash, state); - engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot); + snapshotCache.AddContract(state.Hash, state); + engine = ApplicationEngine.Create(TriggerType.Application, null, snapshotCache); engine.LoadScript(new byte[] { 0x01 }); - NativeContract.ContractManagement.GetContract(engine.Snapshot, state.Hash).Hash.Should().Be(state.Hash); + NativeContract.ContractManagement.GetContract(engine.SnapshotCache, state.Hash).Hash.Should().Be(state.Hash); } [TestMethod] public void TestBlockchain_GetContractById() { var engine = GetEngine(true, true); - var contract = NativeContract.ContractManagement.GetContractById(engine.Snapshot, -1); + var contract = NativeContract.ContractManagement.GetContractById(engine.SnapshotCache, -1); contract.Id.Should().Be(-1); contract.Manifest.Name.Should().Be(nameof(ContractManagement)); } @@ -521,25 +521,25 @@ public void TestBlockchain_GetContractById() public void TestBlockchain_HasMethod() { var engine = GetEngine(true, true); - NativeContract.ContractManagement.HasMethod(engine.Snapshot, NativeContract.NEO.Hash, "symbol", 0).Should().Be(true); - NativeContract.ContractManagement.HasMethod(engine.Snapshot, NativeContract.NEO.Hash, "transfer", 4).Should().Be(true); + NativeContract.ContractManagement.HasMethod(engine.SnapshotCache, NativeContract.NEO.Hash, "symbol", 0).Should().Be(true); + NativeContract.ContractManagement.HasMethod(engine.SnapshotCache, NativeContract.NEO.Hash, "transfer", 4).Should().Be(true); } [TestMethod] public void TestBlockchain_ListContracts() { var engine = GetEngine(true, true); - var list = NativeContract.ContractManagement.ListContracts(engine.Snapshot); + var list = NativeContract.ContractManagement.ListContracts(engine.SnapshotCache); list.ForEach(p => p.Id.Should().BeLessThan(0)); - var snapshot = TestBlockchain.GetTestSnapshotCache(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); var state = TestUtils.GetContract(); - snapshot.AddContract(state.Hash, state); - engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot); + snapshotCache.AddContract(state.Hash, state); + engine = ApplicationEngine.Create(TriggerType.Application, null, snapshotCache); engine.LoadScript(new byte[] { 0x01 }); - NativeContract.ContractManagement.GetContract(engine.Snapshot, state.Hash).Hash.Should().Be(state.Hash); + NativeContract.ContractManagement.GetContract(engine.SnapshotCache, state.Hash).Hash.Should().Be(state.Hash); - var list2 = NativeContract.ContractManagement.ListContracts(engine.Snapshot); + var list2 = NativeContract.ContractManagement.ListContracts(engine.SnapshotCache); list2.Count().Should().Be(list.Count() + 1); } @@ -548,7 +548,7 @@ public void TestStorage_GetContext() { var engine = GetEngine(false, true); var state = TestUtils.GetContract(); - engine.Snapshot.AddContract(state.Hash, state); + engine.SnapshotCache.AddContract(state.Hash, state); engine.LoadScript(state.Script); engine.GetStorageContext().IsReadOnly.Should().BeFalse(); } @@ -558,7 +558,7 @@ public void TestStorage_GetReadOnlyContext() { var engine = GetEngine(false, true); var state = TestUtils.GetContract(); - engine.Snapshot.AddContract(state.Hash, state); + engine.SnapshotCache.AddContract(state.Hash, state); engine.LoadScript(state.Script); engine.GetReadOnlyContext().IsReadOnly.Should().BeTrue(); } @@ -566,7 +566,7 @@ public void TestStorage_GetReadOnlyContext() [TestMethod] public void TestStorage_Get() { - var snapshot = TestBlockchain.GetTestSnapshotCache(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); var state = TestUtils.GetContract(); var storageKey = new StorageKey @@ -579,9 +579,9 @@ public void TestStorage_Get() { Value = new byte[] { 0x01, 0x02, 0x03, 0x04 } }; - snapshot.AddContract(state.Hash, state); - snapshot.Add(storageKey, storageItem); - var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot); + snapshotCache.AddContract(state.Hash, state); + snapshotCache.Add(storageKey, storageItem); + var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshotCache); engine.LoadScript(new byte[] { 0x01 }); engine.Get(new StorageContext @@ -624,7 +624,7 @@ public void TestStorage_Put() Assert.ThrowsException(() => engine.Put(storageContext, key, value)); //storage value is constant - var snapshot = TestBlockchain.GetTestSnapshotCache(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); var storageKey = new StorageKey { @@ -635,9 +635,9 @@ public void TestStorage_Put() { Value = new byte[] { 0x01, 0x02, 0x03, 0x04 } }; - snapshot.AddContract(state.Hash, state); - snapshot.Add(storageKey, storageItem); - engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot); + snapshotCache.AddContract(state.Hash, state); + snapshotCache.Add(storageKey, storageItem); + engine = ApplicationEngine.Create(TriggerType.Application, null, snapshotCache); engine.LoadScript(new byte[] { 0x01 }); key = new byte[] { 0x01 }; value = new byte[] { 0x02 }; @@ -654,7 +654,7 @@ public void TestStorage_Put() public void TestStorage_Delete() { var engine = GetEngine(false, true); - var snapshot = TestBlockchain.GetTestSnapshotCache(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); var state = TestUtils.GetContract(); var storageKey = new StorageKey { @@ -665,9 +665,9 @@ public void TestStorage_Delete() { Value = new byte[] { 0x01, 0x02, 0x03, 0x04 } }; - snapshot.AddContract(state.Hash, state); - snapshot.Add(storageKey, storageItem); - engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot); + snapshotCache.AddContract(state.Hash, state); + snapshotCache.Add(storageKey, storageItem); + engine = ApplicationEngine.Create(TriggerType.Application, null, snapshotCache); engine.LoadScript(new byte[] { 0x01 }); var key = new byte[] { 0x01 }; var storageContext = new StorageContext @@ -697,38 +697,38 @@ public void TestStorageContext_AsReadOnly() [TestMethod] public void TestContract_Call() { - var snapshot = TestBlockchain.GetTestSnapshotCache(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); var method = "method"; var args = new VM.Types.Array { 0, 1 }; var state = TestUtils.GetContract(method, args.Count); - var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, null, ProtocolSettings.Default); + var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshotCache, null, ProtocolSettings.Default); engine.LoadScript(new byte[] { 0x01 }); - engine.Snapshot.AddContract(state.Hash, state); + engine.SnapshotCache.AddContract(state.Hash, state); engine.CallContract(state.Hash, method, CallFlags.All, args); engine.CurrentContext.EvaluationStack.Pop().Should().Be(args[0]); engine.CurrentContext.EvaluationStack.Pop().Should().Be(args[1]); state.Manifest.Permissions[0].Methods = WildcardContainer.Create("a"); - engine.Snapshot.DeleteContract(state.Hash); - engine.Snapshot.AddContract(state.Hash, state); + engine.SnapshotCache.DeleteContract(state.Hash); + engine.SnapshotCache.AddContract(state.Hash, state); Assert.ThrowsException(() => engine.CallContract(state.Hash, method, CallFlags.All, args)); state.Manifest.Permissions[0].Methods = WildcardContainer.CreateWildcard(); - engine.Snapshot.DeleteContract(state.Hash); - engine.Snapshot.AddContract(state.Hash, state); + engine.SnapshotCache.DeleteContract(state.Hash); + engine.SnapshotCache.AddContract(state.Hash, state); engine.CallContract(state.Hash, method, CallFlags.All, args); - engine.Snapshot.DeleteContract(state.Hash); - engine.Snapshot.AddContract(state.Hash, state); + engine.SnapshotCache.DeleteContract(state.Hash); + engine.SnapshotCache.AddContract(state.Hash, state); Assert.ThrowsException(() => engine.CallContract(UInt160.Zero, method, CallFlags.All, args)); } [TestMethod] public void TestContract_Destroy() { - var snapshot = TestBlockchain.GetTestSnapshotCache(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); var state = TestUtils.GetContract(); var scriptHash = UInt160.Parse("0xcb9f3b7c6fb1cf2c13a40637c189bdd066a272b4"); var storageItem = new StorageItem @@ -741,16 +741,16 @@ public void TestContract_Destroy() Id = 0x43000000, Key = new byte[] { 0x01 } }; - snapshot.AddContract(scriptHash, state); - snapshot.Add(storageKey, storageItem); - snapshot.DestroyContract(scriptHash); - snapshot.Find(BitConverter.GetBytes(0x43000000)).Any().Should().BeFalse(); + snapshotCache.AddContract(scriptHash, state); + snapshotCache.Add(storageKey, storageItem); + snapshotCache.DestroyContract(scriptHash); + snapshotCache.Find(BitConverter.GetBytes(0x43000000)).Any().Should().BeFalse(); //storages are removed state = TestUtils.GetContract(); - snapshot.AddContract(scriptHash, state); - snapshot.DestroyContract(scriptHash); - snapshot.Find(BitConverter.GetBytes(0x43000000)).Any().Should().BeFalse(); + snapshotCache.AddContract(scriptHash, state); + snapshotCache.DestroyContract(scriptHash); + snapshotCache.Find(BitConverter.GetBytes(0x43000000)).Any().Should().BeFalse(); } [TestMethod] @@ -769,9 +769,9 @@ public static void LogEvent(object sender, LogEventArgs args) private static ApplicationEngine GetEngine(bool hasContainer = false, bool hasSnapshot = false, bool hasBlock = false, bool addScript = true, long gas = 20_00000000) { var tx = hasContainer ? TestUtils.GetTransaction(UInt160.Zero) : null; - var snapshot = hasSnapshot ? TestBlockchain.GetTestSnapshotCache() : null; + var snapshotCache = hasSnapshot ? TestBlockchain.GetTestSnapshotCache() : null; var block = hasBlock ? new Block { Header = new Header() } : null; - var engine = ApplicationEngine.Create(TriggerType.Application, tx, snapshot, block, TestBlockchain.TheNeoSystem.Settings, gas: gas); + var engine = ApplicationEngine.Create(TriggerType.Application, tx, snapshotCache, block, TestBlockchain.TheNeoSystem.Settings, gas: gas); if (addScript) engine.LoadScript(new byte[] { 0x01 }); return engine; } @@ -827,21 +827,21 @@ public void TestMurmur32() [TestMethod] public void TestGetBlockHash() { - var snapshot = GetEngine(true, true).Snapshot; - var hash = LedgerContract.Ledger.GetBlockHash(snapshot, 0); - var hash2 = LedgerContract.Ledger.GetBlock(snapshot, 0).Hash; - var hash3 = LedgerContract.Ledger.GetHeader(snapshot, 0).Hash; + var snapshotCache = GetEngine(true, true).SnapshotCache; + var hash = LedgerContract.Ledger.GetBlockHash(snapshotCache, 0); + var hash2 = LedgerContract.Ledger.GetBlock(snapshotCache, 0).Hash; + var hash3 = LedgerContract.Ledger.GetHeader(snapshotCache, 0).Hash; hash.ToString().Should().Be(hash2.ToString()); hash.ToString().Should().Be(hash3.ToString()); hash.ToString().Should().Be("0x1f4d1defa46faa5e7b9b8d3f79a06bec777d7c26c4aa5f6f5899a291daa87c15"); - LedgerContract.Ledger.ContainsBlock(snapshot, hash).Should().BeTrue(); + LedgerContract.Ledger.ContainsBlock(snapshotCache, hash).Should().BeTrue(); } [TestMethod] public void TestGetCandidateVote() { - var snapshot = GetEngine(true, true).Snapshot; - var vote = LedgerContract.NEO.GetCandidateVote(snapshot, new ECPoint()); + var snapshotCache = GetEngine(true, true).SnapshotCache; + var vote = LedgerContract.NEO.GetCandidateVote(snapshotCache, new ECPoint()); vote.Should().Be(-1); } diff --git a/tests/Neo.UnitTests/SmartContract/UT_SmartContractHelper.cs b/tests/Neo.UnitTests/SmartContract/UT_SmartContractHelper.cs index ceb13a2a64..42308d91f2 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_SmartContractHelper.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_SmartContractHelper.cs @@ -124,9 +124,9 @@ public void TestIsStandardContract() [TestMethod] public void TestVerifyWitnesses() { - var snapshot1 = TestBlockchain.GetTestSnapshotCache().CreateSnapshot(); + var snapshotCache1 = TestBlockchain.GetTestSnapshotCache().CreateSnapshot(); UInt256 index1 = UInt256.Parse("0xa400ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff01"); - TestUtils.BlocksAdd(snapshot1, index1, new TrimmedBlock() + TestUtils.BlocksAdd(snapshotCache1, index1, new TrimmedBlock() { Header = new Header { @@ -138,10 +138,10 @@ public void TestVerifyWitnesses() }, Hashes = new UInt256[1] { UInt256.Zero }, }); - TestUtils.BlocksDelete(snapshot1, index1); - Assert.AreEqual(false, Neo.SmartContract.Helper.VerifyWitnesses(new Header() { PrevHash = index1 }, TestProtocolSettings.Default, snapshot1, 100)); + TestUtils.BlocksDelete(snapshotCache1, index1); + Assert.AreEqual(false, Neo.SmartContract.Helper.VerifyWitnesses(new Header() { PrevHash = index1 }, TestProtocolSettings.Default, snapshotCache1, 100)); - var snapshot2 = TestBlockchain.GetTestSnapshotCache(); + var snapshotCache2 = TestBlockchain.GetTestSnapshotCache(); UInt256 index2 = UInt256.Parse("0xa400ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff01"); TrimmedBlock block2 = new() { @@ -155,14 +155,14 @@ public void TestVerifyWitnesses() }, Hashes = new UInt256[1] { UInt256.Zero }, }; - TestUtils.BlocksAdd(snapshot2, index2, block2); + TestUtils.BlocksAdd(snapshotCache2, index2, block2); Header header2 = new() { PrevHash = index2, Witness = new Witness { InvocationScript = Array.Empty(), VerificationScript = Array.Empty() } }; - snapshot2.AddContract(UInt160.Zero, new ContractState()); - snapshot2.DeleteContract(UInt160.Zero); - Assert.AreEqual(false, Neo.SmartContract.Helper.VerifyWitnesses(header2, TestProtocolSettings.Default, snapshot2, 100)); + snapshotCache2.AddContract(UInt160.Zero, new ContractState()); + snapshotCache2.DeleteContract(UInt160.Zero); + Assert.AreEqual(false, Neo.SmartContract.Helper.VerifyWitnesses(header2, TestProtocolSettings.Default, snapshotCache2, 100)); - var snapshot3 = TestBlockchain.GetTestSnapshotCache(); + var snapshotCache3 = TestBlockchain.GetTestSnapshotCache(); UInt256 index3 = UInt256.Parse("0xa400ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff01"); TrimmedBlock block3 = new() { @@ -176,7 +176,7 @@ public void TestVerifyWitnesses() }, Hashes = new UInt256[1] { UInt256.Zero }, }; - TestUtils.BlocksAdd(snapshot3, index3, block3); + TestUtils.BlocksAdd(snapshotCache3, index3, block3); Header header3 = new() { PrevHash = index3, @@ -186,13 +186,13 @@ public void TestVerifyWitnesses() VerificationScript = Array.Empty() } }; - snapshot3.AddContract(UInt160.Zero, new ContractState() + snapshotCache3.AddContract(UInt160.Zero, new ContractState() { Nef = new NefFile { Script = Array.Empty() }, Hash = Array.Empty().ToScriptHash(), Manifest = TestUtils.CreateManifest("verify", ContractParameterType.Boolean, ContractParameterType.Signature), }); - Assert.AreEqual(false, Neo.SmartContract.Helper.VerifyWitnesses(header3, TestProtocolSettings.Default, snapshot3, 100)); + Assert.AreEqual(false, Neo.SmartContract.Helper.VerifyWitnesses(header3, TestProtocolSettings.Default, snapshotCache3, 100)); // Smart contract verification @@ -202,13 +202,13 @@ public void TestVerifyWitnesses() Hash = "11".HexToBytes().ToScriptHash(), Manifest = TestUtils.CreateManifest("verify", ContractParameterType.Boolean, ContractParameterType.Signature), // Offset = 0 }; - snapshot3.AddContract(contract.Hash, contract); + snapshotCache3.AddContract(contract.Hash, contract); var tx = new Nep17NativeContractExtensions.ManualWitness(contract.Hash) { Witnesses = new Witness[] { new Witness() { InvocationScript = Array.Empty(), VerificationScript = Array.Empty() } } }; - Assert.AreEqual(true, Neo.SmartContract.Helper.VerifyWitnesses(tx, TestProtocolSettings.Default, snapshot3, 1000)); + Assert.AreEqual(true, Neo.SmartContract.Helper.VerifyWitnesses(tx, TestProtocolSettings.Default, snapshotCache3, 1000)); } } } diff --git a/tests/Neo.UnitTests/SmartContract/UT_Syscalls.cs b/tests/Neo.UnitTests/SmartContract/UT_Syscalls.cs index 43448ef218..a864c5d427 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_Syscalls.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_Syscalls.cs @@ -62,14 +62,14 @@ public void System_Blockchain_GetBlock() Hashes = new[] { tx.Hash } }; - var snapshot = TestBlockchain.GetTestSnapshotCache(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); using ScriptBuilder script = new(); script.EmitDynamicCall(NativeContract.Ledger.Hash, "getBlock", block.Hash.ToArray()); // Without block - var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, settings: TestBlockchain.TheNeoSystem.Settings); + var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshotCache, settings: TestBlockchain.TheNeoSystem.Settings); engine.LoadScript(script.ToArray()); Assert.AreEqual(engine.Execute(), VMState.HALT); @@ -81,18 +81,18 @@ public void System_Blockchain_GetBlock() const byte Prefix_Transaction = 11; const byte Prefix_CurrentBlock = 12; - TestUtils.BlocksAdd(snapshot, block.Hash, block); + TestUtils.BlocksAdd(snapshotCache, block.Hash, block); - var height = snapshot[NativeContract.Ledger.CreateStorageKey(Prefix_CurrentBlock)].GetInteroperable(); + var height = snapshotCache[NativeContract.Ledger.CreateStorageKey(Prefix_CurrentBlock)].GetInteroperable(); height.Index = block.Index + TestProtocolSettings.Default.MaxTraceableBlocks; - snapshot.Add(NativeContract.Ledger.CreateStorageKey(Prefix_Transaction, tx.Hash), new StorageItem(new TransactionState + snapshotCache.Add(NativeContract.Ledger.CreateStorageKey(Prefix_Transaction, tx.Hash), new StorageItem(new TransactionState { BlockIndex = block.Index, Transaction = tx })); - engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, settings: TestBlockchain.TheNeoSystem.Settings); + engine = ApplicationEngine.Create(TriggerType.Application, null, snapshotCache, settings: TestBlockchain.TheNeoSystem.Settings); engine.LoadScript(script.ToArray()); Assert.AreEqual(engine.Execute(), VMState.HALT); @@ -101,10 +101,10 @@ public void System_Blockchain_GetBlock() // With block - height = snapshot[NativeContract.Ledger.CreateStorageKey(Prefix_CurrentBlock)].GetInteroperable(); + height = snapshotCache[NativeContract.Ledger.CreateStorageKey(Prefix_CurrentBlock)].GetInteroperable(); height.Index = block.Index; - engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, settings: TestBlockchain.TheNeoSystem.Settings); + engine = ApplicationEngine.Create(TriggerType.Application, null, snapshotCache, settings: TestBlockchain.TheNeoSystem.Settings); engine.LoadScript(script.ToArray()); Assert.AreEqual(engine.Execute(), VMState.HALT); @@ -117,13 +117,13 @@ public void System_Blockchain_GetBlock() [TestMethod] public void System_ExecutionEngine_GetScriptContainer() { - var snapshot = TestBlockchain.GetTestSnapshotCache(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); using ScriptBuilder script = new(); script.EmitSysCall(ApplicationEngine.System_Runtime_GetScriptContainer); // Without tx - var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot); + var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshotCache); engine.LoadScript(script.ToArray()); Assert.AreEqual(engine.Execute(), VMState.FAULT); @@ -153,7 +153,7 @@ public void System_ExecutionEngine_GetScriptContainer() Witnesses = new Witness[] { new Witness() { VerificationScript = new byte[] { 0x07 } } }, }; - engine = ApplicationEngine.Create(TriggerType.Application, tx, snapshot); + engine = ApplicationEngine.Create(TriggerType.Application, tx, snapshotCache); engine.LoadScript(script.ToArray()); Assert.AreEqual(engine.Execute(), VMState.HALT); @@ -166,7 +166,7 @@ public void System_ExecutionEngine_GetScriptContainer() [TestMethod] public void System_Runtime_GasLeft() { - var snapshot = TestBlockchain.GetTestSnapshotCache(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); using (var script = new ScriptBuilder()) { @@ -181,7 +181,7 @@ public void System_Runtime_GasLeft() // Execute - var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, gas: 100_000_000); + var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshotCache, gas: 100_000_000); engine.LoadScript(script.ToArray()); Assert.AreEqual(engine.Execute(), VMState.HALT); @@ -202,7 +202,7 @@ public void System_Runtime_GasLeft() // Execute - var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot); + var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshotCache); engine.LoadScript(script.ToArray()); // Check the results @@ -218,7 +218,7 @@ public void System_Runtime_GasLeft() public void System_Runtime_GetInvocationCounter() { ContractState contractA, contractB, contractC; - var snapshot = TestBlockchain.GetTestSnapshotCache(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); // Create dummy contracts @@ -236,15 +236,15 @@ public void System_Runtime_GetInvocationCounter() // Init A,B,C contracts // First two drops is for drop method and arguments - snapshot.DeleteContract(contractA.Hash); - snapshot.DeleteContract(contractB.Hash); - snapshot.DeleteContract(contractC.Hash); + snapshotCache.DeleteContract(contractA.Hash); + snapshotCache.DeleteContract(contractB.Hash); + snapshotCache.DeleteContract(contractC.Hash); contractA.Manifest = TestUtils.CreateManifest("dummyMain", ContractParameterType.Any, ContractParameterType.String, ContractParameterType.Integer); contractB.Manifest = TestUtils.CreateManifest("dummyMain", ContractParameterType.Any, ContractParameterType.String, ContractParameterType.Integer); contractC.Manifest = TestUtils.CreateManifest("dummyMain", ContractParameterType.Any, ContractParameterType.String, ContractParameterType.Integer); - snapshot.AddContract(contractA.Hash, contractA); - snapshot.AddContract(contractB.Hash, contractB); - snapshot.AddContract(contractC.Hash, contractC); + snapshotCache.AddContract(contractA.Hash, contractA); + snapshotCache.AddContract(contractB.Hash, contractB); + snapshotCache.AddContract(contractC.Hash, contractC); } // Call A,B,B,C @@ -258,7 +258,7 @@ public void System_Runtime_GetInvocationCounter() // Execute - var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, null, ProtocolSettings.Default); + var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshotCache, null, ProtocolSettings.Default); engine.LoadScript(script.ToArray()); Assert.AreEqual(VMState.HALT, engine.Execute()); diff --git a/tests/Neo.UnitTests/UT_DataCache.cs b/tests/Neo.UnitTests/UT_DataCache.cs index 5271d446ff..5bc5b4085c 100644 --- a/tests/Neo.UnitTests/UT_DataCache.cs +++ b/tests/Neo.UnitTests/UT_DataCache.cs @@ -22,8 +22,8 @@ public class UT_DataCache [TestMethod] public void TestCachedFind_Between() { - var snapshot = TestBlockchain.GetTestSnapshotCache(); - var storages = snapshot.CreateSnapshot(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); + var storages = snapshotCache.CreateSnapshot(); var cache = new ClonedCache(storages); storages.Add @@ -93,8 +93,8 @@ public void TestCachedFind_Last() [TestMethod] public void TestCachedFind_Empty() { - var snapshot = TestBlockchain.GetTestSnapshotCache(); - var storages = snapshot.CreateSnapshot(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); + var storages = snapshotCache.CreateSnapshot(); var cache = new ClonedCache(storages); cache.Add diff --git a/tests/Neo.UnitTests/Wallets/UT_AssetDescriptor.cs b/tests/Neo.UnitTests/Wallets/UT_AssetDescriptor.cs index 427af290b1..ff2386c466 100644 --- a/tests/Neo.UnitTests/Wallets/UT_AssetDescriptor.cs +++ b/tests/Neo.UnitTests/Wallets/UT_AssetDescriptor.cs @@ -22,10 +22,10 @@ public class UT_AssetDescriptor [TestMethod] public void TestConstructorWithNonexistAssetId() { - var snapshot = TestBlockchain.GetTestSnapshotCache(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); Action action = () => { - var descriptor = new Neo.Wallets.AssetDescriptor(snapshot, TestProtocolSettings.Default, UInt160.Parse("01ff00ff00ff00ff00ff00ff00ff00ff00ff00a4")); + var descriptor = new Neo.Wallets.AssetDescriptor(snapshotCache, TestProtocolSettings.Default, UInt160.Parse("01ff00ff00ff00ff00ff00ff00ff00ff00ff00a4")); }; action.Should().Throw(); } @@ -33,8 +33,8 @@ public void TestConstructorWithNonexistAssetId() [TestMethod] public void Check_GAS() { - var snapshot = TestBlockchain.GetTestSnapshotCache(); - var descriptor = new Neo.Wallets.AssetDescriptor(snapshot, TestProtocolSettings.Default, NativeContract.GAS.Hash); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); + var descriptor = new Neo.Wallets.AssetDescriptor(snapshotCache, TestProtocolSettings.Default, NativeContract.GAS.Hash); descriptor.AssetId.Should().Be(NativeContract.GAS.Hash); descriptor.AssetName.Should().Be(nameof(GasToken)); descriptor.ToString().Should().Be(nameof(GasToken)); @@ -45,8 +45,8 @@ public void Check_GAS() [TestMethod] public void Check_NEO() { - var snapshot = TestBlockchain.GetTestSnapshotCache(); - var descriptor = new Neo.Wallets.AssetDescriptor(snapshot, TestProtocolSettings.Default, NativeContract.NEO.Hash); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); + var descriptor = new Neo.Wallets.AssetDescriptor(snapshotCache, TestProtocolSettings.Default, NativeContract.NEO.Hash); descriptor.AssetId.Should().Be(NativeContract.NEO.Hash); descriptor.AssetName.Should().Be(nameof(NeoToken)); descriptor.ToString().Should().Be(nameof(NeoToken)); diff --git a/tests/Neo.UnitTests/Wallets/UT_Wallet.cs b/tests/Neo.UnitTests/Wallets/UT_Wallet.cs index 06619d74f5..bba7ff05a1 100644 --- a/tests/Neo.UnitTests/Wallets/UT_Wallet.cs +++ b/tests/Neo.UnitTests/Wallets/UT_Wallet.cs @@ -217,14 +217,14 @@ public void TestGetAvailable() account.Lock = false; // Fake balance - var snapshot = TestBlockchain.GetTestSnapshotCache(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); var key = NativeContract.GAS.CreateStorageKey(20, account.ScriptHash); - var entry = snapshot.GetAndChange(key, () => new StorageItem(new AccountState())); + var entry = snapshotCache.GetAndChange(key, () => new StorageItem(new AccountState())); entry.GetInteroperable().Balance = 10000 * NativeContract.GAS.Factor; - wallet.GetAvailable(snapshot, NativeContract.GAS.Hash).Should().Be(new BigDecimal(new BigInteger(1000000000000M), 8)); + wallet.GetAvailable(snapshotCache, NativeContract.GAS.Hash).Should().Be(new BigDecimal(new BigInteger(1000000000000M), 8)); - entry = snapshot.GetAndChange(key, () => new StorageItem(new AccountState())); + entry = snapshotCache.GetAndChange(key, () => new StorageItem(new AccountState())); entry.GetInteroperable().Balance = 0; } @@ -237,15 +237,15 @@ public void TestGetBalance() account.Lock = false; // Fake balance - var snapshot = TestBlockchain.GetTestSnapshotCache(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); var key = NativeContract.GAS.CreateStorageKey(20, account.ScriptHash); - var entry = snapshot.GetAndChange(key, () => new StorageItem(new AccountState())); + var entry = snapshotCache.GetAndChange(key, () => new StorageItem(new AccountState())); entry.GetInteroperable().Balance = 10000 * NativeContract.GAS.Factor; - wallet.GetBalance(snapshot, UInt160.Zero, new UInt160[] { account.ScriptHash }).Should().Be(new BigDecimal(BigInteger.Zero, 0)); - wallet.GetBalance(snapshot, NativeContract.GAS.Hash, new UInt160[] { account.ScriptHash }).Should().Be(new BigDecimal(new BigInteger(1000000000000M), 8)); + wallet.GetBalance(snapshotCache, UInt160.Zero, new UInt160[] { account.ScriptHash }).Should().Be(new BigDecimal(BigInteger.Zero, 0)); + wallet.GetBalance(snapshotCache, NativeContract.GAS.Hash, new UInt160[] { account.ScriptHash }).Should().Be(new BigDecimal(new BigInteger(1000000000000M), 8)); - entry = snapshot.GetAndChange(key, () => new StorageItem(new AccountState())); + entry = snapshotCache.GetAndChange(key, () => new StorageItem(new AccountState())); entry.GetInteroperable().Balance = 0; } @@ -290,13 +290,13 @@ public void TestImport2() [TestMethod] public void TestMakeTransaction1() { - var snapshot = TestBlockchain.GetTestSnapshotCache(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); MyWallet wallet = new(); Contract contract = Contract.Create(new ContractParameterType[] { ContractParameterType.Boolean }, new byte[] { 1 }); WalletAccount account = wallet.CreateAccount(contract, glkey.PrivateKey); account.Lock = false; - Action action = () => wallet.MakeTransaction(snapshot, new TransferOutput[] + Action action = () => wallet.MakeTransaction(snapshotCache, new TransferOutput[] { new TransferOutput() { @@ -308,7 +308,7 @@ public void TestMakeTransaction1() }, UInt160.Zero); action.Should().Throw(); - action = () => wallet.MakeTransaction(snapshot, new TransferOutput[] + action = () => wallet.MakeTransaction(snapshotCache, new TransferOutput[] { new TransferOutput() { @@ -320,7 +320,7 @@ public void TestMakeTransaction1() }, account.ScriptHash); action.Should().Throw(); - action = () => wallet.MakeTransaction(snapshot, new TransferOutput[] + action = () => wallet.MakeTransaction(snapshotCache, new TransferOutput[] { new TransferOutput() { @@ -334,14 +334,14 @@ public void TestMakeTransaction1() // Fake balance var key = NativeContract.GAS.CreateStorageKey(20, account.ScriptHash); - var entry1 = snapshot.GetAndChange(key, () => new StorageItem(new AccountState())); + var entry1 = snapshotCache.GetAndChange(key, () => new StorageItem(new AccountState())); entry1.GetInteroperable().Balance = 10000 * NativeContract.GAS.Factor; key = NativeContract.NEO.CreateStorageKey(20, account.ScriptHash); - var entry2 = snapshot.GetAndChange(key, () => new StorageItem(new NeoToken.NeoAccountState())); + var entry2 = snapshotCache.GetAndChange(key, () => new StorageItem(new NeoToken.NeoAccountState())); entry2.GetInteroperable().Balance = 10000 * NativeContract.NEO.Factor; - var tx = wallet.MakeTransaction(snapshot, new TransferOutput[] + var tx = wallet.MakeTransaction(snapshotCache, new TransferOutput[] { new TransferOutput() { @@ -352,7 +352,7 @@ public void TestMakeTransaction1() }); tx.Should().NotBeNull(); - tx = wallet.MakeTransaction(snapshot, new TransferOutput[] + tx = wallet.MakeTransaction(snapshotCache, new TransferOutput[] { new TransferOutput() { @@ -364,8 +364,8 @@ public void TestMakeTransaction1() }); tx.Should().NotBeNull(); - entry1 = snapshot.GetAndChange(key, () => new StorageItem(new AccountState())); - entry2 = snapshot.GetAndChange(key, () => new StorageItem(new AccountState())); + entry1 = snapshotCache.GetAndChange(key, () => new StorageItem(new AccountState())); + entry2 = snapshotCache.GetAndChange(key, () => new StorageItem(new AccountState())); entry1.GetInteroperable().Balance = 0; entry2.GetInteroperable().Balance = 0; } @@ -373,9 +373,9 @@ public void TestMakeTransaction1() [TestMethod] public void TestMakeTransaction2() { - var snapshot = TestBlockchain.GetTestSnapshotCache(); + var snapshotCache = TestBlockchain.GetTestSnapshotCache(); MyWallet wallet = new(); - Action action = () => wallet.MakeTransaction(snapshot, Array.Empty(), null, null, Array.Empty()); + Action action = () => wallet.MakeTransaction(snapshotCache, Array.Empty(), null, null, Array.Empty()); action.Should().Throw(); Contract contract = Contract.Create(new ContractParameterType[] { ContractParameterType.Boolean }, new byte[] { 1 }); @@ -384,10 +384,10 @@ public void TestMakeTransaction2() // Fake balance var key = NativeContract.GAS.CreateStorageKey(20, account.ScriptHash); - var entry = snapshot.GetAndChange(key, () => new StorageItem(new AccountState())); + var entry = snapshotCache.GetAndChange(key, () => new StorageItem(new AccountState())); entry.GetInteroperable().Balance = 1000000 * NativeContract.GAS.Factor; - var tx = wallet.MakeTransaction(snapshot, Array.Empty(), account.ScriptHash, new[]{ new Signer() + var tx = wallet.MakeTransaction(snapshotCache, Array.Empty(), account.ScriptHash, new[]{ new Signer() { Account = account.ScriptHash, Scopes = WitnessScope.CalledByEntry @@ -395,10 +395,10 @@ public void TestMakeTransaction2() tx.Should().NotBeNull(); - tx = wallet.MakeTransaction(snapshot, Array.Empty(), null, null, Array.Empty()); + tx = wallet.MakeTransaction(snapshotCache, Array.Empty(), null, null, Array.Empty()); tx.Should().NotBeNull(); - entry = snapshot.GetAndChange(key, () => new StorageItem(new AccountState())); + entry = snapshotCache.GetAndChange(key, () => new StorageItem(new AccountState())); entry.GetInteroperable().Balance = 0; } From c2141e81aff0b2c42511f643f00f3ea04eac49c5 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Mon, 29 Jul 2024 16:39:59 +0800 Subject: [PATCH 62/71] [Neo Plugin RpcServer UT]Plugin rpcserver wallet UTs (#3433) * wallet * fix util * add comments and fix ut * Update tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Wallet.cs * remove comment --------- Co-authored-by: Christopher Schuchardt Co-authored-by: Shargon Co-authored-by: NGD Admin <154295625+NGDAdmin@users.noreply.github.com> --- src/Plugins/RpcServer/Result.cs | 2 +- .../RpcServer/RpcServer.SmartContract.cs | 10 +- src/Plugins/RpcServer/RpcServer.Wallet.cs | 188 +++++++- .../UT_RpcServer.Wallet.cs | 403 ++++++++++++++++++ tests/Neo.UnitTests/TestUtils.Contract.cs | 105 +++++ tests/Neo.UnitTests/TestUtils.Transaction.cs | 102 +++++ tests/Neo.UnitTests/TestUtils.cs | 179 -------- 7 files changed, 785 insertions(+), 204 deletions(-) create mode 100644 tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Wallet.cs create mode 100644 tests/Neo.UnitTests/TestUtils.Contract.cs diff --git a/src/Plugins/RpcServer/Result.cs b/src/Plugins/RpcServer/Result.cs index 9c7ace227c..c76e15153b 100644 --- a/src/Plugins/RpcServer/Result.cs +++ b/src/Plugins/RpcServer/Result.cs @@ -23,7 +23,7 @@ public static class Result /// The return type /// The execution result /// The Rpc exception - public static T Ok_Or(this Func function, RpcError err, bool withData = false) + public static T Ok_Or(Func function, RpcError err, bool withData = false) { try { diff --git a/src/Plugins/RpcServer/RpcServer.SmartContract.cs b/src/Plugins/RpcServer/RpcServer.SmartContract.cs index 473ae0cb5d..70edc4cedb 100644 --- a/src/Plugins/RpcServer/RpcServer.SmartContract.cs +++ b/src/Plugins/RpcServer/RpcServer.SmartContract.cs @@ -213,7 +213,7 @@ private static Witness[] WitnessesFromJson(JArray _params) } [RpcMethod] - protected virtual JToken InvokeFunction(JArray _params) + protected internal virtual JToken InvokeFunction(JArray _params) { UInt160 script_hash = Result.Ok_Or(() => UInt160.Parse(_params[0].AsString()), RpcError.InvalidParams.WithData($"Invalid script hash {nameof(script_hash)}")); string operation = Result.Ok_Or(() => _params[1].AsString(), RpcError.InvalidParams); @@ -231,7 +231,7 @@ protected virtual JToken InvokeFunction(JArray _params) } [RpcMethod] - protected virtual JToken InvokeScript(JArray _params) + protected internal virtual JToken InvokeScript(JArray _params) { byte[] script = Result.Ok_Or(() => Convert.FromBase64String(_params[0].AsString()), RpcError.InvalidParams); Signer[] signers = _params.Count >= 2 ? SignersFromJson((JArray)_params[1], system.Settings) : null; @@ -241,7 +241,7 @@ protected virtual JToken InvokeScript(JArray _params) } [RpcMethod] - protected virtual JToken TraverseIterator(JArray _params) + protected internal virtual JToken TraverseIterator(JArray _params) { settings.SessionEnabled.True_Or(RpcError.SessionsDisabled); Guid sid = Result.Ok_Or(() => Guid.Parse(_params[0].GetString()), RpcError.InvalidParams.WithData($"Invalid session id {nameof(sid)}")); @@ -262,7 +262,7 @@ protected virtual JToken TraverseIterator(JArray _params) } [RpcMethod] - protected virtual JToken TerminateSession(JArray _params) + protected internal virtual JToken TerminateSession(JArray _params) { settings.SessionEnabled.True_Or(RpcError.SessionsDisabled); Guid sid = Result.Ok_Or(() => Guid.Parse(_params[0].GetString()), RpcError.InvalidParams.WithData("Invalid session id")); @@ -278,7 +278,7 @@ protected virtual JToken TerminateSession(JArray _params) } [RpcMethod] - protected virtual JToken GetUnclaimedGas(JArray _params) + protected internal virtual JToken GetUnclaimedGas(JArray _params) { string address = Result.Ok_Or(() => _params[0].AsString(), RpcError.InvalidParams.WithData($"Invalid address {nameof(address)}")); JObject json = new(); diff --git a/src/Plugins/RpcServer/RpcServer.Wallet.cs b/src/Plugins/RpcServer/RpcServer.Wallet.cs index 155c56d91b..50f3c7a1e0 100644 --- a/src/Plugins/RpcServer/RpcServer.Wallet.cs +++ b/src/Plugins/RpcServer/RpcServer.Wallet.cs @@ -48,22 +48,36 @@ public override void Delete() { } public override void Save() { } } - protected Wallet wallet; + protected internal Wallet wallet; + /// + /// Checks if a wallet is open and throws an error if not. + /// private void CheckWallet() { wallet.NotNull_Or(RpcError.NoOpenedWallet); } + /// + /// Closes the currently opened wallet. + /// + /// An empty array. + /// Returns true if the wallet was successfully closed. [RpcMethod] - protected virtual JToken CloseWallet(JArray _params) + protected internal virtual JToken CloseWallet(JArray _params) { wallet = null; return true; } + /// + /// Exports the private key of a specified address. + /// + /// An array containing the address as a string. + /// The exported private key as a string. + /// Thrown when no wallet is open or the address is invalid. [RpcMethod] - protected virtual JToken DumpPrivKey(JArray _params) + protected internal virtual JToken DumpPrivKey(JArray _params) { CheckWallet(); UInt160 scriptHash = AddressToScriptHash(_params[0].AsString(), system.Settings.AddressVersion); @@ -71,8 +85,14 @@ protected virtual JToken DumpPrivKey(JArray _params) return account.GetKey().Export(); } + /// + /// Creates a new address in the wallet. + /// + /// An empty array. + /// The newly created address as a string. + /// Thrown when no wallet is open. [RpcMethod] - protected virtual JToken GetNewAddress(JArray _params) + protected internal virtual JToken GetNewAddress(JArray _params) { CheckWallet(); WalletAccount account = wallet.CreateAccount(); @@ -81,8 +101,14 @@ protected virtual JToken GetNewAddress(JArray _params) return account.Address; } + /// + /// Gets the balance of a specified asset in the wallet. + /// + /// An array containing the asset ID as a string. + /// A JSON object containing the balance of the specified asset. + /// Thrown when no wallet is open or the asset ID is invalid. [RpcMethod] - protected virtual JToken GetWalletBalance(JArray _params) + protected internal virtual JToken GetWalletBalance(JArray _params) { CheckWallet(); UInt160 asset_id = Result.Ok_Or(() => UInt160.Parse(_params[0].AsString()), RpcError.InvalidParams.WithData($"Invalid asset id: {_params[0]}")); @@ -91,8 +117,14 @@ protected virtual JToken GetWalletBalance(JArray _params) return json; } + /// + /// Gets the amount of unclaimed GAS in the wallet. + /// + /// An empty array. + /// The amount of unclaimed GAS as a string. + /// Thrown when no wallet is open. [RpcMethod] - protected virtual JToken GetWalletUnclaimedGas(JArray _params) + protected internal virtual JToken GetWalletUnclaimedGas(JArray _params) { CheckWallet(); // Datoshi is the smallest unit of GAS, 1 GAS = 10^8 Datoshi @@ -106,8 +138,14 @@ protected virtual JToken GetWalletUnclaimedGas(JArray _params) return datoshi.ToString(); } + /// + /// Imports a private key into the wallet. + /// + /// An array containing the private key as a string. + /// A JSON object containing information about the imported account. + /// Thrown when no wallet is open or the private key is invalid. [RpcMethod] - protected virtual JToken ImportPrivKey(JArray _params) + protected internal virtual JToken ImportPrivKey(JArray _params) { CheckWallet(); string privkey = _params[0].AsString(); @@ -123,10 +161,20 @@ protected virtual JToken ImportPrivKey(JArray _params) }; } + /// + /// Calculates the network fee for a given transaction. + /// + /// An array containing the Base64-encoded serialized transaction. + /// A JSON object containing the calculated network fee. + /// Thrown when the input parameters are invalid or the transaction is malformed. [RpcMethod] - protected virtual JToken CalculateNetworkFee(JArray _params) + protected internal virtual JToken CalculateNetworkFee(JArray _params) { - var tx = Convert.FromBase64String(_params[0].AsString()); + if (_params.Count == 0) + { + throw new RpcException(RpcError.InvalidParams.WithData("Params array is empty, need a raw transaction.")); + } + var tx = Result.Ok_Or(() => Convert.FromBase64String(_params[0].AsString()), RpcError.InvalidParams.WithData($"Invalid tx: {_params[0]}")); ; JObject account = new(); var networkfee = Wallets.Helper.CalculateNetworkFee( @@ -136,8 +184,14 @@ protected virtual JToken CalculateNetworkFee(JArray _params) return account; } + /// + /// Lists all addresses in the wallet. + /// + /// An empty array. + /// An array of JSON objects, each containing information about an address in the wallet. + /// Thrown when no wallet is open. [RpcMethod] - protected virtual JToken ListAddress(JArray _params) + protected internal virtual JToken ListAddress(JArray _params) { CheckWallet(); return wallet.GetAccounts().Select(p => @@ -151,16 +205,39 @@ protected virtual JToken ListAddress(JArray _params) }).ToArray(); } + /// + /// Opens a wallet file. + /// + /// An array containing the wallet path and password. + /// Returns true if the wallet was successfully opened. + /// Thrown when the wallet file is not found, the wallet is not supported, or the password is invalid. [RpcMethod] - protected virtual JToken OpenWallet(JArray _params) + protected internal virtual JToken OpenWallet(JArray _params) { string path = _params[0].AsString(); string password = _params[1].AsString(); File.Exists(path).True_Or(RpcError.WalletNotFound); - wallet = Wallet.Open(path, password, system.Settings).NotNull_Or(RpcError.WalletNotSupported); + try + { + wallet = Wallet.Open(path, password, system.Settings).NotNull_Or(RpcError.WalletNotSupported); + } + catch (NullReferenceException) + { + throw new RpcException(RpcError.WalletNotSupported); + } + catch (InvalidOperationException) + { + throw new RpcException(RpcError.WalletNotSupported.WithData("Invalid password.")); + } + return true; } + /// + /// Processes the result of an invocation with wallet for signing. + /// + /// The result object to process. + /// Optional signers for the transaction. private void ProcessInvokeWithWallet(JObject result, Signer[] signers = null) { if (wallet == null || signers == null || signers.Length == 0) return; @@ -189,8 +266,14 @@ private void ProcessInvokeWithWallet(JObject result, Signer[] signers = null) } } + /// + /// Transfers an asset from a specific address to another address. + /// + /// An array containing asset ID, from address, to address, amount, and optional signers. + /// The transaction details if successful, or the contract parameters if signatures are incomplete. + /// Thrown when no wallet is open, parameters are invalid, or there are insufficient funds. [RpcMethod] - protected virtual JToken SendFrom(JArray _params) + protected internal virtual JToken SendFrom(JArray _params) { CheckWallet(); UInt160 assetId = Result.Ok_Or(() => UInt160.Parse(_params[0].AsString()), RpcError.InvalidParams.WithData($"Invalid asset id: {_params[0]}")); @@ -202,7 +285,7 @@ protected virtual JToken SendFrom(JArray _params) (amount.Sign > 0).True_Or(RpcErrorFactory.InvalidParams("Amount can't be negative.")); Signer[] signers = _params.Count >= 5 ? ((JArray)_params[4]).Select(p => new Signer() { Account = AddressToScriptHash(p.AsString(), system.Settings.AddressVersion), Scopes = WitnessScope.CalledByEntry }).ToArray() : null; - Transaction tx = wallet.MakeTransaction(snapshot, new[] + Transaction tx = Result.Ok_Or(() => wallet.MakeTransaction(snapshot, new[] { new TransferOutput { @@ -210,7 +293,7 @@ protected virtual JToken SendFrom(JArray _params) Value = amount, ScriptHash = to } - }, from, signers).NotNull_Or(RpcError.InsufficientFunds); + }, from, signers), RpcError.InvalidRequest.WithData("Can not process this request.")).NotNull_Or(RpcError.InsufficientFunds); ContractParametersContext transContext = new(snapshot, tx, settings.Network); wallet.Sign(transContext); @@ -227,8 +310,37 @@ protected virtual JToken SendFrom(JArray _params) return SignAndRelay(snapshot, tx); } + /// + /// Transfers assets to multiple addresses. + /// + /// + /// An array containing the following elements: + /// [0] (optional): The address to send from as a string. If omitted, the assets will be sent from any address in the wallet. + /// [1]: An array of transfer objects, each containing: + /// - "asset": The asset ID (UInt160) as a string. + /// - "value": The amount to transfer as a string. + /// - "address": The recipient address as a string. + /// [2] (optional): An array of signers, each containing: + /// - The address of the signer as a string. + /// + /// + /// If the transaction is successfully created and all signatures are present: + /// Returns a JSON object representing the transaction. + /// If not all signatures are present: + /// Returns a JSON object representing the contract parameters that need to be signed. + /// + /// + /// Thrown when: + /// - No wallet is open. + /// - The 'to' parameter is invalid or empty. + /// - Any of the asset IDs are invalid. + /// - Any of the amounts are negative or invalid. + /// - Any of the addresses are invalid. + /// - There are insufficient funds for the transfer. + /// - The network fee exceeds the maximum allowed fee. + /// [RpcMethod] - protected virtual JToken SendMany(JArray _params) + protected internal virtual JToken SendMany(JArray _params) { CheckWallet(); int to_start = 0; @@ -273,8 +385,14 @@ protected virtual JToken SendMany(JArray _params) return SignAndRelay(snapshot, tx); } + /// + /// Transfers an asset to a specific address. + /// + /// An array containing asset ID, to address, and amount. + /// The transaction details if successful, or the contract parameters if signatures are incomplete. + /// Thrown when no wallet is open, parameters are invalid, or there are insufficient funds. [RpcMethod] - protected virtual JToken SendToAddress(JArray _params) + protected internal virtual JToken SendToAddress(JArray _params) { CheckWallet(); UInt160 assetId = Result.Ok_Or(() => UInt160.Parse(_params[0].AsString()), RpcError.InvalidParams.WithData($"Invalid asset hash: {_params[0]}")); @@ -308,8 +426,14 @@ protected virtual JToken SendToAddress(JArray _params) return SignAndRelay(snapshot, tx); } + /// + /// Cancels an unconfirmed transaction. + /// + /// An array containing the transaction ID to cancel, signers, and optional extra fee. + /// The details of the cancellation transaction. + /// Thrown when no wallet is open, the transaction is already confirmed, or there are insufficient funds for the cancellation fee. [RpcMethod] - protected virtual JToken CancelTransaction(JArray _params) + protected internal virtual JToken CancelTransaction(JArray _params) { CheckWallet(); var txid = Result.Ok_Or(() => UInt256.Parse(_params[0].AsString()), RpcError.InvalidParams.WithData($"Invalid txid: {_params[0]}")); @@ -342,8 +466,14 @@ protected virtual JToken CancelTransaction(JArray _params) return SignAndRelay(system.StoreView, tx); } + /// + /// Invokes the verify method of a contract. + /// + /// An array containing the script hash, optional arguments, and optional signers and witnesses. + /// A JSON object containing the result of the verification. + /// Thrown when the script hash is invalid, the contract is not found, or the verification fails. [RpcMethod] - protected virtual JToken InvokeContractVerify(JArray _params) + protected internal virtual JToken InvokeContractVerify(JArray _params) { UInt160 script_hash = Result.Ok_Or(() => UInt160.Parse(_params[0].AsString()), RpcError.InvalidParams.WithData($"Invalid script hash: {_params[0]}")); ContractParameter[] args = _params.Count >= 2 ? ((JArray)_params[1]).Select(p => ContractParameter.FromJson((JObject)p)).ToArray() : Array.Empty(); @@ -352,6 +482,14 @@ protected virtual JToken InvokeContractVerify(JArray _params) return GetVerificationResult(script_hash, args, signers, witnesses); } + /// + /// Gets the result of the contract verification. + /// + /// The script hash of the contract. + /// The contract parameters. + /// Optional signers for the verification. + /// Optional witnesses for the verification. + /// A JSON object containing the verification result. private JObject GetVerificationResult(UInt160 scriptHash, ContractParameter[] args, Signer[] signers = null, Witness[] witnesses = null) { using var snapshot = system.GetSnapshotCache(); @@ -396,6 +534,12 @@ private JObject GetVerificationResult(UInt160 scriptHash, ContractParameter[] ar return json; } + /// + /// Signs and relays a transaction. + /// + /// The data snapshot. + /// The transaction to sign and relay. + /// A JSON object containing the transaction details. private JObject SignAndRelay(DataCache snapshot, Transaction tx) { ContractParametersContext context = new(snapshot, tx, settings.Network); @@ -412,6 +556,12 @@ private JObject SignAndRelay(DataCache snapshot, Transaction tx) } } + /// + /// Converts an address to a script hash. + /// + /// The address to convert. + /// The address version. + /// The script hash corresponding to the address. internal static UInt160 AddressToScriptHash(string address, byte version) { if (UInt160.TryParse(address, out var scriptHash)) diff --git a/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Wallet.cs b/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Wallet.cs new file mode 100644 index 0000000000..2db71ae570 --- /dev/null +++ b/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Wallet.cs @@ -0,0 +1,403 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_RpcServer.Wallet.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.IO; +using Neo.Json; +using Neo.Network.P2P.Payloads; +using Neo.SmartContract; +using Neo.SmartContract.Native; +using Neo.UnitTests; +using Neo.UnitTests.Extensions; +using System; +using System.IO; +using System.Linq; + +namespace Neo.Plugins.RpcServer.Tests; + +partial class UT_RpcServer +{ + [TestMethod] + public void TestOpenWallet() + { + const string Path = "wallet.json"; + const string Password = "123456"; + File.WriteAllText(Path, "{\"name\":null,\"version\":\"1.0\",\"scrypt\":{\"n\":16384,\"r\":8,\"p\":8},\"accounts\":[{\"address\":\"NVizn8DiExdmnpTQfjiVY3dox8uXg3Vrxv\",\"label\":null,\"isDefault\":false,\"lock\":false,\"key\":\"6PYPMrsCJ3D4AXJCFWYT2WMSBGF7dLoaNipW14t4UFAkZw3Z9vQRQV1bEU\",\"contract\":{\"script\":\"DCEDaR\\u002BFVb8lOdiMZ/wCHLiI\\u002Bzuf17YuGFReFyHQhB80yMpBVuezJw==\",\"parameters\":[{\"name\":\"signature\",\"type\":\"Signature\"}],\"deployed\":false},\"extra\":null}],\"extra\":null}"); + var paramsArray = new JArray(Path, Password); + var res = _rpcServer.OpenWallet(paramsArray); + Assert.IsTrue(res.AsBoolean()); + Assert.IsNotNull(_rpcServer.wallet); + Assert.AreEqual(_rpcServer.wallet.GetAccounts().FirstOrDefault()!.Address, "NVizn8DiExdmnpTQfjiVY3dox8uXg3Vrxv"); + _rpcServer.CloseWallet([]); + File.Delete(Path); + Assert.IsNull(_rpcServer.wallet); + } + + [TestMethod] + public void TestOpenInvalidWallet() + { + const string Path = "wallet.json"; + const string Password = "password"; + File.Delete(Path); + var paramsArray = new JArray(Path, Password); + var exception = Assert.ThrowsException(() => _rpcServer.OpenWallet(paramsArray), "Should throw RpcException for unsupported wallet"); + Assert.AreEqual(RpcError.WalletNotFound.Code, exception.HResult); + + File.WriteAllText(Path, "{}"); + exception = Assert.ThrowsException(() => _rpcServer.OpenWallet(paramsArray), "Should throw RpcException for unsupported wallet"); + File.Delete(Path); + Assert.AreEqual(RpcError.WalletNotSupported.Code, exception.HResult); + var result = _rpcServer.CloseWallet(new JArray()); + Assert.IsTrue(result.AsBoolean()); + Assert.IsNull(_rpcServer.wallet); + + File.WriteAllText(Path, "{\"name\":null,\"version\":\"1.0\",\"scrypt\":{\"n\":16384,\"r\":8,\"p\":8},\"accounts\":[{\"address\":\"NVizn8DiExdmnpTQfjiVY3dox8uXg3Vrxv\",\"label\":null,\"isDefault\":false,\"lock\":false,\"key\":\"6PYPMrsCJ3D4AXJCFWYT2WMSBGF7dLoaNipW14t4UFAkZw3Z9vQRQV1bEU\",\"contract\":{\"script\":\"DCEDaR\\u002BFVb8lOdiMZ/wCHLiI\\u002Bzuf17YuGFReFyHQhB80yMpBVuezJw==\",\"parameters\":[{\"name\":\"signature\",\"type\":\"Signature\"}],\"deployed\":false},\"extra\":null}],\"extra\":null}"); + exception = Assert.ThrowsException(() => _rpcServer.OpenWallet(paramsArray), "Should throw RpcException for unsupported wallet"); + Assert.AreEqual(RpcError.WalletNotSupported.Code, exception.HResult); + Assert.AreEqual(exception.Message, "Wallet not supported - Invalid password."); + File.Delete(Path); + } + + [TestMethod] + public void TestDumpPrivKey() + { + TestUtilOpenWallet(); + var account = _rpcServer.wallet.GetAccounts().FirstOrDefault(); + Assert.IsNotNull(account); + var privKey = account.GetKey().Export(); + var address = account.Address; + var result = _rpcServer.DumpPrivKey(new JArray(address)); + Assert.AreEqual(privKey, result.AsString()); + TestUtilCloseWallet(); + } + + [TestMethod] + public void TestGetNewAddress() + { + TestUtilOpenWallet(); + var result = _rpcServer.GetNewAddress([]); + Assert.IsInstanceOfType(result, typeof(JString)); + Assert.IsTrue(_rpcServer.wallet.GetAccounts().Any(a => a.Address == result.AsString())); + TestUtilCloseWallet(); + } + + [TestMethod] + public void TestGetWalletBalance() + { + TestUtilOpenWallet(); + var assetId = NativeContract.NEO.Hash; + var paramsArray = new JArray(assetId.ToString()); + var result = _rpcServer.GetWalletBalance(paramsArray); + Assert.IsInstanceOfType(result, typeof(JObject)); + var json = (JObject)result; + Assert.IsTrue(json.ContainsProperty("balance")); + TestUtilCloseWallet(); + } + + [TestMethod] + public void TestGetWalletBalanceInvalidAsset() + { + TestUtilOpenWallet(); + var assetId = UInt160.Zero; + var paramsArray = new JArray(assetId.ToString()); + var result = _rpcServer.GetWalletBalance(paramsArray); + Assert.IsInstanceOfType(result, typeof(JObject)); + var json = (JObject)result; + Assert.IsTrue(json.ContainsProperty("balance")); + TestUtilCloseWallet(); + } + + [TestMethod] + public void TestGetWalletUnclaimedGas() + { + TestUtilOpenWallet(); + var result = _rpcServer.GetWalletUnclaimedGas([]); + Assert.IsInstanceOfType(result, typeof(JString)); + TestUtilCloseWallet(); + } + + [TestMethod] + public void TestImportPrivKey() + { + TestUtilOpenWallet(); + var privKey = _walletAccount.GetKey().Export(); + var paramsArray = new JArray(privKey); + var result = _rpcServer.ImportPrivKey(paramsArray); + Assert.IsInstanceOfType(result, typeof(JObject)); + var json = (JObject)result; + Assert.IsTrue(json.ContainsProperty("address")); + Assert.IsTrue(json.ContainsProperty("haskey")); + Assert.IsTrue(json.ContainsProperty("label")); + Assert.IsTrue(json.ContainsProperty("watchonly")); + TestUtilCloseWallet(); + } + + [TestMethod] + public void TestImportPrivKeyNoWallet() + { + var privKey = _walletAccount.GetKey().Export(); + var paramsArray = new JArray(privKey); + var exception = Assert.ThrowsException(() => _rpcServer.ImportPrivKey(paramsArray)); + Assert.AreEqual(exception.HResult, RpcError.NoOpenedWallet.Code); + } + + [TestMethod] + public void TestCalculateNetworkFee() + { + var snapshot = _neoSystem.GetSnapshot(); + var tx = TestUtils.CreateValidTx(snapshot, _wallet, _walletAccount); + var txBase64 = Convert.ToBase64String(tx.ToArray()); + var paramsArray = new JArray(txBase64); + var result = _rpcServer.CalculateNetworkFee(paramsArray); + Assert.IsInstanceOfType(result, typeof(JObject)); + var json = (JObject)result; + Assert.IsTrue(json.ContainsProperty("networkfee")); + } + + [TestMethod] + public void TestCalculateNetworkFeeNoParam() + { + var exception = Assert.ThrowsException(() => _rpcServer.CalculateNetworkFee([])); + Assert.AreEqual(exception.HResult, RpcError.InvalidParams.Code); + } + + [TestMethod] + public void TestListAddressNoWallet() + { + var exception = Assert.ThrowsException(() => _rpcServer.ListAddress([])); + Assert.AreEqual(exception.HResult, RpcError.NoOpenedWallet.Code); + } + + [TestMethod] + public void TestListAddress() + { + TestUtilOpenWallet(); + var result = _rpcServer.ListAddress([]); + Assert.IsInstanceOfType(result, typeof(JArray)); + var json = (JArray)result; + Assert.IsTrue(json.Count > 0); + TestUtilCloseWallet(); + } + + [TestMethod] + public void TestSendFromNoWallet() + { + var assetId = NativeContract.GAS.Hash; + var from = _walletAccount.Address; + var to = _walletAccount.Address; + var amount = "1"; + var paramsArray = new JArray(assetId.ToString(), from, to, amount); + var exception = Assert.ThrowsException(() => _rpcServer.SendFrom(paramsArray), "Should throw RpcException for insufficient funds"); + Assert.AreEqual(exception.HResult, RpcError.NoOpenedWallet.Code); + } + + [TestMethod] + public void TestSendFrom() + { + TestUtilOpenWallet(); + var assetId = NativeContract.GAS.Hash; + var from = _walletAccount.Address; + var to = _walletAccount.Address; + var amount = "1"; + var paramsArray = new JArray(assetId.ToString(), from, to, amount); + var exception = Assert.ThrowsException(() => _rpcServer.SendFrom(paramsArray)); + Assert.AreEqual(exception.HResult, RpcError.InvalidRequest.Code); + TestUtilCloseWallet(); + } + + [TestMethod] + public void TestSendMany() + { + var from = _walletAccount.Address; + var to = new JArray { new JObject { ["asset"] = NativeContract.GAS.Hash.ToString(), ["value"] = "1", ["address"] = _walletAccount.Address } }; + var paramsArray = new JArray(from, to); + var exception = Assert.ThrowsException(() => _rpcServer.SendMany(paramsArray), "Should throw RpcException for insufficient funds"); + Assert.AreEqual(exception.HResult, RpcError.NoOpenedWallet.Code); + } + + [TestMethod] + public void TestSendToAddress() + { + var assetId = NativeContract.GAS.Hash; + var to = _walletAccount.Address; + var amount = "1"; + var paramsArray = new JArray(assetId.ToString(), to, amount); + var exception = Assert.ThrowsException(() => _rpcServer.SendToAddress(paramsArray), "Should throw RpcException for insufficient funds"); + Assert.AreEqual(exception.HResult, RpcError.NoOpenedWallet.Code); + } + + [TestMethod] + public void TestCloseWallet_WhenWalletNotOpen() + { + _rpcServer.wallet = null; + var result = _rpcServer.CloseWallet(new JArray()); + Assert.IsTrue(result.AsBoolean()); + } + + [TestMethod] + public void TestDumpPrivKey_WhenWalletNotOpen() + { + _rpcServer.wallet = null; + var exception = Assert.ThrowsException(() => _rpcServer.DumpPrivKey(new JArray(_walletAccount.Address)), "Should throw RpcException for no opened wallet"); + Assert.AreEqual(exception.HResult, RpcError.NoOpenedWallet.Code); + } + + [TestMethod] + public void TestGetNewAddress_WhenWalletNotOpen() + { + _rpcServer.wallet = null; + var exception = Assert.ThrowsException(() => _rpcServer.GetNewAddress(new JArray()), "Should throw RpcException for no opened wallet"); + Assert.AreEqual(exception.HResult, RpcError.NoOpenedWallet.Code); + } + + [TestMethod] + public void TestGetWalletBalance_WhenWalletNotOpen() + { + _rpcServer.wallet = null; + var exception = Assert.ThrowsException(() => _rpcServer.GetWalletBalance(new JArray(NativeContract.NEO.Hash.ToString())), "Should throw RpcException for no opened wallet"); + Assert.AreEqual(exception.HResult, RpcError.NoOpenedWallet.Code); + } + + [TestMethod] + public void TestGetWalletUnclaimedGas_WhenWalletNotOpen() + { + _rpcServer.wallet = null; + var exception = Assert.ThrowsException(() => _rpcServer.GetWalletUnclaimedGas(new JArray()), "Should throw RpcException for no opened wallet"); + Assert.AreEqual(exception.HResult, RpcError.NoOpenedWallet.Code); + } + + [TestMethod] + public void TestImportPrivKey_WhenWalletNotOpen() + { + _rpcServer.wallet = null; + var privKey = _walletAccount.GetKey().Export(); + var exception = Assert.ThrowsException(() => _rpcServer.ImportPrivKey(new JArray(privKey)), "Should throw RpcException for no opened wallet"); + Assert.AreEqual(exception.HResult, RpcError.NoOpenedWallet.Code); + } + + [TestMethod] + public void TestCalculateNetworkFee_InvalidTransactionFormat() + { + var invalidTxBase64 = "invalid_base64"; + var paramsArray = new JArray(invalidTxBase64); + var exception = Assert.ThrowsException(() => _rpcServer.CalculateNetworkFee(paramsArray), "Should throw RpcException for invalid transaction format"); + Assert.AreEqual(exception.HResult, RpcError.InvalidParams.Code); + } + + [TestMethod] + public void TestListAddress_WhenWalletNotOpen() + { + // Ensure the wallet is not open + _rpcServer.wallet = null; + + // Attempt to call ListAddress and expect an RpcException + var exception = Assert.ThrowsException(() => _rpcServer.ListAddress(new JArray())); + + // Verify the exception has the expected error code + Assert.AreEqual(RpcError.NoOpenedWallet.Code, exception.HResult); + } + + [TestMethod] + public void TestCancelTransaction() + { + TestUtilOpenWallet(); + var snapshot = _neoSystem.GetSnapshot(); + var tx = TestUtils.CreateValidTx(snapshot, _wallet, _walletAccount); + snapshot.Commit(); + var paramsArray = new JArray(tx.Hash.ToString(), new JArray(_walletAccount.Address)); + var exception = Assert.ThrowsException(() => _rpcServer.CancelTransaction(paramsArray), "Should throw RpcException for non-existing transaction"); + + Assert.AreEqual(RpcError.InsufficientFunds.Code, exception.HResult); + + // Test with invalid transaction id + var invalidParamsArray = new JArray("invalid_txid", new JArray(_walletAccount.Address)); + exception = Assert.ThrowsException(() => _rpcServer.CancelTransaction(invalidParamsArray), "Should throw RpcException for invalid txid"); + Assert.AreEqual(exception.HResult, RpcError.InvalidParams.Code); + + // Test with no signer + invalidParamsArray = new JArray(tx.Hash.ToString()); + exception = Assert.ThrowsException(() => _rpcServer.CancelTransaction(invalidParamsArray), "Should throw RpcException for invalid txid"); + Assert.AreEqual(exception.HResult, RpcError.BadRequest.Code); + + // Test with null wallet + _rpcServer.wallet = null; + exception = Assert.ThrowsException(() => _rpcServer.CancelTransaction(paramsArray), "Should throw RpcException for no opened wallet"); + Assert.AreEqual(exception.HResult, RpcError.NoOpenedWallet.Code); + TestUtilCloseWallet(); + } + + [TestMethod] + public void TestInvokeContractVerify() + { + var scriptHash = UInt160.Parse("0x70cde1619e405cdef363ab66a1e8dce430d798d5"); + var paramsArray = new JArray(scriptHash.ToString()); + var exception = Assert.ThrowsException(() => _rpcServer.InvokeContractVerify(paramsArray), "Should throw RpcException for unknown contract"); + Assert.AreEqual(exception.HResult, RpcError.UnknownContract.Code); + // Test with invalid script hash + var invalidParamsArray = new JArray("invalid_script_hash"); + exception = Assert.ThrowsException(() => _rpcServer.InvokeContractVerify(invalidParamsArray), "Should throw RpcException for invalid script hash"); + Assert.AreEqual(exception.HResult, RpcError.InvalidParams.Code); + } + + + private void TestUtilOpenWallet() + { + try + { + const string Path = "wallet.json"; + const string Password = "123456"; + File.WriteAllText(Path, "{\"name\":null,\"version\":\"1.0\",\"scrypt\":{\"n\":16384,\"r\":8,\"p\":8},\"accounts\":[{\"address\":\"NVizn8DiExdmnpTQfjiVY3dox8uXg3Vrxv\",\"label\":null,\"isDefault\":false,\"lock\":false,\"key\":\"6PYPMrsCJ3D4AXJCFWYT2WMSBGF7dLoaNipW14t4UFAkZw3Z9vQRQV1bEU\",\"contract\":{\"script\":\"DCEDaR\\u002BFVb8lOdiMZ/wCHLiI\\u002Bzuf17YuGFReFyHQhB80yMpBVuezJw==\",\"parameters\":[{\"name\":\"signature\",\"type\":\"Signature\"}],\"deployed\":false},\"extra\":null}],\"extra\":null}"); + var paramsArray = new JArray(Path, Password); + _rpcServer.OpenWallet(paramsArray); + } + catch (Exception e) + { + Console.WriteLine(e); + } + } + + private void TestUtilCloseWallet() + { + try + { + const string Path = "wallet.json"; + _rpcServer.CloseWallet([]); + File.Delete(Path); + } + catch (Exception e) + { + Console.WriteLine(e); + } + } + + private UInt160 TestUtilAddTestContract() + { + var state = TestUtils.GetContract(); + + var storageKey = new StorageKey + { + Id = state.Id, + Key = new byte[] { 0x01 } + }; + + var storageItem = new StorageItem + { + Value = new byte[] { 0x01, 0x02, 0x03, 0x04 } + }; + + var snapshot = _neoSystem.GetSnapshotCache(); + snapshot.AddContract(state.Hash, state); + snapshot.Add(storageKey, storageItem); + snapshot.Commit(); + return state.Hash; + } +} diff --git a/tests/Neo.UnitTests/TestUtils.Contract.cs b/tests/Neo.UnitTests/TestUtils.Contract.cs new file mode 100644 index 0000000000..da3139561c --- /dev/null +++ b/tests/Neo.UnitTests/TestUtils.Contract.cs @@ -0,0 +1,105 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// TestUtils.Contract.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using Neo.SmartContract; +using Neo.SmartContract.Manifest; +using System; +using System.Linq; + +namespace Neo.UnitTests; + +partial class TestUtils +{ + public static ContractManifest CreateDefaultManifest() + { + return new ContractManifest + { + Name = "testManifest", + Groups = [], + SupportedStandards = [], + Abi = new ContractAbi + { + Events = [], + Methods = + [ + new ContractMethodDescriptor + { + Name = "testMethod", + Parameters = [], + ReturnType = ContractParameterType.Void, + Offset = 0, + Safe = true + } + ] + }, + Permissions = [ContractPermission.DefaultPermission], + Trusts = WildcardContainer.Create(), + Extra = null + }; + } + + public static ContractManifest CreateManifest(string method, ContractParameterType returnType, params ContractParameterType[] parameterTypes) + { + var manifest = CreateDefaultManifest(); + manifest.Abi.Methods = + [ + new ContractMethodDescriptor() + { + Name = method, + Parameters = parameterTypes.Select((p, i) => new ContractParameterDefinition + { + Name = $"p{i}", + Type = p + }).ToArray(), + ReturnType = returnType + } + ]; + return manifest; + } + + public static ContractState GetContract(string method = "test", int parametersCount = 0) + { + NefFile nef = new() + { + Compiler = "", + Source = "", + Tokens = [], + Script = new byte[] { 0x01, 0x01, 0x01, 0x01 } + }; + nef.CheckSum = NefFile.ComputeChecksum(nef); + return new ContractState + { + Id = 0x43000000, + Nef = nef, + Hash = nef.Script.Span.ToScriptHash(), + Manifest = CreateManifest(method, ContractParameterType.Any, Enumerable.Repeat(ContractParameterType.Any, parametersCount).ToArray()) + }; + } + + internal static ContractState GetContract(byte[] script, ContractManifest manifest = null) + { + NefFile nef = new() + { + Compiler = "", + Source = "", + Tokens = [], + Script = script + }; + nef.CheckSum = NefFile.ComputeChecksum(nef); + return new ContractState + { + Id = 1, + Hash = script.ToScriptHash(), + Nef = nef, + Manifest = manifest ?? CreateDefaultManifest() + }; + } +} diff --git a/tests/Neo.UnitTests/TestUtils.Transaction.cs b/tests/Neo.UnitTests/TestUtils.Transaction.cs index f96ac8ec74..f6d6ebd4b5 100644 --- a/tests/Neo.UnitTests/TestUtils.Transaction.cs +++ b/tests/Neo.UnitTests/TestUtils.Transaction.cs @@ -11,6 +11,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.Cryptography; +using Neo.Cryptography.ECC; using Neo.IO; using Neo.Network.P2P.Payloads; using Neo.Persistence; @@ -22,11 +23,112 @@ using System; using System.IO; using System.Linq; +using System.Numerics; namespace Neo.UnitTests; public partial class TestUtils { + public static Transaction CreateValidTx(DataCache snapshot, NEP6Wallet wallet, WalletAccount account) + { + return CreateValidTx(snapshot, wallet, account.ScriptHash, (uint)new Random().Next()); + } + + public static Transaction CreateValidTx(DataCache snapshot, NEP6Wallet wallet, UInt160 account, uint nonce) + { + var tx = wallet.MakeTransaction(snapshot, [ + new TransferOutput + { + AssetId = NativeContract.GAS.Hash, + ScriptHash = account, + Value = new BigDecimal(BigInteger.One, 8) + } + ], + account); + + tx.Nonce = nonce; + tx.Signers = [new Signer { Account = account, Scopes = WitnessScope.CalledByEntry }]; + var data = new ContractParametersContext(snapshot, tx, TestProtocolSettings.Default.Network); + Assert.IsNull(data.GetSignatures(tx.Sender)); + Assert.IsTrue(wallet.Sign(data)); + Assert.IsTrue(data.Completed); + Assert.AreEqual(1, data.GetSignatures(tx.Sender).Count); + + tx.Witnesses = data.GetWitnesses(); + return tx; + } + + public static Transaction CreateValidTx(DataCache snapshot, NEP6Wallet wallet, UInt160 account, uint nonce, UInt256[] conflicts) + { + var tx = wallet.MakeTransaction(snapshot, [ + new TransferOutput + { + AssetId = NativeContract.GAS.Hash, + ScriptHash = account, + Value = new BigDecimal(BigInteger.One, 8) + } + ], + account); + tx.Attributes = conflicts.Select(conflict => new Conflicts { Hash = conflict }).ToArray(); + tx.Nonce = nonce; + tx.Signers = [new Signer { Account = account, Scopes = WitnessScope.CalledByEntry }]; + var data = new ContractParametersContext(snapshot, tx, TestProtocolSettings.Default.Network); + Assert.IsNull(data.GetSignatures(tx.Sender)); + Assert.IsTrue(wallet.Sign(data)); + Assert.IsTrue(data.Completed); + Assert.AreEqual(1, data.GetSignatures(tx.Sender).Count); + tx.Witnesses = data.GetWitnesses(); + return tx; + } + + public static Transaction CreateRandomHashTransaction() + { + var randomBytes = new byte[16]; + TestRandom.NextBytes(randomBytes); + return new Transaction + { + Script = randomBytes, + Attributes = [], + Signers = [new Signer { Account = UInt160.Zero }], + Witnesses = + [ + new Witness + { + InvocationScript = Array.Empty(), + VerificationScript = Array.Empty() + } + ] + }; + } + + public static Transaction GetTransaction(UInt160 sender) + { + return new Transaction + { + Script = new[] { (byte)OpCode.PUSH2 }, + Attributes = [], + Signers = + [ + new Signer + { + Account = sender, + Scopes = WitnessScope.CalledByEntry, + AllowedContracts = [], + AllowedGroups = [], + Rules = [], + } + ], + Witnesses = + [ + new Witness + { + InvocationScript = Array.Empty(), + VerificationScript = Array.Empty() + } + ] + }; + } + public static Transaction CreateInvalidTransaction(DataCache snapshot, NEP6Wallet wallet, WalletAccount account, InvalidTransactionType type, UInt256 conflict = null) { var rand = new Random(); diff --git a/tests/Neo.UnitTests/TestUtils.cs b/tests/Neo.UnitTests/TestUtils.cs index c1694347a7..a9ad4d8ff7 100644 --- a/tests/Neo.UnitTests/TestUtils.cs +++ b/tests/Neo.UnitTests/TestUtils.cs @@ -48,53 +48,6 @@ public static UInt160 RandomUInt160() return new UInt160(data); } - public static ContractManifest CreateDefaultManifest() - { - return new ContractManifest() - { - Name = "testManifest", - Groups = new ContractGroup[0], - SupportedStandards = Array.Empty(), - Abi = new ContractAbi() - { - Events = new ContractEventDescriptor[0], - Methods = new[] - { - new ContractMethodDescriptor - { - Name = "testMethod", - Parameters = new ContractParameterDefinition[0], - ReturnType = ContractParameterType.Void, - Offset = 0, - Safe = true - } - } - }, - Permissions = new[] { ContractPermission.DefaultPermission }, - Trusts = WildcardContainer.Create(), - Extra = null - }; - } - - public static ContractManifest CreateManifest(string method, ContractParameterType returnType, params ContractParameterType[] parameterTypes) - { - ContractManifest manifest = CreateDefaultManifest(); - manifest.Abi.Methods = new ContractMethodDescriptor[] - { - new ContractMethodDescriptor() - { - Name = method, - Parameters = parameterTypes.Select((p, i) => new ContractParameterDefinition - { - Name = $"p{i}", - Type = p - }).ToArray(), - ReturnType = returnType - } - }; - return manifest; - } - public static StorageKey CreateStorageKey(this NativeContract contract, byte prefix, ISerializable key = null) { var k = new KeyBuilder(contract.Id, prefix); @@ -130,118 +83,6 @@ public static NEP6Wallet GenerateTestWallet(string password) return new NEP6Wallet(null, password, TestProtocolSettings.Default, wallet); } - public static Transaction CreateValidTx(DataCache snapshot, NEP6Wallet wallet, WalletAccount account) - { - return CreateValidTx(snapshot, wallet, account.ScriptHash, (uint)new Random().Next()); - } - - public static Transaction CreateValidTx(DataCache snapshot, NEP6Wallet wallet, UInt160 account, uint nonce) - { - var tx = wallet.MakeTransaction(snapshot, [ - new TransferOutput - { - AssetId = NativeContract.GAS.Hash, - ScriptHash = account, - Value = new BigDecimal(BigInteger.One, 8) - } - ], - account); - - tx.Nonce = nonce; - - var data = new ContractParametersContext(snapshot, tx, TestProtocolSettings.Default.Network); - Assert.IsNull(data.GetSignatures(tx.Sender)); - Assert.IsTrue(wallet.Sign(data)); - Assert.IsTrue(data.Completed); - Assert.AreEqual(1, data.GetSignatures(tx.Sender).Count()); - - tx.Witnesses = data.GetWitnesses(); - return tx; - } - - public static Transaction CreateValidTx(DataCache snapshot, NEP6Wallet wallet, UInt160 account, uint nonce, UInt256[] conflicts) - { - var tx = wallet.MakeTransaction(snapshot, [ - new TransferOutput - { - AssetId = NativeContract.GAS.Hash, - ScriptHash = account, - Value = new BigDecimal(BigInteger.One, 8) - } - ], - account); - tx.Attributes = conflicts.Select(conflict => new Conflicts { Hash = conflict }).ToArray(); - tx.Nonce = nonce; - - var data = new ContractParametersContext(snapshot, tx, TestProtocolSettings.Default.Network); - Assert.IsNull(data.GetSignatures(tx.Sender)); - Assert.IsTrue(wallet.Sign(data)); - Assert.IsTrue(data.Completed); - Assert.AreEqual(1, data.GetSignatures(tx.Sender).Count); - tx.Witnesses = data.GetWitnesses(); - return tx; - } - - public static Transaction GetTransaction(UInt160 sender) - { - return new Transaction - { - Script = new byte[] { (byte)OpCode.PUSH2 }, - Attributes = Array.Empty(), - Signers = new[]{ new Signer() - { - Account = sender, - Scopes = WitnessScope.CalledByEntry, - AllowedContracts = Array.Empty(), - AllowedGroups = Array.Empty(), - Rules = Array.Empty(), - } }, - Witnesses = new Witness[]{ new Witness - { - InvocationScript = Array.Empty(), - VerificationScript = Array.Empty() - } } - }; - } - - public static ContractState GetContract(string method = "test", int parametersCount = 0) - { - NefFile nef = new() - { - Compiler = "", - Source = "", - Tokens = Array.Empty(), - Script = new byte[] { 0x01, 0x01, 0x01, 0x01 } - }; - nef.CheckSum = NefFile.ComputeChecksum(nef); - return new ContractState - { - Id = 0x43000000, - Nef = nef, - Hash = nef.Script.Span.ToScriptHash(), - Manifest = CreateManifest(method, ContractParameterType.Any, Enumerable.Repeat(ContractParameterType.Any, parametersCount).ToArray()) - }; - } - - internal static ContractState GetContract(byte[] script, ContractManifest manifest = null) - { - NefFile nef = new() - { - Compiler = "", - Source = "", - Tokens = Array.Empty(), - Script = script - }; - nef.CheckSum = NefFile.ComputeChecksum(nef); - return new ContractState - { - Id = 1, - Hash = script.ToScriptHash(), - Nef = nef, - Manifest = manifest ?? CreateDefaultManifest() - }; - } - internal static StorageItem GetStorageItem(byte[] value) { return new StorageItem @@ -268,26 +109,6 @@ public static void StorageItemAdd(DataCache snapshot, int id, byte[] keyValue, b }, new StorageItem(value)); } - public static Transaction CreateRandomHashTransaction() - { - var randomBytes = new byte[16]; - TestRandom.NextBytes(randomBytes); - return new Transaction - { - Script = randomBytes, - Attributes = Array.Empty(), - Signers = new Signer[] { new Signer() { Account = UInt160.Zero } }, - Witnesses = new[] - { - new Witness - { - InvocationScript = new byte[0], - VerificationScript = new byte[0] - } - } - }; - } - public static void FillMemoryPool(DataCache snapshot, NeoSystem system, NEP6Wallet wallet, WalletAccount account) { for (int i = 0; i < system.Settings.MemoryPoolMaxTransactions; i++) From 1c3fe4564ae316b7d7ad75328bc7b0726d69bc97 Mon Sep 17 00:00:00 2001 From: Christopher Schuchardt Date: Tue, 30 Jul 2024 01:46:47 -0400 Subject: [PATCH 63/71] `[Move]` Part-3 Classes into Different Library - `Neo.Extensions` (#3400) * Part-1 `Neo.IO` - move * Part-2 * Added `BigInteger` to `Neo.Extensions` * Found more `BigInteger` * Added `ByteArray` to `Neo.Extensions` * Added Tests * Added `tests` from `Part-2` --------- Co-authored-by: Shargon Co-authored-by: Jimmy --- .../{Extensions.cs => AssemblyExtensions.cs} | 4 +- src/Neo.CLI/CLI/MainService.Tools.cs | 1 + src/Neo.CLI/CLI/MainService.Vote.cs | 1 + src/Neo.CLI/CLI/MainService.Wallet.cs | 1 + src/Neo.CLI/CLI/MainService.cs | 1 + src/Neo.CLI/Neo.CLI.csproj | 1 + src/Neo.Extensions/ByteExtensions.cs | 59 ++++++++++++ src/Neo.GUI/GUI/DeployContractDialog.cs | 1 + src/Neo.GUI/GUI/InvokeContractDialog.cs | 1 + src/Neo.GUI/GUI/SigningDialog.cs | 1 + src/Neo.GUI/GUI/ViewContractDialog.cs | 1 + src/Neo.GUI/GUI/ViewPrivateKeyDialog.cs | 1 + src/Neo.GUI/GUI/Wrappers/HexConverter.cs | 1 + src/Neo/Cryptography/Base58.cs | 3 +- src/Neo/Cryptography/ECC/ECPoint.cs | 5 +- src/Neo/Cryptography/Helper.cs | 3 +- src/Neo/Helper.cs | 95 ------------------- src/Neo/SmartContract/ContractParameter.cs | 1 + src/Neo/UInt160.cs | 1 + src/Neo/UInt256.cs | 1 + .../DBFTPlugin/Consensus/ConsensusService.cs | 1 + .../Cryptography/MPTTrie/Trie.Delete.cs | 5 +- .../MPTTrie/Cryptography/MPTTrie/Trie.Find.cs | 15 ++- .../Cryptography/MPTTrie/Trie.Proof.cs | 3 +- src/Plugins/OracleService/OracleService.cs | 5 +- src/Plugins/RpcClient/Nep17API.cs | 17 ++-- src/Plugins/RpcServer/RpcServer.Blockchain.cs | 1 + .../Trackers/NEP-11/Nep11Tracker.cs | 1 + .../Cryptography/MPTTrie/UT_Cache.cs | 1 + .../Cryptography/MPTTrie/UT_Node.cs | 1 + .../Cryptography/MPTTrie/UT_Trie.cs | 5 +- .../Neo.Extensions.Tests/UT_ByteExtensions.cs | 37 ++++++++ tests/Neo.Network.RPC.Tests/UT_Nep17API.cs | 16 ++-- tests/Neo.Network.RPC.Tests/UT_Utility.cs | 1 + tests/Neo.Network.RPC.Tests/UT_WalletAPI.cs | 1 + .../Cryptography/UT_Cryptography_Helper.cs | 1 + .../Cryptography/UT_Murmur128.cs | 1 + tests/Neo.UnitTests/Cryptography/UT_SCrypt.cs | 1 + .../Neo.UnitTests/IO/Caching/UT_CloneCache.cs | 1 + tests/Neo.UnitTests/IO/UT_IOHelper.cs | 1 + tests/Neo.UnitTests/Ledger/UT_TrimmedBlock.cs | 1 + .../Network/P2P/Payloads/UT_Block.cs | 1 + .../Network/P2P/Payloads/UT_Header.cs | 1 + .../Network/P2P/Payloads/UT_Signers.cs | 1 + .../Network/P2P/Payloads/UT_Transaction.cs | 2 + .../Network/P2P/Payloads/UT_Witness.cs | 1 + .../SmartContract/Native/UT_CryptoLib.cs | 1 + .../SmartContract/Native/UT_NeoToken.cs | 1 + .../SmartContract/Native/UT_RoleManagement.cs | 1 + .../SmartContract/Native/UT_StdLib.cs | 1 + .../SmartContract/UT_ContractParameter.cs | 1 + .../UT_ContractParameterContext.cs | 1 + .../SmartContract/UT_InteropService.NEO.cs | 1 + .../SmartContract/UT_InteropService.cs | 1 + .../SmartContract/UT_KeyBuilder.cs | 1 + tests/Neo.UnitTests/UT_Helper.cs | 32 ------- tests/Neo.UnitTests/VM/UT_Helper.cs | 1 + 57 files changed, 177 insertions(+), 170 deletions(-) rename src/Neo.CLI/{Extensions.cs => AssemblyExtensions.cs} (88%) create mode 100644 src/Neo.Extensions/ByteExtensions.cs create mode 100644 tests/Neo.Extensions.Tests/UT_ByteExtensions.cs diff --git a/src/Neo.CLI/Extensions.cs b/src/Neo.CLI/AssemblyExtensions.cs similarity index 88% rename from src/Neo.CLI/Extensions.cs rename to src/Neo.CLI/AssemblyExtensions.cs index b8331201be..42e49e13fc 100644 --- a/src/Neo.CLI/Extensions.cs +++ b/src/Neo.CLI/AssemblyExtensions.cs @@ -1,6 +1,6 @@ // Copyright (C) 2015-2024 The Neo Project. // -// Extensions.cs file belongs to the neo project and is free +// AssemblyExtensions.cs file belongs to the neo project and is free // software distributed under the MIT software license, see the // accompanying file LICENSE in the main directory of the // repository or http://www.opensource.org/licenses/mit-license.php @@ -17,7 +17,7 @@ namespace Neo /// /// Extension methods /// - internal static class Extensions + internal static class AssemblyExtensions { public static string GetVersion(this Assembly assembly) { diff --git a/src/Neo.CLI/CLI/MainService.Tools.cs b/src/Neo.CLI/CLI/MainService.Tools.cs index 66723d7df9..a8eab7893c 100644 --- a/src/Neo.CLI/CLI/MainService.Tools.cs +++ b/src/Neo.CLI/CLI/MainService.Tools.cs @@ -11,6 +11,7 @@ using Neo.ConsoleService; using Neo.Cryptography.ECC; +using Neo.Extensions; using Neo.IO; using Neo.SmartContract; using Neo.VM; diff --git a/src/Neo.CLI/CLI/MainService.Vote.cs b/src/Neo.CLI/CLI/MainService.Vote.cs index 12cd48b3a9..bec0bab91d 100644 --- a/src/Neo.CLI/CLI/MainService.Vote.cs +++ b/src/Neo.CLI/CLI/MainService.Vote.cs @@ -11,6 +11,7 @@ using Neo.ConsoleService; using Neo.Cryptography.ECC; +using Neo.Extensions; using Neo.Json; using Neo.SmartContract; using Neo.SmartContract.Native; diff --git a/src/Neo.CLI/CLI/MainService.Wallet.cs b/src/Neo.CLI/CLI/MainService.Wallet.cs index f1390612bc..54bd8dccab 100644 --- a/src/Neo.CLI/CLI/MainService.Wallet.cs +++ b/src/Neo.CLI/CLI/MainService.Wallet.cs @@ -12,6 +12,7 @@ using Akka.Actor; using Neo.ConsoleService; using Neo.Cryptography.ECC; +using Neo.Extensions; using Neo.Json; using Neo.Network.P2P.Payloads; using Neo.Persistence; diff --git a/src/Neo.CLI/CLI/MainService.cs b/src/Neo.CLI/CLI/MainService.cs index de667bc63d..96db57a19d 100644 --- a/src/Neo.CLI/CLI/MainService.cs +++ b/src/Neo.CLI/CLI/MainService.cs @@ -12,6 +12,7 @@ using Akka.Actor; using Neo.ConsoleService; using Neo.Cryptography.ECC; +using Neo.Extensions; using Neo.IO; using Neo.Json; using Neo.Ledger; diff --git a/src/Neo.CLI/Neo.CLI.csproj b/src/Neo.CLI/Neo.CLI.csproj index eaa2cb3067..f2e1359194 100644 --- a/src/Neo.CLI/Neo.CLI.csproj +++ b/src/Neo.CLI/Neo.CLI.csproj @@ -31,6 +31,7 @@ + diff --git a/src/Neo.Extensions/ByteExtensions.cs b/src/Neo.Extensions/ByteExtensions.cs new file mode 100644 index 0000000000..013a8ef1cc --- /dev/null +++ b/src/Neo.Extensions/ByteExtensions.cs @@ -0,0 +1,59 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// ByteExtensions.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using System; +using System.Text; + +namespace Neo.Extensions +{ + public static class ByteExtensions + { + /// + /// Converts a byte array to hex . + /// + /// The byte array to convert. + /// The converted hex . + public static string ToHexString(this byte[] value) + { + StringBuilder sb = new(); + foreach (var b in value) + sb.AppendFormat("{0:x2}", b); + return sb.ToString(); + } + + /// + /// Converts a byte array to hex . + /// + /// The byte array to convert. + /// Indicates whether it should be converted in the reversed byte order. + /// The converted hex . + public static string ToHexString(this byte[] value, bool reverse = false) + { + StringBuilder sb = new(); + for (var i = 0; i < value.Length; i++) + sb.AppendFormat("{0:x2}", value[reverse ? value.Length - i - 1 : i]); + return sb.ToString(); + } + + /// + /// Converts a byte array to hex . + /// + /// The byte array to convert. + /// The converted hex . + public static string ToHexString(this ReadOnlySpan value) + { + StringBuilder sb = new(); + foreach (var b in value) + sb.AppendFormat("{0:x2}", b); + return sb.ToString(); + } + } +} diff --git a/src/Neo.GUI/GUI/DeployContractDialog.cs b/src/Neo.GUI/GUI/DeployContractDialog.cs index 31ca5e6636..0eaf9c1ae1 100644 --- a/src/Neo.GUI/GUI/DeployContractDialog.cs +++ b/src/Neo.GUI/GUI/DeployContractDialog.cs @@ -9,6 +9,7 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using Neo.Extensions; using Neo.SmartContract; using Neo.SmartContract.Native; using Neo.VM; diff --git a/src/Neo.GUI/GUI/InvokeContractDialog.cs b/src/Neo.GUI/GUI/InvokeContractDialog.cs index d8a8a6b66f..e24b3c24ee 100644 --- a/src/Neo.GUI/GUI/InvokeContractDialog.cs +++ b/src/Neo.GUI/GUI/InvokeContractDialog.cs @@ -9,6 +9,7 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using Neo.Extensions; using Neo.Json; using Neo.Network.P2P.Payloads; using Neo.Properties; diff --git a/src/Neo.GUI/GUI/SigningDialog.cs b/src/Neo.GUI/GUI/SigningDialog.cs index 5b515a4365..e7e5b6bb2b 100644 --- a/src/Neo.GUI/GUI/SigningDialog.cs +++ b/src/Neo.GUI/GUI/SigningDialog.cs @@ -10,6 +10,7 @@ // modifications are permitted. using Neo.Cryptography; +using Neo.Extensions; using Neo.Properties; using Neo.Wallets; using System; diff --git a/src/Neo.GUI/GUI/ViewContractDialog.cs b/src/Neo.GUI/GUI/ViewContractDialog.cs index 00ea963328..a97aa648e9 100644 --- a/src/Neo.GUI/GUI/ViewContractDialog.cs +++ b/src/Neo.GUI/GUI/ViewContractDialog.cs @@ -9,6 +9,7 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using Neo.Extensions; using Neo.SmartContract; using Neo.Wallets; using System.Linq; diff --git a/src/Neo.GUI/GUI/ViewPrivateKeyDialog.cs b/src/Neo.GUI/GUI/ViewPrivateKeyDialog.cs index 7beaa56271..4233814df9 100644 --- a/src/Neo.GUI/GUI/ViewPrivateKeyDialog.cs +++ b/src/Neo.GUI/GUI/ViewPrivateKeyDialog.cs @@ -9,6 +9,7 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using Neo.Extensions; using Neo.Wallets; using System.Windows.Forms; diff --git a/src/Neo.GUI/GUI/Wrappers/HexConverter.cs b/src/Neo.GUI/GUI/Wrappers/HexConverter.cs index 757bfd3b97..ecd1fd1e4a 100644 --- a/src/Neo.GUI/GUI/Wrappers/HexConverter.cs +++ b/src/Neo.GUI/GUI/Wrappers/HexConverter.cs @@ -9,6 +9,7 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using Neo.Extensions; using System; using System.ComponentModel; using System.Globalization; diff --git a/src/Neo/Cryptography/Base58.cs b/src/Neo/Cryptography/Base58.cs index adecc8b631..a2f562b06b 100644 --- a/src/Neo/Cryptography/Base58.cs +++ b/src/Neo/Cryptography/Base58.cs @@ -13,7 +13,6 @@ using System.Linq; using System.Numerics; using System.Text; -using static Neo.Helper; namespace Neo.Cryptography { @@ -86,7 +85,7 @@ public static byte[] Decode(string input) var leadingZeros = new byte[leadingZeroCount]; if (bi.IsZero) return leadingZeros; var bytesWithoutLeadingZeros = bi.ToByteArray(isUnsigned: true, isBigEndian: true); - return Concat(leadingZeros, bytesWithoutLeadingZeros); + return [.. leadingZeros, .. bytesWithoutLeadingZeros]; } /// diff --git a/src/Neo/Cryptography/ECC/ECPoint.cs b/src/Neo/Cryptography/ECC/ECPoint.cs index 77d01b90ea..ce6b3ac588 100644 --- a/src/Neo/Cryptography/ECC/ECPoint.cs +++ b/src/Neo/Cryptography/ECC/ECPoint.cs @@ -15,7 +15,6 @@ using System; using System.IO; using System.Numerics; -using static Neo.Helper; namespace Neo.Cryptography.ECC { @@ -225,8 +224,8 @@ public static ECPoint FromBytes(byte[] bytes, ECCurve curve) return bytes.Length switch { 33 or 65 => DecodePoint(bytes, curve), - 64 or 72 => DecodePoint(Concat(new byte[] { 0x04 }, bytes[^64..]), curve), - 96 or 104 => DecodePoint(Concat(new byte[] { 0x04 }, bytes[^96..^32]), curve), + 64 or 72 => DecodePoint([.. new byte[] { 0x04 }, .. bytes[^64..]], curve), + 96 or 104 => DecodePoint([.. new byte[] { 0x04 }, .. bytes[^96..^32]], curve), _ => throw new FormatException(), }; } diff --git a/src/Neo/Cryptography/Helper.cs b/src/Neo/Cryptography/Helper.cs index f13fa08118..41e89f5a49 100644 --- a/src/Neo/Cryptography/Helper.cs +++ b/src/Neo/Cryptography/Helper.cs @@ -22,7 +22,6 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Security.Cryptography; -using static Neo.Helper; using ECPoint = Neo.Cryptography.ECC.ECPoint; namespace Neo.Cryptography @@ -213,7 +212,7 @@ public static byte[] AES256Encrypt(this byte[] plainData, byte[] key, byte[] non var length = cipher.ProcessBytes(plainData, 0, plainData.Length, cipherBytes, 0); cipher.DoFinal(cipherBytes, length); } - return Concat(nonce, cipherBytes, tag); + return [.. nonce, .. cipherBytes, .. tag]; } public static byte[] AES256Decrypt(this byte[] encryptedData, byte[] key, byte[] associatedData = null) diff --git a/src/Neo/Helper.cs b/src/Neo/Helper.cs index 7acf69b0e9..4458d04f42 100644 --- a/src/Neo/Helper.cs +++ b/src/Neo/Helper.cs @@ -17,8 +17,6 @@ using System.Net; using System.Numerics; using System.Reflection; -using System.Runtime.CompilerServices; -using System.Text; namespace Neo { @@ -29,59 +27,6 @@ public static class Helper { private static readonly DateTime unixEpoch = new(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static int BitLen(int w) - { - return (w < 1 << 15 ? (w < 1 << 7 - ? (w < 1 << 3 ? (w < 1 << 1 - ? (w < 1 << 0 ? (w < 0 ? 32 : 0) : 1) - : (w < 1 << 2 ? 2 : 3)) : (w < 1 << 5 - ? (w < 1 << 4 ? 4 : 5) - : (w < 1 << 6 ? 6 : 7))) - : (w < 1 << 11 - ? (w < 1 << 9 ? (w < 1 << 8 ? 8 : 9) : (w < 1 << 10 ? 10 : 11)) - : (w < 1 << 13 ? (w < 1 << 12 ? 12 : 13) : (w < 1 << 14 ? 14 : 15)))) : (w < 1 << 23 ? (w < 1 << 19 - ? (w < 1 << 17 ? (w < 1 << 16 ? 16 : 17) : (w < 1 << 18 ? 18 : 19)) - : (w < 1 << 21 ? (w < 1 << 20 ? 20 : 21) : (w < 1 << 22 ? 22 : 23))) : (w < 1 << 27 - ? (w < 1 << 25 ? (w < 1 << 24 ? 24 : 25) : (w < 1 << 26 ? 26 : 27)) - : (w < 1 << 29 ? (w < 1 << 28 ? 28 : 29) : (w < 1 << 30 ? 30 : 31))))); - } - - /// - /// Concatenates the specified byte arrays. - /// - /// The byte arrays to concatenate. - /// The concatenated byte array. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static byte[] Concat(params byte[][] buffers) - { - int length = 0; - for (int i = 0; i < buffers.Length; i++) - length += buffers[i].Length; - byte[] dst = new byte[length]; - int p = 0; - foreach (byte[] src in buffers) - { - Buffer.BlockCopy(src, 0, dst, p, src.Length); - p += src.Length; - } - return dst; - } - - /// - /// Concatenates two byte arrays. - /// - /// The first byte array to concatenate. - /// The second byte array to concatenate. - /// The concatenated byte array. - public static byte[] Concat(ReadOnlySpan a, ReadOnlySpan b) - { - byte[] buffer = new byte[a.Length + b.Length]; - a.CopyTo(buffer); - b.CopyTo(buffer.AsSpan(a.Length)); - return buffer; - } - internal static void Remove(this HashSet set, ISet other) { if (set.Count > other.Count) @@ -158,46 +103,6 @@ internal static BigInteger NextBigInteger(this Random rand, int sizeInBits) return new BigInteger(b); } - /// - /// Converts a byte array to hex . - /// - /// The byte array to convert. - /// The converted hex . - public static string ToHexString(this byte[] value) - { - StringBuilder sb = new(); - foreach (byte b in value) - sb.AppendFormat("{0:x2}", b); - return sb.ToString(); - } - - /// - /// Converts a byte array to hex . - /// - /// The byte array to convert. - /// Indicates whether it should be converted in the reversed byte order. - /// The converted hex . - public static string ToHexString(this byte[] value, bool reverse = false) - { - StringBuilder sb = new(); - for (int i = 0; i < value.Length; i++) - sb.AppendFormat("{0:x2}", value[reverse ? value.Length - i - 1 : i]); - return sb.ToString(); - } - - /// - /// Converts a byte array to hex . - /// - /// The byte array to convert. - /// The converted hex . - public static string ToHexString(this ReadOnlySpan value) - { - StringBuilder sb = new(); - foreach (byte b in value) - sb.AppendFormat("{0:x2}", b); - return sb.ToString(); - } - /// /// Converts a to timestamp. /// diff --git a/src/Neo/SmartContract/ContractParameter.cs b/src/Neo/SmartContract/ContractParameter.cs index 4abc7aa985..f1b12c6c0a 100644 --- a/src/Neo/SmartContract/ContractParameter.cs +++ b/src/Neo/SmartContract/ContractParameter.cs @@ -10,6 +10,7 @@ // modifications are permitted. using Neo.Cryptography.ECC; +using Neo.Extensions; using Neo.Json; using System; using System.Collections.Generic; diff --git a/src/Neo/UInt160.cs b/src/Neo/UInt160.cs index 8dfd6bf70c..db317ef7e5 100644 --- a/src/Neo/UInt160.cs +++ b/src/Neo/UInt160.cs @@ -9,6 +9,7 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using Neo.Extensions; using Neo.IO; using System; using System.Globalization; diff --git a/src/Neo/UInt256.cs b/src/Neo/UInt256.cs index 7c4d996339..95324ef6ac 100644 --- a/src/Neo/UInt256.cs +++ b/src/Neo/UInt256.cs @@ -9,6 +9,7 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using Neo.Extensions; using Neo.IO; using System; using System.Globalization; diff --git a/src/Plugins/DBFTPlugin/Consensus/ConsensusService.cs b/src/Plugins/DBFTPlugin/Consensus/ConsensusService.cs index eb97e7024b..ad1b88feb1 100644 --- a/src/Plugins/DBFTPlugin/Consensus/ConsensusService.cs +++ b/src/Plugins/DBFTPlugin/Consensus/ConsensusService.cs @@ -10,6 +10,7 @@ // modifications are permitted. using Akka.Actor; +using Neo.Extensions; using Neo.IO; using Neo.Ledger; using Neo.Network.P2P; diff --git a/src/Plugins/MPTTrie/Cryptography/MPTTrie/Trie.Delete.cs b/src/Plugins/MPTTrie/Cryptography/MPTTrie/Trie.Delete.cs index 2041100a14..cb1a09bae7 100644 --- a/src/Plugins/MPTTrie/Cryptography/MPTTrie/Trie.Delete.cs +++ b/src/Plugins/MPTTrie/Cryptography/MPTTrie/Trie.Delete.cs @@ -11,7 +11,6 @@ using System; using System.Collections.Generic; -using static Neo.Helper; namespace Neo.Cryptography.MPTTrie { @@ -57,7 +56,7 @@ private bool TryDelete(ref Node node, ReadOnlySpan path) if (node.Next.Type == NodeType.ExtensionNode) { if (!full) cache.DeleteNode(node.Next.Hash); - node.Key = Concat(node.Key.Span, node.Next.Key.Span); + node.Key = new([.. node.Key.Span, .. node.Next.Key.Span]); node.Next = node.Next.Next; } node.SetDirty(); @@ -107,7 +106,7 @@ private bool TryDelete(ref Node node, ReadOnlySpan path) if (lastChild.Type == NodeType.ExtensionNode) { if (!full) cache.DeleteNode(lastChild.Hash); - lastChild.Key = Concat(childrenIndexes.ToArray(), lastChild.Key.Span); + lastChild.Key = new([.. childrenIndexes.ToArray(), .. lastChild.Key.Span]); lastChild.SetDirty(); cache.PutNode(lastChild); node = lastChild; diff --git a/src/Plugins/MPTTrie/Cryptography/MPTTrie/Trie.Find.cs b/src/Plugins/MPTTrie/Cryptography/MPTTrie/Trie.Find.cs index b3922e8ce8..aeb3a1ec5e 100644 --- a/src/Plugins/MPTTrie/Cryptography/MPTTrie/Trie.Find.cs +++ b/src/Plugins/MPTTrie/Cryptography/MPTTrie/Trie.Find.cs @@ -12,7 +12,6 @@ using System; using System.Collections.Generic; using System.Linq; -using static Neo.Helper; namespace Neo.Cryptography.MPTTrie { @@ -47,7 +46,7 @@ private ReadOnlySpan Seek(ref Node node, ReadOnlySpan path, out Node start = node; return ReadOnlySpan.Empty; } - return Concat(path[..1], Seek(ref node.Children[path[0]], path[1..], out start)); + return new([.. path[..1], .. Seek(ref node.Children[path[0]], path[1..], out start)]); } case NodeType.ExtensionNode: { @@ -58,7 +57,7 @@ private ReadOnlySpan Seek(ref Node node, ReadOnlySpan path, out Node } if (path.StartsWith(node.Key.Span)) { - return Concat(node.Key.Span, Seek(ref node.Next, path[node.Key.Length..], out start)); + return new([.. node.Key.Span, .. Seek(ref node.Next, path[node.Key.Length..], out start)]); } if (node.Key.Span.StartsWith(path)) { @@ -135,10 +134,10 @@ private ReadOnlySpan Seek(ref Node node, ReadOnlySpan path, out Node for (int i = 0; i < Node.BranchChildCount - 1; i++) { if (from[offset] < i) - foreach (var item in Travers(node.Children[i], Concat(path, new byte[] { (byte)i }), from, from.Length)) + foreach (var item in Travers(node.Children[i], [.. path, .. new byte[] { (byte)i }], from, from.Length)) yield return item; else if (i == from[offset]) - foreach (var item in Travers(node.Children[i], Concat(path, new byte[] { (byte)i }), from, offset + 1)) + foreach (var item in Travers(node.Children[i], [.. path, .. new byte[] { (byte)i }], from, offset + 1)) yield return item; } } @@ -148,7 +147,7 @@ private ReadOnlySpan Seek(ref Node node, ReadOnlySpan path, out Node yield return item; for (int i = 0; i < Node.BranchChildCount - 1; i++) { - foreach (var item in Travers(node.Children[i], Concat(path, new byte[] { (byte)i }), from, offset)) + foreach (var item in Travers(node.Children[i], [.. path, .. new byte[] { (byte)i }], from, offset)) yield return item; } } @@ -157,10 +156,10 @@ private ReadOnlySpan Seek(ref Node node, ReadOnlySpan path, out Node case NodeType.ExtensionNode: { if (offset < from.Length && from.AsSpan()[offset..].StartsWith(node.Key.Span)) - foreach (var item in Travers(node.Next, Concat(path, node.Key.Span), from, offset + node.Key.Length)) + foreach (var item in Travers(node.Next, [.. path, .. node.Key.Span], from, offset + node.Key.Length)) yield return item; else if (from.Length <= offset || 0 < node.Key.Span.CompareTo(from.AsSpan(offset))) - foreach (var item in Travers(node.Next, Concat(path, node.Key.Span), from, from.Length)) + foreach (var item in Travers(node.Next, [.. path, .. node.Key.Span], from, from.Length)) yield return item; break; } diff --git a/src/Plugins/MPTTrie/Cryptography/MPTTrie/Trie.Proof.cs b/src/Plugins/MPTTrie/Cryptography/MPTTrie/Trie.Proof.cs index e0925452e3..d3c04053b9 100644 --- a/src/Plugins/MPTTrie/Cryptography/MPTTrie/Trie.Proof.cs +++ b/src/Plugins/MPTTrie/Cryptography/MPTTrie/Trie.Proof.cs @@ -13,7 +13,6 @@ using Neo.Persistence; using System; using System.Collections.Generic; -using static Neo.Helper; namespace Neo.Cryptography.MPTTrie { @@ -86,7 +85,7 @@ public static byte[] VerifyProof(UInt256 root, byte[] key, HashSet proof { using var memoryStore = new MemoryStore(); foreach (byte[] data in proof) - memoryStore.Put(Key(Crypto.Hash256(data)), Concat(data, new byte[] { 1 })); + memoryStore.Put(Key(Crypto.Hash256(data)), [.. data, .. new byte[] { 1 }]); using ISnapshot snapshot = memoryStore.GetSnapshot(); var trie = new Trie(snapshot, root, false); return trie[key]; diff --git a/src/Plugins/OracleService/OracleService.cs b/src/Plugins/OracleService/OracleService.cs index 3f14c8eab8..a6d91892a3 100644 --- a/src/Plugins/OracleService/OracleService.cs +++ b/src/Plugins/OracleService/OracleService.cs @@ -14,6 +14,7 @@ using Neo.ConsoleService; using Neo.Cryptography; using Neo.Cryptography.ECC; +using Neo.Extensions; using Neo.IEventHandlers; using Neo.IO; using Neo.Json; @@ -240,7 +241,7 @@ public JObject SubmitOracleResponse(JArray _params) var oracles = NativeContract.RoleManagement.GetDesignatedByRole(snapshot, Role.Oracle, height); oracles.Any(p => p.Equals(oraclePub)).True_Or(RpcErrorFactory.OracleNotDesignatedNode(oraclePub)); NativeContract.Oracle.GetRequest(snapshot, requestId).NotNull_Or(RpcError.OracleRequestNotFound); - var data = Neo.Helper.Concat(oraclePub.ToArray(), BitConverter.GetBytes(requestId), txSign); + byte[] data = [.. oraclePub.ToArray(), .. BitConverter.GetBytes(requestId), .. txSign]; Crypto.VerifySignature(data, msgSign, oraclePub).True_Or(RpcErrorFactory.InvalidSignature($"Invalid oracle response transaction signature from '{oraclePub}'.")); AddResponseTxSign(snapshot, requestId, oraclePub, txSign); } @@ -262,7 +263,7 @@ private static async Task SendContentAsync(Uri url, string content) private async Task SendResponseSignatureAsync(ulong requestId, byte[] txSign, KeyPair keyPair) { - var message = Neo.Helper.Concat(keyPair.PublicKey.ToArray(), BitConverter.GetBytes(requestId), txSign); + byte[] message = [.. keyPair.PublicKey.ToArray(), .. BitConverter.GetBytes(requestId), .. txSign]; var sign = Crypto.Sign(message, keyPair.PrivateKey); var param = "\"" + Convert.ToBase64String(keyPair.PublicKey.ToArray()) + "\", " + requestId + ", \"" + Convert.ToBase64String(txSign) + "\",\"" + Convert.ToBase64String(sign) + "\""; var content = "{\"id\":" + Interlocked.Increment(ref counter) + ",\"jsonrpc\":\"2.0\",\"method\":\"submitoracleresponse\",\"params\":[" + param + "]}"; diff --git a/src/Plugins/RpcClient/Nep17API.cs b/src/Plugins/RpcClient/Nep17API.cs index 518f470924..0870670231 100644 --- a/src/Plugins/RpcClient/Nep17API.cs +++ b/src/Plugins/RpcClient/Nep17API.cs @@ -19,7 +19,6 @@ using System.Linq; using System.Numerics; using System.Threading.Tasks; -using static Neo.Helper; namespace Neo.Network.RPC { @@ -88,10 +87,10 @@ public async Task TotalSupplyAsync(UInt160 scriptHash) public async Task GetTokenInfoAsync(UInt160 scriptHash) { var contractState = await rpcClient.GetContractStateAsync(scriptHash.ToString()).ConfigureAwait(false); - byte[] script = Concat( - scriptHash.MakeScript("symbol"), - scriptHash.MakeScript("decimals"), - scriptHash.MakeScript("totalSupply")); + byte[] script = [ + .. scriptHash.MakeScript("symbol"), + .. scriptHash.MakeScript("decimals"), + .. scriptHash.MakeScript("totalSupply")]; var name = contractState.Manifest.Name; var result = await rpcClient.InvokeScriptAsync(script).ConfigureAwait(false); var stack = result.Stack; @@ -108,10 +107,10 @@ public async Task GetTokenInfoAsync(UInt160 scriptHash) public async Task GetTokenInfoAsync(string contractHash) { var contractState = await rpcClient.GetContractStateAsync(contractHash).ConfigureAwait(false); - byte[] script = Concat( - contractState.Hash.MakeScript("symbol"), - contractState.Hash.MakeScript("decimals"), - contractState.Hash.MakeScript("totalSupply")); + byte[] script = [ + .. contractState.Hash.MakeScript("symbol"), + .. contractState.Hash.MakeScript("decimals"), + .. contractState.Hash.MakeScript("totalSupply")]; var name = contractState.Manifest.Name; var result = await rpcClient.InvokeScriptAsync(script).ConfigureAwait(false); var stack = result.Stack; diff --git a/src/Plugins/RpcServer/RpcServer.Blockchain.cs b/src/Plugins/RpcServer/RpcServer.Blockchain.cs index 7bc4711f1c..8f73fa3c78 100644 --- a/src/Plugins/RpcServer/RpcServer.Blockchain.cs +++ b/src/Plugins/RpcServer/RpcServer.Blockchain.cs @@ -9,6 +9,7 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using Neo.Extensions; using Neo.IO; using Neo.Json; using Neo.Network.P2P.Payloads; diff --git a/src/Plugins/TokensTracker/Trackers/NEP-11/Nep11Tracker.cs b/src/Plugins/TokensTracker/Trackers/NEP-11/Nep11Tracker.cs index a799e79a7a..e859394e91 100644 --- a/src/Plugins/TokensTracker/Trackers/NEP-11/Nep11Tracker.cs +++ b/src/Plugins/TokensTracker/Trackers/NEP-11/Nep11Tracker.cs @@ -9,6 +9,7 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using Neo.Extensions; using Neo.Json; using Neo.Ledger; using Neo.Network.P2P.Payloads; diff --git a/tests/Neo.Cryptography.MPTTrie.Tests/Cryptography/MPTTrie/UT_Cache.cs b/tests/Neo.Cryptography.MPTTrie.Tests/Cryptography/MPTTrie/UT_Cache.cs index 3a34962059..0b5c0faace 100644 --- a/tests/Neo.Cryptography.MPTTrie.Tests/Cryptography/MPTTrie/UT_Cache.cs +++ b/tests/Neo.Cryptography.MPTTrie.Tests/Cryptography/MPTTrie/UT_Cache.cs @@ -10,6 +10,7 @@ // modifications are permitted. using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Extensions; using Neo.IO; using Neo.Persistence; using System.Text; diff --git a/tests/Neo.Cryptography.MPTTrie.Tests/Cryptography/MPTTrie/UT_Node.cs b/tests/Neo.Cryptography.MPTTrie.Tests/Cryptography/MPTTrie/UT_Node.cs index 8f46fbec27..ba77dcd15e 100644 --- a/tests/Neo.Cryptography.MPTTrie.Tests/Cryptography/MPTTrie/UT_Node.cs +++ b/tests/Neo.Cryptography.MPTTrie.Tests/Cryptography/MPTTrie/UT_Node.cs @@ -10,6 +10,7 @@ // modifications are permitted. using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Extensions; using Neo.IO; using System; using System.Collections.Generic; diff --git a/tests/Neo.Cryptography.MPTTrie.Tests/Cryptography/MPTTrie/UT_Trie.cs b/tests/Neo.Cryptography.MPTTrie.Tests/Cryptography/MPTTrie/UT_Trie.cs index 372de6a738..05592d366b 100644 --- a/tests/Neo.Cryptography.MPTTrie.Tests/Cryptography/MPTTrie/UT_Trie.cs +++ b/tests/Neo.Cryptography.MPTTrie.Tests/Cryptography/MPTTrie/UT_Trie.cs @@ -10,6 +10,7 @@ // modifications are permitted. using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Extensions; using Neo.IO; using Neo.Persistence; using System; @@ -26,7 +27,7 @@ class TestSnapshot : ISnapshot private byte[] StoreKey(byte[] key) { - return Concat(key); + return [.. key]; } public void Put(byte[] key, byte[] value) @@ -65,7 +66,7 @@ public class UT_Trie private void PutToStore(IStore store, Node node) { - store.Put(Concat(new byte[] { 0xf0 }, node.Hash.ToArray()), node.ToArray()); + store.Put([.. new byte[] { 0xf0 }, .. node.Hash.ToArray()], node.ToArray()); } [TestInitialize] diff --git a/tests/Neo.Extensions.Tests/UT_ByteExtensions.cs b/tests/Neo.Extensions.Tests/UT_ByteExtensions.cs new file mode 100644 index 0000000000..a66d462694 --- /dev/null +++ b/tests/Neo.Extensions.Tests/UT_ByteExtensions.cs @@ -0,0 +1,37 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_ByteExtensions.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + + +using FluentAssertions; +using System; + +namespace Neo.Extensions.Tests +{ + [TestClass] + public class UT_ByteExtensions + { + [TestMethod] + public void TestToHexString() + { + byte[] nullStr = null; + Assert.ThrowsException(() => nullStr.ToHexString()); + byte[] empty = Array.Empty(); + empty.ToHexString().Should().Be(""); + empty.ToHexString(false).Should().Be(""); + empty.ToHexString(true).Should().Be(""); + + byte[] str1 = new byte[] { (byte)'n', (byte)'e', (byte)'o' }; + str1.ToHexString().Should().Be("6e656f"); + str1.ToHexString(false).Should().Be("6e656f"); + str1.ToHexString(true).Should().Be("6f656e"); + } + } +} diff --git a/tests/Neo.Network.RPC.Tests/UT_Nep17API.cs b/tests/Neo.Network.RPC.Tests/UT_Nep17API.cs index 3bfb4e87ff..863d424405 100644 --- a/tests/Neo.Network.RPC.Tests/UT_Nep17API.cs +++ b/tests/Neo.Network.RPC.Tests/UT_Nep17API.cs @@ -84,20 +84,20 @@ public async Task TestGetTotalSupply() public async Task TestGetTokenInfo() { UInt160 scriptHash = NativeContract.GAS.Hash; - byte[] testScript = Concat( - scriptHash.MakeScript("symbol"), - scriptHash.MakeScript("decimals"), - scriptHash.MakeScript("totalSupply")); + byte[] testScript = [ + .. scriptHash.MakeScript("symbol"), + .. scriptHash.MakeScript("decimals"), + .. scriptHash.MakeScript("totalSupply")]; UT_TransactionManager.MockInvokeScript(rpcClientMock, testScript, 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) }); scriptHash = NativeContract.NEO.Hash; - testScript = Concat( - scriptHash.MakeScript("symbol"), - scriptHash.MakeScript("decimals"), - scriptHash.MakeScript("totalSupply")); + testScript = [ + .. scriptHash.MakeScript("symbol"), + .. scriptHash.MakeScript("decimals"), + .. scriptHash.MakeScript("totalSupply")]; UT_TransactionManager.MockInvokeScript(rpcClientMock, testScript, new ContractParameter { Type = ContractParameterType.String, Value = NativeContract.NEO.Symbol }, new ContractParameter { Type = ContractParameterType.Integer, Value = new BigInteger(NativeContract.NEO.Decimals) }, diff --git a/tests/Neo.Network.RPC.Tests/UT_Utility.cs b/tests/Neo.Network.RPC.Tests/UT_Utility.cs index fa410c5437..53e381b836 100644 --- a/tests/Neo.Network.RPC.Tests/UT_Utility.cs +++ b/tests/Neo.Network.RPC.Tests/UT_Utility.cs @@ -10,6 +10,7 @@ // modifications are permitted. using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Extensions; using Neo.SmartContract; using Neo.Wallets; using System; diff --git a/tests/Neo.Network.RPC.Tests/UT_WalletAPI.cs b/tests/Neo.Network.RPC.Tests/UT_WalletAPI.cs index 10a35fd064..76851bbe99 100644 --- a/tests/Neo.Network.RPC.Tests/UT_WalletAPI.cs +++ b/tests/Neo.Network.RPC.Tests/UT_WalletAPI.cs @@ -12,6 +12,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; using Neo.Cryptography.ECC; +using Neo.Extensions; using Neo.Json; using Neo.Network.P2P.Payloads; using Neo.Network.RPC.Models; diff --git a/tests/Neo.UnitTests/Cryptography/UT_Cryptography_Helper.cs b/tests/Neo.UnitTests/Cryptography/UT_Cryptography_Helper.cs index 4bfde89ba2..8cddc26d16 100644 --- a/tests/Neo.UnitTests/Cryptography/UT_Cryptography_Helper.cs +++ b/tests/Neo.UnitTests/Cryptography/UT_Cryptography_Helper.cs @@ -12,6 +12,7 @@ using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.Cryptography; +using Neo.Extensions; using Neo.IO; using Neo.Network.P2P.Payloads; using Neo.SmartContract; diff --git a/tests/Neo.UnitTests/Cryptography/UT_Murmur128.cs b/tests/Neo.UnitTests/Cryptography/UT_Murmur128.cs index f33dd7110a..167caf6d3e 100644 --- a/tests/Neo.UnitTests/Cryptography/UT_Murmur128.cs +++ b/tests/Neo.UnitTests/Cryptography/UT_Murmur128.cs @@ -12,6 +12,7 @@ using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.Cryptography; +using Neo.Extensions; using System.Text; namespace Neo.UnitTests.Cryptography diff --git a/tests/Neo.UnitTests/Cryptography/UT_SCrypt.cs b/tests/Neo.UnitTests/Cryptography/UT_SCrypt.cs index c3a3127ff0..ee41f8149a 100644 --- a/tests/Neo.UnitTests/Cryptography/UT_SCrypt.cs +++ b/tests/Neo.UnitTests/Cryptography/UT_SCrypt.cs @@ -10,6 +10,7 @@ // modifications are permitted. using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Extensions; using Org.BouncyCastle.Crypto.Generators; namespace Neo.UnitTests.Cryptography diff --git a/tests/Neo.UnitTests/IO/Caching/UT_CloneCache.cs b/tests/Neo.UnitTests/IO/Caching/UT_CloneCache.cs index e5fea8130a..fd0694f413 100644 --- a/tests/Neo.UnitTests/IO/Caching/UT_CloneCache.cs +++ b/tests/Neo.UnitTests/IO/Caching/UT_CloneCache.cs @@ -11,6 +11,7 @@ using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Extensions; using Neo.IO; using Neo.Persistence; using Neo.SmartContract; diff --git a/tests/Neo.UnitTests/IO/UT_IOHelper.cs b/tests/Neo.UnitTests/IO/UT_IOHelper.cs index 4b74a495b5..48453c992a 100644 --- a/tests/Neo.UnitTests/IO/UT_IOHelper.cs +++ b/tests/Neo.UnitTests/IO/UT_IOHelper.cs @@ -11,6 +11,7 @@ using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Extensions; using Neo.IO; using System; using System.Collections.Generic; diff --git a/tests/Neo.UnitTests/Ledger/UT_TrimmedBlock.cs b/tests/Neo.UnitTests/Ledger/UT_TrimmedBlock.cs index e65bfba843..ae3bc2570b 100644 --- a/tests/Neo.UnitTests/Ledger/UT_TrimmedBlock.cs +++ b/tests/Neo.UnitTests/Ledger/UT_TrimmedBlock.cs @@ -11,6 +11,7 @@ using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Extensions; using Neo.IO; using Neo.Network.P2P.Payloads; using Neo.SmartContract.Native; diff --git a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Block.cs b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Block.cs index 1c31e3483c..c91811c3e2 100644 --- a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Block.cs +++ b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Block.cs @@ -11,6 +11,7 @@ using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Extensions; using Neo.IO; using Neo.Json; using Neo.Ledger; diff --git a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Header.cs b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Header.cs index 0291b6f7c6..7604db6db0 100644 --- a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Header.cs +++ b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Header.cs @@ -11,6 +11,7 @@ using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Extensions; using Neo.IO; using Neo.Network.P2P.Payloads; using Neo.SmartContract.Native; diff --git a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Signers.cs b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Signers.cs index 44d337fd1c..d2358e947c 100644 --- a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Signers.cs +++ b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Signers.cs @@ -12,6 +12,7 @@ using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.Cryptography.ECC; +using Neo.Extensions; using Neo.IO; using Neo.Network.P2P.Payloads; using Neo.Network.P2P.Payloads.Conditions; diff --git a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs index a483ecf0d6..dc910c5142 100644 --- a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs +++ b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs @@ -11,6 +11,8 @@ using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Cryptography.ECC; +using Neo.Extensions; using Neo.IO; using Neo.Json; using Neo.Ledger; diff --git a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Witness.cs b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Witness.cs index cf765365c9..107eb5858c 100644 --- a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Witness.cs +++ b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Witness.cs @@ -11,6 +11,7 @@ using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Extensions; using Neo.IO; using Neo.Json; using Neo.Network.P2P.Payloads; diff --git a/tests/Neo.UnitTests/SmartContract/Native/UT_CryptoLib.cs b/tests/Neo.UnitTests/SmartContract/Native/UT_CryptoLib.cs index cdca35a69e..daf1922644 100644 --- a/tests/Neo.UnitTests/SmartContract/Native/UT_CryptoLib.cs +++ b/tests/Neo.UnitTests/SmartContract/Native/UT_CryptoLib.cs @@ -14,6 +14,7 @@ using Neo.Cryptography; using Neo.Cryptography.BLS12_381; using Neo.Cryptography.ECC; +using Neo.Extensions; using Neo.IO; using Neo.Ledger; using Neo.Network.P2P; diff --git a/tests/Neo.UnitTests/SmartContract/Native/UT_NeoToken.cs b/tests/Neo.UnitTests/SmartContract/Native/UT_NeoToken.cs index cff1eb12b0..2ff07d5a69 100644 --- a/tests/Neo.UnitTests/SmartContract/Native/UT_NeoToken.cs +++ b/tests/Neo.UnitTests/SmartContract/Native/UT_NeoToken.cs @@ -12,6 +12,7 @@ using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.Cryptography.ECC; +using Neo.Extensions; using Neo.IO; using Neo.Network.P2P.Payloads; using Neo.Persistence; diff --git a/tests/Neo.UnitTests/SmartContract/Native/UT_RoleManagement.cs b/tests/Neo.UnitTests/SmartContract/Native/UT_RoleManagement.cs index ad3cb4b6c8..c8d5a176f2 100644 --- a/tests/Neo.UnitTests/SmartContract/Native/UT_RoleManagement.cs +++ b/tests/Neo.UnitTests/SmartContract/Native/UT_RoleManagement.cs @@ -12,6 +12,7 @@ using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.Cryptography.ECC; +using Neo.Extensions; using Neo.IO; using Neo.Network.P2P.Payloads; using Neo.Persistence; diff --git a/tests/Neo.UnitTests/SmartContract/Native/UT_StdLib.cs b/tests/Neo.UnitTests/SmartContract/Native/UT_StdLib.cs index a13d2659ce..1dffb3d384 100644 --- a/tests/Neo.UnitTests/SmartContract/Native/UT_StdLib.cs +++ b/tests/Neo.UnitTests/SmartContract/Native/UT_StdLib.cs @@ -11,6 +11,7 @@ using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Extensions; using Neo.SmartContract; using Neo.SmartContract.Native; using Neo.VM; diff --git a/tests/Neo.UnitTests/SmartContract/UT_ContractParameter.cs b/tests/Neo.UnitTests/SmartContract/UT_ContractParameter.cs index 6618a918e7..4068837f6f 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_ContractParameter.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_ContractParameter.cs @@ -12,6 +12,7 @@ using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.Cryptography.ECC; +using Neo.Extensions; using Neo.Json; using Neo.SmartContract; using System; diff --git a/tests/Neo.UnitTests/SmartContract/UT_ContractParameterContext.cs b/tests/Neo.UnitTests/SmartContract/UT_ContractParameterContext.cs index 9523c41be4..9452cc6ebc 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_ContractParameterContext.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_ContractParameterContext.cs @@ -12,6 +12,7 @@ using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.Cryptography.ECC; +using Neo.Extensions; using Neo.Network.P2P.Payloads; using Neo.SmartContract; using Neo.VM; diff --git a/tests/Neo.UnitTests/SmartContract/UT_InteropService.NEO.cs b/tests/Neo.UnitTests/SmartContract/UT_InteropService.NEO.cs index 657206ab57..e0ccdd7dcc 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_InteropService.NEO.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_InteropService.NEO.cs @@ -12,6 +12,7 @@ using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.Cryptography; +using Neo.Extensions; using Neo.IO; using Neo.Network.P2P; using Neo.SmartContract; diff --git a/tests/Neo.UnitTests/SmartContract/UT_InteropService.cs b/tests/Neo.UnitTests/SmartContract/UT_InteropService.cs index 972f8dc0d1..35dd3dbe37 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_InteropService.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_InteropService.cs @@ -15,6 +15,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.Cryptography; using Neo.Cryptography.ECC; +using Neo.Extensions; using Neo.IO; using Neo.Network.P2P; using Neo.Network.P2P.Payloads; diff --git a/tests/Neo.UnitTests/SmartContract/UT_KeyBuilder.cs b/tests/Neo.UnitTests/SmartContract/UT_KeyBuilder.cs index 3ff52c1324..a3514c7f5a 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_KeyBuilder.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_KeyBuilder.cs @@ -10,6 +10,7 @@ // modifications are permitted. using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Extensions; using Neo.SmartContract; namespace Neo.UnitTests.SmartContract diff --git a/tests/Neo.UnitTests/UT_Helper.cs b/tests/Neo.UnitTests/UT_Helper.cs index 7fa3902cba..413c9dcf31 100644 --- a/tests/Neo.UnitTests/UT_Helper.cs +++ b/tests/Neo.UnitTests/UT_Helper.cs @@ -51,22 +51,6 @@ public void ToScriptHash() res.Should().Be(UInt160.Parse("2d3b96ae1bcc5a585e075e3b81920210dec16302")); } - [TestMethod] - public void TestGetLowestSetBit() - { - var big1 = new BigInteger(0); - big1.GetLowestSetBit().Should().Be(-1); - - var big2 = new BigInteger(512); - big2.GetLowestSetBit().Should().Be(9); - - var big3 = new BigInteger(int.MinValue); - big3.GetLowestSetBit().Should().Be(31); - - var big4 = new BigInteger(long.MinValue); - big4.GetLowestSetBit().Should().Be(63); - } - [TestMethod] public void TestHexToBytes() { @@ -163,22 +147,6 @@ public void TestRemoveHashsetHashSetCache() CollectionAssert.AreEqual(new int[] { 3 }, a.ToArray()); } - [TestMethod] - public void TestToHexString() - { - byte[] nullStr = null; - Assert.ThrowsException(() => nullStr.ToHexString()); - byte[] empty = Array.Empty(); - empty.ToHexString().Should().Be(""); - empty.ToHexString(false).Should().Be(""); - empty.ToHexString(true).Should().Be(""); - - byte[] str1 = new byte[] { (byte)'n', (byte)'e', (byte)'o' }; - str1.ToHexString().Should().Be("6e656f"); - str1.ToHexString(false).Should().Be("6e656f"); - str1.ToHexString(true).Should().Be("6f656e"); - } - [TestMethod] public void TestGetVersion() { diff --git a/tests/Neo.UnitTests/VM/UT_Helper.cs b/tests/Neo.UnitTests/VM/UT_Helper.cs index c5bf61d152..4178ed58d3 100644 --- a/tests/Neo.UnitTests/VM/UT_Helper.cs +++ b/tests/Neo.UnitTests/VM/UT_Helper.cs @@ -12,6 +12,7 @@ using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.Cryptography.ECC; +using Neo.Extensions; using Neo.IO; using Neo.SmartContract; using Neo.SmartContract.Native; From ffb3100034a90baa6af11d52644bf60b04a83861 Mon Sep 17 00:00:00 2001 From: Christopher Schuchardt Date: Tue, 30 Jul 2024 01:53:40 -0400 Subject: [PATCH 64/71] [`Optimization`] Parsing Smart Contract Script Analysis (#3420) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fixed Parsing Smart Contract Script Analysis * Add more opcode outputs * Bug fixes * Move to ToString * Reorder using * Change ToString --------- Co-authored-by: Jimmy Co-authored-by: Vitor Nazário Coelho Co-authored-by: Fernando Diaz Toledano Co-authored-by: NGD Admin <154295625+NGDAdmin@users.noreply.github.com> --- src/Neo.CLI/CLI/MainService.Tools.cs | 67 +++------- src/Neo.CLI/Tools/VMInstruction.cs | 178 +++++++++++++++++++++++++++ 2 files changed, 194 insertions(+), 51 deletions(-) create mode 100644 src/Neo.CLI/Tools/VMInstruction.cs diff --git a/src/Neo.CLI/CLI/MainService.Tools.cs b/src/Neo.CLI/CLI/MainService.Tools.cs index a8eab7893c..60de31493a 100644 --- a/src/Neo.CLI/CLI/MainService.Tools.cs +++ b/src/Neo.CLI/CLI/MainService.Tools.cs @@ -14,7 +14,6 @@ using Neo.Extensions; using Neo.IO; using Neo.SmartContract; -using Neo.VM; using Neo.Wallets; using System; using System.Collections.Generic; @@ -57,7 +56,8 @@ private void OnParseCommand(string value) if (result != null) { - Console.WriteLine($"{pair.Key,-30}\t{result}"); + ConsoleHelper.Info("", "-----", pair.Key, "-----"); + ConsoleHelper.Info("", result, Environment.NewLine); any = true; } } @@ -418,62 +418,27 @@ private static string Base64Fixed(string str) [ParseFunction("Base64 Smart Contract Script Analysis")] private string? ScriptsToOpCode(string base64) { - Script script; try { - var scriptData = Convert.FromBase64String(base64); - script = new Script(scriptData.ToArray(), true); - } - catch (Exception) - { - return null; - } - return ScriptsToOpCode(script); - } + var bytes = Convert.FromBase64String(base64); + var sb = new StringBuilder(); + var line = 0; - private string ScriptsToOpCode(Script script) - { - //Initialize all InteropService - var dic = new Dictionary(); - ApplicationEngine.Services.ToList().ForEach(p => dic.Add(p.Value.Hash, p.Value.Name)); - - //Analyzing Scripts - var ip = 0; - Instruction instruction; - var result = new List(); - while (ip < script.Length && (instruction = script.GetInstruction(ip)) != null) - { - ip += instruction.Size; - - var op = instruction.OpCode; - - if (op.ToString().StartsWith("PUSHINT")) - { - var operand = instruction.Operand.ToArray(); - result.Add($"{op} {new BigInteger(operand)}"); - } - else if (op == OpCode.SYSCALL) + foreach (var instruct in new VMInstruction(bytes)) { - var operand = instruction.Operand.ToArray(); - result.Add($"{op} {dic[BitConverter.ToUInt32(operand)]}"); - } - else - { - if (!instruction.Operand.IsEmpty && instruction.Operand.Length > 0) - { - var operand = instruction.Operand.ToArray(); - var ascii = Encoding.Default.GetString(operand); - ascii = ascii.Any(p => p < '0' || p > 'z') ? operand.ToHexString() : ascii; - - result.Add($"{op} {(operand.Length == 20 ? new UInt160(operand).ToString() : ascii)}"); - } + if (instruct.OperandSize == 0) + sb.AppendFormat("L{0:D04}:{1:X04} {2}{3}", line, instruct.Position, instruct.OpCode, Environment.NewLine); else - { - result.Add($"{op}"); - } + sb.AppendFormat("L{0:D04}:{1:X04} {2,-10}{3}{4}", line, instruct.Position, instruct.OpCode, instruct.DecodeOperand(), Environment.NewLine); + line++; } + + return sb.ToString(); + } + catch + { + return null; } - return Environment.NewLine + string.Join("\r\n", result.ToArray()); } /// diff --git a/src/Neo.CLI/Tools/VMInstruction.cs b/src/Neo.CLI/Tools/VMInstruction.cs new file mode 100644 index 0000000000..9a4ba6a3d4 --- /dev/null +++ b/src/Neo.CLI/Tools/VMInstruction.cs @@ -0,0 +1,178 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// VMInstruction.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using Neo.SmartContract; +using Neo.VM; +using System; +using System.Buffers.Binary; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Numerics; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Text; + +namespace Neo.CLI +{ + [DebuggerDisplay("OpCode={OpCode}, OperandSize={OperandSize}")] + internal sealed class VMInstruction : IEnumerable + { + private const int OpCodeSize = 1; + + public int Position { get; private init; } + public OpCode OpCode { get; private init; } + public ReadOnlyMemory Operand { get; private init; } + public int OperandSize { get; private init; } + public int OperandPrefixSize { get; private init; } + + private static readonly int[] s_operandSizeTable = new int[256]; + private static readonly int[] s_operandSizePrefixTable = new int[256]; + + private readonly ReadOnlyMemory _script; + + public VMInstruction(ReadOnlyMemory script, int start = 0) + { + if (script.IsEmpty) + throw new Exception("Bad Script."); + + var opcode = (OpCode)script.Span[start]; + + if (Enum.IsDefined(opcode) == false) + throw new InvalidDataException($"Invalid opcode at Position: {start}."); + + OperandPrefixSize = s_operandSizePrefixTable[(int)opcode]; + OperandSize = OperandPrefixSize switch + { + 0 => s_operandSizeTable[(int)opcode], + 1 => script.Span[start + 1], + 2 => BinaryPrimitives.ReadUInt16LittleEndian(script.Span[(start + 1)..]), + 4 => unchecked((int)BinaryPrimitives.ReadUInt32LittleEndian(script.Span[(start + 1)..])), + _ => throw new InvalidDataException($"Invalid opcode prefix at Position: {start}."), + }; + + OperandSize += OperandPrefixSize; + + if (start + OperandSize + OpCodeSize > script.Length) + throw new IndexOutOfRangeException("Operand size exceeds end of script."); + + Operand = script.Slice(start + OpCodeSize, OperandSize); + + _script = script; + OpCode = opcode; + Position = start; + } + + static VMInstruction() + { + foreach (var field in typeof(OpCode).GetFields(BindingFlags.Public | BindingFlags.Static)) + { + var attr = field.GetCustomAttribute(); + if (attr == null) continue; + + var index = (uint)(OpCode)field.GetValue(null)!; + s_operandSizeTable[index] = attr.Size; + s_operandSizePrefixTable[index] = attr.SizePrefix; + } + } + + public IEnumerator GetEnumerator() + { + var nip = Position + OperandSize + OpCodeSize; + yield return this; + + VMInstruction? instruct; + for (var ip = nip; ip < _script.Length; ip += instruct.OperandSize + OpCodeSize) + yield return instruct = new VMInstruction(_script, ip); + } + + IEnumerator IEnumerable.GetEnumerator() => + GetEnumerator(); + + public override string ToString() + { + var sb = new StringBuilder(); + sb.AppendFormat("{1:X04} {2,-10}{3}{4}", Position, OpCode, DecodeOperand()); + return sb.ToString(); + } + + public T AsToken(uint index = 0) + where T : unmanaged + { + var size = Unsafe.SizeOf(); + + if (size > OperandSize) + throw new ArgumentOutOfRangeException(nameof(T), $"SizeOf {typeof(T).FullName} is too big for operand. OpCode: {OpCode}."); + if (size + index > OperandSize) + throw new ArgumentOutOfRangeException(nameof(index), $"SizeOf {typeof(T).FullName} + {index} is too big for operand. OpCode: {OpCode}."); + + var bytes = Operand[..OperandSize].ToArray(); + return Unsafe.As(ref bytes[index]); + } + + public string DecodeOperand() + { + var operand = Operand[OperandPrefixSize..].ToArray(); + var asStr = Encoding.UTF8.GetString(operand); + var readable = asStr.All(char.IsAsciiLetterOrDigit); + + return OpCode switch + { + OpCode.JMP or + OpCode.JMPIF or + OpCode.JMPIFNOT or + OpCode.JMPEQ or + OpCode.JMPNE or + OpCode.JMPGT or + OpCode.JMPLT or + OpCode.CALL or + OpCode.ENDTRY => $"[{checked(Position + AsToken()):X08}]", + OpCode.JMP_L or + OpCode.JMPIF_L or + OpCode.PUSHA or + OpCode.JMPIFNOT_L or + OpCode.JMPEQ_L or + OpCode.JMPNE_L or + OpCode.JMPGT_L or + OpCode.JMPLT_L or + OpCode.CALL_L or + OpCode.ENDTRY_L => $"[{checked(Position + AsToken()):X08}]", + OpCode.TRY => $"[{AsToken():X02}, {AsToken(1):X02}]", + OpCode.INITSLOT => $"{AsToken()}, {AsToken(1)}", + OpCode.TRY_L => $"[{checked(Position + AsToken()):X08}, {checked(Position + AsToken()):X08}]", + OpCode.CALLT => $"[{checked(Position + AsToken()):X08}]", + OpCode.NEWARRAY_T or + OpCode.ISTYPE or + OpCode.CONVERT => $"{AsToken():X02}", + OpCode.STLOC or + OpCode.LDLOC or + OpCode.LDSFLD or + OpCode.STSFLD or + OpCode.LDARG or + OpCode.STARG or + OpCode.INITSSLOT => $"{AsToken()}", + OpCode.PUSHINT8 => $"{AsToken()}", + OpCode.PUSHINT16 => $"{AsToken()}", + OpCode.PUSHINT32 => $"{AsToken()}", + OpCode.PUSHINT64 => $"{AsToken()}", + OpCode.PUSHINT128 or + OpCode.PUSHINT256 => $"{new BigInteger(operand)}", + OpCode.SYSCALL => $"[{ApplicationEngine.Services[Unsafe.As(ref operand[0])].Name}]", + OpCode.PUSHDATA1 or + OpCode.PUSHDATA2 or + OpCode.PUSHDATA4 => readable ? $"{Convert.ToHexString(operand)} // {asStr}" : Convert.ToHexString(operand), + _ => readable ? $"\"{asStr}\"" : $"{Convert.ToHexString(operand)}", + }; + } + } +} From 3c7d2492fd6e77e5001c44c4dea4c7c91b345217 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Tue, 30 Jul 2024 14:02:06 +0800 Subject: [PATCH 65/71] update benchmark system (#3442) Co-authored-by: NGD Admin <154295625+NGDAdmin@users.noreply.github.com> --- .../{Benchmarks.cs => Benchmarks.POC.cs} | 13 ++++++------- .../Neo.Benchmarks/Neo.Benchmarks.csproj | 1 + benchmarks/Neo.Benchmarks/Program.cs | 9 +++------ .../{Benchmarks.cs => Benchmarks.POC.cs} | 19 ++++++++++--------- .../Neo.VM.Benchmarks.csproj | 1 + benchmarks/Neo.VM.Benchmarks/Program.cs | 9 +++------ 6 files changed, 24 insertions(+), 28 deletions(-) rename benchmarks/Neo.Benchmarks/{Benchmarks.cs => Benchmarks.POC.cs} (89%) rename benchmarks/Neo.VM.Benchmarks/{Benchmarks.cs => Benchmarks.POC.cs} (87%) diff --git a/benchmarks/Neo.Benchmarks/Benchmarks.cs b/benchmarks/Neo.Benchmarks/Benchmarks.POC.cs similarity index 89% rename from benchmarks/Neo.Benchmarks/Benchmarks.cs rename to benchmarks/Neo.Benchmarks/Benchmarks.POC.cs index 52eec04d44..f073c543a9 100644 --- a/benchmarks/Neo.Benchmarks/Benchmarks.cs +++ b/benchmarks/Neo.Benchmarks/Benchmarks.POC.cs @@ -1,6 +1,6 @@ // Copyright (C) 2015-2024 The Neo Project. // -// Benchmarks.cs file belongs to the neo project and is free +// Benchmarks.POC.cs file belongs to the neo project and is free // software distributed under the MIT software license, see the // accompanying file LICENSE in the main directory of the // repository or http://www.opensource.org/licenses/mit-license.php @@ -9,19 +9,21 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using BenchmarkDotNet.Attributes; using Neo.Network.P2P.Payloads; using Neo.SmartContract; using Neo.VM; using System.Diagnostics; -namespace Neo; +namespace Neo.Benchmark; -static class Benchmarks +public class Benchmarks_PoCs { private static readonly ProtocolSettings protocol = ProtocolSettings.Load("config.json"); private static readonly NeoSystem system = new(protocol, (string)null); - public static void NeoIssue2725() + [Benchmark] + public void NeoIssue2725() { // https://github.com/neo-project/neo/issues/2725 // L00: INITSSLOT 1 @@ -70,10 +72,7 @@ private static void Run(string name, string poc) using var snapshot = system.GetSnapshotCache(); using var engine = ApplicationEngine.Create(TriggerType.Application, tx, snapshot, system.GenesisBlock, protocol, tx.SystemFee); engine.LoadScript(tx.Script); - Stopwatch stopwatch = Stopwatch.StartNew(); engine.Execute(); - stopwatch.Stop(); Debug.Assert(engine.State == VMState.FAULT); - Console.WriteLine($"Benchmark: {name},\tTime: {stopwatch.Elapsed}"); } } diff --git a/benchmarks/Neo.Benchmarks/Neo.Benchmarks.csproj b/benchmarks/Neo.Benchmarks/Neo.Benchmarks.csproj index 22b90aeb03..c4b1a35da9 100644 --- a/benchmarks/Neo.Benchmarks/Neo.Benchmarks.csproj +++ b/benchmarks/Neo.Benchmarks/Neo.Benchmarks.csproj @@ -9,6 +9,7 @@ + diff --git a/benchmarks/Neo.Benchmarks/Program.cs b/benchmarks/Neo.Benchmarks/Program.cs index 9d4125bb9f..e39ef23ff7 100644 --- a/benchmarks/Neo.Benchmarks/Program.cs +++ b/benchmarks/Neo.Benchmarks/Program.cs @@ -9,10 +9,7 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. -using Neo; -using System.Reflection; +using BenchmarkDotNet.Running; +using Neo.Benchmark; -foreach (var method in typeof(Benchmarks).GetMethods(BindingFlags.Public | BindingFlags.Static)) -{ - method.CreateDelegate().Invoke(); -} +BenchmarkRunner.Run(); diff --git a/benchmarks/Neo.VM.Benchmarks/Benchmarks.cs b/benchmarks/Neo.VM.Benchmarks/Benchmarks.POC.cs similarity index 87% rename from benchmarks/Neo.VM.Benchmarks/Benchmarks.cs rename to benchmarks/Neo.VM.Benchmarks/Benchmarks.POC.cs index 6eab691a7d..1a5dac4b97 100644 --- a/benchmarks/Neo.VM.Benchmarks/Benchmarks.cs +++ b/benchmarks/Neo.VM.Benchmarks/Benchmarks.POC.cs @@ -1,6 +1,6 @@ // Copyright (C) 2015-2024 The Neo Project. // -// Benchmarks.cs file belongs to the neo project and is free +// Benchmarks.POC.cs file belongs to the neo project and is free // software distributed under the MIT software license, see the // accompanying file LICENSE in the main directory of the // repository or http://www.opensource.org/licenses/mit-license.php @@ -9,13 +9,15 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using BenchmarkDotNet.Attributes; using System.Diagnostics; -namespace Neo.VM +namespace Neo.VM.Benchmark { - public static class Benchmarks + public class Benchmarks_PoCs { - public static void NeoIssue2528() + [Benchmark] + public void NeoIssue2528() { // https://github.com/neo-project/neo/issues/2528 // L01: INITSLOT 1, 0 @@ -47,7 +49,8 @@ public static void NeoIssue2528() Run(nameof(NeoIssue2528), "VwEAwkpKAfsHdwARwG8AnXcAbwAl9////xHAzwJwlAAAdwAQzm8AnXcAbwAl9////0U="); } - public static void NeoVMIssue418() + [Benchmark] + public void NeoVMIssue418() { // https://github.com/neo-project/neo-vm/issues/418 // L00: NEWARRAY0 @@ -81,7 +84,8 @@ public static void NeoVMIssue418() Run(nameof(NeoVMIssue418), "whBNEcARTRHAVgEB/gGdYBFNEU0SwFMSwFhKJPNFUUU="); } - public static void NeoIssue2723() + [Benchmark] + public void NeoIssue2723() { // L00: INITSSLOT 1 // L01: PUSHINT32 130000 @@ -102,11 +106,8 @@ private static void Run(string name, string poc) byte[] script = Convert.FromBase64String(poc); using ExecutionEngine engine = new(); engine.LoadScript(script); - Stopwatch stopwatch = Stopwatch.StartNew(); engine.Execute(); - stopwatch.Stop(); Debug.Assert(engine.State == VMState.HALT); - Console.WriteLine($"Benchmark: {name},\tTime: {stopwatch.Elapsed}"); } } } diff --git a/benchmarks/Neo.VM.Benchmarks/Neo.VM.Benchmarks.csproj b/benchmarks/Neo.VM.Benchmarks/Neo.VM.Benchmarks.csproj index 4c3c3d6057..ae717e8254 100644 --- a/benchmarks/Neo.VM.Benchmarks/Neo.VM.Benchmarks.csproj +++ b/benchmarks/Neo.VM.Benchmarks/Neo.VM.Benchmarks.csproj @@ -10,6 +10,7 @@ + diff --git a/benchmarks/Neo.VM.Benchmarks/Program.cs b/benchmarks/Neo.VM.Benchmarks/Program.cs index a9c86f405d..028dff9460 100644 --- a/benchmarks/Neo.VM.Benchmarks/Program.cs +++ b/benchmarks/Neo.VM.Benchmarks/Program.cs @@ -9,10 +9,7 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. -using Neo.VM; -using System.Reflection; +using BenchmarkDotNet.Running; +using Neo.VM.Benchmark; -foreach (var method in typeof(Benchmarks).GetMethods(BindingFlags.Public | BindingFlags.Static)) -{ - method.CreateDelegate().Invoke(); -} +BenchmarkRunner.Run(); From 450cb6164e3b5ab2fec8965c3a8bb246adec062a Mon Sep 17 00:00:00 2001 From: Shargon Date: Tue, 30 Jul 2024 10:29:33 -0700 Subject: [PATCH 66/71] [rpc] Extend `getversion` RPC response with additional protocol settings (#3443) * getversion * Extend client --------- Co-authored-by: NGD Admin <154295625+NGDAdmin@users.noreply.github.com> --- src/Plugins/RpcClient/Models/RpcVersion.cs | 13 ++++++++ src/Plugins/RpcServer/RpcServer.Node.cs | 2 ++ tests/Neo.Network.RPC.Tests/RpcTestCases.json | 30 +++++++++++++++++++ .../UT_RpcServer.Node.cs | 2 ++ 4 files changed, 47 insertions(+) diff --git a/src/Plugins/RpcClient/Models/RpcVersion.cs b/src/Plugins/RpcClient/Models/RpcVersion.cs index 430d659f7c..369c206e93 100644 --- a/src/Plugins/RpcClient/Models/RpcVersion.cs +++ b/src/Plugins/RpcClient/Models/RpcVersion.cs @@ -9,6 +9,7 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using Neo.Cryptography.ECC; using Neo.Json; using System; using System.Collections.Generic; @@ -30,6 +31,8 @@ public class RpcProtocol public int MemoryPoolMaxTransactions { get; set; } public ulong InitialGasDistribution { get; set; } public IReadOnlyDictionary Hardforks { get; set; } + public IReadOnlyList SeedList { get; set; } + public IReadOnlyList StandbyCommittee { get; set; } public JObject ToJson() { @@ -49,6 +52,8 @@ public JObject ToJson() ["name"] = StripPrefix(s.Key.ToString(), "HF_"), ["blockheight"] = s.Value, })); + json["standbycommittee"] = new JArray(StandbyCommittee.Select(u => new JString(u.ToString()))); + json["seedlist"] = new JArray(SeedList.Select(u => new JString(u))); return json; } @@ -71,6 +76,14 @@ public static RpcProtocol FromJson(JObject json) // Add HF_ prefix to the hardfork response for proper Hardfork enum parsing. return new KeyValuePair(Enum.Parse(name.StartsWith("HF_") ? name : $"HF_{name}"), (uint)s["blockheight"].AsNumber()); })), + SeedList = new List(((JArray)json["seedlist"]).Select(s => + { + return s.AsString(); + })), + StandbyCommittee = new List(((JArray)json["standbycommittee"]).Select(s => + { + return ECPoint.Parse(s.AsString(), ECCurve.Secp256r1); + })) }; } diff --git a/src/Plugins/RpcServer/RpcServer.Node.cs b/src/Plugins/RpcServer/RpcServer.Node.cs index 21ca583090..716125e2cf 100644 --- a/src/Plugins/RpcServer/RpcServer.Node.cs +++ b/src/Plugins/RpcServer/RpcServer.Node.cs @@ -139,6 +139,8 @@ protected internal virtual JToken GetVersion(JArray _params) forkJson["blockheight"] = hf.Value; return forkJson; })); + protocol["standbycommittee"] = new JArray(system.Settings.StandbyCommittee.Select(u => new JString(u.ToString()))); + protocol["seedlist"] = new JArray(system.Settings.SeedList.Select(u => new JString(u))); json["rpc"] = rpc; json["protocol"] = protocol; return json; diff --git a/tests/Neo.Network.RPC.Tests/RpcTestCases.json b/tests/Neo.Network.RPC.Tests/RpcTestCases.json index cfbffb3ede..c2e4f4b5a2 100644 --- a/tests/Neo.Network.RPC.Tests/RpcTestCases.json +++ b/tests/Neo.Network.RPC.Tests/RpcTestCases.json @@ -2496,6 +2496,36 @@ "name": "Aspidochelone", "blockheight": 0 } + ], + "standbycommittee": [ + "03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c", + "02df48f60e8f3e01c48ff40b9b7f1310d7a8b2a193188befe1c2e3df740e895093", + "03b8d9d5771d8f513aa0869b9cc8d50986403b78c6da36890638c3d46a5adce04a", + "02ca0e27697b9c248f6f16e085fd0061e26f44da85b58ee835c110caa5ec3ba554", + "024c7b7fb6c310fccf1ba33b082519d82964ea93868d676662d4a59ad548df0e7d", + "02aaec38470f6aad0042c6e877cfd8087d2676b0f516fddd362801b9bd3936399e", + "02486fd15702c4490a26703112a5cc1d0923fd697a33406bd5a1c00e0013b09a70", + "023a36c72844610b4d34d1968662424011bf783ca9d984efa19a20babf5582f3fe", + "03708b860c1de5d87f5b151a12c2a99feebd2e8b315ee8e7cf8aa19692a9e18379", + "03c6aa6e12638b36e88adc1ccdceac4db9929575c3e03576c617c49cce7114a050", + "03204223f8c86b8cd5c89ef12e4f0dbb314172e9241e30c9ef2293790793537cf0", + "02a62c915cf19c7f19a50ec217e79fac2439bbaad658493de0c7d8ffa92ab0aa62", + "03409f31f0d66bdc2f70a9730b66fe186658f84a8018204db01c106edc36553cd0", + "0288342b141c30dc8ffcde0204929bb46aed5756b41ef4a56778d15ada8f0c6654", + "020f2887f41474cfeb11fd262e982051c1541418137c02a0f4961af911045de639", + "0222038884bbd1d8ff109ed3bdef3542e768eef76c1247aea8bc8171f532928c30", + "03d281b42002647f0113f36c7b8efb30db66078dfaaa9ab3ff76d043a98d512fde", + "02504acbc1f4b3bdad1d86d6e1a08603771db135a73e61c9d565ae06a1938cd2ad", + "0226933336f1b75baa42d42b71d9091508b638046d19abd67f4e119bf64a7cfb4d", + "03cdcea66032b82f5c30450e381e5295cae85c5e6943af716cc6b646352a6067dc", + "02cd5a5547119e24feaa7c2a0f37b8c9366216bab7054de0065c9be42084003c8a" + ], + "seedlist": [ + "seed1.neo.org:10333", + "seed2.neo.org:10333", + "seed3.neo.org:10333", + "seed4.neo.org:10333", + "seed5.neo.org:10333" ] } } diff --git a/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Node.cs b/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Node.cs index 413df59441..c8b655024c 100644 --- a/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Node.cs +++ b/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.Node.cs @@ -42,6 +42,8 @@ public void TestGetVersion() Assert.IsTrue(protocol.ContainsProperty("maxvaliduntilblockincrement")); Assert.IsTrue(protocol.ContainsProperty("maxtransactionsperblock")); Assert.IsTrue(protocol.ContainsProperty("memorypoolmaxtransactions")); + Assert.IsTrue(protocol.ContainsProperty("standbycommittee")); + Assert.IsTrue(protocol.ContainsProperty("seedlist")); } #region SendRawTransaction Tests From 62789616d2249dc1202db2e91b0e955c28235a5f Mon Sep 17 00:00:00 2001 From: Jimmy Date: Thu, 1 Aug 2024 15:06:07 +0800 Subject: [PATCH 67/71] [Neo Core Add] add char support (#3441) * add char support * Update src/Neo/VM/Helper.cs * add char unit test --------- Co-authored-by: Shargon --- src/Neo/VM/Helper.cs | 3 +++ tests/Neo.UnitTests/VM/UT_Helper.cs | 37 ++++++++++++++++++++++++++++- 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/src/Neo/VM/Helper.cs b/src/Neo/VM/Helper.cs index 4a82041ea5..c6423ac1f1 100644 --- a/src/Neo/VM/Helper.cs +++ b/src/Neo/VM/Helper.cs @@ -217,6 +217,9 @@ public static ScriptBuilder EmitPush(this ScriptBuilder builder, object obj) case short data: builder.EmitPush(data); break; + case char data: + builder.EmitPush((ushort)data); + break; case ushort data: builder.EmitPush(data); break; diff --git a/tests/Neo.UnitTests/VM/UT_Helper.cs b/tests/Neo.UnitTests/VM/UT_Helper.cs index 4178ed58d3..3e83256669 100644 --- a/tests/Neo.UnitTests/VM/UT_Helper.cs +++ b/tests/Neo.UnitTests/VM/UT_Helper.cs @@ -18,6 +18,7 @@ using Neo.SmartContract.Native; using Neo.VM; using Neo.VM.Types; +using Org.BouncyCastle.Asn1.Tsp; using System; using System.Collections.Generic; using System.Linq; @@ -152,7 +153,7 @@ public void TestEmitAppCall3() sb.EmitDynamicCall(UInt160.Zero, "AAAAA", true); byte[] tempArray = new byte[38]; tempArray[0] = (byte)OpCode.PUSHT; - tempArray[1] = (byte)OpCode.PUSH1;//arg.Length + tempArray[1] = (byte)OpCode.PUSH1;//arg.Length tempArray[2] = (byte)OpCode.PACK; tempArray[3] = (byte)OpCode.PUSH15;//(byte)CallFlags.All; tempArray[4] = (byte)OpCode.PUSHDATA1; @@ -401,6 +402,7 @@ public void TestEmitPush3() TestEmitPush3Byte(); TestEmitPush3Short(); TestEmitPush3Ushort(); + TestEmitPush3Char(); TestEmitPush3Int(); TestEmitPush3Uint(); TestEmitPush3Long(); @@ -472,6 +474,16 @@ private void TestEmitPush3Ushort() CollectionAssert.AreEqual(tempArray, sb.ToArray()); } + private void TestEmitPush3Char() + { + ScriptBuilder sb = new ScriptBuilder(); + char temp = char.MinValue; + VM.Helper.EmitPush(sb, temp); + byte[] tempArray = new byte[1]; + tempArray[0] = (byte)OpCode.PUSH0; + CollectionAssert.AreEqual(tempArray, sb.ToArray()); + } + private void TestEmitPush3Short() { ScriptBuilder sb = new ScriptBuilder(); @@ -630,5 +642,28 @@ private void TestToParaMeter2VMArray() Assert.AreEqual(ContractParameterType.Array, parameter.Type); Assert.AreEqual(0, ((List)parameter.Value).Count); } + + [TestMethod] + public void TestCharAsUInt16() + { + Assert.AreEqual(ushort.MaxValue, char.MaxValue); + Assert.AreEqual(ushort.MinValue, char.MinValue); + + // test every char in a loop + for (int i = ushort.MinValue; i < char.MinValue; i++) + { + var c = Convert.ToChar(i); + Assert.AreEqual(i, c); + } + + for (int i = ushort.MinValue; i < ushort.MaxValue; i++) + { + using var sbUInt16 = new ScriptBuilder(); + using var sbChar = new ScriptBuilder(); + sbUInt16.EmitPush((ushort)i); + sbChar.EmitPush(Convert.ToChar(i)); + CollectionAssert.AreEqual(sbUInt16.ToArray(), sbChar.ToArray()); + } + } } } From bd820fb48fe2338aaae27383e949c003577e4d1e Mon Sep 17 00:00:00 2001 From: Christopher Schuchardt Date: Mon, 5 Aug 2024 22:54:47 -0400 Subject: [PATCH 68/71] Stopped `RecoveryLogs` store from being created when `IgnoreRecoveryLogs` is `true` (#3444) Co-authored-by: Shargon --- src/Plugins/DBFTPlugin/Consensus/ConsensusContext.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Plugins/DBFTPlugin/Consensus/ConsensusContext.cs b/src/Plugins/DBFTPlugin/Consensus/ConsensusContext.cs index 2e6a3a19a6..d6a4340544 100644 --- a/src/Plugins/DBFTPlugin/Consensus/ConsensusContext.cs +++ b/src/Plugins/DBFTPlugin/Consensus/ConsensusContext.cs @@ -116,7 +116,9 @@ public ConsensusContext(NeoSystem neoSystem, Settings settings, Wallet wallet) this.wallet = wallet; this.neoSystem = neoSystem; dbftSettings = settings; - store = neoSystem.LoadStore(settings.RecoveryLogs); + + if (dbftSettings.IgnoreRecoveryLogs == false) + store = neoSystem.LoadStore(settings.RecoveryLogs); } public Block CreateBlock() @@ -168,7 +170,7 @@ public Block EnsureHeader() public bool Load() { - byte[] data = store.TryGet(ConsensusStateKey); + byte[] data = store?.TryGet(ConsensusStateKey); if (data is null || data.Length == 0) return false; MemoryReader reader = new(data); try @@ -272,7 +274,7 @@ public void Reset(byte viewNumber) public void Save() { - store.PutSync(ConsensusStateKey, this.ToArray()); + store?.PutSync(ConsensusStateKey, this.ToArray()); } public void Deserialize(ref MemoryReader reader) From 1dcec2e99536536d705500e5a068d62c41a1899d Mon Sep 17 00:00:00 2001 From: Jimmy Date: Tue, 6 Aug 2024 11:02:53 +0800 Subject: [PATCH 69/71] [Neo Core Bug] fix compound type reference issue (#3334) * fix compound type reference issue * fix warning * add benchmark * throw exception instead * Update benchmarks/Neo.VM.Benchmarks/Benchmarks.Types.cs * Update src/Neo.VM/Types/Map.cs * Apply suggestions from code review * Update src/Neo.VM/Types/Map.cs Co-authored-by: Shargon * update accessibality. --------- Co-authored-by: Shargon Co-authored-by: NGD Admin <154295625+NGDAdmin@users.noreply.github.com> --- .../Neo.VM.Benchmarks/Benchmarks.Types.cs | 122 +++++++++++++++ benchmarks/Neo.VM.Benchmarks/TestArray.cs | 141 ++++++++++++++++++ benchmarks/Neo.VM.Benchmarks/TestStruct.cs | 129 ++++++++++++++++ src/Neo.VM/EvaluationStack.cs | 2 + src/Neo.VM/Neo.VM.csproj | 1 + src/Neo.VM/Types/Array.cs | 29 +++- src/Neo.VM/Types/CompoundType.cs | 2 +- src/Neo.VM/Types/Map.cs | 4 + tests/Neo.VM.Tests/UT_ReferenceCounter.cs | 19 +++ 9 files changed, 444 insertions(+), 5 deletions(-) create mode 100644 benchmarks/Neo.VM.Benchmarks/Benchmarks.Types.cs create mode 100644 benchmarks/Neo.VM.Benchmarks/TestArray.cs create mode 100644 benchmarks/Neo.VM.Benchmarks/TestStruct.cs diff --git a/benchmarks/Neo.VM.Benchmarks/Benchmarks.Types.cs b/benchmarks/Neo.VM.Benchmarks/Benchmarks.Types.cs new file mode 100644 index 0000000000..3685e45f12 --- /dev/null +++ b/benchmarks/Neo.VM.Benchmarks/Benchmarks.Types.cs @@ -0,0 +1,122 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Benchmarks.Types.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using BenchmarkDotNet.Attributes; +using Array = Neo.VM.Types.Array; + +namespace Neo.VM.Benchmark; + +public class Benchmarks_Types +{ + public IEnumerable<(int Depth, int ElementsPerLevel)> ParamSource() + { + int[] depths = [2, 4]; + int[] elementsPerLevel = [2, 4, 6]; + + foreach (var depth in depths) + { + foreach (var elements in elementsPerLevel) + { + if (depth <= 8 || elements <= 2) + { + yield return (depth, elements); + } + } + } + } + + [ParamsSource(nameof(ParamSource))] + public (int Depth, int ElementsPerLevel) Params; + + [Benchmark] + public void BenchNestedArrayDeepCopy() + { + var root = new Array(new ReferenceCounter()); + CreateNestedArray(root, Params.Depth, Params.ElementsPerLevel); + _ = root.DeepCopy(); + } + + [Benchmark] + public void BenchNestedArrayDeepCopyWithReferenceCounter() + { + var referenceCounter = new ReferenceCounter(); + var root = new Array(referenceCounter); + CreateNestedArray(root, Params.Depth, Params.ElementsPerLevel, referenceCounter); + _ = root.DeepCopy(); + } + + [Benchmark] + public void BenchNestedTestArrayDeepCopy() + { + var root = new TestArray(new ReferenceCounter()); + CreateNestedTestArray(root, Params.Depth, Params.ElementsPerLevel); + _ = root.DeepCopy(); + } + + [Benchmark] + public void BenchNestedTestArrayDeepCopyWithReferenceCounter() + { + var referenceCounter = new ReferenceCounter(); + var root = new TestArray(referenceCounter); + CreateNestedTestArray(root, Params.Depth, Params.ElementsPerLevel, referenceCounter); + _ = root.DeepCopy(); + } + + private static void CreateNestedArray(Array? rootArray, int depth, int elementsPerLevel = 1, ReferenceCounter? referenceCounter = null) + { + if (depth < 0) + { + throw new ArgumentException("Depth must be non-negative", nameof(depth)); + } + + if (rootArray == null) + { + throw new ArgumentNullException(nameof(rootArray)); + } + + if (depth == 0) + { + return; + } + + for (var i = 0; i < elementsPerLevel; i++) + { + var childArray = new Array(referenceCounter); + rootArray.Add(childArray); + CreateNestedArray(childArray, depth - 1, elementsPerLevel, referenceCounter); + } + } + + private static void CreateNestedTestArray(TestArray rootArray, int depth, int elementsPerLevel = 1, ReferenceCounter referenceCounter = null) + { + if (depth < 0) + { + throw new ArgumentException("Depth must be non-negative", nameof(depth)); + } + + if (rootArray == null) + { + throw new ArgumentNullException(nameof(rootArray)); + } + + if (depth == 0) + { + return; + } + + for (var i = 0; i < elementsPerLevel; i++) + { + var childArray = new TestArray(referenceCounter); + rootArray.Add(childArray); + CreateNestedTestArray(childArray, depth - 1, elementsPerLevel, referenceCounter); + } + } +} diff --git a/benchmarks/Neo.VM.Benchmarks/TestArray.cs b/benchmarks/Neo.VM.Benchmarks/TestArray.cs new file mode 100644 index 0000000000..62fedfed11 --- /dev/null +++ b/benchmarks/Neo.VM.Benchmarks/TestArray.cs @@ -0,0 +1,141 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// TestArray.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using Neo.VM.Types; +using System.Collections; + +namespace Neo.VM.Benchmark; + +public class TestArray : CompoundType, IReadOnlyList +{ + protected readonly List _array; + + /// + /// Get or set item in the array. + /// + /// The index of the item in the array. + /// The item at the specified index. + public StackItem this[int index] + { + get => _array[index]; + set + { + if (IsReadOnly) throw new InvalidOperationException("The object is readonly."); + ReferenceCounter?.RemoveReference(_array[index], this); + _array[index] = value; + ReferenceCounter?.AddReference(value, this); + } + } + + /// + /// The number of items in the array. + /// + public override int Count => _array.Count; + public override IEnumerable SubItems => _array; + public override int SubItemsCount => _array.Count; + public override StackItemType Type => StackItemType.Array; + + /// + /// Create an array containing the specified items. + /// + /// The items to be included in the array. + public TestArray(IEnumerable? items = null) + : this(null, items) + { + } + + /// + /// Create an array containing the specified items. And make the array use the specified . + /// + /// The to be used by this array. + /// The items to be included in the array. + public TestArray(ReferenceCounter? referenceCounter, IEnumerable? items = null) + : base(referenceCounter) + { + _array = items switch + { + null => new List(), + List list => list, + _ => new List(items) + }; + if (referenceCounter != null) + foreach (StackItem item in _array) + referenceCounter.AddReference(item, this); + } + + /// + /// Add a new item at the end of the array. + /// + /// The item to be added. + public void Add(StackItem item) + { + if (IsReadOnly) throw new InvalidOperationException("The object is readonly."); + _array.Add(item); + ReferenceCounter?.AddReference(item, this); + } + + public override void Clear() + { + if (IsReadOnly) throw new InvalidOperationException("The object is readonly."); + if (ReferenceCounter != null) + foreach (StackItem item in _array) + ReferenceCounter.RemoveReference(item, this); + _array.Clear(); + } + + public override StackItem ConvertTo(StackItemType type) + { + if (Type == StackItemType.Array && type == StackItemType.Struct) + return new Struct(ReferenceCounter, new List(_array)); + return base.ConvertTo(type); + } + + internal sealed override StackItem DeepCopy(Dictionary refMap, bool asImmutable) + { + if (refMap.TryGetValue(this, out StackItem? mappedItem)) return mappedItem; + var result = this is TestStruct ? new TestStruct(ReferenceCounter) : new TestArray(ReferenceCounter); + refMap.Add(this, result); + foreach (StackItem item in _array) + result.Add(item.DeepCopy(refMap, asImmutable)); + result.IsReadOnly = true; + return result; + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public IEnumerator GetEnumerator() + { + return _array.GetEnumerator(); + } + + /// + /// Remove the item at the specified index. + /// + /// The index of the item to be removed. + public void RemoveAt(int index) + { + if (IsReadOnly) throw new InvalidOperationException("The object is readonly."); + ReferenceCounter?.RemoveReference(_array[index], this); + _array.RemoveAt(index); + } + + /// + /// Reverse all items in the array. + /// + public void Reverse() + { + if (IsReadOnly) throw new InvalidOperationException("The object is readonly."); + _array.Reverse(); + } +} diff --git a/benchmarks/Neo.VM.Benchmarks/TestStruct.cs b/benchmarks/Neo.VM.Benchmarks/TestStruct.cs new file mode 100644 index 0000000000..5a9541f1e0 --- /dev/null +++ b/benchmarks/Neo.VM.Benchmarks/TestStruct.cs @@ -0,0 +1,129 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// TestStruct.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using Neo.VM.Types; + +namespace Neo.VM.Benchmark; + +public class TestStruct : TestArray +{ + public override StackItemType Type => StackItemType.Struct; + + /// + /// Create a structure with the specified fields. + /// + /// The fields to be included in the structure. + public TestStruct(IEnumerable? fields = null) + : this(null, fields) + { + } + + /// + /// Create a structure with the specified fields. And make the structure use the specified . + /// + /// The to be used by this structure. + /// The fields to be included in the structure. + public TestStruct(ReferenceCounter? referenceCounter, IEnumerable? fields = null) + : base(referenceCounter, fields) + { + } + + /// + /// Create a new structure with the same content as this structure. All nested structures will be copied by value. + /// + /// Execution engine limits + /// The copied structure. + public TestStruct Clone(ExecutionEngineLimits limits) + { + int count = (int)(limits.MaxStackSize - 1); + TestStruct result = new(ReferenceCounter); + Queue queue = new(); + queue.Enqueue(result); + queue.Enqueue(this); + while (queue.Count > 0) + { + TestStruct a = queue.Dequeue(); + TestStruct b = queue.Dequeue(); + foreach (StackItem item in b) + { + count--; + if (count < 0) throw new InvalidOperationException("Beyond clone limits!"); + if (item is TestStruct sb) + { + TestStruct sa = new(ReferenceCounter); + a.Add(sa); + queue.Enqueue(sa); + queue.Enqueue(sb); + } + else + { + a.Add(item); + } + } + } + return result; + } + + public override StackItem ConvertTo(StackItemType type) + { + if (type == StackItemType.Array) + return new TestArray(ReferenceCounter, new List(_array)); + return base.ConvertTo(type); + } + + public override bool Equals(StackItem? other) + { + throw new NotSupportedException(); + } + + internal override bool Equals(StackItem? other, ExecutionEngineLimits limits) + { + if (other is not TestStruct s) return false; + Stack stack1 = new(); + Stack stack2 = new(); + stack1.Push(this); + stack2.Push(s); + uint count = limits.MaxStackSize; + uint maxComparableSize = limits.MaxComparableSize; + while (stack1.Count > 0) + { + if (count-- == 0) + throw new InvalidOperationException("Too many struct items to compare."); + StackItem a = stack1.Pop(); + StackItem b = stack2.Pop(); + if (a is ByteString byteString) + { + if (!byteString.Equals(b, ref maxComparableSize)) return false; + } + else + { + if (maxComparableSize == 0) + throw new InvalidOperationException("The operand exceeds the maximum comparable size."); + maxComparableSize -= 1; + if (a is TestStruct sa) + { + if (ReferenceEquals(a, b)) continue; + if (b is not TestStruct sb) return false; + if (sa.Count != sb.Count) return false; + foreach (StackItem item in sa) + stack1.Push(item); + foreach (StackItem item in sb) + stack2.Push(item); + } + else + { + if (!a.Equals(b)) return false; + } + } + } + return true; + } +} diff --git a/src/Neo.VM/EvaluationStack.cs b/src/Neo.VM/EvaluationStack.cs index 34517b2197..571cb6b2db 100644 --- a/src/Neo.VM/EvaluationStack.cs +++ b/src/Neo.VM/EvaluationStack.cs @@ -26,6 +26,8 @@ public sealed class EvaluationStack : IReadOnlyList private readonly List innerList = new(); private readonly ReferenceCounter referenceCounter; + internal ReferenceCounter ReferenceCounter => referenceCounter; + internal EvaluationStack(ReferenceCounter referenceCounter) { this.referenceCounter = referenceCounter; diff --git a/src/Neo.VM/Neo.VM.csproj b/src/Neo.VM/Neo.VM.csproj index eb137b623a..cc6fb4a3a9 100644 --- a/src/Neo.VM/Neo.VM.csproj +++ b/src/Neo.VM/Neo.VM.csproj @@ -11,6 +11,7 @@ + diff --git a/src/Neo.VM/Types/Array.cs b/src/Neo.VM/Types/Array.cs index e15358a881..76c1486778 100644 --- a/src/Neo.VM/Types/Array.cs +++ b/src/Neo.VM/Types/Array.cs @@ -35,6 +35,11 @@ public StackItem this[int index] if (IsReadOnly) throw new InvalidOperationException("The object is readonly."); ReferenceCounter?.RemoveReference(_array[index], this); _array[index] = value; + if (ReferenceCounter != null && value is CompoundType { ReferenceCounter: null }) + { + throw new InvalidOperationException("Can not set a CompoundType without a ReferenceCounter."); + } + ReferenceCounter?.AddReference(value, this); } } @@ -70,9 +75,18 @@ public Array(ReferenceCounter? referenceCounter, IEnumerable? items = List list => list, _ => new List(items) }; - if (referenceCounter != null) - foreach (StackItem item in _array) - referenceCounter.AddReference(item, this); + + if (referenceCounter == null) return; + + foreach (var item in _array) + { + if (item is CompoundType { ReferenceCounter: null }) + { + throw new InvalidOperationException("Can not set a CompoundType without a ReferenceCounter."); + } + + referenceCounter.AddReference(item, this); + } } /// @@ -83,7 +97,14 @@ public void Add(StackItem item) { if (IsReadOnly) throw new InvalidOperationException("The object is readonly."); _array.Add(item); - ReferenceCounter?.AddReference(item, this); + + if (ReferenceCounter == null) return; + + if (item is CompoundType { ReferenceCounter: null }) + { + throw new InvalidOperationException("Can not set a CompoundType without a ReferenceCounter."); + } + ReferenceCounter.AddReference(item, this); } public override void Clear() diff --git a/src/Neo.VM/Types/CompoundType.cs b/src/Neo.VM/Types/CompoundType.cs index ede743b881..daa9b05be6 100644 --- a/src/Neo.VM/Types/CompoundType.cs +++ b/src/Neo.VM/Types/CompoundType.cs @@ -24,7 +24,7 @@ public abstract class CompoundType : StackItem /// /// The reference counter used to count the items in the VM object. /// - protected readonly ReferenceCounter? ReferenceCounter; + protected internal readonly ReferenceCounter? ReferenceCounter; /// /// Create a new with the specified reference counter. diff --git a/src/Neo.VM/Types/Map.cs b/src/Neo.VM/Types/Map.cs index 5df66fb897..48155b5207 100644 --- a/src/Neo.VM/Types/Map.cs +++ b/src/Neo.VM/Types/Map.cs @@ -54,6 +54,10 @@ public StackItem this[PrimitiveType key] ReferenceCounter.RemoveReference(old_value, this); else ReferenceCounter.AddReference(key, this); + if (value is CompoundType { ReferenceCounter: null }) + { + throw new InvalidOperationException("Can not set a Map without a ReferenceCounter."); + } ReferenceCounter.AddReference(value, this); } dictionary[key] = value; diff --git a/tests/Neo.VM.Tests/UT_ReferenceCounter.cs b/tests/Neo.VM.Tests/UT_ReferenceCounter.cs index f974670805..61f7788dd8 100644 --- a/tests/Neo.VM.Tests/UT_ReferenceCounter.cs +++ b/tests/Neo.VM.Tests/UT_ReferenceCounter.cs @@ -12,6 +12,8 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.VM; using Neo.VM.Types; +using System; +using Array = Neo.VM.Types.Array; namespace Neo.Test { @@ -240,5 +242,22 @@ public void TestArrayNoPush() Assert.AreEqual(VMState.HALT, engine.Execute()); Assert.AreEqual(array.Count, engine.ReferenceCounter.Count); } + + [TestMethod] + [ExpectedException(typeof(InvalidOperationException))] + public void TestInvalidReferenceStackItem() + { + var reference = new ReferenceCounter(); + var arr = new Array(reference); + var arr2 = new Array(); + + for (var i = 0; i < 10; i++) + { + arr2.Add(i); + } + + arr.Add(arr2); + Assert.AreEqual(11, reference.Count); + } } } From 1488958d8b39057009f645a777ab4876029fecff Mon Sep 17 00:00:00 2001 From: Jimmy Date: Tue, 6 Aug 2024 16:18:21 +0800 Subject: [PATCH 70/71] Fix plugin exception (#3426) * Revert "Revert "Plugin unhandled exception (#3349)" (#3366)" This reverts commit f307a31cee4ba6d7a97c43058b73ba194efab9ac. * ensure leveldb is not used in multithread env * Revert "Revert "Plugin unhandled exception (#3349)" (#3366)" This reverts commit f307a31cee4ba6d7a97c43058b73ba194efab9ac. * remove async. * Update src/Neo/Plugins/UnhandledExceptionPolicy.cs Co-authored-by: Christopher Schuchardt * not use linq * Update src/Neo/Plugins/UnhandledExceptionPolicy.cs Co-authored-by: Christopher Schuchardt * use ignore case * Update src/Plugins/TokensTracker/TokensTracker.cs * Update src/Neo/Plugins/Plugin.cs Co-authored-by: Shargon --------- Co-authored-by: Christopher Schuchardt Co-authored-by: Shargon Co-authored-by: NGD Admin <154295625+NGDAdmin@users.noreply.github.com> --- src/Neo/Ledger/Blockchain.cs | 56 ++++++- src/Neo/Plugins/Plugin.cs | 69 +++++++- src/Neo/Plugins/PluginSettings.cs | 33 ++++ src/Neo/Plugins/UnhandledExceptionPolicy.cs | 20 +++ .../ApplicationLogs/ApplicationLogs.json | 3 +- src/Plugins/ApplicationLogs/LogReader.cs | 1 + src/Plugins/ApplicationLogs/Settings.cs | 4 +- src/Plugins/DBFTPlugin/DBFTPlugin.cs | 2 + src/Plugins/DBFTPlugin/DBFTPlugin.json | 3 +- src/Plugins/DBFTPlugin/Settings.cs | 4 +- src/Plugins/OracleService/OracleService.cs | 2 + src/Plugins/OracleService/OracleService.json | 1 + src/Plugins/OracleService/Settings.cs | 4 +- src/Plugins/RpcServer/RpcServer.json | 1 + src/Plugins/RpcServer/RpcServerPlugin.cs | 1 + src/Plugins/RpcServer/Settings.cs | 4 +- src/Plugins/StateService/Settings.cs | 4 +- src/Plugins/StateService/StatePlugin.cs | 2 + src/Plugins/StateService/StateService.json | 3 +- src/Plugins/StorageDumper/Settings.cs | 4 +- src/Plugins/StorageDumper/StorageDumper.cs | 2 +- src/Plugins/StorageDumper/StorageDumper.json | 3 +- src/Plugins/TokensTracker/TokensTracker.cs | 8 + src/Plugins/TokensTracker/TokensTracker.json | 3 +- tests/Neo.UnitTests/Plugins/TestPlugin.cs | 61 ++++++- tests/Neo.UnitTests/Plugins/UT_Plugin.cs | 154 +++++++++++++++++- 26 files changed, 421 insertions(+), 31 deletions(-) create mode 100644 src/Neo/Plugins/PluginSettings.cs create mode 100644 src/Neo/Plugins/UnhandledExceptionPolicy.cs diff --git a/src/Neo/Ledger/Blockchain.cs b/src/Neo/Ledger/Blockchain.cs index ca27bb2124..f675226303 100644 --- a/src/Neo/Ledger/Blockchain.cs +++ b/src/Neo/Ledger/Blockchain.cs @@ -16,6 +16,7 @@ using Neo.Network.P2P; using Neo.Network.P2P.Payloads; using Neo.Persistence; +using Neo.Plugins; using Neo.SmartContract; using Neo.SmartContract.Native; using Neo.VM; @@ -24,6 +25,7 @@ using System.Collections.Immutable; using System.Diagnostics; using System.Linq; +using System.Runtime.CompilerServices; namespace Neo.Ledger { @@ -468,10 +470,10 @@ private void Persist(Block block) Context.System.EventStream.Publish(application_executed); all_application_executed.Add(application_executed); } - Committing?.Invoke(system, block, snapshot, all_application_executed); + InvokeCommitting(system, block, snapshot, all_application_executed); snapshot.Commit(); } - Committed?.Invoke(system, block); + InvokeCommitted(system, block); system.MemPool.UpdatePoolForBlockPersisted(block, system.StoreView); extensibleWitnessWhiteList = null; block_cache.Remove(block.PrevHash); @@ -480,6 +482,56 @@ private void Persist(Block block) Debug.Assert(header.Index == block.Index); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static void InvokeCommitting(NeoSystem system, Block block, DataCache snapshot, IReadOnlyList applicationExecutedList) + { + InvokeHandlers(Committing?.GetInvocationList(), h => ((CommittingHandler)h)(system, block, snapshot, applicationExecutedList)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static void InvokeCommitted(NeoSystem system, Block block) + { + InvokeHandlers(Committed?.GetInvocationList(), h => ((CommittedHandler)h)(system, block)); + } + + private static void InvokeHandlers(Delegate[] handlers, Action handlerAction) + { + if (handlers == null) return; + + foreach (var handler in handlers) + { + try + { + // skip stopped plugin. + if (handler.Target is Plugin { IsStopped: true }) + { + continue; + } + + handlerAction(handler); + } + catch (Exception ex) when (handler.Target is Plugin plugin) + { + Utility.Log(nameof(plugin), LogLevel.Error, ex); + switch (plugin.ExceptionPolicy) + { + case UnhandledExceptionPolicy.StopNode: + throw; + case UnhandledExceptionPolicy.StopPlugin: + //Stop plugin on exception + plugin.IsStopped = true; + break; + case UnhandledExceptionPolicy.Ignore: + // Log the exception and continue with the next handler + break; + default: + throw new InvalidCastException( + $"The exception policy {plugin.ExceptionPolicy} is not valid."); + } + } + } + } + /// /// Gets a object used for creating the actor. /// diff --git a/src/Neo/Plugins/Plugin.cs b/src/Neo/Plugins/Plugin.cs index 248301af56..7b85d85d92 100644 --- a/src/Neo/Plugins/Plugin.cs +++ b/src/Neo/Plugins/Plugin.cs @@ -33,7 +33,8 @@ public abstract class Plugin : IDisposable /// /// The directory containing the plugin folders. Files can be contained in any subdirectory. /// - public static readonly string PluginsDirectory = Combine(GetDirectoryName(System.AppContext.BaseDirectory), "Plugins"); + public static readonly string PluginsDirectory = + Combine(GetDirectoryName(System.AppContext.BaseDirectory), "Plugins"); private static readonly FileSystemWatcher configWatcher; @@ -67,6 +68,18 @@ public abstract class Plugin : IDisposable /// public virtual Version Version => GetType().Assembly.GetName().Version; + /// + /// If the plugin should be stopped when an exception is thrown. + /// Default is StopNode. + /// + protected internal virtual UnhandledExceptionPolicy ExceptionPolicy { get; init; } = UnhandledExceptionPolicy.StopNode; + + /// + /// The plugin will be stopped if an exception is thrown. + /// But it also depends on . + /// + internal bool IsStopped { get; set; } + static Plugin() { if (!Directory.Exists(PluginsDirectory)) return; @@ -74,7 +87,8 @@ static Plugin() { EnableRaisingEvents = true, IncludeSubdirectories = true, - NotifyFilter = NotifyFilters.FileName | NotifyFilters.DirectoryName | NotifyFilters.CreationTime | NotifyFilters.LastWrite | NotifyFilters.Size, + NotifyFilter = NotifyFilters.FileName | NotifyFilters.DirectoryName | NotifyFilters.CreationTime | + NotifyFilters.LastWrite | NotifyFilters.Size, }; configWatcher.Changed += ConfigWatcher_Changed; configWatcher.Created += ConfigWatcher_Changed; @@ -106,7 +120,8 @@ private static void ConfigWatcher_Changed(object sender, FileSystemEventArgs e) { case ".json": case ".dll": - Utility.Log(nameof(Plugin), LogLevel.Warning, $"File {e.Name} is {e.ChangeType}, please restart node."); + Utility.Log(nameof(Plugin), LogLevel.Warning, + $"File {e.Name} is {e.ChangeType}, please restart node."); break; } } @@ -119,7 +134,8 @@ private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEven AssemblyName an = new(args.Name); Assembly assembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(a => a.FullName == args.Name) ?? - AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(a => a.GetName().Name == an.Name); + AppDomain.CurrentDomain.GetAssemblies() + .FirstOrDefault(a => a.GetName().Name == an.Name); if (assembly != null) return assembly; string filename = an.Name + ".dll"; @@ -150,7 +166,8 @@ public virtual void Dispose() /// The content of the configuration file read. protected IConfigurationSection GetConfiguration() { - return new ConfigurationBuilder().AddJsonFile(ConfigFile, optional: true).Build().GetSection("PluginConfiguration"); + return new ConfigurationBuilder().AddJsonFile(ConfigFile, optional: true).Build() + .GetSection("PluginConfiguration"); } private static void LoadPlugin(Assembly assembly) @@ -187,6 +204,7 @@ internal static void LoadPlugins() catch { } } } + foreach (Assembly assembly in assemblies) { LoadPlugin(assembly); @@ -229,7 +247,46 @@ protected internal virtual void OnSystemLoaded(NeoSystem system) /// if the is handled by a plugin; otherwise, . public static bool SendMessage(object message) { - return Plugins.Any(plugin => plugin.OnMessage(message)); + foreach (var plugin in Plugins) + { + if (plugin.IsStopped) + { + continue; + } + + bool result; + try + { + result = plugin.OnMessage(message); + } + catch (Exception ex) + { + Utility.Log(nameof(Plugin), LogLevel.Error, ex); + + switch (plugin.ExceptionPolicy) + { + case UnhandledExceptionPolicy.StopNode: + throw; + case UnhandledExceptionPolicy.StopPlugin: + plugin.IsStopped = true; + break; + case UnhandledExceptionPolicy.Ignore: + break; + default: + throw new InvalidCastException($"The exception policy {plugin.ExceptionPolicy} is not valid."); + } + + continue; // Skip to the next plugin if an exception is handled + } + + if (result) + { + return true; + } + } + + return false; } + } } diff --git a/src/Neo/Plugins/PluginSettings.cs b/src/Neo/Plugins/PluginSettings.cs new file mode 100644 index 0000000000..66549a390e --- /dev/null +++ b/src/Neo/Plugins/PluginSettings.cs @@ -0,0 +1,33 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// PluginSettings.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +using Microsoft.Extensions.Configuration; +using Org.BouncyCastle.Security; +using System; + +namespace Neo.Plugins; + +public abstract class PluginSettings(IConfigurationSection section) +{ + public UnhandledExceptionPolicy ExceptionPolicy + { + get + { + var policyString = section.GetValue(nameof(UnhandledExceptionPolicy), nameof(UnhandledExceptionPolicy.StopNode)); + if (Enum.TryParse(policyString, true, out UnhandledExceptionPolicy policy)) + { + return policy; + } + + throw new InvalidParameterException($"{policyString} is not a valid UnhandledExceptionPolicy"); + } + } +} diff --git a/src/Neo/Plugins/UnhandledExceptionPolicy.cs b/src/Neo/Plugins/UnhandledExceptionPolicy.cs new file mode 100644 index 0000000000..0422f2c5e7 --- /dev/null +++ b/src/Neo/Plugins/UnhandledExceptionPolicy.cs @@ -0,0 +1,20 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UnhandledExceptionPolicy.cs file belongs to the neo project and is free +// software distributed under the MIT software license, see the +// accompanying file LICENSE in the main directory of the +// repository or http://www.opensource.org/licenses/mit-license.php +// for more details. +// +// Redistribution and use in source and binary forms with or without +// modifications are permitted. + +namespace Neo.Plugins +{ + public enum UnhandledExceptionPolicy : byte + { + Ignore = 0, + StopPlugin = 1, + StopNode = 2, + } +} diff --git a/src/Plugins/ApplicationLogs/ApplicationLogs.json b/src/Plugins/ApplicationLogs/ApplicationLogs.json index af601bc81e..2664665dd2 100644 --- a/src/Plugins/ApplicationLogs/ApplicationLogs.json +++ b/src/Plugins/ApplicationLogs/ApplicationLogs.json @@ -3,7 +3,8 @@ "Path": "ApplicationLogs_{0}", "Network": 860833102, "MaxStackSize": 65535, - "Debug": false + "Debug": false, + "UnhandledExceptionPolicy": "StopPlugin" }, "Dependency": [ "RpcServer" diff --git a/src/Plugins/ApplicationLogs/LogReader.cs b/src/Plugins/ApplicationLogs/LogReader.cs index e0e886d93b..b3f767fecb 100644 --- a/src/Plugins/ApplicationLogs/LogReader.cs +++ b/src/Plugins/ApplicationLogs/LogReader.cs @@ -38,6 +38,7 @@ public class LogReader : Plugin, ICommittingHandler, ICommittedHandler, ILogHand public override string Name => "ApplicationLogs"; public override string Description => "Synchronizes smart contract VM executions and notifications (NotifyLog) on blockchain."; + protected override UnhandledExceptionPolicy ExceptionPolicy => Settings.Default.ExceptionPolicy; #region Ctor diff --git a/src/Plugins/ApplicationLogs/Settings.cs b/src/Plugins/ApplicationLogs/Settings.cs index 8f2a0da1e1..6a5f238272 100644 --- a/src/Plugins/ApplicationLogs/Settings.cs +++ b/src/Plugins/ApplicationLogs/Settings.cs @@ -13,7 +13,7 @@ namespace Neo.Plugins.ApplicationLogs { - internal class Settings + internal class Settings : PluginSettings { public string Path { get; } public uint Network { get; } @@ -23,7 +23,7 @@ internal class Settings public static Settings Default { get; private set; } - private Settings(IConfigurationSection section) + private Settings(IConfigurationSection section) : base(section) { Path = section.GetValue("Path", "ApplicationLogs_{0}"); Network = section.GetValue("Network", 5195086u); diff --git a/src/Plugins/DBFTPlugin/DBFTPlugin.cs b/src/Plugins/DBFTPlugin/DBFTPlugin.cs index f09be9d291..65fc5011dc 100644 --- a/src/Plugins/DBFTPlugin/DBFTPlugin.cs +++ b/src/Plugins/DBFTPlugin/DBFTPlugin.cs @@ -31,6 +31,8 @@ public class DBFTPlugin : Plugin, IServiceAddedHandler, IMessageReceivedHandler, public override string ConfigFile => System.IO.Path.Combine(RootPath, "DBFTPlugin.json"); + protected override UnhandledExceptionPolicy ExceptionPolicy => settings.ExceptionPolicy; + public DBFTPlugin() { RemoteNode.MessageReceived += ((IMessageReceivedHandler)this).RemoteNode_MessageReceived_Handler; diff --git a/src/Plugins/DBFTPlugin/DBFTPlugin.json b/src/Plugins/DBFTPlugin/DBFTPlugin.json index 2e2b710ba3..705b2b77cb 100644 --- a/src/Plugins/DBFTPlugin/DBFTPlugin.json +++ b/src/Plugins/DBFTPlugin/DBFTPlugin.json @@ -5,6 +5,7 @@ "AutoStart": false, "Network": 860833102, "MaxBlockSize": 2097152, - "MaxBlockSystemFee": 150000000000 + "MaxBlockSystemFee": 150000000000, + "UnhandledExceptionPolicy": "StopNode" } } diff --git a/src/Plugins/DBFTPlugin/Settings.cs b/src/Plugins/DBFTPlugin/Settings.cs index 28ad21f37a..1f37feaf16 100644 --- a/src/Plugins/DBFTPlugin/Settings.cs +++ b/src/Plugins/DBFTPlugin/Settings.cs @@ -13,7 +13,7 @@ namespace Neo.Plugins.DBFTPlugin { - public class Settings + public class Settings : PluginSettings { public string RecoveryLogs { get; } public bool IgnoreRecoveryLogs { get; } @@ -22,7 +22,7 @@ public class Settings public uint MaxBlockSize { get; } public long MaxBlockSystemFee { get; } - public Settings(IConfigurationSection section) + public Settings(IConfigurationSection section) : base(section) { RecoveryLogs = section.GetValue("RecoveryLogs", "ConsensusState"); IgnoreRecoveryLogs = section.GetValue("IgnoreRecoveryLogs", false); diff --git a/src/Plugins/OracleService/OracleService.cs b/src/Plugins/OracleService/OracleService.cs index a6d91892a3..27ced4e04c 100644 --- a/src/Plugins/OracleService/OracleService.cs +++ b/src/Plugins/OracleService/OracleService.cs @@ -63,6 +63,8 @@ public class OracleService : Plugin, ICommittingHandler, IServiceAddedHandler, I public override string Description => "Built-in oracle plugin"; + protected override UnhandledExceptionPolicy ExceptionPolicy => Settings.Default.ExceptionPolicy; + public override string ConfigFile => System.IO.Path.Combine(RootPath, "OracleService.json"); public OracleService() diff --git a/src/Plugins/OracleService/OracleService.json b/src/Plugins/OracleService/OracleService.json index 1ab0d93399..49bf1153b3 100644 --- a/src/Plugins/OracleService/OracleService.json +++ b/src/Plugins/OracleService/OracleService.json @@ -6,6 +6,7 @@ "MaxOracleTimeout": 10000, "AllowPrivateHost": false, "AllowedContentTypes": [ "application/json" ], + "UnhandledExceptionPolicy": "Ignore", "Https": { "Timeout": 5000 }, diff --git a/src/Plugins/OracleService/Settings.cs b/src/Plugins/OracleService/Settings.cs index 952ea0c27b..db93c1c400 100644 --- a/src/Plugins/OracleService/Settings.cs +++ b/src/Plugins/OracleService/Settings.cs @@ -37,7 +37,7 @@ public NeoFSSettings(IConfigurationSection section) } } - class Settings + class Settings : PluginSettings { public uint Network { get; } public Uri[] Nodes { get; } @@ -51,7 +51,7 @@ class Settings public static Settings Default { get; private set; } - private Settings(IConfigurationSection section) + private Settings(IConfigurationSection section) : base(section) { Network = section.GetValue("Network", 5195086u); Nodes = section.GetSection("Nodes").GetChildren().Select(p => new Uri(p.Get(), UriKind.Absolute)).ToArray(); diff --git a/src/Plugins/RpcServer/RpcServer.json b/src/Plugins/RpcServer/RpcServer.json index 8f6905dead..dc9c25b8da 100644 --- a/src/Plugins/RpcServer/RpcServer.json +++ b/src/Plugins/RpcServer/RpcServer.json @@ -1,5 +1,6 @@ { "PluginConfiguration": { + "UnhandledExceptionPolicy": "Ignore", "Servers": [ { "Network": 860833102, diff --git a/src/Plugins/RpcServer/RpcServerPlugin.cs b/src/Plugins/RpcServer/RpcServerPlugin.cs index c22462d139..03416c1be5 100644 --- a/src/Plugins/RpcServer/RpcServerPlugin.cs +++ b/src/Plugins/RpcServer/RpcServerPlugin.cs @@ -24,6 +24,7 @@ public class RpcServerPlugin : Plugin private static readonly Dictionary> handlers = new(); public override string ConfigFile => System.IO.Path.Combine(RootPath, "RpcServer.json"); + protected override UnhandledExceptionPolicy ExceptionPolicy => settings.ExceptionPolicy; protected override void Configure() { diff --git a/src/Plugins/RpcServer/Settings.cs b/src/Plugins/RpcServer/Settings.cs index ad624d9082..2cf7b72fb8 100644 --- a/src/Plugins/RpcServer/Settings.cs +++ b/src/Plugins/RpcServer/Settings.cs @@ -18,11 +18,11 @@ namespace Neo.Plugins.RpcServer { - class Settings + class Settings : PluginSettings { public IReadOnlyList Servers { get; init; } - public Settings(IConfigurationSection section) + public Settings(IConfigurationSection section) : base(section) { Servers = section.GetSection(nameof(Servers)).GetChildren().Select(p => RpcServerSettings.Load(p)).ToArray(); } diff --git a/src/Plugins/StateService/Settings.cs b/src/Plugins/StateService/Settings.cs index 8557866bc1..a425b57d7e 100644 --- a/src/Plugins/StateService/Settings.cs +++ b/src/Plugins/StateService/Settings.cs @@ -13,7 +13,7 @@ namespace Neo.Plugins.StateService { - internal class Settings + internal class Settings : PluginSettings { public string Path { get; } public bool FullState { get; } @@ -23,7 +23,7 @@ internal class Settings public static Settings Default { get; private set; } - private Settings(IConfigurationSection section) + private Settings(IConfigurationSection section) : base(section) { Path = section.GetValue("Path", "Data_MPT_{0}"); FullState = section.GetValue("FullState", false); diff --git a/src/Plugins/StateService/StatePlugin.cs b/src/Plugins/StateService/StatePlugin.cs index 5f6e1ef1d8..03dcc55aac 100644 --- a/src/Plugins/StateService/StatePlugin.cs +++ b/src/Plugins/StateService/StatePlugin.cs @@ -41,6 +41,8 @@ public class StatePlugin : Plugin, ICommittingHandler, ICommittedHandler, IWalle public override string Description => "Enables MPT for the node"; public override string ConfigFile => System.IO.Path.Combine(RootPath, "StateService.json"); + protected override UnhandledExceptionPolicy ExceptionPolicy => Settings.Default.ExceptionPolicy; + internal IActorRef Store; internal IActorRef Verifier; diff --git a/src/Plugins/StateService/StateService.json b/src/Plugins/StateService/StateService.json index 265436fc30..cadd2da5fd 100644 --- a/src/Plugins/StateService/StateService.json +++ b/src/Plugins/StateService/StateService.json @@ -4,7 +4,8 @@ "FullState": false, "Network": 860833102, "AutoVerify": false, - "MaxFindResultItems": 100 + "MaxFindResultItems": 100, + "UnhandledExceptionPolicy": "StopPlugin" }, "Dependency": [ "RpcServer" diff --git a/src/Plugins/StorageDumper/Settings.cs b/src/Plugins/StorageDumper/Settings.cs index c2761ce6b9..e645cd7074 100644 --- a/src/Plugins/StorageDumper/Settings.cs +++ b/src/Plugins/StorageDumper/Settings.cs @@ -14,7 +14,7 @@ namespace Neo.Plugins.StorageDumper { - internal class Settings + internal class Settings : PluginSettings { /// /// Amount of storages states (heights) to be dump in a given json file @@ -32,7 +32,7 @@ internal class Settings public static Settings? Default { get; private set; } - private Settings(IConfigurationSection section) + private Settings(IConfigurationSection section) : base(section) { // Geting settings for storage changes state dumper BlockCacheSize = section.GetValue("BlockCacheSize", 1000u); diff --git a/src/Plugins/StorageDumper/StorageDumper.cs b/src/Plugins/StorageDumper/StorageDumper.cs index c47df9ac1d..6f5498b3a2 100644 --- a/src/Plugins/StorageDumper/StorageDumper.cs +++ b/src/Plugins/StorageDumper/StorageDumper.cs @@ -30,7 +30,7 @@ public class StorageDumper : Plugin, ICommittingHandler, ICommittedHandler /// private JObject? _currentBlock; private string? _lastCreateDirectory; - + protected override UnhandledExceptionPolicy ExceptionPolicy => Settings.Default?.ExceptionPolicy ?? UnhandledExceptionPolicy.Ignore; public override string Description => "Exports Neo-CLI status data"; diff --git a/src/Plugins/StorageDumper/StorageDumper.json b/src/Plugins/StorageDumper/StorageDumper.json index b327c37e0c..0c314cf262 100644 --- a/src/Plugins/StorageDumper/StorageDumper.json +++ b/src/Plugins/StorageDumper/StorageDumper.json @@ -3,6 +3,7 @@ "BlockCacheSize": 1000, "HeightToBegin": 0, "StoragePerFolder": 100000, - "Exclude": [ -4 ] + "Exclude": [ -4 ], + "UnhandledExceptionPolicy": "Ignore" } } diff --git a/src/Plugins/TokensTracker/TokensTracker.cs b/src/Plugins/TokensTracker/TokensTracker.cs index e5ffdce3f4..34fe0a2c95 100644 --- a/src/Plugins/TokensTracker/TokensTracker.cs +++ b/src/Plugins/TokensTracker/TokensTracker.cs @@ -16,6 +16,7 @@ using Neo.Persistence; using Neo.Plugins.RpcServer; using Neo.Plugins.Trackers; +using System; using System.Collections.Generic; using System.Linq; using static System.IO.Path; @@ -30,8 +31,10 @@ public class TokensTracker : Plugin, ICommittingHandler, ICommittedHandler private uint _network; private string[] _enabledTrackers; private IStore _db; + private UnhandledExceptionPolicy _exceptionPolicy; private NeoSystem neoSystem; private readonly List trackers = new(); + protected override UnhandledExceptionPolicy ExceptionPolicy => _exceptionPolicy; public override string Description => "Enquiries balances and transaction history of accounts through RPC"; @@ -57,6 +60,11 @@ protected override void Configure() _maxResults = config.GetValue("MaxResults", 1000u); _network = config.GetValue("Network", 860833102u); _enabledTrackers = config.GetSection("EnabledTrackers").GetChildren().Select(p => p.Value).ToArray(); + var policyString = config.GetValue(nameof(UnhandledExceptionPolicy), nameof(UnhandledExceptionPolicy.StopNode)); + if (Enum.TryParse(policyString, true, out UnhandledExceptionPolicy policy)) + { + _exceptionPolicy = policy; + } } protected override void OnSystemLoaded(NeoSystem system) diff --git a/src/Plugins/TokensTracker/TokensTracker.json b/src/Plugins/TokensTracker/TokensTracker.json index ca63183b68..dbdbecfd40 100644 --- a/src/Plugins/TokensTracker/TokensTracker.json +++ b/src/Plugins/TokensTracker/TokensTracker.json @@ -4,7 +4,8 @@ "TrackHistory": true, "MaxResults": 1000, "Network": 860833102, - "EnabledTrackers": [ "NEP-11", "NEP-17" ] + "EnabledTrackers": [ "NEP-11", "NEP-17" ], + "UnhandledExceptionPolicy": "StopPlugin" }, "Dependency": [ "RpcServer" diff --git a/tests/Neo.UnitTests/Plugins/TestPlugin.cs b/tests/Neo.UnitTests/Plugins/TestPlugin.cs index dde500b927..d25d1ca3f3 100644 --- a/tests/Neo.UnitTests/Plugins/TestPlugin.cs +++ b/tests/Neo.UnitTests/Plugins/TestPlugin.cs @@ -10,15 +10,60 @@ // modifications are permitted. using Microsoft.Extensions.Configuration; +using Neo.Ledger; +using Neo.Network.P2P.Payloads; +using Neo.Persistence; using Neo.Plugins; +using System; +using System.Collections.Generic; namespace Neo.UnitTests.Plugins { - public class TestPlugin : Plugin + + internal class TestPluginSettings(IConfigurationSection section) : PluginSettings(section) + { + public static TestPluginSettings Default { get; private set; } + public static void Load(IConfigurationSection section) + { + Default = new TestPluginSettings(section); + } + } + internal class TestNonPlugin + { + public TestNonPlugin() + { + Blockchain.Committing += OnCommitting; + Blockchain.Committed += OnCommitted; + } + + private static void OnCommitting(NeoSystem system, Block block, DataCache snapshot, IReadOnlyList applicationExecutedList) + { + throw new NotImplementedException("Test exception from OnCommitting"); + } + + private static void OnCommitted(NeoSystem system, Block block) + { + throw new NotImplementedException("Test exception from OnCommitted"); + } + } + + + internal class TestPlugin : Plugin { - public TestPlugin() : base() { } + private readonly UnhandledExceptionPolicy _exceptionPolicy; + protected internal override UnhandledExceptionPolicy ExceptionPolicy => _exceptionPolicy; - protected override void Configure() { } + public TestPlugin(UnhandledExceptionPolicy exceptionPolicy = UnhandledExceptionPolicy.StopPlugin) + { + Blockchain.Committing += OnCommitting; + Blockchain.Committed += OnCommitted; + _exceptionPolicy = exceptionPolicy; + } + + protected override void Configure() + { + TestPluginSettings.Load(GetConfiguration()); + } public void LogMessage(string message) { @@ -36,5 +81,15 @@ public IConfigurationSection TestGetConfiguration() } protected override bool OnMessage(object message) => true; + + private void OnCommitting(NeoSystem system, Block block, DataCache snapshot, IReadOnlyList applicationExecutedList) + { + throw new NotImplementedException(); + } + + private void OnCommitted(NeoSystem system, Block block) + { + throw new NotImplementedException(); + } } } diff --git a/tests/Neo.UnitTests/Plugins/UT_Plugin.cs b/tests/Neo.UnitTests/Plugins/UT_Plugin.cs index e5e8cb6e49..a76119f11b 100644 --- a/tests/Neo.UnitTests/Plugins/UT_Plugin.cs +++ b/tests/Neo.UnitTests/Plugins/UT_Plugin.cs @@ -11,15 +11,61 @@ using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Ledger; using Neo.Plugins; using System; +using System.Reflection; namespace Neo.UnitTests.Plugins { [TestClass] public class UT_Plugin { - private static readonly object locker = new(); + private static readonly object s_locker = new(); + + [TestInitialize] + public void TestInitialize() + { + ClearEventHandlers(); + } + + [TestCleanup] + public void TestCleanup() + { + ClearEventHandlers(); + } + + private static void ClearEventHandlers() + { + ClearEventHandler("Committing"); + ClearEventHandler("Committed"); + } + + private static void ClearEventHandler(string eventName) + { + var eventInfo = typeof(Blockchain).GetEvent(eventName, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); + if (eventInfo == null) + { + return; + } + + var fields = typeof(Blockchain).GetFields(BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public); + foreach (var field in fields) + { + if (field.FieldType == typeof(MulticastDelegate) || field.FieldType.BaseType == typeof(MulticastDelegate)) + { + var eventDelegate = (MulticastDelegate)field.GetValue(null); + if (eventDelegate != null && field.Name.Contains(eventName)) + { + foreach (var handler in eventDelegate.GetInvocationList()) + { + eventInfo.RemoveEventHandler(null, handler); + } + break; + } + } + } + } [TestMethod] public void TestGetConfigFile() @@ -47,7 +93,7 @@ public void TestGetVersion() [TestMethod] public void TestSendMessage() { - lock (locker) + lock (s_locker) { Plugin.Plugins.Clear(); Plugin.SendMessage("hey1").Should().BeFalse(); @@ -63,5 +109,109 @@ public void TestGetConfiguration() var pp = new TestPlugin(); pp.TestGetConfiguration().Key.Should().Be("PluginConfiguration"); } + + [TestMethod] + public void TestOnException() + { + _ = new TestPlugin(); + // Ensure no exception is thrown + try + { + Blockchain.InvokeCommitting(null, null, null, null); + Blockchain.InvokeCommitted(null, null); + } + catch (Exception ex) + { + Assert.Fail($"InvokeCommitting or InvokeCommitted threw an exception: {ex.Message}"); + } + + // Register TestNonPlugin that throws exceptions + _ = new TestNonPlugin(); + + // Ensure exception is thrown + Assert.ThrowsException(() => + { + Blockchain.InvokeCommitting(null, null, null, null); + }); + + Assert.ThrowsException(() => + { + Blockchain.InvokeCommitted(null, null); + }); + } + + [TestMethod] + public void TestOnPluginStopped() + { + var pp = new TestPlugin(); + Assert.AreEqual(false, pp.IsStopped); + // Ensure no exception is thrown + try + { + Blockchain.InvokeCommitting(null, null, null, null); + Blockchain.InvokeCommitted(null, null); + } + catch (Exception ex) + { + Assert.Fail($"InvokeCommitting or InvokeCommitted threw an exception: {ex.Message}"); + } + + Assert.AreEqual(true, pp.IsStopped); + } + + [TestMethod] + public void TestOnPluginStopOnException() + { + // pp will stop on exception. + var pp = new TestPlugin(); + Assert.AreEqual(false, pp.IsStopped); + // Ensure no exception is thrown + try + { + Blockchain.InvokeCommitting(null, null, null, null); + Blockchain.InvokeCommitted(null, null); + } + catch (Exception ex) + { + Assert.Fail($"InvokeCommitting or InvokeCommitted threw an exception: {ex.Message}"); + } + + Assert.AreEqual(true, pp.IsStopped); + + // pp2 will not stop on exception. + var pp2 = new TestPlugin(UnhandledExceptionPolicy.Ignore); + Assert.AreEqual(false, pp2.IsStopped); + // Ensure no exception is thrown + try + { + Blockchain.InvokeCommitting(null, null, null, null); + Blockchain.InvokeCommitted(null, null); + } + catch (Exception ex) + { + Assert.Fail($"InvokeCommitting or InvokeCommitted threw an exception: {ex.Message}"); + } + + Assert.AreEqual(false, pp2.IsStopped); + } + + [TestMethod] + public void TestOnNodeStopOnPluginException() + { + // node will stop on pp exception. + var pp = new TestPlugin(UnhandledExceptionPolicy.StopNode); + Assert.AreEqual(false, pp.IsStopped); + Assert.ThrowsException(() => + { + Blockchain.InvokeCommitting(null, null, null, null); + }); + + Assert.ThrowsException(() => + { + Blockchain.InvokeCommitted(null, null); + }); + + Assert.AreEqual(false, pp.IsStopped); + } } } From 28043cb293d0713551af4c2d09d32ad2bbc9f96a Mon Sep 17 00:00:00 2001 From: Jimmy Date: Fri, 9 Aug 2024 02:09:30 +0800 Subject: [PATCH 71/71] [Neo Json Fix] Json null tests (#3450) * null operation * fix array --------- Co-authored-by: Shargon Co-authored-by: Christopher Schuchardt --- src/Neo.Json/JArray.cs | 2 +- tests/Neo.Json.UnitTests/UT_JArray.cs | 94 ++++++++++++++++++++++++++- 2 files changed, 94 insertions(+), 2 deletions(-) diff --git a/src/Neo.Json/JArray.cs b/src/Neo.Json/JArray.cs index 903f29941b..5ac193e1eb 100644 --- a/src/Neo.Json/JArray.cs +++ b/src/Neo.Json/JArray.cs @@ -67,7 +67,7 @@ public void Add(JToken? item) public override string AsString() { - return string.Join(",", items.Select(p => p?.AsString())); + return ToString(); } public override void Clear() diff --git a/tests/Neo.Json.UnitTests/UT_JArray.cs b/tests/Neo.Json.UnitTests/UT_JArray.cs index 1538dfe558..768f9a8f89 100644 --- a/tests/Neo.Json.UnitTests/UT_JArray.cs +++ b/tests/Neo.Json.UnitTests/UT_JArray.cs @@ -252,7 +252,7 @@ public void TestAsString() bob, }; var s = jArray.AsString(); - Assert.AreEqual(s, "{\"name\":\"alice\",\"age\":30,\"score\":100.001,\"gender\":\"female\",\"isMarried\":true,\"pet\":{\"name\":\"Tom\",\"type\":\"cat\"}},{\"name\":\"bob\",\"age\":100000,\"score\":0.001,\"gender\":\"male\",\"isMarried\":false,\"pet\":{\"name\":\"Paul\",\"type\":\"dog\"}}"); + Assert.AreEqual(s, "[{\"name\":\"alice\",\"age\":30,\"score\":100.001,\"gender\":\"female\",\"isMarried\":true,\"pet\":{\"name\":\"Tom\",\"type\":\"cat\"}},{\"name\":\"bob\",\"age\":100000,\"score\":0.001,\"gender\":\"male\",\"isMarried\":false,\"pet\":{\"name\":\"Paul\",\"type\":\"dog\"}}]"); } [TestMethod] @@ -325,5 +325,97 @@ public void TestReadOnlyBehavior() var jArray = new JArray(); jArray.IsReadOnly.Should().BeFalse(); } + + [TestMethod] + public void TestAddNull() + { + var jArray = new JArray { null }; + + jArray.Count.Should().Be(1); + jArray[0].Should().BeNull(); + } + + [TestMethod] + public void TestSetNull() + { + var jArray = new JArray { alice }; + jArray[0] = null; + + jArray.Count.Should().Be(1); + jArray[0].Should().BeNull(); + } + + [TestMethod] + public void TestInsertNull() + { + var jArray = new JArray { alice }; + jArray.Insert(0, null); + + jArray.Count.Should().Be(2); + jArray[0].Should().BeNull(); + jArray[1].Should().Be(alice); + } + + [TestMethod] + public void TestRemoveNull() + { + var jArray = new JArray { null, alice }; + jArray.Remove(null); + + jArray.Count.Should().Be(1); + jArray[0].Should().Be(alice); + } + + [TestMethod] + public void TestContainsNull() + { + var jArray = new JArray { null, alice }; + jArray.Contains(null).Should().BeTrue(); + jArray.Contains(bob).Should().BeFalse(); + } + + [TestMethod] + public void TestIndexOfNull() + { + var jArray = new JArray { null, alice }; + jArray.IndexOf(null).Should().Be(0); + jArray.IndexOf(alice).Should().Be(1); + } + + [TestMethod] + public void TestCopyToWithNull() + { + var jArray = new JArray { null, alice }; + JObject[] jObjects = new JObject[2]; + jArray.CopyTo(jObjects, 0); + + jObjects[0].Should().BeNull(); + jObjects[1].Should().Be(alice); + } + + [TestMethod] + public void TestToStringWithNull() + { + var jArray = new JArray { null, alice, bob }; + var jsonString = jArray.ToString(); + var asString = jArray.AsString(); + // JSON string should properly represent the null value + jsonString.Should().Be("[null,{\"name\":\"alice\",\"age\":30,\"score\":100.001,\"gender\":\"female\",\"isMarried\":true,\"pet\":{\"name\":\"Tom\",\"type\":\"cat\"}},{\"name\":\"bob\",\"age\":100000,\"score\":0.001,\"gender\":\"male\",\"isMarried\":false,\"pet\":{\"name\":\"Paul\",\"type\":\"dog\"}}]"); + asString.Should().Be("[null,{\"name\":\"alice\",\"age\":30,\"score\":100.001,\"gender\":\"female\",\"isMarried\":true,\"pet\":{\"name\":\"Tom\",\"type\":\"cat\"}},{\"name\":\"bob\",\"age\":100000,\"score\":0.001,\"gender\":\"male\",\"isMarried\":false,\"pet\":{\"name\":\"Paul\",\"type\":\"dog\"}}]"); + } + + [TestMethod] + public void TestFromStringWithNull() + { + var jsonString = "[null,{\"name\":\"alice\",\"age\":30,\"score\":100.001,\"gender\":\"female\",\"isMarried\":true,\"pet\":{\"name\":\"Tom\",\"type\":\"cat\"}},{\"name\":\"bob\",\"age\":100000,\"score\":0.001,\"gender\":\"male\",\"isMarried\":false,\"pet\":{\"name\":\"Paul\",\"type\":\"dog\"}}]"; + var jArray = (JArray)JArray.Parse(jsonString); + + jArray.Count.Should().Be(3); + jArray[0].Should().BeNull(); + + // Checking the second and third elements + jArray[1]["name"].AsString().Should().Be("alice"); + jArray[2]["name"].AsString().Should().Be("bob"); + } } }