From 5bccb945316f2771b8a5dccfe746691554dec7d3 Mon Sep 17 00:00:00 2001 From: Shargon Date: Wed, 13 Sep 2023 12:41:12 +0200 Subject: [PATCH 001/168] Interop syscall for current tx signers (#2827) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Allow current tx signers * Allow current tx * Change syscall * Update src/Neo/SmartContract/ApplicationEngine.Runtime.cs Co-authored-by: Jimmy * Update ApplicationEngine.Runtime.cs * Update src/Neo/SmartContract/ApplicationEngine.Runtime.cs * Update tests/Neo.UnitTests/SmartContract/UT_InteropService.cs * dotnet format * Add UT --------- Co-authored-by: Jimmy Co-authored-by: Vitor Nazário Coelho --- .../ApplicationEngine.Runtime.cs | 18 ++++++++ .../SmartContract/UT_InteropService.cs | 42 +++++++++++++++++++ .../SmartContract/UT_Syscalls.cs | 12 +++++- tests/Neo.UnitTests/TestUtils.cs | 6 ++- 4 files changed, 76 insertions(+), 2 deletions(-) diff --git a/src/Neo/SmartContract/ApplicationEngine.Runtime.cs b/src/Neo/SmartContract/ApplicationEngine.Runtime.cs index 88d07349f9..41cc6e8c9d 100644 --- a/src/Neo/SmartContract/ApplicationEngine.Runtime.cs +++ b/src/Neo/SmartContract/ApplicationEngine.Runtime.cs @@ -145,6 +145,12 @@ partial class ApplicationEngine /// public static readonly InteropDescriptor System_Runtime_BurnGas = Register("System.Runtime.BurnGas", nameof(BurnGas), 1 << 4, CallFlags.None); + /// + /// The of System.Runtime.CurrentSigners. + /// Get the Signers of the current transaction. + /// + public static readonly InteropDescriptor System_Runtime_CurrentSigners = Register("System.Runtime.CurrentSigners", nameof(GetCurrentSigners), 1 << 4, CallFlags.None); + /// /// The implementation of System.Runtime.Platform. /// Gets the name of the current platform. @@ -414,6 +420,18 @@ protected internal void BurnGas(long gas) AddGas(gas); } + /// + /// Get the Signers of the current transaction. + /// + /// The signers of the current transaction, or null if is not related to a transaction execution. + protected internal Signer[] GetCurrentSigners() + { + if (ScriptContainer is Transaction tx) + return tx.Signers; + + return null; + } + private static bool CheckItemType(StackItem item, ContractParameterType type) { StackItemType aType = item.Type; diff --git a/tests/Neo.UnitTests/SmartContract/UT_InteropService.cs b/tests/Neo.UnitTests/SmartContract/UT_InteropService.cs index 081fb87661..60d4923c75 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_InteropService.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_InteropService.cs @@ -326,6 +326,48 @@ public void TestRuntime_GetInvocationCounter() Assert.AreEqual(1, engine.GetInvocationCounter()); } + [TestMethod] + public void TestRuntime_GetCurrentSigners() + { + using var engine = GetEngine(hasContainer: true); + Assert.AreEqual(UInt160.Zero, engine.GetCurrentSigners()[0].Account); + } + + [TestMethod] + public void TestRuntime_GetCurrentSigners_SysCall() + { + using ScriptBuilder script = new(); + script.EmitSysCall(ApplicationEngine.System_Runtime_CurrentSigners.Hash); + + // Null + + using var engineA = GetEngine(hasSnapshot: true, addScript: false, hasContainer: false); + + engineA.LoadScript(script.ToArray()); + engineA.Execute(); + Assert.AreEqual(engineA.State, VMState.HALT); + + var result = engineA.ResultStack.Pop(); + result.Should().BeOfType(typeof(VM.Types.Null)); + + // Not null + + using var engineB = GetEngine(hasSnapshot: true, addScript: false, hasContainer: true); + + engineB.LoadScript(script.ToArray()); + engineB.Execute(); + Assert.AreEqual(engineB.State, VMState.HALT); + + result = engineB.ResultStack.Pop(); + result.Should().BeOfType(typeof(VM.Types.Array)); + (result as VM.Types.Array).Count.Should().Be(1); + result = (result as VM.Types.Array)[0]; + result.Should().BeOfType(typeof(VM.Types.Array)); + (result as VM.Types.Array).Count.Should().Be(5); + result = (result as VM.Types.Array)[0]; // Address + Assert.AreEqual(UInt160.Zero, new UInt160(result.GetSpan())); + } + [TestMethod] public void TestCrypto_Verify() { diff --git a/tests/Neo.UnitTests/SmartContract/UT_Syscalls.cs b/tests/Neo.UnitTests/SmartContract/UT_Syscalls.cs index c166efdb22..7dd8c5ea78 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_Syscalls.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_Syscalls.cs @@ -1,5 +1,6 @@ using Akka.TestKit.Xunit2; using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Cryptography.ECC; using Neo.IO; using Neo.Network.P2P.Payloads; using Neo.SmartContract; @@ -121,7 +122,16 @@ public void System_ExecutionEngine_GetScriptContainer() var tx = new Transaction() { Script = new byte[] { 0x01 }, - Signers = new Signer[] { new Signer() { Account = UInt160.Zero, Scopes = WitnessScope.None } }, + Signers = new Signer[] { + new Signer() + { + Account = UInt160.Zero, + Scopes = WitnessScope.None, + AllowedContracts = Array.Empty(), + AllowedGroups = Array.Empty(), + Rules = Array.Empty(), + } + }, Attributes = Array.Empty(), NetworkFee = 0x02, SystemFee = 0x03, diff --git a/tests/Neo.UnitTests/TestUtils.cs b/tests/Neo.UnitTests/TestUtils.cs index e3cb45d16c..3233d96f7b 100644 --- a/tests/Neo.UnitTests/TestUtils.cs +++ b/tests/Neo.UnitTests/TestUtils.cs @@ -1,5 +1,6 @@ using FluentAssertions; using Neo.Cryptography; +using Neo.Cryptography.ECC; using Neo.IO; using Neo.Json; using Neo.Network.P2P.Payloads; @@ -108,7 +109,10 @@ public static Transaction GetTransaction(UInt160 sender) Signers = new[]{ new Signer() { Account = sender, - Scopes = WitnessScope.CalledByEntry + Scopes = WitnessScope.CalledByEntry, + AllowedContracts = Array.Empty(), + AllowedGroups = Array.Empty(), + Rules = Array.Empty(), } }, Witnesses = new Witness[]{ new Witness { From 520795601cdc3bec0ad1391082db3d4d5d417ccc Mon Sep 17 00:00:00 2001 From: Jimmy Date: Fri, 15 Sep 2023 18:20:49 +0800 Subject: [PATCH 002/168] String element length (#2854) * Create codeql.yml * implement multiple string length * Delete codeql.yml * remove byte length * remove `stringCharLength` and add more test cases for stringElementLength * Update src/Neo/SmartContract/Native/StdLib.cs Co-authored-by: Shargon * Update tests/Neo.UnitTests/SmartContract/Native/UT_StdLib.cs Co-authored-by: Shargon * Remove empty line * add bad utf-8 unit test --------- Co-authored-by: Shargon --- src/Neo/SmartContract/Native/StdLib.cs | 18 ++++++++ .../SmartContract/Native/UT_StdLib.cs | 41 +++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/src/Neo/SmartContract/Native/StdLib.cs b/src/Neo/SmartContract/Native/StdLib.cs index 709a85724f..cb540d36a1 100644 --- a/src/Neo/SmartContract/Native/StdLib.cs +++ b/src/Neo/SmartContract/Native/StdLib.cs @@ -16,6 +16,7 @@ using System; using System.Globalization; using System.Numerics; +using System.Text; namespace Neo.SmartContract.Native { @@ -222,5 +223,22 @@ private static string[] StringSplit([MaxLength(MaxInputLength)] string str, stri StringSplitOptions options = removeEmptyEntries ? StringSplitOptions.RemoveEmptyEntries : StringSplitOptions.None; return str.Split(separator, options); } + + [ContractMethod(CpuFee = 1 << 8)] + private static int StrLen([MaxLength(MaxInputLength)] string str) + { + // return the length of the string in elements + // it should return 1 for both "🦆" and "ã" + + TextElementEnumerator enumerator = StringInfo.GetTextElementEnumerator(str); + int count = 0; + + while (enumerator.MoveNext()) + { + count++; + } + + return count; + } } } diff --git a/tests/Neo.UnitTests/SmartContract/Native/UT_StdLib.cs b/tests/Neo.UnitTests/SmartContract/Native/UT_StdLib.cs index 8342e15824..3251f67014 100644 --- a/tests/Neo.UnitTests/SmartContract/Native/UT_StdLib.cs +++ b/tests/Neo.UnitTests/SmartContract/Native/UT_StdLib.cs @@ -209,6 +209,47 @@ public void StringSplit() Assert.AreEqual("b", arr[1].GetString()); } + [TestMethod] + public void StringElementLength() + { + var snapshot = TestBlockchain.GetTestSnapshot(); + + 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); + engine.LoadScript(script.ToArray()); + + Assert.AreEqual(engine.Execute(), VMState.HALT); + Assert.AreEqual(3, engine.ResultStack.Count); + Assert.AreEqual(1, engine.ResultStack.Pop().GetInteger()); + Assert.AreEqual(1, engine.ResultStack.Pop().GetInteger()); + Assert.AreEqual(1, engine.ResultStack.Pop().GetInteger()); + } + + [TestMethod] + 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(); + + 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); + engine.LoadScript(script.ToArray()); + + Assert.AreEqual(engine.Execute(), VMState.HALT); + Assert.AreEqual(2, engine.ResultStack.Count); + Assert.AreEqual(3, engine.ResultStack.Pop().GetInteger()); + Assert.AreEqual(1, engine.ResultStack.Pop().GetInteger()); + } + [TestMethod] public void Json_Deserialize() { From bfe6d13a351db92b6804dd5139c0568b6ef97ce7 Mon Sep 17 00:00:00 2001 From: Shargon Date: Mon, 25 Sep 2023 10:29:56 +0200 Subject: [PATCH 003/168] Reduce max depth (#2912) --- src/Neo.Json/JToken.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Neo.Json/JToken.cs b/src/Neo.Json/JToken.cs index 63ab9f4752..8c38fb9bc4 100644 --- a/src/Neo.Json/JToken.cs +++ b/src/Neo.Json/JToken.cs @@ -127,7 +127,7 @@ public int GetInt32() /// The byte array that contains the JSON token. /// The maximum nesting depth when parsing the JSON token. /// The parsed JSON token. - public static JToken? Parse(ReadOnlySpan value, int max_nest = 100) + public static JToken? Parse(ReadOnlySpan value, int max_nest = 64) { Utf8JsonReader reader = new(value, new JsonReaderOptions { @@ -153,7 +153,7 @@ public int GetInt32() /// The that contains the JSON token. /// The maximum nesting depth when parsing the JSON token. /// The parsed JSON token. - public static JToken? Parse(string value, int max_nest = 100) + public static JToken? Parse(string value, int max_nest = 64) { return Parse(StrictUTF8.GetBytes(value), max_nest); } From f6d578b31126c342ebf16dc7198220d3229206b4 Mon Sep 17 00:00:00 2001 From: Hecate2 Date: Mon, 25 Sep 2023 16:34:29 +0800 Subject: [PATCH 004/168] fix contract trust FromStackItem `ContractPermissionDescriptor.Create(StackItem item)` (#2901) * ContractPermissionDescriptor.Create(StackItem item) * Update src/Neo/SmartContract/Manifest/ContractPermissionDescriptor.cs Co-authored-by: Jimmy --------- Co-authored-by: Jimmy Co-authored-by: Shargon --- src/Neo/SmartContract/Manifest/ContractManifest.cs | 2 +- .../SmartContract/Manifest/ContractPermissionDescriptor.cs | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Neo/SmartContract/Manifest/ContractManifest.cs b/src/Neo/SmartContract/Manifest/ContractManifest.cs index e68c764800..341b369ab4 100644 --- a/src/Neo/SmartContract/Manifest/ContractManifest.cs +++ b/src/Neo/SmartContract/Manifest/ContractManifest.cs @@ -81,7 +81,7 @@ void IInteroperable.FromStackItem(StackItem stackItem) { Null _ => WildcardContainer.CreateWildcard(), // Array array when array.Any(p => ((ByteString)p).Size == 0) => WildcardContainer.CreateWildcard(), - Array array => WildcardContainer.Create(array.Select(p => new ContractPermissionDescriptor(p.GetSpan())).ToArray()), + Array array => WildcardContainer.Create(array.Select(ContractPermissionDescriptor.Create).ToArray()), _ => throw new ArgumentException(null, nameof(stackItem)) }; Extra = (JObject)JToken.Parse(@struct[7].GetSpan()); diff --git a/src/Neo/SmartContract/Manifest/ContractPermissionDescriptor.cs b/src/Neo/SmartContract/Manifest/ContractPermissionDescriptor.cs index 133c338c6c..41dc7ca816 100644 --- a/src/Neo/SmartContract/Manifest/ContractPermissionDescriptor.cs +++ b/src/Neo/SmartContract/Manifest/ContractPermissionDescriptor.cs @@ -11,6 +11,7 @@ using Neo.Cryptography.ECC; using Neo.IO; using Neo.Json; +using Neo.VM.Types; using System; namespace Neo.SmartContract.Manifest @@ -66,6 +67,11 @@ internal ContractPermissionDescriptor(ReadOnlySpan span) } } + public static ContractPermissionDescriptor Create(StackItem item) + { + return item.Equals(StackItem.Null) ? CreateWildcard() : new ContractPermissionDescriptor(item.GetSpan()); + } + /// /// Creates a new instance of the class with the specified contract hash. /// From 0e9cb9ff354aaf8c608b6e5e4637466ce225e881 Mon Sep 17 00:00:00 2001 From: belane Date: Fri, 29 Sep 2023 19:03:03 +0200 Subject: [PATCH 005/168] Update CalculateNetworkFee (#2920) * Update CalculateNetworkFee * Clean code * Add argument * Fix MakeTransaction --------- Co-authored-by: Shargon --- src/Neo/Wallets/Wallet.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Neo/Wallets/Wallet.cs b/src/Neo/Wallets/Wallet.cs index 60a3b60891..7ca5aa8b7b 100644 --- a/src/Neo/Wallets/Wallet.cs +++ b/src/Neo/Wallets/Wallet.cs @@ -575,7 +575,7 @@ private Transaction MakeTransaction(DataCache snapshot, ReadOnlyMemory scr tx.SystemFee = engine.GasConsumed; } - tx.NetworkFee = CalculateNetworkFee(snapshot, tx); + tx.NetworkFee = CalculateNetworkFee(snapshot, tx, maxGas); if (value >= tx.SystemFee + tx.NetworkFee) return tx; } throw new InvalidOperationException("Insufficient GAS"); @@ -586,8 +586,9 @@ private Transaction MakeTransaction(DataCache snapshot, ReadOnlyMemory scr /// /// The snapshot used to read data. /// The transaction to calculate. + /// The maximum cost that can be spent when a contract is executed. /// The network fee of the transaction. - public long CalculateNetworkFee(DataCache snapshot, Transaction tx) + public long CalculateNetworkFee(DataCache snapshot, Transaction tx, long maxExecutionCost = ApplicationEngine.TestModeGas) { UInt160[] hashes = tx.GetScriptHashesForVerifying(snapshot); @@ -636,12 +637,14 @@ public long CalculateNetworkFee(DataCache snapshot, Transaction tx) size += Array.Empty().GetVarSize() + invSize; // Check verify cost - using ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Verification, tx, snapshot.CreateSnapshot(), settings: ProtocolSettings); + using ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Verification, tx, snapshot.CreateSnapshot(), settings: ProtocolSettings, 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."); if (!engine.ResultStack.Pop().GetBoolean()) throw new ArgumentException($"Smart contract {contract.Hash} returns false."); + maxExecutionCost -= engine.GasConsumed; + if (maxExecutionCost <= 0) throw new InvalidOperationException("Insufficient GAS."); networkFee += engine.GasConsumed; } else if (IsSignatureContract(witness_script)) @@ -655,10 +658,7 @@ public long CalculateNetworkFee(DataCache snapshot, Transaction tx) size += IO.Helper.GetVarSize(size_inv) + size_inv + witness_script.GetVarSize(); networkFee += exec_fee_factor * MultiSignatureContractCost(m, n); } - else - { - //We can support more contract types in the future. - } + // We can support more contract types in the future. } networkFee += size * NativeContract.Policy.GetFeePerByte(snapshot); return networkFee; From fdc43890d05b88035cd4e81b402e88e75610511d Mon Sep 17 00:00:00 2001 From: Jimmy Date: Tue, 3 Oct 2023 03:49:31 -0500 Subject: [PATCH 006/168] fix benchmark (#2924) --- benchmarks/Neo.Benchmarks/Benchmarks.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmarks/Neo.Benchmarks/Benchmarks.cs b/benchmarks/Neo.Benchmarks/Benchmarks.cs index 50a256e372..fa524c26c7 100644 --- a/benchmarks/Neo.Benchmarks/Benchmarks.cs +++ b/benchmarks/Neo.Benchmarks/Benchmarks.cs @@ -62,7 +62,7 @@ private static void Run(string name, string poc) Stopwatch stopwatch = Stopwatch.StartNew(); engine.Execute(); stopwatch.Stop(); - Debug.Assert(engine.State == VMState.HALT); + Debug.Assert(engine.State == VMState.FAULT); Console.WriteLine($"Benchmark: {name},\tTime: {stopwatch.Elapsed}"); } } From f5e257c11c514e47cdc1da6116e475a7324ba1ac Mon Sep 17 00:00:00 2001 From: Shargon Date: Tue, 10 Oct 2023 11:19:51 +0200 Subject: [PATCH 007/168] Set attribute fee (#2916) * Set attribute fee * Update src/Neo/SmartContract/Native/PolicyContract.cs Co-authored-by: Anna Shaleva * Apply suggestions from code review Co-authored-by: Anna Shaleva * Fix VerifyStateDependent --------- Co-authored-by: Anna Shaleva --- src/Neo/Network/P2P/Payloads/Conflicts.cs | 5 ++ src/Neo/Network/P2P/Payloads/Transaction.cs | 5 +- .../P2P/Payloads/TransactionAttribute.cs | 7 +- .../SmartContract/Native/PolicyContract.cs | 40 ++++++++++- src/Neo/Wallets/Wallet.cs | 18 +++-- .../SmartContract/Native/UT_PolicyContract.cs | 70 ++++++++++++++++++- 6 files changed, 132 insertions(+), 13 deletions(-) diff --git a/src/Neo/Network/P2P/Payloads/Conflicts.cs b/src/Neo/Network/P2P/Payloads/Conflicts.cs index db00b03259..f8ef364365 100644 --- a/src/Neo/Network/P2P/Payloads/Conflicts.cs +++ b/src/Neo/Network/P2P/Payloads/Conflicts.cs @@ -43,5 +43,10 @@ public override bool Verify(DataCache snapshot, Transaction tx) // on-chain transaction. return !NativeContract.Ledger.ContainsTransaction(snapshot, Hash); } + + public override long CalculateNetworkFee(DataCache snapshot, Transaction tx) + { + return tx.Signers.Length * base.CalculateNetworkFee(snapshot, tx); + } } } diff --git a/src/Neo/Network/P2P/Payloads/Transaction.cs b/src/Neo/Network/P2P/Payloads/Transaction.cs index 24581e2b18..73ae25bac8 100644 --- a/src/Neo/Network/P2P/Payloads/Transaction.cs +++ b/src/Neo/Network/P2P/Payloads/Transaction.cs @@ -365,10 +365,13 @@ public virtual VerifyResult VerifyStateDependent(ProtocolSettings settings, Data if (NativeContract.Policy.IsBlocked(snapshot, hash)) return VerifyResult.PolicyFail; if (!(context?.CheckTransaction(this, conflictsList, snapshot) ?? true)) return VerifyResult.InsufficientFunds; + long attributesFee = 0; foreach (TransactionAttribute attribute in Attributes) if (!attribute.Verify(snapshot, this)) return VerifyResult.InvalidAttribute; - long net_fee = NetworkFee - Size * NativeContract.Policy.GetFeePerByte(snapshot); + else + attributesFee += attribute.CalculateNetworkFee(snapshot, this); + long net_fee = NetworkFee - (Size * NativeContract.Policy.GetFeePerByte(snapshot)) - attributesFee; if (net_fee < 0) return VerifyResult.InsufficientFunds; if (net_fee > MaxVerificationGas) net_fee = MaxVerificationGas; diff --git a/src/Neo/Network/P2P/Payloads/TransactionAttribute.cs b/src/Neo/Network/P2P/Payloads/TransactionAttribute.cs index da8620a95c..0da87a94f4 100644 --- a/src/Neo/Network/P2P/Payloads/TransactionAttribute.cs +++ b/src/Neo/Network/P2P/Payloads/TransactionAttribute.cs @@ -8,12 +8,13 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using System; +using System.IO; using Neo.IO; using Neo.IO.Caching; using Neo.Json; using Neo.Persistence; -using System; -using System.IO; +using Neo.SmartContract.Native; namespace Neo.Network.P2P.Payloads { @@ -92,5 +93,7 @@ public void Serialize(BinaryWriter writer) /// The that contains the attribute. /// if the verification passes; otherwise, . public virtual bool Verify(DataCache snapshot, Transaction tx) => true; + + public virtual long CalculateNetworkFee(DataCache snapshot, Transaction tx) => NativeContract.Policy.GetAttributeFee(snapshot, (byte)Type); } } diff --git a/src/Neo/SmartContract/Native/PolicyContract.cs b/src/Neo/SmartContract/Native/PolicyContract.cs index 536bc65691..c754a15a93 100644 --- a/src/Neo/SmartContract/Native/PolicyContract.cs +++ b/src/Neo/SmartContract/Native/PolicyContract.cs @@ -10,9 +10,10 @@ #pragma warning disable IDE0051 -using Neo.Persistence; using System; using System.Numerics; +using Neo.Network.P2P.Payloads; +using Neo.Persistence; namespace Neo.SmartContract.Native { @@ -36,11 +37,21 @@ public sealed class PolicyContract : NativeContract /// public const uint DefaultFeePerByte = 1000; + /// + /// The default fee for attribute. + /// + public const uint DefaultAttributeFee = 0; + /// /// The maximum execution fee factor that the committee can set. /// public const uint MaxExecFeeFactor = 100; + /// + /// The maximum fee for attribute that the committee can set. + /// + public const uint MaxAttributeFee = 10_0000_0000; + /// /// The maximum storage price that the committee can set. /// @@ -50,6 +61,7 @@ public sealed class PolicyContract : NativeContract private const byte Prefix_FeePerByte = 10; private const byte Prefix_ExecFeeFactor = 18; private const byte Prefix_StoragePrice = 19; + private const byte Prefix_AttributeFee = 20; internal PolicyContract() { @@ -96,6 +108,22 @@ public uint GetStoragePrice(DataCache snapshot) return (uint)(BigInteger)snapshot[CreateStorageKey(Prefix_StoragePrice)]; } + /// + /// Gets the fee for attribute. + /// + /// The snapshot used to read data. + /// Attribute type + /// The fee for attribute. + [ContractMethod(CpuFee = 1 << 15, RequiredCallFlags = CallFlags.ReadStates)] + public uint GetAttributeFee(DataCache snapshot, byte attributeType) + { + if (!Enum.IsDefined(typeof(TransactionAttributeType), attributeType)) throw new InvalidOperationException(); + StorageItem entry = snapshot.TryGet(CreateStorageKey(Prefix_AttributeFee).Add(attributeType)); + if (entry == null) return DefaultAttributeFee; + + return (uint)(BigInteger)entry; + } + /// /// Determines whether the specified account is blocked. /// @@ -108,6 +136,16 @@ public bool IsBlocked(DataCache snapshot, UInt160 account) return snapshot.Contains(CreateStorageKey(Prefix_BlockedAccount).Add(account)); } + [ContractMethod(CpuFee = 1 << 15, RequiredCallFlags = CallFlags.States)] + private void SetAttributeFee(ApplicationEngine engine, byte attributeType, uint value) + { + if (!Enum.IsDefined(typeof(TransactionAttributeType), attributeType)) throw new InvalidOperationException(); + 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); + } + [ContractMethod(CpuFee = 1 << 15, RequiredCallFlags = CallFlags.States)] private void SetFeePerByte(ApplicationEngine engine, long value) { diff --git a/src/Neo/Wallets/Wallet.cs b/src/Neo/Wallets/Wallet.cs index 7ca5aa8b7b..d908530987 100644 --- a/src/Neo/Wallets/Wallet.cs +++ b/src/Neo/Wallets/Wallet.cs @@ -8,6 +8,13 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using System; +using System.Collections.Generic; +using System.Linq; +using System.Numerics; +using System.Security.Cryptography; +using System.Security.Cryptography.X509Certificates; +using System.Text; using Neo.Cryptography; using Neo.IO; using Neo.Network.P2P.Payloads; @@ -17,13 +24,6 @@ using Neo.VM; using Neo.Wallets.NEP6; using Org.BouncyCastle.Crypto.Generators; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Numerics; -using System.Security.Cryptography; -using System.Security.Cryptography.X509Certificates; -using System.Text; using static Neo.SmartContract.Helper; using static Neo.Wallets.Helper; using ECPoint = Neo.Cryptography.ECC.ECPoint; @@ -661,6 +661,10 @@ public long CalculateNetworkFee(DataCache snapshot, Transaction tx, long maxExec // We can support more contract types in the future. } networkFee += size * NativeContract.Policy.GetFeePerByte(snapshot); + foreach (TransactionAttribute attr in tx.Attributes) + { + networkFee += attr.CalculateNetworkFee(snapshot, tx); + } return networkFee; } diff --git a/tests/Neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs b/tests/Neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs index 6730dd8825..6793c27614 100644 --- a/tests/Neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs +++ b/tests/Neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs @@ -1,3 +1,6 @@ +using System; +using System.Linq; +using System.Numerics; using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.IO; @@ -6,8 +9,6 @@ using Neo.SmartContract; using Neo.SmartContract.Native; using Neo.UnitTests.Extensions; -using System; -using System.Linq; namespace Neo.UnitTests.SmartContract.Native { @@ -33,6 +34,71 @@ public void Check_Default() var ret = NativeContract.Policy.Call(snapshot, "getFeePerByte"); ret.Should().BeOfType(); ret.GetInteger().Should().Be(1000); + + ret = NativeContract.Policy.Call(snapshot, "getAttributeFee", new ContractParameter(ContractParameterType.Integer) { Value = (BigInteger)(byte)TransactionAttributeType.Conflicts }); + ret.Should().BeOfType(); + ret.GetInteger().Should().Be(PolicyContract.DefaultAttributeFee); + + Assert.ThrowsException(() => NativeContract.Policy.Call(snapshot, "getAttributeFee", new ContractParameter(ContractParameterType.Integer) { Value = (BigInteger)byte.MaxValue })); + } + + [TestMethod] + public void Check_SetAttributeFee() + { + var snapshot = _snapshot.CreateSnapshot(); + + // Fake blockchain + Block block = new() + { + Header = new Header + { + Index = 1000, + PrevHash = UInt256.Zero + } + }; + + var attr = new ContractParameter(ContractParameterType.Integer) { Value = (BigInteger)(byte)TransactionAttributeType.Conflicts }; + + // Without signature + Assert.ThrowsException(() => + { + NativeContract.Policy.Call(snapshot, new Nep17NativeContractExtensions.ManualWitness(), block, + "setAttributeFee", attr, new ContractParameter(ContractParameterType.Integer) { Value = 100500 }); + }); + + var ret = NativeContract.Policy.Call(snapshot, "getAttributeFee", attr); + ret.Should().BeOfType(); + ret.GetInteger().Should().Be(0); + + // With signature, wrong value + UInt160 committeeMultiSigAddr = NativeContract.NEO.GetCommitteeAddress(snapshot); + Assert.ThrowsException(() => + { + NativeContract.Policy.Call(snapshot, new Nep17NativeContractExtensions.ManualWitness(committeeMultiSigAddr), block, + "setAttributeFee", attr, new ContractParameter(ContractParameterType.Integer) { Value = 11_0000_0000 }); + }); + + ret = NativeContract.Policy.Call(snapshot, "getAttributeFee", attr); + ret.Should().BeOfType(); + ret.GetInteger().Should().Be(0); + + // Proper set + ret = NativeContract.Policy.Call(snapshot, new Nep17NativeContractExtensions.ManualWitness(committeeMultiSigAddr), block, + "setAttributeFee", attr, new ContractParameter(ContractParameterType.Integer) { Value = 300300 }); + ret.IsNull.Should().BeTrue(); + + ret = NativeContract.Policy.Call(snapshot, "getAttributeFee", attr); + ret.Should().BeOfType(); + ret.GetInteger().Should().Be(300300); + + // Set to zero + ret = NativeContract.Policy.Call(snapshot, new Nep17NativeContractExtensions.ManualWitness(committeeMultiSigAddr), block, + "setAttributeFee", attr, new ContractParameter(ContractParameterType.Integer) { Value = 0 }); + ret.IsNull.Should().BeTrue(); + + ret = NativeContract.Policy.Call(snapshot, "getAttributeFee", attr); + ret.Should().BeOfType(); + ret.GetInteger().Should().Be(0); } [TestMethod] From 1c7f93360f2acfe1614448dbb078b61b0adddf9f Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Tue, 24 Oct 2023 10:14:10 +0200 Subject: [PATCH 008/168] Ensure nef file fit in VM --- src/Neo/SmartContract/NefFile.cs | 10 ++++------ .../SmartContract/UT_InteropService.NEO.cs | 8 +++++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Neo/SmartContract/NefFile.cs b/src/Neo/SmartContract/NefFile.cs index 346b74bf4c..6df8e4a589 100644 --- a/src/Neo/SmartContract/NefFile.cs +++ b/src/Neo/SmartContract/NefFile.cs @@ -11,6 +11,7 @@ using Neo.Cryptography; using Neo.IO; using Neo.Json; +using Neo.VM; using System; using System.Buffers.Binary; using System.IO; @@ -71,11 +72,6 @@ public class NefFile : ISerializable /// public uint CheckSum { get; set; } - /// - /// The maximum length of the script. - /// - public const int MaxScriptLength = 512 * 1024; - private const int HeaderSize = sizeof(uint) + // Magic 64; // Compiler @@ -108,16 +104,18 @@ private void SerializeHeader(BinaryWriter writer) public void Deserialize(ref MemoryReader reader) { + long startPosition = reader.Position; if (reader.ReadUInt32() != Magic) throw new FormatException("Wrong magic"); Compiler = reader.ReadFixedString(64); Source = reader.ReadVarString(256); if (reader.ReadByte() != 0) throw new FormatException("Reserved bytes must be 0"); Tokens = reader.ReadSerializableArray(128); if (reader.ReadUInt16() != 0) throw new FormatException("Reserved bytes must be 0"); - Script = reader.ReadVarMemory(MaxScriptLength); + Script = reader.ReadVarMemory((int)ExecutionEngineLimits.Default.MaxItemSize); if (Script.Length == 0) throw new ArgumentException($"Script can't be empty"); CheckSum = reader.ReadUInt32(); if (CheckSum != ComputeChecksum(this)) throw new FormatException("CRC verification fail"); + if (reader.Position - startPosition > ExecutionEngineLimits.Default.MaxItemSize) throw new FormatException("Max vm item size exceed"); } /// diff --git a/tests/Neo.UnitTests/SmartContract/UT_InteropService.NEO.cs b/tests/Neo.UnitTests/SmartContract/UT_InteropService.NEO.cs index e6e0cb459b..cabac00932 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_InteropService.NEO.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_InteropService.NEO.cs @@ -121,12 +121,14 @@ public void TestContract_Create() var script_exceedMaxLength = new NefFile() { - Script = new byte[NefFile.MaxScriptLength - 1], + Script = new byte[ExecutionEngineLimits.Default.MaxItemSize - 50], Source = string.Empty, Compiler = "", - Tokens = System.Array.Empty() + Tokens = Array.Empty() }; - script_exceedMaxLength.CheckSum = NefFile.ComputeChecksum(nef); + 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))); var script_zeroLength = System.Array.Empty(); From 29fab8d3f8f21046a95232b29053c08f9d81f0e3 Mon Sep 17 00:00:00 2001 From: Fernando Diaz Toledano Date: Tue, 24 Oct 2023 10:14:57 +0200 Subject: [PATCH 009/168] Revert "Ensure nef file fit in VM" This reverts commit 1c7f93360f2acfe1614448dbb078b61b0adddf9f. --- src/Neo/SmartContract/NefFile.cs | 10 ++++++---- .../SmartContract/UT_InteropService.NEO.cs | 8 +++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Neo/SmartContract/NefFile.cs b/src/Neo/SmartContract/NefFile.cs index 6df8e4a589..346b74bf4c 100644 --- a/src/Neo/SmartContract/NefFile.cs +++ b/src/Neo/SmartContract/NefFile.cs @@ -11,7 +11,6 @@ using Neo.Cryptography; using Neo.IO; using Neo.Json; -using Neo.VM; using System; using System.Buffers.Binary; using System.IO; @@ -72,6 +71,11 @@ public class NefFile : ISerializable /// public uint CheckSum { get; set; } + /// + /// The maximum length of the script. + /// + public const int MaxScriptLength = 512 * 1024; + private const int HeaderSize = sizeof(uint) + // Magic 64; // Compiler @@ -104,18 +108,16 @@ private void SerializeHeader(BinaryWriter writer) public void Deserialize(ref MemoryReader reader) { - long startPosition = reader.Position; if (reader.ReadUInt32() != Magic) throw new FormatException("Wrong magic"); Compiler = reader.ReadFixedString(64); Source = reader.ReadVarString(256); if (reader.ReadByte() != 0) throw new FormatException("Reserved bytes must be 0"); Tokens = reader.ReadSerializableArray(128); if (reader.ReadUInt16() != 0) throw new FormatException("Reserved bytes must be 0"); - Script = reader.ReadVarMemory((int)ExecutionEngineLimits.Default.MaxItemSize); + Script = reader.ReadVarMemory(MaxScriptLength); if (Script.Length == 0) throw new ArgumentException($"Script can't be empty"); CheckSum = reader.ReadUInt32(); if (CheckSum != ComputeChecksum(this)) throw new FormatException("CRC verification fail"); - if (reader.Position - startPosition > ExecutionEngineLimits.Default.MaxItemSize) throw new FormatException("Max vm item size exceed"); } /// diff --git a/tests/Neo.UnitTests/SmartContract/UT_InteropService.NEO.cs b/tests/Neo.UnitTests/SmartContract/UT_InteropService.NEO.cs index cabac00932..e6e0cb459b 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_InteropService.NEO.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_InteropService.NEO.cs @@ -121,14 +121,12 @@ public void TestContract_Create() var script_exceedMaxLength = new NefFile() { - Script = new byte[ExecutionEngineLimits.Default.MaxItemSize - 50], + Script = new byte[NefFile.MaxScriptLength - 1], Source = string.Empty, Compiler = "", - Tokens = Array.Empty() + Tokens = System.Array.Empty() }; - script_exceedMaxLength.CheckSum = NefFile.ComputeChecksum(script_exceedMaxLength); - - Assert.ThrowsException(() => script_exceedMaxLength.ToArray().AsSerializable()); + script_exceedMaxLength.CheckSum = NefFile.ComputeChecksum(nef); Assert.ThrowsException(() => snapshot.DeployContract(UInt160.Zero, script_exceedMaxLength.ToArray(), manifest.ToJson().ToByteArray(true))); var script_zeroLength = System.Array.Empty(); From efa86592d080ebfde685bc87a26177c5bed5431f Mon Sep 17 00:00:00 2001 From: Shargon Date: Fri, 3 Nov 2023 08:20:52 +0100 Subject: [PATCH 010/168] Ensure nef file fit in vm (#2939) --- src/Neo/SmartContract/NefFile.cs | 10 ++++------ .../SmartContract/UT_InteropService.NEO.cs | 8 +++++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Neo/SmartContract/NefFile.cs b/src/Neo/SmartContract/NefFile.cs index 346b74bf4c..6df8e4a589 100644 --- a/src/Neo/SmartContract/NefFile.cs +++ b/src/Neo/SmartContract/NefFile.cs @@ -11,6 +11,7 @@ using Neo.Cryptography; using Neo.IO; using Neo.Json; +using Neo.VM; using System; using System.Buffers.Binary; using System.IO; @@ -71,11 +72,6 @@ public class NefFile : ISerializable /// public uint CheckSum { get; set; } - /// - /// The maximum length of the script. - /// - public const int MaxScriptLength = 512 * 1024; - private const int HeaderSize = sizeof(uint) + // Magic 64; // Compiler @@ -108,16 +104,18 @@ private void SerializeHeader(BinaryWriter writer) public void Deserialize(ref MemoryReader reader) { + long startPosition = reader.Position; if (reader.ReadUInt32() != Magic) throw new FormatException("Wrong magic"); Compiler = reader.ReadFixedString(64); Source = reader.ReadVarString(256); if (reader.ReadByte() != 0) throw new FormatException("Reserved bytes must be 0"); Tokens = reader.ReadSerializableArray(128); if (reader.ReadUInt16() != 0) throw new FormatException("Reserved bytes must be 0"); - Script = reader.ReadVarMemory(MaxScriptLength); + Script = reader.ReadVarMemory((int)ExecutionEngineLimits.Default.MaxItemSize); if (Script.Length == 0) throw new ArgumentException($"Script can't be empty"); CheckSum = reader.ReadUInt32(); if (CheckSum != ComputeChecksum(this)) throw new FormatException("CRC verification fail"); + if (reader.Position - startPosition > ExecutionEngineLimits.Default.MaxItemSize) throw new FormatException("Max vm item size exceed"); } /// diff --git a/tests/Neo.UnitTests/SmartContract/UT_InteropService.NEO.cs b/tests/Neo.UnitTests/SmartContract/UT_InteropService.NEO.cs index e6e0cb459b..cabac00932 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_InteropService.NEO.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_InteropService.NEO.cs @@ -121,12 +121,14 @@ public void TestContract_Create() var script_exceedMaxLength = new NefFile() { - Script = new byte[NefFile.MaxScriptLength - 1], + Script = new byte[ExecutionEngineLimits.Default.MaxItemSize - 50], Source = string.Empty, Compiler = "", - Tokens = System.Array.Empty() + Tokens = Array.Empty() }; - script_exceedMaxLength.CheckSum = NefFile.ComputeChecksum(nef); + 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))); var script_zeroLength = System.Array.Empty(); From 3fc889509ff27adffb17d37c9974ff1815deb255 Mon Sep 17 00:00:00 2001 From: Shargon Date: Sun, 5 Nov 2023 11:54:23 +0100 Subject: [PATCH 011/168] Merge NativeUpdateHistory with HardForks (#2941) * Merge NativeUpdateHistory with HardForks * Change throw message * Ensure Genesis is not configured * Improve comment * Remove Genesis from HF and follow the Anna suggestions * Revert HF value changes --- src/Neo/ProtocolSettings.cs | 26 ++---------- .../ApplicationEngine.Contract.cs | 13 ++---- .../Native/ContractManagement.cs | 22 +++++----- .../SmartContract/Native/NativeContract.cs | 41 +++++++++++++++++++ tests/Neo.UnitTests/UT_ProtocolSettings.cs | 7 ---- 5 files changed, 59 insertions(+), 50 deletions(-) diff --git a/src/Neo/ProtocolSettings.cs b/src/Neo/ProtocolSettings.cs index 5373db8bf0..f1e4e01b11 100644 --- a/src/Neo/ProtocolSettings.cs +++ b/src/Neo/ProtocolSettings.cs @@ -8,14 +8,13 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. -using Microsoft.Extensions.Configuration; -using Neo.Cryptography.ECC; -using Neo.Network.P2P.Payloads; -using Neo.SmartContract.Native; using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; +using Microsoft.Extensions.Configuration; +using Neo.Cryptography.ECC; +using Neo.Network.P2P.Payloads; namespace Neo { @@ -85,10 +84,8 @@ public record ProtocolSettings public uint MaxTraceableBlocks { get; init; } /// - /// Contains the update history of all native contracts. + /// Sets the block height from which a hardfork is activated. /// - public IReadOnlyDictionary NativeUpdateHistory { get; init; } - public ImmutableDictionary Hardforks { get; init; } /// @@ -149,18 +146,6 @@ public record ProtocolSettings MemoryPoolMaxTransactions = 50_000, MaxTraceableBlocks = 2_102_400, InitialGasDistribution = 52_000_000_00000000, - NativeUpdateHistory = new Dictionary - { - [nameof(ContractManagement)] = new[] { 0u }, - [nameof(StdLib)] = new[] { 0u }, - [nameof(CryptoLib)] = new[] { 0u }, - [nameof(LedgerContract)] = new[] { 0u }, - [nameof(NeoToken)] = new[] { 0u }, - [nameof(GasToken)] = new[] { 0u }, - [nameof(PolicyContract)] = new[] { 0u }, - [nameof(RoleManagement)] = new[] { 0u }, - [nameof(OracleContract)] = new[] { 0u } - }, Hardforks = ImmutableDictionary.Empty }; @@ -202,9 +187,6 @@ public static ProtocolSettings Load(IConfigurationSection section) MemoryPoolMaxTransactions = section.GetValue("MemoryPoolMaxTransactions", Default.MemoryPoolMaxTransactions), MaxTraceableBlocks = section.GetValue("MaxTraceableBlocks", Default.MaxTraceableBlocks), InitialGasDistribution = section.GetValue("InitialGasDistribution", Default.InitialGasDistribution), - NativeUpdateHistory = section.GetSection("NativeUpdateHistory").Exists() - ? section.GetSection("NativeUpdateHistory").GetChildren().ToDictionary(p => p.Key, p => p.GetChildren().Select(q => uint.Parse(q.Value)).ToArray()) - : Default.NativeUpdateHistory, Hardforks = section.GetSection("Hardforks").Exists() ? section.GetSection("Hardforks").GetChildren().ToImmutableDictionary(p => Enum.Parse(p.Key), p => uint.Parse(p.Value)) : Default.Hardforks diff --git a/src/Neo/SmartContract/ApplicationEngine.Contract.cs b/src/Neo/SmartContract/ApplicationEngine.Contract.cs index f3d33e7d77..059c9eef07 100644 --- a/src/Neo/SmartContract/ApplicationEngine.Contract.cs +++ b/src/Neo/SmartContract/ApplicationEngine.Contract.cs @@ -95,10 +95,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."); - uint[] updates = ProtocolSettings.NativeUpdateHistory[contract.Name]; - if (updates.Length == 0) - throw new InvalidOperationException($"The native contract {contract.Name} is not active."); - if (updates[0] > NativeContract.Ledger.CurrentIndex(Snapshot)) + if (!contract.IsActive(ProtocolSettings, NativeContract.Ledger.CurrentIndex(Snapshot))) throw new InvalidOperationException($"The native contract {contract.Name} is not active."); contract.Invoke(this, version); } @@ -157,9 +154,7 @@ protected internal async void NativeOnPersist() throw new InvalidOperationException(); foreach (NativeContract contract in NativeContract.Contracts) { - uint[] updates = ProtocolSettings.NativeUpdateHistory[contract.Name]; - if (updates.Length == 0) continue; - if (updates[0] <= PersistingBlock.Index) + if (contract.IsActive(ProtocolSettings, PersistingBlock.Index)) await contract.OnPersist(this); } } @@ -181,9 +176,7 @@ protected internal async void NativePostPersist() throw new InvalidOperationException(); foreach (NativeContract contract in NativeContract.Contracts) { - uint[] updates = ProtocolSettings.NativeUpdateHistory[contract.Name]; - if (updates.Length == 0) continue; - if (updates[0] <= PersistingBlock.Index) + if (contract.IsActive(ProtocolSettings, PersistingBlock.Index)) await contract.PostPersist(this); } } diff --git a/src/Neo/SmartContract/Native/ContractManagement.cs b/src/Neo/SmartContract/Native/ContractManagement.cs index f7ed44542d..62e9bb366d 100644 --- a/src/Neo/SmartContract/Native/ContractManagement.cs +++ b/src/Neo/SmartContract/Native/ContractManagement.cs @@ -106,18 +106,18 @@ internal override async ContractTask OnPersist(ApplicationEngine engine) { foreach (NativeContract contract in Contracts) { - uint[] updates = engine.ProtocolSettings.NativeUpdateHistory[contract.Name]; - if (updates.Length == 0 || updates[0] != engine.PersistingBlock.Index) - continue; - engine.Snapshot.Add(CreateStorageKey(Prefix_Contract).Add(contract.Hash), new StorageItem(new ContractState + if (contract.IsInitializeBlock(engine.ProtocolSettings, engine.PersistingBlock.Index)) { - Id = contract.Id, - Nef = contract.Nef, - Hash = contract.Hash, - Manifest = contract.Manifest - })); - engine.Snapshot.Add(CreateStorageKey(Prefix_ContractHash).AddBigEndian(contract.Id), new StorageItem(contract.Hash.ToArray())); - await contract.Initialize(engine); + engine.Snapshot.Add(CreateStorageKey(Prefix_Contract).Add(contract.Hash), new StorageItem(new ContractState + { + Id = contract.Id, + Nef = contract.Nef, + Hash = contract.Hash, + Manifest = contract.Manifest + })); + engine.Snapshot.Add(CreateStorageKey(Prefix_ContractHash).AddBigEndian(contract.Id), new StorageItem(contract.Hash.ToArray())); + await contract.Initialize(engine); + } } } diff --git a/src/Neo/SmartContract/Native/NativeContract.cs b/src/Neo/SmartContract/Native/NativeContract.cs index 63c15466fb..8c8ffe986f 100644 --- a/src/Neo/SmartContract/Native/NativeContract.cs +++ b/src/Neo/SmartContract/Native/NativeContract.cs @@ -87,6 +87,11 @@ public abstract class NativeContract /// public string Name => GetType().Name; + /// + /// Since Hardfork has to start having access to the native contract. + /// + public virtual Hardfork? ActiveIn { get; } = null; + /// /// The nef of the native contract. /// @@ -160,6 +165,42 @@ protected NativeContract() contractsDictionary.Add(Hash, this); } + /// + /// It is the initialize block + /// + /// The where the HardForks are configured. + /// Block index + /// True if the native contract must be initialized + internal bool IsInitializeBlock(ProtocolSettings settings, uint index) + { + if (ActiveIn is null) return index == 0; + + if (!settings.Hardforks.TryGetValue(ActiveIn.Value, out var activeIn)) + { + return false; + } + + return activeIn == index; + } + + /// + /// Is the native contract active + /// + /// The where the HardForks are configured. + /// Block index + /// True if the native contract is active + internal bool IsActive(ProtocolSettings settings, uint index) + { + if (ActiveIn is null) return true; + + if (!settings.Hardforks.TryGetValue(ActiveIn.Value, out var activeIn)) + { + return false; + } + + return activeIn <= index; + } + /// /// Checks whether the committee has witnessed the current transaction. /// diff --git a/tests/Neo.UnitTests/UT_ProtocolSettings.cs b/tests/Neo.UnitTests/UT_ProtocolSettings.cs index 0af209e10f..42be0e69cc 100644 --- a/tests/Neo.UnitTests/UT_ProtocolSettings.cs +++ b/tests/Neo.UnitTests/UT_ProtocolSettings.cs @@ -1,6 +1,5 @@ using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; -using Neo.SmartContract.Native; using Neo.Wallets; namespace Neo.UnitTests @@ -41,11 +40,5 @@ public void TestGetSeedList() { ProtocolSettings.Default.SeedList.Should().BeEquivalentTo(new string[] { "seed1.neo.org:10333", "seed2.neo.org:10333", "seed3.neo.org:10333", "seed4.neo.org:10333", "seed5.neo.org:10333", }); } - - [TestMethod] - public void TestNativeUpdateHistory() - { - ProtocolSettings.Default.NativeUpdateHistory.Count.Should().Be(NativeContract.Contracts.Count); - } } } From d8243577ea3d50703b109c03301860532995c9d6 Mon Sep 17 00:00:00 2001 From: "Guil. Sperb Machado" Date: Tue, 7 Nov 2023 07:50:31 +0100 Subject: [PATCH 012/168] fix plugins to make single file assemblies possible (#2946) --- src/Neo/Plugins/Plugin.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Neo/Plugins/Plugin.cs b/src/Neo/Plugins/Plugin.cs index c3c66ced8a..be6bb9b4f6 100644 --- a/src/Neo/Plugins/Plugin.cs +++ b/src/Neo/Plugins/Plugin.cs @@ -32,7 +32,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(Assembly.GetEntryAssembly().Location), "Plugins"); + public static readonly string PluginsDirectory = Combine(GetDirectoryName(System.AppContext.BaseDirectory), "Plugins"); private static readonly FileSystemWatcher configWatcher; @@ -123,7 +123,7 @@ private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEven string filename = an.Name + ".dll"; string path = filename; - if (!File.Exists(path)) path = Combine(GetDirectoryName(Assembly.GetEntryAssembly().Location), filename); + if (!File.Exists(path)) path = Combine(GetDirectoryName(System.AppContext.BaseDirectory), filename); if (!File.Exists(path)) path = Combine(PluginsDirectory, filename); if (!File.Exists(path)) path = Combine(PluginsDirectory, args.RequestingAssembly.GetName().Name, filename); if (!File.Exists(path)) return null; From ec6ddf6e56ac7a42c41734eb8954ee388ae5f36a Mon Sep 17 00:00:00 2001 From: Shargon Date: Wed, 8 Nov 2023 09:09:53 +0100 Subject: [PATCH 013/168] Add MaxNestedItems to WitnessCondition.FromJson (#2951) * Add MaxNestedItems WitnessCondition.FromJson * Ensure action * Fix SubItems --- .../Network/P2P/Payloads/Conditions/AndCondition.cs | 8 ++++++-- .../P2P/Payloads/Conditions/BooleanCondition.cs | 7 ++++--- .../Conditions/CalledByContractCondition.cs | 5 +++-- .../Payloads/Conditions/CalledByEntryCondition.cs | 13 ++++++------- .../Payloads/Conditions/CalledByGroupCondition.cs | 5 +++-- .../P2P/Payloads/Conditions/GroupCondition.cs | 5 +++-- .../Network/P2P/Payloads/Conditions/NotCondition.cs | 5 +++-- .../Network/P2P/Payloads/Conditions/OrCondition.cs | 8 ++++++-- .../P2P/Payloads/Conditions/ScriptHashCondition.cs | 5 +++-- .../P2P/Payloads/Conditions/WitnessCondition.cs | 11 +++++------ src/Neo/Network/P2P/Payloads/WitnessRule.cs | 9 +++++++-- .../Network/P2P/Payloads/UT_WitnessContition.cs | 4 ++-- 12 files changed, 51 insertions(+), 34 deletions(-) diff --git a/src/Neo/Network/P2P/Payloads/Conditions/AndCondition.cs b/src/Neo/Network/P2P/Payloads/Conditions/AndCondition.cs index 096b47622b..87bef93068 100644 --- a/src/Neo/Network/P2P/Payloads/Conditions/AndCondition.cs +++ b/src/Neo/Network/P2P/Payloads/Conditions/AndCondition.cs @@ -49,9 +49,13 @@ protected override void SerializeWithoutType(BinaryWriter writer) writer.Write(Expressions); } - private protected override void ParseJson(JObject json) + private protected override void ParseJson(JObject json, int maxNestDepth) { - Expressions = ((JArray)json["expressions"]).Select(p => FromJson((JObject)p)).ToArray(); + if (maxNestDepth <= 0) throw new FormatException(); + JArray expressions = (JArray)json["expressions"]; + if (expressions.Count > MaxSubitems) throw new FormatException(); + Expressions = expressions.Select(p => FromJson((JObject)p, maxNestDepth - 1)).ToArray(); + if (Expressions.Length == 0) throw new FormatException(); } public override JObject ToJson() diff --git a/src/Neo/Network/P2P/Payloads/Conditions/BooleanCondition.cs b/src/Neo/Network/P2P/Payloads/Conditions/BooleanCondition.cs index ad6a914dd1..8fee03cf07 100644 --- a/src/Neo/Network/P2P/Payloads/Conditions/BooleanCondition.cs +++ b/src/Neo/Network/P2P/Payloads/Conditions/BooleanCondition.cs @@ -8,12 +8,13 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using System; +using System.IO; using Neo.IO; using Neo.Json; using Neo.SmartContract; using Neo.VM; using Neo.VM.Types; -using System.IO; namespace Neo.Network.P2P.Payloads.Conditions { @@ -42,7 +43,7 @@ protected override void SerializeWithoutType(BinaryWriter writer) writer.Write(Expression); } - private protected override void ParseJson(JObject json) + private protected override void ParseJson(JObject json, int maxNestDepth) { Expression = json["expression"].GetBoolean(); } @@ -56,7 +57,7 @@ public override JObject ToJson() public override StackItem ToStackItem(ReferenceCounter referenceCounter) { - var result = (Array)base.ToStackItem(referenceCounter); + var result = (VM.Types.Array)base.ToStackItem(referenceCounter); result.Add(Expression); return result; } diff --git a/src/Neo/Network/P2P/Payloads/Conditions/CalledByContractCondition.cs b/src/Neo/Network/P2P/Payloads/Conditions/CalledByContractCondition.cs index 82f24c7676..0c2a98b86c 100644 --- a/src/Neo/Network/P2P/Payloads/Conditions/CalledByContractCondition.cs +++ b/src/Neo/Network/P2P/Payloads/Conditions/CalledByContractCondition.cs @@ -13,6 +13,7 @@ using Neo.SmartContract; using Neo.VM; using Neo.VM.Types; +using System; using System.IO; namespace Neo.Network.P2P.Payloads.Conditions @@ -42,7 +43,7 @@ protected override void SerializeWithoutType(BinaryWriter writer) writer.Write(Hash); } - private protected override void ParseJson(JObject json) + private protected override void ParseJson(JObject json, int maxNestDepth) { Hash = UInt160.Parse(json["hash"].GetString()); } @@ -56,7 +57,7 @@ public override JObject ToJson() public override StackItem ToStackItem(ReferenceCounter referenceCounter) { - var result = (Array)base.ToStackItem(referenceCounter); + var result = (VM.Types.Array)base.ToStackItem(referenceCounter); result.Add(Hash.ToArray()); return result; } diff --git a/src/Neo/Network/P2P/Payloads/Conditions/CalledByEntryCondition.cs b/src/Neo/Network/P2P/Payloads/Conditions/CalledByEntryCondition.cs index 4e5455af57..7e309f4e29 100644 --- a/src/Neo/Network/P2P/Payloads/Conditions/CalledByEntryCondition.cs +++ b/src/Neo/Network/P2P/Payloads/Conditions/CalledByEntryCondition.cs @@ -9,6 +9,7 @@ // modifications are permitted. using Neo.IO; +using Neo.Json; using Neo.SmartContract; using System.IO; @@ -18,10 +19,6 @@ public class CalledByEntryCondition : WitnessCondition { public override WitnessConditionType Type => WitnessConditionType.CalledByEntry; - protected override void DeserializeWithoutType(ref MemoryReader reader, int maxNestDepth) - { - } - public override bool Match(ApplicationEngine engine) { var state = engine.CurrentContext.GetState(); @@ -30,8 +27,10 @@ public override bool Match(ApplicationEngine engine) return state.CallingContext is null; } - protected override void SerializeWithoutType(BinaryWriter writer) - { - } + protected override void DeserializeWithoutType(ref MemoryReader reader, int maxNestDepth) { } + + protected override void SerializeWithoutType(BinaryWriter writer) { } + + private protected override void ParseJson(JObject json, int maxNestDepth) { } } } diff --git a/src/Neo/Network/P2P/Payloads/Conditions/CalledByGroupCondition.cs b/src/Neo/Network/P2P/Payloads/Conditions/CalledByGroupCondition.cs index d542d031db..5c91c8bebd 100644 --- a/src/Neo/Network/P2P/Payloads/Conditions/CalledByGroupCondition.cs +++ b/src/Neo/Network/P2P/Payloads/Conditions/CalledByGroupCondition.cs @@ -15,6 +15,7 @@ using Neo.SmartContract.Native; using Neo.VM; using Neo.VM.Types; +using System; using System.IO; using System.Linq; @@ -47,7 +48,7 @@ protected override void SerializeWithoutType(BinaryWriter writer) writer.Write(Group); } - private protected override void ParseJson(JObject json) + private protected override void ParseJson(JObject json, int maxNestDepth) { Group = ECPoint.Parse(json["group"].GetString(), ECCurve.Secp256r1); } @@ -61,7 +62,7 @@ public override JObject ToJson() public override StackItem ToStackItem(ReferenceCounter referenceCounter) { - var result = (Array)base.ToStackItem(referenceCounter); + var result = (VM.Types.Array)base.ToStackItem(referenceCounter); result.Add(Group.ToArray()); return result; } diff --git a/src/Neo/Network/P2P/Payloads/Conditions/GroupCondition.cs b/src/Neo/Network/P2P/Payloads/Conditions/GroupCondition.cs index 1acd19f190..44299a751c 100644 --- a/src/Neo/Network/P2P/Payloads/Conditions/GroupCondition.cs +++ b/src/Neo/Network/P2P/Payloads/Conditions/GroupCondition.cs @@ -15,6 +15,7 @@ using Neo.SmartContract.Native; using Neo.VM; using Neo.VM.Types; +using System; using System.IO; using System.Linq; @@ -47,7 +48,7 @@ protected override void SerializeWithoutType(BinaryWriter writer) writer.Write(Group); } - private protected override void ParseJson(JObject json) + private protected override void ParseJson(JObject json, int maxNestDepth) { Group = ECPoint.Parse(json["group"].GetString(), ECCurve.Secp256r1); } @@ -61,7 +62,7 @@ public override JObject ToJson() public override StackItem ToStackItem(ReferenceCounter referenceCounter) { - var result = (Array)base.ToStackItem(referenceCounter); + var result = (VM.Types.Array)base.ToStackItem(referenceCounter); result.Add(Group.ToArray()); return result; } diff --git a/src/Neo/Network/P2P/Payloads/Conditions/NotCondition.cs b/src/Neo/Network/P2P/Payloads/Conditions/NotCondition.cs index 667a66770c..6bb2c2c9de 100644 --- a/src/Neo/Network/P2P/Payloads/Conditions/NotCondition.cs +++ b/src/Neo/Network/P2P/Payloads/Conditions/NotCondition.cs @@ -47,9 +47,10 @@ protected override void SerializeWithoutType(BinaryWriter writer) writer.Write(Expression); } - private protected override void ParseJson(JObject json) + private protected override void ParseJson(JObject json, int maxNestDepth) { - Expression = FromJson((JObject)json["expression"]); + if (maxNestDepth <= 0) throw new FormatException(); + Expression = FromJson((JObject)json["expression"], maxNestDepth - 1); } public override JObject ToJson() diff --git a/src/Neo/Network/P2P/Payloads/Conditions/OrCondition.cs b/src/Neo/Network/P2P/Payloads/Conditions/OrCondition.cs index c66becde2a..99fb0490cf 100644 --- a/src/Neo/Network/P2P/Payloads/Conditions/OrCondition.cs +++ b/src/Neo/Network/P2P/Payloads/Conditions/OrCondition.cs @@ -49,9 +49,13 @@ protected override void SerializeWithoutType(BinaryWriter writer) writer.Write(Expressions); } - private protected override void ParseJson(JObject json) + private protected override void ParseJson(JObject json, int maxNestDepth) { - Expressions = ((JArray)json["expressions"]).Select(p => FromJson((JObject)p)).ToArray(); + if (maxNestDepth <= 0) throw new FormatException(); + JArray expressions = (JArray)json["expressions"]; + if (expressions.Count > MaxSubitems) throw new FormatException(); + Expressions = expressions.Select(p => FromJson((JObject)p, maxNestDepth - 1)).ToArray(); + if (Expressions.Length == 0) throw new FormatException(); } public override JObject ToJson() diff --git a/src/Neo/Network/P2P/Payloads/Conditions/ScriptHashCondition.cs b/src/Neo/Network/P2P/Payloads/Conditions/ScriptHashCondition.cs index 315c1fde02..84109b6a99 100644 --- a/src/Neo/Network/P2P/Payloads/Conditions/ScriptHashCondition.cs +++ b/src/Neo/Network/P2P/Payloads/Conditions/ScriptHashCondition.cs @@ -13,6 +13,7 @@ using Neo.SmartContract; using Neo.VM; using Neo.VM.Types; +using System; using System.IO; namespace Neo.Network.P2P.Payloads.Conditions @@ -42,7 +43,7 @@ protected override void SerializeWithoutType(BinaryWriter writer) writer.Write(Hash); } - private protected override void ParseJson(JObject json) + private protected override void ParseJson(JObject json, int maxNestDepth) { Hash = UInt160.Parse(json["hash"].GetString()); } @@ -56,7 +57,7 @@ public override JObject ToJson() public override StackItem ToStackItem(ReferenceCounter referenceCounter) { - var result = (Array)base.ToStackItem(referenceCounter); + var result = (VM.Types.Array)base.ToStackItem(referenceCounter); result.Add(Hash.ToArray()); return result; } diff --git a/src/Neo/Network/P2P/Payloads/Conditions/WitnessCondition.cs b/src/Neo/Network/P2P/Payloads/Conditions/WitnessCondition.cs index ed9f55b941..eaed8ff02f 100644 --- a/src/Neo/Network/P2P/Payloads/Conditions/WitnessCondition.cs +++ b/src/Neo/Network/P2P/Payloads/Conditions/WitnessCondition.cs @@ -21,7 +21,7 @@ namespace Neo.Network.P2P.Payloads.Conditions { public abstract class WitnessCondition : IInteroperable, ISerializable { - private const int MaxSubitems = 16; + internal const int MaxSubitems = 16; internal const int MaxNestingDepth = 2; /// @@ -92,21 +92,20 @@ void ISerializable.Serialize(BinaryWriter writer) /// The for writing data. protected abstract void SerializeWithoutType(BinaryWriter writer); - private protected virtual void ParseJson(JObject json) - { - } + private protected abstract void ParseJson(JObject json, int maxNestDepth); /// /// Converts the from a JSON object. /// /// The represented by a JSON object. + /// The maximum nesting depth allowed during deserialization. /// The converted . - public static WitnessCondition FromJson(JObject json) + public static WitnessCondition FromJson(JObject json, int maxNestDepth) { WitnessConditionType type = Enum.Parse(json["type"].GetString()); if (ReflectionCache.CreateInstance(type) is not WitnessCondition condition) throw new FormatException("Invalid WitnessConditionType."); - condition.ParseJson(json); + condition.ParseJson(json, maxNestDepth); return condition; } diff --git a/src/Neo/Network/P2P/Payloads/WitnessRule.cs b/src/Neo/Network/P2P/Payloads/WitnessRule.cs index a020191e79..15152776c2 100644 --- a/src/Neo/Network/P2P/Payloads/WitnessRule.cs +++ b/src/Neo/Network/P2P/Payloads/WitnessRule.cs @@ -57,10 +57,15 @@ void ISerializable.Serialize(BinaryWriter writer) /// The converted . public static WitnessRule FromJson(JObject json) { + WitnessRuleAction action = Enum.Parse(json["action"].GetString()); + + if (action != WitnessRuleAction.Allow && action != WitnessRuleAction.Deny) + throw new FormatException(); + return new() { - Action = Enum.Parse(json["action"].GetString()), - Condition = WitnessCondition.FromJson((JObject)json["condition"]) + Action = action, + Condition = WitnessCondition.FromJson((JObject)json["condition"], WitnessCondition.MaxNestingDepth) }; } diff --git a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_WitnessContition.cs b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_WitnessContition.cs index 97a7ede352..21260c39b2 100644 --- a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_WitnessContition.cs +++ b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_WitnessContition.cs @@ -22,7 +22,7 @@ public void TestFromJson1() } }; var json = condition.ToJson(); - var new_condi = WitnessCondition.FromJson(json); + var new_condi = WitnessCondition.FromJson(json, 2); Assert.IsTrue(new_condi is OrCondition); var or_condi = (OrCondition)new_condi; Assert.AreEqual(2, or_condi.Expressions.Length); @@ -42,7 +42,7 @@ public void TestFromJson2() var hash2 = UInt160.Parse("0xd2a4cff31913016155e38e474a2c06d08be276cf"); var jstr = "{\"type\":\"Or\",\"expressions\":[{\"type\":\"And\",\"expressions\":[{\"type\":\"CalledByContract\",\"hash\":\"0x0000000000000000000000000000000000000000\"},{\"type\":\"ScriptHash\",\"hash\":\"0xd2a4cff31913016155e38e474a2c06d08be276cf\"}]},{\"type\":\"Or\",\"expressions\":[{\"type\":\"CalledByGroup\",\"group\":\"03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c\"},{\"type\":\"Boolean\",\"expression\":true}]}]}"; var json = (JObject)JToken.Parse(jstr); - var condi = WitnessCondition.FromJson(json); + var condi = WitnessCondition.FromJson(json, 2); var or_condi = (OrCondition)condi; Assert.AreEqual(2, or_condi.Expressions.Length); var and_condi = (AndCondition)or_condi.Expressions[0]; From 8d270e64690455e453e8fa8b71f076d2f572aded Mon Sep 17 00:00:00 2001 From: Anna Shaleva Date: Wed, 8 Nov 2023 11:56:29 +0300 Subject: [PATCH 014/168] Improved scheme for Conflicts attribute storing and pricing (#2913) * Ledger: change conflict records storage scheme This commit is a part of #2907: it implements conflict records storage scheme discribed in https://github.com/neo-project/neo/issues/2907#issuecomment-1722506014. The short scheme description: Do not store the list of conflicting signers in the Ledger's conflict record value. Instead, put each conflicting signer in the conflict record key so that the reculting key is: {Prefix_Transaction, , }, and the value is {}. As an optimisation, for each conflict record store the dummy stub where the key is {Prefix_Transaction, } and the value is {}. This optimisation allows to reduce DB read requests during newly-pooled transaction verification for those transactions that do not have any on-chained conflicts. Also, IsTraceableBlock check is added for on-chain conflicts verification. It is needed to avoid situations when untraceable on-chained conflict affects the newly-pooled transaction verification. Signed-off-by: Anna Shaleva * UT_MemoryPool: remove unused test Malicious_OnChain_Conflict was constructed incorrectly (see the comment in the end of the test) and was replaced by the proper TestMaliciousOnChainConflict test in UT_Blockchain.cs way back ago in https://github.com/neo-project/neo/pull/2818/commits/0c06c915ef381cf146ea5314b6a9920f8fd07b26. Signed-off-by: Anna Shaleva * Policy: introduce fee for Conflicts attribute This commit implements Conflicts attribute policy described in https://github.com/neo-project/neo/issues/2907#issuecomment-1722506014. Signed-off-by: Anna Shaleva * *: remove remnants of ConflictsFee in native Policy ConflictsFee logic was replaced by the generic attribute fee mechanism implemented in #2916. Signed-off-by: Anna Shaleva * Native: do not remove malicious conflict records during OnPersist It's OK to keep them and save O(n) operations during OnPersist. The storage taken by these malicious conflict records is properly paid anyway. See the discussion under https://github.com/neo-project/neo/pull/2913#discussion_r1329176044. Signed-off-by: Anna Shaleva * Properly rewrite previously added malicious conflict if it's in the storage `engine.Snapshot.Add` doesn't allow to rewrite storage entity if it's already exist. Thus, we firstly need to remove it and afterwards to add the updated entity. Signed-off-by: Anna Shaleva * Throw proper exception if TestMaliciousOnChainConflict fails Signed-off-by: Anna Shaleva * Optimize conflicts records storing Use Snapshot.GetAndChange instead of subsequent calls to Delete and Add. Ref. https://github.com/neo-project/neo/pull/2913#discussion_r1384748139. Signed-off-by: Anna Shaleva --------- Signed-off-by: Anna Shaleva Co-authored-by: Shargon Co-authored-by: Jimmy --- src/Neo/Ledger/Blockchain.cs | 2 +- src/Neo/NeoSystem.cs | 2 +- .../SmartContract/Native/LedgerContract.cs | 33 +++++++-- .../SmartContract/Native/TransactionState.cs | 17 ++--- tests/Neo.UnitTests/Ledger/UT_Blockchain.cs | 23 +++++-- tests/Neo.UnitTests/Ledger/UT_MemoryPool.cs | 68 ------------------- .../Ledger/UT_TransactionState.cs | 9 +-- 7 files changed, 55 insertions(+), 99 deletions(-) diff --git a/src/Neo/Ledger/Blockchain.cs b/src/Neo/Ledger/Blockchain.cs index 8acec8c974..b44595f722 100644 --- a/src/Neo/Ledger/Blockchain.cs +++ b/src/Neo/Ledger/Blockchain.cs @@ -206,7 +206,7 @@ private void OnFillMemoryPool(IEnumerable transactions) { if (NativeContract.Ledger.ContainsTransaction(snapshot, tx.Hash)) continue; - if (NativeContract.Ledger.ContainsConflictHash(snapshot, tx.Hash, tx.Signers.Select(s => s.Account))) + if (NativeContract.Ledger.ContainsConflictHash(snapshot, tx.Hash, tx.Signers.Select(s => s.Account), system.Settings.MaxTraceableBlocks)) continue; // First remove the tx if it is unverified in the pool. system.MemPool.TryRemoveUnVerified(tx.Hash, out _); diff --git a/src/Neo/NeoSystem.cs b/src/Neo/NeoSystem.cs index 2f66389672..11590377ad 100644 --- a/src/Neo/NeoSystem.cs +++ b/src/Neo/NeoSystem.cs @@ -287,7 +287,7 @@ public bool ContainsTransaction(UInt256 hash) /// if the transaction conflicts with on-chain transaction; otherwise, . public bool ContainsConflictHash(UInt256 hash, IEnumerable signers) { - return NativeContract.Ledger.ContainsConflictHash(StoreView, hash, signers); + return NativeContract.Ledger.ContainsConflictHash(StoreView, hash, signers, Settings.MaxTraceableBlocks); } } } diff --git a/src/Neo/SmartContract/Native/LedgerContract.cs b/src/Neo/SmartContract/Native/LedgerContract.cs index cd405c098b..b95c518518 100644 --- a/src/Neo/SmartContract/Native/LedgerContract.cs +++ b/src/Neo/SmartContract/Native/LedgerContract.cs @@ -47,13 +47,19 @@ internal override ContractTask OnPersist(ApplicationEngine engine) engine.Snapshot.Add(CreateStorageKey(Prefix_Block).Add(engine.PersistingBlock.Hash), new StorageItem(Trim(engine.PersistingBlock).ToArray())); foreach (TransactionState tx in transactions) { - engine.Snapshot.Add(CreateStorageKey(Prefix_Transaction).Add(tx.Transaction.Hash), new StorageItem(tx)); + // 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)); + + // Store transaction's conflicits. var conflictingSigners = tx.Transaction.Signers.Select(s => s.Account); foreach (var attr in tx.Transaction.GetAttributes()) { - var conflictRecord = engine.Snapshot.GetAndChange(CreateStorageKey(Prefix_Transaction).Add(attr.Hash), - () => new StorageItem(new TransactionState { ConflictingSigners = Array.Empty() })).GetInteroperable(); - conflictRecord.ConflictingSigners = conflictRecord.ConflictingSigners.Concat(conflictingSigners).Distinct().ToArray(); + engine.Snapshot.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.SetState(transactions); @@ -145,11 +151,24 @@ public bool ContainsTransaction(DataCache snapshot, UInt256 hash) /// The snapshot used to read data. /// The hash of the conflicting transaction. /// The list of signer accounts of the conflicting transaction. + /// MaxTraceableBlocks protocol setting. /// if the blockchain contains the hash of the conflicting transaction; otherwise, . - public bool ContainsConflictHash(DataCache snapshot, UInt256 hash, IEnumerable signers) + public bool ContainsConflictHash(DataCache snapshot, UInt256 hash, IEnumerable signers, uint maxTraceableBlocks) { - var state = snapshot.TryGet(CreateStorageKey(Prefix_Transaction).Add(hash))?.GetInteroperable(); - return state is not null && state.Transaction is null && (signers is null || state.ConflictingSigners.Intersect(signers).Any()); + // Check the dummy stub firstly to define whether there's exist at least one conflict record. + var stub = snapshot.TryGet(CreateStorageKey(Prefix_Transaction).Add(hash))?.GetInteroperable(); + if (stub is null || stub.Transaction is not null || !IsTraceableBlock(snapshot, stub.BlockIndex, maxTraceableBlocks)) + return false; + + // At least one conflict record is found, then need to check signers intersection. + foreach (var signer in signers) + { + var state = snapshot.TryGet(CreateStorageKey(Prefix_Transaction).Add(hash).Add(signer))?.GetInteroperable(); + if (state is not null && IsTraceableBlock(snapshot, state.BlockIndex, maxTraceableBlocks)) + return true; + } + + return false; } /// diff --git a/src/Neo/SmartContract/Native/TransactionState.cs b/src/Neo/SmartContract/Native/TransactionState.cs index d3c7f644be..8994a7acd5 100644 --- a/src/Neo/SmartContract/Native/TransactionState.cs +++ b/src/Neo/SmartContract/Native/TransactionState.cs @@ -32,8 +32,6 @@ public class TransactionState : IInteroperable /// public Transaction Transaction; - public UInt160[] ConflictingSigners; - /// /// The execution state /// @@ -47,7 +45,6 @@ IInteroperable IInteroperable.Clone() { BlockIndex = BlockIndex, Transaction = Transaction, - ConflictingSigners = ConflictingSigners, State = State, _rawTransaction = _rawTransaction }; @@ -58,7 +55,6 @@ void IInteroperable.FromReplica(IInteroperable replica) TransactionState from = (TransactionState)replica; BlockIndex = from.BlockIndex; Transaction = from.Transaction; - ConflictingSigners = from.ConflictingSigners; State = from.State; if (_rawTransaction.IsEmpty) _rawTransaction = from._rawTransaction; @@ -67,12 +63,12 @@ void IInteroperable.FromReplica(IInteroperable replica) void IInteroperable.FromStackItem(StackItem stackItem) { Struct @struct = (Struct)stackItem; - if (@struct.Count == 1) - { - ConflictingSigners = ((VM.Types.Array)@struct[0]).Select(u => new UInt160(u.GetSpan())).ToArray(); - return; - } BlockIndex = (uint)@struct[0].GetInteger(); + + // Conflict record. + if (@struct.Count == 1) return; + + // Fully-qualified transaction. _rawTransaction = ((ByteString)@struct[1]).Memory; Transaction = _rawTransaction.AsSerializable(); State = (VMState)(byte)@struct[2].GetInteger(); @@ -80,7 +76,8 @@ void IInteroperable.FromStackItem(StackItem stackItem) StackItem IInteroperable.ToStackItem(ReferenceCounter referenceCounter) { - if (Transaction is null) return new Struct(referenceCounter) { new VM.Types.Array(referenceCounter, ConflictingSigners.Select(u => new ByteString(u.ToArray())).ToArray()) }; + if (Transaction is null) + return new Struct(referenceCounter) { BlockIndex }; if (_rawTransaction.IsEmpty) _rawTransaction = Transaction.ToArray(); return new Struct(referenceCounter) { BlockIndex, _rawTransaction, (byte)State }; diff --git a/tests/Neo.UnitTests/Ledger/UT_Blockchain.cs b/tests/Neo.UnitTests/Ledger/UT_Blockchain.cs index 1cd8c42360..7ecb965ff5 100644 --- a/tests/Neo.UnitTests/Ledger/UT_Blockchain.cs +++ b/tests/Neo.UnitTests/Ledger/UT_Blockchain.cs @@ -135,7 +135,7 @@ public void TestMaliciousOnChainConflict() { Header = new Header() { - Index = 10000, + Index = 5, // allow tx1, tx2 and tx3 to fit into MaxValidUntilBlockIncrement. MerkleRoot = UInt256.Zero, NextConsensus = UInt160.Zero, PrevHash = UInt256.Zero, @@ -149,13 +149,26 @@ public void TestMaliciousOnChainConflict() sb.EmitSysCall(ApplicationEngine.System_Contract_NativeOnPersist); onPersistScript = sb.ToArray(); } - TransactionState[] transactionStates; using (ApplicationEngine engine2 = ApplicationEngine.Create(TriggerType.OnPersist, null, snapshot, block, TestBlockchain.TheNeoSystem.Settings, 0)) { engine2.LoadScript(onPersistScript); - if (engine2.Execute() != VMState.HALT) throw new InvalidOperationException(); - Blockchain.ApplicationExecuted application_executed = new(engine2); - transactionStates = engine2.GetState(); + if (engine2.Execute() != VMState.HALT) throw engine2.FaultException; + engine2.Snapshot.Commit(); + } + snapshot.Commit(); + + // Run PostPersist to update current block index in native Ledger. + // Relevant current block index is needed for conflict records checks. + byte[] postPersistScript; + using (ScriptBuilder sb = new()) + { + sb.EmitSysCall(ApplicationEngine.System_Contract_NativePostPersist); + postPersistScript = sb.ToArray(); + } + using (ApplicationEngine engine2 = ApplicationEngine.Create(TriggerType.PostPersist, null, snapshot, block, TestBlockchain.TheNeoSystem.Settings, 0)) + { + engine2.LoadScript(postPersistScript); + if (engine2.Execute() != VMState.HALT) throw engine2.FaultException; engine2.Snapshot.Commit(); } snapshot.Commit(); diff --git a/tests/Neo.UnitTests/Ledger/UT_MemoryPool.cs b/tests/Neo.UnitTests/Ledger/UT_MemoryPool.cs index de5bff6ba0..eb0aabf1f5 100644 --- a/tests/Neo.UnitTests/Ledger/UT_MemoryPool.cs +++ b/tests/Neo.UnitTests/Ledger/UT_MemoryPool.cs @@ -736,74 +736,6 @@ public void TestUpdatePoolForBlockPersisted() _unit.VerifiedCount.Should().Be(0); } - - [TestMethod] - public async Task Malicious_OnChain_Conflict() - { - // Arrange: prepare mempooled txs that have conflicts. - long txFee = 1; - var snapshot = GetSnapshot(); - BigInteger balance = NativeContract.GAS.BalanceOf(snapshot, senderAccount); - ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, settings: TestBlockchain.TheNeoSystem.Settings, gas: long.MaxValue); - engine.LoadScript(Array.Empty()); - - var tx1 = CreateTransactionWithFeeAndBalanceVerify(txFee); - var tx2 = CreateTransactionWithFeeAndBalanceVerify(txFee); - - tx1.Signers[0].Account = UInt160.Parse("0x0001020304050607080900010203040506070809"); // Different sender - - await NativeContract.GAS.Mint(engine, tx1.Sender, 100000, true); // balance enough for all mempooled txs - await NativeContract.GAS.Mint(engine, tx2.Sender, 100000, true); // balance enough for all mempooled txs - - tx1.Attributes = new TransactionAttribute[] { new Conflicts() { Hash = tx2.Hash } }; - - Assert.AreEqual(_unit.TryAdd(tx1, engine.Snapshot), VerifyResult.Succeed); - - var block = new Block - { - Header = new Header() - { - Index = 10000, - MerkleRoot = UInt256.Zero, - NextConsensus = UInt160.Zero, - PrevHash = UInt256.Zero, - Witness = new Witness() { InvocationScript = Array.Empty(), VerificationScript = Array.Empty() } - }, - Transactions = new Transaction[] { tx1 }, - }; - _unit.UpdatePoolForBlockPersisted(block, engine.Snapshot); - - _unit.SortedTxCount.Should().Be(0); - - // Simulate persist tx1 - - Assert.AreEqual(_unit.TryAdd(tx2, engine.Snapshot), VerifyResult.Succeed); - - byte[] onPersistScript; - using (ScriptBuilder sb = new()) - { - sb.EmitSysCall(ApplicationEngine.System_Contract_NativeOnPersist); - onPersistScript = sb.ToArray(); - } - - TransactionState[] transactionStates; - using (ApplicationEngine engine2 = ApplicationEngine.Create(TriggerType.OnPersist, null, engine.Snapshot, block, TestBlockchain.TheNeoSystem.Settings, 0)) - { - engine2.LoadScript(onPersistScript); - if (engine2.Execute() != VMState.HALT) throw new InvalidOperationException(); - Blockchain.ApplicationExecuted application_executed = new(engine2); - transactionStates = engine2.GetState(); - } - - // Test tx2 arrive - - snapshot.Commit(); - - var senderProbe = CreateTestProbe(); - senderProbe.Send(TestBlockchain.TheNeoSystem.Blockchain, tx2); - senderProbe.ExpectMsg(p => p.Result == VerifyResult.InsufficientFunds); // should be Succedded. - } - public static StorageKey CreateStorageKey(int id, byte prefix, byte[] key = null) { byte[] buffer = GC.AllocateUninitializedArray(sizeof(byte) + (key?.Length ?? 0)); diff --git a/tests/Neo.UnitTests/Ledger/UT_TransactionState.cs b/tests/Neo.UnitTests/Ledger/UT_TransactionState.cs index 0270d97891..13629c4f63 100644 --- a/tests/Neo.UnitTests/Ledger/UT_TransactionState.cs +++ b/tests/Neo.UnitTests/Ledger/UT_TransactionState.cs @@ -36,11 +36,7 @@ public void Initialize() }; originTrimmed = new TransactionState { - ConflictingSigners = new UInt160[] - { - new UInt160(Crypto.Hash160(new byte[] { 1, 2, 3 })), - new UInt160(Crypto.Hash160(new byte[] { 4, 5, 6 })) - } + BlockIndex = 1, }; } @@ -67,10 +63,9 @@ public void TestDeserializeTrimmed() TransactionState dest = new(); ((IInteroperable)dest).FromStackItem(BinarySerializer.Deserialize(ref reader, ExecutionEngineLimits.Default, null)); - dest.BlockIndex.Should().Be(0); + dest.BlockIndex.Should().Be(originTrimmed.BlockIndex); dest.Transaction.Should().Be(null); dest.Transaction.Should().BeNull(); - CollectionAssert.AreEqual(originTrimmed.ConflictingSigners, dest.ConflictingSigners); } } } From 6df83952d01b6c9486814f677fe42a2922ce3ee1 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Fri, 10 Nov 2023 05:38:38 +0800 Subject: [PATCH 015/168] check null scriptcontainer (#2953) * check null scriptcontainer * Clean code * Add comment --------- Co-authored-by: Shargon --- src/Neo/SmartContract/ApplicationEngine.Runtime.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Neo/SmartContract/ApplicationEngine.Runtime.cs b/src/Neo/SmartContract/ApplicationEngine.Runtime.cs index 41cc6e8c9d..533aefaac0 100644 --- a/src/Neo/SmartContract/ApplicationEngine.Runtime.cs +++ b/src/Neo/SmartContract/ApplicationEngine.Runtime.cs @@ -271,6 +271,11 @@ protected internal bool CheckWitnessInternal(UInt160 hash) } return false; } + else + { + // If we don't have the ScriptContainer, we consider that there are no script hashes for verifying + if (ScriptContainer is null) return false; + } // Check allow state callflag From 64fecc46e1dc42f1dfa0378cc67a1756cd17d945 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Fri, 10 Nov 2023 18:26:05 +0800 Subject: [PATCH 016/168] code optimization (#2958) * code optimization * add ut test. --- .../ApplicationEngine.Runtime.cs | 25 ++++++++----------- .../SmartContract/UT_InteropService.cs | 14 +++++++++++ 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/src/Neo/SmartContract/ApplicationEngine.Runtime.cs b/src/Neo/SmartContract/ApplicationEngine.Runtime.cs index 533aefaac0..c23677eb3c 100644 --- a/src/Neo/SmartContract/ApplicationEngine.Runtime.cs +++ b/src/Neo/SmartContract/ApplicationEngine.Runtime.cs @@ -1,10 +1,10 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, +// Copyright (C) 2015-2023 The Neo Project. +// +// The neo is free software distributed under the MIT software license, // see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// project 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. @@ -235,7 +235,7 @@ protected internal bool CheckWitness(byte[] hashOrPubkey) { 20 => new UInt160(hashOrPubkey), 33 => Contract.CreateSignatureRedeemScript(ECPoint.DecodePoint(hashOrPubkey, ECCurve.Secp256r1)).ToScriptHash(), - _ => throw new ArgumentException(null, nameof(hashOrPubkey)) + _ => throw new ArgumentException("Invalid hashOrPubkey.", nameof(hashOrPubkey)) }; return CheckWitnessInternal(hash); } @@ -271,20 +271,15 @@ protected internal bool CheckWitnessInternal(UInt160 hash) } return false; } - else - { - // If we don't have the ScriptContainer, we consider that there are no script hashes for verifying - if (ScriptContainer is null) return false; - } - // Check allow state callflag + // If we don't have the ScriptContainer, we consider that there are no script hashes for verifying + if (ScriptContainer is null) return false; + // Check allow state callflag ValidateCallFlags(CallFlags.ReadStates); // only for non-Transaction types (Block, etc) - - var hashes_for_verifying = ScriptContainer.GetScriptHashesForVerifying(Snapshot); - return hashes_for_verifying.Contains(hash); + return ScriptContainer.GetScriptHashesForVerifying(Snapshot).Contains(hash); } /// diff --git a/tests/Neo.UnitTests/SmartContract/UT_InteropService.cs b/tests/Neo.UnitTests/SmartContract/UT_InteropService.cs index 60d4923c75..083f884636 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_InteropService.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_InteropService.cs @@ -300,6 +300,20 @@ public void TestRuntime_CheckWitness() action.Should().Throw(); } + [TestMethod] + public void TestRuntime_CheckWitness_Null_ScriptContainer() + { + byte[] privateKey = { 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}; + KeyPair keyPair = new(privateKey); + ECPoint pubkey = keyPair.PublicKey; + + var engine = GetEngine(); + + engine.CheckWitness(pubkey.EncodePoint(true)).Should().BeFalse(); + engine.CheckWitness(pubkey.EncodePoint(true)).Should().BeFalse(); + } + [TestMethod] public void TestRuntime_Log() { From 07a18109bd61f94cb2079160f98b7159238a7c47 Mon Sep 17 00:00:00 2001 From: Shargon Date: Fri, 10 Nov 2023 11:29:00 +0100 Subject: [PATCH 017/168] Validate serialization during Contract deploy and Update (#2948) * Fix 2899 * Optimize * Add UT * UT manifest * Add failure ut for testing * Possible fix * Prevent future issues * Prevent deploy * Check items during serialization to avoid serialize and deserialize * Fix comment * Clean code * Clean changes * Move condition * Fix exception message --- .../ApplicationEngine.Runtime.cs | 4 +- src/Neo/SmartContract/BinarySerializer.cs | 55 ++++++++++++++----- .../Manifest/ContractManifest.cs | 17 +++++- .../Native/ContractManagement.cs | 17 +++--- .../SmartContract/Native/OracleContract.cs | 2 +- src/Neo/SmartContract/Native/StdLib.cs | 9 ++- src/Neo/SmartContract/StorageItem.cs | 6 +- .../Neo.UnitTests/Ledger/UT_HashIndexState.cs | 4 +- .../Ledger/UT_TransactionState.cs | 4 +- .../Manifest/UT_ContractManifest.cs | 40 +++++++++++++- .../Manifest/UT_ContractPermission.cs | 27 +++++++++ .../SmartContract/Native/UT_NeoToken.cs | 2 +- .../SmartContract/UT_BinarySerializer.cs | 34 ++++++------ 13 files changed, 161 insertions(+), 60 deletions(-) diff --git a/src/Neo/SmartContract/ApplicationEngine.Runtime.cs b/src/Neo/SmartContract/ApplicationEngine.Runtime.cs index c23677eb3c..5fde33e6b5 100644 --- a/src/Neo/SmartContract/ApplicationEngine.Runtime.cs +++ b/src/Neo/SmartContract/ApplicationEngine.Runtime.cs @@ -362,7 +362,7 @@ protected internal void RuntimeNotify(byte[] eventName, Array state) } using MemoryStream ms = new(MaxNotificationSize); using BinaryWriter writer = new(ms, Utility.StrictUTF8, true); - BinarySerializer.Serialize(writer, state, MaxNotificationSize); + BinarySerializer.Serialize(writer, state, MaxNotificationSize, Limits.MaxStackSize); SendNotification(CurrentScriptHash, name, state); } @@ -373,7 +373,7 @@ protected internal void RuntimeNotifyV1(byte[] eventName, Array state) throw new InvalidOperationException("Notifications are not allowed in dynamic scripts."); using MemoryStream ms = new(MaxNotificationSize); using BinaryWriter writer = new(ms, Utility.StrictUTF8, true); - BinarySerializer.Serialize(writer, state, MaxNotificationSize); + BinarySerializer.Serialize(writer, state, MaxNotificationSize, Limits.MaxStackSize); SendNotification(CurrentScriptHash, Utility.StrictUTF8.GetString(eventName), state); } diff --git a/src/Neo/SmartContract/BinarySerializer.cs b/src/Neo/SmartContract/BinarySerializer.cs index d881762f84..8febeb25e2 100644 --- a/src/Neo/SmartContract/BinarySerializer.cs +++ b/src/Neo/SmartContract/BinarySerializer.cs @@ -8,14 +8,14 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. -using Neo.IO; -using Neo.VM; -using Neo.VM.Types; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Numerics; +using Neo.IO; +using Neo.VM; +using Neo.VM.Types; using Array = Neo.VM.Types.Array; using Boolean = Neo.VM.Types.Boolean; using Buffer = Neo.VM.Types.Buffer; @@ -55,7 +55,7 @@ public ContainerPlaceholder(StackItemType type, int count) public static StackItem Deserialize(ReadOnlyMemory data, ExecutionEngineLimits limits, ReferenceCounter referenceCounter = null) { MemoryReader reader = new(data); - return Deserialize(ref reader, limits with { MaxItemSize = (uint)data.Length }, referenceCounter); + return Deserialize(ref reader, (uint)Math.Min(data.Length, limits.MaxItemSize), limits.MaxStackSize, referenceCounter); } /// @@ -65,7 +65,20 @@ public static StackItem Deserialize(ReadOnlyMemory data, ExecutionEngineLi /// The limits for the deserialization. /// The used by the . /// The deserialized . - public static StackItem Deserialize(ref MemoryReader reader, ExecutionEngineLimits limits, ReferenceCounter referenceCounter) + public static StackItem Deserialize(ref MemoryReader reader, ExecutionEngineLimits limits, ReferenceCounter referenceCounter = null) + { + return Deserialize(ref reader, limits.MaxItemSize, limits.MaxStackSize, referenceCounter); + } + + /// + /// Deserializes a from . + /// + /// The for reading data. + /// The maximum size of the result. + /// The max of items to serialize + /// The used by the . + /// The deserialized . + public static StackItem Deserialize(ref MemoryReader reader, uint maxSize, uint maxItems, ReferenceCounter referenceCounter = null) { Stack deserialized = new(); int undeserialized = 1; @@ -84,23 +97,23 @@ public static StackItem Deserialize(ref MemoryReader reader, ExecutionEngineLimi deserialized.Push(new BigInteger(reader.ReadVarMemory(Integer.MaxSize).Span)); break; case StackItemType.ByteString: - deserialized.Push(reader.ReadVarMemory((int)limits.MaxItemSize)); + deserialized.Push(reader.ReadVarMemory((int)maxSize)); break; case StackItemType.Buffer: - ReadOnlyMemory memory = reader.ReadVarMemory((int)limits.MaxItemSize); + ReadOnlyMemory memory = reader.ReadVarMemory((int)maxSize); deserialized.Push(new Buffer(memory.Span)); break; case StackItemType.Array: case StackItemType.Struct: { - int count = (int)reader.ReadVarInt(limits.MaxStackSize); + int count = (int)reader.ReadVarInt(maxItems); deserialized.Push(new ContainerPlaceholder(type, count)); undeserialized += count; } break; case StackItemType.Map: { - int count = (int)reader.ReadVarInt(limits.MaxStackSize); + int count = (int)reader.ReadVarInt(maxItems); deserialized.Push(new ContainerPlaceholder(type, count)); undeserialized += count * 2; } @@ -108,7 +121,8 @@ public static StackItem Deserialize(ref MemoryReader reader, ExecutionEngineLimi default: throw new FormatException(); } - if (deserialized.Count > limits.MaxStackSize) throw new FormatException(); + if (deserialized.Count > maxItems) + throw new FormatException(); } Stack stack_temp = new(); while (deserialized.Count > 0) @@ -147,17 +161,29 @@ public static StackItem Deserialize(ref MemoryReader reader, ExecutionEngineLimi return stack_temp.Peek(); } + /// + /// Serializes a to byte array. + /// + /// The to be serialized. + /// The used to ensure the limits. + /// The serialized byte array. + public static byte[] Serialize(StackItem item, ExecutionEngineLimits limits) + { + return Serialize(item, limits.MaxItemSize, limits.MaxStackSize); + } + /// /// Serializes a to byte array. /// /// The to be serialized. /// The maximum size of the result. + /// The max of items to serialize /// The serialized byte array. - public static byte[] Serialize(StackItem item, uint maxSize) + public static byte[] Serialize(StackItem item, long maxSize, long maxItems) { using MemoryStream ms = new(); using BinaryWriter writer = new(ms, Utility.StrictUTF8, true); - Serialize(writer, item, maxSize); + Serialize(writer, item, maxSize, maxItems); writer.Flush(); return ms.ToArray(); } @@ -168,13 +194,16 @@ public static byte[] Serialize(StackItem item, uint maxSize) /// The for writing data. /// The to be serialized. /// The maximum size of the result. - public static void Serialize(BinaryWriter writer, StackItem item, uint maxSize) + /// The max of items to serialize + public static void Serialize(BinaryWriter writer, StackItem item, long maxSize, long maxItems) { HashSet serialized = new(ReferenceEqualityComparer.Instance); Stack unserialized = new(); unserialized.Push(item); while (unserialized.Count > 0) { + if (--maxItems < 0) + throw new FormatException(); item = unserialized.Pop(); writer.Write((byte)item.Type); switch (item) diff --git a/src/Neo/SmartContract/Manifest/ContractManifest.cs b/src/Neo/SmartContract/Manifest/ContractManifest.cs index 341b369ab4..a1d3f62fd9 100644 --- a/src/Neo/SmartContract/Manifest/ContractManifest.cs +++ b/src/Neo/SmartContract/Manifest/ContractManifest.cs @@ -8,12 +8,12 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using System; +using System.Linq; using Neo.IO; using Neo.Json; using Neo.VM; using Neo.VM.Types; -using System; -using System.Linq; using Array = Neo.VM.Types.Array; namespace Neo.SmartContract.Manifest @@ -172,10 +172,21 @@ public JObject ToJson() /// /// Determines whether the manifest is valid. /// + /// The used for test serialization. /// The hash of the contract. /// if the manifest is valid; otherwise, . - public bool IsValid(UInt160 hash) + public bool IsValid(ExecutionEngineLimits limits, UInt160 hash) { + // Ensure that is serializable + try + { + _ = BinarySerializer.Serialize(ToStackItem(null), limits); + } + catch + { + return false; + } + // Check groups return Groups.All(u => u.IsValid(hash)); } } diff --git a/src/Neo/SmartContract/Native/ContractManagement.cs b/src/Neo/SmartContract/Native/ContractManagement.cs index 62e9bb366d..75984754af 100644 --- a/src/Neo/SmartContract/Native/ContractManagement.cs +++ b/src/Neo/SmartContract/Native/ContractManagement.cs @@ -10,17 +10,18 @@ #pragma warning disable IDE0051 +using System; +using System.Buffers.Binary; +using System.Collections.Generic; +using System.Linq; +using System.Numerics; using Neo.IO; using Neo.Network.P2P.Payloads; using Neo.Persistence; using Neo.SmartContract.Iterators; using Neo.SmartContract.Manifest; +using Neo.VM; using Neo.VM.Types; -using System; -using System.Buffers.Binary; -using System.Collections.Generic; -using System.Linq; -using System.Numerics; namespace Neo.SmartContract.Native { @@ -249,7 +250,7 @@ private async ContractTask Deploy(ApplicationEngine engine, byte[ Manifest = parsedManifest }; - if (!contract.Manifest.IsValid(hash)) throw new InvalidOperationException($"Invalid Manifest Hash: {hash}"); + 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())); @@ -291,8 +292,8 @@ private ContractTask Update(ApplicationEngine engine, byte[] nefFile, byte[] man ContractManifest manifest_new = ContractManifest.Parse(manifest); if (manifest_new.Name != contract.Manifest.Name) throw new InvalidOperationException("The name of the contract can't be changed."); - if (!manifest_new.IsValid(contract.Hash)) - throw new InvalidOperationException($"Invalid Manifest Hash: {contract.Hash}"); + if (!manifest_new.IsValid(engine.Limits, contract.Hash)) + throw new InvalidOperationException($"Invalid Manifest: {contract.Hash}"); contract.Manifest = manifest_new; } Helper.Check(new VM.Script(contract.Nef.Script, engine.IsHardforkEnabled(Hardfork.HF_Basilisk)), contract.Manifest.Abi); diff --git a/src/Neo/SmartContract/Native/OracleContract.cs b/src/Neo/SmartContract/Native/OracleContract.cs index df35bd98e8..99c9be9f23 100644 --- a/src/Neo/SmartContract/Native/OracleContract.cs +++ b/src/Neo/SmartContract/Native/OracleContract.cs @@ -255,7 +255,7 @@ private async ContractTask Request(ApplicationEngine engine, string url, string Filter = filter, CallbackContract = engine.CallingScriptHash, CallbackMethod = callback, - UserData = BinarySerializer.Serialize(userData, MaxUserDataLength) + UserData = BinarySerializer.Serialize(userData, MaxUserDataLength, engine.Limits.MaxStackSize) })); //Add the id to the IdList diff --git a/src/Neo/SmartContract/Native/StdLib.cs b/src/Neo/SmartContract/Native/StdLib.cs index cb540d36a1..9f7d0108da 100644 --- a/src/Neo/SmartContract/Native/StdLib.cs +++ b/src/Neo/SmartContract/Native/StdLib.cs @@ -10,13 +10,12 @@ #pragma warning disable IDE0051 -using Neo.Cryptography; -using Neo.Json; -using Neo.VM.Types; using System; using System.Globalization; using System.Numerics; -using System.Text; +using Neo.Cryptography; +using Neo.Json; +using Neo.VM.Types; namespace Neo.SmartContract.Native { @@ -32,7 +31,7 @@ internal StdLib() { } [ContractMethod(CpuFee = 1 << 12)] private static byte[] Serialize(ApplicationEngine engine, StackItem item) { - return BinarySerializer.Serialize(item, engine.Limits.MaxItemSize); + return BinarySerializer.Serialize(item, engine.Limits); } [ContractMethod(CpuFee = 1 << 14)] diff --git a/src/Neo/SmartContract/StorageItem.cs b/src/Neo/SmartContract/StorageItem.cs index b8cfa179e6..e7dcc8ead6 100644 --- a/src/Neo/SmartContract/StorageItem.cs +++ b/src/Neo/SmartContract/StorageItem.cs @@ -8,11 +8,11 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. -using Neo.IO; -using Neo.VM; using System; using System.IO; using System.Numerics; +using Neo.IO; +using Neo.VM; namespace Neo.SmartContract { @@ -36,7 +36,7 @@ public ReadOnlyMemory Value return !value.IsEmpty ? value : value = cache switch { BigInteger bi => bi.ToByteArrayStandard(), - IInteroperable interoperable => BinarySerializer.Serialize(interoperable.ToStackItem(null), 1024 * 1024), + IInteroperable interoperable => BinarySerializer.Serialize(interoperable.ToStackItem(null), ExecutionEngineLimits.Default), null => ReadOnlyMemory.Empty, _ => throw new InvalidCastException() }; diff --git a/tests/Neo.UnitTests/Ledger/UT_HashIndexState.cs b/tests/Neo.UnitTests/Ledger/UT_HashIndexState.cs index 7cebe1d9bf..7099512326 100644 --- a/tests/Neo.UnitTests/Ledger/UT_HashIndexState.cs +++ b/tests/Neo.UnitTests/Ledger/UT_HashIndexState.cs @@ -25,10 +25,10 @@ public void Initialize() [TestMethod] public void TestDeserialize() { - var data = BinarySerializer.Serialize(((IInteroperable)origin).ToStackItem(null), 1024); + var data = BinarySerializer.Serialize(((IInteroperable)origin).ToStackItem(null), ExecutionEngineLimits.Default); var reader = new MemoryReader(data); - HashIndexState dest = new HashIndexState(); + HashIndexState dest = new(); ((IInteroperable)dest).FromStackItem(BinarySerializer.Deserialize(ref reader, ExecutionEngineLimits.Default, null)); dest.Hash.Should().Be(origin.Hash); diff --git a/tests/Neo.UnitTests/Ledger/UT_TransactionState.cs b/tests/Neo.UnitTests/Ledger/UT_TransactionState.cs index 13629c4f63..117f9b2a1f 100644 --- a/tests/Neo.UnitTests/Ledger/UT_TransactionState.cs +++ b/tests/Neo.UnitTests/Ledger/UT_TransactionState.cs @@ -43,7 +43,7 @@ public void Initialize() [TestMethod] public void TestDeserialize() { - var data = BinarySerializer.Serialize(((IInteroperable)origin).ToStackItem(null), 1024); + var data = BinarySerializer.Serialize(((IInteroperable)origin).ToStackItem(null), ExecutionEngineLimits.Default); var reader = new MemoryReader(data); TransactionState dest = new(); @@ -57,7 +57,7 @@ public void TestDeserialize() [TestMethod] public void TestDeserializeTrimmed() { - var data = BinarySerializer.Serialize(((IInteroperable)originTrimmed).ToStackItem(null), 1024); + var data = BinarySerializer.Serialize(((IInteroperable)originTrimmed).ToStackItem(null), ExecutionEngineLimits.Default); var reader = new MemoryReader(data); TransactionState dest = new(); diff --git a/tests/Neo.UnitTests/SmartContract/Manifest/UT_ContractManifest.cs b/tests/Neo.UnitTests/SmartContract/Manifest/UT_ContractManifest.cs index 986716e694..1cde958f4e 100644 --- a/tests/Neo.UnitTests/SmartContract/Manifest/UT_ContractManifest.cs +++ b/tests/Neo.UnitTests/SmartContract/Manifest/UT_ContractManifest.cs @@ -12,6 +12,26 @@ namespace Neo.UnitTests.SmartContract.Manifest [TestClass] public class UT_ContractManifest { + [TestMethod] + public void TestMainnetContract() + { + // 0x6f1837723768f27a6f6a14452977e3e0e264f2cc in mainnet + var json = @"{""name"":""Test"",""groups"":[],""features"":{},""supportedstandards"":[],""abi"":{""methods"":[{""name"":""a"",""parameters"":[{""name"":""amountIn"",""type"":""Integer""}],""returntype"":""Void"",""offset"":0,""safe"":false},{""name"":""a0"",""parameters"":[],""returntype"":""Integer"",""offset"":77,""safe"":false},{""name"":""a10"",""parameters"":[],""returntype"":""Void"",""offset"":378,""safe"":false},{""name"":""a11"",""parameters"":[],""returntype"":""Void"",""offset"":398,""safe"":false},{""name"":""a12"",""parameters"":[],""returntype"":""Void"",""offset"":418,""safe"":false},{""name"":""a13"",""parameters"":[],""returntype"":""Void"",""offset"":438,""safe"":false},{""name"":""a14"",""parameters"":[],""returntype"":""Void"",""offset"":458,""safe"":false},{""name"":""a15"",""parameters"":[],""returntype"":""Void"",""offset"":478,""safe"":false},{""name"":""a16"",""parameters"":[],""returntype"":""Void"",""offset"":498,""safe"":false},{""name"":""a17"",""parameters"":[],""returntype"":""Void"",""offset"":518,""safe"":false},{""name"":""a18"",""parameters"":[],""returntype"":""Void"",""offset"":539,""safe"":false},{""name"":""a19"",""parameters"":[],""returntype"":""Void"",""offset"":560,""safe"":false},{""name"":""a20"",""parameters"":[],""returntype"":""Void"",""offset"":581,""safe"":false},{""name"":""a21"",""parameters"":[],""returntype"":""Void"",""offset"":602,""safe"":false},{""name"":""a22"",""parameters"":[],""returntype"":""Void"",""offset"":623,""safe"":false},{""name"":""a23"",""parameters"":[],""returntype"":""Void"",""offset"":644,""safe"":false},{""name"":""a24"",""parameters"":[],""returntype"":""Void"",""offset"":665,""safe"":false},{""name"":""a25"",""parameters"":[],""returntype"":""Void"",""offset"":686,""safe"":false},{""name"":""a26"",""parameters"":[],""returntype"":""Void"",""offset"":707,""safe"":false},{""name"":""a27"",""parameters"":[],""returntype"":""Void"",""offset"":728,""safe"":false},{""name"":""a28"",""parameters"":[],""returntype"":""Void"",""offset"":749,""safe"":false},{""name"":""a29"",""parameters"":[],""returntype"":""Void"",""offset"":770,""safe"":false},{""name"":""a30"",""parameters"":[],""returntype"":""Void"",""offset"":791,""safe"":false},{""name"":""a31"",""parameters"":[],""returntype"":""Void"",""offset"":812,""safe"":false},{""name"":""a32"",""parameters"":[],""returntype"":""Void"",""offset"":833,""safe"":false},{""name"":""a33"",""parameters"":[],""returntype"":""Void"",""offset"":854,""safe"":false},{""name"":""a34"",""parameters"":[],""returntype"":""Void"",""offset"":875,""safe"":false},{""name"":""a35"",""parameters"":[],""returntype"":""Void"",""offset"":896,""safe"":false},{""name"":""a36"",""parameters"":[],""returntype"":""Void"",""offset"":917,""safe"":false},{""name"":""a37"",""parameters"":[],""returntype"":""Void"",""offset"":938,""safe"":false},{""name"":""a38"",""parameters"":[],""returntype"":""Void"",""offset"":959,""safe"":false},{""name"":""a39"",""parameters"":[],""returntype"":""Void"",""offset"":980,""safe"":false},{""name"":""a40"",""parameters"":[],""returntype"":""Void"",""offset"":1001,""safe"":false},{""name"":""a41"",""parameters"":[],""returntype"":""Void"",""offset"":1022,""safe"":false},{""name"":""a42"",""parameters"":[],""returntype"":""Void"",""offset"":1043,""safe"":false},{""name"":""a43"",""parameters"":[],""returntype"":""Void"",""offset"":1064,""safe"":false},{""name"":""a44"",""parameters"":[],""returntype"":""Void"",""offset"":1085,""safe"":false},{""name"":""a45"",""parameters"":[],""returntype"":""Void"",""offset"":1106,""safe"":false},{""name"":""a46"",""parameters"":[],""returntype"":""Void"",""offset"":1127,""safe"":false},{""name"":""a47"",""parameters"":[],""returntype"":""Void"",""offset"":1148,""safe"":false},{""name"":""a48"",""parameters"":[],""returntype"":""Void"",""offset"":1169,""safe"":false},{""name"":""a49"",""parameters"":[],""returntype"":""Void"",""offset"":1190,""safe"":false},{""name"":""a50"",""parameters"":[],""returntype"":""Void"",""offset"":1211,""safe"":false},{""name"":""b"",""parameters"":[{""name"":""amountIn"",""type"":""Integer""}],""returntype"":""Void"",""offset"":1232,""safe"":false},{""name"":""b0"",""parameters"":[],""returntype"":""Integer"",""offset"":1251,""safe"":false},{""name"":""b10"",""parameters"":[],""returntype"":""Void"",""offset"":1275,""safe"":false},{""name"":""b11"",""parameters"":[],""returntype"":""Void"",""offset"":1295,""safe"":false},{""name"":""b12"",""parameters"":[],""returntype"":""Void"",""offset"":1315,""safe"":false},{""name"":""b13"",""parameters"":[],""returntype"":""Void"",""offset"":1335,""safe"":false},{""name"":""b14"",""parameters"":[],""returntype"":""Void"",""offset"":1355,""safe"":false},{""name"":""b15"",""parameters"":[],""returntype"":""Void"",""offset"":1375,""safe"":false},{""name"":""b16"",""parameters"":[],""returntype"":""Void"",""offset"":1395,""safe"":false},{""name"":""b17"",""parameters"":[],""returntype"":""Void"",""offset"":1415,""safe"":false},{""name"":""b18"",""parameters"":[],""returntype"":""Void"",""offset"":1436,""safe"":false},{""name"":""b19"",""parameters"":[],""returntype"":""Void"",""offset"":1457,""safe"":false},{""name"":""b20"",""parameters"":[],""returntype"":""Void"",""offset"":1478,""safe"":false},{""name"":""b21"",""parameters"":[],""returntype"":""Void"",""offset"":1499,""safe"":false},{""name"":""b22"",""parameters"":[],""returntype"":""Void"",""offset"":1520,""safe"":false},{""name"":""b23"",""parameters"":[],""returntype"":""Void"",""offset"":1541,""safe"":false},{""name"":""b24"",""parameters"":[],""returntype"":""Void"",""offset"":1562,""safe"":false},{""name"":""b25"",""parameters"":[],""returntype"":""Void"",""offset"":1583,""safe"":false},{""name"":""b26"",""parameters"":[],""returntype"":""Void"",""offset"":1604,""safe"":false},{""name"":""b27"",""parameters"":[],""returntype"":""Void"",""offset"":1625,""safe"":false},{""name"":""b28"",""parameters"":[],""returntype"":""Void"",""offset"":1646,""safe"":false},{""name"":""b29"",""parameters"":[],""returntype"":""Void"",""offset"":1667,""safe"":false},{""name"":""b30"",""parameters"":[],""returntype"":""Void"",""offset"":1688,""safe"":false},{""name"":""b31"",""parameters"":[],""returntype"":""Void"",""offset"":1709,""safe"":false},{""name"":""b32"",""parameters"":[],""returntype"":""Void"",""offset"":1730,""safe"":false},{""name"":""b33"",""parameters"":[],""returntype"":""Void"",""offset"":1751,""safe"":false},{""name"":""b34"",""parameters"":[],""returntype"":""Void"",""offset"":1772,""safe"":false},{""name"":""b35"",""parameters"":[],""returntype"":""Void"",""offset"":1793,""safe"":false},{""name"":""b36"",""parameters"":[],""returntype"":""Void"",""offset"":1814,""safe"":false},{""name"":""b37"",""parameters"":[],""returntype"":""Void"",""offset"":1835,""safe"":false},{""name"":""b38"",""parameters"":[],""returntype"":""Void"",""offset"":1856,""safe"":false},{""name"":""b39"",""parameters"":[],""returntype"":""Void"",""offset"":1877,""safe"":false},{""name"":""b40"",""parameters"":[],""returntype"":""Void"",""offset"":1898,""safe"":false},{""name"":""b41"",""parameters"":[],""returntype"":""Void"",""offset"":1919,""safe"":false},{""name"":""b42"",""parameters"":[],""returntype"":""Void"",""offset"":1940,""safe"":false},{""name"":""b43"",""parameters"":[],""returntype"":""Void"",""offset"":1961,""safe"":false},{""name"":""b44"",""parameters"":[],""returntype"":""Void"",""offset"":1982,""safe"":false},{""name"":""b45"",""parameters"":[],""returntype"":""Void"",""offset"":2003,""safe"":false},{""name"":""b46"",""parameters"":[],""returntype"":""Void"",""offset"":2024,""safe"":false},{""name"":""b47"",""parameters"":[],""returntype"":""Void"",""offset"":2045,""safe"":false},{""name"":""b48"",""parameters"":[],""returntype"":""Void"",""offset"":2066,""safe"":false},{""name"":""b49"",""parameters"":[],""returntype"":""Void"",""offset"":2087,""safe"":false},{""name"":""b50"",""parameters"":[],""returntype"":""Void"",""offset"":2108,""safe"":false},{""name"":""c"",""parameters"":[{""name"":""amountIn"",""type"":""Integer""}],""returntype"":""Void"",""offset"":2129,""safe"":false},{""name"":""c0"",""parameters"":[],""returntype"":""Integer"",""offset"":2148,""safe"":false},{""name"":""c10"",""parameters"":[],""returntype"":""Void"",""offset"":2172,""safe"":false},{""name"":""c11"",""parameters"":[],""returntype"":""Void"",""offset"":2192,""safe"":false},{""name"":""c12"",""parameters"":[],""returntype"":""Void"",""offset"":2212,""safe"":false},{""name"":""c13"",""parameters"":[],""returntype"":""Void"",""offset"":2232,""safe"":false},{""name"":""c14"",""parameters"":[],""returntype"":""Void"",""offset"":2252,""safe"":false},{""name"":""c15"",""parameters"":[],""returntype"":""Void"",""offset"":2272,""safe"":false},{""name"":""c16"",""parameters"":[],""returntype"":""Void"",""offset"":2292,""safe"":false},{""name"":""c17"",""parameters"":[],""returntype"":""Void"",""offset"":2312,""safe"":false},{""name"":""c18"",""parameters"":[],""returntype"":""Void"",""offset"":2333,""safe"":false},{""name"":""c19"",""parameters"":[],""returntype"":""Void"",""offset"":2354,""safe"":false},{""name"":""c20"",""parameters"":[],""returntype"":""Void"",""offset"":2375,""safe"":false},{""name"":""c21"",""parameters"":[],""returntype"":""Void"",""offset"":2396,""safe"":false},{""name"":""c22"",""parameters"":[],""returntype"":""Void"",""offset"":2417,""safe"":false},{""name"":""c23"",""parameters"":[],""returntype"":""Void"",""offset"":2438,""safe"":false},{""name"":""c24"",""parameters"":[],""returntype"":""Void"",""offset"":2459,""safe"":false},{""name"":""c25"",""parameters"":[],""returntype"":""Void"",""offset"":2480,""safe"":false},{""name"":""c26"",""parameters"":[],""returntype"":""Void"",""offset"":2501,""safe"":false},{""name"":""c27"",""parameters"":[],""returntype"":""Void"",""offset"":2522,""safe"":false},{""name"":""c28"",""parameters"":[],""returntype"":""Void"",""offset"":2543,""safe"":false},{""name"":""c29"",""parameters"":[],""returntype"":""Void"",""offset"":2564,""safe"":false},{""name"":""c30"",""parameters"":[],""returntype"":""Void"",""offset"":2585,""safe"":false},{""name"":""c31"",""parameters"":[],""returntype"":""Void"",""offset"":2606,""safe"":false},{""name"":""c32"",""parameters"":[],""returntype"":""Void"",""offset"":2627,""safe"":false},{""name"":""c33"",""parameters"":[],""returntype"":""Void"",""offset"":2648,""safe"":false},{""name"":""c34"",""parameters"":[],""returntype"":""Void"",""offset"":2669,""safe"":false},{""name"":""c35"",""parameters"":[],""returntype"":""Void"",""offset"":2690,""safe"":false},{""name"":""c36"",""parameters"":[],""returntype"":""Void"",""offset"":2711,""safe"":false},{""name"":""c37"",""parameters"":[],""returntype"":""Void"",""offset"":2732,""safe"":false},{""name"":""c38"",""parameters"":[],""returntype"":""Void"",""offset"":2753,""safe"":false},{""name"":""c39"",""parameters"":[],""returntype"":""Void"",""offset"":2774,""safe"":false},{""name"":""c40"",""parameters"":[],""returntype"":""Void"",""offset"":2795,""safe"":false},{""name"":""c41"",""parameters"":[],""returntype"":""Void"",""offset"":2816,""safe"":false},{""name"":""c42"",""parameters"":[],""returntype"":""Void"",""offset"":2837,""safe"":false},{""name"":""c43"",""parameters"":[],""returntype"":""Void"",""offset"":2858,""safe"":false},{""name"":""c44"",""parameters"":[],""returntype"":""Void"",""offset"":2879,""safe"":false},{""name"":""c45"",""parameters"":[],""returntype"":""Void"",""offset"":2900,""safe"":false},{""name"":""c46"",""parameters"":[],""returntype"":""Void"",""offset"":2921,""safe"":false},{""name"":""c47"",""parameters"":[],""returntype"":""Void"",""offset"":2942,""safe"":false},{""name"":""c48"",""parameters"":[],""returntype"":""Void"",""offset"":2963,""safe"":false},{""name"":""c49"",""parameters"":[],""returntype"":""Void"",""offset"":2984,""safe"":false},{""name"":""c50"",""parameters"":[],""returntype"":""Void"",""offset"":3005,""safe"":false},{""name"":""verify"",""parameters"":[],""returntype"":""Boolean"",""offset"":3026,""safe"":false},{""name"":""d"",""parameters"":[{""name"":""amountIn"",""type"":""Integer""}],""returntype"":""Void"",""offset"":3039,""safe"":false},{""name"":""d0"",""parameters"":[],""returntype"":""Integer"",""offset"":3058,""safe"":false},{""name"":""d10"",""parameters"":[],""returntype"":""Void"",""offset"":3082,""safe"":false},{""name"":""d11"",""parameters"":[],""returntype"":""Void"",""offset"":3102,""safe"":false},{""name"":""d12"",""parameters"":[],""returntype"":""Void"",""offset"":3122,""safe"":false},{""name"":""d13"",""parameters"":[],""returntype"":""Void"",""offset"":3142,""safe"":false},{""name"":""d14"",""parameters"":[],""returntype"":""Void"",""offset"":3162,""safe"":false},{""name"":""d15"",""parameters"":[],""returntype"":""Void"",""offset"":3182,""safe"":false},{""name"":""d16"",""parameters"":[],""returntype"":""Void"",""offset"":3202,""safe"":false},{""name"":""d17"",""parameters"":[],""returntype"":""Void"",""offset"":3222,""safe"":false},{""name"":""d18"",""parameters"":[],""returntype"":""Void"",""offset"":3243,""safe"":false},{""name"":""d19"",""parameters"":[],""returntype"":""Void"",""offset"":3264,""safe"":false},{""name"":""d20"",""parameters"":[],""returntype"":""Void"",""offset"":3285,""safe"":false},{""name"":""d21"",""parameters"":[],""returntype"":""Void"",""offset"":3306,""safe"":false},{""name"":""d22"",""parameters"":[],""returntype"":""Void"",""offset"":3327,""safe"":false},{""name"":""d23"",""parameters"":[],""returntype"":""Void"",""offset"":3348,""safe"":false},{""name"":""d24"",""parameters"":[],""returntype"":""Void"",""offset"":3369,""safe"":false},{""name"":""d25"",""parameters"":[],""returntype"":""Void"",""offset"":3390,""safe"":false},{""name"":""d26"",""parameters"":[],""returntype"":""Void"",""offset"":3411,""safe"":false},{""name"":""d27"",""parameters"":[],""returntype"":""Void"",""offset"":3432,""safe"":false},{""name"":""d28"",""parameters"":[],""returntype"":""Void"",""offset"":3453,""safe"":false},{""name"":""d29"",""parameters"":[],""returntype"":""Void"",""offset"":3474,""safe"":false},{""name"":""d30"",""parameters"":[],""returntype"":""Void"",""offset"":3495,""safe"":false},{""name"":""d31"",""parameters"":[],""returntype"":""Void"",""offset"":3516,""safe"":false},{""name"":""d32"",""parameters"":[],""returntype"":""Void"",""offset"":3537,""safe"":false},{""name"":""d33"",""parameters"":[],""returntype"":""Void"",""offset"":3558,""safe"":false},{""name"":""d34"",""parameters"":[],""returntype"":""Void"",""offset"":3579,""safe"":false},{""name"":""d35"",""parameters"":[],""returntype"":""Void"",""offset"":3600,""safe"":false},{""name"":""d36"",""parameters"":[],""returntype"":""Void"",""offset"":3621,""safe"":false},{""name"":""d37"",""parameters"":[],""returntype"":""Void"",""offset"":3642,""safe"":false},{""name"":""d38"",""parameters"":[],""returntype"":""Void"",""offset"":3663,""safe"":false},{""name"":""d39"",""parameters"":[],""returntype"":""Void"",""offset"":3684,""safe"":false},{""name"":""d40"",""parameters"":[],""returntype"":""Void"",""offset"":3705,""safe"":false},{""name"":""d41"",""parameters"":[],""returntype"":""Void"",""offset"":3726,""safe"":false},{""name"":""d42"",""parameters"":[],""returntype"":""Void"",""offset"":3747,""safe"":false},{""name"":""d43"",""parameters"":[],""returntype"":""Void"",""offset"":3768,""safe"":false},{""name"":""d44"",""parameters"":[],""returntype"":""Void"",""offset"":3789,""safe"":false},{""name"":""d45"",""parameters"":[],""returntype"":""Void"",""offset"":3810,""safe"":false},{""name"":""d46"",""parameters"":[],""returntype"":""Void"",""offset"":3831,""safe"":false},{""name"":""d47"",""parameters"":[],""returntype"":""Void"",""offset"":3852,""safe"":false},{""name"":""d48"",""parameters"":[],""returntype"":""Void"",""offset"":3873,""safe"":false},{""name"":""d49"",""parameters"":[],""returntype"":""Void"",""offset"":3894,""safe"":false},{""name"":""d50"",""parameters"":[],""returntype"":""Void"",""offset"":3915,""safe"":false},{""name"":""e"",""parameters"":[{""name"":""amountIn"",""type"":""Integer""}],""returntype"":""Void"",""offset"":3936,""safe"":false},{""name"":""e0"",""parameters"":[],""returntype"":""Integer"",""offset"":3955,""safe"":false},{""name"":""e10"",""parameters"":[],""returntype"":""Void"",""offset"":3979,""safe"":false},{""name"":""e11"",""parameters"":[],""returntype"":""Void"",""offset"":3999,""safe"":false},{""name"":""e12"",""parameters"":[],""returntype"":""Void"",""offset"":4019,""safe"":false},{""name"":""e13"",""parameters"":[],""returntype"":""Void"",""offset"":4039,""safe"":false},{""name"":""e14"",""parameters"":[],""returntype"":""Void"",""offset"":4059,""safe"":false},{""name"":""e15"",""parameters"":[],""returntype"":""Void"",""offset"":4079,""safe"":false},{""name"":""e16"",""parameters"":[],""returntype"":""Void"",""offset"":4099,""safe"":false},{""name"":""e17"",""parameters"":[],""returntype"":""Void"",""offset"":4119,""safe"":false},{""name"":""e18"",""parameters"":[],""returntype"":""Void"",""offset"":4140,""safe"":false},{""name"":""e19"",""parameters"":[],""returntype"":""Void"",""offset"":4161,""safe"":false},{""name"":""e20"",""parameters"":[],""returntype"":""Void"",""offset"":4182,""safe"":false},{""name"":""e21"",""parameters"":[],""returntype"":""Void"",""offset"":4203,""safe"":false},{""name"":""e22"",""parameters"":[],""returntype"":""Void"",""offset"":4224,""safe"":false},{""name"":""e23"",""parameters"":[],""returntype"":""Void"",""offset"":4245,""safe"":false},{""name"":""e24"",""parameters"":[],""returntype"":""Void"",""offset"":4266,""safe"":false},{""name"":""e25"",""parameters"":[],""returntype"":""Void"",""offset"":4287,""safe"":false},{""name"":""e26"",""parameters"":[],""returntype"":""Void"",""offset"":4308,""safe"":false},{""name"":""e27"",""parameters"":[],""returntype"":""Void"",""offset"":4329,""safe"":false},{""name"":""e28"",""parameters"":[],""returntype"":""Void"",""offset"":4350,""safe"":false},{""name"":""e29"",""parameters"":[],""returntype"":""Void"",""offset"":4371,""safe"":false},{""name"":""e30"",""parameters"":[],""returntype"":""Void"",""offset"":4392,""safe"":false},{""name"":""e31"",""parameters"":[],""returntype"":""Void"",""offset"":4413,""safe"":false},{""name"":""e32"",""parameters"":[],""returntype"":""Void"",""offset"":4434,""safe"":false},{""name"":""e33"",""parameters"":[],""returntype"":""Void"",""offset"":4455,""safe"":false},{""name"":""e34"",""parameters"":[],""returntype"":""Void"",""offset"":4476,""safe"":false},{""name"":""e35"",""parameters"":[],""returntype"":""Void"",""offset"":4497,""safe"":false},{""name"":""e36"",""parameters"":[],""returntype"":""Void"",""offset"":4518,""safe"":false},{""name"":""e37"",""parameters"":[],""returntype"":""Void"",""offset"":4539,""safe"":false},{""name"":""e38"",""parameters"":[],""returntype"":""Void"",""offset"":4560,""safe"":false},{""name"":""e39"",""parameters"":[],""returntype"":""Void"",""offset"":4581,""safe"":false},{""name"":""e40"",""parameters"":[],""returntype"":""Void"",""offset"":4602,""safe"":false},{""name"":""e41"",""parameters"":[],""returntype"":""Void"",""offset"":4623,""safe"":false},{""name"":""e42"",""parameters"":[],""returntype"":""Void"",""offset"":4644,""safe"":false},{""name"":""e43"",""parameters"":[],""returntype"":""Void"",""offset"":4665,""safe"":false},{""name"":""e44"",""parameters"":[],""returntype"":""Void"",""offset"":4686,""safe"":false},{""name"":""e45"",""parameters"":[],""returntype"":""Void"",""offset"":4707,""safe"":false},{""name"":""e46"",""parameters"":[],""returntype"":""Void"",""offset"":4728,""safe"":false},{""name"":""e47"",""parameters"":[],""returntype"":""Void"",""offset"":4749,""safe"":false},{""name"":""e48"",""parameters"":[],""returntype"":""Void"",""offset"":4770,""safe"":false},{""name"":""e49"",""parameters"":[],""returntype"":""Void"",""offset"":4791,""safe"":false},{""name"":""e50"",""parameters"":[],""returntype"":""Void"",""offset"":4812,""safe"":false},{""name"":""f"",""parameters"":[{""name"":""amountIn"",""type"":""Integer""}],""returntype"":""Void"",""offset"":4833,""safe"":false},{""name"":""f0"",""parameters"":[],""returntype"":""Integer"",""offset"":4852,""safe"":false},{""name"":""f10"",""parameters"":[],""returntype"":""Void"",""offset"":4876,""safe"":false},{""name"":""f11"",""parameters"":[],""returntype"":""Void"",""offset"":4896,""safe"":false},{""name"":""f12"",""parameters"":[],""returntype"":""Void"",""offset"":4916,""safe"":false},{""name"":""f13"",""parameters"":[],""returntype"":""Void"",""offset"":4936,""safe"":false},{""name"":""f14"",""parameters"":[],""returntype"":""Void"",""offset"":4956,""safe"":false},{""name"":""f15"",""parameters"":[],""returntype"":""Void"",""offset"":4976,""safe"":false},{""name"":""f16"",""parameters"":[],""returntype"":""Void"",""offset"":4996,""safe"":false},{""name"":""f17"",""parameters"":[],""returntype"":""Void"",""offset"":5016,""safe"":false},{""name"":""f18"",""parameters"":[],""returntype"":""Void"",""offset"":5037,""safe"":false},{""name"":""f19"",""parameters"":[],""returntype"":""Void"",""offset"":5058,""safe"":false},{""name"":""f20"",""parameters"":[],""returntype"":""Void"",""offset"":5079,""safe"":false},{""name"":""f21"",""parameters"":[],""returntype"":""Void"",""offset"":5100,""safe"":false},{""name"":""f22"",""parameters"":[],""returntype"":""Void"",""offset"":5121,""safe"":false},{""name"":""f23"",""parameters"":[],""returntype"":""Void"",""offset"":5142,""safe"":false},{""name"":""f24"",""parameters"":[],""returntype"":""Void"",""offset"":5163,""safe"":false},{""name"":""f25"",""parameters"":[],""returntype"":""Void"",""offset"":5184,""safe"":false},{""name"":""f26"",""parameters"":[],""returntype"":""Void"",""offset"":5205,""safe"":false},{""name"":""f27"",""parameters"":[],""returntype"":""Void"",""offset"":5226,""safe"":false},{""name"":""f28"",""parameters"":[],""returntype"":""Void"",""offset"":5247,""safe"":false},{""name"":""f29"",""parameters"":[],""returntype"":""Void"",""offset"":5268,""safe"":false},{""name"":""f30"",""parameters"":[],""returntype"":""Void"",""offset"":5289,""safe"":false},{""name"":""f31"",""parameters"":[],""returntype"":""Void"",""offset"":5310,""safe"":false},{""name"":""f32"",""parameters"":[],""returntype"":""Void"",""offset"":5331,""safe"":false},{""name"":""f33"",""parameters"":[],""returntype"":""Void"",""offset"":5352,""safe"":false},{""name"":""f34"",""parameters"":[],""returntype"":""Void"",""offset"":5373,""safe"":false},{""name"":""f35"",""parameters"":[],""returntype"":""Void"",""offset"":5394,""safe"":false},{""name"":""f36"",""parameters"":[],""returntype"":""Void"",""offset"":5415,""safe"":false},{""name"":""f37"",""parameters"":[],""returntype"":""Void"",""offset"":5436,""safe"":false},{""name"":""f38"",""parameters"":[],""returntype"":""Void"",""offset"":5457,""safe"":false},{""name"":""f39"",""parameters"":[],""returntype"":""Void"",""offset"":5478,""safe"":false},{""name"":""f40"",""parameters"":[],""returntype"":""Void"",""offset"":5499,""safe"":false},{""name"":""f41"",""parameters"":[],""returntype"":""Void"",""offset"":5520,""safe"":false},{""name"":""f42"",""parameters"":[],""returntype"":""Void"",""offset"":5541,""safe"":false},{""name"":""f43"",""parameters"":[],""returntype"":""Void"",""offset"":5562,""safe"":false},{""name"":""f44"",""parameters"":[],""returntype"":""Void"",""offset"":5583,""safe"":false},{""name"":""f45"",""parameters"":[],""returntype"":""Void"",""offset"":5604,""safe"":false},{""name"":""f46"",""parameters"":[],""returntype"":""Void"",""offset"":5625,""safe"":false},{""name"":""f47"",""parameters"":[],""returntype"":""Void"",""offset"":5646,""safe"":false},{""name"":""f48"",""parameters"":[],""returntype"":""Void"",""offset"":5667,""safe"":false},{""name"":""f49"",""parameters"":[],""returntype"":""Void"",""offset"":5688,""safe"":false},{""name"":""f50"",""parameters"":[],""returntype"":""Void"",""offset"":5709,""safe"":false},{""name"":""g"",""parameters"":[{""name"":""amountIn"",""type"":""Integer""}],""returntype"":""Void"",""offset"":5730,""safe"":false},{""name"":""g0"",""parameters"":[],""returntype"":""Integer"",""offset"":5749,""safe"":false},{""name"":""g10"",""parameters"":[],""returntype"":""Void"",""offset"":5773,""safe"":false},{""name"":""g11"",""parameters"":[],""returntype"":""Void"",""offset"":5793,""safe"":false},{""name"":""g12"",""parameters"":[],""returntype"":""Void"",""offset"":5813,""safe"":false},{""name"":""g13"",""parameters"":[],""returntype"":""Void"",""offset"":5833,""safe"":false},{""name"":""g14"",""parameters"":[],""returntype"":""Void"",""offset"":5853,""safe"":false},{""name"":""g15"",""parameters"":[],""returntype"":""Void"",""offset"":5873,""safe"":false},{""name"":""g16"",""parameters"":[],""returntype"":""Void"",""offset"":5893,""safe"":false},{""name"":""g17"",""parameters"":[],""returntype"":""Void"",""offset"":5913,""safe"":false},{""name"":""g18"",""parameters"":[],""returntype"":""Void"",""offset"":5934,""safe"":false},{""name"":""g19"",""parameters"":[],""returntype"":""Void"",""offset"":5955,""safe"":false},{""name"":""g20"",""parameters"":[],""returntype"":""Void"",""offset"":5976,""safe"":false},{""name"":""g21"",""parameters"":[],""returntype"":""Void"",""offset"":5997,""safe"":false},{""name"":""g22"",""parameters"":[],""returntype"":""Void"",""offset"":6018,""safe"":false},{""name"":""g23"",""parameters"":[],""returntype"":""Void"",""offset"":6039,""safe"":false},{""name"":""g24"",""parameters"":[],""returntype"":""Void"",""offset"":6060,""safe"":false},{""name"":""g25"",""parameters"":[],""returntype"":""Void"",""offset"":6081,""safe"":false},{""name"":""g26"",""parameters"":[],""returntype"":""Void"",""offset"":6102,""safe"":false},{""name"":""g27"",""parameters"":[],""returntype"":""Void"",""offset"":6123,""safe"":false},{""name"":""g28"",""parameters"":[],""returntype"":""Void"",""offset"":6144,""safe"":false},{""name"":""g29"",""parameters"":[],""returntype"":""Void"",""offset"":6165,""safe"":false},{""name"":""g30"",""parameters"":[],""returntype"":""Void"",""offset"":6186,""safe"":false},{""name"":""g31"",""parameters"":[],""returntype"":""Void"",""offset"":6207,""safe"":false},{""name"":""g32"",""parameters"":[],""returntype"":""Void"",""offset"":6228,""safe"":false},{""name"":""g33"",""parameters"":[],""returntype"":""Void"",""offset"":6249,""safe"":false},{""name"":""g34"",""parameters"":[],""returntype"":""Void"",""offset"":6270,""safe"":false},{""name"":""g35"",""parameters"":[],""returntype"":""Void"",""offset"":6291,""safe"":false},{""name"":""g36"",""parameters"":[],""returntype"":""Void"",""offset"":6312,""safe"":false},{""name"":""g37"",""parameters"":[],""returntype"":""Void"",""offset"":6333,""safe"":false},{""name"":""g38"",""parameters"":[],""returntype"":""Void"",""offset"":6354,""safe"":false},{""name"":""g39"",""parameters"":[],""returntype"":""Void"",""offset"":6375,""safe"":false},{""name"":""g40"",""parameters"":[],""returntype"":""Void"",""offset"":6396,""safe"":false},{""name"":""g41"",""parameters"":[],""returntype"":""Void"",""offset"":6417,""safe"":false},{""name"":""g42"",""parameters"":[],""returntype"":""Void"",""offset"":6438,""safe"":false},{""name"":""g43"",""parameters"":[],""returntype"":""Void"",""offset"":6459,""safe"":false},{""name"":""g44"",""parameters"":[],""returntype"":""Void"",""offset"":6480,""safe"":false},{""name"":""g45"",""parameters"":[],""returntype"":""Void"",""offset"":6501,""safe"":false},{""name"":""g46"",""parameters"":[],""returntype"":""Void"",""offset"":6522,""safe"":false},{""name"":""g47"",""parameters"":[],""returntype"":""Void"",""offset"":6543,""safe"":false},{""name"":""g48"",""parameters"":[],""returntype"":""Void"",""offset"":6564,""safe"":false},{""name"":""g49"",""parameters"":[],""returntype"":""Void"",""offset"":6585,""safe"":false},{""name"":""g50"",""parameters"":[],""returntype"":""Void"",""offset"":6606,""safe"":false},{""name"":""h"",""parameters"":[{""name"":""amountIn"",""type"":""Integer""}],""returntype"":""Void"",""offset"":6627,""safe"":false},{""name"":""h0"",""parameters"":[],""returntype"":""Integer"",""offset"":6646,""safe"":false},{""name"":""h10"",""parameters"":[],""returntype"":""Void"",""offset"":6670,""safe"":false},{""name"":""h11"",""parameters"":[],""returntype"":""Void"",""offset"":6690,""safe"":false},{""name"":""h12"",""parameters"":[],""returntype"":""Void"",""offset"":6710,""safe"":false},{""name"":""h13"",""parameters"":[],""returntype"":""Void"",""offset"":6730,""safe"":false},{""name"":""h14"",""parameters"":[],""returntype"":""Void"",""offset"":6750,""safe"":false},{""name"":""h15"",""parameters"":[],""returntype"":""Void"",""offset"":6770,""safe"":false},{""name"":""h16"",""parameters"":[],""returntype"":""Void"",""offset"":6790,""safe"":false},{""name"":""h17"",""parameters"":[],""returntype"":""Void"",""offset"":6810,""safe"":false},{""name"":""h18"",""parameters"":[],""returntype"":""Void"",""offset"":6831,""safe"":false},{""name"":""h19"",""parameters"":[],""returntype"":""Void"",""offset"":6852,""safe"":false},{""name"":""h20"",""parameters"":[],""returntype"":""Void"",""offset"":6873,""safe"":false},{""name"":""h21"",""parameters"":[],""returntype"":""Void"",""offset"":6894,""safe"":false},{""name"":""h22"",""parameters"":[],""returntype"":""Void"",""offset"":6915,""safe"":false},{""name"":""h23"",""parameters"":[],""returntype"":""Void"",""offset"":6936,""safe"":false},{""name"":""h24"",""parameters"":[],""returntype"":""Void"",""offset"":6957,""safe"":false},{""name"":""h25"",""parameters"":[],""returntype"":""Void"",""offset"":6978,""safe"":false},{""name"":""h26"",""parameters"":[],""returntype"":""Void"",""offset"":6999,""safe"":false},{""name"":""h27"",""parameters"":[],""returntype"":""Void"",""offset"":7020,""safe"":false},{""name"":""h28"",""parameters"":[],""returntype"":""Void"",""offset"":7041,""safe"":false},{""name"":""h29"",""parameters"":[],""returntype"":""Void"",""offset"":7062,""safe"":false},{""name"":""h30"",""parameters"":[],""returntype"":""Void"",""offset"":7083,""safe"":false},{""name"":""h31"",""parameters"":[],""returntype"":""Void"",""offset"":7104,""safe"":false},{""name"":""h32"",""parameters"":[],""returntype"":""Void"",""offset"":7125,""safe"":false},{""name"":""h33"",""parameters"":[],""returntype"":""Void"",""offset"":7146,""safe"":false},{""name"":""h34"",""parameters"":[],""returntype"":""Void"",""offset"":7167,""safe"":false},{""name"":""h35"",""parameters"":[],""returntype"":""Void"",""offset"":7188,""safe"":false},{""name"":""h36"",""parameters"":[],""returntype"":""Void"",""offset"":7209,""safe"":false},{""name"":""h37"",""parameters"":[],""returntype"":""Void"",""offset"":7230,""safe"":false},{""name"":""h38"",""parameters"":[],""returntype"":""Void"",""offset"":7251,""safe"":false},{""name"":""h39"",""parameters"":[],""returntype"":""Void"",""offset"":7272,""safe"":false},{""name"":""h40"",""parameters"":[],""returntype"":""Void"",""offset"":7293,""safe"":false},{""name"":""h41"",""parameters"":[],""returntype"":""Void"",""offset"":7314,""safe"":false},{""name"":""h42"",""parameters"":[],""returntype"":""Void"",""offset"":7335,""safe"":false},{""name"":""h43"",""parameters"":[],""returntype"":""Void"",""offset"":7356,""safe"":false},{""name"":""h44"",""parameters"":[],""returntype"":""Void"",""offset"":7377,""safe"":false},{""name"":""h45"",""parameters"":[],""returntype"":""Void"",""offset"":7398,""safe"":false},{""name"":""h46"",""parameters"":[],""returntype"":""Void"",""offset"":7419,""safe"":false},{""name"":""h47"",""parameters"":[],""returntype"":""Void"",""offset"":7440,""safe"":false},{""name"":""h48"",""parameters"":[],""returntype"":""Void"",""offset"":7461,""safe"":false},{""name"":""h49"",""parameters"":[],""returntype"":""Void"",""offset"":7482,""safe"":false},{""name"":""h50"",""parameters"":[],""returntype"":""Void"",""offset"":7503,""safe"":false},{""name"":""i"",""parameters"":[{""name"":""amountIn"",""type"":""Integer""}],""returntype"":""Void"",""offset"":7524,""safe"":false},{""name"":""i0"",""parameters"":[],""returntype"":""Integer"",""offset"":7545,""safe"":false},{""name"":""i10"",""parameters"":[],""returntype"":""Void"",""offset"":7571,""safe"":false},{""name"":""i11"",""parameters"":[],""returntype"":""Void"",""offset"":7593,""safe"":false},{""name"":""i12"",""parameters"":[],""returntype"":""Void"",""offset"":7615,""safe"":false},{""name"":""i13"",""parameters"":[],""returntype"":""Void"",""offset"":7637,""safe"":false},{""name"":""i14"",""parameters"":[],""returntype"":""Void"",""offset"":7659,""safe"":false},{""name"":""i15"",""parameters"":[],""returntype"":""Void"",""offset"":7681,""safe"":false},{""name"":""i16"",""parameters"":[],""returntype"":""Void"",""offset"":7703,""safe"":false},{""name"":""i17"",""parameters"":[],""returntype"":""Void"",""offset"":7725,""safe"":false},{""name"":""i18"",""parameters"":[],""returntype"":""Void"",""offset"":7748,""safe"":false},{""name"":""i19"",""parameters"":[],""returntype"":""Void"",""offset"":7771,""safe"":false},{""name"":""i20"",""parameters"":[],""returntype"":""Void"",""offset"":7794,""safe"":false},{""name"":""i21"",""parameters"":[],""returntype"":""Void"",""offset"":7817,""safe"":false},{""name"":""i22"",""parameters"":[],""returntype"":""Void"",""offset"":7840,""safe"":false},{""name"":""i23"",""parameters"":[],""returntype"":""Void"",""offset"":7863,""safe"":false},{""name"":""i24"",""parameters"":[],""returntype"":""Void"",""offset"":7886,""safe"":false},{""name"":""i25"",""parameters"":[],""returntype"":""Void"",""offset"":7909,""safe"":false},{""name"":""i26"",""parameters"":[],""returntype"":""Void"",""offset"":7932,""safe"":false},{""name"":""i27"",""parameters"":[],""returntype"":""Void"",""offset"":7955,""safe"":false},{""name"":""i28"",""parameters"":[],""returntype"":""Void"",""offset"":7978,""safe"":false},{""name"":""i29"",""parameters"":[],""returntype"":""Void"",""offset"":8001,""safe"":false},{""name"":""i30"",""parameters"":[],""returntype"":""Void"",""offset"":8024,""safe"":false},{""name"":""i31"",""parameters"":[],""returntype"":""Void"",""offset"":8047,""safe"":false},{""name"":""i32"",""parameters"":[],""returntype"":""Void"",""offset"":8070,""safe"":false},{""name"":""i33"",""parameters"":[],""returntype"":""Void"",""offset"":8093,""safe"":false},{""name"":""i34"",""parameters"":[],""returntype"":""Void"",""offset"":8116,""safe"":false},{""name"":""i35"",""parameters"":[],""returntype"":""Void"",""offset"":8139,""safe"":false},{""name"":""i36"",""parameters"":[],""returntype"":""Void"",""offset"":8162,""safe"":false},{""name"":""i37"",""parameters"":[],""returntype"":""Void"",""offset"":8185,""safe"":false},{""name"":""i38"",""parameters"":[],""returntype"":""Void"",""offset"":8208,""safe"":false},{""name"":""i39"",""parameters"":[],""returntype"":""Void"",""offset"":8231,""safe"":false},{""name"":""i40"",""parameters"":[],""returntype"":""Void"",""offset"":8254,""safe"":false},{""name"":""i41"",""parameters"":[],""returntype"":""Void"",""offset"":8277,""safe"":false},{""name"":""i42"",""parameters"":[],""returntype"":""Void"",""offset"":8300,""safe"":false},{""name"":""i43"",""parameters"":[],""returntype"":""Void"",""offset"":8323,""safe"":false},{""name"":""i44"",""parameters"":[],""returntype"":""Void"",""offset"":8346,""safe"":false},{""name"":""i45"",""parameters"":[],""returntype"":""Void"",""offset"":8369,""safe"":false},{""name"":""i46"",""parameters"":[],""returntype"":""Void"",""offset"":8392,""safe"":false},{""name"":""i47"",""parameters"":[],""returntype"":""Void"",""offset"":8415,""safe"":false},{""name"":""i48"",""parameters"":[],""returntype"":""Void"",""offset"":8438,""safe"":false},{""name"":""i49"",""parameters"":[],""returntype"":""Void"",""offset"":8461,""safe"":false},{""name"":""i50"",""parameters"":[],""returntype"":""Void"",""offset"":8484,""safe"":false},{""name"":""update"",""parameters"":[{""name"":""nefFile"",""type"":""ByteArray""},{""name"":""manifest"",""type"":""String""}],""returntype"":""Void"",""offset"":8511,""safe"":false},{""name"":""j"",""parameters"":[{""name"":""amountIn"",""type"":""Integer""}],""returntype"":""Void"",""offset"":8578,""safe"":false},{""name"":""j0"",""parameters"":[],""returntype"":""Integer"",""offset"":8599,""safe"":false},{""name"":""j10"",""parameters"":[],""returntype"":""Void"",""offset"":8625,""safe"":false},{""name"":""j11"",""parameters"":[],""returntype"":""Void"",""offset"":8647,""safe"":false},{""name"":""j12"",""parameters"":[],""returntype"":""Void"",""offset"":8669,""safe"":false},{""name"":""j13"",""parameters"":[],""returntype"":""Void"",""offset"":8691,""safe"":false},{""name"":""j14"",""parameters"":[],""returntype"":""Void"",""offset"":8713,""safe"":false},{""name"":""j15"",""parameters"":[],""returntype"":""Void"",""offset"":8735,""safe"":false},{""name"":""j16"",""parameters"":[],""returntype"":""Void"",""offset"":8757,""safe"":false},{""name"":""j17"",""parameters"":[],""returntype"":""Void"",""offset"":8779,""safe"":false},{""name"":""j18"",""parameters"":[],""returntype"":""Void"",""offset"":8802,""safe"":false},{""name"":""j19"",""parameters"":[],""returntype"":""Void"",""offset"":8825,""safe"":false},{""name"":""j20"",""parameters"":[],""returntype"":""Void"",""offset"":8848,""safe"":false},{""name"":""j21"",""parameters"":[],""returntype"":""Void"",""offset"":8871,""safe"":false},{""name"":""j22"",""parameters"":[],""returntype"":""Void"",""offset"":8894,""safe"":false},{""name"":""j23"",""parameters"":[],""returntype"":""Void"",""offset"":8917,""safe"":false},{""name"":""j24"",""parameters"":[],""returntype"":""Void"",""offset"":8940,""safe"":false},{""name"":""j25"",""parameters"":[],""returntype"":""Void"",""offset"":8963,""safe"":false},{""name"":""j26"",""parameters"":[],""returntype"":""Void"",""offset"":8986,""safe"":false},{""name"":""j27"",""parameters"":[],""returntype"":""Void"",""offset"":9009,""safe"":false},{""name"":""j28"",""parameters"":[],""returntype"":""Void"",""offset"":9032,""safe"":false},{""name"":""j29"",""parameters"":[],""returntype"":""Void"",""offset"":9055,""safe"":false},{""name"":""j30"",""parameters"":[],""returntype"":""Void"",""offset"":9078,""safe"":false},{""name"":""j31"",""parameters"":[],""returntype"":""Void"",""offset"":9101,""safe"":false},{""name"":""j32"",""parameters"":[],""returntype"":""Void"",""offset"":9124,""safe"":false},{""name"":""j33"",""parameters"":[],""returntype"":""Void"",""offset"":9147,""safe"":false},{""name"":""j34"",""parameters"":[],""returntype"":""Void"",""offset"":9170,""safe"":false},{""name"":""j35"",""parameters"":[],""returntype"":""Void"",""offset"":9193,""safe"":false},{""name"":""j36"",""parameters"":[],""returntype"":""Void"",""offset"":9216,""safe"":false},{""name"":""j37"",""parameters"":[],""returntype"":""Void"",""offset"":9239,""safe"":false},{""name"":""j38"",""parameters"":[],""returntype"":""Void"",""offset"":9262,""safe"":false},{""name"":""j39"",""parameters"":[],""returntype"":""Void"",""offset"":9285,""safe"":false},{""name"":""j40"",""parameters"":[],""returntype"":""Void"",""offset"":9308,""safe"":false},{""name"":""j41"",""parameters"":[],""returntype"":""Void"",""offset"":9331,""safe"":false},{""name"":""j42"",""parameters"":[],""returntype"":""Void"",""offset"":9354,""safe"":false},{""name"":""j43"",""parameters"":[],""returntype"":""Void"",""offset"":9377,""safe"":false},{""name"":""j44"",""parameters"":[],""returntype"":""Void"",""offset"":9400,""safe"":false},{""name"":""j45"",""parameters"":[],""returntype"":""Void"",""offset"":9423,""safe"":false},{""name"":""j46"",""parameters"":[],""returntype"":""Void"",""offset"":9446,""safe"":false},{""name"":""j47"",""parameters"":[],""returntype"":""Void"",""offset"":9469,""safe"":false},{""name"":""j48"",""parameters"":[],""returntype"":""Void"",""offset"":9492,""safe"":false},{""name"":""j49"",""parameters"":[],""returntype"":""Void"",""offset"":9515,""safe"":false},{""name"":""j50"",""parameters"":[],""returntype"":""Void"",""offset"":9538,""safe"":false},{""name"":""k"",""parameters"":[{""name"":""amountIn"",""type"":""Integer""}],""returntype"":""Void"",""offset"":9561,""safe"":false},{""name"":""k0"",""parameters"":[],""returntype"":""Integer"",""offset"":9601,""safe"":false},{""name"":""k10"",""parameters"":[],""returntype"":""Void"",""offset"":9646,""safe"":false},{""name"":""k11"",""parameters"":[],""returntype"":""Void"",""offset"":9687,""safe"":false},{""name"":""k12"",""parameters"":[],""returntype"":""Void"",""offset"":9728,""safe"":false},{""name"":""k13"",""parameters"":[],""returntype"":""Void"",""offset"":9769,""safe"":false},{""name"":""k14"",""parameters"":[],""returntype"":""Void"",""offset"":9810,""safe"":false},{""name"":""k15"",""parameters"":[],""returntype"":""Void"",""offset"":9851,""safe"":false},{""name"":""k16"",""parameters"":[],""returntype"":""Void"",""offset"":9892,""safe"":false},{""name"":""k17"",""parameters"":[],""returntype"":""Void"",""offset"":9933,""safe"":false},{""name"":""k18"",""parameters"":[],""returntype"":""Void"",""offset"":9975,""safe"":false},{""name"":""k19"",""parameters"":[],""returntype"":""Void"",""offset"":10017,""safe"":false},{""name"":""k20"",""parameters"":[],""returntype"":""Void"",""offset"":10059,""safe"":false},{""name"":""k21"",""parameters"":[],""returntype"":""Void"",""offset"":10101,""safe"":false},{""name"":""k22"",""parameters"":[],""returntype"":""Void"",""offset"":10143,""safe"":false},{""name"":""k23"",""parameters"":[],""returntype"":""Void"",""offset"":10185,""safe"":false},{""name"":""k24"",""parameters"":[],""returntype"":""Void"",""offset"":10227,""safe"":false},{""name"":""k25"",""parameters"":[],""returntype"":""Void"",""offset"":10269,""safe"":false},{""name"":""k26"",""parameters"":[],""returntype"":""Void"",""offset"":10311,""safe"":false},{""name"":""k27"",""parameters"":[],""returntype"":""Void"",""offset"":10353,""safe"":false},{""name"":""k28"",""parameters"":[],""returntype"":""Void"",""offset"":10395,""safe"":false},{""name"":""k29"",""parameters"":[],""returntype"":""Void"",""offset"":10437,""safe"":false},{""name"":""k30"",""parameters"":[],""returntype"":""Void"",""offset"":10479,""safe"":false},{""name"":""k31"",""parameters"":[],""returntype"":""Void"",""offset"":10521,""safe"":false},{""name"":""k32"",""parameters"":[],""returntype"":""Void"",""offset"":10563,""safe"":false},{""name"":""k33"",""parameters"":[],""returntype"":""Void"",""offset"":10605,""safe"":false},{""name"":""k34"",""parameters"":[],""returntype"":""Void"",""offset"":10647,""safe"":false},{""name"":""k35"",""parameters"":[],""returntype"":""Void"",""offset"":10689,""safe"":false},{""name"":""k36"",""parameters"":[],""returntype"":""Void"",""offset"":10731,""safe"":false},{""name"":""k37"",""parameters"":[],""returntype"":""Void"",""offset"":10773,""safe"":false},{""name"":""k38"",""parameters"":[],""returntype"":""Void"",""offset"":10815,""safe"":false},{""name"":""k39"",""parameters"":[],""returntype"":""Void"",""offset"":10857,""safe"":false},{""name"":""k40"",""parameters"":[],""returntype"":""Void"",""offset"":10899,""safe"":false},{""name"":""k41"",""parameters"":[],""returntype"":""Void"",""offset"":10941,""safe"":false},{""name"":""k42"",""parameters"":[],""returntype"":""Void"",""offset"":10983,""safe"":false},{""name"":""k43"",""parameters"":[],""returntype"":""Void"",""offset"":11025,""safe"":false},{""name"":""k44"",""parameters"":[],""returntype"":""Void"",""offset"":11067,""safe"":false},{""name"":""k45"",""parameters"":[],""returntype"":""Void"",""offset"":11109,""safe"":false},{""name"":""k46"",""parameters"":[],""returntype"":""Void"",""offset"":11151,""safe"":false},{""name"":""k47"",""parameters"":[],""returntype"":""Void"",""offset"":11193,""safe"":false},{""name"":""k48"",""parameters"":[],""returntype"":""Void"",""offset"":11235,""safe"":false},{""name"":""k49"",""parameters"":[],""returntype"":""Void"",""offset"":11277,""safe"":false},{""name"":""k50"",""parameters"":[],""returntype"":""Void"",""offset"":11319,""safe"":false},{""name"":""l"",""parameters"":[{""name"":""amountIn"",""type"":""Integer""}],""returntype"":""Void"",""offset"":11361,""safe"":false},{""name"":""l0"",""parameters"":[],""returntype"":""Integer"",""offset"":11401,""safe"":false},{""name"":""l10"",""parameters"":[],""returntype"":""Void"",""offset"":11446,""safe"":false},{""name"":""l11"",""parameters"":[],""returntype"":""Void"",""offset"":11487,""safe"":false},{""name"":""l12"",""parameters"":[],""returntype"":""Void"",""offset"":11528,""safe"":false},{""name"":""l13"",""parameters"":[],""returntype"":""Void"",""offset"":11569,""safe"":false},{""name"":""l14"",""parameters"":[],""returntype"":""Void"",""offset"":11610,""safe"":false},{""name"":""l15"",""parameters"":[],""returntype"":""Void"",""offset"":11651,""safe"":false},{""name"":""l16"",""parameters"":[],""returntype"":""Void"",""offset"":11692,""safe"":false},{""name"":""l17"",""parameters"":[],""returntype"":""Void"",""offset"":11733,""safe"":false},{""name"":""l18"",""parameters"":[],""returntype"":""Void"",""offset"":11775,""safe"":false},{""name"":""l19"",""parameters"":[],""returntype"":""Void"",""offset"":11817,""safe"":false},{""name"":""l20"",""parameters"":[],""returntype"":""Void"",""offset"":11859,""safe"":false},{""name"":""l21"",""parameters"":[],""returntype"":""Void"",""offset"":11901,""safe"":false},{""name"":""l22"",""parameters"":[],""returntype"":""Void"",""offset"":11943,""safe"":false},{""name"":""l23"",""parameters"":[],""returntype"":""Void"",""offset"":11985,""safe"":false},{""name"":""l24"",""parameters"":[],""returntype"":""Void"",""offset"":12027,""safe"":false},{""name"":""l25"",""parameters"":[],""returntype"":""Void"",""offset"":12069,""safe"":false},{""name"":""l26"",""parameters"":[],""returntype"":""Void"",""offset"":12111,""safe"":false},{""name"":""l27"",""parameters"":[],""returntype"":""Void"",""offset"":12153,""safe"":false},{""name"":""l28"",""parameters"":[],""returntype"":""Void"",""offset"":12195,""safe"":false},{""name"":""l29"",""parameters"":[],""returntype"":""Void"",""offset"":12237,""safe"":false},{""name"":""l30"",""parameters"":[],""returntype"":""Void"",""offset"":12279,""safe"":false},{""name"":""l31"",""parameters"":[],""returntype"":""Void"",""offset"":12321,""safe"":false},{""name"":""l32"",""parameters"":[],""returntype"":""Void"",""offset"":12363,""safe"":false},{""name"":""l33"",""parameters"":[],""returntype"":""Void"",""offset"":12405,""safe"":false},{""name"":""l34"",""parameters"":[],""returntype"":""Void"",""offset"":12447,""safe"":false},{""name"":""l35"",""parameters"":[],""returntype"":""Void"",""offset"":12489,""safe"":false},{""name"":""l36"",""parameters"":[],""returntype"":""Void"",""offset"":12531,""safe"":false},{""name"":""l37"",""parameters"":[],""returntype"":""Void"",""offset"":12573,""safe"":false},{""name"":""l38"",""parameters"":[],""returntype"":""Void"",""offset"":12615,""safe"":false},{""name"":""l39"",""parameters"":[],""returntype"":""Void"",""offset"":12657,""safe"":false},{""name"":""l40"",""parameters"":[],""returntype"":""Void"",""offset"":12699,""safe"":false},{""name"":""l41"",""parameters"":[],""returntype"":""Void"",""offset"":12741,""safe"":false},{""name"":""l42"",""parameters"":[],""returntype"":""Void"",""offset"":12783,""safe"":false},{""name"":""l43"",""parameters"":[],""returntype"":""Void"",""offset"":12825,""safe"":false},{""name"":""l44"",""parameters"":[],""returntype"":""Void"",""offset"":12867,""safe"":false},{""name"":""l45"",""parameters"":[],""returntype"":""Void"",""offset"":12909,""safe"":false},{""name"":""l46"",""parameters"":[],""returntype"":""Void"",""offset"":12951,""safe"":false},{""name"":""l47"",""parameters"":[],""returntype"":""Void"",""offset"":12993,""safe"":false},{""name"":""l48"",""parameters"":[],""returntype"":""Void"",""offset"":13035,""safe"":false},{""name"":""l49"",""parameters"":[],""returntype"":""Void"",""offset"":13077,""safe"":false},{""name"":""l50"",""parameters"":[],""returntype"":""Void"",""offset"":13119,""safe"":false},{""name"":""m"",""parameters"":[{""name"":""amountIn"",""type"":""Integer""}],""returntype"":""Void"",""offset"":13161,""safe"":false},{""name"":""m0"",""parameters"":[],""returntype"":""Integer"",""offset"":13181,""safe"":false},{""name"":""m10"",""parameters"":[],""returntype"":""Void"",""offset"":13206,""safe"":false},{""name"":""m11"",""parameters"":[],""returntype"":""Void"",""offset"":13227,""safe"":false},{""name"":""m12"",""parameters"":[],""returntype"":""Void"",""offset"":13248,""safe"":false},{""name"":""m13"",""parameters"":[],""returntype"":""Void"",""offset"":13269,""safe"":false},{""name"":""m14"",""parameters"":[],""returntype"":""Void"",""offset"":13290,""safe"":false},{""name"":""m15"",""parameters"":[],""returntype"":""Void"",""offset"":13311,""safe"":false},{""name"":""m16"",""parameters"":[],""returntype"":""Void"",""offset"":13332,""safe"":false},{""name"":""m17"",""parameters"":[],""returntype"":""Void"",""offset"":13353,""safe"":false},{""name"":""m18"",""parameters"":[],""returntype"":""Void"",""offset"":13375,""safe"":false},{""name"":""m19"",""parameters"":[],""returntype"":""Void"",""offset"":13397,""safe"":false},{""name"":""m20"",""parameters"":[],""returntype"":""Void"",""offset"":13419,""safe"":false},{""name"":""m21"",""parameters"":[],""returntype"":""Void"",""offset"":13441,""safe"":false},{""name"":""m22"",""parameters"":[],""returntype"":""Void"",""offset"":13463,""safe"":false},{""name"":""m23"",""parameters"":[],""returntype"":""Void"",""offset"":13485,""safe"":false},{""name"":""m24"",""parameters"":[],""returntype"":""Void"",""offset"":13507,""safe"":false},{""name"":""m25"",""parameters"":[],""returntype"":""Void"",""offset"":13529,""safe"":false},{""name"":""m26"",""parameters"":[],""returntype"":""Void"",""offset"":13551,""safe"":false},{""name"":""m27"",""parameters"":[],""returntype"":""Void"",""offset"":13573,""safe"":false},{""name"":""m28"",""parameters"":[],""returntype"":""Void"",""offset"":13595,""safe"":false},{""name"":""m29"",""parameters"":[],""returntype"":""Void"",""offset"":13617,""safe"":false},{""name"":""m30"",""parameters"":[],""returntype"":""Void"",""offset"":13639,""safe"":false},{""name"":""m31"",""parameters"":[],""returntype"":""Void"",""offset"":13661,""safe"":false},{""name"":""m32"",""parameters"":[],""returntype"":""Void"",""offset"":13683,""safe"":false},{""name"":""m33"",""parameters"":[],""returntype"":""Void"",""offset"":13705,""safe"":false},{""name"":""m34"",""parameters"":[],""returntype"":""Void"",""offset"":13727,""safe"":false},{""name"":""m35"",""parameters"":[],""returntype"":""Void"",""offset"":13749,""safe"":false},{""name"":""m36"",""parameters"":[],""returntype"":""Void"",""offset"":13771,""safe"":false},{""name"":""m37"",""parameters"":[],""returntype"":""Void"",""offset"":13793,""safe"":false},{""name"":""m38"",""parameters"":[],""returntype"":""Void"",""offset"":13815,""safe"":false},{""name"":""m39"",""parameters"":[],""returntype"":""Void"",""offset"":13837,""safe"":false},{""name"":""m40"",""parameters"":[],""returntype"":""Void"",""offset"":13859,""safe"":false},{""name"":""m41"",""parameters"":[],""returntype"":""Void"",""offset"":13881,""safe"":false},{""name"":""m42"",""parameters"":[],""returntype"":""Void"",""offset"":13903,""safe"":false},{""name"":""m43"",""parameters"":[],""returntype"":""Void"",""offset"":13925,""safe"":false},{""name"":""m44"",""parameters"":[],""returntype"":""Void"",""offset"":13947,""safe"":false},{""name"":""m45"",""parameters"":[],""returntype"":""Void"",""offset"":13969,""safe"":false},{""name"":""m46"",""parameters"":[],""returntype"":""Void"",""offset"":13991,""safe"":false},{""name"":""m47"",""parameters"":[],""returntype"":""Void"",""offset"":14013,""safe"":false},{""name"":""m48"",""parameters"":[],""returntype"":""Void"",""offset"":14035,""safe"":false},{""name"":""m49"",""parameters"":[],""returntype"":""Void"",""offset"":14057,""safe"":false},{""name"":""m50"",""parameters"":[],""returntype"":""Void"",""offset"":14079,""safe"":false},{""name"":""n"",""parameters"":[{""name"":""amountIn"",""type"":""Integer""}],""returntype"":""Void"",""offset"":14101,""safe"":false},{""name"":""n0"",""parameters"":[],""returntype"":""Integer"",""offset"":14121,""safe"":false},{""name"":""n10"",""parameters"":[],""returntype"":""Void"",""offset"":14146,""safe"":false},{""name"":""n11"",""parameters"":[],""returntype"":""Void"",""offset"":14167,""safe"":false},{""name"":""n12"",""parameters"":[],""returntype"":""Void"",""offset"":14188,""safe"":false},{""name"":""n13"",""parameters"":[],""returntype"":""Void"",""offset"":14209,""safe"":false},{""name"":""n14"",""parameters"":[],""returntype"":""Void"",""offset"":14230,""safe"":false},{""name"":""n15"",""parameters"":[],""returntype"":""Void"",""offset"":14251,""safe"":false},{""name"":""n16"",""parameters"":[],""returntype"":""Void"",""offset"":14272,""safe"":false},{""name"":""n17"",""parameters"":[],""returntype"":""Void"",""offset"":14293,""safe"":false},{""name"":""n18"",""parameters"":[],""returntype"":""Void"",""offset"":14315,""safe"":false},{""name"":""n19"",""parameters"":[],""returntype"":""Void"",""offset"":14337,""safe"":false},{""name"":""n20"",""parameters"":[],""returntype"":""Void"",""offset"":14359,""safe"":false},{""name"":""n21"",""parameters"":[],""returntype"":""Void"",""offset"":14381,""safe"":false},{""name"":""n22"",""parameters"":[],""returntype"":""Void"",""offset"":14403,""safe"":false},{""name"":""n23"",""parameters"":[],""returntype"":""Void"",""offset"":14425,""safe"":false},{""name"":""n24"",""parameters"":[],""returntype"":""Void"",""offset"":14447,""safe"":false},{""name"":""n25"",""parameters"":[],""returntype"":""Void"",""offset"":14469,""safe"":false},{""name"":""n26"",""parameters"":[],""returntype"":""Void"",""offset"":14491,""safe"":false},{""name"":""n27"",""parameters"":[],""returntype"":""Void"",""offset"":14513,""safe"":false},{""name"":""n28"",""parameters"":[],""returntype"":""Void"",""offset"":14535,""safe"":false},{""name"":""n29"",""parameters"":[],""returntype"":""Void"",""offset"":14557,""safe"":false},{""name"":""n30"",""parameters"":[],""returntype"":""Void"",""offset"":14579,""safe"":false},{""name"":""n31"",""parameters"":[],""returntype"":""Void"",""offset"":14601,""safe"":false},{""name"":""n32"",""parameters"":[],""returntype"":""Void"",""offset"":14623,""safe"":false},{""name"":""n33"",""parameters"":[],""returntype"":""Void"",""offset"":14645,""safe"":false},{""name"":""n34"",""parameters"":[],""returntype"":""Void"",""offset"":14667,""safe"":false},{""name"":""n35"",""parameters"":[],""returntype"":""Void"",""offset"":14689,""safe"":false},{""name"":""n36"",""parameters"":[],""returntype"":""Void"",""offset"":14711,""safe"":false},{""name"":""n37"",""parameters"":[],""returntype"":""Void"",""offset"":14733,""safe"":false},{""name"":""n38"",""parameters"":[],""returntype"":""Void"",""offset"":14755,""safe"":false},{""name"":""n39"",""parameters"":[],""returntype"":""Void"",""offset"":14777,""safe"":false},{""name"":""n40"",""parameters"":[],""returntype"":""Void"",""offset"":14799,""safe"":false},{""name"":""n41"",""parameters"":[],""returntype"":""Void"",""offset"":14821,""safe"":false},{""name"":""n42"",""parameters"":[],""returntype"":""Void"",""offset"":14843,""safe"":false},{""name"":""n43"",""parameters"":[],""returntype"":""Void"",""offset"":14865,""safe"":false},{""name"":""n44"",""parameters"":[],""returntype"":""Void"",""offset"":14887,""safe"":false},{""name"":""n45"",""parameters"":[],""returntype"":""Void"",""offset"":14909,""safe"":false},{""name"":""n46"",""parameters"":[],""returntype"":""Void"",""offset"":14931,""safe"":false},{""name"":""n47"",""parameters"":[],""returntype"":""Void"",""offset"":14953,""safe"":false},{""name"":""n48"",""parameters"":[],""returntype"":""Void"",""offset"":14975,""safe"":false},{""name"":""n49"",""parameters"":[],""returntype"":""Void"",""offset"":14997,""safe"":false},{""name"":""n50"",""parameters"":[],""returntype"":""Void"",""offset"":15019,""safe"":false},{""name"":""_initialize"",""parameters"":[],""returntype"":""Void"",""offset"":15041,""safe"":false}],""events"":[]},""permissions"":[{""contract"":""*"",""methods"":""*""}],""trusts"":[],""extra"":{""Author"":""Test"",""Email"":""Test@Test"",""Description"":""This is a Test Contract""}}"; + var manifest = ContractManifest.Parse(json); + + var counter = new ReferenceCounter(); + var item = manifest.ToStackItem(counter); + var data = BinarySerializer.Serialize(item, 1024 * 1024, 4096); + + Assert.ThrowsException(() => BinarySerializer.Deserialize(data, ExecutionEngineLimits.Default, counter)); + Assert.ThrowsException(() => BinarySerializer.Serialize(item, 1024 * 1024, 2048)); + + item = BinarySerializer.Deserialize(data, ExecutionEngineLimits.Default with { MaxStackSize = 4096 }, counter); + var copy = item.ToInteroperable(); + + Assert.AreEqual(manifest.ToJson().ToString(false), copy.ToJson().ToString(false)); + } + [TestMethod] public void ParseFromJson_Default() { @@ -20,7 +40,7 @@ public void ParseFromJson_Default() Assert.AreEqual(manifest.ToJson().ToString(), json); Assert.AreEqual(manifest.ToJson().ToString(), TestUtils.CreateDefaultManifest().ToJson().ToString()); - Assert.IsTrue(manifest.IsValid(UInt160.Zero)); + Assert.IsTrue(manifest.IsValid(ExecutionEngineLimits.Default, UInt160.Zero)); } [TestMethod] @@ -56,7 +76,6 @@ public void ParseFromJson_SafeMethods() [TestMethod] public void ParseFromJson_Trust() { - ReferenceCounter referenceCounter = new ReferenceCounter(); var json = @"{""name"":""testManifest"",""groups"":[],""features"":{},""supportedstandards"":[],""abi"":{""methods"":[{""name"":""testMethod"",""parameters"":[],""returntype"":""Void"",""offset"":0,""safe"":true}],""events"":[]},""permissions"":[{""contract"":""*"",""methods"":""*""}],""trusts"":[""0x0000000000000000000000000000000000000001"",""*""],""extra"":null}"; var manifest = ContractManifest.Parse(json); Assert.AreEqual(manifest.ToJson().ToString(), json); @@ -65,6 +84,23 @@ public void ParseFromJson_Trust() Assert.AreEqual(manifest.ToJson().ToString(), check.ToJson().ToString()); } + [TestMethod] + public void ToInteroperable_Trust() + { + var json = @"{""name"":""CallOracleContract-6"",""groups"":[],""features"":{},""supportedstandards"":[],""abi"":{""methods"":[{""name"":""request"",""parameters"":[{""name"":""url"",""type"":""String""},{""name"":""filter"",""type"":""String""},{""name"":""gasForResponse"",""type"":""Integer""}],""returntype"":""Void"",""offset"":0,""safe"":false},{""name"":""callback"",""parameters"":[{""name"":""url"",""type"":""String""},{""name"":""userData"",""type"":""Any""},{""name"":""responseCode"",""type"":""Integer""},{""name"":""response"",""type"":""ByteArray""}],""returntype"":""Void"",""offset"":86,""safe"":false},{""name"":""getStoredUrl"",""parameters"":[],""returntype"":""String"",""offset"":129,""safe"":false},{""name"":""getStoredResponseCode"",""parameters"":[],""returntype"":""Integer"",""offset"":142,""safe"":false},{""name"":""getStoredResponse"",""parameters"":[],""returntype"":""ByteArray"",""offset"":165,""safe"":false}],""events"":[]},""permissions"":[{""contract"":""0xfe924b7cfe89ddd271abaf7210a80a7e11178758"",""methods"":""*""},{""contract"":""*"",""methods"":""*""}],""trusts"":[""0xfe924b7cfe89ddd271abaf7210a80a7e11178758"",""*""],""extra"":{}}"; + var manifest = ContractManifest.Parse(json); + var s = (VM.Types.Struct)manifest.ToStackItem(new ReferenceCounter()); + manifest = s.ToInteroperable(); + + Assert.IsFalse(manifest.Permissions[0].Contract.IsWildcard); + Assert.IsTrue(manifest.Permissions[0].Methods.IsWildcard); + Assert.IsTrue(manifest.Permissions[1].Contract.IsWildcard); + Assert.IsTrue(manifest.Permissions[1].Methods.IsWildcard); + + Assert.IsFalse(manifest.Trusts[0].IsWildcard); + Assert.IsTrue(manifest.Trusts[1].IsWildcard); + } + [TestMethod] public void ParseFromJson_Groups() { diff --git a/tests/Neo.UnitTests/SmartContract/Manifest/UT_ContractPermission.cs b/tests/Neo.UnitTests/SmartContract/Manifest/UT_ContractPermission.cs index 25f3c36720..18ba983751 100644 --- a/tests/Neo.UnitTests/SmartContract/Manifest/UT_ContractPermission.cs +++ b/tests/Neo.UnitTests/SmartContract/Manifest/UT_ContractPermission.cs @@ -2,6 +2,7 @@ using Neo.Cryptography.ECC; using Neo.SmartContract; using Neo.SmartContract.Manifest; +using Neo.VM.Types; using System; namespace Neo.UnitTests.SmartContract.Manifest @@ -9,6 +10,32 @@ namespace Neo.UnitTests.SmartContract.Manifest [TestClass] public class UT_ContractPermission { + [TestMethod] + public void TestDeserialize() + { + // null + ContractPermission contractPermission = ContractPermission.DefaultPermission; + Struct s = (Struct)contractPermission.ToStackItem(new VM.ReferenceCounter()); + + contractPermission = s.ToInteroperable(); + Assert.IsTrue(contractPermission.Contract.IsWildcard); + Assert.IsTrue(contractPermission.Methods.IsWildcard); + + // not null + contractPermission = new ContractPermission() + { + Contract = ContractPermissionDescriptor.Create(UInt160.Zero), + Methods = WildcardContainer.Create("test") + }; + s = (Struct)contractPermission.ToStackItem(new VM.ReferenceCounter()); + + contractPermission = s.ToInteroperable(); + Assert.IsFalse(contractPermission.Contract.IsWildcard); + Assert.IsFalse(contractPermission.Methods.IsWildcard); + Assert.AreEqual(UInt160.Zero, contractPermission.Contract.Hash); + Assert.AreEqual("test", contractPermission.Methods[0]); + } + [TestMethod] public void TestIsAllowed() { diff --git a/tests/Neo.UnitTests/SmartContract/Native/UT_NeoToken.cs b/tests/Neo.UnitTests/SmartContract/Native/UT_NeoToken.cs index ee1ee4753e..7e8aff59fb 100644 --- a/tests/Neo.UnitTests/SmartContract/Native/UT_NeoToken.cs +++ b/tests/Neo.UnitTests/SmartContract/Native/UT_NeoToken.cs @@ -771,7 +771,7 @@ public void TestClaimGas() })); cachedCommittee.Add((member, 200 * 10000)); } - snapshot.GetOrAdd(new KeyBuilder(NativeContract.NEO.Id, 14), () => new StorageItem()).Value = BinarySerializer.Serialize(cachedCommittee.ToStackItem(null), 4096); + snapshot.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()); item.Value = ((BigInteger)2100 * 10000L).ToByteArray(); diff --git a/tests/Neo.UnitTests/SmartContract/UT_BinarySerializer.cs b/tests/Neo.UnitTests/SmartContract/UT_BinarySerializer.cs index b3f30e0cee..c8182bc82b 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_BinarySerializer.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_BinarySerializer.cs @@ -13,36 +13,34 @@ namespace Neo.UnitTests.SmartContract [TestClass] public class UT_BinarySerializer { - private const int MaxItemSize = 1024 * 1024; - [TestMethod] public void TestSerialize() { - byte[] result1 = BinarySerializer.Serialize(new byte[5], MaxItemSize); + byte[] result1 = BinarySerializer.Serialize(new byte[5], ExecutionEngineLimits.Default); byte[] expectedArray1 = new byte[] { 0x28, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00 }; Assert.AreEqual(Encoding.Default.GetString(expectedArray1), Encoding.Default.GetString(result1)); - byte[] result2 = BinarySerializer.Serialize(true, MaxItemSize); + byte[] result2 = BinarySerializer.Serialize(true, ExecutionEngineLimits.Default); byte[] expectedArray2 = new byte[] { 0x20, 0x01 }; Assert.AreEqual(Encoding.Default.GetString(expectedArray2), Encoding.Default.GetString(result2)); - byte[] result3 = BinarySerializer.Serialize(1, MaxItemSize); + byte[] result3 = BinarySerializer.Serialize(1, ExecutionEngineLimits.Default); byte[] expectedArray3 = new byte[] { 0x21, 0x01, 0x01 }; Assert.AreEqual(Encoding.Default.GetString(expectedArray3), Encoding.Default.GetString(result3)); StackItem stackItem4 = new InteropInterface(new object()); - Action action4 = () => BinarySerializer.Serialize(stackItem4, MaxItemSize); + Action action4 = () => BinarySerializer.Serialize(stackItem4, ExecutionEngineLimits.Default); action4.Should().Throw(); List list6 = new List { 1 }; StackItem stackItem62 = new VM.Types.Array(list6); - byte[] result6 = BinarySerializer.Serialize(stackItem62, MaxItemSize); + byte[] result6 = BinarySerializer.Serialize(stackItem62, ExecutionEngineLimits.Default); byte[] expectedArray6 = new byte[] { 0x40,0x01,0x21,0x01,0x01 }; @@ -50,14 +48,14 @@ public void TestSerialize() List list7 = new List { 1 }; StackItem stackItem72 = new Struct(list7); - byte[] result7 = BinarySerializer.Serialize(stackItem72, MaxItemSize); + byte[] result7 = BinarySerializer.Serialize(stackItem72, ExecutionEngineLimits.Default); byte[] expectedArray7 = new byte[] { 0x41,0x01,0x21,0x01,0x01 }; Assert.AreEqual(Encoding.Default.GetString(expectedArray7), Encoding.Default.GetString(result7)); StackItem stackItem82 = new Map { [2] = 1 }; - byte[] result8 = BinarySerializer.Serialize(stackItem82, MaxItemSize); + byte[] result8 = BinarySerializer.Serialize(stackItem82, ExecutionEngineLimits.Default); byte[] expectedArray8 = new byte[] { 0x48,0x01,0x21,0x01,0x02,0x21,0x01,0x01 }; @@ -65,12 +63,12 @@ public void TestSerialize() Map stackItem91 = new Map(); stackItem91[1] = stackItem91; - Action action9 = () => BinarySerializer.Serialize(stackItem91, MaxItemSize); + Action action9 = () => BinarySerializer.Serialize(stackItem91, ExecutionEngineLimits.Default); action9.Should().Throw(); VM.Types.Array stackItem10 = new VM.Types.Array(); stackItem10.Add(stackItem10); - Action action10 = () => BinarySerializer.Serialize(stackItem10, MaxItemSize); + Action action10 = () => BinarySerializer.Serialize(stackItem10, ExecutionEngineLimits.Default); action10.Should().Throw(); } @@ -78,41 +76,41 @@ public void TestSerialize() public void TestDeserializeStackItem() { StackItem stackItem1 = new ByteString(new byte[5]); - byte[] byteArray1 = BinarySerializer.Serialize(stackItem1, MaxItemSize); + byte[] byteArray1 = BinarySerializer.Serialize(stackItem1, ExecutionEngineLimits.Default); StackItem result1 = BinarySerializer.Deserialize(byteArray1, ExecutionEngineLimits.Default); Assert.AreEqual(stackItem1, result1); StackItem stackItem2 = StackItem.True; - byte[] byteArray2 = BinarySerializer.Serialize(stackItem2, MaxItemSize); + byte[] byteArray2 = BinarySerializer.Serialize(stackItem2, ExecutionEngineLimits.Default); StackItem result2 = BinarySerializer.Deserialize(byteArray2, ExecutionEngineLimits.Default); Assert.AreEqual(stackItem2, result2); StackItem stackItem3 = new Integer(1); - byte[] byteArray3 = BinarySerializer.Serialize(stackItem3, MaxItemSize); + byte[] byteArray3 = BinarySerializer.Serialize(stackItem3, ExecutionEngineLimits.Default); StackItem result3 = BinarySerializer.Deserialize(byteArray3, ExecutionEngineLimits.Default); Assert.AreEqual(stackItem3, result3); - byte[] byteArray4 = BinarySerializer.Serialize(1, MaxItemSize); + byte[] byteArray4 = BinarySerializer.Serialize(1, ExecutionEngineLimits.Default); byteArray4[0] = 0x40; Action action4 = () => BinarySerializer.Deserialize(byteArray4, ExecutionEngineLimits.Default); action4.Should().Throw(); List list5 = new List { 1 }; StackItem stackItem52 = new VM.Types.Array(list5); - byte[] byteArray5 = BinarySerializer.Serialize(stackItem52, MaxItemSize); + byte[] byteArray5 = BinarySerializer.Serialize(stackItem52, ExecutionEngineLimits.Default); StackItem result5 = BinarySerializer.Deserialize(byteArray5, ExecutionEngineLimits.Default); Assert.AreEqual(((VM.Types.Array)stackItem52).Count, ((VM.Types.Array)result5).Count); Assert.AreEqual(((VM.Types.Array)stackItem52).GetEnumerator().Current, ((VM.Types.Array)result5).GetEnumerator().Current); List list6 = new List { 1 }; StackItem stackItem62 = new Struct(list6); - byte[] byteArray6 = BinarySerializer.Serialize(stackItem62, MaxItemSize); + byte[] byteArray6 = BinarySerializer.Serialize(stackItem62, ExecutionEngineLimits.Default); StackItem result6 = BinarySerializer.Deserialize(byteArray6, ExecutionEngineLimits.Default); Assert.AreEqual(((Struct)stackItem62).Count, ((Struct)result6).Count); Assert.AreEqual(((Struct)stackItem62).GetEnumerator().Current, ((Struct)result6).GetEnumerator().Current); StackItem stackItem72 = new Map { [2] = 1 }; - byte[] byteArray7 = BinarySerializer.Serialize(stackItem72, MaxItemSize); + byte[] byteArray7 = BinarySerializer.Serialize(stackItem72, ExecutionEngineLimits.Default); StackItem result7 = BinarySerializer.Deserialize(byteArray7, ExecutionEngineLimits.Default); Assert.AreEqual(((Map)stackItem72).Count, ((Map)result7).Count); CollectionAssert.AreEqual(((Map)stackItem72).Keys.ToArray(), ((Map)result7).Keys.ToArray()); From 1ae6a13f8a269d8aecbf0f686330d56db72accfc Mon Sep 17 00:00:00 2001 From: Jimmy Date: Fri, 10 Nov 2023 19:29:10 +0800 Subject: [PATCH 018/168] fix ut (#2959) --- tests/Neo.UnitTests/SmartContract/UT_InteropService.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/Neo.UnitTests/SmartContract/UT_InteropService.cs b/tests/Neo.UnitTests/SmartContract/UT_InteropService.cs index 083f884636..12b49c91e3 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_InteropService.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_InteropService.cs @@ -311,7 +311,6 @@ public void TestRuntime_CheckWitness_Null_ScriptContainer() var engine = GetEngine(); engine.CheckWitness(pubkey.EncodePoint(true)).Should().BeFalse(); - engine.CheckWitness(pubkey.EncodePoint(true)).Should().BeFalse(); } [TestMethod] From 61a066583eef53c8eb7b770dcc3deb0305ab11db Mon Sep 17 00:00:00 2001 From: Owen Zhang <38493437+superboyiii@users.noreply.github.com> Date: Thu, 16 Nov 2023 15:33:56 +0800 Subject: [PATCH 019/168] 3.6.2 (#2962) * v3.6.2 * Use last neo.vm --------- Co-authored-by: Shargon --- src/Directory.Build.props | 2 +- src/Neo/Neo.csproj | 4 ++-- tests/Neo.Json.UnitTests/Neo.Json.UnitTests.csproj | 4 ++++ tests/Neo.UnitTests/Neo.UnitTests.csproj | 10 +++++++--- 4 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 2e3fbc31b0..49b51f1691 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -3,7 +3,7 @@ 2015-2023 The Neo Project - 3.6.0 + 3.6.2 The Neo Project net7.0 https://github.com/neo-project/neo diff --git a/src/Neo/Neo.csproj b/src/Neo/Neo.csproj index c6919a3371..31026ce74f 100644 --- a/src/Neo/Neo.csproj +++ b/src/Neo/Neo.csproj @@ -10,10 +10,10 @@ - + - + diff --git a/tests/Neo.Json.UnitTests/Neo.Json.UnitTests.csproj b/tests/Neo.Json.UnitTests/Neo.Json.UnitTests.csproj index 3643b6ec17..a7671e8430 100644 --- a/tests/Neo.Json.UnitTests/Neo.Json.UnitTests.csproj +++ b/tests/Neo.Json.UnitTests/Neo.Json.UnitTests.csproj @@ -8,4 +8,8 @@ + + + + diff --git a/tests/Neo.UnitTests/Neo.UnitTests.csproj b/tests/Neo.UnitTests/Neo.UnitTests.csproj index 1aef941090..a7a882c4f5 100644 --- a/tests/Neo.UnitTests/Neo.UnitTests.csproj +++ b/tests/Neo.UnitTests/Neo.UnitTests.csproj @@ -1,12 +1,12 @@ - + true - - + + @@ -17,4 +17,8 @@ + + + + From 62cf4f64175c5fa96098a186abf1c500d65dcc18 Mon Sep 17 00:00:00 2001 From: Ricardo Prado <38396062+lock9@users.noreply.github.com> Date: Wed, 22 Nov 2023 09:32:42 -0300 Subject: [PATCH 020/168] Migrating Neo VM (#2970) --- benchmarks/Neo.VM.Benchmarks/Benchmarks.cs | 101 + .../Neo.VM.Benchmarks.csproj | 16 + benchmarks/Neo.VM.Benchmarks/Program.cs | 7 + neo.sln | 23 +- src/Neo.VM/BadScriptException.cs | 31 + src/Neo.VM/CatchableException.cs | 21 + src/Neo.VM/Collections/OrderedDictionary.cs | 129 + src/Neo.VM/Cryptography/BitOperations.cs | 27 + src/Neo.VM/Cryptography/Murmur32.cs | 97 + src/Neo.VM/Debugger.cs | 137 + src/Neo.VM/EvaluationStack.cs | 162 + src/Neo.VM/ExceptionHandlingContext.cs | 57 + src/Neo.VM/ExceptionHandlingState.cs | 33 + src/Neo.VM/ExecutionContext.SharedStates.cs | 33 + src/Neo.VM/ExecutionContext.cs | 169 + src/Neo.VM/ExecutionEngine.cs | 1702 +++++ src/Neo.VM/ExecutionEngineLimits.cs | 87 + src/Neo.VM/GlobalSuppressions.cs | 18 + src/Neo.VM/Instruction.cs | 234 + src/Neo.VM/IsExternalInit.cs | 17 + src/Neo.VM/Neo.VM.csproj | 9 + src/Neo.VM/OpCode.cs | 905 +++ src/Neo.VM/OperandSizeAttribute.cs | 31 + src/Neo.VM/Properties/AssemblyInfo.cs | 13 + src/Neo.VM/ReferenceCounter.cs | 154 + src/Neo.VM/ReferenceEqualityComparer.cs | 29 + src/Neo.VM/Script.cs | 160 + src/Neo.VM/ScriptBuilder.cs | 199 + src/Neo.VM/Slot.cs | 92 + .../StronglyConnectedComponents/Tarjan.cs | 124 + src/Neo.VM/Types/Array.cs | 145 + src/Neo.VM/Types/Boolean.cs | 70 + src/Neo.VM/Types/Buffer.cs | 110 + src/Neo.VM/Types/ByteString.cs | 136 + src/Neo.VM/Types/CompoundType.cs | 70 + src/Neo.VM/Types/Integer.cs | 133 + src/Neo.VM/Types/InteropInterface.cs | 58 + src/Neo.VM/Types/Map.cs | 180 + src/Neo.VM/Types/Null.cs | 59 + src/Neo.VM/Types/Pointer.cs | 62 + src/Neo.VM/Types/PrimitiveType.cs | 138 + src/Neo.VM/Types/StackItem.Vertex.cs | 35 + src/Neo.VM/Types/StackItem.cs | 261 + src/Neo.VM/Types/StackItemType.cs | 68 + src/Neo.VM/Types/Struct.cs | 133 + src/Neo.VM/Unsafe.cs | 41 + src/Neo.VM/Utility.cs | 89 + src/Neo.VM/VMState.cs | 38 + src/Neo.VM/VMUnhandledException.cs | 52 + src/Neo/Neo.csproj | 2 +- .../Converters/ScriptConverter.cs | 152 + .../Neo.VM.Tests/Converters/UppercaseEnum.cs | 23 + .../Neo.VM.Tests/Extensions/JsonExtensions.cs | 47 + .../Extensions/StringExtensions.cs | 57 + tests/Neo.VM.Tests/Helpers/RandomHelper.cs | 39 + tests/Neo.VM.Tests/Neo.VM.Tests.csproj | 21 + .../Tests/OpCodes/Arithmetic/GE.json | 443 ++ .../Tests/OpCodes/Arithmetic/GT.json | 443 ++ .../Tests/OpCodes/Arithmetic/LE.json | 443 ++ .../Tests/OpCodes/Arithmetic/LT.json | 443 ++ .../Tests/OpCodes/Arithmetic/MODMUL.json | 141 + .../Tests/OpCodes/Arithmetic/MODPOW.json | 145 + .../Tests/OpCodes/Arithmetic/NOT.json | 537 ++ .../Tests/OpCodes/Arithmetic/NUMEQUAL.json | 1058 +++ .../Tests/OpCodes/Arithmetic/NUMNOTEQUAL.json | 1058 +++ .../Tests/OpCodes/Arithmetic/POW.json | 195 + .../Tests/OpCodes/Arithmetic/SHL.json | 245 + .../Tests/OpCodes/Arithmetic/SHR.json | 247 + .../Tests/OpCodes/Arithmetic/SIGN.json | 496 ++ .../Tests/OpCodes/Arithmetic/SQRT.json | 216 + .../Tests/OpCodes/Arrays/APPEND.json | 679 ++ .../Tests/OpCodes/Arrays/CLEARITEMS.json | 126 + .../Tests/OpCodes/Arrays/HASKEY.json | 276 + .../Tests/OpCodes/Arrays/KEYS.json | 63 + .../Tests/OpCodes/Arrays/NEWARRAY.json | 168 + .../Tests/OpCodes/Arrays/NEWARRAY0.json | 28 + .../Tests/OpCodes/Arrays/NEWARRAY_T.json | 289 + .../Tests/OpCodes/Arrays/NEWMAP.json | 48 + .../Tests/OpCodes/Arrays/NEWSTRUCT.json | 168 + .../Tests/OpCodes/Arrays/NEWSTRUCT0.json | 28 + .../Tests/OpCodes/Arrays/PACK.json | 127 + .../Tests/OpCodes/Arrays/PACKMAP.json | 127 + .../Tests/OpCodes/Arrays/PACKSTRUCT.json | 127 + .../Tests/OpCodes/Arrays/PICKITEM.json | 714 ++ .../Tests/OpCodes/Arrays/REMOVE.json | 299 + .../Tests/OpCodes/Arrays/REVERSEITEMS.json | 138 + .../Tests/OpCodes/Arrays/SETITEM.json | 1226 ++++ .../Tests/OpCodes/Arrays/SIZE.json | 266 + .../Tests/OpCodes/Arrays/UNPACK.json | 168 + .../Tests/OpCodes/Arrays/VALUES.json | 194 + .../Tests/OpCodes/BitwiseLogic/AND.json | 811 +++ .../Tests/OpCodes/BitwiseLogic/EQUAL.json | 1447 ++++ .../Tests/OpCodes/BitwiseLogic/INVERT.json | 657 ++ .../Tests/OpCodes/BitwiseLogic/NOTEQUAL.json | 1299 ++++ .../Tests/OpCodes/BitwiseLogic/OR.json | 811 +++ .../Tests/OpCodes/BitwiseLogic/XOR.json | 811 +++ .../Tests/OpCodes/Control/ABORT.json | 22 + .../Tests/OpCodes/Control/ABORTMSG.json | 26 + .../Tests/OpCodes/Control/ASSERT.json | 42 + .../Tests/OpCodes/Control/ASSERTMSG.json | 47 + .../Tests/OpCodes/Control/CALL.json | 134 + .../Tests/OpCodes/Control/CALLA.json | 158 + .../Tests/OpCodes/Control/CALL_L.json | 134 + .../Tests/OpCodes/Control/JMP.json | 74 + .../Tests/OpCodes/Control/JMPEQ.json | 307 + .../Tests/OpCodes/Control/JMPEQ_L.json | 307 + .../Tests/OpCodes/Control/JMPGE.json | 293 + .../Tests/OpCodes/Control/JMPGE_L.json | 293 + .../Tests/OpCodes/Control/JMPGT.json | 307 + .../Tests/OpCodes/Control/JMPGT_L.json | 307 + .../Tests/OpCodes/Control/JMPIF.json | 145 + .../Tests/OpCodes/Control/JMPIFNOT.json | 145 + .../Tests/OpCodes/Control/JMPIFNOT_L.json | 145 + .../Tests/OpCodes/Control/JMPIF_L.json | 145 + .../Tests/OpCodes/Control/JMPLE.json | 293 + .../Tests/OpCodes/Control/JMPLE_L.json | 293 + .../Tests/OpCodes/Control/JMPLT.json | 307 + .../Tests/OpCodes/Control/JMPLT_L.json | 307 + .../Tests/OpCodes/Control/JMPNE.json | 293 + .../Tests/OpCodes/Control/JMPNE_L.json | 293 + .../Tests/OpCodes/Control/JMP_L.json | 74 + .../Tests/OpCodes/Control/NOP.json | 96 + .../Tests/OpCodes/Control/RET.json | 22 + .../Tests/OpCodes/Control/SYSCALL.json | 143 + .../Tests/OpCodes/Control/THROW.json | 24 + .../Tests/OpCodes/Control/TRY_CATCH.json | 175 + .../OpCodes/Control/TRY_CATCH_FINALLY.json | 72 + .../OpCodes/Control/TRY_CATCH_FINALLY10.json | 25 + .../OpCodes/Control/TRY_CATCH_FINALLY2.json | 103 + .../OpCodes/Control/TRY_CATCH_FINALLY3.json | 111 + .../OpCodes/Control/TRY_CATCH_FINALLY4.json | 117 + .../OpCodes/Control/TRY_CATCH_FINALLY5.json | 35 + .../OpCodes/Control/TRY_CATCH_FINALLY6.json | 33 + .../OpCodes/Control/TRY_CATCH_FINALLY7.json | 55 + .../OpCodes/Control/TRY_CATCH_FINALLY8.json | 101 + .../OpCodes/Control/TRY_CATCH_FINALLY9.json | 98 + .../Tests/OpCodes/Control/TRY_FINALLY.json | 49 + .../Tests/OpCodes/Push/PUSHA.json | 86 + .../Tests/OpCodes/Push/PUSHDATA1.json | 47 + .../Tests/OpCodes/Push/PUSHDATA2.json | 47 + .../Tests/OpCodes/Push/PUSHDATA4.json | 99 + .../OpCodes/Push/PUSHINT8_to_PUSHINT256.json | 59 + .../Tests/OpCodes/Push/PUSHM1_to_PUSH16.json | 219 + .../Tests/OpCodes/Push/PUSHNULL.json | 46 + .../Tests/OpCodes/Slot/INITSLOT.json | 206 + .../Tests/OpCodes/Slot/INITSSLOT.json | 97 + .../Tests/OpCodes/Slot/LDARG.json | 69 + .../Tests/OpCodes/Slot/LDARG0.json | 47 + .../Tests/OpCodes/Slot/LDARG1.json | 67 + .../Tests/OpCodes/Slot/LDARG2.json | 68 + .../Tests/OpCodes/Slot/LDARG3.json | 69 + .../Tests/OpCodes/Slot/LDARG4.json | 70 + .../Tests/OpCodes/Slot/LDARG5.json | 71 + .../Tests/OpCodes/Slot/LDARG6.json | 72 + .../Tests/OpCodes/Slot/LDLOC.json | 70 + .../Tests/OpCodes/Slot/LDLOC0.json | 48 + .../Tests/OpCodes/Slot/LDLOC1.json | 66 + .../Tests/OpCodes/Slot/LDLOC2.json | 66 + .../Tests/OpCodes/Slot/LDLOC3.json | 66 + .../Tests/OpCodes/Slot/LDLOC4.json | 66 + .../Tests/OpCodes/Slot/LDLOC5.json | 66 + .../Tests/OpCodes/Slot/LDLOC6.json | 66 + .../Tests/OpCodes/Slot/LDSFLD.json | 70 + .../Tests/OpCodes/Slot/LDSFLD0.json | 48 + .../Tests/OpCodes/Slot/LDSFLD1.json | 66 + .../Tests/OpCodes/Slot/LDSFLD2.json | 66 + .../Tests/OpCodes/Slot/LDSFLD3.json | 66 + .../Tests/OpCodes/Slot/LDSFLD4.json | 66 + .../Tests/OpCodes/Slot/LDSFLD5.json | 66 + .../Tests/OpCodes/Slot/LDSFLD6.json | 66 + .../Tests/OpCodes/Slot/STARG.json | 72 + .../Tests/OpCodes/Slot/STARG0.json | 49 + .../Tests/OpCodes/Slot/STARG1.json | 74 + .../Tests/OpCodes/Slot/STARG2.json | 79 + .../Tests/OpCodes/Slot/STARG3.json | 84 + .../Tests/OpCodes/Slot/STARG4.json | 89 + .../Tests/OpCodes/Slot/STARG5.json | 94 + .../Tests/OpCodes/Slot/STARG6.json | 99 + .../Tests/OpCodes/Slot/STLOC.json | 92 + .../Tests/OpCodes/Slot/STSFLD.json | 84 + .../Tests/OpCodes/Slot/STSFLD0.json | 63 + .../Tests/OpCodes/Slot/STSFLD1.json | 84 + .../Tests/OpCodes/Slot/STSFLD2.json | 87 + .../Tests/OpCodes/Slot/STSFLD3.json | 90 + .../Tests/OpCodes/Slot/STSFLD4.json | 93 + .../Tests/OpCodes/Slot/STSFLD5.json | 96 + .../Tests/OpCodes/Slot/STSFLD6.json | 99 + .../Tests/OpCodes/Splice/CAT.json | 436 ++ .../Tests/OpCodes/Splice/LEFT.json | 228 + .../Tests/OpCodes/Splice/MEMCPY.json | 382 + .../Tests/OpCodes/Splice/NEWBUFFER.json | 159 + .../Tests/OpCodes/Splice/RIGHT.json | 299 + .../Tests/OpCodes/Splice/SUBSTR.json | 478 ++ .../Tests/OpCodes/Stack/CLEAR.json | 59 + .../Tests/OpCodes/Stack/DEPTH.json | 223 + .../Tests/OpCodes/Stack/DROP.json | 73 + .../Neo.VM.Tests/Tests/OpCodes/Stack/NIP.json | 132 + .../Tests/OpCodes/Stack/OVER.json | 243 + .../Tests/OpCodes/Stack/PICK.json | 397 ++ .../Tests/OpCodes/Stack/REVERSE3.json | 85 + .../Tests/OpCodes/Stack/REVERSE4.json | 95 + .../Tests/OpCodes/Stack/REVERSEN.json | 201 + .../Tests/OpCodes/Stack/ROLL.json | 398 ++ .../Neo.VM.Tests/Tests/OpCodes/Stack/ROT.json | 193 + .../Tests/OpCodes/Stack/SWAP.json | 209 + .../Tests/OpCodes/Stack/TUCK.json | 243 + .../Tests/OpCodes/Stack/XDROP.json | 238 + .../Tests/OpCodes/Types/CONVERT.json | 898 +++ .../Tests/OpCodes/Types/ISNULL.json | 147 + .../Tests/OpCodes/Types/ISTYPE.json | 226 + tests/Neo.VM.Tests/Tests/Others/Debugger.json | 426 ++ tests/Neo.VM.Tests/Tests/Others/Init.json | 41 + .../Tests/Others/InvocationLimits.json | 120 + .../Neo.VM.Tests/Tests/Others/OtherCases.json | 36 + .../Tests/Others/ScriptLogic.json | 99 + .../Tests/Others/StackItemLimits.json | 71 + .../Tests/Others/StackLimits.json | 6181 +++++++++++++++++ tests/Neo.VM.Tests/Types/TestEngine.cs | 34 + tests/Neo.VM.Tests/Types/VMUT.cs | 16 + tests/Neo.VM.Tests/Types/VMUTActionType.cs | 13 + tests/Neo.VM.Tests/Types/VMUTEntry.cs | 17 + .../Types/VMUTExecutionContextState.cs | 31 + .../Types/VMUTExecutionEngineState.cs | 21 + tests/Neo.VM.Tests/Types/VMUTStackItem.cs | 14 + tests/Neo.VM.Tests/Types/VMUTStackItemType.cs | 60 + tests/Neo.VM.Tests/Types/VMUTStep.cs | 16 + tests/Neo.VM.Tests/UtDebugger.cs | 207 + tests/Neo.VM.Tests/UtEvaluationStack.cs | 191 + tests/Neo.VM.Tests/UtExecutionContext.cs | 55 + tests/Neo.VM.Tests/UtReferenceCounter.cs | 167 + tests/Neo.VM.Tests/UtScript.cs | 93 + tests/Neo.VM.Tests/UtScriptBuilder.cs | 264 + tests/Neo.VM.Tests/UtSlot.cs | 90 + tests/Neo.VM.Tests/UtStackItem.cs | 199 + tests/Neo.VM.Tests/UtStruct.cs | 64 + tests/Neo.VM.Tests/UtUnsafe.cs | 22 + tests/Neo.VM.Tests/UtUtility.cs | 36 + tests/Neo.VM.Tests/UtVMJson.cs | 74 + tests/Neo.VM.Tests/VMJsonTestBase.cs | 312 + 239 files changed, 49296 insertions(+), 2 deletions(-) create mode 100644 benchmarks/Neo.VM.Benchmarks/Benchmarks.cs create mode 100644 benchmarks/Neo.VM.Benchmarks/Neo.VM.Benchmarks.csproj create mode 100644 benchmarks/Neo.VM.Benchmarks/Program.cs create mode 100644 src/Neo.VM/BadScriptException.cs create mode 100644 src/Neo.VM/CatchableException.cs create mode 100644 src/Neo.VM/Collections/OrderedDictionary.cs create mode 100644 src/Neo.VM/Cryptography/BitOperations.cs create mode 100644 src/Neo.VM/Cryptography/Murmur32.cs create mode 100644 src/Neo.VM/Debugger.cs create mode 100644 src/Neo.VM/EvaluationStack.cs create mode 100644 src/Neo.VM/ExceptionHandlingContext.cs create mode 100644 src/Neo.VM/ExceptionHandlingState.cs create mode 100644 src/Neo.VM/ExecutionContext.SharedStates.cs create mode 100644 src/Neo.VM/ExecutionContext.cs create mode 100644 src/Neo.VM/ExecutionEngine.cs create mode 100644 src/Neo.VM/ExecutionEngineLimits.cs create mode 100644 src/Neo.VM/GlobalSuppressions.cs create mode 100644 src/Neo.VM/Instruction.cs create mode 100644 src/Neo.VM/IsExternalInit.cs create mode 100644 src/Neo.VM/Neo.VM.csproj create mode 100644 src/Neo.VM/OpCode.cs create mode 100644 src/Neo.VM/OperandSizeAttribute.cs create mode 100644 src/Neo.VM/Properties/AssemblyInfo.cs create mode 100644 src/Neo.VM/ReferenceCounter.cs create mode 100644 src/Neo.VM/ReferenceEqualityComparer.cs create mode 100644 src/Neo.VM/Script.cs create mode 100644 src/Neo.VM/ScriptBuilder.cs create mode 100644 src/Neo.VM/Slot.cs create mode 100644 src/Neo.VM/StronglyConnectedComponents/Tarjan.cs create mode 100644 src/Neo.VM/Types/Array.cs create mode 100644 src/Neo.VM/Types/Boolean.cs create mode 100644 src/Neo.VM/Types/Buffer.cs create mode 100644 src/Neo.VM/Types/ByteString.cs create mode 100644 src/Neo.VM/Types/CompoundType.cs create mode 100644 src/Neo.VM/Types/Integer.cs create mode 100644 src/Neo.VM/Types/InteropInterface.cs create mode 100644 src/Neo.VM/Types/Map.cs create mode 100644 src/Neo.VM/Types/Null.cs create mode 100644 src/Neo.VM/Types/Pointer.cs create mode 100644 src/Neo.VM/Types/PrimitiveType.cs create mode 100644 src/Neo.VM/Types/StackItem.Vertex.cs create mode 100644 src/Neo.VM/Types/StackItem.cs create mode 100644 src/Neo.VM/Types/StackItemType.cs create mode 100644 src/Neo.VM/Types/Struct.cs create mode 100644 src/Neo.VM/Unsafe.cs create mode 100644 src/Neo.VM/Utility.cs create mode 100644 src/Neo.VM/VMState.cs create mode 100644 src/Neo.VM/VMUnhandledException.cs create mode 100644 tests/Neo.VM.Tests/Converters/ScriptConverter.cs create mode 100644 tests/Neo.VM.Tests/Converters/UppercaseEnum.cs create mode 100644 tests/Neo.VM.Tests/Extensions/JsonExtensions.cs create mode 100644 tests/Neo.VM.Tests/Extensions/StringExtensions.cs create mode 100644 tests/Neo.VM.Tests/Helpers/RandomHelper.cs create mode 100644 tests/Neo.VM.Tests/Neo.VM.Tests.csproj create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/GE.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/GT.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/LE.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/LT.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/MODMUL.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/MODPOW.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/NOT.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/NUMEQUAL.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/NUMNOTEQUAL.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/POW.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/SHL.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/SHR.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/SIGN.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/SQRT.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Arrays/APPEND.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Arrays/CLEARITEMS.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Arrays/HASKEY.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Arrays/KEYS.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Arrays/NEWARRAY.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Arrays/NEWARRAY0.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Arrays/NEWARRAY_T.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Arrays/NEWMAP.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Arrays/NEWSTRUCT.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Arrays/NEWSTRUCT0.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Arrays/PACK.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Arrays/PACKMAP.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Arrays/PACKSTRUCT.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Arrays/PICKITEM.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Arrays/REMOVE.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Arrays/REVERSEITEMS.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Arrays/SETITEM.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Arrays/SIZE.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Arrays/UNPACK.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Arrays/VALUES.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/BitwiseLogic/AND.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/BitwiseLogic/EQUAL.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/BitwiseLogic/INVERT.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/BitwiseLogic/NOTEQUAL.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/BitwiseLogic/OR.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/BitwiseLogic/XOR.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Control/ABORT.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Control/ABORTMSG.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Control/ASSERT.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Control/ASSERTMSG.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Control/CALL.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Control/CALLA.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Control/CALL_L.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Control/JMP.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPEQ.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPEQ_L.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPGE.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPGE_L.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPGT.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPGT_L.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPIF.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPIFNOT.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPIFNOT_L.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPIF_L.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPLE.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPLE_L.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPLT.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPLT_L.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPNE.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPNE_L.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Control/JMP_L.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Control/NOP.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Control/RET.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Control/SYSCALL.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Control/THROW.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH_FINALLY.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH_FINALLY10.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH_FINALLY2.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH_FINALLY3.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH_FINALLY4.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH_FINALLY5.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH_FINALLY6.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH_FINALLY7.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH_FINALLY8.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH_FINALLY9.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_FINALLY.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Push/PUSHA.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Push/PUSHDATA1.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Push/PUSHDATA2.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Push/PUSHDATA4.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Push/PUSHINT8_to_PUSHINT256.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Push/PUSHM1_to_PUSH16.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Push/PUSHNULL.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Slot/INITSLOT.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Slot/INITSSLOT.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDARG.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDARG0.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDARG1.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDARG2.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDARG3.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDARG4.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDARG5.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDARG6.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDLOC.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDLOC0.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDLOC1.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDLOC2.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDLOC3.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDLOC4.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDLOC5.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDLOC6.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDSFLD.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDSFLD0.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDSFLD1.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDSFLD2.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDSFLD3.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDSFLD4.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDSFLD5.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDSFLD6.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Slot/STARG.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Slot/STARG0.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Slot/STARG1.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Slot/STARG2.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Slot/STARG3.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Slot/STARG4.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Slot/STARG5.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Slot/STARG6.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Slot/STLOC.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Slot/STSFLD.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Slot/STSFLD0.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Slot/STSFLD1.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Slot/STSFLD2.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Slot/STSFLD3.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Slot/STSFLD4.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Slot/STSFLD5.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Slot/STSFLD6.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Splice/CAT.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Splice/LEFT.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Splice/MEMCPY.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Splice/NEWBUFFER.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Splice/RIGHT.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Splice/SUBSTR.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Stack/CLEAR.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Stack/DEPTH.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Stack/DROP.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Stack/NIP.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Stack/OVER.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Stack/PICK.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Stack/REVERSE3.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Stack/REVERSE4.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Stack/REVERSEN.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Stack/ROLL.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Stack/ROT.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Stack/SWAP.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Stack/TUCK.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Stack/XDROP.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Types/CONVERT.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Types/ISNULL.json create mode 100644 tests/Neo.VM.Tests/Tests/OpCodes/Types/ISTYPE.json create mode 100644 tests/Neo.VM.Tests/Tests/Others/Debugger.json create mode 100644 tests/Neo.VM.Tests/Tests/Others/Init.json create mode 100644 tests/Neo.VM.Tests/Tests/Others/InvocationLimits.json create mode 100644 tests/Neo.VM.Tests/Tests/Others/OtherCases.json create mode 100644 tests/Neo.VM.Tests/Tests/Others/ScriptLogic.json create mode 100644 tests/Neo.VM.Tests/Tests/Others/StackItemLimits.json create mode 100644 tests/Neo.VM.Tests/Tests/Others/StackLimits.json create mode 100644 tests/Neo.VM.Tests/Types/TestEngine.cs create mode 100644 tests/Neo.VM.Tests/Types/VMUT.cs create mode 100644 tests/Neo.VM.Tests/Types/VMUTActionType.cs create mode 100644 tests/Neo.VM.Tests/Types/VMUTEntry.cs create mode 100644 tests/Neo.VM.Tests/Types/VMUTExecutionContextState.cs create mode 100644 tests/Neo.VM.Tests/Types/VMUTExecutionEngineState.cs create mode 100644 tests/Neo.VM.Tests/Types/VMUTStackItem.cs create mode 100644 tests/Neo.VM.Tests/Types/VMUTStackItemType.cs create mode 100644 tests/Neo.VM.Tests/Types/VMUTStep.cs create mode 100644 tests/Neo.VM.Tests/UtDebugger.cs create mode 100644 tests/Neo.VM.Tests/UtEvaluationStack.cs create mode 100644 tests/Neo.VM.Tests/UtExecutionContext.cs create mode 100644 tests/Neo.VM.Tests/UtReferenceCounter.cs create mode 100644 tests/Neo.VM.Tests/UtScript.cs create mode 100644 tests/Neo.VM.Tests/UtScriptBuilder.cs create mode 100644 tests/Neo.VM.Tests/UtSlot.cs create mode 100644 tests/Neo.VM.Tests/UtStackItem.cs create mode 100644 tests/Neo.VM.Tests/UtStruct.cs create mode 100644 tests/Neo.VM.Tests/UtUnsafe.cs create mode 100644 tests/Neo.VM.Tests/UtUtility.cs create mode 100644 tests/Neo.VM.Tests/UtVMJson.cs create mode 100644 tests/Neo.VM.Tests/VMJsonTestBase.cs diff --git a/benchmarks/Neo.VM.Benchmarks/Benchmarks.cs b/benchmarks/Neo.VM.Benchmarks/Benchmarks.cs new file mode 100644 index 0000000000..dd7df7d3d1 --- /dev/null +++ b/benchmarks/Neo.VM.Benchmarks/Benchmarks.cs @@ -0,0 +1,101 @@ +using System.Diagnostics; + +namespace Neo.VM +{ + public static class Benchmarks + { + public static void NeoIssue2528() + { + // https://github.com/neo-project/neo/issues/2528 + // L01: INITSLOT 1, 0 + // L02: NEWARRAY0 + // L03: DUP + // L04: DUP + // L05: PUSHINT16 2043 + // L06: STLOC 0 + // L07: PUSH1 + // L08: PACK + // L09: LDLOC 0 + // L10: DEC + // L11: STLOC 0 + // L12: LDLOC 0 + // L13: JMPIF_L L07 + // L14: PUSH1 + // L15: PACK + // L16: APPEND + // L17: PUSHINT32 38000 + // L18: STLOC 0 + // L19: PUSH0 + // L20: PICKITEM + // L21: LDLOC 0 + // L22: DEC + // L23: STLOC 0 + // L24: LDLOC 0 + // L25: JMPIF_L L19 + // L26: DROP + Run(nameof(NeoIssue2528), "VwEAwkpKAfsHdwARwG8AnXcAbwAl9////xHAzwJwlAAAdwAQzm8AnXcAbwAl9////0U="); + } + + public static void NeoVMIssue418() + { + // https://github.com/neo-project/neo-vm/issues/418 + // L00: NEWARRAY0 + // L01: PUSH0 + // L02: PICK + // L03: PUSH1 + // L04: PACK + // L05: PUSH1 + // L06: PICK + // L07: PUSH1 + // L08: PACK + // L09: INITSSLOT 1 + // L10: PUSHINT16 510 + // L11: DEC + // L12: STSFLD0 + // L13: PUSH1 + // L14: PICK + // L15: PUSH1 + // L16: PICK + // L17: PUSH2 + // L18: PACK + // L19: REVERSE3 + // L20: PUSH2 + // L21: PACK + // L22: LDSFLD0 + // L23: DUP + // L24: JMPIF L11 + // L25: DROP + // L26: ROT + // L27: DROP + Run(nameof(NeoVMIssue418), "whBNEcARTRHAVgEB/gGdYBFNEU0SwFMSwFhKJPNFUUU="); + } + + public static void NeoIssue2723() + { + // L00: INITSSLOT 1 + // L01: PUSHINT32 130000 + // L02: STSFLD 0 + // L03: PUSHINT32 1048576 + // L04: NEWBUFFER + // L05: DROP + // L06: LDSFLD 0 + // L07: DEC + // L08: DUP + // L09: STSFLD 0 + // L10: JMPIF L03 + Run(nameof(NeoIssue2723), "VgEC0PsBAGcAAgAAEACIRV8AnUpnACTz"); + } + + 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 new file mode 100644 index 0000000000..bdca77ae89 --- /dev/null +++ b/benchmarks/Neo.VM.Benchmarks/Neo.VM.Benchmarks.csproj @@ -0,0 +1,16 @@ + + + + Exe + net7.0 + Neo.VM + enable + enable + false + + + + + + + diff --git a/benchmarks/Neo.VM.Benchmarks/Program.cs b/benchmarks/Neo.VM.Benchmarks/Program.cs new file mode 100644 index 0000000000..4ab0a66926 --- /dev/null +++ b/benchmarks/Neo.VM.Benchmarks/Program.cs @@ -0,0 +1,7 @@ +using Neo.VM; +using System.Reflection; + +foreach (var method in typeof(Benchmarks).GetMethods(BindingFlags.Public | BindingFlags.Static)) +{ + method.CreateDelegate().Invoke(); +} diff --git a/neo.sln b/neo.sln index e705e23988..827bddc1b2 100644 --- a/neo.sln +++ b/neo.sln @@ -8,7 +8,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.Json", "src\Neo.Json\Ne EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.UnitTests", "tests\Neo.UnitTests\Neo.UnitTests.csproj", "{5B783B30-B422-4C2F-AC22-187A8D1993F4}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Neo.Json.UnitTests", "tests\Neo.Json.UnitTests\Neo.Json.UnitTests.csproj", "{AE6C32EE-8447-4E01-8187-2AE02BB64251}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.Json.UnitTests", "tests\Neo.Json.UnitTests\Neo.Json.UnitTests.csproj", "{AE6C32EE-8447-4E01-8187-2AE02BB64251}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.Benchmarks", "benchmarks\Neo.Benchmarks\Neo.Benchmarks.csproj", "{BCD03521-5F8F-4775-9ADF-FA361480804F}" EndProject @@ -18,6 +18,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{EDE05FA8 EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "benchmarks", "benchmarks", "{C25EB0B0-0CAC-4CC1-8F36-F9229EFB99EC}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.VM.Benchmarks", "benchmarks\Neo.VM.Benchmarks\Neo.VM.Benchmarks.csproj", "{E83633BA-FCF0-4A1A-B5BC-42000E24D437}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.VM", "src\Neo.VM\Neo.VM.csproj", "{0603710E-E0BA-494C-AA0F-6FB0C8A8C754}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.VM.Tests", "tests\Neo.VM.Tests\Neo.VM.Tests.csproj", "{005F84EB-EA2E-449F-930A-7B4173DDC7EC}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -44,6 +50,18 @@ Global {BCD03521-5F8F-4775-9ADF-FA361480804F}.Debug|Any CPU.Build.0 = Debug|Any CPU {BCD03521-5F8F-4775-9ADF-FA361480804F}.Release|Any CPU.ActiveCfg = Release|Any CPU {BCD03521-5F8F-4775-9ADF-FA361480804F}.Release|Any CPU.Build.0 = Release|Any CPU + {E83633BA-FCF0-4A1A-B5BC-42000E24D437}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E83633BA-FCF0-4A1A-B5BC-42000E24D437}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E83633BA-FCF0-4A1A-B5BC-42000E24D437}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E83633BA-FCF0-4A1A-B5BC-42000E24D437}.Release|Any CPU.Build.0 = Release|Any CPU + {0603710E-E0BA-494C-AA0F-6FB0C8A8C754}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0603710E-E0BA-494C-AA0F-6FB0C8A8C754}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0603710E-E0BA-494C-AA0F-6FB0C8A8C754}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0603710E-E0BA-494C-AA0F-6FB0C8A8C754}.Release|Any CPU.Build.0 = Release|Any CPU + {005F84EB-EA2E-449F-930A-7B4173DDC7EC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {005F84EB-EA2E-449F-930A-7B4173DDC7EC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {005F84EB-EA2E-449F-930A-7B4173DDC7EC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {005F84EB-EA2E-449F-930A-7B4173DDC7EC}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -54,6 +72,9 @@ Global {5B783B30-B422-4C2F-AC22-187A8D1993F4} = {EDE05FA8-8E73-4924-BC63-DD117127EEE1} {AE6C32EE-8447-4E01-8187-2AE02BB64251} = {EDE05FA8-8E73-4924-BC63-DD117127EEE1} {BCD03521-5F8F-4775-9ADF-FA361480804F} = {C25EB0B0-0CAC-4CC1-8F36-F9229EFB99EC} + {E83633BA-FCF0-4A1A-B5BC-42000E24D437} = {C25EB0B0-0CAC-4CC1-8F36-F9229EFB99EC} + {0603710E-E0BA-494C-AA0F-6FB0C8A8C754} = {B5339DF7-5D1D-43BA-B332-74B825E1770E} + {005F84EB-EA2E-449F-930A-7B4173DDC7EC} = {EDE05FA8-8E73-4924-BC63-DD117127EEE1} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {BCBA19D9-F868-4C6D-8061-A2B91E06E3EC} diff --git a/src/Neo.VM/BadScriptException.cs b/src/Neo.VM/BadScriptException.cs new file mode 100644 index 0000000000..fcf4b9f2b4 --- /dev/null +++ b/src/Neo.VM/BadScriptException.cs @@ -0,0 +1,31 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project 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; + +namespace Neo.VM +{ + /// + /// Represents the exception thrown when the bad script is parsed. + /// + public class BadScriptException : Exception + { + /// + /// Initializes a new instance of the class. + /// + public BadScriptException() { } + + /// + /// Initializes a new instance of the class with a specified error message. + /// + /// The message that describes the error. + public BadScriptException(string message) : base(message) { } + } +} diff --git a/src/Neo.VM/CatchableException.cs b/src/Neo.VM/CatchableException.cs new file mode 100644 index 0000000000..9235ac5c31 --- /dev/null +++ b/src/Neo.VM/CatchableException.cs @@ -0,0 +1,21 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project 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; + +namespace Neo.VM +{ + public class CatchableException : Exception + { + public CatchableException(string message) : base(message) + { + } + } +} diff --git a/src/Neo.VM/Collections/OrderedDictionary.cs b/src/Neo.VM/Collections/OrderedDictionary.cs new file mode 100644 index 0000000000..5f2d593067 --- /dev/null +++ b/src/Neo.VM/Collections/OrderedDictionary.cs @@ -0,0 +1,129 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project 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.Collections; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Diagnostics.CodeAnalysis; +using System.Linq; + +namespace Neo.VM.Collections +{ + internal class OrderedDictionary : IDictionary + where TKey : notnull + { + private class TItem + { + public readonly TKey Key; + public TValue Value; + + public TItem(TKey key, TValue value) + { + this.Key = key; + this.Value = value; + } + } + + private class InternalCollection : KeyedCollection + { + protected override TKey GetKeyForItem(TItem item) + { + return item.Key; + } + } + + private readonly InternalCollection collection = new(); + + public int Count => collection.Count; + public bool IsReadOnly => false; + public ICollection Keys => collection.Select(p => p.Key).ToArray(); + public ICollection Values => collection.Select(p => p.Value).ToArray(); + + public TValue this[TKey key] + { + get + { + return collection[key].Value; + } + set + { + if (collection.TryGetValue(key, out var entry)) + entry.Value = value; + else + Add(key, value); + } + } + + public void Add(TKey key, TValue value) + { + collection.Add(new TItem(key, value)); + } + + public bool ContainsKey(TKey key) + { + return collection.Contains(key); + } + + public bool Remove(TKey key) + { + return collection.Remove(key); + } + + // supress warning of value parameter nullability mismatch +#pragma warning disable CS8767 + public bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value) +#pragma warning restore CS8767 + { + if (collection.TryGetValue(key, out var entry)) + { + value = entry.Value; + return true; + } + value = default; + return false; + } + + void ICollection>.Add(KeyValuePair item) + { + Add(item.Key, item.Value); + } + + public void Clear() + { + collection.Clear(); + } + + bool ICollection>.Contains(KeyValuePair item) + { + return collection.Contains(item.Key); + } + + void ICollection>.CopyTo(KeyValuePair[] array, int arrayIndex) + { + for (int i = 0; i < collection.Count; i++) + array[i + arrayIndex] = new KeyValuePair(collection[i].Key, collection[i].Value); + } + + bool ICollection>.Remove(KeyValuePair item) + { + return collection.Remove(item.Key); + } + + IEnumerator> IEnumerable>.GetEnumerator() + { + return collection.Select(p => new KeyValuePair(p.Key, p.Value)).GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return collection.Select(p => new KeyValuePair(p.Key, p.Value)).GetEnumerator(); + } + } +} diff --git a/src/Neo.VM/Cryptography/BitOperations.cs b/src/Neo.VM/Cryptography/BitOperations.cs new file mode 100644 index 0000000000..40fc0171af --- /dev/null +++ b/src/Neo.VM/Cryptography/BitOperations.cs @@ -0,0 +1,27 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project 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.Runtime.CompilerServices; + +namespace Neo.VM.Cryptography +{ +#if !NET5_0_OR_GREATER + static class BitOperations + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static uint RotateLeft(uint value, int offset) + => (value << offset) | (value >> (32 - offset)); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ulong RotateLeft(ulong value, int offset) + => (value << offset) | (value >> (64 - offset)); + } +#endif +} diff --git a/src/Neo.VM/Cryptography/Murmur32.cs b/src/Neo.VM/Cryptography/Murmur32.cs new file mode 100644 index 0000000000..5cfa22d9b7 --- /dev/null +++ b/src/Neo.VM/Cryptography/Murmur32.cs @@ -0,0 +1,97 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project 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.Buffers.Binary; +using System.Numerics; +using System.Security.Cryptography; + +namespace Neo.VM.Cryptography +{ + /// + /// Computes the murmur hash for the input data. + /// + sealed class Murmur32 : HashAlgorithm + { + private const uint c1 = 0xcc9e2d51; + private const uint c2 = 0x1b873593; + private const int r1 = 15; + private const int r2 = 13; + private const uint m = 5; + private const uint n = 0xe6546b64; + + private readonly uint seed; + private uint hash; + private int length; + + public override int HashSize => 32; + + /// + /// Initializes a new instance of the class with the specified seed. + /// + /// The seed to be used. + public Murmur32(uint seed) + { + this.seed = seed; + Initialize(); + } + + protected override void HashCore(byte[] array, int ibStart, int cbSize) + { + length += cbSize; + int remainder = cbSize & 3; + int alignedLength = ibStart + (cbSize - remainder); + for (int i = ibStart; i < alignedLength; i += 4) + { + uint k = BinaryPrimitives.ReadUInt32LittleEndian(array.AsSpan(i)); + k *= c1; + k = BitOperations.RotateLeft(k, r1); + k *= c2; + hash ^= k; + hash = BitOperations.RotateLeft(hash, r2); + hash = hash * m + n; + } + if (remainder > 0) + { + uint remainingBytes = 0; + switch (remainder) + { + case 3: remainingBytes ^= (uint)array[alignedLength + 2] << 16; goto case 2; + case 2: remainingBytes ^= (uint)array[alignedLength + 1] << 8; goto case 1; + case 1: remainingBytes ^= array[alignedLength]; break; + } + remainingBytes *= c1; + remainingBytes = BitOperations.RotateLeft(remainingBytes, r1); + remainingBytes *= c2; + hash ^= remainingBytes; + } + } + + protected override byte[] HashFinal() + { + hash ^= (uint)length; + hash ^= hash >> 16; + hash *= 0x85ebca6b; + hash ^= hash >> 13; + hash *= 0xc2b2ae35; + hash ^= hash >> 16; + + byte[] buffer = new byte[sizeof(uint)]; + BinaryPrimitives.WriteUInt32LittleEndian(buffer, hash); + return buffer; + } + + public override void Initialize() + { + hash = seed; + length = 0; + } + } +} diff --git a/src/Neo.VM/Debugger.cs b/src/Neo.VM/Debugger.cs new file mode 100644 index 0000000000..fef4d87e75 --- /dev/null +++ b/src/Neo.VM/Debugger.cs @@ -0,0 +1,137 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project 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.Collections.Generic; + +namespace Neo.VM +{ + /// + /// A simple debugger for . + /// + public class Debugger + { + private readonly ExecutionEngine engine; + private readonly Dictionary> break_points = new(); + + /// + /// Create a debugger on the specified . + /// + /// The to attach the debugger. + public Debugger(ExecutionEngine engine) + { + this.engine = engine; + } + + /// + /// Add a breakpoint at the specified position of the specified script. The VM will break the execution when it reaches the breakpoint. + /// + /// The script to add the breakpoint. + /// The position of the breakpoint in the script. + public void AddBreakPoint(Script script, uint position) + { + if (!break_points.TryGetValue(script, out HashSet? hashset)) + { + hashset = new HashSet(); + break_points.Add(script, hashset); + } + hashset.Add(position); + } + + /// + /// Start or continue execution of the VM. + /// + /// Returns the state of the VM after the execution. + public VMState Execute() + { + if (engine.State == VMState.BREAK) + engine.State = VMState.NONE; + while (engine.State == VMState.NONE) + ExecuteAndCheckBreakPoints(); + return engine.State; + } + + private void ExecuteAndCheckBreakPoints() + { + engine.ExecuteNext(); + if (engine.State == VMState.NONE && engine.InvocationStack.Count > 0 && break_points.Count > 0) + { + if (break_points.TryGetValue(engine.CurrentContext!.Script, out HashSet? hashset) && hashset.Contains((uint)engine.CurrentContext.InstructionPointer)) + engine.State = VMState.BREAK; + } + } + + /// + /// Removes the breakpoint at the specified position in the specified script. + /// + /// The script to remove the breakpoint. + /// The position of the breakpoint in the script. + /// + /// if the breakpoint is successfully found and removed; + /// otherwise, . + /// + public bool RemoveBreakPoint(Script script, uint position) + { + if (!break_points.TryGetValue(script, out HashSet? hashset)) return false; + if (!hashset.Remove(position)) return false; + if (hashset.Count == 0) break_points.Remove(script); + return true; + } + + /// + /// Execute the next instruction. If the instruction involves a call to a method, it steps into the method and breaks the execution on the first instruction of that method. + /// + /// The VM state after the instruction is executed. + public VMState StepInto() + { + if (engine.State == VMState.HALT || engine.State == VMState.FAULT) + return engine.State; + engine.ExecuteNext(); + if (engine.State == VMState.NONE) + engine.State = VMState.BREAK; + return engine.State; + } + + /// + /// Execute until the currently executed method is returned. + /// + /// The VM state after the currently executed method is returned. + public VMState StepOut() + { + if (engine.State == VMState.BREAK) + engine.State = VMState.NONE; + int c = engine.InvocationStack.Count; + while (engine.State == VMState.NONE && engine.InvocationStack.Count >= c) + ExecuteAndCheckBreakPoints(); + if (engine.State == VMState.NONE) + engine.State = VMState.BREAK; + return engine.State; + } + + /// + /// Execute the next instruction. If the instruction involves a call to a method, it does not step into the method (it steps over it instead). + /// + /// The VM state after the instruction is executed. + public VMState StepOver() + { + if (engine.State == VMState.HALT || engine.State == VMState.FAULT) + return engine.State; + engine.State = VMState.NONE; + int c = engine.InvocationStack.Count; + do + { + ExecuteAndCheckBreakPoints(); + } + while (engine.State == VMState.NONE && engine.InvocationStack.Count > c); + if (engine.State == VMState.NONE) + engine.State = VMState.BREAK; + return engine.State; + } + } +} diff --git a/src/Neo.VM/EvaluationStack.cs b/src/Neo.VM/EvaluationStack.cs new file mode 100644 index 0000000000..b5b728ed46 --- /dev/null +++ b/src/Neo.VM/EvaluationStack.cs @@ -0,0 +1,162 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project 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; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; + +namespace Neo.VM +{ + /// + /// Represents the evaluation stack in the VM. + /// + public sealed class EvaluationStack : IReadOnlyList + { + private readonly List innerList = new(); + private readonly ReferenceCounter referenceCounter; + + internal EvaluationStack(ReferenceCounter referenceCounter) + { + this.referenceCounter = referenceCounter; + } + + /// + /// Gets the number of items on the stack. + /// + public int Count => innerList.Count; + + internal void Clear() + { + foreach (StackItem item in innerList) + referenceCounter.RemoveStackReference(item); + innerList.Clear(); + } + + internal void CopyTo(EvaluationStack stack, int count = -1) + { + if (count < -1 || count > innerList.Count) + throw new ArgumentOutOfRangeException(nameof(count)); + if (count == 0) return; + if (count == -1 || count == innerList.Count) + stack.innerList.AddRange(innerList); + else + stack.innerList.AddRange(innerList.Skip(innerList.Count - count)); + } + + public IEnumerator GetEnumerator() + { + return innerList.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return innerList.GetEnumerator(); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void Insert(int index, StackItem item) + { + if (index > innerList.Count) throw new InvalidOperationException($"Insert out of bounds: {index}/{innerList.Count}"); + innerList.Insert(innerList.Count - index, item); + referenceCounter.AddStackReference(item); + } + + internal void MoveTo(EvaluationStack stack, int count = -1) + { + if (count == 0) return; + CopyTo(stack, count); + if (count == -1 || count == innerList.Count) + innerList.Clear(); + else + innerList.RemoveRange(innerList.Count - count, count); + } + + /// + /// Returns the item at the specified index from the top of the stack without removing it. + /// + /// The index of the object from the top of the stack. + /// The item at the specified index. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public StackItem Peek(int index = 0) + { + if (index >= innerList.Count) throw new InvalidOperationException($"Peek out of bounds: {index}/{innerList.Count}"); + if (index < 0) + { + index += innerList.Count; + if (index < 0) throw new InvalidOperationException($"Peek out of bounds: {index}/{innerList.Count}"); + } + return innerList[innerList.Count - index - 1]; + } + + StackItem IReadOnlyList.this[int index] => Peek(index); + + /// + /// Pushes an item onto the top of the stack. + /// + /// The item to be pushed. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Push(StackItem item) + { + innerList.Add(item); + referenceCounter.AddStackReference(item); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void Reverse(int n) + { + if (n < 0 || n > innerList.Count) + throw new ArgumentOutOfRangeException(nameof(n)); + if (n <= 1) return; + innerList.Reverse(innerList.Count - n, n); + } + + /// + /// Removes and returns the item at the top of the stack. + /// + /// The item removed from the top of the stack. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public StackItem Pop() + { + return Remove(0); + } + + /// + /// Removes and returns the item at the top of the stack and convert it to the specified type. + /// + /// The type to convert to. + /// The item removed from the top of the stack. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public T Pop() where T : StackItem + { + return Remove(0); + } + + internal T Remove(int index) where T : StackItem + { + if (index >= innerList.Count) + throw new ArgumentOutOfRangeException(nameof(index)); + if (index < 0) + { + index += innerList.Count; + if (index < 0) + throw new ArgumentOutOfRangeException(nameof(index)); + } + index = innerList.Count - index - 1; + if (innerList[index] is not T item) + throw new InvalidCastException($"The item can't be casted to type {typeof(T)}"); + innerList.RemoveAt(index); + referenceCounter.RemoveStackReference(item); + return item; + } + } +} diff --git a/src/Neo.VM/ExceptionHandlingContext.cs b/src/Neo.VM/ExceptionHandlingContext.cs new file mode 100644 index 0000000000..dd3f03823e --- /dev/null +++ b/src/Neo.VM/ExceptionHandlingContext.cs @@ -0,0 +1,57 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project 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.Diagnostics; + +namespace Neo.VM +{ + /// + /// Represents the context used for exception handling. + /// + [DebuggerDisplay("State={State}, CatchPointer={CatchPointer}, FinallyPointer={FinallyPointer}, EndPointer={EndPointer}")] + public sealed class ExceptionHandlingContext + { + /// + /// The position of the block. + /// + public int CatchPointer { get; } + + /// + /// The position of the block. + /// + public int FinallyPointer { get; } + + /// + /// The end position of the -- block. + /// + public int EndPointer { get; internal set; } = -1; + + /// + /// Indicates whether the block is included in the context. + /// + public bool HasCatch => CatchPointer >= 0; + + /// + /// Indicates whether the block is included in the context. + /// + public bool HasFinally => FinallyPointer >= 0; + + /// + /// Indicates the state of the context. + /// + public ExceptionHandlingState State { get; internal set; } = ExceptionHandlingState.Try; + + internal ExceptionHandlingContext(int catchPointer, int finallyPointer) + { + this.CatchPointer = catchPointer; + this.FinallyPointer = finallyPointer; + } + } +} diff --git a/src/Neo.VM/ExceptionHandlingState.cs b/src/Neo.VM/ExceptionHandlingState.cs new file mode 100644 index 0000000000..ea3a484a9c --- /dev/null +++ b/src/Neo.VM/ExceptionHandlingState.cs @@ -0,0 +1,33 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project 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.VM +{ + /// + /// Indicates the state of the . + /// + public enum ExceptionHandlingState : byte + { + /// + /// Indicates that the block is being executed. + /// + Try, + + /// + /// Indicates that the block is being executed. + /// + Catch, + + /// + /// Indicates that the block is being executed. + /// + Finally + } +} diff --git a/src/Neo.VM/ExecutionContext.SharedStates.cs b/src/Neo.VM/ExecutionContext.SharedStates.cs new file mode 100644 index 0000000000..0e037fcf0a --- /dev/null +++ b/src/Neo.VM/ExecutionContext.SharedStates.cs @@ -0,0 +1,33 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project 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; + +namespace Neo.VM +{ + partial class ExecutionContext + { + private class SharedStates + { + public readonly Script Script; + public readonly EvaluationStack EvaluationStack; + public Slot? StaticFields; + public readonly Dictionary States; + + public SharedStates(Script script, ReferenceCounter referenceCounter) + { + this.Script = script; + this.EvaluationStack = new EvaluationStack(referenceCounter); + this.States = new Dictionary(); + } + } + } +} diff --git a/src/Neo.VM/ExecutionContext.cs b/src/Neo.VM/ExecutionContext.cs new file mode 100644 index 0000000000..be83be823e --- /dev/null +++ b/src/Neo.VM/ExecutionContext.cs @@ -0,0 +1,169 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project 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.Diagnostics; +using System.Runtime.CompilerServices; + +namespace Neo.VM +{ + /// + /// Represents a frame in the VM execution stack. + /// + [DebuggerDisplay("InstructionPointer={InstructionPointer}")] + public sealed partial class ExecutionContext + { + private readonly SharedStates shared_states; + private int instructionPointer; + + /// + /// Indicates the number of values that the context should return when it is unloaded. + /// + public int RVCount { get; } + + /// + /// The script to run in this context. + /// + public Script Script => shared_states.Script; + + /// + /// The evaluation stack for this context. + /// + public EvaluationStack EvaluationStack => shared_states.EvaluationStack; + + /// + /// The slot used to store the static fields. + /// + public Slot? StaticFields + { + get => shared_states.StaticFields; + internal set => shared_states.StaticFields = value; + } + + /// + /// The slot used to store the local variables of the current method. + /// + public Slot? LocalVariables { get; internal set; } + + /// + /// The slot used to store the arguments of the current method. + /// + public Slot? Arguments { get; internal set; } + + /// + /// The stack containing nested . + /// + public Stack? TryStack { get; internal set; } + + /// + /// The pointer indicating the current instruction. + /// + public int InstructionPointer + { + get + { + return instructionPointer; + } + internal set + { + if (value < 0 || value > Script.Length) + throw new ArgumentOutOfRangeException(nameof(value)); + instructionPointer = value; + } + } + + /// + /// Returns the current . + /// + public Instruction? CurrentInstruction + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + return GetInstruction(InstructionPointer); + } + } + + /// + /// Returns the next . + /// + public Instruction? NextInstruction + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + Instruction? current = CurrentInstruction; + if (current is null) return null; + return GetInstruction(InstructionPointer + current.Size); + } + } + + internal ExecutionContext(Script script, int rvcount, ReferenceCounter referenceCounter) + : this(new SharedStates(script, referenceCounter), rvcount, 0) + { + } + + private ExecutionContext(SharedStates shared_states, int rvcount, int initialPosition) + { + if (rvcount < -1 || rvcount > ushort.MaxValue) + throw new ArgumentOutOfRangeException(nameof(rvcount)); + this.shared_states = shared_states; + this.RVCount = rvcount; + this.InstructionPointer = initialPosition; + } + + /// + /// Clones the context so that they share the same script, stack, and static fields. + /// + /// The cloned context. + public ExecutionContext Clone() + { + return Clone(InstructionPointer); + } + + /// + /// Clones the context so that they share the same script, stack, and static fields. + /// + /// The instruction pointer of the new context. + /// The cloned context. + public ExecutionContext Clone(int initialPosition) + { + return new ExecutionContext(shared_states, 0, initialPosition); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private Instruction? GetInstruction(int ip) => ip >= Script.Length ? null : Script.GetInstruction(ip); + + /// + /// Gets custom data of the specified type. If the data does not exist, create a new one. + /// + /// The type of data to be obtained. + /// A delegate used to create the entry. If factory is null, new() will be used. + /// The custom data of the specified type. + public T GetState(Func? factory = null) where T : class, new() + { + if (!shared_states.States.TryGetValue(typeof(T), out object? value)) + { + value = factory is null ? new T() : factory(); + shared_states.States[typeof(T)] = value; + } + return (T)value; + } + + internal bool MoveNext() + { + Instruction? current = CurrentInstruction; + if (current is null) return false; + InstructionPointer += current.Size; + return InstructionPointer < Script.Length; + } + } +} diff --git a/src/Neo.VM/ExecutionEngine.cs b/src/Neo.VM/ExecutionEngine.cs new file mode 100644 index 0000000000..ab344b32ef --- /dev/null +++ b/src/Neo.VM/ExecutionEngine.cs @@ -0,0 +1,1702 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project 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; +using System.Collections.Generic; +using System.Linq; +using System.Numerics; +using System.Runtime.CompilerServices; +using Buffer = Neo.VM.Types.Buffer; +using VMArray = Neo.VM.Types.Array; + +namespace Neo.VM +{ + /// + /// Represents the VM used to execute the script. + /// + public class ExecutionEngine : IDisposable + { + private VMState state = VMState.BREAK; + private bool isJumping = false; + + /// + /// Restrictions on the VM. + /// + public ExecutionEngineLimits Limits { get; } + + /// + /// Used for reference counting of objects in the VM. + /// + public ReferenceCounter ReferenceCounter { get; } + + /// + /// The invocation stack of the VM. + /// + public Stack InvocationStack { get; } = new Stack(); + + /// + /// The top frame of the invocation stack. + /// + public ExecutionContext? CurrentContext { get; private set; } + + /// + /// The bottom frame of the invocation stack. + /// + public ExecutionContext? EntryContext { get; private set; } + + /// + /// The stack to store the return values. + /// + public EvaluationStack ResultStack { get; } + + /// + /// The VM object representing the uncaught exception. + /// + public StackItem? UncaughtException { get; private set; } + + /// + /// The current state of the VM. + /// + public VMState State + { + get + { + return state; + } + internal protected set + { + if (state != value) + { + state = value; + OnStateChanged(); + } + } + } + + /// + /// Initializes a new instance of the class. + /// + public ExecutionEngine() : this(new ReferenceCounter(), ExecutionEngineLimits.Default) + { + } + + /// + /// Initializes a new instance of the class with the specified and . + /// + /// The reference counter to be used. + /// Restrictions on the VM. + protected ExecutionEngine(ReferenceCounter referenceCounter, ExecutionEngineLimits limits) + { + this.Limits = limits; + this.ReferenceCounter = referenceCounter; + this.ResultStack = new EvaluationStack(referenceCounter); + } + + /// + /// Called when a context is unloaded. + /// + /// The context being unloaded. + protected virtual void ContextUnloaded(ExecutionContext context) + { + if (InvocationStack.Count == 0) + { + CurrentContext = null; + EntryContext = null; + } + else + { + CurrentContext = InvocationStack.Peek(); + } + if (context.StaticFields != null && context.StaticFields != CurrentContext?.StaticFields) + { + context.StaticFields.ClearReferences(); + } + context.LocalVariables?.ClearReferences(); + context.Arguments?.ClearReferences(); + } + + public virtual void Dispose() + { + InvocationStack.Clear(); + } + + /// + /// Start execution of the VM. + /// + /// + public virtual VMState Execute() + { + if (State == VMState.BREAK) + State = VMState.NONE; + while (State != VMState.HALT && State != VMState.FAULT) + ExecuteNext(); + return State; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void ExecuteCall(int position) + { + LoadContext(CurrentContext!.Clone(position)); + } + + private void ExecuteInstruction(Instruction instruction) + { + switch (instruction.OpCode) + { + //Push + case OpCode.PUSHINT8: + case OpCode.PUSHINT16: + case OpCode.PUSHINT32: + case OpCode.PUSHINT64: + case OpCode.PUSHINT128: + case OpCode.PUSHINT256: + { + Push(new BigInteger(instruction.Operand.Span)); + break; + } + case OpCode.PUSHT: + { + Push(StackItem.True); + break; + } + case OpCode.PUSHF: + { + Push(StackItem.False); + break; + } + case OpCode.PUSHA: + { + int position = checked(CurrentContext!.InstructionPointer + instruction.TokenI32); + if (position < 0 || position > CurrentContext.Script.Length) + throw new InvalidOperationException($"Bad pointer address: {position}"); + Push(new Pointer(CurrentContext.Script, position)); + break; + } + case OpCode.PUSHNULL: + { + Push(StackItem.Null); + break; + } + case OpCode.PUSHDATA1: + case OpCode.PUSHDATA2: + case OpCode.PUSHDATA4: + { + Limits.AssertMaxItemSize(instruction.Operand.Length); + Push(instruction.Operand); + break; + } + case OpCode.PUSHM1: + case OpCode.PUSH0: + case OpCode.PUSH1: + case OpCode.PUSH2: + case OpCode.PUSH3: + case OpCode.PUSH4: + case OpCode.PUSH5: + case OpCode.PUSH6: + case OpCode.PUSH7: + case OpCode.PUSH8: + case OpCode.PUSH9: + case OpCode.PUSH10: + case OpCode.PUSH11: + case OpCode.PUSH12: + case OpCode.PUSH13: + case OpCode.PUSH14: + case OpCode.PUSH15: + case OpCode.PUSH16: + { + Push((int)instruction.OpCode - (int)OpCode.PUSH0); + break; + } + + // Control + case OpCode.NOP: break; + case OpCode.JMP: + { + ExecuteJumpOffset(instruction.TokenI8); + break; + } + case OpCode.JMP_L: + { + ExecuteJumpOffset(instruction.TokenI32); + break; + } + case OpCode.JMPIF: + { + if (Pop().GetBoolean()) + ExecuteJumpOffset(instruction.TokenI8); + break; + } + case OpCode.JMPIF_L: + { + if (Pop().GetBoolean()) + ExecuteJumpOffset(instruction.TokenI32); + break; + } + case OpCode.JMPIFNOT: + { + if (!Pop().GetBoolean()) + ExecuteJumpOffset(instruction.TokenI8); + break; + } + case OpCode.JMPIFNOT_L: + { + if (!Pop().GetBoolean()) + ExecuteJumpOffset(instruction.TokenI32); + break; + } + case OpCode.JMPEQ: + { + var x2 = Pop().GetInteger(); + var x1 = Pop().GetInteger(); + if (x1 == x2) + ExecuteJumpOffset(instruction.TokenI8); + break; + } + case OpCode.JMPEQ_L: + { + var x2 = Pop().GetInteger(); + var x1 = Pop().GetInteger(); + if (x1 == x2) + ExecuteJumpOffset(instruction.TokenI32); + break; + } + case OpCode.JMPNE: + { + var x2 = Pop().GetInteger(); + var x1 = Pop().GetInteger(); + if (x1 != x2) + ExecuteJumpOffset(instruction.TokenI8); + break; + } + case OpCode.JMPNE_L: + { + var x2 = Pop().GetInteger(); + var x1 = Pop().GetInteger(); + if (x1 != x2) + ExecuteJumpOffset(instruction.TokenI32); + break; + } + case OpCode.JMPGT: + { + var x2 = Pop().GetInteger(); + var x1 = Pop().GetInteger(); + if (x1 > x2) + ExecuteJumpOffset(instruction.TokenI8); + break; + } + case OpCode.JMPGT_L: + { + var x2 = Pop().GetInteger(); + var x1 = Pop().GetInteger(); + if (x1 > x2) + ExecuteJumpOffset(instruction.TokenI32); + break; + } + case OpCode.JMPGE: + { + var x2 = Pop().GetInteger(); + var x1 = Pop().GetInteger(); + if (x1 >= x2) + ExecuteJumpOffset(instruction.TokenI8); + break; + } + case OpCode.JMPGE_L: + { + var x2 = Pop().GetInteger(); + var x1 = Pop().GetInteger(); + if (x1 >= x2) + ExecuteJumpOffset(instruction.TokenI32); + break; + } + case OpCode.JMPLT: + { + var x2 = Pop().GetInteger(); + var x1 = Pop().GetInteger(); + if (x1 < x2) + ExecuteJumpOffset(instruction.TokenI8); + break; + } + case OpCode.JMPLT_L: + { + var x2 = Pop().GetInteger(); + var x1 = Pop().GetInteger(); + if (x1 < x2) + ExecuteJumpOffset(instruction.TokenI32); + break; + } + case OpCode.JMPLE: + { + var x2 = Pop().GetInteger(); + var x1 = Pop().GetInteger(); + if (x1 <= x2) + ExecuteJumpOffset(instruction.TokenI8); + break; + } + case OpCode.JMPLE_L: + { + var x2 = Pop().GetInteger(); + var x1 = Pop().GetInteger(); + if (x1 <= x2) + ExecuteJumpOffset(instruction.TokenI32); + break; + } + case OpCode.CALL: + { + ExecuteCall(checked(CurrentContext!.InstructionPointer + instruction.TokenI8)); + break; + } + case OpCode.CALL_L: + { + ExecuteCall(checked(CurrentContext!.InstructionPointer + instruction.TokenI32)); + break; + } + case OpCode.CALLA: + { + var x = Pop(); + if (x.Script != CurrentContext!.Script) + throw new InvalidOperationException("Pointers can't be shared between scripts"); + ExecuteCall(x.Position); + break; + } + case OpCode.CALLT: + { + LoadToken(instruction.TokenU16); + break; + } + case OpCode.ABORT: + { + throw new Exception($"{OpCode.ABORT} is executed."); + } + case OpCode.ASSERT: + { + var x = Pop().GetBoolean(); + if (!x) + throw new Exception($"{OpCode.ASSERT} is executed with false result."); + break; + } + case OpCode.THROW: + { + ExecuteThrow(Pop()); + break; + } + case OpCode.TRY: + { + int catchOffset = instruction.TokenI8; + int finallyOffset = instruction.TokenI8_1; + ExecuteTry(catchOffset, finallyOffset); + break; + } + case OpCode.TRY_L: + { + int catchOffset = instruction.TokenI32; + int finallyOffset = instruction.TokenI32_1; + ExecuteTry(catchOffset, finallyOffset); + break; + } + case OpCode.ENDTRY: + { + int endOffset = instruction.TokenI8; + ExecuteEndTry(endOffset); + break; + } + case OpCode.ENDTRY_L: + { + int endOffset = instruction.TokenI32; + ExecuteEndTry(endOffset); + break; + } + case OpCode.ENDFINALLY: + { + if (CurrentContext!.TryStack is null) + throw new InvalidOperationException($"The corresponding TRY block cannot be found."); + if (!CurrentContext.TryStack.TryPop(out ExceptionHandlingContext? currentTry)) + throw new InvalidOperationException($"The corresponding TRY block cannot be found."); + + if (UncaughtException is null) + CurrentContext.InstructionPointer = currentTry.EndPointer; + else + HandleException(); + + isJumping = true; + break; + } + case OpCode.RET: + { + ExecutionContext context_pop = InvocationStack.Pop(); + EvaluationStack stack_eval = InvocationStack.Count == 0 ? ResultStack : InvocationStack.Peek().EvaluationStack; + if (context_pop.EvaluationStack != stack_eval) + { + if (context_pop.RVCount >= 0 && context_pop.EvaluationStack.Count != context_pop.RVCount) + throw new InvalidOperationException("RVCount doesn't match with EvaluationStack"); + context_pop.EvaluationStack.CopyTo(stack_eval); + } + if (InvocationStack.Count == 0) + State = VMState.HALT; + ContextUnloaded(context_pop); + isJumping = true; + break; + } + case OpCode.SYSCALL: + { + OnSysCall(instruction.TokenU32); + break; + } + + // Stack ops + case OpCode.DEPTH: + { + Push(CurrentContext!.EvaluationStack.Count); + break; + } + case OpCode.DROP: + { + Pop(); + break; + } + case OpCode.NIP: + { + CurrentContext!.EvaluationStack.Remove(1); + break; + } + case OpCode.XDROP: + { + int n = (int)Pop().GetInteger(); + if (n < 0) + throw new InvalidOperationException($"The negative value {n} is invalid for OpCode.{instruction.OpCode}."); + CurrentContext!.EvaluationStack.Remove(n); + break; + } + case OpCode.CLEAR: + { + CurrentContext!.EvaluationStack.Clear(); + break; + } + case OpCode.DUP: + { + Push(Peek()); + break; + } + case OpCode.OVER: + { + Push(Peek(1)); + break; + } + case OpCode.PICK: + { + int n = (int)Pop().GetInteger(); + if (n < 0) + throw new InvalidOperationException($"The negative value {n} is invalid for OpCode.{instruction.OpCode}."); + Push(Peek(n)); + break; + } + case OpCode.TUCK: + { + CurrentContext!.EvaluationStack.Insert(2, Peek()); + break; + } + case OpCode.SWAP: + { + var x = CurrentContext!.EvaluationStack.Remove(1); + Push(x); + break; + } + case OpCode.ROT: + { + var x = CurrentContext!.EvaluationStack.Remove(2); + Push(x); + break; + } + case OpCode.ROLL: + { + int n = (int)Pop().GetInteger(); + if (n < 0) + throw new InvalidOperationException($"The negative value {n} is invalid for OpCode.{instruction.OpCode}."); + if (n == 0) break; + var x = CurrentContext!.EvaluationStack.Remove(n); + Push(x); + break; + } + case OpCode.REVERSE3: + { + CurrentContext!.EvaluationStack.Reverse(3); + break; + } + case OpCode.REVERSE4: + { + CurrentContext!.EvaluationStack.Reverse(4); + break; + } + case OpCode.REVERSEN: + { + int n = (int)Pop().GetInteger(); + CurrentContext!.EvaluationStack.Reverse(n); + break; + } + + //Slot + case OpCode.INITSSLOT: + { + if (CurrentContext!.StaticFields != null) + throw new InvalidOperationException($"{instruction.OpCode} cannot be executed twice."); + if (instruction.TokenU8 == 0) + throw new InvalidOperationException($"The operand {instruction.TokenU8} is invalid for OpCode.{instruction.OpCode}."); + CurrentContext.StaticFields = new Slot(instruction.TokenU8, ReferenceCounter); + break; + } + case OpCode.INITSLOT: + { + if (CurrentContext!.LocalVariables != null || CurrentContext.Arguments != null) + throw new InvalidOperationException($"{instruction.OpCode} cannot be executed twice."); + if (instruction.TokenU16 == 0) + throw new InvalidOperationException($"The operand {instruction.TokenU16} is invalid for OpCode.{instruction.OpCode}."); + if (instruction.TokenU8 > 0) + { + CurrentContext.LocalVariables = new Slot(instruction.TokenU8, ReferenceCounter); + } + if (instruction.TokenU8_1 > 0) + { + StackItem[] items = new StackItem[instruction.TokenU8_1]; + for (int i = 0; i < instruction.TokenU8_1; i++) + { + items[i] = Pop(); + } + CurrentContext.Arguments = new Slot(items, ReferenceCounter); + } + break; + } + case OpCode.LDSFLD0: + case OpCode.LDSFLD1: + case OpCode.LDSFLD2: + case OpCode.LDSFLD3: + case OpCode.LDSFLD4: + case OpCode.LDSFLD5: + case OpCode.LDSFLD6: + { + ExecuteLoadFromSlot(CurrentContext!.StaticFields, instruction.OpCode - OpCode.LDSFLD0); + break; + } + case OpCode.LDSFLD: + { + ExecuteLoadFromSlot(CurrentContext!.StaticFields, instruction.TokenU8); + break; + } + case OpCode.STSFLD0: + case OpCode.STSFLD1: + case OpCode.STSFLD2: + case OpCode.STSFLD3: + case OpCode.STSFLD4: + case OpCode.STSFLD5: + case OpCode.STSFLD6: + { + ExecuteStoreToSlot(CurrentContext!.StaticFields, instruction.OpCode - OpCode.STSFLD0); + break; + } + case OpCode.STSFLD: + { + ExecuteStoreToSlot(CurrentContext!.StaticFields, instruction.TokenU8); + break; + } + case OpCode.LDLOC0: + case OpCode.LDLOC1: + case OpCode.LDLOC2: + case OpCode.LDLOC3: + case OpCode.LDLOC4: + case OpCode.LDLOC5: + case OpCode.LDLOC6: + { + ExecuteLoadFromSlot(CurrentContext!.LocalVariables, instruction.OpCode - OpCode.LDLOC0); + break; + } + case OpCode.LDLOC: + { + ExecuteLoadFromSlot(CurrentContext!.LocalVariables, instruction.TokenU8); + break; + } + case OpCode.STLOC0: + case OpCode.STLOC1: + case OpCode.STLOC2: + case OpCode.STLOC3: + case OpCode.STLOC4: + case OpCode.STLOC5: + case OpCode.STLOC6: + { + ExecuteStoreToSlot(CurrentContext!.LocalVariables, instruction.OpCode - OpCode.STLOC0); + break; + } + case OpCode.STLOC: + { + ExecuteStoreToSlot(CurrentContext!.LocalVariables, instruction.TokenU8); + break; + } + case OpCode.LDARG0: + case OpCode.LDARG1: + case OpCode.LDARG2: + case OpCode.LDARG3: + case OpCode.LDARG4: + case OpCode.LDARG5: + case OpCode.LDARG6: + { + ExecuteLoadFromSlot(CurrentContext!.Arguments, instruction.OpCode - OpCode.LDARG0); + break; + } + case OpCode.LDARG: + { + ExecuteLoadFromSlot(CurrentContext!.Arguments, instruction.TokenU8); + break; + } + case OpCode.STARG0: + case OpCode.STARG1: + case OpCode.STARG2: + case OpCode.STARG3: + case OpCode.STARG4: + case OpCode.STARG5: + case OpCode.STARG6: + { + ExecuteStoreToSlot(CurrentContext!.Arguments, instruction.OpCode - OpCode.STARG0); + break; + } + case OpCode.STARG: + { + ExecuteStoreToSlot(CurrentContext!.Arguments, instruction.TokenU8); + break; + } + + // Splice + case OpCode.NEWBUFFER: + { + int length = (int)Pop().GetInteger(); + Limits.AssertMaxItemSize(length); + Push(new Buffer(length)); + break; + } + case OpCode.MEMCPY: + { + int count = (int)Pop().GetInteger(); + if (count < 0) + throw new InvalidOperationException($"The value {count} is out of range."); + int si = (int)Pop().GetInteger(); + if (si < 0) + throw new InvalidOperationException($"The value {si} is out of range."); + ReadOnlySpan src = Pop().GetSpan(); + if (checked(si + count) > src.Length) + throw new InvalidOperationException($"The value {count} is out of range."); + int di = (int)Pop().GetInteger(); + if (di < 0) + throw new InvalidOperationException($"The value {di} is out of range."); + Buffer dst = Pop(); + if (checked(di + count) > dst.Size) + throw new InvalidOperationException($"The value {count} is out of range."); + src.Slice(si, count).CopyTo(dst.InnerBuffer.Span[di..]); + break; + } + case OpCode.CAT: + { + var x2 = Pop().GetSpan(); + var x1 = Pop().GetSpan(); + int length = x1.Length + x2.Length; + Limits.AssertMaxItemSize(length); + Buffer result = new(length, false); + x1.CopyTo(result.InnerBuffer.Span); + x2.CopyTo(result.InnerBuffer.Span[x1.Length..]); + Push(result); + break; + } + case OpCode.SUBSTR: + { + int count = (int)Pop().GetInteger(); + if (count < 0) + throw new InvalidOperationException($"The value {count} is out of range."); + int index = (int)Pop().GetInteger(); + if (index < 0) + throw new InvalidOperationException($"The value {index} is out of range."); + var x = Pop().GetSpan(); + if (index + count > x.Length) + throw new InvalidOperationException($"The value {count} is out of range."); + Buffer result = new(count, false); + x.Slice(index, count).CopyTo(result.InnerBuffer.Span); + Push(result); + break; + } + case OpCode.LEFT: + { + int count = (int)Pop().GetInteger(); + if (count < 0) + throw new InvalidOperationException($"The value {count} is out of range."); + var x = Pop().GetSpan(); + if (count > x.Length) + throw new InvalidOperationException($"The value {count} is out of range."); + Buffer result = new(count, false); + x[..count].CopyTo(result.InnerBuffer.Span); + Push(result); + break; + } + case OpCode.RIGHT: + { + int count = (int)Pop().GetInteger(); + if (count < 0) + throw new InvalidOperationException($"The value {count} is out of range."); + var x = Pop().GetSpan(); + if (count > x.Length) + throw new InvalidOperationException($"The value {count} is out of range."); + Buffer result = new(count, false); + x[^count..^0].CopyTo(result.InnerBuffer.Span); + Push(result); + break; + } + + // Bitwise logic + case OpCode.INVERT: + { + var x = Pop().GetInteger(); + Push(~x); + break; + } + case OpCode.AND: + { + var x2 = Pop().GetInteger(); + var x1 = Pop().GetInteger(); + Push(x1 & x2); + break; + } + case OpCode.OR: + { + var x2 = Pop().GetInteger(); + var x1 = Pop().GetInteger(); + Push(x1 | x2); + break; + } + case OpCode.XOR: + { + var x2 = Pop().GetInteger(); + var x1 = Pop().GetInteger(); + Push(x1 ^ x2); + break; + } + case OpCode.EQUAL: + { + StackItem x2 = Pop(); + StackItem x1 = Pop(); + Push(x1.Equals(x2, Limits)); + break; + } + case OpCode.NOTEQUAL: + { + StackItem x2 = Pop(); + StackItem x1 = Pop(); + Push(!x1.Equals(x2, Limits)); + break; + } + + // Numeric + case OpCode.SIGN: + { + var x = Pop().GetInteger(); + Push(x.Sign); + break; + } + case OpCode.ABS: + { + var x = Pop().GetInteger(); + Push(BigInteger.Abs(x)); + break; + } + case OpCode.NEGATE: + { + var x = Pop().GetInteger(); + Push(-x); + break; + } + case OpCode.INC: + { + var x = Pop().GetInteger(); + Push(x + 1); + break; + } + case OpCode.DEC: + { + var x = Pop().GetInteger(); + Push(x - 1); + break; + } + case OpCode.ADD: + { + var x2 = Pop().GetInteger(); + var x1 = Pop().GetInteger(); + Push(x1 + x2); + break; + } + case OpCode.SUB: + { + var x2 = Pop().GetInteger(); + var x1 = Pop().GetInteger(); + Push(x1 - x2); + break; + } + case OpCode.MUL: + { + var x2 = Pop().GetInteger(); + var x1 = Pop().GetInteger(); + Push(x1 * x2); + break; + } + case OpCode.DIV: + { + var x2 = Pop().GetInteger(); + var x1 = Pop().GetInteger(); + Push(x1 / x2); + break; + } + case OpCode.MOD: + { + var x2 = Pop().GetInteger(); + var x1 = Pop().GetInteger(); + Push(x1 % x2); + break; + } + case OpCode.POW: + { + var exponent = (int)Pop().GetInteger(); + Limits.AssertShift(exponent); + var value = Pop().GetInteger(); + Push(BigInteger.Pow(value, exponent)); + break; + } + case OpCode.SQRT: + { + Push(Pop().GetInteger().Sqrt()); + break; + } + case OpCode.MODMUL: + { + var modulus = Pop().GetInteger(); + var x2 = Pop().GetInteger(); + var x1 = Pop().GetInteger(); + Push(x1 * x2 % modulus); + break; + } + case OpCode.MODPOW: + { + var modulus = Pop().GetInteger(); + var exponent = Pop().GetInteger(); + var value = Pop().GetInteger(); + var result = exponent == -1 + ? value.ModInverse(modulus) + : BigInteger.ModPow(value, exponent, modulus); + Push(result); + break; + } + case OpCode.SHL: + { + int shift = (int)Pop().GetInteger(); + Limits.AssertShift(shift); + if (shift == 0) break; + var x = Pop().GetInteger(); + Push(x << shift); + break; + } + case OpCode.SHR: + { + int shift = (int)Pop().GetInteger(); + Limits.AssertShift(shift); + if (shift == 0) break; + var x = Pop().GetInteger(); + Push(x >> shift); + break; + } + case OpCode.NOT: + { + var x = Pop().GetBoolean(); + Push(!x); + break; + } + case OpCode.BOOLAND: + { + var x2 = Pop().GetBoolean(); + var x1 = Pop().GetBoolean(); + Push(x1 && x2); + break; + } + case OpCode.BOOLOR: + { + var x2 = Pop().GetBoolean(); + var x1 = Pop().GetBoolean(); + Push(x1 || x2); + break; + } + case OpCode.NZ: + { + var x = Pop().GetInteger(); + Push(!x.IsZero); + break; + } + case OpCode.NUMEQUAL: + { + var x2 = Pop().GetInteger(); + var x1 = Pop().GetInteger(); + Push(x1 == x2); + break; + } + case OpCode.NUMNOTEQUAL: + { + var x2 = Pop().GetInteger(); + var x1 = Pop().GetInteger(); + Push(x1 != x2); + break; + } + case OpCode.LT: + { + var x2 = Pop(); + var x1 = Pop(); + if (x1.IsNull || x2.IsNull) + Push(false); + else + Push(x1.GetInteger() < x2.GetInteger()); + break; + } + case OpCode.LE: + { + var x2 = Pop(); + var x1 = Pop(); + if (x1.IsNull || x2.IsNull) + Push(false); + else + Push(x1.GetInteger() <= x2.GetInteger()); + break; + } + case OpCode.GT: + { + var x2 = Pop(); + var x1 = Pop(); + if (x1.IsNull || x2.IsNull) + Push(false); + else + Push(x1.GetInteger() > x2.GetInteger()); + break; + } + case OpCode.GE: + { + var x2 = Pop(); + var x1 = Pop(); + if (x1.IsNull || x2.IsNull) + Push(false); + else + Push(x1.GetInteger() >= x2.GetInteger()); + break; + } + case OpCode.MIN: + { + var x2 = Pop().GetInteger(); + var x1 = Pop().GetInteger(); + Push(BigInteger.Min(x1, x2)); + break; + } + case OpCode.MAX: + { + var x2 = Pop().GetInteger(); + var x1 = Pop().GetInteger(); + Push(BigInteger.Max(x1, x2)); + break; + } + case OpCode.WITHIN: + { + BigInteger b = Pop().GetInteger(); + BigInteger a = Pop().GetInteger(); + var x = Pop().GetInteger(); + Push(a <= x && x < b); + break; + } + + // Compound-type + case OpCode.PACKMAP: + { + int size = (int)Pop().GetInteger(); + if (size < 0 || size * 2 > CurrentContext!.EvaluationStack.Count) + throw new InvalidOperationException($"The value {size} is out of range."); + Map map = new(ReferenceCounter); + for (int i = 0; i < size; i++) + { + PrimitiveType key = Pop(); + StackItem value = Pop(); + map[key] = value; + } + Push(map); + break; + } + case OpCode.PACKSTRUCT: + { + int size = (int)Pop().GetInteger(); + if (size < 0 || size > CurrentContext!.EvaluationStack.Count) + throw new InvalidOperationException($"The value {size} is out of range."); + Struct @struct = new(ReferenceCounter); + for (int i = 0; i < size; i++) + { + StackItem item = Pop(); + @struct.Add(item); + } + Push(@struct); + break; + } + case OpCode.PACK: + { + int size = (int)Pop().GetInteger(); + if (size < 0 || size > CurrentContext!.EvaluationStack.Count) + throw new InvalidOperationException($"The value {size} is out of range."); + VMArray array = new(ReferenceCounter); + for (int i = 0; i < size; i++) + { + StackItem item = Pop(); + array.Add(item); + } + Push(array); + break; + } + case OpCode.UNPACK: + { + CompoundType compound = Pop(); + switch (compound) + { + case Map map: + foreach (var (key, value) in map.Reverse()) + { + Push(value); + Push(key); + } + break; + case VMArray array: + for (int i = array.Count - 1; i >= 0; i--) + { + Push(array[i]); + } + break; + default: + throw new InvalidOperationException($"Invalid type for {instruction.OpCode}: {compound.Type}"); + } + Push(compound.Count); + break; + } + case OpCode.NEWARRAY0: + { + Push(new VMArray(ReferenceCounter)); + break; + } + case OpCode.NEWARRAY: + case OpCode.NEWARRAY_T: + { + int n = (int)Pop().GetInteger(); + if (n < 0 || n > Limits.MaxStackSize) + throw new InvalidOperationException($"MaxStackSize exceed: {n}"); + StackItem item; + if (instruction.OpCode == OpCode.NEWARRAY_T) + { + StackItemType type = (StackItemType)instruction.TokenU8; + if (!Enum.IsDefined(typeof(StackItemType), type)) + throw new InvalidOperationException($"Invalid type for {instruction.OpCode}: {instruction.TokenU8}"); + item = instruction.TokenU8 switch + { + (byte)StackItemType.Boolean => StackItem.False, + (byte)StackItemType.Integer => Integer.Zero, + (byte)StackItemType.ByteString => ByteString.Empty, + _ => StackItem.Null + }; + } + else + { + item = StackItem.Null; + } + Push(new VMArray(ReferenceCounter, Enumerable.Repeat(item, n))); + break; + } + case OpCode.NEWSTRUCT0: + { + Push(new Struct(ReferenceCounter)); + break; + } + case OpCode.NEWSTRUCT: + { + int n = (int)Pop().GetInteger(); + if (n < 0 || n > Limits.MaxStackSize) + throw new InvalidOperationException($"MaxStackSize exceed: {n}"); + Struct result = new(ReferenceCounter); + for (var i = 0; i < n; i++) + result.Add(StackItem.Null); + Push(result); + break; + } + case OpCode.NEWMAP: + { + Push(new Map(ReferenceCounter)); + break; + } + case OpCode.SIZE: + { + var x = Pop(); + switch (x) + { + case CompoundType compound: + Push(compound.Count); + break; + case PrimitiveType primitive: + Push(primitive.Size); + break; + case Buffer buffer: + Push(buffer.Size); + break; + default: + throw new InvalidOperationException($"Invalid type for {instruction.OpCode}: {x.Type}"); + } + break; + } + case OpCode.HASKEY: + { + PrimitiveType key = Pop(); + var x = Pop(); + switch (x) + { + case VMArray array: + { + int index = (int)key.GetInteger(); + if (index < 0) + throw new InvalidOperationException($"The negative value {index} is invalid for OpCode.{instruction.OpCode}."); + Push(index < array.Count); + break; + } + case Map map: + { + Push(map.ContainsKey(key)); + break; + } + case Buffer buffer: + { + int index = (int)key.GetInteger(); + if (index < 0) + throw new InvalidOperationException($"The negative value {index} is invalid for OpCode.{instruction.OpCode}."); + Push(index < buffer.Size); + break; + } + case ByteString array: + { + int index = (int)key.GetInteger(); + if (index < 0) + throw new InvalidOperationException($"The negative value {index} is invalid for OpCode.{instruction.OpCode}."); + Push(index < array.Size); + break; + } + default: + throw new InvalidOperationException($"Invalid type for {instruction.OpCode}: {x.Type}"); + } + break; + } + case OpCode.KEYS: + { + Map map = Pop(); + Push(new VMArray(ReferenceCounter, map.Keys)); + break; + } + case OpCode.VALUES: + { + var x = Pop(); + IEnumerable values = x switch + { + VMArray array => array, + Map map => map.Values, + _ => throw new InvalidOperationException($"Invalid type for {instruction.OpCode}: {x.Type}"), + }; + VMArray newArray = new(ReferenceCounter); + foreach (StackItem item in values) + if (item is Struct s) + newArray.Add(s.Clone(Limits)); + else + newArray.Add(item); + Push(newArray); + break; + } + case OpCode.PICKITEM: + { + PrimitiveType key = Pop(); + var x = Pop(); + switch (x) + { + case VMArray array: + { + int index = (int)key.GetInteger(); + if (index < 0 || index >= array.Count) + throw new CatchableException($"The value {index} is out of range."); + Push(array[index]); + break; + } + case Map map: + { + if (!map.TryGetValue(key, out StackItem? value)) + throw new CatchableException($"Key not found in {nameof(Map)}"); + Push(value); + break; + } + case PrimitiveType primitive: + { + ReadOnlySpan byteArray = primitive.GetSpan(); + int index = (int)key.GetInteger(); + if (index < 0 || index >= byteArray.Length) + throw new CatchableException($"The value {index} is out of range."); + Push((BigInteger)byteArray[index]); + break; + } + case Buffer buffer: + { + int index = (int)key.GetInteger(); + if (index < 0 || index >= buffer.Size) + throw new CatchableException($"The value {index} is out of range."); + Push((BigInteger)buffer.InnerBuffer.Span[index]); + break; + } + default: + throw new InvalidOperationException($"Invalid type for {instruction.OpCode}: {x.Type}"); + } + break; + } + case OpCode.APPEND: + { + StackItem newItem = Pop(); + VMArray array = Pop(); + if (newItem is Struct s) newItem = s.Clone(Limits); + array.Add(newItem); + break; + } + case OpCode.SETITEM: + { + StackItem value = Pop(); + if (value is Struct s) value = s.Clone(Limits); + PrimitiveType key = Pop(); + var x = Pop(); + switch (x) + { + case VMArray array: + { + int index = (int)key.GetInteger(); + if (index < 0 || index >= array.Count) + throw new CatchableException($"The value {index} is out of range."); + array[index] = value; + break; + } + case Map map: + { + map[key] = value; + break; + } + case Buffer buffer: + { + int index = (int)key.GetInteger(); + if (index < 0 || index >= buffer.Size) + throw new CatchableException($"The value {index} is out of range."); + if (value is not PrimitiveType p) + throw new InvalidOperationException($"Value must be a primitive type in {instruction.OpCode}"); + int b = (int)p.GetInteger(); + if (b < sbyte.MinValue || b > byte.MaxValue) + throw new InvalidOperationException($"Overflow in {instruction.OpCode}, {b} is not a byte type."); + buffer.InnerBuffer.Span[index] = (byte)b; + break; + } + default: + throw new InvalidOperationException($"Invalid type for {instruction.OpCode}: {x.Type}"); + } + break; + } + case OpCode.REVERSEITEMS: + { + var x = Pop(); + switch (x) + { + case VMArray array: + array.Reverse(); + break; + case Buffer buffer: + buffer.InnerBuffer.Span.Reverse(); + break; + default: + throw new InvalidOperationException($"Invalid type for {instruction.OpCode}: {x.Type}"); + } + break; + } + case OpCode.REMOVE: + { + PrimitiveType key = Pop(); + var x = Pop(); + switch (x) + { + case VMArray array: + int index = (int)key.GetInteger(); + if (index < 0 || index >= array.Count) + throw new InvalidOperationException($"The value {index} is out of range."); + array.RemoveAt(index); + break; + case Map map: + map.Remove(key); + break; + default: + throw new InvalidOperationException($"Invalid type for {instruction.OpCode}: {x.Type}"); + } + break; + } + case OpCode.CLEARITEMS: + { + CompoundType x = Pop(); + x.Clear(); + break; + } + case OpCode.POPITEM: + { + VMArray x = Pop(); + int index = x.Count - 1; + Push(x[index]); + x.RemoveAt(index); + break; + } + + //Types + case OpCode.ISNULL: + { + var x = Pop(); + Push(x.IsNull); + break; + } + case OpCode.ISTYPE: + { + var x = Pop(); + StackItemType type = (StackItemType)instruction.TokenU8; + if (type == StackItemType.Any || !Enum.IsDefined(typeof(StackItemType), type)) + throw new InvalidOperationException($"Invalid type: {type}"); + Push(x.Type == type); + break; + } + case OpCode.CONVERT: + { + var x = Pop(); + Push(x.ConvertTo((StackItemType)instruction.TokenU8)); + break; + } + case OpCode.ABORTMSG: + { + var msg = Pop().GetString(); + throw new Exception($"{OpCode.ABORTMSG} is executed. Reason: {msg}"); + } + case OpCode.ASSERTMSG: + { + var msg = Pop().GetString(); + var x = Pop().GetBoolean(); + if (!x) + throw new Exception($"{OpCode.ASSERTMSG} is executed with false result. Reason: {msg}"); + break; + } + default: throw new InvalidOperationException($"Opcode {instruction.OpCode} is undefined."); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void ExecuteEndTry(int endOffset) + { + if (CurrentContext!.TryStack is null) + throw new InvalidOperationException($"The corresponding TRY block cannot be found."); + if (!CurrentContext.TryStack.TryPeek(out ExceptionHandlingContext? currentTry)) + throw new InvalidOperationException($"The corresponding TRY block cannot be found."); + if (currentTry.State == ExceptionHandlingState.Finally) + throw new InvalidOperationException($"The opcode {OpCode.ENDTRY} can't be executed in a FINALLY block."); + + int endPointer = checked(CurrentContext.InstructionPointer + endOffset); + if (currentTry.HasFinally) + { + currentTry.State = ExceptionHandlingState.Finally; + currentTry.EndPointer = endPointer; + CurrentContext.InstructionPointer = currentTry.FinallyPointer; + } + else + { + CurrentContext.TryStack.Pop(); + CurrentContext.InstructionPointer = endPointer; + } + isJumping = true; + } + + /// + /// Jump to the specified position. + /// + /// The position to jump to. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected void ExecuteJump(int position) + { + if (position < 0 || position >= CurrentContext!.Script.Length) + throw new ArgumentOutOfRangeException($"Jump out of range for position: {position}"); + CurrentContext.InstructionPointer = position; + isJumping = true; + } + + /// + /// Jump to the specified offset from the current position. + /// + /// The offset from the current position to jump to. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected void ExecuteJumpOffset(int offset) + { + ExecuteJump(checked(CurrentContext!.InstructionPointer + offset)); + } + + private void ExecuteLoadFromSlot(Slot? slot, int index) + { + if (slot is null) + throw new InvalidOperationException("Slot has not been initialized."); + if (index < 0 || index >= slot.Count) + throw new InvalidOperationException($"Index out of range when loading from slot: {index}"); + Push(slot[index]); + } + + /// + /// Execute the next instruction. + /// + internal protected void ExecuteNext() + { + if (InvocationStack.Count == 0) + { + State = VMState.HALT; + } + else + { + try + { + ExecutionContext context = CurrentContext!; + Instruction instruction = context.CurrentInstruction ?? Instruction.RET; + PreExecuteInstruction(instruction); + try + { + ExecuteInstruction(instruction); + } + catch (CatchableException ex) when (Limits.CatchEngineExceptions) + { + ExecuteThrow(ex.Message); + } + PostExecuteInstruction(instruction); + if (!isJumping) context.MoveNext(); + isJumping = false; + } + catch (Exception e) + { + OnFault(e); + } + } + } + + private void ExecuteStoreToSlot(Slot? slot, int index) + { + if (slot is null) + throw new InvalidOperationException("Slot has not been initialized."); + if (index < 0 || index >= slot.Count) + throw new InvalidOperationException($"Index out of range when storing to slot: {index}"); + slot[index] = Pop(); + } + + /// + /// Throws a specified exception in the VM. + /// + /// The exception to be thrown. + protected void ExecuteThrow(StackItem ex) + { + UncaughtException = ex; + HandleException(); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void ExecuteTry(int catchOffset, int finallyOffset) + { + if (catchOffset == 0 && finallyOffset == 0) + throw new InvalidOperationException($"catchOffset and finallyOffset can't be 0 in a TRY block"); + if (CurrentContext!.TryStack is null) + CurrentContext.TryStack = new Stack(); + else if (CurrentContext.TryStack.Count >= Limits.MaxTryNestingDepth) + throw new InvalidOperationException("MaxTryNestingDepth exceed."); + int catchPointer = catchOffset == 0 ? -1 : checked(CurrentContext.InstructionPointer + catchOffset); + int finallyPointer = finallyOffset == 0 ? -1 : checked(CurrentContext.InstructionPointer + finallyOffset); + CurrentContext.TryStack.Push(new ExceptionHandlingContext(catchPointer, finallyPointer)); + } + + private void HandleException() + { + int pop = 0; + foreach (var executionContext in InvocationStack) + { + if (executionContext.TryStack != null) + { + while (executionContext.TryStack.TryPeek(out var tryContext)) + { + if (tryContext.State == ExceptionHandlingState.Finally || (tryContext.State == ExceptionHandlingState.Catch && !tryContext.HasFinally)) + { + executionContext.TryStack.Pop(); + continue; + } + for (int i = 0; i < pop; i++) + { + ContextUnloaded(InvocationStack.Pop()); + } + if (tryContext.State == ExceptionHandlingState.Try && tryContext.HasCatch) + { + tryContext.State = ExceptionHandlingState.Catch; + Push(UncaughtException!); + executionContext.InstructionPointer = tryContext.CatchPointer; + UncaughtException = null; + } + else + { + tryContext.State = ExceptionHandlingState.Finally; + executionContext.InstructionPointer = tryContext.FinallyPointer; + } + isJumping = true; + return; + } + } + ++pop; + } + + throw new VMUnhandledException(UncaughtException!); + } + + /// + /// Loads the specified context into the invocation stack. + /// + /// The context to load. + protected virtual void LoadContext(ExecutionContext context) + { + if (InvocationStack.Count >= Limits.MaxInvocationStackSize) + throw new InvalidOperationException($"MaxInvocationStackSize exceed: {InvocationStack.Count}"); + InvocationStack.Push(context); + if (EntryContext is null) EntryContext = context; + CurrentContext = context; + } + + /// + /// Create a new context with the specified script without loading. + /// + /// The script used to create the context. + /// The number of values that the context should return when it is unloaded. + /// The pointer indicating the current instruction. + /// The created context. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + protected ExecutionContext CreateContext(Script script, int rvcount, int initialPosition) + { + return new ExecutionContext(script, rvcount, ReferenceCounter) + { + InstructionPointer = initialPosition + }; + } + + /// + /// Create a new context with the specified script and load it. + /// + /// The script used to create the context. + /// The number of values that the context should return when it is unloaded. + /// The pointer indicating the current instruction. + /// The created context. + public ExecutionContext LoadScript(Script script, int rvcount = -1, int initialPosition = 0) + { + ExecutionContext context = CreateContext(script, rvcount, initialPosition); + LoadContext(context); + return context; + } + + /// + /// When overridden in a derived class, loads the specified method token. + /// Called when is executed. + /// + /// The method token to be loaded. + /// The created context. + protected virtual ExecutionContext LoadToken(ushort token) + { + throw new InvalidOperationException($"Token not found: {token}"); + } + + /// + /// Called when an exception that cannot be caught by the VM is thrown. + /// + /// The exception that caused the state. + protected virtual void OnFault(Exception ex) + { + State = VMState.FAULT; + } + + /// + /// Called when the state of the VM changed. + /// + protected virtual void OnStateChanged() + { + } + + /// + /// When overridden in a derived class, invokes the specified system call. + /// Called when is executed. + /// + /// The system call to be invoked. + protected virtual void OnSysCall(uint method) + { + throw new InvalidOperationException($"Syscall not found: {method}"); + } + + /// + /// Returns the item at the specified index from the top of the current stack without removing it. + /// + /// The index of the object from the top of the stack. + /// The item at the specified index. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public StackItem Peek(int index = 0) + { + return CurrentContext!.EvaluationStack.Peek(index); + } + + /// + /// Removes and returns the item at the top of the current stack. + /// + /// The item removed from the top of the stack. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public StackItem Pop() + { + return CurrentContext!.EvaluationStack.Pop(); + } + + /// + /// Removes and returns the item at the top of the current stack and convert it to the specified type. + /// + /// The type to convert to. + /// The item removed from the top of the stack. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public T Pop() where T : StackItem + { + return CurrentContext!.EvaluationStack.Pop(); + } + + /// + /// Called after an instruction is executed. + /// + protected virtual void PostExecuteInstruction(Instruction instruction) + { + if (ReferenceCounter.CheckZeroReferred() > Limits.MaxStackSize) + throw new InvalidOperationException($"MaxStackSize exceed: {ReferenceCounter.Count}"); + } + + /// + /// Called before an instruction is executed. + /// + protected virtual void PreExecuteInstruction(Instruction instruction) { } + + /// + /// Pushes an item onto the top of the current stack. + /// + /// The item to be pushed. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Push(StackItem item) + { + CurrentContext!.EvaluationStack.Push(item); + } + } +} diff --git a/src/Neo.VM/ExecutionEngineLimits.cs b/src/Neo.VM/ExecutionEngineLimits.cs new file mode 100644 index 0000000000..f31b40e5a1 --- /dev/null +++ b/src/Neo.VM/ExecutionEngineLimits.cs @@ -0,0 +1,87 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project 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.Runtime.CompilerServices; + +namespace Neo.VM +{ + /// + /// Represents the restrictions on the VM. + /// + public sealed record ExecutionEngineLimits + { + /// + /// The default strategy. + /// + public static readonly ExecutionEngineLimits Default = new(); + + /// + /// The maximum number of bits that and can shift. + /// + public int MaxShift { get; init; } = 256; + + /// + /// The maximum number of items that can be contained in the VM's evaluation stacks and slots. + /// + public uint MaxStackSize { get; init; } = 2 * 1024; + + /// + /// The maximum size of an item in the VM. + /// + public uint MaxItemSize { get; init; } = ushort.MaxValue * 2; + + /// + /// The largest comparable size. If a or exceeds this size, comparison operations on it cannot be performed in the VM. + /// + public uint MaxComparableSize { get; init; } = 65536; + + /// + /// The maximum number of frames in the invocation stack of the VM. + /// + public uint MaxInvocationStackSize { get; init; } = 1024; + + /// + /// The maximum nesting depth of -- blocks. + /// + public uint MaxTryNestingDepth { get; init; } = 16; + + /// + /// Allow to catch the ExecutionEngine Exceptions + /// + public bool CatchEngineExceptions { get; init; } = true; + + /// + /// Assert that the size of the item meets the limit. + /// + /// The size to be checked. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void AssertMaxItemSize(int size) + { + if (size < 0 || size > MaxItemSize) + { + throw new InvalidOperationException($"MaxItemSize exceed: {size}"); + } + } + + /// + /// Assert that the number of bits shifted meets the limit. + /// + /// The number of bits shifted. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void AssertShift(int shift) + { + if (shift > MaxShift || shift < 0) + { + throw new InvalidOperationException($"Invalid shift value: {shift}"); + } + } + } +} diff --git a/src/Neo.VM/GlobalSuppressions.cs b/src/Neo.VM/GlobalSuppressions.cs new file mode 100644 index 0000000000..12194f733e --- /dev/null +++ b/src/Neo.VM/GlobalSuppressions.cs @@ -0,0 +1,18 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project 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. + +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +using System.Diagnostics.CodeAnalysis; + +[assembly: SuppressMessage("Usage", "CA1816")] diff --git a/src/Neo.VM/Instruction.cs b/src/Neo.VM/Instruction.cs new file mode 100644 index 0000000000..48b48c94a3 --- /dev/null +++ b/src/Neo.VM/Instruction.cs @@ -0,0 +1,234 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project 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.Buffers.Binary; +using System.Diagnostics; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Text; + +namespace Neo.VM +{ + /// + /// Represents instructions in the VM script. + /// + [DebuggerDisplay("OpCode={OpCode}")] + public class Instruction + { + /// + /// Represents the instruction with . + /// + public static Instruction RET { get; } = new Instruction(OpCode.RET); + + /// + /// The of the instruction. + /// + public readonly OpCode OpCode; + + /// + /// The operand of the instruction. + /// + public readonly ReadOnlyMemory Operand; + + private static readonly int[] OperandSizePrefixTable = new int[256]; + private static readonly int[] OperandSizeTable = new int[256]; + + /// + /// Gets the size of the instruction. + /// + public int Size + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + int prefixSize = OperandSizePrefixTable[(int)OpCode]; + return prefixSize > 0 + ? 1 + prefixSize + Operand.Length + : 1 + OperandSizeTable[(int)OpCode]; + } + } + + /// + /// Gets the first operand as . + /// + public short TokenI16 + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + return BinaryPrimitives.ReadInt16LittleEndian(Operand.Span); + } + } + + /// + /// Gets the first operand as . + /// + public int TokenI32 + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + return BinaryPrimitives.ReadInt32LittleEndian(Operand.Span); + } + } + + /// + /// Gets the second operand as . + /// + public int TokenI32_1 + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + return BinaryPrimitives.ReadInt32LittleEndian(Operand.Span[4..]); + } + } + + /// + /// Gets the first operand as . + /// + public sbyte TokenI8 + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + return (sbyte)Operand.Span[0]; + } + } + + /// + /// Gets the second operand as . + /// + public sbyte TokenI8_1 + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + return (sbyte)Operand.Span[1]; + } + } + + /// + /// Gets the operand as . + /// + public string TokenString + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + return Encoding.ASCII.GetString(Operand.Span); + } + } + + /// + /// Gets the first operand as . + /// + public ushort TokenU16 + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + return BinaryPrimitives.ReadUInt16LittleEndian(Operand.Span); + } + } + + /// + /// Gets the first operand as . + /// + public uint TokenU32 + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + return BinaryPrimitives.ReadUInt32LittleEndian(Operand.Span); + } + } + + /// + /// Gets the first operand as . + /// + public byte TokenU8 + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + return Operand.Span[0]; + } + } + + /// + /// Gets the second operand as . + /// + public byte TokenU8_1 + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + return Operand.Span[1]; + } + } + + static Instruction() + { + foreach (FieldInfo field in typeof(OpCode).GetFields(BindingFlags.Public | BindingFlags.Static)) + { + OperandSizeAttribute? attribute = field.GetCustomAttribute(); + if (attribute == null) continue; + int index = (int)(OpCode)field.GetValue(null)!; + OperandSizePrefixTable[index] = attribute.SizePrefix; + OperandSizeTable[index] = attribute.Size; + } + } + + private Instruction(OpCode opcode) + { + this.OpCode = opcode; + if (!Enum.IsDefined(typeof(OpCode), opcode)) throw new BadScriptException(); + } + + internal Instruction(ReadOnlyMemory script, int ip) : this((OpCode)script.Span[ip++]) + { + ReadOnlySpan span = script.Span; + int operandSizePrefix = OperandSizePrefixTable[(int)OpCode]; + int operandSize = 0; + switch (operandSizePrefix) + { + case 0: + operandSize = OperandSizeTable[(int)OpCode]; + break; + case 1: + if (ip >= span.Length) + throw new BadScriptException($"Instruction out of bounds. InstructionPointer: {ip}"); + operandSize = span[ip]; + break; + case 2: + if (ip + 1 >= span.Length) + throw new BadScriptException($"Instruction out of bounds. InstructionPointer: {ip}"); + operandSize = BinaryPrimitives.ReadUInt16LittleEndian(span[ip..]); + break; + case 4: + if (ip + 3 >= span.Length) + throw new BadScriptException($"Instruction out of bounds. InstructionPointer: {ip}"); + operandSize = BinaryPrimitives.ReadInt32LittleEndian(span[ip..]); + if (operandSize < 0) + throw new BadScriptException($"Instruction out of bounds. InstructionPointer: {ip}, operandSize: {operandSize}"); + break; + } + ip += operandSizePrefix; + if (operandSize > 0) + { + if (ip + operandSize > script.Length) + throw new BadScriptException($"Instrucion out of bounds. InstructionPointer: {ip}, operandSize: {operandSize}, length: {script.Length}"); + Operand = script.Slice(ip, operandSize); + } + } + } +} diff --git a/src/Neo.VM/IsExternalInit.cs b/src/Neo.VM/IsExternalInit.cs new file mode 100644 index 0000000000..874f5f76ce --- /dev/null +++ b/src/Neo.VM/IsExternalInit.cs @@ -0,0 +1,17 @@ +#if !NET5_0_OR_GREATER + +using System.ComponentModel; + +namespace System.Runtime.CompilerServices +{ + /// + /// Reserved to be used by the compiler for tracking metadata. + /// This class should not be used by developers in source code. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + internal static class IsExternalInit + { + } +} + +#endif diff --git a/src/Neo.VM/Neo.VM.csproj b/src/Neo.VM/Neo.VM.csproj new file mode 100644 index 0000000000..5e7e071b22 --- /dev/null +++ b/src/Neo.VM/Neo.VM.csproj @@ -0,0 +1,9 @@ + + + + netstandard2.1;net7.0 + true + enable + + + diff --git a/src/Neo.VM/OpCode.cs b/src/Neo.VM/OpCode.cs new file mode 100644 index 0000000000..313e04a7d1 --- /dev/null +++ b/src/Neo.VM/OpCode.cs @@ -0,0 +1,905 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project 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 +{ + /// + /// Represents the opcode of an . + /// + public enum OpCode : byte + { + #region Constants + + /// + /// Pushes a 1-byte signed integer onto the stack. + /// + [OperandSize(Size = 1)] + PUSHINT8 = 0x00, + /// + /// Pushes a 2-bytes signed integer onto the stack. + /// + [OperandSize(Size = 2)] + PUSHINT16 = 0x01, + /// + /// Pushes a 4-bytes signed integer onto the stack. + /// + [OperandSize(Size = 4)] + PUSHINT32 = 0x02, + /// + /// Pushes a 8-bytes signed integer onto the stack. + /// + [OperandSize(Size = 8)] + PUSHINT64 = 0x03, + /// + /// Pushes a 16-bytes signed integer onto the stack. + /// + [OperandSize(Size = 16)] + PUSHINT128 = 0x04, + /// + /// Pushes a 32-bytes signed integer onto the stack. + /// + [OperandSize(Size = 32)] + PUSHINT256 = 0x05, + /// + /// Pushes the boolean value onto the stack. + /// + PUSHT = 0x08, + /// + /// Pushes the boolean value onto the stack. + /// + PUSHF = 0x09, + /// + /// Converts the 4-bytes offset to an , and pushes it onto the stack. + /// + [OperandSize(Size = 4)] + PUSHA = 0x0A, + /// + /// The item is pushed onto the stack. + /// + PUSHNULL = 0x0B, + /// + /// The next byte contains the number of bytes to be pushed onto the stack. + /// + [OperandSize(SizePrefix = 1)] + PUSHDATA1 = 0x0C, + /// + /// The next two bytes contain the number of bytes to be pushed onto the stack. + /// + [OperandSize(SizePrefix = 2)] + PUSHDATA2 = 0x0D, + /// + /// The next four bytes contain the number of bytes to be pushed onto the stack. + /// + [OperandSize(SizePrefix = 4)] + PUSHDATA4 = 0x0E, + /// + /// The number -1 is pushed onto the stack. + /// + PUSHM1 = 0x0F, + /// + /// The number 0 is pushed onto the stack. + /// + PUSH0 = 0x10, + /// + /// The number 1 is pushed onto the stack. + /// + PUSH1 = 0x11, + /// + /// The number 2 is pushed onto the stack. + /// + PUSH2 = 0x12, + /// + /// The number 3 is pushed onto the stack. + /// + PUSH3 = 0x13, + /// + /// The number 4 is pushed onto the stack. + /// + PUSH4 = 0x14, + /// + /// The number 5 is pushed onto the stack. + /// + PUSH5 = 0x15, + /// + /// The number 6 is pushed onto the stack. + /// + PUSH6 = 0x16, + /// + /// The number 7 is pushed onto the stack. + /// + PUSH7 = 0x17, + /// + /// The number 8 is pushed onto the stack. + /// + PUSH8 = 0x18, + /// + /// The number 9 is pushed onto the stack. + /// + PUSH9 = 0x19, + /// + /// The number 10 is pushed onto the stack. + /// + PUSH10 = 0x1A, + /// + /// The number 11 is pushed onto the stack. + /// + PUSH11 = 0x1B, + /// + /// The number 12 is pushed onto the stack. + /// + PUSH12 = 0x1C, + /// + /// The number 13 is pushed onto the stack. + /// + PUSH13 = 0x1D, + /// + /// The number 14 is pushed onto the stack. + /// + PUSH14 = 0x1E, + /// + /// The number 15 is pushed onto the stack. + /// + PUSH15 = 0x1F, + /// + /// The number 16 is pushed onto the stack. + /// + PUSH16 = 0x20, + + #endregion + + #region Flow control + + /// + /// The operation does nothing. It is intended to fill in space if opcodes are patched. + /// + 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. + /// + [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. + /// + [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. + /// + [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. + /// + [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. + /// + [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. + /// + [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. + /// + [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. + /// + [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. + /// + [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. + /// + [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. + /// + [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. + /// + [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. + /// + [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. + /// + [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. + /// + [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. + /// + [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. + /// + [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. + /// + [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. + /// + ABORT = 0x38, + /// + /// Pop the top value of the stack. If it's false, exit vm execution and set vm state to FAULT. + /// + ASSERT = 0x39, + /// + /// Pop the top value of the stack, and throw it. + /// + 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. + /// + ENDFINALLY = 0x3F, + /// + /// Returns from the current method. + /// + RET = 0x40, + /// + /// Calls to an interop service. + /// + [OperandSize(Size = 4)] + SYSCALL = 0x41, + + #endregion + + #region Stack + + /// + /// Puts the number of stack items onto the stack. + /// + DEPTH = 0x43, + /// + /// Removes the top stack item. + /// + DROP = 0x45, + /// + /// Removes the second-to-top stack item. + /// + NIP = 0x46, + /// + /// The item n back in the main stack is removed. + /// + XDROP = 0x48, + /// + /// Clear the stack + /// + CLEAR = 0x49, + /// + /// Duplicates the top stack item. + /// + DUP = 0x4A, + /// + /// Copies the second-to-top stack item to the top. + /// + OVER = 0x4B, + /// + /// The item n back in the stack is copied to the top. + /// + PICK = 0x4D, + /// + /// The item at the top of the stack is copied and inserted before the second-to-top item. + /// + TUCK = 0x4E, + /// + /// The top two items on the stack are swapped. + /// + SWAP = 0x50, + /// + /// The top three items on the stack are rotated to the left. + /// + ROT = 0x51, + /// + /// The item n back in the stack is moved to the top. + /// + ROLL = 0x52, + /// + /// Reverse the order of the top 3 items on the stack. + /// + REVERSE3 = 0x53, + /// + /// Reverse the order of the top 4 items on the stack. + /// + REVERSE4 = 0x54, + /// + /// Pop the number N on the stack, and reverse the order of the top N items on the stack. + /// + REVERSEN = 0x55, + + #endregion + + #region Slot + + /// + /// Initialize the static field list for the current execution context. + /// + [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. + /// + LDSFLD0 = 0x58, + /// + /// Loads the static field at index 1 onto the evaluation stack. + /// + LDSFLD1 = 0x59, + /// + /// Loads the static field at index 2 onto the evaluation stack. + /// + LDSFLD2 = 0x5A, + /// + /// Loads the static field at index 3 onto the evaluation stack. + /// + LDSFLD3 = 0x5B, + /// + /// Loads the static field at index 4 onto the evaluation stack. + /// + LDSFLD4 = 0x5C, + /// + /// Loads the static field at index 5 onto the evaluation stack. + /// + LDSFLD5 = 0x5D, + /// + /// Loads the static field at index 6 onto the evaluation stack. + /// + LDSFLD6 = 0x5E, + /// + /// Loads the static field at a specified index onto the evaluation stack. The index is represented as a 1-byte unsigned integer. + /// + [OperandSize(Size = 1)] + LDSFLD = 0x5F, + /// + /// Stores the value on top of the evaluation stack in the static field list at index 0. + /// + STSFLD0 = 0x60, + /// + /// Stores the value on top of the evaluation stack in the static field list at index 1. + /// + STSFLD1 = 0x61, + /// + /// Stores the value on top of the evaluation stack in the static field list at index 2. + /// + STSFLD2 = 0x62, + /// + /// Stores the value on top of the evaluation stack in the static field list at index 3. + /// + STSFLD3 = 0x63, + /// + /// Stores the value on top of the evaluation stack in the static field list at index 4. + /// + STSFLD4 = 0x64, + /// + /// Stores the value on top of the evaluation stack in the static field list at index 5. + /// + STSFLD5 = 0x65, + /// + /// Stores the value on top of the evaluation stack in the static field list at index 6. + /// + 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. + /// + [OperandSize(Size = 1)] + STSFLD = 0x67, + /// + /// Loads the local variable at index 0 onto the evaluation stack. + /// + LDLOC0 = 0x68, + /// + /// Loads the local variable at index 1 onto the evaluation stack. + /// + LDLOC1 = 0x69, + /// + /// Loads the local variable at index 2 onto the evaluation stack. + /// + LDLOC2 = 0x6A, + /// + /// Loads the local variable at index 3 onto the evaluation stack. + /// + LDLOC3 = 0x6B, + /// + /// Loads the local variable at index 4 onto the evaluation stack. + /// + LDLOC4 = 0x6C, + /// + /// Loads the local variable at index 5 onto the evaluation stack. + /// + LDLOC5 = 0x6D, + /// + /// Loads the local variable at index 6 onto the evaluation stack. + /// + LDLOC6 = 0x6E, + /// + /// Loads the local variable at a specified index onto the evaluation stack. The index is represented as a 1-byte unsigned integer. + /// + [OperandSize(Size = 1)] + LDLOC = 0x6F, + /// + /// Stores the value on top of the evaluation stack in the local variable list at index 0. + /// + STLOC0 = 0x70, + /// + /// Stores the value on top of the evaluation stack in the local variable list at index 1. + /// + STLOC1 = 0x71, + /// + /// Stores the value on top of the evaluation stack in the local variable list at index 2. + /// + STLOC2 = 0x72, + /// + /// Stores the value on top of the evaluation stack in the local variable list at index 3. + /// + STLOC3 = 0x73, + /// + /// Stores the value on top of the evaluation stack in the local variable list at index 4. + /// + STLOC4 = 0x74, + /// + /// Stores the value on top of the evaluation stack in the local variable list at index 5. + /// + STLOC5 = 0x75, + /// + /// Stores the value on top of the evaluation stack in the local variable list at index 6. + /// + 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. + /// + [OperandSize(Size = 1)] + STLOC = 0x77, + /// + /// Loads the argument at index 0 onto the evaluation stack. + /// + LDARG0 = 0x78, + /// + /// Loads the argument at index 1 onto the evaluation stack. + /// + LDARG1 = 0x79, + /// + /// Loads the argument at index 2 onto the evaluation stack. + /// + LDARG2 = 0x7A, + /// + /// Loads the argument at index 3 onto the evaluation stack. + /// + LDARG3 = 0x7B, + /// + /// Loads the argument at index 4 onto the evaluation stack. + /// + LDARG4 = 0x7C, + /// + /// Loads the argument at index 5 onto the evaluation stack. + /// + LDARG5 = 0x7D, + /// + /// Loads the argument at index 6 onto the evaluation stack. + /// + LDARG6 = 0x7E, + /// + /// Loads the argument at a specified index onto the evaluation stack. The index is represented as a 1-byte unsigned integer. + /// + [OperandSize(Size = 1)] + LDARG = 0x7F, + /// + /// Stores the value on top of the evaluation stack in the argument slot at index 0. + /// + STARG0 = 0x80, + /// + /// Stores the value on top of the evaluation stack in the argument slot at index 1. + /// + STARG1 = 0x81, + /// + /// Stores the value on top of the evaluation stack in the argument slot at index 2. + /// + STARG2 = 0x82, + /// + /// Stores the value on top of the evaluation stack in the argument slot at index 3. + /// + STARG3 = 0x83, + /// + /// Stores the value on top of the evaluation stack in the argument slot at index 4. + /// + STARG4 = 0x84, + /// + /// Stores the value on top of the evaluation stack in the argument slot at index 5. + /// + STARG5 = 0x85, + /// + /// Stores the value on top of the evaluation stack in the argument slot at index 6. + /// + 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. + /// + [OperandSize(Size = 1)] + STARG = 0x87, + + #endregion + + #region Splice + + /// + /// Creates a new and pushes it onto the stack. + /// + NEWBUFFER = 0x88, + /// + /// Copies a range of bytes from one to another. + /// + MEMCPY = 0x89, + /// + /// Concatenates two strings. + /// + CAT = 0x8B, + /// + /// Returns a section of a string. + /// + SUBSTR = 0x8C, + /// + /// Keeps only characters left of the specified point in a string. + /// + LEFT = 0x8D, + /// + /// Keeps only characters right of the specified point in a string. + /// + RIGHT = 0x8E, + + #endregion + + #region Bitwise logic + + /// + /// Flips all of the bits in the input. + /// + INVERT = 0x90, + /// + /// Boolean and between each bit in the inputs. + /// + AND = 0x91, + /// + /// Boolean or between each bit in the inputs. + /// + OR = 0x92, + /// + /// Boolean exclusive or between each bit in the inputs. + /// + XOR = 0x93, + /// + /// Returns 1 if the inputs are exactly equal, 0 otherwise. + /// + EQUAL = 0x97, + /// + /// Returns 1 if the inputs are not equal, 0 otherwise. + /// + NOTEQUAL = 0x98, + + #endregion + + #region Arithmetic + + /// + /// 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. + /// + SIGN = 0x99, + /// + /// The input is made positive. + /// + ABS = 0x9A, + /// + /// The sign of the input is flipped. + /// + NEGATE = 0x9B, + /// + /// 1 is added to the input. + /// + INC = 0x9C, + /// + /// 1 is subtracted from the input. + /// + DEC = 0x9D, + /// + /// a is added to b. + /// + ADD = 0x9E, + /// + /// b is subtracted from a. + /// + SUB = 0x9F, + /// + /// a is multiplied by b. + /// + MUL = 0xA0, + /// + /// a is divided by b. + /// + DIV = 0xA1, + /// + /// Returns the remainder after dividing a by b. + /// + MOD = 0xA2, + /// + /// The result of raising value to the exponent power. + /// + POW = 0xA3, + /// + /// Returns the square root of a specified number. + /// + SQRT = 0xA4, + /// + /// Performs modulus division on a number multiplied by another number. + /// + 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 = 0xA6, + /// + /// Shifts a left b bits, preserving sign. + /// + SHL = 0xA8, + /// + /// Shifts a right b bits, preserving sign. + /// + SHR = 0xA9, + /// + /// If the input is 0 or 1, it is flipped. Otherwise the output will be 0. + /// + NOT = 0xAA, + /// + /// If both a and b are not 0, the output is 1. Otherwise 0. + /// + BOOLAND = 0xAB, + /// + /// If a or b is not 0, the output is 1. Otherwise 0. + /// + BOOLOR = 0xAC, + /// + /// Returns 0 if the input is 0. 1 otherwise. + /// + NZ = 0xB1, + /// + /// Returns 1 if the numbers are equal, 0 otherwise. + /// + NUMEQUAL = 0xB3, + /// + /// Returns 1 if the numbers are not equal, 0 otherwise. + /// + NUMNOTEQUAL = 0xB4, + /// + /// Returns 1 if a is less than b, 0 otherwise. + /// + LT = 0xB5, + /// + /// Returns 1 if a is less than or equal to b, 0 otherwise. + /// + LE = 0xB6, + /// + /// Returns 1 if a is greater than b, 0 otherwise. + /// + GT = 0xB7, + /// + /// Returns 1 if a is greater than or equal to b, 0 otherwise. + /// + GE = 0xB8, + /// + /// Returns the smaller of a and b. + /// + MIN = 0xB9, + /// + /// Returns the larger of a and b. + /// + MAX = 0xBA, + /// + /// Returns 1 if x is within the specified range (left-inclusive), 0 otherwise. + /// + WITHIN = 0xBB, + + #endregion + + #region Compound-type + + /// + /// 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. + /// + 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. + /// + 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. + /// + 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. + /// + UNPACK = 0xC1, + /// + /// An empty array (with size 0) is put on top of the main stack. + /// + 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. + /// + 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. + /// + [OperandSize(Size = 1)] + NEWARRAY_T = 0xC4, + /// + /// An empty struct (with size 0) is put on top of the main stack. + /// + 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. + /// + NEWSTRUCT = 0xC6, + /// + /// A Map is created and put on top of the main stack. + /// + NEWMAP = 0xC8, + /// + /// An array is removed from top of the main stack. Its size is put on top of the main stack. + /// + 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. + /// + 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. + /// + 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. + /// + 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. + /// + PICKITEM = 0xCE, + /// + /// The item on top of main stack is removed and appended to the second item on top of the main stack. + /// + 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. + /// + SETITEM = 0xD0, + /// + /// An array is removed from the top of the main stack and its elements are reversed. + /// + 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. + /// + REMOVE = 0xD2, + /// + /// Remove all the items from the compound-type. + /// + CLEARITEMS = 0xD3, + /// + /// Remove the last element from an array, and push it onto the stack. + /// + POPITEM = 0xD4, + + #endregion + + #region Types + + /// + /// Returns if the input is ; + /// otherwise. + /// + ISNULL = 0xD8, + /// + /// Returns if the top item of the stack is of the specified type; + /// otherwise. + /// + [OperandSize(Size = 1)] + ISTYPE = 0xD9, + /// + /// Converts the top item of the stack to the specified type. + /// + [OperandSize(Size = 1)] + CONVERT = 0xDB, + + #endregion + + #region Extensions + + /// + /// 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. + /// + 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. + /// + ASSERTMSG = 0xE1 + + #endregion + } +} diff --git a/src/Neo.VM/OperandSizeAttribute.cs b/src/Neo.VM/OperandSizeAttribute.cs new file mode 100644 index 0000000000..1240989bb8 --- /dev/null +++ b/src/Neo.VM/OperandSizeAttribute.cs @@ -0,0 +1,31 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project 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; + +namespace Neo.VM +{ + /// + /// Indicates the operand length of an . + /// + [AttributeUsage(AttributeTargets.Field, AllowMultiple = false)] + public class OperandSizeAttribute : Attribute + { + /// + /// When it is greater than 0, indicates the size of the operand. + /// + public int Size { get; set; } + + /// + /// When it is greater than 0, indicates the size prefix of the operand. + /// + public int SizePrefix { get; set; } + } +} diff --git a/src/Neo.VM/Properties/AssemblyInfo.cs b/src/Neo.VM/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..b25e1d9752 --- /dev/null +++ b/src/Neo.VM/Properties/AssemblyInfo.cs @@ -0,0 +1,13 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project 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.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("Neo.VM.Tests")] diff --git a/src/Neo.VM/ReferenceCounter.cs b/src/Neo.VM/ReferenceCounter.cs new file mode 100644 index 0000000000..63732646cd --- /dev/null +++ b/src/Neo.VM/ReferenceCounter.cs @@ -0,0 +1,154 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project 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.StronglyConnectedComponents; +using Neo.VM.Types; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; + +namespace Neo.VM +{ + /// + /// Used for reference counting of objects in the VM. + /// + public sealed class ReferenceCounter + { + 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; + + /// + /// Indicates the number of this counter. + /// + public int Count => references_count; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool NeedTrack(StackItem item) + { +#pragma warning disable CS0162 + if (TrackAllItems) return true; +#pragma warning restore CS0162 + if (item is CompoundType or Buffer) return true; + return false; + } + + 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++; + } + + 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); + } + + internal void AddZeroReferred(StackItem item) + { + zero_referred.Add(item); + if (!NeedTrack(item)) return; + cached_components?.AddLast(new HashSet(ReferenceEqualityComparer.Instance) { item }); + tracked_items.Add(item); + } + + internal int CheckZeroReferred() + { + if (zero_referred.Count > 0) + { + zero_referred.Clear(); + if (cached_components is null) + { + //Tarjan tarjan = new(tracked_items.Where(p => p.StackReferences == 0)); + Tarjan tarjan = new(tracked_items); + cached_components = tarjan.Invoke(); + } + foreach (StackItem item in tracked_items) + item.Reset(); + for (var node = cached_components.First; node != null;) + { + var component = node.Value; + bool on_stack = false; + foreach (StackItem item in component) + { + if (item.StackReferences > 0 || item.ObjectReferences?.Values.Any(p => p.References > 0 && p.Item.OnStack) == true) + { + on_stack = true; + break; + } + } + if (on_stack) + { + foreach (StackItem item in component) + item.OnStack = true; + node = node.Next; + } + else + { + foreach (StackItem item in component) + { + tracked_items.Remove(item); + if (item is CompoundType compound) + { + references_count -= compound.SubItemsCount; + foreach (StackItem subitem in compound.SubItems) + { + if (component.Contains(subitem)) continue; + if (!NeedTrack(subitem)) continue; + subitem.ObjectReferences!.Remove(compound); + } + } + item.Cleanup(); + } + var nodeToRemove = node; + node = node.Next; + cached_components.Remove(nodeToRemove); + } + } + } + return references_count; + } + + 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); + } + + internal void RemoveStackReference(StackItem item) + { + references_count--; + if (!NeedTrack(item)) return; + if (--item.StackReferences == 0) + zero_referred.Add(item); + } + } +} diff --git a/src/Neo.VM/ReferenceEqualityComparer.cs b/src/Neo.VM/ReferenceEqualityComparer.cs new file mode 100644 index 0000000000..7c9d68ad64 --- /dev/null +++ b/src/Neo.VM/ReferenceEqualityComparer.cs @@ -0,0 +1,29 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project 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.Collections.Generic; +using System.Runtime.CompilerServices; + +namespace Neo.VM +{ +#if !NET5_0_OR_GREATER + // https://github.dev/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/ReferenceEqualityComparer.cs + public sealed class ReferenceEqualityComparer : IEqualityComparer, System.Collections.IEqualityComparer + { + private ReferenceEqualityComparer() { } + + public static ReferenceEqualityComparer Instance { get; } = new ReferenceEqualityComparer(); + + public new bool Equals(object? x, object? y) => ReferenceEquals(x, y); + + public int GetHashCode(object? obj) => RuntimeHelpers.GetHashCode(obj!); + } +#endif +} diff --git a/src/Neo.VM/Script.cs b/src/Neo.VM/Script.cs new file mode 100644 index 0000000000..863fec9576 --- /dev/null +++ b/src/Neo.VM/Script.cs @@ -0,0 +1,160 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project 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; +using System.Collections.Generic; +using System.Diagnostics; +using System.Runtime.CompilerServices; + +namespace Neo.VM +{ + /// + /// Represents the script executed in the VM. + /// + [DebuggerDisplay("Length={Length}")] + public class Script + { + private readonly ReadOnlyMemory _value; + private readonly bool strictMode; + private readonly Dictionary _instructions = new(); + + /// + /// The length of the script. + /// + public int Length + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + return _value.Length; + } + } + + /// + /// Gets the at the specified index. + /// + /// The index to locate. + /// The at the specified index. + public OpCode this[int index] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + return (OpCode)_value.Span[index]; + } + } + + /// + /// Initializes a new instance of the class. + /// + /// The bytecodes of the script. + public Script(ReadOnlyMemory script) : this(script, false) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The bytecodes of the script. + /// + /// Indicates whether strict mode is enabled. + /// In strict mode, the script will be checked, but the loading speed will be slower. + /// + /// In strict mode, the script was found to contain bad instructions. + public Script(ReadOnlyMemory script, bool strictMode) + { + this._value = script; + if (strictMode) + { + for (int ip = 0; ip < script.Length; ip += GetInstruction(ip).Size) { } + foreach (var (ip, instruction) in _instructions) + { + switch (instruction.OpCode) + { + case OpCode.JMP: + case OpCode.JMPIF: + case OpCode.JMPIFNOT: + case OpCode.JMPEQ: + case OpCode.JMPNE: + case OpCode.JMPGT: + case OpCode.JMPGE: + case OpCode.JMPLT: + case OpCode.JMPLE: + case OpCode.CALL: + case OpCode.ENDTRY: + if (!_instructions.ContainsKey(checked(ip + instruction.TokenI8))) + throw new BadScriptException($"ip: {ip}, opcode: {instruction.OpCode}"); + break; + case OpCode.PUSHA: + case OpCode.JMP_L: + case OpCode.JMPIF_L: + case OpCode.JMPIFNOT_L: + case OpCode.JMPEQ_L: + case OpCode.JMPNE_L: + case OpCode.JMPGT_L: + case OpCode.JMPGE_L: + case OpCode.JMPLT_L: + case OpCode.JMPLE_L: + case OpCode.CALL_L: + case OpCode.ENDTRY_L: + if (!_instructions.ContainsKey(checked(ip + instruction.TokenI32))) + throw new BadScriptException($"ip: {ip}, opcode: {instruction.OpCode}"); + break; + case OpCode.TRY: + if (!_instructions.ContainsKey(checked(ip + instruction.TokenI8))) + throw new BadScriptException($"ip: {ip}, opcode: {instruction.OpCode}"); + if (!_instructions.ContainsKey(checked(ip + instruction.TokenI8_1))) + throw new BadScriptException($"ip: {ip}, opcode: {instruction.OpCode}"); + break; + case OpCode.TRY_L: + if (!_instructions.ContainsKey(checked(ip + instruction.TokenI32))) + throw new BadScriptException($"ip: {ip}, opcode: {instruction.OpCode}"); + if (!_instructions.ContainsKey(checked(ip + instruction.TokenI32_1))) + throw new BadScriptException($"ip: {ip}, opcode: {instruction.OpCode}"); + break; + case OpCode.NEWARRAY_T: + case OpCode.ISTYPE: + case OpCode.CONVERT: + StackItemType type = (StackItemType)instruction.TokenU8; + if (!Enum.IsDefined(typeof(StackItemType), type)) + throw new BadScriptException(); + if (instruction.OpCode != OpCode.NEWARRAY_T && type == StackItemType.Any) + throw new BadScriptException($"ip: {ip}, opcode: {instruction.OpCode}"); + break; + } + } + } + this.strictMode = strictMode; + } + + /// + /// Get the at the specified position. + /// + /// The position to get the . + /// The at the specified position. + /// In strict mode, the was not found at the specified position. + public Instruction GetInstruction(int ip) + { + if (ip >= Length) throw new ArgumentOutOfRangeException(nameof(ip)); + if (!_instructions.TryGetValue(ip, out Instruction? instruction)) + { + if (strictMode) throw new ArgumentException($"ip not found with strict mode", nameof(ip)); + instruction = new Instruction(_value, ip); + _instructions.Add(ip, instruction); + } + return instruction; + } + + public static implicit operator ReadOnlyMemory(Script script) => script._value; + public static implicit operator Script(ReadOnlyMemory script) => new(script); + public static implicit operator Script(byte[] script) => new(script); + } +} diff --git a/src/Neo.VM/ScriptBuilder.cs b/src/Neo.VM/ScriptBuilder.cs new file mode 100644 index 0000000000..d2cb995532 --- /dev/null +++ b/src/Neo.VM/ScriptBuilder.cs @@ -0,0 +1,199 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project 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.IO; +using System.Numerics; + +namespace Neo.VM +{ + /// + /// A helper class for building scripts. + /// + public class ScriptBuilder : IDisposable + { + private readonly MemoryStream ms = new(); + private readonly BinaryWriter writer; + + /// + /// The length of the script. + /// + public int Length => (int)ms.Position; + + /// + /// Initializes a new instance of the class. + /// + public ScriptBuilder() + { + writer = new BinaryWriter(ms); + } + + public void Dispose() + { + writer.Dispose(); + ms.Dispose(); + } + + /// + /// Emits an with the specified and operand. + /// + /// The to be emitted. + /// The operand to be emitted. + /// A reference to this instance after the emit operation has completed. + public ScriptBuilder Emit(OpCode opcode, ReadOnlySpan operand = default) + { + writer.Write((byte)opcode); + writer.Write(operand); + return this; + } + + /// + /// Emits a call with the specified offset. + /// + /// The offset to be called. + /// A reference to this instance after the emit operation has completed. + public ScriptBuilder EmitCall(int offset) + { + if (offset < sbyte.MinValue || offset > sbyte.MaxValue) + return Emit(OpCode.CALL_L, BitConverter.GetBytes(offset)); + else + return Emit(OpCode.CALL, new[] { (byte)offset }); + } + + /// + /// Emits a jump with the specified offset. + /// + /// The to be emitted. It must be a jump + /// The offset to jump. + /// A reference to this instance after the emit operation has completed. + public ScriptBuilder EmitJump(OpCode opcode, int offset) + { + if (opcode < OpCode.JMP || opcode > OpCode.JMPLE_L) + throw new ArgumentOutOfRangeException(nameof(opcode)); + if ((int)opcode % 2 == 0 && (offset < sbyte.MinValue || offset > sbyte.MaxValue)) + opcode += 1; + if ((int)opcode % 2 == 0) + return Emit(opcode, new[] { (byte)offset }); + else + return Emit(opcode, BitConverter.GetBytes(offset)); + } + + /// + /// Emits a push with the specified number. + /// + /// The number to be pushed. + /// A reference to this instance after the emit operation has completed. + public ScriptBuilder EmitPush(BigInteger value) + { + if (value >= -1 && value <= 16) return Emit(OpCode.PUSH0 + (byte)(int)value); + Span buffer = stackalloc byte[32]; + if (!value.TryWriteBytes(buffer, out int bytesWritten, isUnsigned: false, isBigEndian: false)) + throw new ArgumentOutOfRangeException(nameof(value)); + return bytesWritten switch + { + 1 => Emit(OpCode.PUSHINT8, PadRight(buffer, bytesWritten, 1, value.Sign < 0)), + 2 => Emit(OpCode.PUSHINT16, PadRight(buffer, bytesWritten, 2, value.Sign < 0)), + <= 4 => Emit(OpCode.PUSHINT32, PadRight(buffer, bytesWritten, 4, value.Sign < 0)), + <= 8 => Emit(OpCode.PUSHINT64, PadRight(buffer, bytesWritten, 8, value.Sign < 0)), + <= 16 => Emit(OpCode.PUSHINT128, PadRight(buffer, bytesWritten, 16, value.Sign < 0)), + _ => Emit(OpCode.PUSHINT256, PadRight(buffer, bytesWritten, 32, value.Sign < 0)), + }; + } + + /// + /// Emits a push with the specified boolean value. + /// + /// The value to be pushed. + /// A reference to this instance after the emit operation has completed. + public ScriptBuilder EmitPush(bool value) + { + return Emit(value ? OpCode.PUSHT : OpCode.PUSHF); + } + + /// + /// Emits a push with the specified data. + /// + /// The data to be pushed. + /// A reference to this instance after the emit operation has completed. + public ScriptBuilder EmitPush(ReadOnlySpan data) + { + if (data == null) + throw new ArgumentNullException(nameof(data)); + if (data.Length < 0x100) + { + Emit(OpCode.PUSHDATA1); + writer.Write((byte)data.Length); + writer.Write(data); + } + else if (data.Length < 0x10000) + { + Emit(OpCode.PUSHDATA2); + writer.Write((ushort)data.Length); + writer.Write(data); + } + else// if (data.Length < 0x100000000L) + { + Emit(OpCode.PUSHDATA4); + writer.Write(data.Length); + writer.Write(data); + } + return this; + } + + /// + /// Emits a push with the specified . + /// + /// The to be pushed. + /// A reference to this instance after the emit operation has completed. + public ScriptBuilder EmitPush(string data) + { + return EmitPush(Utility.StrictUTF8.GetBytes(data)); + } + + /// + /// Emits raw script. + /// + /// The raw script to be emitted. + /// A reference to this instance after the emit operation has completed. + public ScriptBuilder EmitRaw(ReadOnlySpan script = default) + { + writer.Write(script); + return this; + } + + /// + /// Emits an with . + /// + /// The operand of . + /// A reference to this instance after the emit operation has completed. + public ScriptBuilder EmitSysCall(uint api) + { + return Emit(OpCode.SYSCALL, BitConverter.GetBytes(api)); + } + + /// + /// Converts the value of this instance to a byte array. + /// + /// A byte array contains the script. + public byte[] ToArray() + { + writer.Flush(); + return ms.ToArray(); + } + + private static ReadOnlySpan PadRight(Span buffer, int dataLength, int padLength, bool negative) + { + byte pad = negative ? (byte)0xff : (byte)0; + for (int x = dataLength; x < padLength; x++) + buffer[x] = pad; + return buffer[..padLength]; + } + } +} diff --git a/src/Neo.VM/Slot.cs b/src/Neo.VM/Slot.cs new file mode 100644 index 0000000000..9f4609f792 --- /dev/null +++ b/src/Neo.VM/Slot.cs @@ -0,0 +1,92 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project 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; +using System.Collections.Generic; + +namespace Neo.VM +{ + /// + /// Used to store local variables, arguments and static fields in the VM. + /// + public class Slot : IReadOnlyList + { + private readonly ReferenceCounter referenceCounter; + private readonly StackItem[] items; + + /// + /// Gets the item at the specified index in the slot. + /// + /// The zero-based index of the item to get. + /// The item at the specified index in the slot. + public StackItem this[int index] + { + get + { + return items[index]; + } + internal set + { + ref var oldValue = ref items[index]; + referenceCounter.RemoveStackReference(oldValue); + oldValue = value; + referenceCounter.AddStackReference(value); + } + } + + /// + /// Gets the number of items in the slot. + /// + public int Count => items.Length; + + /// + /// Creates a slot containing the specified items. + /// + /// The items to be contained. + /// The reference counter to be used. + public Slot(StackItem[] items, ReferenceCounter referenceCounter) + { + this.referenceCounter = referenceCounter; + this.items = items; + foreach (StackItem item in items) + referenceCounter.AddStackReference(item); + } + + /// + /// Create a slot of the specified size. + /// + /// Indicates the number of items contained in the slot. + /// The reference counter to be used. + public Slot(int count, ReferenceCounter referenceCounter) + { + this.referenceCounter = referenceCounter; + this.items = new StackItem[count]; + System.Array.Fill(items, StackItem.Null); + referenceCounter.AddStackReference(StackItem.Null, count); + } + + internal void ClearReferences() + { + foreach (StackItem item in items) + referenceCounter.RemoveStackReference(item); + } + + IEnumerator IEnumerable.GetEnumerator() + { + foreach (StackItem item in items) yield return item; + } + + IEnumerator IEnumerable.GetEnumerator() + { + return items.GetEnumerator(); + } + } +} diff --git a/src/Neo.VM/StronglyConnectedComponents/Tarjan.cs b/src/Neo.VM/StronglyConnectedComponents/Tarjan.cs new file mode 100644 index 0000000000..6fe867cd80 --- /dev/null +++ b/src/Neo.VM/StronglyConnectedComponents/Tarjan.cs @@ -0,0 +1,124 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project 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 T = Neo.VM.Types.StackItem; + +namespace Neo.VM.StronglyConnectedComponents +{ + class Tarjan + { + private readonly IEnumerable vertexs; + private readonly LinkedList> components = new(); + private readonly Stack stack = new(); + private int index = 0; + + public Tarjan(IEnumerable vertexs) + { + this.vertexs = vertexs; + } + + public LinkedList> Invoke() + { + foreach (var v in vertexs) + { + if (v.DFN < 0) + { + StrongConnectNonRecursive(v); + } + } + return components; + } + + private void StrongConnect(T v) + { + v.DFN = v.LowLink = ++index; + stack.Push(v); + v.OnStack = true; + + foreach (T w in v.Successors) + { + if (w.DFN < 0) + { + StrongConnect(w); + v.LowLink = Math.Min(v.LowLink, w.LowLink); + } + else if (w.OnStack) + { + v.LowLink = Math.Min(v.LowLink, w.DFN); + } + } + + if (v.LowLink == v.DFN) + { + HashSet scc = new(ReferenceEqualityComparer.Instance); + T w; + do + { + w = stack.Pop(); + w.OnStack = false; + scc.Add(w); + } while (v != w); + components.AddLast(scc); + } + } + + private void StrongConnectNonRecursive(T v) + { + Stack<(T node, T?, IEnumerator?, int)> sstack = new(); + sstack.Push((v, null, null, 0)); + while (sstack.TryPop(out var state)) + { + v = state.node; + var (_, w, s, n) = state; + switch (n) + { + case 0: + v.DFN = v.LowLink = ++index; + stack.Push(v); + v.OnStack = true; + s = v.Successors.GetEnumerator(); + goto case 2; + case 1: + v.LowLink = Math.Min(v.LowLink, w!.LowLink); + goto case 2; + case 2: + while (s!.MoveNext()) + { + w = s.Current; + if (w.DFN < 0) + { + sstack.Push((v, w, s, 1)); + v = w; + goto case 0; + } + else if (w.OnStack) + { + v.LowLink = Math.Min(v.LowLink, w.DFN); + } + } + if (v.LowLink == v.DFN) + { + HashSet scc = new(ReferenceEqualityComparer.Instance); + do + { + w = stack.Pop(); + w.OnStack = false; + scc.Add(w); + } while (v != w); + components.AddLast(scc); + } + break; + } + } + } + } +} diff --git a/src/Neo.VM/Types/Array.cs b/src/Neo.VM/Types/Array.cs new file mode 100644 index 0000000000..780521415b --- /dev/null +++ b/src/Neo.VM/Types/Array.cs @@ -0,0 +1,145 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project 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; +using System.Collections.Generic; + +namespace Neo.VM.Types +{ + /// + /// Represents an array or a complex object in the VM. + /// + public class Array : 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 Array(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 Array(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; + Array result = this is Struct ? new Struct(ReferenceCounter) : new Array(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/src/Neo.VM/Types/Boolean.cs b/src/Neo.VM/Types/Boolean.cs new file mode 100644 index 0000000000..56f620438d --- /dev/null +++ b/src/Neo.VM/Types/Boolean.cs @@ -0,0 +1,70 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project 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.Diagnostics; +using System.Numerics; +using System.Runtime.CompilerServices; + +namespace Neo.VM.Types +{ + /// + /// Represents a boolean ( or ) value in the VM. + /// + [DebuggerDisplay("Type={GetType().Name}, Value={value}")] + public class Boolean : PrimitiveType + { + private static readonly ReadOnlyMemory TRUE = new byte[] { 1 }; + private static readonly ReadOnlyMemory FALSE = new byte[] { 0 }; + + private readonly bool value; + + public override ReadOnlyMemory Memory => value ? TRUE : FALSE; + public override int Size => sizeof(bool); + public override StackItemType Type => StackItemType.Boolean; + + /// + /// Create a new VM object representing the boolean type. + /// + /// The initial value of the object. + internal Boolean(bool value) + { + this.value = value; + } + + public override bool Equals(StackItem? other) + { + if (ReferenceEquals(this, other)) return true; + if (other is Boolean b) return value == b.value; + return false; + } + + public override bool GetBoolean() + { + return value; + } + + public override int GetHashCode() + { + return HashCode.Combine(value); + } + + public override BigInteger GetInteger() + { + return value ? BigInteger.One : BigInteger.Zero; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Boolean(bool value) + { + return value ? True : False; + } + } +} diff --git a/src/Neo.VM/Types/Buffer.cs b/src/Neo.VM/Types/Buffer.cs new file mode 100644 index 0000000000..d80eecd4f5 --- /dev/null +++ b/src/Neo.VM/Types/Buffer.cs @@ -0,0 +1,110 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project 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.Buffers; +using System.Collections.Generic; +using System.Diagnostics; +using System.Numerics; + +namespace Neo.VM.Types +{ + /// + /// Represents a memory block that can be used for reading and writing in the VM. + /// + [DebuggerDisplay("Type={GetType().Name}, Value={System.Convert.ToHexString(GetSpan())}")] + public class Buffer : StackItem + { + /// + /// The internal byte array used to store the actual data. + /// + public readonly Memory InnerBuffer; + + /// + /// The size of the buffer. + /// + public int Size => InnerBuffer.Length; + public override StackItemType Type => StackItemType.Buffer; + + private readonly byte[] _buffer; + private bool _keep_alive = false; + + /// + /// Create a buffer of the specified size. + /// + /// The size of this buffer. + /// Indicates whether the created buffer is zero-initialized. + public Buffer(int size, bool zeroInitialize = true) + { + _buffer = ArrayPool.Shared.Rent(size); + InnerBuffer = new Memory(_buffer, 0, size); + if (zeroInitialize) InnerBuffer.Span.Clear(); + } + + /// + /// Create a buffer with the specified data. + /// + /// The data to be contained in this buffer. + public Buffer(ReadOnlySpan data) : this(data.Length, false) + { + data.CopyTo(InnerBuffer.Span); + } + + internal override void Cleanup() + { + if (!_keep_alive) + ArrayPool.Shared.Return(_buffer, clearArray: false); + } + + public void KeepAlive() + { + _keep_alive = true; + } + + public override StackItem ConvertTo(StackItemType type) + { + switch (type) + { + case StackItemType.Integer: + if (InnerBuffer.Length > Integer.MaxSize) + throw new InvalidCastException(); + return new BigInteger(InnerBuffer.Span); + case StackItemType.ByteString: +#if NET5_0_OR_GREATER + byte[] clone = GC.AllocateUninitializedArray(InnerBuffer.Length); +#else + byte[] clone = new byte[InnerBuffer.Length]; +#endif + InnerBuffer.CopyTo(clone); + return clone; + default: + return base.ConvertTo(type); + } + } + + internal override StackItem DeepCopy(Dictionary refMap, bool asImmutable) + { + if (refMap.TryGetValue(this, out StackItem? mappedItem)) return mappedItem; + StackItem result = asImmutable ? new ByteString(InnerBuffer.ToArray()) : new Buffer(InnerBuffer.Span); + refMap.Add(this, result); + return result; + } + + public override bool GetBoolean() + { + return true; + } + + public override ReadOnlySpan GetSpan() + { + return InnerBuffer.Span; + } + } +} diff --git a/src/Neo.VM/Types/ByteString.cs b/src/Neo.VM/Types/ByteString.cs new file mode 100644 index 0000000000..ddfe062210 --- /dev/null +++ b/src/Neo.VM/Types/ByteString.cs @@ -0,0 +1,136 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project 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.Cryptography; +using System; +using System.Buffers.Binary; +using System.Diagnostics; +using System.Numerics; +using System.Runtime.CompilerServices; + +namespace Neo.VM.Types +{ + /// + /// Represents an immutable memory block in the VM. + /// + [DebuggerDisplay("Type={GetType().Name}, Value={System.Convert.ToHexString(GetSpan())}")] + public class ByteString : PrimitiveType + { + /// + /// An empty . + /// + public static readonly ByteString Empty = ReadOnlyMemory.Empty; + + private static readonly uint s_seed = unchecked((uint)new Random().Next()); + private int _hashCode = 0; + + public override ReadOnlyMemory Memory { get; } + public override StackItemType Type => StackItemType.ByteString; + + /// + /// Create a new with the specified data. + /// + /// The data to be contained in this . + public ByteString(ReadOnlyMemory data) + { + this.Memory = data; + } + + private bool Equals(ByteString other) + { + return GetSpan().SequenceEqual(other.GetSpan()); + } + + public override bool Equals(StackItem? other) + { + if (ReferenceEquals(this, other)) return true; + if (other is not ByteString b) return false; + return Equals(b); + } + + internal override bool Equals(StackItem? other, ExecutionEngineLimits limits) + { + uint maxComparableSize = limits.MaxComparableSize; + return Equals(other, ref maxComparableSize); + } + + internal bool Equals(StackItem? other, ref uint limits) + { + if (Size > limits || limits == 0) + throw new InvalidOperationException("The operand exceeds the maximum comparable size."); + uint comparedSize = 1; + try + { + if (other is not ByteString b) return false; + comparedSize = Math.Max((uint)Math.Max(Size, b.Size), comparedSize); + if (ReferenceEquals(this, b)) return true; + if (b.Size > limits) + throw new InvalidOperationException("The operand exceeds the maximum comparable size."); + return Equals(b); + } + finally + { + limits -= comparedSize; + } + } + + public override bool GetBoolean() + { + if (Size > Integer.MaxSize) throw new InvalidCastException(); + return Unsafe.NotZero(GetSpan()); + } + + public override int GetHashCode() + { + if (_hashCode == 0) + { + using Murmur32 murmur = new(s_seed); + _hashCode = BinaryPrimitives.ReadInt32LittleEndian(murmur.ComputeHash(GetSpan().ToArray())); + } + return _hashCode; + } + + public override BigInteger GetInteger() + { + if (Size > Integer.MaxSize) throw new InvalidCastException($"MaxSize exceed: {Size}"); + return new BigInteger(GetSpan()); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator ReadOnlyMemory(ByteString value) + { + return value.Memory; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator ReadOnlySpan(ByteString value) + { + return value.Memory.Span; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator ByteString(byte[] value) + { + return new ByteString(value); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator ByteString(ReadOnlyMemory value) + { + return new ByteString(value); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator ByteString(string value) + { + return new ByteString(Utility.StrictUTF8.GetBytes(value)); + } + } +} diff --git a/src/Neo.VM/Types/CompoundType.cs b/src/Neo.VM/Types/CompoundType.cs new file mode 100644 index 0000000000..b3592a1e8b --- /dev/null +++ b/src/Neo.VM/Types/CompoundType.cs @@ -0,0 +1,70 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project 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.Diagnostics; + +namespace Neo.VM.Types +{ + /// + /// The base class for complex types in the VM. + /// + [DebuggerDisplay("Type={GetType().Name}, Count={Count}, Id={System.Collections.Generic.ReferenceEqualityComparer.Instance.GetHashCode(this)}")] + public abstract class CompoundType : StackItem + { + /// + /// The reference counter used to count the items in the VM object. + /// + protected readonly ReferenceCounter? ReferenceCounter; + + /// + /// Create a new with the specified reference counter. + /// + /// The reference counter to be used. + protected CompoundType(ReferenceCounter? referenceCounter) + { + this.ReferenceCounter = referenceCounter; + referenceCounter?.AddZeroReferred(this); + } + + /// + /// The number of items in this VM object. + /// + public abstract int Count { get; } + + public abstract IEnumerable SubItems { get; } + + public abstract int SubItemsCount { get; } + + public bool IsReadOnly { get; protected set; } + + /// + /// Remove all items from the VM object. + /// + public abstract void Clear(); + + internal abstract override StackItem DeepCopy(Dictionary refMap, bool asImmutable); + + public sealed override bool GetBoolean() + { + return true; + } + + /// + /// The operation is not supported. Always throw . + /// + /// This method always throws the exception. + public override int GetHashCode() + { + throw new NotSupportedException(); + } + } +} diff --git a/src/Neo.VM/Types/Integer.cs b/src/Neo.VM/Types/Integer.cs new file mode 100644 index 0000000000..04489fc54f --- /dev/null +++ b/src/Neo.VM/Types/Integer.cs @@ -0,0 +1,133 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project 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.Diagnostics; +using System.Numerics; +using System.Runtime.CompilerServices; + +namespace Neo.VM.Types +{ + /// + /// Represents an integer value in the VM. + /// + [DebuggerDisplay("Type={GetType().Name}, Value={value}")] + public class Integer : PrimitiveType + { + /// + /// The maximum size of an integer in bytes. + /// + public const int MaxSize = 32; + + /// + /// Represents the number 0. + /// + public static readonly Integer Zero = 0; + private readonly BigInteger value; + + public override ReadOnlyMemory Memory => value.IsZero ? ReadOnlyMemory.Empty : value.ToByteArray(); + public override int Size { get; } + public override StackItemType Type => StackItemType.Integer; + + /// + /// Create an integer with the specified value. + /// + /// The value of the integer. + public Integer(BigInteger value) + { + if (value.IsZero) + { + Size = 0; + } + else + { + Size = value.GetByteCount(); + if (Size > MaxSize) throw new ArgumentException($"MaxSize exceed: {Size}"); + } + this.value = value; + } + + public override bool Equals(StackItem? other) + { + if (ReferenceEquals(this, other)) return true; + if (other is Integer i) return value == i.value; + return false; + } + + public override bool GetBoolean() + { + return !value.IsZero; + } + + public override int GetHashCode() + { + return HashCode.Combine(value); + } + + public override BigInteger GetInteger() + { + return value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Integer(sbyte value) + { + return (BigInteger)value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Integer(byte value) + { + return (BigInteger)value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Integer(short value) + { + return (BigInteger)value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Integer(ushort value) + { + return (BigInteger)value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Integer(int value) + { + return (BigInteger)value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Integer(uint value) + { + return (BigInteger)value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Integer(long value) + { + return (BigInteger)value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Integer(ulong value) + { + return (BigInteger)value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Integer(BigInteger value) + { + return new Integer(value); + } + } +} diff --git a/src/Neo.VM/Types/InteropInterface.cs b/src/Neo.VM/Types/InteropInterface.cs new file mode 100644 index 0000000000..44edf11b0f --- /dev/null +++ b/src/Neo.VM/Types/InteropInterface.cs @@ -0,0 +1,58 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project 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.Diagnostics; + +namespace Neo.VM.Types +{ + /// + /// Represents an interface used to interoperate with the outside of the the VM. + /// + [DebuggerDisplay("Type={GetType().Name}, Value={_object}")] + public class InteropInterface : StackItem + { + private readonly object _object; + + public override StackItemType Type => StackItemType.InteropInterface; + + /// + /// Create an interoperability interface that wraps the specified . + /// + /// The wrapped . + public InteropInterface(object value) + { + _object = value ?? throw new ArgumentNullException(nameof(value)); + } + + public override bool Equals(StackItem? other) + { + if (ReferenceEquals(this, other)) return true; + if (other is InteropInterface i) return _object.Equals(i._object); + return false; + } + + public override bool GetBoolean() + { + return true; + } + + public override int GetHashCode() + { + return HashCode.Combine(_object); + } + + public override T GetInterface() + { + if (_object is T t) return t; + throw new InvalidCastException($"The item can't be casted to type {typeof(T)}"); + } + } +} diff --git a/src/Neo.VM/Types/Map.cs b/src/Neo.VM/Types/Map.cs new file mode 100644 index 0000000000..6be029614b --- /dev/null +++ b/src/Neo.VM/Types/Map.cs @@ -0,0 +1,180 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project 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.Collections; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; + +namespace Neo.VM.Types +{ + /// + /// Represents an ordered collection of key-value pairs in the VM. + /// + public class Map : CompoundType, IReadOnlyDictionary + { + /// + /// Indicates the maximum size of keys in bytes. + /// + public const int MaxKeySize = 64; + + private readonly OrderedDictionary dictionary = new(); + + /// + /// Gets or sets the element that has the specified key in the map. + /// + /// The key to locate. + /// The element that has the specified key in the map. + public StackItem this[PrimitiveType key] + { + get + { + if (key.Size > MaxKeySize) + throw new ArgumentException($"MaxKeySize exceed: {key.Size}"); + return dictionary[key]; + } + set + { + if (key.Size > MaxKeySize) + throw new ArgumentException($"MaxKeySize exceed: {key.Size}"); + if (IsReadOnly) throw new InvalidOperationException("The object is readonly."); + if (ReferenceCounter != null) + { + if (dictionary.TryGetValue(key, out StackItem? old_value)) + ReferenceCounter.RemoveReference(old_value, this); + else + ReferenceCounter.AddReference(key, this); + ReferenceCounter.AddReference(value, this); + } + dictionary[key] = value; + } + } + + public override int Count => dictionary.Count; + + /// + /// Gets an enumerable collection that contains the keys in the map. + /// + public IEnumerable Keys => dictionary.Keys; + + public override IEnumerable SubItems => Keys.Concat(Values); + + public override int SubItemsCount => dictionary.Count * 2; + + public override StackItemType Type => StackItemType.Map; + + /// + /// Gets an enumerable collection that contains the values in the map. + /// + public IEnumerable Values => dictionary.Values; + + /// + /// Create a new map with the specified reference counter. + /// + /// The reference counter to be used. + public Map(ReferenceCounter? referenceCounter = null) + : base(referenceCounter) + { + } + + public override void Clear() + { + if (IsReadOnly) throw new InvalidOperationException("The object is readonly."); + if (ReferenceCounter != null) + foreach (var pair in dictionary) + { + ReferenceCounter.RemoveReference(pair.Key, this); + ReferenceCounter.RemoveReference(pair.Value, this); + } + dictionary.Clear(); + } + + /// + /// Determines whether the map contains an element that has the specified key. + /// + /// The key to locate. + /// + /// if the map contains an element that has the specified key; + /// otherwise, . + /// + public bool ContainsKey(PrimitiveType key) + { + if (key.Size > MaxKeySize) + throw new ArgumentException($"MaxKeySize exceed: {key.Size}"); + return dictionary.ContainsKey(key); + } + + internal override StackItem DeepCopy(Dictionary refMap, bool asImmutable) + { + if (refMap.TryGetValue(this, out StackItem? mappedItem)) return mappedItem; + Map result = new(ReferenceCounter); + refMap.Add(this, result); + foreach (var (k, v) in dictionary) + result[k] = v.DeepCopy(refMap, asImmutable); + result.IsReadOnly = true; + return result; + } + + IEnumerator> IEnumerable>.GetEnumerator() + { + return ((IDictionary)dictionary).GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return ((IDictionary)dictionary).GetEnumerator(); + } + + /// + /// Removes the element with the specified key from the map. + /// + /// The key of the element to remove. + /// + /// if the element is successfully removed; + /// otherwise, . + /// This method also returns if was not found in the original map. + /// + public bool Remove(PrimitiveType key) + { + if (key.Size > MaxKeySize) + throw new ArgumentException($"MaxKeySize exceed: {key.Size}"); + if (IsReadOnly) throw new InvalidOperationException("The object is readonly."); + if (!dictionary.Remove(key, out StackItem? old_value)) + return false; + ReferenceCounter?.RemoveReference(key, this); + ReferenceCounter?.RemoveReference(old_value, this); + return true; + } + + /// + /// Gets the value that is associated with the specified key. + /// + /// The key to locate. + /// + /// When this method returns, the value associated with the specified key, if the key is found; + /// otherwise, . + /// + /// + /// if the map contains an element that has the specified key; + /// otherwise, . + /// +// supress warning of value parameter nullability mismatch +#pragma warning disable CS8767 + public bool TryGetValue(PrimitiveType key, [MaybeNullWhen(false)] out StackItem value) +#pragma warning restore CS8767 + { + if (key.Size > MaxKeySize) + throw new ArgumentException($"MaxKeySize exceed: {key.Size}"); + return dictionary.TryGetValue(key, out value); + } + } +} diff --git a/src/Neo.VM/Types/Null.cs b/src/Neo.VM/Types/Null.cs new file mode 100644 index 0000000000..d342f422e3 --- /dev/null +++ b/src/Neo.VM/Types/Null.cs @@ -0,0 +1,59 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project 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.Diagnostics.CodeAnalysis; + +namespace Neo.VM.Types +{ + /// + /// Represents in the VM. + /// + public class Null : StackItem + { + public override StackItemType Type => StackItemType.Any; + + internal Null() { } + + public override StackItem ConvertTo(StackItemType type) + { + if (type == StackItemType.Any || !Enum.IsDefined(typeof(StackItemType), type)) + throw new InvalidCastException($"Type can't be converted to StackItemType: {type}"); + return this; + } + + public override bool Equals(StackItem? other) + { + if (ReferenceEquals(this, other)) return true; + return other is Null; + } + + public override bool GetBoolean() + { + return false; + } + + public override int GetHashCode() + { + return 0; + } + + [return: MaybeNull] + public override T GetInterface() + { + return default; + } + + public override string? GetString() + { + return null; + } + } +} diff --git a/src/Neo.VM/Types/Pointer.cs b/src/Neo.VM/Types/Pointer.cs new file mode 100644 index 0000000000..5af77ed414 --- /dev/null +++ b/src/Neo.VM/Types/Pointer.cs @@ -0,0 +1,62 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project 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.Diagnostics; + +namespace Neo.VM.Types +{ + /// + /// Represents the instruction pointer in the VM, used as the target of jump instructions. + /// + [DebuggerDisplay("Type={GetType().Name}, Position={Position}")] + public class Pointer : StackItem + { + /// + /// The object containing this pointer. + /// + public Script Script { get; } + + /// + /// The position of the pointer in the script. + /// + public int Position { get; } + + public override StackItemType Type => StackItemType.Pointer; + + /// + /// Create a code pointer with the specified script and position. + /// + /// The object containing this pointer. + /// The position of the pointer in the script. + public Pointer(Script script, int position) + { + this.Script = script; + this.Position = position; + } + + public override bool Equals(StackItem? other) + { + if (other == this) return true; + if (other is Pointer p) return Position == p.Position && Script == p.Script; + return false; + } + + public override bool GetBoolean() + { + return true; + } + + public override int GetHashCode() + { + return HashCode.Combine(Script, Position); + } + } +} diff --git a/src/Neo.VM/Types/PrimitiveType.cs b/src/Neo.VM/Types/PrimitiveType.cs new file mode 100644 index 0000000000..794804dcc9 --- /dev/null +++ b/src/Neo.VM/Types/PrimitiveType.cs @@ -0,0 +1,138 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project 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.VM.Types +{ + /// + /// The base class for primitive types in the VM. + /// + public abstract class PrimitiveType : StackItem + { + public abstract ReadOnlyMemory Memory { get; } + + /// + /// The size of the VM object in bytes. + /// + public virtual int Size => Memory.Length; + + public override StackItem ConvertTo(StackItemType type) + { + if (type == Type) return this; + return type switch + { + StackItemType.Integer => GetInteger(), + StackItemType.ByteString => Memory, + StackItemType.Buffer => new Buffer(GetSpan()), + _ => base.ConvertTo(type) + }; + } + + internal sealed override StackItem DeepCopy(Dictionary refMap, bool asImmutable) + { + return this; + } + + public abstract override bool Equals(StackItem? other); + + /// + /// Get the hash code of the VM object, which is used for key comparison in the . + /// + /// The hash code of this VM object. + public abstract override int GetHashCode(); + + public sealed override ReadOnlySpan GetSpan() + { + return Memory.Span; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator PrimitiveType(sbyte value) + { + return (Integer)value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator PrimitiveType(byte value) + { + return (Integer)value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator PrimitiveType(short value) + { + return (Integer)value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator PrimitiveType(ushort value) + { + return (Integer)value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator PrimitiveType(int value) + { + return (Integer)value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator PrimitiveType(uint value) + { + return (Integer)value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator PrimitiveType(long value) + { + return (Integer)value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator PrimitiveType(ulong value) + { + return (Integer)value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator PrimitiveType(BigInteger value) + { + return (Integer)value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator PrimitiveType(bool value) + { + return (Boolean)value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator PrimitiveType(byte[] value) + { + return (ByteString)value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator PrimitiveType(ReadOnlyMemory value) + { + return (ByteString)value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator PrimitiveType(string value) + { + return (ByteString)value; + } + } +} diff --git a/src/Neo.VM/Types/StackItem.Vertex.cs b/src/Neo.VM/Types/StackItem.Vertex.cs new file mode 100644 index 0000000000..6458a568d8 --- /dev/null +++ b/src/Neo.VM/Types/StackItem.Vertex.cs @@ -0,0 +1,35 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project 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.Collections.Generic; +using System.Linq; + +namespace Neo.VM.Types +{ + partial class StackItem + { + internal class ObjectReferenceEntry + { + public StackItem Item; + public int References; + public ObjectReferenceEntry(StackItem item) => Item = item; + } + + internal int StackReferences = 0; + internal Dictionary? ObjectReferences; + internal int DFN = -1; + internal int LowLink = 0; + internal bool OnStack = false; + + internal IEnumerable Successors => ObjectReferences?.Values.Where(p => p.References > 0).Select(p => p.Item) ?? System.Array.Empty(); + + internal void Reset() => (DFN, LowLink, OnStack) = (-1, 0, false); + } +} diff --git a/src/Neo.VM/Types/StackItem.cs b/src/Neo.VM/Types/StackItem.cs new file mode 100644 index 0000000000..94c39aee40 --- /dev/null +++ b/src/Neo.VM/Types/StackItem.cs @@ -0,0 +1,261 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project 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. + +#pragma warning disable CS0659 + +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Numerics; +using System.Runtime.CompilerServices; + +namespace Neo.VM.Types +{ + /// + /// The base class for all types in the VM. + /// + public abstract partial class StackItem : IEquatable + { + [ThreadStatic] + private static Boolean? tls_true = null; + + /// + /// Represents in the VM. + /// + public static Boolean True + { + get + { + tls_true ??= new(true); + return tls_true; + } + } + + [ThreadStatic] + private static Boolean? tls_false = null; + + /// + /// Represents in the VM. + /// + public static Boolean False + { + get + { + tls_false ??= new(false); + return tls_false; + } + } + + [ThreadStatic] + private static Null? tls_null = null; + + /// + /// Represents in the VM. + /// + public static StackItem Null + { + get + { + tls_null ??= new(); + return tls_null; + } + } + + /// + /// Indicates whether the object is . + /// + public bool IsNull => this is Null; + + /// + /// The type of this VM object. + /// + public abstract StackItemType Type { get; } + + /// + /// Convert the VM object to the specified type. + /// + /// The type to be converted to. + /// The converted object. + public virtual StackItem ConvertTo(StackItemType type) + { + if (type == Type) return this; + if (type == StackItemType.Boolean) return GetBoolean(); + throw new InvalidCastException(); + } + + internal virtual void Cleanup() + { + } + + /// + /// Copy the object and all its children. + /// + /// The copied object. + public StackItem DeepCopy(bool asImmutable = false) + { + return DeepCopy(new(ReferenceEqualityComparer.Instance), asImmutable); + } + + internal virtual StackItem DeepCopy(Dictionary refMap, bool asImmutable) + { + return this; + } + + public sealed override bool Equals(object? obj) + { + if (ReferenceEquals(this, obj)) return true; + if (obj is StackItem item) return Equals(item); + return false; + } + + public virtual bool Equals(StackItem? other) + { + return ReferenceEquals(this, other); + } + + internal virtual bool Equals(StackItem? other, ExecutionEngineLimits limits) + { + return Equals(other); + } + + /// + /// Wrap the specified and return an containing the . + /// + /// The wrapped . + /// + public static StackItem FromInterface(object? value) + { + if (value is null) return Null; + return new InteropInterface(value); + } + + /// + /// Get the boolean value represented by the VM object. + /// + /// The boolean value represented by the VM object. + public abstract bool GetBoolean(); + + /// + /// Get the integer value represented by the VM object. + /// + /// The integer value represented by the VM object. + public virtual BigInteger GetInteger() + { + throw new InvalidCastException(); + } + + /// + /// Get the wrapped by this interface and convert it to the specified type. + /// + /// The type to convert to. + /// The wrapped . + [return: MaybeNull] + public virtual T GetInterface() where T : notnull + { + throw new InvalidCastException(); + } + + /// + /// Get the readonly span used to read the VM object data. + /// + /// + public virtual ReadOnlySpan GetSpan() + { + throw new InvalidCastException(); + } + + /// + /// Get the value represented by the VM object. + /// + /// The value represented by the VM object. + public virtual string? GetString() + { + return Utility.StrictUTF8.GetString(GetSpan()); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator StackItem(sbyte value) + { + return (Integer)value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator StackItem(byte value) + { + return (Integer)value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator StackItem(short value) + { + return (Integer)value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator StackItem(ushort value) + { + return (Integer)value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator StackItem(int value) + { + return (Integer)value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator StackItem(uint value) + { + return (Integer)value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator StackItem(long value) + { + return (Integer)value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator StackItem(ulong value) + { + return (Integer)value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator StackItem(BigInteger value) + { + return (Integer)value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator StackItem(bool value) + { + return value ? True : False; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator StackItem(byte[] value) + { + return (ByteString)value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator StackItem(ReadOnlyMemory value) + { + return (ByteString)value; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator StackItem(string value) + { + return (ByteString)value; + } + } +} diff --git a/src/Neo.VM/Types/StackItemType.cs b/src/Neo.VM/Types/StackItemType.cs new file mode 100644 index 0000000000..47a8407a83 --- /dev/null +++ b/src/Neo.VM/Types/StackItemType.cs @@ -0,0 +1,68 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project 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.VM.Types +{ + /// + /// An enumeration representing the types in the VM. + /// + public enum StackItemType : byte + { + /// + /// Represents any type. + /// + Any = 0x00, + + /// + /// Represents a code pointer. + /// + Pointer = 0x10, + + /// + /// Represents the boolean ( or ) type. + /// + Boolean = 0x20, + + /// + /// Represents an integer. + /// + Integer = 0x21, + + /// + /// Represents an immutable memory block. + /// + ByteString = 0x28, + + /// + /// Represents a memory block that can be used for reading and writing. + /// + Buffer = 0x30, + + /// + /// Represents an array or a complex object. + /// + Array = 0x40, + + /// + /// Represents a structure. + /// + Struct = 0x41, + + /// + /// Represents an ordered collection of key-value pairs. + /// + Map = 0x48, + + /// + /// Represents an interface used to interoperate with the outside of the the VM. + /// + InteropInterface = 0x60, + } +} diff --git a/src/Neo.VM/Types/Struct.cs b/src/Neo.VM/Types/Struct.cs new file mode 100644 index 0000000000..07b21ba540 --- /dev/null +++ b/src/Neo.VM/Types/Struct.cs @@ -0,0 +1,133 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project 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; + +namespace Neo.VM.Types +{ + /// + /// Represents a structure in the VM. + /// + public class Struct : Array + { + public override StackItemType Type => StackItemType.Struct; + + /// + /// Create a structure with the specified fields. + /// + /// The fields to be included in the structure. + public Struct(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 Struct(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 Struct Clone(ExecutionEngineLimits limits) + { + int count = (int)(limits.MaxStackSize - 1); + Struct result = new(ReferenceCounter); + Queue queue = new(); + queue.Enqueue(result); + queue.Enqueue(this); + while (queue.Count > 0) + { + Struct a = queue.Dequeue(); + Struct b = queue.Dequeue(); + foreach (StackItem item in b) + { + count--; + if (count < 0) throw new InvalidOperationException("Beyond clone limits!"); + if (item is Struct sb) + { + Struct 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 Array(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 Struct 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 Struct sa) + { + if (ReferenceEquals(a, b)) continue; + if (b is not Struct 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/Unsafe.cs b/src/Neo.VM/Unsafe.cs new file mode 100644 index 0000000000..71d31311ae --- /dev/null +++ b/src/Neo.VM/Unsafe.cs @@ -0,0 +1,41 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project 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.Runtime.CompilerServices; + +namespace Neo.VM +{ + unsafe internal static class Unsafe + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool NotZero(ReadOnlySpan x) + { + int len = x.Length; + if (len == 0) return false; + fixed (byte* xp = x) + { + long* xlp = (long*)xp; + for (; len >= 8; len -= 8) + { + if (*xlp != 0) return true; + xlp++; + } + byte* xbp = (byte*)xlp; + for (; len > 0; len--) + { + if (*xbp != 0) return true; + xbp++; + } + } + return false; + } + } +} diff --git a/src/Neo.VM/Utility.cs b/src/Neo.VM/Utility.cs new file mode 100644 index 0000000000..6601df9400 --- /dev/null +++ b/src/Neo.VM/Utility.cs @@ -0,0 +1,89 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project 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.Numerics; +using System.Runtime.CompilerServices; +using System.Text; + +namespace Neo.VM +{ + internal static class Utility + { + public static Encoding StrictUTF8 { get; } + + static Utility() + { + StrictUTF8 = (Encoding)Encoding.UTF8.Clone(); + StrictUTF8.DecoderFallback = DecoderFallback.ExceptionFallback; + StrictUTF8.EncoderFallback = EncoderFallback.ExceptionFallback; + } + + public static BigInteger ModInverse(this BigInteger value, BigInteger modulus) + { + if (value <= 0) throw new ArgumentOutOfRangeException(nameof(value)); + if (modulus < 2) throw new ArgumentOutOfRangeException(nameof(modulus)); + BigInteger r = value, old_r = modulus, s = 1, old_s = 0; + while (r > 0) + { + BigInteger q = old_r / r; + (old_r, r) = (r, old_r % r); + (old_s, s) = (s, old_s - q * s); + } + BigInteger result = old_s % modulus; + if (result < 0) result += modulus; + if (!(value * result % modulus).IsOne) throw new InvalidOperationException(); + return result; + } + + public static BigInteger Sqrt(this BigInteger value) + { + if (value < 0) throw new InvalidOperationException("value can not be negative"); + if (value.IsZero) return BigInteger.Zero; + if (value < 4) return BigInteger.One; + + var z = value; + var x = BigInteger.One << (int)(((value - 1).GetBitLength() + 1) >> 1); + while (x < z) + { + z = x; + x = (value / x + x) / 2; + } + + return z; + } + +#if !NET5_0_OR_GREATER + static int GetBitLength(this BigInteger i) + { + byte[] b = i.ToByteArray(); + return (b.Length - 1) * 8 + BitLen(i.Sign > 0 ? b[b.Length - 1] : 255 - b[b.Length - 1]); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + 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))))); + } +#endif + } +} diff --git a/src/Neo.VM/VMState.cs b/src/Neo.VM/VMState.cs new file mode 100644 index 0000000000..6d441120bb --- /dev/null +++ b/src/Neo.VM/VMState.cs @@ -0,0 +1,38 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project 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.VM +{ + /// + /// Indicates the status of the VM. + /// + public enum VMState : byte + { + /// + /// Indicates that the execution is in progress or has not yet begun. + /// + NONE = 0, + + /// + /// Indicates that the execution has been completed successfully. + /// + HALT = 1 << 0, + + /// + /// Indicates that the execution has ended, and an exception that cannot be caught is thrown. + /// + FAULT = 1 << 1, + + /// + /// Indicates that a breakpoint is currently being hit. + /// + BREAK = 1 << 2, + } +} diff --git a/src/Neo.VM/VMUnhandledException.cs b/src/Neo.VM/VMUnhandledException.cs new file mode 100644 index 0000000000..7d3da757c5 --- /dev/null +++ b/src/Neo.VM/VMUnhandledException.cs @@ -0,0 +1,52 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-vm is free software distributed under the MIT software license, +// see the accompanying file LICENSE in the main directory of the +// project 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; +using System.Text; +using Array = Neo.VM.Types.Array; + +namespace Neo.VM +{ + /// + /// Represents an unhandled exception in the VM. + /// Thrown when there is an exception in the VM that is not caught by any script. + /// + public class VMUnhandledException : Exception + { + /// + /// The unhandled exception in the VM. + /// + public StackItem ExceptionObject { get; } + + /// + /// Initializes a new instance of the class. + /// + /// The unhandled exception in the VM. + public VMUnhandledException(StackItem ex) : base(GetExceptionMessage(ex)) + { + ExceptionObject = ex; + } + + private static string GetExceptionMessage(StackItem e) + { + StringBuilder sb = new("An unhandled exception was thrown."); + ByteString? s = e as ByteString; + if (s is null && e is Array array && array.Count > 0) + s = array[0] as ByteString; + if (s != null) + { + sb.Append(' '); + sb.Append(Encoding.UTF8.GetString(s.GetSpan())); + } + return sb.ToString(); + } + } +} diff --git a/src/Neo/Neo.csproj b/src/Neo/Neo.csproj index 31026ce74f..2d3a8a04cc 100644 --- a/src/Neo/Neo.csproj +++ b/src/Neo/Neo.csproj @@ -13,12 +13,12 @@ - + diff --git a/tests/Neo.VM.Tests/Converters/ScriptConverter.cs b/tests/Neo.VM.Tests/Converters/ScriptConverter.cs new file mode 100644 index 0000000000..c0610a573c --- /dev/null +++ b/tests/Neo.VM.Tests/Converters/ScriptConverter.cs @@ -0,0 +1,152 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Test.Extensions; +using Neo.VM; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System; +using System.Linq; +using System.Text.RegularExpressions; + +namespace Neo.Test.Converters +{ + internal class ScriptConverter : JsonConverter + { + public override bool CanConvert(Type objectType) + { + return objectType == typeof(byte[]) || objectType == typeof(string); + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + switch (reader.TokenType) + { + case JsonToken.String: + { + if (reader.Value is string str) + { + Assert.IsTrue(str.StartsWith("0x"), $"'0x' prefix required for value: '{str}'"); + return str.FromHexString(); + } + break; + } + case JsonToken.Bytes: + { + if (reader.Value is byte[] data) return data; + break; + } + case JsonToken.StartArray: + { + using var script = new ScriptBuilder(); + + foreach (var entry in JArray.Load(reader)) + { + var mul = 1; + var value = entry.Value(); + + if (Enum.IsDefined(typeof(OpCode), value) && Enum.TryParse(value, out var opCode)) + { + for (int x = 0; x < mul; x++) + { + script.Emit(opCode); + } + } + else + { + for (int x = 0; x < mul; x++) + { + Assert.IsTrue(value.StartsWith("0x"), $"'0x' prefix required for value: '{value}'"); + script.EmitRaw(value.FromHexString()); + } + } + } + + return script.ToArray(); + } + } + + throw new FormatException(); + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + if (value is byte[] data) + { + int ip = 0; + var array = new JArray(); + + try + { + for (ip = 0; ip < data.Length;) + { + var instruction = new Instruction(data, ip); + + array.Add(instruction.OpCode.ToString().ToUpperInvariant()); + + // Operand Size + + if (instruction.Size - 1 - instruction.Operand.Length > 0) + { + array.Add(data.Skip(ip + 1).Take(instruction.Size - 1 - instruction.Operand.Length).ToArray().ToHexString()); + } + + if (!instruction.Operand.IsEmpty) + { + // Data + + array.Add(instruction.Operand.ToArray().ToHexString()); + } + + ip += instruction.Size; + } + } + catch + { + // Something was wrong, but maybe it's intentioned + + if (Enum.IsDefined(typeof(OpCode), data[ip])) + { + // Check if it was the content and not the opcode + + array.Add(((OpCode)data[ip]).ToString().ToUpperInvariant()); + array.Add(data[(ip + 1)..].ToHexString()); + } + else + { + array.Add(data[ip..].ToHexString()); + } + } + + // Write the script + + writer.WriteStartArray(); + foreach (var entry in array) writer.WriteValue(entry.Value()); + writer.WriteEndArray(); + + // Double check - Ensure that the format is exactly the same + + using var script = new ScriptBuilder(); + + foreach (var entry in array) + { + if (Enum.TryParse(entry.Value(), out var opCode)) + { + script.Emit(opCode); + } + else + { + script.EmitRaw(entry.Value().FromHexString()); + } + } + + if (script.ToArray().ToHexString() != data.ToHexString()) + { + throw new FormatException(); + } + } + else + { + throw new FormatException(); + } + } + } +} diff --git a/tests/Neo.VM.Tests/Converters/UppercaseEnum.cs b/tests/Neo.VM.Tests/Converters/UppercaseEnum.cs new file mode 100644 index 0000000000..b1b168a3be --- /dev/null +++ b/tests/Neo.VM.Tests/Converters/UppercaseEnum.cs @@ -0,0 +1,23 @@ +using Newtonsoft.Json; +using System; + +namespace Neo.Test.Converters +{ + internal class UppercaseEnum : JsonConverter + { + public override bool CanConvert(Type objectType) + { + return objectType.IsEnum; + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + return Enum.Parse(objectType, reader.Value.ToString(), true); + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + writer.WriteValue(value.ToString().ToUpperInvariant()); + } + } +} diff --git a/tests/Neo.VM.Tests/Extensions/JsonExtensions.cs b/tests/Neo.VM.Tests/Extensions/JsonExtensions.cs new file mode 100644 index 0000000000..6f0c4d73d5 --- /dev/null +++ b/tests/Neo.VM.Tests/Extensions/JsonExtensions.cs @@ -0,0 +1,47 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; +using Newtonsoft.Json.Serialization; + +namespace Neo.Test.Extensions +{ + public static class JsonExtensions + { + private static readonly JsonSerializerSettings _settings; + + /// + /// Static constructor + /// + static JsonExtensions() + { + _settings = new JsonSerializerSettings + { + ContractResolver = new CamelCasePropertyNamesContractResolver(), + Formatting = Formatting.Indented, + NullValueHandling = NullValueHandling.Ignore, + }; + + _settings.Converters.Add(new StringEnumConverter(new CamelCaseNamingStrategy())); + } + + /// + /// Deserialize json to object + /// + /// Type + /// Json + /// Unit test + public static T DeserializeJson(this string input) + { + return JsonConvert.DeserializeObject(input, _settings); + } + + /// + /// Serialize UT to json + /// + /// Unit test + /// Json + public static string ToJson(this object ut) + { + return JsonConvert.SerializeObject(ut, _settings); + } + } +} diff --git a/tests/Neo.VM.Tests/Extensions/StringExtensions.cs b/tests/Neo.VM.Tests/Extensions/StringExtensions.cs new file mode 100644 index 0000000000..cab595568b --- /dev/null +++ b/tests/Neo.VM.Tests/Extensions/StringExtensions.cs @@ -0,0 +1,57 @@ +using System; +using System.Globalization; + +namespace Neo.Test.Extensions +{ + internal static class StringExtensions + { + /// + /// Convert buffer to hex string + /// + /// Data + /// Return hex string + public static string ToHexString(this byte[] data) + { + if (data == null) return ""; + + var m = data.Length; + if (m == 0) return ""; + + var sb = new char[(m * 2) + 2]; + + sb[0] = '0'; + sb[1] = 'x'; + + for (int x = 0, y = 2; x < m; x++, y += 2) + { + var hex = data[x].ToString("x2"); + + sb[y] = hex[0]; + sb[y + 1] = hex[1]; + } + + return new string(sb); + } + + /// + /// Convert string in Hex format to byte array + /// + /// Hexadecimal string + /// Return byte array + public static byte[] FromHexString(this string value) + { + if (string.IsNullOrEmpty(value)) + return Array.Empty(); + if (value.StartsWith("0x")) + value = value[2..]; + if (value.Length % 2 == 1) + throw new FormatException(); + + var result = new byte[value.Length / 2]; + for (var i = 0; i < result.Length; i++) + result[i] = byte.Parse(value.Substring(i * 2, 2), NumberStyles.AllowHexSpecifier); + + return result; + } + } +} diff --git a/tests/Neo.VM.Tests/Helpers/RandomHelper.cs b/tests/Neo.VM.Tests/Helpers/RandomHelper.cs new file mode 100644 index 0000000000..53085b44d5 --- /dev/null +++ b/tests/Neo.VM.Tests/Helpers/RandomHelper.cs @@ -0,0 +1,39 @@ +using System; + +namespace Neo.Test.Helpers +{ + public class RandomHelper + { + private const string _randchars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + private static readonly Random _rand = new(); + + /// + /// Get random buffer + /// + /// Length + /// Buffer + public static byte[] RandBuffer(int length) + { + var buffer = new byte[length]; + _rand.NextBytes(buffer); + return buffer; + } + + /// + /// Get random string + /// + /// Length + /// Buffer + public static string RandString(int length) + { + var stringChars = new char[length]; + + for (int i = 0; i < stringChars.Length; i++) + { + stringChars[i] = _randchars[_rand.Next(_randchars.Length)]; + } + + return new string(stringChars); + } + } +} diff --git a/tests/Neo.VM.Tests/Neo.VM.Tests.csproj b/tests/Neo.VM.Tests/Neo.VM.Tests.csproj new file mode 100644 index 0000000000..b86f27296a --- /dev/null +++ b/tests/Neo.VM.Tests/Neo.VM.Tests.csproj @@ -0,0 +1,21 @@ + + + + net7.0 + 9.0 + Neo.Test + true + false + + + + + + + + + PreserveNewest + + + + diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/GE.json b/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/GE.json new file mode 100644 index 0000000000..d70ebf3be6 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/GE.json @@ -0,0 +1,443 @@ +{ + "category": "Numeric", + "name": "GE same types", + "tests": [ + { + "name": "Without two pushes", + "script": [ + "GE" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without one push", + "script": [ + "PUSH0", + "GE" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "GE", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + } + ] + }, + { + "name": "Real test [0,0]", + "script": [ + "PUSH0", + "PUSH0", + "GE" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "GE", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Real test [1,0]", + "script": [ + "PUSH1", + "PUSH0", + "GE" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "GE", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Real test [0,1]", + "script": [ + "PUSH0", + "PUSH1", + "GE" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "GE", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test [null,1]", + "script": [ + "PUSHNULL", + "PUSH1", + "GE" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "GE", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "null" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test [1,null]", + "script": [ + "PUSH1", + "PUSHNULL", + "GE" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "GE", + "evaluationStack": [ + { + "type": "null" + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "FAULT test [1,array]", + "script": [ + "PUSH1", + "NEWARRAY0", + "GE" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "GE", + "evaluationStack": [ + { + "type": "array", + "value": [] + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT", + "resultStack": [ + { + "type": "boolean", + "value": false + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/GT.json b/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/GT.json new file mode 100644 index 0000000000..edc0767b3c --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/GT.json @@ -0,0 +1,443 @@ +{ + "category": "Numeric", + "name": "GT same types", + "tests": [ + { + "name": "Without two pushes", + "script": [ + "GT" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without one push", + "script": [ + "PUSH0", + "GT" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "GT", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + } + ] + }, + { + "name": "Real test [0,0]", + "script": [ + "PUSH0", + "PUSH0", + "GT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "GT", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test [1,0]", + "script": [ + "PUSH1", + "PUSH0", + "GT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "GT", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Real test [0,1]", + "script": [ + "PUSH0", + "PUSH1", + "GT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "GT", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test [null,1]", + "script": [ + "PUSHNULL", + "PUSH1", + "GT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "GT", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "null" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test [1,null]", + "script": [ + "PUSH1", + "PUSHNULL", + "GT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "GT", + "evaluationStack": [ + { + "type": "null" + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "FAULT test [1,array]", + "script": [ + "PUSH1", + "NEWARRAY0", + "GT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "GT", + "evaluationStack": [ + { + "type": "array", + "value": [] + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT", + "resultStack": [ + { + "type": "boolean", + "value": false + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/LE.json b/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/LE.json new file mode 100644 index 0000000000..eb85215322 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/LE.json @@ -0,0 +1,443 @@ +{ + "category": "Numeric", + "name": "LE same types", + "tests": [ + { + "name": "Without two pushes", + "script": [ + "LE" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without one push", + "script": [ + "PUSH0", + "LE" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "LE", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + } + ] + }, + { + "name": "Real test [0,0]", + "script": [ + "PUSH0", + "PUSH0", + "LE" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "LE", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Real test [1,0]", + "script": [ + "PUSH1", + "PUSH0", + "LE" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "LE", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test [0,1]", + "script": [ + "PUSH0", + "PUSH1", + "LE" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "LE", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Real test [null,1]", + "script": [ + "PUSHNULL", + "PUSH1", + "LE" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "LE", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "null" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test [1,null]", + "script": [ + "PUSH1", + "PUSHNULL", + "LE" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "LE", + "evaluationStack": [ + { + "type": "null" + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "FAULT test [1,array]", + "script": [ + "PUSH1", + "NEWARRAY0", + "LE" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "LE", + "evaluationStack": [ + { + "type": "array", + "value": [] + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT", + "resultStack": [ + { + "type": "boolean", + "value": false + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/LT.json b/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/LT.json new file mode 100644 index 0000000000..ed2b6fac01 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/LT.json @@ -0,0 +1,443 @@ +{ + "category": "Numeric", + "name": "LT same types", + "tests": [ + { + "name": "Without two pushes", + "script": [ + "LT" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without one push", + "script": [ + "PUSH0", + "LT" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "LT", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + } + ] + }, + { + "name": "Real test [0,0]", + "script": [ + "PUSH0", + "PUSH0", + "LT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "LT", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test [1,0]", + "script": [ + "PUSH1", + "PUSH0", + "LT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "LT", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test [0,1]", + "script": [ + "PUSH0", + "PUSH1", + "LT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "LT", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Real test [null,1]", + "script": [ + "PUSHNULL", + "PUSH1", + "LT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "LT", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "null" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test [1,null]", + "script": [ + "PUSH1", + "PUSHNULL", + "LT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "LT", + "evaluationStack": [ + { + "type": "null" + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "FAULT test [1,array]", + "script": [ + "PUSH1", + "NEWARRAY0", + "LT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "LT", + "evaluationStack": [ + { + "type": "array", + "value": [] + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT", + "resultStack": [ + { + "type": "boolean", + "value": false + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/MODMUL.json b/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/MODMUL.json new file mode 100644 index 0000000000..e3b93bfb56 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/MODMUL.json @@ -0,0 +1,141 @@ +{ + "category": "Numeric", + "name": "MODMUL", + "tests": [ + { + "name": "Exception - Without items", + "script": [ + "MODMUL" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "MODMUL", + "evaluationStack": [] + } + ] + } + } + ] + }, + { + "name": "Real test (8 * 2 % 3)", + "script": [ + "PUSH8", + "PUSH2", + "PUSH3", + "MODMUL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "MODMUL", + "evaluationStack": [ + { + "type": "Integer", + "value": 3 + }, + { + "type": "Integer", + "value": 2 + }, + { + "type": "Integer", + "value": 8 + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "invocationStack": [], + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + }, + { + "name": "Real test (16 * 2 % 4)", + "script": [ + "PUSH16", + "PUSH2", + "PUSH4", + "MODMUL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "MODMUL", + "evaluationStack": [ + { + "type": "Integer", + "value": 4 + }, + { + "type": "Integer", + "value": 2 + }, + { + "type": "Integer", + "value": 16 + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "invocationStack": [], + "resultStack": [ + { + "type": "Integer", + "value": 0 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/MODPOW.json b/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/MODPOW.json new file mode 100644 index 0000000000..68efa97efa --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/MODPOW.json @@ -0,0 +1,145 @@ +{ + "category": "Numeric", + "name": "MODPOW", + "tests": [ + { + "name": "Exception - Without items", + "script": [ + "MODPOW" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "MODPOW", + "evaluationStack": [] + } + ] + } + } + ] + }, + { + "name": "Real test (19 ModInverse 141 = 52)", + "script": [ + "PUSHINT8", + "0x13", + "PUSHM1", + "PUSHINT16", + "0x8d00", + "MODPOW" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "MODPOW", + "evaluationStack": [ + { + "type": "Integer", + "value": 141 + }, + { + "type": "Integer", + "value": -1 + }, + { + "type": "Integer", + "value": 19 + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "invocationStack": [], + "resultStack": [ + { + "type": "Integer", + "value": 52 + } + ] + } + } + ] + }, + { + "name": "Real test (ModPow 19, 2, 141 = 79)", + "script": [ + "PUSHINT8", + "0x13", + "PUSH2", + "PUSHINT16", + "0x8d00", + "MODPOW" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "MODPOW", + "evaluationStack": [ + { + "type": "Integer", + "value": 141 + }, + { + "type": "Integer", + "value": 2 + }, + { + "type": "Integer", + "value": 19 + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "invocationStack": [], + "resultStack": [ + { + "type": "Integer", + "value": 79 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/NOT.json b/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/NOT.json new file mode 100644 index 0000000000..72d36c6fc7 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/NOT.json @@ -0,0 +1,537 @@ +{ + "category": "Numeric", + "name": "NOT", + "tests": [ + { + "name": "Without push", + "script": [ + "NOT" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "With bool", + "script": [ + "PUSH1", + "NOT", + "NOT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "NOT", + "evaluationStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "With integer 0x03", + "script": [ + "PUSH3", + "NOT" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "NOT", + "evaluationStack": [ + { + "type": "integer", + "value": 3 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "With map", + "script": [ + "NEWMAP", + "NOT" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "NOT", + "evaluationStack": [ + { + "type": "map", + "value": {} + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "With array", + "script": [ + "PUSH0", + "NEWARRAY", + "NOT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "NOT", + "evaluationStack": [ + { + "type": "array", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "With struct", + "script": [ + "PUSH0", + "NEWSTRUCT", + "NOT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "NOT", + "evaluationStack": [ + { + "type": "struct", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "With byte array 0x0000", + "script": [ + "PUSHDATA1", + "0x02", + "0x0000", + "NOT" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "NOT", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x0000" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "With byte array 0x0001", + "script": [ + "PUSHDATA1", + "0x02", + "0x0001", + "NOT" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "NOT", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x0001" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "With interop", + "script": [ + "SYSCALL", + "0x77777777", + "NOT" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "NOT", + "evaluationStack": [ + { + "type": "interop", + "value": "Object" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/NUMEQUAL.json b/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/NUMEQUAL.json new file mode 100644 index 0000000000..613a2bd31d --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/NUMEQUAL.json @@ -0,0 +1,1058 @@ +{ + "category": "Numeric", + "name": "NUMEQUAL same types", + "tests": [ + { + "name": "Without two pushes", + "script": [ + "NUMEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without one push", + "script": [ + "PUSH0", + "NUMEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "NUMEQUAL", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + } + ] + }, + { + "name": "Real test [Bool,Bool]=true", + "script": [ + "PUSH0", + "NOT", + "PUSH0", + "NOT", + "NUMEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "NUMEQUAL", + "evaluationStack": [ + { + "type": "boolean", + "value": true + }, + { + "type": "boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Real test [Bool,Bool]=false", + "script": [ + "PUSH0", + "NOT", + "PUSH0", + "NOT", + "NOT", + "NUMEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "NUMEQUAL", + "evaluationStack": [ + { + "type": "boolean", + "value": false + }, + { + "type": "boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test [Integer,Integer]=true", + "script": [ + "PUSH1", + "PUSH1", + "NUMEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "NUMEQUAL", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Real test [Integer,Integer]=false", + "script": [ + "PUSH2", + "PUSH1", + "NUMEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "NUMEQUAL", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 2 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test [Array,Array]=Fault", + "script": [ + "PUSH0", + "NEWARRAY", + "DUP", + "NUMEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "NUMEQUAL", + "evaluationStack": [ + { + "type": "array", + "value": [] + }, + { + "type": "array", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [Array,Array]=fault", + "script": [ + "PUSH0", + "NEWARRAY", + "PUSH0", + "NEWARRAY", + "NUMEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "NUMEQUAL", + "evaluationStack": [ + { + "type": "array", + "value": [] + }, + { + "type": "array", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [Struct,Struct]=fault with clone", + "script": [ + "PUSH0", + "NEWSTRUCT", + "DUP", + "NUMEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "NUMEQUAL", + "evaluationStack": [ + { + "type": "struct", + "value": [] + }, + { + "type": "struct", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [Struct,Struct]=fault without clone", + "script": [ + "PUSH0", + "NEWSTRUCT", + "PUSH0", + "NEWSTRUCT", + "NUMEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "NUMEQUAL", + "evaluationStack": [ + { + "type": "struct", + "value": [] + }, + { + "type": "struct", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [Struct,Struct]=fault", + "script": [ + "PUSH0", + "NEWSTRUCT", + "PUSH1", + "NEWSTRUCT", + "NUMEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "NUMEQUAL", + "evaluationStack": [ + { + "type": "struct", + "value": [ + { + "type": "Null" + } + ] + }, + { + "type": "struct", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [Map,Map]=Fault", + "script": [ + "NEWMAP", + "DUP", + "NUMEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "NUMEQUAL", + "evaluationStack": [ + { + "type": "map", + "value": {} + }, + { + "type": "map", + "value": {} + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [Map,Map]=Fault", + "script": [ + "NEWMAP", + "NEWMAP", + "NUMEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "NUMEQUAL", + "evaluationStack": [ + { + "type": "map", + "value": {} + }, + { + "type": "map", + "value": {} + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [ByteString,ByteString]=true", + "script": [ + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000123", + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000123", + "NUMEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 38, + "nextInstruction": "NUMEQUAL", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000123" + }, + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000123" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 39, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Real test [ByteString,ByteString]=false same length", + "script": [ + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000123", + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000124", + "NUMEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 38, + "nextInstruction": "NUMEQUAL", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000124" + }, + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000123" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 39, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test [ByteString,ByteString]=false different length", + "script": [ + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000123", + "PUSHDATA1", + "0x10", + "0x00000000000000000000000000000124", + "NUMEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 37, + "nextInstruction": "NUMEQUAL", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x00000000000000000000000000000124" + }, + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000123" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 38, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test [ByteString,ByteString]=false different length", + "script": [ + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000123", + "PUSHDATA1", + "0x10", + "0x00000000000000000000000000000124", + "NUMEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 37, + "nextInstruction": "NUMEQUAL", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x00000000000000000000000000000124" + }, + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000123" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 38, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test with clone [Interop,Interop]=fault", + "script": [ + "SYSCALL", + "0x77777777", + "DUP", + "NUMEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "DUP", + "evaluationStack": [ + { + "type": "interop", + "value": "Object" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "NUMEQUAL", + "evaluationStack": [ + { + "type": "interop", + "value": "Object" + }, + { + "type": "interop", + "value": "Object" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [Interop,Interop]=fault", + "script": [ + "SYSCALL", + "0x77777777", + "SYSCALL", + "0x77777777", + "NUMEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 10, + "nextInstruction": "NUMEQUAL", + "evaluationStack": [ + { + "type": "interop", + "value": "Object" + }, + { + "type": "interop", + "value": "Object" + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/NUMNOTEQUAL.json b/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/NUMNOTEQUAL.json new file mode 100644 index 0000000000..386212cfed --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/NUMNOTEQUAL.json @@ -0,0 +1,1058 @@ +{ + "category": "Numeric", + "name": "NUMNOTEQUAL same types", + "tests": [ + { + "name": "Without two pushes", + "script": [ + "NUMNOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without one push", + "script": [ + "PUSH0", + "NUMNOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "NUMNOTEQUAL", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + } + ] + }, + { + "name": "Real test [Bool,Bool]=false", + "script": [ + "PUSH0", + "NOT", + "PUSH0", + "NOT", + "NUMNOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "NUMNOTEQUAL", + "evaluationStack": [ + { + "type": "boolean", + "value": true + }, + { + "type": "boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test [Bool,Bool]=true", + "script": [ + "PUSH0", + "NOT", + "PUSH0", + "NOT", + "NOT", + "NUMNOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "NUMNOTEQUAL", + "evaluationStack": [ + { + "type": "boolean", + "value": false + }, + { + "type": "boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Real test [Integer,Integer]=false", + "script": [ + "PUSH1", + "PUSH1", + "NUMNOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "NUMNOTEQUAL", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test [Integer,Integer]=true", + "script": [ + "PUSH2", + "PUSH1", + "NUMNOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "NUMNOTEQUAL", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 2 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Real test [Array,Array]=Fault", + "script": [ + "PUSH0", + "NEWARRAY", + "DUP", + "NUMNOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "NUMNOTEQUAL", + "evaluationStack": [ + { + "type": "array", + "value": [] + }, + { + "type": "array", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [Array,Array]=fault", + "script": [ + "PUSH0", + "NEWARRAY", + "PUSH0", + "NEWARRAY", + "NUMNOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "NUMNOTEQUAL", + "evaluationStack": [ + { + "type": "array", + "value": [] + }, + { + "type": "array", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [Struct,Struct]=fault with clone", + "script": [ + "PUSH0", + "NEWSTRUCT", + "DUP", + "NUMNOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "NUMNOTEQUAL", + "evaluationStack": [ + { + "type": "struct", + "value": [] + }, + { + "type": "struct", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [Struct,Struct]=fault without clone", + "script": [ + "PUSH0", + "NEWSTRUCT", + "PUSH0", + "NEWSTRUCT", + "NUMNOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "NUMNOTEQUAL", + "evaluationStack": [ + { + "type": "struct", + "value": [] + }, + { + "type": "struct", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [Struct,Struct]=fault", + "script": [ + "PUSH0", + "NEWSTRUCT", + "PUSH1", + "NEWSTRUCT", + "NUMNOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "NUMNOTEQUAL", + "evaluationStack": [ + { + "type": "struct", + "value": [ + { + "type": "Null" + } + ] + }, + { + "type": "struct", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [Map,Map]=Fault", + "script": [ + "NEWMAP", + "DUP", + "NUMNOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "NUMNOTEQUAL", + "evaluationStack": [ + { + "type": "map", + "value": {} + }, + { + "type": "map", + "value": {} + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [Map,Map]=Fault", + "script": [ + "NEWMAP", + "NEWMAP", + "NUMNOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "NUMNOTEQUAL", + "evaluationStack": [ + { + "type": "map", + "value": {} + }, + { + "type": "map", + "value": {} + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [ByteString,ByteString]=false", + "script": [ + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000123", + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000123", + "NUMNOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 38, + "nextInstruction": "NUMNOTEQUAL", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000123" + }, + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000123" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 39, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test [ByteString,ByteString]=true same length", + "script": [ + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000123", + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000124", + "NUMNOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 38, + "nextInstruction": "NUMNOTEQUAL", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000124" + }, + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000123" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 39, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Real test [ByteString,ByteString]=true different length", + "script": [ + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000123", + "PUSHDATA1", + "0x10", + "0x00000000000000000000000000000124", + "NUMNOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 37, + "nextInstruction": "NUMNOTEQUAL", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x00000000000000000000000000000124" + }, + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000123" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 38, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Real test [ByteString,ByteString]=true different length", + "script": [ + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000123", + "PUSHDATA1", + "0x10", + "0x00000000000000000000000000000124", + "NUMNOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 37, + "nextInstruction": "NUMNOTEQUAL", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x00000000000000000000000000000124" + }, + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000123" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 38, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Real test with clone [Interop,Interop]=fault", + "script": [ + "SYSCALL", + "0x77777777", + "DUP", + "NUMNOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "DUP", + "evaluationStack": [ + { + "type": "interop", + "value": "Object" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "NUMNOTEQUAL", + "evaluationStack": [ + { + "type": "interop", + "value": "Object" + }, + { + "type": "interop", + "value": "Object" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [Interop,Interop]=fault", + "script": [ + "SYSCALL", + "0x77777777", + "SYSCALL", + "0x77777777", + "NUMNOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 10, + "nextInstruction": "NUMNOTEQUAL", + "evaluationStack": [ + { + "type": "interop", + "value": "Object" + }, + { + "type": "interop", + "value": "Object" + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/POW.json b/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/POW.json new file mode 100644 index 0000000000..c9a100e2e4 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/POW.json @@ -0,0 +1,195 @@ +{ + "category": "Numeric", + "name": "POW", + "tests": [ + { + "name": "Exception - Without items", + "script": [ + "POW" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "POW", + "evaluationStack": [] + } + ] + } + } + ] + }, + { + "name": "Exception - With only one item", + "script": [ + "PUSH1", + "POW" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "FAULT", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "POW", + "evaluationStack": [] + } + ] + } + } + ] + }, + { + "name": "Real test 1", + "script": [ + "PUSH1", + "PUSH1", + "POW" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "invocationStack": [], + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + }, + { + "name": "Real test 1", + "script": [ + "PUSH9", + "PUSH2", + "POW" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Integer", + "value": 81 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "invocationStack": [], + "resultStack": [ + { + "type": "Integer", + "value": 81 + } + ] + } + } + ] + }, + { + "name": "Real test 1", + "script": [ + "PUSH2", + "PUSH9", + "POW" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Integer", + "value": 512 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "invocationStack": [], + "resultStack": [ + { + "type": "Integer", + "value": 512 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/SHL.json b/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/SHL.json new file mode 100644 index 0000000000..7e660f6c92 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/SHL.json @@ -0,0 +1,245 @@ +{ + "category": "Numeric", + "name": "SHL", + "tests": [ + { + "name": "Exception - Above the limit 0 << 257", + "script": [ + "PUSH0", + "PUSHDATA1", + "0x02", + "0x0101", + "SHL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "SHL", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x0101" + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Exception - Below the limit 0 << -257", + "script": [ + "PUSH0", + "PUSHDATA1", + "0x02", + "0xfffe", + "SHL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "SHL", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0xFFFE" + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test 0 << 256", + "script": [ + "PUSH0", + "PUSHDATA1", + "0x02", + "0x0001", + "SHL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "SHL", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x0001" + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + } + ] + }, + { + "name": "Real test 16 << 4", + "script": [ + "PUSH16", + "PUSH4", + "SHL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "SHL", + "evaluationStack": [ + { + "type": "integer", + "value": 4 + }, + { + "type": "integer", + "value": 16 + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 256 + } + ] + } + } + ] + }, + { + "name": "Real test 16 << 0", + "script": [ + "PUSH16", + "PUSH0", + "SHL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "SHL", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + }, + { + "type": "integer", + "value": 16 + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 16 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/SHR.json b/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/SHR.json new file mode 100644 index 0000000000..818364e92a --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/SHR.json @@ -0,0 +1,247 @@ +{ + "category": "Numeric", + "name": "SHR", + "tests": [ + { + "name": "Exception - Above the limit 0 >> 257", + "script": [ + "PUSH0", + "PUSHDATA1", + "0x02", + "0x0101", + "SHR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "SHR", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x0101" + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Exception - Below the limit 0 >> -257", + "script": [ + "PUSH0", + "PUSHDATA1", + "0x02", + "0xfffe", + "SHR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "SHR", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0xFFFE" + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test 0 >> 256", + "script": [ + "PUSH0", + "PUSHDATA1", + "0x02", + "0x0001", + "SHR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "SHR", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x0001" + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + } + ] + }, + { + "name": "Real test 256 >> 0", + "script": [ + "PUSHDATA1", + "0x02", + "0x0001", + "PUSH0", + "SHR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "SHR", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + }, + { + "type": "ByteString", + "value": "0x0001" + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "ByteString", + "value": "0x0001" + } + ] + } + } + ] + }, + { + "name": "Real test 4 >> 16", + "script": [ + "PUSH4", + "PUSH16", + "SHR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "SHR", + "evaluationStack": [ + { + "type": "integer", + "value": 16 + }, + { + "type": "integer", + "value": 4 + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/SIGN.json b/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/SIGN.json new file mode 100644 index 0000000000..24111873f9 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/SIGN.json @@ -0,0 +1,496 @@ +{ + "category": "Numeric", + "name": "SIGN", + "tests": [ + { + "name": "Without push", + "script": [ + "SIGN" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "With bool", + "script": [ + "PUSH1", + "NOT", + "SIGN" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "SIGN", + "evaluationStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + } + ] + }, + { + "name": "With integer 0x03", + "script": [ + "PUSH3", + "SIGN" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "SIGN", + "evaluationStack": [ + { + "type": "integer", + "value": 3 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + } + ] + }, + { + "name": "With integer -1", + "script": [ + "PUSHM1", + "SIGN" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "SIGN", + "evaluationStack": [ + { + "type": "integer", + "value": -1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": -1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": -1 + } + ] + } + } + ] + }, + { + "name": "With map", + "script": [ + "NEWMAP", + "SIGN" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "SIGN", + "evaluationStack": [ + { + "type": "map", + "value": {} + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "With array", + "script": [ + "PUSH0", + "NEWARRAY", + "SIGN" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "SIGN", + "evaluationStack": [ + { + "type": "array", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "With struct", + "script": [ + "PUSH0", + "NEWSTRUCT", + "SIGN" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "SIGN", + "evaluationStack": [ + { + "type": "struct", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "With byte array 0x0000", + "script": [ + "PUSHDATA1", + "0x02", + "0x0000", + "SIGN" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "SIGN", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x0000" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + } + ] + }, + { + "name": "With byte array 0x0001", + "script": [ + "PUSHDATA1", + "0x02", + "0x0001", + "SIGN" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "SIGN", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x0001" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + } + ] + }, + { + "name": "With interop", + "script": [ + "SYSCALL", + "0x77777777", + "SIGN" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "SIGN", + "evaluationStack": [ + { + "type": "interop", + "value": "Object" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/SQRT.json b/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/SQRT.json new file mode 100644 index 0000000000..8b63674edd --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Arithmetic/SQRT.json @@ -0,0 +1,216 @@ +{ + "category": "Numeric", + "name": "SQRT", + "tests": [ + { + "name": "Exception - Without items", + "script": [ + "SQRT" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "SQRT", + "evaluationStack": [] + } + ] + } + } + ] + }, + { + "name": "Real test 1", + "script": [ + "PUSH1", + "SQRT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "invocationStack": [], + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + }, + { + "name": "Real test with 81", + "script": [ + "PUSHINT8", + "0x51", + "SQRT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Integer", + "value": 9 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "invocationStack": [], + "resultStack": [ + { + "type": "Integer", + "value": 9 + } + ] + } + } + ] + }, + { + "name": "Real test with 15625", + "script": [ + "PUSHINT16", + "0x093d", + "SQRT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Integer", + "value": 125 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "invocationStack": [], + "resultStack": [ + { + "type": "Integer", + "value": 125 + } + ] + } + } + ] + }, + { + "name": "Real test with 4", + "script": [ + "PUSHINT8", + "0x04", + "SQRT" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "invocationStack": [], + "resultStack": [ + { + "type": "Integer", + "value": 2 + } + ] + } + } + ] + }, + { + "name": "Real test with 2", + "script": [ + "PUSHINT8", + "0x02", + "SQRT" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "invocationStack": [], + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/APPEND.json b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/APPEND.json new file mode 100644 index 0000000000..61593452e7 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/APPEND.json @@ -0,0 +1,679 @@ +{ + "category": "Arrays", + "name": "APPEND", + "tests": [ + { + "name": "Without push", + "script": [ + "PUSH1", + "APPEND" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without array", + "script": [ + "PUSH1", + "PUSH2", + "APPEND" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Clone test [Array]", + "script": [ + "INITSSLOT", + "0x01", + "PUSH0", + "NEWARRAY", + "DUP", + "PUSH5", + "APPEND", + "STSFLD0", + "PUSH0", + "NEWARRAY", + "DUP", + "LDSFLD0", + "APPEND", + "LDSFLD0", + "PUSH6", + "APPEND", + "LDSFLD0" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 8, + "nextInstruction": "PUSH0", + "staticFields": [ + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": 5 + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 10, + "nextInstruction": "DUP", + "evaluationStack": [ + { + "type": "array", + "value": [] + } + ], + "staticFields": [ + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": 5 + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 13, + "nextInstruction": "LDSFLD0", + "evaluationStack": [ + { + "type": "array", + "value": [ + { + "type": "Array", + "value": [ + { + "type": "Integer", + "value": "5" + } + ] + } + ] + } + ], + "staticFields": [ + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": "5" + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 17, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": "5" + }, + { + "type": "Integer", + "value": "6" + } + ] + }, + { + "type": "array", + "value": [ + { + "type": "Array", + "value": [ + { + "type": "Integer", + "value": "5" + }, + { + "type": "Integer", + "value": "6" + } + ] + } + ] + } + ], + "staticFields": [ + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": "5" + }, + { + "type": "Integer", + "value": "6" + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": "5" + }, + { + "type": "Integer", + "value": "6" + } + ] + }, + { + "type": "array", + "value": [ + { + "type": "Array", + "value": [ + { + "type": "Integer", + "value": "5" + }, + { + "type": "Integer", + "value": "6" + } + ] + } + ] + } + ] + } + } + ] + }, + { + "name": "Clone test [Struct]", + "script": [ + "INITSSLOT", + "0x01", + "PUSH0", + "NEWSTRUCT", + "DUP", + "PUSH5", + "APPEND", + "STSFLD0", + "PUSH0", + "NEWSTRUCT", + "DUP", + "LDSFLD0", + "APPEND", + "LDSFLD0", + "PUSH6", + "APPEND", + "LDSFLD0" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 8, + "nextInstruction": "PUSH0", + "staticFields": [ + { + "type": "struct", + "value": [ + { + "type": "Integer", + "value": 5 + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 10, + "nextInstruction": "DUP", + "evaluationStack": [ + { + "type": "struct", + "value": [] + } + ], + "staticFields": [ + { + "type": "struct", + "value": [ + { + "type": "Integer", + "value": 5 + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 13, + "nextInstruction": "LDSFLD0", + "evaluationStack": [ + { + "type": "struct", + "value": [ + { + "type": "Struct", + "value": [ + { + "type": "Integer", + "value": 5 + } + ] + } + ] + } + ], + "staticFields": [ + { + "type": "struct", + "value": [ + { + "type": "Integer", + "value": 5 + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 17, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "struct", + "value": [ + { + "type": "Integer", + "value": 5 + }, + { + "type": "Integer", + "value": 6 + } + ] + }, + { + "type": "struct", + "value": [ + { + "type": "Struct", + "value": [ + { + "type": "Integer", + "value": 5 + } + ] + } + ] + } + ], + "staticFields": [ + { + "type": "struct", + "value": [ + { + "type": "Integer", + "value": 5 + }, + { + "type": "Integer", + "value": 6 + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "struct", + "value": [ + { + "type": "Integer", + "value": 5 + }, + { + "type": "Integer", + "value": 6 + } + ] + }, + { + "type": "struct", + "value": [ + { + "type": "Struct", + "value": [ + { + "type": "Integer", + "value": 5 + } + ] + } + ] + } + ] + } + } + ] + }, + { + "name": "Real test [Array]", + "script": [ + "PUSH0", + "NEWARRAY", + "DUP", + "PUSH5", + "APPEND" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "APPEND", + "evaluationStack": [ + { + "type": "integer", + "value": 5 + }, + { + "type": "array", + "value": [] + }, + { + "type": "array", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": "5" + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": "5" + } + ] + } + ] + } + } + ] + }, + { + "name": "Real test [Struct]", + "script": [ + "PUSH0", + "NEWSTRUCT", + "DUP", + "PUSH5", + "APPEND" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "APPEND", + "evaluationStack": [ + { + "type": "integer", + "value": 5 + }, + { + "type": "struct", + "value": [] + }, + { + "type": "struct", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "struct", + "value": [ + { + "type": "Integer", + "value": "5" + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "struct", + "value": [ + { + "type": "Integer", + "value": "5" + } + ] + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/CLEARITEMS.json b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/CLEARITEMS.json new file mode 100644 index 0000000000..20f82d0a34 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/CLEARITEMS.json @@ -0,0 +1,126 @@ +{ + "category": "Arrays", + "name": "CLEARITEMS", + "tests": [ + { + "name": "Without push", + "script": [ + "CLEARITEMS" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Wrong type", + "script": [ + "PUSH2", + "CLEARITEMS" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [Array]", + "script": [ + "PUSH0", + "PUSH1", + "PUSH2", + "PACK", + "DUP", + "CLEARITEMS" + ], + "steps": [ + { + "actions": [ + "StepInto", + "StepInto", + "StepInto", + "StepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "DUP", + "evaluationStack": [ + { + "type": "Array", + "value": [ + { + "type": "Integer", + "value": 1 + }, + { + "type": "Integer", + "value": 0 + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Array", + "value": [] + } + ] + } + } + ] + }, + { + "name": "Real test [Map]", + "script": [ + "NEWMAP", + "DUP", + "PUSH0", + "PUSH0", + "SETITEM", + "DUP", + "CLEARITEMS" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Map", + "value": {} + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/HASKEY.json b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/HASKEY.json new file mode 100644 index 0000000000..213087bd29 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/HASKEY.json @@ -0,0 +1,276 @@ +{ + "category": "Arrays", + "name": "HASKEY", + "tests": [ + { + "name": "Without push", + "script": [ + "HASKEY" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Wrong key type", + "script": [ + "PUSH1", + "NEWARRAY", + "NEWMAP", + "HASKEY" + ], + "steps": [ + { + "actions": [ + "StepInto", + "StepInto", + "StepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "HASKEY", + "evaluationStack": [ + { + "type": "Map", + "value": {} + }, + { + "type": "Array", + "value": [ + { + "type": "Null" + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [Buffer]", + "script": [ + "PUSH2", + "NEWBUFFER", + "PUSH0", + "HASKEY" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Real test [Map]", + "script": [ + "INITSSLOT", + "0x01", + "NEWMAP", + "DUP", + "STSFLD0", + "PUSH1", + "PUSH2", + "SETITEM", + "LDSFLD0", + "PUSH3", + "HASKEY", + "DROP", + "LDSFLD0", + "PUSH1", + "HASKEY" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 10, + "nextInstruction": "HASKEY", + "evaluationStack": [ + { + "type": "Integer", + "value": 3 + }, + { + "type": "map", + "value": { + "0x01": { + "type": "Integer", + "value": 2 + } + } + } + ], + "staticFields": [ + { + "type": "map", + "value": { + "0x01": { + "type": "Integer", + "value": 2 + } + } + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 11, + "nextInstruction": "DROP", + "evaluationStack": [ + { + "type": "Boolean", + "value": false + } + ], + "staticFields": [ + { + "type": "map", + "value": { + "0x01": { + "type": "Integer", + "value": 2 + } + } + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Check key size [Map]", + "script": [ + "NEWMAP", + "PUSHINT8", + "0x41", + "NEWBUFFER", + "CONVERT", + "0x28", + "HASKEY" + ], + "steps": [ + { + "actions": [ + "stepinto", + "stepinto", + "stepinto", + "stepinto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "HASKEY", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + }, + { + "type": "map", + "value": {} + } + ] + } + ] + } + }, + { + "actions": [ + "stepinto" + ], + "result": { + "state": "FAULT", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "HASKEY", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" + }, + { + "type": "map", + "value": {} + } + ] + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/KEYS.json b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/KEYS.json new file mode 100644 index 0000000000..fb6a9d985c --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/KEYS.json @@ -0,0 +1,63 @@ +{ + "category": "Arrays", + "name": "KEYS", + "tests": [ + { + "name": "Keys in map", + "script": [ + "NEWMAP", + "DUP", + "DUP", + "PUSH0", + "PUSH0", + "SETITEM", + "PUSH1", + "PUSH1", + "SETITEM", + "KEYS" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": 0 + }, + { + "type": "Integer", + "value": 1 + } + ] + } + ] + } + } + ] + }, + { + "name": "Invalid StackItem [Integer!=Map]", + "script": [ + "PUSH0", + "KEYS" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + } + ] +} \ No newline at end of file diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/NEWARRAY.json b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/NEWARRAY.json new file mode 100644 index 0000000000..5244c72f4e --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/NEWARRAY.json @@ -0,0 +1,168 @@ +{ + "category": "Arrays", + "name": "NEWARRAY", + "tests": [ + { + "name": "Without push", + "script": [ + "NEWARRAY" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "With wrong type", + "script": [ + "NEWMAP", + "NEWARRAY" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "With negative push", + "script": [ + "PUSHM1", + "NEWARRAY" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "PUSH2", + "NEWARRAY" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "array", + "value": [ + { + "type": "Null" + }, + { + "type": "Null" + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "array", + "value": [ + { + "type": "Null" + }, + { + "type": "Null" + } + ] + } + ] + } + } + ] + }, + { + "name": "Clone Struct to Array", + "script": [ + "PUSH1", + "NEWSTRUCT", + "DUP", + "PUSH0", + "PUSH5", + "SETITEM", + "NEWARRAY" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "NEWARRAY", + "evaluationStack": [ + { + "type": "struct", + "value": [ + { + "type": "Integer", + "value": 5 + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/NEWARRAY0.json b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/NEWARRAY0.json new file mode 100644 index 0000000000..21cd6436e2 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/NEWARRAY0.json @@ -0,0 +1,28 @@ +{ + "category": "Arrays", + "name": "NEWARRAY0", + "tests": [ + { + "name": "Real test", + "script": [ + "NEWARRAY0" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Array", + "value": [] + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/NEWARRAY_T.json b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/NEWARRAY_T.json new file mode 100644 index 0000000000..d1cea504ad --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/NEWARRAY_T.json @@ -0,0 +1,289 @@ +{ + "category": "Arrays", + "name": "NEWARRAY_T", + "tests": [ + { + "name": "Real test [Any]", + "script": [ + "PUSH2", + "NEWARRAY_T", + "0x00" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Array", + "value": [ + { + "type": "Null" + }, + { + "type": "Null" + } + ] + } + ] + } + } + ] + }, + { + "name": "Real test [Pointer]", + "script": [ + "PUSH2", + "NEWARRAY_T", + "0x10" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Array", + "value": [ + { + "type": "Null" + }, + { + "type": "Null" + } + ] + } + ] + } + } + ] + }, + { + "name": "Real test [Integer]", + "script": [ + "PUSH2", + "NEWARRAY_T", + "0x21" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Array", + "value": [ + { + "type": "Integer", + "value": 0 + }, + { + "type": "Integer", + "value": 0 + } + ] + } + ] + } + } + ] + }, + { + "name": "Real test [ByteString]", + "script": [ + "PUSH2", + "NEWARRAY_T", + "0x28" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Array", + "value": [ + { + "type": "ByteString", + "value": "0x" + }, + { + "type": "ByteString", + "value": "0x" + } + ] + } + ] + } + } + ] + }, + { + "name": "Real test [Buffer]", + "script": [ + "PUSH2", + "NEWARRAY_T", + "0x30" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Array", + "value": [ + { + "type": "Null" + }, + { + "type": "Null" + } + ] + } + ] + } + } + ] + }, + { + "name": "Real test [Array]", + "script": [ + "PUSH2", + "NEWARRAY_T", + "0x40" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Array", + "value": [ + { + "type": "Null" + }, + { + "type": "Null" + } + ] + } + ] + } + } + ] + }, + { + "name": "Real test [Struct]", + "script": [ + "PUSH2", + "NEWARRAY_T", + "0x41" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Array", + "value": [ + { + "type": "Null" + }, + { + "type": "Null" + } + ] + } + ] + } + } + ] + }, + { + "name": "Real test [Map]", + "script": [ + "PUSH2", + "NEWARRAY_T", + "0x48" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Array", + "value": [ + { + "type": "Null" + }, + { + "type": "Null" + } + ] + } + ] + } + } + ] + }, + { + "name": "Real test [InteropInterface]", + "script": [ + "PUSH2", + "NEWARRAY_T", + "0x60" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Array", + "value": [ + { + "type": "Null" + }, + { + "type": "Null" + } + ] + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/NEWMAP.json b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/NEWMAP.json new file mode 100644 index 0000000000..a7000735d5 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/NEWMAP.json @@ -0,0 +1,48 @@ +{ + "category": "Arrays", + "name": "NEWMAP", + "tests": [ + { + "name": "Real test", + "script": [ + "NEWMAP" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "map", + "value": {} + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "map", + "value": {} + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/NEWSTRUCT.json b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/NEWSTRUCT.json new file mode 100644 index 0000000000..dbe9547dde --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/NEWSTRUCT.json @@ -0,0 +1,168 @@ +{ + "category": "Arrays", + "name": "NEWSTRUCT", + "tests": [ + { + "name": "Without push", + "script": [ + "NEWSTRUCT" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "With wrong type", + "script": [ + "NEWMAP", + "NEWSTRUCT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "With negative push", + "script": [ + "PUSHM1", + "NEWSTRUCT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "PUSH2", + "NEWSTRUCT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "struct", + "value": [ + { + "type": "Null" + }, + { + "type": "Null" + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "struct", + "value": [ + { + "type": "Null" + }, + { + "type": "Null" + } + ] + } + ] + } + } + ] + }, + { + "name": "Clone Array to Struct", + "script": [ + "PUSH1", + "NEWARRAY", + "DUP", + "PUSH0", + "PUSH5", + "SETITEM", + "NEWSTRUCT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "NEWSTRUCT", + "evaluationStack": [ + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": 5 + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/NEWSTRUCT0.json b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/NEWSTRUCT0.json new file mode 100644 index 0000000000..62d5a595d3 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/NEWSTRUCT0.json @@ -0,0 +1,28 @@ +{ + "category": "Arrays", + "name": "NEWSTRUCT0", + "tests": [ + { + "name": "Real test", + "script": [ + "NEWSTRUCT0" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Struct", + "value": [] + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/PACK.json b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/PACK.json new file mode 100644 index 0000000000..e4cc0f40ee --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/PACK.json @@ -0,0 +1,127 @@ +{ + "category": "Arrays", + "name": "PACK", + "tests": [ + { + "name": "Real test", + "script": [ + "PUSH5", + "PUSH6", + "PUSH2", + "PACK" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": 6 + }, + { + "type": "Integer", + "value": 5 + } + ] + } + ] + } + } + ] + }, + { + "name": "Not enough size", + "script": [ + "PUSH5", + "PUSH2", + "PACK" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Wrong type [Map]", + "script": [ + "NEWMAP", + "PACK" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Wrong type [Array]", + "script": [ + "PUSH1", + "NEWARRAY", + "PACK" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Wrong type [Struct]", + "script": [ + "PUSH1", + "NEWSTRUCT", + "PACK" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without items", + "script": [ + "PACK" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/PACKMAP.json b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/PACKMAP.json new file mode 100644 index 0000000000..dd68bd19c1 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/PACKMAP.json @@ -0,0 +1,127 @@ +{ + "category": "Arrays", + "name": "PACKMAP", + "tests": [ + { + "name": "Real test", + "script": [ + "PUSH5", + "PUSH6", + "PUSH1", + "PACKMAP" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Map", + "value": { + "0x06": { + "type": "Integer", + "value": "5" + } + } + } + ] + } + } + ] + }, + { + "name": "Not enough size", + "script": [ + "PUSH5", + "PUSH1", + "PACKMAP" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Wrong type [Map]", + "script": [ + "PUSH1", + "PUSH1", + "NEWMAP", + "PACKMAP" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Wrong type [Array]", + "script": [ + "PUSH1", + "PUSH1", + "NEWARRAY", + "PACKMAP" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Wrong type [Struct]", + "script": [ + "PUSH1", + "PUSH1", + "NEWSTRUCT", + "PACKMAP" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without items", + "script": [ + "PACKMAP" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/PACKSTRUCT.json b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/PACKSTRUCT.json new file mode 100644 index 0000000000..e0517d27b9 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/PACKSTRUCT.json @@ -0,0 +1,127 @@ +{ + "category": "Arrays", + "name": "PACK", + "tests": [ + { + "name": "Real test", + "script": [ + "PUSH5", + "PUSH6", + "PUSH2", + "PACKSTRUCT" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "struct", + "value": [ + { + "type": "Integer", + "value": 6 + }, + { + "type": "Integer", + "value": 5 + } + ] + } + ] + } + } + ] + }, + { + "name": "Not enough size", + "script": [ + "PUSH5", + "PUSH2", + "PACKSTRUCT" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Wrong type [Map]", + "script": [ + "NEWMAP", + "PACKSTRUCT" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Wrong type [Array]", + "script": [ + "PUSH1", + "NEWARRAY", + "PACKSTRUCT" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Wrong type [Struct]", + "script": [ + "PUSH1", + "NEWSTRUCT", + "PACKSTRUCT" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without items", + "script": [ + "PACKSTRUCT" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/PICKITEM.json b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/PICKITEM.json new file mode 100644 index 0000000000..19a6f54a8c --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/PICKITEM.json @@ -0,0 +1,714 @@ +{ + "category": "Arrays", + "name": "PICKITEM", + "tests": [ + { + "name": "Wrong array", + "script": [ + "PUSH0", + "PUSH0", + "PICKITEM" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without push", + "script": [ + "PICKITEM" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Wrong key type", + "script": [ + "PUSH1", + "NEWARRAY", + "NEWMAP", + "PICKITEM" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "PICKITEM", + "evaluationStack": [ + { + "type": "map", + "value": {} + }, + { + "type": "array", + "value": [ + { + "type": "Null" + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Out of bounds [Array]", + "script": [ + "PUSH2", + "NEWARRAY", + "PUSH3", + "PICKITEM" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "PICKITEM", + "evaluationStack": [ + { + "type": "integer", + "value": 3 + }, + { + "type": "array", + "value": [ + { + "type": "Null" + }, + { + "type": "Null" + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Out of bounds [Struct]", + "script": [ + "PUSH2", + "NEWSTRUCT", + "PUSH3", + "PICKITEM" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "PICKITEM", + "evaluationStack": [ + { + "type": "integer", + "value": 3 + }, + { + "type": "struct", + "value": [ + { + "type": "Null" + }, + { + "type": "Null" + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [Array]", + "script": [ + "INITSSLOT", + "0x01", + "PUSH3", + "NEWARRAY", + "STSFLD0", + "LDSFLD0", + "PUSH0", + "PUSH1", + "SETITEM", + "LDSFLD0", + "PUSH1", + "PUSH2", + "SETITEM", + "LDSFLD0", + "PUSH2", + "PUSH3", + "SETITEM", + "LDSFLD0", + "PUSH2", + "PICKITEM" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 19, + "nextInstruction": "PICKITEM", + "evaluationStack": [ + { + "type": "integer", + "value": 2 + }, + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": 1 + }, + { + "type": "Integer", + "value": 2 + }, + { + "type": "Integer", + "value": 3 + } + ] + } + ], + "staticFields": [ + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": 1 + }, + { + "type": "Integer", + "value": 2 + }, + { + "type": "Integer", + "value": 3 + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 20, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 3 + } + ], + "staticFields": [ + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": 1 + }, + { + "type": "Integer", + "value": 2 + }, + { + "type": "Integer", + "value": 3 + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 3 + } + ] + } + } + ] + }, + { + "name": "Real test [Struct]", + "script": [ + "INITSSLOT", + "0x01", + "PUSH3", + "NEWSTRUCT", + "STSFLD0", + "LDSFLD0", + "PUSH0", + "PUSH1", + "SETITEM", + "LDSFLD0", + "PUSH1", + "PUSH2", + "SETITEM", + "LDSFLD0", + "PUSH2", + "PUSH3", + "SETITEM", + "LDSFLD0", + "PUSH2", + "PICKITEM" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 19, + "nextInstruction": "PICKITEM", + "evaluationStack": [ + { + "type": "integer", + "value": 2 + }, + { + "type": "struct", + "value": [ + { + "type": "Integer", + "value": 1 + }, + { + "type": "Integer", + "value": 2 + }, + { + "type": "Integer", + "value": 3 + } + ] + } + ], + "staticFields": [ + { + "type": "struct", + "value": [ + { + "type": "Integer", + "value": 1 + }, + { + "type": "Integer", + "value": 2 + }, + { + "type": "Integer", + "value": 3 + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 20, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 3 + } + ], + "staticFields": [ + { + "type": "struct", + "value": [ + { + "type": "Integer", + "value": 1 + }, + { + "type": "Integer", + "value": 2 + }, + { + "type": "Integer", + "value": 3 + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 3 + } + ] + } + } + ] + }, + { + "name": "OutOfBounds with -1 [ByteString]", + "script": [ + "PUSHDATA1", + "0x02", + "0x0102", + "PUSHM1", + "PICKITEM" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "PICKITEM", + "evaluationStack": [ + { + "type": "integer", + "value": -1 + }, + { + "type": "ByteString", + "value": "0x0102" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "OutOfBounds with more than length [ByteString]", + "script": [ + "PUSHDATA1", + "0x02", + "0x0102", + "PUSH4", + "PICKITEM" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "PICKITEM", + "evaluationStack": [ + { + "type": "integer", + "value": 4 + }, + { + "type": "ByteString", + "value": "0x0102" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [ByteString]", + "script": [ + "PUSHDATA1", + "0x02", + "0x0102", + "PUSH0", + "PICKITEM" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "PICKITEM", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + }, + { + "type": "ByteString", + "value": "0x0102" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + } + ] + }, + { + "name": "Real test [Buffer]", + "script": [ + "PUSHDATA1", + "0x02", + "0x0102", + "CONVERT", + "0x30", + "PUSH0", + "PICKITEM" + ], + "steps": [ + { + "actions": [ + "StepInto", + "StepInto", + "StepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 7, + "nextInstruction": "PICKITEM", + "evaluationStack": [ + { + "type": "Integer", + "value": 0 + }, + { + "type": "Buffer", + "value": "0x0102" + } + ] + } + ] + } + }, + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/REMOVE.json b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/REMOVE.json new file mode 100644 index 0000000000..cba3a4d0a7 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/REMOVE.json @@ -0,0 +1,299 @@ +{ + "category": "Arrays", + "name": "REMOVE", + "tests": [ + { + "name": "Without push", + "script": [ + "PUSH1", + "REMOVE" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without array", + "script": [ + "PUSH1", + "PUSH2", + "REMOVE" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Wrong key", + "script": [ + "PUSH2", + "NEWMAP", + "REMOVE" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Out of bounds", + "script": [ + "PUSH6", + "PUSH5", + "PUSH2", + "PACK", + "PUSH2", + "REMOVE" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [Array]", + "script": [ + "INITSSLOT", + "0x01", + "PUSH6", + "PUSH5", + "PUSH2", + "PACK", + "STSFLD0", + "LDSFLD0", + "PUSH0", + "REMOVE", + "LDSFLD0", + "UNPACK" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 9, + "nextInstruction": "REMOVE", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + }, + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": 5 + }, + { + "type": "Integer", + "value": 6 + } + ] + } + ], + "staticFields": [ + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": 5 + }, + { + "type": "Integer", + "value": 6 + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 10, + "nextInstruction": "LDSFLD0", + "staticFields": [ + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": 6 + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 6 + } + ] + } + } + ] + }, + { + "name": "Real test [Struct]", + "script": [ + "INITSSLOT", + "0x01", + "PUSH0", + "NEWSTRUCT", + "DUP", + "PUSH5", + "APPEND", + "STSFLD0", + "LDSFLD0", + "PUSH0", + "REMOVE", + "LDSFLD0", + "UNPACK" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 10, + "nextInstruction": "REMOVE", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + }, + { + "type": "struct", + "value": [ + { + "type": "Integer", + "value": 5 + } + ] + } + ], + "staticFields": [ + { + "type": "struct", + "value": [ + { + "type": "Integer", + "value": 5 + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 11, + "nextInstruction": "LDSFLD0", + "staticFields": [ + { + "type": "struct", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/REVERSEITEMS.json b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/REVERSEITEMS.json new file mode 100644 index 0000000000..b4dec58eaf --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/REVERSEITEMS.json @@ -0,0 +1,138 @@ +{ + "category": "Arrays", + "name": "REVERSEITEMS", + "tests": [ + { + "name": "Without push", + "script": [ + "REVERSEITEMS" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without Array", + "script": [ + "PUSH9", + "REVERSEITEMS" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [Array]", + "script": [ + "PUSH9", + "PUSH8", + "PUSH2", + "PACK", + "DUP", + "REVERSEITEMS" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": 9 + }, + { + "type": "Integer", + "value": 8 + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": 9 + }, + { + "type": "Integer", + "value": 8 + } + ] + } + ] + } + } + ] + }, + { + "name": "Real test [Buffer]", + "script": [ + "PUSHDATA1", + "0x03", + "0x010203", + "CONVERT", + "0x30", + "DUP", + "REVERSEITEMS" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Buffer", + "value": "0x030201" + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/SETITEM.json b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/SETITEM.json new file mode 100644 index 0000000000..0ed33f2968 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/SETITEM.json @@ -0,0 +1,1226 @@ +{ + "category": "Arrays", + "name": "SETITEM", + "tests": [ + { + "name": "Map in key", + "script": [ + "PUSH1", + "NEWMAP", + "PUSH0", + "SETITEM" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "SETITEM", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + }, + { + "type": "map", + "value": {} + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without array", + "script": [ + "PUSH0", + "PUSH0", + "PUSH0", + "SETITEM" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "SETITEM", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + }, + { + "type": "integer", + "value": 0 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without push", + "script": [ + "SETITEM" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Out of bounds [Array]", + "script": [ + "PUSH1", + "NEWARRAY", + "PUSH1", + "PUSH5", + "SETITEM" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "SETITEM", + "evaluationStack": [ + { + "type": "integer", + "value": 5 + }, + { + "type": "integer", + "value": 1 + }, + { + "type": "array", + "value": [ + { + "type": "Null" + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Out of bounds [Struct]", + "script": [ + "PUSH1", + "NEWSTRUCT", + "PUSH1", + "PUSH5", + "SETITEM" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "SETITEM", + "evaluationStack": [ + { + "type": "integer", + "value": 5 + }, + { + "type": "integer", + "value": 1 + }, + { + "type": "struct", + "value": [ + { + "type": "Null" + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [Map]", + "script": [ + "INITSSLOT", + "0x01", + "NEWMAP", + "DUP", + "STSFLD0", + "PUSH1", + "PUSH2", + "SETITEM", + "LDSFLD0", + "PUSH3", + "PUSH4", + "SETITEM", + "LDSFLD0", + "PUSH1", + "PUSH2", + "SETITEM", + "LDSFLD0", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "PUSH1", + "evaluationStack": [ + { + "type": "map", + "value": {} + } + ], + "staticFields": [ + { + "type": "map", + "value": {} + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 7, + "nextInstruction": "SETITEM", + "evaluationStack": [ + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + }, + { + "type": "map", + "value": {} + } + ], + "staticFields": [ + { + "type": "map", + "value": {} + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 8, + "nextInstruction": "LDSFLD0", + "staticFields": [ + { + "type": "map", + "value": { + "0x01": { + "type": "Integer", + "value": 2 + } + } + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 9, + "nextInstruction": "PUSH3", + "evaluationStack": [ + { + "type": "map", + "value": { + "0x01": { + "type": "Integer", + "value": 2 + } + } + } + ], + "staticFields": [ + { + "type": "map", + "value": { + "0x01": { + "type": "Integer", + "value": 2 + } + } + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 13, + "nextInstruction": "PUSH1", + "evaluationStack": [ + { + "type": "map", + "value": { + "0x01": { + "type": "Integer", + "value": 2 + }, + "0x03": { + "type": "Integer", + "value": 4 + } + } + } + ], + "staticFields": [ + { + "type": "map", + "value": { + "0x01": { + "type": "Integer", + "value": 2 + }, + "0x03": { + "type": "Integer", + "value": 4 + } + } + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "map", + "value": { + "0x01": { + "type": "Integer", + "value": 2 + }, + "0x03": { + "type": "Integer", + "value": 4 + } + } + } + ] + } + } + ] + }, + { + "name": "Real test [Array]", + "script": [ + "PUSH1", + "NEWARRAY", + "DUP", + "PUSH0", + "PUSH5", + "SETITEM" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "SETITEM", + "evaluationStack": [ + { + "type": "integer", + "value": 5 + }, + { + "type": "integer", + "value": 0 + }, + { + "type": "array", + "value": [ + { + "type": "Null" + } + ] + }, + { + "type": "array", + "value": [ + { + "type": "Null" + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": 5 + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": 5 + } + ] + } + ] + } + } + ] + }, + { + "name": "Real test [Struct]", + "script": [ + "PUSH1", + "NEWSTRUCT", + "DUP", + "PUSH0", + "PUSH5", + "SETITEM" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "SETITEM", + "evaluationStack": [ + { + "type": "integer", + "value": 5 + }, + { + "type": "integer", + "value": 0 + }, + { + "type": "struct", + "value": [ + { + "type": "Null" + } + ] + }, + { + "type": "struct", + "value": [ + { + "type": "Null" + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "struct", + "value": [ + { + "type": "Integer", + "value": 5 + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "struct", + "value": [ + { + "type": "Integer", + "value": 5 + } + ] + } + ] + } + } + ] + }, + { + "name": "Clone test [Array]", + "script": [ + "INITSSLOT", + "0x01", + "PUSH1", + "NEWARRAY", + "DUP", + "PUSH0", + "PUSH5", + "SETITEM", + "STSFLD0", + "LDSFLD0", + "DUP", + "PUSH0", + "PUSH4", + "SETITEM", + "LDSFLD0" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "PUSH0", + "evaluationStack": [ + { + "type": "array", + "value": [ + { + "type": "Null" + } + ] + }, + { + "type": "array", + "value": [ + { + "type": "Null" + } + ] + } + ], + "staticFields": [ + { + "type": "Null" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 8, + "nextInstruction": "STSFLD0", + "evaluationStack": [ + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": 5 + } + ] + } + ], + "staticFields": [ + { + "type": "Null" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 11, + "nextInstruction": "PUSH0", + "evaluationStack": [ + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": 5 + } + ] + }, + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": 5 + } + ] + } + ], + "staticFields": [ + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": 5 + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 14, + "nextInstruction": "LDSFLD0", + "evaluationStack": [ + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": 4 + } + ] + } + ], + "staticFields": [ + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": 4 + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 15, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": 4 + } + ] + }, + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": 4 + } + ] + } + ], + "staticFields": [ + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": 4 + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": 4 + } + ] + }, + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": 4 + } + ] + } + ] + } + } + ] + }, + { + "name": "Clone test [Struct]", + "script": [ + "INITSSLOT", + "0x01", + "PUSH1", + "NEWSTRUCT", + "DUP", + "PUSH0", + "PUSH5", + "SETITEM", + "STSFLD0", + "LDSFLD0", + "DUP", + "PUSH0", + "PUSH4", + "SETITEM", + "LDSFLD0" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "PUSH0", + "evaluationStack": [ + { + "type": "struct", + "value": [ + { + "type": "Null" + } + ] + }, + { + "type": "struct", + "value": [ + { + "type": "Null" + } + ] + } + ], + "staticFields": [ + { + "type": "Null" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 8, + "nextInstruction": "STSFLD0", + "evaluationStack": [ + { + "type": "struct", + "value": [ + { + "type": "Integer", + "value": 5 + } + ] + } + ], + "staticFields": [ + { + "type": "Null" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 11, + "nextInstruction": "PUSH0", + "evaluationStack": [ + { + "type": "struct", + "value": [ + { + "type": "Integer", + "value": 5 + } + ] + }, + { + "type": "struct", + "value": [ + { + "type": "Integer", + "value": 5 + } + ] + } + ], + "staticFields": [ + { + "type": "struct", + "value": [ + { + "type": "Integer", + "value": 5 + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 14, + "nextInstruction": "LDSFLD0", + "evaluationStack": [ + { + "type": "struct", + "value": [ + { + "type": "Integer", + "value": 4 + } + ] + } + ], + "staticFields": [ + { + "type": "struct", + "value": [ + { + "type": "Integer", + "value": 4 + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 15, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "struct", + "value": [ + { + "type": "Integer", + "value": 4 + } + ] + }, + { + "type": "struct", + "value": [ + { + "type": "Integer", + "value": 4 + } + ] + } + ], + "staticFields": [ + { + "type": "struct", + "value": [ + { + "type": "Integer", + "value": 4 + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "struct", + "value": [ + { + "type": "Integer", + "value": 4 + } + ] + }, + { + "type": "struct", + "value": [ + { + "type": "Integer", + "value": 4 + } + ] + } + ] + } + } + ] + }, + { + "name": "Real test [Buffer]", + "script": [ + "PUSHDATA1", + "0x02", + "0x0102", + "CONVERT", + "0x30", + "DUP", + "PUSH0", + "PUSH5", + "SETITEM" + ], + "steps": [ + { + "actions": [ + "StepInto", + "StepInto", + "StepInto", + "StepInto", + "StepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 9, + "nextInstruction": "SETITEM", + "evaluationStack": [ + { + "type": "Integer", + "value": 5 + }, + { + "type": "Integer", + "value": 0 + }, + { + "type": "Buffer", + "value": "0x0102" + }, + { + "type": "Buffer", + "value": "0x0102" + } + ] + } + ] + } + }, + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Buffer", + "value": "0x0502" + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/SIZE.json b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/SIZE.json new file mode 100644 index 0000000000..fa2907411d --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/SIZE.json @@ -0,0 +1,266 @@ +{ + "category": "Arrays", + "name": "SIZE", + "tests": [ + { + "name": "Wrong type SYSCALL[0x77777777]+SIZE", + "script": [ + "SYSCALL", + "0x77777777", + "SIZE" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "SIZE", + "evaluationStack": [ + { + "type": "interop", + "value": "Object" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without PUSH+SIZE", + "script": [ + "SIZE" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test with ByteString", + "script": [ + "PUSHDATA1", + "0x01", + "0x00", + "SIZE" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + } + ] + }, + { + "name": "Real test with Buffer", + "script": [ + "PUSH10", + "NEWBUFFER", + "SIZE" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 10 + } + ] + } + } + ] + }, + { + "name": "Real test with array", + "script": [ + "PUSH3", + "NEWARRAY", + "SIZE" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 3 + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 3 + } + ] + } + } + ] + }, + { + "name": "Real test with struct", + "script": [ + "PUSH3", + "NEWSTRUCT", + "SIZE" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 3 + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 3 + } + ] + } + } + ] + }, + { + "name": "Real test with map", + "script": [ + "NEWMAP", + "SIZE" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/UNPACK.json b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/UNPACK.json new file mode 100644 index 0000000000..63c92aad3a --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/UNPACK.json @@ -0,0 +1,168 @@ +{ + "category": "Arrays", + "name": "UNPACK", + "tests": [ + { + "name": "Without array", + "script": [ + "PUSH10", + "UNPACK" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without push", + "script": [ + "UNPACK" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without push", + "script": [ + "PUSH5", + "PUSH6", + "PUSH2", + "PACK", + "UNPACK" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "UNPACK", + "evaluationStack": [ + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": 6 + }, + { + "type": "Integer", + "value": 5 + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 6 + }, + { + "type": "integer", + "value": 5 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 6 + }, + { + "type": "integer", + "value": 5 + } + ] + } + } + ] + }, + { + "name": "With map", + "script": [ + "PUSH5", + "PUSH6", + "PUSH1", + "PACKMAP", + "UNPACK" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 1 + }, + { + "type": "Integer", + "value": 6 + }, + { + "type": "Integer", + "value": 5 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/VALUES.json b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/VALUES.json new file mode 100644 index 0000000000..4cf832eb59 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Arrays/VALUES.json @@ -0,0 +1,194 @@ +{ + "category": "Arrays", + "name": "VALUES", + "tests": [ + { + "name": "No StackItem", + "script": [ + "KEYS" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Invalid StackItem [Integer != (Map|Array|Struct)]", + "script": [ + "PUSH0", + "KEYS" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Values in map", + "script": [ + "NEWMAP", + "DUP", + "DUP", + "PUSH0", + "PUSH2", + "SETITEM", + "PUSH1", + "PUSH4", + "SETITEM", + "VALUES" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": 2 + }, + { + "type": "Integer", + "value": 4 + } + ] + } + ] + } + } + ] + }, + { + "name": "Simple values in array", + "script": [ + "PUSH2", + "NEWARRAY_T", + "0x00", + "VALUES" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "array", + "value": [ + { + "type": "Null" + }, + { + "type": "Null" + } + ] + } + ] + } + } + ] + }, + { + "name": "Compound value in array [inner struct]", + "script": [ + "PUSH1", + "NEWARRAY", + "DUP", + "PUSH0", + "PUSH2", + "NEWSTRUCT", + "SETITEM", + "VALUES" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "array", + "value": [ + { + "type": "struct", + "value": [ + { + "type": "Null" + }, + { + "type": "Null" + } + ] + } + ] + } + ] + } + } + ] + }, + { + "name": "Compound value in array [inner map]", + "script": [ + "PUSH1", + "NEWARRAY", + "DUP", + "PUSH0", + "NEWMAP", + "DUP", + "PUSH0", + "PUSH1", + "SETITEM", + "SETITEM", + "VALUES" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "array", + "value": [ + { + "type": "map", + "value": { + "": { + "type": "Integer", + "value": 1 + } + } + } + ] + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/BitwiseLogic/AND.json b/tests/Neo.VM.Tests/Tests/OpCodes/BitwiseLogic/AND.json new file mode 100644 index 0000000000..f1e1cc7d14 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/BitwiseLogic/AND.json @@ -0,0 +1,811 @@ +{ + "category": "Bitwise Logic", + "name": "AND", + "tests": [ + { + "name": "Without two pushes", + "script": [ + "AND" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without one push", + "script": [ + "PUSH0", + "AND" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "AND", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [true,true]=1", + "script": [ + "PUSH0", + "NOT", + "PUSH0", + "NOT", + "AND" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "AND", + "evaluationStack": [ + { + "type": "boolean", + "value": true + }, + { + "type": "boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + }, + { + "name": "Real test [false,true]=0", + "script": [ + "PUSH0", + "NOT", + "PUSH0", + "NOT", + "NOT", + "AND" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "AND", + "evaluationStack": [ + { + "type": "boolean", + "value": false + }, + { + "type": "boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 0 + } + ] + } + } + ] + }, + { + "name": "Real test [1,1]=1", + "script": [ + "PUSH1", + "PUSH1", + "AND" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "AND", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + }, + { + "name": "Real test [1,2]=0", + "script": [ + "PUSH2", + "PUSH1", + "AND" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "AND", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 2 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 0 + } + ] + } + } + ] + }, + { + "name": "Real test [Array,Array]=FAULT", + "script": [ + "PUSH0", + "NEWARRAY", + "DUP", + "AND" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "AND", + "evaluationStack": [ + { + "type": "array", + "value": [] + }, + { + "type": "array", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [Struct,Struct]=FAULT", + "script": [ + "PUSH0", + "NEWSTRUCT", + "DUP", + "AND" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "AND", + "evaluationStack": [ + { + "type": "struct", + "value": [] + }, + { + "type": "struct", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [Map,Map]=FAULT", + "script": [ + "NEWMAP", + "DUP", + "AND" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "AND", + "evaluationStack": [ + { + "type": "map", + "value": {} + }, + { + "type": "map", + "value": {} + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [ByteString,ByteString]=11911212070228631137091015067172167745536", + "script": [ + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000123", + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000123", + "AND" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 38, + "nextInstruction": "AND", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000123" + }, + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000123" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 39, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Integer", + "value": "11911212070228631137091015067172167745536" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": "11911212070228631137091015067172167745536" + } + ] + } + } + ] + }, + { + "name": "Real test [ByteString,ByteString]=10890364969465815746700891244876863111168", + "script": [ + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000123", + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000124", + "AND" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 38, + "nextInstruction": "AND", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000124" + }, + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000123" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 39, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Integer", + "value": "10890364969465815746700891244876863111168" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": "10890364969465815746700891244876863111168" + } + ] + } + } + ] + }, + { + "name": "Real test [ByteString,ByteString]=0", + "script": [ + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000123", + "PUSHDATA1", + "0x10", + "0x00000000000000000000000000000124", + "AND" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 37, + "nextInstruction": "AND", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x00000000000000000000000000000124" + }, + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000123" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 38, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 0 + } + ] + } + } + ] + }, + { + "name": "Real test with clone [Interop,Interop]=FAULT", + "script": [ + "SYSCALL", + "0x77777777", + "DUP", + "AND" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "DUP", + "evaluationStack": [ + { + "type": "interop", + "value": "Object" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "AND", + "evaluationStack": [ + { + "type": "interop", + "value": "Object" + }, + { + "type": "interop", + "value": "Object" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [Buffer,Buffer]=FAULT", + "script": [ + "PUSHDATA1", + "0x01AA", + "CONVERT", + "0x30", + "PUSHDATA1", + "0x01BB", + "CONVERT", + "0x30", + "AND" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 10, + "nextInstruction": "AND", + "evaluationStack": [ + { + "type": "Buffer", + "value": "0xBB" + }, + { + "type": "Buffer", + "value": "0xAA" + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/BitwiseLogic/EQUAL.json b/tests/Neo.VM.Tests/Tests/OpCodes/BitwiseLogic/EQUAL.json new file mode 100644 index 0000000000..75a484d0db --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/BitwiseLogic/EQUAL.json @@ -0,0 +1,1447 @@ +{ + "category": "Bitwise Logic", + "name": "EQUAL same types", + "tests": [ + { + "name": "Without two pushes", + "script": [ + "EQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without one push", + "script": [ + "PUSH0", + "EQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "EQUAL", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [Bool,Bool]=true", + "script": [ + "PUSH0", + "NOT", + "PUSH0", + "NOT", + "EQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "EQUAL", + "evaluationStack": [ + { + "type": "boolean", + "value": true + }, + { + "type": "boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Real test [Bool,Bool]=false", + "script": [ + "PUSH0", + "NOT", + "PUSH0", + "NOT", + "NOT", + "EQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "EQUAL", + "evaluationStack": [ + { + "type": "boolean", + "value": false + }, + { + "type": "boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test [Integer,Integer]=true", + "script": [ + "PUSH1", + "PUSH1", + "EQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "EQUAL", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Real test [Integer,Integer]=false", + "script": [ + "PUSH2", + "PUSH1", + "EQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "EQUAL", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 2 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test [Array,Array]=true", + "script": [ + "PUSH0", + "NEWARRAY", + "DUP", + "EQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "EQUAL", + "evaluationStack": [ + { + "type": "array", + "value": [] + }, + { + "type": "array", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Real test [Array,Array]=false", + "script": [ + "PUSH0", + "NEWARRAY", + "PUSH0", + "NEWARRAY", + "EQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "EQUAL", + "evaluationStack": [ + { + "type": "array", + "value": [] + }, + { + "type": "array", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test [Struct,Struct]=true with clone", + "script": [ + "PUSH0", + "NEWSTRUCT", + "DUP", + "EQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "EQUAL", + "evaluationStack": [ + { + "type": "struct", + "value": [] + }, + { + "type": "struct", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Real test [Struct,Struct]=true without clone", + "script": [ + "PUSH0", + "NEWSTRUCT", + "PUSH0", + "NEWSTRUCT", + "EQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "EQUAL", + "evaluationStack": [ + { + "type": "struct", + "value": [] + }, + { + "type": "struct", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Real test [Struct,Struct]=false", + "script": [ + "PUSH0", + "NEWSTRUCT", + "PUSH1", + "NEWSTRUCT", + "EQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "EQUAL", + "evaluationStack": [ + { + "type": "struct", + "value": [ + { + "type": "Null" + } + ] + }, + { + "type": "struct", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test [Map,Map]=true", + "script": [ + "NEWMAP", + "DUP", + "EQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "EQUAL", + "evaluationStack": [ + { + "type": "map", + "value": {} + }, + { + "type": "map", + "value": {} + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Real test [Map,Map]=false", + "script": [ + "NEWMAP", + "NEWMAP", + "EQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "EQUAL", + "evaluationStack": [ + { + "type": "map", + "value": {} + }, + { + "type": "map", + "value": {} + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test [ByteString,ByteString]=true", + "script": [ + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000123", + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000123", + "EQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 38, + "nextInstruction": "EQUAL", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000123" + }, + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000123" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 39, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Real test [ByteString,ByteString]=false same length", + "script": [ + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000123", + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000124", + "EQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 38, + "nextInstruction": "EQUAL", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000124" + }, + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000123" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 39, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test [ByteString,ByteString]=false different length", + "script": [ + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000123", + "PUSHDATA1", + "0x10", + "0x00000000000000000000000000000124", + "EQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 37, + "nextInstruction": "EQUAL", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x00000000000000000000000000000124" + }, + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000123" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 38, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test [ByteString,ByteString]=false different length", + "script": [ + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000123", + "PUSHDATA1", + "0x10", + "0x00000000000000000000000000000124", + "EQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 37, + "nextInstruction": "EQUAL", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x00000000000000000000000000000124" + }, + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000123" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 38, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test with clone [Interop,Interop]=true", + "script": [ + "SYSCALL", + "0x77777777", + "DUP", + "EQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "DUP", + "evaluationStack": [ + { + "type": "interop", + "value": "Object" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "EQUAL", + "evaluationStack": [ + { + "type": "interop", + "value": "Object" + }, + { + "type": "interop", + "value": "Object" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 7, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Real test [Interop,Interop]=false", + "script": [ + "SYSCALL", + "0x77777777", + "SYSCALL", + "0x77777777", + "EQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 10, + "nextInstruction": "EQUAL", + "evaluationStack": [ + { + "type": "interop", + "value": "Object" + }, + { + "type": "interop", + "value": "Object" + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test [Buffer,Buffer]=false", + "script": [ + "PUSHDATA1", + "0x01AA", + "CONVERT", + "0x30", + "PUSHDATA1", + "0x01BB", + "CONVERT", + "0x30", + "EQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 10, + "nextInstruction": "EQUAL", + "evaluationStack": [ + { + "type": "Buffer", + "value": "0xBB" + }, + { + "type": "Buffer", + "value": "0xAA" + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test [Buffer,Buffer]=false", + "script": [ + "PUSHDATA1", + "0x01AA", + "CONVERT", + "0x30", + "PUSHDATA1", + "0x01AA", + "CONVERT", + "0x30", + "EQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 10, + "nextInstruction": "EQUAL", + "evaluationStack": [ + { + "type": "Buffer", + "value": "0xAA" + }, + { + "type": "Buffer", + "value": "0xAA" + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test [Buffer,Buffer]=true", + "script": [ + "PUSHDATA1", + "0x01AA", + "CONVERT", + "0x30", + "DUP", + "EQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "EQUAL", + "evaluationStack": [ + { + "type": "Buffer", + "value": "0xAA" + }, + { + "type": "Buffer", + "value": "0xAA" + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/BitwiseLogic/INVERT.json b/tests/Neo.VM.Tests/Tests/OpCodes/BitwiseLogic/INVERT.json new file mode 100644 index 0000000000..636e08628b --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/BitwiseLogic/INVERT.json @@ -0,0 +1,657 @@ +{ + "category": "Bitwise Logic", + "name": "INVERT", + "tests": [ + { + "name": "Without two pushes", + "script": [ + "INVERT" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "With 0", + "script": [ + "PUSH0", + "INVERT" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "INVERT", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": -1 + } + ] + } + } + ] + }, + { + "name": "Real test [true]=-2", + "script": [ + "PUSH0", + "NOT", + "INVERT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "INVERT", + "evaluationStack": [ + { + "type": "boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Integer", + "value": -2 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": -2 + } + ] + } + } + ] + }, + { + "name": "Real test [false]=-1", + "script": [ + "PUSH0", + "NOT", + "NOT", + "INVERT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "INVERT", + "evaluationStack": [ + { + "type": "boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Integer", + "value": -1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": -1 + } + ] + } + } + ] + }, + { + "name": "Real test [1]=-2", + "script": [ + "PUSH1", + "INVERT" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "INVERT", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Integer", + "value": -2 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": -2 + } + ] + } + } + ] + }, + { + "name": "Real test [2]=-3", + "script": [ + "PUSH2", + "INVERT" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "INVERT", + "evaluationStack": [ + { + "type": "integer", + "value": 2 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Integer", + "value": -3 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": -3 + } + ] + } + } + ] + }, + { + "name": "Real test [Array]=FAULT", + "script": [ + "PUSH0", + "NEWARRAY", + "INVERT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "INVERT", + "evaluationStack": [ + { + "type": "array", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [Struct]=FAULT", + "script": [ + "PUSH0", + "NEWSTRUCT", + "INVERT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "INVERT", + "evaluationStack": [ + { + "type": "struct", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [Map]=FAULT", + "script": [ + "NEWMAP", + "INVERT" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "INVERT", + "evaluationStack": [ + { + "type": "map", + "value": {} + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [ByteString]=-11911212070228631137091015067172167745537", + "script": [ + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000123", + "INVERT" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 19, + "nextInstruction": "INVERT", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000123" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 20, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Integer", + "value": "-11911212070228631137091015067172167745537" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": "-11911212070228631137091015067172167745537" + } + ] + } + } + ] + }, + { + "name": "Real test [ByteString]=-12251494437149569600554389674603935956993", + "script": [ + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000124", + "INVERT" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 19, + "nextInstruction": "INVERT", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000124" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 20, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Integer", + "value": "-12251494437149569600554389674603935956993" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": "-12251494437149569600554389674603935956993" + } + ] + } + } + ] + }, + { + "name": "Real test with clone [Interop]=FAULT", + "script": [ + "SYSCALL", + "0x77777777", + "INVERT" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "INVERT", + "evaluationStack": [ + { + "type": "interop", + "value": "Object" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [Buffer,Buffer]=FAULT", + "script": [ + "PUSHDATA1", + "0x01AA", + "CONVERT", + "0x30", + "PUSHDATA1", + "0x01BB", + "CONVERT", + "0x30", + "INVERT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 10, + "nextInstruction": "INVERT", + "evaluationStack": [ + { + "type": "Buffer", + "value": "0xBB" + }, + { + "type": "Buffer", + "value": "0xAA" + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/BitwiseLogic/NOTEQUAL.json b/tests/Neo.VM.Tests/Tests/OpCodes/BitwiseLogic/NOTEQUAL.json new file mode 100644 index 0000000000..95acf9509d --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/BitwiseLogic/NOTEQUAL.json @@ -0,0 +1,1299 @@ +{ + "category": "Bitwise Logic", + "name": "NOTEQUAL", + "tests": [ + { + "name": "Without two pushes", + "script": [ + "NOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without one push", + "script": [ + "PUSH0", + "NOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "NOTEQUAL", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "StepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [Integer,Integer]=false", + "script": [ + "PUSH1", + "PUSH1", + "NOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "NOTEQUAL", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test [Integer,Integer]=true", + "script": [ + "PUSH2", + "PUSH1", + "NOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "NOTEQUAL", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 2 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Real test [Array,Array]=false", + "script": [ + "PUSH0", + "NEWARRAY", + "DUP", + "NOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "NOTEQUAL", + "evaluationStack": [ + { + "type": "array", + "value": [] + }, + { + "type": "array", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test [Array,Array]=true", + "script": [ + "PUSH0", + "NEWARRAY", + "PUSH0", + "NEWARRAY", + "NOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "NOTEQUAL", + "evaluationStack": [ + { + "type": "array", + "value": [] + }, + { + "type": "array", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Real test [Struct,Struct]=false with clone", + "script": [ + "PUSH0", + "NEWSTRUCT", + "DUP", + "NOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "NOTEQUAL", + "evaluationStack": [ + { + "type": "struct", + "value": [] + }, + { + "type": "struct", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test [Struct,Struct]=false without clone", + "script": [ + "PUSH0", + "NEWSTRUCT", + "PUSH0", + "NEWSTRUCT", + "NOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "NOTEQUAL", + "evaluationStack": [ + { + "type": "struct", + "value": [] + }, + { + "type": "struct", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test [Struct,Struct]=true", + "script": [ + "PUSH0", + "NEWSTRUCT", + "PUSH1", + "NEWSTRUCT", + "NOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "NOTEQUAL", + "evaluationStack": [ + { + "type": "struct", + "value": [ + { + "type": "Null" + } + ] + }, + { + "type": "struct", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Real test [Map,Map]=false", + "script": [ + "NEWMAP", + "DUP", + "NOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "NOTEQUAL", + "evaluationStack": [ + { + "type": "map", + "value": {} + }, + { + "type": "map", + "value": {} + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test [Map,Map]=true", + "script": [ + "NEWMAP", + "NEWMAP", + "NOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "NOTEQUAL", + "evaluationStack": [ + { + "type": "map", + "value": {} + }, + { + "type": "map", + "value": {} + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Real test [ByteString,ByteString]=false", + "script": [ + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000123", + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000123", + "NOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 38, + "nextInstruction": "NOTEQUAL", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000123" + }, + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000123" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 39, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test [ByteString,ByteString]=true same length", + "script": [ + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000123", + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000124", + "NOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 38, + "nextInstruction": "NOTEQUAL", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000124" + }, + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000123" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 39, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Real test [ByteString,ByteString]=true different length", + "script": [ + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000123", + "PUSHDATA1", + "0x10", + "0x00000000000000000000000000000124", + "NOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 37, + "nextInstruction": "NOTEQUAL", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x00000000000000000000000000000124" + }, + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000123" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 38, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Real test [ByteString,ByteString]=true different length", + "script": [ + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000123", + "PUSHDATA1", + "0x10", + "0x00000000000000000000000000000124", + "NOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 37, + "nextInstruction": "NOTEQUAL", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x00000000000000000000000000000124" + }, + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000123" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 38, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Real test with clone [Interop,Interop]=false", + "script": [ + "SYSCALL", + "0x77777777", + "DUP", + "NOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "DUP", + "evaluationStack": [ + { + "type": "interop", + "value": "Object" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "NOTEQUAL", + "evaluationStack": [ + { + "type": "interop", + "value": "Object" + }, + { + "type": "interop", + "value": "Object" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 7, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Real test [Interop,Interop]=true", + "script": [ + "SYSCALL", + "0x77777777", + "SYSCALL", + "0x77777777", + "NOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 10, + "nextInstruction": "NOTEQUAL", + "evaluationStack": [ + { + "type": "interop", + "value": "Object" + }, + { + "type": "interop", + "value": "Object" + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Real test [Buffer,Buffer]=true", + "script": [ + "PUSHDATA1", + "0x01AA", + "CONVERT", + "0x30", + "PUSHDATA1", + "0x01BB", + "CONVERT", + "0x30", + "NOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 10, + "nextInstruction": "NOTEQUAL", + "evaluationStack": [ + { + "type": "Buffer", + "value": "0xBB" + }, + { + "type": "Buffer", + "value": "0xAA" + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Real test [Buffer,Buffer]=true", + "script": [ + "PUSHDATA1", + "0x01AA", + "CONVERT", + "0x30", + "PUSHDATA1", + "0x01AA", + "CONVERT", + "0x30", + "NOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 10, + "nextInstruction": "NOTEQUAL", + "evaluationStack": [ + { + "type": "Buffer", + "value": "0xAA" + }, + { + "type": "Buffer", + "value": "0xAA" + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Real test [Buffer,Buffer]=false", + "script": [ + "PUSHDATA1", + "0x01AA", + "CONVERT", + "0x30", + "DUP", + "NOTEQUAL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "NOTEQUAL", + "evaluationStack": [ + { + "type": "Buffer", + "value": "0xAA" + }, + { + "type": "Buffer", + "value": "0xAA" + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/BitwiseLogic/OR.json b/tests/Neo.VM.Tests/Tests/OpCodes/BitwiseLogic/OR.json new file mode 100644 index 0000000000..fb52b32b71 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/BitwiseLogic/OR.json @@ -0,0 +1,811 @@ +{ + "category": "Bitwise Logic", + "name": "OR", + "tests": [ + { + "name": "Without two pushes", + "script": [ + "OR" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without one push", + "script": [ + "PUSH0", + "OR" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "OR", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [true,true]=1", + "script": [ + "PUSH0", + "NOT", + "PUSH0", + "NOT", + "OR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "OR", + "evaluationStack": [ + { + "type": "boolean", + "value": true + }, + { + "type": "boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + }, + { + "name": "Real test [false,true]=1", + "script": [ + "PUSH0", + "NOT", + "PUSH0", + "NOT", + "NOT", + "OR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "OR", + "evaluationStack": [ + { + "type": "boolean", + "value": false + }, + { + "type": "boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + }, + { + "name": "Real test [1,1]=1", + "script": [ + "PUSH1", + "PUSH1", + "OR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "OR", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + }, + { + "name": "Real test [1,2]=3", + "script": [ + "PUSH2", + "PUSH1", + "OR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "OR", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 2 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Integer", + "value": 3 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 3 + } + ] + } + } + ] + }, + { + "name": "Real test [Array,Array]=FAULT", + "script": [ + "PUSH0", + "NEWARRAY", + "DUP", + "OR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "OR", + "evaluationStack": [ + { + "type": "array", + "value": [] + }, + { + "type": "array", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [Struct,Struct]=FAULT", + "script": [ + "PUSH0", + "NEWSTRUCT", + "DUP", + "OR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "OR", + "evaluationStack": [ + { + "type": "struct", + "value": [] + }, + { + "type": "struct", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [Map,Map]=FAULT", + "script": [ + "NEWMAP", + "DUP", + "OR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "OR", + "evaluationStack": [ + { + "type": "map", + "value": {} + }, + { + "type": "map", + "value": {} + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [ByteString,ByteString]=11911212070228631137091015067172167745536", + "script": [ + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000123", + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000123", + "OR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 38, + "nextInstruction": "OR", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000123" + }, + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000123" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 39, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Integer", + "value": "11911212070228631137091015067172167745536" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": "11911212070228631137091015067172167745536" + } + ] + } + } + ] + }, + { + "name": "Real test [ByteString,ByteString]=13272341537912384990944513496899240591360", + "script": [ + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000123", + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000124", + "OR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 38, + "nextInstruction": "OR", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000124" + }, + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000123" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 39, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Integer", + "value": "13272341537912384990944513496899240591360" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": "13272341537912384990944513496899240591360" + } + ] + } + } + ] + }, + { + "name": "Real test [ByteString,ByteString]=11959069470373746643343180651838589370368", + "script": [ + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000123", + "PUSHDATA1", + "0x10", + "0x00000000000000000000000000000124", + "OR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 37, + "nextInstruction": "OR", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x00000000000000000000000000000124" + }, + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000123" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 38, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Integer", + "value": "11959069470373746643343180651838589370368" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": "11959069470373746643343180651838589370368" + } + ] + } + } + ] + }, + { + "name": "Real test with clone [Interop,Interop]=FAULT", + "script": [ + "SYSCALL", + "0x77777777", + "DUP", + "OR" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "DUP", + "evaluationStack": [ + { + "type": "interop", + "value": "Object" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "OR", + "evaluationStack": [ + { + "type": "interop", + "value": "Object" + }, + { + "type": "interop", + "value": "Object" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [Buffer,Buffer]=FAULT", + "script": [ + "PUSHDATA1", + "0x01AA", + "CONVERT", + "0x30", + "PUSHDATA1", + "0x01BB", + "CONVERT", + "0x30", + "OR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 10, + "nextInstruction": "OR", + "evaluationStack": [ + { + "type": "Buffer", + "value": "0xBB" + }, + { + "type": "Buffer", + "value": "0xAA" + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/BitwiseLogic/XOR.json b/tests/Neo.VM.Tests/Tests/OpCodes/BitwiseLogic/XOR.json new file mode 100644 index 0000000000..bae4cf557b --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/BitwiseLogic/XOR.json @@ -0,0 +1,811 @@ +{ + "category": "Bitwise Logic", + "name": "XOR", + "tests": [ + { + "name": "Without two pushes", + "script": [ + "XOR" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without one push", + "script": [ + "PUSH0", + "XOR" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "XOR", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [true,true]=0", + "script": [ + "PUSH0", + "NOT", + "PUSH0", + "NOT", + "XOR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "XOR", + "evaluationStack": [ + { + "type": "boolean", + "value": true + }, + { + "type": "boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 0 + } + ] + } + } + ] + }, + { + "name": "Real test [false,true]=1", + "script": [ + "PUSH0", + "NOT", + "PUSH0", + "NOT", + "NOT", + "XOR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "XOR", + "evaluationStack": [ + { + "type": "boolean", + "value": false + }, + { + "type": "boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + }, + { + "name": "Real test [1,1]=0", + "script": [ + "PUSH1", + "PUSH1", + "XOR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "XOR", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 0 + } + ] + } + } + ] + }, + { + "name": "Real test [1,2]=3", + "script": [ + "PUSH2", + "PUSH1", + "XOR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "XOR", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 2 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Integer", + "value": 3 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 3 + } + ] + } + } + ] + }, + { + "name": "Real test [Array,Array]=FAULT", + "script": [ + "PUSH0", + "NEWARRAY", + "DUP", + "XOR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "XOR", + "evaluationStack": [ + { + "type": "array", + "value": [] + }, + { + "type": "array", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [Struct,Struct]=FAULT", + "script": [ + "PUSH0", + "NEWSTRUCT", + "DUP", + "XOR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "XOR", + "evaluationStack": [ + { + "type": "struct", + "value": [] + }, + { + "type": "struct", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [Map,Map]=FAULT", + "script": [ + "NEWMAP", + "DUP", + "XOR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "XOR", + "evaluationStack": [ + { + "type": "map", + "value": {} + }, + { + "type": "map", + "value": {} + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [ByteString,ByteString]=0", + "script": [ + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000123", + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000123", + "XOR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 38, + "nextInstruction": "XOR", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000123" + }, + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000123" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 39, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 0 + } + ] + } + } + ] + }, + { + "name": "Real test [ByteString,ByteString]=2381976568446569244243622252022377480192", + "script": [ + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000123", + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000124", + "XOR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 38, + "nextInstruction": "XOR", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000124" + }, + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000123" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 39, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Integer", + "value": "2381976568446569244243622252022377480192" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": "2381976568446569244243622252022377480192" + } + ] + } + } + ] + }, + { + "name": "Real test [ByteString,ByteString]=11959069470373746643343180651838589370368", + "script": [ + "PUSHDATA1", + "0x11", + "0x0000000000000000000000000000000123", + "PUSHDATA1", + "0x10", + "0x00000000000000000000000000000124", + "XOR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 37, + "nextInstruction": "XOR", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x00000000000000000000000000000124" + }, + { + "type": "ByteString", + "value": "0x0000000000000000000000000000000123" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 38, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Integer", + "value": "11959069470373746643343180651838589370368" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": "11959069470373746643343180651838589370368" + } + ] + } + } + ] + }, + { + "name": "Real test with clone [Interop,Interop]=FAULT", + "script": [ + "SYSCALL", + "0x77777777", + "DUP", + "XOR" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "DUP", + "evaluationStack": [ + { + "type": "interop", + "value": "Object" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "XOR", + "evaluationStack": [ + { + "type": "interop", + "value": "Object" + }, + { + "type": "interop", + "value": "Object" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [Buffer,Buffer]=FAULT", + "script": [ + "PUSHDATA1", + "0x01AA", + "CONVERT", + "0x30", + "PUSHDATA1", + "0x01BB", + "CONVERT", + "0x30", + "XOR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 10, + "nextInstruction": "XOR", + "evaluationStack": [ + { + "type": "Buffer", + "value": "0xBB" + }, + { + "type": "Buffer", + "value": "0xAA" + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/ABORT.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/ABORT.json new file mode 100644 index 0000000000..17c3a35e2e --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/ABORT.json @@ -0,0 +1,22 @@ +{ + "category": "Control", + "name": "ABORT", + "tests": [ + { + "name": "Basic Test", + "script": [ + "ABORT" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/ABORTMSG.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/ABORTMSG.json new file mode 100644 index 0000000000..a7e795eb2c --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/ABORTMSG.json @@ -0,0 +1,26 @@ +{ + "category": "Control", + "name": "ABORTMSG", + "tests": [ + { + "name": "Basic Test", + "script": [ + "PUSHDATA1", + "0x03", + "0x4e454f", + "ABORTMSG" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT", + "exceptionMessage": "ABORTMSG is executed. Reason: NEO" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/ASSERT.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/ASSERT.json new file mode 100644 index 0000000000..bb7d14c5e8 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/ASSERT.json @@ -0,0 +1,42 @@ +{ + "category": "Control", + "name": "ASSERT", + "tests": [ + { + "name": "Fault Test", + "script": [ + "PUSH0", + "ASSERT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Halt Test", + "script": [ + "PUSH1", + "ASSERT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "execute" + ], + "result": { + "state": "HALT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/ASSERTMSG.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/ASSERTMSG.json new file mode 100644 index 0000000000..fc4c572ec3 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/ASSERTMSG.json @@ -0,0 +1,47 @@ +{ + "category": "Control", + "name": "ASSERTMSG", + "tests": [ + { + "name": "Fault Test", + "script": [ + "PUSH0", + "PUSHDATA1", + "0x04", + "0x4641494c", + "ASSERTMSG" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT", + "exceptionMessage": "ASSERTMSG is executed with false result. Reason: FAIL" + } + } + ] + }, + { + "name": "Halt Test", + "script": [ + "PUSH1", + "PUSHDATA1", + "0x04", + "0x50415353", + "ASSERTMSG" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/CALL.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/CALL.json new file mode 100644 index 0000000000..1b717c3a66 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/CALL.json @@ -0,0 +1,134 @@ +{ + "category": "Control", + "name": "CALL", + "tests": [ + { + "name": "Error negative", + "script": [ + "CALL", + "0xFF00" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Error out of bounds", + "script": [ + "CALL", + "0x0A" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "CALL", + "0x03", + "RET", + "PUSH0", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "PUSH0" + }, + { + "instructionPointer": 2, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + }, + { + "instructionPointer": 2, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/CALLA.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/CALLA.json new file mode 100644 index 0000000000..627442a5f1 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/CALLA.json @@ -0,0 +1,158 @@ +{ + "category": "Control", + "name": "CALLA", + "tests": [ + { + "name": "Wrong type", + "script": [ + "PUSH2", + "CALLA" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "CALLA", + "evaluationStack": [ + { + "type": "integer", + "value": 2 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "PUSHA", + "0x07000000", + "CALLA", + "RET", + "PUSH0", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "CALLA", + "evaluationStack": [ + { + "type": "pointer", + "value": 7 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 7, + "nextInstruction": "PUSH0" + }, + { + "instructionPointer": 6, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 8, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + }, + { + "instructionPointer": 6, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/CALL_L.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/CALL_L.json new file mode 100644 index 0000000000..5f60bda0ca --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/CALL_L.json @@ -0,0 +1,134 @@ +{ + "category": "Control", + "name": "CALL_L", + "tests": [ + { + "name": "Error negative", + "script": [ + "CALL_L", + "0x000000FF" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Error out of bounds", + "script": [ + "CALL_L", + "0x0A000000" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "CALL_L", + "0x06000000", + "RET", + "PUSH0", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "PUSH0" + }, + { + "instructionPointer": 5, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 7, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + }, + { + "instructionPointer": 5, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMP.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMP.json new file mode 100644 index 0000000000..172e50b956 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMP.json @@ -0,0 +1,74 @@ +{ + "category": "Control", + "name": "JMP", + "tests": [ + { + "name": "Out of range [<0]", + "script": [ + "JMP", + "0xff", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Out of range [>length]", + "script": [ + "JMP", + "0x7f", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "JMP", + "0x02", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPEQ.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPEQ.json new file mode 100644 index 0000000000..3e7a3144ba --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPEQ.json @@ -0,0 +1,307 @@ +{ + "category": "Control", + "name": "JMPEQ", + "tests": [ + { + "name": "Without all items", + "script": [ + "JMPEQ", + "0x00" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without one", + "script": [ + "PUSH1", + "JMPEQ", + "0x00" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [>]", + "script": [ + "PUSH1", + "PUSH0", + "JMPEQ", + "0x03", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH0", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPEQ", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "NOP" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + }, + { + "name": "Real test [==]", + "script": [ + "PUSH1", + "PUSH1", + "JMPEQ", + "0x03", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH1", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPEQ", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + }, + { + "name": "Real test [<]", + "script": [ + "PUSH0", + "PUSH1", + "JMPEQ", + "0x03", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH1", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPEQ", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "NOP" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPEQ_L.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPEQ_L.json new file mode 100644 index 0000000000..78ed4a0e70 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPEQ_L.json @@ -0,0 +1,307 @@ +{ + "category": "Control", + "name": "JMPEQ_L", + "tests": [ + { + "name": "Without all items", + "script": [ + "JMPEQ_L", + "0x00000000" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without one", + "script": [ + "PUSH1", + "JMPEQ_L", + "0x00000000" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [>]", + "script": [ + "PUSH1", + "PUSH0", + "JMPEQ_L", + "0x06000000", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH0", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPEQ_L", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 7, + "nextInstruction": "NOP" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 8, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + }, + { + "name": "Real test [==]", + "script": [ + "PUSH1", + "PUSH1", + "JMPEQ_L", + "0x06000000", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH1", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPEQ_L", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 8, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + }, + { + "name": "Real test [<]", + "script": [ + "PUSH0", + "PUSH1", + "JMPEQ_L", + "0x06000000", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH1", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPEQ_L", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 7, + "nextInstruction": "NOP" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 8, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPGE.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPGE.json new file mode 100644 index 0000000000..84f7d00c59 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPGE.json @@ -0,0 +1,293 @@ +{ + "category": "Control", + "name": "JMPGE", + "tests": [ + { + "name": "Without all items", + "script": [ + "JMPGE", + "0x00" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without one", + "script": [ + "PUSH1", + "JMPGE", + "0x00" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [>]", + "script": [ + "PUSH1", + "PUSH0", + "JMPGE", + "0x03", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH0", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPGE", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + }, + { + "name": "Real test [==]", + "script": [ + "PUSH1", + "PUSH1", + "JMPGE", + "0x03", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH1", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPGE", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + }, + { + "name": "Real test [<]", + "script": [ + "PUSH0", + "PUSH1", + "JMPGE", + "0x03", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH1", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPGE", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "NOP" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPGE_L.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPGE_L.json new file mode 100644 index 0000000000..2fa99ff25d --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPGE_L.json @@ -0,0 +1,293 @@ +{ + "category": "Control", + "name": "JMPGE_L", + "tests": [ + { + "name": "Without all items", + "script": [ + "JMPGE_L", + "0x00000000" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without one", + "script": [ + "PUSH1", + "JMPGE_L", + "0x00000000" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [>]", + "script": [ + "PUSH1", + "PUSH0", + "JMPGE_L", + "0x06000000", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH0", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPGE_L", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 8, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + }, + { + "name": "Real test [==]", + "script": [ + "PUSH1", + "PUSH1", + "JMPGE_L", + "0x06000000", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH1", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPGE_L", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 8, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + }, + { + "name": "Real test [<]", + "script": [ + "PUSH0", + "PUSH1", + "JMPGE_L", + "0x06000000", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH1", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPGE_L", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 7, + "nextInstruction": "NOP" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 8, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPGT.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPGT.json new file mode 100644 index 0000000000..c4ca491cca --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPGT.json @@ -0,0 +1,307 @@ +{ + "category": "Control", + "name": "JMPGT", + "tests": [ + { + "name": "Without all items", + "script": [ + "JMPGT", + "0x00" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without one", + "script": [ + "PUSH1", + "JMPGT", + "0x00" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [>]", + "script": [ + "PUSH1", + "PUSH0", + "JMPGT", + "0x03", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH0", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPGT", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + }, + { + "name": "Real test [==]", + "script": [ + "PUSH1", + "PUSH1", + "JMPGT", + "0x03", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH1", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPGT", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "NOP" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + }, + { + "name": "Real test [<]", + "script": [ + "PUSH0", + "PUSH1", + "JMPGT", + "0x03", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH1", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPGT", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "NOP" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPGT_L.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPGT_L.json new file mode 100644 index 0000000000..5523aa87c9 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPGT_L.json @@ -0,0 +1,307 @@ +{ + "category": "Control", + "name": "JMPGT_L", + "tests": [ + { + "name": "Without all items", + "script": [ + "JMPGT_L", + "0x00000000" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without one", + "script": [ + "PUSH1", + "JMPGT_L", + "0x00000000" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [>]", + "script": [ + "PUSH1", + "PUSH0", + "JMPGT_L", + "0x06000000", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH0", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPGT_L", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 8, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + }, + { + "name": "Real test [==]", + "script": [ + "PUSH1", + "PUSH1", + "JMPGT_L", + "0x06000000", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH1", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPGT_L", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 7, + "nextInstruction": "NOP" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 8, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + }, + { + "name": "Real test [<]", + "script": [ + "PUSH0", + "PUSH1", + "JMPGT_L", + "0x06000000", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH1", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPGT_L", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 7, + "nextInstruction": "NOP" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 8, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPIF.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPIF.json new file mode 100644 index 0000000000..121c8b76c7 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPIF.json @@ -0,0 +1,145 @@ +{ + "category": "Control", + "name": "JMPIF", + "tests": [ + { + "name": "Without items", + "script": [ + "JMPIF", + "0x00" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [1]", + "script": [ + "PUSH1", + "JMPIF", + "0x03", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "JMPIF", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + }, + { + "name": "Real test [0]", + "script": [ + "PUSH0", + "JMPIF", + "0x03", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "JMPIF", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "NOP" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPIFNOT.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPIFNOT.json new file mode 100644 index 0000000000..e11227ce40 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPIFNOT.json @@ -0,0 +1,145 @@ +{ + "category": "Control", + "name": "JMPIFNOT", + "tests": [ + { + "name": "Without items", + "script": [ + "JMPIFNOT", + "0x00" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [1]", + "script": [ + "PUSH1", + "JMPIFNOT", + "0x03", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "JMPIFNOT", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "NOP" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + }, + { + "name": "Real test [0]", + "script": [ + "PUSH0", + "JMPIFNOT", + "0x03", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "JMPIFNOT", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPIFNOT_L.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPIFNOT_L.json new file mode 100644 index 0000000000..90e37bee74 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPIFNOT_L.json @@ -0,0 +1,145 @@ +{ + "category": "Control", + "name": "JMPIFNOT_L", + "tests": [ + { + "name": "Without items", + "script": [ + "JMPIFNOT_L", + "0x00000000" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [1]", + "script": [ + "PUSH1", + "JMPIFNOT_L", + "0x06000000", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "JMPIFNOT_L", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "NOP" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 7, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + }, + { + "name": "Real test [0]", + "script": [ + "PUSH0", + "JMPIFNOT_L", + "0x06000000", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "JMPIFNOT_L", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 7, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPIF_L.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPIF_L.json new file mode 100644 index 0000000000..a9d0e1e352 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPIF_L.json @@ -0,0 +1,145 @@ +{ + "category": "Control", + "name": "JMPIF_L", + "tests": [ + { + "name": "Without items", + "script": [ + "JMPIF_L", + "0x00000000" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [1]", + "script": [ + "PUSH1", + "JMPIF_L", + "0x06000000", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "JMPIF_L", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 7, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + }, + { + "name": "Real test [0]", + "script": [ + "PUSH0", + "JMPIF_L", + "0x06000000", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "JMPIF_L", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "NOP" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 7, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPLE.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPLE.json new file mode 100644 index 0000000000..5325d60cf2 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPLE.json @@ -0,0 +1,293 @@ +{ + "category": "Control", + "name": "JMPLE", + "tests": [ + { + "name": "Without all items", + "script": [ + "JMPLE", + "0x00" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without one", + "script": [ + "PUSH1", + "JMPLE", + "0x00" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [>]", + "script": [ + "PUSH1", + "PUSH0", + "JMPLE", + "0x03", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH0", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPLE", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "NOP" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + }, + { + "name": "Real test [==]", + "script": [ + "PUSH1", + "PUSH1", + "JMPLE", + "0x03", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH1", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPLE", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + }, + { + "name": "Real test [<]", + "script": [ + "PUSH0", + "PUSH1", + "JMPLE", + "0x03", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH1", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPLE", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPLE_L.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPLE_L.json new file mode 100644 index 0000000000..3ccc3c06e8 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPLE_L.json @@ -0,0 +1,293 @@ +{ + "category": "Control", + "name": "JMPLE_L", + "tests": [ + { + "name": "Without all items", + "script": [ + "JMPLE_L", + "0x00000000" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without one", + "script": [ + "PUSH1", + "JMPLE_L", + "0x00000000" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [>]", + "script": [ + "PUSH1", + "PUSH0", + "JMPLE_L", + "0x06000000", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH0", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPLE_L", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 7, + "nextInstruction": "NOP" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 8, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + }, + { + "name": "Real test [==]", + "script": [ + "PUSH1", + "PUSH1", + "JMPLE_L", + "0x06000000", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH1", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPLE_L", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 8, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + }, + { + "name": "Real test [<]", + "script": [ + "PUSH0", + "PUSH1", + "JMPLE_L", + "0x06000000", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH1", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPLE_L", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 8, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPLT.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPLT.json new file mode 100644 index 0000000000..72946b6c6a --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPLT.json @@ -0,0 +1,307 @@ +{ + "category": "Control", + "name": "JMPLT", + "tests": [ + { + "name": "Without all items", + "script": [ + "JMPLT", + "0x00" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without one", + "script": [ + "PUSH1", + "JMPLT", + "0x00" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [>]", + "script": [ + "PUSH1", + "PUSH0", + "JMPLT", + "0x03", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH0", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPLT", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "NOP" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + }, + { + "name": "Real test [==]", + "script": [ + "PUSH1", + "PUSH1", + "JMPLT", + "0x03", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH1", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPLT", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "NOP" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + }, + { + "name": "Real test [<]", + "script": [ + "PUSH0", + "PUSH1", + "JMPLT", + "0x03", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH1", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPLT", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPLT_L.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPLT_L.json new file mode 100644 index 0000000000..196b455d0a --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPLT_L.json @@ -0,0 +1,307 @@ +{ + "category": "Control", + "name": "JMPLT_L", + "tests": [ + { + "name": "Without all items", + "script": [ + "JMPLT_L", + "0x00000000" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without one", + "script": [ + "PUSH1", + "JMPLT_L", + "0x00000000" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [>]", + "script": [ + "PUSH1", + "PUSH0", + "JMPLT_L", + "0x06000000", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH0", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPLT_L", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 7, + "nextInstruction": "NOP" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 8, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + }, + { + "name": "Real test [==]", + "script": [ + "PUSH1", + "PUSH1", + "JMPLT_L", + "0x06000000", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH1", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPLT_L", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 7, + "nextInstruction": "NOP" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 8, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + }, + { + "name": "Real test [<]", + "script": [ + "PUSH0", + "PUSH1", + "JMPLT_L", + "0x06000000", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH1", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPLT_L", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 8, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPNE.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPNE.json new file mode 100644 index 0000000000..53498bc05b --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPNE.json @@ -0,0 +1,293 @@ +{ + "category": "Control", + "name": "JMPNE", + "tests": [ + { + "name": "Without all items", + "script": [ + "JMPNE", + "0x00" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without one", + "script": [ + "PUSH1", + "JMPNE", + "0x00" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [>]", + "script": [ + "PUSH1", + "PUSH0", + "JMPNE", + "0x03", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH0", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPNE", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + }, + { + "name": "Real test [==]", + "script": [ + "PUSH1", + "PUSH1", + "JMPNE", + "0x03", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH1", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPNE", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "NOP" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + }, + { + "name": "Real test [<]", + "script": [ + "PUSH0", + "PUSH1", + "JMPNE", + "0x03", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH1", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPNE", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPNE_L.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPNE_L.json new file mode 100644 index 0000000000..a1adb96021 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMPNE_L.json @@ -0,0 +1,293 @@ +{ + "category": "Control", + "name": "JMPNE_L", + "tests": [ + { + "name": "Without all items", + "script": [ + "JMPNE_L", + "0x00000000" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without one", + "script": [ + "PUSH1", + "JMPNE_L", + "0x00000000" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [>]", + "script": [ + "PUSH1", + "PUSH0", + "JMPNE_L", + "0x06000000", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH0", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPNE_L", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 8, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + }, + { + "name": "Real test [==]", + "script": [ + "PUSH1", + "PUSH1", + "JMPNE_L", + "0x06000000", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH1", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPNE_L", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 7, + "nextInstruction": "NOP" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 8, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + }, + { + "name": "Real test [<]", + "script": [ + "PUSH0", + "PUSH1", + "JMPNE_L", + "0x06000000", + "NOP", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "PUSH1", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "JMPNE_L", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 8, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMP_L.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMP_L.json new file mode 100644 index 0000000000..4f6157d1de --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/JMP_L.json @@ -0,0 +1,74 @@ +{ + "category": "Control", + "name": "JMP_L", + "tests": [ + { + "name": "Out of range [<0]", + "script": [ + "JMP_L", + "0xffffffff", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Out of range [>length]", + "script": [ + "JMP_L", + "0xffffff7f", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "JMP_L", + "0x05000000", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/NOP.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/NOP.json new file mode 100644 index 0000000000..3564f8afa2 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/NOP.json @@ -0,0 +1,96 @@ +{ + "category": "Control", + "name": "NOP", + "tests": [ + { + "name": "Real test", + "script": [ + "NOP", + "NOP", + "NOP", + "NOP", + "NOP" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "NOP" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "NOP" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "NOP" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "NOP" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/RET.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/RET.json new file mode 100644 index 0000000000..993f8af213 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/RET.json @@ -0,0 +1,22 @@ +{ + "category": "Control", + "name": "RET", + "tests": [ + { + "name": "Real test", + "script": [ + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/SYSCALL.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/SYSCALL.json new file mode 100644 index 0000000000..c99da78b24 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/SYSCALL.json @@ -0,0 +1,143 @@ +{ + "category": "Control", + "name": "SYSCALL", + "tests": [ + { + "name": "Syscall that does not exist", + "script": [ + "SYSCALL", + "0x00" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Wrong script", + "script": [ + "SYSCALL", + "0x2a537973", + "DEPTH", + "CALL_L", + "0x6d2e0000", + "PUSHDATA1", + "0x457865637574696f6e456e67696e652e476574536372697074436f6e7461696e6572" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [IMessageProvider]", + "script": [ + "SYSCALL", + "0x77777777" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "interop", + "value": "Object" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "interop", + "value": "Object" + } + ] + } + } + ] + }, + { + "name": "Wrong script", + "script": [ + "SYSCALL", + "0xfdffff00" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Wrong script", + "script": [ + "SYSCALL", + "0xfeffffff", + "0xff", + "PUSH0" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Wrong script", + "script": [ + "SYSCALL", + "0xffffffff", + "0xffffffffff", + "PUSH0" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/THROW.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/THROW.json new file mode 100644 index 0000000000..a382516154 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/THROW.json @@ -0,0 +1,24 @@ +{ + "category": "Control", + "name": "THROW", + "tests": [ + { + "name": "Fault Test", + "script": [ + "PUSH0", + "THROW" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH.json new file mode 100644 index 0000000000..d08f084d95 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH.json @@ -0,0 +1,175 @@ +{ + "category": "Control", + "name": "TRY_CATCH", + "tests": [ + { + "name": "try catch with syscall exception", + "script": [ + "TRY", + "0x0a00", + "SYSCALL", + "0xdeaddead", + "ENDTRY", + "0x05", + "PUSH1", + "ENDTRY", + "0x02", + "PUSH2" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 11, + "nextInstruction": "ENDTRY", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "ByteString", + "value": "0x6572726f72" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + }, + { + "type": "ByteString", + "value": "0x6572726f72" + } + ] + } + } + ] + }, + { + "name": "try catch without exception", + "script": [ + "TRY", + "0x0600", + "PUSH0", + "ENDTRY", + "0x05", + "PUSH3", + "ENDTRY", + "0x02", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 9, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + } + ] + }, + { + "name": "try catch with exception", + "script": [ + "TRY", + "0x0700", + "PUSH0", + "THROW", + "ENDTRY", + "0x05", + "PUSH1", + "ENDTRY", + "0x02", + "PUSH2" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 7, + "nextInstruction": "PUSH1", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 10, + "nextInstruction": "PUSH2", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH_FINALLY.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH_FINALLY.json new file mode 100644 index 0000000000..769829fc3d --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH_FINALLY.json @@ -0,0 +1,72 @@ +{ + "category": "Control", + "name": "TRY_CATCH_FINALLY", + "tests": [ + { + "name": "try catch finally without exception", + "script": [ + "TRY", + "0x080a", + "PUSH0", + "ENDTRY", + "0x08", + "RET", + "PUSH2", + "ENDTRY", + "0x04", + "PUSH3", + "ENDFINALLY", + "PUSH4" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 10, + "nextInstruction": "PUSH3", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 12, + "nextInstruction": "PUSH4", + "evaluationStack": [ + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH_FINALLY10.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH_FINALLY10.json new file mode 100644 index 0000000000..fae60b985f --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH_FINALLY10.json @@ -0,0 +1,25 @@ +{ + "category": "Control", + "name": "TRY_CATCH_FINALLY", + "tests": [ + { + "name": "try + finally without ENDTRY", + "script": [ + "TRY", + "0x0003", + "ENDFINALLY" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH_FINALLY2.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH_FINALLY2.json new file mode 100644 index 0000000000..37299f2423 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH_FINALLY2.json @@ -0,0 +1,103 @@ +{ + "category": "Control", + "name": "TRY_CATCH_FINALLY", + "tests": [ + { + "name": "try catch finally with exception", + "script": [ + "TRY", + "0x080C", + "PUSH0", + "THROW", + "ENDTRY", + "0x06", + "RET", + "PUSH1", + "ENDTRY", + "0x02", + "RET", + "PUSH2", + "ENDFINALLY", + "PUSH3" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 8, + "nextInstruction": "PUSH1", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 12, + "nextInstruction": "PUSH2", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 11, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH_FINALLY3.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH_FINALLY3.json new file mode 100644 index 0000000000..b6cd601ff2 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH_FINALLY3.json @@ -0,0 +1,111 @@ +{ + "category": "Control", + "name": "TRY_CATCH_FINALLY", + "tests": [ + { + "name": "try{ try{ throw }catch{ }}catch{ }finally{ }", + "script": [ + "TRY", + "0x0e13", + "TRY", + "0x0700", + "PUSH0", + "THROW", + "ENDTRY", + "0x01", + "PUSH1", + "ENDTRY", + "0x02", + "ENDTRY", + "0x02", + "RET", + "PUSH2", + "ENDTRY", + "0x04", + "PUSH3", + "ENDFINALLY", + "PUSH4" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 10, + "nextInstruction": "PUSH1", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 13, + "nextInstruction": "ENDTRY", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 15, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH_FINALLY4.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH_FINALLY4.json new file mode 100644 index 0000000000..710cadb12c --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH_FINALLY4.json @@ -0,0 +1,117 @@ +{ + "category": "Control", + "name": "TRY_CATCH_FINALLY", + "tests": [ + { + "name": "try{ try{ throw }catch{ throw } }catch{ }finally{ }", + "script": [ + "TRY", + "0x1014", + "TRY", + "0x0700", + "PUSH0", + "THROW", + "ENDTRY", + "0x01", + "PUSH1", + "THROW", + "ENDTRY", + "0x04", + "ENDTRY", + "0x01", + "PUSH2", + "ENDTRY", + "0x02", + "RET", + "PUSH3", + "ENDFINALLY", + "PUSH4" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 10, + "nextInstruction": "PUSH1", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 16, + "nextInstruction": "PUSH2", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 19, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH_FINALLY5.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH_FINALLY5.json new file mode 100644 index 0000000000..6cb08caa3c --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH_FINALLY5.json @@ -0,0 +1,35 @@ +{ + "category": "Control", + "name": "TRY_CATCH_FINALLY", + "tests": [ + { + "name": "try{ assert false }catch{ push2 }finally{ push3 }", + "script": [ + "TRY", + "0x0608", + "PUSH0", + "ASSERT", + "ENDTRY", + "0x01", + "PUSH2", + "ENDTRY", + "0x01", + "PUSH3", + "ENDFINALLY", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH_FINALLY6.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH_FINALLY6.json new file mode 100644 index 0000000000..40b5bf2667 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH_FINALLY6.json @@ -0,0 +1,33 @@ +{ + "category": "Control", + "name": "TRY_CATCH_FINALLY", + "tests": [ + { + "name": "try{ abort }catch{ push2 }finally{ push3 }", + "script": [ + "TRY", + "0x0507", + "ABORT", + "ENDTRY", + "0x01", + "PUSH2", + "ENDTRY", + "0x01", + "PUSH3", + "ENDFINALLY", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH_FINALLY7.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH_FINALLY7.json new file mode 100644 index 0000000000..766e88f839 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH_FINALLY7.json @@ -0,0 +1,55 @@ +{ + "category": "Control", + "name": "TRY_CATCH_FINALLY", + "tests": [ + { + "name": "try{ throw }catch{ abort }finally{ push3 }", + "script": [ + "TRY", + "0x070a", + "PUSH0", + "THROW", + "ENDTRY", + "0x01", + "ABORT", + "ENDTRY", + "0x01", + "PUSH3", + "ENDFINALLY", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer":7, + "nextInstruction": "ABORT", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH_FINALLY8.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH_FINALLY8.json new file mode 100644 index 0000000000..93f2f84c26 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH_FINALLY8.json @@ -0,0 +1,101 @@ +{ + "category": "Control", + "name": "TRY_CATCH_FINALLY", + "tests": [ + { + "name": "try{ throw }catch{ throw }finally{ push3 }", + "script": [ + "TRY", + "0x070b", + "PUSH0", + "THROW", + "ENDTRY", + "0x01", + "PUSH2", + "THROW", + "ENDTRY", + "0x01", + "PUSH3", + "ENDFINALLY", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 7, + "nextInstruction": "PUSH2", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 11, + "nextInstruction": "PUSH3", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 12, + "nextInstruction": "ENDFINALLY", + "evaluationStack": [ + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH_FINALLY9.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH_FINALLY9.json new file mode 100644 index 0000000000..fe766a025a --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_CATCH_FINALLY9.json @@ -0,0 +1,98 @@ +{ + "category": "Control", + "name": "TRY_CATCH_FINALLY", + "tests": [ + { + "name": "try{ PUSH0, call A: PUSH1 { call B: PUSH2 throw an exception } }catch{ PUSH3 }", + "script": [ + "TRY", + "0x0f00", + "PUSH0", + "CALL", + "0x03", + "RET", + "PUSH1", + "CALL", + "0x02", + "PUSH2", + "THROW", + "RET", + "ENDTRY", + "0x01", + "PUSH3", + "ENDTRY", + "0x02", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 15, + "nextInstruction": "PUSH3", + "evaluationStack": [ + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 18, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_FINALLY.json b/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_FINALLY.json new file mode 100644 index 0000000000..abb4788a32 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Control/TRY_FINALLY.json @@ -0,0 +1,49 @@ +{ + "category": "Control", + "name": "TRY_FINALLY", + "tests": [ + { + "name": "try finally with exception", + "script": [ + "TRY", + "0x0009", + "PUSH0", + "THROW", + "ENDTRY", + "0x01", + "JMP", + "0x03", + "PUSH1", + "ENDFINALLY", + "PUSH2" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 9, + "nextInstruction": "PUSH1" + } + ] + } + }, + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Push/PUSHA.json b/tests/Neo.VM.Tests/Tests/OpCodes/Push/PUSHA.json new file mode 100644 index 0000000000..c6a0bf4c4f --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Push/PUSHA.json @@ -0,0 +1,86 @@ +{ + "category": "Push", + "name": "PUSHA", + "tests": [ + { + "name": "Out of range [-1]", + "script": [ + "PUSHA", + "0xffffffff" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Out of range [>length]", + "script": [ + "PUSHA", + "0xffffff7f" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "PUSHA", + "0x00000000" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "pointer", + "value": 0 + } + ] + } + } + ] + }, + { + "name": "Real test [=length]", + "script": [ + "PUSHA", + "0x05000000" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "pointer", + "value": 5 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Push/PUSHDATA1.json b/tests/Neo.VM.Tests/Tests/OpCodes/Push/PUSHDATA1.json new file mode 100644 index 0000000000..5831718b95 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Push/PUSHDATA1.json @@ -0,0 +1,47 @@ +{ + "category": "Push", + "name": "PUSHDATA1", + "tests": [ + { + "name": "Good definition", + "script": [ + "PUSHDATA1", + "0x04", + "0x01020304" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "ByteString", + "value": "0x01020304" + } + ] + } + } + ] + }, + { + "name": "Without enough length", + "script": [ + "PUSHDATA1", + "0x0501020304" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Push/PUSHDATA2.json b/tests/Neo.VM.Tests/Tests/OpCodes/Push/PUSHDATA2.json new file mode 100644 index 0000000000..b31e47fb74 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Push/PUSHDATA2.json @@ -0,0 +1,47 @@ +{ + "category": "Push", + "name": "PUSHDATA2", + "tests": [ + { + "name": "Good definition", + "script": [ + "PUSHDATA2", + "0x0400", + "0x01020304" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "ByteString", + "value": "0x01020304" + } + ] + } + } + ] + }, + { + "name": "Without enough length", + "script": [ + "PUSHDATA2", + "0x050001020304" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Push/PUSHDATA4.json b/tests/Neo.VM.Tests/Tests/OpCodes/Push/PUSHDATA4.json new file mode 100644 index 0000000000..d61a42b3a4 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Push/PUSHDATA4.json @@ -0,0 +1,99 @@ +{ + "category": "Push", + "name": "PUSHDATA4", + "tests": [ + { + "name": "More length than script", + "script": [ + "PUSHDATA4", + "0x00080000" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Negative length", + "script": [ + "PUSHDATA4", + "0xffffffff" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Good definition", + "script": [ + "PUSHDATA4", + "0x04000000", + "0x01020304" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "ByteString", + "value": "0x01020304" + } + ] + } + } + ] + }, + { + "name": "Without enough length", + "script": [ + "PUSHDATA4", + "0x0500000001020304" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Max length (Parse Instruction Error)", + "script": [ + "PUSHDATA4", + "0x01001000", + "0xFF" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Push/PUSHINT8_to_PUSHINT256.json b/tests/Neo.VM.Tests/Tests/OpCodes/Push/PUSHINT8_to_PUSHINT256.json new file mode 100644 index 0000000000..72cca284bb --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Push/PUSHINT8_to_PUSHINT256.json @@ -0,0 +1,59 @@ +{ + "category": "Push", + "name": "PUSHINT8 to PUSHINT256", + "tests": [ + { + "name": "Basic Test", + "script": [ + "PUSHINT8", + "0xff", + "PUSHINT16", + "0xfeff", + "PUSHINT32", + "0xfdffffff", + "PUSHINT64", + "0xfcffffffffffffff", + "PUSHINT128", + "0xfbffffffffffffffffffffffffffffff", + "PUSHINT256", + "0xfaffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": -6 + }, + { + "type": "integer", + "value": -5 + }, + { + "type": "integer", + "value": -4 + }, + { + "type": "integer", + "value": -3 + }, + { + "type": "integer", + "value": -2 + }, + { + "type": "integer", + "value": -1 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Push/PUSHM1_to_PUSH16.json b/tests/Neo.VM.Tests/Tests/OpCodes/Push/PUSHM1_to_PUSH16.json new file mode 100644 index 0000000000..3b7f06ed6b --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Push/PUSHM1_to_PUSH16.json @@ -0,0 +1,219 @@ +{ + "category": "Push", + "name": "From PUSHM1 to PUSH16 [-1 to 16]", + "tests": [ + { + "name": "Basic Test", + "script": [ + "PUSHM1", + "PUSH0", + "PUSH1", + "PUSH2", + "PUSH3", + "PUSH4", + "PUSH5", + "PUSH6", + "PUSH7", + "PUSH8", + "PUSH9", + "PUSH10", + "PUSH11", + "PUSH12", + "PUSH13", + "PUSH14", + "PUSH15", + "PUSH16", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 18, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 16 + }, + { + "type": "integer", + "value": 15 + }, + { + "type": "integer", + "value": 14 + }, + { + "type": "integer", + "value": 13 + }, + { + "type": "integer", + "value": 12 + }, + { + "type": "integer", + "value": 11 + }, + { + "type": "integer", + "value": 10 + }, + { + "type": "integer", + "value": 9 + }, + { + "type": "integer", + "value": 8 + }, + { + "type": "integer", + "value": 7 + }, + { + "type": "integer", + "value": 6 + }, + { + "type": "integer", + "value": 5 + }, + { + "type": "integer", + "value": 4 + }, + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 0 + }, + { + "type": "integer", + "value": -1 + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 16 + }, + { + "type": "integer", + "value": 15 + }, + { + "type": "integer", + "value": 14 + }, + { + "type": "integer", + "value": 13 + }, + { + "type": "integer", + "value": 12 + }, + { + "type": "integer", + "value": 11 + }, + { + "type": "integer", + "value": 10 + }, + { + "type": "integer", + "value": 9 + }, + { + "type": "integer", + "value": 8 + }, + { + "type": "integer", + "value": 7 + }, + { + "type": "integer", + "value": 6 + }, + { + "type": "integer", + "value": 5 + }, + { + "type": "integer", + "value": 4 + }, + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 0 + }, + { + "type": "integer", + "value": -1 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Push/PUSHNULL.json b/tests/Neo.VM.Tests/Tests/OpCodes/Push/PUSHNULL.json new file mode 100644 index 0000000000..5b5247edb1 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Push/PUSHNULL.json @@ -0,0 +1,46 @@ +{ + "category": "Push", + "name": "PUSHNULL", + "tests": [ + { + "name": "Good definition", + "script": [ + "PUSHNULL" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "null" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "null" + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/INITSLOT.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/INITSLOT.json new file mode 100644 index 0000000000..458463ea55 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/INITSLOT.json @@ -0,0 +1,206 @@ +{ + "category": "Slot", + "name": "INITSLOT", + "tests": [ + { + "name": "Without enough items", + "script": [ + "INITSLOT", + "0x0101" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without 0 items", + "script": [ + "INITSLOT", + "0x0000" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [LocalVariables]", + "script": [ + "INITSLOT", + "0x0100" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "localVariables": [ + { + "type": "Null" + } + ] + } + ] + } + }, + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT" + } + } + ] + }, + { + "name": "Real test [Arguments]", + "script": [ + "PUSH1", + "INITSLOT", + "0x0001" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "RET", + "arguments": [ + { + "type": "Integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT" + } + } + ] + }, + { + "name": "Real test [LocalVariables + Arguments]", + "script": [ + "PUSH1", + "INITSLOT", + "0x0101" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "RET", + "localVariables": [ + { + "type": "Null" + } + ], + "arguments": [ + { + "type": "Integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT" + } + } + ] + }, + { + "name": "Initialize twice", + "script": [ + "PUSH0", + "INITSLOT", + "0x0101", + "PUSH0", + "INITSLOT", + "0x0101" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "PUSH0", + "localVariables": [ + { + "type": "Null" + } + ], + "arguments": [ + { + "type": "Integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/INITSSLOT.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/INITSSLOT.json new file mode 100644 index 0000000000..e3a3e149f4 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/INITSSLOT.json @@ -0,0 +1,97 @@ +{ + "category": "Slot", + "name": "INITSSLOT", + "tests": [ + { + "name": "Without 0 items", + "script": [ + "INITSSLOT", + "0x00" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "INITSSLOT", + "0x01" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "RET", + "staticFields": [ + { + "type": "Null" + } + ] + } + ] + } + }, + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT" + } + } + ] + }, + { + "name": "Initialize twice", + "script": [ + "INITSSLOT", + "0x01", + "INITSSLOT", + "0x02" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "INITSSLOT", + "staticFields": [ + { + "type": "Null" + } + ] + } + ] + } + }, + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDARG.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDARG.json new file mode 100644 index 0000000000..e3be41d38c --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDARG.json @@ -0,0 +1,69 @@ +{ + "category": "Slot", + "name": "LDARG", + "tests": [ + { + "name": "Without slot", + "script": [ + "LDARG", + "0x00" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Index out of range", + "script": [ + "PUSH1", + "INITSLOT", + "0x0001", + "LDARG", + "0x01" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "PUSH1", + "INITSLOT", + "0x0001", + "LDARG", + "0x00" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDARG0.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDARG0.json new file mode 100644 index 0000000000..038e8db3a6 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDARG0.json @@ -0,0 +1,47 @@ +{ + "category": "Slot", + "name": "LDARG0", + "tests": [ + { + "name": "Without slot", + "script": [ + "LDARG0" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "PUSH1", + "INITSLOT", + "0x0001", + "LDARG0" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDARG1.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDARG1.json new file mode 100644 index 0000000000..522b1e68ac --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDARG1.json @@ -0,0 +1,67 @@ +{ + "category": "Slot", + "name": "LDARG1", + "tests": [ + { + "name": "Without slot", + "script": [ + "LDARG1" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Index out of range", + "script": [ + "PUSH1", + "INITSLOT", + "0x0001", + "LDARG1" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "PUSH1", + "PUSH2", + "INITSLOT", + "0x0002", + "LDARG1" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDARG2.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDARG2.json new file mode 100644 index 0000000000..16ec5d743d --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDARG2.json @@ -0,0 +1,68 @@ +{ + "category": "Slot", + "name": "LDARG2", + "tests": [ + { + "name": "Without slot", + "script": [ + "LDARG2" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Index out of range", + "script": [ + "PUSH1", + "INITSLOT", + "0x0001", + "LDARG2" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "PUSH1", + "PUSH2", + "PUSH3", + "INITSLOT", + "0x0003", + "LDARG2" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDARG3.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDARG3.json new file mode 100644 index 0000000000..5a4a844a1b --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDARG3.json @@ -0,0 +1,69 @@ +{ + "category": "Slot", + "name": "LDARG3", + "tests": [ + { + "name": "Without slot", + "script": [ + "LDARG3" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Index out of range", + "script": [ + "PUSH1", + "INITSLOT", + "0x0001", + "LDARG3" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "PUSH1", + "PUSH2", + "PUSH3", + "PUSH4", + "INITSLOT", + "0x0004", + "LDARG3" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDARG4.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDARG4.json new file mode 100644 index 0000000000..4a091e5ff2 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDARG4.json @@ -0,0 +1,70 @@ +{ + "category": "Slot", + "name": "LDARG4", + "tests": [ + { + "name": "Without slot", + "script": [ + "LDARG4" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Index out of range", + "script": [ + "PUSH1", + "INITSLOT", + "0x0001", + "LDARG4" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "PUSH1", + "PUSH2", + "PUSH3", + "PUSH4", + "PUSH5", + "INITSLOT", + "0x0005", + "LDARG4" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDARG5.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDARG5.json new file mode 100644 index 0000000000..1d0d706266 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDARG5.json @@ -0,0 +1,71 @@ +{ + "category": "Slot", + "name": "LDARG5", + "tests": [ + { + "name": "Without slot", + "script": [ + "LDARG5" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Index out of range", + "script": [ + "PUSH1", + "INITSLOT", + "0x0001", + "LDARG5" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "PUSH1", + "PUSH2", + "PUSH3", + "PUSH4", + "PUSH5", + "PUSH6", + "INITSLOT", + "0x0006", + "LDARG5" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDARG6.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDARG6.json new file mode 100644 index 0000000000..56da5d948b --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDARG6.json @@ -0,0 +1,72 @@ +{ + "category": "Slot", + "name": "LDARG6", + "tests": [ + { + "name": "Without slot", + "script": [ + "LDARG6" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Index out of range", + "script": [ + "PUSH1", + "INITSLOT", + "0x0001", + "LDARG6" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "PUSH1", + "PUSH2", + "PUSH3", + "PUSH4", + "PUSH5", + "PUSH6", + "PUSH7", + "INITSLOT", + "0x0007", + "LDARG6" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDLOC.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDLOC.json new file mode 100644 index 0000000000..87f165dbdf --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDLOC.json @@ -0,0 +1,70 @@ +{ + "category": "Slot", + "name": "LDLOC", + "tests": [ + { + "name": "Without slot", + "script": [ + "LDLOC", + "0x00" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Index out of range", + "script": [ + "INITSLOT", + "0x0100", + "LDLOC", + "0x01" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "INITSLOT", + "0x0100", + "PUSH1", + "STLOC", + "0x00", + "LDLOC", + "0x00" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDLOC0.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDLOC0.json new file mode 100644 index 0000000000..294a7b8df0 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDLOC0.json @@ -0,0 +1,48 @@ +{ + "category": "Slot", + "name": "LDLOC0", + "tests": [ + { + "name": "Without slot", + "script": [ + "LDLOC0" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "INITSLOT", + "0x0100", + "PUSH1", + "STLOC0", + "LDLOC0" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDLOC1.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDLOC1.json new file mode 100644 index 0000000000..f9e648200a --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDLOC1.json @@ -0,0 +1,66 @@ +{ + "category": "Slot", + "name": "LDLOC1", + "tests": [ + { + "name": "Without slot", + "script": [ + "LDLOC1" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Index out of range", + "script": [ + "INITSLOT", + "0x0100", + "LDLOC1" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "INITSLOT", + "0x0200", + "PUSH1", + "STLOC1", + "LDLOC1" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDLOC2.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDLOC2.json new file mode 100644 index 0000000000..075f338683 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDLOC2.json @@ -0,0 +1,66 @@ +{ + "category": "Slot", + "name": "LDLOC2", + "tests": [ + { + "name": "Without slot", + "script": [ + "LDLOC2" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Index out of range", + "script": [ + "INITSLOT", + "0x0100", + "LDLOC2" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "INITSLOT", + "0x0300", + "PUSH1", + "STLOC2", + "LDLOC2" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDLOC3.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDLOC3.json new file mode 100644 index 0000000000..5463edaebc --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDLOC3.json @@ -0,0 +1,66 @@ +{ + "category": "Slot", + "name": "LDLOC3", + "tests": [ + { + "name": "Without slot", + "script": [ + "LDLOC3" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Index out of range", + "script": [ + "INITSLOT", + "0x0100", + "LDLOC3" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "INITSLOT", + "0x0400", + "PUSH1", + "STLOC3", + "LDLOC3" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDLOC4.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDLOC4.json new file mode 100644 index 0000000000..23a616975d --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDLOC4.json @@ -0,0 +1,66 @@ +{ + "category": "Slot", + "name": "LDLOC4", + "tests": [ + { + "name": "Without slot", + "script": [ + "LDLOC4" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Index out of range", + "script": [ + "INITSLOT", + "0x0100", + "LDLOC4" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "INITSLOT", + "0x0500", + "PUSH1", + "STLOC4", + "LDLOC4" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDLOC5.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDLOC5.json new file mode 100644 index 0000000000..9bde0a550a --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDLOC5.json @@ -0,0 +1,66 @@ +{ + "category": "Slot", + "name": "LDLOC5", + "tests": [ + { + "name": "Without slot", + "script": [ + "LDLOC5" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Index out of range", + "script": [ + "INITSLOT", + "0x0100", + "LDLOC5" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "INITSLOT", + "0x0600", + "PUSH1", + "STLOC5", + "LDLOC5" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDLOC6.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDLOC6.json new file mode 100644 index 0000000000..edf7963263 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDLOC6.json @@ -0,0 +1,66 @@ +{ + "category": "Slot", + "name": "LDLOC6", + "tests": [ + { + "name": "Without slot", + "script": [ + "LDLOC6" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Index out of range", + "script": [ + "INITSLOT", + "0x0100", + "LDLOC6" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "INITSLOT", + "0x0700", + "PUSH1", + "STLOC6", + "LDLOC6" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDSFLD.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDSFLD.json new file mode 100644 index 0000000000..311c0a5964 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDSFLD.json @@ -0,0 +1,70 @@ +{ + "category": "Slot", + "name": "LDSFLD", + "tests": [ + { + "name": "Without slot", + "script": [ + "LDSFLD", + "0x00" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Index out of range", + "script": [ + "INITSSLOT", + "0x01", + "LDSFLD", + "0x01" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "INITSSLOT", + "0x01", + "PUSH1", + "STSFLD", + "0x00", + "LDSFLD", + "0x00" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDSFLD0.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDSFLD0.json new file mode 100644 index 0000000000..8a750b04f2 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDSFLD0.json @@ -0,0 +1,48 @@ +{ + "category": "Slot", + "name": "LDSFLD0", + "tests": [ + { + "name": "Without slot", + "script": [ + "LDSFLD0" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "INITSSLOT", + "0x01", + "PUSH1", + "STSFLD0", + "LDSFLD0" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDSFLD1.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDSFLD1.json new file mode 100644 index 0000000000..4289e1aa91 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDSFLD1.json @@ -0,0 +1,66 @@ +{ + "category": "Slot", + "name": "LDSFLD1", + "tests": [ + { + "name": "Without slot", + "script": [ + "LDSFLD1" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Index out of range", + "script": [ + "INITSSLOT", + "0x01", + "LDSFLD1" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "INITSSLOT", + "0x02", + "PUSH1", + "STSFLD1", + "LDSFLD1" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDSFLD2.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDSFLD2.json new file mode 100644 index 0000000000..e03ab04d48 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDSFLD2.json @@ -0,0 +1,66 @@ +{ + "category": "Slot", + "name": "LDSFLD2", + "tests": [ + { + "name": "Without slot", + "script": [ + "LDSFLD2" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Index out of range", + "script": [ + "INITSSLOT", + "0x01", + "LDSFLD2" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "INITSSLOT", + "0x03", + "PUSH1", + "STSFLD2", + "LDSFLD2" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDSFLD3.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDSFLD3.json new file mode 100644 index 0000000000..d10624f5a7 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDSFLD3.json @@ -0,0 +1,66 @@ +{ + "category": "Slot", + "name": "LDSFLD3", + "tests": [ + { + "name": "Without slot", + "script": [ + "LDSFLD3" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Index out of range", + "script": [ + "INITSSLOT", + "0x01", + "LDSFLD3" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "INITSSLOT", + "0x04", + "PUSH1", + "STSFLD3", + "LDSFLD3" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDSFLD4.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDSFLD4.json new file mode 100644 index 0000000000..b405defe0f --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDSFLD4.json @@ -0,0 +1,66 @@ +{ + "category": "Slot", + "name": "LDSFLD4", + "tests": [ + { + "name": "Without slot", + "script": [ + "LDSFLD4" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Index out of range", + "script": [ + "INITSSLOT", + "0x01", + "LDSFLD4" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "INITSSLOT", + "0x05", + "PUSH1", + "STSFLD4", + "LDSFLD4" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDSFLD5.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDSFLD5.json new file mode 100644 index 0000000000..c6b3ee058f --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDSFLD5.json @@ -0,0 +1,66 @@ +{ + "category": "Slot", + "name": "LDSFLD5", + "tests": [ + { + "name": "Without slot", + "script": [ + "LDSFLD5" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Index out of range", + "script": [ + "INITSSLOT", + "0x01", + "LDSFLD5" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "INITSSLOT", + "0x06", + "PUSH1", + "STSFLD5", + "LDSFLD5" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDSFLD6.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDSFLD6.json new file mode 100644 index 0000000000..cd7ae9b500 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/LDSFLD6.json @@ -0,0 +1,66 @@ +{ + "category": "Slot", + "name": "LDSFLD6", + "tests": [ + { + "name": "Without slot", + "script": [ + "LDSFLD6" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Index out of range", + "script": [ + "INITSSLOT", + "0x01", + "LDSFLD6" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "INITSSLOT", + "0x07", + "PUSH1", + "STSFLD6", + "LDSFLD6" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STARG.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STARG.json new file mode 100644 index 0000000000..bdf9f2f5c5 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STARG.json @@ -0,0 +1,72 @@ +{ + "category": "Slot", + "name": "STARG", + "tests": [ + { + "name": "Without slot", + "script": [ + "PUSH1", + "STARG", + "0x00" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Index out of range", + "script": [ + "PUSH0", + "INITSLOT", + "0x0001", + "PUSH1", + "STARG", + "0x01" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "PUSH1", + "INITSLOT", + "0x0001", + "PUSH0", + "STARG", + "0x00" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "arguments": [ + { + "type": "Integer", + "value": 0 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STARG0.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STARG0.json new file mode 100644 index 0000000000..b5666c3754 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STARG0.json @@ -0,0 +1,49 @@ +{ + "category": "Slot", + "name": "STARG0", + "tests": [ + { + "name": "Without slot", + "script": [ + "PUSH1", + "STARG0" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "PUSH0", + "INITSLOT", + "0x0001", + "PUSH1", + "STARG0" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "arguments": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STARG1.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STARG1.json new file mode 100644 index 0000000000..da52006943 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STARG1.json @@ -0,0 +1,74 @@ +{ + "category": "Slot", + "name": "STARG1", + "tests": [ + { + "name": "Without slot", + "script": [ + "PUSH1", + "STARG1" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Index out of range", + "script": [ + "PUSH0", + "INITSLOT", + "0x0001", + "PUSH1", + "STARG1" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "PUSH1", + "PUSH2", + "INITSLOT", + "0x0002", + "PUSH0", + "STARG1" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "arguments": [ + { + "type": "Integer", + "value": 1 + }, + { + "type": "Integer", + "value": 0 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STARG2.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STARG2.json new file mode 100644 index 0000000000..8c6952eedd --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STARG2.json @@ -0,0 +1,79 @@ +{ + "category": "Slot", + "name": "STARG2", + "tests": [ + { + "name": "Without slot", + "script": [ + "PUSH1", + "STARG2" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Index out of range", + "script": [ + "PUSH0", + "INITSLOT", + "0x0001", + "PUSH1", + "STARG2" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "PUSH1", + "PUSH2", + "PUSH3", + "INITSLOT", + "0x0003", + "PUSH0", + "STARG2" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "arguments": [ + { + "type": "Integer", + "value": 1 + }, + { + "type": "Integer", + "value": 2 + }, + { + "type": "Integer", + "value": 0 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STARG3.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STARG3.json new file mode 100644 index 0000000000..e8ed64b00d --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STARG3.json @@ -0,0 +1,84 @@ +{ + "category": "Slot", + "name": "STARG3", + "tests": [ + { + "name": "Without slot", + "script": [ + "PUSH1", + "STARG3" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Index out of range", + "script": [ + "PUSH0", + "INITSLOT", + "0x0001", + "PUSH1", + "STARG3" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "PUSH1", + "PUSH2", + "PUSH3", + "PUSH4", + "INITSLOT", + "0x0004", + "PUSH0", + "STARG3" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "arguments": [ + { + "type": "Integer", + "value": 1 + }, + { + "type": "Integer", + "value": 2 + }, + { + "type": "Integer", + "value": 3 + }, + { + "type": "Integer", + "value": 0 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STARG4.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STARG4.json new file mode 100644 index 0000000000..7b32e0e09a --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STARG4.json @@ -0,0 +1,89 @@ +{ + "category": "Slot", + "name": "STARG4", + "tests": [ + { + "name": "Without slot", + "script": [ + "PUSH1", + "STARG4" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Index out of range", + "script": [ + "PUSH0", + "INITSLOT", + "0x0001", + "PUSH1", + "STARG4" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "PUSH1", + "PUSH2", + "PUSH3", + "PUSH4", + "PUSH5", + "INITSLOT", + "0x0005", + "PUSH0", + "STARG4" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "arguments": [ + { + "type": "Integer", + "value": 1 + }, + { + "type": "Integer", + "value": 2 + }, + { + "type": "Integer", + "value": 3 + }, + { + "type": "Integer", + "value": 4 + }, + { + "type": "Integer", + "value": 0 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STARG5.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STARG5.json new file mode 100644 index 0000000000..9bcef878b4 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STARG5.json @@ -0,0 +1,94 @@ +{ + "category": "Slot", + "name": "STARG5", + "tests": [ + { + "name": "Without slot", + "script": [ + "PUSH1", + "STARG5" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Index out of range", + "script": [ + "PUSH0", + "INITSLOT", + "0x0001", + "PUSH1", + "STARG5" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "PUSH1", + "PUSH2", + "PUSH3", + "PUSH4", + "PUSH5", + "PUSH6", + "INITSLOT", + "0x0006", + "PUSH0", + "STARG5" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "arguments": [ + { + "type": "Integer", + "value": 1 + }, + { + "type": "Integer", + "value": 2 + }, + { + "type": "Integer", + "value": 3 + }, + { + "type": "Integer", + "value": 4 + }, + { + "type": "Integer", + "value": 5 + }, + { + "type": "Integer", + "value": 0 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STARG6.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STARG6.json new file mode 100644 index 0000000000..e8c0f09b9f --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STARG6.json @@ -0,0 +1,99 @@ +{ + "category": "Slot", + "name": "STARG6", + "tests": [ + { + "name": "Without slot", + "script": [ + "PUSH1", + "STARG6" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Index out of range", + "script": [ + "PUSH0", + "INITSLOT", + "0x0001", + "PUSH1", + "STARG6" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "PUSH1", + "PUSH2", + "PUSH3", + "PUSH4", + "PUSH5", + "PUSH6", + "PUSH7", + "INITSLOT", + "0x0007", + "PUSH0", + "STARG6" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "arguments": [ + { + "type": "Integer", + "value": 1 + }, + { + "type": "Integer", + "value": 2 + }, + { + "type": "Integer", + "value": 3 + }, + { + "type": "Integer", + "value": 4 + }, + { + "type": "Integer", + "value": 5 + }, + { + "type": "Integer", + "value": 6 + }, + { + "type": "Integer", + "value": 0 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STLOC.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STLOC.json new file mode 100644 index 0000000000..aae5bbb9ea --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STLOC.json @@ -0,0 +1,92 @@ +{ + "category": "Slot", + "name": "STLOC", + "tests": [ + { + "name": "Without slot", + "script": [ + "STLOC", + "0x00" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without enough items", + "script": [ + "INITSLOT", + "0x0100", + "PUSH2", + "STLOC" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "INITSLOT", + "0x0100", + "PUSH1", + "STLOC", + "0x00", + "LDLOC", + "0x00" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "LDLOC", + "localVariables": [ + { + "type": "Integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 1 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STSFLD.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STSFLD.json new file mode 100644 index 0000000000..149244cbbd --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STSFLD.json @@ -0,0 +1,84 @@ +{ + "category": "Slot", + "name": "STSFLD", + "tests": [ + { + "name": "Without slot", + "script": [ + "STSFLD", + "0x00" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Index out of range", + "script": [ + "INITSSLOT", + "0x01", + "STSFLD", + "0x01" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "INITSSLOT", + "0x01", + "PUSH1", + "STSFLD", + "0x00" + ], + "steps": [ + { + "actions": [ + "StepInto", + "StepInto", + "StepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET", + "staticFields": [ + { + "type": "Integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STSFLD0.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STSFLD0.json new file mode 100644 index 0000000000..d2ee516f22 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STSFLD0.json @@ -0,0 +1,63 @@ +{ + "category": "Slot", + "name": "STSFLD0", + "tests": [ + { + "name": "Without slot", + "script": [ + "STSFLD0" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "INITSSLOT", + "0x01", + "PUSH1", + "STSFLD0" + ], + "steps": [ + { + "actions": [ + "StepInto", + "StepInto", + "StepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "RET", + "staticFields": [ + { + "type": "Integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STSFLD1.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STSFLD1.json new file mode 100644 index 0000000000..5ba84602c1 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STSFLD1.json @@ -0,0 +1,84 @@ +{ + "category": "Slot", + "name": "STSFLD1", + "tests": [ + { + "name": "Without slot", + "script": [ + "STSFLD1" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Index out of range", + "script": [ + "INITSSLOT", + "0x01", + "STSFLD1" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "INITSSLOT", + "0x02", + "PUSH1", + "STSFLD1" + ], + "steps": [ + { + "actions": [ + "StepInto", + "StepInto", + "StepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "RET", + "staticFields": [ + { + "type": "Null" + }, + { + "type": "Integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STSFLD2.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STSFLD2.json new file mode 100644 index 0000000000..d5c42ba76c --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STSFLD2.json @@ -0,0 +1,87 @@ +{ + "category": "Slot", + "name": "STSFLD2", + "tests": [ + { + "name": "Without slot", + "script": [ + "STSFLD2" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Index out of range", + "script": [ + "INITSSLOT", + "0x01", + "STSFLD2" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "INITSSLOT", + "0x03", + "PUSH1", + "STSFLD2" + ], + "steps": [ + { + "actions": [ + "StepInto", + "StepInto", + "StepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "RET", + "staticFields": [ + { + "type": "Null" + }, + { + "type": "Null" + }, + { + "type": "Integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STSFLD3.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STSFLD3.json new file mode 100644 index 0000000000..f4ba41a606 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STSFLD3.json @@ -0,0 +1,90 @@ +{ + "category": "Slot", + "name": "STSFLD3", + "tests": [ + { + "name": "Without slot", + "script": [ + "STSFLD3" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Index out of range", + "script": [ + "INITSSLOT", + "0x01", + "STSFLD3" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "INITSSLOT", + "0x04", + "PUSH1", + "STSFLD3" + ], + "steps": [ + { + "actions": [ + "StepInto", + "StepInto", + "StepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "RET", + "staticFields": [ + { + "type": "Null" + }, + { + "type": "Null" + }, + { + "type": "Null" + }, + { + "type": "Integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STSFLD4.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STSFLD4.json new file mode 100644 index 0000000000..48f4d09aa9 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STSFLD4.json @@ -0,0 +1,93 @@ +{ + "category": "Slot", + "name": "STSFLD4", + "tests": [ + { + "name": "Without slot", + "script": [ + "STSFLD4" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Index out of range", + "script": [ + "INITSSLOT", + "0x01", + "STSFLD4" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "INITSSLOT", + "0x05", + "PUSH1", + "STSFLD4" + ], + "steps": [ + { + "actions": [ + "StepInto", + "StepInto", + "StepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "RET", + "staticFields": [ + { + "type": "Null" + }, + { + "type": "Null" + }, + { + "type": "Null" + }, + { + "type": "Null" + }, + { + "type": "Integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STSFLD5.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STSFLD5.json new file mode 100644 index 0000000000..f3d2573d63 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STSFLD5.json @@ -0,0 +1,96 @@ +{ + "category": "Slot", + "name": "STSFLD5", + "tests": [ + { + "name": "Without slot", + "script": [ + "STSFLD5" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Index out of range", + "script": [ + "INITSSLOT", + "0x01", + "STSFLD5" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "INITSSLOT", + "0x06", + "PUSH1", + "STSFLD5" + ], + "steps": [ + { + "actions": [ + "StepInto", + "StepInto", + "StepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "RET", + "staticFields": [ + { + "type": "Null" + }, + { + "type": "Null" + }, + { + "type": "Null" + }, + { + "type": "Null" + }, + { + "type": "Null" + }, + { + "type": "Integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STSFLD6.json b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STSFLD6.json new file mode 100644 index 0000000000..2d89c71887 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Slot/STSFLD6.json @@ -0,0 +1,99 @@ +{ + "category": "Slot", + "name": "STSFLD6", + "tests": [ + { + "name": "Without slot", + "script": [ + "STSFLD6" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Index out of range", + "script": [ + "INITSSLOT", + "0x01", + "STSFLD6" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "INITSSLOT", + "0x07", + "PUSH1", + "STSFLD6" + ], + "steps": [ + { + "actions": [ + "StepInto", + "StepInto", + "StepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "RET", + "staticFields": [ + { + "type": "Null" + }, + { + "type": "Null" + }, + { + "type": "Null" + }, + { + "type": "Null" + }, + { + "type": "Null" + }, + { + "type": "Null" + }, + { + "type": "Integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Splice/CAT.json b/tests/Neo.VM.Tests/Tests/OpCodes/Splice/CAT.json new file mode 100644 index 0000000000..f7b6cf3430 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Splice/CAT.json @@ -0,0 +1,436 @@ +{ + "category": "Splice", + "name": "CAT", + "tests": [ + { + "name": "Max Item Length", + "script": [ + "INITSLOT", + "0x0200", + "PUSHINT32", + "0x00000100", + "STLOC0", + "PUSH1", + "STLOC1", + "PUSHDATA2", + "0x1000", + "0x000102030405060708090A0B0C0D0E0F", + "PUSHDATA2", + "0x1000", + "0x000102030405060708090A0B0C0D0E0F", + "CAT", + "LDLOC1", + "INC", + "STLOC1", + "LDLOC1", + "LDLOC0", + "LT", + "JMPIF_L", + "0xE6FFFFFF", + "PUSHDATA1", + "0x01", + "0x00", + "CAT" + ], + "steps": [ + { + "actions": ["execute"], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Wrong type [Map,ByteString]", + "script": [ + "PUSH0", + "NEWMAP", + "CAT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Wrong type [ByteString,Map]", + "script": [ + "NEWMAP", + "PUSH0", + "CAT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Wrong push", + "script": [ + "CAT" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "PUSHDATA1", + "0x01", + "0x01", + "PUSHDATA1", + "0x02", + "0x0203", + "CAT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 8, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Buffer", + "value": "0x010203" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Buffer", + "value": "0x010203" + } + ] + } + } + ] + }, + { + "name": "CAT int(0) with empty ByteString", + "script": [ + "PUSH1", + "DEC", + "PUSH0", + "CAT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "CAT", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Buffer", + "value": "" + } + ] + } + } + ] + }, + { + "name": "CAT 0x01 with empty ByteString", + "script": [ + "PUSH1", + "PUSH0", + "CAT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "CAT", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Buffer", + "value": "0x01" + } + ] + } + } + ] + }, + { + "name": "CAT empty ByteString with 0x01", + "script": [ + "PUSH0", + "PUSH1", + "CAT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "CAT", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Buffer", + "value": "0x01" + } + ] + } + } + ] + }, + { + "name": "CAT Buffers", + "script": [ + "PUSHDATA1", + "0x01AA", + "CONVERT", + "0x30", + "PUSHDATA1", + "0x01BB", + "CONVERT", + "0x30", + "INITSLOT", + "0x0002", + "LDARG1", + "LDARG0", + "CAT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 10, + "nextInstruction": "INITSLOT", + "evaluationStack": [ + { + "type": "Buffer", + "value": "0xBB" + }, + { + "type": "Buffer", + "value": "0xAA" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 13, + "nextInstruction": "LDARG1", + "arguments": [ + { + "type": "Buffer", + "value": "0xBB" + }, + { + "type": "Buffer", + "value": "0xAA" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 15, + "nextInstruction": "CAT", + "evaluationStack": [ + { + "type": "Buffer", + "value": "0xBB" + }, + { + "type": "Buffer", + "value": "0xAA" + } + ], + "arguments": [ + { + "type": "Buffer", + "value": "0xBB" + }, + { + "type": "Buffer", + "value": "0xAA" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 16, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Buffer", + "value": "0xAABB" + } + ], + "arguments": [ + { + "type": "Buffer", + "value": "0xBB" + }, + { + "type": "Buffer", + "value": "0xAA" + } + ] + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Splice/LEFT.json b/tests/Neo.VM.Tests/Tests/OpCodes/Splice/LEFT.json new file mode 100644 index 0000000000..02c0dbc0ce --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Splice/LEFT.json @@ -0,0 +1,228 @@ +{ + "category": "Splice", + "name": "LEFT", + "tests": [ + { + "name": "Without push", + "script": [ + "PUSH11", + "LEFT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Wrong type [Map]", + "script": [ + "PUSH4", + "NEWMAP", + "LEFT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "LEFT", + "evaluationStack": [ + { + "type": "map", + "value": {} + }, + { + "type": "integer", + "value": 4 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Negative value", + "script": [ + "PUSHDATA1", + "0x03", + "0x010203", + "PUSHM1", + "LEFT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "LEFT", + "evaluationStack": [ + { + "type": "integer", + "value": -1 + }, + { + "type": "ByteString", + "value": "0x010203" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Overflow string", + "script": [ + "PUSHDATA1", + "0x03", + "0x010203", + "PUSH4", + "LEFT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "LEFT", + "evaluationStack": [ + { + "type": "integer", + "value": 4 + }, + { + "type": "ByteString", + "value": "0x010203" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "PUSHDATA1", + "0x03", + "0x010203", + "PUSH2", + "LEFT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "LEFT", + "evaluationStack": [ + { + "type": "integer", + "value": 2 + }, + { + "type": "ByteString", + "value": "0x010203" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 7, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Buffer", + "value": "0x0102" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Buffer", + "value": "0x0102" + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Splice/MEMCPY.json b/tests/Neo.VM.Tests/Tests/OpCodes/Splice/MEMCPY.json new file mode 100644 index 0000000000..fcff55af20 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Splice/MEMCPY.json @@ -0,0 +1,382 @@ +{ + "category": "Splice", + "name": "MEMCPY", + "tests": [ + { + "name": "Max Item Length", + "script": [ + "PUSH4", + "NEWBUFFER", + "PUSHINT32", + "0x00001000", + "PUSHDATA1", + "0x02", + "0x1111", + "PUSH0", + "PUSH2", + "MEMCPY" + ], + "steps": [ + { + "actions": [ + "StepInto", + "StepInto", + "StepInto", + "StepInto", + "StepInto", + "StepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 13, + "nextInstruction": "MEMCPY", + "evaluationStack": [ + { + "type": "Integer", + "value": 2 + }, + { + "type": "Integer", + "value": 0 + }, + { + "type": "ByteString", + "value": "0x1111" + }, + { + "type": "Integer", + "value": 1048576 + }, + { + "type": "Buffer", + "value": "0x00000000" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Negative di", + "script": [ + "PUSH4", + "NEWBUFFER", + "PUSHM1", + "PUSHDATA1", + "0x02", + "0x1111", + "PUSH0", + "PUSH2", + "MEMCPY" + ], + "steps": [ + { + "actions": [ + "StepInto", + "StepInto", + "StepInto", + "StepInto", + "StepInto", + "StepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 9, + "nextInstruction": "MEMCPY", + "evaluationStack": [ + { + "type": "Integer", + "value": 2 + }, + { + "type": "Integer", + "value": 0 + }, + { + "type": "ByteString", + "value": "0x1111" + }, + { + "type": "Integer", + "value": -1 + }, + { + "type": "Buffer", + "value": "0x00000000" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Negative si", + "script": [ + "PUSH4", + "NEWBUFFER", + "PUSHINT32", + "0x00001000", + "PUSHDATA1", + "0x02", + "0x1111", + "PUSHM1", + "PUSH2", + "MEMCPY" + ], + "steps": [ + { + "actions": [ + "StepInto", + "StepInto", + "StepInto", + "StepInto", + "StepInto", + "StepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 13, + "nextInstruction": "MEMCPY", + "evaluationStack": [ + { + "type": "Integer", + "value": 2 + }, + { + "type": "Integer", + "value": -1 + }, + { + "type": "ByteString", + "value": "0x1111" + }, + { + "type": "Integer", + "value": 1048576 + }, + { + "type": "Buffer", + "value": "0x00000000" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Negative n", + "script": [ + "PUSH4", + "NEWBUFFER", + "PUSHINT32", + "0x00001000", + "PUSHDATA1", + "0x02", + "0x1111", + "PUSH0", + "PUSHM1", + "MEMCPY" + ], + "steps": [ + { + "actions": [ + "StepInto", + "StepInto", + "StepInto", + "StepInto", + "StepInto", + "StepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 13, + "nextInstruction": "MEMCPY", + "evaluationStack": [ + { + "type": "Integer", + "value": -1 + }, + { + "type": "Integer", + "value": 0 + }, + { + "type": "ByteString", + "value": "0x1111" + }, + { + "type": "Integer", + "value": 1048576 + }, + { + "type": "Buffer", + "value": "0x00000000" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Wrong type [Array]", + "script": [ + "PUSH0", + "NEWARRAY", + "PUSHINT32", + "0x00001000", + "PUSHDATA1", + "0x02", + "0x1111", + "PUSH0", + "PUSH2", + "MEMCPY" + ], + "steps": [ + { + "actions": [ + "StepInto", + "StepInto", + "StepInto", + "StepInto", + "StepInto", + "StepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 13, + "nextInstruction": "MEMCPY", + "evaluationStack": [ + { + "type": "Integer", + "value": 2 + }, + { + "type": "Integer", + "value": 0 + }, + { + "type": "ByteString", + "value": "0x1111" + }, + { + "type": "Integer", + "value": 1048576 + }, + { + "type": "Array", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "No push", + "script": [ + "MEMCPY" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "PUSH4", + "NEWBUFFER", + "DUP", + "PUSH1", + "PUSHDATA1", + "0x02", + "0x1111", + "PUSH0", + "PUSH2", + "MEMCPY" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Buffer", + "value": "0x00111100" + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Splice/NEWBUFFER.json b/tests/Neo.VM.Tests/Tests/OpCodes/Splice/NEWBUFFER.json new file mode 100644 index 0000000000..f3c60bb802 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Splice/NEWBUFFER.json @@ -0,0 +1,159 @@ +{ + "category": "Splice", + "name": "NEWBUFFER", + "tests": [ + { + "name": "Max Item Length", + "script": [ + "PUSHINT256", + "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "NEWBUFFER" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 33, + "nextInstruction": "NEWBUFFER", + "evaluationStack": [ + { + "type": "Integer", + "value": "57896044618658097711785492504343953926634992332820282019728792003956564819967" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "-1 Length", + "script": [ + "PUSHM1", + "NEWBUFFER" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "NEWBUFFER", + "evaluationStack": [ + { + "type": "Integer", + "value": -1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Wrong type [Array]", + "script": [ + "PUSH0", + "NEWARRAY", + "NEWBUFFER" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "NEWBUFFER", + "evaluationStack": [ + { + "type": "Array", + "value": [] + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "No push", + "script": [ + "NEWBUFFER" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test [Integer]", + "script": [ + "PUSH10", + "NEWBUFFER" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Buffer", + "value": "0x00000000000000000000" + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Splice/RIGHT.json b/tests/Neo.VM.Tests/Tests/OpCodes/Splice/RIGHT.json new file mode 100644 index 0000000000..6c30ea8c91 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Splice/RIGHT.json @@ -0,0 +1,299 @@ +{ + "category": "Splice", + "name": "RIGHT", + "tests": [ + { + "name": "Without push", + "script": [ + "PUSH11", + "RIGHT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Wrong type [Map]", + "script": [ + "PUSH4", + "NEWMAP", + "RIGHT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "RIGHT", + "evaluationStack": [ + { + "type": "map", + "value": {} + }, + { + "type": "integer", + "value": 4 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Negative value", + "script": [ + "PUSHDATA1", + "0x03", + "0x010203", + "PUSHM1", + "RIGHT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "RIGHT", + "evaluationStack": [ + { + "type": "integer", + "value": -1 + }, + { + "type": "ByteString", + "value": "0x010203" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Overflow string", + "script": [ + "PUSHDATA1", + "0x03", + "0x010203", + "PUSH4", + "RIGHT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "RIGHT", + "evaluationStack": [ + { + "type": "integer", + "value": 4 + }, + { + "type": "ByteString", + "value": "0x010203" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "PUSHDATA1", + "0x03", + "0x010203", + "PUSH2", + "RIGHT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "RIGHT", + "evaluationStack": [ + { + "type": "integer", + "value": 2 + }, + { + "type": "ByteString", + "value": "0x010203" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 7, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Buffer", + "value": "0x0203" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Buffer", + "value": "0x0203" + } + ] + } + } + ] + }, + { + "name": "Real test [whole input]", + "script": [ + "PUSHDATA1", + "0x03", + "0x010203", + "PUSH3", + "RIGHT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "RIGHT", + "evaluationStack": [ + { + "type": "integer", + "value": 3 + }, + { + "type": "ByteString", + "value": "0x010203" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 7, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Buffer", + "value": "0x010203" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Buffer", + "value": "0x010203" + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Splice/SUBSTR.json b/tests/Neo.VM.Tests/Tests/OpCodes/Splice/SUBSTR.json new file mode 100644 index 0000000000..7b78d7e053 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Splice/SUBSTR.json @@ -0,0 +1,478 @@ +{ + "category": "Splice", + "name": "SUBSTR", + "tests": [ + { + "name": "Without 3 items", + "script": [ + "PUSH2", + "PUSH3", + "SUBSTR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "SUBSTR", + "evaluationStack": [ + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 2 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "With negative count", + "script": [ + "PUSH0", + "PUSH0", + "PUSHM1", + "SUBSTR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "SUBSTR", + "evaluationStack": [ + { + "type": "integer", + "value": -1 + }, + { + "type": "integer", + "value": 0 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "With map as string", + "script": [ + "NEWMAP", + "PUSH0", + "PUSH0", + "SUBSTR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "SUBSTR", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + }, + { + "type": "integer", + "value": 0 + }, + { + "type": "map", + "value": {} + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "With map as count", + "script": [ + "PUSH0", + "PUSH0", + "NEWMAP", + "SUBSTR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "SUBSTR", + "evaluationStack": [ + { + "type": "map", + "value": {} + }, + { + "type": "integer", + "value": 0 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "With map as index", + "script": [ + "PUSH0", + "NEWMAP", + "PUSH0", + "SUBSTR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "SUBSTR", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + }, + { + "type": "map", + "value": {} + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "With negative index", + "script": [ + "PUSH0", + "PUSHM1", + "PUSH0", + "SUBSTR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "SUBSTR", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + }, + { + "type": "integer", + "value": -1 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Overflow string index", + "script": [ + "PUSHDATA1", + "0x02", + "0x0001", + "PUSH9", + "PUSH2", + "SUBSTR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "SUBSTR", + "evaluationStack": [ + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 9 + }, + { + "type": "ByteString", + "value": "0x0001" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Overflow string count", + "script": [ + "PUSHDATA1", + "0x0a", + "0x00010203040506070809", + "PUSH2", + "PUSH9", + "SUBSTR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 14, + "nextInstruction": "SUBSTR", + "evaluationStack": [ + { + "type": "integer", + "value": 9 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "ByteString", + "value": "0x00010203040506070809" + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "PUSHDATA1", + "0x0a", + "0x00010203040506070809", + "PUSH2", + "PUSH1", + "SUBSTR" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 14, + "nextInstruction": "SUBSTR", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "ByteString", + "value": "0x00010203040506070809" + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Buffer", + "value": "0x02" + } + ] + } + } + ] + }, + { + "name": "Integer overflow Test", + "script": [ + "PUSHDATA1", + "0xff", + "0x414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141", + "PUSHDATA1", + "0x04", + "0xfd000000", + "PUSHDATA1", + "0x04", + "0x03ffff7f", + "SUBSTR" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Stack/CLEAR.json b/tests/Neo.VM.Tests/Tests/OpCodes/Stack/CLEAR.json new file mode 100644 index 0000000000..36e9fcdd09 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Stack/CLEAR.json @@ -0,0 +1,59 @@ +{ + "category": "Stack", + "name": "CLEAR", + "tests": [ + { + "name": "Without push", + "script": [ + "CLEAR" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT" + } + } + ] + }, + { + "name": "With push", + "script": [ + "PUSH2", + "CLEAR" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "CLEAR", + "evaluationStack": [ + { + "type": "integer", + "value": 2 + } + ] + } + ] + } + }, + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Stack/DEPTH.json b/tests/Neo.VM.Tests/Tests/OpCodes/Stack/DEPTH.json new file mode 100644 index 0000000000..9a2ed2f774 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Stack/DEPTH.json @@ -0,0 +1,223 @@ +{ + "category": "Stack", + "name": "DEPTH", + "tests": [ + { + "name": "Without push", + "script": [ + "DEPTH" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + } + ] + }, + { + "name": "With push", + "script": [ + "PUSH2", + "DEPTH" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "DEPTH", + "evaluationStack": [ + { + "type": "integer", + "value": 2 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 2 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 2 + } + ] + } + } + ] + }, + { + "name": "3xDEPTH", + "script": [ + "DEPTH", + "DEPTH", + "DEPTH" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "DEPTH", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "DEPTH", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 0 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Stack/DROP.json b/tests/Neo.VM.Tests/Tests/OpCodes/Stack/DROP.json new file mode 100644 index 0000000000..804a710958 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Stack/DROP.json @@ -0,0 +1,73 @@ +{ + "category": "Stack", + "name": "DROP", + "tests": [ + { + "name": "Without push", + "script": [ + "DROP" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without push", + "script": [ + "PUSH5", + "DROP" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "DROP", + "evaluationStack": [ + { + "type": "integer", + "value": 5 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Stack/NIP.json b/tests/Neo.VM.Tests/Tests/OpCodes/Stack/NIP.json new file mode 100644 index 0000000000..e363d56444 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Stack/NIP.json @@ -0,0 +1,132 @@ +{ + "category": "Stack", + "name": "NIP", + "tests": [ + { + "name": "Without push", + "script": [ + "NIP" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without two stack items", + "script": [ + "PUSH5", + "NIP" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "NIP", + "evaluationStack": [ + { + "type": "integer", + "value": 5 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "PUSH0", + "PUSHDATA1", + "0x09", + "0x000000000000000000", + "NOT", + "NIP" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 13, + "nextInstruction": "NIP", + "evaluationStack": [ + { + "type": "Boolean", + "value": true + }, + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 14, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Stack/OVER.json b/tests/Neo.VM.Tests/Tests/OpCodes/Stack/OVER.json new file mode 100644 index 0000000000..03ec0d16ee --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Stack/OVER.json @@ -0,0 +1,243 @@ +{ + "category": "Stack", + "name": "OVER", + "tests": [ + { + "name": "Without push", + "script": [ + "OVER" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "With one push", + "script": [ + "PUSH0", + "OVER" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "OVER", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test with 2 items", + "script": [ + "PUSH1", + "PUSH2", + "OVER" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "OVER", + "evaluationStack": [ + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + } + } + ] + }, + { + "name": "Real test with 3 items", + "script": [ + "PUSH1", + "PUSH2", + "PUSH3", + "OVER" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "OVER", + "evaluationStack": [ + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Stack/PICK.json b/tests/Neo.VM.Tests/Tests/OpCodes/Stack/PICK.json new file mode 100644 index 0000000000..5791acec70 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Stack/PICK.json @@ -0,0 +1,397 @@ +{ + "category": "Stack", + "name": "PICK", + "tests": [ + { + "name": "Without push", + "script": [ + "PICK" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Pick outside", + "script": [ + "PUSH1", + "PUSH2", + "PUSH3", + "PUSH4", + "PICK" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "PICK", + "evaluationStack": [ + { + "type": "integer", + "value": 4 + }, + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Less than 0", + "script": [ + "PUSH1", + "PUSH2", + "PUSH3", + "PUSHM1", + "PICK" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "PICK", + "evaluationStack": [ + { + "type": "integer", + "value": -1 + }, + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Wrong type", + "script": [ + "PUSH1", + "PUSH2", + "PUSH3", + "NEWMAP", + "PICK" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "PICK", + "evaluationStack": [ + { + "type": "map", + "value": {} + }, + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "PUSH3", + "PUSH2", + "PUSH1", + "PUSH2", + "PICK" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "PICK", + "evaluationStack": [ + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 3 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 3 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 3 + } + ] + } + } + ] + }, + { + "name": "Real test with 0", + "script": [ + "PUSH3", + "PUSH2", + "PUSH1", + "PUSH0", + "PICK" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "PICK", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + }, + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 3 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 3 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 3 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Stack/REVERSE3.json b/tests/Neo.VM.Tests/Tests/OpCodes/Stack/REVERSE3.json new file mode 100644 index 0000000000..1260a70d68 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Stack/REVERSE3.json @@ -0,0 +1,85 @@ +{ + "category": "Stack", + "name": "REVERSE3", + "tests": [ + { + "name": "Without push", + "script": [ + "REVERSE3" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "With push", + "script": [ + "PUSH1", + "PUSH2", + "PUSH3", + "REVERSE3" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "REVERSE3", + "evaluationStack": [ + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 3 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Stack/REVERSE4.json b/tests/Neo.VM.Tests/Tests/OpCodes/Stack/REVERSE4.json new file mode 100644 index 0000000000..d3e04e437e --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Stack/REVERSE4.json @@ -0,0 +1,95 @@ +{ + "category": "Stack", + "name": "REVERSE4", + "tests": [ + { + "name": "Without push", + "script": [ + "REVERSE4" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "With push", + "script": [ + "PUSH1", + "PUSH2", + "PUSH3", + "PUSH4", + "REVERSE4" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "REVERSE4", + "evaluationStack": [ + { + "type": "integer", + "value": 4 + }, + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 4 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Stack/REVERSEN.json b/tests/Neo.VM.Tests/Tests/OpCodes/Stack/REVERSEN.json new file mode 100644 index 0000000000..e9a1518826 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Stack/REVERSEN.json @@ -0,0 +1,201 @@ +{ + "category": "Stack", + "name": "REVERSEN", + "tests": [ + { + "name": "Without push", + "script": [ + "REVERSEN" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "N = -1", + "script": [ + "PUSH1", + "PUSHM1", + "REVERSEN" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "N < DEPTH", + "script": [ + "PUSH1", + "REVERSEN" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT", + "resultStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + } + ] + }, + { + "name": "Reverse 0 item", + "script": [ + "PUSH1", + "PUSH2", + "PUSH3", + "PUSH0", + "REVERSEN" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "REVERSEN", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + }, + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + } + } + ] + }, + { + "name": "Reverse 3 items", + "script": [ + "PUSH1", + "PUSH2", + "PUSH3", + "PUSH3", + "REVERSEN" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "REVERSEN", + "evaluationStack": [ + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 3 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Stack/ROLL.json b/tests/Neo.VM.Tests/Tests/OpCodes/Stack/ROLL.json new file mode 100644 index 0000000000..882c577d4a --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Stack/ROLL.json @@ -0,0 +1,398 @@ +{ + "category": "Stack", + "name": "ROLL", + "tests": [ + { + "name": "Without push", + "script": [ + "ROLL" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "With -1", + "script": [ + "PUSHM1", + "ROLL" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Pick outside", + "script": [ + "PUSH1", + "PUSH2", + "PUSH3", + "PUSH4", + "ROLL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "ROLL", + "evaluationStack": [ + { + "type": "integer", + "value": 4 + }, + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Less than 0", + "script": [ + "PUSH1", + "PUSH2", + "PUSH3", + "PUSHM1", + "ROLL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "ROLL", + "evaluationStack": [ + { + "type": "integer", + "value": -1 + }, + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "With 0", + "script": [ + "PUSH1", + "PUSH2", + "PUSH3", + "PUSH0", + "ROLL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "ROLL", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + }, + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + } + } + ] + }, + { + "name": "Wrong type", + "script": [ + "PUSH1", + "PUSH2", + "PUSH3", + "NEWMAP", + "ROLL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "ROLL", + "evaluationStack": [ + { + "type": "map", + "value": {} + }, + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "PUSH3", + "PUSH2", + "PUSH1", + "PUSH2", + "ROLL" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "ROLL", + "evaluationStack": [ + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 3 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 2 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 2 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Stack/ROT.json b/tests/Neo.VM.Tests/Tests/OpCodes/Stack/ROT.json new file mode 100644 index 0000000000..48c8771af3 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Stack/ROT.json @@ -0,0 +1,193 @@ +{ + "category": "Stack", + "name": "ROT", + "tests": [ + { + "name": "Without push", + "script": [ + "ROT" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "With one push", + "script": [ + "PUSH0", + "ROT" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "ROT", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "With 2 items", + "script": [ + "PUSH1", + "PUSH2", + "ROT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "ROT", + "evaluationStack": [ + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test with 3 items", + "script": [ + "PUSH1", + "PUSH2", + "PUSH3", + "ROT" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "ROT", + "evaluationStack": [ + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 2 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 2 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Stack/SWAP.json b/tests/Neo.VM.Tests/Tests/OpCodes/Stack/SWAP.json new file mode 100644 index 0000000000..c5e93a9b59 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Stack/SWAP.json @@ -0,0 +1,209 @@ +{ + "category": "Stack", + "name": "SWAP", + "tests": [ + { + "name": "Without push", + "script": [ + "SWAP" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "With one push", + "script": [ + "PUSH0", + "SWAP" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "SWAP", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test with 2 items", + "script": [ + "PUSH1", + "PUSH2", + "SWAP" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "SWAP", + "evaluationStack": [ + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 2 + } + ] + } + ] + } + } + ] + }, + { + "name": "Real test with 3 items", + "script": [ + "PUSH1", + "PUSH2", + "PUSH3", + "SWAP" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "SWAP", + "evaluationStack": [ + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 1 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Stack/TUCK.json b/tests/Neo.VM.Tests/Tests/OpCodes/Stack/TUCK.json new file mode 100644 index 0000000000..031855f31f --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Stack/TUCK.json @@ -0,0 +1,243 @@ +{ + "category": "Stack", + "name": "TUCK", + "tests": [ + { + "name": "Without push", + "script": [ + "TUCK" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Outside", + "script": [ + "PUSH0", + "TUCK" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "TUCK", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test - Last item", + "script": [ + "PUSH1", + "PUSH2", + "TUCK" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "TUCK", + "evaluationStack": [ + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 2 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 2 + } + ] + } + } + ] + }, + { + "name": "Real test", + "script": [ + "PUSH1", + "PUSH2", + "PUSH3", + "TUCK" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "TUCK", + "evaluationStack": [ + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 1 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Stack/XDROP.json b/tests/Neo.VM.Tests/Tests/OpCodes/Stack/XDROP.json new file mode 100644 index 0000000000..8666fed600 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Stack/XDROP.json @@ -0,0 +1,238 @@ +{ + "category": "Stack", + "name": "XDROP", + "tests": [ + { + "name": "Without push", + "script": [ + "XDROP" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "With -1", + "script": [ + "PUSHM1", + "XDROP" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Overflow drop", + "script": [ + "PUSH3", + "PUSH2", + "PUSH1", + "PUSH3", + "XDROP" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "XDROP", + "evaluationStack": [ + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 3 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Wrong index type [Map]", + "script": [ + "PUSH3", + "PUSH2", + "PUSH1", + "NEWMAP", + "XDROP" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "XDROP", + "evaluationStack": [ + { + "type": "map", + "value": {} + }, + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 3 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Real test", + "script": [ + "PUSH3", + "PUSH2", + "PUSH1", + "PUSH1", + "XDROP" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "XDROP", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 3 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 3 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 1 + }, + { + "type": "integer", + "value": 3 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Types/CONVERT.json b/tests/Neo.VM.Tests/Tests/OpCodes/Types/CONVERT.json new file mode 100644 index 0000000000..473ed8bba4 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Types/CONVERT.json @@ -0,0 +1,898 @@ +{ + "category": "Types", + "name": "CONVERT", + "tests": [ + { + "name": "Null to Buffer", + "script": [ + "PUSHNULL", + "CONVERT", + "0x30" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "CONVERT", + "evaluationStack": [ + { + "type": "null" + } + ] + } + ] + } + }, + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "null" + } + ] + } + } + ] + }, + { + "name": "Null to Boolean", + "script": [ + "PUSHNULL", + "CONVERT", + "0x20" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "CONVERT", + "evaluationStack": [ + { + "type": "null" + } + ] + } + ] + } + }, + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "null" + } + ] + } + } + ] + }, + { + "name": "Struct to Array", + "script": [ + "PUSH1", + "NEWSTRUCT", + "DUP", + "PUSH0", + "PUSH5", + "SETITEM", + "CONVERT", + "0x40" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "CONVERT", + "evaluationStack": [ + { + "type": "struct", + "value": [ + { + "type": "Integer", + "value": 5 + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": 5 + } + ] + } + ] + } + } + ] + }, + { + "name": "Struct to Boolean", + "script": [ + "PUSH0", + "NEWSTRUCT", + "CONVERT", + "0x20" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "CONVERT", + "evaluationStack": [ + { + "type": "struct", + "value": [ + ] + } + ] + } + ] + } + }, + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Array to Boolean", + "script": [ + "PUSH0", + "NEWARRAY", + "CONVERT", + "0x20" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "CONVERT", + "evaluationStack": [ + { + "type": "array", + "value": [ + ] + } + ] + } + ] + } + }, + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Array to Struct", + "script": [ + "PUSH1", + "NEWARRAY", + "DUP", + "PUSH0", + "PUSH5", + "SETITEM", + "CONVERT", + "0x41" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "CONVERT", + "evaluationStack": [ + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": 5 + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "struct", + "value": [ + { + "type": "Integer", + "value": 5 + } + ] + } + ] + } + } + ] + }, + { + "name": "Array to Integer", + "script": [ + "PUSH1", + "NEWARRAY", + "DUP", + "PUSH0", + "PUSH4", + "SETITEM", + "CONVERT", + "0x21" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "CONVERT", + "evaluationStack": [ + { + "type": "array", + "value": [ + { + "type": "Integer", + "value": 4 + } + ] + } + ] + } + ] + } + }, + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Integer to ByteString", + "script": [ + "PUSHINT8", + "0x0A", + "CONVERT", + "0x28" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "ByteString", + "value": "0x0A" + } + ] + } + } + ] + }, + { + "name": "Integer to Boolean", + "script": [ + "PUSHINT8", + "0x0A", + "CONVERT", + "0x20" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Integer to Boolean", + "script": [ + "PUSHINT8", + "0x00", + "CONVERT", + "0x20" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Integer to Boolean", + "script": [ + "PUSHINT8", + "0x01", + "CONVERT", + "0x20" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Integer to Buffer", + "script": [ + "PUSHINT8", + "0x0A", + "CONVERT", + "0x30" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Buffer", + "value": "0x0A" + } + ] + } + } + ] + }, + { + "name": "ByteString to Buffer", + "script": [ + "PUSHDATA1", + "0x0A", + "0x00000000000000000000", + "CONVERT", + "0x30" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Buffer", + "value": "0x00000000000000000000" + } + ] + } + } + ] + }, + { + "name": "ByteString to Integer", + "script": [ + "PUSHDATA1", + "0x02", + "0x0A0B", + "CONVERT", + "0x21" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 2826 + } + ] + } + } + ] + }, + { + "name": "ByteString to Boolean", + "script": [ + "PUSHDATA1", + "0x02", + "0x0A0B", + "CONVERT", + "0x20" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "ByteString to Boolean", + "script": [ + "PUSHDATA1", + "0x02", + "0x0000", + "CONVERT", + "0x20" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "ByteString to Boolean", + "script": [ + "PUSHDATA1", + "0x02", + "0x0001", + "CONVERT", + "0x20" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "ByteString to Boolean", + "script": [ + "PUSHDATA1", + "0x01", + "0x01", + "CONVERT", + "0x20" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Buffer to ByteString", + "script": [ + "PUSHDATA1", + "0x0A", + "0x00000000000000000000", + "CONVERT", + "0x30", + "CONVERT", + "0x28" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "ByteString", + "value": "0x00000000000000000000" + } + ] + } + } + ] + }, + { + "name": "Buffer to Boolean", + "script": [ + "PUSHDATA1", + "0x01", + "0x00", + "CONVERT", + "0x30", + "CONVERT", + "0x20" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Buffer to Boolean", + "script": [ + "PUSHDATA1", + "0x01", + "0x02", + "CONVERT", + "0x30", + "CONVERT", + "0x20" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Buffer to Integer", + "script": [ + "PUSHDATA1", + "0x02", + "0x0102", + "CONVERT", + "0x30", + "CONVERT", + "0x21" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Integer", + "value": 513 + } + ] + } + } + ] + }, + { + "name": "Buffer to Integer (Exceed)", + "script": [ + "PUSHDATA1", + "0x21", + "0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", + "CONVERT", + "0x30", + "CONVERT", + "0x21" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Buffer to Any", + "script": [ + "PUSHDATA1", + "0x02", + "0x0102", + "CONVERT", + "0x30", + "CONVERT", + "0x00" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Buffer to Interop", + "script": [ + "PUSHDATA1", + "0x02", + "0x0102", + "CONVERT", + "0x30", + "CONVERT", + "0x60" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "ByteString to non-defined", + "script": [ + "PUSHDATA1", + "0x01", + "0xAA", + "CONVERT", + "0xFF" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Array to non-defined", + "script": [ + "NEWARRAY0", + "CONVERT", + "0xFF" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Struct to non-defined", + "script": [ + "NEWSTRUCT0", + "CONVERT", + "0xFF" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Null to non-defined", + "script": [ + "PUSHNULL", + "CONVERT", + "0xFF" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "FAULT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Types/ISNULL.json b/tests/Neo.VM.Tests/Tests/OpCodes/Types/ISNULL.json new file mode 100644 index 0000000000..b87fa84726 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Types/ISNULL.json @@ -0,0 +1,147 @@ +{ + "category": "Types", + "name": "ISNULL", + "tests": [ + { + "name": "Without push", + "script": [ + "ISNULL" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Good definition", + "script": [ + "PUSHNULL", + "ISNULL" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "ISNULL", + "evaluationStack": [ + { + "type": "null" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "With empty ByteString", + "script": [ + "PUSH0", + "ISNULL" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "ISNULL", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/OpCodes/Types/ISTYPE.json b/tests/Neo.VM.Tests/Tests/OpCodes/Types/ISTYPE.json new file mode 100644 index 0000000000..6bdbd7495c --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/OpCodes/Types/ISTYPE.json @@ -0,0 +1,226 @@ +{ + "category": "Types", + "name": "ISTYPE", + "tests": [ + { + "name": "Array", + "script": [ + "NEWARRAY0", + "ISTYPE", + "0x40" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Buffer", + "script": [ + "PUSH0", + "NEWBUFFER", + "ISTYPE", + "0x30" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "ByteString", + "script": [ + "PUSHDATA1", + "0x00", + "ISTYPE", + "0x28" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Integer", + "script": [ + "PUSH0", + "ISTYPE", + "0x21" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "InteropInterface", + "script": [ + "SYSCALL", + "0x77777777", + "ISTYPE", + "0x60" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Map", + "script": [ + "NEWMAP", + "ISTYPE", + "0x48" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Null", + "script": [ + "PUSHNULL", + "ISTYPE", + "0x20" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + } + ] + }, + { + "name": "Pointer", + "script": [ + "PUSHA", + "0x00000000", + "ISTYPE", + "0x10" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + }, + { + "name": "Struct", + "script": [ + "NEWSTRUCT0", + "ISTYPE", + "0x41" + ], + "steps": [ + { + "actions": [ + "Execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/Others/Debugger.json b/tests/Neo.VM.Tests/Tests/Others/Debugger.json new file mode 100644 index 0000000000..7dd1096d55 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/Others/Debugger.json @@ -0,0 +1,426 @@ +{ + "category": "Others", + "name": "Debugger", + "tests": [ + { + "name": "Step Into", + "script": [ + "PUSH1", + "CALL", + "0x04", + "PUSH3", + "RET", + "PUSH2", + "RET" + ], + "steps": [ + { + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 0, + "nextInstruction": "PUSH1" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "CALL", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 5, + "nextInstruction": "PUSH2", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + }, + { + "instructionPointer": 3, + "nextInstruction": "PUSH3", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 6, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + }, + { + "instructionPointer": 3, + "nextInstruction": "PUSH3", + "evaluationStack": [ + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "PUSH3", + "evaluationStack": [ + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + } + } + ] + }, + { + "name": "Step Out", + "script": [ + "PUSH1", + "CALL", + "0x04", + "PUSH3", + "RET", + "PUSH2", + "RET" + ], + "steps": [ + { + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 0, + "nextInstruction": "PUSH1" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "CALL", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepOut" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + } + } + ] + }, + { + "name": "Step Over", + "script": [ + "PUSH1", + "CALL", + "0x04", + "PUSH3", + "RET", + "PUSH2", + "RET" + ], + "steps": [ + { + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 0, + "nextInstruction": "PUSH1" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "CALL", + "evaluationStack": [ + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepOver" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "PUSH3", + "evaluationStack": [ + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepOver" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "RET", + "evaluationStack": [ + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + } + ] + } + }, + { + "actions": [ + "stepOver" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + } + } + ] + }, + { + "name": "Execute", + "script": [ + "PUSH1", + "CALL", + "0x04", + "PUSH3", + "RET", + "PUSH2", + "RET" + ], + "steps": [ + { + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 0, + "nextInstruction": "PUSH1" + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT", + "resultStack": [ + { + "type": "integer", + "value": 3 + }, + { + "type": "integer", + "value": 2 + }, + { + "type": "integer", + "value": 1 + } + ] + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/Others/Init.json b/tests/Neo.VM.Tests/Tests/Others/Init.json new file mode 100644 index 0000000000..ab95168cde --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/Others/Init.json @@ -0,0 +1,41 @@ +{ + "category": "Others", + "name": "Init", + "tests": [ + { + "name": "Init script", + "script": [ + "RET" + ], + "steps": [ + { + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 0, + "nextInstruction": "RET" + } + ] + } + } + ] + }, + { + "name": "Init script", + "script": [ + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/Others/InvocationLimits.json b/tests/Neo.VM.Tests/Tests/Others/InvocationLimits.json new file mode 100644 index 0000000000..5939dabf80 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/Others/InvocationLimits.json @@ -0,0 +1,120 @@ +{ + "category": "Limits", + "name": "Invocation limits", + "tests": [ + { + "name": "More than 1024 ExecutionContext", + "script": [ + "INITSSLOT", + "0x01", + "PUSHDATA1", + "0x02", + "0x0004", + "INC", + "STSFLD0", + "LDSFLD0", + "DEC", + "DUP", + "STSFLD0", + "JMPIFNOT", + "0x04", + "CALL", + "0xfa", + "RET" + ], + "steps": [ + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 8, + "nextInstruction": "LDSFLD0", + "staticFields": [ + { + "type": "integer", + "value": 1025 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto", + "stepInto", + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 12, + "nextInstruction": "JMPIFNOT", + "evaluationStack": [ + { + "type": "integer", + "value": 1024 + } + ], + "staticFields": [ + { + "type": "integer", + "value": 1024 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto", + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 8, + "nextInstruction": "LDSFLD0", + "staticFields": [ + { + "type": "integer", + "value": 1024 + } + ] + }, + { + "instructionPointer": 16, + "nextInstruction": "RET", + "staticFields": [ + { + "type": "integer", + "value": 1024 + } + ] + } + ] + } + }, + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/Others/OtherCases.json b/tests/Neo.VM.Tests/Tests/Others/OtherCases.json new file mode 100644 index 0000000000..693bf7cba7 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/Others/OtherCases.json @@ -0,0 +1,36 @@ +{ + "category": "Limits", + "name": "OtherCases", + "tests": [ + { + "name": "Wrong script", + "script": [ + "0xff" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Without script", + "script": [], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/Others/ScriptLogic.json b/tests/Neo.VM.Tests/Tests/Others/ScriptLogic.json new file mode 100644 index 0000000000..a49be7a8bf --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/Others/ScriptLogic.json @@ -0,0 +1,99 @@ +{ + "category": "Others", + "name": "ScriptLogic", + "tests": [ + { + "name": "Script logic", + "script": [ + "PUSH0", + "NOT", + "NOT", + "DROP" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 1, + "nextInstruction": "NOT", + "evaluationStack": [ + { + "type": "integer", + "value": 0 + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 2, + "nextInstruction": "NOT", + "evaluationStack": [ + { + "type": "Boolean", + "value": true + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 3, + "nextInstruction": "DROP", + "evaluationStack": [ + { + "type": "Boolean", + "value": false + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 4, + "nextInstruction": "RET" + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "HALT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/Others/StackItemLimits.json b/tests/Neo.VM.Tests/Tests/Others/StackItemLimits.json new file mode 100644 index 0000000000..77293f9f89 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/Others/StackItemLimits.json @@ -0,0 +1,71 @@ +{ + "category": "Limits", + "name": "Stack item limits [StackItemLimits] [StackItemLimits] [StackItemLimits]", + "tests": [ + { + "name": "Max boolean ByteString", + "script": [ + "PUSHDATA1", + "0x21", + "0x000000000000000000000000000000000000000000000000000000000000000000", + "NOT" + ], + "steps": [ + { + "actions": [ + "stepInto" + ], + "result": { + "state": "BREAK", + "invocationStack": [ + { + "instructionPointer": 35, + "nextInstruction": "NOT", + "evaluationStack": [ + { + "type": "ByteString", + "value": "0x000000000000000000000000000000000000000000000000000000000000000000" + } + ] + } + ] + } + }, + { + "actions": [ + "stepInto" + ], + "result": { + "state": "FAULT" + } + } + ] + }, + { + "name": "Max items with PUSHDATA (2048+1)", + "script": [ + "PUSHINT16", + "0x0004", + "NEWARRAY", + "UNPACK", + "PUSHINT16", + "0xfe03", + "NEWARRAY", + "UNPACK", + "PUSHDATA1", + "0x01", + "0x01" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Tests/Others/StackLimits.json b/tests/Neo.VM.Tests/Tests/Others/StackLimits.json new file mode 100644 index 0000000000..8191112a26 --- /dev/null +++ b/tests/Neo.VM.Tests/Tests/Others/StackLimits.json @@ -0,0 +1,6181 @@ +{ + "category": "Limits", + "name": "Stack limits [StackLimits] [StackLimits] [StackLimits]", + "tests": [ + { + "name": "Good: 2048 PUSH1 + 2048 DROP", + "script": [ + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP", + "DROP" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "HALT" + } + } + ] + }, + { + "name": "Bad: 2049 PUSH1", + "script": [ + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1", + "PUSH1" + ], + "steps": [ + { + "actions": [ + "execute" + ], + "result": { + "state": "FAULT" + } + } + ] + } + ] +} diff --git a/tests/Neo.VM.Tests/Types/TestEngine.cs b/tests/Neo.VM.Tests/Types/TestEngine.cs new file mode 100644 index 0000000000..832e9a7fb4 --- /dev/null +++ b/tests/Neo.VM.Tests/Types/TestEngine.cs @@ -0,0 +1,34 @@ +using System; +using Neo.VM; +using Neo.VM.Types; + +namespace Neo.Test.Types +{ + class TestEngine : ExecutionEngine + { + public Exception FaultException { get; private set; } + + protected override void OnSysCall(uint method) + { + if (method == 0x77777777) + { + CurrentContext.EvaluationStack.Push(StackItem.FromInterface(new object())); + return; + } + + if (method == 0xaddeadde) + { + ExecuteThrow("error"); + return; + } + + throw new System.Exception(); + } + + protected override void OnFault(Exception ex) + { + FaultException = ex; + base.OnFault(ex); + } + } +} diff --git a/tests/Neo.VM.Tests/Types/VMUT.cs b/tests/Neo.VM.Tests/Types/VMUT.cs new file mode 100644 index 0000000000..a018d05c29 --- /dev/null +++ b/tests/Neo.VM.Tests/Types/VMUT.cs @@ -0,0 +1,16 @@ +using Newtonsoft.Json; + +namespace Neo.Test.Types +{ + public class VMUT + { + [JsonProperty] + public string Category { get; set; } + + [JsonProperty] + public string Name { get; set; } + + [JsonProperty] + public VMUTEntry[] Tests { get; set; } + } +} diff --git a/tests/Neo.VM.Tests/Types/VMUTActionType.cs b/tests/Neo.VM.Tests/Types/VMUTActionType.cs new file mode 100644 index 0000000000..a90691a6ad --- /dev/null +++ b/tests/Neo.VM.Tests/Types/VMUTActionType.cs @@ -0,0 +1,13 @@ +namespace Neo.Test.Types +{ + public enum VMUTActionType + { + Execute, + + // Steps + + StepInto, + StepOut, + StepOver, + } +} diff --git a/tests/Neo.VM.Tests/Types/VMUTEntry.cs b/tests/Neo.VM.Tests/Types/VMUTEntry.cs new file mode 100644 index 0000000000..64c1e76d94 --- /dev/null +++ b/tests/Neo.VM.Tests/Types/VMUTEntry.cs @@ -0,0 +1,17 @@ +using Neo.Test.Converters; +using Newtonsoft.Json; + +namespace Neo.Test.Types +{ + public class VMUTEntry + { + [JsonProperty(Order = 1)] + public string Name { get; set; } + + [JsonProperty(Order = 2), JsonConverter(typeof(ScriptConverter))] + public byte[] Script { get; set; } + + [JsonProperty(Order = 3)] + public VMUTStep[] Steps { get; set; } + } +} diff --git a/tests/Neo.VM.Tests/Types/VMUTExecutionContextState.cs b/tests/Neo.VM.Tests/Types/VMUTExecutionContextState.cs new file mode 100644 index 0000000000..b0d20ae2f9 --- /dev/null +++ b/tests/Neo.VM.Tests/Types/VMUTExecutionContextState.cs @@ -0,0 +1,31 @@ +using Neo.Test.Converters; +using Neo.VM; +using Newtonsoft.Json; + +namespace Neo.Test.Types +{ + public class VMUTExecutionContextState + { + [JsonProperty] + public int InstructionPointer { get; set; } + + [JsonProperty, JsonConverter(typeof(UppercaseEnum))] + public OpCode NextInstruction { get; set; } + + // Stacks + + [JsonProperty] + public VMUTStackItem[] EvaluationStack { get; set; } + + // Slots + + [JsonProperty] + public VMUTStackItem[] StaticFields { get; set; } + + [JsonProperty] + public VMUTStackItem[] Arguments { get; set; } + + [JsonProperty] + public VMUTStackItem[] LocalVariables { get; set; } + } +} diff --git a/tests/Neo.VM.Tests/Types/VMUTExecutionEngineState.cs b/tests/Neo.VM.Tests/Types/VMUTExecutionEngineState.cs new file mode 100644 index 0000000000..235654b0a4 --- /dev/null +++ b/tests/Neo.VM.Tests/Types/VMUTExecutionEngineState.cs @@ -0,0 +1,21 @@ +using Neo.Test.Converters; +using Neo.VM; +using Newtonsoft.Json; + +namespace Neo.Test.Types +{ + public class VMUTExecutionEngineState + { + [JsonProperty, JsonConverter(typeof(UppercaseEnum))] + public VMState State { get; set; } + + [JsonProperty] + public VMUTStackItem[] ResultStack { get; set; } + + [JsonProperty] + public VMUTExecutionContextState[] InvocationStack { get; set; } + + [JsonProperty] + public string ExceptionMessage { get; set; } + } +} diff --git a/tests/Neo.VM.Tests/Types/VMUTStackItem.cs b/tests/Neo.VM.Tests/Types/VMUTStackItem.cs new file mode 100644 index 0000000000..5bbca0ff9f --- /dev/null +++ b/tests/Neo.VM.Tests/Types/VMUTStackItem.cs @@ -0,0 +1,14 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace Neo.Test.Types +{ + public class VMUTStackItem + { + [JsonProperty] + public VMUTStackItemType Type { get; set; } + + [JsonProperty] + public JToken Value { get; set; } + } +} diff --git a/tests/Neo.VM.Tests/Types/VMUTStackItemType.cs b/tests/Neo.VM.Tests/Types/VMUTStackItemType.cs new file mode 100644 index 0000000000..c11c5c86b9 --- /dev/null +++ b/tests/Neo.VM.Tests/Types/VMUTStackItemType.cs @@ -0,0 +1,60 @@ +namespace Neo.Test.Types +{ + public enum VMUTStackItemType + { + /// + /// Null + /// + Null, + + /// + /// An address of function + /// + Pointer, + + /// + /// Boolean (true,false) + /// + Boolean, + + /// + /// ByteString + /// + ByteString, + + /// + /// ByteString as UTF8 string + /// + String, + + /// + /// Mutable byte array + /// + Buffer, + + /// + /// InteropInterface + /// + Interop, + + /// + /// BigInteger + /// + Integer, + + /// + /// Array + /// + Array, + + /// + /// Struct + /// + Struct, + + /// + /// Map + /// + Map + } +} diff --git a/tests/Neo.VM.Tests/Types/VMUTStep.cs b/tests/Neo.VM.Tests/Types/VMUTStep.cs new file mode 100644 index 0000000000..d0d88e0ca4 --- /dev/null +++ b/tests/Neo.VM.Tests/Types/VMUTStep.cs @@ -0,0 +1,16 @@ +using Newtonsoft.Json; + +namespace Neo.Test.Types +{ + public class VMUTStep + { + [JsonProperty] + public string Name { get; set; } + + [JsonProperty] + public VMUTActionType[] Actions { get; set; } + + [JsonProperty] + public VMUTExecutionEngineState Result { get; set; } + } +} diff --git a/tests/Neo.VM.Tests/UtDebugger.cs b/tests/Neo.VM.Tests/UtDebugger.cs new file mode 100644 index 0000000000..7b7f582416 --- /dev/null +++ b/tests/Neo.VM.Tests/UtDebugger.cs @@ -0,0 +1,207 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.VM; + +namespace Neo.Test +{ + [TestClass] + public class UtDebugger + { + [TestMethod] + public void TestBreakPoint() + { + using ExecutionEngine engine = new(); + using ScriptBuilder script = new(); + script.Emit(OpCode.NOP); + script.Emit(OpCode.NOP); + script.Emit(OpCode.NOP); + script.Emit(OpCode.NOP); + + engine.LoadScript(script.ToArray()); + + Debugger debugger = new(engine); + + Assert.IsFalse(debugger.RemoveBreakPoint(engine.CurrentContext.Script, 3)); + + Assert.AreEqual(OpCode.NOP, engine.CurrentContext.NextInstruction.OpCode); + + debugger.AddBreakPoint(engine.CurrentContext.Script, 2); + debugger.AddBreakPoint(engine.CurrentContext.Script, 3); + debugger.Execute(); + Assert.AreEqual(OpCode.NOP, engine.CurrentContext.NextInstruction.OpCode); + Assert.AreEqual(2, engine.CurrentContext.InstructionPointer); + Assert.AreEqual(VMState.BREAK, engine.State); + + Assert.IsTrue(debugger.RemoveBreakPoint(engine.CurrentContext.Script, 2)); + Assert.IsFalse(debugger.RemoveBreakPoint(engine.CurrentContext.Script, 2)); + Assert.IsTrue(debugger.RemoveBreakPoint(engine.CurrentContext.Script, 3)); + Assert.IsFalse(debugger.RemoveBreakPoint(engine.CurrentContext.Script, 3)); + debugger.Execute(); + Assert.AreEqual(VMState.HALT, engine.State); + } + + [TestMethod] + public void TestWithoutBreakPoints() + { + using ExecutionEngine engine = new(); + using ScriptBuilder script = new(); + script.Emit(OpCode.NOP); + script.Emit(OpCode.NOP); + script.Emit(OpCode.NOP); + script.Emit(OpCode.NOP); + + engine.LoadScript(script.ToArray()); + + Debugger debugger = new(engine); + + Assert.AreEqual(OpCode.NOP, engine.CurrentContext.NextInstruction.OpCode); + + debugger.Execute(); + + Assert.IsNull(engine.CurrentContext); + Assert.AreEqual(VMState.HALT, engine.State); + } + + [TestMethod] + public void TestWithoutDebugger() + { + using ExecutionEngine engine = new(); + using ScriptBuilder script = new(); + script.Emit(OpCode.NOP); + script.Emit(OpCode.NOP); + script.Emit(OpCode.NOP); + script.Emit(OpCode.NOP); + + engine.LoadScript(script.ToArray()); + + Assert.AreEqual(OpCode.NOP, engine.CurrentContext.NextInstruction.OpCode); + + engine.Execute(); + + Assert.IsNull(engine.CurrentContext); + Assert.AreEqual(VMState.HALT, engine.State); + } + + [TestMethod] + public void TestStepOver() + { + using ExecutionEngine engine = new(); + using ScriptBuilder script = new(); + /* ┌ CALL + │ ┌> NOT + │ │ RET + └> │ PUSH0 + └─┘ RET */ + script.EmitCall(4); + script.Emit(OpCode.NOT); + script.Emit(OpCode.RET); + script.Emit(OpCode.PUSH0); + script.Emit(OpCode.RET); + + engine.LoadScript(script.ToArray()); + + Debugger debugger = new(engine); + + Assert.AreEqual(OpCode.NOT, engine.CurrentContext.NextInstruction.OpCode); + Assert.AreEqual(VMState.BREAK, debugger.StepOver()); + Assert.AreEqual(2, engine.CurrentContext.InstructionPointer); + Assert.AreEqual(VMState.BREAK, engine.State); + Assert.AreEqual(OpCode.RET, engine.CurrentContext.NextInstruction.OpCode); + + debugger.Execute(); + + Assert.AreEqual(true, engine.ResultStack.Pop().GetBoolean()); + Assert.AreEqual(VMState.HALT, engine.State); + + // Test step over again + + Assert.AreEqual(VMState.HALT, debugger.StepOver()); + Assert.AreEqual(VMState.HALT, engine.State); + } + + [TestMethod] + public void TestStepInto() + { + using ExecutionEngine engine = new(); + using ScriptBuilder script = new(); + /* ┌ CALL + │ ┌> NOT + │ │ RET + └> │ PUSH0 + └─┘ RET */ + script.EmitCall(4); + script.Emit(OpCode.NOT); + script.Emit(OpCode.RET); + script.Emit(OpCode.PUSH0); + script.Emit(OpCode.RET); + + engine.LoadScript(script.ToArray()); + + Debugger debugger = new(engine); + + var context = engine.CurrentContext; + + Assert.AreEqual(context, engine.CurrentContext); + Assert.AreEqual(context, engine.EntryContext); + Assert.AreEqual(OpCode.NOT, engine.CurrentContext.NextInstruction.OpCode); + + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + + Assert.AreNotEqual(context, engine.CurrentContext); + Assert.AreEqual(context, engine.EntryContext); + Assert.AreEqual(OpCode.RET, engine.CurrentContext.NextInstruction.OpCode); + + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + + Assert.AreEqual(context, engine.CurrentContext); + Assert.AreEqual(context, engine.EntryContext); + Assert.AreEqual(OpCode.RET, engine.CurrentContext.NextInstruction.OpCode); + + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(VMState.HALT, debugger.StepInto()); + + Assert.AreEqual(true, engine.ResultStack.Pop().GetBoolean()); + Assert.AreEqual(VMState.HALT, engine.State); + + // Test step into again + + Assert.AreEqual(VMState.HALT, debugger.StepInto()); + Assert.AreEqual(VMState.HALT, engine.State); + } + + [TestMethod] + public void TestBreakPointStepOver() + { + using ExecutionEngine engine = new(); + using ScriptBuilder script = new(); + /* ┌ CALL + │ ┌> NOT + │ │ RET + └>X│ PUSH0 + └┘ RET */ + script.EmitCall(4); + script.Emit(OpCode.NOT); + script.Emit(OpCode.RET); + script.Emit(OpCode.PUSH0); + script.Emit(OpCode.RET); + + engine.LoadScript(script.ToArray()); + + Debugger debugger = new(engine); + + Assert.AreEqual(OpCode.NOT, engine.CurrentContext.NextInstruction.OpCode); + + debugger.AddBreakPoint(engine.CurrentContext.Script, 5); + Assert.AreEqual(VMState.BREAK, debugger.StepOver()); + + Assert.IsNull(engine.CurrentContext.NextInstruction); + Assert.AreEqual(5, engine.CurrentContext.InstructionPointer); + Assert.AreEqual(VMState.BREAK, engine.State); + + debugger.Execute(); + + Assert.AreEqual(true, engine.ResultStack.Pop().GetBoolean()); + Assert.AreEqual(VMState.HALT, engine.State); + } + } +} diff --git a/tests/Neo.VM.Tests/UtEvaluationStack.cs b/tests/Neo.VM.Tests/UtEvaluationStack.cs new file mode 100644 index 0000000000..b8853b39ec --- /dev/null +++ b/tests/Neo.VM.Tests/UtEvaluationStack.cs @@ -0,0 +1,191 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.VM; +using Neo.VM.Types; +using System; +using System.Collections; +using System.Linq; + +namespace Neo.Test +{ + [TestClass] + public class UtEvaluationStack + { + private static EvaluationStack CreateOrderedStack(int count) + { + var check = new Integer[count]; + var stack = new EvaluationStack(new ReferenceCounter()); + + for (int x = 1; x <= count; x++) + { + stack.Push(x); + check[x - 1] = x; + } + + Assert.AreEqual(count, stack.Count); + CollectionAssert.AreEqual(check, stack.ToArray()); + + return stack; + } + + public static IEnumerable GetEnumerable(IEnumerator enumerator) + { + while (enumerator.MoveNext()) yield return enumerator.Current; + } + + [TestMethod] + public void TestClear() + { + var stack = CreateOrderedStack(3); + stack.Clear(); + Assert.AreEqual(0, stack.Count); + } + + [TestMethod] + public void TestCopyTo() + { + var stack = CreateOrderedStack(3); + var copy = new EvaluationStack(new ReferenceCounter()); + + Assert.ThrowsException(() => stack.CopyTo(copy, -2)); + Assert.ThrowsException(() => stack.CopyTo(copy, 4)); + + stack.CopyTo(copy, 0); + + Assert.AreEqual(3, stack.Count); + Assert.AreEqual(0, copy.Count); + CollectionAssert.AreEqual(new Integer[] { 1, 2, 3 }, stack.ToArray()); + + stack.CopyTo(copy, -1); + + Assert.AreEqual(3, stack.Count); + Assert.AreEqual(3, copy.Count); + CollectionAssert.AreEqual(new Integer[] { 1, 2, 3 }, stack.ToArray()); + + // Test IEnumerable + + var enumerable = (IEnumerable)copy; + var enumerator = enumerable.GetEnumerator(); + + CollectionAssert.AreEqual(new Integer[] { 1, 2, 3 }, GetEnumerable(enumerator).Cast().ToArray()); + + copy.CopyTo(stack, 2); + + Assert.AreEqual(5, stack.Count); + Assert.AreEqual(3, copy.Count); + + CollectionAssert.AreEqual(new Integer[] { 1, 2, 3, 2, 3 }, stack.ToArray()); + CollectionAssert.AreEqual(new Integer[] { 1, 2, 3 }, copy.ToArray()); + } + + [TestMethod] + public void TestMoveTo() + { + var stack = CreateOrderedStack(3); + var other = new EvaluationStack(new ReferenceCounter()); + + stack.MoveTo(other, 0); + + Assert.AreEqual(3, stack.Count); + Assert.AreEqual(0, other.Count); + CollectionAssert.AreEqual(new Integer[] { 1, 2, 3 }, stack.ToArray()); + + stack.MoveTo(other, -1); + + Assert.AreEqual(0, stack.Count); + Assert.AreEqual(3, other.Count); + CollectionAssert.AreEqual(new Integer[] { 1, 2, 3 }, other.ToArray()); + + // Test IEnumerable + + var enumerable = (IEnumerable)other; + var enumerator = enumerable.GetEnumerator(); + + CollectionAssert.AreEqual(new Integer[] { 1, 2, 3 }, GetEnumerable(enumerator).Cast().ToArray()); + + other.MoveTo(stack, 2); + + Assert.AreEqual(2, stack.Count); + Assert.AreEqual(1, other.Count); + + CollectionAssert.AreEqual(new Integer[] { 2, 3 }, stack.ToArray()); + CollectionAssert.AreEqual(new Integer[] { 1 }, other.ToArray()); + } + + [TestMethod] + public void TestInsertPeek() + { + var stack = new EvaluationStack(new ReferenceCounter()); + + stack.Insert(0, 3); + stack.Insert(1, 1); + stack.Insert(1, 2); + + Assert.ThrowsException(() => stack.Insert(4, 2)); + + Assert.AreEqual(3, stack.Count); + CollectionAssert.AreEqual(new Integer[] { 1, 2, 3 }, stack.ToArray()); + + Assert.AreEqual(3, stack.Peek(0)); + Assert.AreEqual(2, stack.Peek(1)); + Assert.AreEqual(1, stack.Peek(-1)); + + Assert.ThrowsException(() => stack.Peek(-4)); + } + + [TestMethod] + public void TestPopPush() + { + var stack = CreateOrderedStack(3); + + Assert.AreEqual(3, stack.Pop()); + Assert.AreEqual(2, stack.Pop()); + Assert.AreEqual(1, stack.Pop()); + + Assert.ThrowsException(() => stack.Pop()); + + stack = CreateOrderedStack(3); + + Assert.IsTrue(stack.Pop().Equals(3)); + Assert.IsTrue(stack.Pop().Equals(2)); + Assert.IsTrue(stack.Pop().Equals(1)); + + Assert.ThrowsException(() => stack.Pop()); + } + + [TestMethod] + public void TestRemove() + { + var stack = CreateOrderedStack(3); + + Assert.IsTrue(stack.Remove(0).Equals(3)); + Assert.IsTrue(stack.Remove(0).Equals(2)); + Assert.IsTrue(stack.Remove(-1).Equals(1)); + + Assert.ThrowsException(() => stack.Remove(0)); + Assert.ThrowsException(() => stack.Remove(-1)); + } + + [TestMethod] + public void TestReverse() + { + var stack = CreateOrderedStack(3); + + stack.Reverse(3); + Assert.IsTrue(stack.Pop().Equals(1)); + Assert.IsTrue(stack.Pop().Equals(2)); + Assert.IsTrue(stack.Pop().Equals(3)); + Assert.ThrowsException(() => stack.Pop().Equals(0)); + + stack = CreateOrderedStack(3); + + Assert.ThrowsException(() => stack.Reverse(-1)); + Assert.ThrowsException(() => stack.Reverse(4)); + + stack.Reverse(1); + Assert.IsTrue(stack.Pop().Equals(3)); + Assert.IsTrue(stack.Pop().Equals(2)); + Assert.IsTrue(stack.Pop().Equals(1)); + Assert.ThrowsException(() => stack.Pop().Equals(0)); + } + } +} diff --git a/tests/Neo.VM.Tests/UtExecutionContext.cs b/tests/Neo.VM.Tests/UtExecutionContext.cs new file mode 100644 index 0000000000..cad2bc0f3e --- /dev/null +++ b/tests/Neo.VM.Tests/UtExecutionContext.cs @@ -0,0 +1,55 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.VM; +using System; +using System.Collections.Generic; + +namespace Neo.Test +{ + [TestClass] + public class UtExecutionContext + { + class TestState + { + public bool Flag = false; + } + + [TestMethod] + public void StateTest() + { + var context = new ExecutionContext(Array.Empty(), -1, new ReferenceCounter()); + + // Test factory + + var flag = context.GetState(() => new TestState() { Flag = true }); + Assert.IsTrue(flag.Flag); + + flag.Flag = false; + + flag = context.GetState(() => new TestState() { Flag = true }); + Assert.IsFalse(flag.Flag); + + // Test new + + var stack = context.GetState>(); + Assert.AreEqual(0, stack.Count); + stack.Push(100); + stack = context.GetState>(); + Assert.AreEqual(100, stack.Pop()); + stack.Push(100); + + // Test clone + + var copy = context.Clone(); + var copyStack = copy.GetState>(); + Assert.AreEqual(1, copyStack.Count); + copyStack.Push(200); + copyStack = context.GetState>(); + Assert.AreEqual(200, copyStack.Pop()); + Assert.AreEqual(100, copyStack.Pop()); + copyStack.Push(200); + + stack = context.GetState>(); + Assert.AreEqual(200, stack.Pop()); + } + } +} diff --git a/tests/Neo.VM.Tests/UtReferenceCounter.cs b/tests/Neo.VM.Tests/UtReferenceCounter.cs new file mode 100644 index 0000000000..3a877eac83 --- /dev/null +++ b/tests/Neo.VM.Tests/UtReferenceCounter.cs @@ -0,0 +1,167 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.VM; +using Neo.VM.Types; + +namespace Neo.Test +{ + [TestClass] + public class UtReferenceCounter + { + [TestMethod] + public void TestCircularReferences() + { + using ScriptBuilder sb = new(); + sb.Emit(OpCode.INITSSLOT, new byte[] { 1 }); //{}|{null}:1 + sb.EmitPush(0); //{0}|{null}:2 + sb.Emit(OpCode.NEWARRAY); //{A[]}|{null}:2 + sb.Emit(OpCode.DUP); //{A[],A[]}|{null}:3 + sb.Emit(OpCode.DUP); //{A[],A[],A[]}|{null}:4 + sb.Emit(OpCode.APPEND); //{A[A]}|{null}:3 + sb.Emit(OpCode.DUP); //{A[A],A[A]}|{null}:4 + sb.EmitPush(0); //{A[A],A[A],0}|{null}:5 + sb.Emit(OpCode.NEWARRAY); //{A[A],A[A],B[]}|{null}:5 + sb.Emit(OpCode.STSFLD0); //{A[A],A[A]}|{B[]}:4 + sb.Emit(OpCode.LDSFLD0); //{A[A],A[A],B[]}|{B[]}:5 + sb.Emit(OpCode.APPEND); //{A[A,B]}|{B[]}:4 + sb.Emit(OpCode.LDSFLD0); //{A[A,B],B[]}|{B[]}:5 + sb.EmitPush(0); //{A[A,B],B[],0}|{B[]}:6 + sb.Emit(OpCode.NEWARRAY); //{A[A,B],B[],C[]}|{B[]}:6 + sb.Emit(OpCode.TUCK); //{A[A,B],C[],B[],C[]}|{B[]}:7 + sb.Emit(OpCode.APPEND); //{A[A,B],C[]}|{B[C]}:6 + sb.EmitPush(0); //{A[A,B],C[],0}|{B[C]}:7 + sb.Emit(OpCode.NEWARRAY); //{A[A,B],C[],D[]}|{B[C]}:7 + sb.Emit(OpCode.TUCK); //{A[A,B],D[],C[],D[]}|{B[C]}:8 + sb.Emit(OpCode.APPEND); //{A[A,B],D[]}|{B[C[D]]}:7 + sb.Emit(OpCode.LDSFLD0); //{A[A,B],D[],B[C]}|{B[C[D]]}:8 + sb.Emit(OpCode.APPEND); //{A[A,B]}|{B[C[D[B]]]}:7 + sb.Emit(OpCode.PUSHNULL); //{A[A,B],null}|{B[C[D[B]]]}:8 + sb.Emit(OpCode.STSFLD0); //{A[A,B[C[D[B]]]]}|{null}:7 + sb.Emit(OpCode.DUP); //{A[A,B[C[D[B]]]],A[A,B]}|{null}:8 + sb.EmitPush(1); //{A[A,B[C[D[B]]]],A[A,B],1}|{null}:9 + sb.Emit(OpCode.REMOVE); //{A[A]}|{null}:3 + sb.Emit(OpCode.STSFLD0); //{}|{A[A]}:2 + sb.Emit(OpCode.RET); //{}:0 + + using ExecutionEngine engine = new(); + Debugger debugger = new(engine); + engine.LoadScript(sb.ToArray()); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(1, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(2, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(2, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(3, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(4, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(3, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(4, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(5, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(5, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(4, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(5, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(4, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(5, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(6, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(6, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(7, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(6, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(7, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(7, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(8, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(7, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(8, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(7, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(8, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(7, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(8, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(9, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(3, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(2, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.HALT, debugger.Execute()); + Assert.AreEqual(0, engine.ReferenceCounter.Count); + } + + [TestMethod] + public void TestRemoveReferrer() + { + using ScriptBuilder sb = new(); + sb.Emit(OpCode.INITSSLOT, new byte[] { 1 }); //{}|{null}:1 + sb.EmitPush(0); //{0}|{null}:2 + sb.Emit(OpCode.NEWARRAY); //{A[]}|{null}:2 + sb.Emit(OpCode.DUP); //{A[],A[]}|{null}:3 + sb.EmitPush(0); //{A[],A[],0}|{null}:4 + sb.Emit(OpCode.NEWARRAY); //{A[],A[],B[]}|{null}:4 + sb.Emit(OpCode.STSFLD0); //{A[],A[]}|{B[]}:3 + sb.Emit(OpCode.LDSFLD0); //{A[],A[],B[]}|{B[]}:4 + sb.Emit(OpCode.APPEND); //{A[B]}|{B[]}:3 + sb.Emit(OpCode.DROP); //{}|{B[]}:1 + sb.Emit(OpCode.RET); //{}:0 + + using ExecutionEngine engine = new(); + Debugger debugger = new(engine); + engine.LoadScript(sb.ToArray()); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(1, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(2, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(2, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(3, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(4, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(4, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(3, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(4, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(3, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.BREAK, debugger.StepInto()); + Assert.AreEqual(1, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.HALT, debugger.Execute()); + Assert.AreEqual(0, engine.ReferenceCounter.Count); + } + + [TestMethod] + public void TestArrayNoPush() + { + using ScriptBuilder sb = new(); + sb.Emit(OpCode.RET); + using ExecutionEngine engine = new(); + engine.LoadScript(sb.ToArray()); + Assert.AreEqual(0, engine.ReferenceCounter.Count); + Array array = new(engine.ReferenceCounter, new StackItem[] { 1, 2, 3, 4 }); + Assert.AreEqual(array.Count, engine.ReferenceCounter.Count); + Assert.AreEqual(VMState.HALT, engine.Execute()); + Assert.AreEqual(0, engine.ReferenceCounter.Count); + } + } +} diff --git a/tests/Neo.VM.Tests/UtScript.cs b/tests/Neo.VM.Tests/UtScript.cs new file mode 100644 index 0000000000..7e5c401488 --- /dev/null +++ b/tests/Neo.VM.Tests/UtScript.cs @@ -0,0 +1,93 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.VM; +using System; +using System.Text; + +namespace Neo.Test +{ + [TestClass] + public class UtScript + { + [TestMethod] + public void Conversion() + { + byte[] rawScript; + using (var builder = new ScriptBuilder()) + { + builder.Emit(OpCode.PUSH0); + builder.Emit(OpCode.CALL, new byte[] { 0x00, 0x01 }); + builder.EmitSysCall(123); + + rawScript = builder.ToArray(); + } + + var script = new Script(rawScript); + + ReadOnlyMemory scriptConversion = script; + Assert.AreEqual(rawScript, scriptConversion); + } + + [TestMethod] + public void StrictMode() + { + var rawScript = new byte[] { (byte)OpCode.PUSH0, 0xFF }; + Assert.ThrowsException(() => new Script(rawScript, true)); + + var script = new Script(rawScript, false); + Assert.AreEqual(2, script.Length); + + rawScript = new byte[] { (byte)OpCode.PUSHDATA1 }; + Assert.ThrowsException(() => new Script(rawScript, true)); + + rawScript = new byte[] { (byte)OpCode.PUSHDATA2 }; + Assert.ThrowsException(() => new Script(rawScript, true)); + + rawScript = new byte[] { (byte)OpCode.PUSHDATA4 }; + Assert.ThrowsException(() => new Script(rawScript, true)); + } + + [TestMethod] + public void Parse() + { + Script script; + + using (var builder = new ScriptBuilder()) + { + builder.Emit(OpCode.PUSH0); + builder.Emit(OpCode.CALL_L, new byte[] { 0x00, 0x01, 0x00, 0x00 }); + builder.EmitSysCall(123); + + script = new Script(builder.ToArray()); + } + + Assert.AreEqual(11, script.Length); + + var ins = script.GetInstruction(0); + + Assert.AreEqual(OpCode.PUSH0, ins.OpCode); + Assert.IsTrue(ins.Operand.IsEmpty); + Assert.AreEqual(1, ins.Size); + Assert.ThrowsException(() => { var x = ins.TokenI16; }); + Assert.ThrowsException(() => { var x = ins.TokenU32; }); + + ins = script.GetInstruction(1); + + Assert.AreEqual(OpCode.CALL_L, ins.OpCode); + CollectionAssert.AreEqual(new byte[] { 0x00, 0x01, 0x00, 0x00 }, ins.Operand.ToArray()); + Assert.AreEqual(5, ins.Size); + Assert.AreEqual(256, ins.TokenI32); + Assert.AreEqual(Encoding.ASCII.GetString(new byte[] { 0x00, 0x01, 0x00, 0x00 }), ins.TokenString); + + ins = script.GetInstruction(6); + + Assert.AreEqual(OpCode.SYSCALL, ins.OpCode); + CollectionAssert.AreEqual(new byte[] { 123, 0x00, 0x00, 0x00 }, ins.Operand.ToArray()); + Assert.AreEqual(5, ins.Size); + Assert.AreEqual(123, ins.TokenI16); + Assert.AreEqual(Encoding.ASCII.GetString(new byte[] { 123, 0x00, 0x00, 0x00 }), ins.TokenString); + Assert.AreEqual(123U, ins.TokenU32); + + Assert.ThrowsException(() => script.GetInstruction(100)); + } + } +} diff --git a/tests/Neo.VM.Tests/UtScriptBuilder.cs b/tests/Neo.VM.Tests/UtScriptBuilder.cs new file mode 100644 index 0000000000..006e8f0acd --- /dev/null +++ b/tests/Neo.VM.Tests/UtScriptBuilder.cs @@ -0,0 +1,264 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Test.Extensions; +using Neo.Test.Helpers; +using Neo.VM; +using System; +using System.Linq; +using System.Numerics; +using System.Text; + +namespace Neo.Test +{ + [TestClass] + public class UtScriptBuilder + { + [TestMethod] + public void TestEmit() + { + using (ScriptBuilder script = new()) + { + Assert.AreEqual(0, script.Length); + script.Emit(OpCode.NOP); + Assert.AreEqual(1, script.Length); + + CollectionAssert.AreEqual(new byte[] { 0x21 }, script.ToArray()); + } + + using (ScriptBuilder script = new()) + { + script.Emit(OpCode.NOP, new byte[] { 0x66 }); + CollectionAssert.AreEqual(new byte[] { 0x21, 0x66 }, script.ToArray()); + } + } + + [TestMethod] + public void TestBigInteger() + { + using (ScriptBuilder script = new()) + { + Assert.AreEqual(0, script.Length); + script.EmitPush(-100000); + Assert.AreEqual(5, script.Length); + + CollectionAssert.AreEqual(new byte[] { 2, 96, 121, 254, 255 }, script.ToArray()); + } + + using (ScriptBuilder script = new()) + { + Assert.AreEqual(0, script.Length); + script.EmitPush(100000); + Assert.AreEqual(5, script.Length); + + CollectionAssert.AreEqual(new byte[] { 2, 160, 134, 1, 0 }, script.ToArray()); + } + } + + [TestMethod] + public void TestEmitSysCall() + { + using ScriptBuilder script = new(); + script.EmitSysCall(0xE393C875); + CollectionAssert.AreEqual(new byte[] { (byte)OpCode.SYSCALL, 0x75, 0xC8, 0x93, 0xE3 }.ToArray(), script.ToArray()); + } + + [TestMethod] + public void TestEmitCall() + { + using (ScriptBuilder script = new()) + { + script.EmitCall(0); + CollectionAssert.AreEqual(new[] { (byte)OpCode.CALL, (byte)0 }, script.ToArray()); + } + using (ScriptBuilder script = new()) + { + script.EmitCall(12345); + CollectionAssert.AreEqual(new[] { (byte)OpCode.CALL_L }.Concat(BitConverter.GetBytes(12345)).ToArray(), script.ToArray()); + } + using (ScriptBuilder script = new()) + { + script.EmitCall(-12345); + CollectionAssert.AreEqual(new[] { (byte)OpCode.CALL_L }.Concat(BitConverter.GetBytes(-12345)).ToArray(), script.ToArray()); + } + } + + [TestMethod] + public void TestEmitJump() + { + var offset_i8 = sbyte.MaxValue; + var offset_i32 = int.MaxValue; + + foreach (OpCode op in Enum.GetValues(typeof(OpCode))) + { + using ScriptBuilder script = new(); + if (op < OpCode.JMP || op > OpCode.JMPLE_L) + { + Assert.ThrowsException(() => script.EmitJump(op, offset_i8)); + Assert.ThrowsException(() => script.EmitJump(op, offset_i32)); + } + else + { + script.EmitJump(op, offset_i8); + script.EmitJump(op, offset_i32); + if ((int)op % 2 == 0) + CollectionAssert.AreEqual(new[] { (byte)op, (byte)offset_i8, (byte)(op + 1) }.Concat(BitConverter.GetBytes(offset_i32)).ToArray(), script.ToArray()); + else + CollectionAssert.AreEqual(new[] { (byte)op }.Concat(BitConverter.GetBytes((int)offset_i8)).Concat(new[] { (byte)op }).Concat(BitConverter.GetBytes(offset_i32)).ToArray(), script.ToArray()); + } + } + + offset_i8 = sbyte.MinValue; + offset_i32 = int.MinValue; + + foreach (OpCode op in Enum.GetValues(typeof(OpCode))) + { + using ScriptBuilder script = new(); + if (op < OpCode.JMP || op > OpCode.JMPLE_L) + { + Assert.ThrowsException(() => script.EmitJump(op, offset_i8)); + Assert.ThrowsException(() => script.EmitJump(op, offset_i32)); + } + else + { + script.EmitJump(op, offset_i8); + script.EmitJump(op, offset_i32); + if ((int)op % 2 == 0) + CollectionAssert.AreEqual(new[] { (byte)op, (byte)offset_i8, (byte)(op + 1) }.Concat(BitConverter.GetBytes(offset_i32)).ToArray(), script.ToArray()); + else + CollectionAssert.AreEqual(new[] { (byte)op }.Concat(BitConverter.GetBytes((int)offset_i8)).Concat(new[] { (byte)op }).Concat(BitConverter.GetBytes(offset_i32)).ToArray(), script.ToArray()); + } + } + } + + [TestMethod] + public void TestEmitPushBigInteger() + { + using (ScriptBuilder script = new()) + { + script.EmitPush(BigInteger.MinusOne); + CollectionAssert.AreEqual(new byte[] { 0x0F }, script.ToArray()); + } + + using (ScriptBuilder script = new()) + { + script.EmitPush(BigInteger.Zero); + CollectionAssert.AreEqual(new byte[] { 0x10 }, script.ToArray()); + } + + for (byte x = 1; x <= 16; x++) + { + using ScriptBuilder script = new(); + script.EmitPush(new BigInteger(x)); + CollectionAssert.AreEqual(new byte[] { (byte)(OpCode.PUSH0 + x) }, script.ToArray()); + } + + CollectionAssert.AreEqual("0080".FromHexString(), new ScriptBuilder().EmitPush(sbyte.MinValue).ToArray()); + CollectionAssert.AreEqual("007f".FromHexString(), new ScriptBuilder().EmitPush(sbyte.MaxValue).ToArray()); + CollectionAssert.AreEqual("01ff00".FromHexString(), new ScriptBuilder().EmitPush(byte.MaxValue).ToArray()); + CollectionAssert.AreEqual("010080".FromHexString(), new ScriptBuilder().EmitPush(short.MinValue).ToArray()); + CollectionAssert.AreEqual("01ff7f".FromHexString(), new ScriptBuilder().EmitPush(short.MaxValue).ToArray()); + CollectionAssert.AreEqual("02ffff0000".FromHexString(), new ScriptBuilder().EmitPush(ushort.MaxValue).ToArray()); + CollectionAssert.AreEqual("0200000080".FromHexString(), new ScriptBuilder().EmitPush(int.MinValue).ToArray()); + CollectionAssert.AreEqual("02ffffff7f".FromHexString(), new ScriptBuilder().EmitPush(int.MaxValue).ToArray()); + CollectionAssert.AreEqual("03ffffffff00000000".FromHexString(), new ScriptBuilder().EmitPush(uint.MaxValue).ToArray()); + CollectionAssert.AreEqual("030000000000000080".FromHexString(), new ScriptBuilder().EmitPush(long.MinValue).ToArray()); + CollectionAssert.AreEqual("03ffffffffffffff7f".FromHexString(), new ScriptBuilder().EmitPush(long.MaxValue).ToArray()); + CollectionAssert.AreEqual("04ffffffffffffffff0000000000000000".FromHexString(), new ScriptBuilder().EmitPush(ulong.MaxValue).ToArray()); + CollectionAssert.AreEqual("050100000000000000feffffffffffffff00000000000000000000000000000000".FromHexString(), new ScriptBuilder().EmitPush(new BigInteger(ulong.MaxValue) * new BigInteger(ulong.MaxValue)).ToArray()); + + Assert.ThrowsException(() => new ScriptBuilder().EmitPush( + new BigInteger("050100000000000000feffffffffffffff0100000000000000feffffffffffffff00000000000000000000000000000000".FromHexString()))); + } + + [TestMethod] + public void TestEmitPushBool() + { + using (ScriptBuilder script = new()) + { + script.EmitPush(true); + CollectionAssert.AreEqual(new byte[] { (byte)OpCode.PUSHT }, script.ToArray()); + } + + using (ScriptBuilder script = new()) + { + script.EmitPush(false); + CollectionAssert.AreEqual(new byte[] { (byte)OpCode.PUSHF }, script.ToArray()); + } + } + + [TestMethod] + public void TestEmitPushReadOnlySpan() + { + using ScriptBuilder script = new(); + var data = new byte[] { 0x01, 0x02 }; + script.EmitPush(new ReadOnlySpan(data)); + + CollectionAssert.AreEqual(new byte[] { (byte)OpCode.PUSHDATA1, (byte)data.Length }.Concat(data).ToArray(), script.ToArray()); + } + + [TestMethod] + public void TestEmitPushByteArray() + { + using (ScriptBuilder script = new()) + { + Assert.ThrowsException(() => script.EmitPush((byte[])null)); + } + + using (ScriptBuilder script = new()) + { + var data = RandomHelper.RandBuffer(0x4C); + + script.EmitPush(data); + CollectionAssert.AreEqual(new byte[] { (byte)OpCode.PUSHDATA1, (byte)data.Length }.Concat(data).ToArray(), script.ToArray()); + } + + using (ScriptBuilder script = new()) + { + var data = RandomHelper.RandBuffer(0x100); + + script.EmitPush(data); + CollectionAssert.AreEqual(new byte[] { (byte)OpCode.PUSHDATA2 }.Concat(BitConverter.GetBytes((short)data.Length)).Concat(data).ToArray(), script.ToArray()); + } + + using (ScriptBuilder script = new()) + { + var data = RandomHelper.RandBuffer(0x10000); + + script.EmitPush(data); + CollectionAssert.AreEqual(new byte[] { (byte)OpCode.PUSHDATA4 }.Concat(BitConverter.GetBytes(data.Length)).Concat(data).ToArray(), script.ToArray()); + } + } + + [TestMethod] + public void TestEmitPushString() + { + using (ScriptBuilder script = new()) + { + Assert.ThrowsException(() => script.EmitPush((string)null)); + } + + using (ScriptBuilder script = new()) + { + var data = RandomHelper.RandString(0x4C); + + script.EmitPush(data); + CollectionAssert.AreEqual(new byte[] { (byte)OpCode.PUSHDATA1, (byte)data.Length }.Concat(Encoding.UTF8.GetBytes(data)).ToArray(), script.ToArray()); + } + + using (ScriptBuilder script = new()) + { + var data = RandomHelper.RandString(0x100); + + script.EmitPush(data); + CollectionAssert.AreEqual(new byte[] { (byte)OpCode.PUSHDATA2 }.Concat(BitConverter.GetBytes((short)data.Length)).Concat(Encoding.UTF8.GetBytes(data)).ToArray(), script.ToArray()); + } + + using (ScriptBuilder script = new()) + { + var data = RandomHelper.RandString(0x10000); + + script.EmitPush(data); + CollectionAssert.AreEqual(new byte[] { (byte)OpCode.PUSHDATA4 }.Concat(BitConverter.GetBytes(data.Length)).Concat(Encoding.UTF8.GetBytes(data)).ToArray(), script.ToArray()); + } + } + } +} diff --git a/tests/Neo.VM.Tests/UtSlot.cs b/tests/Neo.VM.Tests/UtSlot.cs new file mode 100644 index 0000000000..1e3403d650 --- /dev/null +++ b/tests/Neo.VM.Tests/UtSlot.cs @@ -0,0 +1,90 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.VM; +using Neo.VM.Types; +using System; +using System.Collections; +using System.Linq; +using System.Numerics; + +namespace Neo.Test +{ + [TestClass] + public class UtSlot + { + private static Slot CreateOrderedSlot(int count) + { + var check = new Integer[count]; + + for (int x = 1; x <= count; x++) + { + check[x - 1] = x; + } + + var slot = new Slot(check, new ReferenceCounter()); + + Assert.AreEqual(count, slot.Count); + CollectionAssert.AreEqual(check, slot.ToArray()); + + return slot; + } + + public static IEnumerable GetEnumerable(IEnumerator enumerator) + { + while (enumerator.MoveNext()) yield return enumerator.Current; + } + + [TestMethod] + public void TestGet() + { + var slot = CreateOrderedSlot(3); + + Assert.IsTrue(slot[0] is Integer item0 && item0.Equals(1)); + Assert.IsTrue(slot[1] is Integer item1 && item1.Equals(2)); + Assert.IsTrue(slot[2] is Integer item2 && item2.Equals(3)); + Assert.ThrowsException(() => slot[3] is Integer item3); + } + + [TestMethod] + public void TestEnumerable() + { + var slot = CreateOrderedSlot(3); + + BigInteger i = 1; + foreach (Integer item in slot) + { + Assert.AreEqual(item.GetInteger(), i); + i++; + } + + CollectionAssert.AreEqual(new Integer[] { 1, 2, 3 }, slot.ToArray()); + + // Test IEnumerable + + var enumerable = (IEnumerable)slot; + var enumerator = enumerable.GetEnumerator(); + + CollectionAssert.AreEqual(new Integer[] { 1, 2, 3 }, GetEnumerable(enumerator).Cast().ToArray()); + + Assert.AreEqual(3, slot.Count); + + CollectionAssert.AreEqual(new Integer[] { 1, 2, 3 }, slot.ToArray()); + + // Empty + + slot = CreateOrderedSlot(0); + + CollectionAssert.AreEqual(System.Array.Empty(), slot.ToArray()); + + // Test IEnumerable + + enumerable = (IEnumerable)slot; + enumerator = enumerable.GetEnumerator(); + + CollectionAssert.AreEqual(System.Array.Empty(), GetEnumerable(enumerator).Cast().ToArray()); + + Assert.AreEqual(0, slot.Count); + + CollectionAssert.AreEqual(System.Array.Empty(), slot.ToArray()); + } + } +} diff --git a/tests/Neo.VM.Tests/UtStackItem.cs b/tests/Neo.VM.Tests/UtStackItem.cs new file mode 100644 index 0000000000..5ca73ae796 --- /dev/null +++ b/tests/Neo.VM.Tests/UtStackItem.cs @@ -0,0 +1,199 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.VM; +using Neo.VM.Types; +using System.Numerics; + +namespace Neo.Test +{ + [TestClass] + public class UtStackItem + { + [TestMethod] + public void HashCodeTest() + { + StackItem itemA = "NEO"; + StackItem itemB = "NEO"; + StackItem itemC = "SmartEconomy"; + + Assert.IsTrue(itemA.GetHashCode() == itemB.GetHashCode()); + Assert.IsTrue(itemA.GetHashCode() != itemC.GetHashCode()); + + itemA = new VM.Types.Buffer(1); + itemB = new VM.Types.Buffer(1); + + Assert.IsTrue(itemA.GetHashCode() != itemB.GetHashCode()); + + itemA = true; + itemB = true; + itemC = false; + + Assert.IsTrue(itemA.GetHashCode() == itemB.GetHashCode()); + Assert.IsTrue(itemA.GetHashCode() != itemC.GetHashCode()); + + itemA = 1; + itemB = 1; + itemC = 123; + + Assert.IsTrue(itemA.GetHashCode() == itemB.GetHashCode()); + Assert.IsTrue(itemA.GetHashCode() != itemC.GetHashCode()); + + itemA = new Null(); + itemB = new Null(); + + Assert.IsTrue(itemA.GetHashCode() == itemB.GetHashCode()); + + itemA = new VM.Types.Array(); + + Assert.ThrowsException(() => itemA.GetHashCode()); + + itemA = new Struct(); + + Assert.ThrowsException(() => itemA.GetHashCode()); + + itemA = new Map(); + + Assert.ThrowsException(() => itemA.GetHashCode()); + + itemA = new InteropInterface(123); + itemB = new InteropInterface(123); + + Assert.IsTrue(itemA.GetHashCode() == itemB.GetHashCode()); + + var script = new Script(System.Array.Empty()); + itemA = new Pointer(script, 123); + itemB = new Pointer(script, 123); + itemC = new Pointer(script, 1234); + + Assert.IsTrue(itemA.GetHashCode() == itemB.GetHashCode()); + Assert.IsTrue(itemA.GetHashCode() != itemC.GetHashCode()); + } + + [TestMethod] + public void NullTest() + { + StackItem nullItem = System.Array.Empty(); + Assert.AreNotEqual(StackItem.Null, nullItem); + + nullItem = new Null(); + Assert.AreEqual(StackItem.Null, nullItem); + } + + [TestMethod] + public void EqualTest() + { + StackItem itemA = "NEO"; + StackItem itemB = "NEO"; + StackItem itemC = "SmartEconomy"; + StackItem itemD = "Smarteconomy"; + StackItem itemE = "smarteconomy"; + + Assert.IsTrue(itemA.Equals(itemB)); + Assert.IsFalse(itemA.Equals(itemC)); + Assert.IsFalse(itemC.Equals(itemD)); + Assert.IsFalse(itemD.Equals(itemE)); + Assert.IsFalse(itemA.Equals(new object())); + } + + [TestMethod] + public void CastTest() + { + // Signed byte + + StackItem item = sbyte.MaxValue; + + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(new BigInteger(sbyte.MaxValue), ((Integer)item).GetInteger()); + + // Unsigned byte + + item = byte.MaxValue; + + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(new BigInteger(byte.MaxValue), ((Integer)item).GetInteger()); + + // Signed short + + item = short.MaxValue; + + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(new BigInteger(short.MaxValue), ((Integer)item).GetInteger()); + + // Unsigned short + + item = ushort.MaxValue; + + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(new BigInteger(ushort.MaxValue), ((Integer)item).GetInteger()); + + // Signed integer + + item = int.MaxValue; + + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(new BigInteger(int.MaxValue), ((Integer)item).GetInteger()); + + // Unsigned integer + + item = uint.MaxValue; + + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(new BigInteger(uint.MaxValue), ((Integer)item).GetInteger()); + + // Signed long + + item = long.MaxValue; + + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(new BigInteger(long.MaxValue), ((Integer)item).GetInteger()); + + // Unsigned long + + item = ulong.MaxValue; + + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(new BigInteger(ulong.MaxValue), ((Integer)item).GetInteger()); + + // BigInteger + + item = BigInteger.MinusOne; + + Assert.IsInstanceOfType(item, typeof(Integer)); + Assert.AreEqual(new BigInteger(-1), ((Integer)item).GetInteger()); + + // Boolean + + item = true; + + Assert.IsInstanceOfType(item, typeof(VM.Types.Boolean)); + Assert.IsTrue(item.GetBoolean()); + + // ByteString + + item = new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09 }; + + Assert.IsInstanceOfType(item, typeof(ByteString)); + CollectionAssert.AreEqual(new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09 }, item.GetSpan().ToArray()); + } + + [TestMethod] + public void DeepCopyTest() + { + Array a = new() + { + true, + 1, + new byte[] { 1 }, + StackItem.Null, + new Buffer(new byte[] { 1 }), + new Map { [0] = 1, [2] = 3 }, + new Struct { 1, 2, 3 } + }; + a.Add(a); + Array aa = (Array)a.DeepCopy(); + Assert.AreNotEqual(a, aa); + Assert.AreSame(aa, aa[^1]); + Assert.IsTrue(a[^2].Equals(aa[^2], ExecutionEngineLimits.Default)); + Assert.AreNotSame(a[^2], aa[^2]); + } + } +} diff --git a/tests/Neo.VM.Tests/UtStruct.cs b/tests/Neo.VM.Tests/UtStruct.cs new file mode 100644 index 0000000000..eb66ca934b --- /dev/null +++ b/tests/Neo.VM.Tests/UtStruct.cs @@ -0,0 +1,64 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.VM; +using Neo.VM.Types; +using System; + +namespace Neo.Test +{ + [TestClass] + public class UtStruct + { + private readonly Struct @struct; + + public UtStruct() + { + @struct = new Struct { 1 }; + for (int i = 0; i < 20000; i++) + @struct = new Struct { @struct }; + } + + [TestMethod] + public void Clone() + { + Struct s1 = new() { 1, new Struct { 2 } }; + Struct s2 = s1.Clone(ExecutionEngineLimits.Default); + s1[0] = 3; + Assert.AreEqual(1, s2[0]); + ((Struct)s1[1])[0] = 3; + Assert.AreEqual(2, ((Struct)s2[1])[0]); + Assert.ThrowsException(() => @struct.Clone(ExecutionEngineLimits.Default)); + } + + [TestMethod] + public void Equals() + { + Struct s1 = new() { 1, new Struct { 2 } }; + Struct s2 = new() { 1, new Struct { 2 } }; + Assert.IsTrue(s1.Equals(s2, ExecutionEngineLimits.Default)); + Struct s3 = new() { 1, new Struct { 3 } }; + Assert.IsFalse(s1.Equals(s3, ExecutionEngineLimits.Default)); + Assert.ThrowsException(() => @struct.Equals(@struct.Clone(ExecutionEngineLimits.Default), ExecutionEngineLimits.Default)); + } + + [TestMethod] + public void EqualsDos() + { + string payloadStr = new string('h', 65535); + Struct s1 = new(); + Struct s2 = new(); + for (int i = 0; i < 2; i++) + { + s1.Add(payloadStr); + s2.Add(payloadStr); + } + Assert.ThrowsException(() => s1.Equals(s2, ExecutionEngineLimits.Default)); + + for (int i = 0; i < 1000; i++) + { + s1.Add(payloadStr); + s2.Add(payloadStr); + } + Assert.ThrowsException(() => s1.Equals(s2, ExecutionEngineLimits.Default)); + } + } +} diff --git a/tests/Neo.VM.Tests/UtUnsafe.cs b/tests/Neo.VM.Tests/UtUnsafe.cs new file mode 100644 index 0000000000..50c5ce59af --- /dev/null +++ b/tests/Neo.VM.Tests/UtUnsafe.cs @@ -0,0 +1,22 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.VM; + +namespace Neo.Test +{ + [TestClass] + public class UtUnsafe + { + [TestMethod] + public void NotZero() + { + Assert.IsFalse(Unsafe.NotZero(System.Array.Empty())); + Assert.IsFalse(Unsafe.NotZero(new byte[4])); + Assert.IsFalse(Unsafe.NotZero(new byte[8])); + Assert.IsFalse(Unsafe.NotZero(new byte[11])); + + Assert.IsTrue(Unsafe.NotZero(new byte[4] { 0x00, 0x00, 0x00, 0x01 })); + Assert.IsTrue(Unsafe.NotZero(new byte[8] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 })); + Assert.IsTrue(Unsafe.NotZero(new byte[11] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 })); + } + } +} diff --git a/tests/Neo.VM.Tests/UtUtility.cs b/tests/Neo.VM.Tests/UtUtility.cs new file mode 100644 index 0000000000..d833a57fdf --- /dev/null +++ b/tests/Neo.VM.Tests/UtUtility.cs @@ -0,0 +1,36 @@ +using System; +using System.Numerics; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.VM; + +namespace Neo.Test +{ + [TestClass] + public class UtUtility + { + [TestMethod] + public void SqrtTest() + { + Assert.ThrowsException(() => BigInteger.MinusOne.Sqrt()); + + Assert.AreEqual(BigInteger.Zero, BigInteger.Zero.Sqrt()); + Assert.AreEqual(new BigInteger(1), new BigInteger(1).Sqrt()); + Assert.AreEqual(new BigInteger(1), new BigInteger(2).Sqrt()); + Assert.AreEqual(new BigInteger(1), new BigInteger(3).Sqrt()); + Assert.AreEqual(new BigInteger(2), new BigInteger(4).Sqrt()); + Assert.AreEqual(new BigInteger(9), new BigInteger(81).Sqrt()); + } + + [TestMethod] + public void ModInverseTest() + { + Assert.ThrowsException(() => BigInteger.One.ModInverse(BigInteger.Zero)); + Assert.ThrowsException(() => BigInteger.One.ModInverse(BigInteger.One)); + Assert.ThrowsException(() => BigInteger.Zero.ModInverse(BigInteger.Zero)); + Assert.ThrowsException(() => BigInteger.Zero.ModInverse(BigInteger.One)); + Assert.ThrowsException(() => new BigInteger(ushort.MaxValue).ModInverse(byte.MaxValue)); + + Assert.AreEqual(new BigInteger(52), new BigInteger(19).ModInverse(141)); + } + } +} diff --git a/tests/Neo.VM.Tests/UtVMJson.cs b/tests/Neo.VM.Tests/UtVMJson.cs new file mode 100644 index 0000000000..a80395b9c5 --- /dev/null +++ b/tests/Neo.VM.Tests/UtVMJson.cs @@ -0,0 +1,74 @@ +using System; +using System.IO; +using System.Text; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Test.Extensions; +using Neo.Test.Types; + +namespace Neo.Test +{ + [TestClass] + public class UtVMJson : VMJsonTestBase + { + [TestMethod] + public void TestOthers() => TestJson("./Tests/Others"); + + [TestMethod] + public void TestOpCodesArrays() => TestJson("./Tests/OpCodes/Arrays"); + + [TestMethod] + public void TestOpCodesStack() => TestJson("./Tests/OpCodes/Stack"); + + [TestMethod] + public void TestOpCodesSlot() => TestJson("./Tests/OpCodes/Slot"); + + [TestMethod] + public void TestOpCodesSplice() => TestJson("./Tests/OpCodes/Splice"); + + [TestMethod] + public void TestOpCodesControl() => TestJson("./Tests/OpCodes/Control"); + + [TestMethod] + public void TestOpCodesPush() => TestJson("./Tests/OpCodes/Push"); + + [TestMethod] + public void TestOpCodesArithmetic() => TestJson("./Tests/OpCodes/Arithmetic"); + + [TestMethod] + public void TestOpCodesBitwiseLogic() => TestJson("./Tests/OpCodes/BitwiseLogic"); + + [TestMethod] + public void TestOpCodesTypes() => TestJson("./Tests/OpCodes/Types"); + + private void TestJson(string path) + { + foreach (var file in Directory.GetFiles(path, "*.json", SearchOption.AllDirectories)) + { + Console.WriteLine($"Processing file '{file}'"); + + var realFile = Path.GetFullPath(file); + var json = File.ReadAllText(realFile, Encoding.UTF8); + var ut = json.DeserializeJson(); + + Assert.IsFalse(string.IsNullOrEmpty(ut.Name), "Name is required"); + + if (json != ut.ToJson().Replace("\r\n", "\n")) + { + // Format json + + Console.WriteLine($"The file '{realFile}' was optimized"); + //File.WriteAllText(realFile, ut.ToJson().Replace("\r\n", "\n"), Encoding.UTF8); + } + + try + { + ExecuteTest(ut); + } + catch (Exception ex) + { + throw new AggregateException("Error in file: " + realFile, ex); + } + } + } + } +} diff --git a/tests/Neo.VM.Tests/VMJsonTestBase.cs b/tests/Neo.VM.Tests/VMJsonTestBase.cs new file mode 100644 index 0000000000..ac8e1494f6 --- /dev/null +++ b/tests/Neo.VM.Tests/VMJsonTestBase.cs @@ -0,0 +1,312 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Test.Extensions; +using Neo.Test.Types; +using Neo.VM; +using Neo.VM.Types; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Neo.Test +{ + public abstract class VMJsonTestBase + { + /// + /// Execute this test + /// + /// Test + public void ExecuteTest(VMUT ut) + { + foreach (var test in ut.Tests) + { + Assert.IsFalse(string.IsNullOrEmpty(test.Name), "Name is required"); + + using TestEngine engine = new(); + Debugger debugger = new(engine); + + if (test.Script.Length > 0) + { + engine.LoadScript(test.Script); + } + + // Execute Steps + + if (test.Steps != null) + { + foreach (var step in test.Steps) + { + // Actions + + if (step.Actions != null) foreach (var run in step.Actions) + { + switch (run) + { + case VMUTActionType.Execute: debugger.Execute(); break; + case VMUTActionType.StepInto: debugger.StepInto(); break; + case VMUTActionType.StepOut: debugger.StepOut(); break; + case VMUTActionType.StepOver: debugger.StepOver(); break; + } + } + + // Review results + + var add = string.IsNullOrEmpty(step.Name) ? "" : "-" + step.Name; + + AssertResult(step.Result, engine, $"{ut.Category}-{ut.Name}-{test.Name}{add}: "); + } + } + } + } + + /// + /// Assert result + /// + /// Engine + /// Result + /// Message + private void AssertResult(VMUTExecutionEngineState result, TestEngine engine, string message) + { + AssertAreEqual(result.State.ToString().ToLowerInvariant(), engine.State.ToString().ToLowerInvariant(), message + "State is different"); + if (engine.State == VMState.FAULT) + { + if (result.ExceptionMessage != null) + { + AssertAreEqual(result.ExceptionMessage, engine.FaultException.Message, message + " [Exception]"); + } + return; + } + AssertResult(result.InvocationStack, engine.InvocationStack, message + " [Invocation stack]"); + AssertResult(result.ResultStack, engine.ResultStack, message + " [Result stack] "); + } + + /// + /// Assert invocation stack + /// + /// Stack + /// Result + /// Message + private void AssertResult(VMUTExecutionContextState[] result, Stack stack, string message) + { + AssertAreEqual(result == null ? 0 : result.Length, stack.Count, message + "Stack is different"); + + int x = 0; + foreach (var context in stack) + { + var opcode = context.InstructionPointer >= context.Script.Length ? OpCode.RET : context.Script[context.InstructionPointer]; + + AssertAreEqual(result[x].NextInstruction, opcode, message + "Next instruction is different"); + AssertAreEqual(result[x].InstructionPointer, context.InstructionPointer, message + "Instruction pointer is different"); + + // Check stack + + AssertResult(result[x].EvaluationStack, context.EvaluationStack, message + " [EvaluationStack]"); + + // Check slots + + AssertResult(result[x].Arguments, context.Arguments, message + " [Arguments]"); + AssertResult(result[x].LocalVariables, context.LocalVariables, message + " [LocalVariables]"); + AssertResult(result[x].StaticFields, context.StaticFields, message + " [StaticFields]"); + + x++; + } + } + + /// + /// Assert result stack + /// + /// Stack + /// Result + /// Message + private void AssertResult(VMUTStackItem[] result, EvaluationStack stack, string message) + { + AssertAreEqual(stack.Count, result == null ? 0 : result.Length, message + "Stack is different"); + + for (int x = 0, max = stack.Count; x < max; x++) + { + AssertAreEqual(ItemToJson(stack.Peek(x)).ToString(Formatting.None), PrepareJsonItem(result[x]).ToString(Formatting.None), message + "Stack item is different"); + } + } + + /// + /// Assert result slot + /// + /// Slot + /// Result + /// Message + private void AssertResult(VMUTStackItem[] result, Slot slot, string message) + { + AssertAreEqual(slot == null ? 0 : slot.Count, result == null ? 0 : result.Length, message + "Slot is different"); + + for (int x = 0, max = slot == null ? 0 : slot.Count; x < max; x++) + { + AssertAreEqual(ItemToJson(slot[x]).ToString(Formatting.None), PrepareJsonItem(result[x]).ToString(Formatting.None), message + "Stack item is different"); + } + } + + private JObject PrepareJsonItem(VMUTStackItem item) + { + var ret = new JObject + { + ["type"] = item.Type.ToString(), + ["value"] = item.Value + }; + + switch (item.Type) + { + case VMUTStackItemType.Null: + { + ret["type"] = VMUTStackItemType.Null.ToString(); + ret.Remove("value"); + break; + } + case VMUTStackItemType.Pointer: + { + ret["type"] = VMUTStackItemType.Pointer.ToString(); + ret["value"] = item.Value.Value(); + break; + } + case VMUTStackItemType.String: + { + // Easy access + + ret["type"] = VMUTStackItemType.ByteString.ToString(); + ret["value"] = Encoding.UTF8.GetBytes(item.Value.Value()); + break; + } + case VMUTStackItemType.ByteString: + case VMUTStackItemType.Buffer: + { + var value = ret["value"].Value(); + Assert.IsTrue(string.IsNullOrEmpty(value) || value.StartsWith("0x"), $"'0x' prefix required for value: '{value}'"); + ret["value"] = value.FromHexString(); + break; + } + case VMUTStackItemType.Integer: + { + // Ensure format + + ret["value"] = ret["value"].Value(); + break; + } + case VMUTStackItemType.Struct: + case VMUTStackItemType.Array: + { + var array = (JArray)ret["value"]; + + for (int x = 0, m = array.Count; x < m; x++) + { + array[x] = PrepareJsonItem(JsonConvert.DeserializeObject(array[x].ToString())); + } + + ret["value"] = array; + break; + } + case VMUTStackItemType.Map: + { + var obj = (JObject)ret["value"]; + + foreach (var prop in obj.Properties()) + { + obj[prop.Name] = PrepareJsonItem(JsonConvert.DeserializeObject(prop.Value.ToString())); + } + + ret["value"] = obj; + break; + } + } + + return ret; + } + + private JToken ItemToJson(StackItem item) + { + if (item == null) return null; + + JToken value; + string type = item.GetType().Name; + + switch (item) + { + case VM.Types.Null _: + { + return new JObject + { + ["type"] = type, + }; + } + case Pointer p: + { + return new JObject + { + ["type"] = type, + ["value"] = p.Position + }; + } + case VM.Types.Boolean v: value = new JValue(v.GetBoolean()); break; + case VM.Types.Integer v: value = new JValue(v.GetInteger().ToString()); break; + case VM.Types.ByteString v: value = new JValue(v.GetSpan().ToArray()); break; + case VM.Types.Buffer v: value = new JValue(v.InnerBuffer.ToArray()); break; + //case VM.Types.Struct v: + case VM.Types.Array v: + { + var jarray = new JArray(); + + foreach (var entry in v) + { + jarray.Add(ItemToJson(entry)); + } + + value = jarray; + break; + } + case VM.Types.Map v: + { + var jdic = new JObject(); + + foreach (var entry in v) + { + jdic.Add(entry.Key.GetSpan().ToArray().ToHexString(), ItemToJson(entry.Value)); + } + + value = jdic; + break; + } + case VM.Types.InteropInterface v: + { + type = "Interop"; + var obj = v.GetInterface(); + + value = obj.GetType().Name.ToString(); + break; + } + default: throw new NotImplementedException(); + } + + return new JObject + { + ["type"] = type, + ["value"] = value + }; + } + + /// + /// Assert with message + /// + /// A + /// B + /// Message + private static void AssertAreEqual(object expected, object actual, string message) + { + if (expected is byte[] ba) expected = ba.ToHexString().ToUpperInvariant(); + if (actual is byte[] bb) actual = bb.ToHexString().ToUpperInvariant(); + + if (expected.ToJson() != actual.ToJson()) + { + throw new Exception(message + + $"{Environment.NewLine}Expected:{Environment.NewLine + expected.ToString() + Environment.NewLine}Actual:{Environment.NewLine + actual.ToString()}"); + } + } + } +} From cde23d54e7ef085e4837fceb0681d596a153d354 Mon Sep 17 00:00:00 2001 From: Shargon Date: Wed, 22 Nov 2023 15:58:36 +0100 Subject: [PATCH 021/168] Update Neo.VM location in README.md (#2988) * Update README.md * Update README.md --- README.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/README.md b/README.md index 39d02a7fba..4c80cc59c2 100644 --- a/README.md +++ b/README.md @@ -16,8 +16,6 @@
Neo · - Neo VM - · Neo Modules · Neo DevPack @@ -130,7 +128,6 @@ An overview of the project folders can be seen below. Code references are provided for all platform building blocks. That includes the base library, the VM, a command line application and the compiler. * [neo:](https://github.com/neo-project/neo/) Neo core library, contains base classes, including ledger, p2p and IO modules. -* [neo-vm:](https://github.com/neo-project/neo-vm/) Neo Virtual Machine is a decoupled VM that Neo uses to execute its scripts. It also uses the `InteropService` layer to extend its functionalities. * [neo-node:](https://github.com/neo-project/neo-node/) Executable version of the Neo library, exposing features using a command line application or GUI. * [neo-modules:](https://github.com/neo-project/neo-modules/) Neo modules include additional tools and plugins to be used with Neo. * [neo-devpack-dotnet:](https://github.com/neo-project/neo-devpack-dotnet/) These are the official tools used to convert a C# smart-contract into a *neo executable file*. From 2e7e70e74647485031dd5ec567d861cf14814854 Mon Sep 17 00:00:00 2001 From: Ricardo Prado <38396062+lock9@users.noreply.github.com> Date: Wed, 22 Nov 2023 14:21:39 -0300 Subject: [PATCH 022/168] Fix Neo VM target frameworks (#2989) --- src/Directory.Build.props | 2 +- src/Neo.VM/Neo.VM.csproj | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 49b51f1691..6a1c44f64e 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -5,7 +5,7 @@ 2015-2023 The Neo Project 3.6.2 The Neo Project - net7.0 + net7.0 https://github.com/neo-project/neo MIT git diff --git a/src/Neo.VM/Neo.VM.csproj b/src/Neo.VM/Neo.VM.csproj index 5e7e071b22..add3762a3e 100644 --- a/src/Neo.VM/Neo.VM.csproj +++ b/src/Neo.VM/Neo.VM.csproj @@ -2,6 +2,7 @@ netstandard2.1;net7.0 + 9.0 true enable From 683af79b0d639cef0a8b1e91208395ca289d1664 Mon Sep 17 00:00:00 2001 From: Shargon Date: Sat, 25 Nov 2023 17:19:06 +0100 Subject: [PATCH 023/168] Remove unnecessary default seedlist (#2980) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Remove unnecessary default seedlist Close #2772 * fix ut * Update TestProtocolSettings.cs * use existing default setting for test setting. * add ut-test cases * add test to ut setting.load * Update TestBlockchain.cs * Apply suggestions from code review * Update tests/Neo.UnitTests/UT_ProtocolSettings.cs * Update tests/Neo.UnitTests/TestProtocolSettings.cs * Fix some UT --------- Co-authored-by: Jinghui Liao Co-authored-by: Vitor Nazário Coelho --- src/Neo/ProtocolSettings.cs | 40 +---- .../Cryptography/UT_Cryptography_Helper.cs | 2 +- tests/Neo.UnitTests/Ledger/UT_Blockchain.cs | 2 +- tests/Neo.UnitTests/Ledger/UT_MemoryPool.cs | 4 +- tests/Neo.UnitTests/Ledger/UT_TrimmedBlock.cs | 2 +- tests/Neo.UnitTests/Neo.UnitTests.csproj | 7 + .../Network/P2P/Payloads/UT_Block.cs | 4 +- .../Network/P2P/Payloads/UT_Transaction.cs | 58 +++--- .../Network/P2P/Payloads/UT_Witness.cs | 2 +- .../Network/P2P/UT_RemoteNode.cs | 2 +- .../SmartContract/Native/UT_GasToken.cs | 2 +- .../SmartContract/Native/UT_NeoToken.cs | 66 +++---- .../SmartContract/Native/UT_RoleManagement.cs | 2 +- .../UT_ApplicationEngine.Contract.cs | 6 +- .../SmartContract/UT_ApplicationEngine.cs | 2 +- .../UT_ContractParameterContext.cs | 26 +-- .../Neo.UnitTests/SmartContract/UT_Helper.cs | 8 +- .../SmartContract/UT_InteropService.NEO.cs | 4 +- .../SmartContract/UT_InteropService.cs | 2 +- .../SmartContract/UT_SmartContractHelper.cs | 8 +- .../SmartContract/UT_Syscalls.cs | 2 +- tests/Neo.UnitTests/TestBlockchain.cs | 4 +- tests/Neo.UnitTests/TestProtocolSettings.cs | 57 ++++++ tests/Neo.UnitTests/TestUtils.cs | 2 +- tests/Neo.UnitTests/TestWalletAccount.cs | 2 +- tests/Neo.UnitTests/UT_Helper.cs | 4 +- tests/Neo.UnitTests/UT_ProtocolSettings.cs | 168 +++++++++++++++++- .../Wallets/NEP6/UT_NEP6Account.cs | 4 +- .../Wallets/NEP6/UT_NEP6Wallet.cs | 14 +- .../Wallets/UT_AssetDescriptor.cs | 6 +- tests/Neo.UnitTests/Wallets/UT_Wallet.cs | 4 +- .../Neo.UnitTests/Wallets/UT_WalletAccount.cs | 2 +- .../Wallets/UT_Wallets_Helper.cs | 4 +- tests/Neo.UnitTests/test.config.json | 66 +++++++ 34 files changed, 421 insertions(+), 167 deletions(-) create mode 100644 tests/Neo.UnitTests/TestProtocolSettings.cs create mode 100644 tests/Neo.UnitTests/test.config.json diff --git a/src/Neo/ProtocolSettings.cs b/src/Neo/ProtocolSettings.cs index f1e4e01b11..74807e4d97 100644 --- a/src/Neo/ProtocolSettings.cs +++ b/src/Neo/ProtocolSettings.cs @@ -104,43 +104,11 @@ public record ProtocolSettings /// public static ProtocolSettings Default { get; } = new ProtocolSettings { - Network = 0x334F454Eu, + Network = 0u, AddressVersion = 0x35, - 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" - }, + StandbyCommittee = Array.Empty(), + ValidatorsCount = 0, + SeedList = Array.Empty(), MillisecondsPerBlock = 15000, MaxTransactionsPerBlock = 512, MemoryPoolMaxTransactions = 50_000, diff --git a/tests/Neo.UnitTests/Cryptography/UT_Cryptography_Helper.cs b/tests/Neo.UnitTests/Cryptography/UT_Cryptography_Helper.cs index c2033e3fd7..e0c8bf3149 100644 --- a/tests/Neo.UnitTests/Cryptography/UT_Cryptography_Helper.cs +++ b/tests/Neo.UnitTests/Cryptography/UT_Cryptography_Helper.cs @@ -53,7 +53,7 @@ public void TestRIPEMD160() [TestMethod] public void TestAESEncryptAndDecrypt() { - NEP6Wallet wallet = new NEP6Wallet("", "1", ProtocolSettings.Default); + NEP6Wallet wallet = new NEP6Wallet("", "1", TestProtocolSettings.Default); wallet.CreateAccount(); WalletAccount account = wallet.GetAccounts().ToArray()[0]; KeyPair key = account.GetKey(); diff --git a/tests/Neo.UnitTests/Ledger/UT_Blockchain.cs b/tests/Neo.UnitTests/Ledger/UT_Blockchain.cs index 7ecb965ff5..0237b76e3d 100644 --- a/tests/Neo.UnitTests/Ledger/UT_Blockchain.cs +++ b/tests/Neo.UnitTests/Ledger/UT_Blockchain.cs @@ -89,7 +89,7 @@ private static Transaction CreateValidTx(DataCache snapshot, NEP6Wallet wallet, tx.Nonce = nonce; - var data = new ContractParametersContext(snapshot, tx, ProtocolSettings.Default.Network); + var data = new ContractParametersContext(snapshot, tx, TestProtocolSettings.Default.Network); Assert.IsNull(data.GetSignatures(tx.Sender)); Assert.IsTrue(wallet.Sign(data)); Assert.IsTrue(data.Completed); diff --git a/tests/Neo.UnitTests/Ledger/UT_MemoryPool.cs b/tests/Neo.UnitTests/Ledger/UT_MemoryPool.cs index eb0aabf1f5..abe054f4f2 100644 --- a/tests/Neo.UnitTests/Ledger/UT_MemoryPool.cs +++ b/tests/Neo.UnitTests/Ledger/UT_MemoryPool.cs @@ -47,7 +47,7 @@ public void TestSetup() TimeProvider.ResetToDefault(); // Create a MemoryPool with capacity of 100 - _unit = new MemoryPool(new NeoSystem(ProtocolSettings.Default with { MemoryPoolMaxTransactions = 100 })); + _unit = new MemoryPool(new NeoSystem(TestProtocolSettings.Default with { MemoryPoolMaxTransactions = 100 })); // Verify capacity equals the amount specified _unit.Capacity.Should().Be(100); @@ -638,7 +638,7 @@ public void TestGetVerifiedTransactions() [TestMethod] public void TestReVerifyTopUnverifiedTransactionsIfNeeded() { - _unit = new MemoryPool(new NeoSystem(ProtocolSettings.Default with { MemoryPoolMaxTransactions = 600 })); + _unit = new MemoryPool(new NeoSystem(TestProtocolSettings.Default with { MemoryPoolMaxTransactions = 600 })); AddTransaction(CreateTransaction(100000001)); AddTransaction(CreateTransaction(100000001)); diff --git a/tests/Neo.UnitTests/Ledger/UT_TrimmedBlock.cs b/tests/Neo.UnitTests/Ledger/UT_TrimmedBlock.cs index 5a62071cad..9a8d7e1caa 100644 --- a/tests/Neo.UnitTests/Ledger/UT_TrimmedBlock.cs +++ b/tests/Neo.UnitTests/Ledger/UT_TrimmedBlock.cs @@ -105,7 +105,7 @@ public void TestDeserialize() newBlock.Deserialize(ref reader); } tblock.Hashes.Length.Should().Be(newBlock.Hashes.Length); - tblock.Header.ToJson(ProtocolSettings.Default).ToString().Should().Be(newBlock.Header.ToJson(ProtocolSettings.Default).ToString()); + tblock.Header.ToJson(TestProtocolSettings.Default).ToString().Should().Be(newBlock.Header.ToJson(ProtocolSettings.Default).ToString()); } } } diff --git a/tests/Neo.UnitTests/Neo.UnitTests.csproj b/tests/Neo.UnitTests/Neo.UnitTests.csproj index a7a882c4f5..909c3c53e3 100644 --- a/tests/Neo.UnitTests/Neo.UnitTests.csproj +++ b/tests/Neo.UnitTests/Neo.UnitTests.csproj @@ -10,6 +10,13 @@ + + + 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 d839af965b..2c1c72ca25 100644 --- a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Block.cs +++ b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Block.cs @@ -59,7 +59,7 @@ public void Size_Get_1_Transaction() TestUtils.GetTransaction(UInt160.Zero) }; - uut.Size.Should().Be(167); // 159 + nonce + uut.Size.Should().Be(167); // 159 + nonce } [TestMethod] @@ -162,7 +162,7 @@ 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); - JObject jObj = uut.ToJson(ProtocolSettings.Default); + JObject jObj = uut.ToJson(TestProtocolSettings.Default); jObj.Should().NotBeNull(); jObj["hash"].AsString().Should().Be("0x60193a05005c433787d8a9b95da332bbeebb311e904525e9fb1bacc34ff1ead7"); jObj["size"].AsNumber().Should().Be(167); // 159 + nonce diff --git a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs index 1df1340012..d2241c43bf 100644 --- a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs +++ b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs @@ -145,10 +145,10 @@ public void FeeIsMultiSigContract() // Sign - var wrongData = new ContractParametersContext(snapshot, tx, ProtocolSettings.Default.Network + 1); + var wrongData = new ContractParametersContext(snapshot, tx, TestProtocolSettings.Default.Network + 1); Assert.IsFalse(walletA.Sign(wrongData)); - var data = new ContractParametersContext(snapshot, tx, ProtocolSettings.Default.Network); + var data = new ContractParametersContext(snapshot, tx, TestProtocolSettings.Default.Network); Assert.IsTrue(walletA.Sign(data)); Assert.IsTrue(walletB.Sign(data)); Assert.IsTrue(data.Completed); @@ -157,7 +157,7 @@ public void FeeIsMultiSigContract() // Fast check - Assert.IsTrue(tx.VerifyWitnesses(ProtocolSettings.Default, snapshot, tx.NetworkFee)); + Assert.IsTrue(tx.VerifyWitnesses(TestProtocolSettings.Default, snapshot, tx.NetworkFee)); // Check @@ -219,7 +219,7 @@ public void FeeIsSignatureContractDetailed() // Sign // ---- - var data = new ContractParametersContext(snapshot, tx, ProtocolSettings.Default.Network); + var data = new ContractParametersContext(snapshot, 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); @@ -233,7 +233,7 @@ public void FeeIsSignatureContractDetailed() // Fast check - Assert.IsTrue(tx.VerifyWitnesses(ProtocolSettings.Default, snapshot, tx.NetworkFee)); + Assert.IsTrue(tx.VerifyWitnesses(TestProtocolSettings.Default, snapshot, tx.NetworkFee)); // Check @@ -330,7 +330,7 @@ public void FeeIsSignatureContract_TestScope_Global() // Sign // ---- - var data = new ContractParametersContext(snapshot, tx, ProtocolSettings.Default.Network); + var data = new ContractParametersContext(snapshot, tx, TestProtocolSettings.Default.Network); bool signed = wallet.Sign(data); Assert.IsTrue(signed); @@ -339,7 +339,7 @@ public void FeeIsSignatureContract_TestScope_Global() tx.Witnesses.Length.Should().Be(1); // Fast check - Assert.IsTrue(tx.VerifyWitnesses(ProtocolSettings.Default, snapshot, tx.NetworkFee)); + Assert.IsTrue(tx.VerifyWitnesses(TestProtocolSettings.Default, snapshot, tx.NetworkFee)); // Check long verificationGas = 0; @@ -410,7 +410,7 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_GAS() // Sign // ---- - var data = new ContractParametersContext(snapshot, tx, ProtocolSettings.Default.Network); + var data = new ContractParametersContext(snapshot, tx, TestProtocolSettings.Default.Network); bool signed = wallet.Sign(data); Assert.IsTrue(signed); @@ -419,7 +419,7 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_GAS() tx.Witnesses.Length.Should().Be(1); // Fast check - Assert.IsTrue(tx.VerifyWitnesses(ProtocolSettings.Default, snapshot, tx.NetworkFee)); + Assert.IsTrue(tx.VerifyWitnesses(TestProtocolSettings.Default, snapshot, tx.NetworkFee)); // Check long verificationGas = 0; @@ -493,7 +493,7 @@ public void FeeIsSignatureContract_TestScope_CalledByEntry_Plus_GAS() // Sign // ---- - var data = new ContractParametersContext(snapshot, tx, ProtocolSettings.Default.Network); + var data = new ContractParametersContext(snapshot, tx, TestProtocolSettings.Default.Network); bool signed = wallet.Sign(data); Assert.IsTrue(signed); @@ -502,7 +502,7 @@ public void FeeIsSignatureContract_TestScope_CalledByEntry_Plus_GAS() tx.Witnesses.Length.Should().Be(1); // Fast check - Assert.IsTrue(tx.VerifyWitnesses(ProtocolSettings.Default, snapshot, tx.NetworkFee)); + Assert.IsTrue(tx.VerifyWitnesses(TestProtocolSettings.Default, snapshot, tx.NetworkFee)); // Check long verificationGas = 0; @@ -618,7 +618,7 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_NEO_GAS() // Sign // ---- - var data = new ContractParametersContext(snapshot, tx, ProtocolSettings.Default.Network); + var data = new ContractParametersContext(snapshot, tx, TestProtocolSettings.Default.Network); bool signed = wallet.Sign(data); Assert.IsTrue(signed); @@ -632,7 +632,7 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_NEO_GAS() tx.Signers.Length.Should().Be(1); // Fast check - Assert.IsTrue(tx.VerifyWitnesses(ProtocolSettings.Default, snapshot, tx.NetworkFee)); + Assert.IsTrue(tx.VerifyWitnesses(TestProtocolSettings.Default, snapshot, tx.NetworkFee)); // Check long verificationGas = 0; @@ -758,7 +758,7 @@ public void Transaction_Reverify_Hashes_Length_Unequal_To_Witnesses_Length() { Version = 0x00, Nonce = 0x01020304, - SystemFee = (long)BigInteger.Pow(10, 8), // 1 GAS + SystemFee = (long)BigInteger.Pow(10, 8), // 1 GAS NetworkFee = 0x0000000000000001, ValidUntilBlock = 0x01020304, Attributes = Array.Empty(), @@ -774,7 +774,7 @@ public void Transaction_Reverify_Hashes_Length_Unequal_To_Witnesses_Length() }; UInt160[] hashes = txSimple.GetScriptHashesForVerifying(snapshot); Assert.AreEqual(1, hashes.Length); - Assert.AreNotEqual(VerifyResult.Succeed, txSimple.VerifyStateDependent(ProtocolSettings.Default, snapshot, new TransactionVerificationContext(), new List())); + Assert.AreNotEqual(VerifyResult.Succeed, txSimple.VerifyStateDependent(TestProtocolSettings.Default, snapshot, new TransactionVerificationContext(), new List())); } [TestMethod] @@ -785,7 +785,7 @@ public void Transaction_Serialize_Deserialize_Simple() { Version = 0x00, Nonce = 0x01020304, - SystemFee = (long)BigInteger.Pow(10, 8), // 1 GAS + SystemFee = (long)BigInteger.Pow(10, 8), // 1 GAS NetworkFee = 0x0000000000000001, ValidUntilBlock = 0x01020304, Signers = new Signer[] { new Signer() { Account = UInt160.Zero } }, @@ -802,7 +802,7 @@ public void Transaction_Serialize_Deserialize_Simple() "04030201" + // nonce "00e1f50500000000" + // system fee (1 GAS) "0100000000000000" + // network fee (1 satoshi) - "04030201" + // timelimit + "04030201" + // timelimit "01000000000000000000000000000000000000000000" + // empty signer "00" + // no attributes "0111" + // push1 script @@ -842,7 +842,7 @@ public void Transaction_Serialize_Deserialize_DistinctCosigners() { Version = 0x00, Nonce = 0x01020304, - SystemFee = (long)BigInteger.Pow(10, 8), // 1 GAS + SystemFee = (long)BigInteger.Pow(10, 8), // 1 GAS NetworkFee = 0x0000000000000001, ValidUntilBlock = 0x01020304, Attributes = Array.Empty(), @@ -904,7 +904,7 @@ public void Transaction_Serialize_Deserialize_MaxSizeCosigners() { Version = 0x00, Nonce = 0x01020304, - SystemFee = (long)BigInteger.Pow(10, 8), // 1 GAS + SystemFee = (long)BigInteger.Pow(10, 8), // 1 GAS NetworkFee = 0x0000000000000001, ValidUntilBlock = 0x01020304, Attributes = Array.Empty(), @@ -937,7 +937,7 @@ public void Transaction_Serialize_Deserialize_MaxSizeCosigners() { Version = 0x00, Nonce = 0x01020304, - SystemFee = (long)BigInteger.Pow(10, 8), // 1 GAS + SystemFee = (long)BigInteger.Pow(10, 8), // 1 GAS NetworkFee = 0x0000000000000001, ValidUntilBlock = 0x01020304, Attributes = Array.Empty(), @@ -1012,7 +1012,7 @@ public void FeeIsSignatureContract_TestScope_FeeOnly_Default() // Sign // ---- - var data = new ContractParametersContext(snapshot, tx, ProtocolSettings.Default.Network); + var data = new ContractParametersContext(snapshot, tx, TestProtocolSettings.Default.Network); bool signed = wallet.Sign(data); Assert.IsTrue(signed); @@ -1021,7 +1021,7 @@ public void FeeIsSignatureContract_TestScope_FeeOnly_Default() tx.Witnesses.Length.Should().Be(1); // Fast check - Assert.IsTrue(tx.VerifyWitnesses(ProtocolSettings.Default, snapshot, tx.NetworkFee)); + Assert.IsTrue(tx.VerifyWitnesses(TestProtocolSettings.Default, snapshot, tx.NetworkFee)); // Check long verificationGas = 0; @@ -1117,9 +1117,9 @@ public void Test_VerifyStateIndependent() } } }; - tx.VerifyStateIndependent(ProtocolSettings.Default).Should().Be(VerifyResult.OverSize); + tx.VerifyStateIndependent(TestProtocolSettings.Default).Should().Be(VerifyResult.OverSize); tx.Script = Array.Empty(); - tx.VerifyStateIndependent(ProtocolSettings.Default).Should().Be(VerifyResult.Succeed); + tx.VerifyStateIndependent(TestProtocolSettings.Default).Should().Be(VerifyResult.Succeed); var walletA = TestUtils.GenerateTestWallet("123"); var walletB = TestUtils.GenerateTestWallet("123"); @@ -1161,13 +1161,13 @@ public void Test_VerifyStateIndependent() // Sign - var data = new ContractParametersContext(snapshot, tx, ProtocolSettings.Default.Network); + var data = new ContractParametersContext(snapshot, tx, TestProtocolSettings.Default.Network); Assert.IsTrue(walletA.Sign(data)); Assert.IsTrue(walletB.Sign(data)); Assert.IsTrue(data.Completed); tx.Witnesses = data.GetWitnesses(); - tx.VerifyStateIndependent(ProtocolSettings.Default).Should().Be(VerifyResult.Succeed); + tx.VerifyStateIndependent(TestProtocolSettings.Default).Should().Be(VerifyResult.Succeed); // Different hash @@ -1176,7 +1176,7 @@ public void Test_VerifyStateIndependent() VerificationScript = walletB.GetAccounts().First().Contract.Script, InvocationScript = tx.Witnesses[0].InvocationScript.ToArray() }; - tx.VerifyStateIndependent(ProtocolSettings.Default).Should().Be(VerifyResult.Invalid); + tx.VerifyStateIndependent(TestProtocolSettings.Default).Should().Be(VerifyResult.Invalid); } [TestMethod] @@ -1250,13 +1250,13 @@ public void Test_VerifyStateDependent() // Sign - var data = new ContractParametersContext(snapshot, tx, ProtocolSettings.Default.Network); + var data = new ContractParametersContext(snapshot, tx, TestProtocolSettings.Default.Network); Assert.IsTrue(walletA.Sign(data)); Assert.IsTrue(walletB.Sign(data)); Assert.IsTrue(data.Completed); tx.Witnesses = data.GetWitnesses(); - tx.VerifyStateDependent(ProtocolSettings.Default, snapshot, new TransactionVerificationContext(), new List()).Should().Be(VerifyResult.Succeed); + tx.VerifyStateDependent(TestProtocolSettings.Default, snapshot, 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 d142ffc927..f73f24cb0a 100644 --- a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Witness.cs +++ b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Witness.cs @@ -66,7 +66,7 @@ private static Witness PrepareDummyWitness(int pubKeys, int m) ValidUntilBlock = 0, Version = 0, Witnesses = Array.Empty() - }, ProtocolSettings.Default.Network); + }, TestProtocolSettings.Default.Network); for (int x = 0; x < m; x++) { diff --git a/tests/Neo.UnitTests/Network/P2P/UT_RemoteNode.cs b/tests/Neo.UnitTests/Network/P2P/UT_RemoteNode.cs index 4e514e99a3..2366e92f2f 100644 --- a/tests/Neo.UnitTests/Network/P2P/UT_RemoteNode.cs +++ b/tests/Neo.UnitTests/Network/P2P/UT_RemoteNode.cs @@ -61,7 +61,7 @@ public void RemoteNode_Test_Accept_IfSameNetwork() { UserAgent = "Unit Test".PadLeft(1024, '0'), Nonce = 1, - Network = ProtocolSettings.Default.Network, + Network = TestProtocolSettings.Default.Network, Timestamp = 5, Version = 6, Capabilities = new NodeCapability[] diff --git a/tests/Neo.UnitTests/SmartContract/Native/UT_GasToken.cs b/tests/Neo.UnitTests/SmartContract/Native/UT_GasToken.cs index 997c4ce335..8f623de719 100644 --- a/tests/Neo.UnitTests/SmartContract/Native/UT_GasToken.cs +++ b/tests/Neo.UnitTests/SmartContract/Native/UT_GasToken.cs @@ -40,7 +40,7 @@ public async Task Check_BalanceOfTransferAndBurn() { var snapshot = _snapshot.CreateSnapshot(); var persistingBlock = new Block { Header = new Header { Index = 1000 } }; - byte[] from = Contract.GetBFTAddress(ProtocolSettings.Default.StandbyValidators).ToArray(); + byte[] from = Contract.GetBFTAddress(TestProtocolSettings.Default.StandbyValidators).ToArray(); byte[] to = new byte[20]; var supply = NativeContract.GAS.TotalSupply(snapshot); supply.Should().Be(5200000050000000); // 3000000000000000 + 50000000 (neo holder reward) diff --git a/tests/Neo.UnitTests/SmartContract/Native/UT_NeoToken.cs b/tests/Neo.UnitTests/SmartContract/Native/UT_NeoToken.cs index 7e8aff59fb..e09b5e8743 100644 --- a/tests/Neo.UnitTests/SmartContract/Native/UT_NeoToken.cs +++ b/tests/Neo.UnitTests/SmartContract/Native/UT_NeoToken.cs @@ -51,7 +51,7 @@ public void Check_Vote() var storageKey = new KeyBuilder(NativeContract.Ledger.Id, 12); snapshot.Add(storageKey, new StorageItem(new HashIndexState { Hash = UInt256.Zero, Index = persistingBlock.Index - 1 })); - byte[] from = Contract.GetBFTAddress(ProtocolSettings.Default.StandbyValidators).ToArray(); + byte[] from = Contract.GetBFTAddress(TestProtocolSettings.Default.StandbyValidators).ToArray(); // No signature @@ -109,7 +109,7 @@ public void Check_Vote_Sameaccounts() var storageKey = new KeyBuilder(NativeContract.Ledger.Id, 12); snapshot.Add(storageKey, new StorageItem(new HashIndexState { Hash = UInt256.Zero, Index = persistingBlock.Index - 1 })); - byte[] from = Contract.GetBFTAddress(ProtocolSettings.Default.StandbyValidators).ToArray(); + byte[] from = Contract.GetBFTAddress(TestProtocolSettings.Default.StandbyValidators).ToArray(); var accountState = snapshot.TryGet(CreateStorageKey(20, from)).GetInteroperable(); accountState.Balance = 100; snapshot.Add(CreateStorageKey(33, ECCurve.Secp256r1.G.ToArray()), new StorageItem(new CandidateState() { Registered = true })); @@ -141,8 +141,8 @@ public void Check_Vote_ChangeVote() var storageKey = new KeyBuilder(NativeContract.Ledger.Id, 12); snapshot.Add(storageKey, new StorageItem(new HashIndexState { Hash = UInt256.Zero, Index = persistingBlock.Index - 1 })); //from vote to G - byte[] from = ProtocolSettings.Default.StandbyValidators[0].ToArray(); - var from_Account = Contract.CreateSignatureContract(ProtocolSettings.Default.StandbyValidators[0]).ScriptHash.ToArray(); + 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(); accountState.Balance = 100; @@ -175,8 +175,8 @@ public void Check_Vote_VoteToNull() 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 })); - byte[] from = ProtocolSettings.Default.StandbyValidators[0].ToArray(); - var from_Account = Contract.CreateSignatureContract(ProtocolSettings.Default.StandbyValidators[0]).ScriptHash.ToArray(); + 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(); accountState.Balance = 100; @@ -211,7 +211,7 @@ public void Check_UnclaimedGas() var storageKey = new KeyBuilder(NativeContract.Ledger.Id, 12); snapshot.Add(storageKey, new StorageItem(new HashIndexState { Hash = UInt256.Zero, Index = persistingBlock.Index - 1 })); - byte[] from = Contract.GetBFTAddress(ProtocolSettings.Default.StandbyValidators).ToArray(); + byte[] from = Contract.GetBFTAddress(TestProtocolSettings.Default.StandbyValidators).ToArray(); var unclaim = Check_UnclaimedGas(snapshot, from, persistingBlock); unclaim.Value.Should().Be(new BigInteger(0.5 * 1000 * 100000000L)); @@ -228,7 +228,7 @@ public void Check_RegisterValidator() var snapshot = _snapshot.CreateSnapshot(); var keyCount = snapshot.GetChangeSet().Count(); - var point = ProtocolSettings.Default.StandbyValidators[0].EncodePoint(true).Clone() as byte[]; + var point = TestProtocolSettings.Default.StandbyValidators[0].EncodePoint(true).Clone() as byte[]; var ret = Check_RegisterValidator(snapshot, point, _persistingBlock); // Exists ret.State.Should().BeTrue(); @@ -256,7 +256,7 @@ public void Check_UnregisterCandidate() var snapshot = _snapshot.CreateSnapshot(); _persistingBlock.Header.Index = 1; var keyCount = snapshot.GetChangeSet().Count(); - var point = ProtocolSettings.Default.StandbyValidators[0].EncodePoint(true); + var point = TestProtocolSettings.Default.StandbyValidators[0].EncodePoint(true); //without register var ret = Check_UnregisterCandidate(snapshot, point, _persistingBlock); @@ -293,7 +293,7 @@ public void Check_UnregisterCandidate() snapshot.Add(CreateStorageKey(20, G_Account), new StorageItem(new NeoAccountState())); var accountState = snapshot.TryGet(CreateStorageKey(20, G_Account)).GetInteroperable(); accountState.Balance = 100; - Check_Vote(snapshot, G_Account, ProtocolSettings.Default.StandbyValidators[0].ToArray(), true, _persistingBlock); + Check_Vote(snapshot, G_Account, TestProtocolSettings.Default.StandbyValidators[0].ToArray(), true, _persistingBlock); ret = Check_UnregisterCandidate(snapshot, point, _persistingBlock); ret.State.Should().BeTrue(); ret.Result.Should().BeTrue(); @@ -304,11 +304,11 @@ public void Check_UnregisterCandidate() pointState.Votes.Should().Be(100); //vote fail - ret = Check_Vote(snapshot, G_Account, ProtocolSettings.Default.StandbyValidators[0].ToArray(), true, _persistingBlock); + ret = Check_Vote(snapshot, 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.VoteTo.Should().Be(ProtocolSettings.Default.StandbyValidators[0]); + accountState.VoteTo.Should().Be(TestProtocolSettings.Default.StandbyValidators[0]); } [TestMethod] @@ -316,7 +316,7 @@ public void Check_GetCommittee() { var snapshot = _snapshot.CreateSnapshot(); var keyCount = snapshot.GetChangeSet().Count(); - var point = ProtocolSettings.Default.StandbyValidators[0].EncodePoint(true); + var point = TestProtocolSettings.Default.StandbyValidators[0].EncodePoint(true); var persistingBlock = _persistingBlock; persistingBlock.Header.Index = 1; //register with votes with 20000000 @@ -332,9 +332,9 @@ public void Check_GetCommittee() ret.Result.Should().BeTrue(); var committeemembers = NativeContract.NEO.GetCommittee(snapshot); - var defaultCommittee = ProtocolSettings.Default.StandbyCommittee.OrderBy(p => p).ToArray(); + var defaultCommittee = TestProtocolSettings.Default.StandbyCommittee.OrderBy(p => p).ToArray(); committeemembers.GetType().Should().Be(typeof(ECPoint[])); - for (int i = 0; i < ProtocolSettings.Default.CommitteeMembersCount; i++) + for (int i = 0; i < TestProtocolSettings.Default.CommitteeMembersCount; i++) { committeemembers[i].Should().Be(defaultCommittee[i]); } @@ -344,7 +344,7 @@ public void Check_GetCommittee() { Header = new Header { - Index = (uint)ProtocolSettings.Default.CommitteeMembersCount, + Index = (uint)TestProtocolSettings.Default.CommitteeMembersCount, MerkleRoot = UInt256.Zero, NextConsensus = UInt160.Zero, PrevHash = UInt256.Zero, @@ -352,9 +352,9 @@ public void Check_GetCommittee() }, Transactions = Array.Empty() }; - for (int i = 0; i < ProtocolSettings.Default.CommitteeMembersCount - 1; i++) + for (int i = 0; i < TestProtocolSettings.Default.CommitteeMembersCount - 1; i++) { - ret = Check_RegisterValidator(snapshot, ProtocolSettings.Default.StandbyCommittee[i].ToArray(), persistingBlock); + ret = Check_RegisterValidator(snapshot, TestProtocolSettings.Default.StandbyCommittee[i].ToArray(), persistingBlock); ret.State.Should().BeTrue(); ret.Result.Should().BeTrue(); } @@ -362,13 +362,13 @@ public void Check_GetCommittee() Check_OnPersist(snapshot, persistingBlock).Should().BeTrue(); committeemembers = NativeContract.NEO.GetCommittee(snapshot); - committeemembers.Length.Should().Be(ProtocolSettings.Default.CommitteeMembersCount); + committeemembers.Length.Should().Be(TestProtocolSettings.Default.CommitteeMembersCount); committeemembers.Contains(ECCurve.Secp256r1.G).Should().BeTrue(); - for (int i = 0; i < ProtocolSettings.Default.CommitteeMembersCount - 1; i++) + for (int i = 0; i < TestProtocolSettings.Default.CommitteeMembersCount - 1; i++) { - committeemembers.Contains(ProtocolSettings.Default.StandbyCommittee[i]).Should().BeTrue(); + committeemembers.Contains(TestProtocolSettings.Default.StandbyCommittee[i]).Should().BeTrue(); } - committeemembers.Contains(ProtocolSettings.Default.StandbyCommittee[ProtocolSettings.Default.CommitteeMembersCount - 1]).Should().BeFalse(); + committeemembers.Contains(TestProtocolSettings.Default.StandbyCommittee[TestProtocolSettings.Default.CommitteeMembersCount - 1]).Should().BeFalse(); } [TestMethod] @@ -377,7 +377,7 @@ public void Check_Transfer() var snapshot = _snapshot.CreateSnapshot(); var persistingBlock = new Block { Header = new Header { Index = 1000 } }; - byte[] from = Contract.GetBFTAddress(ProtocolSettings.Default.StandbyValidators).ToArray(); + byte[] from = Contract.GetBFTAddress(TestProtocolSettings.Default.StandbyValidators).ToArray(); byte[] to = new byte[20]; var storageKey = new KeyBuilder(NativeContract.Ledger.Id, 12); @@ -434,7 +434,7 @@ public void Check_Transfer() public void Check_BalanceOf() { var snapshot = _snapshot.CreateSnapshot(); - byte[] account = Contract.GetBFTAddress(ProtocolSettings.Default.StandbyValidators).ToArray(); + byte[] account = Contract.GetBFTAddress(TestProtocolSettings.Default.StandbyValidators).ToArray(); NativeContract.NEO.BalanceOf(snapshot, account).Should().Be(100_000_000); @@ -462,7 +462,7 @@ public void Check_CommitteeBonus() Check_PostPersist(snapshot, persistingBlock).Should().BeTrue(); - var committee = ProtocolSettings.Default.StandbyCommittee; + 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); @@ -545,9 +545,9 @@ public void TestCalculateBonus() snapshot.GetAndChange(key, () => new StorageItem(new NeoAccountState { Balance = 100, - VoteTo = ProtocolSettings.Default.StandbyCommittee[0] + VoteTo = TestProtocolSettings.Default.StandbyCommittee[0] })); - snapshot.Add(new KeyBuilder(NativeContract.NEO.Id, 23).Add(ProtocolSettings.Default.StandbyCommittee[0]).AddBigEndian(uint.MaxValue - 50), new StorageItem() { Value = new BigInteger(50 * 10000L).ToByteArray() }); + 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); } @@ -687,7 +687,7 @@ public void TestGetCommittee() public void TestGetValidators() { var snapshot = _snapshot.CreateSnapshot(); - var result = NativeContract.NEO.ComputeNextBlockValidators(snapshot, ProtocolSettings.Default); + var result = NativeContract.NEO.ComputeNextBlockValidators(snapshot, TestProtocolSettings.Default); result[0].ToArray().ToHexString().Should().Be("02486fd15702c4490a26703112a5cc1d0923fd697a33406bd5a1c00e0013b09a70"); result[1].ToArray().ToHexString().Should().Be("024c7b7fb6c310fccf1ba33b082519d82964ea93868d676662d4a59ad548df0e7d"); result[2].ToArray().ToHexString().Should().Be("02aaec38470f6aad0042c6e877cfd8087d2676b0f516fddd362801b9bd3936399e"); @@ -759,9 +759,9 @@ public void TestClaimGas() // Initialize block snapshot.Add(CreateStorageKey(1), new StorageItem(new BigInteger(30000000))); - ECPoint[] standbyCommittee = ProtocolSettings.Default.StandbyCommittee.OrderBy(p => p).ToArray(); + ECPoint[] standbyCommittee = TestProtocolSettings.Default.StandbyCommittee.OrderBy(p => p).ToArray(); CachedCommittee cachedCommittee = new(); - for (var i = 0; i < ProtocolSettings.Default.CommitteeMembersCount; i++) + 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() @@ -790,9 +790,9 @@ public void TestClaimGas() }; Check_PostPersist(snapshot, persistingBlock).Should().BeTrue(); - var committee = ProtocolSettings.Default.StandbyCommittee.OrderBy(p => p).ToArray(); + var committee = TestProtocolSettings.Default.StandbyCommittee.OrderBy(p => p).ToArray(); var accountA = committee[0]; - var accountB = committee[ProtocolSettings.Default.CommitteeMembersCount - 1]; + var accountB = committee[TestProtocolSettings.Default.CommitteeMembersCount - 1]; NativeContract.NEO.BalanceOf(snapshot, Contract.CreateSignatureContract(accountA).ScriptHash).Should().Be(0); StorageItem storageItem = snapshot.TryGet(new KeyBuilder(NativeContract.NEO.Id, 23).Add(accountA)); @@ -837,7 +837,7 @@ public void TestClaimGas() }; Check_PostPersist(snapshot, persistingBlock).Should().BeTrue(); - accountA = ProtocolSettings.Default.StandbyCommittee.OrderBy(p => p).ToArray()[2]; + accountA = TestProtocolSettings.Default.StandbyCommittee.OrderBy(p => p).ToArray()[2]; NativeContract.NEO.BalanceOf(snapshot, Contract.CreateSignatureContract(committee[2]).ScriptHash).Should().Be(0); storageItem = snapshot.TryGet(new KeyBuilder(NativeContract.NEO.Id, 23).Add(committee[2])); diff --git a/tests/Neo.UnitTests/SmartContract/Native/UT_RoleManagement.cs b/tests/Neo.UnitTests/SmartContract/Native/UT_RoleManagement.cs index 45a0a0ddb6..ffea2d6044 100644 --- a/tests/Neo.UnitTests/SmartContract/Native/UT_RoleManagement.cs +++ b/tests/Neo.UnitTests/SmartContract/Native/UT_RoleManagement.cs @@ -30,7 +30,7 @@ public void TestSetAndGet() { var snapshot1 = _snapshot.CreateSnapshot(); UInt160 committeeMultiSigAddr = NativeContract.NEO.GetCommitteeAddress(snapshot1); - ECPoint[] validators = NativeContract.NEO.ComputeNextBlockValidators(snapshot1, ProtocolSettings.Default); + ECPoint[] validators = NativeContract.NEO.ComputeNextBlockValidators(snapshot1, TestProtocolSettings.Default); List notifications = new List(); EventHandler ev = (o, e) => notifications.Add(e); ApplicationEngine.Notify += ev; diff --git a/tests/Neo.UnitTests/SmartContract/UT_ApplicationEngine.Contract.cs b/tests/Neo.UnitTests/SmartContract/UT_ApplicationEngine.Contract.cs index 939cc282a2..1614e5e32d 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_ApplicationEngine.Contract.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_ApplicationEngine.Contract.cs @@ -11,8 +11,8 @@ public partial class UT_ApplicationEngine [TestMethod] public void TestCreateStandardAccount() { - var settings = ProtocolSettings.Default; - using var engine = ApplicationEngine.Create(TriggerType.Application, null, null, settings: TestBlockchain.TheNeoSystem.Settings, gas: 1100_00000000); + var settings = TestProtocolSettings.Default; + using var engine = ApplicationEngine.Create(TriggerType.Application, null, null, settings: TestProtocolSettings.Default, gas: 1100_00000000); using var script = new ScriptBuilder(); script.EmitSysCall(ApplicationEngine.System_Contract_CreateStandardAccount, settings.StandbyCommittee[0].EncodePoint(true)); @@ -27,7 +27,7 @@ public void TestCreateStandardAccount() [TestMethod] public void TestCreateStandardMultisigAccount() { - var settings = ProtocolSettings.Default; + var settings = TestProtocolSettings.Default; using var engine = ApplicationEngine.Create(TriggerType.Application, null, null, settings: TestBlockchain.TheNeoSystem.Settings, gas: 1100_00000000); using var script = new ScriptBuilder(); diff --git a/tests/Neo.UnitTests/SmartContract/UT_ApplicationEngine.cs b/tests/Neo.UnitTests/SmartContract/UT_ApplicationEngine.cs index 3687f0605e..5656fc2799 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_ApplicationEngine.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_ApplicationEngine.cs @@ -54,7 +54,7 @@ public void TestCreateDummyBlock() { var snapshot = TestBlockchain.GetTestSnapshot(); byte[] SyscallSystemRuntimeCheckWitnessHash = new byte[] { 0x68, 0xf8, 0x27, 0xec, 0x8c }; - ApplicationEngine engine = ApplicationEngine.Run(SyscallSystemRuntimeCheckWitnessHash, snapshot); + ApplicationEngine engine = ApplicationEngine.Run(SyscallSystemRuntimeCheckWitnessHash, snapshot, 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()); diff --git a/tests/Neo.UnitTests/SmartContract/UT_ContractParameterContext.cs b/tests/Neo.UnitTests/SmartContract/UT_ContractParameterContext.cs index c8696cb437..3413039fb5 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_ContractParameterContext.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_ContractParameterContext.cs @@ -34,7 +34,7 @@ public void TestGetComplete() { var snapshot = TestBlockchain.GetTestSnapshot(); Transaction tx = TestUtils.GetTransaction(UInt160.Parse("0x1bd5c777ec35768892bd3daab60fb7a1cb905066")); - var context = new ContractParametersContext(snapshot, tx, ProtocolSettings.Default.Network); + var context = new ContractParametersContext(snapshot, tx, TestProtocolSettings.Default.Network); context.Completed.Should().BeFalse(); } @@ -43,17 +43,17 @@ public void TestToString() { var snapshot = TestBlockchain.GetTestSnapshot(); Transaction tx = TestUtils.GetTransaction(UInt160.Parse("0x1bd5c777ec35768892bd3daab60fb7a1cb905066")); - var context = new ContractParametersContext(snapshot, tx, ProtocolSettings.Default.Network); + var context = new ContractParametersContext(snapshot, 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"":" + ProtocolSettings.Default.Network + "}"); + str.Should().Be(@"{""type"":""Neo.Network.P2P.Payloads.Transaction"",""hash"":""0x602c1fa1c08b041e4e6b87aa9a9f9c643166cd34bdd5215a3dd85778c59cce88"",""data"":""AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFmUJDLobcPtqo9vZKIdjXsd8fVGwEAARI="",""items"":{},""network"":" + TestProtocolSettings.Default.Network + "}"); } [TestMethod] public void TestParse() { var snapshot = TestBlockchain.GetTestSnapshot(); - 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\":" + ProtocolSettings.Default.Network + "}", snapshot); + 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()); } @@ -71,11 +71,11 @@ public void TestAdd() { var snapshot = TestBlockchain.GetTestSnapshot(); Transaction tx = TestUtils.GetTransaction(UInt160.Zero); - var context1 = new ContractParametersContext(snapshot, tx, ProtocolSettings.Default.Network); + var context1 = new ContractParametersContext(snapshot, 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, ProtocolSettings.Default.Network); + var context2 = new ContractParametersContext(snapshot, 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(); @@ -86,7 +86,7 @@ public void TestGetParameter() { var snapshot = TestBlockchain.GetTestSnapshot(); Transaction tx = TestUtils.GetTransaction(UInt160.Parse("0x902e0d38da5e513b6d07c1c55b85e77d3dce8063")); - var context = new ContractParametersContext(snapshot, tx, ProtocolSettings.Default.Network); + var context = new ContractParametersContext(snapshot, tx, TestProtocolSettings.Default.Network); context.GetParameter(tx.Sender, 0).Should().BeNull(); context.Add(contract, 0, new byte[] { 0x01 }); @@ -99,7 +99,7 @@ public void TestGetWitnesses() { var snapshot = TestBlockchain.GetTestSnapshot(); Transaction tx = TestUtils.GetTransaction(UInt160.Parse("0x902e0d38da5e513b6d07c1c55b85e77d3dce8063")); - var context = new ContractParametersContext(snapshot, tx, ProtocolSettings.Default.Network); + var context = new ContractParametersContext(snapshot, tx, TestProtocolSettings.Default.Network); context.Add(contract, 0, new byte[] { 0x01 }); Witness[] witnesses = context.GetWitnesses(); witnesses.Length.Should().Be(1); @@ -116,12 +116,12 @@ public void TestAddSignature() //singleSign - var context = new ContractParametersContext(snapshot, tx, ProtocolSettings.Default.Network); + var context = new ContractParametersContext(snapshot, 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, ProtocolSettings.Default.Network); + context = new ContractParametersContext(snapshot, tx, TestProtocolSettings.Default.Network); context.AddSignature(contract1, key.PublicKey, new byte[] { 0x01 }).Should().BeFalse(); contract1.ParameterList = new[] { ContractParameterType.Signature, ContractParameterType.Signature }; @@ -143,16 +143,16 @@ public void TestAddSignature() }); var multiSender = UInt160.Parse("0xf76b51bc6605ac3cfcd188173af0930507f51210"); tx = TestUtils.GetTransaction(multiSender); - context = new ContractParametersContext(snapshot, tx, ProtocolSettings.Default.Network); + context = new ContractParametersContext(snapshot, 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, ProtocolSettings.Default.Network); + context = new ContractParametersContext(snapshot, tx, TestProtocolSettings.Default.Network); context.AddSignature(multiSignContract, key.PublicKey, new byte[] { 0x01 }).Should().BeFalse(); tx = TestUtils.GetTransaction(multiSender); - context = new ContractParametersContext(snapshot, tx, ProtocolSettings.Default.Network); + context = new ContractParametersContext(snapshot, 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_Helper.cs b/tests/Neo.UnitTests/SmartContract/UT_Helper.cs index 2c5eb02dff..67d637392e 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_Helper.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_Helper.cs @@ -70,10 +70,10 @@ public void TestSignatureContractCost() tx.Signers[0].Account = contract.ScriptHash; using ScriptBuilder invocationScript = new(); - invocationScript.EmitPush(Neo.Wallets.Helper.Sign(tx, _key, ProtocolSettings.Default.Network)); + invocationScript.EmitPush(Neo.Wallets.Helper.Sign(tx, _key, TestProtocolSettings.Default.Network)); tx.Witnesses = new Witness[] { new Witness() { InvocationScript = invocationScript.ToArray(), VerificationScript = contract.Script } }; - using var engine = ApplicationEngine.Create(TriggerType.Verification, tx, null, null, ProtocolSettings.Default); + using var engine = ApplicationEngine.Create(TriggerType.Verification, tx, null, null, TestProtocolSettings.Default); engine.LoadScript(contract.Script); engine.LoadScript(new Script(invocationScript.ToArray(), true), configureState: p => p.CallFlags = CallFlags.None); Assert.AreEqual(VMState.HALT, engine.Execute()); @@ -91,9 +91,9 @@ public void TestMultiSignatureContractCost() tx.Signers[0].Account = contract.ScriptHash; using ScriptBuilder invocationScript = new(); - invocationScript.EmitPush(Neo.Wallets.Helper.Sign(tx, _key, ProtocolSettings.Default.Network)); + invocationScript.EmitPush(Neo.Wallets.Helper.Sign(tx, _key, TestProtocolSettings.Default.Network)); - using var engine = ApplicationEngine.Create(TriggerType.Verification, tx, null, null, ProtocolSettings.Default); + using var engine = ApplicationEngine.Create(TriggerType.Verification, tx, null, null, TestProtocolSettings.Default); engine.LoadScript(contract.Script); engine.LoadScript(new Script(invocationScript.ToArray(), true), configureState: p => p.CallFlags = CallFlags.None); Assert.AreEqual(VMState.HALT, engine.Execute()); diff --git a/tests/Neo.UnitTests/SmartContract/UT_InteropService.NEO.cs b/tests/Neo.UnitTests/SmartContract/UT_InteropService.NEO.cs index cabac00932..b4233bc6a9 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_InteropService.NEO.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_InteropService.NEO.cs @@ -23,7 +23,7 @@ public void TestCheckSig() { var engine = GetEngine(true); IVerifiable iv = engine.ScriptContainer; - byte[] message = iv.GetSignData(ProtocolSettings.Default.Network); + byte[] message = iv.GetSignData(TestProtocolSettings.Default.Network); byte[] privateKey = { 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}; KeyPair keyPair = new KeyPair(privateKey); @@ -39,7 +39,7 @@ public void TestCrypto_CheckMultiSig() { var engine = GetEngine(true); IVerifiable iv = engine.ScriptContainer; - byte[] message = iv.GetSignData(ProtocolSettings.Default.Network); + byte[] message = iv.GetSignData(TestProtocolSettings.Default.Network); byte[] privkey1 = { 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}; diff --git a/tests/Neo.UnitTests/SmartContract/UT_InteropService.cs b/tests/Neo.UnitTests/SmartContract/UT_InteropService.cs index 12b49c91e3..d1c518aaa1 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_InteropService.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_InteropService.cs @@ -386,7 +386,7 @@ public void TestCrypto_Verify() { var engine = GetEngine(true); IVerifiable iv = engine.ScriptContainer; - byte[] message = iv.GetSignData(ProtocolSettings.Default.Network); + byte[] message = iv.GetSignData(TestProtocolSettings.Default.Network); byte[] privateKey = { 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}; KeyPair keyPair = new(privateKey); diff --git a/tests/Neo.UnitTests/SmartContract/UT_SmartContractHelper.cs b/tests/Neo.UnitTests/SmartContract/UT_SmartContractHelper.cs index 773c3ed4e1..c4b55384a8 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_SmartContractHelper.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_SmartContractHelper.cs @@ -131,7 +131,7 @@ public void TestVerifyWitnesses() Hashes = new UInt256[1] { UInt256.Zero }, }); BlocksDelete(snapshot1, index1); - Assert.AreEqual(false, Neo.SmartContract.Helper.VerifyWitnesses(new Header() { PrevHash = index1 }, ProtocolSettings.Default, snapshot1, 100)); + Assert.AreEqual(false, Neo.SmartContract.Helper.VerifyWitnesses(new Header() { PrevHash = index1 }, TestProtocolSettings.Default, snapshot1, 100)); var snapshot2 = TestBlockchain.GetTestSnapshot(); UInt256 index2 = UInt256.Parse("0xa400ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff01"); @@ -152,7 +152,7 @@ public void TestVerifyWitnesses() snapshot2.AddContract(UInt160.Zero, new ContractState()); snapshot2.DeleteContract(UInt160.Zero); - Assert.AreEqual(false, Neo.SmartContract.Helper.VerifyWitnesses(header2, ProtocolSettings.Default, snapshot2, 100)); + Assert.AreEqual(false, Neo.SmartContract.Helper.VerifyWitnesses(header2, TestProtocolSettings.Default, snapshot2, 100)); var snapshot3 = TestBlockchain.GetTestSnapshot(); UInt256 index3 = UInt256.Parse("0xa400ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff01"); @@ -184,7 +184,7 @@ public void TestVerifyWitnesses() Hash = Array.Empty().ToScriptHash(), Manifest = TestUtils.CreateManifest("verify", ContractParameterType.Boolean, ContractParameterType.Signature), }); - Assert.AreEqual(false, Neo.SmartContract.Helper.VerifyWitnesses(header3, ProtocolSettings.Default, snapshot3, 100)); + Assert.AreEqual(false, Neo.SmartContract.Helper.VerifyWitnesses(header3, TestProtocolSettings.Default, snapshot3, 100)); // Smart contract verification @@ -200,7 +200,7 @@ public void TestVerifyWitnesses() Witnesses = new Witness[] { new Witness() { InvocationScript = Array.Empty(), VerificationScript = Array.Empty() } } }; - Assert.AreEqual(true, Neo.SmartContract.Helper.VerifyWitnesses(tx, ProtocolSettings.Default, snapshot3, 1000)); + Assert.AreEqual(true, Neo.SmartContract.Helper.VerifyWitnesses(tx, TestProtocolSettings.Default, snapshot3, 1000)); } private static void BlocksDelete(DataCache snapshot, UInt256 hash) diff --git a/tests/Neo.UnitTests/SmartContract/UT_Syscalls.cs b/tests/Neo.UnitTests/SmartContract/UT_Syscalls.cs index 7dd8c5ea78..77c4f7d5ef 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_Syscalls.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_Syscalls.cs @@ -71,7 +71,7 @@ public void System_Blockchain_GetBlock() const byte Prefix_CurrentBlock = 12; var height = snapshot[NativeContract.Ledger.CreateStorageKey(Prefix_CurrentBlock)].GetInteroperable(); - height.Index = block.Index + ProtocolSettings.Default.MaxTraceableBlocks; + height.Index = block.Index + TestProtocolSettings.Default.MaxTraceableBlocks; UT_SmartContractHelper.BlocksAdd(snapshot, block.Hash, block); snapshot.Add(NativeContract.Ledger.CreateStorageKey(Prefix_Transaction, tx.Hash), new StorageItem(new TransactionState diff --git a/tests/Neo.UnitTests/TestBlockchain.cs b/tests/Neo.UnitTests/TestBlockchain.cs index f1ea5eb975..e2fdad04c2 100644 --- a/tests/Neo.UnitTests/TestBlockchain.cs +++ b/tests/Neo.UnitTests/TestBlockchain.cs @@ -1,5 +1,5 @@ -using Neo.Persistence; using System; +using Neo.Persistence; namespace Neo.UnitTests { @@ -11,7 +11,7 @@ public static class TestBlockchain static TestBlockchain() { Console.WriteLine("initialize NeoSystem"); - TheNeoSystem = new NeoSystem(ProtocolSettings.Default, null, null); + TheNeoSystem = new NeoSystem(TestProtocolSettings.Default, null, null); } internal static DataCache GetTestSnapshot() diff --git a/tests/Neo.UnitTests/TestProtocolSettings.cs b/tests/Neo.UnitTests/TestProtocolSettings.cs new file mode 100644 index 0000000000..88f3be2c52 --- /dev/null +++ b/tests/Neo.UnitTests/TestProtocolSettings.cs @@ -0,0 +1,57 @@ +using Neo.Persistence; +using System; +using System.Collections.Immutable; +using Neo.Cryptography.ECC; + +namespace Neo.UnitTests +{ + public static class TestProtocolSettings + { + public static 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.UnitTests/TestUtils.cs b/tests/Neo.UnitTests/TestUtils.cs index 3233d96f7b..1425919608 100644 --- a/tests/Neo.UnitTests/TestUtils.cs +++ b/tests/Neo.UnitTests/TestUtils.cs @@ -97,7 +97,7 @@ public static NEP6Wallet GenerateTestWallet(string password) wallet["accounts"] = new JArray(); wallet["extra"] = null; wallet.ToString().Should().Be("{\"name\":\"noname\",\"version\":\"1.0\",\"scrypt\":{\"n\":2,\"r\":1,\"p\":1},\"accounts\":[],\"extra\":null}"); - return new NEP6Wallet(null, password, ProtocolSettings.Default, wallet); + return new NEP6Wallet(null, password, TestProtocolSettings.Default, wallet); } public static Transaction GetTransaction(UInt160 sender) diff --git a/tests/Neo.UnitTests/TestWalletAccount.cs b/tests/Neo.UnitTests/TestWalletAccount.cs index bc6d04825b..a36e26fc96 100644 --- a/tests/Neo.UnitTests/TestWalletAccount.cs +++ b/tests/Neo.UnitTests/TestWalletAccount.cs @@ -13,7 +13,7 @@ class TestWalletAccount : WalletAccount public override KeyPair GetKey() => key; public TestWalletAccount(UInt160 hash) - : base(hash, ProtocolSettings.Default) + : base(hash, TestProtocolSettings.Default) { var mock = new Mock(); mock.SetupGet(p => p.ScriptHash).Returns(hash); diff --git a/tests/Neo.UnitTests/UT_Helper.cs b/tests/Neo.UnitTests/UT_Helper.cs index fda1e40ace..d4a08469eb 100644 --- a/tests/Neo.UnitTests/UT_Helper.cs +++ b/tests/Neo.UnitTests/UT_Helper.cs @@ -19,7 +19,7 @@ public class UT_Helper public void GetSignData() { TestVerifiable verifiable = new(); - byte[] res = verifiable.GetSignData(ProtocolSettings.Default.Network); + byte[] res = verifiable.GetSignData(TestProtocolSettings.Default.Network); res.ToHexString().Should().Be("4e454f3350b51da6bb366be3ea50140cda45ba7df575287c0371000b2037ed3898ff8bf5"); } @@ -27,7 +27,7 @@ public void GetSignData() public void Sign() { TestVerifiable verifiable = new(); - byte[] res = verifiable.Sign(new KeyPair(TestUtils.GetByteArray(32, 0x42)), ProtocolSettings.Default.Network); + byte[] res = verifiable.Sign(new KeyPair(TestUtils.GetByteArray(32, 0x42)), TestProtocolSettings.Default.Network); res.Length.Should().Be(64); } diff --git a/tests/Neo.UnitTests/UT_ProtocolSettings.cs b/tests/Neo.UnitTests/UT_ProtocolSettings.cs index 42be0e69cc..74b529738a 100644 --- a/tests/Neo.UnitTests/UT_ProtocolSettings.cs +++ b/tests/Neo.UnitTests/UT_ProtocolSettings.cs @@ -1,5 +1,7 @@ +using System; using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Cryptography.ECC; using Neo.Wallets; namespace Neo.UnitTests @@ -11,34 +13,188 @@ public class UT_ProtocolSettings public void CheckFirstLetterOfAddresses() { UInt160 min = UInt160.Parse("0x0000000000000000000000000000000000000000"); - min.ToAddress(ProtocolSettings.Default.AddressVersion)[0].Should().Be('N'); + min.ToAddress(TestProtocolSettings.Default.AddressVersion)[0].Should().Be('N'); UInt160 max = UInt160.Parse("0xffffffffffffffffffffffffffffffffffffffff"); - max.ToAddress(ProtocolSettings.Default.AddressVersion)[0].Should().Be('N'); + max.ToAddress(TestProtocolSettings.Default.AddressVersion)[0].Should().Be('N'); } [TestMethod] public void Default_Network_should_be_mainnet_Network_value() { var mainNetNetwork = 0x334F454Eu; - ProtocolSettings.Default.Network.Should().Be(mainNetNetwork); + TestProtocolSettings.Default.Network.Should().Be(mainNetNetwork); } [TestMethod] public void TestGetMemoryPoolMaxTransactions() { - ProtocolSettings.Default.MemoryPoolMaxTransactions.Should().Be(50000); + TestProtocolSettings.Default.MemoryPoolMaxTransactions.Should().Be(50000); } [TestMethod] public void TestGetMillisecondsPerBlock() { - ProtocolSettings.Default.MillisecondsPerBlock.Should().Be(15000); + TestProtocolSettings.Default.MillisecondsPerBlock.Should().Be(15000); } [TestMethod] public void TestGetSeedList() { - ProtocolSettings.Default.SeedList.Should().BeEquivalentTo(new string[] { "seed1.neo.org:10333", "seed2.neo.org:10333", "seed3.neo.org:10333", "seed4.neo.org:10333", "seed5.neo.org:10333", }); + TestProtocolSettings.Default.SeedList.Should().BeEquivalentTo(new string[] { "seed1.neo.org:10333", "seed2.neo.org:10333", "seed3.neo.org:10333", "seed4.neo.org:10333", "seed5.neo.org:10333", }); + } + + [TestMethod] + public void TestStandbyCommitteeAddressesFormat() + { + foreach (var point in TestProtocolSettings.Default.StandbyCommittee) + { + point.ToString().Should().MatchRegex("^[0-9A-Fa-f]{66}$"); // ECPoint is 66 hex characters + } + } + + [TestMethod] + public void TestValidatorsCount() + { + TestProtocolSettings.Default.StandbyCommittee.Count.Should().Be(TestProtocolSettings.Default.ValidatorsCount * 3); + } + + [TestMethod] + public void TestMaxTransactionsPerBlock() + { + TestProtocolSettings.Default.MaxTransactionsPerBlock.Should().BePositive().And.BeLessOrEqualTo(50000); // Assuming 50000 as a reasonable upper limit + } + + [TestMethod] + public void TestMaxTraceableBlocks() + { + TestProtocolSettings.Default.MaxTraceableBlocks.Should().BePositive(); + } + + [TestMethod] + public void TestInitialGasDistribution() + { + TestProtocolSettings.Default.InitialGasDistribution.Should().BeGreaterThan(0); + } + + [TestMethod] + public void TestHardforksSettings() + { + TestProtocolSettings.Default.Hardforks.Should().NotBeNull(); + } + + [TestMethod] + public void TestAddressVersion() + { + TestProtocolSettings.Default.AddressVersion.Should().BeInRange(0, 255); // Address version is a byte + } + + [TestMethod] + public void TestNetworkSettingsConsistency() + { + TestProtocolSettings.Default.Network.Should().BePositive(); + TestProtocolSettings.Default.SeedList.Should().NotBeEmpty(); + } + + [TestMethod] + public void TestECPointParsing() + { + foreach (var point in TestProtocolSettings.Default.StandbyCommittee) + { + Action act = () => ECPoint.Parse(point.ToString(), ECCurve.Secp256r1); + act.Should().NotThrow(); + } + } + + [TestMethod] + public void TestSeedListFormatAndReachability() + { + foreach (var seed in TestProtocolSettings.Default.SeedList) + { + seed.Should().MatchRegex(@"^[\w.-]+:\d+$"); // Format: domain:port + } + } + + [TestMethod] + public void TestDefaultNetworkValue() + { + ProtocolSettings.Default.Network.Should().Be(0); + } + + [TestMethod] + public void TestDefaultAddressVersionValue() + { + TestProtocolSettings.Default.AddressVersion.Should().Be(ProtocolSettings.Default.AddressVersion); + } + + [TestMethod] + public void TestDefaultValidatorsCountValue() + { + ProtocolSettings.Default.ValidatorsCount.Should().Be(0); + } + + [TestMethod] + public void TestDefaultMillisecondsPerBlockValue() + { + TestProtocolSettings.Default.MillisecondsPerBlock.Should().Be(ProtocolSettings.Default.MillisecondsPerBlock); + } + + [TestMethod] + public void TestDefaultMaxTransactionsPerBlockValue() + { + TestProtocolSettings.Default.MaxTransactionsPerBlock.Should().Be(ProtocolSettings.Default.MaxTransactionsPerBlock); + } + + [TestMethod] + public void TestDefaultMemoryPoolMaxTransactionsValue() + { + TestProtocolSettings.Default.MemoryPoolMaxTransactions.Should().Be(ProtocolSettings.Default.MemoryPoolMaxTransactions); + } + + [TestMethod] + public void TestDefaultMaxTraceableBlocksValue() + { + TestProtocolSettings.Default.MaxTraceableBlocks.Should().Be(ProtocolSettings.Default.MaxTraceableBlocks); + } + + [TestMethod] + public void TestDefaultInitialGasDistributionValue() + { + TestProtocolSettings.Default.InitialGasDistribution.Should().Be(ProtocolSettings.Default.InitialGasDistribution); + } + + [TestMethod] + public void TestDefaultHardforksValue() + { + TestProtocolSettings.Default.Hardforks.Should().BeEquivalentTo(ProtocolSettings.Default.Hardforks); + } + + [TestMethod] + public void TestTimePerBlockCalculation() + { + var expectedTimeSpan = TimeSpan.FromMilliseconds(TestProtocolSettings.Default.MillisecondsPerBlock); + TestProtocolSettings.Default.TimePerBlock.Should().Be(expectedTimeSpan); + } + + [TestMethod] + public void TestLoad() + { + var loadedSetting = ProtocolSettings.Load("test.config.json", false); + + // Comparing all properties + TestProtocolSettings.Default.Network.Should().Be(loadedSetting.Network); + TestProtocolSettings.Default.AddressVersion.Should().Be(loadedSetting.AddressVersion); + TestProtocolSettings.Default.StandbyCommittee.Should().BeEquivalentTo(loadedSetting.StandbyCommittee); + TestProtocolSettings.Default.ValidatorsCount.Should().Be(loadedSetting.ValidatorsCount); + TestProtocolSettings.Default.SeedList.Should().BeEquivalentTo(loadedSetting.SeedList); + TestProtocolSettings.Default.MillisecondsPerBlock.Should().Be(loadedSetting.MillisecondsPerBlock); + TestProtocolSettings.Default.MaxTransactionsPerBlock.Should().Be(loadedSetting.MaxTransactionsPerBlock); + TestProtocolSettings.Default.MemoryPoolMaxTransactions.Should().Be(loadedSetting.MemoryPoolMaxTransactions); + TestProtocolSettings.Default.MaxTraceableBlocks.Should().Be(loadedSetting.MaxTraceableBlocks); + TestProtocolSettings.Default.InitialGasDistribution.Should().Be(loadedSetting.InitialGasDistribution); + TestProtocolSettings.Default.Hardforks.Should().BeEquivalentTo(loadedSetting.Hardforks); + + // If StandbyValidators is a derived property, comparing it as well + TestProtocolSettings.Default.StandbyValidators.Should().BeEquivalentTo(loadedSetting.StandbyValidators); } } } diff --git a/tests/Neo.UnitTests/Wallets/NEP6/UT_NEP6Account.cs b/tests/Neo.UnitTests/Wallets/NEP6/UT_NEP6Account.cs index 3090752ee8..3aac2f8f48 100644 --- a/tests/Neo.UnitTests/Wallets/NEP6/UT_NEP6Account.cs +++ b/tests/Neo.UnitTests/Wallets/NEP6/UT_NEP6Account.cs @@ -23,7 +23,7 @@ public static void ClassSetup(TestContext ctx) byte[] privateKey = { 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}; _keyPair = new KeyPair(privateKey); - _nep2 = _keyPair.Export("Satoshi", ProtocolSettings.Default.AddressVersion, 2, 1, 1); + _nep2 = _keyPair.Export("Satoshi", TestProtocolSettings.Default.AddressVersion, 2, 1, 1); } [TestInitialize] @@ -86,7 +86,7 @@ public void TestFromJson() json["contract"] = null; json["extra"] = null; NEP6Account account = NEP6Account.FromJson(json, _wallet); - account.ScriptHash.Should().Be("NdtB8RXRmJ7Nhw1FPTm7E6HoDZGnDw37nf".ToScriptHash(ProtocolSettings.Default.AddressVersion)); + account.ScriptHash.Should().Be("NdtB8RXRmJ7Nhw1FPTm7E6HoDZGnDw37nf".ToScriptHash(TestProtocolSettings.Default.AddressVersion)); account.Label.Should().BeNull(); account.IsDefault.Should().BeTrue(); account.Lock.Should().BeFalse(); diff --git a/tests/Neo.UnitTests/Wallets/NEP6/UT_NEP6Wallet.cs b/tests/Neo.UnitTests/Wallets/NEP6/UT_NEP6Wallet.cs index bd8e087aa7..098a6e1933 100644 --- a/tests/Neo.UnitTests/Wallets/NEP6/UT_NEP6Wallet.cs +++ b/tests/Neo.UnitTests/Wallets/NEP6/UT_NEP6Wallet.cs @@ -41,7 +41,7 @@ public static void ClassInit(TestContext context) } keyPair = new KeyPair(privateKey); testScriptHash = Contract.CreateSignatureContract(keyPair.PublicKey).ScriptHash; - nep2key = keyPair.Export("123", ProtocolSettings.Default.AddressVersion, 2, 1, 1); + nep2key = keyPair.Export("123", TestProtocolSettings.Default.AddressVersion, 2, 1, 1); } private string CreateWalletFile() @@ -77,10 +77,10 @@ public void TestCreateAccount() Script = new byte[1], Signers = new Signer[] { new Signer() { Account = acc.ScriptHash } }, }; - var ctx = new ContractParametersContext(TestBlockchain.GetTestSnapshot(), tx, ProtocolSettings.Default.Network); + var ctx = new ContractParametersContext(TestBlockchain.GetTestSnapshot(), tx, TestProtocolSettings.Default.Network); Assert.IsTrue(uut.Sign(ctx)); tx.Witnesses = ctx.GetWitnesses(); - Assert.IsTrue(tx.VerifyWitnesses(ProtocolSettings.Default, TestBlockchain.GetTestSnapshot(), long.MaxValue)); + Assert.IsTrue(tx.VerifyWitnesses(TestProtocolSettings.Default, TestBlockchain.GetTestSnapshot(), long.MaxValue)); Assert.ThrowsException(() => uut.CreateAccount((byte[])null)); Assert.ThrowsException(() => uut.CreateAccount("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551".HexToBytes())); } @@ -95,7 +95,7 @@ public void TestChangePassword() wallet["accounts"] = new JArray(); wallet["extra"] = new JObject(); File.WriteAllText(wPath, wallet.ToString()); - uut = new NEP6Wallet(wPath, "123", ProtocolSettings.Default); + uut = new NEP6Wallet(wPath, "123", TestProtocolSettings.Default); uut.CreateAccount(keyPair.PrivateKey); uut.ChangePassword("456", "123").Should().BeFalse(); uut.ChangePassword("123", "456").Should().BeTrue(); @@ -106,11 +106,11 @@ public void TestChangePassword() [TestMethod] public void TestConstructorWithPathAndName() { - NEP6Wallet wallet = new(wPath, "123", ProtocolSettings.Default); + NEP6Wallet wallet = new(wPath, "123", TestProtocolSettings.Default); Assert.AreEqual("name", wallet.Name); Assert.AreEqual(new ScryptParameters(2, 1, 1).ToJson().ToString(), wallet.Scrypt.ToJson().ToString()); Assert.AreEqual(new Version("1.0").ToString(), wallet.Version.ToString()); - wallet = new NEP6Wallet("", "123", ProtocolSettings.Default, "test"); + wallet = new NEP6Wallet("", "123", TestProtocolSettings.Default, "test"); Assert.AreEqual("test", wallet.Name); Assert.AreEqual(ScryptParameters.Default.ToJson().ToString(), wallet.Scrypt.ToJson().ToString()); Assert.AreEqual(Version.Parse("1.0"), wallet.Version); @@ -126,7 +126,7 @@ public void TestConstructorWithJObject() wallet["accounts"] = new JArray(); wallet["extra"] = new JObject(); wallet.ToString().Should().Be("{\"name\":\"test\",\"version\":\"1.0\",\"scrypt\":{\"n\":16384,\"r\":8,\"p\":8},\"accounts\":[],\"extra\":{}}"); - NEP6Wallet w = new(null, "123", ProtocolSettings.Default, wallet); + NEP6Wallet w = new(null, "123", TestProtocolSettings.Default, wallet); Assert.AreEqual("test", w.Name); Assert.AreEqual(Version.Parse("1.0").ToString(), w.Version.ToString()); } diff --git a/tests/Neo.UnitTests/Wallets/UT_AssetDescriptor.cs b/tests/Neo.UnitTests/Wallets/UT_AssetDescriptor.cs index d87811cf7f..a8d8308145 100644 --- a/tests/Neo.UnitTests/Wallets/UT_AssetDescriptor.cs +++ b/tests/Neo.UnitTests/Wallets/UT_AssetDescriptor.cs @@ -14,7 +14,7 @@ public void TestConstructorWithNonexistAssetId() var snapshot = TestBlockchain.GetTestSnapshot(); Action action = () => { - var descriptor = new Neo.Wallets.AssetDescriptor(snapshot, ProtocolSettings.Default, UInt160.Parse("01ff00ff00ff00ff00ff00ff00ff00ff00ff00a4")); + var descriptor = new Neo.Wallets.AssetDescriptor(snapshot, TestProtocolSettings.Default, UInt160.Parse("01ff00ff00ff00ff00ff00ff00ff00ff00ff00a4")); }; action.Should().Throw(); } @@ -23,7 +23,7 @@ public void TestConstructorWithNonexistAssetId() public void Check_GAS() { var snapshot = TestBlockchain.GetTestSnapshot(); - var descriptor = new Neo.Wallets.AssetDescriptor(snapshot, ProtocolSettings.Default, NativeContract.GAS.Hash); + 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)); descriptor.ToString().Should().Be(nameof(GasToken)); @@ -35,7 +35,7 @@ public void Check_GAS() public void Check_NEO() { var snapshot = TestBlockchain.GetTestSnapshot(); - var descriptor = new Neo.Wallets.AssetDescriptor(snapshot, ProtocolSettings.Default, NativeContract.NEO.Hash); + 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)); 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 bf42ad7cd0..63a9d3e372 100644 --- a/tests/Neo.UnitTests/Wallets/UT_Wallet.cs +++ b/tests/Neo.UnitTests/Wallets/UT_Wallet.cs @@ -20,7 +20,7 @@ internal class MyWallet : Wallet private readonly Dictionary accounts = new(); - public MyWallet() : base(null, ProtocolSettings.Default) + public MyWallet() : base(null, TestProtocolSettings.Default) { } @@ -112,7 +112,7 @@ public class UT_Wallet public static void ClassInit(TestContext ctx) { glkey = UT_Crypto.GenerateCertainKey(32); - nep2Key = glkey.Export("pwd", ProtocolSettings.Default.AddressVersion, 2, 1, 1); + nep2Key = glkey.Export("pwd", TestProtocolSettings.Default.AddressVersion, 2, 1, 1); } [TestMethod] diff --git a/tests/Neo.UnitTests/Wallets/UT_WalletAccount.cs b/tests/Neo.UnitTests/Wallets/UT_WalletAccount.cs index 13ba4d113f..6ad53945d9 100644 --- a/tests/Neo.UnitTests/Wallets/UT_WalletAccount.cs +++ b/tests/Neo.UnitTests/Wallets/UT_WalletAccount.cs @@ -11,7 +11,7 @@ public class MyWalletAccount : WalletAccount public override bool HasKey => key != null; public MyWalletAccount(UInt160 scriptHash) - : base(scriptHash, ProtocolSettings.Default) + : base(scriptHash, TestProtocolSettings.Default) { } diff --git a/tests/Neo.UnitTests/Wallets/UT_Wallets_Helper.cs b/tests/Neo.UnitTests/Wallets/UT_Wallets_Helper.cs index 8c5f23f5a4..4fa35dc1a0 100644 --- a/tests/Neo.UnitTests/Wallets/UT_Wallets_Helper.cs +++ b/tests/Neo.UnitTests/Wallets/UT_Wallets_Helper.cs @@ -15,9 +15,9 @@ public void TestToScriptHash() { byte[] array = { 0x01 }; UInt160 scriptHash = new UInt160(Crypto.Hash160(array)); - "NdtB8RXRmJ7Nhw1FPTm7E6HoDZGnDw37nf".ToScriptHash(ProtocolSettings.Default.AddressVersion).Should().Be(scriptHash); + "NdtB8RXRmJ7Nhw1FPTm7E6HoDZGnDw37nf".ToScriptHash(TestProtocolSettings.Default.AddressVersion).Should().Be(scriptHash); - Action action = () => "3vQB7B6MrGQZaxCuFg4oh".ToScriptHash(ProtocolSettings.Default.AddressVersion); + Action action = () => "3vQB7B6MrGQZaxCuFg4oh".ToScriptHash(TestProtocolSettings.Default.AddressVersion); action.Should().Throw(); var address = scriptHash.ToAddress(ProtocolSettings.Default.AddressVersion); diff --git a/tests/Neo.UnitTests/test.config.json b/tests/Neo.UnitTests/test.config.json new file mode 100644 index 0000000000..0d2f885da6 --- /dev/null +++ b/tests/Neo.UnitTests/test.config.json @@ -0,0 +1,66 @@ +{ + "ApplicationConfiguration": { + "Logger": { + "Path": "Logs", + "ConsoleOutput": false, + "Active": false + }, + "Storage": { + "Engine": "LevelDBStore", + "Path": "Data_LevelDB_{0}" + }, + "P2P": { + "Port": 10333, + "WsPort": 10334, + "MinDesiredConnections": 10, + "MaxConnections": 40, + "MaxConnectionsPerAddress": 3 + }, + "UnlockWallet": { + "Path": "", + "Password": "", + "IsActive": false + } + }, + "ProtocolConfiguration": { + "Network": 860833102, + "AddressVersion": 53, + "MillisecondsPerBlock": 15000, + "MaxTransactionsPerBlock": 512, + "MemoryPoolMaxTransactions": 50000, + "MaxTraceableBlocks": 2102400, + "Hardforks": {}, + "InitialGasDistribution": 5200000000000000, + "ValidatorsCount": 7, + "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" + ] + } +} From 40d108671e306c2e3b37b8ca12caa0f86d83e0e3 Mon Sep 17 00:00:00 2001 From: Ricardo Prado <38396062+lock9@users.noreply.github.com> Date: Thu, 7 Dec 2023 05:22:27 -0300 Subject: [PATCH 024/168] Neo-node Migration (#2990) * Neo Node Migration * Added blockchain show block/transactions/contracts commands #905 (cschuchardt88) Added icon to applications #908 (cschuchardt88) * Update README.md --- README.md | 3 - neo.sln | 28 + src/Neo.CLI/CLI/ConsolePercent.cs | 145 ++ src/Neo.CLI/CLI/Helper.cs | 41 + src/Neo.CLI/CLI/MainService.Blockchain.cs | 317 ++++ src/Neo.CLI/CLI/MainService.Contracts.cs | 182 ++ src/Neo.CLI/CLI/MainService.Logger.cs | 171 ++ src/Neo.CLI/CLI/MainService.NEP17.cs | 140 ++ src/Neo.CLI/CLI/MainService.Native.cs | 29 + src/Neo.CLI/CLI/MainService.Network.cs | 164 ++ src/Neo.CLI/CLI/MainService.Node.cs | 118 ++ src/Neo.CLI/CLI/MainService.Plugins.cs | 244 +++ src/Neo.CLI/CLI/MainService.Tools.cs | 462 +++++ src/Neo.CLI/CLI/MainService.Vote.cs | 239 +++ src/Neo.CLI/CLI/MainService.Wallet.cs | 743 ++++++++ src/Neo.CLI/CLI/MainService.cs | 609 +++++++ src/Neo.CLI/Dockerfile | 20 + src/Neo.CLI/Extensions.cs | 28 + src/Neo.CLI/Neo.CLI.csproj | 29 + src/Neo.CLI/Program.cs | 23 + src/Neo.CLI/Settings.cs | 120 ++ src/Neo.CLI/config.fs.mainnet.json | 53 + src/Neo.CLI/config.fs.testnet.json | 53 + src/Neo.CLI/config.json | 69 + src/Neo.CLI/config.mainnet.json | 69 + src/Neo.CLI/config.testnet.json | 69 + src/Neo.CLI/neo.ico | Bin 0 -> 105486 bytes src/Neo.ConsoleService/CommandQuoteToken.cs | 53 + src/Neo.ConsoleService/CommandSpaceToken.cs | 64 + src/Neo.ConsoleService/CommandStringToken.cs | 90 + src/Neo.ConsoleService/CommandToken.cs | 225 +++ src/Neo.ConsoleService/CommandTokenType.cs | 19 + src/Neo.ConsoleService/ConsoleColorSet.cs | 51 + .../ConsoleCommandAttribute.cs | 45 + .../ConsoleCommandMethod.cs | 120 ++ src/Neo.ConsoleService/ConsoleHelper.cs | 65 + src/Neo.ConsoleService/ConsoleServiceBase.cs | 627 +++++++ .../Neo.ConsoleService.csproj | 12 + .../Properties/AssemblyInfo.cs | 13 + src/Neo.ConsoleService/ServiceProxy.cs | 34 + src/Neo.GUI/GUI/BulkPayDialog.Designer.cs | 129 ++ src/Neo.GUI/GUI/BulkPayDialog.cs | 80 + src/Neo.GUI/GUI/BulkPayDialog.es-ES.resx | 148 ++ src/Neo.GUI/GUI/BulkPayDialog.resx | 354 ++++ src/Neo.GUI/GUI/BulkPayDialog.zh-Hans.resx | 157 ++ .../GUI/ChangePasswordDialog.Designer.cs | 137 ++ src/Neo.GUI/GUI/ChangePasswordDialog.cs | 53 + .../GUI/ChangePasswordDialog.es-ES.resx | 181 ++ src/Neo.GUI/GUI/ChangePasswordDialog.resx | 369 ++++ .../GUI/ChangePasswordDialog.zh-Hans.resx | 172 ++ src/Neo.GUI/GUI/ConsoleForm.Designer.cs | 91 + src/Neo.GUI/GUI/ConsoleForm.cs | 67 + src/Neo.GUI/GUI/ConsoleForm.resx | 120 ++ .../CreateMultiSigContractDialog.Designer.cs | 153 ++ .../GUI/CreateMultiSigContractDialog.cs | 71 + .../CreateMultiSigContractDialog.es-ES.resx | 179 ++ .../GUI/CreateMultiSigContractDialog.resx | 399 +++++ .../CreateMultiSigContractDialog.zh-Hans.resx | 178 ++ src/Neo.GUI/GUI/CreateWalletDialog.cs | 71 + .../GUI/CreateWalletDialog.designer.cs | 143 ++ src/Neo.GUI/GUI/CreateWalletDialog.es-ES.resx | 169 ++ src/Neo.GUI/GUI/CreateWalletDialog.resx | 363 ++++ .../GUI/CreateWalletDialog.zh-Hans.resx | 181 ++ .../GUI/DeployContractDialog.Designer.cs | 308 ++++ src/Neo.GUI/GUI/DeployContractDialog.cs | 60 + .../GUI/DeployContractDialog.es-ES.resx | 217 +++ src/Neo.GUI/GUI/DeployContractDialog.resx | 972 +++++++++++ .../GUI/DeployContractDialog.zh-Hans.resx | 259 +++ .../DeveloperToolsForm.ContractParameters.cs | 117 ++ .../GUI/DeveloperToolsForm.Designer.cs | 259 +++ .../GUI/DeveloperToolsForm.TxBuilder.cs | 36 + src/Neo.GUI/GUI/DeveloperToolsForm.cs | 23 + src/Neo.GUI/GUI/DeveloperToolsForm.es-ES.resx | 153 ++ src/Neo.GUI/GUI/DeveloperToolsForm.resx | 669 ++++++++ .../GUI/DeveloperToolsForm.zh-Hans.resx | 153 ++ src/Neo.GUI/GUI/ElectionDialog.Designer.cs | 92 + src/Neo.GUI/GUI/ElectionDialog.cs | 51 + src/Neo.GUI/GUI/ElectionDialog.es-ES.resx | 123 ++ src/Neo.GUI/GUI/ElectionDialog.resx | 231 +++ src/Neo.GUI/GUI/ElectionDialog.zh-Hans.resx | 146 ++ src/Neo.GUI/GUI/Helper.cs | 74 + .../ImportCustomContractDialog.Designer.cs | 137 ++ src/Neo.GUI/GUI/ImportCustomContractDialog.cs | 53 + .../GUI/ImportCustomContractDialog.es-ES.resx | 154 ++ .../GUI/ImportCustomContractDialog.resx | 366 ++++ .../ImportCustomContractDialog.zh-Hans.resx | 160 ++ src/Neo.GUI/GUI/ImportPrivateKeyDialog.cs | 40 + .../GUI/ImportPrivateKeyDialog.designer.cs | 102 ++ .../GUI/ImportPrivateKeyDialog.es-ES.resx | 136 ++ src/Neo.GUI/GUI/ImportPrivateKeyDialog.resx | 267 +++ .../GUI/ImportPrivateKeyDialog.zh-Hans.resx | 132 ++ src/Neo.GUI/GUI/InformationBox.Designer.cs | 100 ++ src/Neo.GUI/GUI/InformationBox.cs | 43 + src/Neo.GUI/GUI/InformationBox.es-ES.resx | 129 ++ src/Neo.GUI/GUI/InformationBox.resx | 255 +++ src/Neo.GUI/GUI/InformationBox.zh-Hans.resx | 126 ++ src/Neo.GUI/GUI/InputBox.Designer.cs | 102 ++ src/Neo.GUI/GUI/InputBox.cs | 32 + src/Neo.GUI/GUI/InputBox.es-ES.resx | 126 ++ src/Neo.GUI/GUI/InputBox.resx | 249 +++ src/Neo.GUI/GUI/InputBox.zh-Hans.resx | 126 ++ .../GUI/InvokeContractDialog.Designer.cs | 270 +++ src/Neo.GUI/GUI/InvokeContractDialog.cs | 145 ++ .../GUI/InvokeContractDialog.es-ES.resx | 154 ++ src/Neo.GUI/GUI/InvokeContractDialog.resx | 735 ++++++++ .../GUI/InvokeContractDialog.zh-Hans.resx | 184 ++ src/Neo.GUI/GUI/MainForm.Designer.cs | 732 ++++++++ src/Neo.GUI/GUI/MainForm.cs | 615 +++++++ src/Neo.GUI/GUI/MainForm.es-ES.resx | 437 +++++ src/Neo.GUI/GUI/MainForm.resx | 1488 +++++++++++++++++ src/Neo.GUI/GUI/MainForm.zh-Hans.resx | 445 +++++ src/Neo.GUI/GUI/OpenWalletDialog.cs | 65 + src/Neo.GUI/GUI/OpenWalletDialog.designer.cs | 125 ++ src/Neo.GUI/GUI/OpenWalletDialog.es-ES.resx | 151 ++ src/Neo.GUI/GUI/OpenWalletDialog.resx | 315 ++++ src/Neo.GUI/GUI/OpenWalletDialog.zh-Hans.resx | 157 ++ src/Neo.GUI/GUI/ParametersEditor.Designer.cs | 200 +++ src/Neo.GUI/GUI/ParametersEditor.cs | 197 +++ src/Neo.GUI/GUI/ParametersEditor.es-ES.resx | 141 ++ src/Neo.GUI/GUI/ParametersEditor.resx | 489 ++++++ src/Neo.GUI/GUI/ParametersEditor.zh-Hans.resx | 144 ++ src/Neo.GUI/GUI/PayToDialog.Designer.cs | 142 ++ src/Neo.GUI/GUI/PayToDialog.cs | 105 ++ src/Neo.GUI/GUI/PayToDialog.es-ES.resx | 163 ++ src/Neo.GUI/GUI/PayToDialog.resx | 384 +++++ src/Neo.GUI/GUI/PayToDialog.zh-Hans.resx | 193 +++ src/Neo.GUI/GUI/QueueReader.cs | 48 + src/Neo.GUI/GUI/SigningDialog.Designer.cs | 172 ++ src/Neo.GUI/GUI/SigningDialog.cs | 106 ++ src/Neo.GUI/GUI/SigningDialog.es-ES.resx | 141 ++ src/Neo.GUI/GUI/SigningDialog.resx | 462 +++++ src/Neo.GUI/GUI/SigningDialog.zh-Hans.resx | 151 ++ src/Neo.GUI/GUI/SigningTxDialog.Designer.cs | 142 ++ src/Neo.GUI/GUI/SigningTxDialog.cs | 66 + src/Neo.GUI/GUI/SigningTxDialog.es-ES.resx | 141 ++ src/Neo.GUI/GUI/SigningTxDialog.resx | 372 +++++ src/Neo.GUI/GUI/SigningTxDialog.zh-Hans.resx | 141 ++ src/Neo.GUI/GUI/TextBoxWriter.cs | 39 + src/Neo.GUI/GUI/TransferDialog.Designer.cs | 131 ++ src/Neo.GUI/GUI/TransferDialog.cs | 41 + src/Neo.GUI/GUI/TransferDialog.es-ES.resx | 132 ++ src/Neo.GUI/GUI/TransferDialog.resx | 369 ++++ src/Neo.GUI/GUI/TransferDialog.zh-Hans.resx | 142 ++ src/Neo.GUI/GUI/TxOutListBox.Designer.cs | 109 ++ src/Neo.GUI/GUI/TxOutListBox.cs | 102 ++ src/Neo.GUI/GUI/TxOutListBox.resx | 300 ++++ src/Neo.GUI/GUI/TxOutListBoxItem.cs | 24 + src/Neo.GUI/GUI/UpdateDialog.Designer.cs | 149 ++ src/Neo.GUI/GUI/UpdateDialog.cs | 76 + src/Neo.GUI/GUI/UpdateDialog.es-ES.resx | 157 ++ src/Neo.GUI/GUI/UpdateDialog.resx | 399 +++++ src/Neo.GUI/GUI/UpdateDialog.zh-Hans.resx | 160 ++ .../GUI/ViewContractDialog.Designer.cs | 143 ++ src/Neo.GUI/GUI/ViewContractDialog.cs | 29 + src/Neo.GUI/GUI/ViewContractDialog.es-ES.resx | 187 +++ src/Neo.GUI/GUI/ViewContractDialog.resx | 387 +++++ .../GUI/ViewContractDialog.zh-Hans.resx | 172 ++ src/Neo.GUI/GUI/ViewPrivateKeyDialog.cs | 28 + .../GUI/ViewPrivateKeyDialog.designer.cs | 155 ++ .../GUI/ViewPrivateKeyDialog.es-ES.resx | 160 ++ src/Neo.GUI/GUI/ViewPrivateKeyDialog.resx | 408 +++++ .../GUI/ViewPrivateKeyDialog.zh-Hans.resx | 178 ++ src/Neo.GUI/GUI/VotingDialog.Designer.cs | 111 ++ src/Neo.GUI/GUI/VotingDialog.cs | 53 + src/Neo.GUI/GUI/VotingDialog.es-ES.resx | 132 ++ src/Neo.GUI/GUI/VotingDialog.resx | 300 ++++ src/Neo.GUI/GUI/VotingDialog.zh-Hans.resx | 132 ++ src/Neo.GUI/GUI/Wrappers/HexConverter.cs | 48 + src/Neo.GUI/GUI/Wrappers/ScriptEditor.cs | 35 + src/Neo.GUI/GUI/Wrappers/SignerWrapper.cs | 37 + .../Wrappers/TransactionAttributeWrapper.cs | 29 + .../GUI/Wrappers/TransactionWrapper.cs | 58 + src/Neo.GUI/GUI/Wrappers/UIntBaseConverter.cs | 53 + src/Neo.GUI/GUI/Wrappers/WitnessWrapper.cs | 35 + src/Neo.GUI/IO/Actors/EventWrapper.cs | 42 + src/Neo.GUI/Neo.GUI.csproj | 60 + src/Neo.GUI/Program.cs | 95 ++ src/Neo.GUI/Properties/Resources.Designer.cs | 133 ++ src/Neo.GUI/Properties/Resources.resx | 139 ++ src/Neo.GUI/Properties/Strings.Designer.cs | 542 ++++++ src/Neo.GUI/Properties/Strings.es-Es.resx | 259 +++ src/Neo.GUI/Properties/Strings.resx | 277 +++ src/Neo.GUI/Properties/Strings.zh-Hans.resx | 277 +++ src/Neo.GUI/Resources/add.png | Bin 0 -> 299 bytes src/Neo.GUI/Resources/add2.png | Bin 0 -> 419 bytes src/Neo.GUI/Resources/remark.png | Bin 0 -> 386 bytes src/Neo.GUI/Resources/remove.png | Bin 0 -> 291 bytes src/Neo.GUI/Resources/search.png | Bin 0 -> 442 bytes src/Neo.GUI/Resources/update.bat | 13 + src/Neo.GUI/neo.ico | Bin 0 -> 370070 bytes .../CommandTokenTest.cs | 92 + .../Neo.ConsoleService.Tests.csproj | 10 + 192 files changed, 33583 insertions(+), 3 deletions(-) create mode 100644 src/Neo.CLI/CLI/ConsolePercent.cs create mode 100644 src/Neo.CLI/CLI/Helper.cs create mode 100644 src/Neo.CLI/CLI/MainService.Blockchain.cs create mode 100644 src/Neo.CLI/CLI/MainService.Contracts.cs create mode 100644 src/Neo.CLI/CLI/MainService.Logger.cs create mode 100644 src/Neo.CLI/CLI/MainService.NEP17.cs create mode 100644 src/Neo.CLI/CLI/MainService.Native.cs create mode 100644 src/Neo.CLI/CLI/MainService.Network.cs create mode 100644 src/Neo.CLI/CLI/MainService.Node.cs create mode 100644 src/Neo.CLI/CLI/MainService.Plugins.cs create mode 100644 src/Neo.CLI/CLI/MainService.Tools.cs create mode 100644 src/Neo.CLI/CLI/MainService.Vote.cs create mode 100644 src/Neo.CLI/CLI/MainService.Wallet.cs create mode 100644 src/Neo.CLI/CLI/MainService.cs create mode 100644 src/Neo.CLI/Dockerfile create mode 100644 src/Neo.CLI/Extensions.cs create mode 100644 src/Neo.CLI/Neo.CLI.csproj create mode 100644 src/Neo.CLI/Program.cs create mode 100644 src/Neo.CLI/Settings.cs create mode 100644 src/Neo.CLI/config.fs.mainnet.json create mode 100644 src/Neo.CLI/config.fs.testnet.json create mode 100644 src/Neo.CLI/config.json create mode 100644 src/Neo.CLI/config.mainnet.json create mode 100644 src/Neo.CLI/config.testnet.json create mode 100644 src/Neo.CLI/neo.ico create mode 100644 src/Neo.ConsoleService/CommandQuoteToken.cs create mode 100644 src/Neo.ConsoleService/CommandSpaceToken.cs create mode 100644 src/Neo.ConsoleService/CommandStringToken.cs create mode 100644 src/Neo.ConsoleService/CommandToken.cs create mode 100644 src/Neo.ConsoleService/CommandTokenType.cs create mode 100644 src/Neo.ConsoleService/ConsoleColorSet.cs create mode 100644 src/Neo.ConsoleService/ConsoleCommandAttribute.cs create mode 100644 src/Neo.ConsoleService/ConsoleCommandMethod.cs create mode 100644 src/Neo.ConsoleService/ConsoleHelper.cs create mode 100644 src/Neo.ConsoleService/ConsoleServiceBase.cs create mode 100644 src/Neo.ConsoleService/Neo.ConsoleService.csproj create mode 100644 src/Neo.ConsoleService/Properties/AssemblyInfo.cs create mode 100644 src/Neo.ConsoleService/ServiceProxy.cs create mode 100644 src/Neo.GUI/GUI/BulkPayDialog.Designer.cs create mode 100644 src/Neo.GUI/GUI/BulkPayDialog.cs create mode 100644 src/Neo.GUI/GUI/BulkPayDialog.es-ES.resx create mode 100644 src/Neo.GUI/GUI/BulkPayDialog.resx create mode 100644 src/Neo.GUI/GUI/BulkPayDialog.zh-Hans.resx create mode 100644 src/Neo.GUI/GUI/ChangePasswordDialog.Designer.cs create mode 100644 src/Neo.GUI/GUI/ChangePasswordDialog.cs create mode 100644 src/Neo.GUI/GUI/ChangePasswordDialog.es-ES.resx create mode 100644 src/Neo.GUI/GUI/ChangePasswordDialog.resx create mode 100644 src/Neo.GUI/GUI/ChangePasswordDialog.zh-Hans.resx create mode 100644 src/Neo.GUI/GUI/ConsoleForm.Designer.cs create mode 100644 src/Neo.GUI/GUI/ConsoleForm.cs create mode 100644 src/Neo.GUI/GUI/ConsoleForm.resx create mode 100644 src/Neo.GUI/GUI/CreateMultiSigContractDialog.Designer.cs create mode 100644 src/Neo.GUI/GUI/CreateMultiSigContractDialog.cs create mode 100644 src/Neo.GUI/GUI/CreateMultiSigContractDialog.es-ES.resx create mode 100644 src/Neo.GUI/GUI/CreateMultiSigContractDialog.resx create mode 100644 src/Neo.GUI/GUI/CreateMultiSigContractDialog.zh-Hans.resx create mode 100644 src/Neo.GUI/GUI/CreateWalletDialog.cs create mode 100644 src/Neo.GUI/GUI/CreateWalletDialog.designer.cs create mode 100644 src/Neo.GUI/GUI/CreateWalletDialog.es-ES.resx create mode 100644 src/Neo.GUI/GUI/CreateWalletDialog.resx create mode 100644 src/Neo.GUI/GUI/CreateWalletDialog.zh-Hans.resx create mode 100644 src/Neo.GUI/GUI/DeployContractDialog.Designer.cs create mode 100644 src/Neo.GUI/GUI/DeployContractDialog.cs create mode 100644 src/Neo.GUI/GUI/DeployContractDialog.es-ES.resx create mode 100644 src/Neo.GUI/GUI/DeployContractDialog.resx create mode 100644 src/Neo.GUI/GUI/DeployContractDialog.zh-Hans.resx create mode 100644 src/Neo.GUI/GUI/DeveloperToolsForm.ContractParameters.cs create mode 100644 src/Neo.GUI/GUI/DeveloperToolsForm.Designer.cs create mode 100644 src/Neo.GUI/GUI/DeveloperToolsForm.TxBuilder.cs create mode 100644 src/Neo.GUI/GUI/DeveloperToolsForm.cs create mode 100644 src/Neo.GUI/GUI/DeveloperToolsForm.es-ES.resx create mode 100644 src/Neo.GUI/GUI/DeveloperToolsForm.resx create mode 100644 src/Neo.GUI/GUI/DeveloperToolsForm.zh-Hans.resx create mode 100644 src/Neo.GUI/GUI/ElectionDialog.Designer.cs create mode 100644 src/Neo.GUI/GUI/ElectionDialog.cs create mode 100644 src/Neo.GUI/GUI/ElectionDialog.es-ES.resx create mode 100644 src/Neo.GUI/GUI/ElectionDialog.resx create mode 100644 src/Neo.GUI/GUI/ElectionDialog.zh-Hans.resx create mode 100644 src/Neo.GUI/GUI/Helper.cs create mode 100644 src/Neo.GUI/GUI/ImportCustomContractDialog.Designer.cs create mode 100644 src/Neo.GUI/GUI/ImportCustomContractDialog.cs create mode 100644 src/Neo.GUI/GUI/ImportCustomContractDialog.es-ES.resx create mode 100644 src/Neo.GUI/GUI/ImportCustomContractDialog.resx create mode 100644 src/Neo.GUI/GUI/ImportCustomContractDialog.zh-Hans.resx create mode 100644 src/Neo.GUI/GUI/ImportPrivateKeyDialog.cs create mode 100644 src/Neo.GUI/GUI/ImportPrivateKeyDialog.designer.cs create mode 100644 src/Neo.GUI/GUI/ImportPrivateKeyDialog.es-ES.resx create mode 100644 src/Neo.GUI/GUI/ImportPrivateKeyDialog.resx create mode 100644 src/Neo.GUI/GUI/ImportPrivateKeyDialog.zh-Hans.resx create mode 100644 src/Neo.GUI/GUI/InformationBox.Designer.cs create mode 100644 src/Neo.GUI/GUI/InformationBox.cs create mode 100644 src/Neo.GUI/GUI/InformationBox.es-ES.resx create mode 100644 src/Neo.GUI/GUI/InformationBox.resx create mode 100644 src/Neo.GUI/GUI/InformationBox.zh-Hans.resx create mode 100644 src/Neo.GUI/GUI/InputBox.Designer.cs create mode 100644 src/Neo.GUI/GUI/InputBox.cs create mode 100644 src/Neo.GUI/GUI/InputBox.es-ES.resx create mode 100644 src/Neo.GUI/GUI/InputBox.resx create mode 100644 src/Neo.GUI/GUI/InputBox.zh-Hans.resx create mode 100644 src/Neo.GUI/GUI/InvokeContractDialog.Designer.cs create mode 100644 src/Neo.GUI/GUI/InvokeContractDialog.cs create mode 100644 src/Neo.GUI/GUI/InvokeContractDialog.es-ES.resx create mode 100644 src/Neo.GUI/GUI/InvokeContractDialog.resx create mode 100644 src/Neo.GUI/GUI/InvokeContractDialog.zh-Hans.resx create mode 100644 src/Neo.GUI/GUI/MainForm.Designer.cs create mode 100644 src/Neo.GUI/GUI/MainForm.cs create mode 100644 src/Neo.GUI/GUI/MainForm.es-ES.resx create mode 100644 src/Neo.GUI/GUI/MainForm.resx create mode 100644 src/Neo.GUI/GUI/MainForm.zh-Hans.resx create mode 100644 src/Neo.GUI/GUI/OpenWalletDialog.cs create mode 100644 src/Neo.GUI/GUI/OpenWalletDialog.designer.cs create mode 100644 src/Neo.GUI/GUI/OpenWalletDialog.es-ES.resx create mode 100644 src/Neo.GUI/GUI/OpenWalletDialog.resx create mode 100644 src/Neo.GUI/GUI/OpenWalletDialog.zh-Hans.resx create mode 100644 src/Neo.GUI/GUI/ParametersEditor.Designer.cs create mode 100644 src/Neo.GUI/GUI/ParametersEditor.cs create mode 100644 src/Neo.GUI/GUI/ParametersEditor.es-ES.resx create mode 100644 src/Neo.GUI/GUI/ParametersEditor.resx create mode 100644 src/Neo.GUI/GUI/ParametersEditor.zh-Hans.resx create mode 100644 src/Neo.GUI/GUI/PayToDialog.Designer.cs create mode 100644 src/Neo.GUI/GUI/PayToDialog.cs create mode 100644 src/Neo.GUI/GUI/PayToDialog.es-ES.resx create mode 100644 src/Neo.GUI/GUI/PayToDialog.resx create mode 100644 src/Neo.GUI/GUI/PayToDialog.zh-Hans.resx create mode 100644 src/Neo.GUI/GUI/QueueReader.cs create mode 100644 src/Neo.GUI/GUI/SigningDialog.Designer.cs create mode 100644 src/Neo.GUI/GUI/SigningDialog.cs create mode 100644 src/Neo.GUI/GUI/SigningDialog.es-ES.resx create mode 100644 src/Neo.GUI/GUI/SigningDialog.resx create mode 100644 src/Neo.GUI/GUI/SigningDialog.zh-Hans.resx create mode 100644 src/Neo.GUI/GUI/SigningTxDialog.Designer.cs create mode 100644 src/Neo.GUI/GUI/SigningTxDialog.cs create mode 100644 src/Neo.GUI/GUI/SigningTxDialog.es-ES.resx create mode 100644 src/Neo.GUI/GUI/SigningTxDialog.resx create mode 100644 src/Neo.GUI/GUI/SigningTxDialog.zh-Hans.resx create mode 100644 src/Neo.GUI/GUI/TextBoxWriter.cs create mode 100644 src/Neo.GUI/GUI/TransferDialog.Designer.cs create mode 100644 src/Neo.GUI/GUI/TransferDialog.cs create mode 100644 src/Neo.GUI/GUI/TransferDialog.es-ES.resx create mode 100644 src/Neo.GUI/GUI/TransferDialog.resx create mode 100644 src/Neo.GUI/GUI/TransferDialog.zh-Hans.resx create mode 100644 src/Neo.GUI/GUI/TxOutListBox.Designer.cs create mode 100644 src/Neo.GUI/GUI/TxOutListBox.cs create mode 100644 src/Neo.GUI/GUI/TxOutListBox.resx create mode 100644 src/Neo.GUI/GUI/TxOutListBoxItem.cs create mode 100644 src/Neo.GUI/GUI/UpdateDialog.Designer.cs create mode 100644 src/Neo.GUI/GUI/UpdateDialog.cs create mode 100644 src/Neo.GUI/GUI/UpdateDialog.es-ES.resx create mode 100644 src/Neo.GUI/GUI/UpdateDialog.resx create mode 100644 src/Neo.GUI/GUI/UpdateDialog.zh-Hans.resx create mode 100644 src/Neo.GUI/GUI/ViewContractDialog.Designer.cs create mode 100644 src/Neo.GUI/GUI/ViewContractDialog.cs create mode 100644 src/Neo.GUI/GUI/ViewContractDialog.es-ES.resx create mode 100644 src/Neo.GUI/GUI/ViewContractDialog.resx create mode 100644 src/Neo.GUI/GUI/ViewContractDialog.zh-Hans.resx create mode 100644 src/Neo.GUI/GUI/ViewPrivateKeyDialog.cs create mode 100644 src/Neo.GUI/GUI/ViewPrivateKeyDialog.designer.cs create mode 100644 src/Neo.GUI/GUI/ViewPrivateKeyDialog.es-ES.resx create mode 100644 src/Neo.GUI/GUI/ViewPrivateKeyDialog.resx create mode 100644 src/Neo.GUI/GUI/ViewPrivateKeyDialog.zh-Hans.resx create mode 100644 src/Neo.GUI/GUI/VotingDialog.Designer.cs create mode 100644 src/Neo.GUI/GUI/VotingDialog.cs create mode 100644 src/Neo.GUI/GUI/VotingDialog.es-ES.resx create mode 100644 src/Neo.GUI/GUI/VotingDialog.resx create mode 100644 src/Neo.GUI/GUI/VotingDialog.zh-Hans.resx create mode 100644 src/Neo.GUI/GUI/Wrappers/HexConverter.cs create mode 100644 src/Neo.GUI/GUI/Wrappers/ScriptEditor.cs create mode 100644 src/Neo.GUI/GUI/Wrappers/SignerWrapper.cs create mode 100644 src/Neo.GUI/GUI/Wrappers/TransactionAttributeWrapper.cs create mode 100644 src/Neo.GUI/GUI/Wrappers/TransactionWrapper.cs create mode 100644 src/Neo.GUI/GUI/Wrappers/UIntBaseConverter.cs create mode 100644 src/Neo.GUI/GUI/Wrappers/WitnessWrapper.cs create mode 100644 src/Neo.GUI/IO/Actors/EventWrapper.cs create mode 100644 src/Neo.GUI/Neo.GUI.csproj create mode 100644 src/Neo.GUI/Program.cs create mode 100644 src/Neo.GUI/Properties/Resources.Designer.cs create mode 100644 src/Neo.GUI/Properties/Resources.resx create mode 100644 src/Neo.GUI/Properties/Strings.Designer.cs create mode 100644 src/Neo.GUI/Properties/Strings.es-Es.resx create mode 100644 src/Neo.GUI/Properties/Strings.resx create mode 100644 src/Neo.GUI/Properties/Strings.zh-Hans.resx create mode 100644 src/Neo.GUI/Resources/add.png create mode 100644 src/Neo.GUI/Resources/add2.png create mode 100644 src/Neo.GUI/Resources/remark.png create mode 100644 src/Neo.GUI/Resources/remove.png create mode 100644 src/Neo.GUI/Resources/search.png create mode 100644 src/Neo.GUI/Resources/update.bat create mode 100644 src/Neo.GUI/neo.ico create mode 100644 tests/Neo.ConsoleService.Tests/CommandTokenTest.cs create mode 100644 tests/Neo.ConsoleService.Tests/Neo.ConsoleService.Tests.csproj diff --git a/README.md b/README.md index 4c80cc59c2..8f64dcc854 100644 --- a/README.md +++ b/README.md @@ -19,8 +19,6 @@ Neo Modules · Neo DevPack - · - Neo Node

@@ -128,7 +126,6 @@ An overview of the project folders can be seen below. Code references are provided for all platform building blocks. That includes the base library, the VM, a command line application and the compiler. * [neo:](https://github.com/neo-project/neo/) Neo core library, contains base classes, including ledger, p2p and IO modules. -* [neo-node:](https://github.com/neo-project/neo-node/) Executable version of the Neo library, exposing features using a command line application or GUI. * [neo-modules:](https://github.com/neo-project/neo-modules/) Neo modules include additional tools and plugins to be used with Neo. * [neo-devpack-dotnet:](https://github.com/neo-project/neo-devpack-dotnet/) These are the official tools used to convert a C# smart-contract into a *neo executable file*. diff --git a/neo.sln b/neo.sln index 827bddc1b2..2168c241b3 100644 --- a/neo.sln +++ b/neo.sln @@ -24,6 +24,14 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.VM", "src\Neo.VM\Neo.VM EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.VM.Tests", "tests\Neo.VM.Tests\Neo.VM.Tests.csproj", "{005F84EB-EA2E-449F-930A-7B4173DDC7EC}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Neo.ConsoleService", "src\Neo.ConsoleService\Neo.ConsoleService.csproj", "{9E886812-7243-48D8-BEAF-47AADC11C054}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Neo.GUI", "src\Neo.GUI\Neo.GUI.csproj", "{02ABDE42-9880-43B4-B6F7-8D618602A277}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Neo.CLI", "src\Neo.CLI\Neo.CLI.csproj", "{BDFBE455-4C1F-4FC4-B5FC-1387B93A8687}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Neo.ConsoleService.Tests", "tests\Neo.ConsoleService.Tests\Neo.ConsoleService.Tests.csproj", "{B40F8584-5AFB-452C-AEFA-009C80CC23A9}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -62,6 +70,22 @@ Global {005F84EB-EA2E-449F-930A-7B4173DDC7EC}.Debug|Any CPU.Build.0 = Debug|Any CPU {005F84EB-EA2E-449F-930A-7B4173DDC7EC}.Release|Any CPU.ActiveCfg = Release|Any CPU {005F84EB-EA2E-449F-930A-7B4173DDC7EC}.Release|Any CPU.Build.0 = Release|Any CPU + {9E886812-7243-48D8-BEAF-47AADC11C054}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9E886812-7243-48D8-BEAF-47AADC11C054}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9E886812-7243-48D8-BEAF-47AADC11C054}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9E886812-7243-48D8-BEAF-47AADC11C054}.Release|Any CPU.Build.0 = Release|Any CPU + {02ABDE42-9880-43B4-B6F7-8D618602A277}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {02ABDE42-9880-43B4-B6F7-8D618602A277}.Debug|Any CPU.Build.0 = Debug|Any CPU + {02ABDE42-9880-43B4-B6F7-8D618602A277}.Release|Any CPU.ActiveCfg = Release|Any CPU + {02ABDE42-9880-43B4-B6F7-8D618602A277}.Release|Any CPU.Build.0 = Release|Any CPU + {BDFBE455-4C1F-4FC4-B5FC-1387B93A8687}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BDFBE455-4C1F-4FC4-B5FC-1387B93A8687}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BDFBE455-4C1F-4FC4-B5FC-1387B93A8687}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BDFBE455-4C1F-4FC4-B5FC-1387B93A8687}.Release|Any CPU.Build.0 = Release|Any CPU + {B40F8584-5AFB-452C-AEFA-009C80CC23A9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B40F8584-5AFB-452C-AEFA-009C80CC23A9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B40F8584-5AFB-452C-AEFA-009C80CC23A9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B40F8584-5AFB-452C-AEFA-009C80CC23A9}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -75,6 +99,10 @@ Global {E83633BA-FCF0-4A1A-B5BC-42000E24D437} = {C25EB0B0-0CAC-4CC1-8F36-F9229EFB99EC} {0603710E-E0BA-494C-AA0F-6FB0C8A8C754} = {B5339DF7-5D1D-43BA-B332-74B825E1770E} {005F84EB-EA2E-449F-930A-7B4173DDC7EC} = {EDE05FA8-8E73-4924-BC63-DD117127EEE1} + {9E886812-7243-48D8-BEAF-47AADC11C054} = {B5339DF7-5D1D-43BA-B332-74B825E1770E} + {02ABDE42-9880-43B4-B6F7-8D618602A277} = {B5339DF7-5D1D-43BA-B332-74B825E1770E} + {BDFBE455-4C1F-4FC4-B5FC-1387B93A8687} = {B5339DF7-5D1D-43BA-B332-74B825E1770E} + {B40F8584-5AFB-452C-AEFA-009C80CC23A9} = {EDE05FA8-8E73-4924-BC63-DD117127EEE1} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {BCBA19D9-F868-4C6D-8061-A2B91E06E3EC} diff --git a/src/Neo.CLI/CLI/ConsolePercent.cs b/src/Neo.CLI/CLI/ConsolePercent.cs new file mode 100644 index 0000000000..09077f2503 --- /dev/null +++ b/src/Neo.CLI/CLI/ConsolePercent.cs @@ -0,0 +1,145 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-cli is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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; + +namespace Neo.CLI +{ + public class ConsolePercent : IDisposable + { + #region Variables + + private readonly long _maxValue; + private long _value; + private decimal _lastFactor; + private string _lastPercent; + + private readonly int _x, _y; + + private bool _inputRedirected; + + #endregion + + #region Properties + + ///

+ /// Value + /// + public long Value + { + get => _value; + set + { + if (value == _value) return; + + _value = Math.Min(value, _maxValue); + Invalidate(); + } + } + + /// + /// Maximum value + /// + public long MaxValue + { + get => _maxValue; + init + { + if (value == _maxValue) return; + + _maxValue = value; + + if (_value > _maxValue) + _value = _maxValue; + + Invalidate(); + } + } + + /// + /// Percent + /// + public decimal Percent + { + get + { + if (_maxValue == 0) return 0; + return (_value * 100M) / _maxValue; + } + } + + #endregion + + /// + /// Constructor + /// + /// Value + /// Maximum value + public ConsolePercent(long value = 0, long maxValue = 100) + { + _inputRedirected = Console.IsInputRedirected; + _lastFactor = -1; + _x = _inputRedirected ? 0 : Console.CursorLeft; + _y = _inputRedirected ? 0 : Console.CursorTop; + + MaxValue = maxValue; + Value = value; + Invalidate(); + } + + /// + /// Invalidate + /// + public void Invalidate() + { + var factor = Math.Round((Percent / 100M), 1); + var percent = Percent.ToString("0.0").PadLeft(5, ' '); + + if (_lastFactor == factor && _lastPercent == percent) + { + return; + } + + _lastFactor = factor; + _lastPercent = percent; + + var fill = string.Empty.PadLeft((int)(10 * factor), '■'); + var clean = string.Empty.PadLeft(10 - fill.Length, _inputRedirected ? '□' : '■'); + + if (_inputRedirected) + { + Console.WriteLine("[" + fill + clean + "] (" + percent + "%)"); + } + else + { + Console.SetCursorPosition(_x, _y); + + var prevColor = Console.ForegroundColor; + + Console.ForegroundColor = ConsoleColor.White; + Console.Write("["); + Console.ForegroundColor = Percent > 50 ? ConsoleColor.Green : ConsoleColor.DarkGreen; + Console.Write(fill); + Console.ForegroundColor = ConsoleColor.White; + Console.Write(clean + "] (" + percent + "%)"); + + Console.ForegroundColor = prevColor; + } + } + + /// + /// Free console + /// + public void Dispose() + { + Console.WriteLine(""); + } + } +} diff --git a/src/Neo.CLI/CLI/Helper.cs b/src/Neo.CLI/CLI/Helper.cs new file mode 100644 index 0000000000..d0bc4e8d34 --- /dev/null +++ b/src/Neo.CLI/CLI/Helper.cs @@ -0,0 +1,41 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-cli is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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 Neo.SmartContract.Manifest; + +namespace Neo.CLI +{ + internal static class Helper + { + public static bool IsYes(this string input) + { + if (input == null) return false; + + input = input.ToLowerInvariant(); + + return input == "yes" || input == "y"; + } + + public static string ToBase64String(this byte[] input) => System.Convert.ToBase64String(input); + + public static void IsScriptValid(this ReadOnlyMemory script, ContractAbi abi) + { + try + { + SmartContract.Helper.Check(script.ToArray(), abi); + } + catch (Exception e) + { + throw new FormatException($"Bad Script or Manifest Format: {e.Message}"); + } + } + } +} diff --git a/src/Neo.CLI/CLI/MainService.Blockchain.cs b/src/Neo.CLI/CLI/MainService.Blockchain.cs new file mode 100644 index 0000000000..3e5fc90a9b --- /dev/null +++ b/src/Neo.CLI/CLI/MainService.Blockchain.cs @@ -0,0 +1,317 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-cli is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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.ConsoleService; +using Neo.Network.P2P.Payloads; +using Neo.SmartContract; +using Neo.SmartContract.Native; +using System; +using System.Linq; + +namespace Neo.CLI +{ + partial class MainService + { + /// + /// Process "export blocks" command + /// + /// Start + /// Number of blocks + /// Path + [ConsoleCommand("export blocks", Category = "Blockchain Commands")] + private void OnExportBlocksStartCountCommand(uint start, uint count = uint.MaxValue, string path = null) + { + uint height = NativeContract.Ledger.CurrentIndex(NeoSystem.StoreView); + if (height < start) + { + ConsoleHelper.Error("invalid start height."); + return; + } + + count = Math.Min(count, height - start + 1); + + if (string.IsNullOrEmpty(path)) + { + path = $"chain.{start}.acc"; + } + + WriteBlocks(start, count, path, true); + } + + [ConsoleCommand("show block", Category = "Blockchain Commands")] + private void OnShowBlockCommand(string indexOrHash) + { + lock (syncRoot) + { + Block block = null; + + if (uint.TryParse(indexOrHash, out var index)) + block = NativeContract.Ledger.GetBlock(_neoSystem.StoreView, index); + else if (UInt256.TryParse(indexOrHash, out var hash)) + block = NativeContract.Ledger.GetBlock(_neoSystem.StoreView, hash); + else + { + ConsoleHelper.Error("Enter a valid block index or hash."); + return; + } + + if (block is null) + { + ConsoleHelper.Error($"Block {indexOrHash} doesn't exist."); + return; + } + + DateTime blockDatetime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc); + blockDatetime = blockDatetime.AddMilliseconds(block.Timestamp).ToLocalTime(); + + ConsoleHelper.Info("", "-------------", "Block", "-------------"); + ConsoleHelper.Info(); + ConsoleHelper.Info("", " Timestamp: ", $"{blockDatetime}"); + ConsoleHelper.Info("", " Index: ", $"{block.Index}"); + ConsoleHelper.Info("", " Hash: ", $"{block.Hash}"); + ConsoleHelper.Info("", " Nonce: ", $"{block.Nonce}"); + ConsoleHelper.Info("", " MerkleRoot: ", $"{block.MerkleRoot}"); + 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("", " Version: ", $"{block.Version}"); + ConsoleHelper.Info("", " Size: ", $"{block.Size} Byte(s)"); + ConsoleHelper.Info(); + + ConsoleHelper.Info("", "-------------", "Witness", "-------------"); + ConsoleHelper.Info(); + ConsoleHelper.Info("", " Invocation Script: ", $"{Convert.ToBase64String(block.Witness.InvocationScript.Span)}"); + ConsoleHelper.Info("", " Verification Script: ", $"{Convert.ToBase64String(block.Witness.VerificationScript.Span)}"); + ConsoleHelper.Info("", " ScriptHash: ", $"{block.Witness.ScriptHash}"); + ConsoleHelper.Info("", " Size: ", $"{block.Witness.Size} Byte(s)"); + ConsoleHelper.Info(); + + ConsoleHelper.Info("", "-------------", "Transactions", "-------------"); + ConsoleHelper.Info(); + + if (block.Transactions.Length == 0) + { + ConsoleHelper.Info("", " No Transaction(s)"); + } + else + { + foreach (var tx in block.Transactions) + ConsoleHelper.Info($" {tx.Hash}"); + } + ConsoleHelper.Info(); + ConsoleHelper.Info("", "--------------------------------------"); + } + } + + [ConsoleCommand("show tx", Category = "Blockchain Commands")] + public void OnShowTransactionCommand(UInt256 hash) + { + lock (syncRoot) + { + var tx = NativeContract.Ledger.GetTransactionState(_neoSystem.StoreView, hash); + + if (tx is null) + { + ConsoleHelper.Error($"Transaction {hash} doesn't exist."); + return; + } + + var block = NativeContract.Ledger.GetHeader(_neoSystem.StoreView, tx.BlockIndex); + + DateTime transactionDatetime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc); + transactionDatetime = transactionDatetime.AddMilliseconds(block.Timestamp).ToLocalTime(); + + ConsoleHelper.Info("", "-------------", "Transaction", "-------------"); + ConsoleHelper.Info(); + ConsoleHelper.Info("", " Timestamp: ", $"{transactionDatetime}"); + ConsoleHelper.Info("", " Hash: ", $"{tx.Transaction.Hash}"); + ConsoleHelper.Info("", " Nonce: ", $"{tx.Transaction.Nonce}"); + ConsoleHelper.Info("", " Sender: ", $"{tx.Transaction.Sender}"); + ConsoleHelper.Info("", " ValidUntilBlock: ", $"{tx.Transaction.ValidUntilBlock}"); + ConsoleHelper.Info("", " FeePerByte: ", $"{tx.Transaction.FeePerByte}"); + ConsoleHelper.Info("", " NetworkFee: ", $"{tx.Transaction.NetworkFee}"); + ConsoleHelper.Info("", " SystemFee: ", $"{tx.Transaction.SystemFee}"); + ConsoleHelper.Info("", " Script: ", $"{Convert.ToBase64String(tx.Transaction.Script.Span)}"); + ConsoleHelper.Info("", " Version: ", $"{tx.Transaction.Version}"); + ConsoleHelper.Info("", " BlockIndex: ", $"{block.Index}"); + ConsoleHelper.Info("", " BlockHash: ", $"{block.Hash}"); + ConsoleHelper.Info("", " Size: ", $"{tx.Transaction.Size} Byte(s)"); + ConsoleHelper.Info(); + + ConsoleHelper.Info("", "-------------", "Signers", "-------------"); + ConsoleHelper.Info(); + + foreach (var signer in tx.Transaction.Signers) + { + if (signer.Rules.Length == 0) + ConsoleHelper.Info("", " Rules: ", "[]"); + else + ConsoleHelper.Info("", " Rules: ", $"[{string.Join(", ", signer.Rules.Select(s => $"\"{s.ToJson()}\""))}]"); + ConsoleHelper.Info("", " Account: ", $"{signer.Account}"); + ConsoleHelper.Info("", " Scopes: ", $"{signer.Scopes}"); + if (signer.AllowedContracts.Length == 0) + ConsoleHelper.Info("", " AllowedContracts: ", "[]"); + else + ConsoleHelper.Info("", " AllowedContracts: ", $"[{string.Join(", ", signer.AllowedContracts.Select(s => s.ToString()))}]"); + if (signer.AllowedGroups.Length == 0) + ConsoleHelper.Info("", " AllowedGroups: ", "[]"); + else + ConsoleHelper.Info("", " AllowedGroups: ", $"[{string.Join(", ", signer.AllowedGroups.Select(s => s.ToString()))}]"); + ConsoleHelper.Info("", " Size: ", $"{signer.Size} Byte(s)"); + ConsoleHelper.Info(); + } + + ConsoleHelper.Info("", "-------------", "Witnesses", "-------------"); + ConsoleHelper.Info(); + foreach (var witness in tx.Transaction.Witnesses) + { + ConsoleHelper.Info("", " InvocationScript: ", $"{Convert.ToBase64String(witness.InvocationScript.Span)}"); + ConsoleHelper.Info("", " VerificationScript: ", $"{Convert.ToBase64String(witness.VerificationScript.Span)}"); + ConsoleHelper.Info("", " ScriptHash: ", $"{witness.ScriptHash}"); + ConsoleHelper.Info("", " Size: ", $"{witness.Size} Byte(s)"); + ConsoleHelper.Info(); + } + + ConsoleHelper.Info("", "-------------", "Attributes", "-------------"); + ConsoleHelper.Info(); + if (tx.Transaction.Attributes.Length == 0) + { + ConsoleHelper.Info("", " No Attribute(s)."); + } + else + { + foreach (var attribute in tx.Transaction.Attributes) + { + switch (attribute) + { + case Conflicts c: + ConsoleHelper.Info("", " Type: ", $"{c.Type}"); + ConsoleHelper.Info("", " Hash: ", $"{c.Hash}"); + ConsoleHelper.Info("", " Size: ", $"{c.Size} Byte(s)"); + break; + case OracleResponse o: + ConsoleHelper.Info("", " Type: ", $"{o.Type}"); + ConsoleHelper.Info("", " Id: ", $"{o.Id}"); + ConsoleHelper.Info("", " Code: ", $"{o.Code}"); + ConsoleHelper.Info("", " Result: ", $"{Convert.ToBase64String(o.Result.Span)}"); + ConsoleHelper.Info("", " Size: ", $"{o.Size} Byte(s)"); + break; + case HighPriorityAttribute p: + ConsoleHelper.Info("", " Type: ", $"{p.Type}"); + break; + case NotValidBefore n: + ConsoleHelper.Info("", " Type: ", $"{n.Type}"); + ConsoleHelper.Info("", " Height: ", $"{n.Height}"); + break; + default: + ConsoleHelper.Info("", " Type: ", $"{attribute.Type}"); + ConsoleHelper.Info("", " Size: ", $"{attribute.Size} Byte(s)"); + break; + } + } + } + ConsoleHelper.Info(); + ConsoleHelper.Info("", "--------------------------------------"); + } + } + + [ConsoleCommand("show contract", Category = "Blockchain Commands")] + public void OnShowContractCommand(string nameOrHash) + { + lock (syncRoot) + { + ContractState contract = null; + + if (UInt160.TryParse(nameOrHash, out var scriptHash)) + contract = NativeContract.ContractManagement.GetContract(_neoSystem.StoreView, scriptHash); + else + { + var nativeContract = NativeContract.Contracts.SingleOrDefault(s => s.Name.Equals(nameOrHash, StringComparison.InvariantCultureIgnoreCase)); + + if (nativeContract != null) + contract = NativeContract.ContractManagement.GetContract(_neoSystem.StoreView, nativeContract.Hash); + } + + if (contract is null) + { + ConsoleHelper.Error($"Contract {nameOrHash} doesn't exist."); + return; + } + + ConsoleHelper.Info("", "-------------", "Contract", "-------------"); + ConsoleHelper.Info(); + ConsoleHelper.Info("", " Name: ", $"{contract.Manifest.Name}"); + ConsoleHelper.Info("", " Hash: ", $"{contract.Hash}"); + ConsoleHelper.Info("", " Id: ", $"{contract.Id}"); + ConsoleHelper.Info("", " UpdateCounter: ", $"{contract.UpdateCounter}"); + ConsoleHelper.Info("", " SupportedStandards: ", $"{string.Join(" ", contract.Manifest.SupportedStandards)}"); + ConsoleHelper.Info("", " Checksum: ", $"{contract.Nef.CheckSum}"); + ConsoleHelper.Info("", " Compiler: ", $"{contract.Nef.Compiler}"); + ConsoleHelper.Info("", " SourceCode: ", $"{contract.Nef.Source}"); + ConsoleHelper.Info("", " Trusts: ", $"[{string.Join(", ", contract.Manifest.Trusts.Select(s => s.ToJson()?.GetString()))}]"); + if (contract.Manifest.Extra is null) + { + foreach (var extra in contract.Manifest.Extra.Properties) + { + ConsoleHelper.Info("", $" {extra.Key,18}: ", $"{extra.Value?.GetString()}"); + } + } + ConsoleHelper.Info(); + + ConsoleHelper.Info("", "-------------", "Groups", "-------------"); + ConsoleHelper.Info(); + if (contract.Manifest.Groups.Length == 0) + { + ConsoleHelper.Info("", " No Group(s)."); + } + else + { + foreach (var group in contract.Manifest.Groups) + { + ConsoleHelper.Info("", " PubKey: ", $"{group.PubKey}"); + ConsoleHelper.Info("", " Signature: ", $"{Convert.ToBase64String(group.Signature)}"); + } + } + ConsoleHelper.Info(); + + ConsoleHelper.Info("", "-------------", "Permissions", "-------------"); + ConsoleHelper.Info(); + foreach (var permission in contract.Manifest.Permissions) + { + ConsoleHelper.Info("", " Contract: ", $"{permission.Contract.ToJson()?.GetString()}"); + if (permission.Methods.IsWildcard) + ConsoleHelper.Info("", " Methods: ", "*"); + else + ConsoleHelper.Info("", " Methods: ", $"{string.Join(", ", permission.Methods)}"); + ConsoleHelper.Info(); + } + + ConsoleHelper.Info("", "-------------", "Methods", "-------------"); + ConsoleHelper.Info(); + foreach (var method in contract.Manifest.Abi.Methods) + { + ConsoleHelper.Info("", " Name: ", $"{method.Name}"); + ConsoleHelper.Info("", " Safe: ", $"{method.Safe}"); + ConsoleHelper.Info("", " Offset: ", $"{method.Offset}"); + ConsoleHelper.Info("", " Parameters: ", $"[{string.Join(", ", method.Parameters.Select(s => s.Type.ToString()))}]"); + ConsoleHelper.Info("", " ReturnType: ", $"{method.ReturnType}"); + ConsoleHelper.Info(); + } + + ConsoleHelper.Info("", "-------------", "Script", "-------------"); + ConsoleHelper.Info(); + ConsoleHelper.Info($" {Convert.ToBase64String(contract.Nef.Script.Span)}"); + ConsoleHelper.Info(); + ConsoleHelper.Info("", "--------------------------------"); + } + } + } +} diff --git a/src/Neo.CLI/CLI/MainService.Contracts.cs b/src/Neo.CLI/CLI/MainService.Contracts.cs new file mode 100644 index 0000000000..77b4a77219 --- /dev/null +++ b/src/Neo.CLI/CLI/MainService.Contracts.cs @@ -0,0 +1,182 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-cli is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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.ConsoleService; +using Neo.Json; +using Neo.Network.P2P.Payloads; +using Neo.SmartContract; +using Neo.SmartContract.Native; +using System; +using System.Linq; +using System.Numerics; + +namespace Neo.CLI +{ + partial class MainService + { + /// + /// Process "deploy" command + /// + /// File path + /// Manifest path + /// Extra data for deploy + [ConsoleCommand("deploy", Category = "Contract Commands")] + private void OnDeployCommand(string filePath, string manifestPath = null, JObject data = null) + { + if (NoWallet()) return; + byte[] script = LoadDeploymentScript(filePath, manifestPath, data, out var nef, out var manifest); + Transaction tx; + try + { + tx = CurrentWallet.MakeTransaction(NeoSystem.StoreView, script); + } + catch (InvalidOperationException e) + { + ConsoleHelper.Error(GetExceptionMessage(e)); + return; + } + UInt160 hash = SmartContract.Helper.GetContractHash(tx.Sender, nef.CheckSum, manifest.Name); + + ConsoleHelper.Info("Contract hash: ", $"{hash}"); + ConsoleHelper.Info("Gas consumed: ", $"{new BigDecimal((BigInteger)tx.SystemFee, NativeContract.GAS.Decimals)}"); + ConsoleHelper.Info("Network fee: ", $"{new BigDecimal((BigInteger)tx.NetworkFee, NativeContract.GAS.Decimals)}"); + ConsoleHelper.Info("Total fee: ", $"{new BigDecimal((BigInteger)(tx.SystemFee + tx.NetworkFee), NativeContract.GAS.Decimals)} GAS"); + if (!ReadUserInput("Relay tx? (no|yes)").IsYes()) // Add this in case just want to get hash but not relay + { + return; + } + SignAndSendTx(NeoSystem.StoreView, tx); + } + + /// + /// Process "update" command + /// + /// Script hash + /// File path + /// Manifest path + /// Sender + /// Signer Accounts + /// Extra data for update + [ConsoleCommand("update", Category = "Contract Commands")] + private void OnUpdateCommand(UInt160 scriptHash, string filePath, string manifestPath, UInt160 sender, UInt160[] signerAccounts = null, JObject data = null) + { + Signer[] signers = Array.Empty(); + + if (NoWallet()) return; + if (sender != null) + { + if (signerAccounts == null) + signerAccounts = new[] { sender }; + else if (signerAccounts.Contains(sender) && signerAccounts[0] != sender) + { + var signersList = signerAccounts.ToList(); + signersList.Remove(sender); + signerAccounts = signersList.Prepend(sender).ToArray(); + } + else if (!signerAccounts.Contains(sender)) + { + signerAccounts = signerAccounts.Prepend(sender).ToArray(); + } + signers = signerAccounts.Select(p => new Signer() { Account = p, Scopes = WitnessScope.CalledByEntry }).ToArray(); + } + + Transaction tx; + try + { + byte[] script = LoadUpdateScript(scriptHash, filePath, manifestPath, data, out var nef, out var manifest); + tx = CurrentWallet.MakeTransaction(NeoSystem.StoreView, script, sender, signers); + } + catch (InvalidOperationException e) + { + ConsoleHelper.Error(GetExceptionMessage(e)); + return; + } + ContractState contract = NativeContract.ContractManagement.GetContract(NeoSystem.StoreView, scriptHash); + if (contract == null) + { + ConsoleHelper.Warning($"Can't upgrade, contract hash not exist: {scriptHash}"); + } + else + { + ConsoleHelper.Info("Contract hash: ", $"{scriptHash}"); + ConsoleHelper.Info("Updated times: ", $"{contract.UpdateCounter}"); + ConsoleHelper.Info("Gas consumed: ", $"{new BigDecimal((BigInteger)tx.SystemFee, NativeContract.GAS.Decimals)}"); + ConsoleHelper.Info("Network fee: ", $"{new BigDecimal((BigInteger)tx.NetworkFee, NativeContract.GAS.Decimals)}"); + ConsoleHelper.Info("Total fee: ", $"{new BigDecimal((BigInteger)(tx.SystemFee + tx.NetworkFee), NativeContract.GAS.Decimals)} GAS"); + if (!ReadUserInput("Relay tx? (no|yes)").IsYes()) // Add this in case just want to get hash but not relay + { + return; + } + SignAndSendTx(NeoSystem.StoreView, tx); + } + } + + /// + /// Process "invoke" command + /// + /// Script hash + /// Operation + /// Contract parameters + /// Transaction's sender + /// Signer's accounts + /// Max fee for running the script + [ConsoleCommand("invoke", Category = "Contract Commands")] + private void OnInvokeCommand(UInt160 scriptHash, string operation, JArray contractParameters = null, UInt160 sender = null, UInt160[] signerAccounts = null, decimal maxGas = 20) + { + var gas = new BigDecimal(maxGas, NativeContract.GAS.Decimals); + Signer[] signers = Array.Empty(); + if (!NoWallet() && sender != null) + { + if (signerAccounts == null) + signerAccounts = new UInt160[1] { sender }; + else if (signerAccounts.Contains(sender) && signerAccounts[0] != sender) + { + var signersList = signerAccounts.ToList(); + signersList.Remove(sender); + signerAccounts = signersList.Prepend(sender).ToArray(); + } + else if (!signerAccounts.Contains(sender)) + { + signerAccounts = signerAccounts.Prepend(sender).ToArray(); + } + signers = signerAccounts.Select(p => new Signer() { Account = p, Scopes = WitnessScope.CalledByEntry }).ToArray(); + } + + Transaction tx = new Transaction + { + Signers = signers, + Attributes = Array.Empty(), + Witnesses = Array.Empty(), + }; + + if (!OnInvokeWithResult(scriptHash, operation, out _, tx, contractParameters, gas: (long)gas.Value)) return; + + if (NoWallet()) return; + try + { + tx = CurrentWallet.MakeTransaction(NeoSystem.StoreView, tx.Script, sender, signers, maxGas: (long)gas.Value); + } + catch (InvalidOperationException e) + { + ConsoleHelper.Error(GetExceptionMessage(e)); + return; + } + ConsoleHelper.Info("Network fee: ", + $"{new BigDecimal((BigInteger)tx.NetworkFee, NativeContract.GAS.Decimals)}\t", + "Total fee: ", + $"{new BigDecimal((BigInteger)(tx.SystemFee + tx.NetworkFee), NativeContract.GAS.Decimals)} GAS"); + if (!ReadUserInput("Relay tx? (no|yes)").IsYes()) + { + return; + } + SignAndSendTx(NeoSystem.StoreView, tx); + } + } +} diff --git a/src/Neo.CLI/CLI/MainService.Logger.cs b/src/Neo.CLI/CLI/MainService.Logger.cs new file mode 100644 index 0000000000..6624f931a6 --- /dev/null +++ b/src/Neo.CLI/CLI/MainService.Logger.cs @@ -0,0 +1,171 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-cli is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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.ConsoleService; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using static System.IO.Path; + +namespace Neo.CLI +{ + partial class MainService + { + private static readonly ConsoleColorSet DebugColor = new(ConsoleColor.Cyan); + private static readonly ConsoleColorSet InfoColor = new(ConsoleColor.White); + private static readonly ConsoleColorSet WarningColor = new(ConsoleColor.Yellow); + private static readonly ConsoleColorSet ErrorColor = new(ConsoleColor.Red); + private static readonly ConsoleColorSet FatalColor = new(ConsoleColor.Red); + + private readonly object syncRoot = new(); + private bool _showLog = Settings.Default.Logger.ConsoleOutput; + + private void Initialize_Logger() + { + Utility.Logging += OnLog; + } + + private void Dispose_Logger() + { + Utility.Logging -= OnLog; + } + + /// + /// Process "console log off" command to turn off console log + /// + [ConsoleCommand("console log off", Category = "Log Commands")] + private void OnLogOffCommand() + { + _showLog = false; + } + + /// + /// Process "console log on" command to turn on the console log + /// + [ConsoleCommand("console log on", Category = "Log Commands")] + private void OnLogOnCommand() + { + _showLog = true; + } + + private static void GetErrorLogs(StringBuilder sb, Exception ex) + { + sb.AppendLine(ex.GetType().ToString()); + sb.AppendLine(ex.Message); + sb.AppendLine(ex.StackTrace); + if (ex is AggregateException ex2) + { + foreach (Exception inner in ex2.InnerExceptions) + { + sb.AppendLine(); + GetErrorLogs(sb, inner); + } + } + else if (ex.InnerException != null) + { + sb.AppendLine(); + GetErrorLogs(sb, ex.InnerException); + } + } + + private void OnLog(string source, LogLevel level, object message) + { + if (!Settings.Default.Logger.Active) + return; + + if (message is Exception ex) + { + var sb = new StringBuilder(); + GetErrorLogs(sb, ex); + message = sb.ToString(); + } + + lock (syncRoot) + { + DateTime now = DateTime.Now; + var log = $"[{now.TimeOfDay:hh\\:mm\\:ss\\.fff}]"; + if (_showLog) + { + var currentColor = new ConsoleColorSet(); + var messages = message is string msg ? Parse(msg) : new[] { message.ToString() }; + ConsoleColorSet logColor; + string logLevel; + switch (level) + { + case LogLevel.Debug: logColor = DebugColor; logLevel = "DEBUG"; break; + case LogLevel.Error: logColor = ErrorColor; logLevel = "ERROR"; break; + case LogLevel.Fatal: logColor = FatalColor; logLevel = "FATAL"; break; + case LogLevel.Info: logColor = InfoColor; logLevel = "INFO"; break; + case LogLevel.Warning: logColor = WarningColor; logLevel = "WARN"; break; + default: logColor = InfoColor; logLevel = "INFO"; break; + } + logColor.Apply(); + Console.Write($"{logLevel} {log} \t{messages[0],-20}"); + for (var i = 1; i < messages.Length; i++) + { + if (messages[i].Length > 20) + { + messages[i] = $"{messages[i][..10]}...{messages[i][(messages[i].Length - 10)..]}"; + } + Console.Write(i % 2 == 0 ? $"={messages[i]} " : $" {messages[i]}"); + } + currentColor.Apply(); + Console.WriteLine(); + } + + if (string.IsNullOrEmpty(Settings.Default.Logger.Path)) return; + var sb = new StringBuilder(source); + foreach (var c in GetInvalidFileNameChars()) + sb.Replace(c, '-'); + var path = Combine(Settings.Default.Logger.Path, sb.ToString()); + Directory.CreateDirectory(path); + path = Combine(path, $"{now:yyyy-MM-dd}.log"); + try + { + File.AppendAllLines(path, new[] { $"[{level}]{log} {message}" }); + } + catch (IOException) + { + Console.WriteLine("Error writing the log file: " + path); + } + } + } + + /// + /// Parse the log message + /// + /// expected format [key1 = msg1 key2 = msg2] + /// + private static string[] Parse(string message) + { + var equals = message.Trim().Split('='); + + if (equals.Length == 1) return new[] { message }; + + var messages = new List(); + foreach (var t in @equals) + { + var msg = t.Trim(); + var parts = msg.Split(' '); + var d = parts.Take(parts.Length - 1); + + if (parts.Length > 1) + { + messages.Add(string.Join(" ", d)); + } + messages.Add(parts.LastOrDefault()); + } + + return messages.ToArray(); + } + } +} diff --git a/src/Neo.CLI/CLI/MainService.NEP17.cs b/src/Neo.CLI/CLI/MainService.NEP17.cs new file mode 100644 index 0000000000..34de5e58e5 --- /dev/null +++ b/src/Neo.CLI/CLI/MainService.NEP17.cs @@ -0,0 +1,140 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-cli is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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.ConsoleService; +using Neo.Json; +using Neo.Network.P2P.Payloads; +using Neo.SmartContract; +using Neo.SmartContract.Native; +using Neo.VM.Types; +using Neo.Wallets; +using System; +using System.Collections.Generic; +using System.Linq; +using Array = System.Array; + +namespace Neo.CLI +{ + partial class MainService + { + /// + /// Process "transfer" command + /// + /// Script hash + /// To + /// Amount + /// From + /// Data + /// Signer's accounts + [ConsoleCommand("transfer", Category = "NEP17 Commands")] + private void OnTransferCommand(UInt160 tokenHash, UInt160 to, decimal amount, UInt160 from = null, string data = null, UInt160[] signersAccounts = null) + { + var snapshot = NeoSystem.StoreView; + var asset = new AssetDescriptor(snapshot, NeoSystem.Settings, tokenHash); + var value = new BigDecimal(amount, asset.Decimals); + + if (NoWallet()) return; + + Transaction tx; + try + { + tx = CurrentWallet.MakeTransaction(snapshot, new[] + { + new TransferOutput + { + AssetId = tokenHash, + Value = value, + ScriptHash = to, + Data = data + } + }, from: from, cosigners: signersAccounts?.Select(p => new Signer + { + // default access for transfers should be valid only for first invocation + Scopes = WitnessScope.CalledByEntry, + Account = p + }) + .ToArray() ?? Array.Empty()); + } + catch (InvalidOperationException e) + { + ConsoleHelper.Error(GetExceptionMessage(e)); + return; + } + if (!ReadUserInput("Relay tx(no|yes)").IsYes()) + { + return; + } + SignAndSendTx(snapshot, tx); + } + + /// + /// Process "balanceOf" command + /// + /// Script hash + /// Address + [ConsoleCommand("balanceOf", Category = "NEP17 Commands")] + private void OnBalanceOfCommand(UInt160 tokenHash, UInt160 address) + { + var arg = new JObject + { + ["type"] = "Hash160", + ["value"] = address.ToString() + }; + + var asset = new AssetDescriptor(NeoSystem.StoreView, NeoSystem.Settings, tokenHash); + + if (!OnInvokeWithResult(tokenHash, "balanceOf", out StackItem balanceResult, null, new JArray(arg))) return; + + var balance = new BigDecimal(((PrimitiveType)balanceResult).GetInteger(), asset.Decimals); + + Console.WriteLine(); + ConsoleHelper.Info($"{asset.AssetName} balance: ", $"{balance}"); + } + + /// + /// Process "name" command + /// + /// Script hash + [ConsoleCommand("name", Category = "NEP17 Commands")] + private void OnNameCommand(UInt160 tokenHash) + { + ContractState contract = NativeContract.ContractManagement.GetContract(NeoSystem.StoreView, tokenHash); + if (contract == null) Console.WriteLine($"Contract hash not exist: {tokenHash}"); + else ConsoleHelper.Info("Result: ", contract.Manifest.Name); + } + + /// + /// Process "decimals" command + /// + /// Script hash + [ConsoleCommand("decimals", Category = "NEP17 Commands")] + private void OnDecimalsCommand(UInt160 tokenHash) + { + if (!OnInvokeWithResult(tokenHash, "decimals", out StackItem result)) return; + + ConsoleHelper.Info("Result: ", $"{((PrimitiveType)result).GetInteger()}"); + } + + /// + /// Process "totalSupply" command + /// + /// Script hash + [ConsoleCommand("totalSupply", Category = "NEP17 Commands")] + private void OnTotalSupplyCommand(UInt160 tokenHash) + { + if (!OnInvokeWithResult(tokenHash, "totalSupply", out StackItem result)) return; + + var asset = new AssetDescriptor(NeoSystem.StoreView, NeoSystem.Settings, tokenHash); + var totalSupply = new BigDecimal(((PrimitiveType)result).GetInteger(), asset.Decimals); + + ConsoleHelper.Info("Result: ", $"{totalSupply}"); + } + } +} diff --git a/src/Neo.CLI/CLI/MainService.Native.cs b/src/Neo.CLI/CLI/MainService.Native.cs new file mode 100644 index 0000000000..189168b73e --- /dev/null +++ b/src/Neo.CLI/CLI/MainService.Native.cs @@ -0,0 +1,29 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-cli is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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.ConsoleService; +using Neo.SmartContract.Native; +using System; +using System.Linq; + +namespace Neo.CLI +{ + partial class MainService + { + /// + /// Process "list nativecontract" command + /// + [ConsoleCommand("list nativecontract", Category = "Native Contract")] + private void OnListNativeContract() + { + NativeContract.Contracts.ToList().ForEach(p => ConsoleHelper.Info($"\t{p.Name,-20}", $"{p.Hash}")); + } + } +} diff --git a/src/Neo.CLI/CLI/MainService.Network.cs b/src/Neo.CLI/CLI/MainService.Network.cs new file mode 100644 index 0000000000..b09bd5aeda --- /dev/null +++ b/src/Neo.CLI/CLI/MainService.Network.cs @@ -0,0 +1,164 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-cli is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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.ConsoleService; +using Neo.IO; +using Neo.Json; +using Neo.Network.P2P; +using Neo.Network.P2P.Capabilities; +using Neo.Network.P2P.Payloads; +using Neo.SmartContract; +using Neo.SmartContract.Native; +using System; +using System.Net; + +namespace Neo.CLI +{ + partial class MainService + { + /// + /// Process "broadcast addr" command + /// + /// Payload + /// Port + [ConsoleCommand("broadcast addr", Category = "Network Commands")] + private void OnBroadcastAddressCommand(IPAddress payload, ushort port) + { + if (payload == null) + { + ConsoleHelper.Warning("You must input the payload to relay."); + return; + } + + OnBroadcastCommand(MessageCommand.Addr, + AddrPayload.Create( + NetworkAddressWithTime.Create( + payload, DateTime.UtcNow.ToTimestamp(), + new FullNodeCapability(), + new ServerCapability(NodeCapabilityType.TcpServer, port)) + )); + } + + /// + /// Process "broadcast block" command + /// + /// Hash + [ConsoleCommand("broadcast block", Category = "Network Commands")] + private void OnBroadcastGetBlocksByHashCommand(UInt256 hash) + { + OnBroadcastCommand(MessageCommand.Block, NativeContract.Ledger.GetBlock(NeoSystem.StoreView, hash)); + } + + /// + /// Process "broadcast block" command + /// + /// Block index + [ConsoleCommand("broadcast block", Category = "Network Commands")] + private void OnBroadcastGetBlocksByHeightCommand(uint height) + { + OnBroadcastCommand(MessageCommand.Block, NativeContract.Ledger.GetBlock(NeoSystem.StoreView, height)); + } + + /// + /// Process "broadcast getblocks" command + /// + /// Hash + [ConsoleCommand("broadcast getblocks", Category = "Network Commands")] + private void OnBroadcastGetBlocksCommand(UInt256 hash) + { + OnBroadcastCommand(MessageCommand.GetBlocks, GetBlocksPayload.Create(hash)); + } + + /// + /// Process "broadcast getheaders" command + /// + /// Index + [ConsoleCommand("broadcast getheaders", Category = "Network Commands")] + private void OnBroadcastGetHeadersCommand(uint index) + { + OnBroadcastCommand(MessageCommand.GetHeaders, GetBlockByIndexPayload.Create(index)); + } + + /// + /// Process "broadcast getdata" command + /// + /// Type + /// Payload + [ConsoleCommand("broadcast getdata", Category = "Network Commands")] + private void OnBroadcastGetDataCommand(InventoryType type, UInt256[] payload) + { + OnBroadcastCommand(MessageCommand.GetData, InvPayload.Create(type, payload)); + } + + /// + /// Process "broadcast inv" command + /// + /// Type + /// Payload + [ConsoleCommand("broadcast inv", Category = "Network Commands")] + private void OnBroadcastInvCommand(InventoryType type, UInt256[] payload) + { + OnBroadcastCommand(MessageCommand.Inv, InvPayload.Create(type, payload)); + } + + /// + /// Process "broadcast transaction" command + /// + /// Hash + [ConsoleCommand("broadcast transaction", Category = "Network Commands")] + private void OnBroadcastTransactionCommand(UInt256 hash) + { + if (NeoSystem.MemPool.TryGetValue(hash, out Transaction tx)) + OnBroadcastCommand(MessageCommand.Transaction, tx); + } + + private void OnBroadcastCommand(MessageCommand command, ISerializable ret) + { + NeoSystem.LocalNode.Tell(Message.Create(command, ret)); + } + + /// + /// Process "relay" command + /// + /// Json object + [ConsoleCommand("relay", Category = "Network Commands")] + private void OnRelayCommand(JObject jsonObjectToRelay) + { + if (jsonObjectToRelay == null) + { + ConsoleHelper.Warning("You must input JSON object to relay."); + return; + } + + try + { + ContractParametersContext context = ContractParametersContext.Parse(jsonObjectToRelay.ToString(), NeoSystem.StoreView); + if (!context.Completed) + { + ConsoleHelper.Error("The signature is incomplete."); + return; + } + if (!(context.Verifiable is Transaction tx)) + { + ConsoleHelper.Warning("Only support to relay transaction."); + return; + } + tx.Witnesses = context.GetWitnesses(); + NeoSystem.Blockchain.Tell(tx); + Console.WriteLine($"Data relay success, the hash is shown as follows: {Environment.NewLine}{tx.Hash}"); + } + catch (Exception e) + { + ConsoleHelper.Error(GetExceptionMessage(e)); + } + } + } +} diff --git a/src/Neo.CLI/CLI/MainService.Node.cs b/src/Neo.CLI/CLI/MainService.Node.cs new file mode 100644 index 0000000000..9752dfd5ea --- /dev/null +++ b/src/Neo.CLI/CLI/MainService.Node.cs @@ -0,0 +1,118 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-cli is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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.ConsoleService; +using Neo.Network.P2P; +using Neo.Network.P2P.Payloads; +using Neo.SmartContract.Native; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace Neo.CLI +{ + partial class MainService + { + /// + /// Process "show pool" command + /// + [ConsoleCommand("show pool", Category = "Node Commands", Description = "Show the current state of the mempool")] + private void OnShowPoolCommand(bool verbose = false) + { + int verifiedCount, unverifiedCount; + if (verbose) + { + NeoSystem.MemPool.GetVerifiedAndUnverifiedTransactions( + out IEnumerable verifiedTransactions, + out IEnumerable unverifiedTransactions); + ConsoleHelper.Info("Verified Transactions:"); + foreach (Transaction tx in verifiedTransactions) + Console.WriteLine($" {tx.Hash} {tx.GetType().Name} {tx.NetworkFee} GAS_NetFee"); + ConsoleHelper.Info("Unverified Transactions:"); + foreach (Transaction tx in unverifiedTransactions) + Console.WriteLine($" {tx.Hash} {tx.GetType().Name} {tx.NetworkFee} GAS_NetFee"); + + verifiedCount = verifiedTransactions.Count(); + unverifiedCount = unverifiedTransactions.Count(); + } + else + { + verifiedCount = NeoSystem.MemPool.VerifiedCount; + unverifiedCount = NeoSystem.MemPool.UnVerifiedCount; + } + Console.WriteLine($"total: {NeoSystem.MemPool.Count}, verified: {verifiedCount}, unverified: {unverifiedCount}"); + } + + /// + /// Process "show state" command + /// + [ConsoleCommand("show state", Category = "Node Commands", Description = "Show the current state of the node")] + private void OnShowStateCommand() + { + var cancel = new CancellationTokenSource(); + + Console.CursorVisible = false; + Console.Clear(); + + Task broadcast = Task.Run(async () => + { + while (!cancel.Token.IsCancellationRequested) + { + NeoSystem.LocalNode.Tell(Message.Create(MessageCommand.Ping, PingPayload.Create(NativeContract.Ledger.CurrentIndex(NeoSystem.StoreView)))); + await Task.Delay(NeoSystem.Settings.TimePerBlock, cancel.Token); + } + }); + Task task = Task.Run(async () => + { + int maxLines = 0; + while (!cancel.Token.IsCancellationRequested) + { + uint height = NativeContract.Ledger.CurrentIndex(NeoSystem.StoreView); + uint headerHeight = NeoSystem.HeaderCache.Last?.Index ?? height; + + Console.SetCursorPosition(0, 0); + WriteLineWithoutFlicker($"block: {height}/{headerHeight} connected: {LocalNode.ConnectedCount} unconnected: {LocalNode.UnconnectedCount}", Console.WindowWidth - 1); + + int linesWritten = 1; + foreach (RemoteNode node in LocalNode.GetRemoteNodes().OrderByDescending(u => u.LastBlockIndex).Take(Console.WindowHeight - 2).ToArray()) + { + ConsoleHelper.Info(" ip: ", + $"{node.Remote.Address,-15}\t", + "port: ", + $"{node.Remote.Port,-5}\t", + "listen: ", + $"{node.ListenerTcpPort,-5}\t", + "height: ", + $"{node.LastBlockIndex,-7}"); + linesWritten++; + } + + maxLines = Math.Max(maxLines, linesWritten); + + while (linesWritten < maxLines) + { + WriteLineWithoutFlicker("", Console.WindowWidth - 1); + maxLines--; + } + + await Task.Delay(500, cancel.Token); + } + }); + ReadLine(); + cancel.Cancel(); + try { Task.WaitAll(task, broadcast); } catch { } + Console.WriteLine(); + Console.CursorVisible = true; + } + } +} diff --git a/src/Neo.CLI/CLI/MainService.Plugins.cs b/src/Neo.CLI/CLI/MainService.Plugins.cs new file mode 100644 index 0000000000..6373c9c4a7 --- /dev/null +++ b/src/Neo.CLI/CLI/MainService.Plugins.cs @@ -0,0 +1,244 @@ +// Copyright (C) 2016-2023 The Neo Project. +// The neo-cli is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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 Neo.ConsoleService; +using Neo.Json; +using Neo.Plugins; +using System; +using System.Collections.Generic; +using System.IO; +using System.IO.Compression; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Security.Cryptography; +using System.Threading.Tasks; + +namespace Neo.CLI +{ + partial class MainService + { + /// + /// Process "install" command + /// + /// Plugin name + [ConsoleCommand("install", Category = "Plugin Commands")] + private async Task OnInstallCommandAsync(string pluginName) + { + if (PluginExists(pluginName)) + { + ConsoleHelper.Warning($"Plugin already exist."); + return; + } + + await InstallPluginAsync(pluginName); + ConsoleHelper.Warning("Install successful, please restart neo-cli."); + } + + /// + /// Force to install a plugin again. This will overwrite + /// existing plugin files, in case of any file missing or + /// damage to the old version. + /// + /// name of the plugin + [ConsoleCommand("reinstall", Category = "Plugin Commands", Description = "Overwrite existing plugin by force.")] + private async Task OnReinstallCommand(string pluginName) + { + await InstallPluginAsync(pluginName, overWrite: true); + ConsoleHelper.Warning("Reinstall successful, please restart neo-cli."); + } + + /// + /// Download plugin from github release + /// The function of download and install are divided + /// for the consideration of `update` command that + /// might be added in the future. + /// + /// name of the plugin + /// Downloaded content + private async Task DownloadPluginAsync(string pluginName) + { + var url = + $"https://github.com/neo-project/neo-modules/releases/download/v{typeof(Plugin).Assembly.GetVersion()}/{pluginName}.zip"; + using HttpClient http = new(); + HttpResponseMessage response = await http.GetAsync(url); + if (response.StatusCode == HttpStatusCode.NotFound) + { + response.Dispose(); + Version versionCore = typeof(Plugin).Assembly.GetName().Version; + HttpRequestMessage request = new(HttpMethod.Get, + "https://api.github.com/repos/neo-project/neo-modules/releases"); + request.Headers.UserAgent.ParseAdd( + $"{GetType().Assembly.GetName().Name}/{GetType().Assembly.GetVersion()}"); + using HttpResponseMessage responseApi = await http.SendAsync(request); + byte[] buffer = await responseApi.Content.ReadAsByteArrayAsync(); + var releases = JObject.Parse(buffer); + var asset = ((JArray)releases) + .Where(p => !p["tag_name"].GetString().Contains('-')) + .Select(p => new + { + Version = Version.Parse(p["tag_name"].GetString().TrimStart('v')), + Assets = (JArray)p["assets"] + }) + .OrderByDescending(p => p.Version) + .First(p => p.Version <= versionCore).Assets + .FirstOrDefault(p => p["name"].GetString() == $"{pluginName}.zip"); + if (asset is null) throw new Exception("Plugin doesn't exist."); + response = await http.GetAsync(asset["browser_download_url"].GetString()); + } + + using (response) + { + var totalRead = 0L; + byte[] buffer = new byte[1024]; + int read; + await using Stream stream = await response.Content.ReadAsStreamAsync(); + ConsoleHelper.Info("From ", $"{url}"); + var output = new MemoryStream(); + while ((read = await stream.ReadAsync(buffer)) > 0) + { + output.Write(buffer, 0, read); + totalRead += read; + Console.Write( + $"\rDownloading {pluginName}.zip {totalRead / 1024}KB/{response.Content.Headers.ContentLength / 1024}KB {(totalRead * 100) / response.Content.Headers.ContentLength}%"); + } + + Console.WriteLine(); + return output; + } + } + + /// + /// Install plugin from stream + /// + /// name of the plugin + /// Install by force for `update` + private async Task InstallPluginAsync(string pluginName, HashSet installed = null, + bool overWrite = false) + { + installed ??= new HashSet(); + if (!installed.Add(pluginName)) return; + if (!overWrite && PluginExists(pluginName)) return; + + await using MemoryStream stream = await DownloadPluginAsync(pluginName); + using (SHA256 sha256 = SHA256.Create()) + { + ConsoleHelper.Info("SHA256: ", $"{sha256.ComputeHash(stream.ToArray()).ToHexString()}"); + } + + using ZipArchive zip = new(stream, ZipArchiveMode.Read); + ZipArchiveEntry entry = zip.Entries.FirstOrDefault(p => p.Name == "config.json"); + if (entry is not null) + { + await using Stream es = entry.Open(); + await InstallDependenciesAsync(es, installed); + } + zip.ExtractToDirectory("./", true); + } + + /// + /// Install the dependency of the plugin + /// + /// plugin config path in temp + /// Dependency set + private async Task InstallDependenciesAsync(Stream config, HashSet installed) + { + IConfigurationSection dependency = new ConfigurationBuilder() + .AddJsonStream(config) + .Build() + .GetSection("Dependency"); + + if (!dependency.Exists()) return; + var dependencies = dependency.GetChildren().Select(p => p.Get()).ToArray(); + if (dependencies.Length == 0) return; + + foreach (string plugin in dependencies.Where(p => !PluginExists(p))) + { + ConsoleHelper.Info($"Installing dependency: {plugin}"); + await InstallPluginAsync(plugin, installed); + } + } + + /// + /// Check that the plugin has all necessary files + /// + /// Name of the plugin + /// + private static bool PluginExists(string pluginName) + { + return Plugin.Plugins.Any(p => p.Name.Equals(pluginName, StringComparison.InvariantCultureIgnoreCase)); + } + + /// + /// Process "uninstall" command + /// + /// Plugin name + [ConsoleCommand("uninstall", Category = "Plugin Commands")] + private void OnUnInstallCommand(string pluginName) + { + if (!PluginExists(pluginName)) + { + ConsoleHelper.Warning("Plugin not found"); + return; + } + + foreach (var p in Plugin.Plugins) + { + try + { + using var reader = File.OpenRead($"./Plugins/{p.Name}/config.json"); + if (new ConfigurationBuilder() + .AddJsonStream(reader) + .Build() + .GetSection("Dependency") + .GetChildren() + .Select(d => d.Get()) + .Any(v => v.Equals(pluginName, StringComparison.InvariantCultureIgnoreCase))) + { + ConsoleHelper.Error( + $"Can not uninstall. Other plugins depend on this plugin, try `reinstall {pluginName}` if the plugin is broken."); + return; + } + } + catch (Exception) + { + // ignored + } + } + try + { + Directory.Delete($"Plugins/{pluginName}", true); + } + catch (IOException) { } + ConsoleHelper.Info("Uninstall successful, please restart neo-cli."); + } + + /// + /// Process "plugins" command + /// + [ConsoleCommand("plugins", Category = "Plugin Commands")] + private void OnPluginsCommand() + { + if (Plugin.Plugins.Count > 0) + { + Console.WriteLine("Loaded plugins:"); + foreach (Plugin plugin in Plugin.Plugins) + { + var name = $"{plugin.Name}@{plugin.Version}"; + Console.WriteLine($"\t{name,-25}{plugin.Description}"); + } + } + else + { + ConsoleHelper.Warning("No loaded plugins"); + } + } + } +} diff --git a/src/Neo.CLI/CLI/MainService.Tools.cs b/src/Neo.CLI/CLI/MainService.Tools.cs new file mode 100644 index 0000000000..0136617729 --- /dev/null +++ b/src/Neo.CLI/CLI/MainService.Tools.cs @@ -0,0 +1,462 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-cli is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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.ConsoleService; +using Neo.IO; +using Neo.Wallets; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Numerics; + +namespace Neo.CLI +{ + partial class MainService + { + /// + /// Process "parse" command + /// + [ConsoleCommand("parse", Category = "Base Commands", Description = "Parse a value to its possible conversions.")] + private void OnParseCommand(string value) + { + var parseFunctions = new Dictionary>() + { + { "Address to ScriptHash", AddressToScripthash }, + { "Address to Base64", AddressToBase64 }, + { "ScriptHash to Address", ScripthashToAddress }, + { "Base64 to Address", Base64ToAddress }, + { "Base64 to String", Base64ToString }, + { "Base64 to Big Integer", Base64ToNumber }, + { "Big Integer to Hex String", NumberToHex }, + { "Big Integer to Base64", NumberToBase64 }, + { "Hex String to String", HexToString }, + { "Hex String to Big Integer", HexToNumber }, + { "String to Hex String", StringToHex }, + { "String to Base64", StringToBase64 } + }; + + bool any = false; + + foreach (var pair in parseFunctions) + { + var parseMethod = pair.Value; + var result = parseMethod(value); + + if (result != null) + { + Console.WriteLine($"{pair.Key,-30}\t{result}"); + any = true; + } + } + + if (!any) + { + ConsoleHelper.Warning($"Was not possible to convert: '{value}'"); + } + } + + /// + /// Converts an hexadecimal value to an UTF-8 string + /// + /// + /// Hexadecimal value to be converted + /// + /// + /// Returns null when is not possible to parse the hexadecimal value to a UTF-8 + /// string or when the converted string is not printable; otherwise, returns + /// the string represented by the hexadecimal value + /// + private string HexToString(string hexString) + { + try + { + var clearHexString = ClearHexString(hexString); + var bytes = clearHexString.HexToBytes(); + var utf8String = Utility.StrictUTF8.GetString(bytes); + return IsPrintable(utf8String) ? utf8String : null; + } + catch + { + return null; + } + } + + /// + /// Converts an hex value to a big integer + /// + /// + /// Hexadecimal value to be converted + /// + /// + /// Returns null when is not possible to parse the hex value to big integer value; + /// otherwise, returns the string that represents the converted big integer. + /// + private string HexToNumber(string hexString) + { + try + { + var clearHexString = ClearHexString(hexString); + var bytes = clearHexString.HexToBytes(); + var number = new BigInteger(bytes); + + return number.ToString(); + } + catch + { + return null; + } + } + + /// + /// Formats a string value to a default hexadecimal representation of a byte array + /// + /// + /// The string value to be formatted + /// + /// + /// Returns the formatted string. + /// + /// + /// Throw when is the string is not a valid hex representation of a byte array. + /// + private string ClearHexString(string hexString) + { + bool hasHexPrefix = hexString.StartsWith("0x", StringComparison.InvariantCultureIgnoreCase); + + try + { + if (hasHexPrefix) + { + hexString = hexString.Substring(2); + } + + if (hexString.Length % 2 == 1) + { + // if the length is an odd number, it cannot be parsed to a byte array + // it may be a valid hex string, so include a leading zero to parse correctly + hexString = "0" + hexString; + } + + if (hasHexPrefix) + { + // if the input value starts with '0x', the first byte is the less significant + // to parse correctly, reverse the byte array + return hexString.HexToBytes().Reverse().ToArray().ToHexString(); + } + } + catch (FormatException) + { + throw new ArgumentException(); + } + + return hexString; + } + + /// + /// Converts a string in a hexadecimal value + /// + /// + /// String value to be converted + /// + /// + /// Returns null when it is not possible to parse the string value to a hexadecimal + /// value; otherwise returns the hexadecimal value that represents the converted string + /// + private string StringToHex(string strParam) + { + try + { + var bytesParam = Utility.StrictUTF8.GetBytes(strParam); + return bytesParam.ToHexString(); + } + catch + { + return null; + } + } + + /// + /// Converts a string in Base64 string + /// + /// + /// String value to be converted + /// + /// + /// Returns null when is not possible to parse the string value to a Base64 value; + /// otherwise returns the Base64 value that represents the converted string + /// + /// + /// Throw . + /// + private string StringToBase64(string strParam) + { + try + { + byte[] bytearray = Utility.StrictUTF8.GetBytes(strParam); + string base64 = Convert.ToBase64String(bytearray.AsSpan()); + return base64; + } + catch + { + return null; + } + } + + /// + /// Converts a string number in hexadecimal format + /// + /// + /// String that represents the number to be converted + /// + /// + /// Returns null when the string does not represent a big integer value or when + /// it is not possible to parse the big integer value to hexadecimal; otherwise, + /// returns the string that represents the converted hexadecimal value + /// + private string NumberToHex(string strParam) + { + try + { + if (!BigInteger.TryParse(strParam, out var numberParam)) + { + return null; + } + return numberParam.ToByteArray().ToHexString(); + } + catch + { + return null; + } + } + + /// + /// Converts a string number in Base64 byte array + /// + /// + /// String that represents the number to be converted + /// + /// + /// Returns null when the string does not represent a big integer value or when + /// it is not possible to parse the big integer value to Base64 value; otherwise, + /// returns the string that represents the converted Base64 value + /// + private string NumberToBase64(string strParam) + { + try + { + if (!BigInteger.TryParse(strParam, out var number)) + { + return null; + } + byte[] bytearray = number.ToByteArray(); + string base64 = Convert.ToBase64String(bytearray.AsSpan()); + + return base64; + } + catch + { + return null; + } + } + + /// + /// Converts an address to its corresponding scripthash + /// + /// + /// String that represents the address to be converted + /// + /// + /// Returns null when the string does not represent an address or when + /// it is not possible to parse the address to scripthash; otherwise returns + /// the string that represents the converted scripthash + /// + private string AddressToScripthash(string address) + { + try + { + var bigEndScript = address.ToScriptHash(NeoSystem.Settings.AddressVersion); + + return bigEndScript.ToString(); + } + catch + { + return null; + } + } + + /// + /// Converts an address to Base64 byte array + /// + /// + /// String that represents the address to be converted + /// + /// + /// Returns null when the string does not represent an address or when it is + /// not possible to parse the address to Base64 value; otherwise returns + /// the string that represents the converted Base64 value. + /// + private string AddressToBase64(string address) + { + try + { + var script = address.ToScriptHash(NeoSystem.Settings.AddressVersion); + string base64 = Convert.ToBase64String(script.ToArray().AsSpan()); + + return base64; + } + catch + { + return null; + } + } + + /// + /// Converts a big end script hash to its equivalent address + /// + /// + /// String that represents the scripthash to be converted + /// + /// + /// Returns null when the string does not represent an scripthash; + /// otherwise, returns the string that represents the converted address + /// + private string ScripthashToAddress(string script) + { + try + { + UInt160 scriptHash; + if (script.StartsWith("0x")) + { + if (!UInt160.TryParse(script, out scriptHash)) + { + return null; + } + } + else + { + if (!UInt160.TryParse(script, out UInt160 littleEndScript)) + { + return null; + } + string bigEndScript = littleEndScript.ToArray().ToHexString(); + if (!UInt160.TryParse(bigEndScript, out scriptHash)) + { + return null; + } + } + + var hexScript = scriptHash.ToAddress(NeoSystem.Settings.AddressVersion); + return hexScript; + } + catch + { + return null; + } + } + + /// + /// Converts an Base64 byte array to address + /// + /// + /// String that represents the Base64 value + /// + /// + /// Returns null when the string does not represent an Base64 value or when + /// it is not possible to parse the Base64 value to address; otherwise, + /// returns the string that represents the converted address + /// + private string Base64ToAddress(string bytearray) + { + try + { + byte[] result = Convert.FromBase64String(bytearray).Reverse().ToArray(); + string hex = result.ToHexString(); + + if (!UInt160.TryParse(hex, out var scripthash)) + { + return null; + } + + string address = scripthash.ToAddress(NeoSystem.Settings.AddressVersion); + return address; + } + catch + { + return null; + } + } + + /// + /// Converts an Base64 hex string to string + /// + /// + /// String that represents the Base64 value + /// + /// + /// Returns null when the string does not represent an Base64 value or when + /// it is not possible to parse the Base64 value to string value or the converted + /// string is not printable; otherwise, returns the string that represents + /// the Base64 value. + /// + private string Base64ToString(string bytearray) + { + try + { + byte[] result = Convert.FromBase64String(bytearray); + string utf8String = Utility.StrictUTF8.GetString(result); + return IsPrintable(utf8String) ? utf8String : null; + } + catch + { + return null; + } + } + + /// + /// Converts an Base64 hex string to big integer value + /// + /// + /// String that represents the Base64 value + /// + /// + /// Returns null when the string does not represent an Base64 value or when + /// it is not possible to parse the Base64 value to big integer value; otherwise + /// returns the string that represents the converted big integer + /// + private string Base64ToNumber(string bytearray) + { + try + { + var bytes = Convert.FromBase64String(bytearray); + var number = new BigInteger(bytes); + return number.ToString(); + } + catch + { + return null; + } + } + + /// + /// Checks if the string is null or cannot be printed. + /// + /// + /// The string to test + /// + /// + /// Returns false if the string is null, or if it is empty, or if each character cannot be printed; + /// otherwise, returns true. + /// + private bool IsPrintable(string value) + { + return !string.IsNullOrWhiteSpace(value) && value.Any(c => !char.IsControl(c)); + } + } +} diff --git a/src/Neo.CLI/CLI/MainService.Vote.cs b/src/Neo.CLI/CLI/MainService.Vote.cs new file mode 100644 index 0000000000..aa23562eb9 --- /dev/null +++ b/src/Neo.CLI/CLI/MainService.Vote.cs @@ -0,0 +1,239 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-cli is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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.ConsoleService; +using Neo.Cryptography.ECC; +using Neo.Json; +using Neo.SmartContract; +using Neo.SmartContract.Native; +using Neo.VM; +using Neo.VM.Types; +using Neo.Wallets; +using System; +using System.Linq; +using System.Numerics; + +namespace Neo.CLI +{ + partial class MainService + { + /// + /// Process "register candidate" command + /// + /// register account scriptHash + [ConsoleCommand("register candidate", Category = "Vote Commands")] + private void OnRegisterCandidateCommand(UInt160 account) + { + var testGas = NativeContract.NEO.GetRegisterPrice(NeoSystem.StoreView) + (BigInteger)Math.Pow(10, NativeContract.GAS.Decimals) * 10; + if (NoWallet()) return; + WalletAccount currentAccount = CurrentWallet.GetAccount(account); + + if (currentAccount == null) + { + ConsoleHelper.Warning("This address isn't in your wallet!"); + return; + } + else + { + if (currentAccount.Lock || currentAccount.WatchOnly) + { + ConsoleHelper.Warning("Locked or WatchOnly address."); + return; + } + } + + ECPoint publicKey = currentAccount.GetKey()?.PublicKey; + byte[] script; + using (ScriptBuilder scriptBuilder = new ScriptBuilder()) + { + scriptBuilder.EmitDynamicCall(NativeContract.NEO.Hash, "registerCandidate", publicKey); + script = scriptBuilder.ToArray(); + } + + SendTransaction(script, account, (long)testGas); + } + + /// + /// Process "unregister candidate" command + /// + /// unregister account scriptHash + [ConsoleCommand("unregister candidate", Category = "Vote Commands")] + private void OnUnregisterCandidateCommand(UInt160 account) + { + if (NoWallet()) return; + WalletAccount currentAccount = CurrentWallet.GetAccount(account); + + if (currentAccount == null) + { + ConsoleHelper.Warning("This address isn't in your wallet!"); + return; + } + else + { + if (currentAccount.Lock || currentAccount.WatchOnly) + { + ConsoleHelper.Warning("Locked or WatchOnly address."); + return; + } + } + + ECPoint publicKey = currentAccount?.GetKey()?.PublicKey; + byte[] script; + using (ScriptBuilder scriptBuilder = new ScriptBuilder()) + { + scriptBuilder.EmitDynamicCall(NativeContract.NEO.Hash, "unregisterCandidate", publicKey); + script = scriptBuilder.ToArray(); + } + + SendTransaction(script, account); + } + + /// + /// Process "vote" command + /// + /// Sender account + /// Voting publicKey + [ConsoleCommand("vote", Category = "Vote Commands")] + private void OnVoteCommand(UInt160 senderAccount, ECPoint publicKey) + { + if (NoWallet()) return; + byte[] script; + using (ScriptBuilder scriptBuilder = new ScriptBuilder()) + { + scriptBuilder.EmitDynamicCall(NativeContract.NEO.Hash, "vote", senderAccount, publicKey); + script = scriptBuilder.ToArray(); + } + + SendTransaction(script, senderAccount); + } + + /// + /// Process "unvote" command + /// + /// Sender account + [ConsoleCommand("unvote", Category = "Vote Commands")] + private void OnUnvoteCommand(UInt160 senderAccount) + { + if (NoWallet()) return; + byte[] script; + using (ScriptBuilder scriptBuilder = new ScriptBuilder()) + { + scriptBuilder.EmitDynamicCall(NativeContract.NEO.Hash, "vote", senderAccount, null); + script = scriptBuilder.ToArray(); + } + + SendTransaction(script, senderAccount); + } + + /// + /// Process "get candidates" + /// + [ConsoleCommand("get candidates", Category = "Vote Commands")] + private void OnGetCandidatesCommand() + { + if (!OnInvokeWithResult(NativeContract.NEO.Hash, "getCandidates", out StackItem result, null, null, false)) return; + + var resJArray = (VM.Types.Array)result; + + if (resJArray.Count > 0) + { + Console.WriteLine(); + ConsoleHelper.Info("Candidates:"); + + foreach (var item in resJArray) + { + var value = (VM.Types.Array)item; + + Console.Write(((ByteString)value?[0])?.GetSpan().ToHexString() + "\t"); + Console.WriteLine(((Integer)value?[1]).GetInteger()); + } + } + } + + /// + /// Process "get committee" + /// + [ConsoleCommand("get committee", Category = "Vote Commands")] + private void OnGetCommitteeCommand() + { + if (!OnInvokeWithResult(NativeContract.NEO.Hash, "getCommittee", out StackItem result, null, null, false)) return; + + var resJArray = (VM.Types.Array)result; + + if (resJArray.Count > 0) + { + Console.WriteLine(); + ConsoleHelper.Info("Committee:"); + + foreach (var item in resJArray) + { + Console.WriteLine(((ByteString)item)?.GetSpan().ToHexString()); + } + } + } + + /// + /// Process "get next validators" + /// + [ConsoleCommand("get next validators", Category = "Vote Commands")] + private void OnGetNextBlockValidatorsCommand() + { + if (!OnInvokeWithResult(NativeContract.NEO.Hash, "getNextBlockValidators", out StackItem result, null, null, false)) return; + + var resJArray = (VM.Types.Array)result; + + if (resJArray.Count > 0) + { + Console.WriteLine(); + ConsoleHelper.Info("Next validators:"); + + foreach (var item in resJArray) + { + Console.WriteLine(((ByteString)item)?.GetSpan().ToHexString()); + } + } + } + + /// + /// Process "get accountstate" + /// + [ConsoleCommand("get accountstate", Category = "Vote Commands")] + private void OnGetAccountState(UInt160 address) + { + string notice = "No vote record!"; + var arg = new JObject + { + ["type"] = "Hash160", + ["value"] = address.ToString() + }; + + if (!OnInvokeWithResult(NativeContract.NEO.Hash, "getAccountState", out StackItem result, null, new JArray(arg))) return; + Console.WriteLine(); + if (result.IsNull) + { + ConsoleHelper.Warning(notice); + return; + } + var resJArray = (VM.Types.Array)result; + foreach (StackItem value in resJArray) + { + if (value.IsNull) + { + ConsoleHelper.Warning(notice); + return; + } + } + var publickey = ECPoint.Parse(((ByteString)resJArray?[2])?.GetSpan().ToHexString(), ECCurve.Secp256r1); + ConsoleHelper.Info("Voted: ", Contract.CreateSignatureRedeemScript(publickey).ToScriptHash().ToAddress(NeoSystem.Settings.AddressVersion)); + ConsoleHelper.Info("Amount: ", new BigDecimal(((Integer)resJArray?[0]).GetInteger(), NativeContract.NEO.Decimals).ToString()); + ConsoleHelper.Info("Block: ", ((Integer)resJArray?[1]).GetInteger().ToString()); + } + } +} diff --git a/src/Neo.CLI/CLI/MainService.Wallet.cs b/src/Neo.CLI/CLI/MainService.Wallet.cs new file mode 100644 index 0000000000..f916ea1bbc --- /dev/null +++ b/src/Neo.CLI/CLI/MainService.Wallet.cs @@ -0,0 +1,743 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-cli is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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.ConsoleService; +using Neo.Cryptography.ECC; +using Neo.Json; +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.IO; +using System.Linq; +using System.Numerics; +using System.Threading.Tasks; +using static Neo.SmartContract.Helper; + +namespace Neo.CLI +{ + partial class MainService + { + /// + /// Process "open wallet" command + /// + /// Path + [ConsoleCommand("open wallet", Category = "Wallet Commands")] + private void OnOpenWallet(string path) + { + if (!File.Exists(path)) + { + ConsoleHelper.Error("File does not exist"); + return; + } + string password = ReadUserInput("password", true); + if (password.Length == 0) + { + ConsoleHelper.Info("Cancelled"); + return; + } + try + { + OpenWallet(path, password); + } + catch (System.Security.Cryptography.CryptographicException) + { + ConsoleHelper.Error($"Failed to open file \"{path}\""); + } + } + + /// + /// Process "close wallet" command + /// + [ConsoleCommand("close wallet", Category = "Wallet Commands")] + private void OnCloseWalletCommand() + { + if (NoWallet()) return; + CurrentWallet = null; + ConsoleHelper.Info("Wallet is closed"); + } + + /// + /// Process "upgrade wallet" command + /// + [ConsoleCommand("upgrade wallet", Category = "Wallet Commands")] + private void OnUpgradeWalletCommand(string path) + { + if (Path.GetExtension(path).ToLowerInvariant() != ".db3") + { + ConsoleHelper.Warning("Can't upgrade the wallet file. Check if your wallet is in db3 format."); + return; + } + if (!File.Exists(path)) + { + ConsoleHelper.Error("File does not exist."); + return; + } + string password = ReadUserInput("password", true); + if (password.Length == 0) + { + ConsoleHelper.Info("Cancelled"); + return; + } + string pathNew = Path.ChangeExtension(path, ".json"); + if (File.Exists(pathNew)) + { + ConsoleHelper.Warning($"File '{pathNew}' already exists"); + return; + } + NEP6Wallet.Migrate(pathNew, path, password, NeoSystem.Settings).Save(); + Console.WriteLine($"Wallet file upgrade complete. New wallet file has been auto-saved at: {pathNew}"); + } + + /// + /// Process "create address" command + /// + /// Count + [ConsoleCommand("create address", Category = "Wallet Commands")] + private void OnCreateAddressCommand(ushort count = 1) + { + if (NoWallet()) return; + string path = "address.txt"; + if (File.Exists(path)) + { + if (!ReadUserInput($"The file '{path}' already exists, do you want to overwrite it? (yes|no)", false).IsYes()) + { + return; + } + } + + List addresses = new List(); + using (var percent = new ConsolePercent(0, count)) + { + Parallel.For(0, count, (i) => + { + WalletAccount account = CurrentWallet.CreateAccount(); + lock (addresses) + { + addresses.Add(account.Address); + percent.Value++; + } + }); + } + + if (CurrentWallet is NEP6Wallet wallet) + wallet.Save(); + + Console.WriteLine($"Export addresses to {path}"); + File.WriteAllLines(path, addresses); + } + + /// + /// Process "delete address" command + /// + /// Address + [ConsoleCommand("delete address", Category = "Wallet Commands")] + private void OnDeleteAddressCommand(UInt160 address) + { + if (NoWallet()) return; + + if (ReadUserInput($"Warning: Irrevocable operation!\nAre you sure to delete account {address.ToAddress(NeoSystem.Settings.AddressVersion)}? (no|yes)").IsYes()) + { + if (CurrentWallet.DeleteAccount(address)) + { + if (CurrentWallet is NEP6Wallet wallet) + { + wallet.Save(); + } + ConsoleHelper.Info($"Address {address} deleted."); + } + else + { + ConsoleHelper.Warning($"Address {address} doesn't exist."); + } + } + } + + /// + /// Process "export key" command + /// + /// Path + /// ScriptHash + [ConsoleCommand("export key", Category = "Wallet Commands")] + private void OnExportKeyCommand(string path = null, UInt160 scriptHash = null) + { + if (NoWallet()) return; + if (path != null && File.Exists(path)) + { + ConsoleHelper.Error($"File '{path}' already exists"); + return; + } + string password = ReadUserInput("password", true); + if (password.Length == 0) + { + ConsoleHelper.Info("Cancelled"); + return; + } + if (!CurrentWallet.VerifyPassword(password)) + { + ConsoleHelper.Error("Incorrect password"); + return; + } + IEnumerable keys; + if (scriptHash == null) + keys = CurrentWallet.GetAccounts().Where(p => p.HasKey).Select(p => p.GetKey()); + else + { + var account = CurrentWallet.GetAccount(scriptHash); + keys = account?.HasKey != true ? Array.Empty() : new[] { account.GetKey() }; + } + if (path == null) + foreach (KeyPair key in keys) + Console.WriteLine(key.Export()); + else + File.WriteAllLines(path, keys.Select(p => p.Export())); + } + + /// + /// Process "create wallet" command + /// + [ConsoleCommand("create wallet", Category = "Wallet Commands")] + private void OnCreateWalletCommand(string path, string wifOrFile = null) + { + string password = ReadUserInput("password", true); + if (password.Length == 0) + { + ConsoleHelper.Info("Cancelled"); + return; + } + string password2 = ReadUserInput("repeat password", true); + if (password != password2) + { + ConsoleHelper.Error("Two passwords not match."); + return; + } + if (File.Exists(path)) + { + Console.WriteLine("This wallet already exists, please create another one."); + return; + } + bool createDefaultAccount = wifOrFile is null; + CreateWallet(path, password, createDefaultAccount); + if (!createDefaultAccount) OnImportKeyCommand(wifOrFile); + } + + /// + /// Process "import multisigaddress" command + /// + /// Required signatures + /// Public keys + [ConsoleCommand("import multisigaddress", Category = "Wallet Commands")] + private void OnImportMultisigAddress(ushort m, ECPoint[] publicKeys) + { + if (NoWallet()) return; + int n = publicKeys.Length; + + if (m < 1 || m > n || n > 1024) + { + ConsoleHelper.Error("Invalid parameters."); + return; + } + + Contract multiSignContract = Contract.CreateMultiSigContract(m, publicKeys); + KeyPair keyPair = CurrentWallet.GetAccounts().FirstOrDefault(p => p.HasKey && publicKeys.Contains(p.GetKey().PublicKey))?.GetKey(); + + CurrentWallet.CreateAccount(multiSignContract, keyPair); + if (CurrentWallet is NEP6Wallet wallet) + wallet.Save(); + + ConsoleHelper.Info("Multisig. Addr.: ", multiSignContract.ScriptHash.ToAddress(NeoSystem.Settings.AddressVersion)); + } + + /// + /// Process "import key" command + /// + [ConsoleCommand("import key", Category = "Wallet Commands")] + private void OnImportKeyCommand(string wifOrFile) + { + if (NoWallet()) return; + byte[] prikey = null; + try + { + prikey = Wallet.GetPrivateKeyFromWIF(wifOrFile); + } + catch (FormatException) { } + if (prikey == null) + { + var fileInfo = new FileInfo(wifOrFile); + + if (!fileInfo.Exists) + { + ConsoleHelper.Error($"File '{fileInfo.FullName}' doesn't exists"); + return; + } + + if (wifOrFile.Length > 1024 * 1024) + { + if (!ReadUserInput($"The file '{fileInfo.FullName}' is too big, do you want to continue? (yes|no)", false).IsYes()) + { + return; + } + } + + string[] lines = File.ReadAllLines(fileInfo.FullName).Where(u => !string.IsNullOrEmpty(u)).ToArray(); + using (var percent = new ConsolePercent(0, lines.Length)) + { + for (int i = 0; i < lines.Length; i++) + { + if (lines[i].Length == 64) + prikey = lines[i].HexToBytes(); + else + prikey = Wallet.GetPrivateKeyFromWIF(lines[i]); + CurrentWallet.CreateAccount(prikey); + Array.Clear(prikey, 0, prikey.Length); + percent.Value++; + } + } + } + else + { + WalletAccount account = CurrentWallet.CreateAccount(prikey); + Array.Clear(prikey, 0, prikey.Length); + ConsoleHelper.Info("Address: ", account.Address); + ConsoleHelper.Info(" Pubkey: ", account.GetKey().PublicKey.EncodePoint(true).ToHexString()); + } + if (CurrentWallet is NEP6Wallet wallet) + wallet.Save(); + } + + /// + /// Process "import watchonly" command + /// + [ConsoleCommand("import watchonly", Category = "Wallet Commands")] + private void OnImportWatchOnlyCommand(string addressOrFile) + { + if (NoWallet()) return; + UInt160 address = null; + try + { + address = StringToAddress(addressOrFile, NeoSystem.Settings.AddressVersion); + } + catch (FormatException) { } + if (address is null) + { + var fileInfo = new FileInfo(addressOrFile); + + if (!fileInfo.Exists) + { + ConsoleHelper.Warning($"File '{fileInfo.FullName}' doesn't exists"); + return; + } + + if (fileInfo.Length > 1024 * 1024) + { + if (!ReadUserInput($"The file '{fileInfo.FullName}' is too big, do you want to continue? (yes|no)", false).IsYes()) + { + return; + } + } + + string[] lines = File.ReadAllLines(fileInfo.FullName).Where(u => !string.IsNullOrEmpty(u)).ToArray(); + using (var percent = new ConsolePercent(0, lines.Length)) + { + for (int i = 0; i < lines.Length; i++) + { + address = StringToAddress(lines[i], NeoSystem.Settings.AddressVersion); + CurrentWallet.CreateAccount(address); + percent.Value++; + } + } + } + else + { + WalletAccount account = CurrentWallet.GetAccount(address); + if (account is not null) + { + ConsoleHelper.Warning("This address is already in your wallet"); + } + else + { + account = CurrentWallet.CreateAccount(address); + ConsoleHelper.Info("Address: ", account.Address); + } + } + if (CurrentWallet is NEP6Wallet wallet) + wallet.Save(); + } + + /// + /// Process "list address" command + /// + [ConsoleCommand("list address", Category = "Wallet Commands")] + private void OnListAddressCommand() + { + if (NoWallet()) return; + var snapshot = NeoSystem.StoreView; + foreach (var account in CurrentWallet.GetAccounts()) + { + var contract = account.Contract; + var type = "Nonstandard"; + + if (account.WatchOnly) + { + type = "WatchOnly"; + } + else if (IsMultiSigContract(contract.Script)) + { + type = "MultiSignature"; + } + else if (IsSignatureContract(contract.Script)) + { + type = "Standard"; + } + else if (NativeContract.ContractManagement.GetContract(snapshot, account.ScriptHash) != null) + { + type = "Deployed-Nonstandard"; + } + + ConsoleHelper.Info(" Address: ", $"{account.Address}\t{type}"); + ConsoleHelper.Info("ScriptHash: ", $"{account.ScriptHash}\n"); + } + } + + /// + /// Process "list asset" command + /// + [ConsoleCommand("list asset", Category = "Wallet Commands")] + private void OnListAssetCommand() + { + var snapshot = NeoSystem.StoreView; + if (NoWallet()) return; + foreach (UInt160 account in CurrentWallet.GetAccounts().Select(p => p.ScriptHash)) + { + Console.WriteLine(account.ToAddress(NeoSystem.Settings.AddressVersion)); + ConsoleHelper.Info("NEO: ", $"{CurrentWallet.GetBalance(snapshot, NativeContract.NEO.Hash, account)}"); + ConsoleHelper.Info("GAS: ", $"{CurrentWallet.GetBalance(snapshot, NativeContract.GAS.Hash, account)}"); + Console.WriteLine(); + } + Console.WriteLine("----------------------------------------------------"); + ConsoleHelper.Info("Total: NEO: ", $"{CurrentWallet.GetAvailable(snapshot, NativeContract.NEO.Hash),10} ", "GAS: ", $"{CurrentWallet.GetAvailable(snapshot, NativeContract.GAS.Hash),18}"); + Console.WriteLine(); + ConsoleHelper.Info("NEO hash: ", NativeContract.NEO.Hash.ToString()); + ConsoleHelper.Info("GAS hash: ", NativeContract.GAS.Hash.ToString()); + } + + /// + /// Process "list key" command + /// + [ConsoleCommand("list key", Category = "Wallet Commands")] + private void OnListKeyCommand() + { + if (NoWallet()) return; + foreach (WalletAccount account in CurrentWallet.GetAccounts().Where(p => p.HasKey)) + { + ConsoleHelper.Info(" Address: ", account.Address); + ConsoleHelper.Info("ScriptHash: ", account.ScriptHash.ToString()); + ConsoleHelper.Info(" PublicKey: ", account.GetKey().PublicKey.EncodePoint(true).ToHexString()); + Console.WriteLine(); + } + } + + /// + /// Process "sign" command + /// + /// Json object to sign + [ConsoleCommand("sign", Category = "Wallet Commands")] + private void OnSignCommand(JObject jsonObjectToSign) + { + if (NoWallet()) return; + + if (jsonObjectToSign == null) + { + ConsoleHelper.Warning("You must input JSON object pending signature data."); + return; + } + try + { + var snapshot = NeoSystem.StoreView; + ContractParametersContext context = ContractParametersContext.Parse(jsonObjectToSign.ToString(), snapshot); + if (context.Network != _neoSystem.Settings.Network) + { + ConsoleHelper.Warning("Network mismatch."); + return; + } + else if (!CurrentWallet.Sign(context)) + { + ConsoleHelper.Warning("Non-existent private key in wallet."); + return; + } + ConsoleHelper.Info("Signed Output: ", $"{Environment.NewLine}{context}"); + } + catch (Exception e) + { + ConsoleHelper.Error(GetExceptionMessage(e)); + } + } + + /// + /// Process "send" command + /// + /// Asset id + /// To + /// Amount + /// From + /// Data + /// Signer's accounts + [ConsoleCommand("send", Category = "Wallet Commands")] + private void OnSendCommand(UInt160 asset, UInt160 to, string amount, UInt160 from = null, string data = null, UInt160[] signerAccounts = null) + { + if (NoWallet()) return; + string password = ReadUserInput("password", true); + if (password.Length == 0) + { + ConsoleHelper.Info("Cancelled"); + return; + } + if (!CurrentWallet.VerifyPassword(password)) + { + ConsoleHelper.Error("Incorrect password"); + return; + } + var snapshot = NeoSystem.StoreView; + Transaction tx; + AssetDescriptor descriptor = new(snapshot, NeoSystem.Settings, asset); + if (!BigDecimal.TryParse(amount, descriptor.Decimals, out BigDecimal decimalAmount) || decimalAmount.Sign <= 0) + { + ConsoleHelper.Error("Incorrect Amount Format"); + return; + } + try + { + tx = CurrentWallet.MakeTransaction(snapshot, new[] + { + new TransferOutput + { + AssetId = asset, + Value = decimalAmount, + ScriptHash = to, + Data = data + } + }, from: from, cosigners: signerAccounts?.Select(p => new Signer + { + // default access for transfers should be valid only for first invocation + Scopes = WitnessScope.CalledByEntry, + Account = p + }) + .ToArray() ?? Array.Empty()); + } + catch (Exception e) + { + ConsoleHelper.Error(GetExceptionMessage(e)); + return; + } + + if (tx == null) + { + ConsoleHelper.Warning("Insufficient funds"); + return; + } + + ConsoleHelper.Info("Network fee: ", + $"{new BigDecimal((BigInteger)tx.NetworkFee, NativeContract.GAS.Decimals)}\t", + "Total fee: ", + $"{new BigDecimal((BigInteger)(tx.SystemFee + tx.NetworkFee), NativeContract.GAS.Decimals)} GAS"); + if (!ReadUserInput("Relay tx? (no|yes)").IsYes()) + { + return; + } + SignAndSendTx(NeoSystem.StoreView, tx); + } + + /// + /// Process "cancel" command + /// + /// conflict txid + /// Transaction's sender + /// Signer's accounts + [ConsoleCommand("cancel", Category = "Wallet Commands")] + private void OnCancelCommand(UInt256 txid, UInt160 sender = null, UInt160[] signerAccounts = null) + { + TransactionState state = NativeContract.Ledger.GetTransactionState(NeoSystem.StoreView, txid); + if (state != null) + { + ConsoleHelper.Error("This tx is already confirmed, can't be cancelled."); + return; + } + + var conflict = new TransactionAttribute[] { new Conflicts() { Hash = txid } }; + Signer[] signers = Array.Empty(); + if (!NoWallet() && sender != null) + { + if (signerAccounts == null) + signerAccounts = new UInt160[1] { sender }; + else if (signerAccounts.Contains(sender) && signerAccounts[0] != sender) + { + var signersList = signerAccounts.ToList(); + signersList.Remove(sender); + signerAccounts = signersList.Prepend(sender).ToArray(); + } + else if (!signerAccounts.Contains(sender)) + { + signerAccounts = signerAccounts.Prepend(sender).ToArray(); + } + signers = signerAccounts.Select(p => new Signer() { Account = p, Scopes = WitnessScope.None }).ToArray(); + } + + Transaction tx = new Transaction + { + Signers = signers, + Attributes = conflict, + Witnesses = Array.Empty(), + }; + + try + { + using ScriptBuilder scriptBuilder = new(); + scriptBuilder.Emit(OpCode.RET); + tx = CurrentWallet.MakeTransaction(NeoSystem.StoreView, scriptBuilder.ToArray(), sender, signers, conflict); + } + catch (InvalidOperationException e) + { + ConsoleHelper.Error(GetExceptionMessage(e)); + return; + } + + if (NeoSystem.MemPool.TryGetValue(txid, out Transaction conflictTx)) + { + tx.NetworkFee = Math.Max(tx.NetworkFee, conflictTx.NetworkFee) + 1; + } + else + { + var snapshot = NeoSystem.StoreView; + AssetDescriptor descriptor = new(snapshot, NeoSystem.Settings, NativeContract.GAS.Hash); + string extracFee = ReadUserInput("This tx is not in mempool, please input extra fee manually"); + if (!BigDecimal.TryParse(extracFee, descriptor.Decimals, out BigDecimal decimalExtraFee) || decimalExtraFee.Sign <= 0) + { + ConsoleHelper.Error("Incorrect Amount Format"); + return; + } + tx.NetworkFee += (long)decimalExtraFee.Value; + }; + + ConsoleHelper.Info("Network fee: ", + $"{new BigDecimal((BigInteger)tx.NetworkFee, NativeContract.GAS.Decimals)}\t", + "Total fee: ", + $"{new BigDecimal((BigInteger)(tx.SystemFee + tx.NetworkFee), NativeContract.GAS.Decimals)} GAS"); + if (!ReadUserInput("Relay tx? (no|yes)").IsYes()) + { + return; + } + SignAndSendTx(NeoSystem.StoreView, tx); + } + + /// + /// Process "show gas" command + /// + [ConsoleCommand("show gas", Category = "Wallet Commands")] + private void OnShowGasCommand() + { + if (NoWallet()) return; + BigInteger gas = BigInteger.Zero; + var snapshot = NeoSystem.StoreView; + uint height = NativeContract.Ledger.CurrentIndex(snapshot) + 1; + foreach (UInt160 account in CurrentWallet.GetAccounts().Select(p => p.ScriptHash)) + gas += NativeContract.NEO.UnclaimedGas(snapshot, account, height); + ConsoleHelper.Info("Unclaimed gas: ", new BigDecimal(gas, NativeContract.GAS.Decimals).ToString()); + } + + /// + /// Process "change password" command + /// + [ConsoleCommand("change password", Category = "Wallet Commands")] + private void OnChangePasswordCommand() + { + if (NoWallet()) return; + string oldPassword = ReadUserInput("password", true); + if (oldPassword.Length == 0) + { + ConsoleHelper.Info("Cancelled"); + return; + } + if (!CurrentWallet.VerifyPassword(oldPassword)) + { + ConsoleHelper.Error("Incorrect password"); + return; + } + string newPassword = ReadUserInput("New password", true); + string newPasswordReEntered = ReadUserInput("Re-Enter Password", true); + if (!newPassword.Equals(newPasswordReEntered)) + { + ConsoleHelper.Error("Two passwords entered are inconsistent!"); + return; + } + + if (CurrentWallet is NEP6Wallet wallet) + { + string backupFile = wallet.Path + ".bak"; + if (!File.Exists(wallet.Path) || File.Exists(backupFile)) + { + ConsoleHelper.Error("Wallet backup fail"); + return; + } + try + { + File.Copy(wallet.Path, backupFile); + } + catch (IOException) + { + ConsoleHelper.Error("Wallet backup fail"); + return; + } + } + + bool succeed = CurrentWallet.ChangePassword(oldPassword, newPassword); + if (succeed) + { + if (CurrentWallet is NEP6Wallet nep6Wallet) + nep6Wallet.Save(); + Console.WriteLine("Password changed successfully"); + } + else + { + ConsoleHelper.Error("Failed to change password"); + } + } + + private void SignAndSendTx(DataCache snapshot, Transaction tx) + { + ContractParametersContext context; + try + { + context = new ContractParametersContext(snapshot, tx, _neoSystem.Settings.Network); + } + catch (InvalidOperationException e) + { + ConsoleHelper.Error("Failed creating contract params: " + GetExceptionMessage(e)); + throw; + } + CurrentWallet.Sign(context); + if (context.Completed) + { + tx.Witnesses = context.GetWitnesses(); + NeoSystem.Blockchain.Tell(tx); + ConsoleHelper.Info("Signed and relayed transaction with hash:\n", $"{tx.Hash}"); + } + else + { + ConsoleHelper.Info("Incomplete signature:\n", $"{context}"); + } + } + } +} diff --git a/src/Neo.CLI/CLI/MainService.cs b/src/Neo.CLI/CLI/MainService.cs new file mode 100644 index 0000000000..7beea39310 --- /dev/null +++ b/src/Neo.CLI/CLI/MainService.cs @@ -0,0 +1,609 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-cli is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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.ConsoleService; +using Neo.Cryptography.ECC; +using Neo.IO; +using Neo.Json; +using Neo.Ledger; +using Neo.Network.P2P; +using Neo.Network.P2P.Payloads; +using Neo.Plugins; +using Neo.SmartContract; +using Neo.SmartContract.Manifest; +using Neo.SmartContract.Native; +using Neo.VM; +using Neo.VM.Types; +using Neo.Wallets; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.IO.Compression; +using System.Linq; +using System.Net; +using System.Numerics; +using System.Reflection; +using System.Text.RegularExpressions; +using System.Threading; +using Array = System.Array; + +namespace Neo.CLI +{ + public partial class MainService : ConsoleServiceBase, IWalletProvider + { + public event EventHandler WalletChanged; + + public const long TestModeGas = 20_00000000; + + private Wallet _currentWallet; + public LocalNode LocalNode; + + public Wallet CurrentWallet + { + get => _currentWallet; + private set + { + _currentWallet = value; + WalletChanged?.Invoke(this, value); + } + } + + private NeoSystem _neoSystem; + public NeoSystem NeoSystem + { + get => _neoSystem; + private set => _neoSystem = value; + } + + protected override string Prompt => "neo"; + public override string ServiceName => "NEO-CLI"; + + /// + /// Constructor + /// + public MainService() : base() + { + RegisterCommandHandler(false, str => StringToAddress(str, NeoSystem.Settings.AddressVersion)); + RegisterCommandHandler(false, UInt256.Parse); + RegisterCommandHandler(str => str.Select(u => UInt256.Parse(u.Trim())).ToArray()); + RegisterCommandHandler(arr => arr.Select(str => StringToAddress(str, NeoSystem.Settings.AddressVersion)).ToArray()); + RegisterCommandHandler(str => ECPoint.Parse(str.Trim(), ECCurve.Secp256r1)); + RegisterCommandHandler(str => str.Select(u => ECPoint.Parse(u.Trim(), ECCurve.Secp256r1)).ToArray()); + RegisterCommandHandler(str => JToken.Parse(str)); + RegisterCommandHandler(str => (JObject)JToken.Parse(str)); + RegisterCommandHandler(str => decimal.Parse(str, CultureInfo.InvariantCulture)); + RegisterCommandHandler(obj => (JArray)obj); + + RegisterCommand(this); + + Initialize_Logger(); + } + + internal static UInt160 StringToAddress(string input, byte version) + { + switch (input.ToLowerInvariant()) + { + case "neo": return NativeContract.NEO.Hash; + case "gas": return NativeContract.GAS.Hash; + } + + // Try to parse as UInt160 + + if (UInt160.TryParse(input, out var addr)) + { + return addr; + } + + // Accept wallet format + + return input.ToScriptHash(version); + } + + Wallet IWalletProvider.GetWallet() + { + return CurrentWallet; + } + + 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}"); + Console.WriteLine(); + + base.RunConsole(); + } + + public void CreateWallet(string path, string password, bool createDefaultAccount = true) + { + Wallet wallet = Wallet.Create(null, path, password, NeoSystem.Settings); + if (wallet == null) + { + ConsoleHelper.Warning("Wallet files in that format are not supported, please use a .json or .db3 file extension."); + return; + } + if (createDefaultAccount) + { + WalletAccount account = wallet.CreateAccount(); + ConsoleHelper.Info(" Address: ", account.Address); + ConsoleHelper.Info(" Pubkey: ", account.GetKey().PublicKey.EncodePoint(true).ToHexString()); + ConsoleHelper.Info("ScriptHash: ", $"{account.ScriptHash}"); + } + wallet.Save(); + CurrentWallet = wallet; + } + + private IEnumerable GetBlocks(Stream stream, bool read_start = false) + { + using BinaryReader r = new BinaryReader(stream); + uint start = read_start ? r.ReadUInt32() : 0; + uint count = r.ReadUInt32(); + uint end = start + count - 1; + uint currentHeight = NativeContract.Ledger.CurrentIndex(NeoSystem.StoreView); + if (end <= currentHeight) yield break; + for (uint height = start; height <= end; height++) + { + var size = r.ReadInt32(); + if (size > Message.PayloadMaxSize) + throw new ArgumentException($"Block {height} exceeds the maximum allowed size"); + + byte[] array = r.ReadBytes(size); + if (height > currentHeight) + { + Block block = array.AsSerializable(); + yield return block; + } + } + } + + private IEnumerable GetBlocksFromFile() + { + const string pathAcc = "chain.acc"; + if (File.Exists(pathAcc)) + using (FileStream fs = new FileStream(pathAcc, FileMode.Open, FileAccess.Read, FileShare.Read)) + foreach (var block in GetBlocks(fs)) + yield return block; + + const string pathAccZip = pathAcc + ".zip"; + if (File.Exists(pathAccZip)) + using (FileStream fs = new FileStream(pathAccZip, FileMode.Open, FileAccess.Read, FileShare.Read)) + using (ZipArchive zip = new ZipArchive(fs, ZipArchiveMode.Read)) + using (Stream zs = zip.GetEntry(pathAcc).Open()) + foreach (var block in GetBlocks(zs)) + yield return block; + + var paths = Directory.EnumerateFiles(".", "chain.*.acc", SearchOption.TopDirectoryOnly).Concat(Directory.EnumerateFiles(".", "chain.*.acc.zip", SearchOption.TopDirectoryOnly)).Select(p => new + { + FileName = Path.GetFileName(p), + Start = uint.Parse(Regex.Match(p, @"\d+").Value), + IsCompressed = p.EndsWith(".zip") + }).OrderBy(p => p.Start); + + uint height = NativeContract.Ledger.CurrentIndex(NeoSystem.StoreView); + foreach (var path in paths) + { + if (path.Start > height + 1) break; + if (path.IsCompressed) + using (FileStream fs = new FileStream(path.FileName, FileMode.Open, FileAccess.Read, FileShare.Read)) + using (ZipArchive zip = new ZipArchive(fs, ZipArchiveMode.Read)) + using (Stream zs = zip.GetEntry(Path.GetFileNameWithoutExtension(path.FileName)).Open()) + foreach (var block in GetBlocks(zs, true)) + yield return block; + else + using (FileStream fs = new FileStream(path.FileName, FileMode.Open, FileAccess.Read, FileShare.Read)) + foreach (var block in GetBlocks(fs, true)) + yield return block; + } + } + + private bool NoWallet() + { + if (CurrentWallet != null) return false; + ConsoleHelper.Error("You have to open the wallet first."); + return true; + } + + private byte[] LoadDeploymentScript(string nefFilePath, string manifestFilePath, JObject data, out NefFile nef, out ContractManifest manifest) + { + if (string.IsNullOrEmpty(manifestFilePath)) + { + manifestFilePath = Path.ChangeExtension(nefFilePath, ".manifest.json"); + } + + // Read manifest + + var info = new FileInfo(manifestFilePath); + if (!info.Exists || info.Length >= Transaction.MaxTransactionSize) + { + throw new ArgumentException(nameof(manifestFilePath)); + } + + manifest = ContractManifest.Parse(File.ReadAllBytes(manifestFilePath)); + + // Read nef + + info = new FileInfo(nefFilePath); + if (!info.Exists || info.Length >= Transaction.MaxTransactionSize) + { + throw new ArgumentException(nameof(nefFilePath)); + } + + nef = File.ReadAllBytes(nefFilePath).AsSerializable(); + + ContractParameter dataParameter = null; + if (data is not null) + try + { + dataParameter = ContractParameter.FromJson(data); + } + catch + { + throw new FormatException("invalid data"); + } + + // Basic script checks + nef.Script.IsScriptValid(manifest.Abi); + + // Build script + + using (ScriptBuilder sb = new ScriptBuilder()) + { + if (dataParameter is not null) + sb.EmitDynamicCall(NativeContract.ContractManagement.Hash, "deploy", nef.ToArray(), manifest.ToJson().ToString(), dataParameter); + else + sb.EmitDynamicCall(NativeContract.ContractManagement.Hash, "deploy", nef.ToArray(), manifest.ToJson().ToString()); + return sb.ToArray(); + } + } + + private byte[] LoadUpdateScript(UInt160 scriptHash, string nefFilePath, string manifestFilePath, JObject data, out NefFile nef, out ContractManifest manifest) + { + if (string.IsNullOrEmpty(manifestFilePath)) + { + manifestFilePath = Path.ChangeExtension(nefFilePath, ".manifest.json"); + } + + // Read manifest + + var info = new FileInfo(manifestFilePath); + if (!info.Exists || info.Length >= Transaction.MaxTransactionSize) + { + throw new ArgumentException(nameof(manifestFilePath)); + } + + manifest = ContractManifest.Parse(File.ReadAllBytes(manifestFilePath)); + + // Read nef + + info = new FileInfo(nefFilePath); + if (!info.Exists || info.Length >= Transaction.MaxTransactionSize) + { + throw new ArgumentException(nameof(nefFilePath)); + } + + nef = File.ReadAllBytes(nefFilePath).AsSerializable(); + + ContractParameter dataParameter = null; + if (data is not null) + try + { + dataParameter = ContractParameter.FromJson(data); + } + catch + { + throw new FormatException("invalid data"); + } + + // Basic script checks + nef.Script.IsScriptValid(manifest.Abi); + + // Build script + + using (ScriptBuilder sb = new ScriptBuilder()) + { + if (dataParameter is null) + sb.EmitDynamicCall(scriptHash, "update", nef.ToArray(), manifest.ToJson().ToString()); + else + sb.EmitDynamicCall(scriptHash, "update", nef.ToArray(), manifest.ToJson().ToString(), dataParameter); + return sb.ToArray(); + } + } + + public override void OnStart(string[] args) + { + base.OnStart(args); + Start(args); + } + + public override void OnStop() + { + base.OnStop(); + Stop(); + } + + public void OpenWallet(string path, string password) + { + if (!File.Exists(path)) + { + throw new FileNotFoundException(); + } + + CurrentWallet = Wallet.Open(path, password, NeoSystem.Settings) ?? throw new NotSupportedException(); + } + + public async void Start(string[] args) + { + if (NeoSystem != null) return; + bool verifyImport = true; + for (int i = 0; i < args.Length; i++) + switch (args[i]) + { + case "/noverify": + case "--noverify": + verifyImport = false; + break; + } + + ProtocolSettings protocol = ProtocolSettings.Load("config.json"); + + NeoSystem = new NeoSystem(protocol, Settings.Default.Storage.Engine, string.Format(Settings.Default.Storage.Path, protocol.Network.ToString("X8"))); + NeoSystem.AddService(this); + + LocalNode = NeoSystem.LocalNode.Ask(new LocalNode.GetInstance()).Result; + + foreach (var plugin in Plugin.Plugins) + { + // Register plugins commands + + RegisterCommand(plugin, plugin.Name); + } + + using (IEnumerator blocksBeingImported = GetBlocksFromFile().GetEnumerator()) + { + while (true) + { + List blocksToImport = new List(); + for (int i = 0; i < 10; i++) + { + if (!blocksBeingImported.MoveNext()) break; + blocksToImport.Add(blocksBeingImported.Current); + } + if (blocksToImport.Count == 0) break; + await NeoSystem.Blockchain.Ask(new Blockchain.Import + { + Blocks = blocksToImport, + Verify = verifyImport + }); + if (NeoSystem is null) return; + } + } + NeoSystem.StartNode(new ChannelsConfig + { + Tcp = new IPEndPoint(IPAddress.Any, Settings.Default.P2P.Port), + WebSocket = new IPEndPoint(IPAddress.Any, Settings.Default.P2P.WsPort), + MinDesiredConnections = Settings.Default.P2P.MinDesiredConnections, + MaxConnections = Settings.Default.P2P.MaxConnections, + MaxConnectionsPerAddress = Settings.Default.P2P.MaxConnectionsPerAddress + }); + + if (Settings.Default.UnlockWallet.IsActive) + { + try + { + OpenWallet(Settings.Default.UnlockWallet.Path, Settings.Default.UnlockWallet.Password); + } + catch (FileNotFoundException) + { + ConsoleHelper.Warning($"wallet file \"{Settings.Default.UnlockWallet.Path}\" not found."); + } + catch (System.Security.Cryptography.CryptographicException) + { + ConsoleHelper.Error($"Failed to open file \"{Settings.Default.UnlockWallet.Path}\""); + } + catch (Exception ex) + { + ConsoleHelper.Error(ex.GetBaseException().Message); + } + } + } + + public void Stop() + { + Dispose_Logger(); + Interlocked.Exchange(ref _neoSystem, null)?.Dispose(); + } + + private void WriteBlocks(uint start, uint count, string path, bool writeStart) + { + uint end = start + count - 1; + using FileStream fs = new FileStream(path, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None, 4096, FileOptions.WriteThrough); + if (fs.Length > 0) + { + byte[] buffer = new byte[sizeof(uint)]; + if (writeStart) + { + fs.Seek(sizeof(uint), SeekOrigin.Begin); + fs.Read(buffer, 0, buffer.Length); + start += BitConverter.ToUInt32(buffer, 0); + fs.Seek(sizeof(uint), SeekOrigin.Begin); + } + else + { + fs.Read(buffer, 0, buffer.Length); + start = BitConverter.ToUInt32(buffer, 0); + fs.Seek(0, SeekOrigin.Begin); + } + } + else + { + if (writeStart) + { + fs.Write(BitConverter.GetBytes(start), 0, sizeof(uint)); + } + } + if (start <= end) + fs.Write(BitConverter.GetBytes(count), 0, sizeof(uint)); + fs.Seek(0, SeekOrigin.End); + Console.WriteLine("Export block from " + start + " to " + end); + + using (var percent = new ConsolePercent(start, end)) + { + for (uint i = start; i <= end; i++) + { + Block block = NativeContract.Ledger.GetBlock(NeoSystem.StoreView, i); + byte[] array = block.ToArray(); + fs.Write(BitConverter.GetBytes(array.Length), 0, sizeof(int)); + fs.Write(array, 0, array.Length); + percent.Value = i; + } + } + } + + private static void WriteLineWithoutFlicker(string message = "", int maxWidth = 80) + { + if (message.Length > 0) Console.Write(message); + var spacesToErase = maxWidth - message.Length; + if (spacesToErase < 0) spacesToErase = 0; + Console.WriteLine(new string(' ', spacesToErase)); + } + + /// + /// Make and send transaction with script, sender + /// + /// script + /// sender + /// Max fee for running the script + private void SendTransaction(byte[] script, UInt160 account = null, long gas = TestModeGas) + { + Signer[] signers = Array.Empty(); + var snapshot = NeoSystem.StoreView; + + if (account != null) + { + signers = CurrentWallet.GetAccounts() + .Where(p => !p.Lock && !p.WatchOnly && p.ScriptHash == account && NativeContract.GAS.BalanceOf(snapshot, p.ScriptHash).Sign > 0) + .Select(p => new Signer { Account = p.ScriptHash, Scopes = WitnessScope.CalledByEntry }) + .ToArray(); + } + + try + { + Transaction tx = CurrentWallet.MakeTransaction(snapshot, script, account, signers, maxGas: gas); + ConsoleHelper.Info("Invoking script with: ", $"'{Convert.ToBase64String(tx.Script.Span)}'"); + + using (ApplicationEngine engine = ApplicationEngine.Run(tx.Script, snapshot, container: tx, settings: NeoSystem.Settings, gas: gas)) + { + PrintExecutionOutput(engine, true); + if (engine.State == VMState.FAULT) return; + } + + if (!ReadUserInput("Relay tx(no|yes)").IsYes()) + { + return; + } + + SignAndSendTx(NeoSystem.StoreView, tx); + } + catch (InvalidOperationException e) + { + ConsoleHelper.Error(GetExceptionMessage(e)); + } + } + + /// + /// Process "invoke" command + /// + /// Script hash + /// Operation + /// Result + /// Transaction + /// Contract parameters + /// Show result stack if it is true + /// Max fee for running the script + /// Return true if it was successful + private bool OnInvokeWithResult(UInt160 scriptHash, string operation, out StackItem result, IVerifiable verifiable = null, JArray contractParameters = null, bool showStack = true, long gas = TestModeGas) + { + List parameters = new List(); + + if (contractParameters != null) + { + foreach (var contractParameter in contractParameters) + { + parameters.Add(ContractParameter.FromJson((JObject)contractParameter)); + } + } + + ContractState contract = NativeContract.ContractManagement.GetContract(NeoSystem.StoreView, scriptHash); + if (contract == null) + { + ConsoleHelper.Error("Contract does not exist."); + result = StackItem.Null; + return false; + } + else + { + if (contract.Manifest.Abi.GetMethod(operation, parameters.Count) == null) + { + ConsoleHelper.Error("This method does not not exist in this contract."); + result = StackItem.Null; + return false; + } + } + + byte[] script; + + using (ScriptBuilder scriptBuilder = new ScriptBuilder()) + { + scriptBuilder.EmitDynamicCall(scriptHash, operation, parameters.ToArray()); + script = scriptBuilder.ToArray(); + ConsoleHelper.Info("Invoking script with: ", $"'{script.ToBase64String()}'"); + } + + if (verifiable is Transaction tx) + { + tx.Script = script; + } + + using ApplicationEngine engine = ApplicationEngine.Run(script, NeoSystem.StoreView, container: verifiable, settings: NeoSystem.Settings, gas: gas); + PrintExecutionOutput(engine, showStack); + result = engine.State == VMState.FAULT ? null : engine.ResultStack.Peek(); + return engine.State != VMState.FAULT; + } + + private void PrintExecutionOutput(ApplicationEngine engine, bool showStack = true) + { + ConsoleHelper.Info("VM State: ", engine.State.ToString()); + ConsoleHelper.Info("Gas Consumed: ", new BigDecimal((BigInteger)engine.GasConsumed, NativeContract.GAS.Decimals).ToString()); + + if (showStack) + ConsoleHelper.Info("Result Stack: ", new JArray(engine.ResultStack.Select(p => p.ToJson())).ToString()); + + if (engine.State == VMState.FAULT) + ConsoleHelper.Error(GetExceptionMessage(engine.FaultException)); + } + + static string GetExceptionMessage(Exception exception) + { + if (exception == null) return "Engine faulted."; + + if (exception.InnerException != null) + { + return GetExceptionMessage(exception.InnerException); + } + + return exception.Message; + } + } +} diff --git a/src/Neo.CLI/Dockerfile b/src/Neo.CLI/Dockerfile new file mode 100644 index 0000000000..7b67a6812d --- /dev/null +++ b/src/Neo.CLI/Dockerfile @@ -0,0 +1,20 @@ +FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:7.0 AS Build + +# Run this from the repository root folder +COPY src . +COPY NuGet.Config /Neo.CLI + +WORKDIR /Neo.CLI +RUN dotnet restore && dotnet publish -f net7.0 -c Release -o /app + +FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/aspnet:7.0 AS Final +RUN apt-get update && apt-get install -y \ + screen \ + libleveldb-dev \ + sqlite3 +RUN rm -rf /var/lib/apt/lists/* + +WORKDIR /Neo.CLI +COPY --from=Build /app . + +ENTRYPOINT ["screen","-DmS","node","dotnet","neo-cli.dll","-r"] diff --git a/src/Neo.CLI/Extensions.cs b/src/Neo.CLI/Extensions.cs new file mode 100644 index 0000000000..d3dd1aa5ed --- /dev/null +++ b/src/Neo.CLI/Extensions.cs @@ -0,0 +1,28 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-cli is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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.Linq; +using System.Reflection; + +namespace Neo +{ + /// + /// Extension methods + /// + internal static class Extensions + { + public static string GetVersion(this Assembly assembly) + { + CustomAttributeData attribute = assembly.CustomAttributes.FirstOrDefault(p => p.AttributeType == typeof(AssemblyInformationalVersionAttribute)); + if (attribute == null) return assembly.GetName().Version.ToString(3); + return (string)attribute.ConstructorArguments[0].Value; + } + } +} diff --git a/src/Neo.CLI/Neo.CLI.csproj b/src/Neo.CLI/Neo.CLI.csproj new file mode 100644 index 0000000000..19f92a92cc --- /dev/null +++ b/src/Neo.CLI/Neo.CLI.csproj @@ -0,0 +1,29 @@ + + + + Neo.CLI + neo-cli + Exe + Neo.CLI + Neo + Neo.CLI + neo.ico + + + + + + + + + PreserveNewest + PreserveNewest + + + + + + + + + diff --git a/src/Neo.CLI/Program.cs b/src/Neo.CLI/Program.cs new file mode 100644 index 0000000000..8a12b7dddb --- /dev/null +++ b/src/Neo.CLI/Program.cs @@ -0,0 +1,23 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-cli is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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.CLI; + +namespace Neo +{ + static class Program + { + static void Main(string[] args) + { + var mainService = new MainService(); + mainService.Run(args); + } + } +} diff --git a/src/Neo.CLI/Settings.cs b/src/Neo.CLI/Settings.cs new file mode 100644 index 0000000000..ace4cb4863 --- /dev/null +++ b/src/Neo.CLI/Settings.cs @@ -0,0 +1,120 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-cli is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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 Neo.Network.P2P; +using System.Threading; + +namespace Neo +{ + public class Settings + { + public LoggerSettings Logger { get; } + public StorageSettings Storage { get; } + public P2PSettings P2P { get; } + public UnlockWalletSettings UnlockWallet { get; } + + static Settings _default; + + static bool UpdateDefault(IConfiguration configuration) + { + var settings = new Settings(configuration.GetSection("ApplicationConfiguration")); + return null == Interlocked.CompareExchange(ref _default, settings, null); + } + + public static bool Initialize(IConfiguration configuration) + { + return UpdateDefault(configuration); + } + + public static Settings Default + { + get + { + if (_default == null) + { + IConfigurationRoot config = new ConfigurationBuilder().AddJsonFile("config.json", optional: true).Build(); + Initialize(config); + } + + return _default; + } + } + + public Settings(IConfigurationSection section) + { + this.Logger = new LoggerSettings(section.GetSection("Logger")); + this.Storage = new StorageSettings(section.GetSection("Storage")); + this.P2P = new P2PSettings(section.GetSection("P2P")); + this.UnlockWallet = new UnlockWalletSettings(section.GetSection("UnlockWallet")); + } + } + + public class LoggerSettings + { + public string Path { get; } + public bool ConsoleOutput { get; } + public bool Active { get; } + + public LoggerSettings(IConfigurationSection section) + { + this.Path = section.GetValue("Path", "Logs"); + this.ConsoleOutput = section.GetValue("ConsoleOutput", false); + this.Active = section.GetValue("Active", false); + } + } + + public class StorageSettings + { + public string Engine { get; } + public string Path { get; } + + public StorageSettings(IConfigurationSection section) + { + this.Engine = section.GetValue("Engine", "LevelDBStore"); + this.Path = section.GetValue("Path", "Data_LevelDB_{0}"); + } + } + + public class P2PSettings + { + public ushort Port { get; } + public ushort WsPort { get; } + public int MinDesiredConnections { get; } + public int MaxConnections { get; } + public int MaxConnectionsPerAddress { get; } + + public P2PSettings(IConfigurationSection section) + { + this.Port = ushort.Parse(section.GetValue("Port", "10333")); + this.WsPort = ushort.Parse(section.GetValue("WsPort", "10334")); + this.MinDesiredConnections = section.GetValue("MinDesiredConnections", Peer.DefaultMinDesiredConnections); + this.MaxConnections = section.GetValue("MaxConnections", Peer.DefaultMaxConnections); + this.MaxConnectionsPerAddress = section.GetValue("MaxConnectionsPerAddress", 3); + } + } + + public class UnlockWalletSettings + { + public string Path { get; } + public string Password { get; } + public bool IsActive { get; } + + public UnlockWalletSettings(IConfigurationSection section) + { + if (section.Exists()) + { + this.Path = section.GetValue("Path", ""); + this.Password = section.GetValue("Password", ""); + this.IsActive = bool.Parse(section.GetValue("IsActive", "false")); + } + } + } +} diff --git a/src/Neo.CLI/config.fs.mainnet.json b/src/Neo.CLI/config.fs.mainnet.json new file mode 100644 index 0000000000..1e1b5fc92d --- /dev/null +++ b/src/Neo.CLI/config.fs.mainnet.json @@ -0,0 +1,53 @@ +{ + "ApplicationConfiguration": { + "Logger": { + "Path": "Logs", + "ConsoleOutput": false, + "Active": false + }, + "Storage": { + "Engine": "LevelDBStore", + "Path": "Data_LevelDB_{0}" + }, + "P2P": { + "Port": 40333, + "WsPort": 40334, + "MinDesiredConnections": 10, + "MaxConnections": 40, + "MaxConnectionsPerAddress": 3 + }, + "UnlockWallet": { + "Path": "", + "Password": "", + "IsActive": false + } + }, + "ProtocolConfiguration": { + "Network": 91414437, + "AddressVersion": 53, + "MillisecondsPerBlock": 15000, + "MaxTransactionsPerBlock": 512, + "MemoryPoolMaxTransactions": 50000, + "MaxTraceableBlocks": 2102400, + "InitialGasDistribution": 5200000000000000, + "ValidatorsCount": 7, + "StandbyCommittee": [ + "026fa34ec057d74c2fdf1a18e336d0bd597ea401a0b2ad57340d5c220d09f44086", + "039a9db2a30942b1843db673aeb0d4fd6433f74cec1d879de6343cb9fcf7628fa4", + "0366d255e7ce23ea6f7f1e4bedf5cbafe598705b47e6ec213ef13b2f0819e8ab33", + "023f9cb7bbe154d529d5c719fdc39feaa831a43ae03d2a4280575b60f52fa7bc52", + "039ba959e0ab6dc616df8b803692f1c30ba9071b76b05535eb994bf5bbc402ad5f", + "035a2a18cddafa25ad353dea5e6730a1b9fcb4b918c4a0303c4387bb9c3b816adf", + "031f4d9c66f2ec348832c48fd3a16dfaeb59e85f557ae1e07f6696d0375c64f97b" + ], + "SeedList": [ + "morph1.fs.neo.org:40333", + "morph2.fs.neo.org:40333", + "morph3.fs.neo.org:40333", + "morph4.fs.neo.org:40333", + "morph5.fs.neo.org:40333", + "morph6.fs.neo.org:40333", + "morph7.fs.neo.org:40333" + ] + } +} diff --git a/src/Neo.CLI/config.fs.testnet.json b/src/Neo.CLI/config.fs.testnet.json new file mode 100644 index 0000000000..5e827a8480 --- /dev/null +++ b/src/Neo.CLI/config.fs.testnet.json @@ -0,0 +1,53 @@ +{ + "ApplicationConfiguration": { + "Logger": { + "Path": "Logs", + "ConsoleOutput": false, + "Active": false + }, + "Storage": { + "Engine": "LevelDBStore", + "Path": "Data_LevelDB_{0}" + }, + "P2P": { + "Port": 50333, + "WsPort": 50334, + "MinDesiredConnections": 10, + "MaxConnections": 40, + "MaxConnectionsPerAddress": 3 + }, + "UnlockWallet": { + "Path": "", + "Password": "", + "IsActive": false + } + }, + "ProtocolConfiguration": { + "Network": 91466898, + "AddressVersion": 53, + "MillisecondsPerBlock": 15000, + "MaxTransactionsPerBlock": 512, + "MemoryPoolMaxTransactions": 50000, + "MaxTraceableBlocks": 2102400, + "InitialGasDistribution": 5200000000000000, + "ValidatorsCount": 7, + "StandbyCommittee": [ + "02082828ec6efc92e5e7790da851be72d2091a961c1ac9a1772acbf181ac56b831", + "02b2bcf7e09c0237ab6ef21808e6f7546329823bc6b43488335bd357aea443fabe", + "03577029a5072ebbab12d2495b59e2cf27afb37f9640c1c1354f1bdd221e6fb82d", + "03e6ea086e4b42fa5f0535179862db7eea7e44644e5e9608d6131aa48868c12cfc", + "0379328ab4907ea7c47f61e5c9d2c78c39dc9d1c4341ca496376070a0a5e20131e", + "02f8af6440dfe0e676ae2bb6727e5cc31a6f2459e29f48e85428862b7577dbc203", + "02e19c0634c85d35937699cdeaa10595ec2e18bfe86ba0494cf6c5c6861c66b97d" + ], + "SeedList": [ + "morph01.testnet.fs.neo.org:50333", + "morph02.testnet.fs.neo.org:50333", + "morph03.testnet.fs.neo.org:50333", + "morph04.testnet.fs.neo.org:50333", + "morph05.testnet.fs.neo.org:50333", + "morph06.testnet.fs.neo.org:50333", + "morph07.testnet.fs.neo.org:50333" + ] + } +} diff --git a/src/Neo.CLI/config.json b/src/Neo.CLI/config.json new file mode 100644 index 0000000000..6c9423ed05 --- /dev/null +++ b/src/Neo.CLI/config.json @@ -0,0 +1,69 @@ +{ + "ApplicationConfiguration": { + "Logger": { + "Path": "Logs", + "ConsoleOutput": false, + "Active": false + }, + "Storage": { + "Engine": "LevelDBStore", + "Path": "Data_LevelDB_{0}" + }, + "P2P": { + "Port": 10333, + "WsPort": 10334, + "MinDesiredConnections": 10, + "MaxConnections": 40, + "MaxConnectionsPerAddress": 3 + }, + "UnlockWallet": { + "Path": "", + "Password": "", + "IsActive": false + } + }, + "ProtocolConfiguration": { + "Network": 860833102, + "AddressVersion": 53, + "MillisecondsPerBlock": 15000, + "MaxTransactionsPerBlock": 512, + "MemoryPoolMaxTransactions": 50000, + "MaxTraceableBlocks": 2102400, + "Hardforks": { + "HF_Aspidochelone": 1730000, + "HF_Basilisk": 4120000 + }, + "InitialGasDistribution": 5200000000000000, + "ValidatorsCount": 7, + "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/src/Neo.CLI/config.mainnet.json b/src/Neo.CLI/config.mainnet.json new file mode 100644 index 0000000000..6c9423ed05 --- /dev/null +++ b/src/Neo.CLI/config.mainnet.json @@ -0,0 +1,69 @@ +{ + "ApplicationConfiguration": { + "Logger": { + "Path": "Logs", + "ConsoleOutput": false, + "Active": false + }, + "Storage": { + "Engine": "LevelDBStore", + "Path": "Data_LevelDB_{0}" + }, + "P2P": { + "Port": 10333, + "WsPort": 10334, + "MinDesiredConnections": 10, + "MaxConnections": 40, + "MaxConnectionsPerAddress": 3 + }, + "UnlockWallet": { + "Path": "", + "Password": "", + "IsActive": false + } + }, + "ProtocolConfiguration": { + "Network": 860833102, + "AddressVersion": 53, + "MillisecondsPerBlock": 15000, + "MaxTransactionsPerBlock": 512, + "MemoryPoolMaxTransactions": 50000, + "MaxTraceableBlocks": 2102400, + "Hardforks": { + "HF_Aspidochelone": 1730000, + "HF_Basilisk": 4120000 + }, + "InitialGasDistribution": 5200000000000000, + "ValidatorsCount": 7, + "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/src/Neo.CLI/config.testnet.json b/src/Neo.CLI/config.testnet.json new file mode 100644 index 0000000000..1d118016a3 --- /dev/null +++ b/src/Neo.CLI/config.testnet.json @@ -0,0 +1,69 @@ +{ + "ApplicationConfiguration": { + "Logger": { + "Path": "Logs", + "ConsoleOutput": false, + "Active": false + }, + "Storage": { + "Engine": "LevelDBStore", + "Path": "Data_LevelDB_{0}" + }, + "P2P": { + "Port": 20333, + "WsPort": 20334, + "MinDesiredConnections": 10, + "MaxConnections": 40, + "MaxConnectionsPerAddress": 3 + }, + "UnlockWallet": { + "Path": "", + "Password": "", + "IsActive": false + } + }, + "ProtocolConfiguration": { + "Network": 894710606, + "AddressVersion": 53, + "MillisecondsPerBlock": 15000, + "MaxTransactionsPerBlock": 5000, + "MemoryPoolMaxTransactions": 50000, + "MaxTraceableBlocks": 2102400, + "Hardforks": { + "HF_Aspidochelone": 210000, + "HF_Basilisk": 2680000 + }, + "InitialGasDistribution": 5200000000000000, + "ValidatorsCount": 7, + "StandbyCommittee": [ + "023e9b32ea89b94d066e649b124fd50e396ee91369e8e2a6ae1b11c170d022256d", + "03009b7540e10f2562e5fd8fac9eaec25166a58b26e412348ff5a86927bfac22a2", + "02ba2c70f5996f357a43198705859fae2cfea13e1172962800772b3d588a9d4abd", + "03408dcd416396f64783ac587ea1e1593c57d9fea880c8a6a1920e92a259477806", + "02a7834be9b32e2981d157cb5bbd3acb42cfd11ea5c3b10224d7a44e98c5910f1b", + "0214baf0ceea3a66f17e7e1e839ea25fd8bed6cd82e6bb6e68250189065f44ff01", + "030205e9cefaea5a1dfc580af20c8d5aa2468bb0148f1a5e4605fc622c80e604ba", + "025831cee3708e87d78211bec0d1bfee9f4c85ae784762f042e7f31c0d40c329b8", + "02cf9dc6e85d581480d91e88e8cbeaa0c153a046e89ded08b4cefd851e1d7325b5", + "03840415b0a0fcf066bcc3dc92d8349ebd33a6ab1402ef649bae00e5d9f5840828", + "026328aae34f149853430f526ecaa9cf9c8d78a4ea82d08bdf63dd03c4d0693be6", + "02c69a8d084ee7319cfecf5161ff257aa2d1f53e79bf6c6f164cff5d94675c38b3", + "0207da870cedb777fceff948641021714ec815110ca111ccc7a54c168e065bda70", + "035056669864feea401d8c31e447fb82dd29f342a9476cfd449584ce2a6165e4d7", + "0370c75c54445565df62cfe2e76fbec4ba00d1298867972213530cae6d418da636", + "03957af9e77282ae3263544b7b2458903624adc3f5dee303957cb6570524a5f254", + "03d84d22b8753cf225d263a3a782a4e16ca72ef323cfde04977c74f14873ab1e4c", + "02147c1b1d5728e1954958daff2f88ee2fa50a06890a8a9db3fa9e972b66ae559f", + "03c609bea5a4825908027e4ab217e7efc06e311f19ecad9d417089f14927a173d5", + "0231edee3978d46c335e851c76059166eb8878516f459e085c0dd092f0f1d51c21", + "03184b018d6b2bc093e535519732b3fd3f7551c8cffaf4621dd5a0b89482ca66c9" + ], + "SeedList": [ + "seed1t5.neo.org:20333", + "seed2t5.neo.org:20333", + "seed3t5.neo.org:20333", + "seed4t5.neo.org:20333", + "seed5t5.neo.org:20333" + ] + } +} diff --git a/src/Neo.CLI/neo.ico b/src/Neo.CLI/neo.ico new file mode 100644 index 0000000000000000000000000000000000000000..403aa7f3764f3dd49f9edd8e93302bf24cc35fcf GIT binary patch literal 105486 zcmeI52V4}#7su!BfI~#V4i>O$u%Tdy4QyZuHZU3!do*fdi-w3%0Y$|wh)A(uLm@^i z(TENHQH;GCjTNN`SimTX1@8ZQd$-3y5Dw&klid$rX7_e?_RV{5W@lz+b{P{fDWgTi zYBT+Ej5%Z7%}u`DSYO2E;x}7c#dcT5f~$y_rKNm(M+3$#491zY72C!*e~yTmn8>$1 z%P?lPLd1;mJH(#USK-x>_>mm5&#~tGsGrZWVdl#pf z>z>{nw(5G^oXF?N(_i&)Z#ZzgepAn0R{jTOj`}X4N_fcfkV*FS<~<2={-ch*$N0ZP zt~T_KpXYblA=v7`uJhg9=QXcjSho2%|MAOi)mT6Lvh~$6y{-m(Mo-?{Wx$r*kDs~B z+OuldaPhkzFSukp>UjU+wpNEDrrina{GIDXnUQz>UU~h64DFgE(mC?#`~t(a_xp~l z(6aLd?~Cb;Q+uA7FX|b0>OzwVwcb{)GlMl*{QDPahZngI53u`XNZK1&AL~u6MzV>M zM&AB$ba)yG|`LI?x z&!s0W9sfGwUF91Gj0VrJ8+)2Lo%LEjeS+!Rm;SOSS^YKX-_7yvX;bIrr2`LKx_VZ5 zf9s5=Xvfxre=K%ieWTKtM()=mpH!cHV~nkN%V#OayE&{8?eO^DZ#M=8OCGi#+2zk( z<-0xEH1=i7s&~?tdQ9KZ*TgNc{j1-itXto;TlU!P@xYbSH&~gQoirO7@H%BvYVuaI zo>AYj;DWn|Y1NYB?3=!K29Dl6 zNq1~}{X3%feUrS#MeBH_``qktJGh#o(UzBnkyEVFQd*taR4dJJs>8zxp%1o4{@l3j zoWNg`-`>A=ym2{+<>ft3UyQGQbh%0UI&<_JwUXv)ez0H9zVd z7&yxFV#UM;9&?)BdpSJG-D%hxy^#}}guf|sq=$cU#nCM$y*Oq+-rS*+w?&IEX81$I z!ghO|7d8q1ynXqOW#a6=I`U>w$f5yp)^l0tVeh~#djgki`*%yzTkn5N8f9&@{LS&H z&w4+b6uI+Sz1Bg`$8Kq|aKp&CH*SYWuUu>WC0nu&m%nPfvED+nx&ITbU7lp0E{#q* z(7@+m(!5=<@d*xfkNVt<+Pu7li{qY~NmeX199P(4yrK5q`3-8g`pz;LwqvgN(hvw! z{p&Up4f>@#C>QZXr)4KA+pzgxhi$8QxJ<9Nl~JGd;ICIM{88O~Wsk6VNg2i&Gp96} ze*d7CaeL1@;@`haefL?l&Q*_g4Xxz%e0uuOZ%z;Tsn-16HSC=CroE7@pXE2pF`U)B zf55|XRwIv}BF&wiJnp^v(U{BI$Bz@WyPV#o@BUpcLw_?E_da;^i&K-~X^*c-s$9S3 zIx@z$qGYM;$++Qg!`injJH%kr zXD_~f#2PsoIn`gA(Q@t^uO7cIbRPYL`Q8{;KcwzSvoY}_1Pg!9KL8@dfNakXqb%Dm5oV+&@E zxw7fUZ<$k{F@K~61e&E@j*c41oF~-1agr-yKYTXvIQ(p0By%8{cX6 z`1B6&wm4IE{#rlxt8MPyrS4IWfku;Rl;37%4>_yfp5S>AI-1|v!M<86w*2(=#PI_S zZDZOQJSbxq)5dr5TbHC!PUeQTb2{|edVj>-35N`A(@k9i`ld{1A7Co!Z*y|)Pd6(6 zym#u0?~&ogShA>B7Q63P`zCa#q3!c8X8vzmzpDd&GIblBqPw>DpKNPtrI9U^Inl>l z(*KuZ(E}HZViS?meO#7Bg>{YzAKnAo+uo%AwBhL>>uuL0J$wJfdYW3XfhP^!d|FCs zk3A=BX4A&^eLK0iH9CA)|AB=`;-kMK(l1_%X>6_+q%U^WpJrt}XZf*bH{6mdb+f6r zZTp0XcQ-=*a*S!kqV}nRQ2|F}U{&k(88929zEP2I;DA3Nc`X!w?}+gs+1JHf8CSZNT@QgX?p zqs4ewe@wtkr?duh?q00e&1QOE*OfJ78F#N84`~PIdT06FN`vHK4+eC3WXW8f?+BW1 z;&#Nv>C`&WrLU^lSokEw`L;0JYS#DqD0q5|{eo6w>~%-CxODN%E?LTsOYIEZ8jdmb zXck$ue8-mtbBsE5^OU;0kl2j8d+2J&qN^{FZ>|sYtg-lqZ=ZG8p72YGOVGxFi9z-Y z-Xd>R+E@FI&YkX``zAilsB>ceOs5?+^laA*6#I4?a^a2rf-g73g&kTr&}c_lQ#R;q z+JI4>uMvT6M~liUME#qcd$ptg7kak)oiheJXgtSg&iyT2tLxc@42v01rc8nx0~(o4EX9u;?fh%MvTMF*sFEq`pEa!=J&cf!_U^}_>-XYdp8`79A}K#DDrrB zHgaj?()aydSM$I7_L0Y>F0oaETF1Fvsc&d})84<<&ZM^kl13$+USKYsd*pll1nJw) z_fBu#tlP$h9_6D~+wOQi`%08+t+Qq%-WSiFakp2HG~vPZ zDZ?Gcf7OF3786^pn^9p=?a2++-8cCmZ_8fjnMmM_Uo3>U81|_{V}|ce|b+= zNzTZDK+zfL`xIek|pE$Q$*c0l~K>CL(2rhVJYBQ^4`U;j;aT6xdoQlF;D zqpu%r5p33Q@b!qYmz-}5h^`UY*5u}abwi%%{4FjUnsIcH_2frYzL?ZPvVT%Lotkx@ z9bKuYw&9K#aADKX=^es?uH4Zxe7YradgSzV3C9*W{???-PWO~*r^gN47QTM4^onfv z`Q%xF`_9^hz5l+(`7Pg{d{+NNzpZ8tjc|gHC=Q@ZoV_w;?Vl-eNMGtm0G`Y=<&yk8DF_bM{YiOFeJfwL+}ZU|sJ*-Gf;z18BKt6TZFic`;2h(Zg8_3F{L`>w7d=QYN<8~uRh z54DekMbLnt0YL+T1_TWV8W1!fXh6__paDSxf(8T)2pSMHAZS3)fS>_E1A+zw4U|+3 ztbN3oe;kvndzdMq_iiRyxr-a*llh~t_Q`0#`!-{Ku}mBg!^*?gB9Qocneao52OC%3+&zxyalP?2p9)HFhwZw z`HeqH2(>{2t7A~U$1=TuIMxJqo((R7G>`#g3UadlJJ?&M;61{}U<>HuwTBt{>|x@) zd$mCWrBBAdc*X+anGUE4`%VN$Kq^qRId6Lk^Rhqh2NY7da0@I(nP7!bx@>pp({V{l z@jB#lB5c~6fKw&ya2ET&A@Bt$rb_*>cMU=A3_{K32>@7uJ zZ;j9sw*Cja$*0W=)BdWyK=p4;Ah+$>I2>F$39vWr6vNj$r$pt4yX=0j{yh4OQ6m@JujQ9 z?$?CvX%@28BdjYHo|EHg&=J^;2322a3yplY+i zT-UVyRegclk_o^McH01z;W;j z6h=KxTkX&L0fmLu*J#a{v^8Um!DmGXO%utotcm05aT4^$Re_yHfZgCMpKko|#>T87kTfpvVKvsmj z%=V1!9&Ap}*a~W!qByU(>VLd_^AoDw*H~Qkhpo?n?9bSW!j1*KhBnz>)mNymF&ZrO z+Qk~J$kyLnjP|EKnu6M*IL^~H`}2K^*I|1vuQ1jdeFO zLfJ2r|CwWlRPWb$t!FRS`@q%}U~`?Fk;-hX_6pkntQ}+GqDHX4a@<&6_NM*$F4xs| zfMPmOuz#NRS1s2^=eJxhCbO!2S;7AQv45eK>uMXKm<|-|&)J_Z*N>x&pUv0TQI8XE z+*nM8DWc1kV*68nOcK}$#)7&)Z?&5B^&&El#xGNf?9Z3$|G>^Zpr04&>ln|W6H|} zMaI&AsDk}9pj0i2Qn0@k8A}7A3ij84Qne^b!TwrgEDeY%*k1!m)uJc``)iT0G$5*A ze+?*Ai=q_luSLevfT)7~HK0^2ic+w@78y$eq6+rcfKs(6O2PhGWGoGcD%f8GO4Xt$ z1^a7}u{0p6V1ErLRg0n&?5{<}(txOf{WYLeEs9dGzZMxw1ELD{*ML&BC`!TpT4XE@ zh$`4$14`ARCH16zs1>#?pYOg8en1R4s~9u)h`=O9P?`_Sb+? zwJ1u#{#s-#4Tvh(Ujs_jq9_IXYmu=uAgW-04JcKMq7>|}MaI&AsDk}9pj0i2Qn0@k z8A}7A3ij84Qne^bt+YSBP3ZMZieKhDe@o<3D}>oK@QK-<_X7&4otJ<`n>+hhGXy64p0{wtbxGjnF3HFc6@!QjUTk0`2yvWgJ2ZujMb4|GF2(g4q-O5AhFjrY+H9LvPO7_vHoP>>ABmjz!a93Ale&a=_SSetZS5*PR< zgRknq?lr;pAOcW7Dc$1)UnrOkNOz>eR%30ZZlEnD=wG!V~Ck(TbjAH)NpuJB(!$m~CkWwz_%S(&w3 z)+Wr&C+WV0cCG|egg*~~5BvsFKxwWkP@fPt77=sji^f&ocvQ zs}H+>a?ga+vG<3LnfZb-VzCt-x5&feQ@27k!gs?C)K=}ywO?~LN9astOgW{?y zkpHEEV_*U>13GB435$j`!1X)h**Wg1i^O#~XL5aES>KL>k_E z1A+zw4G0<#G$3d|(14%;K?8yY1PurpC;|=0v~hWDlU3^ZMp?GsOGH_=QzR_Q32qXm zdcu1qVX7xYV_WqEM%z+ljPJSa%oC!y?aUKkG#sxyAx*K(pAf0o=1;&TcRWs@U39p7 zTf}YCZ}M$s!>wm-OS5fD^4K=Yw%;}Dwp13)6bs3(kdOO?wiWU#x6S1WQEn^r!*BEY z;_E1Deu+SciMx4!v7L40Kk9Gv*z}bbttavJ28m^Tlbr z7QIK}bFc)AU4001tissOzy&l0dfvMkTN$eTs!)toq%_mqXba#1&H(U_@m&x%mxF(gP%WgD=5rhZ^gWL3b3awnFGHGn-eEls1Oj_d z4v1IpDw%o^>nhTWcVi%pmBAno0_eRExy@(#Q2Kd2P?!d;f_b0?kOGkx{GzxQ@^7S% z%CT~w2UrUp0Cnf{sgr(Q7a2(R3vd*SN4}_qP{$iSAu7WBfijHVmqvM--koO+7J%!Z zAoE%ClYU+g6ut+EU@PbcjDdLd9yDgS{+q0xVU5k!P!kXr1n=A2{9Up&&68^grUM#l z|FLtl3YvaZUA#fsZ-FJCEhq!u5RoqUr7hClhKUA%6<}pPS%`GfytL7P=9CoX`)&#& z{k$$Hf24vaFcs7TI$p>hNWU0q_68Y1mQUzifOkP|D6RF|?^9mdKc?P97wDAGR_X*p2<4wk_5ldn_0 zj{)1j2v8eHDeqI7RhKr{K)Q8+v>=p_^pjt|0++!G&8uzgAa^noK|D{+IaqdP4d&SN{?0FZjQ@ z4%+X34^e~i1R zfKZJ0`Y{?qSCk8`TO8?E)dh{GxdZ6kwH<%~-l1J&`2*K0?)3Az;NSCj8Zyy)e+Un3NI7A0`MTC^rketU$b)8vmi1o{w3lcf!Vl^`Iwo zQ6Bk&#-$a?f_P~B&$ocaLgX}#@nd8!>~m=x+TXwfG)8&((e>-q$Xn!Bh>st~`U}?S z{pqg(<;lWMLqX#sSx6@OzQio}Kt1}VWnnIelk`C2|H^{Szzf_1>W+CVXxef+kKT`c z3oHj6;Qt2n9UgxT)}QDejO)-iU&?0{fg{)f@*4A+TRQTykI(ZPaZLwc40(#BexMxl zEU&AXL6(W&7@)db2FOpkayypFeELSo9xxnGnXf}WSyI|hcwaYt_lFIWz(dHMrM`RJb&^9T5{LWg{NLeNJ?D?}h@K+u4o0YL+WqyhEc zV(`XBer%-t4GkHJmt){H4&07N`KxgbkM z6?!2Bg%mFW?xhR}&9O<_6qLl!Tp<@PFDEGE~z7zBT(l#PdEy#TVs59^OIb?oPK)Ly}6-0iTS4lRY^2!ek0JSi0n*64k zLht7g=EX6{{^O8_D(Jsp-Y58v;6DZP9Qj#-{|Npg_)me_jmq|ymfycFLjKmk z0PuYooJ&ZJKE^ZDI~Ujd*!ClhE4c=!FW^g1UC~#^Xbd^G@Xu4!6DeOu;d&n{KkrA> zA4g-3FN0Np-WN(X5h=!;{r5Rhz9h~0V8mZo^7HASkkUfqz>a`%;4@GTP#+oRV>wHc z|6dWGCgfL53-yED1Dn7oK;u`aPn91Fn17*F&OkhxmY+`xrGsp86RZbz@GG*3nDeg! zwtsLw**FQj2mG}(9a37TzmNK|X8=o30f_w`s3=#BRh(lCsPB{JWt{}{en(BqpFRFF zxaJ@rrMVvYS#S{`f=?6jk${jR5p^XvS06Gw<&-B3nIV-&=eS<+%0fP+uBi? z4k{z4ADz-N9vlLc78>vSF>;g4H1>|}cgsP0K;- z6xX8nAX8eXjL%OxDBUEp7Z?akfiiv?Po{~b8XkaCxj^?&8c&XEl1-`s(i`QKe*npr z-M?s?{4N1(2K_*7KzdNhtqGa)ic{tK60BDSL%?s~9-y)@4jcnC=C&@NJjLC!JkKNc z0(*B}lBvJHS0^*i(+WUe-cRJkg#yaBQ#fx zisItqHW80;v5dE+EAWG zMO}vOk5mVsx>OIa3_Ji-M|_U!_rx{no#OO7^f}l827$UjO7GvNcZ@GrdH-;0cwcUK z-%_TN#QdC2%VTF5%kLUg6W2Tlk^tzr=O!fPH}8H{Jy30@2J>+_(dJ-@G2k@qOC` zygupqAFvcSfcn6Y{0|}LgA^K9rLju6j~mF>^<%iP72^?i4^S3}-255q`VsjrU)M*T zT#j$yP};b>RtV)!ey_jaOb&&}NBksQKOgxI_80X35zdywse=Eh?SFJ{oC_L(EPWOg z%yUqznm^@3|8#GnF{5|EuV5&kK1$Iq;kZ}<+wwSH-TPnmdn4Vmsn6IAP`!ofXMJx>G78KCpP_$BvIyn0-K4yw!13$A4Nw^UyCe&Z-3$d^fU*lu z<}L${p?;b=z!7W#)DQTfIvAhk4~4ugHX)8)z`*{8+^{>SLtwz0@aX z4UAXck)KcT6vi?G^$bOyts&wc0BBzFX%GOq11bkZ?*GHp3Yh=$lG8UDGEhG&@)WM6 z52^s_bLIPAS;abe#UkwgkOt)a2l#)SrijsWF>{%lasnQmMTRx!dK&0+*LlMAa=7An z>dlY<>dK&Q9*OKdb!E7@%49LhtIDXK!UR}?g7i}~?9BNE^M8OkG1`5!6vnq;tWl@; zxu=Mm{OJ+J~50N0=4h4w@n zY0m8>#6f)my#YOMxeVyJ0AC)xNBk5YwSD>aFpcqk2xtz#XwYay2-9yP7Bxa!a2Ob_ zUa67vKh;-)0o5639+rdbcIson&X-)~iK2DDcyHR;pA5fj0+7Eo1$OfdF>%a|k z1=WEr;Lgt}Zq?t6YRb11$J0HM>Uxa<*)#|Y1Ju?cebavKzG_fKH5N7274=oFe#xgz zMb6cC8Kb$mg|U3`lR|fj>rkJ2eizi3n9N4TQlv5#$yKRTVxVf4Il%rLQC7uVagq&3 zG~!6Zd9nx~lQF7?8H3tD-FjH1x{7vFH10Qh7#lwqbrY(bzjrw_6n`9(wA z8$03NNb{2_1Fnu$194Max`;~^98dm0J~bNb1W$2(5YDImV49yr-;L`E4DcL6)JDSf zJuBzD;rKNm7SLD>$^#iVe>2XfbE!^|4qkwrxF=h*)fN4S`}`pVyKsE=a)LkqI?lNa zRsxzIRt4uv+Ujuq-iA1zBggY&**foi%o6961!BNz)`wrCVyv2WTF>$PIOdPvB{iYj zy!4;j`MH=)xl2Rm2OwVVolljJhTN7Mu1_|+38)=R^D+C4n}~Qfbs{c)iUSws|rK-6hz|~I`{v14>Df> literal 0 HcmV?d00001 diff --git a/src/Neo.ConsoleService/CommandQuoteToken.cs b/src/Neo.ConsoleService/CommandQuoteToken.cs new file mode 100644 index 0000000000..497a956a7f --- /dev/null +++ b/src/Neo.ConsoleService/CommandQuoteToken.cs @@ -0,0 +1,53 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The Neo.ConsoleService is free software distributed under the MIT +// software license, see the accompanying file LICENSE in the main directory +// of the project 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.Diagnostics; + +namespace Neo.ConsoleService +{ + [DebuggerDisplay("Value={Value}, Value={Value}")] + internal class CommandQuoteToken : CommandToken + { + /// + /// Constructor + /// + /// Offset + /// Value + public CommandQuoteToken(int offset, char value) : base(CommandTokenType.Quote, offset) + { + if (value != '\'' && value != '"') + { + throw new ArgumentException("Not valid quote"); + } + + Value = value.ToString(); + } + + /// + /// Parse command line quotes + /// + /// Command line + /// Index + /// CommandQuoteToken + internal static CommandQuoteToken Parse(string commandLine, ref int index) + { + var c = commandLine[index]; + + if (c == '\'' || c == '"') + { + index++; + return new CommandQuoteToken(index - 1, c); + } + + throw new ArgumentException("No quote found"); + } + } +} diff --git a/src/Neo.ConsoleService/CommandSpaceToken.cs b/src/Neo.ConsoleService/CommandSpaceToken.cs new file mode 100644 index 0000000000..9a59f14410 --- /dev/null +++ b/src/Neo.ConsoleService/CommandSpaceToken.cs @@ -0,0 +1,64 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The Neo.ConsoleService is free software distributed under the MIT +// software license, see the accompanying file LICENSE in the main directory +// of the project 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.Diagnostics; + +namespace Neo.ConsoleService +{ + [DebuggerDisplay("Value={Value}, Count={Count}")] + internal class CommandSpaceToken : CommandToken + { + /// + /// Count + /// + public int Count { get; } + + /// + /// Constructor + /// + /// Offset + /// Count + public CommandSpaceToken(int offset, int count) : base(CommandTokenType.Space, offset) + { + Value = "".PadLeft(count, ' '); + Count = count; + } + + /// + /// Parse command line spaces + /// + /// Command line + /// Index + /// CommandSpaceToken + internal static CommandSpaceToken Parse(string commandLine, ref int index) + { + int offset = index; + int count = 0; + + for (int ix = index, max = commandLine.Length; ix < max; ix++) + { + if (commandLine[ix] == ' ') + { + count++; + } + else + { + break; + } + } + + if (count == 0) throw new ArgumentException("No spaces found"); + + index += count; + return new CommandSpaceToken(offset, count); + } + } +} diff --git a/src/Neo.ConsoleService/CommandStringToken.cs b/src/Neo.ConsoleService/CommandStringToken.cs new file mode 100644 index 0000000000..c22d989996 --- /dev/null +++ b/src/Neo.ConsoleService/CommandStringToken.cs @@ -0,0 +1,90 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The Neo.ConsoleService is free software distributed under the MIT +// software license, see the accompanying file LICENSE in the main directory +// of the project 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.Diagnostics; + +namespace Neo.ConsoleService +{ + [DebuggerDisplay("Value={Value}, RequireQuotes={RequireQuotes}")] + internal class CommandStringToken : CommandToken + { + /// + /// Require quotes + /// + public bool RequireQuotes { get; } + + /// + /// Constructor + /// + /// Offset + /// Value + public CommandStringToken(int offset, string value) : base(CommandTokenType.String, offset) + { + Value = value; + RequireQuotes = value.IndexOfAny(new char[] { '\'', '"' }) != -1; + } + + /// + /// Parse command line spaces + /// + /// Command line + /// Index + /// Quote (could be null) + /// CommandSpaceToken + internal static CommandStringToken Parse(string commandLine, ref int index, CommandQuoteToken quote) + { + int end; + int offset = index; + + if (quote != null) + { + var ix = index; + + do + { + end = commandLine.IndexOf(quote.Value[0], ix + 1); + + if (end == -1) + { + throw new ArgumentException("String not closed"); + } + + if (IsScaped(commandLine, end - 1)) + { + ix = end; + end = -1; + } + } + while (end < 0); + } + else + { + end = commandLine.IndexOf(' ', index + 1); + } + + if (end == -1) + { + end = commandLine.Length; + } + + var ret = new CommandStringToken(offset, commandLine.Substring(index, end - index)); + index += end - index; + return ret; + } + + private static bool IsScaped(string commandLine, int index) + { + // TODO: Scape the scape + + return (commandLine[index] == '\\'); + } + } +} diff --git a/src/Neo.ConsoleService/CommandToken.cs b/src/Neo.ConsoleService/CommandToken.cs new file mode 100644 index 0000000000..a8b8a47fd6 --- /dev/null +++ b/src/Neo.ConsoleService/CommandToken.cs @@ -0,0 +1,225 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The Neo.ConsoleService is free software distributed under the MIT +// software license, see the accompanying file LICENSE in the main directory +// of the project 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.Text; + +namespace Neo.ConsoleService +{ + internal abstract class CommandToken + { + /// + /// Offset + /// + public int Offset { get; } + + /// + /// Type + /// + public CommandTokenType Type { get; } + + /// + /// Value + /// + public string Value { get; protected init; } + + /// + /// Constructor + /// + /// Type + /// Offset + protected CommandToken(CommandTokenType type, int offset) + { + Type = type; + Offset = offset; + } + + /// + /// Parse command line + /// + /// Command line + /// + public static IEnumerable Parse(string commandLine) + { + CommandToken lastToken = null; + + for (int index = 0, count = commandLine.Length; index < count;) + { + switch (commandLine[index]) + { + case ' ': + { + lastToken = CommandSpaceToken.Parse(commandLine, ref index); + yield return lastToken; + break; + } + case '"': + case '\'': + { + // "'" + if (lastToken is CommandQuoteToken quote && quote.Value[0] != commandLine[index]) + { + goto default; + } + + lastToken = CommandQuoteToken.Parse(commandLine, ref index); + yield return lastToken; + break; + } + default: + { + lastToken = CommandStringToken.Parse(commandLine, ref index, + lastToken is CommandQuoteToken quote ? quote : null); + + yield return lastToken; + break; + } + } + } + } + + /// + /// Create string arguments + /// + /// Tokens + /// Remove escape + /// Arguments + public static string[] ToArguments(IEnumerable tokens, bool removeEscape = true) + { + var list = new List(); + + CommandToken lastToken = null; + + foreach (var token in tokens) + { + if (token is CommandStringToken str) + { + if (removeEscape && lastToken is CommandQuoteToken quote) + { + // Remove escape + + list.Add(str.Value.Replace("\\" + quote.Value, quote.Value)); + } + else + { + list.Add(str.Value); + } + } + + lastToken = token; + } + + return list.ToArray(); + } + + /// + /// Create a string from token list + /// + /// Tokens + /// String + public static string ToString(IEnumerable tokens) + { + var sb = new StringBuilder(); + + foreach (var token in tokens) + { + sb.Append(token.Value); + } + + return sb.ToString(); + } + + /// + /// Trim + /// + /// Args + public static void Trim(List args) + { + // Trim start + + while (args.Count > 0 && args[0].Type == CommandTokenType.Space) + { + args.RemoveAt(0); + } + + // Trim end + + while (args.Count > 0 && args[^1].Type == CommandTokenType.Space) + { + args.RemoveAt(args.Count - 1); + } + } + + /// + /// Read String + /// + /// Args + /// Consume all if not quoted + /// String + public static string ReadString(List args, bool consumeAll) + { + Trim(args); + + var quoted = false; + + if (args.Count > 0 && args[0].Type == CommandTokenType.Quote) + { + quoted = true; + args.RemoveAt(0); + } + else + { + if (consumeAll) + { + // Return all if it's not quoted + + var ret = ToString(args); + args.Clear(); + + return ret; + } + } + + if (args.Count > 0) + { + switch (args[0]) + { + case CommandQuoteToken _: + { + if (quoted) + { + args.RemoveAt(0); + return ""; + } + + throw new ArgumentException(); + } + case CommandSpaceToken _: throw new ArgumentException(); + case CommandStringToken str: + { + args.RemoveAt(0); + + if (quoted && args.Count > 0 && args[0].Type == CommandTokenType.Quote) + { + // Remove last quote + + args.RemoveAt(0); + } + + return str.Value; + } + } + } + + return null; + } + } +} diff --git a/src/Neo.ConsoleService/CommandTokenType.cs b/src/Neo.ConsoleService/CommandTokenType.cs new file mode 100644 index 0000000000..828ea34b4e --- /dev/null +++ b/src/Neo.ConsoleService/CommandTokenType.cs @@ -0,0 +1,19 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The Neo.ConsoleService is free software distributed under the MIT +// software license, see the accompanying file LICENSE in the main directory +// of the project 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.ConsoleService +{ + internal enum CommandTokenType : byte + { + String, + Space, + Quote, + } +} diff --git a/src/Neo.ConsoleService/ConsoleColorSet.cs b/src/Neo.ConsoleService/ConsoleColorSet.cs new file mode 100644 index 0000000000..465ab39f98 --- /dev/null +++ b/src/Neo.ConsoleService/ConsoleColorSet.cs @@ -0,0 +1,51 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The Neo.ConsoleService is free software distributed under the MIT +// software license, see the accompanying file LICENSE in the main directory +// of the project 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; + +namespace Neo.ConsoleService +{ + public class ConsoleColorSet + { + public ConsoleColor Foreground; + public ConsoleColor Background; + + /// + /// Create a new color set with the current console colors + /// + public ConsoleColorSet() : this(Console.ForegroundColor, Console.BackgroundColor) { } + + /// + /// Create a new color set + /// + /// Foreground color + public ConsoleColorSet(ConsoleColor foreground) : this(foreground, Console.BackgroundColor) { } + + /// + /// Create a new color set + /// + /// Foreground color + /// Background color + public ConsoleColorSet(ConsoleColor foreground, ConsoleColor background) + { + Foreground = foreground; + Background = background; + } + + /// + /// Apply the current set + /// + public void Apply() + { + Console.ForegroundColor = Foreground; + Console.BackgroundColor = Background; + } + } +} diff --git a/src/Neo.ConsoleService/ConsoleCommandAttribute.cs b/src/Neo.ConsoleService/ConsoleCommandAttribute.cs new file mode 100644 index 0000000000..b880c03bec --- /dev/null +++ b/src/Neo.ConsoleService/ConsoleCommandAttribute.cs @@ -0,0 +1,45 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The Neo.ConsoleService is free software distributed under the MIT +// software license, see the accompanying file LICENSE in the main directory +// of the project 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.Diagnostics; +using System.Linq; + +namespace Neo.ConsoleService +{ + [DebuggerDisplay("Verbs={string.Join(' ',Verbs)}")] + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] + public class ConsoleCommandAttribute : Attribute + { + /// + /// Verbs + /// + public string[] Verbs { get; } + + /// + /// Category + /// + public string Category { get; set; } + + /// + /// Description + /// + public string Description { get; set; } + + /// + /// Constructor + /// + /// Verbs + public ConsoleCommandAttribute(string verbs) + { + Verbs = verbs.Split(' ', StringSplitOptions.RemoveEmptyEntries).Select(u => u.ToLowerInvariant()).ToArray(); + } + } +} diff --git a/src/Neo.ConsoleService/ConsoleCommandMethod.cs b/src/Neo.ConsoleService/ConsoleCommandMethod.cs new file mode 100644 index 0000000000..55176ecbc3 --- /dev/null +++ b/src/Neo.ConsoleService/ConsoleCommandMethod.cs @@ -0,0 +1,120 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The Neo.ConsoleService is free software distributed under the MIT +// software license, see the accompanying file LICENSE in the main directory +// of the project 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.Collections.Generic; +using System.Diagnostics; +using System.Reflection; + +namespace Neo.ConsoleService +{ + [DebuggerDisplay("Key={Key}")] + internal class ConsoleCommandMethod + { + /// + /// Verbs + /// + public string[] Verbs { get; } + + /// + /// Key + /// + public string Key => string.Join(' ', Verbs); + + /// + /// Help category + /// + public string HelpCategory { get; set; } + + /// + /// Help message + /// + public string HelpMessage { get; set; } + + /// + /// Instance + /// + public object Instance { get; } + + /// + /// Method + /// + public MethodInfo Method { get; } + + /// + /// Set instance command + /// + /// Instance + /// Method + /// Attribute + public ConsoleCommandMethod(object instance, MethodInfo method, ConsoleCommandAttribute attribute) + { + Method = method; + Instance = instance; + Verbs = attribute.Verbs; + HelpCategory = attribute.Category; + HelpMessage = attribute.Description; + } + + /// + /// Is this command + /// + /// Tokens + /// Consumed Arguments + /// True if is this command + public bool IsThisCommand(CommandToken[] tokens, out int consumedArgs) + { + int checks = Verbs.Length; + bool quoted = false; + var tokenList = new List(tokens); + + while (checks > 0 && tokenList.Count > 0) + { + switch (tokenList[0]) + { + case CommandSpaceToken _: + { + tokenList.RemoveAt(0); + break; + } + case CommandQuoteToken _: + { + quoted = !quoted; + tokenList.RemoveAt(0); + break; + } + case CommandStringToken str: + { + if (Verbs[^checks] != str.Value.ToLowerInvariant()) + { + consumedArgs = 0; + return false; + } + + checks--; + tokenList.RemoveAt(0); + break; + } + } + } + + if (quoted && tokenList.Count > 0 && tokenList[0].Type == CommandTokenType.Quote) + { + tokenList.RemoveAt(0); + } + + // Trim start + + while (tokenList.Count > 0 && tokenList[0].Type == CommandTokenType.Space) tokenList.RemoveAt(0); + + consumedArgs = tokens.Length - tokenList.Count; + return checks == 0; + } + } +} diff --git a/src/Neo.ConsoleService/ConsoleHelper.cs b/src/Neo.ConsoleService/ConsoleHelper.cs new file mode 100644 index 0000000000..fdf6f180cd --- /dev/null +++ b/src/Neo.ConsoleService/ConsoleHelper.cs @@ -0,0 +1,65 @@ +using System; + +namespace Neo.ConsoleService +{ + public static class ConsoleHelper + { + private static readonly ConsoleColorSet InfoColor = new(ConsoleColor.Cyan); + private static readonly ConsoleColorSet WarningColor = new(ConsoleColor.Yellow); + private static readonly ConsoleColorSet ErrorColor = new(ConsoleColor.Red); + + /// + /// Info handles message in the format of "[tag]:[message]", + /// avoid using Info if the `tag` is too long + /// + /// The log message in pairs of (tag, message) + public static void Info(params string[] values) + { + var currentColor = new ConsoleColorSet(); + + for (int i = 0; i < values.Length; i++) + { + if (i % 2 == 0) + InfoColor.Apply(); + else + currentColor.Apply(); + Console.Write(values[i]); + } + currentColor.Apply(); + Console.WriteLine(); + } + + /// + /// Use warning if something unexpected happens + /// or the execution result is not correct. + /// Also use warning if you just want to remind + /// user of doing something. + /// + /// Warning message + public static void Warning(string msg) + { + Log("Warning", WarningColor, msg); + } + + /// + /// Use Error if the verification or input format check fails + /// or exception that breaks the execution of interactive + /// command throws. + /// + /// Error message + public static void Error(string msg) + { + Log("Error", ErrorColor, msg); + } + + private static void Log(string tag, ConsoleColorSet colorSet, string msg) + { + var currentColor = new ConsoleColorSet(); + + colorSet.Apply(); + Console.Write($"{tag}: "); + currentColor.Apply(); + Console.WriteLine(msg); + } + } +} diff --git a/src/Neo.ConsoleService/ConsoleServiceBase.cs b/src/Neo.ConsoleService/ConsoleServiceBase.cs new file mode 100644 index 0000000000..ae55b5fd76 --- /dev/null +++ b/src/Neo.ConsoleService/ConsoleServiceBase.cs @@ -0,0 +1,627 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The Neo.ConsoleService is free software distributed under the MIT +// software license, see the accompanying file LICENSE in the main directory +// of the project 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.Diagnostics; +using System.IO; +using System.Linq; +using System.Net; +using System.Reflection; +using System.Runtime.Loader; +using System.Security; +using System.ServiceProcess; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace Neo.ConsoleService +{ + public abstract class ConsoleServiceBase + { + protected virtual string Depends => null; + protected virtual string Prompt => "service"; + + public abstract string ServiceName { get; } + + protected bool ShowPrompt { get; set; } = true; + public bool ReadingPassword { get; set; } = false; + + private bool _running; + private readonly CancellationTokenSource _shutdownTokenSource = new(); + private readonly CountdownEvent _shutdownAcknowledged = new(1); + private readonly Dictionary> _verbs = new(); + private readonly Dictionary _instances = new(); + private readonly Dictionary, bool, object>> _handlers = new(); + + private bool OnCommand(string commandLine) + { + if (string.IsNullOrEmpty(commandLine)) + { + return true; + } + + string possibleHelp = null; + var commandArgs = CommandToken.Parse(commandLine).ToArray(); + var availableCommands = new List<(ConsoleCommandMethod Command, object[] Arguments)>(); + + foreach (var entries in _verbs.Values) + { + foreach (var command in entries) + { + if (command.IsThisCommand(commandArgs, out var consumedArgs)) + { + var arguments = new List(); + var args = commandArgs.Skip(consumedArgs).ToList(); + + CommandSpaceToken.Trim(args); + + try + { + var parameters = command.Method.GetParameters(); + + foreach (var arg in parameters) + { + // Parse argument + + if (TryProcessValue(arg.ParameterType, args, arg == parameters.Last(), out var value)) + { + arguments.Add(value); + } + else + { + if (arg.HasDefaultValue) + { + arguments.Add(arg.DefaultValue); + } + else + { + throw new ArgumentException(arg.Name); + } + } + } + + availableCommands.Add((command, arguments.ToArray())); + } + catch + { + // Skip parse errors + possibleHelp = command.Key; + } + } + } + } + + switch (availableCommands.Count) + { + case 0: + { + if (!string.IsNullOrEmpty(possibleHelp)) + { + OnHelpCommand(possibleHelp); + return true; + } + + return false; + } + case 1: + { + var (command, arguments) = availableCommands[0]; + object result = command.Method.Invoke(command.Instance, arguments); + if (result is Task task) task.Wait(); + return true; + } + default: + { + // Show Ambiguous call + + throw new ArgumentException("Ambiguous calls for: " + string.Join(',', availableCommands.Select(u => u.Command.Key).Distinct())); + } + } + } + + private bool TryProcessValue(Type parameterType, List args, bool canConsumeAll, out object value) + { + if (args.Count > 0) + { + if (_handlers.TryGetValue(parameterType, out var handler)) + { + value = handler(args, canConsumeAll); + return true; + } + + if (parameterType.IsEnum) + { + var arg = CommandToken.ReadString(args, canConsumeAll); + value = Enum.Parse(parameterType, arg.Trim(), true); + return true; + } + } + + value = null; + return false; + } + + #region Commands + + /// + /// Process "help" command + /// + [ConsoleCommand("help", Category = "Base Commands")] + protected void OnHelpCommand(string key) + { + var withHelp = new List(); + + // Try to find a plugin with this name + + if (_instances.TryGetValue(key.Trim().ToLowerInvariant(), out var instance)) + { + // Filter only the help of this plugin + + key = ""; + foreach (var commands in _verbs.Values.Select(u => u)) + { + withHelp.AddRange + ( + commands.Where(u => !string.IsNullOrEmpty(u.HelpCategory) && u.Instance == instance) + ); + } + } + else + { + // Fetch commands + + foreach (var commands in _verbs.Values.Select(u => u)) + { + withHelp.AddRange(commands.Where(u => !string.IsNullOrEmpty(u.HelpCategory))); + } + } + + // Sort and show + + withHelp.Sort((a, b) => + { + var cate = string.Compare(a.HelpCategory, b.HelpCategory, StringComparison.Ordinal); + if (cate == 0) + { + cate = string.Compare(a.Key, b.Key, StringComparison.Ordinal); + } + return cate; + }); + + if (string.IsNullOrEmpty(key) || key.Equals("help", StringComparison.InvariantCultureIgnoreCase)) + { + string last = null; + foreach (var command in withHelp) + { + if (last != command.HelpCategory) + { + Console.WriteLine($"{command.HelpCategory}:"); + last = command.HelpCategory; + } + + Console.Write($"\t{command.Key}"); + Console.WriteLine(" " + string.Join(' ', + command.Method.GetParameters() + .Select(u => u.HasDefaultValue ? $"[{u.Name}={(u.DefaultValue == null ? "null" : u.DefaultValue.ToString())}]" : $"<{u.Name}>")) + ); + } + } + else + { + // Show help for this specific command + + string last = null; + string lastKey = null; + bool found = false; + + foreach (var command in withHelp.Where(u => u.Key == key)) + { + found = true; + + if (last != command.HelpMessage) + { + Console.WriteLine($"{command.HelpMessage}"); + last = command.HelpMessage; + } + + if (lastKey != command.Key) + { + Console.WriteLine("You can call this command like this:"); + lastKey = command.Key; + } + + Console.Write($"\t{command.Key}"); + Console.WriteLine(" " + string.Join(' ', + command.Method.GetParameters() + .Select(u => u.HasDefaultValue ? $"[{u.Name}={u.DefaultValue?.ToString() ?? "null"}]" : $"<{u.Name}>")) + ); + } + + if (!found) + { + throw new ArgumentException("Command not found."); + } + } + } + + /// + /// Process "clear" command + /// + [ConsoleCommand("clear", Category = "Base Commands", Description = "Clear is used in order to clean the console output.")] + protected void OnClear() + { + Console.Clear(); + } + + /// + /// Process "version" command + /// + [ConsoleCommand("version", Category = "Base Commands", Description = "Show the current version.")] + protected void OnVersion() + { + Console.WriteLine(Assembly.GetEntryAssembly().GetName().Version); + } + + /// + /// Process "exit" command + /// + [ConsoleCommand("exit", Category = "Base Commands", Description = "Exit the node.")] + protected void OnExit() + { + _running = false; + } + + #endregion + + public virtual void OnStart(string[] args) + { + // Register sigterm event handler + AssemblyLoadContext.Default.Unloading += SigTermEventHandler; + // Register sigint event handler + Console.CancelKeyPress += CancelHandler; + } + + public virtual void OnStop() + { + _shutdownAcknowledged.Signal(); + } + + public string ReadUserInput(string prompt, bool password = false) + { + const string t = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; + var sb = new StringBuilder(); + + if (!string.IsNullOrEmpty(prompt)) + { + Console.Write(prompt + ": "); + } + + if (password) ReadingPassword = true; + var prevForeground = Console.ForegroundColor; + Console.ForegroundColor = ConsoleColor.Yellow; + + if (Console.IsInputRedirected) + { + // neo-gui Console require it + sb.Append(Console.ReadLine()); + } + else + { + ConsoleKeyInfo key; + do + { + key = Console.ReadKey(true); + + if (t.IndexOf(key.KeyChar) != -1) + { + sb.Append(key.KeyChar); + Console.Write(password ? '*' : key.KeyChar); + } + else if (key.Key == ConsoleKey.Backspace && sb.Length > 0) + { + sb.Length--; + Console.Write("\b \b"); + } + } while (key.Key != ConsoleKey.Enter); + } + + Console.ForegroundColor = prevForeground; + if (password) ReadingPassword = false; + Console.WriteLine(); + return sb.ToString(); + } + + public SecureString ReadSecureString(string prompt) + { + const string t = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; + SecureString securePwd = new SecureString(); + ConsoleKeyInfo key; + + if (!string.IsNullOrEmpty(prompt)) + { + Console.Write(prompt + ": "); + } + + ReadingPassword = true; + Console.ForegroundColor = ConsoleColor.Yellow; + + do + { + key = Console.ReadKey(true); + if (t.IndexOf(key.KeyChar) != -1) + { + securePwd.AppendChar(key.KeyChar); + Console.Write('*'); + } + else if (key.Key == ConsoleKey.Backspace && securePwd.Length > 0) + { + securePwd.RemoveAt(securePwd.Length - 1); + Console.Write(key.KeyChar); + Console.Write(' '); + Console.Write(key.KeyChar); + } + } while (key.Key != ConsoleKey.Enter); + + Console.ForegroundColor = ConsoleColor.White; + ReadingPassword = false; + Console.WriteLine(); + securePwd.MakeReadOnly(); + return securePwd; + } + + private void TriggerGracefulShutdown() + { + if (!_running) return; + _running = false; + _shutdownTokenSource.Cancel(); + // Wait for us to have triggered shutdown. + _shutdownAcknowledged.Wait(); + } + + private void SigTermEventHandler(AssemblyLoadContext obj) + { + TriggerGracefulShutdown(); + } + + private void CancelHandler(object sender, ConsoleCancelEventArgs e) + { + e.Cancel = true; + TriggerGracefulShutdown(); + } + + /// + /// Constructor + /// + protected ConsoleServiceBase() + { + // Register self commands + + RegisterCommandHandler(CommandToken.ReadString); + + RegisterCommandHandler((args, canConsumeAll) => + { + if (canConsumeAll) + { + var ret = CommandToken.ToString(args); + args.Clear(); + return ret.Split(new[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); + } + + return CommandToken.ReadString(args, false).Split(',', ' '); + }); + + RegisterCommandHandler(false, str => byte.Parse(str)); + RegisterCommandHandler(false, str => str == "1" || str == "yes" || str == "y" || bool.Parse(str)); + RegisterCommandHandler(false, str => ushort.Parse(str)); + RegisterCommandHandler(false, str => uint.Parse(str)); + RegisterCommandHandler(false, IPAddress.Parse); + } + + /// + /// Register command handler + /// + /// Return type + /// Handler + private void RegisterCommandHandler(Func, bool, object> handler) + { + _handlers[typeof(TRet)] = handler; + } + + /// + /// Register command handler + /// + /// Base type + /// Return type + /// Can consume all + /// Handler + public void RegisterCommandHandler(bool canConsumeAll, Func handler) + { + _handlers[typeof(TRet)] = (args, _) => + { + var value = (T)_handlers[typeof(T)](args, canConsumeAll); + return handler(value); + }; + } + + /// + /// Register command handler + /// + /// Base type + /// Return type + /// Handler + public void RegisterCommandHandler(Func handler) + { + _handlers[typeof(TRet)] = (args, consumeAll) => + { + var value = (T)_handlers[typeof(T)](args, consumeAll); + return handler(value); + }; + } + + /// + /// Register commands + /// + /// Instance + /// Name + public void RegisterCommand(object instance, string name = null) + { + if (!string.IsNullOrEmpty(name)) + { + _instances.Add(name.ToLowerInvariant(), instance); + } + + foreach (var method in instance.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) + { + foreach (var attribute in method.GetCustomAttributes()) + { + // Check handlers + + if (!method.GetParameters().All(u => u.ParameterType.IsEnum || _handlers.ContainsKey(u.ParameterType))) + { + throw new ArgumentException("Handler not found for the command: " + method); + } + + // Add command + + var command = new ConsoleCommandMethod(instance, method, attribute); + + if (!_verbs.TryGetValue(command.Key, out var commands)) + { + _verbs.Add(command.Key, new List(new[] { command })); + } + else + { + commands.Add(command); + } + } + } + } + + public void Run(string[] args) + { + if (Environment.UserInteractive) + { + if (args.Length > 0 && args[0] == "/install") + { + if (Environment.OSVersion.Platform != PlatformID.Win32NT) + { + ConsoleHelper.Warning("Only support for installing services on Windows."); + return; + } + string arguments = string.Format("create {0} start= auto binPath= \"{1}\"", ServiceName, Process.GetCurrentProcess().MainModule.FileName); + if (!string.IsNullOrEmpty(Depends)) + { + arguments += string.Format(" depend= {0}", Depends); + } + Process process = Process.Start(new ProcessStartInfo + { + Arguments = arguments, + FileName = Path.Combine(Environment.SystemDirectory, "sc.exe"), + RedirectStandardOutput = true, + UseShellExecute = false + }); + process.WaitForExit(); + Console.Write(process.StandardOutput.ReadToEnd()); + } + else if (args.Length > 0 && args[0] == "/uninstall") + { + if (Environment.OSVersion.Platform != PlatformID.Win32NT) + { + ConsoleHelper.Warning("Only support for installing services on Windows."); + return; + } + Process process = Process.Start(new ProcessStartInfo + { + Arguments = string.Format("delete {0}", ServiceName), + FileName = Path.Combine(Environment.SystemDirectory, "sc.exe"), + RedirectStandardOutput = true, + UseShellExecute = false + }); + process.WaitForExit(); + Console.Write(process.StandardOutput.ReadToEnd()); + } + else + { + OnStart(args); + RunConsole(); + OnStop(); + } + } + else + { + Debug.Assert(OperatingSystem.IsWindows()); + ServiceBase.Run(new ServiceProxy(this)); + } + } + + protected string ReadLine() + { + Task readLineTask = Task.Run(Console.ReadLine); + + try + { + readLineTask.Wait(_shutdownTokenSource.Token); + } + catch (OperationCanceledException) + { + return null; + } + + return readLineTask.Result; + } + + public virtual void RunConsole() + { + _running = true; + if (Environment.OSVersion.Platform == PlatformID.Win32NT) + try + { + Console.Title = ServiceName; + } + catch { } + + Console.ForegroundColor = ConsoleColor.DarkGreen; + Console.SetIn(new StreamReader(Console.OpenStandardInput(), Console.InputEncoding, false, ushort.MaxValue)); + + while (_running) + { + if (ShowPrompt) + { + Console.ForegroundColor = ConsoleColor.Green; + Console.Write($"{Prompt}> "); + } + + Console.ForegroundColor = ConsoleColor.Yellow; + string line = ReadLine()?.Trim(); + if (line == null) break; + Console.ForegroundColor = ConsoleColor.White; + + try + { + if (!OnCommand(line)) + { + ConsoleHelper.Error("Command not found"); + } + } + catch (TargetInvocationException ex) when (ex.InnerException is not null) + { + ConsoleHelper.Error(ex.InnerException.Message); + } + catch (Exception ex) + { + ConsoleHelper.Error(ex.Message); + } + } + + Console.ResetColor(); + } + } +} diff --git a/src/Neo.ConsoleService/Neo.ConsoleService.csproj b/src/Neo.ConsoleService/Neo.ConsoleService.csproj new file mode 100644 index 0000000000..c5ef250052 --- /dev/null +++ b/src/Neo.ConsoleService/Neo.ConsoleService.csproj @@ -0,0 +1,12 @@ + + + + 1.2.0 + + + + + + + + diff --git a/src/Neo.ConsoleService/Properties/AssemblyInfo.cs b/src/Neo.ConsoleService/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..661513fb43 --- /dev/null +++ b/src/Neo.ConsoleService/Properties/AssemblyInfo.cs @@ -0,0 +1,13 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The Neo.ConsoleService is free software distributed under the MIT +// software license, see the accompanying file LICENSE in the main directory +// of the project 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.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("Neo.ConsoleService.Tests")] diff --git a/src/Neo.ConsoleService/ServiceProxy.cs b/src/Neo.ConsoleService/ServiceProxy.cs new file mode 100644 index 0000000000..c8060f0d47 --- /dev/null +++ b/src/Neo.ConsoleService/ServiceProxy.cs @@ -0,0 +1,34 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The Neo.ConsoleService is free software distributed under the MIT +// software license, see the accompanying file LICENSE in the main directory +// of the project 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.ServiceProcess; + +namespace Neo.ConsoleService +{ + internal class ServiceProxy : ServiceBase + { + private readonly ConsoleServiceBase _service; + + public ServiceProxy(ConsoleServiceBase service) + { + this._service = service; + } + + protected override void OnStart(string[] args) + { + _service.OnStart(args); + } + + protected override void OnStop() + { + _service.OnStop(); + } + } +} diff --git a/src/Neo.GUI/GUI/BulkPayDialog.Designer.cs b/src/Neo.GUI/GUI/BulkPayDialog.Designer.cs new file mode 100644 index 0000000000..41ad15e57a --- /dev/null +++ b/src/Neo.GUI/GUI/BulkPayDialog.Designer.cs @@ -0,0 +1,129 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-gui is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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.GUI +{ + partial class BulkPayDialog + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(BulkPayDialog)); + this.textBox3 = new System.Windows.Forms.TextBox(); + this.label4 = new System.Windows.Forms.Label(); + this.comboBox1 = new System.Windows.Forms.ComboBox(); + this.label3 = new System.Windows.Forms.Label(); + this.button1 = new System.Windows.Forms.Button(); + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.textBox1 = new System.Windows.Forms.TextBox(); + this.groupBox1.SuspendLayout(); + this.SuspendLayout(); + // + // textBox3 + // + resources.ApplyResources(this.textBox3, "textBox3"); + this.textBox3.Name = "textBox3"; + this.textBox3.ReadOnly = true; + // + // label4 + // + resources.ApplyResources(this.label4, "label4"); + this.label4.Name = "label4"; + // + // comboBox1 + // + resources.ApplyResources(this.comboBox1, "comboBox1"); + this.comboBox1.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.comboBox1.FormattingEnabled = true; + this.comboBox1.Name = "comboBox1"; + this.comboBox1.SelectedIndexChanged += new System.EventHandler(this.comboBox1_SelectedIndexChanged); + // + // label3 + // + resources.ApplyResources(this.label3, "label3"); + this.label3.Name = "label3"; + // + // button1 + // + resources.ApplyResources(this.button1, "button1"); + this.button1.DialogResult = System.Windows.Forms.DialogResult.OK; + this.button1.Name = "button1"; + this.button1.UseVisualStyleBackColor = true; + // + // groupBox1 + // + resources.ApplyResources(this.groupBox1, "groupBox1"); + this.groupBox1.Controls.Add(this.textBox1); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.TabStop = false; + // + // textBox1 + // + this.textBox1.AcceptsReturn = true; + resources.ApplyResources(this.textBox1, "textBox1"); + this.textBox1.Name = "textBox1"; + this.textBox1.TextChanged += new System.EventHandler(this.textBox1_TextChanged); + // + // BulkPayDialog + // + resources.ApplyResources(this, "$this"); + this.AcceptButton = this.button1; + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.groupBox1); + this.Controls.Add(this.textBox3); + this.Controls.Add(this.label4); + this.Controls.Add(this.comboBox1); + this.Controls.Add(this.label3); + this.Controls.Add(this.button1); + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "BulkPayDialog"; + this.ShowInTaskbar = false; + this.groupBox1.ResumeLayout(false); + this.groupBox1.PerformLayout(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.TextBox textBox3; + private System.Windows.Forms.Label label4; + private System.Windows.Forms.ComboBox comboBox1; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.Button button1; + private System.Windows.Forms.GroupBox groupBox1; + private System.Windows.Forms.TextBox textBox1; + } +} diff --git a/src/Neo.GUI/GUI/BulkPayDialog.cs b/src/Neo.GUI/GUI/BulkPayDialog.cs new file mode 100644 index 0000000000..b33cb9edec --- /dev/null +++ b/src/Neo.GUI/GUI/BulkPayDialog.cs @@ -0,0 +1,80 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-gui is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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; +using System; +using System.Linq; +using System.Windows.Forms; +using static Neo.Program; + +namespace Neo.GUI +{ + internal partial class BulkPayDialog : Form + { + public BulkPayDialog(AssetDescriptor asset = null) + { + InitializeComponent(); + if (asset == null) + { + foreach (UInt160 assetId in NEP5Watched) + { + try + { + comboBox1.Items.Add(new AssetDescriptor(Service.NeoSystem.StoreView, Service.NeoSystem.Settings, assetId)); + } + catch (ArgumentException) + { + continue; + } + } + } + else + { + comboBox1.Items.Add(asset); + comboBox1.SelectedIndex = 0; + comboBox1.Enabled = false; + } + } + + public TxOutListBoxItem[] GetOutputs() + { + AssetDescriptor asset = (AssetDescriptor)comboBox1.SelectedItem; + return textBox1.Lines.Where(p => !string.IsNullOrWhiteSpace(p)).Select(p => + { + string[] line = p.Split(new[] { ' ', '\t', ',' }, StringSplitOptions.RemoveEmptyEntries); + return new TxOutListBoxItem + { + AssetName = asset.AssetName, + AssetId = asset.AssetId, + Value = BigDecimal.Parse(line[1], asset.Decimals), + ScriptHash = line[0].ToScriptHash(Service.NeoSystem.Settings.AddressVersion) + }; + }).Where(p => p.Value.Value != 0).ToArray(); + } + + private void comboBox1_SelectedIndexChanged(object sender, EventArgs e) + { + if (comboBox1.SelectedItem is AssetDescriptor asset) + { + textBox3.Text = Service.CurrentWallet.GetAvailable(Service.NeoSystem.StoreView, asset.AssetId).ToString(); + } + else + { + textBox3.Text = ""; + } + textBox1_TextChanged(this, EventArgs.Empty); + } + + private void textBox1_TextChanged(object sender, EventArgs e) + { + button1.Enabled = comboBox1.SelectedIndex >= 0 && textBox1.TextLength > 0; + } + } +} diff --git a/src/Neo.GUI/GUI/BulkPayDialog.es-ES.resx b/src/Neo.GUI/GUI/BulkPayDialog.es-ES.resx new file mode 100644 index 0000000000..3aa43a7bae --- /dev/null +++ b/src/Neo.GUI/GUI/BulkPayDialog.es-ES.resx @@ -0,0 +1,148 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + 24, 54 + + + 44, 17 + + + Saldo: + + + 22, 17 + + + 46, 17 + + + Activo: + + + Aceptar + + + Pagar a + + + Pago + + \ No newline at end of file diff --git a/src/Neo.GUI/GUI/BulkPayDialog.resx b/src/Neo.GUI/GUI/BulkPayDialog.resx new file mode 100644 index 0000000000..0a6c0c3d28 --- /dev/null +++ b/src/Neo.GUI/GUI/BulkPayDialog.resx @@ -0,0 +1,354 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + Top, Left, Right + + + + 74, 51 + + + 468, 23 + + + + 12 + + + textBox3 + + + System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 1 + + + True + + + NoControl + + + 12, 54 + + + 56, 17 + + + 11 + + + Balance: + + + label4 + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 2 + + + Top, Left, Right + + + 74, 14 + + + 468, 25 + + + 10 + + + comboBox1 + + + System.Windows.Forms.ComboBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 3 + + + True + + + NoControl + + + 26, 17 + + + 42, 17 + + + 9 + + + Asset: + + + label3 + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 4 + + + Bottom, Right + + + False + + + NoControl + + + 467, 325 + + + 75, 23 + + + 17 + + + OK + + + button1 + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 5 + + + Top, Bottom, Left, Right + + + Fill + + + Consolas, 9pt + + + 3, 19 + + + True + + + Vertical + + + 524, 217 + + + 0 + + + False + + + textBox1 + + + System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + groupBox1 + + + 0 + + + 12, 80 + + + 530, 239 + + + 18 + + + Pay to + + + groupBox1 + + + System.Windows.Forms.GroupBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 0 + + + True + + + 7, 17 + + + 554, 360 + + + 微软雅黑, 9pt + + + 3, 4, 3, 4 + + + CenterScreen + + + Payment + + + BulkPayDialog + + + System.Windows.Forms.Form, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/src/Neo.GUI/GUI/BulkPayDialog.zh-Hans.resx b/src/Neo.GUI/GUI/BulkPayDialog.zh-Hans.resx new file mode 100644 index 0000000000..e429e3bf5e --- /dev/null +++ b/src/Neo.GUI/GUI/BulkPayDialog.zh-Hans.resx @@ -0,0 +1,157 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + 62, 51 + + + 480, 23 + + + 44, 17 + + + 余额: + + + 62, 14 + + + 480, 25 + + + 12, 17 + + + 44, 17 + + + 资产: + + + 确定 + + + 账户和金额 + + + 支付 + + \ No newline at end of file diff --git a/src/Neo.GUI/GUI/ChangePasswordDialog.Designer.cs b/src/Neo.GUI/GUI/ChangePasswordDialog.Designer.cs new file mode 100644 index 0000000000..0d9c6ea80c --- /dev/null +++ b/src/Neo.GUI/GUI/ChangePasswordDialog.Designer.cs @@ -0,0 +1,137 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-gui is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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.GUI +{ + partial class ChangePasswordDialog + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ChangePasswordDialog)); + this.label1 = new System.Windows.Forms.Label(); + this.textBox1 = new System.Windows.Forms.TextBox(); + this.label2 = new System.Windows.Forms.Label(); + this.textBox2 = new System.Windows.Forms.TextBox(); + this.label3 = new System.Windows.Forms.Label(); + this.textBox3 = new System.Windows.Forms.TextBox(); + this.button1 = new System.Windows.Forms.Button(); + this.button2 = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // label1 + // + resources.ApplyResources(this.label1, "label1"); + this.label1.Name = "label1"; + // + // textBox1 + // + resources.ApplyResources(this.textBox1, "textBox1"); + this.textBox1.Name = "textBox1"; + this.textBox1.UseSystemPasswordChar = true; + this.textBox1.TextChanged += new System.EventHandler(this.textBox_TextChanged); + // + // label2 + // + resources.ApplyResources(this.label2, "label2"); + this.label2.Name = "label2"; + // + // textBox2 + // + resources.ApplyResources(this.textBox2, "textBox2"); + this.textBox2.Name = "textBox2"; + this.textBox2.UseSystemPasswordChar = true; + this.textBox2.TextChanged += new System.EventHandler(this.textBox_TextChanged); + // + // label3 + // + resources.ApplyResources(this.label3, "label3"); + this.label3.Name = "label3"; + // + // textBox3 + // + resources.ApplyResources(this.textBox3, "textBox3"); + this.textBox3.Name = "textBox3"; + this.textBox3.UseSystemPasswordChar = true; + this.textBox3.TextChanged += new System.EventHandler(this.textBox_TextChanged); + // + // button1 + // + resources.ApplyResources(this.button1, "button1"); + this.button1.DialogResult = System.Windows.Forms.DialogResult.OK; + this.button1.Name = "button1"; + this.button1.UseVisualStyleBackColor = true; + // + // button2 + // + resources.ApplyResources(this.button2, "button2"); + this.button2.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.button2.Name = "button2"; + this.button2.UseVisualStyleBackColor = true; + // + // ChangePasswordDialog + // + this.AcceptButton = this.button1; + resources.ApplyResources(this, "$this"); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.button2; + this.Controls.Add(this.button2); + this.Controls.Add(this.button1); + this.Controls.Add(this.textBox3); + this.Controls.Add(this.label3); + this.Controls.Add(this.textBox2); + this.Controls.Add(this.label2); + this.Controls.Add(this.textBox1); + this.Controls.Add(this.label1); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "ChangePasswordDialog"; + this.ShowInTaskbar = false; + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Label label1; + private System.Windows.Forms.TextBox textBox1; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.TextBox textBox2; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.TextBox textBox3; + private System.Windows.Forms.Button button1; + private System.Windows.Forms.Button button2; + } +} diff --git a/src/Neo.GUI/GUI/ChangePasswordDialog.cs b/src/Neo.GUI/GUI/ChangePasswordDialog.cs new file mode 100644 index 0000000000..7bda7e93a1 --- /dev/null +++ b/src/Neo.GUI/GUI/ChangePasswordDialog.cs @@ -0,0 +1,53 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-gui is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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.Windows.Forms; + +namespace Neo.GUI +{ + internal partial class ChangePasswordDialog : Form + { + public string OldPassword + { + get + { + return textBox1.Text; + } + set + { + textBox1.Text = value; + } + } + + public string NewPassword + { + get + { + return textBox2.Text; + } + set + { + textBox2.Text = value; + textBox3.Text = value; + } + } + + public ChangePasswordDialog() + { + InitializeComponent(); + } + + private void textBox_TextChanged(object sender, EventArgs e) + { + button1.Enabled = textBox1.TextLength > 0 && textBox2.TextLength > 0 && textBox3.Text == textBox2.Text; + } + } +} diff --git a/src/Neo.GUI/GUI/ChangePasswordDialog.es-ES.resx b/src/Neo.GUI/GUI/ChangePasswordDialog.es-ES.resx new file mode 100644 index 0000000000..27c58de2d0 --- /dev/null +++ b/src/Neo.GUI/GUI/ChangePasswordDialog.es-ES.resx @@ -0,0 +1,181 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + 55, 15 + + + 115, 17 + + + Contraseña actual: + + + 177, 12 + + + 275, 23 + + + 55, 44 + + + 116, 17 + + + Nueva contraseña: + + + 177, 41 + + + 275, 23 + + + 159, 17 + + + Repetir nueva contraseña: + + + 177, 70 + + + 275, 23 + + + 296, 107 + + + Aceptar + + + 377, 107 + + + Cancelar + + + 464, 142 + + + Cambiar contraseña + + \ No newline at end of file diff --git a/src/Neo.GUI/GUI/ChangePasswordDialog.resx b/src/Neo.GUI/GUI/ChangePasswordDialog.resx new file mode 100644 index 0000000000..89c4851043 --- /dev/null +++ b/src/Neo.GUI/GUI/ChangePasswordDialog.resx @@ -0,0 +1,369 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + True + + + + 41, 15 + + + 92, 17 + + + 0 + + + Old Password: + + + label1 + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 7 + + + + Top, Left, Right + + + 139, 12 + + + 234, 23 + + + 1 + + + textBox1 + + + System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 6 + + + True + + + NoControl + + + 36, 44 + + + 97, 17 + + + 2 + + + New Password: + + + label2 + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 5 + + + Top, Left, Right + + + 139, 41 + + + 234, 23 + + + 3 + + + textBox2 + + + System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 4 + + + True + + + NoControl + + + 12, 73 + + + 121, 17 + + + 4 + + + Re-Enter Password: + + + label3 + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 3 + + + Top, Left, Right + + + 139, 70 + + + 234, 23 + + + 5 + + + textBox3 + + + System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 2 + + + Bottom, Right + + + False + + + 217, 107 + + + 75, 23 + + + 6 + + + OK + + + button1 + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 1 + + + Bottom, Right + + + NoControl + + + 298, 107 + + + 75, 23 + + + 7 + + + Cancel + + + button2 + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 0 + + + True + + + 7, 17 + + + 385, 142 + + + Microsoft YaHei UI, 9pt + + + 2, 2, 2, 2 + + + CenterScreen + + + Change Password + + + ChangePasswordDialog + + + System.Windows.Forms.Form, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/src/Neo.GUI/GUI/ChangePasswordDialog.zh-Hans.resx b/src/Neo.GUI/GUI/ChangePasswordDialog.zh-Hans.resx new file mode 100644 index 0000000000..9ec5cb724c --- /dev/null +++ b/src/Neo.GUI/GUI/ChangePasswordDialog.zh-Hans.resx @@ -0,0 +1,172 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + 24, 15 + + + 47, 17 + + + 旧密码: + + + 77, 12 + + + 296, 23 + + + 24, 44 + + + 47, 17 + + + 新密码: + + + 77, 41 + + + 296, 23 + + + 59, 17 + + + 重复密码: + + + 77, 70 + + + 296, 23 + + + 确定 + + + 取消 + + + 修改密码 + + \ No newline at end of file diff --git a/src/Neo.GUI/GUI/ConsoleForm.Designer.cs b/src/Neo.GUI/GUI/ConsoleForm.Designer.cs new file mode 100644 index 0000000000..e3fd639db0 --- /dev/null +++ b/src/Neo.GUI/GUI/ConsoleForm.Designer.cs @@ -0,0 +1,91 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-gui is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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.GUI +{ + partial class ConsoleForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.textBox1 = new System.Windows.Forms.TextBox(); + this.textBox2 = new System.Windows.Forms.TextBox(); + this.SuspendLayout(); + // + // textBox1 + // + this.textBox1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textBox1.Location = new System.Drawing.Point(12, 12); + this.textBox1.Font = new System.Drawing.Font("Consolas", 11.0f); + this.textBox1.MaxLength = 1048576; + this.textBox1.Multiline = true; + this.textBox1.Name = "textBox1"; + this.textBox1.ReadOnly = true; + this.textBox1.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; + this.textBox1.Size = new System.Drawing.Size(609, 367); + this.textBox1.TabIndex = 1; + // + // textBox2 + // + this.textBox2.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textBox2.Location = new System.Drawing.Point(12, 385); + this.textBox2.Font = new System.Drawing.Font("Consolas", 11.0f); + this.textBox2.Name = "textBox2"; + this.textBox2.Size = new System.Drawing.Size(609, 21); + this.textBox2.TabIndex = 0; + this.textBox2.KeyDown += new System.Windows.Forms.KeyEventHandler(this.textBox2_KeyDown); + // + // ConsoleForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(633, 418); + this.Controls.Add(this.textBox2); + this.Controls.Add(this.textBox1); + this.Name = "ConsoleForm"; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; + this.Text = "Console"; + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.TextBox textBox1; + private System.Windows.Forms.TextBox textBox2; + } +} diff --git a/src/Neo.GUI/GUI/ConsoleForm.cs b/src/Neo.GUI/GUI/ConsoleForm.cs new file mode 100644 index 0000000000..55deace519 --- /dev/null +++ b/src/Neo.GUI/GUI/ConsoleForm.cs @@ -0,0 +1,67 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-gui is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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.IO; +using System.Threading; +using System.Windows.Forms; + +namespace Neo.GUI +{ + internal partial class ConsoleForm : Form + { + private Thread thread; + private readonly QueueReader queue = new QueueReader(); + + public ConsoleForm() + { + InitializeComponent(); + } + + protected override void OnHandleCreated(EventArgs e) + { + base.OnHandleCreated(e); + Console.SetOut(new TextBoxWriter(textBox1)); + Console.SetIn(queue); + thread = new Thread(Program.Service.RunConsole); + thread.Start(); + } + + protected override void OnFormClosing(FormClosingEventArgs e) + { + queue.Enqueue($"exit{Environment.NewLine}"); + thread.Join(); + Console.SetIn(new StreamReader(Console.OpenStandardInput())); + Console.SetOut(new StreamWriter(Console.OpenStandardOutput())); + base.OnFormClosing(e); + } + + private void textBox2_KeyDown(object sender, KeyEventArgs e) + { + if (e.KeyCode == Keys.Enter) + { + e.SuppressKeyPress = true; + string line = $"{textBox2.Text}{Environment.NewLine}"; + textBox1.AppendText(Program.Service.ReadingPassword ? "***" : line); + switch (textBox2.Text.ToLower()) + { + case "clear": + textBox1.Clear(); + break; + case "exit": + Close(); + return; + } + queue.Enqueue(line); + textBox2.Clear(); + } + } + } +} diff --git a/src/Neo.GUI/GUI/ConsoleForm.resx b/src/Neo.GUI/GUI/ConsoleForm.resx new file mode 100644 index 0000000000..1af7de150c --- /dev/null +++ b/src/Neo.GUI/GUI/ConsoleForm.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/src/Neo.GUI/GUI/CreateMultiSigContractDialog.Designer.cs b/src/Neo.GUI/GUI/CreateMultiSigContractDialog.Designer.cs new file mode 100644 index 0000000000..e91c25c9b7 --- /dev/null +++ b/src/Neo.GUI/GUI/CreateMultiSigContractDialog.Designer.cs @@ -0,0 +1,153 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-gui is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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.GUI +{ + partial class CreateMultiSigContractDialog + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(CreateMultiSigContractDialog)); + this.button5 = new System.Windows.Forms.Button(); + this.button4 = new System.Windows.Forms.Button(); + this.textBox5 = new System.Windows.Forms.TextBox(); + this.label7 = new System.Windows.Forms.Label(); + this.listBox1 = new System.Windows.Forms.ListBox(); + this.numericUpDown2 = new System.Windows.Forms.NumericUpDown(); + this.label6 = new System.Windows.Forms.Label(); + this.button6 = new System.Windows.Forms.Button(); + this.button1 = new System.Windows.Forms.Button(); + ((System.ComponentModel.ISupportInitialize)(this.numericUpDown2)).BeginInit(); + this.SuspendLayout(); + // + // button5 + // + resources.ApplyResources(this.button5, "button5"); + this.button5.Name = "button5"; + this.button5.UseVisualStyleBackColor = true; + this.button5.Click += new System.EventHandler(this.button5_Click); + // + // button4 + // + resources.ApplyResources(this.button4, "button4"); + this.button4.Name = "button4"; + this.button4.UseVisualStyleBackColor = true; + this.button4.Click += new System.EventHandler(this.button4_Click); + // + // textBox5 + // + resources.ApplyResources(this.textBox5, "textBox5"); + this.textBox5.Name = "textBox5"; + this.textBox5.TextChanged += new System.EventHandler(this.textBox5_TextChanged); + // + // label7 + // + resources.ApplyResources(this.label7, "label7"); + this.label7.Name = "label7"; + // + // listBox1 + // + resources.ApplyResources(this.listBox1, "listBox1"); + this.listBox1.FormattingEnabled = true; + this.listBox1.Name = "listBox1"; + this.listBox1.SelectedIndexChanged += new System.EventHandler(this.listBox1_SelectedIndexChanged); + // + // numericUpDown2 + // + resources.ApplyResources(this.numericUpDown2, "numericUpDown2"); + this.numericUpDown2.Maximum = new decimal(new int[] { + 0, + 0, + 0, + 0}); + this.numericUpDown2.Name = "numericUpDown2"; + this.numericUpDown2.ValueChanged += new System.EventHandler(this.numericUpDown2_ValueChanged); + // + // label6 + // + resources.ApplyResources(this.label6, "label6"); + this.label6.Name = "label6"; + // + // button6 + // + resources.ApplyResources(this.button6, "button6"); + this.button6.DialogResult = System.Windows.Forms.DialogResult.OK; + this.button6.Name = "button6"; + this.button6.UseVisualStyleBackColor = true; + // + // button1 + // + resources.ApplyResources(this.button1, "button1"); + this.button1.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.button1.Name = "button1"; + this.button1.UseVisualStyleBackColor = true; + // + // CreateMultiSigContractDialog + // + this.AcceptButton = this.button6; + resources.ApplyResources(this, "$this"); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.button1; + this.Controls.Add(this.button1); + this.Controls.Add(this.button6); + this.Controls.Add(this.button5); + this.Controls.Add(this.button4); + this.Controls.Add(this.textBox5); + this.Controls.Add(this.label7); + this.Controls.Add(this.listBox1); + this.Controls.Add(this.numericUpDown2); + this.Controls.Add(this.label6); + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "CreateMultiSigContractDialog"; + this.ShowInTaskbar = false; + ((System.ComponentModel.ISupportInitialize)(this.numericUpDown2)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Button button5; + private System.Windows.Forms.Button button4; + private System.Windows.Forms.TextBox textBox5; + private System.Windows.Forms.Label label7; + private System.Windows.Forms.ListBox listBox1; + private System.Windows.Forms.NumericUpDown numericUpDown2; + private System.Windows.Forms.Label label6; + private System.Windows.Forms.Button button6; + private System.Windows.Forms.Button button1; + } +} diff --git a/src/Neo.GUI/GUI/CreateMultiSigContractDialog.cs b/src/Neo.GUI/GUI/CreateMultiSigContractDialog.cs new file mode 100644 index 0000000000..b94e6c5b1f --- /dev/null +++ b/src/Neo.GUI/GUI/CreateMultiSigContractDialog.cs @@ -0,0 +1,71 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-gui is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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; +using Neo.SmartContract; +using Neo.Wallets; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Windows.Forms; +using static Neo.Program; + +namespace Neo.GUI +{ + internal partial class CreateMultiSigContractDialog : Form + { + private ECPoint[] publicKeys; + + public CreateMultiSigContractDialog() + { + InitializeComponent(); + } + + public Contract GetContract() + { + publicKeys = listBox1.Items.OfType().Select(p => ECPoint.DecodePoint(p.HexToBytes(), ECCurve.Secp256r1)).ToArray(); + return Contract.CreateMultiSigContract((int)numericUpDown2.Value, publicKeys); + } + + public KeyPair GetKey() + { + HashSet hashSet = new HashSet(publicKeys); + return Service.CurrentWallet.GetAccounts().FirstOrDefault(p => p.HasKey && hashSet.Contains(p.GetKey().PublicKey))?.GetKey(); + } + + private void numericUpDown2_ValueChanged(object sender, EventArgs e) + { + button6.Enabled = numericUpDown2.Value > 0; + } + + private void listBox1_SelectedIndexChanged(object sender, EventArgs e) + { + button5.Enabled = listBox1.SelectedIndices.Count > 0; + } + + private void textBox5_TextChanged(object sender, EventArgs e) + { + button4.Enabled = textBox5.TextLength > 0; + } + + private void button4_Click(object sender, EventArgs e) + { + listBox1.Items.Add(textBox5.Text); + textBox5.Clear(); + numericUpDown2.Maximum = listBox1.Items.Count; + } + + private void button5_Click(object sender, EventArgs e) + { + listBox1.Items.RemoveAt(listBox1.SelectedIndex); + numericUpDown2.Maximum = listBox1.Items.Count; + } + } +} diff --git a/src/Neo.GUI/GUI/CreateMultiSigContractDialog.es-ES.resx b/src/Neo.GUI/GUI/CreateMultiSigContractDialog.es-ES.resx new file mode 100644 index 0000000000..c5eefc3279 --- /dev/null +++ b/src/Neo.GUI/GUI/CreateMultiSigContractDialog.es-ES.resx @@ -0,0 +1,179 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + 573, 246 + + + 542, 246 + + + 168, 246 + + + 368, 23 + + + 147, 17 + + + Lista de claves públicas: + + + 168, 41 + + + 430, 199 + + + 168, 12 + + + 442, 275 + + + Confirmar + + + 523, 275 + + + Cancelar + + + + NoControl + + + 29, 14 + + + 133, 17 + + + Nº mínimo de firmas: + + + 610, 310 + + + Contrato con múltiples firmas + + \ No newline at end of file diff --git a/src/Neo.GUI/GUI/CreateMultiSigContractDialog.resx b/src/Neo.GUI/GUI/CreateMultiSigContractDialog.resx new file mode 100644 index 0000000000..fcd5dfc317 --- /dev/null +++ b/src/Neo.GUI/GUI/CreateMultiSigContractDialog.resx @@ -0,0 +1,399 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + False + + + + 425, 199 + + + 551, 310 + + + 114, 12 + + + button5 + + + $this + + + + 3, 4, 3, 4 + + + False + + + 514, 246 + + + True + + + System.Windows.Forms.NumericUpDown, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Windows.Forms.Form, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 12 + + + cancel + + + 5 + + + 14 + + + 12, 14 + + + button6 + + + textBox5 + + + 7, 17 + + + True + + + Min. Sig. Num.: + + + $this + + + Bottom, Right + + + 3 + + + 13 + + + Bottom, Right + + + 464, 275 + + + 114, 41 + + + 75, 23 + + + 93, 17 + + + confirm + + + $this + + + $this + + + numericUpDown2 + + + 483, 246 + + + 2 + + + System.Windows.Forms.ListBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 7 + + + 114, 246 + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 15 + + + CenterScreen + + + False + + + 363, 23 + + + label7 + + + Bottom, Right + + + 25, 23 + + + 197, 23 + + + $this + + + 1 + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 383, 275 + + + Bottom, Right + + + listBox1 + + + 7 + + + 6 + + + $this + + + 4 + + + 微软雅黑, 9pt + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Bottom, Left, Right + + + button1 + + + False + + + 15, 41 + + + System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 11 + + + $this + + + 0 + + + 8 + + + CreateMultiSigContractDialog + + + $this + + + 25, 23 + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + - + + + $this + + + button4 + + + 8 + + + True + + + 96, 17 + + + Multi-Signature + + + 10 + + + 75, 23 + + + 17 + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 9 + + + label6 + + + Top, Bottom, Left, Right + + + Public Key List: + + + True + + \ No newline at end of file diff --git a/src/Neo.GUI/GUI/CreateMultiSigContractDialog.zh-Hans.resx b/src/Neo.GUI/GUI/CreateMultiSigContractDialog.zh-Hans.resx new file mode 100644 index 0000000000..acd731d2a1 --- /dev/null +++ b/src/Neo.GUI/GUI/CreateMultiSigContractDialog.zh-Hans.resx @@ -0,0 +1,178 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + 491, 263 + + + 460, 263 + + + 99, 263 + + + 355, 23 + + + 34, 41 + + + 59, 17 + + + 公钥列表: + + + 99, 41 + + + 417, 216 + + + 99, 12 + + + 120, 23 + + + 83, 17 + + + 最小签名数量: + + + 360, 292 + + + 确定 + + + 441, 292 + + + 取消 + + + 528, 327 + + + 多方签名 + + \ No newline at end of file diff --git a/src/Neo.GUI/GUI/CreateWalletDialog.cs b/src/Neo.GUI/GUI/CreateWalletDialog.cs new file mode 100644 index 0000000000..4573dad6d4 --- /dev/null +++ b/src/Neo.GUI/GUI/CreateWalletDialog.cs @@ -0,0 +1,71 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-gui is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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.Windows.Forms; + +namespace Neo.GUI +{ + internal partial class CreateWalletDialog : Form + { + public CreateWalletDialog() + { + InitializeComponent(); + } + + public string Password + { + get + { + return textBox2.Text; + } + set + { + textBox2.Text = value; + textBox3.Text = value; + } + } + + public string WalletPath + { + get + { + return textBox1.Text; + } + set + { + textBox1.Text = value; + } + } + + private void textBox_TextChanged(object sender, EventArgs e) + { + if (textBox1.TextLength == 0 || textBox2.TextLength == 0 || textBox3.TextLength == 0) + { + button2.Enabled = false; + return; + } + if (textBox2.Text != textBox3.Text) + { + button2.Enabled = false; + return; + } + button2.Enabled = true; + } + + private void button1_Click(object sender, EventArgs e) + { + if (saveFileDialog1.ShowDialog() == DialogResult.OK) + { + textBox1.Text = saveFileDialog1.FileName; + } + } + } +} diff --git a/src/Neo.GUI/GUI/CreateWalletDialog.designer.cs b/src/Neo.GUI/GUI/CreateWalletDialog.designer.cs new file mode 100644 index 0000000000..c4f41b6573 --- /dev/null +++ b/src/Neo.GUI/GUI/CreateWalletDialog.designer.cs @@ -0,0 +1,143 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-gui is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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.GUI +{ + partial class CreateWalletDialog + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(CreateWalletDialog)); + this.label1 = new System.Windows.Forms.Label(); + this.textBox1 = new System.Windows.Forms.TextBox(); + this.button1 = new System.Windows.Forms.Button(); + this.label2 = new System.Windows.Forms.Label(); + this.textBox2 = new System.Windows.Forms.TextBox(); + this.label3 = new System.Windows.Forms.Label(); + this.textBox3 = new System.Windows.Forms.TextBox(); + this.button2 = new System.Windows.Forms.Button(); + this.saveFileDialog1 = new System.Windows.Forms.SaveFileDialog(); + this.SuspendLayout(); + // + // label1 + // + resources.ApplyResources(this.label1, "label1"); + this.label1.Name = "label1"; + // + // textBox1 + // + resources.ApplyResources(this.textBox1, "textBox1"); + this.textBox1.Name = "textBox1"; + this.textBox1.ReadOnly = true; + this.textBox1.TextChanged += new System.EventHandler(this.textBox_TextChanged); + // + // button1 + // + resources.ApplyResources(this.button1, "button1"); + this.button1.Name = "button1"; + this.button1.UseVisualStyleBackColor = true; + this.button1.Click += new System.EventHandler(this.button1_Click); + // + // label2 + // + resources.ApplyResources(this.label2, "label2"); + this.label2.Name = "label2"; + // + // textBox2 + // + resources.ApplyResources(this.textBox2, "textBox2"); + this.textBox2.Name = "textBox2"; + this.textBox2.UseSystemPasswordChar = true; + this.textBox2.TextChanged += new System.EventHandler(this.textBox_TextChanged); + // + // label3 + // + resources.ApplyResources(this.label3, "label3"); + this.label3.Name = "label3"; + // + // textBox3 + // + resources.ApplyResources(this.textBox3, "textBox3"); + this.textBox3.Name = "textBox3"; + this.textBox3.UseSystemPasswordChar = true; + this.textBox3.TextChanged += new System.EventHandler(this.textBox_TextChanged); + // + // button2 + // + resources.ApplyResources(this.button2, "button2"); + this.button2.DialogResult = System.Windows.Forms.DialogResult.OK; + this.button2.Name = "button2"; + this.button2.UseVisualStyleBackColor = true; + // + // saveFileDialog1 + // + this.saveFileDialog1.DefaultExt = "json"; + resources.ApplyResources(this.saveFileDialog1, "saveFileDialog1"); + // + // CreateWalletDialog + // + this.AcceptButton = this.button2; + resources.ApplyResources(this, "$this"); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.button2); + this.Controls.Add(this.textBox3); + this.Controls.Add(this.label3); + this.Controls.Add(this.textBox2); + this.Controls.Add(this.label2); + this.Controls.Add(this.button1); + this.Controls.Add(this.textBox1); + this.Controls.Add(this.label1); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "CreateWalletDialog"; + this.ShowInTaskbar = false; + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Label label1; + private System.Windows.Forms.TextBox textBox1; + private System.Windows.Forms.Button button1; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.TextBox textBox2; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.TextBox textBox3; + private System.Windows.Forms.Button button2; + private System.Windows.Forms.SaveFileDialog saveFileDialog1; + } +} diff --git a/src/Neo.GUI/GUI/CreateWalletDialog.es-ES.resx b/src/Neo.GUI/GUI/CreateWalletDialog.es-ES.resx new file mode 100644 index 0000000000..09d7d9f325 --- /dev/null +++ b/src/Neo.GUI/GUI/CreateWalletDialog.es-ES.resx @@ -0,0 +1,169 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + 9, 16 + + + 137, 17 + + + Fichero de monedero: + + + 152, 13 + + + 293, 23 + + + Buscar... + + + 69, 51 + + + 77, 17 + + + Contraseña: + + + 152, 48 + + + 25, 84 + + + 121, 17 + + + Repetir contraseña: + + + 152, 81 + + + Confirmar + + + Nuevo monedero + + \ No newline at end of file diff --git a/src/Neo.GUI/GUI/CreateWalletDialog.resx b/src/Neo.GUI/GUI/CreateWalletDialog.resx new file mode 100644 index 0000000000..bfe06e458d --- /dev/null +++ b/src/Neo.GUI/GUI/CreateWalletDialog.resx @@ -0,0 +1,363 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + confirm + + + Wallet File: + + + Wallet File|*.json + + + $this + + + 5 + + + + 150, 23 + + + browse + + + label1 + + + System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 3 + + + 87, 17 + + + $this + + + 7, 17 + + + 0 + + + label3 + + + + True + + + + Top, Right + + + 105, 48 + + + CenterScreen + + + $this + + + 12, 84 + + + 7 + + + $this + + + 75, 23 + + + 0 + + + 5 + + + 70, 17 + + + 340, 23 + + + 6 + + + 105, 13 + + + 9 + + + 6 + + + saveFileDialog1 + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 451, 12 + + + 4 + + + 67, 17 + + + $this + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + textBox1 + + + 2 + + + System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 微软雅黑, 9pt + + + Re-Password: + + + 8 + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + button1 + + + True + + + 451, 86 + + + True + + + System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + label2 + + + 1 + + + System.Windows.Forms.Form, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 1 + + + Top, Left, Right + + + Bottom, Right + + + 29, 16 + + + New Wallet + + + Password: + + + 7 + + + System.Windows.Forms.SaveFileDialog, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 32, 51 + + + button2 + + + textBox3 + + + $this + + + 150, 23 + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 105, 81 + + + 538, 121 + + + 75, 23 + + + CreateWalletDialog + + + textBox2 + + + 2 + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + False + + + True + + + 17, 17 + + \ No newline at end of file diff --git a/src/Neo.GUI/GUI/CreateWalletDialog.zh-Hans.resx b/src/Neo.GUI/GUI/CreateWalletDialog.zh-Hans.resx new file mode 100644 index 0000000000..ae934ad543 --- /dev/null +++ b/src/Neo.GUI/GUI/CreateWalletDialog.zh-Hans.resx @@ -0,0 +1,181 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + 12, 15 + + + 83, 17 + + + 钱包文件位置: + + + 101, 12 + + + 289, 23 + + + 396, 12 + + + 浏览 + + + 60, 44 + + + 35, 17 + + + 密码: + + + 101, 41 + + + 36, 73 + + + 59, 17 + + + 重复密码: + + + 101, 70 + + + 396, 70 + + + 确定 + + + 钱包文件|*.json + + + 483, 105 + + + 新建钱包 + + \ No newline at end of file diff --git a/src/Neo.GUI/GUI/DeployContractDialog.Designer.cs b/src/Neo.GUI/GUI/DeployContractDialog.Designer.cs new file mode 100644 index 0000000000..629b5e96dd --- /dev/null +++ b/src/Neo.GUI/GUI/DeployContractDialog.Designer.cs @@ -0,0 +1,308 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-gui is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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.GUI +{ + partial class DeployContractDialog + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(DeployContractDialog)); + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.textBox5 = new System.Windows.Forms.TextBox(); + this.label5 = new System.Windows.Forms.Label(); + this.textBox4 = new System.Windows.Forms.TextBox(); + this.label4 = new System.Windows.Forms.Label(); + this.textBox3 = new System.Windows.Forms.TextBox(); + this.label3 = new System.Windows.Forms.Label(); + this.textBox2 = new System.Windows.Forms.TextBox(); + this.label2 = new System.Windows.Forms.Label(); + this.textBox1 = new System.Windows.Forms.TextBox(); + this.label1 = new System.Windows.Forms.Label(); + this.groupBox2 = new System.Windows.Forms.GroupBox(); + this.textBox7 = new System.Windows.Forms.TextBox(); + this.label7 = new System.Windows.Forms.Label(); + this.textBox6 = new System.Windows.Forms.TextBox(); + this.label6 = new System.Windows.Forms.Label(); + this.groupBox3 = new System.Windows.Forms.GroupBox(); + this.textBox9 = new System.Windows.Forms.TextBox(); + this.button1 = new System.Windows.Forms.Button(); + this.checkBox1 = new System.Windows.Forms.CheckBox(); + this.textBox8 = new System.Windows.Forms.TextBox(); + this.button2 = new System.Windows.Forms.Button(); + this.button3 = new System.Windows.Forms.Button(); + this.openFileDialog1 = new System.Windows.Forms.OpenFileDialog(); + this.checkBox2 = new System.Windows.Forms.CheckBox(); + this.checkBox3 = new System.Windows.Forms.CheckBox(); + this.label8 = new System.Windows.Forms.Label(); + this.groupBox1.SuspendLayout(); + this.groupBox2.SuspendLayout(); + this.groupBox3.SuspendLayout(); + this.SuspendLayout(); + // + // groupBox1 + // + resources.ApplyResources(this.groupBox1, "groupBox1"); + this.groupBox1.Controls.Add(this.textBox5); + this.groupBox1.Controls.Add(this.label5); + this.groupBox1.Controls.Add(this.textBox4); + this.groupBox1.Controls.Add(this.label4); + this.groupBox1.Controls.Add(this.textBox3); + this.groupBox1.Controls.Add(this.label3); + this.groupBox1.Controls.Add(this.textBox2); + this.groupBox1.Controls.Add(this.label2); + this.groupBox1.Controls.Add(this.textBox1); + this.groupBox1.Controls.Add(this.label1); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.TabStop = false; + // + // textBox5 + // + resources.ApplyResources(this.textBox5, "textBox5"); + this.textBox5.AcceptsReturn = true; + this.textBox5.AcceptsTab = true; + this.textBox5.Name = "textBox5"; + this.textBox5.TextChanged += new System.EventHandler(this.textBox_TextChanged); + // + // label5 + // + resources.ApplyResources(this.label5, "label5"); + this.label5.Name = "label5"; + // + // textBox4 + // + resources.ApplyResources(this.textBox4, "textBox4"); + this.textBox4.Name = "textBox4"; + this.textBox4.TextChanged += new System.EventHandler(this.textBox_TextChanged); + // + // label4 + // + resources.ApplyResources(this.label4, "label4"); + this.label4.Name = "label4"; + // + // textBox3 + // + resources.ApplyResources(this.textBox3, "textBox3"); + this.textBox3.Name = "textBox3"; + this.textBox3.TextChanged += new System.EventHandler(this.textBox_TextChanged); + // + // label3 + // + resources.ApplyResources(this.label3, "label3"); + this.label3.Name = "label3"; + // + // textBox2 + // + resources.ApplyResources(this.textBox2, "textBox2"); + this.textBox2.Name = "textBox2"; + this.textBox2.TextChanged += new System.EventHandler(this.textBox_TextChanged); + // + // label2 + // + resources.ApplyResources(this.label2, "label2"); + this.label2.Name = "label2"; + // + // textBox1 + // + resources.ApplyResources(this.textBox1, "textBox1"); + this.textBox1.Name = "textBox1"; + this.textBox1.TextChanged += new System.EventHandler(this.textBox_TextChanged); + // + // label1 + // + resources.ApplyResources(this.label1, "label1"); + this.label1.Name = "label1"; + // + // groupBox2 + // + resources.ApplyResources(this.groupBox2, "groupBox2"); + this.groupBox2.Controls.Add(this.textBox7); + this.groupBox2.Controls.Add(this.label7); + this.groupBox2.Controls.Add(this.textBox6); + this.groupBox2.Controls.Add(this.label6); + this.groupBox2.Name = "groupBox2"; + this.groupBox2.TabStop = false; + // + // textBox7 + // + resources.ApplyResources(this.textBox7, "textBox7"); + this.textBox7.Name = "textBox7"; + // + // label7 + // + resources.ApplyResources(this.label7, "label7"); + this.label7.Name = "label7"; + // + // textBox6 + // + resources.ApplyResources(this.textBox6, "textBox6"); + this.textBox6.Name = "textBox6"; + // + // label6 + // + resources.ApplyResources(this.label6, "label6"); + this.label6.Name = "label6"; + // + // groupBox3 + // + resources.ApplyResources(this.groupBox3, "groupBox3"); + this.groupBox3.Controls.Add(this.label8); + this.groupBox3.Controls.Add(this.checkBox2); + this.groupBox3.Controls.Add(this.checkBox3); + this.groupBox3.Controls.Add(this.textBox9); + this.groupBox3.Controls.Add(this.button1); + this.groupBox3.Controls.Add(this.checkBox1); + this.groupBox3.Controls.Add(this.textBox8); + this.groupBox3.Name = "groupBox3"; + this.groupBox3.TabStop = false; + // + // textBox9 + // + resources.ApplyResources(this.textBox9, "textBox9"); + this.textBox9.BorderStyle = System.Windows.Forms.BorderStyle.None; + this.textBox9.Name = "textBox9"; + this.textBox9.ReadOnly = true; + // + // button1 + // + resources.ApplyResources(this.button1, "button1"); + this.button1.Name = "button1"; + this.button1.UseVisualStyleBackColor = true; + this.button1.Click += new System.EventHandler(this.button1_Click); + // + // checkBox1 + // + resources.ApplyResources(this.checkBox1, "checkBox1"); + this.checkBox1.Name = "checkBox1"; + this.checkBox1.UseVisualStyleBackColor = true; + // + // textBox8 + // + resources.ApplyResources(this.textBox8, "textBox8"); + this.textBox8.Name = "textBox8"; + this.textBox8.TextChanged += new System.EventHandler(this.textBox_TextChanged); + // + // button2 + // + resources.ApplyResources(this.button2, "button2"); + this.button2.DialogResult = System.Windows.Forms.DialogResult.OK; + this.button2.Name = "button2"; + this.button2.UseVisualStyleBackColor = true; + // + // button3 + // + resources.ApplyResources(this.button3, "button3"); + this.button3.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.button3.Name = "button3"; + this.button3.UseVisualStyleBackColor = true; + // + // openFileDialog1 + // + resources.ApplyResources(this.openFileDialog1, "openFileDialog1"); + this.openFileDialog1.DefaultExt = "avm"; + // + // checkBox2 + // + resources.ApplyResources(this.checkBox2, "checkBox2"); + this.checkBox2.Name = "checkBox2"; + this.checkBox2.UseVisualStyleBackColor = true; + // + // checkBox3 + // + resources.ApplyResources(this.checkBox3, "checkBox3"); + this.checkBox3.Name = "checkBox3"; + this.checkBox3.UseVisualStyleBackColor = true; + // + // label8 + // + resources.ApplyResources(this.label8, "label8"); + this.label8.Name = "label8"; + // + // DeployContractDialog + // + resources.ApplyResources(this, "$this"); + this.AcceptButton = this.button2; + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.button3; + this.Controls.Add(this.groupBox1); + this.Controls.Add(this.groupBox2); + this.Controls.Add(this.groupBox3); + this.Controls.Add(this.button3); + this.Controls.Add(this.button2); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "DeployContractDialog"; + this.ShowInTaskbar = false; + this.groupBox1.ResumeLayout(false); + this.groupBox1.PerformLayout(); + this.groupBox2.ResumeLayout(false); + this.groupBox2.PerformLayout(); + this.groupBox3.ResumeLayout(false); + this.groupBox3.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.GroupBox groupBox1; + private System.Windows.Forms.TextBox textBox1; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.TextBox textBox2; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.TextBox textBox3; + private System.Windows.Forms.TextBox textBox4; + private System.Windows.Forms.Label label4; + private System.Windows.Forms.Label label5; + private System.Windows.Forms.TextBox textBox5; + private System.Windows.Forms.GroupBox groupBox2; + private System.Windows.Forms.Label label6; + private System.Windows.Forms.TextBox textBox6; + private System.Windows.Forms.Label label7; + private System.Windows.Forms.TextBox textBox7; + private System.Windows.Forms.GroupBox groupBox3; + private System.Windows.Forms.TextBox textBox8; + private System.Windows.Forms.CheckBox checkBox1; + private System.Windows.Forms.Button button1; + private System.Windows.Forms.Button button2; + private System.Windows.Forms.Button button3; + private System.Windows.Forms.OpenFileDialog openFileDialog1; + private System.Windows.Forms.TextBox textBox9; + private System.Windows.Forms.CheckBox checkBox2; + private System.Windows.Forms.Label label8; + private System.Windows.Forms.CheckBox checkBox3; + } +} diff --git a/src/Neo.GUI/GUI/DeployContractDialog.cs b/src/Neo.GUI/GUI/DeployContractDialog.cs new file mode 100644 index 0000000000..aa415ddd90 --- /dev/null +++ b/src/Neo.GUI/GUI/DeployContractDialog.cs @@ -0,0 +1,60 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-gui is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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.Native; +using Neo.VM; +using System; +using System.IO; +using System.Windows.Forms; + +namespace Neo.GUI +{ + internal partial class DeployContractDialog : Form + { + public DeployContractDialog() + { + InitializeComponent(); + } + + public byte[] GetScript() + { + byte[] script = textBox8.Text.HexToBytes(); + string manifest = ""; + using ScriptBuilder sb = new ScriptBuilder(); + sb.EmitDynamicCall(NativeContract.ContractManagement.Hash, "deploy", script, manifest); + return sb.ToArray(); + } + + private void textBox_TextChanged(object sender, EventArgs e) + { + button2.Enabled = textBox1.TextLength > 0 + && textBox2.TextLength > 0 + && textBox3.TextLength > 0 + && textBox4.TextLength > 0 + && textBox5.TextLength > 0 + && textBox8.TextLength > 0; + try + { + textBox9.Text = textBox8.Text.HexToBytes().ToScriptHash().ToString(); + } + catch (FormatException) + { + textBox9.Text = ""; + } + } + + private void button1_Click(object sender, EventArgs e) + { + if (openFileDialog1.ShowDialog() != DialogResult.OK) return; + textBox8.Text = File.ReadAllBytes(openFileDialog1.FileName).ToHexString(); + } + } +} diff --git a/src/Neo.GUI/GUI/DeployContractDialog.es-ES.resx b/src/Neo.GUI/GUI/DeployContractDialog.es-ES.resx new file mode 100644 index 0000000000..7bd4a2e05b --- /dev/null +++ b/src/Neo.GUI/GUI/DeployContractDialog.es-ES.resx @@ -0,0 +1,217 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + 3, 141 + + + 79, 17 + + + Descripción: + + + 31, 112 + + + 52, 17 + + + Correo: + + + 40, 83 + + + 43, 17 + + + Autor: + + + Versión: + + + 23, 25 + + + 60, 17 + + + Nombre: + + + 140, 51 + + + 374, 23 + + + 43, 54 + + + 91, 17 + + + Tipo devuelto: + + + 140, 22 + + + 374, 23 + + + 128, 17 + + + Lista de parámetros: + + + Metadatos + + + Cargar + + + 199, 21 + + + Es necesario almacenamiento + + + Código + + + 368, 530 + + + 83, 23 + + + Desplegar + + + Cancelar + + + Desplegar contrato + + \ No newline at end of file diff --git a/src/Neo.GUI/GUI/DeployContractDialog.resx b/src/Neo.GUI/GUI/DeployContractDialog.resx new file mode 100644 index 0000000000..16bd3de8c2 --- /dev/null +++ b/src/Neo.GUI/GUI/DeployContractDialog.resx @@ -0,0 +1,972 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + Top, Left, Right + + + Top, Bottom, Left, Right + + + + 114, 163 + + + 4, 4, 4, 4 + + + + True + + + Vertical + + + 545, 99 + + + 9 + + + textBox5 + + + System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + groupBox1 + + + 0 + + + True + + + NoControl + + + 8, 165 + + + 4, 0, 4, 0 + + + 97, 20 + + + 8 + + + Description: + + + label5 + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + groupBox1 + + + 1 + + + Top, Left, Right + + + 114, 128 + + + 4, 4, 4, 4 + + + 545, 27 + + + 7 + + + textBox4 + + + System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + groupBox1 + + + 2 + + + True + + + NoControl + + + 53, 132 + + + 4, 0, 4, 0 + + + 51, 20 + + + 6 + + + Email: + + + label4 + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + groupBox1 + + + 3 + + + Top, Left, Right + + + 114, 95 + + + 4, 4, 4, 4 + + + 545, 27 + + + 5 + + + textBox3 + + + System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + groupBox1 + + + 4 + + + True + + + NoControl + + + 42, 97 + + + 4, 0, 4, 0 + + + 64, 20 + + + 4 + + + Author: + + + label3 + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + groupBox1 + + + 5 + + + Top, Left, Right + + + 114, 60 + + + 4, 4, 4, 4 + + + 545, 27 + + + 3 + + + textBox2 + + + System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + groupBox1 + + + 6 + + + True + + + NoControl + + + 36, 64 + + + 4, 0, 4, 0 + + + 68, 20 + + + 2 + + + Version: + + + label2 + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + groupBox1 + + + 7 + + + Top, Left, Right + + + 114, 25 + + + 4, 4, 4, 4 + + + 545, 27 + + + 1 + + + textBox1 + + + System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + groupBox1 + + + 8 + + + True + + + 42, 29 + + + 4, 0, 4, 0 + + + 56, 20 + + + 0 + + + Name: + + + label1 + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + groupBox1 + + + 9 + + + 15, 15 + + + 4, 4, 4, 4 + + + 4, 4, 4, 4 + + + 669, 268 + + + 0 + + + Information + + + groupBox1 + + + System.Windows.Forms.GroupBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 0 + + + 15, 289 + + + 4, 4, 4, 4 + + + 4, 4, 4, 4 + + + 669, 97 + + + 1 + + + Metadata + + + groupBox2 + + + System.Windows.Forms.GroupBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 1 + + + Top, Left, Right + + + 136, 60 + + + 4, 4, 4, 4 + + + 523, 27 + + + 3 + + + textBox7 + + + System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + groupBox2 + + + 0 + + + True + + + NoControl + + + 24, 64 + + + 4, 0, 4, 0 + + + 102, 20 + + + 2 + + + Return Type: + + + label7 + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + groupBox2 + + + 1 + + + Top, Left, Right + + + 136, 25 + + + 4, 4, 4, 4 + + + 523, 27 + + + 1 + + + textBox6 + + + System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + groupBox2 + + + 2 + + + True + + + 8, 29 + + + 4, 0, 4, 0 + + + 117, 20 + + + 0 + + + Parameter List: + + + label6 + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + groupBox2 + + + 3 + + + Top, Bottom, Left, Right + + + Bottom, Left + + + True + + + NoControl + + + 357, 189 + + + 4, 4, 4, 4 + + + 87, 24 + + + 3 + + + Payable + + + checkBox3 + + + System.Windows.Forms.CheckBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + groupBox3 + + + 0 + + + True + + + NoControl + + + 9, 162 + + + 4, 0, 4, 0 + + + 96, 20 + + + 3 + + + Script Hash: + + + label8 + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + groupBox3 + + + 1 + + + Bottom, Left + + + True + + + NoControl + + + 180, 189 + + + 4, 4, 4, 4 + + + 127, 24 + + + 2 + + + Need Dyncall + + + checkBox2 + + + System.Windows.Forms.CheckBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + groupBox3 + + + 2 + + + Bottom, Left + + + 112, 162 + + + 4, 4, 4, 4 + + + 401, 20 + + + 4 + + + textBox9 + + + System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + groupBox3 + + + 3 + + + Bottom, Right + + + 564, 188 + + + 4, 4, 4, 4 + + + 96, 27 + + + 4 + + + Load + + + button1 + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + groupBox3 + + + 4 + + + Bottom, Left + + + True + + + 8, 189 + + + 4, 4, 4, 4 + + + 133, 24 + + + 1 + + + Need Storage + + + checkBox1 + + + System.Windows.Forms.CheckBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + groupBox3 + + + 5 + + + Top, Bottom, Left, Right + + + 8, 25 + + + 4, 4, 4, 4 + + + True + + + Vertical + + + 652, 155 + + + 0 + + + textBox8 + + + System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + groupBox3 + + + 6 + + + 15, 395 + + + 4, 4, 4, 4 + + + 4, 4, 4, 4 + + + 669, 223 + + + 2 + + + Code + + + groupBox3 + + + System.Windows.Forms.GroupBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 2 + + + Bottom, Right + + + False + + + 483, 624 + + + 4, 4, 4, 4 + + + 96, 27 + + + 3 + + + Deploy + + + button2 + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 4 + + + Bottom, Right + + + NoControl + + + 588, 624 + + + 4, 4, 4, 4 + + + 96, 27 + + + 4 + + + Cancel + + + button3 + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 3 + + + 17, 17 + + + AVM File|*.avm + + + True + + + 9, 20 + + + 699, 665 + + + Microsoft YaHei, 9pt + + + 4, 5, 4, 5 + + + CenterScreen + + + Deploy Contract + + + openFileDialog1 + + + System.Windows.Forms.OpenFileDialog, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + DeployContractDialog + + + System.Windows.Forms.Form, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + diff --git a/src/Neo.GUI/GUI/DeployContractDialog.zh-Hans.resx b/src/Neo.GUI/GUI/DeployContractDialog.zh-Hans.resx new file mode 100644 index 0000000000..ae91b44198 --- /dev/null +++ b/src/Neo.GUI/GUI/DeployContractDialog.zh-Hans.resx @@ -0,0 +1,259 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + 70, 122 + + + 444, 75 + + + 30, 125 + + + 34, 15 + + + 说明: + + + 70, 96 + + + 444, 23 + + + 6, 99 + + + 58, 15 + + + 电子邮件: + + + 70, 71 + + + 444, 23 + + + 30, 74 + + + 34, 15 + + + 作者: + + + 70, 45 + + + 444, 23 + + + 30, 48 + + + 34, 15 + + + 版本: + + + 70, 19 + + + 444, 23 + + + 30, 22 + + + 34, 15 + + + 名称: + + + 信息 + + + 70, 45 + + + 444, 23 + + + 18, 48 + + + 46, 15 + + + 返回值: + + + 70, 19 + + + 444, 23 + + + 58, 15 + + + 参数列表: + + + 元数据 + + + 98, 19 + + + 需要动态调用 + + + 加载 + + + 110, 19 + + + 需要创建存储区 + + + 代码 + + + 部署 + + + 取消 + + + AVM文件|*.avm + + + 部署合约 + + \ No newline at end of file diff --git a/src/Neo.GUI/GUI/DeveloperToolsForm.ContractParameters.cs b/src/Neo.GUI/GUI/DeveloperToolsForm.ContractParameters.cs new file mode 100644 index 0000000000..8fc35b7b88 --- /dev/null +++ b/src/Neo.GUI/GUI/DeveloperToolsForm.ContractParameters.cs @@ -0,0 +1,117 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-gui is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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.Network.P2P.Payloads; +using Neo.Properties; +using Neo.SmartContract; +using Neo.Wallets; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Windows.Forms; +using static Neo.Program; + +namespace Neo.GUI +{ + partial class DeveloperToolsForm + { + private ContractParametersContext context; + + private void listBox1_SelectedIndexChanged(object sender, EventArgs e) + { + if (listBox1.SelectedIndex < 0) return; + listBox2.Items.Clear(); + if (Service.CurrentWallet == null) return; + UInt160 hash = ((string)listBox1.SelectedItem).ToScriptHash(Service.NeoSystem.Settings.AddressVersion); + var parameters = context.GetParameters(hash); + if (parameters == null) + { + var parameterList = Service.CurrentWallet.GetAccount(hash).Contract.ParameterList; + if (parameterList != null) + { + var pList = new List(); + for (int i = 0; i < parameterList.Length; i++) + { + pList.Add(new ContractParameter(parameterList[i])); + context.Add(Service.CurrentWallet.GetAccount(hash).Contract, i, null); + } + } + } + listBox2.Items.AddRange(context.GetParameters(hash).ToArray()); + button4.Visible = context.Completed; + } + + private void listBox2_SelectedIndexChanged(object sender, EventArgs e) + { + if (listBox2.SelectedIndex < 0) return; + textBox1.Text = listBox2.SelectedItem.ToString(); + textBox2.Clear(); + } + + private void button1_Click(object sender, EventArgs e) + { + string input = InputBox.Show("ParametersContext", "ParametersContext"); + if (string.IsNullOrEmpty(input)) return; + try + { + context = ContractParametersContext.Parse(input, Service.NeoSystem.StoreView); + } + catch (FormatException ex) + { + MessageBox.Show(ex.Message); + return; + } + listBox1.Items.Clear(); + listBox2.Items.Clear(); + textBox1.Clear(); + textBox2.Clear(); + listBox1.Items.AddRange(context.ScriptHashes.Select(p => p.ToAddress(Service.NeoSystem.Settings.AddressVersion)).ToArray()); + button2.Enabled = true; + button4.Visible = context.Completed; + } + + private void button2_Click(object sender, EventArgs e) + { + InformationBox.Show(context.ToString(), "ParametersContext", "ParametersContext"); + } + + private void button3_Click(object sender, EventArgs e) + { + if (listBox1.SelectedIndex < 0) return; + if (listBox2.SelectedIndex < 0) return; + ContractParameter parameter = (ContractParameter)listBox2.SelectedItem; + parameter.SetValue(textBox2.Text); + listBox2.Items[listBox2.SelectedIndex] = parameter; + textBox1.Text = textBox2.Text; + button4.Visible = context.Completed; + } + + private void button4_Click(object sender, EventArgs e) + { + if (!(context.Verifiable is Transaction tx)) + { + MessageBox.Show("Only support to broadcast transaction."); + return; + } + tx.Witnesses = context.GetWitnesses(); + Blockchain.RelayResult reason = Service.NeoSystem.Blockchain.Ask(tx).Result; + if (reason.Result == VerifyResult.Succeed) + { + InformationBox.Show(tx.Hash.ToString(), Strings.RelaySuccessText, Strings.RelaySuccessTitle); + } + else + { + MessageBox.Show($"Transaction cannot be broadcast: {reason}"); + } + } + } +} diff --git a/src/Neo.GUI/GUI/DeveloperToolsForm.Designer.cs b/src/Neo.GUI/GUI/DeveloperToolsForm.Designer.cs new file mode 100644 index 0000000000..31faf836d9 --- /dev/null +++ b/src/Neo.GUI/GUI/DeveloperToolsForm.Designer.cs @@ -0,0 +1,259 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-gui is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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.GUI +{ + partial class DeveloperToolsForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(DeveloperToolsForm)); + this.splitContainer1 = new System.Windows.Forms.SplitContainer(); + this.propertyGrid1 = new System.Windows.Forms.PropertyGrid(); + this.button8 = new System.Windows.Forms.Button(); + this.tabControl1 = new System.Windows.Forms.TabControl(); + this.tabPage1 = new System.Windows.Forms.TabPage(); + this.tabPage2 = new System.Windows.Forms.TabPage(); + this.button4 = new System.Windows.Forms.Button(); + this.button3 = new System.Windows.Forms.Button(); + this.button2 = new System.Windows.Forms.Button(); + this.button1 = new System.Windows.Forms.Button(); + this.groupBox4 = new System.Windows.Forms.GroupBox(); + this.textBox2 = new System.Windows.Forms.TextBox(); + this.groupBox3 = new System.Windows.Forms.GroupBox(); + this.textBox1 = new System.Windows.Forms.TextBox(); + this.groupBox2 = new System.Windows.Forms.GroupBox(); + this.listBox2 = new System.Windows.Forms.ListBox(); + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.listBox1 = new System.Windows.Forms.ListBox(); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit(); + this.splitContainer1.Panel1.SuspendLayout(); + this.splitContainer1.Panel2.SuspendLayout(); + this.splitContainer1.SuspendLayout(); + this.tabControl1.SuspendLayout(); + this.tabPage1.SuspendLayout(); + this.tabPage2.SuspendLayout(); + this.groupBox4.SuspendLayout(); + this.groupBox3.SuspendLayout(); + this.groupBox2.SuspendLayout(); + this.groupBox1.SuspendLayout(); + this.SuspendLayout(); + // + // splitContainer1 + // + resources.ApplyResources(this.splitContainer1, "splitContainer1"); + this.splitContainer1.FixedPanel = System.Windows.Forms.FixedPanel.Panel2; + this.splitContainer1.Name = "splitContainer1"; + // + // splitContainer1.Panel1 + // + resources.ApplyResources(this.splitContainer1.Panel1, "splitContainer1.Panel1"); + this.splitContainer1.Panel1.Controls.Add(this.propertyGrid1); + // + // splitContainer1.Panel2 + // + resources.ApplyResources(this.splitContainer1.Panel2, "splitContainer1.Panel2"); + this.splitContainer1.Panel2.Controls.Add(this.button8); + // + // propertyGrid1 + // + resources.ApplyResources(this.propertyGrid1, "propertyGrid1"); + this.propertyGrid1.Name = "propertyGrid1"; + this.propertyGrid1.SelectedObjectsChanged += new System.EventHandler(this.propertyGrid1_SelectedObjectsChanged); + // + // button8 + // + resources.ApplyResources(this.button8, "button8"); + this.button8.Name = "button8"; + this.button8.UseVisualStyleBackColor = true; + this.button8.Click += new System.EventHandler(this.button8_Click); + // + // tabControl1 + // + resources.ApplyResources(this.tabControl1, "tabControl1"); + this.tabControl1.Controls.Add(this.tabPage1); + this.tabControl1.Controls.Add(this.tabPage2); + this.tabControl1.Name = "tabControl1"; + this.tabControl1.SelectedIndex = 0; + // + // tabPage1 + // + resources.ApplyResources(this.tabPage1, "tabPage1"); + this.tabPage1.Controls.Add(this.splitContainer1); + this.tabPage1.Name = "tabPage1"; + this.tabPage1.UseVisualStyleBackColor = true; + // + // tabPage2 + // + resources.ApplyResources(this.tabPage2, "tabPage2"); + this.tabPage2.Controls.Add(this.button4); + this.tabPage2.Controls.Add(this.button3); + this.tabPage2.Controls.Add(this.button2); + this.tabPage2.Controls.Add(this.button1); + this.tabPage2.Controls.Add(this.groupBox4); + this.tabPage2.Controls.Add(this.groupBox3); + this.tabPage2.Controls.Add(this.groupBox2); + this.tabPage2.Controls.Add(this.groupBox1); + this.tabPage2.Name = "tabPage2"; + this.tabPage2.UseVisualStyleBackColor = true; + // + // button4 + // + resources.ApplyResources(this.button4, "button4"); + this.button4.Name = "button4"; + this.button4.UseVisualStyleBackColor = true; + this.button4.Click += new System.EventHandler(this.button4_Click); + // + // button3 + // + resources.ApplyResources(this.button3, "button3"); + this.button3.Name = "button3"; + this.button3.UseVisualStyleBackColor = true; + this.button3.Click += new System.EventHandler(this.button3_Click); + // + // button2 + // + resources.ApplyResources(this.button2, "button2"); + this.button2.Name = "button2"; + this.button2.UseVisualStyleBackColor = true; + this.button2.Click += new System.EventHandler(this.button2_Click); + // + // button1 + // + resources.ApplyResources(this.button1, "button1"); + this.button1.Name = "button1"; + this.button1.UseVisualStyleBackColor = true; + this.button1.Click += new System.EventHandler(this.button1_Click); + // + // groupBox4 + // + resources.ApplyResources(this.groupBox4, "groupBox4"); + this.groupBox4.Controls.Add(this.textBox2); + this.groupBox4.Name = "groupBox4"; + this.groupBox4.TabStop = false; + // + // textBox2 + // + resources.ApplyResources(this.textBox2, "textBox2"); + this.textBox2.Name = "textBox2"; + // + // groupBox3 + // + resources.ApplyResources(this.groupBox3, "groupBox3"); + this.groupBox3.Controls.Add(this.textBox1); + this.groupBox3.Name = "groupBox3"; + this.groupBox3.TabStop = false; + // + // textBox1 + // + resources.ApplyResources(this.textBox1, "textBox1"); + this.textBox1.Name = "textBox1"; + this.textBox1.ReadOnly = true; + // + // groupBox2 + // + resources.ApplyResources(this.groupBox2, "groupBox2"); + this.groupBox2.Controls.Add(this.listBox2); + this.groupBox2.Name = "groupBox2"; + this.groupBox2.TabStop = false; + // + // listBox2 + // + resources.ApplyResources(this.listBox2, "listBox2"); + this.listBox2.FormattingEnabled = true; + this.listBox2.Name = "listBox2"; + this.listBox2.SelectedIndexChanged += new System.EventHandler(this.listBox2_SelectedIndexChanged); + // + // groupBox1 + // + resources.ApplyResources(this.groupBox1, "groupBox1"); + this.groupBox1.Controls.Add(this.listBox1); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.TabStop = false; + // + // listBox1 + // + resources.ApplyResources(this.listBox1, "listBox1"); + this.listBox1.FormattingEnabled = true; + this.listBox1.Name = "listBox1"; + this.listBox1.SelectedIndexChanged += new System.EventHandler(this.listBox1_SelectedIndexChanged); + // + // DeveloperToolsForm + // + resources.ApplyResources(this, "$this"); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.tabControl1); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; + this.KeyPreview = true; + this.MaximizeBox = false; + this.Name = "DeveloperToolsForm"; + this.splitContainer1.Panel1.ResumeLayout(false); + this.splitContainer1.Panel2.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit(); + this.splitContainer1.ResumeLayout(false); + this.tabControl1.ResumeLayout(false); + this.tabPage1.ResumeLayout(false); + this.tabPage2.ResumeLayout(false); + this.groupBox4.ResumeLayout(false); + this.groupBox4.PerformLayout(); + this.groupBox3.ResumeLayout(false); + this.groupBox3.PerformLayout(); + this.groupBox2.ResumeLayout(false); + this.groupBox1.ResumeLayout(false); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.TabControl tabControl1; + private System.Windows.Forms.TabPage tabPage2; + private System.Windows.Forms.GroupBox groupBox1; + private System.Windows.Forms.GroupBox groupBox3; + private System.Windows.Forms.GroupBox groupBox2; + private System.Windows.Forms.ListBox listBox1; + private System.Windows.Forms.ListBox listBox2; + private System.Windows.Forms.GroupBox groupBox4; + private System.Windows.Forms.TextBox textBox2; + private System.Windows.Forms.TextBox textBox1; + private System.Windows.Forms.Button button1; + private System.Windows.Forms.Button button3; + private System.Windows.Forms.Button button2; + private System.Windows.Forms.Button button4; + private System.Windows.Forms.TabPage tabPage1; + private System.Windows.Forms.SplitContainer splitContainer1; + private System.Windows.Forms.PropertyGrid propertyGrid1; + private System.Windows.Forms.Button button8; + } +} diff --git a/src/Neo.GUI/GUI/DeveloperToolsForm.TxBuilder.cs b/src/Neo.GUI/GUI/DeveloperToolsForm.TxBuilder.cs new file mode 100644 index 0000000000..eabb5812b6 --- /dev/null +++ b/src/Neo.GUI/GUI/DeveloperToolsForm.TxBuilder.cs @@ -0,0 +1,36 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-gui is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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.GUI.Wrappers; +using Neo.SmartContract; +using System; + +namespace Neo.GUI +{ + partial class DeveloperToolsForm + { + private void InitializeTxBuilder() + { + propertyGrid1.SelectedObject = new TransactionWrapper(); + } + + private void propertyGrid1_SelectedObjectsChanged(object sender, EventArgs e) + { + splitContainer1.Panel2.Enabled = propertyGrid1.SelectedObject != null; + } + + private void button8_Click(object sender, EventArgs e) + { + TransactionWrapper wrapper = (TransactionWrapper)propertyGrid1.SelectedObject; + ContractParametersContext context = new ContractParametersContext(Program.Service.NeoSystem.StoreView, wrapper.Unwrap(), Program.Service.NeoSystem.Settings.Network); + InformationBox.Show(context.ToString(), "ParametersContext", "ParametersContext"); + } + } +} diff --git a/src/Neo.GUI/GUI/DeveloperToolsForm.cs b/src/Neo.GUI/GUI/DeveloperToolsForm.cs new file mode 100644 index 0000000000..c921599945 --- /dev/null +++ b/src/Neo.GUI/GUI/DeveloperToolsForm.cs @@ -0,0 +1,23 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-gui is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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.Windows.Forms; + +namespace Neo.GUI +{ + internal partial class DeveloperToolsForm : Form + { + public DeveloperToolsForm() + { + InitializeComponent(); + InitializeTxBuilder(); + } + } +} diff --git a/src/Neo.GUI/GUI/DeveloperToolsForm.es-ES.resx b/src/Neo.GUI/GUI/DeveloperToolsForm.es-ES.resx new file mode 100644 index 0000000000..9e330876eb --- /dev/null +++ b/src/Neo.GUI/GUI/DeveloperToolsForm.es-ES.resx @@ -0,0 +1,153 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Parametros de contexto + + + Parámetros del contrato + + + Emitir + + + Actualizar + + + Mostrar + + + Cargar + + + Nuevo valor + + + Valor actual + + + Parámetros + + + Hash del script + + + Herramienta de desarrollo + + \ No newline at end of file diff --git a/src/Neo.GUI/GUI/DeveloperToolsForm.resx b/src/Neo.GUI/GUI/DeveloperToolsForm.resx new file mode 100644 index 0000000000..63e49aa4b5 --- /dev/null +++ b/src/Neo.GUI/GUI/DeveloperToolsForm.resx @@ -0,0 +1,669 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + Fill + + + + 3, 3 + + + Fill + + + 0, 0 + + + 444, 414 + + + + 1 + + + propertyGrid1 + + + System.Windows.Forms.PropertyGrid, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + splitContainer1.Panel1 + + + 0 + + + splitContainer1.Panel1 + + + System.Windows.Forms.SplitterPanel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + splitContainer1 + + + 0 + + + Bottom, Left, Right + + + NoControl + + + 3, 386 + + + 173, 23 + + + 3 + + + Get Parameters Context + + + button8 + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + splitContainer1.Panel2 + + + 0 + + + False + + + splitContainer1.Panel2 + + + System.Windows.Forms.SplitterPanel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + splitContainer1 + + + 1 + + + 627, 414 + + + 444 + + + 1 + + + splitContainer1 + + + System.Windows.Forms.SplitContainer, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tabPage1 + + + 0 + + + 4, 26 + + + 3, 3, 3, 3 + + + 633, 420 + + + 3 + + + Tx Builder + + + tabPage1 + + + System.Windows.Forms.TabPage, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tabControl1 + + + 0 + + + Bottom, Left + + + 170, 389 + + + 75, 23 + + + 7 + + + Broadcast + + + False + + + button4 + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tabPage2 + + + 0 + + + Bottom, Right + + + 550, 389 + + + 75, 23 + + + 6 + + + Update + + + button3 + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tabPage2 + + + 1 + + + Bottom, Left + + + False + + + 89, 389 + + + 75, 23 + + + 5 + + + Show + + + button2 + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tabPage2 + + + 2 + + + Bottom, Left + + + 8, 389 + + + 75, 23 + + + 4 + + + Load + + + button1 + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tabPage2 + + + 3 + + + Bottom, Left, Right + + + Fill + + + 3, 19 + + + True + + + 199, 98 + + + 0 + + + textBox2 + + + System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + groupBox4 + + + 0 + + + 420, 263 + + + 205, 120 + + + 3 + + + New Value + + + groupBox4 + + + System.Windows.Forms.GroupBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tabPage2 + + + 4 + + + Top, Bottom, Left, Right + + + Fill + + + 3, 19 + + + True + + + 199, 229 + + + 0 + + + textBox1 + + + System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + groupBox3 + + + 0 + + + 420, 6 + + + 205, 251 + + + 2 + + + Current Value + + + groupBox3 + + + System.Windows.Forms.GroupBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tabPage2 + + + 5 + + + Top, Bottom, Left + + + Fill + + + False + + + 17 + + + 3, 19 + + + 194, 355 + + + 0 + + + listBox2 + + + System.Windows.Forms.ListBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + groupBox2 + + + 0 + + + 214, 6 + + + 200, 377 + + + 1 + + + Parameters + + + groupBox2 + + + System.Windows.Forms.GroupBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tabPage2 + + + 6 + + + Top, Bottom, Left + + + Fill + + + False + + + 17 + + + 3, 19 + + + 194, 355 + + + 0 + + + listBox1 + + + System.Windows.Forms.ListBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + groupBox1 + + + 0 + + + 8, 6 + + + 200, 377 + + + 0 + + + ScriptHash + + + groupBox1 + + + System.Windows.Forms.GroupBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tabPage2 + + + 7 + + + 4, 26 + + + 3, 3, 3, 3 + + + 633, 420 + + + 2 + + + Contract Parameters + + + tabPage2 + + + System.Windows.Forms.TabPage, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tabControl1 + + + 1 + + + Fill + + + 0, 0 + + + 641, 450 + + + 0 + + + tabControl1 + + + System.Windows.Forms.TabControl, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 0 + + + True + + + 7, 17 + + + 641, 450 + + + 微软雅黑, 9pt + + + CenterScreen + + + Neo Developer Tools + + + DeveloperToolsForm + + + System.Windows.Forms.Form, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/src/Neo.GUI/GUI/DeveloperToolsForm.zh-Hans.resx b/src/Neo.GUI/GUI/DeveloperToolsForm.zh-Hans.resx new file mode 100644 index 0000000000..2b25fc62cb --- /dev/null +++ b/src/Neo.GUI/GUI/DeveloperToolsForm.zh-Hans.resx @@ -0,0 +1,153 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 获取合约参数上下文 + + + 交易构造器 + + + 广播 + + + 更新 + + + 显示 + + + 加载 + + + 新值 + + + 当前值 + + + 参数 + + + 合约参数 + + + NEO开发人员工具 + + \ No newline at end of file diff --git a/src/Neo.GUI/GUI/ElectionDialog.Designer.cs b/src/Neo.GUI/GUI/ElectionDialog.Designer.cs new file mode 100644 index 0000000000..512c24643a --- /dev/null +++ b/src/Neo.GUI/GUI/ElectionDialog.Designer.cs @@ -0,0 +1,92 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-gui is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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.GUI +{ + partial class ElectionDialog + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ElectionDialog)); + this.label1 = new System.Windows.Forms.Label(); + this.comboBox1 = new System.Windows.Forms.ComboBox(); + this.button1 = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // label1 + // + resources.ApplyResources(this.label1, "label1"); + this.label1.Name = "label1"; + // + // comboBox1 + // + resources.ApplyResources(this.comboBox1, "comboBox1"); + this.comboBox1.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.comboBox1.FormattingEnabled = true; + this.comboBox1.Name = "comboBox1"; + this.comboBox1.SelectedIndexChanged += new System.EventHandler(this.comboBox1_SelectedIndexChanged); + // + // button1 + // + resources.ApplyResources(this.button1, "button1"); + this.button1.DialogResult = System.Windows.Forms.DialogResult.OK; + this.button1.Name = "button1"; + this.button1.UseVisualStyleBackColor = true; + // + // ElectionDialog + // + this.AcceptButton = this.button1; + resources.ApplyResources(this, "$this"); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.button1); + this.Controls.Add(this.comboBox1); + this.Controls.Add(this.label1); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "ElectionDialog"; + this.ShowInTaskbar = false; + this.Load += new System.EventHandler(this.ElectionDialog_Load); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Label label1; + private System.Windows.Forms.ComboBox comboBox1; + private System.Windows.Forms.Button button1; + } +} diff --git a/src/Neo.GUI/GUI/ElectionDialog.cs b/src/Neo.GUI/GUI/ElectionDialog.cs new file mode 100644 index 0000000000..c28bbfa068 --- /dev/null +++ b/src/Neo.GUI/GUI/ElectionDialog.cs @@ -0,0 +1,51 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-gui is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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; +using Neo.IO; +using Neo.SmartContract.Native; +using Neo.VM; +using System; +using System.Linq; +using System.Windows.Forms; +using static Neo.Program; +using static Neo.SmartContract.Helper; + +namespace Neo.GUI +{ + public partial class ElectionDialog : Form + { + public ElectionDialog() + { + InitializeComponent(); + } + + public byte[] GetScript() + { + ECPoint pubkey = (ECPoint)comboBox1.SelectedItem; + using ScriptBuilder sb = new ScriptBuilder(); + sb.EmitDynamicCall(NativeContract.NEO.Hash, "registerValidator", pubkey); + return sb.ToArray(); + } + + private void ElectionDialog_Load(object sender, EventArgs e) + { + comboBox1.Items.AddRange(Service.CurrentWallet.GetAccounts().Where(p => !p.WatchOnly && IsSignatureContract(p.Contract.Script)).Select(p => p.GetKey().PublicKey).ToArray()); + } + + private void comboBox1_SelectedIndexChanged(object sender, EventArgs e) + { + if (comboBox1.SelectedIndex >= 0) + { + button1.Enabled = true; + } + } + } +} diff --git a/src/Neo.GUI/GUI/ElectionDialog.es-ES.resx b/src/Neo.GUI/GUI/ElectionDialog.es-ES.resx new file mode 100644 index 0000000000..5ab76de86d --- /dev/null +++ b/src/Neo.GUI/GUI/ElectionDialog.es-ES.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Votación + + \ No newline at end of file diff --git a/src/Neo.GUI/GUI/ElectionDialog.resx b/src/Neo.GUI/GUI/ElectionDialog.resx new file mode 100644 index 0000000000..ea655e7977 --- /dev/null +++ b/src/Neo.GUI/GUI/ElectionDialog.resx @@ -0,0 +1,231 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + True + + + + 12, 17 + + + 70, 17 + + + 0 + + + Public Key: + + + label1 + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 2 + + + + Top, Left, Right + + + 83, 14 + + + 442, 25 + + + 9 + + + comboBox1 + + + System.Windows.Forms.ComboBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 1 + + + Bottom, Right + + + False + + + 450, 56 + + + 75, 26 + + + 12 + + + OK + + + button1 + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 0 + + + True + + + 7, 17 + + + 537, 95 + + + 微软雅黑, 9pt + + + 3, 5, 3, 5 + + + CenterScreen + + + Election + + + ElectionDialog + + + System.Windows.Forms.Form, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/src/Neo.GUI/GUI/ElectionDialog.zh-Hans.resx b/src/Neo.GUI/GUI/ElectionDialog.zh-Hans.resx new file mode 100644 index 0000000000..53e9edf8f2 --- /dev/null +++ b/src/Neo.GUI/GUI/ElectionDialog.zh-Hans.resx @@ -0,0 +1,146 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + 24, 15 + + + 44, 17 + + + 公钥: + + + 73, 12 + + + 452, 25 + + + 确定 + + + + NoControl + + + 选举 + + \ No newline at end of file diff --git a/src/Neo.GUI/GUI/Helper.cs b/src/Neo.GUI/GUI/Helper.cs new file mode 100644 index 0000000000..73897f63ca --- /dev/null +++ b/src/Neo.GUI/GUI/Helper.cs @@ -0,0 +1,74 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-gui is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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.Network.P2P; +using Neo.Network.P2P.Payloads; +using Neo.Properties; +using Neo.SmartContract; +using System; +using System.Collections.Generic; +using System.Windows.Forms; +using static Neo.Program; + +namespace Neo.GUI +{ + internal static class Helper + { + private static readonly Dictionary tool_forms = new Dictionary(); + + private static void Helper_FormClosing(object sender, FormClosingEventArgs e) + { + tool_forms.Remove(sender.GetType()); + } + + public static void Show() where T : Form, new() + { + Type t = typeof(T); + if (!tool_forms.ContainsKey(t)) + { + tool_forms.Add(t, new T()); + tool_forms[t].FormClosing += Helper_FormClosing; + } + tool_forms[t].Show(); + tool_forms[t].Activate(); + } + + public static void SignAndShowInformation(Transaction tx) + { + if (tx == null) + { + MessageBox.Show(Strings.InsufficientFunds); + return; + } + ContractParametersContext context; + try + { + context = new ContractParametersContext(Service.NeoSystem.StoreView, tx, Program.Service.NeoSystem.Settings.Network); + } + catch (InvalidOperationException) + { + MessageBox.Show(Strings.UnsynchronizedBlock); + return; + } + Service.CurrentWallet.Sign(context); + if (context.Completed) + { + tx.Witnesses = context.GetWitnesses(); + Service.NeoSystem.Blockchain.Tell(tx); + InformationBox.Show(tx.Hash.ToString(), Strings.SendTxSucceedMessage, Strings.SendTxSucceedTitle); + } + else + { + InformationBox.Show(context.ToString(), Strings.IncompletedSignatureMessage, Strings.IncompletedSignatureTitle); + } + } + } +} diff --git a/src/Neo.GUI/GUI/ImportCustomContractDialog.Designer.cs b/src/Neo.GUI/GUI/ImportCustomContractDialog.Designer.cs new file mode 100644 index 0000000000..d06a03890e --- /dev/null +++ b/src/Neo.GUI/GUI/ImportCustomContractDialog.Designer.cs @@ -0,0 +1,137 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-gui is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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.GUI +{ + partial class ImportCustomContractDialog + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ImportCustomContractDialog)); + this.label1 = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.textBox1 = new System.Windows.Forms.TextBox(); + this.textBox2 = new System.Windows.Forms.TextBox(); + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.button1 = new System.Windows.Forms.Button(); + this.button2 = new System.Windows.Forms.Button(); + this.textBox3 = new System.Windows.Forms.TextBox(); + this.groupBox1.SuspendLayout(); + this.SuspendLayout(); + // + // label1 + // + resources.ApplyResources(this.label1, "label1"); + this.label1.Name = "label1"; + // + // label2 + // + resources.ApplyResources(this.label2, "label2"); + this.label2.Name = "label2"; + // + // textBox1 + // + resources.ApplyResources(this.textBox1, "textBox1"); + this.textBox1.Name = "textBox1"; + this.textBox1.TextChanged += new System.EventHandler(this.Input_Changed); + // + // textBox2 + // + resources.ApplyResources(this.textBox2, "textBox2"); + this.textBox2.Name = "textBox2"; + this.textBox2.TextChanged += new System.EventHandler(this.Input_Changed); + // + // groupBox1 + // + resources.ApplyResources(this.groupBox1, "groupBox1"); + this.groupBox1.Controls.Add(this.textBox2); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.TabStop = false; + // + // button1 + // + resources.ApplyResources(this.button1, "button1"); + this.button1.DialogResult = System.Windows.Forms.DialogResult.OK; + this.button1.Name = "button1"; + this.button1.UseVisualStyleBackColor = true; + // + // button2 + // + resources.ApplyResources(this.button2, "button2"); + this.button2.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.button2.Name = "button2"; + this.button2.UseVisualStyleBackColor = true; + // + // textBox3 + // + resources.ApplyResources(this.textBox3, "textBox3"); + this.textBox3.Name = "textBox3"; + // + // ImportCustomContractDialog + // + this.AcceptButton = this.button1; + resources.ApplyResources(this, "$this"); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.button2; + this.Controls.Add(this.textBox3); + this.Controls.Add(this.button2); + this.Controls.Add(this.button1); + this.Controls.Add(this.groupBox1); + this.Controls.Add(this.textBox1); + this.Controls.Add(this.label2); + this.Controls.Add(this.label1); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "ImportCustomContractDialog"; + this.ShowInTaskbar = false; + this.groupBox1.ResumeLayout(false); + this.groupBox1.PerformLayout(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.TextBox textBox1; + private System.Windows.Forms.TextBox textBox2; + private System.Windows.Forms.GroupBox groupBox1; + private System.Windows.Forms.Button button1; + private System.Windows.Forms.Button button2; + private System.Windows.Forms.TextBox textBox3; + } +} diff --git a/src/Neo.GUI/GUI/ImportCustomContractDialog.cs b/src/Neo.GUI/GUI/ImportCustomContractDialog.cs new file mode 100644 index 0000000000..aa3eef48dc --- /dev/null +++ b/src/Neo.GUI/GUI/ImportCustomContractDialog.cs @@ -0,0 +1,53 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-gui is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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.Wallets; +using System; +using System.Linq; +using System.Windows.Forms; + +namespace Neo.GUI +{ + internal partial class ImportCustomContractDialog : Form + { + public Contract GetContract() + { + ContractParameterType[] parameterList = textBox1.Text.HexToBytes().Select(p => (ContractParameterType)p).ToArray(); + byte[] redeemScript = textBox2.Text.HexToBytes(); + return Contract.Create(parameterList, redeemScript); + } + + public KeyPair GetKey() + { + if (textBox3.TextLength == 0) return null; + byte[] privateKey; + try + { + privateKey = Wallet.GetPrivateKeyFromWIF(textBox3.Text); + } + catch (FormatException) + { + privateKey = textBox3.Text.HexToBytes(); + } + return new KeyPair(privateKey); + } + + public ImportCustomContractDialog() + { + InitializeComponent(); + } + + private void Input_Changed(object sender, EventArgs e) + { + button1.Enabled = textBox1.TextLength > 0 && textBox2.TextLength > 0; + } + } +} diff --git a/src/Neo.GUI/GUI/ImportCustomContractDialog.es-ES.resx b/src/Neo.GUI/GUI/ImportCustomContractDialog.es-ES.resx new file mode 100644 index 0000000000..a61aa86444 --- /dev/null +++ b/src/Neo.GUI/GUI/ImportCustomContractDialog.es-ES.resx @@ -0,0 +1,154 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + 13, 15 + + + 23, 44 + + + 114, 16 + + + Lista de parámetros: + + + 143, 41 + + + 433, 23 + + + Confirmar + + + Cancelar + + + 143, 12 + + + 433, 23 + + + Importar contrato personalizado + + \ No newline at end of file diff --git a/src/Neo.GUI/GUI/ImportCustomContractDialog.resx b/src/Neo.GUI/GUI/ImportCustomContractDialog.resx new file mode 100644 index 0000000000..f7b634476e --- /dev/null +++ b/src/Neo.GUI/GUI/ImportCustomContractDialog.resx @@ -0,0 +1,366 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + True + + + + 12, 15 + + + 124, 16 + + + 0 + + + Private Key (optional): + + + label1 + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 6 + + + True + + + 50, 44 + + + 86, 16 + + + 10 + + + Parameter List: + + + label2 + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 5 + + + + Top, Left, Right + + + 142, 41 + + + 434, 23 + + + 11 + + + textBox1 + + + System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 4 + + + Fill + + + 3, 19 + + + 131072 + + + True + + + Vertical + + + 558, 323 + + + 13 + + + textBox2 + + + System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + groupBox1 + + + 0 + + + Top, Bottom, Left, Right + + + 12, 70 + + + 564, 345 + + + 14 + + + Script + + + groupBox1 + + + System.Windows.Forms.GroupBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 3 + + + Bottom, Right + + + False + + + 420, 421 + + + 75, 23 + + + 15 + + + OK + + + button1 + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 2 + + + Bottom, Right + + + 501, 421 + + + 75, 23 + + + 16 + + + Cancel + + + button2 + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 1 + + + 142, 12 + + + 434, 23 + + + 17 + + + textBox3 + + + System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 0 + + + True + + + 7, 16 + + + 588, 456 + + + 微软雅黑, 9pt + + + 3, 4, 3, 4 + + + CenterScreen + + + Import Custom Contract + + + ImportCustomContractDialog + + + System.Windows.Forms.Form, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/src/Neo.GUI/GUI/ImportCustomContractDialog.zh-Hans.resx b/src/Neo.GUI/GUI/ImportCustomContractDialog.zh-Hans.resx new file mode 100644 index 0000000000..78fbe3ff92 --- /dev/null +++ b/src/Neo.GUI/GUI/ImportCustomContractDialog.zh-Hans.resx @@ -0,0 +1,160 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + 83, 16 + + + 私钥(可选): + + + 36, 44 + + + 59, 16 + + + 形参列表: + + + 101, 41 + + + 475, 23 + + + 脚本代码 + + + 确定 + + + 取消 + + + 101, 12 + + + 475, 23 + + + 导入自定义合约 + + \ No newline at end of file diff --git a/src/Neo.GUI/GUI/ImportPrivateKeyDialog.cs b/src/Neo.GUI/GUI/ImportPrivateKeyDialog.cs new file mode 100644 index 0000000000..30390eb9ce --- /dev/null +++ b/src/Neo.GUI/GUI/ImportPrivateKeyDialog.cs @@ -0,0 +1,40 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-gui is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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.Windows.Forms; + +namespace Neo.GUI +{ + internal partial class ImportPrivateKeyDialog : Form + { + public ImportPrivateKeyDialog() + { + InitializeComponent(); + } + + public string[] WifStrings + { + get + { + return textBox1.Lines; + } + set + { + textBox1.Lines = value; + } + } + + private void textBox1_TextChanged(object sender, EventArgs e) + { + button1.Enabled = textBox1.TextLength > 0; + } + } +} diff --git a/src/Neo.GUI/GUI/ImportPrivateKeyDialog.designer.cs b/src/Neo.GUI/GUI/ImportPrivateKeyDialog.designer.cs new file mode 100644 index 0000000000..e0df823ec7 --- /dev/null +++ b/src/Neo.GUI/GUI/ImportPrivateKeyDialog.designer.cs @@ -0,0 +1,102 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-gui is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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.GUI +{ + partial class ImportPrivateKeyDialog + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ImportPrivateKeyDialog)); + this.textBox1 = new System.Windows.Forms.TextBox(); + this.button1 = new System.Windows.Forms.Button(); + this.button2 = new System.Windows.Forms.Button(); + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.groupBox1.SuspendLayout(); + this.SuspendLayout(); + // + // textBox1 + // + resources.ApplyResources(this.textBox1, "textBox1"); + this.textBox1.Name = "textBox1"; + this.textBox1.TextChanged += new System.EventHandler(this.textBox1_TextChanged); + // + // button1 + // + resources.ApplyResources(this.button1, "button1"); + this.button1.DialogResult = System.Windows.Forms.DialogResult.OK; + this.button1.Name = "button1"; + this.button1.UseVisualStyleBackColor = true; + // + // button2 + // + resources.ApplyResources(this.button2, "button2"); + this.button2.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.button2.Name = "button2"; + this.button2.UseVisualStyleBackColor = true; + // + // groupBox1 + // + resources.ApplyResources(this.groupBox1, "groupBox1"); + this.groupBox1.Controls.Add(this.textBox1); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.TabStop = false; + // + // ImportPrivateKeyDialog + // + this.AcceptButton = this.button1; + resources.ApplyResources(this, "$this"); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.button2; + this.Controls.Add(this.groupBox1); + this.Controls.Add(this.button2); + this.Controls.Add(this.button1); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "ImportPrivateKeyDialog"; + this.ShowInTaskbar = false; + this.groupBox1.ResumeLayout(false); + this.groupBox1.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + private System.Windows.Forms.TextBox textBox1; + private System.Windows.Forms.Button button1; + private System.Windows.Forms.Button button2; + private System.Windows.Forms.GroupBox groupBox1; + } +} diff --git a/src/Neo.GUI/GUI/ImportPrivateKeyDialog.es-ES.resx b/src/Neo.GUI/GUI/ImportPrivateKeyDialog.es-ES.resx new file mode 100644 index 0000000000..86ff978402 --- /dev/null +++ b/src/Neo.GUI/GUI/ImportPrivateKeyDialog.es-ES.resx @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Cancelar + + + Clave privada WIF: + + + + NoControl + + + Aceptar + + + Importar clave privada + + \ No newline at end of file diff --git a/src/Neo.GUI/GUI/ImportPrivateKeyDialog.resx b/src/Neo.GUI/GUI/ImportPrivateKeyDialog.resx new file mode 100644 index 0000000000..5cf34443a4 --- /dev/null +++ b/src/Neo.GUI/GUI/ImportPrivateKeyDialog.resx @@ -0,0 +1,267 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + Fill + + + + 3, 19 + + + + True + + + Vertical + + + 454, 79 + + + 0 + + + False + + + textBox1 + + + System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + groupBox1 + + + 0 + + + Bottom, Right + + + False + + + 316, 119 + + + 75, 23 + + + 1 + + + OK + + + button1 + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 2 + + + Bottom, Right + + + 397, 119 + + + 75, 23 + + + 2 + + + Cancel + + + button2 + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 1 + + + Top, Bottom, Left, Right + + + 12, 12 + + + 460, 101 + + + 0 + + + WIF Private Key: + + + groupBox1 + + + System.Windows.Forms.GroupBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 0 + + + True + + + 7, 17 + + + 484, 154 + + + 微软雅黑, 9pt + + + 3, 4, 3, 4 + + + CenterScreen + + + Import Private Key + + + ImportPrivateKeyDialog + + + System.Windows.Forms.Form, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/src/Neo.GUI/GUI/ImportPrivateKeyDialog.zh-Hans.resx b/src/Neo.GUI/GUI/ImportPrivateKeyDialog.zh-Hans.resx new file mode 100644 index 0000000000..5db4bf12ea --- /dev/null +++ b/src/Neo.GUI/GUI/ImportPrivateKeyDialog.zh-Hans.resx @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 确定 + + + 取消 + + + WIF私钥: + + + 导入私钥 + + \ No newline at end of file diff --git a/src/Neo.GUI/GUI/InformationBox.Designer.cs b/src/Neo.GUI/GUI/InformationBox.Designer.cs new file mode 100644 index 0000000000..8b41144a9b --- /dev/null +++ b/src/Neo.GUI/GUI/InformationBox.Designer.cs @@ -0,0 +1,100 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-gui is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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.GUI +{ + partial class InformationBox + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(InformationBox)); + this.textBox1 = new System.Windows.Forms.TextBox(); + this.button1 = new System.Windows.Forms.Button(); + this.button2 = new System.Windows.Forms.Button(); + this.label1 = new System.Windows.Forms.Label(); + this.SuspendLayout(); + // + // textBox1 + // + resources.ApplyResources(this.textBox1, "textBox1"); + this.textBox1.Name = "textBox1"; + this.textBox1.ReadOnly = true; + // + // button1 + // + resources.ApplyResources(this.button1, "button1"); + this.button1.Name = "button1"; + this.button1.UseVisualStyleBackColor = true; + this.button1.Click += new System.EventHandler(this.button1_Click); + // + // button2 + // + resources.ApplyResources(this.button2, "button2"); + this.button2.DialogResult = System.Windows.Forms.DialogResult.OK; + this.button2.Name = "button2"; + this.button2.UseVisualStyleBackColor = true; + // + // label1 + // + resources.ApplyResources(this.label1, "label1"); + this.label1.Name = "label1"; + // + // InformationBox + // + this.AcceptButton = this.button2; + resources.ApplyResources(this, "$this"); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.button2; + this.Controls.Add(this.label1); + this.Controls.Add(this.button2); + this.Controls.Add(this.button1); + this.Controls.Add(this.textBox1); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "InformationBox"; + this.ShowInTaskbar = false; + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.TextBox textBox1; + private System.Windows.Forms.Button button1; + private System.Windows.Forms.Button button2; + private System.Windows.Forms.Label label1; + } +} diff --git a/src/Neo.GUI/GUI/InformationBox.cs b/src/Neo.GUI/GUI/InformationBox.cs new file mode 100644 index 0000000000..7cdd881255 --- /dev/null +++ b/src/Neo.GUI/GUI/InformationBox.cs @@ -0,0 +1,43 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-gui is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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.Windows.Forms; + +namespace Neo.GUI +{ + internal partial class InformationBox : Form + { + public InformationBox() + { + InitializeComponent(); + } + + public static DialogResult Show(string text, string message = null, string title = null) + { + using InformationBox box = new InformationBox(); + box.textBox1.Text = text; + if (message != null) + { + box.label1.Text = message; + } + if (title != null) + { + box.Text = title; + } + return box.ShowDialog(); + } + + private void button1_Click(object sender, System.EventArgs e) + { + textBox1.SelectAll(); + textBox1.Copy(); + } + } +} diff --git a/src/Neo.GUI/GUI/InformationBox.es-ES.resx b/src/Neo.GUI/GUI/InformationBox.es-ES.resx new file mode 100644 index 0000000000..1af985f64c --- /dev/null +++ b/src/Neo.GUI/GUI/InformationBox.es-ES.resx @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Copiar + + + Cancelar + + + Información + + \ No newline at end of file diff --git a/src/Neo.GUI/GUI/InformationBox.resx b/src/Neo.GUI/GUI/InformationBox.resx new file mode 100644 index 0000000000..3aec9d5ab6 --- /dev/null +++ b/src/Neo.GUI/GUI/InformationBox.resx @@ -0,0 +1,255 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + Top, Bottom, Left, Right + + + + 12, 29 + + + + True + + + Vertical + + + 489, 203 + + + 0 + + + textBox1 + + + System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 3 + + + Bottom, Right + + + 345, 238 + + + 75, 23 + + + 1 + + + copy + + + button1 + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 2 + + + Bottom, Right + + + 426, 238 + + + 75, 23 + + + 2 + + + close + + + button2 + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 1 + + + True + + + 12, 9 + + + 0, 17 + + + 3 + + + label1 + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 0 + + + True + + + 7, 17 + + + 513, 273 + + + 微软雅黑, 9pt + + + CenterScreen + + + InformationBox + + + InformationBox + + + System.Windows.Forms.Form, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/src/Neo.GUI/GUI/InformationBox.zh-Hans.resx b/src/Neo.GUI/GUI/InformationBox.zh-Hans.resx new file mode 100644 index 0000000000..ab3b23dc17 --- /dev/null +++ b/src/Neo.GUI/GUI/InformationBox.zh-Hans.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 复制 + + + 关闭 + + \ No newline at end of file diff --git a/src/Neo.GUI/GUI/InputBox.Designer.cs b/src/Neo.GUI/GUI/InputBox.Designer.cs new file mode 100644 index 0000000000..aa376ca91f --- /dev/null +++ b/src/Neo.GUI/GUI/InputBox.Designer.cs @@ -0,0 +1,102 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-gui is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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.GUI +{ + partial class InputBox + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(InputBox)); + this.textBox1 = new System.Windows.Forms.TextBox(); + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.button1 = new System.Windows.Forms.Button(); + this.button2 = new System.Windows.Forms.Button(); + this.groupBox1.SuspendLayout(); + this.SuspendLayout(); + // + // textBox1 + // + resources.ApplyResources(this.textBox1, "textBox1"); + this.textBox1.Name = "textBox1"; + // + // groupBox1 + // + resources.ApplyResources(this.groupBox1, "groupBox1"); + this.groupBox1.Controls.Add(this.textBox1); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.TabStop = false; + // + // button1 + // + resources.ApplyResources(this.button1, "button1"); + this.button1.DialogResult = System.Windows.Forms.DialogResult.OK; + this.button1.Name = "button1"; + this.button1.UseVisualStyleBackColor = true; + // + // button2 + // + resources.ApplyResources(this.button2, "button2"); + this.button2.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.button2.Name = "button2"; + this.button2.UseVisualStyleBackColor = true; + // + // InputBox + // + this.AcceptButton = this.button1; + resources.ApplyResources(this, "$this"); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.button2; + this.Controls.Add(this.button2); + this.Controls.Add(this.button1); + this.Controls.Add(this.groupBox1); + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "InputBox"; + this.ShowIcon = false; + this.ShowInTaskbar = false; + this.groupBox1.ResumeLayout(false); + this.groupBox1.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.TextBox textBox1; + private System.Windows.Forms.GroupBox groupBox1; + private System.Windows.Forms.Button button1; + private System.Windows.Forms.Button button2; + } +} diff --git a/src/Neo.GUI/GUI/InputBox.cs b/src/Neo.GUI/GUI/InputBox.cs new file mode 100644 index 0000000000..cdfc5a63eb --- /dev/null +++ b/src/Neo.GUI/GUI/InputBox.cs @@ -0,0 +1,32 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-gui is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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.Windows.Forms; + +namespace Neo.GUI +{ + internal partial class InputBox : Form + { + private InputBox(string text, string caption, string content) + { + InitializeComponent(); + this.Text = caption; + groupBox1.Text = text; + textBox1.Text = content; + } + + public static string Show(string text, string caption, string content = "") + { + using InputBox dialog = new InputBox(text, caption, content); + if (dialog.ShowDialog() != DialogResult.OK) return null; + return dialog.textBox1.Text; + } + } +} diff --git a/src/Neo.GUI/GUI/InputBox.es-ES.resx b/src/Neo.GUI/GUI/InputBox.es-ES.resx new file mode 100644 index 0000000000..3e13191c48 --- /dev/null +++ b/src/Neo.GUI/GUI/InputBox.es-ES.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Aceptar + + + Cancelar + + \ No newline at end of file diff --git a/src/Neo.GUI/GUI/InputBox.resx b/src/Neo.GUI/GUI/InputBox.resx new file mode 100644 index 0000000000..84533a5c93 --- /dev/null +++ b/src/Neo.GUI/GUI/InputBox.resx @@ -0,0 +1,249 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + 2 + + + True + + + 0 + + + + 7, 17 + + + InputBox + + + 75, 23 + + + System.Windows.Forms.Form, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + button2 + + + InputBox + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + groupBox1 + + + 390, 118 + + + 420, 193 + + + 2 + + + + CenterScreen + + + 75, 23 + + + 2, 2, 2, 2 + + + groupBox1 + + + 0 + + + 3, 19 + + + System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + System.Windows.Forms.GroupBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 12, 12 + + + 1 + + + 0 + + + Fill + + + $this + + + groupBox1 + + + 0 + + + 1 + + + button1 + + + textBox1 + + + OK + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 252, 158 + + + Microsoft YaHei UI, 9pt + + + 396, 140 + + + 333, 158 + + + Cancel + + + $this + + + True + + \ No newline at end of file diff --git a/src/Neo.GUI/GUI/InputBox.zh-Hans.resx b/src/Neo.GUI/GUI/InputBox.zh-Hans.resx new file mode 100644 index 0000000000..0ede664604 --- /dev/null +++ b/src/Neo.GUI/GUI/InputBox.zh-Hans.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 确定 + + + 取消 + + \ No newline at end of file diff --git a/src/Neo.GUI/GUI/InvokeContractDialog.Designer.cs b/src/Neo.GUI/GUI/InvokeContractDialog.Designer.cs new file mode 100644 index 0000000000..04f845def9 --- /dev/null +++ b/src/Neo.GUI/GUI/InvokeContractDialog.Designer.cs @@ -0,0 +1,270 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-gui is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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.GUI +{ + partial class InvokeContractDialog + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(InvokeContractDialog)); + this.button6 = new System.Windows.Forms.Button(); + this.textBox6 = new System.Windows.Forms.TextBox(); + this.button3 = new System.Windows.Forms.Button(); + this.button4 = new System.Windows.Forms.Button(); + this.label6 = new System.Windows.Forms.Label(); + this.label7 = new System.Windows.Forms.Label(); + this.button5 = new System.Windows.Forms.Button(); + this.openFileDialog1 = new System.Windows.Forms.OpenFileDialog(); + this.tabControl1 = new System.Windows.Forms.TabControl(); + this.tabPage3 = new System.Windows.Forms.TabPage(); + this.button8 = new System.Windows.Forms.Button(); + this.textBox9 = new System.Windows.Forms.TextBox(); + this.label10 = new System.Windows.Forms.Label(); + this.comboBox1 = new System.Windows.Forms.ComboBox(); + this.label9 = new System.Windows.Forms.Label(); + this.button7 = new System.Windows.Forms.Button(); + this.textBox8 = new System.Windows.Forms.TextBox(); + this.label8 = new System.Windows.Forms.Label(); + this.tabPage2 = new System.Windows.Forms.TabPage(); + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.textBox7 = new System.Windows.Forms.TextBox(); + this.openFileDialog2 = new System.Windows.Forms.OpenFileDialog(); + this.tabControl1.SuspendLayout(); + this.tabPage3.SuspendLayout(); + this.tabPage2.SuspendLayout(); + this.groupBox1.SuspendLayout(); + this.SuspendLayout(); + // + // button6 + // + resources.ApplyResources(this.button6, "button6"); + this.button6.Name = "button6"; + this.button6.UseVisualStyleBackColor = true; + this.button6.Click += new System.EventHandler(this.button6_Click); + // + // textBox6 + // + resources.ApplyResources(this.textBox6, "textBox6"); + this.textBox6.Name = "textBox6"; + this.textBox6.TextChanged += new System.EventHandler(this.textBox6_TextChanged); + // + // button3 + // + resources.ApplyResources(this.button3, "button3"); + this.button3.DialogResult = System.Windows.Forms.DialogResult.OK; + this.button3.Name = "button3"; + this.button3.UseVisualStyleBackColor = true; + // + // button4 + // + resources.ApplyResources(this.button4, "button4"); + this.button4.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.button4.Name = "button4"; + this.button4.UseVisualStyleBackColor = true; + // + // label6 + // + resources.ApplyResources(this.label6, "label6"); + this.label6.Name = "label6"; + // + // label7 + // + resources.ApplyResources(this.label7, "label7"); + this.label7.Name = "label7"; + // + // button5 + // + resources.ApplyResources(this.button5, "button5"); + this.button5.Name = "button5"; + this.button5.UseVisualStyleBackColor = true; + this.button5.Click += new System.EventHandler(this.button5_Click); + // + // openFileDialog1 + // + resources.ApplyResources(this.openFileDialog1, "openFileDialog1"); + this.openFileDialog1.DefaultExt = "avm"; + // + // tabControl1 + // + resources.ApplyResources(this.tabControl1, "tabControl1"); + this.tabControl1.Controls.Add(this.tabPage3); + this.tabControl1.Controls.Add(this.tabPage2); + this.tabControl1.Name = "tabControl1"; + this.tabControl1.SelectedIndex = 0; + // + // tabPage3 + // + resources.ApplyResources(this.tabPage3, "tabPage3"); + this.tabPage3.Controls.Add(this.button8); + this.tabPage3.Controls.Add(this.textBox9); + this.tabPage3.Controls.Add(this.label10); + this.tabPage3.Controls.Add(this.comboBox1); + this.tabPage3.Controls.Add(this.label9); + this.tabPage3.Controls.Add(this.button7); + this.tabPage3.Controls.Add(this.textBox8); + this.tabPage3.Controls.Add(this.label8); + this.tabPage3.Name = "tabPage3"; + this.tabPage3.UseVisualStyleBackColor = true; + // + // button8 + // + resources.ApplyResources(this.button8, "button8"); + this.button8.Name = "button8"; + this.button8.UseVisualStyleBackColor = true; + this.button8.Click += new System.EventHandler(this.button8_Click); + // + // textBox9 + // + resources.ApplyResources(this.textBox9, "textBox9"); + this.textBox9.Name = "textBox9"; + this.textBox9.ReadOnly = true; + // + // label10 + // + resources.ApplyResources(this.label10, "label10"); + this.label10.Name = "label10"; + // + // comboBox1 + // + resources.ApplyResources(this.comboBox1, "comboBox1"); + this.comboBox1.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.comboBox1.FormattingEnabled = true; + this.comboBox1.Name = "comboBox1"; + this.comboBox1.SelectedIndexChanged += new System.EventHandler(this.comboBox1_SelectedIndexChanged); + // + // label9 + // + resources.ApplyResources(this.label9, "label9"); + this.label9.Name = "label9"; + // + // button7 + // + resources.ApplyResources(this.button7, "button7"); + this.button7.Name = "button7"; + this.button7.UseVisualStyleBackColor = true; + this.button7.Click += new System.EventHandler(this.button7_Click); + // + // textBox8 + // + resources.ApplyResources(this.textBox8, "textBox8"); + this.textBox8.Name = "textBox8"; + this.textBox8.ReadOnly = true; + // + // label8 + // + resources.ApplyResources(this.label8, "label8"); + this.label8.Name = "label8"; + // + // tabPage2 + // + resources.ApplyResources(this.tabPage2, "tabPage2"); + this.tabPage2.Controls.Add(this.button6); + this.tabPage2.Controls.Add(this.textBox6); + this.tabPage2.Name = "tabPage2"; + this.tabPage2.UseVisualStyleBackColor = true; + // + // groupBox1 + // + resources.ApplyResources(this.groupBox1, "groupBox1"); + this.groupBox1.Controls.Add(this.textBox7); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.TabStop = false; + // + // textBox7 + // + resources.ApplyResources(this.textBox7, "textBox7"); + this.textBox7.Name = "textBox7"; + this.textBox7.ReadOnly = true; + // + // openFileDialog2 + // + resources.ApplyResources(this.openFileDialog2, "openFileDialog2"); + this.openFileDialog2.DefaultExt = "abi.json"; + // + // InvokeContractDialog + // + resources.ApplyResources(this, "$this"); + this.AcceptButton = this.button3; + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.button4; + this.Controls.Add(this.groupBox1); + this.Controls.Add(this.tabControl1); + this.Controls.Add(this.button5); + this.Controls.Add(this.label7); + this.Controls.Add(this.label6); + this.Controls.Add(this.button4); + this.Controls.Add(this.button3); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "InvokeContractDialog"; + this.ShowInTaskbar = false; + this.tabControl1.ResumeLayout(false); + this.tabPage3.ResumeLayout(false); + this.tabPage3.PerformLayout(); + this.tabPage2.ResumeLayout(false); + this.tabPage2.PerformLayout(); + this.groupBox1.ResumeLayout(false); + this.groupBox1.PerformLayout(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + private System.Windows.Forms.TextBox textBox6; + private System.Windows.Forms.Button button3; + private System.Windows.Forms.Button button4; + private System.Windows.Forms.Label label6; + private System.Windows.Forms.Label label7; + private System.Windows.Forms.Button button5; + private System.Windows.Forms.Button button6; + private System.Windows.Forms.OpenFileDialog openFileDialog1; + private System.Windows.Forms.TabControl tabControl1; + private System.Windows.Forms.TabPage tabPage2; + private System.Windows.Forms.GroupBox groupBox1; + private System.Windows.Forms.TextBox textBox7; + private System.Windows.Forms.TabPage tabPage3; + private System.Windows.Forms.TextBox textBox8; + private System.Windows.Forms.Label label8; + private System.Windows.Forms.Button button7; + private System.Windows.Forms.OpenFileDialog openFileDialog2; + private System.Windows.Forms.Label label9; + private System.Windows.Forms.ComboBox comboBox1; + private System.Windows.Forms.Button button8; + private System.Windows.Forms.TextBox textBox9; + private System.Windows.Forms.Label label10; + } +} diff --git a/src/Neo.GUI/GUI/InvokeContractDialog.cs b/src/Neo.GUI/GUI/InvokeContractDialog.cs new file mode 100644 index 0000000000..3a92b5afda --- /dev/null +++ b/src/Neo.GUI/GUI/InvokeContractDialog.cs @@ -0,0 +1,145 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-gui is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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.Json; +using Neo.Network.P2P.Payloads; +using Neo.Properties; +using Neo.SmartContract; +using Neo.VM; +using System; +using System.IO; +using System.Linq; +using System.Text; +using System.Windows.Forms; +using static Neo.Program; + +namespace Neo.GUI +{ + internal partial class InvokeContractDialog : Form + { + private readonly Transaction tx; + private JObject abi; + private UInt160 script_hash; + private ContractParameter[] parameters; + + public InvokeContractDialog() + { + InitializeComponent(); + } + + public InvokeContractDialog(Transaction tx) : this() + { + this.tx = tx; + tabControl1.SelectedTab = tabPage2; + textBox6.Text = tx.Script.Span.ToHexString(); + textBox6.ReadOnly = true; + } + + public InvokeContractDialog(byte[] script) : this() + { + tabControl1.SelectedTab = tabPage2; + textBox6.Text = script.ToHexString(); + } + + public Transaction GetTransaction() + { + byte[] script = textBox6.Text.Trim().HexToBytes(); + return tx ?? Service.CurrentWallet.MakeTransaction(Service.NeoSystem.StoreView, script); + } + + private void UpdateScript() + { + using ScriptBuilder sb = new ScriptBuilder(); + sb.EmitDynamicCall(script_hash, (string)comboBox1.SelectedItem, parameters); + textBox6.Text = sb.ToArray().ToHexString(); + } + + private void textBox6_TextChanged(object sender, EventArgs e) + { + button3.Enabled = false; + button5.Enabled = textBox6.TextLength > 0; + } + + private void button5_Click(object sender, EventArgs e) + { + byte[] script; + try + { + script = textBox6.Text.Trim().HexToBytes(); + } + catch (FormatException ex) + { + MessageBox.Show(ex.Message); + return; + } + Transaction tx_test = tx ?? new Transaction + { + Signers = new Signer[0], + Attributes = new TransactionAttribute[0], + Script = script, + Witnesses = new Witness[0] + }; + using ApplicationEngine engine = ApplicationEngine.Run(tx_test.Script, Service.NeoSystem.StoreView, container: tx_test); + StringBuilder sb = new StringBuilder(); + sb.AppendLine($"VM State: {engine.State}"); + sb.AppendLine($"Gas Consumed: {engine.GasConsumed}"); + sb.AppendLine($"Evaluation Stack: {new JArray(engine.ResultStack.Select(p => p.ToParameter().ToJson()))}"); + textBox7.Text = sb.ToString(); + if (engine.State != VMState.FAULT) + { + label7.Text = engine.GasConsumed + " gas"; + button3.Enabled = true; + } + else + { + MessageBox.Show(Strings.ExecutionFailed); + } + } + + private void button6_Click(object sender, EventArgs e) + { + if (openFileDialog1.ShowDialog() != DialogResult.OK) return; + textBox6.Text = File.ReadAllBytes(openFileDialog1.FileName).ToHexString(); + } + + private void button7_Click(object sender, EventArgs e) + { + if (openFileDialog2.ShowDialog() != DialogResult.OK) return; + abi = (JObject)JToken.Parse(File.ReadAllText(openFileDialog2.FileName)); + script_hash = UInt160.Parse(abi["hash"].AsString()); + textBox8.Text = script_hash.ToString(); + comboBox1.Items.Clear(); + comboBox1.Items.AddRange(((JArray)abi["functions"]).Select(p => p["name"].AsString()).Where(p => p != abi["entrypoint"].AsString()).ToArray()); + textBox9.Clear(); + button8.Enabled = false; + } + + private void button8_Click(object sender, EventArgs e) + { + using (ParametersEditor dialog = new ParametersEditor(parameters)) + { + dialog.ShowDialog(); + } + UpdateScript(); + } + + private void comboBox1_SelectedIndexChanged(object sender, EventArgs e) + { + if (!(comboBox1.SelectedItem is string method)) return; + JArray functions = (JArray)abi["functions"]; + var function = functions.First(p => p["name"].AsString() == method); + JArray _params = (JArray)function["parameters"]; + parameters = _params.Select(p => new ContractParameter(p["type"].AsEnum())).ToArray(); + textBox9.Text = string.Join(", ", _params.Select(p => p["name"].AsString())); + button8.Enabled = parameters.Length > 0; + UpdateScript(); + } + } +} diff --git a/src/Neo.GUI/GUI/InvokeContractDialog.es-ES.resx b/src/Neo.GUI/GUI/InvokeContractDialog.es-ES.resx new file mode 100644 index 0000000000..20f5cf4799 --- /dev/null +++ b/src/Neo.GUI/GUI/InvokeContractDialog.es-ES.resx @@ -0,0 +1,154 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Cargar + + + Invocar + + + Cancelar + + + + 38, 17 + + + Tasa: + + + 79, 17 + + + no evaluada + + + Prueba + + + 78, 17 + + + Parámetros: + + + Invocar contrato + + \ No newline at end of file diff --git a/src/Neo.GUI/GUI/InvokeContractDialog.resx b/src/Neo.GUI/GUI/InvokeContractDialog.resx new file mode 100644 index 0000000000..df3c2f0ab5 --- /dev/null +++ b/src/Neo.GUI/GUI/InvokeContractDialog.resx @@ -0,0 +1,735 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + Bottom, Right + + + + 376, 190 + + + 75, 23 + + + + 1 + + + Load + + + button6 + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tabPage2 + + + 0 + + + Top, Bottom, Left, Right + + + 6, 6 + + + True + + + Vertical + + + 445, 178 + + + 0 + + + textBox6 + + + System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tabPage2 + + + 1 + + + Bottom, Right + + + False + + + 321, 482 + + + 75, 23 + + + 6 + + + Invoke + + + button3 + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 6 + + + Bottom, Right + + + NoControl + + + 402, 482 + + + 75, 23 + + + 7 + + + Cancel + + + button4 + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 5 + + + Bottom, Left + + + True + + + 12, 482 + + + 31, 17 + + + 3 + + + Fee: + + + label6 + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 4 + + + Bottom, Left + + + True + + + 49, 482 + + + 87, 17 + + + 4 + + + not evaluated + + + label7 + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 3 + + + Bottom, Right + + + False + + + 240, 482 + + + 75, 23 + + + 5 + + + Test + + + button5 + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 2 + + + 17, 17 + + + AVM File|*.avm + + + Top, Right + + + False + + + NoControl + + + 426, 67 + + + 25, 25 + + + 17 + + + ... + + + button8 + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tabPage3 + + + 0 + + + Top, Left, Right + + + 89, 68 + + + 331, 23 + + + 16 + + + textBox9 + + + System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tabPage3 + + + 1 + + + True + + + NoControl + + + 6, 71 + + + 77, 17 + + + 15 + + + Parameters: + + + label10 + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tabPage3 + + + 2 + + + 89, 36 + + + 362, 25 + + + 14 + + + comboBox1 + + + System.Windows.Forms.ComboBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tabPage3 + + + 3 + + + True + + + NoControl + + + 26, 39 + + + 57, 17 + + + 13 + + + Method: + + + label9 + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tabPage3 + + + 4 + + + Bottom, Right + + + NoControl + + + 354, 188 + + + 97, 25 + + + 12 + + + Open ABI File + + + button7 + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tabPage3 + + + 5 + + + Top, Left, Right + + + 89, 7 + + + 362, 23 + + + 2 + + + textBox8 + + + System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tabPage3 + + + 6 + + + True + + + NoControl + + + 10, 10 + + + 73, 17 + + + 1 + + + ScriptHash: + + + label8 + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tabPage3 + + + 7 + + + 4, 26 + + + 3, 3, 3, 3 + + + 457, 219 + + + 2 + + + ABI + + + tabPage3 + + + System.Windows.Forms.TabPage, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tabControl1 + + + 0 + + + 4, 26 + + + 3, 3, 3, 3 + + + 457, 219 + + + 1 + + + Custom + + + tabPage2 + + + System.Windows.Forms.TabPage, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tabControl1 + + + 1 + + + 12, 12 + + + 465, 249 + + + 8 + + + tabControl1 + + + System.Windows.Forms.TabControl, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 1 + + + Fill + + + 3, 19 + + + True + + + Both + + + 459, 184 + + + 0 + + + False + + + textBox7 + + + System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + groupBox1 + + + 0 + + + 12, 267 + + + 465, 206 + + + 9 + + + Results + + + groupBox1 + + + System.Windows.Forms.GroupBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 0 + + + 165, 17 + + + ABI File|*.abi.json + + + True + + + 7, 17 + + + 489, 514 + + + 微软雅黑, 9pt + + + 3, 4, 3, 4 + + + CenterScreen + + + Invoke Contract + + + openFileDialog1 + + + System.Windows.Forms.OpenFileDialog, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + openFileDialog2 + + + System.Windows.Forms.OpenFileDialog, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + InvokeContractDialog + + + System.Windows.Forms.Form, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/src/Neo.GUI/GUI/InvokeContractDialog.zh-Hans.resx b/src/Neo.GUI/GUI/InvokeContractDialog.zh-Hans.resx new file mode 100644 index 0000000000..d39deccbfa --- /dev/null +++ b/src/Neo.GUI/GUI/InvokeContractDialog.zh-Hans.resx @@ -0,0 +1,184 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 加载 + + + 调用 + + + 取消 + + + + 47, 17 + + + 手续费: + + + 65, 482 + + + 44, 17 + + + 未评估 + + + 试运行 + + + AVM文件|*.avm + + + 24, 71 + + + 59, 17 + + + 参数列表: + + + 48, 39 + + + 35, 17 + + + 方法: + + + 打开ABI文件 + + + 自定义 + + + 运行结果 + + + ABI文件|*.abi.json + + + 调用合约 + + \ No newline at end of file diff --git a/src/Neo.GUI/GUI/MainForm.Designer.cs b/src/Neo.GUI/GUI/MainForm.Designer.cs new file mode 100644 index 0000000000..2f4da98d9c --- /dev/null +++ b/src/Neo.GUI/GUI/MainForm.Designer.cs @@ -0,0 +1,732 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-gui is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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.GUI +{ + partial class MainForm + { + /// + /// 必需的设计器变量。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清理所有正在使用的资源。 + /// + /// 如果应释放托管资源,为 true;否则为 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows 窗体设计器生成的代码 + + /// + /// 设计器支持所需的方法 - 不要 + /// 使用代码编辑器修改此方法的内容。 + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm)); + this.menuStrip1 = new System.Windows.Forms.MenuStrip(); + this.钱包WToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.创建钱包数据库NToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.打开钱包数据库OToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator(); + this.修改密码CToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripSeparator2 = new System.Windows.Forms.ToolStripSeparator(); + this.退出XToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.交易TToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.转账TToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripSeparator5 = new System.Windows.Forms.ToolStripSeparator(); + this.签名SToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.高级AToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.deployContractToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.invokeContractToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripSeparator11 = new System.Windows.Forms.ToolStripSeparator(); + this.选举EToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.signDataToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripSeparator9 = new System.Windows.Forms.ToolStripSeparator(); + this.optionsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.帮助HToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.查看帮助VToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.官网WToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripSeparator3 = new System.Windows.Forms.ToolStripSeparator(); + this.开发人员工具TToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.consoleToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripSeparator4 = new System.Windows.Forms.ToolStripSeparator(); + this.关于AntSharesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.listView1 = new System.Windows.Forms.ListView(); + this.columnHeader1 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.columnHeader4 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.columnHeader11 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.contextMenuStrip1 = new System.Windows.Forms.ContextMenuStrip(this.components); + this.创建新地址NToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.导入私钥IToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.importWIFToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripSeparator10 = new System.Windows.Forms.ToolStripSeparator(); + this.importWatchOnlyAddressToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.创建智能合约SToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.多方签名MToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripSeparator12 = new System.Windows.Forms.ToolStripSeparator(); + this.自定义CToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.toolStripSeparator6 = new System.Windows.Forms.ToolStripSeparator(); + this.查看私钥VToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.viewContractToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.voteToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.复制到剪贴板CToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.删除DToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.statusStrip1 = new System.Windows.Forms.StatusStrip(); + this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel(); + this.lbl_height = new System.Windows.Forms.ToolStripStatusLabel(); + this.toolStripStatusLabel4 = new System.Windows.Forms.ToolStripStatusLabel(); + this.lbl_count_node = new System.Windows.Forms.ToolStripStatusLabel(); + this.toolStripProgressBar1 = new System.Windows.Forms.ToolStripProgressBar(); + this.toolStripStatusLabel2 = new System.Windows.Forms.ToolStripStatusLabel(); + this.toolStripStatusLabel3 = new System.Windows.Forms.ToolStripStatusLabel(); + this.timer1 = new System.Windows.Forms.Timer(this.components); + this.tabControl1 = new System.Windows.Forms.TabControl(); + this.tabPage1 = new System.Windows.Forms.TabPage(); + this.tabPage2 = new System.Windows.Forms.TabPage(); + this.listView2 = new System.Windows.Forms.ListView(); + this.columnHeader2 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.columnHeader6 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.columnHeader3 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.columnHeader5 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.tabPage3 = new System.Windows.Forms.TabPage(); + this.listView3 = new System.Windows.Forms.ListView(); + this.columnHeader7 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.columnHeader8 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.columnHeader9 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.columnHeader10 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.contextMenuStrip3 = new System.Windows.Forms.ContextMenuStrip(this.components); + this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem(); + this.menuStrip1.SuspendLayout(); + this.contextMenuStrip1.SuspendLayout(); + this.statusStrip1.SuspendLayout(); + this.tabControl1.SuspendLayout(); + this.tabPage1.SuspendLayout(); + this.tabPage2.SuspendLayout(); + this.tabPage3.SuspendLayout(); + this.contextMenuStrip3.SuspendLayout(); + this.SuspendLayout(); + // + // menuStrip1 + // + resources.ApplyResources(this.menuStrip1, "menuStrip1"); + this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.钱包WToolStripMenuItem, + this.交易TToolStripMenuItem, + this.高级AToolStripMenuItem, + this.帮助HToolStripMenuItem}); + this.menuStrip1.Name = "menuStrip1"; + // + // 钱包WToolStripMenuItem + // + resources.ApplyResources(this.钱包WToolStripMenuItem, "钱包WToolStripMenuItem"); + this.钱包WToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.创建钱包数据库NToolStripMenuItem, + this.打开钱包数据库OToolStripMenuItem, + this.toolStripSeparator1, + this.修改密码CToolStripMenuItem, + this.toolStripSeparator2, + this.退出XToolStripMenuItem}); + this.钱包WToolStripMenuItem.Name = "钱包WToolStripMenuItem"; + // + // 创建钱包数据库NToolStripMenuItem + // + resources.ApplyResources(this.创建钱包数据库NToolStripMenuItem, "创建钱包数据库NToolStripMenuItem"); + this.创建钱包数据库NToolStripMenuItem.Name = "创建钱包数据库NToolStripMenuItem"; + this.创建钱包数据库NToolStripMenuItem.Click += new System.EventHandler(this.创建钱包数据库NToolStripMenuItem_Click); + // + // 打开钱包数据库OToolStripMenuItem + // + resources.ApplyResources(this.打开钱包数据库OToolStripMenuItem, "打开钱包数据库OToolStripMenuItem"); + this.打开钱包数据库OToolStripMenuItem.Name = "打开钱包数据库OToolStripMenuItem"; + this.打开钱包数据库OToolStripMenuItem.Click += new System.EventHandler(this.打开钱包数据库OToolStripMenuItem_Click); + // + // toolStripSeparator1 + // + resources.ApplyResources(this.toolStripSeparator1, "toolStripSeparator1"); + this.toolStripSeparator1.Name = "toolStripSeparator1"; + // + // 修改密码CToolStripMenuItem + // + resources.ApplyResources(this.修改密码CToolStripMenuItem, "修改密码CToolStripMenuItem"); + this.修改密码CToolStripMenuItem.Name = "修改密码CToolStripMenuItem"; + this.修改密码CToolStripMenuItem.Click += new System.EventHandler(this.修改密码CToolStripMenuItem_Click); + // + // toolStripSeparator2 + // + resources.ApplyResources(this.toolStripSeparator2, "toolStripSeparator2"); + this.toolStripSeparator2.Name = "toolStripSeparator2"; + // + // 退出XToolStripMenuItem + // + resources.ApplyResources(this.退出XToolStripMenuItem, "退出XToolStripMenuItem"); + this.退出XToolStripMenuItem.Name = "退出XToolStripMenuItem"; + this.退出XToolStripMenuItem.Click += new System.EventHandler(this.退出XToolStripMenuItem_Click); + // + // 交易TToolStripMenuItem + // + resources.ApplyResources(this.交易TToolStripMenuItem, "交易TToolStripMenuItem"); + this.交易TToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.转账TToolStripMenuItem, + this.toolStripSeparator5, + this.签名SToolStripMenuItem}); + this.交易TToolStripMenuItem.Name = "交易TToolStripMenuItem"; + // + // 转账TToolStripMenuItem + // + resources.ApplyResources(this.转账TToolStripMenuItem, "转账TToolStripMenuItem"); + this.转账TToolStripMenuItem.Name = "转账TToolStripMenuItem"; + this.转账TToolStripMenuItem.Click += new System.EventHandler(this.转账TToolStripMenuItem_Click); + // + // toolStripSeparator5 + // + resources.ApplyResources(this.toolStripSeparator5, "toolStripSeparator5"); + this.toolStripSeparator5.Name = "toolStripSeparator5"; + // + // 签名SToolStripMenuItem + // + resources.ApplyResources(this.签名SToolStripMenuItem, "签名SToolStripMenuItem"); + this.签名SToolStripMenuItem.Name = "签名SToolStripMenuItem"; + this.签名SToolStripMenuItem.Click += new System.EventHandler(this.签名SToolStripMenuItem_Click); + // + // 高级AToolStripMenuItem + // + resources.ApplyResources(this.高级AToolStripMenuItem, "高级AToolStripMenuItem"); + this.高级AToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.deployContractToolStripMenuItem, + this.invokeContractToolStripMenuItem, + this.toolStripSeparator11, + this.选举EToolStripMenuItem, + this.signDataToolStripMenuItem, + this.toolStripSeparator9, + this.optionsToolStripMenuItem}); + this.高级AToolStripMenuItem.Name = "高级AToolStripMenuItem"; + // + // deployContractToolStripMenuItem + // + resources.ApplyResources(this.deployContractToolStripMenuItem, "deployContractToolStripMenuItem"); + this.deployContractToolStripMenuItem.Name = "deployContractToolStripMenuItem"; + this.deployContractToolStripMenuItem.Click += new System.EventHandler(this.deployContractToolStripMenuItem_Click); + // + // invokeContractToolStripMenuItem + // + resources.ApplyResources(this.invokeContractToolStripMenuItem, "invokeContractToolStripMenuItem"); + this.invokeContractToolStripMenuItem.Name = "invokeContractToolStripMenuItem"; + this.invokeContractToolStripMenuItem.Click += new System.EventHandler(this.invokeContractToolStripMenuItem_Click); + // + // toolStripSeparator11 + // + resources.ApplyResources(this.toolStripSeparator11, "toolStripSeparator11"); + this.toolStripSeparator11.Name = "toolStripSeparator11"; + // + // 选举EToolStripMenuItem + // + resources.ApplyResources(this.选举EToolStripMenuItem, "选举EToolStripMenuItem"); + this.选举EToolStripMenuItem.Name = "选举EToolStripMenuItem"; + this.选举EToolStripMenuItem.Click += new System.EventHandler(this.选举EToolStripMenuItem_Click); + // + // signDataToolStripMenuItem + // + resources.ApplyResources(this.signDataToolStripMenuItem, "signDataToolStripMenuItem"); + this.signDataToolStripMenuItem.Name = "signDataToolStripMenuItem"; + this.signDataToolStripMenuItem.Click += new System.EventHandler(this.signDataToolStripMenuItem_Click); + // + // toolStripSeparator9 + // + resources.ApplyResources(this.toolStripSeparator9, "toolStripSeparator9"); + this.toolStripSeparator9.Name = "toolStripSeparator9"; + // + // optionsToolStripMenuItem + // + resources.ApplyResources(this.optionsToolStripMenuItem, "optionsToolStripMenuItem"); + this.optionsToolStripMenuItem.Name = "optionsToolStripMenuItem"; + this.optionsToolStripMenuItem.Click += new System.EventHandler(this.optionsToolStripMenuItem_Click); + // + // 帮助HToolStripMenuItem + // + resources.ApplyResources(this.帮助HToolStripMenuItem, "帮助HToolStripMenuItem"); + this.帮助HToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.查看帮助VToolStripMenuItem, + this.官网WToolStripMenuItem, + this.toolStripSeparator3, + this.开发人员工具TToolStripMenuItem, + this.consoleToolStripMenuItem, + this.toolStripSeparator4, + this.关于AntSharesToolStripMenuItem}); + this.帮助HToolStripMenuItem.Name = "帮助HToolStripMenuItem"; + // + // 查看帮助VToolStripMenuItem + // + resources.ApplyResources(this.查看帮助VToolStripMenuItem, "查看帮助VToolStripMenuItem"); + this.查看帮助VToolStripMenuItem.Name = "查看帮助VToolStripMenuItem"; + // + // 官网WToolStripMenuItem + // + resources.ApplyResources(this.官网WToolStripMenuItem, "官网WToolStripMenuItem"); + this.官网WToolStripMenuItem.Name = "官网WToolStripMenuItem"; + this.官网WToolStripMenuItem.Click += new System.EventHandler(this.官网WToolStripMenuItem_Click); + // + // toolStripSeparator3 + // + resources.ApplyResources(this.toolStripSeparator3, "toolStripSeparator3"); + this.toolStripSeparator3.Name = "toolStripSeparator3"; + // + // 开发人员工具TToolStripMenuItem + // + resources.ApplyResources(this.开发人员工具TToolStripMenuItem, "开发人员工具TToolStripMenuItem"); + this.开发人员工具TToolStripMenuItem.Name = "开发人员工具TToolStripMenuItem"; + this.开发人员工具TToolStripMenuItem.Click += new System.EventHandler(this.开发人员工具TToolStripMenuItem_Click); + // + // consoleToolStripMenuItem + // + resources.ApplyResources(this.consoleToolStripMenuItem, "consoleToolStripMenuItem"); + this.consoleToolStripMenuItem.Name = "consoleToolStripMenuItem"; + this.consoleToolStripMenuItem.Click += new System.EventHandler(this.consoleToolStripMenuItem_Click); + // + // toolStripSeparator4 + // + resources.ApplyResources(this.toolStripSeparator4, "toolStripSeparator4"); + this.toolStripSeparator4.Name = "toolStripSeparator4"; + // + // 关于AntSharesToolStripMenuItem + // + resources.ApplyResources(this.关于AntSharesToolStripMenuItem, "关于AntSharesToolStripMenuItem"); + this.关于AntSharesToolStripMenuItem.Name = "关于AntSharesToolStripMenuItem"; + this.关于AntSharesToolStripMenuItem.Click += new System.EventHandler(this.关于AntSharesToolStripMenuItem_Click); + // + // listView1 + // + resources.ApplyResources(this.listView1, "listView1"); + this.listView1.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.columnHeader1, + this.columnHeader4, + this.columnHeader11}); + this.listView1.ContextMenuStrip = this.contextMenuStrip1; + this.listView1.FullRowSelect = true; + this.listView1.GridLines = true; + this.listView1.Groups.AddRange(new System.Windows.Forms.ListViewGroup[] { + ((System.Windows.Forms.ListViewGroup)(resources.GetObject("listView1.Groups"))), + ((System.Windows.Forms.ListViewGroup)(resources.GetObject("listView1.Groups1"))), + ((System.Windows.Forms.ListViewGroup)(resources.GetObject("listView1.Groups2")))}); + this.listView1.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.Nonclickable; + this.listView1.HideSelection = false; + this.listView1.Name = "listView1"; + this.listView1.UseCompatibleStateImageBehavior = false; + this.listView1.View = System.Windows.Forms.View.Details; + this.listView1.DoubleClick += new System.EventHandler(this.listView1_DoubleClick); + // + // columnHeader1 + // + resources.ApplyResources(this.columnHeader1, "columnHeader1"); + // + // columnHeader4 + // + resources.ApplyResources(this.columnHeader4, "columnHeader4"); + // + // columnHeader11 + // + resources.ApplyResources(this.columnHeader11, "columnHeader11"); + // + // contextMenuStrip1 + // + resources.ApplyResources(this.contextMenuStrip1, "contextMenuStrip1"); + this.contextMenuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.创建新地址NToolStripMenuItem, + this.导入私钥IToolStripMenuItem, + this.创建智能合约SToolStripMenuItem, + this.toolStripSeparator6, + this.查看私钥VToolStripMenuItem, + this.viewContractToolStripMenuItem, + this.voteToolStripMenuItem, + this.复制到剪贴板CToolStripMenuItem, + this.删除DToolStripMenuItem}); + this.contextMenuStrip1.Name = "contextMenuStrip1"; + this.contextMenuStrip1.Opening += new System.ComponentModel.CancelEventHandler(this.contextMenuStrip1_Opening); + // + // 创建新地址NToolStripMenuItem + // + resources.ApplyResources(this.创建新地址NToolStripMenuItem, "创建新地址NToolStripMenuItem"); + this.创建新地址NToolStripMenuItem.Name = "创建新地址NToolStripMenuItem"; + this.创建新地址NToolStripMenuItem.Click += new System.EventHandler(this.创建新地址NToolStripMenuItem_Click); + // + // 导入私钥IToolStripMenuItem + // + resources.ApplyResources(this.导入私钥IToolStripMenuItem, "导入私钥IToolStripMenuItem"); + this.导入私钥IToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.importWIFToolStripMenuItem, + this.toolStripSeparator10, + this.importWatchOnlyAddressToolStripMenuItem}); + this.导入私钥IToolStripMenuItem.Name = "导入私钥IToolStripMenuItem"; + // + // importWIFToolStripMenuItem + // + resources.ApplyResources(this.importWIFToolStripMenuItem, "importWIFToolStripMenuItem"); + this.importWIFToolStripMenuItem.Name = "importWIFToolStripMenuItem"; + this.importWIFToolStripMenuItem.Click += new System.EventHandler(this.importWIFToolStripMenuItem_Click); + // + // toolStripSeparator10 + // + resources.ApplyResources(this.toolStripSeparator10, "toolStripSeparator10"); + this.toolStripSeparator10.Name = "toolStripSeparator10"; + // + // importWatchOnlyAddressToolStripMenuItem + // + resources.ApplyResources(this.importWatchOnlyAddressToolStripMenuItem, "importWatchOnlyAddressToolStripMenuItem"); + this.importWatchOnlyAddressToolStripMenuItem.Name = "importWatchOnlyAddressToolStripMenuItem"; + this.importWatchOnlyAddressToolStripMenuItem.Click += new System.EventHandler(this.importWatchOnlyAddressToolStripMenuItem_Click); + // + // 创建智能合约SToolStripMenuItem + // + resources.ApplyResources(this.创建智能合约SToolStripMenuItem, "创建智能合约SToolStripMenuItem"); + this.创建智能合约SToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.多方签名MToolStripMenuItem, + this.toolStripSeparator12, + this.自定义CToolStripMenuItem}); + this.创建智能合约SToolStripMenuItem.Name = "创建智能合约SToolStripMenuItem"; + // + // 多方签名MToolStripMenuItem + // + resources.ApplyResources(this.多方签名MToolStripMenuItem, "多方签名MToolStripMenuItem"); + this.多方签名MToolStripMenuItem.Name = "多方签名MToolStripMenuItem"; + this.多方签名MToolStripMenuItem.Click += new System.EventHandler(this.多方签名MToolStripMenuItem_Click); + // + // toolStripSeparator12 + // + resources.ApplyResources(this.toolStripSeparator12, "toolStripSeparator12"); + this.toolStripSeparator12.Name = "toolStripSeparator12"; + // + // 自定义CToolStripMenuItem + // + resources.ApplyResources(this.自定义CToolStripMenuItem, "自定义CToolStripMenuItem"); + this.自定义CToolStripMenuItem.Name = "自定义CToolStripMenuItem"; + this.自定义CToolStripMenuItem.Click += new System.EventHandler(this.自定义CToolStripMenuItem_Click); + // + // toolStripSeparator6 + // + resources.ApplyResources(this.toolStripSeparator6, "toolStripSeparator6"); + this.toolStripSeparator6.Name = "toolStripSeparator6"; + // + // 查看私钥VToolStripMenuItem + // + resources.ApplyResources(this.查看私钥VToolStripMenuItem, "查看私钥VToolStripMenuItem"); + this.查看私钥VToolStripMenuItem.Name = "查看私钥VToolStripMenuItem"; + this.查看私钥VToolStripMenuItem.Click += new System.EventHandler(this.查看私钥VToolStripMenuItem_Click); + // + // viewContractToolStripMenuItem + // + resources.ApplyResources(this.viewContractToolStripMenuItem, "viewContractToolStripMenuItem"); + this.viewContractToolStripMenuItem.Name = "viewContractToolStripMenuItem"; + this.viewContractToolStripMenuItem.Click += new System.EventHandler(this.viewContractToolStripMenuItem_Click); + // + // voteToolStripMenuItem + // + resources.ApplyResources(this.voteToolStripMenuItem, "voteToolStripMenuItem"); + this.voteToolStripMenuItem.Name = "voteToolStripMenuItem"; + this.voteToolStripMenuItem.Click += new System.EventHandler(this.voteToolStripMenuItem_Click); + // + // 复制到剪贴板CToolStripMenuItem + // + resources.ApplyResources(this.复制到剪贴板CToolStripMenuItem, "复制到剪贴板CToolStripMenuItem"); + this.复制到剪贴板CToolStripMenuItem.Name = "复制到剪贴板CToolStripMenuItem"; + this.复制到剪贴板CToolStripMenuItem.Click += new System.EventHandler(this.复制到剪贴板CToolStripMenuItem_Click); + // + // 删除DToolStripMenuItem + // + resources.ApplyResources(this.删除DToolStripMenuItem, "删除DToolStripMenuItem"); + this.删除DToolStripMenuItem.Name = "删除DToolStripMenuItem"; + this.删除DToolStripMenuItem.Click += new System.EventHandler(this.删除DToolStripMenuItem_Click); + // + // statusStrip1 + // + resources.ApplyResources(this.statusStrip1, "statusStrip1"); + this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.toolStripStatusLabel1, + this.lbl_height, + this.toolStripStatusLabel4, + this.lbl_count_node, + this.toolStripProgressBar1, + this.toolStripStatusLabel2, + this.toolStripStatusLabel3}); + this.statusStrip1.LayoutStyle = System.Windows.Forms.ToolStripLayoutStyle.HorizontalStackWithOverflow; + this.statusStrip1.Name = "statusStrip1"; + this.statusStrip1.SizingGrip = false; + // + // toolStripStatusLabel1 + // + resources.ApplyResources(this.toolStripStatusLabel1, "toolStripStatusLabel1"); + this.toolStripStatusLabel1.Name = "toolStripStatusLabel1"; + // + // lbl_height + // + resources.ApplyResources(this.lbl_height, "lbl_height"); + this.lbl_height.Name = "lbl_height"; + // + // toolStripStatusLabel4 + // + resources.ApplyResources(this.toolStripStatusLabel4, "toolStripStatusLabel4"); + this.toolStripStatusLabel4.Name = "toolStripStatusLabel4"; + // + // lbl_count_node + // + resources.ApplyResources(this.lbl_count_node, "lbl_count_node"); + this.lbl_count_node.Name = "lbl_count_node"; + // + // toolStripProgressBar1 + // + resources.ApplyResources(this.toolStripProgressBar1, "toolStripProgressBar1"); + this.toolStripProgressBar1.Alignment = System.Windows.Forms.ToolStripItemAlignment.Right; + this.toolStripProgressBar1.Maximum = 15; + this.toolStripProgressBar1.Name = "toolStripProgressBar1"; + this.toolStripProgressBar1.Step = 1; + // + // toolStripStatusLabel2 + // + resources.ApplyResources(this.toolStripStatusLabel2, "toolStripStatusLabel2"); + this.toolStripStatusLabel2.Alignment = System.Windows.Forms.ToolStripItemAlignment.Right; + this.toolStripStatusLabel2.Name = "toolStripStatusLabel2"; + // + // toolStripStatusLabel3 + // + resources.ApplyResources(this.toolStripStatusLabel3, "toolStripStatusLabel3"); + this.toolStripStatusLabel3.IsLink = true; + this.toolStripStatusLabel3.Name = "toolStripStatusLabel3"; + this.toolStripStatusLabel3.Click += new System.EventHandler(this.toolStripStatusLabel3_Click); + // + // timer1 + // + this.timer1.Enabled = true; + this.timer1.Interval = 500; + this.timer1.Tick += new System.EventHandler(this.timer1_Tick); + // + // tabControl1 + // + resources.ApplyResources(this.tabControl1, "tabControl1"); + this.tabControl1.Controls.Add(this.tabPage1); + this.tabControl1.Controls.Add(this.tabPage2); + this.tabControl1.Controls.Add(this.tabPage3); + this.tabControl1.Name = "tabControl1"; + this.tabControl1.SelectedIndex = 0; + // + // tabPage1 + // + resources.ApplyResources(this.tabPage1, "tabPage1"); + this.tabPage1.Controls.Add(this.listView1); + this.tabPage1.Name = "tabPage1"; + this.tabPage1.UseVisualStyleBackColor = true; + // + // tabPage2 + // + resources.ApplyResources(this.tabPage2, "tabPage2"); + this.tabPage2.Controls.Add(this.listView2); + this.tabPage2.Name = "tabPage2"; + this.tabPage2.UseVisualStyleBackColor = true; + // + // listView2 + // + resources.ApplyResources(this.listView2, "listView2"); + this.listView2.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.columnHeader2, + this.columnHeader6, + this.columnHeader3, + this.columnHeader5}); + this.listView2.FullRowSelect = true; + this.listView2.GridLines = true; + this.listView2.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.Nonclickable; + this.listView2.HideSelection = false; + this.listView2.Name = "listView2"; + this.listView2.ShowGroups = false; + this.listView2.UseCompatibleStateImageBehavior = false; + this.listView2.View = System.Windows.Forms.View.Details; + this.listView2.DoubleClick += new System.EventHandler(this.listView2_DoubleClick); + // + // columnHeader2 + // + resources.ApplyResources(this.columnHeader2, "columnHeader2"); + // + // columnHeader6 + // + resources.ApplyResources(this.columnHeader6, "columnHeader6"); + // + // columnHeader3 + // + resources.ApplyResources(this.columnHeader3, "columnHeader3"); + // + // columnHeader5 + // + resources.ApplyResources(this.columnHeader5, "columnHeader5"); + // + // tabPage3 + // + resources.ApplyResources(this.tabPage3, "tabPage3"); + this.tabPage3.Controls.Add(this.listView3); + this.tabPage3.Name = "tabPage3"; + this.tabPage3.UseVisualStyleBackColor = true; + // + // listView3 + // + resources.ApplyResources(this.listView3, "listView3"); + this.listView3.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.columnHeader7, + this.columnHeader8, + this.columnHeader9, + this.columnHeader10}); + this.listView3.ContextMenuStrip = this.contextMenuStrip3; + this.listView3.FullRowSelect = true; + this.listView3.GridLines = true; + this.listView3.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.Nonclickable; + this.listView3.HideSelection = false; + this.listView3.Name = "listView3"; + this.listView3.ShowGroups = false; + this.listView3.UseCompatibleStateImageBehavior = false; + this.listView3.View = System.Windows.Forms.View.Details; + this.listView3.DoubleClick += new System.EventHandler(this.listView3_DoubleClick); + // + // columnHeader7 + // + resources.ApplyResources(this.columnHeader7, "columnHeader7"); + // + // columnHeader8 + // + resources.ApplyResources(this.columnHeader8, "columnHeader8"); + // + // columnHeader9 + // + resources.ApplyResources(this.columnHeader9, "columnHeader9"); + // + // columnHeader10 + // + resources.ApplyResources(this.columnHeader10, "columnHeader10"); + // + // contextMenuStrip3 + // + resources.ApplyResources(this.contextMenuStrip3, "contextMenuStrip3"); + this.contextMenuStrip3.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.toolStripMenuItem1}); + this.contextMenuStrip3.Name = "contextMenuStrip3"; + // + // toolStripMenuItem1 + // + resources.ApplyResources(this.toolStripMenuItem1, "toolStripMenuItem1"); + this.toolStripMenuItem1.Name = "toolStripMenuItem1"; + this.toolStripMenuItem1.Click += new System.EventHandler(this.toolStripMenuItem1_Click); + // + // MainForm + // + resources.ApplyResources(this, "$this"); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.tabControl1); + this.Controls.Add(this.statusStrip1); + this.Controls.Add(this.menuStrip1); + this.MainMenuStrip = this.menuStrip1; + this.Name = "MainForm"; + this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.MainForm_FormClosing); + this.Load += new System.EventHandler(this.MainForm_Load); + this.menuStrip1.ResumeLayout(false); + this.menuStrip1.PerformLayout(); + this.contextMenuStrip1.ResumeLayout(false); + this.statusStrip1.ResumeLayout(false); + this.statusStrip1.PerformLayout(); + this.tabControl1.ResumeLayout(false); + this.tabPage1.ResumeLayout(false); + this.tabPage2.ResumeLayout(false); + this.tabPage3.ResumeLayout(false); + this.contextMenuStrip3.ResumeLayout(false); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.MenuStrip menuStrip1; + private System.Windows.Forms.ToolStripMenuItem 钱包WToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem 创建钱包数据库NToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem 打开钱包数据库OToolStripMenuItem; + private System.Windows.Forms.ToolStripSeparator toolStripSeparator1; + private System.Windows.Forms.ToolStripMenuItem 修改密码CToolStripMenuItem; + private System.Windows.Forms.ColumnHeader columnHeader1; + private System.Windows.Forms.ToolStripSeparator toolStripSeparator2; + private System.Windows.Forms.ToolStripMenuItem 退出XToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem 帮助HToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem 查看帮助VToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem 官网WToolStripMenuItem; + private System.Windows.Forms.ToolStripSeparator toolStripSeparator3; + private System.Windows.Forms.ToolStripMenuItem 开发人员工具TToolStripMenuItem; + private System.Windows.Forms.ToolStripSeparator toolStripSeparator4; + private System.Windows.Forms.ToolStripMenuItem 关于AntSharesToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem 交易TToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem 签名SToolStripMenuItem; + private System.Windows.Forms.ContextMenuStrip contextMenuStrip1; + private System.Windows.Forms.ToolStripMenuItem 创建新地址NToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem 导入私钥IToolStripMenuItem; + private System.Windows.Forms.ToolStripSeparator toolStripSeparator6; + private System.Windows.Forms.ToolStripMenuItem 查看私钥VToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem 复制到剪贴板CToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem 删除DToolStripMenuItem; + private System.Windows.Forms.ToolStripSeparator toolStripSeparator5; + private System.Windows.Forms.StatusStrip statusStrip1; + private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabel1; + private System.Windows.Forms.ToolStripStatusLabel lbl_height; + private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabel4; + private System.Windows.Forms.ToolStripStatusLabel lbl_count_node; + private System.Windows.Forms.Timer timer1; + private System.Windows.Forms.TabControl tabControl1; + private System.Windows.Forms.TabPage tabPage1; + private System.Windows.Forms.TabPage tabPage2; + private System.Windows.Forms.ListView listView2; + private System.Windows.Forms.ColumnHeader columnHeader2; + private System.Windows.Forms.ColumnHeader columnHeader3; + private System.Windows.Forms.ToolStripMenuItem 转账TToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem 高级AToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem 创建智能合约SToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem 多方签名MToolStripMenuItem; + private System.Windows.Forms.ListView listView1; + private System.Windows.Forms.ColumnHeader columnHeader5; + private System.Windows.Forms.ColumnHeader columnHeader6; + private System.Windows.Forms.ToolStripMenuItem importWIFToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem 选举EToolStripMenuItem; + private System.Windows.Forms.TabPage tabPage3; + private System.Windows.Forms.ListView listView3; + private System.Windows.Forms.ColumnHeader columnHeader7; + private System.Windows.Forms.ColumnHeader columnHeader8; + private System.Windows.Forms.ColumnHeader columnHeader9; + private System.Windows.Forms.ToolStripProgressBar toolStripProgressBar1; + private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabel2; + private System.Windows.Forms.ToolStripMenuItem 自定义CToolStripMenuItem; + private System.Windows.Forms.ColumnHeader columnHeader10; + private System.Windows.Forms.ContextMenuStrip contextMenuStrip3; + private System.Windows.Forms.ToolStripMenuItem toolStripMenuItem1; + private System.Windows.Forms.ToolStripSeparator toolStripSeparator9; + private System.Windows.Forms.ToolStripMenuItem optionsToolStripMenuItem; + private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabel3; + private System.Windows.Forms.ToolStripMenuItem viewContractToolStripMenuItem; + private System.Windows.Forms.ToolStripSeparator toolStripSeparator10; + private System.Windows.Forms.ToolStripMenuItem importWatchOnlyAddressToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem voteToolStripMenuItem; + private System.Windows.Forms.ColumnHeader columnHeader4; + private System.Windows.Forms.ColumnHeader columnHeader11; + private System.Windows.Forms.ToolStripSeparator toolStripSeparator11; + private System.Windows.Forms.ToolStripMenuItem deployContractToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem invokeContractToolStripMenuItem; + private System.Windows.Forms.ToolStripSeparator toolStripSeparator12; + private System.Windows.Forms.ToolStripMenuItem signDataToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem consoleToolStripMenuItem; + } +} + diff --git a/src/Neo.GUI/GUI/MainForm.cs b/src/Neo.GUI/GUI/MainForm.cs new file mode 100644 index 0000000000..d8e89c083a --- /dev/null +++ b/src/Neo.GUI/GUI/MainForm.cs @@ -0,0 +1,615 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-gui is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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.IO.Actors; +using Neo.Ledger; +using Neo.Network.P2P.Payloads; +using Neo.Properties; +using Neo.SmartContract; +using Neo.SmartContract.Native; +using Neo.VM; +using Neo.Wallets; +using Neo.Wallets.NEP6; +using System; +using System.ComponentModel; +using System.Diagnostics; +using System.Drawing; +using System.IO; +using System.Linq; +using System.Numerics; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Security.Cryptography; +using System.Windows.Forms; +using System.Xml.Linq; +using static Neo.Program; +using static Neo.SmartContract.Helper; +using VMArray = Neo.VM.Types.Array; + +namespace Neo.GUI +{ + internal partial class MainForm : Form + { + private bool check_nep5_balance = false; + private DateTime persistence_time = DateTime.MinValue; + private IActorRef actor; + + public MainForm(XDocument xdoc = null) + { + InitializeComponent(); + + toolStripProgressBar1.Maximum = (int)Service.NeoSystem.Settings.TimePerBlock.TotalSeconds; + + if (xdoc != null) + { + Version version = Assembly.GetExecutingAssembly().GetName().Version; + Version latest = Version.Parse(xdoc.Element("update").Attribute("latest").Value); + if (version < latest) + { + toolStripStatusLabel3.Tag = xdoc; + toolStripStatusLabel3.Text += $": {latest}"; + toolStripStatusLabel3.Visible = true; + } + } + } + + private void AddAccount(WalletAccount account, bool selected = false) + { + ListViewItem item = listView1.Items[account.Address]; + if (item != null) + { + if (!account.WatchOnly && ((WalletAccount)item.Tag).WatchOnly) + { + listView1.Items.Remove(item); + item = null; + } + } + if (item == null) + { + string groupName = account.WatchOnly ? "watchOnlyGroup" : IsSignatureContract(account.Contract.Script) ? "standardContractGroup" : "nonstandardContractGroup"; + item = listView1.Items.Add(new ListViewItem(new[] + { + new ListViewItem.ListViewSubItem + { + Name = "address", + Text = account.Address + }, + new ListViewItem.ListViewSubItem + { + Name = NativeContract.NEO.Symbol + }, + new ListViewItem.ListViewSubItem + { + Name = NativeContract.GAS.Symbol + } + }, -1, listView1.Groups[groupName]) + { + Name = account.Address, + Tag = account + }); + } + item.Selected = selected; + } + + private void Blockchain_PersistCompleted(Blockchain.PersistCompleted e) + { + if (IsDisposed) return; + persistence_time = DateTime.UtcNow; + if (Service.CurrentWallet != null) + check_nep5_balance = true; + BeginInvoke(new Action(RefreshConfirmations)); + } + + private static void OpenBrowser(string url) + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + Process.Start(new ProcessStartInfo("cmd", $"/c start {url}")); + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + Process.Start("xdg-open", url); + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + Process.Start("open", url); + } + } + + private void Service_WalletChanged(object sender, Wallet wallet) + { + if (InvokeRequired) + { + Invoke(new EventHandler(Service_WalletChanged), sender, wallet); + return; + } + + listView3.Items.Clear(); + 修改密码CToolStripMenuItem.Enabled = wallet != null; + 交易TToolStripMenuItem.Enabled = wallet != null; + signDataToolStripMenuItem.Enabled = wallet != null; + deployContractToolStripMenuItem.Enabled = wallet != null; + invokeContractToolStripMenuItem.Enabled = wallet != null; + 选举EToolStripMenuItem.Enabled = wallet != null; + 创建新地址NToolStripMenuItem.Enabled = wallet != null; + 导入私钥IToolStripMenuItem.Enabled = wallet != null; + 创建智能合约SToolStripMenuItem.Enabled = wallet != null; + listView1.Items.Clear(); + if (wallet != null) + { + foreach (WalletAccount account in wallet.GetAccounts().ToArray()) + { + AddAccount(account); + } + } + check_nep5_balance = true; + } + + private void RefreshConfirmations() + { + foreach (ListViewItem item in listView3.Items) + { + uint? height = item.Tag as uint?; + int? confirmations = (int)NativeContract.Ledger.CurrentIndex(Service.NeoSystem.StoreView) - (int?)height + 1; + if (confirmations <= 0) confirmations = null; + item.SubItems["confirmations"].Text = confirmations?.ToString() ?? Strings.Unconfirmed; + } + } + + private void MainForm_Load(object sender, EventArgs e) + { + actor = Service.NeoSystem.ActorSystem.ActorOf(EventWrapper.Props(Blockchain_PersistCompleted)); + Service.WalletChanged += Service_WalletChanged; + } + + private void MainForm_FormClosing(object sender, FormClosingEventArgs e) + { + if (actor != null) + Service.NeoSystem.ActorSystem.Stop(actor); + Service.WalletChanged -= Service_WalletChanged; + } + + private void timer1_Tick(object sender, EventArgs e) + { + uint height = NativeContract.Ledger.CurrentIndex(Service.NeoSystem.StoreView); + uint headerHeight = Service.NeoSystem.HeaderCache.Last?.Index ?? height; + + lbl_height.Text = $"{height}/{headerHeight}"; + lbl_count_node.Text = Service.LocalNode.ConnectedCount.ToString(); + TimeSpan persistence_span = DateTime.UtcNow - persistence_time; + if (persistence_span < TimeSpan.Zero) persistence_span = TimeSpan.Zero; + if (persistence_span > Service.NeoSystem.Settings.TimePerBlock) + { + toolStripProgressBar1.Style = ProgressBarStyle.Marquee; + } + else + { + toolStripProgressBar1.Value = persistence_span.Seconds; + toolStripProgressBar1.Style = ProgressBarStyle.Blocks; + } + if (Service.CurrentWallet is null) return; + if (!check_nep5_balance || persistence_span < TimeSpan.FromSeconds(2)) return; + 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(); + foreach (UInt160 assetId in NEP5Watched) + { + byte[] script; + using (ScriptBuilder sb = new ScriptBuilder()) + { + for (int i = addresses.Length - 1; i >= 0; i--) + sb.EmitDynamicCall(assetId, "balanceOf", addresses[i]); + sb.Emit(OpCode.DEPTH, OpCode.PACK); + sb.EmitDynamicCall(assetId, "decimals"); + sb.EmitDynamicCall(assetId, "name"); + script = sb.ToArray(); + } + using ApplicationEngine engine = ApplicationEngine.Run(script, snapshot, gas: 0_20000000L * addresses.Length); + if (engine.State.HasFlag(VMState.FAULT)) continue; + string name = engine.ResultStack.Pop().GetString(); + byte decimals = (byte)engine.ResultStack.Pop().GetInteger(); + BigInteger[] balances = ((VMArray)engine.ResultStack.Pop()).Select(p => p.GetInteger()).ToArray(); + string symbol = null; + if (assetId.Equals(NativeContract.NEO.Hash)) + symbol = NativeContract.NEO.Symbol; + else if (assetId.Equals(NativeContract.GAS.Hash)) + symbol = NativeContract.GAS.Symbol; + if (symbol != null) + for (int i = 0; i < addresses.Length; i++) + listView1.Items[addresses[i].ToAddress(Service.NeoSystem.Settings.AddressVersion)].SubItems[symbol].Text = new BigDecimal(balances[i], decimals).ToString(); + BigInteger amount = balances.Sum(); + if (amount == 0) + { + listView2.Items.RemoveByKey(assetId.ToString()); + continue; + } + BigDecimal balance = new BigDecimal(amount, decimals); + if (listView2.Items.ContainsKey(assetId.ToString())) + { + listView2.Items[assetId.ToString()].SubItems["value"].Text = balance.ToString(); + } + else + { + listView2.Items.Add(new ListViewItem(new[] + { + new ListViewItem.ListViewSubItem + { + Name = "name", + Text = name + }, + new ListViewItem.ListViewSubItem + { + Name = "type", + Text = "NEP-5" + }, + new ListViewItem.ListViewSubItem + { + Name = "value", + Text = balance.ToString() + }, + new ListViewItem.ListViewSubItem + { + ForeColor = Color.Gray, + Name = "issuer", + Text = $"ScriptHash:{assetId}" + } + }, -1) + { + Name = assetId.ToString(), + UseItemStyleForSubItems = false + }); + } + } + } + + private void 创建钱包数据库NToolStripMenuItem_Click(object sender, EventArgs e) + { + using CreateWalletDialog dialog = new CreateWalletDialog(); + if (dialog.ShowDialog() != DialogResult.OK) return; + Service.CreateWallet(dialog.WalletPath, dialog.Password); + } + + private void 打开钱包数据库OToolStripMenuItem_Click(object sender, EventArgs e) + { + using OpenWalletDialog dialog = new OpenWalletDialog(); + if (dialog.ShowDialog() != DialogResult.OK) return; + try + { + Service.OpenWallet(dialog.WalletPath, dialog.Password); + } + catch (CryptographicException) + { + MessageBox.Show(Strings.PasswordIncorrect); + } + } + + private void 修改密码CToolStripMenuItem_Click(object sender, EventArgs e) + { + using ChangePasswordDialog dialog = new ChangePasswordDialog(); + if (dialog.ShowDialog() != DialogResult.OK) return; + if (Service.CurrentWallet.ChangePassword(dialog.OldPassword, dialog.NewPassword)) + { + if (Service.CurrentWallet is NEP6Wallet wallet) + wallet.Save(); + MessageBox.Show(Strings.ChangePasswordSuccessful); + } + else + { + MessageBox.Show(Strings.PasswordIncorrect); + } + } + + private void 退出XToolStripMenuItem_Click(object sender, EventArgs e) + { + Close(); + } + + private void 转账TToolStripMenuItem_Click(object sender, EventArgs e) + { + Transaction tx; + using (TransferDialog dialog = new TransferDialog()) + { + if (dialog.ShowDialog() != DialogResult.OK) return; + tx = dialog.GetTransaction(); + } + using (InvokeContractDialog dialog = new InvokeContractDialog(tx)) + { + if (dialog.ShowDialog() != DialogResult.OK) return; + tx = dialog.GetTransaction(); + } + Helper.SignAndShowInformation(tx); + } + + private void 签名SToolStripMenuItem_Click(object sender, EventArgs e) + { + using SigningTxDialog dialog = new SigningTxDialog(); + dialog.ShowDialog(); + } + + private void deployContractToolStripMenuItem_Click(object sender, EventArgs e) + { + try + { + byte[] script; + using (DeployContractDialog dialog = new DeployContractDialog()) + { + if (dialog.ShowDialog() != DialogResult.OK) return; + script = dialog.GetScript(); + } + using (InvokeContractDialog dialog = new InvokeContractDialog(script)) + { + if (dialog.ShowDialog() != DialogResult.OK) return; + Helper.SignAndShowInformation(dialog.GetTransaction()); + } + } + catch { } + } + + private void invokeContractToolStripMenuItem_Click(object sender, EventArgs e) + { + using InvokeContractDialog dialog = new InvokeContractDialog(); + if (dialog.ShowDialog() != DialogResult.OK) return; + try + { + Helper.SignAndShowInformation(dialog.GetTransaction()); + } + catch + { + return; + } + } + + private void 选举EToolStripMenuItem_Click(object sender, EventArgs e) + { + try + { + byte[] script; + using (ElectionDialog dialog = new ElectionDialog()) + { + if (dialog.ShowDialog() != DialogResult.OK) return; + script = dialog.GetScript(); + } + using (InvokeContractDialog dialog = new InvokeContractDialog(script)) + { + if (dialog.ShowDialog() != DialogResult.OK) return; + Helper.SignAndShowInformation(dialog.GetTransaction()); + } + } + catch { } + } + + private void signDataToolStripMenuItem_Click(object sender, EventArgs e) + { + using SigningDialog dialog = new SigningDialog(); + dialog.ShowDialog(); + } + + private void optionsToolStripMenuItem_Click(object sender, EventArgs e) + { + } + + private void 官网WToolStripMenuItem_Click(object sender, EventArgs e) + { + OpenBrowser("https://neo.org/"); + } + + private void 开发人员工具TToolStripMenuItem_Click(object sender, EventArgs e) + { + Helper.Show(); + } + + private void consoleToolStripMenuItem_Click(object sender, EventArgs e) + { + Helper.Show(); + } + + private void 关于AntSharesToolStripMenuItem_Click(object sender, EventArgs e) + { + MessageBox.Show($"{Strings.AboutMessage} {Strings.AboutVersion}{Assembly.GetExecutingAssembly().GetName().Version}", Strings.About); + } + + private void contextMenuStrip1_Opening(object sender, CancelEventArgs e) + { + 查看私钥VToolStripMenuItem.Enabled = + listView1.SelectedIndices.Count == 1 && + !((WalletAccount)listView1.SelectedItems[0].Tag).WatchOnly && + IsSignatureContract(((WalletAccount)listView1.SelectedItems[0].Tag).Contract.Script); + viewContractToolStripMenuItem.Enabled = + listView1.SelectedIndices.Count == 1 && + !((WalletAccount)listView1.SelectedItems[0].Tag).WatchOnly; + voteToolStripMenuItem.Enabled = + listView1.SelectedIndices.Count == 1 && + !((WalletAccount)listView1.SelectedItems[0].Tag).WatchOnly && + !string.IsNullOrEmpty(listView1.SelectedItems[0].SubItems[NativeContract.NEO.Symbol].Text) && + decimal.Parse(listView1.SelectedItems[0].SubItems[NativeContract.NEO.Symbol].Text) > 0; + 复制到剪贴板CToolStripMenuItem.Enabled = listView1.SelectedIndices.Count == 1; + 删除DToolStripMenuItem.Enabled = listView1.SelectedIndices.Count > 0; + } + + private void 创建新地址NToolStripMenuItem_Click(object sender, EventArgs e) + { + listView1.SelectedIndices.Clear(); + WalletAccount account = Service.CurrentWallet.CreateAccount(); + AddAccount(account, true); + if (Service.CurrentWallet is NEP6Wallet wallet) + wallet.Save(); + } + + private void importWIFToolStripMenuItem_Click(object sender, EventArgs e) + { + using ImportPrivateKeyDialog dialog = new ImportPrivateKeyDialog(); + if (dialog.ShowDialog() != DialogResult.OK) return; + listView1.SelectedIndices.Clear(); + foreach (string wif in dialog.WifStrings) + { + WalletAccount account; + try + { + account = Service.CurrentWallet.Import(wif); + } + catch (FormatException) + { + continue; + } + AddAccount(account, true); + } + if (Service.CurrentWallet is NEP6Wallet wallet) + wallet.Save(); + } + + private void importWatchOnlyAddressToolStripMenuItem_Click(object sender, EventArgs e) + { + string text = InputBox.Show(Strings.Address, Strings.ImportWatchOnlyAddress); + if (string.IsNullOrEmpty(text)) return; + using (StringReader reader = new StringReader(text)) + { + while (true) + { + string address = reader.ReadLine(); + if (address == null) break; + address = address.Trim(); + if (string.IsNullOrEmpty(address)) continue; + UInt160 scriptHash; + try + { + scriptHash = address.ToScriptHash(Service.NeoSystem.Settings.AddressVersion); + } + catch (FormatException) + { + continue; + } + WalletAccount account = Service.CurrentWallet.CreateAccount(scriptHash); + AddAccount(account, true); + } + } + if (Service.CurrentWallet is NEP6Wallet wallet) + wallet.Save(); + } + + private void 多方签名MToolStripMenuItem_Click(object sender, EventArgs e) + { + using CreateMultiSigContractDialog dialog = new CreateMultiSigContractDialog(); + if (dialog.ShowDialog() != DialogResult.OK) return; + Contract contract = dialog.GetContract(); + if (contract == null) + { + MessageBox.Show(Strings.AddContractFailedMessage); + return; + } + WalletAccount account = Service.CurrentWallet.CreateAccount(contract, dialog.GetKey()); + if (Service.CurrentWallet is NEP6Wallet wallet) + wallet.Save(); + listView1.SelectedIndices.Clear(); + AddAccount(account, true); + } + + private void 自定义CToolStripMenuItem_Click(object sender, EventArgs e) + { + using ImportCustomContractDialog dialog = new ImportCustomContractDialog(); + if (dialog.ShowDialog() != DialogResult.OK) return; + Contract contract = dialog.GetContract(); + WalletAccount account = Service.CurrentWallet.CreateAccount(contract, dialog.GetKey()); + if (Service.CurrentWallet is NEP6Wallet wallet) + wallet.Save(); + listView1.SelectedIndices.Clear(); + AddAccount(account, true); + } + + private void 查看私钥VToolStripMenuItem_Click(object sender, EventArgs e) + { + WalletAccount account = (WalletAccount)listView1.SelectedItems[0].Tag; + using ViewPrivateKeyDialog dialog = new ViewPrivateKeyDialog(account); + dialog.ShowDialog(); + } + + private void viewContractToolStripMenuItem_Click(object sender, EventArgs e) + { + WalletAccount account = (WalletAccount)listView1.SelectedItems[0].Tag; + using ViewContractDialog dialog = new ViewContractDialog(account.Contract); + dialog.ShowDialog(); + } + + private void voteToolStripMenuItem_Click(object sender, EventArgs e) + { + try + { + WalletAccount account = (WalletAccount)listView1.SelectedItems[0].Tag; + byte[] script; + using (VotingDialog dialog = new VotingDialog(account.ScriptHash)) + { + if (dialog.ShowDialog() != DialogResult.OK) return; + script = dialog.GetScript(); + } + using (InvokeContractDialog dialog = new InvokeContractDialog(script)) + { + if (dialog.ShowDialog() != DialogResult.OK) return; + Helper.SignAndShowInformation(dialog.GetTransaction()); + } + } + catch { } + } + + private void 复制到剪贴板CToolStripMenuItem_Click(object sender, EventArgs e) + { + try + { + Clipboard.SetText(listView1.SelectedItems[0].Text); + } + catch (ExternalException) { } + } + + private void 删除DToolStripMenuItem_Click(object sender, EventArgs e) + { + if (MessageBox.Show(Strings.DeleteAddressConfirmationMessage, Strings.DeleteAddressConfirmationCaption, MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2) != DialogResult.Yes) + return; + WalletAccount[] accounts = listView1.SelectedItems.OfType().Select(p => (WalletAccount)p.Tag).ToArray(); + foreach (WalletAccount account in accounts) + { + listView1.Items.RemoveByKey(account.Address); + Service.CurrentWallet.DeleteAccount(account.ScriptHash); + } + if (Service.CurrentWallet is NEP6Wallet wallet) + wallet.Save(); + check_nep5_balance = true; + } + + private void toolStripMenuItem1_Click(object sender, EventArgs e) + { + if (listView3.SelectedItems.Count == 0) return; + Clipboard.SetDataObject(listView3.SelectedItems[0].SubItems[1].Text); + } + + private void listView1_DoubleClick(object sender, EventArgs e) + { + if (listView1.SelectedIndices.Count == 0) return; + OpenBrowser($"https://neoscan.io/address/{listView1.SelectedItems[0].Text}"); + } + + private void listView2_DoubleClick(object sender, EventArgs e) + { + if (listView2.SelectedIndices.Count == 0) return; + OpenBrowser($"https://neoscan.io/asset/{listView2.SelectedItems[0].Name[2..]}"); + } + + private void listView3_DoubleClick(object sender, EventArgs e) + { + if (listView3.SelectedIndices.Count == 0) return; + OpenBrowser($"https://neoscan.io/transaction/{listView3.SelectedItems[0].Name[2..]}"); + } + + private void toolStripStatusLabel3_Click(object sender, EventArgs e) + { + using UpdateDialog dialog = new UpdateDialog((XDocument)toolStripStatusLabel3.Tag); + dialog.ShowDialog(); + } + } +} diff --git a/src/Neo.GUI/GUI/MainForm.es-ES.resx b/src/Neo.GUI/GUI/MainForm.es-ES.resx new file mode 100644 index 0000000000..468113ceba --- /dev/null +++ b/src/Neo.GUI/GUI/MainForm.es-ES.resx @@ -0,0 +1,437 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + 210, 22 + + + &Nueva base de datos... + + + 210, 22 + + + &Abrir base de datos... + + + 207, 6 + + + 210, 22 + + + &Cambiar contraseña... + + + 207, 6 + + + 210, 22 + + + &Salir + + + 82, 21 + + + &Monedero + + + 141, 22 + + + &Transferir... + + + 138, 6 + + + 141, 22 + + + &Firma... + + + 89, 21 + + + &Transacción + + + 198, 22 + + + &Desplegar contrato... + + + 198, 22 + + + I&nvocar contrato... + + + 195, 6 + + + 198, 22 + + + &Votación... + + + 198, 22 + + + 195, 6 + + + 198, 22 + + + &Opciones... + + + A&vanzado + + + 259, 22 + + + &Obtener ayuda + + + 259, 22 + + + &Web oficial + + + 256, 6 + + + 259, 22 + + + &Herramienta de desarrollo + + + 259, 22 + + + 256, 6 + + + 259, 22 + + + &Acerca de NEO + + + 56, 21 + + + &Ayuda + + + Dirección + + + 275, 22 + + + Crear &nueva dirección + + + 266, 22 + + + Importar desde &WIF... + + + 263, 6 + + + 266, 22 + + + Importar dirección sólo lectur&a... + + + 275, 22 + + + &Importar + + + 178, 22 + + + &Múltiples firmas... + + + 175, 6 + + + 178, 22 + + + &Personalizado... + + + 275, 22 + + + Crear nueva &dirección de contrato + + + 272, 6 + + + 275, 22 + + + Ver clave &privada + + + 275, 22 + + + Ver c&ontrato + + + 275, 22 + + + &Votar... + + + 275, 22 + + + &Copiar al portapapeles + + + 275, 22 + + + &Eliminar... + + + 276, 186 + + + + AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w + LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACJTeXN0 + ZW0uV2luZG93cy5Gb3Jtcy5MaXN0Vmlld0dyb3VwBAAAAAZIZWFkZXIPSGVhZGVyQWxpZ25tZW50A1Rh + ZwROYW1lAQQCAShTeXN0ZW0uV2luZG93cy5Gb3Jtcy5Ib3Jpem9udGFsQWxpZ25tZW50AgAAAAIAAAAG + AwAAABBDdWVudGEgZXN0w6FuZGFyBfz///8oU3lzdGVtLldpbmRvd3MuRm9ybXMuSG9yaXpvbnRhbEFs + aWdubWVudAEAAAAHdmFsdWVfXwAIAgAAAAAAAAAKBgUAAAAVc3RhbmRhcmRDb250cmFjdEdyb3VwCw== + + + + + AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w + LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACJTeXN0 + ZW0uV2luZG93cy5Gb3Jtcy5MaXN0Vmlld0dyb3VwBAAAAAZIZWFkZXIPSGVhZGVyQWxpZ25tZW50A1Rh + ZwROYW1lAQQCAShTeXN0ZW0uV2luZG93cy5Gb3Jtcy5Ib3Jpem9udGFsQWxpZ25tZW50AgAAAAIAAAAG + AwAAABZEaXJlY2Npw7NuIGRlIGNvbnRyYXRvBfz///8oU3lzdGVtLldpbmRvd3MuRm9ybXMuSG9yaXpv + bnRhbEFsaWdubWVudAEAAAAHdmFsdWVfXwAIAgAAAAAAAAAKBgUAAAAYbm9uc3RhbmRhcmRDb250cmFj + dEdyb3VwCw== + + + + + AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w + LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACJTeXN0 + ZW0uV2luZG93cy5Gb3Jtcy5MaXN0Vmlld0dyb3VwBAAAAAZIZWFkZXIPSGVhZGVyQWxpZ25tZW50A1Rh + ZwROYW1lAQQCAShTeXN0ZW0uV2luZG93cy5Gb3Jtcy5Ib3Jpem9udGFsQWxpZ25tZW50AgAAAAIAAAAG + AwAAABhEaXJlY2Npw7NuIHPDs2xvIGxlY3R1cmEF/P///yhTeXN0ZW0uV2luZG93cy5Gb3Jtcy5Ib3Jp + em9udGFsQWxpZ25tZW50AQAAAAd2YWx1ZV9fAAgCAAAAAAAAAAoGBQAAAA53YXRjaE9ubHlHcm91cAs= + + + + 58, 17 + + + Tamaño: + + + 74, 17 + + + Conectado: + + + 172, 17 + + + Esperando próximo bloque: + + + 152, 17 + + + Descargar nueva versión + + + Cuenta + + + Activo + + + Tipo + + + Saldo + + + Emisor + + + Activos + + + Fecha + + + ID de la transacción + + + Confirmación + + + Tipo + + + 147, 22 + + + &Copiar TXID + + + 148, 26 + + + Historial de transacciones + + \ No newline at end of file diff --git a/src/Neo.GUI/GUI/MainForm.resx b/src/Neo.GUI/GUI/MainForm.resx new file mode 100644 index 0000000000..21c7f5a2b2 --- /dev/null +++ b/src/Neo.GUI/GUI/MainForm.resx @@ -0,0 +1,1488 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + + + 216, 22 + + + &New Wallet Database... + + + 216, 22 + + + &Open Wallet Database... + + + 213, 6 + + + + False + + + 216, 22 + + + &Change Password... + + + 213, 6 + + + 216, 22 + + + E&xit + + + 56, 21 + + + &Wallet + + + 140, 22 + + + &Transfer... + + + 137, 6 + + + 140, 22 + + + &Signature... + + + False + + + 87, 21 + + + &Transaction + + + False + + + 179, 22 + + + &Deploy Contract... + + + False + + + 179, 22 + + + In&voke Contract... + + + 176, 6 + + + False + + + 179, 22 + + + &Election... + + + False + + + 179, 22 + + + &Sign Message... + + + 176, 6 + + + 179, 22 + + + &Options... + + + 77, 21 + + + &Advanced + + + 194, 22 + + + Check for &Help + + + 194, 22 + + + Official &Web + + + 191, 6 + + + + F12 + + + 194, 22 + + + Developer &Tool + + + 194, 22 + + + &Console + + + 191, 6 + + + 194, 22 + + + &About NEO + + + 47, 21 + + + &Help + + + 0, 0 + + + 7, 3, 0, 3 + + + 903, 27 + + + 0 + + + menuStrip1 + + + menuStrip1 + + + System.Windows.Forms.MenuStrip, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 4 + + + Address + + + 300 + + + NEO + + + 120 + + + GAS + + + 120 + + + 348, 17 + + + False + + + 198, 22 + + + Create &New Add. + + + 248, 22 + + + Import from &WIF... + + + 245, 6 + + + 248, 22 + + + Import Watch-Only &Address... + + + False + + + 198, 22 + + + &Import + + + 174, 22 + + + &Multi-Signature... + + + 171, 6 + + + 174, 22 + + + &Custom... + + + False + + + 198, 22 + + + Create Contract &Add. + + + 195, 6 + + + False + + + 198, 22 + + + View &Private Key + + + False + + + 198, 22 + + + View C&ontract + + + False + + + 198, 22 + + + &Vote... + + + False + + + Ctrl+C + + + False + + + 198, 22 + + + &Copy to Clipboard + + + False + + + 198, 22 + + + &Delete... + + + 199, 186 + + + contextMenuStrip1 + + + System.Windows.Forms.ContextMenuStrip, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Fill + + + + AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w + LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACJTeXN0 + ZW0uV2luZG93cy5Gb3Jtcy5MaXN0Vmlld0dyb3VwBAAAAAZIZWFkZXIPSGVhZGVyQWxpZ25tZW50A1Rh + ZwROYW1lAQQCAShTeXN0ZW0uV2luZG93cy5Gb3Jtcy5Ib3Jpem9udGFsQWxpZ25tZW50AgAAAAIAAAAG + AwAAABBTdGFuZGFyZCBBY2NvdW50Bfz///8oU3lzdGVtLldpbmRvd3MuRm9ybXMuSG9yaXpvbnRhbEFs + aWdubWVudAEAAAAHdmFsdWVfXwAIAgAAAAAAAAAKBgUAAAAVc3RhbmRhcmRDb250cmFjdEdyb3VwCw== + + + + + AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w + LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACJTeXN0 + ZW0uV2luZG93cy5Gb3Jtcy5MaXN0Vmlld0dyb3VwBAAAAAZIZWFkZXIPSGVhZGVyQWxpZ25tZW50A1Rh + ZwROYW1lAQQCAShTeXN0ZW0uV2luZG93cy5Gb3Jtcy5Ib3Jpem9udGFsQWxpZ25tZW50AgAAAAIAAAAG + AwAAABBDb250cmFjdCBBZGRyZXNzBfz///8oU3lzdGVtLldpbmRvd3MuRm9ybXMuSG9yaXpvbnRhbEFs + aWdubWVudAEAAAAHdmFsdWVfXwAIAgAAAAAAAAAKBgUAAAAYbm9uc3RhbmRhcmRDb250cmFjdEdyb3Vw + Cw== + + + + + AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w + LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACJTeXN0 + ZW0uV2luZG93cy5Gb3Jtcy5MaXN0Vmlld0dyb3VwBAAAAAZIZWFkZXIPSGVhZGVyQWxpZ25tZW50A1Rh + ZwROYW1lAQQCAShTeXN0ZW0uV2luZG93cy5Gb3Jtcy5Ib3Jpem9udGFsQWxpZ25tZW50AgAAAAIAAAAG + AwAAABJXYXRjaC1Pbmx5IEFkZHJlc3MF/P///yhTeXN0ZW0uV2luZG93cy5Gb3Jtcy5Ib3Jpem9udGFs + QWxpZ25tZW50AQAAAAd2YWx1ZV9fAAgCAAAAAAAAAAoGBQAAAA53YXRjaE9ubHlHcm91cAs= + + + + 3, 3 + + + 889, 521 + + + 1 + + + listView1 + + + System.Windows.Forms.ListView, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tabPage1 + + + 0 + + + 137, 17 + + + 49, 17 + + + Height: + + + 27, 17 + + + 0/0 + + + 73, 17 + + + Connected: + + + 15, 17 + + + 0 + + + 100, 16 + + + 140, 17 + + + Waiting for next block: + + + 145, 17 + + + Download New Version + + + False + + + 0, 584 + + + 903, 22 + + + 2 + + + statusStrip1 + + + statusStrip1 + + + System.Windows.Forms.StatusStrip, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 3 + + + 258, 17 + + + 4, 26 + + + 3, 3, 3, 3 + + + 895, 527 + + + 0 + + + Account + + + tabPage1 + + + System.Windows.Forms.TabPage, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tabControl1 + + + 0 + + + Asset + + + 160 + + + Type + + + 100 + + + Balance + + + 192 + + + Issuer + + + 398 + + + Fill + + + 3, 3 + + + 889, 521 + + + 2 + + + listView2 + + + System.Windows.Forms.ListView, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tabPage2 + + + 0 + + + 4, 26 + + + 3, 3, 3, 3 + + + 895, 527 + + + 1 + + + Asset + + + tabPage2 + + + System.Windows.Forms.TabPage, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tabControl1 + + + 1 + + + Time + + + 132 + + + Transaction ID + + + 482 + + + confirm + + + 78 + + + Transaction Type + + + 163 + + + 513, 17 + + + 138, 22 + + + &Copy TXID + + + 139, 26 + + + contextMenuStrip3 + + + System.Windows.Forms.ContextMenuStrip, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Fill + + + 3, 3 + + + 889, 521 + + + 0 + + + listView3 + + + System.Windows.Forms.ListView, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tabPage3 + + + 0 + + + 4, 26 + + + 3, 3, 3, 3 + + + 895, 527 + + + 2 + + + Transaction History + + + tabPage3 + + + System.Windows.Forms.TabPage, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + tabControl1 + + + 2 + + + Fill + + + 0, 27 + + + 903, 557 + + + 3 + + + tabControl1 + + + System.Windows.Forms.TabControl, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 2 + + + True + + + 7, 17 + + + 903, 606 + + + Microsoft YaHei UI, 9pt + + + + AAABAAEAQEAAAAEAIAAoQgAAFgAAACgAAABAAAAAgAAAAAEAIAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAA2G8OANdrdgDWaJMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAADadhYA2XOFANhv7wDXav8A1WarAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAANx+HgDbepMA2nb1ANhx/wDXbP8A1mf/ANVjqwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA3oUoAN2BoQDcffsA23j/ANlz/wDYbv8A1mn/ANVk/wDU + YKsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADgjTYA34mvAN6E/QDcf/8A23r/ANp1/wDY + cP8A12v/ANZm/wDUYf8A012rAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA5JgAAOKUQgDhkL0A4Iz/AN+H/wDd + gv8A3H3/ANp4/wDZc/8A2G7/ANZo/wDVZP8A017/ANJaqwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADmnwIA5JtQAOOXyQDi + k/8A4Y7/AN+J/wDehP8A3H//ANt6/wDadf8A2HD/ANdr/wDVZv8A1GH/ANNc/wDRV6sAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOinBADm + o14A5Z/XAOSa/wDjlf8A4ZD/AOCL/wDehv8A3YH/ANx8/wDad/8A2XL/ANdt/wDWaP8A1WP/ANNe/wDS + Wf8A0VWrAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAOipRgDnpuEA5qH/AOWc/wDjl/8A4pL/AOCN/wDfiP8A3oP/ANx+/wDbef8A2XT/ANhv/wDX + av8A1WX/ANRg/wDSW/8A0Vb/ANBSqwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAADop34A56P/AOWe/wDkmf8A4pT/AOGP/wDgiv8A3oX/AN2A/wDb + e/8A2nb/ANlx/wDXbP8A1mf/ANRi/wDTXf8A0lj/ANBT/wDPT6sAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAL0NMAC9DXIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA56R+AOah/wDknP8A45f/AOKS/wDg + jf8A34j/AN2D/wDcff8A23n/ANlz/wDYb/8A1mn/ANVk/wDUX/8A0lr/ANFV/wDPUP8AzkyrAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAvQ08AL0NtwC9Df8AvQ2/AAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOaifgDl + nv8A5Jn/AOKU/wDhj/8A34r/AN6F/wDdgP8A23v/ANp2/wDYcf8A12z/ANZn/wDUYv8A013/ANFY/wDQ + U/8Az07/AM1JqwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL0NAAC9DUoAvQ3FAL0N/wC9Df8AvQ3/AL0NvwAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAADln34A5Jv/AOOW/wDhkf8A4Iz/AN+H/wDdgv8A3H3/ANp4/wDZc/8A2G7/ANZp/wDV + ZP8A01//ANJa/wDRVf8Az1D/AM5L/wDNR6sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAvQ0EAL0NWAC9DdEAvQ3/AL0N/wC9 + Df8AvQ3/AL0N/wC9Db8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA5Jx+AOOY/wDik/8A4Y7/AN+J/wDehP8A3H//ANt6/wDa + df8A2HD/ANdr/wDVZv8A1GH/ANNc/wDRV/8A0FL/AM5N/wDNSP8AzESrAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC9DQgAvQ1mAL0N3QC9 + Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ2/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOSZfgDjlf8A4ZD/AOCL/wDe + hv8A3YH/ANx8/wDad/8A2XL/ANdt/wDWaP8A1WP/ANNe/wDSWf8A0FT/AM9P/wDOSv8AzEX/AMtBqwAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL0NDgC9 + DXQAvQ3nAL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0NvwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADj + ln4A4pL/AOCO/wDfiP8A3oT/ANx+/wDbef8A2XT/ANhv/wDXav8A1WX/ANRg/wDSW/8A0Vb/ANBR/wDO + TP8AzUf/AMxC/wDKPqsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAvQ0UAL0NgwC9De8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9 + Db8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAA4pN+AOGQ/wDgi/8A3ob/AN2B/wDbfP8A2nf/ANly/wDXbf8A1mj/ANRj/wDT + Xv8A0ln/ANBU/wDPT/8AzUn/AMxF/wDLP/8AyjurAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAC9DR4AvQ2RAL0N9QC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9 + Df8AvQ3/AL0N/wC9Df8AvQ2/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOGRfgDgjf8A34j/AN2D/wDcfv8A23n/ANl0/wDY + b/8A12r/ANVl/wDUYP8A0lv/ANFW/wDQUf8Azkz/AM1H/wDLQv8Ayj3/AMk4qwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAL0NKAC9DZ8AvQ35AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9 + Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0NvwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADhjn4A4Ir/AN6F/wDd + gP8A23v/ANp2/wDZcf8A12z/ANZn/wDUYv8A013/ANJY/wDQU/8Az07/AM1J/wDMRP8Ayz//AMk6/wDI + NqsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC9DdsAvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9 + Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Db8AAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAA4It+AN+H/wDdgv8A3H3/ANt4/wDZc/8A2G7/ANZp/wDVZP8A1F//ANJa/wDRVf8Az1D/AM5L/wDN + Rv8Ay0H/AMo8/wDIN/8AxzOrAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAvQ3bAL0N/wC9 + Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9 + Df8AvQ2/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAN+IfgDehP8A3X//ANt6/wDadf8A2HD/ANdr/wDWZv8A1GH/ANNc/wDR + V/8A0FL/AM9N/wDNSP8AzEP/AMo+/wDJOf8AyDT/AMYwqwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAL0N2wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9 + Df8AvQ3/AL0N/wC9Df8AvQ3/AL0NvwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADehX4A3YL/ANx9/wDaeP8A2XP/ANhu/wDW + af8A1WT/ANNe/wDSWv8A0VT/AM9Q/wDOSv8AzEX/AMtA/wDKO/8AyDb/AMcx/wDGLasAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC9DdsAvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9 + Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Db8AAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA3YN+ANx//wDb + ev8A2nX/ANhw/wDXa/8A1Wb/ANRh/wDTXP8A0Vf/ANBS/wDOTf8AzUj/AMxD/wDKPv8AyTn/AMc0/wDG + L/8AxSqrAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAvQ3bAL0N/wC9Df8AvQ3/AL0N/wC9 + Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ2/AAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAN2AfgDcfP8A2nf/ANly/wDXbf8A1mj/ANVj/wDTXv8A0ln/ANBU/wDPT/8Azkr/AMxF/wDL + QP8AyTv/AMg2/wDHMf8AxSz/AMQoqwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL0N2wC9 + Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9 + Df8AvQ3/AL0NvwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAADcfX4A23n/ANl0/wDYb/8A12r/ANVl/wDUYP8A0lv/ANFW/wDQ + Uf8Azkz/AM1H/wDLQv8Ayj3/AMk4/wDHM/8Axi7/AMQp/wDDJasAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAC9DdsAvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9 + Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Db8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA23p+ANp2/wDZcf8A12z/ANZn/wDU + Yv8A013/ANJY/wDQU/8Az07/AM1J/wDMRP8Ayz//AMk6/wDINf8AxjD/AMUr/wDEJv8AwiKrAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAvQ3bAL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9 + Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ2/AAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANp3fgDZ + c/8A2G//ANZp/wDVZf8A1F//ANJa/wDRVf8Az1D/AM5L/wDNRv8Ay0H/AMo8/wDIN/8AxzL/AMYt/wDE + KP8AwyP/AMIfqwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL0N2wC9Df8AvQ3/AL0N/wC9 + Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0NvwAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAADZdH4A2HH/ANds/wDWZ/8A1GL/ANNd/wDRWP8A0FP/AM9O/wDNSf8AzET/AMo//wDJ + Ov8AyDX/AMYw/wDFKv8Awyb/AMIg/wDBHKsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC9 + DdsAvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9 + Df8AvQ3/AL0N/wC9Db8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA2XJ+ANhu/wDWaf8A1WT/ANNf/wDSWv8A0VX/AM9Q/wDO + S/8AzEb/AMtB/wDKPP8AyDf/AMcy/wDFLf8AxCj/AMMj/wDBHv8AwBmrAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAvQ3bAL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9 + Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ2/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANhvfgDXa/8A1Wb/ANRh/wDT + XP8A0Vf/ANBS/wDOTf8AzUj/AMxD/wDKPv8AyTn/AMg0/wDGL/8AxSr/AMMl/wDCIP8AwRv/AL8XqwAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL0N2wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9 + Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0NvwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADX + bH4A1mj/ANVj/wDTXv8A0ln/ANBU/wDPT/8Azkr/AMxF/wDLQP8AyTv/AMg2/wDHMf8AxSz/AMQn/wDD + Iv8AwR3/AMAY/wC/FKsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC9DdsAvQ3/AL0N/wC9 + Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9 + Db8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAA1ml+ANVl/wDUYP8A0lv/ANFW/wDQUf8Azkz/AM1H/wDMQv8Ayj3/AMk4/wDH + M/8Axi7/AMUp/wDDJP8Awh//AMAa/wC/Ff8AvhGrAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAvQ3bAL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9 + Df8AvQ3/AL0N/wC9Df8AvQ2/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANZmfgDVY/8A017/ANJZ/wDQVP8Az0//AM5K/wDM + Rf8Ayz//AMk7/wDINf8AxzH/AMUr/wDEJv8AwiH/AMEc/wDAF/8AvhL/AL0OqwAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAL0N2wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9 + Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0NvwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADVZH4A1GD/ANJb/wDR + Vv8A0FH/AM5M/wDNR/8Ay0L/AMo9/wDJOP8AxzP/AMYu/wDEKf8AwyT/AMIf/wDAGv8AvxX/AL0Q/wC9 + DasAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC9DdsAvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9 + Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9DL8AAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAA1GF+ANNd/wDSWP8A0FP/AM9O/wDNSf8AzET/AMs//wDJOv8AyDX/AMYw/wDFK/8AxCb/AMIh/wDB + HP8Avxf/AL4S/wC9Df8AvQ2rAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAvQ3bAL0N/wC9 + Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9 + DP8AvQy/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAANNefgDSWv8A0VX/AM9Q/wDOS/8AzUb/AMtB/wDKPP8AyDf/AMcy/wDG + Lf8AxCj/AMMj/wDBHv8AwBn/AL8U/wC9D/8AvQ3VAL0NTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAL0N2wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9 + Df8AvQ3/AL0N/wC9Df8AvQz/ALwMvwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADSW34A0Vf/ANBS/wDPTf8AzUj/AMxD/wDK + Pv8AyTn/AMg0/wDGL/8AxSr/AMMl/wDCIP8AwRv/AL8W/wC+EskAvQ5QAL0NMgC9DakAvQ3RAL0NdgC9 + DRwAAAAAAAAAAAAAAAAAAAAAAAAAAAC9DdsAvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9 + Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQz/ALwM/wC8C78AAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA0lh+ANFU/wDP + UP8Azkr/AMxG/wDLQP8Ayjv/AMg2/wDHMf8AxSz/AMQn/wDDIv8AwR3/AMAZuwC/FUIAvQ0+AL0NtwC9 + Df8AvQ3/AL0N/wC9Df8AvQ39AL0NvQC9DWIAvQ0OAAAAAAAAAAAAvQ3bAL0N/wC9Df8AvQ3/AL0N/wC9 + Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQz/AL0M/wC8C/8AvAu/AAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAANFVfgDQUv8Azk3/AM1I/wDMQ/8Ayj7/AMk5/wDHNP8Axi//AMUq/wDDJf0AwiCtAMEcNgC/ + FEwAvhDFAL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N9wC9DakAvQ1OAL0NJgC9 + DXwAvQ3XAL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0M/wC8 + DP8AvAv/ALwLvwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAADQU34Az0//AM5K/wDMRf8Ay0D/AMk7/wDINv8AxzH/AMUs+QDE + J58AwyMsAMEbWAC/F9EAvhP/AL0O/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9 + Df8AvQ3/AL0N/wC9DesAvQ2VAL0NOAC9DTQAvQ2RAL0N6QC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9 + Df8AvQ3/AL0M/wC9DP8AvAv/ALwL/wC8C78AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAz1B+AM5M/wDNR/8Ay0L/AMo9/wDJ + OP8AxzP1AMYvkwDFKiYAwyNmAMIf3QDAGv8AvxX/AL0Q/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9 + Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3bAL0NgQC9DSgAvQ1IAL0NpQC9 + DfUAvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9DP8AvAz/ALwL/wC8C/8AvAq/AAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM5NfgDN + Sf8AzET/AMs//wDJOu8AyDaFAMcxIgDFKnQAxCbnAMIh/wDBHP8Avxf/AL4S/wC9Df8AvQ3/AL0N/wC9 + Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9 + Df8AvQ3/AL0NyQC9DWwAvQ0gAL0NXAC9DbkAvQ37AL0N/wC9DP8AvAz/ALwL/wC8C/8AvAr/ALwKvwAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAADOSn4AzUb/AMtC5wDKPXYAyDciAMcxgwDGLe8AxCj/AMMj/wDBHv8AwBn/AL8U/wC9 + D/8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9 + Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N+wC9DbMAvQ1YAL0NIgC9DXAAvQzNALwM/wC8 + C/8AvAv/ALwK/wC7Cr8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzUhgAMxFaADKPSYAyTmRAMg09QDGMP8AxSv/AMMm/wDC + IP8AwRz/AL8W/wC+Ev8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9 + Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9 + DfEAvQyfALwMRAC8CywAvAuHALwK4QC8Cv8Auwm/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADLQEQAyjztAMg3/wDH + Mv8Axi3/AMQo/wDDI/8AwR7/AMAZ/wC/FP8AvQ//AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9 + Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9 + Df8AvQ3/AL0N/wC9Df8AvQ3/AL0M/wC8DP8AvAvlALwLiwC8CjAAuwo+ALsJagAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAMk5CgDINFoAxi+3AMUq+wDDJf8AwiD/AMEb/wC/Fv8AvhH/AL0N/wC9Df8AvQ3/AL0N/wC9 + Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9 + Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0M/wC8DP8AvAv/ALwL/wC8Cv8AvAr/ALsJxQC7 + CRoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADEJxYAwyJuAMEdywDAGP8AvhP/AL0O/wC9 + Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9 + Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0M/wC9DP8AvAv/ALwL/wC8 + Cv8AvArpALsKeAC7CRAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAvxUoAL4RgwC9Dd8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9 + Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9 + DP8AvAz/ALwL/wC8C98AvApqALwKCgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAvQ0AAL0NPAC9DZcAvQ3tAL0N/wC9Df8AvQ3/AL0N/wC9 + Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9 + Df8AvQ3/AL0N/wC9DP8AvAz/ALwL1QC8C1wAvAsEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL0NBgC9 + DVAAvQ2rAL0N9wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9 + Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQzJALwMUAC8DAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC9DRAAvQ1kAL0NwQC9Df0AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9 + Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9DbsAvQ1CAL0MAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAvQ0eAL0NeAC9 + DdUAvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ3/AL0N/wC9Df8AvQ39AL0NrQC9DTQAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAL0NMAC9DY0AvQ3lAL0N/wC9Df8AvQ3/AL0N/wC9DfkAvQ2fAL0NKAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL0NAgC9DUYAvQ2hAL0N6QC9 + DZEAvQ0eAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAA/////////////////////////////////////////////////////////+//////////D/// + //////wP////////8A/////////AD////////wAP///////8AA////////AAD///////wAAP///////A + AA///////8AAD///8f//wAAP///B///AAA///wH//8AAD//8Af//wAAP//AB///AAA//gAH//8AAD/4A + Af//wAAP+AAB///AAA/wAAH//8AAD/AAAf//wAAP8AAB///AAA/wAAH//8AAD/AAAf//wAAP8AAB///A + AA/wAAH//8AAD/AAAf//wAAP8AAB///AAA/wAAH//8AAD/AAAf//wAAP8AAB///AAA/wAAH//8AAD/AA + Af//wAAP8AAB///AAA/wAAH//8AAD/AAAf//wAAf8AAB///AAGfwAAH//8ABgPAAAf//wAYAHAAB///A + GAADAAH//8BgAABgAf//wYAAABwB///MAAAAA4H///AAAAAAYf//4AAAAAAP///4AAAAAAP///8AAAAA + D////8AAAAA/////+AAAAP//////AAAD///////gAA////////wAP////////wD/////////4/////// + //////////////////////////////////////////////////8= + + + + 3, 4, 3, 4 + + + CenterScreen + + + neo-gui + + + 钱包WToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 创建钱包数据库NToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 打开钱包数据库OToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + toolStripSeparator1 + + + System.Windows.Forms.ToolStripSeparator, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 修改密码CToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + toolStripSeparator2 + + + System.Windows.Forms.ToolStripSeparator, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 退出XToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 交易TToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 转账TToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + toolStripSeparator5 + + + System.Windows.Forms.ToolStripSeparator, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 签名SToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 高级AToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + deployContractToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + invokeContractToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + toolStripSeparator11 + + + System.Windows.Forms.ToolStripSeparator, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 选举EToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + signDataToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + toolStripSeparator9 + + + System.Windows.Forms.ToolStripSeparator, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + optionsToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 帮助HToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 查看帮助VToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 官网WToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + toolStripSeparator3 + + + System.Windows.Forms.ToolStripSeparator, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 开发人员工具TToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + consoleToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + toolStripSeparator4 + + + System.Windows.Forms.ToolStripSeparator, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 关于AntSharesToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + columnHeader1 + + + System.Windows.Forms.ColumnHeader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + columnHeader4 + + + System.Windows.Forms.ColumnHeader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + columnHeader11 + + + System.Windows.Forms.ColumnHeader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 创建新地址NToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 导入私钥IToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + importWIFToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + toolStripSeparator10 + + + System.Windows.Forms.ToolStripSeparator, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + importWatchOnlyAddressToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 创建智能合约SToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 多方签名MToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + toolStripSeparator12 + + + System.Windows.Forms.ToolStripSeparator, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 自定义CToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + toolStripSeparator6 + + + System.Windows.Forms.ToolStripSeparator, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 查看私钥VToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + viewContractToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + voteToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 复制到剪贴板CToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 删除DToolStripMenuItem + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + toolStripStatusLabel1 + + + System.Windows.Forms.ToolStripStatusLabel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + lbl_height + + + System.Windows.Forms.ToolStripStatusLabel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + toolStripStatusLabel4 + + + System.Windows.Forms.ToolStripStatusLabel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + lbl_count_node + + + System.Windows.Forms.ToolStripStatusLabel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + toolStripProgressBar1 + + + System.Windows.Forms.ToolStripProgressBar, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + toolStripStatusLabel2 + + + System.Windows.Forms.ToolStripStatusLabel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + toolStripStatusLabel3 + + + System.Windows.Forms.ToolStripStatusLabel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + timer1 + + + System.Windows.Forms.Timer, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + columnHeader2 + + + System.Windows.Forms.ColumnHeader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + columnHeader6 + + + System.Windows.Forms.ColumnHeader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + columnHeader3 + + + System.Windows.Forms.ColumnHeader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + columnHeader5 + + + System.Windows.Forms.ColumnHeader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + columnHeader7 + + + System.Windows.Forms.ColumnHeader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + columnHeader8 + + + System.Windows.Forms.ColumnHeader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + columnHeader9 + + + System.Windows.Forms.ColumnHeader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + columnHeader10 + + + System.Windows.Forms.ColumnHeader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + toolStripMenuItem1 + + + System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + MainForm + + + System.Windows.Forms.Form, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + diff --git a/src/Neo.GUI/GUI/MainForm.zh-Hans.resx b/src/Neo.GUI/GUI/MainForm.zh-Hans.resx new file mode 100644 index 0000000000..086c4e916a --- /dev/null +++ b/src/Neo.GUI/GUI/MainForm.zh-Hans.resx @@ -0,0 +1,445 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + 187, 22 + + + 创建钱包数据库(&N)... + + + 187, 22 + + + 打开钱包数据库(&O)... + + + 184, 6 + + + 187, 22 + + + 修改密码(&C)... + + + 184, 6 + + + 187, 22 + + + 退出(&X) + + + 64, 21 + + + 钱包(&W) + + + 124, 22 + + + 转账(&T)... + + + 121, 6 + + + 124, 22 + + + 签名(&S)... + + + 59, 21 + + + 交易(&T) + + + 150, 22 + + + 部署合约(&D)... + + + 150, 22 + + + 调用合约(&V)... + + + 147, 6 + + + 150, 22 + + + 选举(&E)... + + + 150, 22 + + + 消息签名(&S)... + + + 147, 6 + + + 150, 22 + + + 选项(&O)... + + + 60, 21 + + + 高级(&A) + + + 191, 22 + + + 查看帮助(&H) + + + 191, 22 + + + 官网(&W) + + + 188, 6 + + + 191, 22 + + + 开发人员工具(&T) + + + 191, 22 + + + 控制台(&C) + + + 188, 6 + + + 191, 22 + + + 关于&NEO + + + 61, 21 + + + 帮助(&H) + + + 地址 + + + 164, 22 + + + 创建新地址(&N) + + + 173, 22 + + + 导入&WIF... + + + 170, 6 + + + 173, 22 + + + 导入监视地址(&A)... + + + 164, 22 + + + 导入(&I) + + + 153, 22 + + + 多方签名(&M)... + + + 150, 6 + + + 153, 22 + + + 自定义(&C)... + + + 164, 22 + + + 创建合约地址(&A) + + + 161, 6 + + + 164, 22 + + + 查看私钥(&P) + + + 164, 22 + + + 查看合约(&O) + + + 164, 22 + + + 投票(&V)... + + + 164, 22 + + + 复制到剪贴板(&C) + + + 164, 22 + + + 删除(&D)... + + + 165, 186 + + + + AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w + LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACJTeXN0 + ZW0uV2luZG93cy5Gb3Jtcy5MaXN0Vmlld0dyb3VwBAAAAAZIZWFkZXIPSGVhZGVyQWxpZ25tZW50A1Rh + ZwROYW1lAQQCAShTeXN0ZW0uV2luZG93cy5Gb3Jtcy5Ib3Jpem9udGFsQWxpZ25tZW50AgAAAAIAAAAG + AwAAAAzmoIflh4botKbmiLcF/P///yhTeXN0ZW0uV2luZG93cy5Gb3Jtcy5Ib3Jpem9udGFsQWxpZ25t + ZW50AQAAAAd2YWx1ZV9fAAgCAAAAAAAAAAoGBQAAABVzdGFuZGFyZENvbnRyYWN0R3JvdXAL + + + + + AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w + LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACJTeXN0 + ZW0uV2luZG93cy5Gb3Jtcy5MaXN0Vmlld0dyb3VwBAAAAAZIZWFkZXIPSGVhZGVyQWxpZ25tZW50A1Rh + ZwROYW1lAQQCAShTeXN0ZW0uV2luZG93cy5Gb3Jtcy5Ib3Jpem9udGFsQWxpZ25tZW50AgAAAAIAAAAG + AwAAAAzlkIjnuqblnLDlnYAF/P///yhTeXN0ZW0uV2luZG93cy5Gb3Jtcy5Ib3Jpem9udGFsQWxpZ25t + ZW50AQAAAAd2YWx1ZV9fAAgCAAAAAAAAAAoGBQAAABhub25zdGFuZGFyZENvbnRyYWN0R3JvdXAL + + + + + AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w + LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACJTeXN0 + ZW0uV2luZG93cy5Gb3Jtcy5MaXN0Vmlld0dyb3VwBAAAAAZIZWFkZXIPSGVhZGVyQWxpZ25tZW50A1Rh + ZwROYW1lAQQCAShTeXN0ZW0uV2luZG93cy5Gb3Jtcy5Ib3Jpem9udGFsQWxpZ25tZW50AgAAAAIAAAAG + AwAAAAznm5Hop4blnLDlnYAF/P///yhTeXN0ZW0uV2luZG93cy5Gb3Jtcy5Ib3Jpem9udGFsQWxpZ25t + ZW50AQAAAAd2YWx1ZV9fAAgCAAAAAAAAAAoGBQAAAA53YXRjaE9ubHlHcm91cAs= + + + + 35, 17 + + + 高度: + + + 47, 17 + + + 连接数: + + + 95, 17 + + + 等待下一个区块: + + + 68, 17 + + + 发现新版本 + + + 账户 + + + 资产 + + + 类型 + + + 余额 + + + 发行者 + + + 资产 + + + 时间 + + + 交易编号 + + + 确认 + + + 交易类型 + + + 137, 22 + + + 复制交易ID + + + 138, 26 + + + 交易记录 + + \ No newline at end of file diff --git a/src/Neo.GUI/GUI/OpenWalletDialog.cs b/src/Neo.GUI/GUI/OpenWalletDialog.cs new file mode 100644 index 0000000000..aaeaa0bfd1 --- /dev/null +++ b/src/Neo.GUI/GUI/OpenWalletDialog.cs @@ -0,0 +1,65 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-gui is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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.Windows.Forms; + +namespace Neo.GUI +{ + internal partial class OpenWalletDialog : Form + { + public OpenWalletDialog() + { + InitializeComponent(); + } + + public string Password + { + get + { + return textBox2.Text; + } + set + { + textBox2.Text = value; + } + } + + public string WalletPath + { + get + { + return textBox1.Text; + } + set + { + textBox1.Text = value; + } + } + + private void textBox_TextChanged(object sender, EventArgs e) + { + if (textBox1.TextLength == 0 || textBox2.TextLength == 0) + { + button2.Enabled = false; + return; + } + button2.Enabled = true; + } + + private void button1_Click(object sender, EventArgs e) + { + if (openFileDialog1.ShowDialog() == DialogResult.OK) + { + textBox1.Text = openFileDialog1.FileName; + } + } + } +} diff --git a/src/Neo.GUI/GUI/OpenWalletDialog.designer.cs b/src/Neo.GUI/GUI/OpenWalletDialog.designer.cs new file mode 100644 index 0000000000..9db0ac01b8 --- /dev/null +++ b/src/Neo.GUI/GUI/OpenWalletDialog.designer.cs @@ -0,0 +1,125 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-gui is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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.GUI +{ + partial class OpenWalletDialog + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(OpenWalletDialog)); + this.button2 = new System.Windows.Forms.Button(); + this.textBox2 = new System.Windows.Forms.TextBox(); + this.label2 = new System.Windows.Forms.Label(); + this.button1 = new System.Windows.Forms.Button(); + this.textBox1 = new System.Windows.Forms.TextBox(); + this.label1 = new System.Windows.Forms.Label(); + this.openFileDialog1 = new System.Windows.Forms.OpenFileDialog(); + this.SuspendLayout(); + // + // button2 + // + resources.ApplyResources(this.button2, "button2"); + this.button2.DialogResult = System.Windows.Forms.DialogResult.OK; + this.button2.Name = "button2"; + this.button2.UseVisualStyleBackColor = true; + // + // textBox2 + // + resources.ApplyResources(this.textBox2, "textBox2"); + this.textBox2.Name = "textBox2"; + this.textBox2.UseSystemPasswordChar = true; + this.textBox2.TextChanged += new System.EventHandler(this.textBox_TextChanged); + // + // label2 + // + resources.ApplyResources(this.label2, "label2"); + this.label2.Name = "label2"; + // + // button1 + // + resources.ApplyResources(this.button1, "button1"); + this.button1.Name = "button1"; + this.button1.UseVisualStyleBackColor = true; + this.button1.Click += new System.EventHandler(this.button1_Click); + // + // textBox1 + // + resources.ApplyResources(this.textBox1, "textBox1"); + this.textBox1.Name = "textBox1"; + this.textBox1.ReadOnly = true; + this.textBox1.TextChanged += new System.EventHandler(this.textBox_TextChanged); + // + // label1 + // + resources.ApplyResources(this.label1, "label1"); + this.label1.Name = "label1"; + // + // openFileDialog1 + // + this.openFileDialog1.DefaultExt = "json"; + resources.ApplyResources(this.openFileDialog1, "openFileDialog1"); + // + // OpenWalletDialog + // + this.AcceptButton = this.button2; + resources.ApplyResources(this, "$this"); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.button2); + this.Controls.Add(this.textBox2); + this.Controls.Add(this.label2); + this.Controls.Add(this.button1); + this.Controls.Add(this.textBox1); + this.Controls.Add(this.label1); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "OpenWalletDialog"; + this.ShowInTaskbar = false; + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Button button2; + private System.Windows.Forms.TextBox textBox2; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.Button button1; + private System.Windows.Forms.TextBox textBox1; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.OpenFileDialog openFileDialog1; + } +} diff --git a/src/Neo.GUI/GUI/OpenWalletDialog.es-ES.resx b/src/Neo.GUI/GUI/OpenWalletDialog.es-ES.resx new file mode 100644 index 0000000000..bf023cf9a0 --- /dev/null +++ b/src/Neo.GUI/GUI/OpenWalletDialog.es-ES.resx @@ -0,0 +1,151 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + 142, 41 + + + 65, 44 + + + 71, 16 + + + Contraseña: + + + Buscar... + + + 142, 12 + + + 204, 23 + + + 124, 16 + + + Fichero de nomedero: + + + Abrir monedero + + \ No newline at end of file diff --git a/src/Neo.GUI/GUI/OpenWalletDialog.resx b/src/Neo.GUI/GUI/OpenWalletDialog.resx new file mode 100644 index 0000000000..8b5a8e2e01 --- /dev/null +++ b/src/Neo.GUI/GUI/OpenWalletDialog.resx @@ -0,0 +1,315 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + 8 + + + 15 + + + Password: + + + 5 + + + System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + 7, 16 + + + + Top, Left, Right + + + True + + + OK + + + 16, 44 + + + 352, 68 + + + $this + + + Wallet File: + + + button2 + + + OpenWalletDialog + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Top, Right + + + $this + + + $this + + + 12, 15 + + + textBox1 + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 263, 23 + + + 439, 103 + + + System.Windows.Forms.OpenFileDialog, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Bottom, Right + + + CenterScreen + + + 75, 23 + + + openFileDialog1 + + + textBox2 + + + label1 + + + label2 + + + 75, 23 + + + 9 + + + System.Windows.Forms.Form, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Browse + + + False + + + System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + NEP-6 Wallet|*.json|SQLite Wallet|*.db3 + + + 83, 12 + + + 61, 16 + + + 3 + + + 150, 23 + + + True + + + 65, 16 + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 1 + + + 11 + + + 83, 41 + + + 4 + + + 10 + + + button1 + + + 0 + + + $this + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 352, 12 + + + 微软雅黑, 9pt + + + Open Wallet + + + 2 + + + 12 + + + $this + + + True + + + 17, 17 + + \ No newline at end of file diff --git a/src/Neo.GUI/GUI/OpenWalletDialog.zh-Hans.resx b/src/Neo.GUI/GUI/OpenWalletDialog.zh-Hans.resx new file mode 100644 index 0000000000..5c4bf63eda --- /dev/null +++ b/src/Neo.GUI/GUI/OpenWalletDialog.zh-Hans.resx @@ -0,0 +1,157 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + 确定 + + + 101, 41 + + + 60, 44 + + + 35, 16 + + + 密码: + + + 浏览 + + + 101, 12 + + + 245, 23 + + + 83, 16 + + + 钱包文件位置: + + + NEP-6钱包文件|*.json|SQLite钱包文件|*.db3 + + + 打开钱包 + + \ No newline at end of file diff --git a/src/Neo.GUI/GUI/ParametersEditor.Designer.cs b/src/Neo.GUI/GUI/ParametersEditor.Designer.cs new file mode 100644 index 0000000000..5d6d92d268 --- /dev/null +++ b/src/Neo.GUI/GUI/ParametersEditor.Designer.cs @@ -0,0 +1,200 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-gui is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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.GUI +{ + partial class ParametersEditor + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ParametersEditor)); + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.listView1 = new System.Windows.Forms.ListView(); + this.columnHeader1 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.columnHeader2 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.columnHeader3 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.panel1 = new System.Windows.Forms.Panel(); + this.button4 = new System.Windows.Forms.Button(); + this.button3 = new System.Windows.Forms.Button(); + this.groupBox2 = new System.Windows.Forms.GroupBox(); + this.textBox1 = new System.Windows.Forms.TextBox(); + this.groupBox3 = new System.Windows.Forms.GroupBox(); + this.button2 = new System.Windows.Forms.Button(); + this.button1 = new System.Windows.Forms.Button(); + this.textBox2 = new System.Windows.Forms.TextBox(); + this.groupBox1.SuspendLayout(); + this.panel1.SuspendLayout(); + this.groupBox2.SuspendLayout(); + this.groupBox3.SuspendLayout(); + this.SuspendLayout(); + // + // groupBox1 + // + resources.ApplyResources(this.groupBox1, "groupBox1"); + this.groupBox1.Controls.Add(this.listView1); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.TabStop = false; + // + // listView1 + // + resources.ApplyResources(this.listView1, "listView1"); + this.listView1.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.columnHeader1, + this.columnHeader2, + this.columnHeader3}); + this.listView1.FullRowSelect = true; + this.listView1.GridLines = true; + this.listView1.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.Nonclickable; + this.listView1.MultiSelect = false; + this.listView1.Name = "listView1"; + this.listView1.ShowGroups = false; + this.listView1.UseCompatibleStateImageBehavior = false; + this.listView1.View = System.Windows.Forms.View.Details; + this.listView1.SelectedIndexChanged += new System.EventHandler(this.listView1_SelectedIndexChanged); + // + // columnHeader1 + // + resources.ApplyResources(this.columnHeader1, "columnHeader1"); + // + // columnHeader2 + // + resources.ApplyResources(this.columnHeader2, "columnHeader2"); + // + // columnHeader3 + // + resources.ApplyResources(this.columnHeader3, "columnHeader3"); + // + // panel1 + // + resources.ApplyResources(this.panel1, "panel1"); + this.panel1.Controls.Add(this.button4); + this.panel1.Controls.Add(this.button3); + this.panel1.Name = "panel1"; + // + // button4 + // + resources.ApplyResources(this.button4, "button4"); + this.button4.Name = "button4"; + this.button4.UseVisualStyleBackColor = true; + this.button4.Click += new System.EventHandler(this.button4_Click); + // + // button3 + // + resources.ApplyResources(this.button3, "button3"); + this.button3.Name = "button3"; + this.button3.UseVisualStyleBackColor = true; + this.button3.Click += new System.EventHandler(this.button3_Click); + // + // groupBox2 + // + resources.ApplyResources(this.groupBox2, "groupBox2"); + this.groupBox2.Controls.Add(this.textBox1); + this.groupBox2.Name = "groupBox2"; + this.groupBox2.TabStop = false; + // + // textBox1 + // + resources.ApplyResources(this.textBox1, "textBox1"); + this.textBox1.Name = "textBox1"; + this.textBox1.ReadOnly = true; + // + // groupBox3 + // + resources.ApplyResources(this.groupBox3, "groupBox3"); + this.groupBox3.Controls.Add(this.panel1); + this.groupBox3.Controls.Add(this.button2); + this.groupBox3.Controls.Add(this.button1); + this.groupBox3.Controls.Add(this.textBox2); + this.groupBox3.Name = "groupBox3"; + this.groupBox3.TabStop = false; + // + // button2 + // + resources.ApplyResources(this.button2, "button2"); + this.button2.Name = "button2"; + this.button2.UseVisualStyleBackColor = true; + this.button2.Click += new System.EventHandler(this.button2_Click); + // + // button1 + // + resources.ApplyResources(this.button1, "button1"); + this.button1.Name = "button1"; + this.button1.UseVisualStyleBackColor = true; + this.button1.Click += new System.EventHandler(this.button1_Click); + // + // textBox2 + // + resources.ApplyResources(this.textBox2, "textBox2"); + this.textBox2.Name = "textBox2"; + this.textBox2.TextChanged += new System.EventHandler(this.textBox2_TextChanged); + // + // ParametersEditor + // + resources.ApplyResources(this, "$this"); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.groupBox3); + this.Controls.Add(this.groupBox2); + this.Controls.Add(this.groupBox1); + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "ParametersEditor"; + this.ShowInTaskbar = false; + this.groupBox1.ResumeLayout(false); + this.panel1.ResumeLayout(false); + this.groupBox2.ResumeLayout(false); + this.groupBox2.PerformLayout(); + this.groupBox3.ResumeLayout(false); + this.groupBox3.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.GroupBox groupBox1; + private System.Windows.Forms.ListView listView1; + private System.Windows.Forms.GroupBox groupBox2; + private System.Windows.Forms.TextBox textBox1; + private System.Windows.Forms.GroupBox groupBox3; + private System.Windows.Forms.TextBox textBox2; + private System.Windows.Forms.Button button1; + private System.Windows.Forms.ColumnHeader columnHeader1; + private System.Windows.Forms.ColumnHeader columnHeader2; + private System.Windows.Forms.ColumnHeader columnHeader3; + private System.Windows.Forms.Button button2; + private System.Windows.Forms.Button button3; + private System.Windows.Forms.Button button4; + private System.Windows.Forms.Panel panel1; + } +} diff --git a/src/Neo.GUI/GUI/ParametersEditor.cs b/src/Neo.GUI/GUI/ParametersEditor.cs new file mode 100644 index 0000000000..6a42f8d934 --- /dev/null +++ b/src/Neo.GUI/GUI/ParametersEditor.cs @@ -0,0 +1,197 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-gui is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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; +using Neo.SmartContract; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Numerics; +using System.Windows.Forms; + +namespace Neo.GUI +{ + internal partial class ParametersEditor : Form + { + private readonly IList parameters; + + public ParametersEditor(IList parameters) + { + InitializeComponent(); + this.parameters = parameters; + listView1.Items.AddRange(parameters.Select((p, i) => new ListViewItem(new[] + { + new ListViewItem.ListViewSubItem + { + Name = "index", + Text = $"[{i}]" + }, + new ListViewItem.ListViewSubItem + { + Name = "type", + Text = p.Type.ToString() + }, + new ListViewItem.ListViewSubItem + { + Name = "value", + Text = p.ToString() + } + }, -1) + { + Tag = p + }).ToArray()); + panel1.Enabled = !parameters.IsReadOnly; + } + + private void listView1_SelectedIndexChanged(object sender, EventArgs e) + { + if (listView1.SelectedIndices.Count > 0) + { + textBox1.Text = listView1.SelectedItems[0].SubItems["value"].Text; + textBox2.Enabled = ((ContractParameter)listView1.SelectedItems[0].Tag).Type != ContractParameterType.Array; + button2.Enabled = !textBox2.Enabled; + button4.Enabled = true; + } + else + { + textBox1.Clear(); + textBox2.Enabled = true; + button2.Enabled = false; + button4.Enabled = false; + } + textBox2.Clear(); + } + + private void textBox2_TextChanged(object sender, EventArgs e) + { + button1.Enabled = listView1.SelectedIndices.Count > 0 && textBox2.TextLength > 0; + button3.Enabled = textBox2.TextLength > 0; + } + + private void button1_Click(object sender, EventArgs e) + { + if (listView1.SelectedIndices.Count == 0) return; + ContractParameter parameter = (ContractParameter)listView1.SelectedItems[0].Tag; + try + { + parameter.SetValue(textBox2.Text); + listView1.SelectedItems[0].SubItems["value"].Text = parameter.ToString(); + textBox1.Text = listView1.SelectedItems[0].SubItems["value"].Text; + textBox2.Clear(); + } + catch (Exception err) + { + MessageBox.Show(err.Message); + } + } + + private void button2_Click(object sender, EventArgs e) + { + if (listView1.SelectedIndices.Count == 0) return; + ContractParameter parameter = (ContractParameter)listView1.SelectedItems[0].Tag; + using ParametersEditor dialog = new ParametersEditor((IList)parameter.Value); + dialog.ShowDialog(); + listView1.SelectedItems[0].SubItems["value"].Text = parameter.ToString(); + textBox1.Text = listView1.SelectedItems[0].SubItems["value"].Text; + } + + private void button3_Click(object sender, EventArgs e) + { + string s = textBox2.Text; + ContractParameter parameter = new ContractParameter(); + if (string.Equals(s, "true", StringComparison.OrdinalIgnoreCase)) + { + parameter.Type = ContractParameterType.Boolean; + parameter.Value = true; + } + else if (string.Equals(s, "false", StringComparison.OrdinalIgnoreCase)) + { + parameter.Type = ContractParameterType.Boolean; + parameter.Value = false; + } + else if (long.TryParse(s, out long num)) + { + parameter.Type = ContractParameterType.Integer; + parameter.Value = num; + } + else if (s.StartsWith("0x")) + { + if (UInt160.TryParse(s, out UInt160 i160)) + { + parameter.Type = ContractParameterType.Hash160; + parameter.Value = i160; + } + else if (UInt256.TryParse(s, out UInt256 i256)) + { + parameter.Type = ContractParameterType.Hash256; + parameter.Value = i256; + } + else if (BigInteger.TryParse(s.Substring(2), NumberStyles.AllowHexSpecifier, null, out BigInteger bi)) + { + parameter.Type = ContractParameterType.Integer; + parameter.Value = bi; + } + else + { + parameter.Type = ContractParameterType.String; + parameter.Value = s; + } + } + else if (ECPoint.TryParse(s, ECCurve.Secp256r1, out ECPoint point)) + { + parameter.Type = ContractParameterType.PublicKey; + parameter.Value = point; + } + else + { + try + { + parameter.Value = s.HexToBytes(); + parameter.Type = ContractParameterType.ByteArray; + } + catch (FormatException) + { + parameter.Type = ContractParameterType.String; + parameter.Value = s; + } + } + parameters.Add(parameter); + listView1.Items.Add(new ListViewItem(new[] + { + new ListViewItem.ListViewSubItem + { + Name = "index", + Text = $"[{listView1.Items.Count}]" + }, + new ListViewItem.ListViewSubItem + { + Name = "type", + Text = parameter.Type.ToString() + }, + new ListViewItem.ListViewSubItem + { + Name = "value", + Text = parameter.ToString() + } + }, -1) + { + Tag = parameter + }); + } + + private void button4_Click(object sender, EventArgs e) + { + int index = listView1.SelectedIndices[0]; + parameters.RemoveAt(index); + listView1.Items.RemoveAt(index); + } + } +} diff --git a/src/Neo.GUI/GUI/ParametersEditor.es-ES.resx b/src/Neo.GUI/GUI/ParametersEditor.es-ES.resx new file mode 100644 index 0000000000..21e7fad664 --- /dev/null +++ b/src/Neo.GUI/GUI/ParametersEditor.es-ES.resx @@ -0,0 +1,141 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Tipo + + + Valor + + + Lista de parámetros + + + Valor anterior + + + Actualizar + + + Nuevo valor + + + Definir parámetros + + \ No newline at end of file diff --git a/src/Neo.GUI/GUI/ParametersEditor.resx b/src/Neo.GUI/GUI/ParametersEditor.resx new file mode 100644 index 0000000000..a2f2d31c9e --- /dev/null +++ b/src/Neo.GUI/GUI/ParametersEditor.resx @@ -0,0 +1,489 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + False + + + + + + + 661, 485 + + + ParametersEditor + + + False + + + False + + + + + + + System.Windows.Forms.ColumnHeader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + groupBox3 + + + panel1 + + + Value + + + 2 + + + 0 + + + Update + + + 0 + + + + Top, Bottom, Left, Right + + + 1 + + + System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 233, 126 + + + 3 + + + groupBox3 + + + True + + + 3, 22 + + + 23, 23 + + + 7, 17 + + + 1 + + + 74, 23 + + + 3, 4, 3, 4 + + + panel1 + + + Bottom, Right + + + 0 + + + Type + + + CenterScreen + + + Top, Bottom, Left, Right + + + False + + + textBox1 + + + Parameter List + + + 75, 23 + + + groupBox3 + + + 75, 23 + + + 380, 436 + + + 233, 250 + + + 0 + + + 3, 19 + + + 410, 290 + + + 0 + + + System.Windows.Forms.ListView, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + panel1 + + + 29, 0 + + + 1 + + + System.Windows.Forms.GroupBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 80, 154 + + + 161, 154 + + + 3 + + + Edit Array + + + Bottom, Left, Right + + + Old Value + + + 410, 12 + + + groupBox2 + + + System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 微软雅黑, 9pt + + + groupBox3 + + + 2 + + + System.Windows.Forms.GroupBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + button1 + + + listView1 + + + columnHeader3 + + + - + + + 12, 12 + + + columnHeader1 + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 392, 461 + + + 0 + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Fill + + + 0 + + + 3, 154 + + + True + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Top, Bottom, Left, Right + + + System.Windows.Forms.Panel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Bottom, Left, Right + + + $this + + + System.Windows.Forms.GroupBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Windows.Forms.Form, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + NoControl + + + System.Windows.Forms.ColumnHeader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 0 + + + 0, 0 + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 239, 272 + + + 200 + + + columnHeader2 + + + 50 + + + groupBox2 + + + button2 + + + groupBox3 + + + 2 + + + button4 + + + 1 + + + 23, 23 + + + 1 + + + 2 + + + Bottom, Right + + + Set Parameters + + + groupBox1 + + + groupBox1 + + + 0, 0, 0, 0 + + + New Value + + + 0 + + + 100 + + + $this + + + textBox2 + + + 1 + + + $this + + + 2 + + + Top, Bottom, Left + + + button3 + + + 6, 19 + + + 239, 183 + + + System.Windows.Forms.ColumnHeader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + True + + \ No newline at end of file diff --git a/src/Neo.GUI/GUI/ParametersEditor.zh-Hans.resx b/src/Neo.GUI/GUI/ParametersEditor.zh-Hans.resx new file mode 100644 index 0000000000..8db893dbac --- /dev/null +++ b/src/Neo.GUI/GUI/ParametersEditor.zh-Hans.resx @@ -0,0 +1,144 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 参数列表 + + + 类型 + + + + + + 当前值 + + + 新值 + + + 编辑数组 + + + 更新 + + + 设置参数 + + \ No newline at end of file diff --git a/src/Neo.GUI/GUI/PayToDialog.Designer.cs b/src/Neo.GUI/GUI/PayToDialog.Designer.cs new file mode 100644 index 0000000000..100d32f50d --- /dev/null +++ b/src/Neo.GUI/GUI/PayToDialog.Designer.cs @@ -0,0 +1,142 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-gui is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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.GUI +{ + partial class PayToDialog + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(PayToDialog)); + this.label1 = new System.Windows.Forms.Label(); + this.textBox1 = new System.Windows.Forms.TextBox(); + this.label2 = new System.Windows.Forms.Label(); + this.textBox2 = new System.Windows.Forms.TextBox(); + this.button1 = new System.Windows.Forms.Button(); + this.label3 = new System.Windows.Forms.Label(); + this.comboBox1 = new System.Windows.Forms.ComboBox(); + this.label4 = new System.Windows.Forms.Label(); + this.textBox3 = new System.Windows.Forms.TextBox(); + this.SuspendLayout(); + // + // label1 + // + resources.ApplyResources(this.label1, "label1"); + this.label1.Name = "label1"; + // + // textBox1 + // + resources.ApplyResources(this.textBox1, "textBox1"); + this.textBox1.Name = "textBox1"; + this.textBox1.TextChanged += new System.EventHandler(this.textBox_TextChanged); + // + // label2 + // + resources.ApplyResources(this.label2, "label2"); + this.label2.Name = "label2"; + // + // textBox2 + // + resources.ApplyResources(this.textBox2, "textBox2"); + this.textBox2.Name = "textBox2"; + this.textBox2.TextChanged += new System.EventHandler(this.textBox_TextChanged); + // + // button1 + // + resources.ApplyResources(this.button1, "button1"); + this.button1.DialogResult = System.Windows.Forms.DialogResult.OK; + this.button1.Name = "button1"; + this.button1.UseVisualStyleBackColor = true; + // + // label3 + // + resources.ApplyResources(this.label3, "label3"); + this.label3.Name = "label3"; + // + // comboBox1 + // + resources.ApplyResources(this.comboBox1, "comboBox1"); + this.comboBox1.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.comboBox1.FormattingEnabled = true; + this.comboBox1.Name = "comboBox1"; + this.comboBox1.SelectedIndexChanged += new System.EventHandler(this.comboBox1_SelectedIndexChanged); + // + // label4 + // + resources.ApplyResources(this.label4, "label4"); + this.label4.Name = "label4"; + // + // textBox3 + // + resources.ApplyResources(this.textBox3, "textBox3"); + this.textBox3.Name = "textBox3"; + this.textBox3.ReadOnly = true; + // + // PayToDialog + // + this.AcceptButton = this.button1; + resources.ApplyResources(this, "$this"); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.textBox3); + this.Controls.Add(this.label4); + this.Controls.Add(this.comboBox1); + this.Controls.Add(this.label3); + this.Controls.Add(this.button1); + this.Controls.Add(this.textBox2); + this.Controls.Add(this.label2); + this.Controls.Add(this.textBox1); + this.Controls.Add(this.label1); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "PayToDialog"; + this.ShowInTaskbar = false; + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Label label1; + private System.Windows.Forms.TextBox textBox1; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.TextBox textBox2; + private System.Windows.Forms.Button button1; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.ComboBox comboBox1; + private System.Windows.Forms.Label label4; + private System.Windows.Forms.TextBox textBox3; + } +} diff --git a/src/Neo.GUI/GUI/PayToDialog.cs b/src/Neo.GUI/GUI/PayToDialog.cs new file mode 100644 index 0000000000..b4dc3abdbd --- /dev/null +++ b/src/Neo.GUI/GUI/PayToDialog.cs @@ -0,0 +1,105 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-gui is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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; +using System; +using System.Windows.Forms; +using static Neo.Program; + +namespace Neo.GUI +{ + internal partial class PayToDialog : Form + { + public PayToDialog(AssetDescriptor asset = null, UInt160 scriptHash = null) + { + InitializeComponent(); + if (asset is null) + { + foreach (UInt160 assetId in NEP5Watched) + { + try + { + comboBox1.Items.Add(new AssetDescriptor(Service.NeoSystem.StoreView, Service.NeoSystem.Settings, assetId)); + } + catch (ArgumentException) + { + continue; + } + } + } + else + { + comboBox1.Items.Add(asset); + comboBox1.SelectedIndex = 0; + comboBox1.Enabled = false; + } + if (scriptHash != null) + { + textBox1.Text = scriptHash.ToAddress(Service.NeoSystem.Settings.AddressVersion); + textBox1.ReadOnly = true; + } + } + + public TxOutListBoxItem GetOutput() + { + AssetDescriptor asset = (AssetDescriptor)comboBox1.SelectedItem; + return new TxOutListBoxItem + { + AssetName = asset.AssetName, + AssetId = asset.AssetId, + Value = BigDecimal.Parse(textBox2.Text, asset.Decimals), + ScriptHash = textBox1.Text.ToScriptHash(Service.NeoSystem.Settings.AddressVersion) + }; + } + + private void comboBox1_SelectedIndexChanged(object sender, EventArgs e) + { + if (comboBox1.SelectedItem is AssetDescriptor asset) + { + textBox3.Text = Service.CurrentWallet.GetAvailable(Service.NeoSystem.StoreView, asset.AssetId).ToString(); + } + else + { + textBox3.Text = ""; + } + textBox_TextChanged(this, EventArgs.Empty); + } + + private void textBox_TextChanged(object sender, EventArgs e) + { + if (comboBox1.SelectedIndex < 0 || textBox1.TextLength == 0 || textBox2.TextLength == 0) + { + button1.Enabled = false; + return; + } + try + { + textBox1.Text.ToScriptHash(Service.NeoSystem.Settings.AddressVersion); + } + catch (FormatException) + { + button1.Enabled = false; + return; + } + AssetDescriptor asset = (AssetDescriptor)comboBox1.SelectedItem; + if (!BigDecimal.TryParse(textBox2.Text, asset.Decimals, out BigDecimal amount)) + { + button1.Enabled = false; + return; + } + if (amount.Sign <= 0) + { + button1.Enabled = false; + return; + } + button1.Enabled = true; + } + } +} diff --git a/src/Neo.GUI/GUI/PayToDialog.es-ES.resx b/src/Neo.GUI/GUI/PayToDialog.es-ES.resx new file mode 100644 index 0000000000..525ae78e9a --- /dev/null +++ b/src/Neo.GUI/GUI/PayToDialog.es-ES.resx @@ -0,0 +1,163 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + 12, 88 + + + 56, 17 + + + Pagar a: + + + 28, 122 + + + 40, 17 + + + Total: + + + Aceptar + + + 22, 17 + + + 46, 17 + + + Activo: + + + 24, 54 + + + 44, 17 + + + Saldo: + + + Pago + + \ No newline at end of file diff --git a/src/Neo.GUI/GUI/PayToDialog.resx b/src/Neo.GUI/GUI/PayToDialog.resx new file mode 100644 index 0000000000..2c575df5ab --- /dev/null +++ b/src/Neo.GUI/GUI/PayToDialog.resx @@ -0,0 +1,384 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + True + + + + 21, 88 + + + 47, 17 + + + 4 + + + Pay to: + + + label1 + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 8 + + + + Top, Left, Right + + + 74, 85 + + + 468, 23 + + + 5 + + + textBox1 + + + System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 7 + + + True + + + 12, 122 + + + 56, 17 + + + 6 + + + Amount: + + + label2 + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 6 + + + Top, Left, Right + + + 74, 119 + + + 468, 23 + + + 7 + + + textBox2 + + + System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 5 + + + Top, Right + + + False + + + 467, 157 + + + 75, 23 + + + 8 + + + OK + + + button1 + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 4 + + + True + + + 26, 17 + + + 42, 17 + + + 0 + + + Asset: + + + label3 + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 3 + + + Top, Left, Right + + + 74, 14 + + + 468, 25 + + + 1 + + + comboBox1 + + + System.Windows.Forms.ComboBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 2 + + + True + + + 12, 54 + + + 56, 17 + + + 2 + + + Balance: + + + label4 + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 1 + + + Top, Left, Right + + + 74, 51 + + + 468, 23 + + + 3 + + + textBox3 + + + System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 0 + + + True + + + 7, 17 + + + 554, 192 + + + 微软雅黑, 9pt + + + 3, 4, 3, 4 + + + CenterScreen + + + Payment + + + PayToDialog + + + System.Windows.Forms.Form, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/src/Neo.GUI/GUI/PayToDialog.zh-Hans.resx b/src/Neo.GUI/GUI/PayToDialog.zh-Hans.resx new file mode 100644 index 0000000000..9f55c74270 --- /dev/null +++ b/src/Neo.GUI/GUI/PayToDialog.zh-Hans.resx @@ -0,0 +1,193 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + 12, 75 + + + 59, 17 + + + 对方账户: + + + 77, 72 + + + 308, 23 + + + 36, 104 + + + 35, 17 + + + 数额: + + + 77, 101 + + + 227, 23 + + + 310, 101 + + + 确定 + + + 36, 15 + + + 35, 17 + + + 资产: + + + 77, 12 + + + 308, 25 + + + 36, 46 + + + 35, 17 + + + 余额: + + + 77, 43 + + + 308, 23 + + + 397, 134 + + + 支付 + + \ No newline at end of file diff --git a/src/Neo.GUI/GUI/QueueReader.cs b/src/Neo.GUI/GUI/QueueReader.cs new file mode 100644 index 0000000000..12f1260f3f --- /dev/null +++ b/src/Neo.GUI/GUI/QueueReader.cs @@ -0,0 +1,48 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-gui is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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.Collections.Generic; +using System.IO; +using System.Threading; + +namespace Neo.GUI +{ + internal class QueueReader : TextReader + { + private readonly Queue queue = new Queue(); + private string current; + private int index; + + public void Enqueue(string str) + { + queue.Enqueue(str); + } + + public override int Peek() + { + while (string.IsNullOrEmpty(current)) + { + while (!queue.TryDequeue(out current)) + Thread.Sleep(100); + index = 0; + } + return current[index]; + } + + public override int Read() + { + int c = Peek(); + if (c != -1) + if (++index >= current.Length) + current = null; + return c; + } + } +} diff --git a/src/Neo.GUI/GUI/SigningDialog.Designer.cs b/src/Neo.GUI/GUI/SigningDialog.Designer.cs new file mode 100644 index 0000000000..8c03f84901 --- /dev/null +++ b/src/Neo.GUI/GUI/SigningDialog.Designer.cs @@ -0,0 +1,172 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-gui is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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.GUI +{ + partial class SigningDialog + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(SigningDialog)); + this.button1 = new System.Windows.Forms.Button(); + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.textBox1 = new System.Windows.Forms.TextBox(); + this.groupBox2 = new System.Windows.Forms.GroupBox(); + this.textBox2 = new System.Windows.Forms.TextBox(); + this.button2 = new System.Windows.Forms.Button(); + this.button3 = new System.Windows.Forms.Button(); + this.cmbFormat = new System.Windows.Forms.ComboBox(); + this.cmbAddress = new System.Windows.Forms.ComboBox(); + this.label1 = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.groupBox1.SuspendLayout(); + this.groupBox2.SuspendLayout(); + this.SuspendLayout(); + // + // button1 + // + resources.ApplyResources(this.button1, "button1"); + this.button1.Name = "button1"; + this.button1.UseVisualStyleBackColor = true; + this.button1.Click += new System.EventHandler(this.button1_Click); + // + // groupBox1 + // + resources.ApplyResources(this.groupBox1, "groupBox1"); + this.groupBox1.Controls.Add(this.textBox1); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.TabStop = false; + // + // textBox1 + // + resources.ApplyResources(this.textBox1, "textBox1"); + this.textBox1.Name = "textBox1"; + // + // groupBox2 + // + resources.ApplyResources(this.groupBox2, "groupBox2"); + this.groupBox2.Controls.Add(this.textBox2); + this.groupBox2.Name = "groupBox2"; + this.groupBox2.TabStop = false; + // + // textBox2 + // + resources.ApplyResources(this.textBox2, "textBox2"); + this.textBox2.Name = "textBox2"; + this.textBox2.ReadOnly = true; + // + // button2 + // + resources.ApplyResources(this.button2, "button2"); + this.button2.Name = "button2"; + this.button2.UseVisualStyleBackColor = true; + this.button2.Click += new System.EventHandler(this.button2_Click); + // + // button3 + // + resources.ApplyResources(this.button3, "button3"); + this.button3.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.button3.Name = "button3"; + this.button3.UseVisualStyleBackColor = true; + // + // cmbFormat + // + resources.ApplyResources(this.cmbFormat, "cmbFormat"); + this.cmbFormat.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cmbFormat.FormattingEnabled = true; + this.cmbFormat.Items.AddRange(new object[] { + resources.GetString("cmbFormat.Items"), + resources.GetString("cmbFormat.Items1")}); + this.cmbFormat.Name = "cmbFormat"; + // + // cmbAddress + // + resources.ApplyResources(this.cmbAddress, "cmbAddress"); + this.cmbAddress.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cmbAddress.FormattingEnabled = true; + this.cmbAddress.Name = "cmbAddress"; + // + // label1 + // + resources.ApplyResources(this.label1, "label1"); + this.label1.Name = "label1"; + // + // label2 + // + resources.ApplyResources(this.label2, "label2"); + this.label2.Name = "label2"; + // + // SigningDialog + // + resources.ApplyResources(this, "$this"); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.button3; + this.Controls.Add(this.label2); + this.Controls.Add(this.label1); + this.Controls.Add(this.cmbAddress); + this.Controls.Add(this.cmbFormat); + this.Controls.Add(this.button3); + this.Controls.Add(this.button2); + this.Controls.Add(this.groupBox2); + this.Controls.Add(this.groupBox1); + this.Controls.Add(this.button1); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "SigningDialog"; + this.ShowInTaskbar = false; + this.groupBox1.ResumeLayout(false); + this.groupBox1.PerformLayout(); + this.groupBox2.ResumeLayout(false); + this.groupBox2.PerformLayout(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Button button1; + private System.Windows.Forms.GroupBox groupBox1; + private System.Windows.Forms.TextBox textBox1; + private System.Windows.Forms.GroupBox groupBox2; + private System.Windows.Forms.TextBox textBox2; + private System.Windows.Forms.Button button2; + private System.Windows.Forms.Button button3; + private System.Windows.Forms.ComboBox cmbFormat; + private System.Windows.Forms.ComboBox cmbAddress; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Label label2; + } +} diff --git a/src/Neo.GUI/GUI/SigningDialog.cs b/src/Neo.GUI/GUI/SigningDialog.cs new file mode 100644 index 0000000000..f94d92c438 --- /dev/null +++ b/src/Neo.GUI/GUI/SigningDialog.cs @@ -0,0 +1,106 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-gui is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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; +using Neo.Properties; +using Neo.Wallets; +using System; +using System.Linq; +using System.Text; +using System.Windows.Forms; +using static Neo.Program; + +namespace Neo.GUI +{ + internal partial class SigningDialog : Form + { + private class WalletEntry + { + public WalletAccount Account; + + public override string ToString() + { + if (!string.IsNullOrEmpty(Account.Label)) + { + return $"[{Account.Label}] " + Account.Address; + } + return Account.Address; + } + } + + + public SigningDialog() + { + InitializeComponent(); + + cmbFormat.SelectedIndex = 0; + cmbAddress.Items.AddRange(Service.CurrentWallet.GetAccounts() + .Where(u => u.HasKey) + .Select(u => new WalletEntry() { Account = u }) + .ToArray()); + + if (cmbAddress.Items.Count > 0) + { + cmbAddress.SelectedIndex = 0; + } + else + { + textBox2.Enabled = false; + button1.Enabled = false; + } + } + + private void button1_Click(object sender, EventArgs e) + { + if (textBox1.Text == "") + { + MessageBox.Show(Strings.SigningFailedNoDataMessage); + return; + } + + byte[] raw, signedData; + try + { + switch (cmbFormat.SelectedIndex) + { + case 0: raw = Encoding.UTF8.GetBytes(textBox1.Text); break; + case 1: raw = textBox1.Text.HexToBytes(); break; + default: return; + } + } + catch (Exception err) + { + MessageBox.Show(err.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + return; + } + + var account = (WalletEntry)cmbAddress.SelectedItem; + var keys = account.Account.GetKey(); + + try + { + signedData = Crypto.Sign(raw, keys.PrivateKey, keys.PublicKey.EncodePoint(false).Skip(1).ToArray()); + } + catch (Exception err) + { + MessageBox.Show(err.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + return; + } + + textBox2.Text = signedData?.ToHexString(); + } + + private void button2_Click(object sender, EventArgs e) + { + textBox2.SelectAll(); + textBox2.Copy(); + } + } +} diff --git a/src/Neo.GUI/GUI/SigningDialog.es-ES.resx b/src/Neo.GUI/GUI/SigningDialog.es-ES.resx new file mode 100644 index 0000000000..c440dbe4b2 --- /dev/null +++ b/src/Neo.GUI/GUI/SigningDialog.es-ES.resx @@ -0,0 +1,141 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Firma + + + Entrada + + + Salida + + + Copiar + + + Cancelar + + + Emitir + + + Firma + + \ No newline at end of file diff --git a/src/Neo.GUI/GUI/SigningDialog.resx b/src/Neo.GUI/GUI/SigningDialog.resx new file mode 100644 index 0000000000..d462a50fac --- /dev/null +++ b/src/Neo.GUI/GUI/SigningDialog.resx @@ -0,0 +1,462 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + Top + + + + 189, 269 + + + 75, 23 + + + + 2 + + + Sign + + + button1 + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 8 + + + Top, Left, Right + + + Fill + + + 3, 19 + + + True + + + Vertical + + + 424, 139 + + + 1 + + + textBox1 + + + System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + groupBox1 + + + 0 + + + 12, 97 + + + 430, 161 + + + 3 + + + Input + + + groupBox1 + + + System.Windows.Forms.GroupBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 7 + + + Top, Bottom, Left, Right + + + Fill + + + 3, 19 + + + True + + + Vertical + + + 424, 117 + + + 1 + + + textBox2 + + + System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + groupBox2 + + + 0 + + + 12, 298 + + + 430, 139 + + + 4 + + + Output + + + groupBox2 + + + System.Windows.Forms.GroupBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 6 + + + Bottom, Right + + + 286, 453 + + + 75, 23 + + + 5 + + + Copy + + + button2 + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 5 + + + Bottom, Right + + + 367, 453 + + + 75, 23 + + + 6 + + + Close + + + button3 + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 4 + + + Text + + + Hex + + + 367, 48 + + + 2, 3, 2, 3 + + + 72, 25 + + + 7 + + + cmbFormat + + + System.Windows.Forms.ComboBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 3 + + + 15, 48 + + + 2, 3, 2, 3 + + + 349, 25 + + + 8 + + + cmbAddress + + + System.Windows.Forms.ComboBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 2 + + + True + + + 12, 21 + + + 2, 0, 2, 0 + + + 56, 17 + + + 9 + + + Address + + + label1 + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 1 + + + True + + + NoControl + + + 364, 21 + + + 2, 0, 2, 0 + + + 49, 17 + + + 9 + + + Format + + + label2 + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 0 + + + True + + + 7, 17 + + + 454, 488 + + + Microsoft YaHei UI, 9pt + + + 3, 4, 3, 4 + + + CenterScreen + + + Signature + + + SigningDialog + + + System.Windows.Forms.Form, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/src/Neo.GUI/GUI/SigningDialog.zh-Hans.resx b/src/Neo.GUI/GUI/SigningDialog.zh-Hans.resx new file mode 100644 index 0000000000..282612d0f8 --- /dev/null +++ b/src/Neo.GUI/GUI/SigningDialog.zh-Hans.resx @@ -0,0 +1,151 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 签名 + + + 输入 + + + 输出 + + + 复制 + + + 关闭 + + + + 32, 17 + + + 地址 + + + 32, 17 + + + 格式 + + + 签名 + + \ No newline at end of file diff --git a/src/Neo.GUI/GUI/SigningTxDialog.Designer.cs b/src/Neo.GUI/GUI/SigningTxDialog.Designer.cs new file mode 100644 index 0000000000..45ecb20563 --- /dev/null +++ b/src/Neo.GUI/GUI/SigningTxDialog.Designer.cs @@ -0,0 +1,142 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-gui is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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.GUI +{ + partial class SigningTxDialog + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(SigningTxDialog)); + this.button1 = new System.Windows.Forms.Button(); + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.textBox1 = new System.Windows.Forms.TextBox(); + this.groupBox2 = new System.Windows.Forms.GroupBox(); + this.textBox2 = new System.Windows.Forms.TextBox(); + this.button2 = new System.Windows.Forms.Button(); + this.button3 = new System.Windows.Forms.Button(); + this.button4 = new System.Windows.Forms.Button(); + this.groupBox1.SuspendLayout(); + this.groupBox2.SuspendLayout(); + this.SuspendLayout(); + // + // button1 + // + resources.ApplyResources(this.button1, "button1"); + this.button1.Name = "button1"; + this.button1.UseVisualStyleBackColor = true; + this.button1.Click += new System.EventHandler(this.button1_Click); + // + // groupBox1 + // + resources.ApplyResources(this.groupBox1, "groupBox1"); + this.groupBox1.Controls.Add(this.textBox1); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.TabStop = false; + // + // textBox1 + // + resources.ApplyResources(this.textBox1, "textBox1"); + this.textBox1.Name = "textBox1"; + // + // groupBox2 + // + resources.ApplyResources(this.groupBox2, "groupBox2"); + this.groupBox2.Controls.Add(this.textBox2); + this.groupBox2.Name = "groupBox2"; + this.groupBox2.TabStop = false; + // + // textBox2 + // + resources.ApplyResources(this.textBox2, "textBox2"); + this.textBox2.Name = "textBox2"; + this.textBox2.ReadOnly = true; + // + // button2 + // + resources.ApplyResources(this.button2, "button2"); + this.button2.Name = "button2"; + this.button2.UseVisualStyleBackColor = true; + this.button2.Click += new System.EventHandler(this.button2_Click); + // + // button3 + // + resources.ApplyResources(this.button3, "button3"); + this.button3.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.button3.Name = "button3"; + this.button3.UseVisualStyleBackColor = true; + // + // button4 + // + resources.ApplyResources(this.button4, "button4"); + this.button4.Name = "button4"; + this.button4.UseVisualStyleBackColor = true; + this.button4.Click += new System.EventHandler(this.button4_Click); + // + // SigningTxDialog + // + resources.ApplyResources(this, "$this"); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.button3; + this.Controls.Add(this.button4); + this.Controls.Add(this.button3); + this.Controls.Add(this.button2); + this.Controls.Add(this.groupBox2); + this.Controls.Add(this.groupBox1); + this.Controls.Add(this.button1); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "SigningTxDialog"; + this.ShowInTaskbar = false; + this.groupBox1.ResumeLayout(false); + this.groupBox1.PerformLayout(); + this.groupBox2.ResumeLayout(false); + this.groupBox2.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.Button button1; + private System.Windows.Forms.GroupBox groupBox1; + private System.Windows.Forms.TextBox textBox1; + private System.Windows.Forms.GroupBox groupBox2; + private System.Windows.Forms.TextBox textBox2; + private System.Windows.Forms.Button button2; + private System.Windows.Forms.Button button3; + private System.Windows.Forms.Button button4; + } +} diff --git a/src/Neo.GUI/GUI/SigningTxDialog.cs b/src/Neo.GUI/GUI/SigningTxDialog.cs new file mode 100644 index 0000000000..718cf07b63 --- /dev/null +++ b/src/Neo.GUI/GUI/SigningTxDialog.cs @@ -0,0 +1,66 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-gui is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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.Network.P2P; +using Neo.Network.P2P.Payloads; +using Neo.Properties; +using Neo.SmartContract; +using System; +using System.Windows.Forms; +using static Neo.Program; + +namespace Neo.GUI +{ + internal partial class SigningTxDialog : Form + { + public SigningTxDialog() + { + InitializeComponent(); + } + + private void button1_Click(object sender, EventArgs e) + { + if (textBox1.Text == "") + { + MessageBox.Show(Strings.SigningFailedNoDataMessage); + return; + } + ContractParametersContext context = ContractParametersContext.Parse(textBox1.Text, Service.NeoSystem.StoreView); + if (!Service.CurrentWallet.Sign(context)) + { + MessageBox.Show(Strings.SigningFailedKeyNotFoundMessage); + return; + } + textBox2.Text = context.ToString(); + if (context.Completed) button4.Visible = true; + } + + private void button2_Click(object sender, EventArgs e) + { + textBox2.SelectAll(); + textBox2.Copy(); + } + + private void button4_Click(object sender, EventArgs e) + { + ContractParametersContext context = ContractParametersContext.Parse(textBox2.Text, Service.NeoSystem.StoreView); + if (!(context.Verifiable is Transaction tx)) + { + MessageBox.Show("Only support to broadcast transaction."); + return; + } + tx.Witnesses = context.GetWitnesses(); + Service.NeoSystem.Blockchain.Tell(tx); + InformationBox.Show(tx.Hash.ToString(), Strings.RelaySuccessText, Strings.RelaySuccessTitle); + button4.Visible = false; + } + } +} diff --git a/src/Neo.GUI/GUI/SigningTxDialog.es-ES.resx b/src/Neo.GUI/GUI/SigningTxDialog.es-ES.resx new file mode 100644 index 0000000000..c440dbe4b2 --- /dev/null +++ b/src/Neo.GUI/GUI/SigningTxDialog.es-ES.resx @@ -0,0 +1,141 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Firma + + + Entrada + + + Salida + + + Copiar + + + Cancelar + + + Emitir + + + Firma + + \ No newline at end of file diff --git a/src/Neo.GUI/GUI/SigningTxDialog.resx b/src/Neo.GUI/GUI/SigningTxDialog.resx new file mode 100644 index 0000000000..1f1af30e86 --- /dev/null +++ b/src/Neo.GUI/GUI/SigningTxDialog.resx @@ -0,0 +1,372 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + Top + + + + 190, 191 + + + 75, 23 + + + + 2 + + + Sign + + + button1 + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 5 + + + Top, Left, Right + + + 12, 12 + + + 430, 173 + + + 3 + + + Input + + + groupBox1 + + + System.Windows.Forms.GroupBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 4 + + + Fill + + + 3, 19 + + + True + + + Vertical + + + 424, 151 + + + 1 + + + textBox1 + + + System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + groupBox1 + + + 0 + + + Top, Bottom, Left, Right + + + 12, 220 + + + 430, 227 + + + 4 + + + Output + + + groupBox2 + + + System.Windows.Forms.GroupBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 3 + + + Fill + + + 3, 19 + + + True + + + Vertical + + + 424, 205 + + + 1 + + + textBox2 + + + System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + groupBox2 + + + 0 + + + Bottom, Right + + + 286, 453 + + + 75, 23 + + + 5 + + + Copy + + + button2 + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 2 + + + Bottom, Right + + + 367, 453 + + + 75, 23 + + + 6 + + + Close + + + button3 + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 1 + + + 12, 453 + + + 75, 23 + + + 7 + + + Broadcast + + + False + + + button4 + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 0 + + + True + + + 7, 17 + + + 454, 488 + + + 微软雅黑, 9pt + + + 3, 4, 3, 4 + + + CenterScreen + + + Signature + + + SigningTxDialog + + + System.Windows.Forms.Form, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + diff --git a/src/Neo.GUI/GUI/SigningTxDialog.zh-Hans.resx b/src/Neo.GUI/GUI/SigningTxDialog.zh-Hans.resx new file mode 100644 index 0000000000..218f36f8e5 --- /dev/null +++ b/src/Neo.GUI/GUI/SigningTxDialog.zh-Hans.resx @@ -0,0 +1,141 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 签名 + + + 输入 + + + 输出 + + + 复制 + + + 关闭 + + + 广播 + + + 签名 + + \ No newline at end of file diff --git a/src/Neo.GUI/GUI/TextBoxWriter.cs b/src/Neo.GUI/GUI/TextBoxWriter.cs new file mode 100644 index 0000000000..c8be8a86ed --- /dev/null +++ b/src/Neo.GUI/GUI/TextBoxWriter.cs @@ -0,0 +1,39 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-gui is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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.IO; +using System.Text; +using System.Windows.Forms; + +namespace Neo.GUI +{ + internal class TextBoxWriter : TextWriter + { + private readonly TextBoxBase textBox; + + public override Encoding Encoding => Encoding.UTF8; + + public TextBoxWriter(TextBoxBase textBox) + { + this.textBox = textBox; + } + + public override void Write(char value) + { + textBox.Invoke(new Action(() => { textBox.Text += value; })); + } + + public override void Write(string value) + { + textBox.Invoke(new Action(textBox.AppendText), value); + } + } +} diff --git a/src/Neo.GUI/GUI/TransferDialog.Designer.cs b/src/Neo.GUI/GUI/TransferDialog.Designer.cs new file mode 100644 index 0000000000..2d19a83fce --- /dev/null +++ b/src/Neo.GUI/GUI/TransferDialog.Designer.cs @@ -0,0 +1,131 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-gui is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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.GUI +{ + partial class TransferDialog + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(TransferDialog)); + this.groupBox3 = new System.Windows.Forms.GroupBox(); + this.txOutListBox1 = new Neo.GUI.TxOutListBox(); + this.button4 = new System.Windows.Forms.Button(); + this.button3 = new System.Windows.Forms.Button(); + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.comboBoxFrom = new System.Windows.Forms.ComboBox(); + this.labelFrom = new System.Windows.Forms.Label(); + this.groupBox3.SuspendLayout(); + this.groupBox1.SuspendLayout(); + this.SuspendLayout(); + // + // groupBox3 + // + resources.ApplyResources(this.groupBox3, "groupBox3"); + this.groupBox3.Controls.Add(this.txOutListBox1); + this.groupBox3.Name = "groupBox3"; + this.groupBox3.TabStop = false; + // + // txOutListBox1 + // + resources.ApplyResources(this.txOutListBox1, "txOutListBox1"); + this.txOutListBox1.Asset = null; + this.txOutListBox1.Name = "txOutListBox1"; + this.txOutListBox1.ReadOnly = false; + this.txOutListBox1.ScriptHash = null; + this.txOutListBox1.ItemsChanged += new System.EventHandler(this.txOutListBox1_ItemsChanged); + // + // button4 + // + resources.ApplyResources(this.button4, "button4"); + this.button4.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.button4.Name = "button4"; + this.button4.UseVisualStyleBackColor = true; + // + // button3 + // + resources.ApplyResources(this.button3, "button3"); + this.button3.DialogResult = System.Windows.Forms.DialogResult.OK; + this.button3.Name = "button3"; + this.button3.UseVisualStyleBackColor = true; + // + // groupBox1 + // + resources.ApplyResources(this.groupBox1, "groupBox1"); + this.groupBox1.Controls.Add(this.comboBoxFrom); + this.groupBox1.Controls.Add(this.labelFrom); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.TabStop = false; + // + // comboBoxFrom + // + resources.ApplyResources(this.comboBoxFrom, "comboBoxFrom"); + this.comboBoxFrom.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.comboBoxFrom.FormattingEnabled = true; + this.comboBoxFrom.Name = "comboBoxFrom"; + // + // labelFrom + // + resources.ApplyResources(this.labelFrom, "labelFrom"); + this.labelFrom.Name = "labelFrom"; + // + // TransferDialog + // + resources.ApplyResources(this, "$this"); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.groupBox1); + this.Controls.Add(this.button4); + this.Controls.Add(this.button3); + this.Controls.Add(this.groupBox3); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.Name = "TransferDialog"; + this.ShowInTaskbar = false; + this.groupBox3.ResumeLayout(false); + this.groupBox1.ResumeLayout(false); + this.groupBox1.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + private System.Windows.Forms.GroupBox groupBox3; + private System.Windows.Forms.Button button4; + private System.Windows.Forms.Button button3; + private TxOutListBox txOutListBox1; + private System.Windows.Forms.GroupBox groupBox1; + private System.Windows.Forms.ComboBox comboBoxFrom; + private System.Windows.Forms.Label labelFrom; + } +} diff --git a/src/Neo.GUI/GUI/TransferDialog.cs b/src/Neo.GUI/GUI/TransferDialog.cs new file mode 100644 index 0000000000..16f7764d68 --- /dev/null +++ b/src/Neo.GUI/GUI/TransferDialog.cs @@ -0,0 +1,41 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-gui is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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.Payloads; +using Neo.SmartContract; +using Neo.Wallets; +using System; +using System.Linq; +using System.Windows.Forms; +using static Neo.Program; + +namespace Neo.GUI +{ + public partial class TransferDialog : Form + { + public TransferDialog() + { + InitializeComponent(); + comboBoxFrom.Items.AddRange(Service.CurrentWallet.GetAccounts().Where(p => !p.WatchOnly).Select(p => p.Address).ToArray()); + } + + public Transaction GetTransaction() + { + TransferOutput[] outputs = txOutListBox1.Items.ToArray(); + UInt160 from = comboBoxFrom.SelectedItem is null ? null : ((string)comboBoxFrom.SelectedItem).ToScriptHash(Service.NeoSystem.Settings.AddressVersion); + return Service.CurrentWallet.MakeTransaction(Service.NeoSystem.StoreView, outputs, from); + } + + private void txOutListBox1_ItemsChanged(object sender, EventArgs e) + { + button3.Enabled = txOutListBox1.ItemCount > 0; + } + } +} diff --git a/src/Neo.GUI/GUI/TransferDialog.es-ES.resx b/src/Neo.GUI/GUI/TransferDialog.es-ES.resx new file mode 100644 index 0000000000..662fc871c4 --- /dev/null +++ b/src/Neo.GUI/GUI/TransferDialog.es-ES.resx @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Lista de destinatarios + + + Cancelar + + + Aceptar + + + Transferir + + \ No newline at end of file diff --git a/src/Neo.GUI/GUI/TransferDialog.resx b/src/Neo.GUI/GUI/TransferDialog.resx new file mode 100644 index 0000000000..f902756230 --- /dev/null +++ b/src/Neo.GUI/GUI/TransferDialog.resx @@ -0,0 +1,369 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + Top, Left, Right + + + Top, Bottom, Left, Right + + + + Microsoft YaHei UI, 9pt + + + 6, 24 + + + 3, 4, 3, 4 + + + 551, 276 + + + + 0 + + + txOutListBox1 + + + Neo.UI.TxOutListBox, neo-gui, Version=2.10.7263.32482, Culture=neutral, PublicKeyToken=null + + + groupBox3 + + + 0 + + + 12, 13 + + + 3, 4, 3, 4 + + + 3, 4, 3, 4 + + + 563, 308 + + + 0 + + + Recipient List + + + groupBox3 + + + System.Windows.Forms.GroupBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 3 + + + Bottom, Right + + + NoControl + + + 500, 401 + + + 3, 4, 3, 4 + + + 75, 24 + + + 2 + + + Cancel + + + button4 + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 1 + + + Bottom, Right + + + False + + + NoControl + + + 419, 401 + + + 3, 4, 3, 4 + + + 75, 24 + + + 1 + + + OK + + + button3 + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 2 + + + Top, Left, Right + + + Top, Left, Right + + + 78, 22 + + + 418, 0 + + + 479, 25 + + + 2 + + + comboBoxFrom + + + System.Windows.Forms.ComboBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + groupBox1 + + + 0 + + + True + + + NoControl + + + 31, 25 + + + 41, 17 + + + 4 + + + From: + + + MiddleLeft + + + labelFrom + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + groupBox1 + + + 1 + + + 12, 328 + + + 563, 60 + + + 4 + + + Advanced + + + groupBox1 + + + System.Windows.Forms.GroupBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 0 + + + True + + + 7, 17 + + + 587, 440 + + + Microsoft YaHei UI, 9pt + + + 3, 4, 3, 4 + + + CenterScreen + + + Transfer + + + TransferDialog + + + System.Windows.Forms.Form, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/src/Neo.GUI/GUI/TransferDialog.zh-Hans.resx b/src/Neo.GUI/GUI/TransferDialog.zh-Hans.resx new file mode 100644 index 0000000000..33ddb97439 --- /dev/null +++ b/src/Neo.GUI/GUI/TransferDialog.zh-Hans.resx @@ -0,0 +1,142 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 收款人列表 + + + 取消 + + + 确定 + + + 高级 + + + + 44, 17 + + + 转自: + + + 转账 + + \ No newline at end of file diff --git a/src/Neo.GUI/GUI/TxOutListBox.Designer.cs b/src/Neo.GUI/GUI/TxOutListBox.Designer.cs new file mode 100644 index 0000000000..ad9f54d846 --- /dev/null +++ b/src/Neo.GUI/GUI/TxOutListBox.Designer.cs @@ -0,0 +1,109 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-gui is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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.GUI +{ + partial class TxOutListBox + { + /// + /// 必需的设计器变量。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清理所有正在使用的资源。 + /// + /// 如果应释放托管资源,为 true;否则为 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region 组件设计器生成的代码 + + /// + /// 设计器支持所需的方法 - 不要修改 + /// 使用代码编辑器修改此方法的内容。 + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(TxOutListBox)); + this.listBox1 = new System.Windows.Forms.ListBox(); + this.panel1 = new System.Windows.Forms.Panel(); + this.button1 = new System.Windows.Forms.Button(); + this.button2 = new System.Windows.Forms.Button(); + this.button3 = new System.Windows.Forms.Button(); + this.panel1.SuspendLayout(); + this.SuspendLayout(); + // + // listBox1 + // + resources.ApplyResources(this.listBox1, "listBox1"); + this.listBox1.Name = "listBox1"; + this.listBox1.SelectionMode = System.Windows.Forms.SelectionMode.MultiExtended; + this.listBox1.SelectedIndexChanged += new System.EventHandler(this.listBox1_SelectedIndexChanged); + // + // panel1 + // + resources.ApplyResources(this.panel1, "panel1"); + this.panel1.Controls.Add(this.button1); + this.panel1.Controls.Add(this.button2); + this.panel1.Controls.Add(this.button3); + this.panel1.Name = "panel1"; + // + // button1 + // + resources.ApplyResources(this.button1, "button1"); + this.button1.Image = global::Neo.Properties.Resources.add; + this.button1.Name = "button1"; + this.button1.UseVisualStyleBackColor = true; + this.button1.Click += new System.EventHandler(this.button1_Click); + // + // button2 + // + resources.ApplyResources(this.button2, "button2"); + this.button2.Image = global::Neo.Properties.Resources.remove; + this.button2.Name = "button2"; + this.button2.UseVisualStyleBackColor = true; + this.button2.Click += new System.EventHandler(this.button2_Click); + // + // button3 + // + resources.ApplyResources(this.button3, "button3"); + this.button3.Image = global::Neo.Properties.Resources.add2; + this.button3.Name = "button3"; + this.button3.UseVisualStyleBackColor = true; + this.button3.Click += new System.EventHandler(this.button3_Click); + // + // TxOutListBox + // + resources.ApplyResources(this, "$this"); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.panel1); + this.Controls.Add(this.listBox1); + this.Name = "TxOutListBox"; + this.panel1.ResumeLayout(false); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.ListBox listBox1; + private System.Windows.Forms.Panel panel1; + private System.Windows.Forms.Button button1; + private System.Windows.Forms.Button button2; + private System.Windows.Forms.Button button3; + } +} diff --git a/src/Neo.GUI/GUI/TxOutListBox.cs b/src/Neo.GUI/GUI/TxOutListBox.cs new file mode 100644 index 0000000000..8157c7c252 --- /dev/null +++ b/src/Neo.GUI/GUI/TxOutListBox.cs @@ -0,0 +1,102 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-gui is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Windows.Forms; + +namespace Neo.GUI +{ + [DefaultEvent(nameof(ItemsChanged))] + internal partial class TxOutListBox : UserControl + { + public event EventHandler ItemsChanged; + + public AssetDescriptor Asset { get; set; } + + public int ItemCount => listBox1.Items.Count; + + public IEnumerable Items => listBox1.Items.OfType(); + + public bool ReadOnly + { + get + { + return !panel1.Enabled; + } + set + { + panel1.Enabled = !value; + } + } + + private UInt160 _script_hash = null; + public UInt160 ScriptHash + { + get + { + return _script_hash; + } + set + { + _script_hash = value; + button3.Enabled = value == null; + } + } + + public TxOutListBox() + { + InitializeComponent(); + } + + public void Clear() + { + if (listBox1.Items.Count > 0) + { + listBox1.Items.Clear(); + button2.Enabled = false; + ItemsChanged?.Invoke(this, EventArgs.Empty); + } + } + + private void listBox1_SelectedIndexChanged(object sender, EventArgs e) + { + button2.Enabled = listBox1.SelectedIndices.Count > 0; + } + + private void button1_Click(object sender, EventArgs e) + { + using PayToDialog dialog = new PayToDialog(asset: Asset, scriptHash: ScriptHash); + if (dialog.ShowDialog() != DialogResult.OK) return; + listBox1.Items.Add(dialog.GetOutput()); + ItemsChanged?.Invoke(this, EventArgs.Empty); + } + + private void button2_Click(object sender, EventArgs e) + { + while (listBox1.SelectedIndices.Count > 0) + { + listBox1.Items.RemoveAt(listBox1.SelectedIndices[0]); + } + ItemsChanged?.Invoke(this, EventArgs.Empty); + } + + private void button3_Click(object sender, EventArgs e) + { + using BulkPayDialog dialog = new BulkPayDialog(Asset); + if (dialog.ShowDialog() != DialogResult.OK) return; + listBox1.Items.AddRange(dialog.GetOutputs()); + ItemsChanged?.Invoke(this, EventArgs.Empty); + } + } +} diff --git a/src/Neo.GUI/GUI/TxOutListBox.resx b/src/Neo.GUI/GUI/TxOutListBox.resx new file mode 100644 index 0000000000..92bba21c58 --- /dev/null +++ b/src/Neo.GUI/GUI/TxOutListBox.resx @@ -0,0 +1,300 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + Top, Bottom, Left, Right + + + + True + + + False + + + 17 + + + + 0, 0 + + + 3, 4, 3, 4 + + + True + + + 349, 167 + + + 0 + + + listBox1 + + + System.Windows.Forms.ListBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 1 + + + Bottom, Left, Right + + + Bottom, Left + + + NoControl + + + 0, 0 + + + 3, 4, 3, 4 + + + 27, 27 + + + 0 + + + button1 + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + panel1 + + + 0 + + + Bottom, Left + + + False + + + NoControl + + + 33, 0 + + + 3, 4, 3, 4 + + + 27, 27 + + + 1 + + + button2 + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + panel1 + + + 1 + + + Bottom, Left + + + NoControl + + + 66, 0 + + + 3, 4, 3, 4 + + + 27, 27 + + + 2 + + + button3 + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + panel1 + + + 2 + + + 0, 175 + + + 349, 27 + + + 1 + + + panel1 + + + System.Windows.Forms.Panel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 0 + + + True + + + 7, 17 + + + 微软雅黑, 9pt + + + 3, 4, 3, 4 + + + 349, 202 + + + TxOutListBox + + + System.Windows.Forms.UserControl, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/src/Neo.GUI/GUI/TxOutListBoxItem.cs b/src/Neo.GUI/GUI/TxOutListBoxItem.cs new file mode 100644 index 0000000000..40356aa8ef --- /dev/null +++ b/src/Neo.GUI/GUI/TxOutListBoxItem.cs @@ -0,0 +1,24 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-gui is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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.GUI +{ + internal class TxOutListBoxItem : TransferOutput + { + public string AssetName; + + public override string ToString() + { + return $"{ScriptHash.ToAddress(Program.Service.NeoSystem.Settings.AddressVersion)}\t{Value}\t{AssetName}"; + } + } +} diff --git a/src/Neo.GUI/GUI/UpdateDialog.Designer.cs b/src/Neo.GUI/GUI/UpdateDialog.Designer.cs new file mode 100644 index 0000000000..6af087d42b --- /dev/null +++ b/src/Neo.GUI/GUI/UpdateDialog.Designer.cs @@ -0,0 +1,149 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-gui is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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.GUI +{ + partial class UpdateDialog + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(UpdateDialog)); + this.label1 = new System.Windows.Forms.Label(); + this.textBox1 = new System.Windows.Forms.TextBox(); + this.linkLabel1 = new System.Windows.Forms.LinkLabel(); + this.button1 = new System.Windows.Forms.Button(); + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.textBox2 = new System.Windows.Forms.TextBox(); + this.button2 = new System.Windows.Forms.Button(); + this.linkLabel2 = new System.Windows.Forms.LinkLabel(); + this.progressBar1 = new System.Windows.Forms.ProgressBar(); + this.groupBox1.SuspendLayout(); + this.SuspendLayout(); + // + // label1 + // + resources.ApplyResources(this.label1, "label1"); + this.label1.Name = "label1"; + // + // textBox1 + // + resources.ApplyResources(this.textBox1, "textBox1"); + this.textBox1.BorderStyle = System.Windows.Forms.BorderStyle.None; + this.textBox1.Name = "textBox1"; + this.textBox1.ReadOnly = true; + // + // linkLabel1 + // + resources.ApplyResources(this.linkLabel1, "linkLabel1"); + this.linkLabel1.Name = "linkLabel1"; + this.linkLabel1.TabStop = true; + this.linkLabel1.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkLabel1_LinkClicked); + // + // button1 + // + resources.ApplyResources(this.button1, "button1"); + this.button1.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.button1.Name = "button1"; + this.button1.UseVisualStyleBackColor = true; + // + // groupBox1 + // + resources.ApplyResources(this.groupBox1, "groupBox1"); + this.groupBox1.Controls.Add(this.textBox2); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.TabStop = false; + // + // textBox2 + // + resources.ApplyResources(this.textBox2, "textBox2"); + this.textBox2.Name = "textBox2"; + this.textBox2.ReadOnly = true; + // + // button2 + // + resources.ApplyResources(this.button2, "button2"); + this.button2.Name = "button2"; + this.button2.UseVisualStyleBackColor = true; + this.button2.Click += new System.EventHandler(this.button2_Click); + // + // linkLabel2 + // + resources.ApplyResources(this.linkLabel2, "linkLabel2"); + this.linkLabel2.Name = "linkLabel2"; + this.linkLabel2.TabStop = true; + this.linkLabel2.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkLabel2_LinkClicked); + // + // progressBar1 + // + resources.ApplyResources(this.progressBar1, "progressBar1"); + this.progressBar1.Name = "progressBar1"; + // + // UpdateDialog + // + resources.ApplyResources(this, "$this"); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.button1; + this.Controls.Add(this.progressBar1); + this.Controls.Add(this.linkLabel2); + this.Controls.Add(this.button2); + this.Controls.Add(this.groupBox1); + this.Controls.Add(this.button1); + this.Controls.Add(this.linkLabel1); + this.Controls.Add(this.textBox1); + this.Controls.Add(this.label1); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "UpdateDialog"; + this.ShowInTaskbar = false; + this.groupBox1.ResumeLayout(false); + this.groupBox1.PerformLayout(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Label label1; + private System.Windows.Forms.TextBox textBox1; + private System.Windows.Forms.LinkLabel linkLabel1; + private System.Windows.Forms.Button button1; + private System.Windows.Forms.GroupBox groupBox1; + private System.Windows.Forms.TextBox textBox2; + private System.Windows.Forms.Button button2; + private System.Windows.Forms.LinkLabel linkLabel2; + private System.Windows.Forms.ProgressBar progressBar1; + } +} diff --git a/src/Neo.GUI/GUI/UpdateDialog.cs b/src/Neo.GUI/GUI/UpdateDialog.cs new file mode 100644 index 0000000000..c058c4dcb7 --- /dev/null +++ b/src/Neo.GUI/GUI/UpdateDialog.cs @@ -0,0 +1,76 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-gui is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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.Properties; +using System; +using System.Diagnostics; +using System.IO; +using System.IO.Compression; +using System.Linq; +using System.Net.Http; +using System.Windows.Forms; +using System.Xml.Linq; + +namespace Neo.GUI +{ + internal partial class UpdateDialog : Form + { + private readonly HttpClient http = new(); + private readonly string download_url; + private string download_path; + + public UpdateDialog(XDocument xdoc) + { + InitializeComponent(); + Version latest = Version.Parse(xdoc.Element("update").Attribute("latest").Value); + textBox1.Text = latest.ToString(); + XElement release = xdoc.Element("update").Elements("release").First(p => p.Attribute("version").Value == latest.ToString()); + textBox2.Text = release.Element("changes").Value.Replace("\n", Environment.NewLine); + download_url = release.Attribute("file").Value; + } + + private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) + { + Process.Start("https://neo.org/"); + } + + private void linkLabel2_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) + { + Process.Start(download_url); + } + + private async void button2_Click(object sender, EventArgs e) + { + button1.Enabled = false; + button2.Enabled = false; + download_path = "update.zip"; + using (Stream responseStream = await http.GetStreamAsync(download_url)) + using (FileStream fileStream = new(download_path, FileMode.Create, FileAccess.Write, FileShare.None)) + { + await responseStream.CopyToAsync(fileStream); + } + DirectoryInfo di = new DirectoryInfo("update"); + if (di.Exists) di.Delete(true); + di.Create(); + ZipFile.ExtractToDirectory(download_path, di.Name); + FileSystemInfo[] fs = di.GetFileSystemInfos(); + if (fs.Length == 1 && fs[0] is DirectoryInfo directory) + { + directory.MoveTo("update2"); + di.Delete(); + Directory.Move("update2", di.Name); + } + File.WriteAllBytes("update.bat", Resources.UpdateBat); + Close(); + if (Program.MainForm != null) Program.MainForm.Close(); + Process.Start("update.bat"); + } + } +} diff --git a/src/Neo.GUI/GUI/UpdateDialog.es-ES.resx b/src/Neo.GUI/GUI/UpdateDialog.es-ES.resx new file mode 100644 index 0000000000..5f94e9b654 --- /dev/null +++ b/src/Neo.GUI/GUI/UpdateDialog.es-ES.resx @@ -0,0 +1,157 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + 94, 17 + + + Última versión: + + + 112, 15 + + + 332, 16 + + + 73, 17 + + + Web oficial + + + Cancelar + + + Registro de cambios + + + Actualizar + + + 68, 17 + + + Descargar + + + Actualización disponible + + \ No newline at end of file diff --git a/src/Neo.GUI/GUI/UpdateDialog.resx b/src/Neo.GUI/GUI/UpdateDialog.resx new file mode 100644 index 0000000000..23e774988f --- /dev/null +++ b/src/Neo.GUI/GUI/UpdateDialog.resx @@ -0,0 +1,399 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + True + + + + 12, 15 + + + 102, 17 + + + 0 + + + Newest Version: + + + label1 + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 7 + + + + Top, Left, Right + + + 120, 15 + + + 324, 16 + + + 1 + + + textBox1 + + + System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 6 + + + Bottom, Left + + + True + + + 12, 335 + + + 79, 17 + + + 4 + + + Official Web + + + linkLabel1 + + + System.Windows.Forms.LinkLabel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 5 + + + Bottom, Right + + + 369, 332 + + + 75, 23 + + + 7 + + + Close + + + button1 + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 4 + + + Top, Bottom, Left, Right + + + Fill + + + 3, 19 + + + True + + + Both + + + 426, 234 + + + 0 + + + False + + + textBox2 + + + System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + groupBox1 + + + 0 + + + 12, 41 + + + 432, 256 + + + 2 + + + Change logs + + + groupBox1 + + + System.Windows.Forms.GroupBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 3 + + + Bottom, Right + + + 288, 332 + + + 75, 23 + + + 6 + + + Update + + + button2 + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 2 + + + Bottom, Left + + + True + + + NoControl + + + 97, 335 + + + 67, 17 + + + 5 + + + Download + + + linkLabel2 + + + System.Windows.Forms.LinkLabel, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 1 + + + 12, 303 + + + 432, 23 + + + 3 + + + progressBar1 + + + System.Windows.Forms.ProgressBar, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 0 + + + True + + + 7, 17 + + + 456, 367 + + + 微软雅黑, 9pt + + + 3, 4, 3, 4 + + + CenterScreen + + + Update Available + + + UpdateDialog + + + System.Windows.Forms.Form, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/src/Neo.GUI/GUI/UpdateDialog.zh-Hans.resx b/src/Neo.GUI/GUI/UpdateDialog.zh-Hans.resx new file mode 100644 index 0000000000..6db88c3a6e --- /dev/null +++ b/src/Neo.GUI/GUI/UpdateDialog.zh-Hans.resx @@ -0,0 +1,160 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + 59, 17 + + + 最新版本: + + + 77, 15 + + + 367, 16 + + + 32, 17 + + + 官网 + + + 关闭 + + + 更新日志 + + + 更新 + + + 50, 335 + + + 32, 17 + + + 下载 + + + 发现新版本 + + \ No newline at end of file diff --git a/src/Neo.GUI/GUI/ViewContractDialog.Designer.cs b/src/Neo.GUI/GUI/ViewContractDialog.Designer.cs new file mode 100644 index 0000000000..5adbe25451 --- /dev/null +++ b/src/Neo.GUI/GUI/ViewContractDialog.Designer.cs @@ -0,0 +1,143 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-gui is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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.GUI +{ + partial class ViewContractDialog + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ViewContractDialog)); + this.label1 = new System.Windows.Forms.Label(); + this.textBox1 = new System.Windows.Forms.TextBox(); + this.label2 = new System.Windows.Forms.Label(); + this.textBox2 = new System.Windows.Forms.TextBox(); + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.textBox4 = new System.Windows.Forms.TextBox(); + this.button1 = new System.Windows.Forms.Button(); + this.label3 = new System.Windows.Forms.Label(); + this.textBox3 = new System.Windows.Forms.TextBox(); + this.groupBox1.SuspendLayout(); + this.SuspendLayout(); + // + // label1 + // + resources.ApplyResources(this.label1, "label1"); + this.label1.Name = "label1"; + // + // textBox1 + // + resources.ApplyResources(this.textBox1, "textBox1"); + this.textBox1.Name = "textBox1"; + this.textBox1.ReadOnly = true; + // + // label2 + // + resources.ApplyResources(this.label2, "label2"); + this.label2.Name = "label2"; + // + // textBox2 + // + resources.ApplyResources(this.textBox2, "textBox2"); + this.textBox2.Name = "textBox2"; + this.textBox2.ReadOnly = true; + // + // groupBox1 + // + resources.ApplyResources(this.groupBox1, "groupBox1"); + this.groupBox1.Controls.Add(this.textBox4); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.TabStop = false; + // + // textBox4 + // + resources.ApplyResources(this.textBox4, "textBox4"); + this.textBox4.Name = "textBox4"; + this.textBox4.ReadOnly = true; + // + // button1 + // + resources.ApplyResources(this.button1, "button1"); + this.button1.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.button1.Name = "button1"; + this.button1.UseVisualStyleBackColor = true; + // + // label3 + // + resources.ApplyResources(this.label3, "label3"); + this.label3.Name = "label3"; + // + // textBox3 + // + resources.ApplyResources(this.textBox3, "textBox3"); + this.textBox3.Name = "textBox3"; + this.textBox3.ReadOnly = true; + // + // ViewContractDialog + // + resources.ApplyResources(this, "$this"); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.button1; + this.Controls.Add(this.textBox3); + this.Controls.Add(this.label3); + this.Controls.Add(this.button1); + this.Controls.Add(this.groupBox1); + this.Controls.Add(this.textBox2); + this.Controls.Add(this.label2); + this.Controls.Add(this.textBox1); + this.Controls.Add(this.label1); + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "ViewContractDialog"; + this.ShowInTaskbar = false; + this.groupBox1.ResumeLayout(false); + this.groupBox1.PerformLayout(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Label label1; + private System.Windows.Forms.TextBox textBox1; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.TextBox textBox2; + private System.Windows.Forms.GroupBox groupBox1; + private System.Windows.Forms.Button button1; + private System.Windows.Forms.TextBox textBox4; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.TextBox textBox3; + } +} diff --git a/src/Neo.GUI/GUI/ViewContractDialog.cs b/src/Neo.GUI/GUI/ViewContractDialog.cs new file mode 100644 index 0000000000..ada56ef90f --- /dev/null +++ b/src/Neo.GUI/GUI/ViewContractDialog.cs @@ -0,0 +1,29 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-gui is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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 System.Linq; +using System.Windows.Forms; +using Neo.Wallets; + +namespace Neo.GUI +{ + public partial class ViewContractDialog : Form + { + public ViewContractDialog(Contract contract) + { + InitializeComponent(); + textBox1.Text = contract.ScriptHash.ToAddress(Program.Service.NeoSystem.Settings.AddressVersion); + textBox2.Text = contract.ScriptHash.ToString(); + textBox3.Text = contract.ParameterList.Cast().ToArray().ToHexString(); + textBox4.Text = contract.Script.ToHexString(); + } + } +} diff --git a/src/Neo.GUI/GUI/ViewContractDialog.es-ES.resx b/src/Neo.GUI/GUI/ViewContractDialog.es-ES.resx new file mode 100644 index 0000000000..c792cfc6ab --- /dev/null +++ b/src/Neo.GUI/GUI/ViewContractDialog.es-ES.resx @@ -0,0 +1,187 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + 72, 15 + + + 65, 17 + + + Dirección: + + + 143, 12 + + + 363, 23 + + + 39, 44 + + + 98, 17 + + + Hash del script: + + + 143, 41 + + + 363, 23 + + + 494, 273 + + + Código del script + + + 488, 251 + + + 431, 378 + + + Cancelar + + + 9, 73 + + + 128, 17 + + + Lista de parámetros: + + + 143, 70 + + + 363, 23 + + + 518, 413 + + + Ver contrato + + \ No newline at end of file diff --git a/src/Neo.GUI/GUI/ViewContractDialog.resx b/src/Neo.GUI/GUI/ViewContractDialog.resx new file mode 100644 index 0000000000..97c2f61083 --- /dev/null +++ b/src/Neo.GUI/GUI/ViewContractDialog.resx @@ -0,0 +1,387 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + True + + + + 47, 15 + + + 59, 17 + + + 0 + + + Address: + + + label1 + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 7 + + + + Top, Left, Right + + + 112, 12 + + + 328, 23 + + + 1 + + + textBox1 + + + System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 6 + + + True + + + 29, 44 + + + 77, 17 + + + 2 + + + Script Hash: + + + label2 + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 5 + + + Top, Left, Right + + + 112, 41 + + + 328, 23 + + + 3 + + + textBox2 + + + System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 4 + + + Top, Bottom, Left, Right + + + Fill + + + 3, 19 + + + True + + + Vertical + + + 422, 251 + + + 0 + + + textBox4 + + + System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + groupBox1 + + + 0 + + + 12, 99 + + + 428, 273 + + + 6 + + + Redeem Script + + + groupBox1 + + + System.Windows.Forms.GroupBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 3 + + + Bottom, Right + + + 365, 378 + + + 75, 23 + + + 7 + + + Close + + + button1 + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 2 + + + True + + + 12, 73 + + + 94, 17 + + + 4 + + + Parameter List: + + + label3 + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 1 + + + Top, Left, Right + + + 112, 70 + + + 328, 23 + + + 5 + + + textBox3 + + + System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 0 + + + True + + + 7, 17 + + + 452, 413 + + + Microsoft YaHei UI, 9pt + + + 2, 2, 2, 2 + + + CenterScreen + + + View Contract + + + ViewContractDialog + + + System.Windows.Forms.Form, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/src/Neo.GUI/GUI/ViewContractDialog.zh-Hans.resx b/src/Neo.GUI/GUI/ViewContractDialog.zh-Hans.resx new file mode 100644 index 0000000000..9a870a5476 --- /dev/null +++ b/src/Neo.GUI/GUI/ViewContractDialog.zh-Hans.resx @@ -0,0 +1,172 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + 36, 15 + + + 35, 17 + + + 地址: + + + 77, 12 + + + 363, 23 + + + 12, 44 + + + 59, 17 + + + 脚本散列: + + + 77, 41 + + + 363, 23 + + + 脚本 + + + 关闭 + + + 59, 17 + + + 形参列表: + + + 77, 70 + + + 363, 23 + + + 查看合约 + + \ No newline at end of file diff --git a/src/Neo.GUI/GUI/ViewPrivateKeyDialog.cs b/src/Neo.GUI/GUI/ViewPrivateKeyDialog.cs new file mode 100644 index 0000000000..f273595210 --- /dev/null +++ b/src/Neo.GUI/GUI/ViewPrivateKeyDialog.cs @@ -0,0 +1,28 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-gui is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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; +using System.Windows.Forms; + +namespace Neo.GUI +{ + internal partial class ViewPrivateKeyDialog : Form + { + public ViewPrivateKeyDialog(WalletAccount account) + { + InitializeComponent(); + KeyPair key = account.GetKey(); + textBox3.Text = account.Address; + textBox4.Text = key.PublicKey.EncodePoint(true).ToHexString(); + textBox1.Text = key.PrivateKey.ToHexString(); + textBox2.Text = key.Export(); + } + } +} diff --git a/src/Neo.GUI/GUI/ViewPrivateKeyDialog.designer.cs b/src/Neo.GUI/GUI/ViewPrivateKeyDialog.designer.cs new file mode 100644 index 0000000000..2ba3d9773f --- /dev/null +++ b/src/Neo.GUI/GUI/ViewPrivateKeyDialog.designer.cs @@ -0,0 +1,155 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-gui is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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.GUI +{ + partial class ViewPrivateKeyDialog + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ViewPrivateKeyDialog)); + this.label1 = new System.Windows.Forms.Label(); + this.textBox1 = new System.Windows.Forms.TextBox(); + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.textBox2 = new System.Windows.Forms.TextBox(); + this.label4 = new System.Windows.Forms.Label(); + this.label3 = new System.Windows.Forms.Label(); + this.button1 = new System.Windows.Forms.Button(); + this.textBox3 = new System.Windows.Forms.TextBox(); + this.label2 = new System.Windows.Forms.Label(); + this.textBox4 = new System.Windows.Forms.TextBox(); + this.groupBox1.SuspendLayout(); + this.SuspendLayout(); + // + // label1 + // + resources.ApplyResources(this.label1, "label1"); + this.label1.Name = "label1"; + // + // textBox1 + // + resources.ApplyResources(this.textBox1, "textBox1"); + this.textBox1.Name = "textBox1"; + this.textBox1.ReadOnly = true; + // + // groupBox1 + // + resources.ApplyResources(this.groupBox1, "groupBox1"); + this.groupBox1.Controls.Add(this.textBox2); + this.groupBox1.Controls.Add(this.label4); + this.groupBox1.Controls.Add(this.label3); + this.groupBox1.Controls.Add(this.textBox1); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.TabStop = false; + // + // textBox2 + // + resources.ApplyResources(this.textBox2, "textBox2"); + this.textBox2.Name = "textBox2"; + this.textBox2.ReadOnly = true; + // + // label4 + // + resources.ApplyResources(this.label4, "label4"); + this.label4.Name = "label4"; + // + // label3 + // + resources.ApplyResources(this.label3, "label3"); + this.label3.Name = "label3"; + // + // button1 + // + resources.ApplyResources(this.button1, "button1"); + this.button1.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.button1.Name = "button1"; + this.button1.UseVisualStyleBackColor = true; + // + // textBox3 + // + resources.ApplyResources(this.textBox3, "textBox3"); + this.textBox3.BorderStyle = System.Windows.Forms.BorderStyle.None; + this.textBox3.Name = "textBox3"; + this.textBox3.ReadOnly = true; + // + // label2 + // + resources.ApplyResources(this.label2, "label2"); + this.label2.Name = "label2"; + // + // textBox4 + // + resources.ApplyResources(this.textBox4, "textBox4"); + this.textBox4.BorderStyle = System.Windows.Forms.BorderStyle.None; + this.textBox4.Name = "textBox4"; + this.textBox4.ReadOnly = true; + // + // ViewPrivateKeyDialog + // + this.AcceptButton = this.button1; + resources.ApplyResources(this, "$this"); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.button1; + this.Controls.Add(this.textBox4); + this.Controls.Add(this.label2); + this.Controls.Add(this.textBox3); + this.Controls.Add(this.button1); + this.Controls.Add(this.groupBox1); + this.Controls.Add(this.label1); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "ViewPrivateKeyDialog"; + this.ShowInTaskbar = false; + this.groupBox1.ResumeLayout(false); + this.groupBox1.PerformLayout(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Label label1; + private System.Windows.Forms.TextBox textBox1; + private System.Windows.Forms.GroupBox groupBox1; + private System.Windows.Forms.TextBox textBox2; + private System.Windows.Forms.Label label4; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.Button button1; + private System.Windows.Forms.TextBox textBox3; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.TextBox textBox4; + } +} diff --git a/src/Neo.GUI/GUI/ViewPrivateKeyDialog.es-ES.resx b/src/Neo.GUI/GUI/ViewPrivateKeyDialog.es-ES.resx new file mode 100644 index 0000000000..4c3e507b35 --- /dev/null +++ b/src/Neo.GUI/GUI/ViewPrivateKeyDialog.es-ES.resx @@ -0,0 +1,160 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + 32, 11 + + + 65, 17 + + + Dirección: + + + Clave privada + + + Cerrar + + + 100, 11 + + + 470, 16 + + + 9, 36 + + + 88, 17 + + + Clave pública: + + + 100, 36 + + + 470, 16 + + + Ver clave pública + + \ No newline at end of file diff --git a/src/Neo.GUI/GUI/ViewPrivateKeyDialog.resx b/src/Neo.GUI/GUI/ViewPrivateKeyDialog.resx new file mode 100644 index 0000000000..49368fb3f2 --- /dev/null +++ b/src/Neo.GUI/GUI/ViewPrivateKeyDialog.resx @@ -0,0 +1,408 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + True + + + + 29, 11 + + + 59, 17 + + + 0 + + + Address: + + + label1 + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 5 + + + + Top, Left, Right + + + 47, 22 + + + 494, 23 + + + 1 + + + textBox1 + + + System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + groupBox1 + + + 3 + + + Top, Left, Right + + + Top, Left, Right + + + 47, 51 + + + 494, 23 + + + 3 + + + textBox2 + + + System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + groupBox1 + + + 0 + + + True + + + 8, 54 + + + 33, 17 + + + 2 + + + WIF: + + + label4 + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + groupBox1 + + + 1 + + + True + + + 6, 25 + + + 35, 17 + + + 0 + + + HEX: + + + label3 + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + groupBox1 + + + 2 + + + 12, 73 + + + 558, 93 + + + 2 + + + Private Key + + + groupBox1 + + + System.Windows.Forms.GroupBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 4 + + + Bottom, Right + + + 495, 172 + + + 75, 23 + + + 3 + + + close + + + button1 + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 3 + + + Top, Left, Right + + + 94, 11 + + + 476, 16 + + + 4 + + + textBox3 + + + System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 2 + + + True + + + 18, 36 + + + 70, 17 + + + 5 + + + Public Key: + + + label2 + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 1 + + + Top, Left, Right + + + 94, 36 + + + 476, 16 + + + 6 + + + textBox4 + + + System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 0 + + + True + + + 7, 17 + + + 582, 207 + + + 微软雅黑, 9pt + + + 3, 4, 3, 4 + + + CenterScreen + + + View Private Key + + + ViewPrivateKeyDialog + + + System.Windows.Forms.Form, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/src/Neo.GUI/GUI/ViewPrivateKeyDialog.zh-Hans.resx b/src/Neo.GUI/GUI/ViewPrivateKeyDialog.zh-Hans.resx new file mode 100644 index 0000000000..aac178a792 --- /dev/null +++ b/src/Neo.GUI/GUI/ViewPrivateKeyDialog.zh-Hans.resx @@ -0,0 +1,178 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + 18, 9 + + + 35, 17 + + + 地址: + + + 487, 23 + + + 487, 23 + + + 12, 53 + + + 540, 85 + + + 私钥 + + + 477, 153 + + + 关闭 + + + 59, 9 + + + 493, 16 + + + 18, 31 + + + 35, 17 + + + 公钥: + + + 59, 31 + + + 493, 16 + + + 564, 188 + + + 查看私钥 + + \ No newline at end of file diff --git a/src/Neo.GUI/GUI/VotingDialog.Designer.cs b/src/Neo.GUI/GUI/VotingDialog.Designer.cs new file mode 100644 index 0000000000..0ce4b7ee30 --- /dev/null +++ b/src/Neo.GUI/GUI/VotingDialog.Designer.cs @@ -0,0 +1,111 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-gui is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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.GUI +{ + partial class VotingDialog + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(VotingDialog)); + this.label1 = new System.Windows.Forms.Label(); + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.textBox1 = new System.Windows.Forms.TextBox(); + this.button1 = new System.Windows.Forms.Button(); + this.button2 = new System.Windows.Forms.Button(); + this.groupBox1.SuspendLayout(); + this.SuspendLayout(); + // + // label1 + // + resources.ApplyResources(this.label1, "label1"); + this.label1.Name = "label1"; + // + // groupBox1 + // + resources.ApplyResources(this.groupBox1, "groupBox1"); + this.groupBox1.Controls.Add(this.textBox1); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.TabStop = false; + // + // textBox1 + // + resources.ApplyResources(this.textBox1, "textBox1"); + this.textBox1.AcceptsReturn = true; + this.textBox1.Name = "textBox1"; + // + // button1 + // + resources.ApplyResources(this.button1, "button1"); + this.button1.DialogResult = System.Windows.Forms.DialogResult.OK; + this.button1.Name = "button1"; + this.button1.UseVisualStyleBackColor = true; + // + // button2 + // + resources.ApplyResources(this.button2, "button2"); + this.button2.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.button2.Name = "button2"; + this.button2.UseVisualStyleBackColor = true; + // + // VotingDialog + // + resources.ApplyResources(this, "$this"); + this.AcceptButton = this.button1; + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.button2; + this.Controls.Add(this.button2); + this.Controls.Add(this.button1); + this.Controls.Add(this.groupBox1); + this.Controls.Add(this.label1); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "VotingDialog"; + this.ShowInTaskbar = false; + this.groupBox1.ResumeLayout(false); + this.groupBox1.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.Label label1; + private System.Windows.Forms.GroupBox groupBox1; + private System.Windows.Forms.Button button1; + private System.Windows.Forms.Button button2; + private System.Windows.Forms.TextBox textBox1; + } +} diff --git a/src/Neo.GUI/GUI/VotingDialog.cs b/src/Neo.GUI/GUI/VotingDialog.cs new file mode 100644 index 0000000000..9b827eb00e --- /dev/null +++ b/src/Neo.GUI/GUI/VotingDialog.cs @@ -0,0 +1,53 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-gui is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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; +using Neo.IO; +using Neo.SmartContract; +using Neo.SmartContract.Native; +using Neo.VM; +using Neo.Wallets; +using System.Linq; +using System.Windows.Forms; + +namespace Neo.GUI +{ + internal partial class VotingDialog : Form + { + private readonly UInt160 script_hash; + + public byte[] GetScript() + { + ECPoint[] pubkeys = textBox1.Lines.Select(p => ECPoint.Parse(p, ECCurve.Secp256r1)).ToArray(); + using ScriptBuilder sb = new ScriptBuilder(); + sb.EmitDynamicCall(NativeContract.NEO.Hash, "vote", new ContractParameter + { + Type = ContractParameterType.Hash160, + Value = script_hash + }, new ContractParameter + { + Type = ContractParameterType.Array, + Value = pubkeys.Select(p => new ContractParameter + { + Type = ContractParameterType.PublicKey, + Value = p + }).ToArray() + }); + return sb.ToArray(); + } + + public VotingDialog(UInt160 script_hash) + { + InitializeComponent(); + this.script_hash = script_hash; + label1.Text = script_hash.ToAddress(Program.Service.NeoSystem.Settings.AddressVersion); + } + } +} diff --git a/src/Neo.GUI/GUI/VotingDialog.es-ES.resx b/src/Neo.GUI/GUI/VotingDialog.es-ES.resx new file mode 100644 index 0000000000..e2afed46e3 --- /dev/null +++ b/src/Neo.GUI/GUI/VotingDialog.es-ES.resx @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Candidatos + + + Aceptar + + + Cancelar + + + Votación + + \ No newline at end of file diff --git a/src/Neo.GUI/GUI/VotingDialog.resx b/src/Neo.GUI/GUI/VotingDialog.resx new file mode 100644 index 0000000000..2416392148 --- /dev/null +++ b/src/Neo.GUI/GUI/VotingDialog.resx @@ -0,0 +1,300 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + Top, Left, Right + + + + 微软雅黑, 11pt + + + 12, 23 + + + 562, 39 + + + + 0 + + + label1 + + + MiddleCenter + + + label1 + + + System.Windows.Forms.Label, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 3 + + + Top, Bottom, Left, Right + + + Fill + + + Lucida Console, 9pt + + + 3, 19 + + + True + + + Vertical + + + 556, 368 + + + 0 + + + False + + + textBox1 + + + System.Windows.Forms.TextBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + groupBox1 + + + 0 + + + 12, 65 + + + 562, 390 + + + 1 + + + Candidates + + + groupBox1 + + + System.Windows.Forms.GroupBox, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 2 + + + Bottom, Right + + + 418, 461 + + + 75, 23 + + + 2 + + + OK + + + button1 + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 1 + + + Bottom, Right + + + 499, 461 + + + 75, 23 + + + 3 + + + Cancel + + + button2 + + + System.Windows.Forms.Button, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + $this + + + 0 + + + True + + + 7, 17 + + + 586, 496 + + + 微软雅黑, 9pt + + + 3, 4, 3, 4 + + + CenterScreen + + + Voting + + + VotingDialog + + + System.Windows.Forms.Form, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/src/Neo.GUI/GUI/VotingDialog.zh-Hans.resx b/src/Neo.GUI/GUI/VotingDialog.zh-Hans.resx new file mode 100644 index 0000000000..e41916cae4 --- /dev/null +++ b/src/Neo.GUI/GUI/VotingDialog.zh-Hans.resx @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 候选人 + + + 确定 + + + 取消 + + + 投票 + + \ No newline at end of file diff --git a/src/Neo.GUI/GUI/Wrappers/HexConverter.cs b/src/Neo.GUI/GUI/Wrappers/HexConverter.cs new file mode 100644 index 0000000000..724af82b66 --- /dev/null +++ b/src/Neo.GUI/GUI/Wrappers/HexConverter.cs @@ -0,0 +1,48 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-gui is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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.ComponentModel; +using System.Globalization; + +namespace Neo.GUI.Wrappers +{ + internal class HexConverter : TypeConverter + { + public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) + { + if (sourceType == typeof(string)) + return true; + return false; + } + + public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) + { + if (destinationType == typeof(string)) + return true; + return false; + } + + public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) + { + if (value is string s) + return s.HexToBytes(); + throw new NotSupportedException(); + } + + public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) + { + if (destinationType != typeof(string)) + throw new NotSupportedException(); + if (!(value is byte[] array)) return null; + return array.ToHexString(); + } + } +} diff --git a/src/Neo.GUI/GUI/Wrappers/ScriptEditor.cs b/src/Neo.GUI/GUI/Wrappers/ScriptEditor.cs new file mode 100644 index 0000000000..199c33b6f4 --- /dev/null +++ b/src/Neo.GUI/GUI/Wrappers/ScriptEditor.cs @@ -0,0 +1,35 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-gui is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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.ComponentModel; +using System.IO; +using System.Windows.Forms; +using System.Windows.Forms.Design; + +namespace Neo.GUI.Wrappers +{ + internal class ScriptEditor : FileNameEditor + { + public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value) + { + string path = (string)base.EditValue(context, provider, null); + if (path == null) return null; + return File.ReadAllBytes(path); + } + + protected override void InitializeDialog(OpenFileDialog openFileDialog) + { + base.InitializeDialog(openFileDialog); + openFileDialog.DefaultExt = "avm"; + openFileDialog.Filter = "NeoContract|*.avm"; + } + } +} diff --git a/src/Neo.GUI/GUI/Wrappers/SignerWrapper.cs b/src/Neo.GUI/GUI/Wrappers/SignerWrapper.cs new file mode 100644 index 0000000000..70f9d4a045 --- /dev/null +++ b/src/Neo.GUI/GUI/Wrappers/SignerWrapper.cs @@ -0,0 +1,37 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-gui is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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; +using Neo.Network.P2P.Payloads; +using System.Collections.Generic; +using System.ComponentModel; + +namespace Neo.GUI.Wrappers +{ + internal class SignerWrapper + { + [TypeConverter(typeof(UIntBaseConverter))] + public UInt160 Account { get; set; } + public WitnessScope Scopes { get; set; } + public List AllowedContracts { get; set; } = new List(); + public List AllowedGroups { get; set; } = new List(); + + public Signer Unwrap() + { + return new Signer + { + Account = Account, + Scopes = Scopes, + AllowedContracts = AllowedContracts.ToArray(), + AllowedGroups = AllowedGroups.ToArray() + }; + } + } +} diff --git a/src/Neo.GUI/GUI/Wrappers/TransactionAttributeWrapper.cs b/src/Neo.GUI/GUI/Wrappers/TransactionAttributeWrapper.cs new file mode 100644 index 0000000000..bb42f9e761 --- /dev/null +++ b/src/Neo.GUI/GUI/Wrappers/TransactionAttributeWrapper.cs @@ -0,0 +1,29 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-gui is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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.IO; +using Neo.Network.P2P.Payloads; +using System.ComponentModel; + +namespace Neo.GUI.Wrappers +{ + internal class TransactionAttributeWrapper + { + public TransactionAttributeType Usage { get; set; } + [TypeConverter(typeof(HexConverter))] + public byte[] Data { get; set; } + + public TransactionAttribute Unwrap() + { + MemoryReader reader = new(Data); + return TransactionAttribute.DeserializeFrom(ref reader); + } + } +} diff --git a/src/Neo.GUI/GUI/Wrappers/TransactionWrapper.cs b/src/Neo.GUI/GUI/Wrappers/TransactionWrapper.cs new file mode 100644 index 0000000000..e1aeef4e96 --- /dev/null +++ b/src/Neo.GUI/GUI/Wrappers/TransactionWrapper.cs @@ -0,0 +1,58 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-gui is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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.Payloads; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing.Design; +using System.Linq; + +namespace Neo.GUI.Wrappers +{ + internal class TransactionWrapper + { + [Category("Basic")] + public byte Version { get; set; } + [Category("Basic")] + public uint Nonce { get; set; } + [Category("Basic")] + public List Signers { get; set; } + [Category("Basic")] + public long SystemFee { get; set; } + [Category("Basic")] + public long NetworkFee { get; set; } + [Category("Basic")] + public uint ValidUntilBlock { get; set; } + [Category("Basic")] + public List Attributes { get; set; } = new List(); + [Category("Basic")] + [Editor(typeof(ScriptEditor), typeof(UITypeEditor))] + [TypeConverter(typeof(HexConverter))] + public byte[] Script { get; set; } + [Category("Basic")] + public List Witnesses { get; set; } = new List(); + + public Transaction Unwrap() + { + return new Transaction + { + Version = Version, + Nonce = Nonce, + Signers = Signers.Select(p => p.Unwrap()).ToArray(), + SystemFee = SystemFee, + NetworkFee = NetworkFee, + ValidUntilBlock = ValidUntilBlock, + Attributes = Attributes.Select(p => p.Unwrap()).ToArray(), + Script = Script, + Witnesses = Witnesses.Select(p => p.Unwrap()).ToArray() + }; + } + } +} diff --git a/src/Neo.GUI/GUI/Wrappers/UIntBaseConverter.cs b/src/Neo.GUI/GUI/Wrappers/UIntBaseConverter.cs new file mode 100644 index 0000000000..20d458577f --- /dev/null +++ b/src/Neo.GUI/GUI/Wrappers/UIntBaseConverter.cs @@ -0,0 +1,53 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-gui is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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.ComponentModel; +using System.Globalization; + +namespace Neo.GUI.Wrappers +{ + internal class UIntBaseConverter : TypeConverter + { + public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) + { + if (sourceType == typeof(string)) + return true; + return false; + } + + public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) + { + if (destinationType == typeof(string)) + return true; + return false; + } + + public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) + { + if (value is string s) + return context.PropertyDescriptor.PropertyType.GetMethod("Parse").Invoke(null, new[] { s }); + throw new NotSupportedException(); + } + + public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) + { + if (destinationType != typeof(string)) + throw new NotSupportedException(); + + return value switch + { + UInt160 i => i.ToString(), + UInt256 i => i.ToString(), + _ => null, + }; + } + } +} diff --git a/src/Neo.GUI/GUI/Wrappers/WitnessWrapper.cs b/src/Neo.GUI/GUI/Wrappers/WitnessWrapper.cs new file mode 100644 index 0000000000..bc5ffddc09 --- /dev/null +++ b/src/Neo.GUI/GUI/Wrappers/WitnessWrapper.cs @@ -0,0 +1,35 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-gui is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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.Payloads; +using System.ComponentModel; +using System.Drawing.Design; + +namespace Neo.GUI.Wrappers +{ + internal class WitnessWrapper + { + [Editor(typeof(ScriptEditor), typeof(UITypeEditor))] + [TypeConverter(typeof(HexConverter))] + public byte[] InvocationScript { get; set; } + [Editor(typeof(ScriptEditor), typeof(UITypeEditor))] + [TypeConverter(typeof(HexConverter))] + public byte[] VerificationScript { get; set; } + + public Witness Unwrap() + { + return new Witness + { + InvocationScript = InvocationScript, + VerificationScript = VerificationScript + }; + } + } +} diff --git a/src/Neo.GUI/IO/Actors/EventWrapper.cs b/src/Neo.GUI/IO/Actors/EventWrapper.cs new file mode 100644 index 0000000000..77562aa6f4 --- /dev/null +++ b/src/Neo.GUI/IO/Actors/EventWrapper.cs @@ -0,0 +1,42 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-gui is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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 System; + +namespace Neo.IO.Actors +{ + internal class EventWrapper : UntypedActor + { + private readonly Action callback; + + public EventWrapper(Action callback) + { + this.callback = callback; + Context.System.EventStream.Subscribe(Self, typeof(T)); + } + + protected override void OnReceive(object message) + { + if (message is T obj) callback(obj); + } + + protected override void PostStop() + { + Context.System.EventStream.Unsubscribe(Self); + base.PostStop(); + } + + public static Props Props(Action callback) + { + return Akka.Actor.Props.Create(() => new EventWrapper(callback)); + } + } +} diff --git a/src/Neo.GUI/Neo.GUI.csproj b/src/Neo.GUI/Neo.GUI.csproj new file mode 100644 index 0000000000..3921bb12b1 --- /dev/null +++ b/src/Neo.GUI/Neo.GUI.csproj @@ -0,0 +1,60 @@ + + + + 2016-2023 The Neo Project + Neo.GUI + WinExe + net7.0-windows + true + Neo + true + Neo.GUI + neo.ico + + + + + + + + + DeveloperToolsForm.cs + + + DeveloperToolsForm.cs + + + True + True + Resources.resx + + + True + True + Strings.resx + + + + + + ResXFileCodeGenerator + Resources.Designer.cs + + + ResXFileCodeGenerator + Strings.Designer.cs + + + Strings.resx + + + Strings.resx + + + + + + + + + \ No newline at end of file diff --git a/src/Neo.GUI/Program.cs b/src/Neo.GUI/Program.cs new file mode 100644 index 0000000000..f872706ff5 --- /dev/null +++ b/src/Neo.GUI/Program.cs @@ -0,0 +1,95 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-gui is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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.CLI; +using Neo.GUI; +using Neo.SmartContract.Native; +using System; +using System.IO; +using System.Reflection; +using System.Windows.Forms; +using System.Xml.Linq; + +namespace Neo +{ + static class Program + { + public static MainService Service = new MainService(); + public static MainForm MainForm; + public static UInt160[] NEP5Watched = { NativeContract.NEO.Hash, NativeContract.GAS.Hash }; + + private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) + { + using FileStream fs = new FileStream("error.log", FileMode.Create, FileAccess.Write, FileShare.None); + using StreamWriter w = new StreamWriter(fs); + if (e.ExceptionObject is Exception ex) + { + PrintErrorLogs(w, ex); + } + else + { + w.WriteLine(e.ExceptionObject.GetType()); + w.WriteLine(e.ExceptionObject); + } + } + + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main(string[] args) + { + AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; + Application.SetHighDpiMode(HighDpiMode.SystemAware); + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + XDocument xdoc = null; + try + { + xdoc = XDocument.Load("https://raw.githubusercontent.com/neo-project/neo-gui/master/update.xml"); + } + catch { } + if (xdoc != null) + { + Version version = Assembly.GetExecutingAssembly().GetName().Version; + Version minimum = Version.Parse(xdoc.Element("update").Attribute("minimum").Value); + if (version < minimum) + { + using UpdateDialog dialog = new UpdateDialog(xdoc); + dialog.ShowDialog(); + return; + } + } + Service.Start(args); + Application.Run(MainForm = new MainForm(xdoc)); + Service.Stop(); + } + + private static void PrintErrorLogs(StreamWriter writer, Exception ex) + { + writer.WriteLine(ex.GetType()); + writer.WriteLine(ex.Message); + writer.WriteLine(ex.StackTrace); + if (ex is AggregateException ex2) + { + foreach (Exception inner in ex2.InnerExceptions) + { + writer.WriteLine(); + PrintErrorLogs(writer, inner); + } + } + else if (ex.InnerException != null) + { + writer.WriteLine(); + PrintErrorLogs(writer, ex.InnerException); + } + } + } +} diff --git a/src/Neo.GUI/Properties/Resources.Designer.cs b/src/Neo.GUI/Properties/Resources.Designer.cs new file mode 100644 index 0000000000..4cbcca4fd2 --- /dev/null +++ b/src/Neo.GUI/Properties/Resources.Designer.cs @@ -0,0 +1,133 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-gui is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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. + +//------------------------------------------------------------------------------ +// +// 此代码由工具生成。 +// 运行时版本:4.0.30319.42000 +// +// 对此文件的更改可能会导致不正确的行为,并且如果 +// 重新生成代码,这些更改将会丢失。 +// +//------------------------------------------------------------------------------ + +namespace Neo.Properties { + using System; + + + /// + /// 一个强类型的资源类,用于查找本地化的字符串等。 + /// + // 此类是由 StronglyTypedResourceBuilder + // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。 + // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen + // (以 /str 作为命令选项),或重新生成 VS 项目。 + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// 返回此类使用的缓存的 ResourceManager 实例。 + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Neo.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// 重写当前线程的 CurrentUICulture 属性 + /// 重写当前线程的 CurrentUICulture 属性。 + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// 查找 System.Drawing.Bitmap 类型的本地化资源。 + /// + internal static System.Drawing.Bitmap add { + get { + object obj = ResourceManager.GetObject("add", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查找 System.Drawing.Bitmap 类型的本地化资源。 + /// + internal static System.Drawing.Bitmap add2 { + get { + object obj = ResourceManager.GetObject("add2", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查找 System.Drawing.Bitmap 类型的本地化资源。 + /// + internal static System.Drawing.Bitmap remark { + get { + object obj = ResourceManager.GetObject("remark", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查找 System.Drawing.Bitmap 类型的本地化资源。 + /// + internal static System.Drawing.Bitmap remove { + get { + object obj = ResourceManager.GetObject("remove", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查找 System.Drawing.Bitmap 类型的本地化资源。 + /// + internal static System.Drawing.Bitmap search { + get { + object obj = ResourceManager.GetObject("search", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// 查找 System.Byte[] 类型的本地化资源。 + /// + internal static byte[] UpdateBat { + get { + object obj = ResourceManager.GetObject("UpdateBat", resourceCulture); + return ((byte[])(obj)); + } + } + } +} diff --git a/src/Neo.GUI/Properties/Resources.resx b/src/Neo.GUI/Properties/Resources.resx new file mode 100644 index 0000000000..40ca55734d --- /dev/null +++ b/src/Neo.GUI/Properties/Resources.resx @@ -0,0 +1,139 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\Resources\add.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\add2.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\remark.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\remove.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\search.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\update.bat;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/src/Neo.GUI/Properties/Strings.Designer.cs b/src/Neo.GUI/Properties/Strings.Designer.cs new file mode 100644 index 0000000000..ceafe6ac3a --- /dev/null +++ b/src/Neo.GUI/Properties/Strings.Designer.cs @@ -0,0 +1,542 @@ +// Copyright (C) 2016-2023 The Neo Project. +// +// The neo-gui is free software distributed under the MIT software +// license, see the accompanying file LICENSE in the main directory of +// the project 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. + +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Neo.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Strings { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Strings() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Neo.Properties.Strings", typeof(Strings).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to About. + /// + internal static string About { + get { + return ResourceManager.GetString("About", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to NEO. + /// + internal static string AboutMessage { + get { + return ResourceManager.GetString("AboutMessage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Version:. + /// + internal static string AboutVersion { + get { + return ResourceManager.GetString("AboutVersion", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Failed to add smart contract, corresponding private key missing in this wallet.. + /// + internal static string AddContractFailedMessage { + get { + return ResourceManager.GetString("AddContractFailedMessage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Address. + /// + internal static string Address { + get { + return ResourceManager.GetString("Address", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cancel. + /// + internal static string Cancel { + get { + return ResourceManager.GetString("Cancel", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Change password successful.. + /// + internal static string ChangePasswordSuccessful { + get { + return ResourceManager.GetString("ChangePasswordSuccessful", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Confirm. + /// + internal static string Confirm { + get { + return ResourceManager.GetString("Confirm", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to will be consumed, confirm?. + /// + internal static string CostTips { + get { + return ResourceManager.GetString("CostTips", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Cost Warning. + /// + internal static string CostTitle { + get { + return ResourceManager.GetString("CostTitle", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Confirmation. + /// + internal static string DeleteAddressConfirmationCaption { + get { + return ResourceManager.GetString("DeleteAddressConfirmationCaption", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Upon deletion, assets in these addresses will be permanently lost, are you sure to proceed?. + /// + internal static string DeleteAddressConfirmationMessage { + get { + return ResourceManager.GetString("DeleteAddressConfirmationMessage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Assets cannot be recovered once deleted, are you sure to delete the assets?. + /// + internal static string DeleteAssetConfirmationMessage { + get { + return ResourceManager.GetString("DeleteAssetConfirmationMessage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Confirmation. + /// + internal static string DeleteConfirmation { + get { + return ResourceManager.GetString("DeleteConfirmation", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Enter remark here, which will be recorded on the blockchain. + /// + internal static string EnterRemarkMessage { + get { + return ResourceManager.GetString("EnterRemarkMessage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Transaction Remark. + /// + internal static string EnterRemarkTitle { + get { + return ResourceManager.GetString("EnterRemarkTitle", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Execution terminated in fault state.. + /// + internal static string ExecutionFailed { + get { + return ResourceManager.GetString("ExecutionFailed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Expired. + /// + internal static string ExpiredCertificate { + get { + return ResourceManager.GetString("ExpiredCertificate", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Failed. + /// + internal static string Failed { + get { + return ResourceManager.GetString("Failed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to High Priority Transaction. + /// + internal static string HighPriority { + get { + return ResourceManager.GetString("HighPriority", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Import Watch-Only Address. + /// + internal static string ImportWatchOnlyAddress { + get { + return ResourceManager.GetString("ImportWatchOnlyAddress", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Transaction initiated, but the signature is incomplete.. + /// + internal static string IncompletedSignatureMessage { + get { + return ResourceManager.GetString("IncompletedSignatureMessage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Incomplete signature. + /// + internal static string IncompletedSignatureTitle { + get { + return ResourceManager.GetString("IncompletedSignatureTitle", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to You have cancelled the certificate installation.. + /// + internal static string InstallCertificateCancel { + get { + return ResourceManager.GetString("InstallCertificateCancel", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Install the certificate. + /// + internal static string InstallCertificateCaption { + get { + return ResourceManager.GetString("InstallCertificateCaption", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to NEO must install Onchain root certificate to validate assets on the blockchain, install it now?. + /// + internal static string InstallCertificateText { + get { + return ResourceManager.GetString("InstallCertificateText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Insufficient funds, transaction cannot be initiated.. + /// + internal static string InsufficientFunds { + get { + return ResourceManager.GetString("InsufficientFunds", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid. + /// + internal static string InvalidCertificate { + get { + return ResourceManager.GetString("InvalidCertificate", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Migrate Wallet. + /// + internal static string MigrateWalletCaption { + get { + return ResourceManager.GetString("MigrateWalletCaption", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Opening wallet files in older versions, update to newest format? + ///Note: updated files cannot be openned by clients in older versions!. + /// + internal static string MigrateWalletMessage { + get { + return ResourceManager.GetString("MigrateWalletMessage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Wallet file relocated. New wallet file has been saved at: . + /// + internal static string MigrateWalletSucceedMessage { + get { + return ResourceManager.GetString("MigrateWalletSucceedMessage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Password Incorrect. + /// + internal static string PasswordIncorrect { + get { + return ResourceManager.GetString("PasswordIncorrect", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Data broadcast success, the hash is shown as follows:. + /// + internal static string RelaySuccessText { + get { + return ResourceManager.GetString("RelaySuccessText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Broadcast Success. + /// + internal static string RelaySuccessTitle { + get { + return ResourceManager.GetString("RelaySuccessTitle", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Raw:. + /// + internal static string RelayTitle { + get { + return ResourceManager.GetString("RelayTitle", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Transaction sent, TXID:. + /// + internal static string SendTxSucceedMessage { + get { + return ResourceManager.GetString("SendTxSucceedMessage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Transaction successful. + /// + internal static string SendTxSucceedTitle { + get { + return ResourceManager.GetString("SendTxSucceedTitle", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The private key that can sign the data is not found.. + /// + internal static string SigningFailedKeyNotFoundMessage { + get { + return ResourceManager.GetString("SigningFailedKeyNotFoundMessage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to You must input JSON object pending signature data.. + /// + internal static string SigningFailedNoDataMessage { + get { + return ResourceManager.GetString("SigningFailedNoDataMessage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to System. + /// + internal static string SystemIssuer { + get { + return ResourceManager.GetString("SystemIssuer", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Validation failed, the counterparty falsified the transaction content!. + /// + internal static string TradeFailedFakeDataMessage { + get { + return ResourceManager.GetString("TradeFailedFakeDataMessage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Validation failed, the counterparty generated illegal transaction content!. + /// + internal static string TradeFailedInvalidDataMessage { + get { + return ResourceManager.GetString("TradeFailedInvalidDataMessage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Validation failed, invalid transaction or unsynchronized blockchain, please try again when synchronized!. + /// + internal static string TradeFailedNoSyncMessage { + get { + return ResourceManager.GetString("TradeFailedNoSyncMessage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Need Signature. + /// + internal static string TradeNeedSignatureCaption { + get { + return ResourceManager.GetString("TradeNeedSignatureCaption", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Transaction generated, please send the following information to the counterparty for signing:. + /// + internal static string TradeNeedSignatureMessage { + get { + return ResourceManager.GetString("TradeNeedSignatureMessage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Trade Request. + /// + internal static string TradeRequestCreatedCaption { + get { + return ResourceManager.GetString("TradeRequestCreatedCaption", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Transaction request generated, please send it to the counterparty or merge it with the counterparty's request.. + /// + internal static string TradeRequestCreatedMessage { + get { + return ResourceManager.GetString("TradeRequestCreatedMessage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Trade Success. + /// + internal static string TradeSuccessCaption { + get { + return ResourceManager.GetString("TradeSuccessCaption", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Transaction sent, this is the TXID:. + /// + internal static string TradeSuccessMessage { + get { + return ResourceManager.GetString("TradeSuccessMessage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to unconfirmed. + /// + internal static string Unconfirmed { + get { + return ResourceManager.GetString("Unconfirmed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to unknown issuer. + /// + internal static string UnknownIssuer { + get { + return ResourceManager.GetString("UnknownIssuer", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Blockchain unsynchronized, transaction cannot be sent.. + /// + internal static string UnsynchronizedBlock { + get { + return ResourceManager.GetString("UnsynchronizedBlock", resourceCulture); + } + } + } +} diff --git a/src/Neo.GUI/Properties/Strings.es-Es.resx b/src/Neo.GUI/Properties/Strings.es-Es.resx new file mode 100644 index 0000000000..c3ab2fa426 --- /dev/null +++ b/src/Neo.GUI/Properties/Strings.es-Es.resx @@ -0,0 +1,259 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Acerca de + + + NEO + + + Versión: + + + Fallo al añadir el contrato inteligente. Falta la correspondiente clave privada en el monedero. + + + Dirección + + + Contraseña cambiada con éxito. + + + Confirmación + + + Una vez eliminados, los activos de estas direcciones se perderán permanentemente. ¿Deseas continuar? + + + Los activos no se pueden recuperar una vez eliminados. ¿Deseas eliminarlos? + + + Confirmación + + + Notas de la transacción que se grabará en la blockchain. + + + Notas de la transacción + + + La ejecución terminó con un estado de error. + + + Caducado + + + Falló + + + Importar dirección sólo lectura + + + Transacción iniciada aunque la firma está incompleta. + + + Firma incompleta + + + Instalación del certificado cancelada. + + + Instalar certificado + + + NEO debe instalar el certificado raíz de Onchain para validar activos en la blockchain. ¿Instalar ahora? + + + Fondos insuficientes, la transacción no se puede iniciar. + + + Inválido + + + Migrar monedero + + + Abriendo ficheros de monederos antiguos, actualizar al nuevo formato? +Aviso: los ficheros actualizados no podran ser abiertos por clientes de versiones antiguas. + + + Contraseña incorrecta + + + Datos emitidos con éxito. El hash se muestra como sigue: + + + Emisión realizada con éxito + + + Raw: + + + Transacción enviada, TXID: + + + Transacción realizada con éxito + + + Falta la clave privada para firmar los datos. + + + Debes introducir el objeto JSON de los datos pendientes de firmar. + + + System + + + ¡Falló la validación! El contratante falsificó el contenido de la transacción. + + + ¡Falló la validación! El contratante generó una transacción con contenido ilegal. + + + ¡Falló la validación! Transacción no válida o blockchain sin sincronizar. Inténtalo de nuevo después de sincronizar. + + + Firma necesaria. + + + Transacción generada. Por favor, envia la siguiente información al contratante para su firma: + + + Solicitud de transacción. + + + Solicitud de transacción generada. Por favor, enviala al contratante o incorporala a la solicitud del contratante. + + + Transacción realizada con éxito. + + + Transacción enviada, este es el TXID: + + + Sin confirmar. + + + Emisor desconocido. + + + Blockchain sin sincronizar, la transacción no puede ser enviada. + + \ No newline at end of file diff --git a/src/Neo.GUI/Properties/Strings.resx b/src/Neo.GUI/Properties/Strings.resx new file mode 100644 index 0000000000..95a3fced89 --- /dev/null +++ b/src/Neo.GUI/Properties/Strings.resx @@ -0,0 +1,277 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + About + + + NEO + + + Version: + + + Failed to add smart contract, corresponding private key missing in this wallet. + + + Address + + + Cancel + + + Change password successful. + + + Confirm + + + will be consumed, confirm? + + + Cost Warning + + + Confirmation + + + Upon deletion, assets in these addresses will be permanently lost, are you sure to proceed? + + + Assets cannot be recovered once deleted, are you sure to delete the assets? + + + Confirmation + + + Enter remark here, which will be recorded on the blockchain + + + Transaction Remark + + + Execution terminated in fault state. + + + Expired + + + Failed + + + High Priority Transaction + + + Import Watch-Only Address + + + Transaction initiated, but the signature is incomplete. + + + Incomplete signature + + + You have cancelled the certificate installation. + + + Install the certificate + + + NEO must install Onchain root certificate to validate assets on the blockchain, install it now? + + + Insufficient funds, transaction cannot be initiated. + + + Invalid + + + Migrate Wallet + + + Opening wallet files in older versions, update to newest format? +Note: updated files cannot be openned by clients in older versions! + + + Wallet file relocated. New wallet file has been saved at: + + + Password Incorrect + + + Data broadcast success, the hash is shown as follows: + + + Broadcast Success + + + Raw: + + + Transaction sent, TXID: + + + Transaction successful + + + The private key that can sign the data is not found. + + + You must input JSON object pending signature data. + + + System + + + Validation failed, the counterparty falsified the transaction content! + + + Validation failed, the counterparty generated illegal transaction content! + + + Validation failed, invalid transaction or unsynchronized blockchain, please try again when synchronized! + + + Need Signature + + + Transaction generated, please send the following information to the counterparty for signing: + + + Trade Request + + + Transaction request generated, please send it to the counterparty or merge it with the counterparty's request. + + + Trade Success + + + Transaction sent, this is the TXID: + + + unconfirmed + + + unknown issuer + + + Blockchain unsynchronized, transaction cannot be sent. + + \ No newline at end of file diff --git a/src/Neo.GUI/Properties/Strings.zh-Hans.resx b/src/Neo.GUI/Properties/Strings.zh-Hans.resx new file mode 100644 index 0000000000..678c4f324d --- /dev/null +++ b/src/Neo.GUI/Properties/Strings.zh-Hans.resx @@ -0,0 +1,277 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 关于 + + + NEO + + + 版本: + + + 无法添加智能合约,因为当前钱包中不包含签署该合约的私钥。 + + + 地址 + + + 取消 + + + 修改密码成功。 + + + 确认 + + + 费用即将被消耗,确认? + + + 消费提示 + + + 删除地址确认 + + + 删除地址后,这些地址中的资产将永久性地丢失,确认要继续吗? + + + 资产删除后将无法恢复,您确定要删除以下资产吗? + + + 删除确认 + + + 请输入备注信息,该信息将被记录在区块链上 + + + 交易备注 + + + 合约执行遇到错误并退出。 + + + 证书已过期 + + + 失败 + + + 优先交易 + + + 导入监视地址 + + + 交易构造完成,但没有足够的签名: + + + 签名不完整 + + + 您已取消了证书安装过程。 + + + 安装证书 + + + NEO需要安装Onchain的根证书才能对区块链上的资产进行认证,是否现在就安装证书? + + + 余额不足,无法创建交易。 + + + 证书错误 + + + 钱包文件升级 + + + 正在打开旧版本的钱包文件,是否尝试将文件升级为新版格式? +注意,升级后将无法用旧版本的客户端打开该文件! + + + 钱包文件迁移成功,新的钱包文件已经自动保存到以下位置: + + + 密码错误! + + + 数据广播成功,这是广播数据的散列值: + + + 广播成功 + + + 原始数据: + + + 交易已发送,这是交易编号(TXID): + + + 交易成功 + + + 没有找到可以签署该数据的私钥。 + + + 必须输入一段含有待签名数据的JSON对象。 + + + NEO系统 + + + 验证失败,对方篡改了交易内容! + + + 验证失败,对方构造了非法的交易内容! + + + 验证失败,交易无效或者区块链未同步完成,请同步后再试! + + + 签名不完整 + + + 交易构造完成,请将以下信息发送给对方进行签名: + + + 交易请求 + + + 交易请求已生成,请发送给对方,或与对方的请求合并: + + + 交易成功 + + + 交易已发送,这是交易编号(TXID): + + + 未确认 + + + 未知发行者 + + + 区块链未同步完成,无法发送该交易。 + + \ No newline at end of file diff --git a/src/Neo.GUI/Resources/add.png b/src/Neo.GUI/Resources/add.png new file mode 100644 index 0000000000000000000000000000000000000000..08816d65191b4895f0ace827deba9fa9a2cc8818 GIT binary patch literal 299 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP=YDR+uenMVO6iP5s=4T z;_2(k{*aYJh*eTb?Oiia$k@}xF+}5ha)N^3pY$K+Kg@3wRy^S1aXca5z=;C~J~TJZ zoffu$DJ;W*cT+)v102g|2<56j^?!cXUfa#4u4XKsxbUs7akvVHA%zn z$(LI?`p?_L=bw}oezW#;^h5ppg?9y%*Q#h|r01P2$>&aKl%E?lrTnbnk3&ka#R|XN z1Y8^)ROh+>QI2_VNSe#F_{g^$b@_fZe$BY<7a7wR*#1@fGyCU6UUl0SItGVdN=gBp zty!lvI6-E$sR$z z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBD8ZEE?e4l8Mw7hL_;{xG-7x9B932TkuM zPBonPoLh`%;&mP)oRhhi~6SE-h`MwFx^mZVxG7o`Fz1|tJQb6o>dT?2~{Lvt%rLn}i|Z37D{ jpgY3sx==La=BH$)RpQogkh{$csDZ)L)z4*}Q$iB}yEb`l literal 0 HcmV?d00001 diff --git a/src/Neo.GUI/Resources/remove.png b/src/Neo.GUI/Resources/remove.png new file mode 100644 index 0000000000000000000000000000000000000000..a99083bd7046bbb209eee4b1136f75fed3517cc9 GIT binary patch literal 291 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP=YDR+uenMVO6iP5s=4T z;_2(k{*aYJh*kgUoN6hckhZ6bV~EE252#JG#5JNMC9x#cD!C{XNHG{07@F%EnCco>gcw>_8JJp` om}?sV83x~7C+$Pgkei>9nO2EgLz{#a6Ho(#r>mdKI;Vst0IJwaK>z>% literal 0 HcmV?d00001 diff --git a/src/Neo.GUI/Resources/search.png b/src/Neo.GUI/Resources/search.png new file mode 100644 index 0000000000000000000000000000000000000000..fb951a1276d9d1707efb3a3ea675ac817b54bb89 GIT binary patch literal 442 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6SkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6d9Oz#v{QXIG#NP=YDR+uenMVO6iP5s=4T z;_2(k{*aYR*h*oW**k8a&>>G3#}JM4y%!C=m9%librn`LiJRMHFowr+;@+O{OMZ&HK+9v2$(dd`&f_ zdDrdNR|shSb6QtZ%PePNUE6E!aSrGk)e_f;l9a@fRIB8oR3OD*WMF8nYhbEtXb@s( vX=Q3*Wo)EvU}0roz+@y>jiMnpKP5A*61Rrp{AI_18W=oX{an^LB{Ts52>6q{ literal 0 HcmV?d00001 diff --git a/src/Neo.GUI/Resources/update.bat b/src/Neo.GUI/Resources/update.bat new file mode 100644 index 0000000000..fff10101e1 --- /dev/null +++ b/src/Neo.GUI/Resources/update.bat @@ -0,0 +1,13 @@ +@echo off +set "taskname=neo-gui.exe" +echo waiting... +:wait +ping 127.0.1 -n 3 >nul +tasklist | find "%taskname%" /i >nul 2>nul +if "%errorlevel%" NEQ "1" goto wait +echo updating... +copy /Y update\* * +rmdir /S /Q update +del /F /Q update.zip +start %taskname% +del /F /Q update.bat diff --git a/src/Neo.GUI/neo.ico b/src/Neo.GUI/neo.ico new file mode 100644 index 0000000000000000000000000000000000000000..141d11d686a2a1fe3bb2d9dbd81d5b477c99ef32 GIT binary patch literal 370070 zcmeI52bf${`Nq#|O;1RngtDOsp-GUYLwQPpIrsUi>fK1*$q&xe#DCYN9VP*jfJwk4U=lD1m;_7$)gyr!OP!nfs;il? z-1VCAR_1(PztFkS*E%<0LFRib#3W!6h`t17FLO@3pT5)$2Zu~s;_jTj#2q|?-!mN( z=Q;<@n=sEEHF3Ucy8J5VCgBt8FbS9hqA!8duW@eb63Y7Jt{&=T?Km38)|A|!`)Du$p1%Y> zPHJ{P>*4bF%CK_U4c_60A}PcUiHTsOLTp6i28aI^3Qc9;ZA z0^OGY_4=S6Z~AiAAI^^jv*G*8IdZ-f{P(^D;QU(j-TxR~-k0FKAEysno^A9#m7NXEE>Q`cLS~Tk3{^{lSfJUj2B*=6u+H^fdp&zF-x8;9lwkN6l}6ddq1G_2jF4+z=_N=95LPM1C>abvd+^Y z=Dg8|S3?=UIyfAD-2+xejPvEnfA0%aCwL3Y!xtRHTBHH=9mW__w8JD&QVERMKHi>Z z4PER?+VpUKKcF>sZ-W0tnD^cXlvDZd`5!)iiXV6tKQMv0hC6WXedFV-S+q6ECFMai zMK)k9+VYIiH$N9}U-R*Hgy(*ZT`BwSJ%{r-mplJE`hvgV15TST-)%%+K|Qd;Bv3F3 zXe~W!ZW<`>x1#TUJiLFjOv?F8KBAKNANB?BQ7>4CFZd2VV69V`YdF!`2LG!6R!{jYrue-HnU1MA=PfQwD0 zeX#q1RZ5;R&9=U60narjPyKk`qO89SzQ11OoDcgr<9~YohyB6p_=8*U1N+lYFc`n! z7Tr^(gs75aYrRdPA8$`MepH5l-ch23}|GE-5oKGH%|GDws`vR>+(pci{v%csD)1Kc2p0r!{uJ1KJi6BR>lpv@IFM#Eb-SjQa;(Yk@E6OBlkpx)a@^SD&YPwIRACHem$tf`FQ!1<+(g-{4X5;!@fX$ z1&@Mr=quQ)`A%1lPjG@A*-1cqXH22*p6}N7rGEbv>h@FM{0kr#JGW=j%gy*-9R7!W z!TZz+?#37V5dN?8s~cELa<_9eb=mQtn(i9I_hhNtyE!Xe4dwi{;8*bd3GlJ;z9@dr z_+Nbfhke0P{DAf~+?%n)zWNr*4!c$p!_(*WX6pAdSHSsYZUf5sQ{ehv!28DeqHsQ3 z7c%~rmjB)tXf2YTYq&N2hP6`{rRPSa{yL3vp6^!HQpOJfhrsna!Mniv@zU4T!@Moj z|Hl8G;lK9-I%_QPPt*yHrO$9J_A#qHb!KIA3`{wjx4(^Wd{&M*K z90=Q?{ogb4F#bn}|K1PiEMM?E{f3t^ey}~?LFvtUBv($~Lt%ZLo4qoq-){xi#{tdF zsg`xM<>Jqb|Iy@s*cYg;K>MEm6o0UB^Syivn!bW>{wR8N0X?D9zTHdy94XTD-YiLdXDkGJo)eafX@E~PvQs82A`u|P&a9D z>DvZye=P8JW#{sch4H`q`R{#!`V2LesPTh-rS<^E|FZOb#{bIUzxM+#vKDcO@xLtj zSn7I{@!$Ag5LaR4e_8q)pIqi=?|EL8i*Gaj z8~^jF_xp#f{$G~$9^=39-%~iRv+>{fZ|#3;|6BXNto(qL|5pCzRqp$Tt^6-5-uwOu z;JRLR z{r}egZ~gyeq`VBJT@~|Hl7<@LwIrQx@R^Zgy_c0@rKOTsI0|a6UfZ zDe#&3f=K!TjsFGb zzxM`qKHx=Qb%Mh4Jd^J< z{u}>$g#X?TG~fqj(ob;V4fGW(aKrEg2jK&518;#$c5A;EMmENO9 zCvejj1nqt@{ErO(!@l5Z>I9eF8jK(GqE0XhUvMEl;5qQA z`GSJ^0^`5&Ka%|SzM!Ty{@>*JE=HeWUwpw{j3-`$53sSs{M!J=f8&3o`S1OJKhL0E zfFFo4zi177!H@9+4}f>9PLNZb!1!~L8~=^}k>4e2ww^$e1L0SOjsM2~a^%1F1>)y3@bzM_!<65- z+NqT3TWyuID{wO&b?yr09peZ3^UhspdrTvaSAmbSlFr6|<9|8xKg`7sXczny&YlcL z&|gq9m9|5!$G(RIK0y7BvF7-?#Dnn#3-ALUfJ*5rF#a3=D~12w7l@nhz}5Nqfp5{* zH)!(htS6*iFlbn=-hi=#`-3?Jb@&zSae69o{2i409;e2ChUo<@ZQUaqg=-ljsM2~O6Gq@U+^e=J)3<9H>0nw zp8xYcF1{t0W7MCv$2af;H-Qx(9B-8WH~t&{tA+nz9%}E=U@Q?IuOgp3gCreu7`| zJru?dg0V#2JA*iuN5~f#|Be5~|I|9V<{CZ%Ur!9$2lHIrezw{|@ke5Bmb+zwzJrpUQt@UzS_|{<_V+fnGhY@XqU@Q?| z@MYe61@C_Wll z3M23@N7MGuy2N7aYiRs8{u}@E^j&Z;d5xJ2qEO;M`qz;tN>A zpzo>U1GeDZzXVT#LbVT!|Hgmge_{CV{eaFIOMD*AUN~XC8%1A1{nR}6EYUX*Cf!ay z!M#D9K;J;vjdx#39Ixl;3ylB9f8&4Q`5*QLs<;1aJjpP`(HJ_hX5N z@&3EPJ0KiyHvb#{jsM2~?(-%aZl$|tC4S%*us^=+0Q8@!$Aw{4X8_*oitp&{r_+uH5~A{0Q@l9DATN(%#sKy1+#6 zd>3^BaC7tFEE3 z#B|?NH~t&{jsHE%fA0r$)>z_w@bz$f!RjD(bsl>dxzWMeWH;k>_BGVLC3D?zy#GPq zzky)b9r{!5;qoPYj<{EG-UOo8B24~c7D%brw-f?JU6QCtht8Ig7fhO`p#*uOXxRL zTR)#eb&F{WT*H+M^YbgYq`~-KmcGyU-}635_4Wtx0mp$6Q`px~>j$>@VlFJ~xo3?3 z#{X=s4|}in@;_63=S^gD3x41L`um4n&K^dS^Q;qOtCM{1GyWU@v$Y}Pf0ykZ%{zV` zKQIaG%s60!>I6|fjQ_^}Z0*zd-zERU^#ko8@K5}}Szsi6d%<1>*~+?9_Zk0<|JmA_ z@xNRA_r5@N0)5Bu9{j*z^c4we98K>R=?4&%S^KU+gI{%6hqRq*{uc=a`!}xFf&(?0Moc~(ytA4x_ zDdRU}9&eq>`f@*v|Hl7pZMX{guQvU^;ruVa7PRYoUBWlSC+D#@XtuI0)qTc)#ackzfGR*hVwt9Ex*n$o1L3+hjXi~maRm}|32ft@jqKDt`Ppm zzX3MS{S@AhoPG!23#T7%|L?Sx+G}GeWAszt{20#tXWk3vS!1`!CfVk=^6xYL8~?Ml@-pDR zIR6%0zZuRSNcldHZ+_QIDATz)+3F>q`;7m_|7`6i!u;2Ky!+w&k*uK~PG4SZ-rus# zRdwHI{5Sq*%YcaSU;FF+70#al-#43a8*Ax%VE>G4Wf#@^jQ_^}Y;7|F{8vBTlhp4o zg7Z5tH>Z)YdOPxvfbrk>pRM`yApf;j)(m*R>!kT^koxW?^9@Zq@|S?|-}s-c6_t?x zD(Bx}{;j^Lbr5a(A=CK2p33^Yzn^Vt?Y?XzVEi}!XJaS2r^x&l=idjvhx5mP;jFi* zZN5F*)Y*NxNWl1S{Lj{Iip2j9d9U`rJ{xQ{=`L3@)8^%5tCGC$GyWU@vo)du^8Zub z^&jf@mx9sE$E&BTx1$FnVEi}!XKQu^;QuSUV-Dr~Sol8Zl3Sd!{`+jDU!41l|Hl7p zEh|Uwy;m+U^{zwtj?W9x$d;=I<_jbqOJrj+*$SN%Tz=2*q1HN^iV{C_Q+-;aH82QVkkjxv>i z@!$BLt?4pW=QLgi-`Bo~eQ>ASIDNLFi|l>If8&3)#;GxSk8Gc@`=TuYwip_aO0O2GJU{4b_`*}J1H0pq{%KiU>*sVk-gjQ_^} zV%nFzJK7R3{u}?JZK0OBVoJdHZ~QN&ec8LCEdk@d@ju!YYN;!x1dRX2|6 zapPtzbNv>wm*&hB(Y7y3U9=@&{4YQLqqEPz0GR)3W!jpSv39||FMCv5AgrL!SA;* z*YF_v4F}*4>?@uX=p&5(X>H$gz|KpY#u8tJ|C4AF>^N(gYrM|-2`a`D82^p`*g&>^ zPQKt#>I7#}C)fy|(7?6(9qSP6C{GC(|FgFJY&lXb_kD=%+yM?@3~~6i@37n@1Fz>a81!1!Mj z+b;&6%JrR^U-UMZi!b;lzF+|J4P(>ZiWU#5H8sY6<3Bb~D&L~^!4fbDU$7(nhJENa zbhH!f=phLh|4U~3rQ%q*#3Ntu4{#QKU?h7O)oc8~UD`uLsM2VS|Hgl8pr?Jt`^+u+ z9d&{q;se&1`FMN}qYb`TrKBujwvGQiZu>pWy{N^nvBYce2m7#ZN&l(VXINBkVEi}! zN1*&q=YurY@LBL1`V6<5`I@Vxeqcv|C1CtF{zsJmVV|J6hL6DilW8BU#~wztwuez+ z9D(uQ_+JM6_r5@5iSL1V_=0cZ2UZLAFk0^1j^8c}AFAyw#((2~8S&ry0iERwUZtO4 zGQQx;v=RDGe%ZO%wl=X_F3k9E{4Z1fhke2S$b;4;o`Wyg;;Pr!Z`I z82^p`70iF{3qB@~FX9I-0o$?9asBnyPY^f)`LzM1(!nd( z{4{*QF6?2{pZbBj=7Y-j1LS$Eaoy?wW&>?DpmmA=1mp1mTV46Ot6`pzJ8@2B`U3K4 z{I8xeu2f}drNr|t{P;b61V__8So?1FIX-$uW%&W)f1BU06q~ht6yBd}uA#n%awF}7 zuhU1+7k^L@-$OC}8~?EZ^BLL8K}8zIzxM|IPM||2f-$e8FG9 zPpK1ZIOBC!7wlm)p?um1v~Bbqm)pt1n`Q?&+kusz*_WS{Dy#S4(gL{jU3|crGoE1& zqt~2UZA7$v0b?ERD!%Oq_csP7fjs(G z^#z;ljvt`jawFewqHjarecpq5%^dQe{!jA-#?wmVX({rgxrTp$Psh?e7|t4mn%VFy z>c>@#dCpkjYVcn}N&jKs9-uXr<_pXhl!7;v7KipKSjqUojg+fjXHDV&_ArXUF}L2< z(e?&fKY8nG_=2Tw6Yw+g@fgtFY?Y=X%a7@_6gD7V&;pk(qfW5tRb{e1d86$a@1(zg zwoE-~--$d-0M7yCrxbFtI84r!U<0e*OR#Sd{NG|u8O|vp-EJcLt}%`fqYyg z_-f08=`kN0Sgw9_crg~f51#r8d|}>TB_7l1%b3^_j2|?T-%aW3_&Gk{381xA`N+_o zHTji`4XB(~pMNkXi2CvB)8BM8l=oG0)c1>L6@M3FU*_KUf}N4aRIm(~FEB2b3zxf- zPW6XBjIEytR1dCW4v-y4fclR^9x>VpgZTg3$Y}wvdB^4ly2Gz1-m5n5zp?Fe!B+H* z*Ba+LcX|5e`^Aq2{$K-S_7m_YWT^U56!mLqGQD)P0gZJ%4<=KVeT6x5jq1nSY?sdM z-a=C)pngN`$%-tu1s4GI6{!8xQRa4SGU;g>P}}u-IIn#GhD?8{eAoV_GO=fWnT8)| zet|l{GB=3&z*mv;l|bKv?rEJ{{MD@k)l2Vy^M_)W>t6RUV_ewkcYfWoe5usfcRCCo zK>J`i>m{gDt%1zHhwK-jgAah!3#yxorSipE+y7^5@2B+HZ#Z+Qt8ZoSv ztwC7M-U`dy`sm~|@DE_~3d|1_+81cO-m{c77r^^bpz#LQ!D*e2AImDS>05LiB%n12 z^sUyRqc4KX(ASGVzPix1VDGCAnQ9#RRk%I_eD&((t{3glirCw)19d9yQvHUko9d4r z_&T@&J*scUcxy7q#s*ekE4N`c-=a=GSo3lgmiZjqiX(WI8Pd4Rw5Nl;OEll&2=uCX z$6BMDjUCuM)gvd_#J$+ak#K&*6xOZSIDM8RD}&qkev{KaMzdaHEODvZ9Q+^p{yVUB ziPgjLj{aQr`$w>aGbtxFV~t&XHO;{-1KJiPi5fqc{BPO^OI<(w{f^kcM4)dx+4w=_ z`vUp<=g|9aSbMT9HqaOT2mN?OF*bW?q$QyC0dq2Im}4{$n>Ya5xD~7fRxhX=U!ZdS zHS{|h?7=>k{bs%4Vwz{_>LP8Pmbem1;Ck$VvY>{(!*#Heo~kpV=3%pI>1|+N)J#z#ZF=b{#F5=(~J>z>l9m zKi>N4x4%JS^z~h7+`>%)sS=n*zoF)HVoUw7Da|{c1zs{g5Gg;XIUbt#^>f3b^V5wURU!XP0^T9j7>Hs|>gJ;pj6<~DGkEd@`(4S+6 zNuZb#kc|o0oxbU|KIfD10qQHTxrW8{18UR1j_j`ndxOD`eaN^jbMMC-QcR88yG;VA z5>T6xF=IDXzJPDNVvk#6pBI4_%oh}_P9)9;YwW1oA3{IgFzR8o$l4B*K;$IA{E-;w z6O>O&+%?#)_B*z*#O~J%#Q8_SDeA{VrnT3-9XWMdf=mJ#C7?12tceXD4m9uhZD4%` znPs4F%RWgte;)0sZLXo5zuMN+X0$I0C=Ur}j?oh`tfc+4qwMV z4x7TB_w1u#he@E~B`{3SED@} z>@W#bvjk}GYAmsqbqH&5J_?R32I5L3_yV=*|3;J+Ov0h2%n31|%h z9H~=Z0UY@S+<6L=+kR%^yw=!V1h&=w&2!4&d-fevVV5R>9+kjl>_KrQd&k3}-S7p| z;nd3@s&xXTOKYfSk>0VO4?fHelYmJePYKM?8U(mRzxXixz`?W^=EJi$Kot53UMC%M zl`i&IS-tsr)=jtFXte9!wMW~HXrelZD{1PU(!c&9!?q4$g>ZY!?OhmYzjC|3JGduaTf_|C!yZAw|+ zI6?iER>v>Aa_x;Kfo@1ZV~MO$*8C#vckI87q>?p;88Vq{w{5a(C$?A5$yZ}w2{t9^4yl6Z^6 zBw!LKm;~m~569SB3?6SxpWzwsTKgTV?Vhf$;7vGx2lxJfy8SS%X}r$n<`hg9_9Bx& zPf6f{hvV~(XTRwh;P;L|-$r@{_`R}zLVaPQBiS2|Z&ll25-dqjTeeIBCIORxNx&pv5~xNAv=;VQ*2U{CSk>tbpEj;)>gwWw# zC4%7X?az12K|J;C;ciT_j9WT9-!Xzja9jK?IRgLs_VDB!_}7QRlXBo+9|{jg5U4J= zC$NwB-Ju*TPV;;?2W`Qj_lI)O{`zoudk)%PpA_zMkWgI^Nhp175hPTX67F>ndVSLS z6FCUKJ~=!tqVVgJ!{a#!zrI7ba**`;4&jQRvvB30)9@w>H~9pHpZF8z2S1s87=Oa% z;Tn_al4>8Vi^KP)2~To|X~L5tNE4nELAvlzX_3Z$lO0~V=fe@C4G-lYZFndLX~RPi zqz`Y;LHh9at%ov%x9K25cv}Q%!(VB)`Ly9Jt*tEyC8rN>YV{GM52tq3>GPC}i5#SV zo`N?KL5A?Q2r`5dK|BYU!kb#-HKt7AK7vf)K7x$li5z4Mr(~CiGKME2$Q(W}$U)}t zcn&g$$0O(@Jjg*O;Xw{M2@fLZEL=J0ESwyS?<}0kPfMrajjf+{8cq&64Ug9kLu^N3 zjjgS1q#isGl)GaOUuMaK`Y&>obNYUY{{M z@%l{R{`Hx{{p&M?2c{oHkv{*v?UqSCZLd%N{`S|W4{v{c`tWf<(lVwmZW-}=(xtzt z{qeN#AJ=(!`1R?Y55GQLc6b@O zK01UqC5Lv*Uuy4Vhv!ow=olWNW)M}!@DR1rhIfph<= zJ4BHBd~yy_!;>RO6P_fZG~r1RqzO-oAYFKyb5AE9O8#&J>7EZqkTyJ&gS6qH2-1d! zB1j+Jo`dw^?Vacu!pC?8X9#bLAVYXt4l;zdIK|M? zcA4_e7=?EdL6gE;$EQ5!e+YszN03lq#t53?&->Q4e{0)05u7OkZ-S{lGX91!{`vGd zXrn-DYpBblE%KoCl6XVf9JIeat%yRePa8p7>J>*CD;lTY+m6NU>5Bi?p%_TXLCA&a zB`Fb%YkPJ4pYh2NB&A+=bcmqC>r*1=@OCa2ha>2adfmM$9Nwf~l8>YuBnQQ>LJ_2S zeNqmZ(mfwC!?eNeIY?4n`@L;B7}Ne+(tkdONk4`z5;@55`Zf`b2|behZxBI>>e}yV z(G4l8YYz`{FsA)F)aX}I=9-I@oW2ASrUlVpmXi7sP&Oc-9Xkq z?8#i{;p=S^&u7y{&P|-_HkdHaZ3-GDEu_P+Pi4uV+Hxaqi{tE_6+_qYefO8RixcZ# z-sAkmriA|2MgJ4#xSugAYKqd)j2Oi9+h%+k(o6 z55S+m$=JaLpdPrvYvm`4YI(Y*E@-c*OjkW_ZS;HuxD&hs($(WK>9?!ji=lsS2Ri=` zs4aOb_!fR)D0UFECCx9STC={Bsd^kb9t;iu*Mb$Gt9o2ldd?JHZ2gCA;S+421x%zr zVQ1{1kJ=BH&rOv>wfv&;T;KY{ud7V&i=KA{lfa9h6yHZJrT)DwsC@Vc{0;mJpD+?M zsLpuIxa!dSiIj!3)1~uX=zeQ-eJ=PH(06X~Ez>h`J>Bm;p?_}&zI=EGJ6Hq`#V@R( z@?qK{=jwY^mMw_u>?EGLe$_Mo|J`R3?KlnU;p;5MQ z`OVR{gxcQmK3IHv4LTo$p7m|hIbazmRy{7AZnOCL)lY3NtD<}PjZ9#pF{{g?oA8dzT=%uz~GxHUS zeGFxOOwdkOJ#MKRfv%4O_XCZkN1;sbj%}5z{=F^uzQ#Xb3nyX+>w~&U3kq94B>LUO zb&avDj-I~@ZUt|aq0YnhQSSQpcA&HR8s7vrgKtts48ay^R6gX}*NDy=(DPU@19W$c zEiCV-{a;D?58HzJ8eargU;{gW-XJEwkjsJ2Hv{j2sOc}?^i-<;y)A_M8c)U^8gtbD z7U*7ex_spwwdX5c|K1LCR^QTK(|?i;SCjsinf{Y>FJEN(&%z-fC-eX9^FYHswVeJp z{-@SojQ_^}&gTD@6TiDktMT9XZ}tCV8!-QG{@?t67dBw^|F$(?U6rv>4!80@+4o!f zzYE^`VB^2>9~-d#|MKnwGXHP>-`ao4Hel^PU&wcIuCns~dyJE<0#UBZ=aM$_|H<4> zssC$EHS?zWq5A{C^+0R;{a!G+$UI8VnEt!azg*xD)@W-j9`mK@m|MFZ`ac#d2JZvS zr-_nIyOS2ve-`==7lW6w-bU+gu!TmjHM;*5&>lcqpVJ-LN8w)6e>e3XwuPy;2R@;O z@?ikF-xJIPnp0IS<%8)z5B+;v=r_o@DU=V`K`lOEP4s^#xE*L6ujXJ!f$QngVEQkB z{=FUOeAHP%`Jg>R8?c3u=>ANgb^Ti3AGNxI>A%4G58J{q7gIj41`9jrgKyXg{a*oI z0Gf-Rj*q4O&GcVD{ns;-9^Tiee%Q>q3ctptwjr?52pVD z>VKX1UctMe)6?bqK|{xNce07e*ar915k7+R3E)A{6KzS;e*yKM*em*QbSeM75~vP% z7_yl%+({fFCs`ajq&nzCUmdhQRB_5;=4 zb}BFQI~c%yd-2R{ApL~jRp|PG>A(2;59>_47QcUmp0@_#eQen9_FALL2d&TL_gd^= zE$)>+(Z2J=XiJ*@ORIlx3u*_dyjLIc@#wkg0{1i!z8UAUz~6z! zq6*QLH2wFC{=FUOEdTxnxDgyk8(}c^P^0~P{C;n;gGuqeMztmTa?j4(I}x;ieA<$x z|DM->*cP;hi~0vH2cyw*A9x>|u034XPf3UTLt-pSb%i0^cQCjGid@%h-Q~%x$bXNb6Z%ZDE zPgnz=P}>}8OUCdG$NYl2LVR4ZH}`J~E(HGpowX%R|Iycf*cMb*(D>p^Y+w&;L2bnv zjXn8#qs~+Ah_@vb&b?m)SApfAV_VYnUtanT+k$xg1o$Pse{1X@*bnsRv*Yyy|5tv3 zaD9trIQRYt{0_VeA!6B@9jWm-?F`%%W% z%%V@Qkca6%Rhm7hf3^Ex1J{8A(fJT`UpoQ+?)!yPQ=8u}rvFs=m0172E`Jv~{}H}@ zZBVEBy!!fzeVG1JC0qji`?mbU=scKX%sKc@WWStxaZ~ePnB4K^{;tdFN3L+<-5~|AIuw`K;L~W^M!l*F#V@$ zpaA+;Jx=>e+yuS_&x3D+tDRn~dR%HQvirsKpDL#u^{;xI#^dh>N5S>=KwT7d9?r4p zKP-*-|J~5PugCoro&OA;Z%W-={c*90xACqXD$`SQl=&Caf2wS<(7)<&PlJol_m_M< z?$R8`U{X_1x?fEHsj|+Xf7Rn&1v9`{^ga;1YmIQ^%JkG6W&XwVpDLS>{?!Mo`S`bj z?^2!*L+7=ccQYhP-)K(FLe{^S{!>Mj(Em>8{225-0@R1+UZp-!zQ36MQ+21YRQ!8P z-(4<6A8cw0O81NDzjU&WVoaw0C~Bp2X)^tnPS#P3$@CvZt&}cJrvK8(I*Kuw{-das z(xs`w^*?snQdc))1$}e_N+;8Dim8J2uWtan0j|XczA=5NTa9y#Y{8Cp2~@cLWdp*; z;5l#!*b!UkJ!7eh&05|rhid%~c~t86-@Wd`=g-LRhu|;ZH2lHmK*O|UtfAYmIxV2e z^dGi`|B?5VU;+36K4FdNOI$5ySHpfh)pAs^{=>HL337N9%m8~}2mP>vnrbK?O#eas zz}te#hgIN7a4vSR73W?vmbuuex8M=VU_MWG{TBJFrt;tGIh(U=;eBvFI2M1<#JLVz zaD9h$SIW`7pFElVQ}>SQXdj;ynDQTZ_I4LF|D3jCh+4W|EY>)+di$_ITn`w`lZXJ7{-`M+TXeG1wKzFZE|f6n^% zcA&FwOWw}^hhYnAg4&s7P(GOc3!?w9EvT-r6wCr+v4j4gX1e@B1p5_C{{`27*cS8+ zaOb?4TEj4dwenQ8`TiMb*Ez1>ctZJ@P&Q8yErVqEJ4V{!5~NZwET7e9*Y$ zP2eE>!eDHnX7+1*C!%lZy#i^l_J7yy|FHfF`M>&|Uj!4tPP8NXVh^#YFVodnqPC>z zzvTQ+XFt9z`8V`&7Iv^H=LYpJ9d}i6eS+yf68aC@gxZqtfIGntDI3Y*EjhE0T7n^STOLR}+UEGZgsIO7|&OY zo4L~}A9{gp(98MY-$3oGLihyv7L9FbZ-_(Dcd(vE^*AfjbJ1Awp1G2Kaq$rhpbQ?1 zzSQ1Y0=ipQP?;`YBA;>+cC``jtLMGO^Wv$mU~dlk6=++dw_5bJ20A|i@@+q;?7M5-fcEN;TFA5}Z{I&Q5d^I|4K$jbHJ`JeP^+OA9#Bva9)Cc$$FJSERu0{sxDFl|-+rwJKGkI+Tn_}d`)eK;9}cf= z4c^{%zZ=)#dW>C%<>lJs5f^LwbzJQ2*9ked-Jj4y`*mEf?bq=K+OPi`#L#}d>gP&G z=z8GzwZ2wevcgsy`J!q<{;_*xHyuk}FEH4h|R^FY!y4~M{a7snHy_&YA)2mFs?Iy^uM!Vf5g0WlKycgz8|haU(e5PG0V!L6-6GOr^aL;Uvk z7@C5++aK_ki6k|)UB{Eu)OH<@q5ZP8g(%x^kH;`36wU*2^Y_2CB;Br3Ea~>v*5un; zTi;GRIg*%m0pmf;jo@$3A1A0@z9eX)sXuoe{_mx4Zt=~vH9#-Exfav66)Wjb9hAHV z;~AV+2O7_~8MJ^6$#)%?1MUaMg7tuYb4Q+4o{~_WX?Lk#riMHY0DFRI;AP;t_9x!tMUEC8tfwS-`mvM{h2zm$n;5(F2Iy5Fi{*>oNFcO>&9tK^F(R7u6F9&^Z`2+ALa0(D->SYs0 zpVKpvIPSLz`(_Oe`CJG57~Bau>v!xpMv-m)y&QDb_s0FVNx#ki!$55*_!0QAxUOr- z=MZop&>XH6K;vZ{^VijNF8L43Lf>g^0h7QO&^O?Rd_{p)#RdHb?S8C3dE6CD0xtmX z$GXaArtp08?`0u=d<6au&H|f(2H-BaF*kmwPgH%Qti?HNegtKf`j3~e)@q4689W4(PW2ymm7ng07bE{+S@>^P&qM}$ zf&uWO)3TI2YHsE&;4M(>xfaFFzn6vhu?jp6&IKwz(jMe_J@78*t}b)Azf}46a`60+ zk4U?dL?Zw1RdD`g3+Gt=P5;I$b|9*>4R@*;ZRu$v_=;fdG3i)0S zoCqEQ?*pZ?D)O&3)+G8g68(U^$@g~PLhuw&A4nnP5IOxT|Nf|{MGkR$s3G42!PkKL z2A6?C@FUXs_j1sg{7MGu2d$$IaBa>a~o*+e~TPgYX z`O!Jt54sE2{Sy38St<@)1pWiWqe{%bmxb~sf2e-Y{{x!?`O8|$k3pRG16P6LKxFzq z!sWj&{}TS+`#+z*?wrMscfg(C2<%}v=b$X59BG);dH+{Q+kZvMe^^%P2VDwggT0VN zuT1^oJ<`B$FR=lcXWADiEvb8q}WY+@(lrxlQYUlvRu zzq^A08b8;Z3bie|I?6Qve$K!RiX1GAX0{d;k7B@_H0HUXODyCVte} z;T(1E|A^<``?0@}*E4~}IUDh1G4&r5;)rPe<;R`^zXo3feUxYUu|kb=d)Y-S|Ej-D z0%L*tLOLD0^m)kV9F_d5cB=e>tjDhN$+v$tGWqujD)HI!U()d(%@5m3a|AW-B3(VW z#Ol{PHjV$6s{NxmCC`D2f!3(?K^8I1A?&GxG?X&`e$IsCAY0I!!Bc_OZZ>G1@TBKU zD+%K5iTryx=&U(6ntL-J`~YZ8v-Z?12|tLdr}H0{h1T-F0;YrAf#%=U1nYG}VNISjMuHaMb~| zW<^}uA6yG^o!_2ox{L9g%2KVpxtRQ~(bacDj*su3AX#XA!@A%oa1RhSB-di3u^8_Z zA5^#e6F3cQLjG$fccWeznhW2^^PdMl2akb|fZkt>bm#LR@HlXzt+MG0|x`mn|}kS zT+T;--Fa4V=^Fw!0i{7{iTk*QTyxjG=R&@sp13yvKLNi7n%`awe#rmG58Vy4cW@J^ zS9|dU)@AkNAzy)Ah#y)vvkf>8h=<~1KC;lWD%bxC&H|f*M)KUF{RNq19pZ<|Qt{C5 z(WbqzRTgDyW+dS3lGi84fMtklnQ8h99d0JOjBZQy&{BRSQH(^2RbEL8sedxEvX zDnH`BLTiQPE7k`=TlV-8`Z2Z(Sf$+)I1*d^uyeyWU9NO42pAvVp(ohTfdGCE0{B@0 ziTz#11wRweqMzC1poKpiwJpIZxAXYK^NSN_wpR$=N1VBy8(W-nJm2vgq?_Nz#lvfZ zofd1jNq+6X#gs z98Zr!t_k@zCic~6Ozfl6l-M^Tu>ptnmRQW~V>s&xPTEK#zU2hF*66x*RbtPG&y+sx z6EO-L28y{)#73jr{GjShzV0-H|F;EeOqlQbGTyZnSQ7;MA8>YzZMzLNCviP-BxZ>v z((9(Z8l<}y*V_U0Rm+br2YZuF?PZ{`>HEOhU^M76;kIBbPvd#&2YCpzbIB=(#Pr+XM_{2EZ5 zMg1_Uw{=$E=`8&|AO5WQzYl_Q!LDEcXv@dwy|T|qP*;u1TlOKF{sK^a^%3wo$hIBR zo%H*BNGDp;uo!5r?)spPIXj)&*H5lyZy>HT-v4w$FYwT6p>x02GpgEA;(MieE@5_18sXS=S$?@PzK0Y3nXz}rCS>r5v-o&GgQ z-#>xYTiyqL1T^PX^Q*rA&I5k~nbw>2bo$kf)SfS1#^S*9U=BD0YyfnR)&*S-9s_Fk z`1_-lexEMoLpu34m=4sYkxrDK1Hld8b)fZLM}dG(vdv=Ff5hJo_TN$dKK6WE_sy86U8nZ{(BW~(L{R=6)30lBK)&`=FbK3A z5l;U{q*HDD+rf`$N3O$J>&Dw`N12FV`d5(7`QQ|=E$AhC(b^UMj~{KUibVQ7UmqcT z;^#JC2&e@?nmg;S>mm6o%~}ijB#^)SDp0$&#@k0@--N8YIF&g4tCPl?f$Bcr10z7t zKf*cKCt?(Rs@*wCoPPBe4hQPjjoU`TrW<;9C)Mru7CZgwqxOeS^MOD1zvO=|V*2+@ z^i2moE=Xy}Z{(ly_#29pezhev26zlu52&wN{d@7FfcelnL81G9lz#O=sBc<*)KkD7 zU~SLz`~zsd z?tWl((3X#L?n|$e#63#C=1z1KM=8Rk6V3VhD-c(<0@6ufUk9I`oDY6i9{YlGfX0Tp zGtN@%{QQsfXbeU3Wxo$LWFAJH=4<#P7<-A2zbGF=!9L(O;IF`sCl))MUA{vm3;`RYxeb9&W$ELiTlKl1`C>t;S zXIoxmbM;^Ya1wX`C@A}EN;0!8yA${EY*;VS-54+q zJOJJW9n+A@wS31tKpY$c0vq8R#2pAX+jO^UqV2ye8H4rjN}Q#WwZJamQlK$E$u3*_ z(tVl-_Y^oEd>O0(R8MM)OYs)t*zTaVIHXs_skjdX@)IwCk3dH~D9xJx`7F2r$fh;d zL-S>WG;eocF;biPoqM0$mXEm1mId<*H237EKzWfbmJfUpTnml_n}N18^S}GT*E7da zijbijcF0FOee%VclcF^Xn}Y$2?*}~O|KJ#q7{kpqjm#%vx{ziRX_^>kCQFUcd8KB9 zabB!>PQlzN0-S46L<61UX95axJ~Q#2lX5;c2I)9S=_6eyInt|hW8$p*aDB4!$9Y`h z%q*$kI>UUiis15I~NX%gxnx_q^ zJQ%+?h+np;a(8FY3?2pY?>{5H1AzLk{{^OkF`yB|esevU@8&W2r9^&T3C;tEV-z?R z{2r*z686Jq5s%_mf1>(A)z`iXECxq{EkHj%r|XJaGbd)x6P&x?ks!_*;#e1)41Nce z0M#2i`b=GSj6d8zt2qrXg9YFSFhuiZPCPF;4XQ8j9?7=}sBS$2sNEpnmM+flZ=J;- zPK)}~TEGQh7qAAXx%`&6tchn3_&ZP;5PpAG|7RP2I4y4xx4sRdzR0+5kFSGJ8@8+X zI)>*GztSRk>{}u6YYa&?AC_@f{}(R*^W2uieQ!6@P_XzXKOXe4>ia39!6cw@!FNGt zGALO5*lcXV?LmL3`g(T-Uj|i@h4xK*++E4FzAekHtMuJks z@6)0(;W=;y=&f=|X$QkVPX3SQvdRBS;?q8x6Tz1$hZ@IEcW$@+iyFUdOl8i+KzrK_ z2k~(y^6ifT=YJ+~ya48c!@*DxJ8!mgbqzkoCMywRT<21 z+9yLq8Gg<){`+};3{c%LHsRR}k#zENp7EDlM0QuYxs! z>a{5{(QiQhr@M8(aD1Kpul^hLH>xjX8&Iz~_+R;PTq=onjryUE2X}$a>f4>glTDcV zKBS+q^wrgC4DN>$N!3p3`K>ax3_C_{wq`OD&(7PT1>c7~E_-j+_llIoQ z#eqKL(|ZHyPVIrmK`#1vFY)Y5&T23A0kK~^i0p|g-I1ofss6C_fZ8T{kNRCYlZnEX zgDGGipth9W(bk3?ynecvGyk^n&TZ=uWy4C#>EJ%F49M2Sy_dlqK)O@=xaM-^^l!XV z=J$3tB+*uLQ+Y4%SDR@&a2z-S1ipu}!rTsTfnM#x5b#&7P>1w9T==98{{aXKv(?~ z8hcxJ>v;aiqxu#l=Of_JX{-l3n)2?)U~LeT^XqKLde9nP%psWo>2Ecl{zci6xc&*x z-_7&a@to>MuL9K>)jsPFRIch-@!tobAV0jjg= zUD-T;Co)tU=pgVkP(A1hpt)@?fzH#fHD>YWRWFtfe7t|)|1*JXy|eU(pO@U##=ixq z4z?zcKg;I%?YQ?RU}I3P=d@R>Y^aOpa+rmG6_Em%ly_d=WI_>y>`-i8XN2Ndu5=oCR(Ir-99Yeh>C4 g(EU1A4x}$ILzxl3gTJ+)3D9rr%a_GGvy$uo2azAm7XSbN literal 0 HcmV?d00001 diff --git a/tests/Neo.ConsoleService.Tests/CommandTokenTest.cs b/tests/Neo.ConsoleService.Tests/CommandTokenTest.cs new file mode 100644 index 0000000000..233e486f81 --- /dev/null +++ b/tests/Neo.ConsoleService.Tests/CommandTokenTest.cs @@ -0,0 +1,92 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Linq; + +namespace Neo.ConsoleService.Tests +{ + [TestClass] + public class CommandTokenTest + { + [TestMethod] + public void Test1() + { + var cmd = " "; + var args = CommandToken.Parse(cmd).ToArray(); + + AreEqual(args, new CommandSpaceToken(0, 1)); + Assert.AreEqual(cmd, CommandToken.ToString(args)); + } + + [TestMethod] + public void Test2() + { + var cmd = "show state"; + var args = CommandToken.Parse(cmd).ToArray(); + + AreEqual(args, new CommandStringToken(0, "show"), new CommandSpaceToken(4, 2), new CommandStringToken(6, "state")); + Assert.AreEqual(cmd, CommandToken.ToString(args)); + } + + [TestMethod] + public void Test3() + { + var cmd = "show \"hello world\""; + var args = CommandToken.Parse(cmd).ToArray(); + + AreEqual(args, + new CommandStringToken(0, "show"), + new CommandSpaceToken(4, 1), + new CommandQuoteToken(5, '"'), + new CommandStringToken(6, "hello world"), + new CommandQuoteToken(17, '"') + ); + Assert.AreEqual(cmd, CommandToken.ToString(args)); + } + + [TestMethod] + public void Test4() + { + var cmd = "show \"'\""; + var args = CommandToken.Parse(cmd).ToArray(); + + AreEqual(args, + new CommandStringToken(0, "show"), + new CommandSpaceToken(4, 1), + new CommandQuoteToken(5, '"'), + new CommandStringToken(6, "'"), + new CommandQuoteToken(7, '"') + ); + Assert.AreEqual(cmd, CommandToken.ToString(args)); + } + + [TestMethod] + public void Test5() + { + var cmd = "show \"123\\\"456\""; + var args = CommandToken.Parse(cmd).ToArray(); + + AreEqual(args, + new CommandStringToken(0, "show"), + new CommandSpaceToken(4, 1), + new CommandQuoteToken(5, '"'), + new CommandStringToken(6, "123\\\"456"), + new CommandQuoteToken(14, '"') + ); + Assert.AreEqual(cmd, CommandToken.ToString(args)); + } + + private void AreEqual(CommandToken[] args, params CommandToken[] compare) + { + Assert.AreEqual(compare.Length, args.Length); + + for (int x = 0; x < args.Length; x++) + { + var a = args[x]; + var b = compare[x]; + + Assert.AreEqual(a.Type, b.Type); + Assert.AreEqual(a.Value, b.Value); + Assert.AreEqual(a.Offset, b.Offset); + } + } + } +} diff --git a/tests/Neo.ConsoleService.Tests/Neo.ConsoleService.Tests.csproj b/tests/Neo.ConsoleService.Tests/Neo.ConsoleService.Tests.csproj new file mode 100644 index 0000000000..b4b29127f6 --- /dev/null +++ b/tests/Neo.ConsoleService.Tests/Neo.ConsoleService.Tests.csproj @@ -0,0 +1,10 @@ + + + + neo_cli.Tests + + + + + + From ef8577606e9cc106430979347910b9d9279ed60c Mon Sep 17 00:00:00 2001 From: Shargon Date: Tue, 12 Dec 2023 08:26:26 +0100 Subject: [PATCH 025/168] Fix warning (#3021) --- src/Neo.CLI/CLI/MainService.Plugins.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Neo.CLI/CLI/MainService.Plugins.cs b/src/Neo.CLI/CLI/MainService.Plugins.cs index 6373c9c4a7..f126eef996 100644 --- a/src/Neo.CLI/CLI/MainService.Plugins.cs +++ b/src/Neo.CLI/CLI/MainService.Plugins.cs @@ -118,7 +118,8 @@ private async Task DownloadPluginAsync(string pluginName) /// /// Install plugin from stream /// - /// name of the plugin + /// Name of the plugin + /// Dependency set /// Install by force for `update` private async Task InstallPluginAsync(string pluginName, HashSet installed = null, bool overWrite = false) From 52f660a3eb63520bc817f951d3d1b378e170d0f8 Mon Sep 17 00:00:00 2001 From: Christopher Schuchardt Date: Tue, 12 Dec 2023 02:37:12 -0500 Subject: [PATCH 026/168] Nuget Package Icon & Symbols (#3020) * Added package icon to nuget * Remove format for old symbol nuget packages * Pack packages fix * Apply suggestions from code review --------- Co-authored-by: Shargon --- .github/workflows/main.yml | 53 ++++++++++++++++++++++++++++++++++--- src/Directory.Build.props | 6 +++++ src/neo.png | Bin 0 -> 1419 bytes 3 files changed, 56 insertions(+), 3 deletions(-) create mode 100644 src/neo.png diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 05cc47a22f..b9e1e9b97e 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -49,8 +49,32 @@ jobs: uses: actions/setup-dotnet@v2 with: dotnet-version: ${{ env.DOTNET_VERSION }} - - name: Pack with dotnet - run: git rev-list --count HEAD |xargs printf "CI%05d" |xargs dotnet pack -c Debug -o out --include-source --version-suffix + - name: Set Version + run: git rev-list --count HEAD | xargs printf 'CI%05d' | xargs -I{} echo 'VERSION={}' >> $GITHUB_ENV + - name : Pack (Neo) + run: | + dotnet pack ./src/Neo \ + --configuration Debug \ + --output ./out \ + --version-suffix ${{ env.VERSION }} + - name : Pack (Neo.Json) + run: | + dotnet pack ./src/Neo.Json \ + --configuration Debug \ + --output ./out \ + --version-suffix ${{ env.VERSION }} + - name : Pack (Neo.VM) + run: | + dotnet pack ./src/Neo.VM \ + --configuration Debug \ + --output ./out \ + --version-suffix ${{ env.VERSION }} + - name : Pack (Neo.ConsoleService) + run: | + dotnet pack ./src/Neo.ConsoleService \ + --configuration Debug \ + --output ./out \ + --version-suffix ${{ env.VERSION }} - name: Publish to MyGet run: dotnet nuget push out/*.nupkg -s https://www.myget.org/F/neo/api/v2/package -k ${MYGET_TOKEN} -ss https://www.myget.org/F/neo/symbols/api/v2/package -sk ${MYGET_TOKEN} env: @@ -86,10 +110,33 @@ jobs: uses: actions/setup-dotnet@v2 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.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: Publish to NuGet if: steps.check_tag.outputs.statusCode == '404' run: | - dotnet pack -o out -c Release dotnet nuget push out/*.nupkg -s https://api.nuget.org/v3/index.json -k ${NUGET_TOKEN} env: NUGET_TOKEN: ${{ secrets.NUGET_TOKEN }} diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 6a1c44f64e..137cc55db2 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -6,12 +6,18 @@ 3.6.2 The Neo Project net7.0 + neo.png https://github.com/neo-project/neo MIT git https://github.com/neo-project/neo.git + true + snupkg The Neo Project true + + + diff --git a/src/neo.png b/src/neo.png new file mode 100644 index 0000000000000000000000000000000000000000..1a71de07eb55e4630535a8bd211257d0a4dbfb1c GIT binary patch literal 1419 zcma)6Su`666pbZ_E!HYZLyL6md#g%wmPXQY0#v0 z)u5Jf1l6gf)-gg!f(BDt)i$=_Z$9Uod*40xeY|_l{di=I8&XD6O%ebA$e>)Da7XHL zObM~0>9JIYJQAU39MS<$)qiT?$cPf)Kf(ckT8h+OF!0EOqFj8U0RRKkF@-oC9uNQk z2thf)@ua||0-v-~h*PQE9_05Tk%R4znP>A!UAqn#40&)9-9pEDe+$y*Cxest$q;SV zZgD@LappU;ILZWk)55^HvxQ29s43NoCLFA<3k^N7g@eJ<1NA zP~LCw!3v^Sc1d-mb7EB#y*s@pVh<1Ss0QDw+FXAmJ1%;SeJ0ehy0_hYbX3P;_9@qI zTOJpXei|MV0nIH;dv_M-gc+g>7*%xH*7~qoua&2c_BOcb0-h5VBfdv=}zzNIO z4?4k^$Gf;m&aK;#8aW_k_FZNyLb>Ycq8Ytr3K0M*n>_SngjV>5pw9z~crQNg=P~se z6+DSK8jm4GU#7oqOG1;Zm-f#Cw{TwM9q}>#W#&-OmAbqtQ<{)(-obTekFDoSN&it& z78Da^R>j}3@6u>?hfQGg$JDn?+vlUvO3>tCYy+%pyGWNNAZe8J3hk%l+p}B^wVwQg z)Wy1Rfd)&Xw*PHX$y{al8Pcx!4A zKbaYvr;d;b)&3KFSOER@gQtW)?8JYOu9kBz#P4`JDObl8e)Io<8A;Uawq)+Z-r;%^ z`F$cB@7K`~3QvW4*}F^QYGIp5Tc_TtMXXV`%D_CO8L`p}FKm+(th(u)Wbh`uCsqpN zTdh%X2Uh;s)@uviBNte6%!I+$!*N17YkNgl0iM;qh>t%RqghcooYFVHl=zS=D9>Ul zx^nV=QLszl?2Ql324*Kd8ezviaOV(+s{M!vtJCIlQc$uWvRml;4pDpYY`rXNB+@1l z9s+yz>tp!Oq=S`h*_-C`rc90bf66j)j}C`QyAV{D9U{8=TGRWaKTRhY^OfU=;w}9% zmz~xV5_R!y*;3~sQeLg&eZHdH%o=b@W0()A+mlpJwq4S0d=2=ky3S198sTL6r5FzxCo>BAv_bc7yuBP-ySc(KY86pPJ+* zcH*Q|F*Y$6)--p$rTJuxpi*!_y++{0CRWjIP%*rstUBzpShPhwz0@`(?PD4f@30>rhsthyd5egCPi)F?Ed6G0a>7L(r1z7} Q(E|mb5N=LY4nax(0@8w_9{>OV literal 0 HcmV?d00001 From c64443403e538fab7cb88202358cfa93dc406d98 Mon Sep 17 00:00:00 2001 From: Christopher Schuchardt Date: Tue, 12 Dec 2023 10:28:33 -0500 Subject: [PATCH 027/168] Package icons - hotfix (#3022) * Added package icon to nuget * Remove format for old symbol nuget packages * Pack packages fix * Apply suggestions from code review * fix publish * fix * Fixed version number * delete unwanted files * Update MainService.Plugins.cs * Update MainService.Plugins.cs --------- Co-authored-by: Shargon --- .github/workflows/main.yml | 39 +++++++++++++------------------------- 1 file changed, 13 insertions(+), 26 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index b9e1e9b97e..c4e5ff36e9 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -17,9 +17,9 @@ jobs: runs-on: ${{ matrix.os }} steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup .NET - uses: actions/setup-dotnet@v2 + uses: actions/setup-dotnet@v4 with: dotnet-version: ${{ env.DOTNET_VERSION }} - name: Check format @@ -42,39 +42,26 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 - name: Setup .NET - uses: actions/setup-dotnet@v2 + uses: actions/setup-dotnet@v4 with: dotnet-version: ${{ env.DOTNET_VERSION }} - name: Set Version - run: git rev-list --count HEAD | xargs printf 'CI%05d' | xargs -I{} echo 'VERSION={}' >> $GITHUB_ENV + run: git rev-list --count HEAD | xargs printf 'CI%05d' | xargs -I{} echo 'VERSION_SUFFIX={}' >> $GITHUB_ENV - name : Pack (Neo) run: | - dotnet pack ./src/Neo \ - --configuration Debug \ - --output ./out \ - --version-suffix ${{ env.VERSION }} - - name : Pack (Neo.Json) - run: | - dotnet pack ./src/Neo.Json \ + dotnet pack \ --configuration Debug \ --output ./out \ - --version-suffix ${{ env.VERSION }} - - name : Pack (Neo.VM) + --version-suffix ${{ env.VERSION_SUFFIX }} + - name: Remove Unwanted Files + working-directory: ./out run: | - dotnet pack ./src/Neo.VM \ - --configuration Debug \ - --output ./out \ - --version-suffix ${{ env.VERSION }} - - name : Pack (Neo.ConsoleService) - run: | - dotnet pack ./src/Neo.ConsoleService \ - --configuration Debug \ - --output ./out \ - --version-suffix ${{ env.VERSION }} + rm -v Neo.CLI* + rm -v Neo.GUI* - name: Publish to MyGet run: dotnet nuget push out/*.nupkg -s https://www.myget.org/F/neo/api/v2/package -k ${MYGET_TOKEN} -ss https://www.myget.org/F/neo/symbols/api/v2/package -sk ${MYGET_TOKEN} env: @@ -86,7 +73,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Get version id: get_version run: | @@ -107,7 +94,7 @@ jobs: prerelease: ${{ contains(steps.get_version.outputs.version, '-') }} - name: Setup .NET if: steps.check_tag.outputs.statusCode == '404' - uses: actions/setup-dotnet@v2 + uses: actions/setup-dotnet@v4 with: dotnet-version: ${{ env.DOTNET_VERSION }} - name : Pack (Neo) From aede70b125e74fd6e60e768fd133743cec41c8aa Mon Sep 17 00:00:00 2001 From: Christopher Schuchardt Date: Wed, 13 Dec 2023 15:03:10 -0500 Subject: [PATCH 028/168] Fixed MyGet Workflow (#3027) * Fixed myget * Fixed myget --- .github/workflows/main.yml | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c4e5ff36e9..66b767ffff 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -63,9 +63,16 @@ jobs: rm -v Neo.CLI* rm -v Neo.GUI* - name: Publish to MyGet - run: dotnet nuget push out/*.nupkg -s https://www.myget.org/F/neo/api/v2/package -k ${MYGET_TOKEN} -ss https://www.myget.org/F/neo/symbols/api/v2/package -sk ${MYGET_TOKEN} - env: - MYGET_TOKEN: ${{ secrets.MYGET_TOKEN }} + working-directory: ./out + run: | + for filename in *.nupkg; do + dotnet nuget push "${filename}" \ + --source https://www.myget.org/F/neo/api/v2/package \ + --api-key "${{ secrets.MYGET_TOKEN }}" \ + --symbol-source https://www.myget.org/F/neo/symbols/api/v2/package \ + --symbol-api-key "${{ secrets.MYGET_TOKEN }}"; + done; + shell: bash Release: if: github.ref == 'refs/heads/master' && startsWith(github.repository, 'neo-project/') From 30ac705e518524897dfe6932b3089901587879ab Mon Sep 17 00:00:00 2001 From: Christopher Schuchardt Date: Fri, 15 Dec 2023 02:20:11 -0500 Subject: [PATCH 029/168] fixed myget (#3029) --- .github/workflows/main.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 66b767ffff..04fe3fccd4 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -67,10 +67,8 @@ jobs: run: | for filename in *.nupkg; do dotnet nuget push "${filename}" \ - --source https://www.myget.org/F/neo/api/v2/package \ - --api-key "${{ secrets.MYGET_TOKEN }}" \ - --symbol-source https://www.myget.org/F/neo/symbols/api/v2/package \ - --symbol-api-key "${{ secrets.MYGET_TOKEN }}"; + --source https://www.myget.org/F/neo/api/v3/index.json \ + --api-key "${{ secrets.MYGET_TOKEN }}"; done; shell: bash From c78ac5adbd790b1fc60d3ea9abc87cf3eee74a6e Mon Sep 17 00:00:00 2001 From: Jimmy Date: Mon, 25 Dec 2023 19:35:04 +0800 Subject: [PATCH 030/168] Add: print out the stack (#3033) * print out the stack * reverse the string order * Apply suggestions from code review * use left as the bottom of the stack * add compound * Update src/Neo.VM/EvaluationStack.cs --------- Co-authored-by: Shargon --- src/Neo.VM/EvaluationStack.cs | 28 +++++++++++++++++++++---- tests/Neo.VM.Tests/UtEvaluationStack.cs | 13 ++++++++++++ 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/src/Neo.VM/EvaluationStack.cs b/src/Neo.VM/EvaluationStack.cs index b5b728ed46..97b2a7f371 100644 --- a/src/Neo.VM/EvaluationStack.cs +++ b/src/Neo.VM/EvaluationStack.cs @@ -1,10 +1,10 @@ // Copyright (C) 2016-2023 The Neo Project. -// -// The neo-vm is free software distributed under the MIT software license, +// +// The neo-vm is free software distributed under the MIT software license, // see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// project 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. @@ -35,6 +35,26 @@ internal EvaluationStack(ReferenceCounter referenceCounter) /// public int Count => innerList.Count; + public override string ToString() + { + return $@"[{string.Join(", ", innerList.Select(p => + { + var value = p.Type switch + { + StackItemType.Pointer => $"({((Pointer)p).Position})", + StackItemType.Boolean => $"({p.GetBoolean()})", + StackItemType.Integer => $"({p.GetInteger()})", + StackItemType.ByteString => $"(\"{p.GetString()}\")", + StackItemType.Array + or StackItemType.Map + or StackItemType.Struct => $"({((CompoundType)p).Count})", + _ => "" + }; + return $"{p.Type.ToString()}{value}"; + } + ))}]"; + } + internal void Clear() { foreach (StackItem item in innerList) diff --git a/tests/Neo.VM.Tests/UtEvaluationStack.cs b/tests/Neo.VM.Tests/UtEvaluationStack.cs index b8853b39ec..03f1294d66 100644 --- a/tests/Neo.VM.Tests/UtEvaluationStack.cs +++ b/tests/Neo.VM.Tests/UtEvaluationStack.cs @@ -187,5 +187,18 @@ public void TestReverse() Assert.IsTrue(stack.Pop().Equals(1)); Assert.ThrowsException(() => stack.Pop().Equals(0)); } + + [TestMethod] + public void TestToString() + { + var stack = new EvaluationStack(new ReferenceCounter()); + + stack.Insert(0, 3); + stack.Insert(1, 1); + stack.Insert(2, "test"); + stack.Insert(3, true); + + Assert.AreEqual("[Boolean(True), ByteString(\"test\"), Integer(1), Integer(3)]", stack.ToString()); + } } } From 254fc9935f82d5c18d1a1c3c6e3b74a0515f8bd4 Mon Sep 17 00:00:00 2001 From: Christopher Schuchardt Date: Wed, 27 Dec 2023 03:58:55 -0500 Subject: [PATCH 031/168] Nuget MyGet Fix (#3031) * fix * Added disable-buffering * typo fixed * Fix package Neo.ConsoleService * Add global.json configuration for targetting right version of dotnet sdk if you have dotnet 8.0 installed --------- Co-authored-by: Shargon --- .github/workflows/main.yml | 4 +++- global.json | 7 +++++++ src/Neo.ConsoleService/Neo.ConsoleService.csproj | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-) create mode 100644 global.json diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 04fe3fccd4..768cdc56ef 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -68,7 +68,9 @@ jobs: for filename in *.nupkg; do dotnet nuget push "${filename}" \ --source https://www.myget.org/F/neo/api/v3/index.json \ - --api-key "${{ secrets.MYGET_TOKEN }}"; + --api-key "${{ secrets.MYGET_TOKEN }}" \ + --disable-buffering \ + --no-service-endpoint; done; shell: bash diff --git a/global.json b/global.json new file mode 100644 index 0000000000..943dd9e463 --- /dev/null +++ b/global.json @@ -0,0 +1,7 @@ +{ + "sdk": { + "version": "7.0.404", + "rollForward": "latestFeature", + "allowPrerelease": false + } +} diff --git a/src/Neo.ConsoleService/Neo.ConsoleService.csproj b/src/Neo.ConsoleService/Neo.ConsoleService.csproj index c5ef250052..173e3be4e0 100644 --- a/src/Neo.ConsoleService/Neo.ConsoleService.csproj +++ b/src/Neo.ConsoleService/Neo.ConsoleService.csproj @@ -1,7 +1,7 @@ - 1.2.0 + Neo.ConsoleService From 9db894ffb8fd89a61175e9ef87152357034d0c18 Mon Sep 17 00:00:00 2001 From: Christopher Schuchardt Date: Sat, 30 Dec 2023 04:13:17 -0500 Subject: [PATCH 032/168] Added README to packages (#3026) --- src/Directory.Build.props | 2 ++ src/README.md | 25 +++++++++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 src/README.md diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 137cc55db2..ed3a744939 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -9,6 +9,7 @@ neo.png https://github.com/neo-project/neo MIT + README.md git https://github.com/neo-project/neo.git true @@ -19,5 +20,6 @@ + diff --git a/src/README.md b/src/README.md new file mode 100644 index 0000000000..58a2cf66b5 --- /dev/null +++ b/src/README.md @@ -0,0 +1,25 @@ +## Overview +This repository contain main classes of the [Neo](https://www.neo.org) blockchain. +Visit the [documentation](https://docs.neo.org/docs/en-us/index.html) to get started. + +## Related projects +Code references are provided for all platform building blocks. That includes the base library, the VM, a command line application and the compiler. + +- [neo:](https://github.com/neo-project/neo/) Neo core library, contains base classes, including ledger, p2p and IO modules. +- [neo-modules:](https://github.com/neo-project/neo-modules/) Neo modules include additional tools and plugins to be used with Neo. +- [neo-devpack-dotnet:](https://github.com/neo-project/neo-devpack-dotnet/) These are the official tools used to convert a C# smart-contract into a *neo executable file*. + +## Opening a new issue +Please feel free to create new issues to suggest features or ask questions. + +- [Feature request](https://github.com/neo-project/neo/issues/new?assignees=&labels=discussion&template=feature-or-enhancement-request.md&title=) +- [Bug report](https://github.com/neo-project/neo/issues/new?assignees=&labels=&template=bug_report.md&title=) +- [Questions](https://github.com/neo-project/neo/issues/new?assignees=&labels=question&template=questions.md&title=) + +If you found a security issue, please refer to our [security policy](https://github.com/neo-project/neo/security/policy). + +## Bounty program +You can be rewarded by finding security issues. Please refer to our [bounty program page](https://neo.org/bounty) for more information. + +## License +The NEO project is licensed under the [MIT license](http://www.opensource.org/licenses/mit-license.php). From bcf6eab8e90cf294741ab2623e430a82f6895dc2 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Sun, 31 Dec 2023 17:26:13 +0800 Subject: [PATCH 033/168] Fix: fix equal (#3028) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix equal * fix format * remove redundent * make it more strick * expand the equal to jnumber and jstring * Apply suggestions from code review * Update src/Neo.Json/JNumber.cs --------- Co-authored-by: Shargon Co-authored-by: Vitor Nazário Coelho --- src/Neo.Json/JBoolean.cs | 36 +++++++++++++++-- src/Neo.Json/JNumber.cs | 53 +++++++++++++++++++++++-- src/Neo.Json/JString.cs | 39 ++++++++++++++++-- tests/Neo.Json.UnitTests/UT_JBoolean.cs | 9 +++++ tests/Neo.Json.UnitTests/UT_JNumber.cs | 11 ++++- tests/Neo.Json.UnitTests/UT_JString.cs | 9 +++++ 6 files changed, 144 insertions(+), 13 deletions(-) diff --git a/src/Neo.Json/JBoolean.cs b/src/Neo.Json/JBoolean.cs index 9398270aae..feb3d16b1d 100644 --- a/src/Neo.Json/JBoolean.cs +++ b/src/Neo.Json/JBoolean.cs @@ -1,10 +1,10 @@ // Copyright (C) 2015-2022 The Neo Project. -// -// The Neo.Json is free software distributed under the MIT software license, +// +// The Neo.Json is free software distributed under the MIT software license, // see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// project 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. @@ -71,5 +71,33 @@ public static implicit operator JBoolean(bool value) { return new JBoolean(value); } + + public static bool operator ==(JBoolean left, JBoolean right) + { + return left.Value.Equals(right.Value); + } + + public static bool operator !=(JBoolean left, JBoolean right) + { + return !left.Value.Equals(right.Value); + } + + public override bool Equals(object? obj) + { + if (ReferenceEquals(this, obj)) + { + return true; + } + if (obj is JBoolean other) + { + return this.Value.Equals(other.Value); + } + return false; + } + + public override int GetHashCode() + { + return Value.GetHashCode(); + } } } diff --git a/src/Neo.Json/JNumber.cs b/src/Neo.Json/JNumber.cs index 7e58b72567..65f4991cd8 100644 --- a/src/Neo.Json/JNumber.cs +++ b/src/Neo.Json/JNumber.cs @@ -1,10 +1,10 @@ // Copyright (C) 2015-2022 The Neo Project. -// -// The Neo.Json is free software distributed under the MIT software license, +// +// The Neo.Json is free software distributed under the MIT software license, // see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// project 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. @@ -117,5 +117,50 @@ public static implicit operator JNumber(double value) { return new JNumber(value); } + + public static implicit operator JNumber(long value) + { + return new JNumber(value); + } + + public static bool operator ==(JNumber left, JNumber? right) + { + if (right is null) return false; + return ReferenceEquals(left, right) || left.Value.Equals(right.Value); + } + + public static bool operator !=(JNumber left, JNumber right) + { + return !(left == right); + } + + public override bool Equals(object? obj) + { + if (obj is null) return false; + if (ReferenceEquals(this, obj)) return true; + + var other = obj switch + { + JNumber jNumber => jNumber, + uint u => new JNumber(u), + int i => new JNumber(i), + ulong ul => new JNumber(ul), + long l => new JNumber(l), + byte b => new JNumber(b), + sbyte sb => new JNumber(sb), + short s => new JNumber(s), + ushort us => new JNumber(us), + decimal d => new JNumber((double)d), + float f => new JNumber(f), + double d => new JNumber(d), + _ => throw new ArgumentOutOfRangeException(nameof(obj), obj, null) + }; + return other == this; + } + + public override int GetHashCode() + { + return Value.GetHashCode(); + } } } diff --git a/src/Neo.Json/JString.cs b/src/Neo.Json/JString.cs index 714ff85928..42bc63937c 100644 --- a/src/Neo.Json/JString.cs +++ b/src/Neo.Json/JString.cs @@ -1,10 +1,10 @@ // Copyright (C) 2015-2022 The Neo Project. -// -// The Neo.Json is free software distributed under the MIT software license, +// +// The Neo.Json is free software distributed under the MIT software license, // see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// project 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. @@ -92,5 +92,36 @@ public static implicit operator JString(Enum value) { return value == null ? null : new JString(value); } + + public static bool operator ==(JString left, JString? right) + { + if (right is null) return false; + return ReferenceEquals(left, right) || left.Value.Equals(right.Value); + } + + public static bool operator !=(JString left, JString right) + { + return !(left == right); + } + + public override bool Equals(object? obj) + { + if (obj is null) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj is JString other) + { + return this == other; + } + if (obj is string str) + { + return this.Value == str; + } + return false; + } + + public override int GetHashCode() + { + return Value.GetHashCode(); + } } } diff --git a/tests/Neo.Json.UnitTests/UT_JBoolean.cs b/tests/Neo.Json.UnitTests/UT_JBoolean.cs index 679c9b622d..e03654f8b9 100644 --- a/tests/Neo.Json.UnitTests/UT_JBoolean.cs +++ b/tests/Neo.Json.UnitTests/UT_JBoolean.cs @@ -19,5 +19,14 @@ public void TestAsNumber() jFalse.AsNumber().Should().Be(0); jTrue.AsNumber().Should().Be(1); } + + [TestMethod] + public void TestEqual() + { + Assert.IsTrue(jTrue.Equals(new JBoolean(true))); + Assert.IsTrue(jTrue == new JBoolean(true)); + Assert.IsTrue(jFalse.Equals(new JBoolean())); + Assert.IsTrue(jFalse == new JBoolean()); + } } } diff --git a/tests/Neo.Json.UnitTests/UT_JNumber.cs b/tests/Neo.Json.UnitTests/UT_JNumber.cs index 6156bc1cb5..8435e0ad47 100644 --- a/tests/Neo.Json.UnitTests/UT_JNumber.cs +++ b/tests/Neo.Json.UnitTests/UT_JNumber.cs @@ -49,9 +49,18 @@ public void TestGetEnum() new JNumber(1).GetEnum().Should().Be(Woo.Jerry); new JNumber(2).GetEnum().Should().Be(Woo.James); new JNumber(3).AsEnum().Should().Be(Woo.Tom); - Action action = () => new JNumber(3).GetEnum(); action.Should().Throw(); } + + [TestMethod] + public void TestEqual() + { + Assert.IsTrue(maxInt.Equals(JNumber.MAX_SAFE_INTEGER)); + Assert.IsTrue(maxInt == JNumber.MAX_SAFE_INTEGER); + Assert.IsTrue(minInt.Equals(JNumber.MIN_SAFE_INTEGER)); + Assert.IsTrue(minInt == JNumber.MIN_SAFE_INTEGER); + Assert.IsTrue(zero == new JNumber()); + } } } diff --git a/tests/Neo.Json.UnitTests/UT_JString.cs b/tests/Neo.Json.UnitTests/UT_JString.cs index 3188bf0e59..54e87ad49f 100644 --- a/tests/Neo.Json.UnitTests/UT_JString.cs +++ b/tests/Neo.Json.UnitTests/UT_JString.cs @@ -48,5 +48,14 @@ public void TestGetEnum() woo = s.AsEnum(Woo.Jerry, false); Assert.AreEqual(Woo.Jerry, woo); } + [TestMethod] + public void TestEqual() + { + var str = "hello world"; + var jString = new JString(str); + Assert.IsTrue(jString.Equals(str)); + Assert.IsTrue(jString == str); + Assert.IsTrue(jString != "hello world2"); + } } } From 447b149e117589a1ceed0e754d5616917e555f52 Mon Sep 17 00:00:00 2001 From: Shargon Date: Sun, 31 Dec 2023 01:29:37 -0800 Subject: [PATCH 034/168] Set project as nullable (#3042) * Set project as nullable * Clean code * format * Remove more nullables * ConsoleService nullable * More changes * Clean CLI warnings * Only CLI and Console Service * Clean changes --------- Co-authored-by: Jimmy --- src/Neo.CLI/CLI/ConsolePercent.cs | 6 +- src/Neo.CLI/CLI/MainService.Blockchain.cs | 22 ++-- src/Neo.CLI/CLI/MainService.Contracts.cs | 12 +-- src/Neo.CLI/CLI/MainService.Logger.cs | 10 +- src/Neo.CLI/CLI/MainService.NEP17.cs | 5 +- src/Neo.CLI/CLI/MainService.Native.cs | 1 - src/Neo.CLI/CLI/MainService.Plugins.cs | 29 ++--- src/Neo.CLI/CLI/MainService.Tools.cs | 26 ++--- src/Neo.CLI/CLI/MainService.Vote.cs | 34 +++--- src/Neo.CLI/CLI/MainService.Wallet.cs | 60 ++++++----- src/Neo.CLI/CLI/MainService.cs | 101 ++++++++++++------ src/Neo.CLI/Extensions.cs | 6 +- src/Neo.CLI/Neo.CLI.csproj | 1 + src/Neo.CLI/Settings.cs | 20 ++-- src/Neo.ConsoleService/CommandStringToken.cs | 2 +- src/Neo.ConsoleService/CommandToken.cs | 13 ++- .../ConsoleCommandAttribute.cs | 4 +- src/Neo.ConsoleService/ConsoleServiceBase.cs | 69 +++++++----- .../Neo.ConsoleService.csproj | 1 + 19 files changed, 244 insertions(+), 178 deletions(-) diff --git a/src/Neo.CLI/CLI/ConsolePercent.cs b/src/Neo.CLI/CLI/ConsolePercent.cs index 09077f2503..8c5e2a137d 100644 --- a/src/Neo.CLI/CLI/ConsolePercent.cs +++ b/src/Neo.CLI/CLI/ConsolePercent.cs @@ -19,11 +19,11 @@ public class ConsolePercent : IDisposable private readonly long _maxValue; private long _value; private decimal _lastFactor; - private string _lastPercent; + private string? _lastPercent; private readonly int _x, _y; - private bool _inputRedirected; + private readonly bool _inputRedirected; #endregion @@ -99,7 +99,7 @@ public ConsolePercent(long value = 0, long maxValue = 100) /// public void Invalidate() { - var factor = Math.Round((Percent / 100M), 1); + var factor = Math.Round(Percent / 100M, 1); var percent = Percent.ToString("0.0").PadLeft(5, ' '); if (_lastFactor == factor && _lastPercent == percent) diff --git a/src/Neo.CLI/CLI/MainService.Blockchain.cs b/src/Neo.CLI/CLI/MainService.Blockchain.cs index 3e5fc90a9b..f85368ec37 100644 --- a/src/Neo.CLI/CLI/MainService.Blockchain.cs +++ b/src/Neo.CLI/CLI/MainService.Blockchain.cs @@ -26,7 +26,7 @@ partial class MainService /// Number of blocks /// Path [ConsoleCommand("export blocks", Category = "Blockchain Commands")] - private void OnExportBlocksStartCountCommand(uint start, uint count = uint.MaxValue, string path = null) + private void OnExportBlocksStartCountCommand(uint start, uint count = uint.MaxValue, string? path = null) { uint height = NativeContract.Ledger.CurrentIndex(NeoSystem.StoreView); if (height < start) @@ -50,12 +50,12 @@ private void OnShowBlockCommand(string indexOrHash) { lock (syncRoot) { - Block block = null; + Block? block = null; if (uint.TryParse(indexOrHash, out var index)) - block = NativeContract.Ledger.GetBlock(_neoSystem.StoreView, index); + block = NativeContract.Ledger.GetBlock(NeoSystem.StoreView, index); else if (UInt256.TryParse(indexOrHash, out var hash)) - block = NativeContract.Ledger.GetBlock(_neoSystem.StoreView, hash); + block = NativeContract.Ledger.GetBlock(NeoSystem.StoreView, hash); else { ConsoleHelper.Error("Enter a valid block index or hash."); @@ -81,7 +81,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.GetSnapshot())[block.PrimaryIndex]}"); ConsoleHelper.Info("", " Version: ", $"{block.Version}"); ConsoleHelper.Info("", " Size: ", $"{block.Size} Byte(s)"); ConsoleHelper.Info(); @@ -116,7 +116,7 @@ public void OnShowTransactionCommand(UInt256 hash) { lock (syncRoot) { - var tx = NativeContract.Ledger.GetTransactionState(_neoSystem.StoreView, hash); + var tx = NativeContract.Ledger.GetTransactionState(NeoSystem.StoreView, hash); if (tx is null) { @@ -124,7 +124,7 @@ public void OnShowTransactionCommand(UInt256 hash) return; } - var block = NativeContract.Ledger.GetHeader(_neoSystem.StoreView, tx.BlockIndex); + var block = NativeContract.Ledger.GetHeader(NeoSystem.StoreView, tx.BlockIndex); DateTime transactionDatetime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc); transactionDatetime = transactionDatetime.AddMilliseconds(block.Timestamp).ToLocalTime(); @@ -228,16 +228,16 @@ public void OnShowContractCommand(string nameOrHash) { lock (syncRoot) { - ContractState contract = null; + ContractState? contract = null; if (UInt160.TryParse(nameOrHash, out var scriptHash)) - contract = NativeContract.ContractManagement.GetContract(_neoSystem.StoreView, scriptHash); + contract = NativeContract.ContractManagement.GetContract(NeoSystem.StoreView, scriptHash); else { var nativeContract = NativeContract.Contracts.SingleOrDefault(s => s.Name.Equals(nameOrHash, StringComparison.InvariantCultureIgnoreCase)); if (nativeContract != null) - contract = NativeContract.ContractManagement.GetContract(_neoSystem.StoreView, nativeContract.Hash); + contract = NativeContract.ContractManagement.GetContract(NeoSystem.StoreView, nativeContract.Hash); } if (contract is null) @@ -257,7 +257,7 @@ public void OnShowContractCommand(string nameOrHash) ConsoleHelper.Info("", " Compiler: ", $"{contract.Nef.Compiler}"); ConsoleHelper.Info("", " SourceCode: ", $"{contract.Nef.Source}"); ConsoleHelper.Info("", " Trusts: ", $"[{string.Join(", ", contract.Manifest.Trusts.Select(s => s.ToJson()?.GetString()))}]"); - if (contract.Manifest.Extra is null) + if (contract.Manifest.Extra is not null) { foreach (var extra in contract.Manifest.Extra.Properties) { diff --git a/src/Neo.CLI/CLI/MainService.Contracts.cs b/src/Neo.CLI/CLI/MainService.Contracts.cs index 77b4a77219..f60faddf04 100644 --- a/src/Neo.CLI/CLI/MainService.Contracts.cs +++ b/src/Neo.CLI/CLI/MainService.Contracts.cs @@ -28,14 +28,14 @@ partial class MainService /// Manifest path /// Extra data for deploy [ConsoleCommand("deploy", Category = "Contract Commands")] - private void OnDeployCommand(string filePath, string manifestPath = null, JObject data = null) + private void OnDeployCommand(string filePath, string? manifestPath = null, JObject? data = null) { if (NoWallet()) return; byte[] script = LoadDeploymentScript(filePath, manifestPath, data, out var nef, out var manifest); Transaction tx; try { - tx = CurrentWallet.MakeTransaction(NeoSystem.StoreView, script); + tx = CurrentWallet!.MakeTransaction(NeoSystem.StoreView, script); } catch (InvalidOperationException e) { @@ -65,7 +65,7 @@ private void OnDeployCommand(string filePath, string manifestPath = null, JObjec /// Signer Accounts /// Extra data for update [ConsoleCommand("update", Category = "Contract Commands")] - private void OnUpdateCommand(UInt160 scriptHash, string filePath, string manifestPath, UInt160 sender, UInt160[] signerAccounts = null, JObject data = null) + private void OnUpdateCommand(UInt160 scriptHash, string filePath, string manifestPath, UInt160 sender, UInt160[]? signerAccounts = null, JObject? data = null) { Signer[] signers = Array.Empty(); @@ -91,7 +91,7 @@ private void OnUpdateCommand(UInt160 scriptHash, string filePath, string manifes try { byte[] script = LoadUpdateScript(scriptHash, filePath, manifestPath, data, out var nef, out var manifest); - tx = CurrentWallet.MakeTransaction(NeoSystem.StoreView, script, sender, signers); + tx = CurrentWallet!.MakeTransaction(NeoSystem.StoreView, script, sender, signers); } catch (InvalidOperationException e) { @@ -128,7 +128,7 @@ private void OnUpdateCommand(UInt160 scriptHash, string filePath, string manifes /// Signer's accounts /// Max fee for running the script [ConsoleCommand("invoke", Category = "Contract Commands")] - private void OnInvokeCommand(UInt160 scriptHash, string operation, JArray contractParameters = null, UInt160 sender = null, UInt160[] signerAccounts = null, decimal maxGas = 20) + private void OnInvokeCommand(UInt160 scriptHash, string operation, JArray? contractParameters = null, UInt160? sender = null, UInt160[]? signerAccounts = null, decimal maxGas = 20) { var gas = new BigDecimal(maxGas, NativeContract.GAS.Decimals); Signer[] signers = Array.Empty(); @@ -161,7 +161,7 @@ private void OnInvokeCommand(UInt160 scriptHash, string operation, JArray contra if (NoWallet()) return; try { - tx = CurrentWallet.MakeTransaction(NeoSystem.StoreView, tx.Script, sender, signers, maxGas: (long)gas.Value); + tx = CurrentWallet!.MakeTransaction(NeoSystem.StoreView, tx.Script, sender, signers, maxGas: (long)gas.Value); } catch (InvalidOperationException e) { diff --git a/src/Neo.CLI/CLI/MainService.Logger.cs b/src/Neo.CLI/CLI/MainService.Logger.cs index 6624f931a6..47a813d7e2 100644 --- a/src/Neo.CLI/CLI/MainService.Logger.cs +++ b/src/Neo.CLI/CLI/MainService.Logger.cs @@ -112,9 +112,9 @@ private void OnLog(string source, LogLevel level, object message) Console.Write($"{logLevel} {log} \t{messages[0],-20}"); for (var i = 1; i < messages.Length; i++) { - if (messages[i].Length > 20) + if (messages[i]?.Length > 20) { - messages[i] = $"{messages[i][..10]}...{messages[i][(messages[i].Length - 10)..]}"; + messages[i] = $"{messages[i]![..10]}...{messages[i]![(messages[i]!.Length - 10)..]}"; } Console.Write(i % 2 == 0 ? $"={messages[i]} " : $" {messages[i]}"); } @@ -162,7 +162,11 @@ private static string[] Parse(string message) { messages.Add(string.Join(" ", d)); } - messages.Add(parts.LastOrDefault()); + var last = parts.LastOrDefault(); + if (last is not null) + { + messages.Add(last); + } } return messages.ToArray(); diff --git a/src/Neo.CLI/CLI/MainService.NEP17.cs b/src/Neo.CLI/CLI/MainService.NEP17.cs index 34de5e58e5..17d62ff4d2 100644 --- a/src/Neo.CLI/CLI/MainService.NEP17.cs +++ b/src/Neo.CLI/CLI/MainService.NEP17.cs @@ -16,7 +16,6 @@ using Neo.VM.Types; using Neo.Wallets; using System; -using System.Collections.Generic; using System.Linq; using Array = System.Array; @@ -34,7 +33,7 @@ partial class MainService /// Data /// Signer's accounts [ConsoleCommand("transfer", Category = "NEP17 Commands")] - private void OnTransferCommand(UInt160 tokenHash, UInt160 to, decimal amount, UInt160 from = null, string data = null, UInt160[] signersAccounts = null) + private void OnTransferCommand(UInt160 tokenHash, UInt160 to, decimal amount, UInt160? from = null, string? data = null, UInt160[]? signersAccounts = null) { var snapshot = NeoSystem.StoreView; var asset = new AssetDescriptor(snapshot, NeoSystem.Settings, tokenHash); @@ -45,7 +44,7 @@ private void OnTransferCommand(UInt160 tokenHash, UInt160 to, decimal amount, UI Transaction tx; try { - tx = CurrentWallet.MakeTransaction(snapshot, new[] + tx = CurrentWallet!.MakeTransaction(snapshot, new[] { new TransferOutput { diff --git a/src/Neo.CLI/CLI/MainService.Native.cs b/src/Neo.CLI/CLI/MainService.Native.cs index 189168b73e..0cdf1ca45c 100644 --- a/src/Neo.CLI/CLI/MainService.Native.cs +++ b/src/Neo.CLI/CLI/MainService.Native.cs @@ -10,7 +10,6 @@ using Neo.ConsoleService; using Neo.SmartContract.Native; -using System; using System.Linq; namespace Neo.CLI diff --git a/src/Neo.CLI/CLI/MainService.Plugins.cs b/src/Neo.CLI/CLI/MainService.Plugins.cs index f126eef996..169df18a25 100644 --- a/src/Neo.CLI/CLI/MainService.Plugins.cs +++ b/src/Neo.CLI/CLI/MainService.Plugins.cs @@ -72,26 +72,27 @@ private async Task DownloadPluginAsync(string pluginName) if (response.StatusCode == HttpStatusCode.NotFound) { response.Dispose(); - Version versionCore = typeof(Plugin).Assembly.GetName().Version; + Version versionCore = typeof(Plugin).Assembly.GetName().Version!; HttpRequestMessage request = new(HttpMethod.Get, "https://api.github.com/repos/neo-project/neo-modules/releases"); request.Headers.UserAgent.ParseAdd( $"{GetType().Assembly.GetName().Name}/{GetType().Assembly.GetVersion()}"); using HttpResponseMessage responseApi = await http.SendAsync(request); byte[] buffer = await responseApi.Content.ReadAsByteArrayAsync(); - var releases = JObject.Parse(buffer); - var asset = ((JArray)releases) - .Where(p => !p["tag_name"].GetString().Contains('-')) + if (JToken.Parse(buffer) is not JArray arr) throw new Exception("Plugin doesn't exist."); + var asset = arr + .Where(p => p?["tag_name"] is not null && p?["assets"] is not null) + .Where(p => !p!["tag_name"]!.GetString().Contains('-')) .Select(p => new { - Version = Version.Parse(p["tag_name"].GetString().TrimStart('v')), - Assets = (JArray)p["assets"] + Version = Version.Parse(p!["tag_name"]!.GetString().TrimStart('v')), + Assets = p["assets"] as JArray }) .OrderByDescending(p => p.Version) - .First(p => p.Version <= versionCore).Assets - .FirstOrDefault(p => p["name"].GetString() == $"{pluginName}.zip"); + .First(p => p.Version <= versionCore).Assets? + .FirstOrDefault(p => p?["name"]?.GetString() == $"{pluginName}.zip"); if (asset is null) throw new Exception("Plugin doesn't exist."); - response = await http.GetAsync(asset["browser_download_url"].GetString()); + response = await http.GetAsync(asset["browser_download_url"]?.GetString()); } using (response) @@ -121,7 +122,7 @@ private async Task DownloadPluginAsync(string pluginName) /// Name of the plugin /// Dependency set /// Install by force for `update` - private async Task InstallPluginAsync(string pluginName, HashSet installed = null, + private async Task InstallPluginAsync(string pluginName, HashSet? installed = null, bool overWrite = false) { installed ??= new HashSet(); @@ -135,7 +136,7 @@ private async Task InstallPluginAsync(string pluginName, HashSet install } using ZipArchive zip = new(stream, ZipArchiveMode.Read); - ZipArchiveEntry entry = zip.Entries.FirstOrDefault(p => p.Name == "config.json"); + ZipArchiveEntry? entry = zip.Entries.FirstOrDefault(p => p.Name == "config.json"); if (entry is not null) { await using Stream es = entry.Open(); @@ -160,10 +161,10 @@ private async Task InstallDependenciesAsync(Stream config, HashSet insta var dependencies = dependency.GetChildren().Select(p => p.Get()).ToArray(); if (dependencies.Length == 0) return; - foreach (string plugin in dependencies.Where(p => !PluginExists(p))) + foreach (string? plugin in dependencies.Where(p => p is not null && !PluginExists(p))) { ConsoleHelper.Info($"Installing dependency: {plugin}"); - await InstallPluginAsync(plugin, installed); + await InstallPluginAsync(plugin!, installed); } } @@ -201,7 +202,7 @@ private void OnUnInstallCommand(string pluginName) .GetSection("Dependency") .GetChildren() .Select(d => d.Get()) - .Any(v => v.Equals(pluginName, StringComparison.InvariantCultureIgnoreCase))) + .Any(v => v is not null && v.Equals(pluginName, StringComparison.InvariantCultureIgnoreCase))) { ConsoleHelper.Error( $"Can not uninstall. Other plugins depend on this plugin, try `reinstall {pluginName}` if the plugin is broken."); diff --git a/src/Neo.CLI/CLI/MainService.Tools.cs b/src/Neo.CLI/CLI/MainService.Tools.cs index 0136617729..870f0261a9 100644 --- a/src/Neo.CLI/CLI/MainService.Tools.cs +++ b/src/Neo.CLI/CLI/MainService.Tools.cs @@ -26,7 +26,7 @@ partial class MainService [ConsoleCommand("parse", Category = "Base Commands", Description = "Parse a value to its possible conversions.")] private void OnParseCommand(string value) { - var parseFunctions = new Dictionary>() + var parseFunctions = new Dictionary>() { { "Address to ScriptHash", AddressToScripthash }, { "Address to Base64", AddressToBase64 }, @@ -73,7 +73,7 @@ private void OnParseCommand(string value) /// string or when the converted string is not printable; otherwise, returns /// the string represented by the hexadecimal value /// - private string HexToString(string hexString) + private string? HexToString(string hexString) { try { @@ -98,7 +98,7 @@ private string HexToString(string hexString) /// Returns null when is not possible to parse the hex value to big integer value; /// otherwise, returns the string that represents the converted big integer. /// - private string HexToNumber(string hexString) + private string? HexToNumber(string hexString) { try { @@ -169,7 +169,7 @@ private string ClearHexString(string hexString) /// Returns null when it is not possible to parse the string value to a hexadecimal /// value; otherwise returns the hexadecimal value that represents the converted string /// - private string StringToHex(string strParam) + private string? StringToHex(string strParam) { try { @@ -195,7 +195,7 @@ private string StringToHex(string strParam) /// /// Throw . /// - private string StringToBase64(string strParam) + private string? StringToBase64(string strParam) { try { @@ -220,7 +220,7 @@ private string StringToBase64(string strParam) /// it is not possible to parse the big integer value to hexadecimal; otherwise, /// returns the string that represents the converted hexadecimal value /// - private string NumberToHex(string strParam) + private string? NumberToHex(string strParam) { try { @@ -247,7 +247,7 @@ private string NumberToHex(string strParam) /// it is not possible to parse the big integer value to Base64 value; otherwise, /// returns the string that represents the converted Base64 value /// - private string NumberToBase64(string strParam) + private string? NumberToBase64(string strParam) { try { @@ -277,7 +277,7 @@ private string NumberToBase64(string strParam) /// it is not possible to parse the address to scripthash; otherwise returns /// the string that represents the converted scripthash /// - private string AddressToScripthash(string address) + private string? AddressToScripthash(string address) { try { @@ -302,7 +302,7 @@ private string AddressToScripthash(string address) /// not possible to parse the address to Base64 value; otherwise returns /// the string that represents the converted Base64 value. /// - private string AddressToBase64(string address) + private string? AddressToBase64(string address) { try { @@ -327,7 +327,7 @@ private string AddressToBase64(string address) /// Returns null when the string does not represent an scripthash; /// otherwise, returns the string that represents the converted address /// - private string ScripthashToAddress(string script) + private string? ScripthashToAddress(string script) { try { @@ -372,7 +372,7 @@ private string ScripthashToAddress(string script) /// it is not possible to parse the Base64 value to address; otherwise, /// returns the string that represents the converted address /// - private string Base64ToAddress(string bytearray) + private string? Base64ToAddress(string bytearray) { try { @@ -405,7 +405,7 @@ private string Base64ToAddress(string bytearray) /// string is not printable; otherwise, returns the string that represents /// the Base64 value. /// - private string Base64ToString(string bytearray) + private string? Base64ToString(string bytearray) { try { @@ -430,7 +430,7 @@ private string Base64ToString(string bytearray) /// it is not possible to parse the Base64 value to big integer value; otherwise /// returns the string that represents the converted big integer /// - private string Base64ToNumber(string bytearray) + private string? Base64ToNumber(string bytearray) { try { diff --git a/src/Neo.CLI/CLI/MainService.Vote.cs b/src/Neo.CLI/CLI/MainService.Vote.cs index aa23562eb9..67f37b648e 100644 --- a/src/Neo.CLI/CLI/MainService.Vote.cs +++ b/src/Neo.CLI/CLI/MainService.Vote.cs @@ -17,7 +17,6 @@ using Neo.VM.Types; using Neo.Wallets; using System; -using System.Linq; using System.Numerics; namespace Neo.CLI @@ -33,7 +32,7 @@ private void OnRegisterCandidateCommand(UInt160 account) { var testGas = NativeContract.NEO.GetRegisterPrice(NeoSystem.StoreView) + (BigInteger)Math.Pow(10, NativeContract.GAS.Decimals) * 10; if (NoWallet()) return; - WalletAccount currentAccount = CurrentWallet.GetAccount(account); + WalletAccount currentAccount = CurrentWallet!.GetAccount(account); if (currentAccount == null) { @@ -49,9 +48,9 @@ private void OnRegisterCandidateCommand(UInt160 account) } } - ECPoint publicKey = currentAccount.GetKey()?.PublicKey; + ECPoint? publicKey = currentAccount.GetKey()?.PublicKey; byte[] script; - using (ScriptBuilder scriptBuilder = new ScriptBuilder()) + using (ScriptBuilder scriptBuilder = new()) { scriptBuilder.EmitDynamicCall(NativeContract.NEO.Hash, "registerCandidate", publicKey); script = scriptBuilder.ToArray(); @@ -68,7 +67,7 @@ private void OnRegisterCandidateCommand(UInt160 account) private void OnUnregisterCandidateCommand(UInt160 account) { if (NoWallet()) return; - WalletAccount currentAccount = CurrentWallet.GetAccount(account); + WalletAccount currentAccount = CurrentWallet!.GetAccount(account); if (currentAccount == null) { @@ -84,9 +83,9 @@ private void OnUnregisterCandidateCommand(UInt160 account) } } - ECPoint publicKey = currentAccount?.GetKey()?.PublicKey; + ECPoint? publicKey = currentAccount?.GetKey()?.PublicKey; byte[] script; - using (ScriptBuilder scriptBuilder = new ScriptBuilder()) + using (ScriptBuilder scriptBuilder = new()) { scriptBuilder.EmitDynamicCall(NativeContract.NEO.Hash, "unregisterCandidate", publicKey); script = scriptBuilder.ToArray(); @@ -105,7 +104,7 @@ private void OnVoteCommand(UInt160 senderAccount, ECPoint publicKey) { if (NoWallet()) return; byte[] script; - using (ScriptBuilder scriptBuilder = new ScriptBuilder()) + using (ScriptBuilder scriptBuilder = new()) { scriptBuilder.EmitDynamicCall(NativeContract.NEO.Hash, "vote", senderAccount, publicKey); script = scriptBuilder.ToArray(); @@ -123,7 +122,7 @@ private void OnUnvoteCommand(UInt160 senderAccount) { if (NoWallet()) return; byte[] script; - using (ScriptBuilder scriptBuilder = new ScriptBuilder()) + using (ScriptBuilder scriptBuilder = new()) { scriptBuilder.EmitDynamicCall(NativeContract.NEO.Hash, "vote", senderAccount, null); script = scriptBuilder.ToArray(); @@ -150,9 +149,10 @@ private void OnGetCandidatesCommand() foreach (var item in resJArray) { var value = (VM.Types.Array)item; + if (value is null) continue; - Console.Write(((ByteString)value?[0])?.GetSpan().ToHexString() + "\t"); - Console.WriteLine(((Integer)value?[1]).GetInteger()); + Console.Write(((ByteString)value[0])?.GetSpan().ToHexString() + "\t"); + Console.WriteLine(((Integer)value[1]).GetInteger()); } } } @@ -222,6 +222,12 @@ private void OnGetAccountState(UInt160 address) return; } var resJArray = (VM.Types.Array)result; + if (resJArray is null) + { + ConsoleHelper.Warning(notice); + return; + } + foreach (StackItem value in resJArray) { if (value.IsNull) @@ -230,10 +236,10 @@ private void OnGetAccountState(UInt160 address) return; } } - var publickey = ECPoint.Parse(((ByteString)resJArray?[2])?.GetSpan().ToHexString(), ECCurve.Secp256r1); + var publickey = ECPoint.Parse(((ByteString)resJArray[2])?.GetSpan().ToHexString(), ECCurve.Secp256r1); ConsoleHelper.Info("Voted: ", Contract.CreateSignatureRedeemScript(publickey).ToScriptHash().ToAddress(NeoSystem.Settings.AddressVersion)); - ConsoleHelper.Info("Amount: ", new BigDecimal(((Integer)resJArray?[0]).GetInteger(), NativeContract.NEO.Decimals).ToString()); - ConsoleHelper.Info("Block: ", ((Integer)resJArray?[1]).GetInteger().ToString()); + ConsoleHelper.Info("Amount: ", new BigDecimal(((Integer)resJArray[0]).GetInteger(), NativeContract.NEO.Decimals).ToString()); + ConsoleHelper.Info("Block: ", ((Integer)resJArray[1]).GetInteger().ToString()); } } } diff --git a/src/Neo.CLI/CLI/MainService.Wallet.cs b/src/Neo.CLI/CLI/MainService.Wallet.cs index f916ea1bbc..48531f1f4e 100644 --- a/src/Neo.CLI/CLI/MainService.Wallet.cs +++ b/src/Neo.CLI/CLI/MainService.Wallet.cs @@ -124,7 +124,7 @@ private void OnCreateAddressCommand(ushort count = 1) { Parallel.For(0, count, (i) => { - WalletAccount account = CurrentWallet.CreateAccount(); + WalletAccount account = CurrentWallet!.CreateAccount(); lock (addresses) { addresses.Add(account.Address); @@ -151,7 +151,7 @@ private void OnDeleteAddressCommand(UInt160 address) if (ReadUserInput($"Warning: Irrevocable operation!\nAre you sure to delete account {address.ToAddress(NeoSystem.Settings.AddressVersion)}? (no|yes)").IsYes()) { - if (CurrentWallet.DeleteAccount(address)) + if (CurrentWallet!.DeleteAccount(address)) { if (CurrentWallet is NEP6Wallet wallet) { @@ -172,7 +172,7 @@ private void OnDeleteAddressCommand(UInt160 address) /// Path /// ScriptHash [ConsoleCommand("export key", Category = "Wallet Commands")] - private void OnExportKeyCommand(string path = null, UInt160 scriptHash = null) + private void OnExportKeyCommand(string? path = null, UInt160? scriptHash = null) { if (NoWallet()) return; if (path != null && File.Exists(path)) @@ -186,7 +186,7 @@ private void OnExportKeyCommand(string path = null, UInt160 scriptHash = null) ConsoleHelper.Info("Cancelled"); return; } - if (!CurrentWallet.VerifyPassword(password)) + if (!CurrentWallet!.VerifyPassword(password)) { ConsoleHelper.Error("Incorrect password"); return; @@ -210,7 +210,7 @@ private void OnExportKeyCommand(string path = null, UInt160 scriptHash = null) /// Process "create wallet" command /// [ConsoleCommand("create wallet", Category = "Wallet Commands")] - private void OnCreateWalletCommand(string path, string wifOrFile = null) + private void OnCreateWalletCommand(string path, string? wifOrFile = null) { string password = ReadUserInput("password", true); if (password.Length == 0) @@ -231,7 +231,7 @@ private void OnCreateWalletCommand(string path, string wifOrFile = null) } bool createDefaultAccount = wifOrFile is null; CreateWallet(path, password, createDefaultAccount); - if (!createDefaultAccount) OnImportKeyCommand(wifOrFile); + if (!createDefaultAccount) OnImportKeyCommand(wifOrFile!); } /// @@ -252,7 +252,7 @@ private void OnImportMultisigAddress(ushort m, ECPoint[] publicKeys) } Contract multiSignContract = Contract.CreateMultiSigContract(m, publicKeys); - KeyPair keyPair = CurrentWallet.GetAccounts().FirstOrDefault(p => p.HasKey && publicKeys.Contains(p.GetKey().PublicKey))?.GetKey(); + KeyPair? keyPair = CurrentWallet!.GetAccounts().FirstOrDefault(p => p.HasKey && publicKeys.Contains(p.GetKey().PublicKey))?.GetKey(); CurrentWallet.CreateAccount(multiSignContract, keyPair); if (CurrentWallet is NEP6Wallet wallet) @@ -268,7 +268,7 @@ private void OnImportMultisigAddress(ushort m, ECPoint[] publicKeys) private void OnImportKeyCommand(string wifOrFile) { if (NoWallet()) return; - byte[] prikey = null; + byte[]? prikey = null; try { prikey = Wallet.GetPrivateKeyFromWIF(wifOrFile); @@ -301,7 +301,7 @@ private void OnImportKeyCommand(string wifOrFile) prikey = lines[i].HexToBytes(); else prikey = Wallet.GetPrivateKeyFromWIF(lines[i]); - CurrentWallet.CreateAccount(prikey); + CurrentWallet!.CreateAccount(prikey); Array.Clear(prikey, 0, prikey.Length); percent.Value++; } @@ -309,7 +309,7 @@ private void OnImportKeyCommand(string wifOrFile) } else { - WalletAccount account = CurrentWallet.CreateAccount(prikey); + WalletAccount account = CurrentWallet!.CreateAccount(prikey); Array.Clear(prikey, 0, prikey.Length); ConsoleHelper.Info("Address: ", account.Address); ConsoleHelper.Info(" Pubkey: ", account.GetKey().PublicKey.EncodePoint(true).ToHexString()); @@ -325,7 +325,7 @@ private void OnImportKeyCommand(string wifOrFile) private void OnImportWatchOnlyCommand(string addressOrFile) { if (NoWallet()) return; - UInt160 address = null; + UInt160? address = null; try { address = StringToAddress(addressOrFile, NeoSystem.Settings.AddressVersion); @@ -355,14 +355,14 @@ private void OnImportWatchOnlyCommand(string addressOrFile) for (int i = 0; i < lines.Length; i++) { address = StringToAddress(lines[i], NeoSystem.Settings.AddressVersion); - CurrentWallet.CreateAccount(address); + CurrentWallet!.CreateAccount(address); percent.Value++; } } } else { - WalletAccount account = CurrentWallet.GetAccount(address); + WalletAccount account = CurrentWallet!.GetAccount(address); if (account is not null) { ConsoleHelper.Warning("This address is already in your wallet"); @@ -385,7 +385,7 @@ private void OnListAddressCommand() { if (NoWallet()) return; var snapshot = NeoSystem.StoreView; - foreach (var account in CurrentWallet.GetAccounts()) + foreach (var account in CurrentWallet!.GetAccounts()) { var contract = account.Contract; var type = "Nonstandard"; @@ -420,7 +420,7 @@ private void OnListAssetCommand() { var snapshot = NeoSystem.StoreView; if (NoWallet()) return; - foreach (UInt160 account in CurrentWallet.GetAccounts().Select(p => p.ScriptHash)) + foreach (UInt160 account in CurrentWallet!.GetAccounts().Select(p => p.ScriptHash)) { Console.WriteLine(account.ToAddress(NeoSystem.Settings.AddressVersion)); ConsoleHelper.Info("NEO: ", $"{CurrentWallet.GetBalance(snapshot, NativeContract.NEO.Hash, account)}"); @@ -441,7 +441,7 @@ private void OnListAssetCommand() private void OnListKeyCommand() { if (NoWallet()) return; - foreach (WalletAccount account in CurrentWallet.GetAccounts().Where(p => p.HasKey)) + foreach (WalletAccount account in CurrentWallet!.GetAccounts().Where(p => p.HasKey)) { ConsoleHelper.Info(" Address: ", account.Address); ConsoleHelper.Info("ScriptHash: ", account.ScriptHash.ToString()); @@ -468,12 +468,12 @@ private void OnSignCommand(JObject jsonObjectToSign) { var snapshot = NeoSystem.StoreView; ContractParametersContext context = ContractParametersContext.Parse(jsonObjectToSign.ToString(), snapshot); - if (context.Network != _neoSystem.Settings.Network) + if (context.Network != NeoSystem.Settings.Network) { ConsoleHelper.Warning("Network mismatch."); return; } - else if (!CurrentWallet.Sign(context)) + else if (!CurrentWallet!.Sign(context)) { ConsoleHelper.Warning("Non-existent private key in wallet."); return; @@ -496,7 +496,7 @@ private void OnSignCommand(JObject jsonObjectToSign) /// Data /// Signer's accounts [ConsoleCommand("send", Category = "Wallet Commands")] - private void OnSendCommand(UInt160 asset, UInt160 to, string amount, UInt160 from = null, string data = null, UInt160[] signerAccounts = null) + private void OnSendCommand(UInt160 asset, UInt160 to, string amount, UInt160? from = null, string? data = null, UInt160[]? signerAccounts = null) { if (NoWallet()) return; string password = ReadUserInput("password", true); @@ -505,7 +505,7 @@ private void OnSendCommand(UInt160 asset, UInt160 to, string amount, UInt160 fro ConsoleHelper.Info("Cancelled"); return; } - if (!CurrentWallet.VerifyPassword(password)) + if (!CurrentWallet!.VerifyPassword(password)) { ConsoleHelper.Error("Incorrect password"); return; @@ -567,8 +567,10 @@ private void OnSendCommand(UInt160 asset, UInt160 to, string amount, UInt160 fro /// Transaction's sender /// Signer's accounts [ConsoleCommand("cancel", Category = "Wallet Commands")] - private void OnCancelCommand(UInt256 txid, UInt160 sender = null, UInt160[] signerAccounts = null) + private void OnCancelCommand(UInt256 txid, UInt160? sender = null, UInt160[]? signerAccounts = null) { + if (NoWallet()) return; + TransactionState state = NativeContract.Ledger.GetTransactionState(NeoSystem.StoreView, txid); if (state != null) { @@ -578,7 +580,7 @@ private void OnCancelCommand(UInt256 txid, UInt160 sender = null, UInt160[] sign var conflict = new TransactionAttribute[] { new Conflicts() { Hash = txid } }; Signer[] signers = Array.Empty(); - if (!NoWallet() && sender != null) + if (sender != null) { if (signerAccounts == null) signerAccounts = new UInt160[1] { sender }; @@ -595,7 +597,7 @@ private void OnCancelCommand(UInt256 txid, UInt160 sender = null, UInt160[] sign signers = signerAccounts.Select(p => new Signer() { Account = p, Scopes = WitnessScope.None }).ToArray(); } - Transaction tx = new Transaction + Transaction tx = new() { Signers = signers, Attributes = conflict, @@ -606,7 +608,7 @@ private void OnCancelCommand(UInt256 txid, UInt160 sender = null, UInt160[] sign { using ScriptBuilder scriptBuilder = new(); scriptBuilder.Emit(OpCode.RET); - tx = CurrentWallet.MakeTransaction(NeoSystem.StoreView, scriptBuilder.ToArray(), sender, signers, conflict); + tx = CurrentWallet!.MakeTransaction(NeoSystem.StoreView, scriptBuilder.ToArray(), sender, signers, conflict); } catch (InvalidOperationException e) { @@ -652,7 +654,7 @@ private void OnShowGasCommand() BigInteger gas = BigInteger.Zero; var snapshot = NeoSystem.StoreView; uint height = NativeContract.Ledger.CurrentIndex(snapshot) + 1; - foreach (UInt160 account in CurrentWallet.GetAccounts().Select(p => p.ScriptHash)) + foreach (UInt160 account in CurrentWallet!.GetAccounts().Select(p => p.ScriptHash)) gas += NativeContract.NEO.UnclaimedGas(snapshot, account, height); ConsoleHelper.Info("Unclaimed gas: ", new BigDecimal(gas, NativeContract.GAS.Decimals).ToString()); } @@ -670,7 +672,7 @@ private void OnChangePasswordCommand() ConsoleHelper.Info("Cancelled"); return; } - if (!CurrentWallet.VerifyPassword(oldPassword)) + if (!CurrentWallet!.VerifyPassword(oldPassword)) { ConsoleHelper.Error("Incorrect password"); return; @@ -717,17 +719,19 @@ private void OnChangePasswordCommand() private void SignAndSendTx(DataCache snapshot, Transaction tx) { + if (NoWallet()) return; + ContractParametersContext context; try { - context = new ContractParametersContext(snapshot, tx, _neoSystem.Settings.Network); + context = new ContractParametersContext(snapshot, tx, NeoSystem.Settings.Network); } catch (InvalidOperationException e) { ConsoleHelper.Error("Failed creating contract params: " + GetExceptionMessage(e)); throw; } - CurrentWallet.Sign(context); + CurrentWallet!.Sign(context); if (context.Completed) { tx.Witnesses = context.GetWitnesses(); diff --git a/src/Neo.CLI/CLI/MainService.cs b/src/Neo.CLI/CLI/MainService.cs index 7beea39310..c097176340 100644 --- a/src/Neo.CLI/CLI/MainService.cs +++ b/src/Neo.CLI/CLI/MainService.cs @@ -40,14 +40,13 @@ namespace Neo.CLI { public partial class MainService : ConsoleServiceBase, IWalletProvider { - public event EventHandler WalletChanged; + public event EventHandler? WalletChanged = null; public const long TestModeGas = 20_00000000; - private Wallet _currentWallet; - public LocalNode LocalNode; + private Wallet? _currentWallet; - public Wallet CurrentWallet + public Wallet? CurrentWallet { get => _currentWallet; private set @@ -57,13 +56,21 @@ private set } } - private NeoSystem _neoSystem; + private NeoSystem? _neoSystem; public NeoSystem NeoSystem { - get => _neoSystem; + get => _neoSystem!; private set => _neoSystem = value; } + private LocalNode? _localNode; + + public LocalNode LocalNode + { + get => _localNode!; + private set => _localNode = value; + } + protected override string Prompt => "neo"; public override string ServiceName => "NEO-CLI"; @@ -78,8 +85,8 @@ public MainService() : base() RegisterCommandHandler(arr => arr.Select(str => StringToAddress(str, NeoSystem.Settings.AddressVersion)).ToArray()); RegisterCommandHandler(str => ECPoint.Parse(str.Trim(), ECCurve.Secp256r1)); RegisterCommandHandler(str => str.Select(u => ECPoint.Parse(u.Trim(), ECCurve.Secp256r1)).ToArray()); - RegisterCommandHandler(str => JToken.Parse(str)); - RegisterCommandHandler(str => (JObject)JToken.Parse(str)); + RegisterCommandHandler(str => JToken.Parse(str)!); + RegisterCommandHandler(str => (JObject)JToken.Parse(str)!); RegisterCommandHandler(str => decimal.Parse(str, CultureInfo.InvariantCulture)); RegisterCommandHandler(obj => (JArray)obj); @@ -108,7 +115,7 @@ internal static UInt160 StringToAddress(string input, byte version) return input.ToScriptHash(version); } - Wallet IWalletProvider.GetWallet() + Wallet? IWalletProvider.GetWallet() { return CurrentWallet; } @@ -117,9 +124,9 @@ 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(); + 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}"); Console.WriteLine(); @@ -172,17 +179,22 @@ private IEnumerable GetBlocksFromFile() { const string pathAcc = "chain.acc"; if (File.Exists(pathAcc)) - using (FileStream fs = new FileStream(pathAcc, FileMode.Open, FileAccess.Read, FileShare.Read)) + using (FileStream fs = new(pathAcc, FileMode.Open, FileAccess.Read, FileShare.Read)) foreach (var block in GetBlocks(fs)) yield return block; const string pathAccZip = pathAcc + ".zip"; if (File.Exists(pathAccZip)) - using (FileStream fs = new FileStream(pathAccZip, FileMode.Open, FileAccess.Read, FileShare.Read)) - using (ZipArchive zip = new ZipArchive(fs, ZipArchiveMode.Read)) - using (Stream zs = zip.GetEntry(pathAcc).Open()) - foreach (var block in GetBlocks(zs)) - yield return block; + using (FileStream fs = new(pathAccZip, FileMode.Open, FileAccess.Read, FileShare.Read)) + using (ZipArchive zip = new(fs, ZipArchiveMode.Read)) + using (Stream? zs = zip.GetEntry(pathAcc)?.Open()) + { + if (zs is not null) + { + foreach (var block in GetBlocks(zs)) + yield return block; + } + } var paths = Directory.EnumerateFiles(".", "chain.*.acc", SearchOption.TopDirectoryOnly).Concat(Directory.EnumerateFiles(".", "chain.*.acc.zip", SearchOption.TopDirectoryOnly)).Select(p => new { @@ -196,13 +208,18 @@ private IEnumerable GetBlocksFromFile() { if (path.Start > height + 1) break; if (path.IsCompressed) - using (FileStream fs = new FileStream(path.FileName, FileMode.Open, FileAccess.Read, FileShare.Read)) - using (ZipArchive zip = new ZipArchive(fs, ZipArchiveMode.Read)) - using (Stream zs = zip.GetEntry(Path.GetFileNameWithoutExtension(path.FileName)).Open()) - foreach (var block in GetBlocks(zs, true)) - yield return block; + using (FileStream fs = new(path.FileName, FileMode.Open, FileAccess.Read, FileShare.Read)) + using (ZipArchive zip = new(fs, ZipArchiveMode.Read)) + using (Stream? zs = zip.GetEntry(Path.GetFileNameWithoutExtension(path.FileName))?.Open()) + { + if (zs is not null) + { + foreach (var block in GetBlocks(zs, true)) + yield return block; + } + } else - using (FileStream fs = new FileStream(path.FileName, FileMode.Open, FileAccess.Read, FileShare.Read)) + using (FileStream fs = new(path.FileName, FileMode.Open, FileAccess.Read, FileShare.Read)) foreach (var block in GetBlocks(fs, true)) yield return block; } @@ -215,7 +232,7 @@ private bool NoWallet() return true; } - private byte[] LoadDeploymentScript(string nefFilePath, string manifestFilePath, JObject data, out NefFile nef, out ContractManifest manifest) + private byte[] LoadDeploymentScript(string nefFilePath, string? manifestFilePath, JObject? data, out NefFile nef, out ContractManifest manifest) { if (string.IsNullOrEmpty(manifestFilePath)) { @@ -242,7 +259,7 @@ private byte[] LoadDeploymentScript(string nefFilePath, string manifestFilePath, nef = File.ReadAllBytes(nefFilePath).AsSerializable(); - ContractParameter dataParameter = null; + ContractParameter? dataParameter = null; if (data is not null) try { @@ -268,7 +285,7 @@ private byte[] LoadDeploymentScript(string nefFilePath, string manifestFilePath, } } - private byte[] LoadUpdateScript(UInt160 scriptHash, string nefFilePath, string manifestFilePath, JObject data, out NefFile nef, out ContractManifest manifest) + private byte[] LoadUpdateScript(UInt160 scriptHash, string nefFilePath, string manifestFilePath, JObject? data, out NefFile nef, out ContractManifest manifest) { if (string.IsNullOrEmpty(manifestFilePath)) { @@ -295,7 +312,7 @@ private byte[] LoadUpdateScript(UInt160 scriptHash, string nefFilePath, string m nef = File.ReadAllBytes(nefFilePath).AsSerializable(); - ContractParameter dataParameter = null; + ContractParameter? dataParameter = null; if (data is not null) try { @@ -402,6 +419,15 @@ public async void Start(string[] args) { try { + if (Settings.Default.UnlockWallet.Path is null) + { + throw new InvalidOperationException("UnlockWallet.Path must be defined"); + } + else if (Settings.Default.UnlockWallet.Password is null) + { + throw new InvalidOperationException("UnlockWallet.Password must be defined"); + } + OpenWallet(Settings.Default.UnlockWallet.Path, Settings.Default.UnlockWallet.Password); } catch (FileNotFoundException) @@ -485,14 +511,16 @@ private static void WriteLineWithoutFlicker(string message = "", int maxWidth = /// script /// sender /// Max fee for running the script - private void SendTransaction(byte[] script, UInt160 account = null, long gas = TestModeGas) + private void SendTransaction(byte[] script, UInt160? account = null, long gas = TestModeGas) { + if (NoWallet()) return; + Signer[] signers = Array.Empty(); var snapshot = NeoSystem.StoreView; if (account != null) { - signers = CurrentWallet.GetAccounts() + signers = CurrentWallet!.GetAccounts() .Where(p => !p.Lock && !p.WatchOnly && p.ScriptHash == account && NativeContract.GAS.BalanceOf(snapshot, p.ScriptHash).Sign > 0) .Select(p => new Signer { Account = p.ScriptHash, Scopes = WitnessScope.CalledByEntry }) .ToArray(); @@ -500,7 +528,7 @@ private void SendTransaction(byte[] script, UInt160 account = null, long gas = T try { - Transaction tx = CurrentWallet.MakeTransaction(snapshot, script, account, signers, maxGas: gas); + Transaction tx = CurrentWallet!.MakeTransaction(snapshot, script, account, signers, maxGas: gas); ConsoleHelper.Info("Invoking script with: ", $"'{Convert.ToBase64String(tx.Script.Span)}'"); using (ApplicationEngine engine = ApplicationEngine.Run(tx.Script, snapshot, container: tx, settings: NeoSystem.Settings, gas: gas)) @@ -533,15 +561,18 @@ private void SendTransaction(byte[] script, UInt160 account = null, long gas = T /// Show result stack if it is true /// Max fee for running the script /// Return true if it was successful - private bool OnInvokeWithResult(UInt160 scriptHash, string operation, out StackItem result, IVerifiable verifiable = null, JArray contractParameters = null, bool showStack = true, long gas = TestModeGas) + private bool OnInvokeWithResult(UInt160 scriptHash, string operation, out StackItem result, IVerifiable? verifiable = null, JArray? contractParameters = null, bool showStack = true, long gas = TestModeGas) { - List parameters = new List(); + List parameters = new(); if (contractParameters != null) { foreach (var contractParameter in contractParameters) { - parameters.Add(ContractParameter.FromJson((JObject)contractParameter)); + if (contractParameter is not null) + { + parameters.Add(ContractParameter.FromJson((JObject)contractParameter)); + } } } @@ -578,7 +609,7 @@ private bool OnInvokeWithResult(UInt160 scriptHash, string operation, out StackI using ApplicationEngine engine = ApplicationEngine.Run(script, NeoSystem.StoreView, container: verifiable, settings: NeoSystem.Settings, gas: gas); PrintExecutionOutput(engine, showStack); - result = engine.State == VMState.FAULT ? null : engine.ResultStack.Peek(); + result = engine.State == VMState.FAULT ? StackItem.Null : engine.ResultStack.Peek(); return engine.State != VMState.FAULT; } diff --git a/src/Neo.CLI/Extensions.cs b/src/Neo.CLI/Extensions.cs index d3dd1aa5ed..dec28a8e0d 100644 --- a/src/Neo.CLI/Extensions.cs +++ b/src/Neo.CLI/Extensions.cs @@ -20,9 +20,9 @@ internal static class Extensions { public static string GetVersion(this Assembly assembly) { - CustomAttributeData attribute = assembly.CustomAttributes.FirstOrDefault(p => p.AttributeType == typeof(AssemblyInformationalVersionAttribute)); - if (attribute == null) return assembly.GetName().Version.ToString(3); - return (string)attribute.ConstructorArguments[0].Value; + CustomAttributeData? attribute = assembly.CustomAttributes.FirstOrDefault(p => p.AttributeType == typeof(AssemblyInformationalVersionAttribute)); + if (attribute == null) return assembly.GetName().Version?.ToString(3) ?? string.Empty; + return (string)attribute.ConstructorArguments[0].Value!; } } } diff --git a/src/Neo.CLI/Neo.CLI.csproj b/src/Neo.CLI/Neo.CLI.csproj index 19f92a92cc..cd1b75fbc0 100644 --- a/src/Neo.CLI/Neo.CLI.csproj +++ b/src/Neo.CLI/Neo.CLI.csproj @@ -8,6 +8,7 @@ Neo Neo.CLI neo.ico + enable diff --git a/src/Neo.CLI/Settings.cs b/src/Neo.CLI/Settings.cs index ace4cb4863..df67a91237 100644 --- a/src/Neo.CLI/Settings.cs +++ b/src/Neo.CLI/Settings.cs @@ -21,7 +21,7 @@ public class Settings public P2PSettings P2P { get; } public UnlockWalletSettings UnlockWallet { get; } - static Settings _default; + static Settings? _default; static bool UpdateDefault(IConfiguration configuration) { @@ -44,7 +44,7 @@ public static Settings Default Initialize(config); } - return _default; + return _default!; } } @@ -65,7 +65,7 @@ public class LoggerSettings public LoggerSettings(IConfigurationSection section) { - this.Path = section.GetValue("Path", "Logs"); + this.Path = section.GetValue("Path", "Logs")!; this.ConsoleOutput = section.GetValue("ConsoleOutput", false); this.Active = section.GetValue("Active", false); } @@ -78,8 +78,8 @@ public class StorageSettings public StorageSettings(IConfigurationSection section) { - this.Engine = section.GetValue("Engine", "LevelDBStore"); - this.Path = section.GetValue("Path", "Data_LevelDB_{0}"); + this.Engine = section.GetValue("Engine", "LevelDBStore")!; + this.Path = section.GetValue("Path", "Data_LevelDB_{0}")!; } } @@ -93,8 +93,8 @@ public class P2PSettings public P2PSettings(IConfigurationSection section) { - this.Port = ushort.Parse(section.GetValue("Port", "10333")); - this.WsPort = ushort.Parse(section.GetValue("WsPort", "10334")); + this.Port = ushort.Parse(section.GetValue("Port", "10333")!); + this.WsPort = ushort.Parse(section.GetValue("WsPort", "10334")!); this.MinDesiredConnections = section.GetValue("MinDesiredConnections", Peer.DefaultMinDesiredConnections); this.MaxConnections = section.GetValue("MaxConnections", Peer.DefaultMaxConnections); this.MaxConnectionsPerAddress = section.GetValue("MaxConnectionsPerAddress", 3); @@ -103,8 +103,8 @@ public P2PSettings(IConfigurationSection section) public class UnlockWalletSettings { - public string Path { get; } - public string Password { get; } + public string? Path { get; } + public string? Password { get; } public bool IsActive { get; } public UnlockWalletSettings(IConfigurationSection section) @@ -113,7 +113,7 @@ public UnlockWalletSettings(IConfigurationSection section) { this.Path = section.GetValue("Path", ""); this.Password = section.GetValue("Password", ""); - this.IsActive = bool.Parse(section.GetValue("IsActive", "false")); + this.IsActive = bool.Parse(section.GetValue("IsActive", "false")!); } } } diff --git a/src/Neo.ConsoleService/CommandStringToken.cs b/src/Neo.ConsoleService/CommandStringToken.cs index c22d989996..f4ee1e6c97 100644 --- a/src/Neo.ConsoleService/CommandStringToken.cs +++ b/src/Neo.ConsoleService/CommandStringToken.cs @@ -39,7 +39,7 @@ public CommandStringToken(int offset, string value) : base(CommandTokenType.Stri /// Index /// Quote (could be null) /// CommandSpaceToken - internal static CommandStringToken Parse(string commandLine, ref int index, CommandQuoteToken quote) + internal static CommandStringToken Parse(string commandLine, ref int index, CommandQuoteToken? quote) { int end; int offset = index; diff --git a/src/Neo.ConsoleService/CommandToken.cs b/src/Neo.ConsoleService/CommandToken.cs index a8b8a47fd6..d4088e8c9b 100644 --- a/src/Neo.ConsoleService/CommandToken.cs +++ b/src/Neo.ConsoleService/CommandToken.cs @@ -29,7 +29,7 @@ internal abstract class CommandToken /// /// Value /// - public string Value { get; protected init; } + public string Value { get; protected init; } = string.Empty; /// /// Constructor @@ -49,7 +49,7 @@ protected CommandToken(CommandTokenType type, int offset) /// public static IEnumerable Parse(string commandLine) { - CommandToken lastToken = null; + CommandToken? lastToken = null; for (int index = 0, count = commandLine.Length; index < count;) { @@ -79,7 +79,10 @@ public static IEnumerable Parse(string commandLine) lastToken = CommandStringToken.Parse(commandLine, ref index, lastToken is CommandQuoteToken quote ? quote : null); - yield return lastToken; + if (lastToken is not null) + { + yield return lastToken; + } break; } } @@ -96,7 +99,7 @@ public static string[] ToArguments(IEnumerable tokens, bool remove { var list = new List(); - CommandToken lastToken = null; + CommandToken? lastToken = null; foreach (var token in tokens) { @@ -164,7 +167,7 @@ public static void Trim(List args) /// Args /// Consume all if not quoted /// String - public static string ReadString(List args, bool consumeAll) + public static string? ReadString(List args, bool consumeAll) { Trim(args); diff --git a/src/Neo.ConsoleService/ConsoleCommandAttribute.cs b/src/Neo.ConsoleService/ConsoleCommandAttribute.cs index b880c03bec..0d18a5d1db 100644 --- a/src/Neo.ConsoleService/ConsoleCommandAttribute.cs +++ b/src/Neo.ConsoleService/ConsoleCommandAttribute.cs @@ -26,12 +26,12 @@ public class ConsoleCommandAttribute : Attribute /// /// Category /// - public string Category { get; set; } + public string Category { get; set; } = string.Empty; /// /// Description /// - public string Description { get; set; } + public string Description { get; set; } = string.Empty; /// /// Constructor diff --git a/src/Neo.ConsoleService/ConsoleServiceBase.cs b/src/Neo.ConsoleService/ConsoleServiceBase.cs index ae55b5fd76..8b4a54bdf3 100644 --- a/src/Neo.ConsoleService/ConsoleServiceBase.cs +++ b/src/Neo.ConsoleService/ConsoleServiceBase.cs @@ -26,7 +26,7 @@ namespace Neo.ConsoleService { public abstract class ConsoleServiceBase { - protected virtual string Depends => null; + protected virtual string? Depends => null; protected virtual string Prompt => "service"; public abstract string ServiceName { get; } @@ -48,9 +48,9 @@ private bool OnCommand(string commandLine) return true; } - string possibleHelp = null; + string? possibleHelp = null; var commandArgs = CommandToken.Parse(commandLine).ToArray(); - var availableCommands = new List<(ConsoleCommandMethod Command, object[] Arguments)>(); + var availableCommands = new List<(ConsoleCommandMethod Command, object?[] Arguments)>(); foreach (var entries in _verbs.Values) { @@ -58,7 +58,7 @@ private bool OnCommand(string commandLine) { if (command.IsThisCommand(commandArgs, out var consumedArgs)) { - var arguments = new List(); + var arguments = new List(); var args = commandArgs.Skip(consumedArgs).ToList(); CommandSpaceToken.Trim(args); @@ -114,7 +114,7 @@ private bool OnCommand(string commandLine) case 1: { var (command, arguments) = availableCommands[0]; - object result = command.Method.Invoke(command.Instance, arguments); + object? result = command.Method.Invoke(command.Instance, arguments); if (result is Task task) task.Wait(); return true; } @@ -127,7 +127,7 @@ private bool OnCommand(string commandLine) } } - private bool TryProcessValue(Type parameterType, List args, bool canConsumeAll, out object value) + private bool TryProcessValue(Type parameterType, List args, bool canConsumeAll, out object? value) { if (args.Count > 0) { @@ -140,8 +140,11 @@ private bool TryProcessValue(Type parameterType, List args, bool c if (parameterType.IsEnum) { var arg = CommandToken.ReadString(args, canConsumeAll); - value = Enum.Parse(parameterType, arg.Trim(), true); - return true; + if (arg is not null) + { + value = Enum.Parse(parameterType, arg.Trim(), true); + return true; + } } } @@ -198,7 +201,7 @@ protected void OnHelpCommand(string key) if (string.IsNullOrEmpty(key) || key.Equals("help", StringComparison.InvariantCultureIgnoreCase)) { - string last = null; + string? last = null; foreach (var command in withHelp) { if (last != command.HelpCategory) @@ -218,8 +221,8 @@ protected void OnHelpCommand(string key) { // Show help for this specific command - string last = null; - string lastKey = null; + string? last = null; + string? lastKey = null; bool found = false; foreach (var command in withHelp.Where(u => u.Key == key)) @@ -267,7 +270,7 @@ protected void OnClear() [ConsoleCommand("version", Category = "Base Commands", Description = "Show the current version.")] protected void OnVersion() { - Console.WriteLine(Assembly.GetEntryAssembly().GetName().Version); + Console.WriteLine(Assembly.GetEntryAssembly()!.GetName().Version); } /// @@ -391,7 +394,7 @@ private void SigTermEventHandler(AssemblyLoadContext obj) TriggerGracefulShutdown(); } - private void CancelHandler(object sender, ConsoleCancelEventArgs e) + private void CancelHandler(object? sender, ConsoleCancelEventArgs e) { e.Cancel = true; TriggerGracefulShutdown(); @@ -404,7 +407,7 @@ protected ConsoleServiceBase() { // Register self commands - RegisterCommandHandler(CommandToken.ReadString); + RegisterCommandHandler((args, canConsumeAll) => CommandToken.ReadString(args, canConsumeAll) ?? ""); RegisterCommandHandler((args, canConsumeAll) => { @@ -415,7 +418,7 @@ protected ConsoleServiceBase() return ret.Split(new[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); } - return CommandToken.ReadString(args, false).Split(',', ' '); + return (CommandToken.ReadString(args, false)?.Split(',', ' ')) ?? Array.Empty(); }); RegisterCommandHandler(false, str => byte.Parse(str)); @@ -471,7 +474,7 @@ public void RegisterCommandHandler(Func handler) /// /// Instance /// Name - public void RegisterCommand(object instance, string name = null) + public void RegisterCommand(object instance, string? name = null) { if (!string.IsNullOrEmpty(name)) { @@ -516,20 +519,27 @@ public void Run(string[] args) ConsoleHelper.Warning("Only support for installing services on Windows."); return; } - string arguments = string.Format("create {0} start= auto binPath= \"{1}\"", ServiceName, Process.GetCurrentProcess().MainModule.FileName); + string arguments = string.Format("create {0} start= auto binPath= \"{1}\"", ServiceName, Process.GetCurrentProcess().MainModule!.FileName); if (!string.IsNullOrEmpty(Depends)) { arguments += string.Format(" depend= {0}", Depends); } - Process process = Process.Start(new ProcessStartInfo + Process? process = Process.Start(new ProcessStartInfo { Arguments = arguments, FileName = Path.Combine(Environment.SystemDirectory, "sc.exe"), RedirectStandardOutput = true, UseShellExecute = false }); - process.WaitForExit(); - Console.Write(process.StandardOutput.ReadToEnd()); + if (process is null) + { + ConsoleHelper.Error("Error installing the service with sc.exe."); + } + else + { + process.WaitForExit(); + Console.Write(process.StandardOutput.ReadToEnd()); + } } else if (args.Length > 0 && args[0] == "/uninstall") { @@ -538,15 +548,22 @@ public void Run(string[] args) ConsoleHelper.Warning("Only support for installing services on Windows."); return; } - Process process = Process.Start(new ProcessStartInfo + Process? process = Process.Start(new ProcessStartInfo { Arguments = string.Format("delete {0}", ServiceName), FileName = Path.Combine(Environment.SystemDirectory, "sc.exe"), RedirectStandardOutput = true, UseShellExecute = false }); - process.WaitForExit(); - Console.Write(process.StandardOutput.ReadToEnd()); + if (process is null) + { + ConsoleHelper.Error("Error installing the service with sc.exe."); + } + else + { + process.WaitForExit(); + Console.Write(process.StandardOutput.ReadToEnd()); + } } else { @@ -562,9 +579,9 @@ public void Run(string[] args) } } - protected string ReadLine() + protected string? ReadLine() { - Task readLineTask = Task.Run(Console.ReadLine); + Task readLineTask = Task.Run(Console.ReadLine); try { @@ -600,7 +617,7 @@ public virtual void RunConsole() } Console.ForegroundColor = ConsoleColor.Yellow; - string line = ReadLine()?.Trim(); + string? line = ReadLine()?.Trim(); if (line == null) break; Console.ForegroundColor = ConsoleColor.White; diff --git a/src/Neo.ConsoleService/Neo.ConsoleService.csproj b/src/Neo.ConsoleService/Neo.ConsoleService.csproj index 173e3be4e0..5c2fd653ad 100644 --- a/src/Neo.ConsoleService/Neo.ConsoleService.csproj +++ b/src/Neo.ConsoleService/Neo.ConsoleService.csproj @@ -2,6 +2,7 @@ Neo.ConsoleService + enable From 13f506c286e83c38437c93cfa74ed0aaebf2802a Mon Sep 17 00:00:00 2001 From: Jimmy Date: Tue, 2 Jan 2024 17:05:00 +0800 Subject: [PATCH 035/168] Fix: Editconfig (#3023) * use roslyn editconfig * dotnet format on new editconfig * use roslyn editconfig * dotnet format on new editconfig * ignore IDE0060 * Update .editorconfig * Update .editorconfig * Update .editorconfig * fix format * Run code clean up with fixes * Fixed code format of code * Fixed readonly warnings * shargon's fixes * Remove goto * Remove globals.json --------- Co-authored-by: Christopher R Schuchardt Co-authored-by: Fernando Diaz Toledano --- .editorconfig | 287 +++++++++++++++++- SpellingExclusions.dic | 0 benchmarks/Neo.Benchmarks/Benchmarks.cs | 11 + benchmarks/Neo.Benchmarks/Program.cs | 11 + benchmarks/Neo.VM.Benchmarks/Benchmarks.cs | 11 + benchmarks/Neo.VM.Benchmarks/Program.cs | 11 + src/Neo.CLI/CLI/ConsolePercent.cs | 13 +- src/Neo.CLI/CLI/Helper.cs | 15 +- src/Neo.CLI/CLI/MainService.Blockchain.cs | 13 +- src/Neo.CLI/CLI/MainService.Contracts.cs | 13 +- src/Neo.CLI/CLI/MainService.Logger.cs | 11 +- src/Neo.CLI/CLI/MainService.NEP17.cs | 13 +- src/Neo.CLI/CLI/MainService.Native.cs | 13 +- src/Neo.CLI/CLI/MainService.Network.cs | 13 +- src/Neo.CLI/CLI/MainService.Node.cs | 13 +- src/Neo.CLI/CLI/MainService.Plugins.cs | 10 +- src/Neo.CLI/CLI/MainService.Tools.cs | 13 +- src/Neo.CLI/CLI/MainService.Vote.cs | 13 +- src/Neo.CLI/CLI/MainService.Wallet.cs | 13 +- src/Neo.CLI/CLI/MainService.cs | 13 +- src/Neo.CLI/Extensions.cs | 13 +- src/Neo.CLI/Program.cs | 13 +- src/Neo.CLI/Settings.cs | 13 +- src/Neo.ConsoleService/CommandQuoteToken.cs | 13 +- src/Neo.ConsoleService/CommandSpaceToken.cs | 13 +- src/Neo.ConsoleService/CommandStringToken.cs | 13 +- src/Neo.ConsoleService/CommandToken.cs | 13 +- src/Neo.ConsoleService/CommandTokenType.cs | 13 +- src/Neo.ConsoleService/ConsoleColorSet.cs | 13 +- .../ConsoleCommandAttribute.cs | 13 +- .../ConsoleCommandMethod.cs | 13 +- src/Neo.ConsoleService/ConsoleHelper.cs | 11 + src/Neo.ConsoleService/ConsoleServiceBase.cs | 13 +- .../Properties/AssemblyInfo.cs | 13 +- src/Neo.ConsoleService/ServiceProxy.cs | 13 +- src/Neo.GUI/GUI/BulkPayDialog.cs | 13 +- src/Neo.GUI/GUI/ChangePasswordDialog.cs | 13 +- src/Neo.GUI/GUI/ConsoleForm.cs | 13 +- .../GUI/CreateMultiSigContractDialog.cs | 13 +- src/Neo.GUI/GUI/CreateWalletDialog.cs | 13 +- src/Neo.GUI/GUI/DeployContractDialog.cs | 13 +- .../DeveloperToolsForm.ContractParameters.cs | 13 +- .../GUI/DeveloperToolsForm.TxBuilder.cs | 13 +- src/Neo.GUI/GUI/DeveloperToolsForm.cs | 13 +- src/Neo.GUI/GUI/ElectionDialog.cs | 13 +- src/Neo.GUI/GUI/Helper.cs | 14 +- src/Neo.GUI/GUI/ImportCustomContractDialog.cs | 13 +- src/Neo.GUI/GUI/ImportPrivateKeyDialog.cs | 13 +- src/Neo.GUI/GUI/InformationBox.cs | 13 +- src/Neo.GUI/GUI/InputBox.cs | 13 +- src/Neo.GUI/GUI/InvokeContractDialog.cs | 13 +- src/Neo.GUI/GUI/MainForm.cs | 13 +- src/Neo.GUI/GUI/OpenWalletDialog.cs | 13 +- src/Neo.GUI/GUI/ParametersEditor.cs | 13 +- src/Neo.GUI/GUI/PayToDialog.cs | 13 +- src/Neo.GUI/GUI/QueueReader.cs | 13 +- src/Neo.GUI/GUI/SigningDialog.cs | 13 +- src/Neo.GUI/GUI/SigningTxDialog.cs | 14 +- src/Neo.GUI/GUI/TextBoxWriter.cs | 13 +- src/Neo.GUI/GUI/TransferDialog.cs | 13 +- src/Neo.GUI/GUI/TxOutListBox.cs | 13 +- src/Neo.GUI/GUI/TxOutListBoxItem.cs | 13 +- src/Neo.GUI/GUI/UpdateDialog.cs | 13 +- src/Neo.GUI/GUI/ViewContractDialog.cs | 15 +- src/Neo.GUI/GUI/ViewPrivateKeyDialog.cs | 13 +- src/Neo.GUI/GUI/VotingDialog.cs | 13 +- src/Neo.GUI/GUI/Wrappers/HexConverter.cs | 13 +- src/Neo.GUI/GUI/Wrappers/ScriptEditor.cs | 13 +- src/Neo.GUI/GUI/Wrappers/SignerWrapper.cs | 13 +- .../Wrappers/TransactionAttributeWrapper.cs | 13 +- .../GUI/Wrappers/TransactionWrapper.cs | 13 +- src/Neo.GUI/GUI/Wrappers/UIntBaseConverter.cs | 13 +- src/Neo.GUI/GUI/Wrappers/WitnessWrapper.cs | 13 +- src/Neo.GUI/IO/Actors/EventWrapper.cs | 13 +- src/Neo.GUI/Program.cs | 13 +- src/Neo.Json/JArray.cs | 13 +- src/Neo.Json/JBoolean.cs | 9 +- src/Neo.Json/JContainer.cs | 13 +- src/Neo.Json/JNumber.cs | 9 +- src/Neo.Json/JObject.cs | 13 +- src/Neo.Json/JPathToken.cs | 13 +- src/Neo.Json/JPathTokenType.cs | 13 +- src/Neo.Json/JString.cs | 9 +- src/Neo.Json/JToken.cs | 13 +- .../OrderedDictionary.KeyCollection.cs | 13 +- .../OrderedDictionary.ValueCollection.cs | 13 +- src/Neo.Json/OrderedDictionary.cs | 13 +- src/Neo.Json/Properties/AssemblyInfo.cs | 11 + src/Neo.Json/Utility.cs | 13 +- src/Neo.VM/BadScriptException.cs | 13 +- src/Neo.VM/CatchableException.cs | 13 +- src/Neo.VM/Collections/OrderedDictionary.cs | 9 +- src/Neo.VM/Cryptography/BitOperations.cs | 9 +- src/Neo.VM/Cryptography/Murmur32.cs | 13 +- src/Neo.VM/Debugger.cs | 13 +- src/Neo.VM/EvaluationStack.cs | 9 +- src/Neo.VM/ExceptionHandlingContext.cs | 13 +- src/Neo.VM/ExceptionHandlingState.cs | 13 +- src/Neo.VM/ExecutionContext.SharedStates.cs | 13 +- src/Neo.VM/ExecutionContext.cs | 13 +- src/Neo.VM/ExecutionEngine.cs | 13 +- src/Neo.VM/ExecutionEngineLimits.cs | 13 +- src/Neo.VM/GlobalSuppressions.cs | 13 +- src/Neo.VM/Instruction.cs | 9 +- src/Neo.VM/IsExternalInit.cs | 11 + src/Neo.VM/OpCode.cs | 13 +- src/Neo.VM/OperandSizeAttribute.cs | 13 +- src/Neo.VM/Properties/AssemblyInfo.cs | 13 +- src/Neo.VM/ReferenceCounter.cs | 13 +- src/Neo.VM/ReferenceEqualityComparer.cs | 9 +- src/Neo.VM/Script.cs | 13 +- src/Neo.VM/ScriptBuilder.cs | 9 +- src/Neo.VM/Slot.cs | 13 +- .../StronglyConnectedComponents/Tarjan.cs | 9 +- src/Neo.VM/Types/Array.cs | 13 +- src/Neo.VM/Types/Boolean.cs | 13 +- src/Neo.VM/Types/Buffer.cs | 9 +- src/Neo.VM/Types/ByteString.cs | 13 +- src/Neo.VM/Types/CompoundType.cs | 13 +- src/Neo.VM/Types/Integer.cs | 13 +- src/Neo.VM/Types/InteropInterface.cs | 13 +- src/Neo.VM/Types/Map.cs | 9 +- src/Neo.VM/Types/Null.cs | 13 +- src/Neo.VM/Types/Pointer.cs | 13 +- src/Neo.VM/Types/PrimitiveType.cs | 13 +- src/Neo.VM/Types/StackItem.Vertex.cs | 17 +- src/Neo.VM/Types/StackItem.cs | 13 +- src/Neo.VM/Types/StackItemType.cs | 13 +- src/Neo.VM/Types/Struct.cs | 13 +- src/Neo.VM/Unsafe.cs | 13 +- src/Neo.VM/Utility.cs | 9 +- src/Neo.VM/VMState.cs | 13 +- src/Neo.VM/VMUnhandledException.cs | 13 +- src/Neo/BigDecimal.cs | 31 +- src/Neo/Cryptography/Base58.cs | 13 +- src/Neo/Cryptography/BloomFilter.cs | 13 +- src/Neo/Cryptography/Crypto.cs | 13 +- src/Neo/Cryptography/ECC/ECCurve.cs | 13 +- src/Neo/Cryptography/ECC/ECFieldElement.cs | 13 +- src/Neo/Cryptography/ECC/ECPoint.cs | 13 +- src/Neo/Cryptography/Helper.cs | 13 +- src/Neo/Cryptography/MerkleTree.cs | 13 +- src/Neo/Cryptography/MerkleTreeNode.cs | 13 +- src/Neo/Cryptography/Murmur128.cs | 13 +- src/Neo/Cryptography/Murmur32.cs | 13 +- src/Neo/Cryptography/RIPEMD160Managed.cs | 13 +- src/Neo/Hardfork.cs | 13 +- src/Neo/Helper.cs | 13 +- src/Neo/IO/Actors/Idle.cs | 13 +- src/Neo/IO/Actors/PriorityMailbox.cs | 13 +- src/Neo/IO/Actors/PriorityMessageQueue.cs | 13 +- src/Neo/IO/ByteArrayComparer.cs | 13 +- src/Neo/IO/ByteArrayEqualityComparer.cs | 9 +- src/Neo/IO/Caching/Cache.cs | 13 +- src/Neo/IO/Caching/ECPointCache.cs | 13 +- src/Neo/IO/Caching/FIFOCache.cs | 13 +- src/Neo/IO/Caching/HashSetCache.cs | 9 +- src/Neo/IO/Caching/IndexedQueue.cs | 13 +- src/Neo/IO/Caching/KeyedCollectionSlim.cs | 11 + src/Neo/IO/Caching/ReflectionCache.cs | 13 +- .../IO/Caching/ReflectionCacheAttribute.cs | 13 +- src/Neo/IO/Caching/RelayCache.cs | 13 +- src/Neo/IO/Helper.cs | 13 +- src/Neo/IO/ISerializable.cs | 13 +- src/Neo/IO/MemoryReader.cs | 19 +- .../Ledger/Blockchain.ApplicationExecuted.cs | 13 +- src/Neo/Ledger/Blockchain.cs | 13 +- src/Neo/Ledger/HeaderCache.cs | 13 +- src/Neo/Ledger/MemoryPool.cs | 13 +- src/Neo/Ledger/PoolItem.cs | 13 +- src/Neo/Ledger/TransactionRemovalReason.cs | 13 +- src/Neo/Ledger/TransactionRemovedEventArgs.cs | 13 +- src/Neo/Ledger/TransactionRouter.cs | 13 +- .../Ledger/TransactionVerificationContext.cs | 13 +- src/Neo/Ledger/VerifyResult.cs | 13 +- src/Neo/LogLevel.cs | 13 +- src/Neo/NeoSystem.cs | 13 +- .../P2P/Capabilities/FullNodeCapability.cs | 13 +- .../P2P/Capabilities/NodeCapability.cs | 13 +- .../P2P/Capabilities/NodeCapabilityType.cs | 13 +- .../P2P/Capabilities/ServerCapability.cs | 13 +- src/Neo/Network/P2P/ChannelsConfig.cs | 13 +- src/Neo/Network/P2P/Connection.cs | 13 +- src/Neo/Network/P2P/Helper.cs | 13 +- src/Neo/Network/P2P/LocalNode.cs | 13 +- src/Neo/Network/P2P/Message.cs | 13 +- src/Neo/Network/P2P/MessageCommand.cs | 13 +- src/Neo/Network/P2P/MessageFlags.cs | 13 +- src/Neo/Network/P2P/Payloads/AddrPayload.cs | 13 +- src/Neo/Network/P2P/Payloads/Block.cs | 13 +- .../P2P/Payloads/Conditions/AndCondition.cs | 13 +- .../Payloads/Conditions/BooleanCondition.cs | 16 +- .../Conditions/CalledByContractCondition.cs | 14 +- .../Conditions/CalledByEntryCondition.cs | 13 +- .../Conditions/CalledByGroupCondition.cs | 14 +- .../P2P/Payloads/Conditions/GroupCondition.cs | 14 +- .../P2P/Payloads/Conditions/NotCondition.cs | 13 +- .../P2P/Payloads/Conditions/OrCondition.cs | 13 +- .../Conditions/ScriptHashCondition.cs | 14 +- .../Payloads/Conditions/WitnessCondition.cs | 13 +- .../Conditions/WitnessConditionType.cs | 13 +- src/Neo/Network/P2P/Payloads/Conflicts.cs | 11 + .../Network/P2P/Payloads/ExtensiblePayload.cs | 13 +- .../Network/P2P/Payloads/FilterAddPayload.cs | 13 +- .../Network/P2P/Payloads/FilterLoadPayload.cs | 13 +- .../P2P/Payloads/GetBlockByIndexPayload.cs | 13 +- .../Network/P2P/Payloads/GetBlocksPayload.cs | 13 +- src/Neo/Network/P2P/Payloads/Header.cs | 13 +- .../Network/P2P/Payloads/HeadersPayload.cs | 13 +- .../P2P/Payloads/HighPriorityAttribute.cs | 13 +- src/Neo/Network/P2P/Payloads/IInventory.cs | 13 +- src/Neo/Network/P2P/Payloads/IVerifiable.cs | 13 +- src/Neo/Network/P2P/Payloads/InvPayload.cs | 13 +- src/Neo/Network/P2P/Payloads/InventoryType.cs | 13 +- .../P2P/Payloads/MerkleBlockPayload.cs | 13 +- .../P2P/Payloads/NetworkAddressWithTime.cs | 13 +- .../Network/P2P/Payloads/NotValidBefore.cs | 11 + .../Network/P2P/Payloads/OracleResponse.cs | 13 +- .../P2P/Payloads/OracleResponseCode.cs | 13 +- src/Neo/Network/P2P/Payloads/PingPayload.cs | 13 +- src/Neo/Network/P2P/Payloads/Signer.cs | 13 +- src/Neo/Network/P2P/Payloads/Transaction.cs | 13 +- .../P2P/Payloads/TransactionAttribute.cs | 17 +- .../P2P/Payloads/TransactionAttributeType.cs | 13 +- .../Network/P2P/Payloads/VersionPayload.cs | 13 +- src/Neo/Network/P2P/Payloads/Witness.cs | 13 +- src/Neo/Network/P2P/Payloads/WitnessRule.cs | 13 +- .../Network/P2P/Payloads/WitnessRuleAction.cs | 13 +- src/Neo/Network/P2P/Payloads/WitnessScope.cs | 13 +- src/Neo/Network/P2P/Peer.cs | 13 +- .../Network/P2P/RemoteNode.ProtocolHandler.cs | 13 +- src/Neo/Network/P2P/RemoteNode.cs | 13 +- src/Neo/Network/P2P/TaskManager.cs | 13 +- src/Neo/Network/P2P/TaskSession.cs | 13 +- src/Neo/Network/UPnP.cs | 13 +- src/Neo/Persistence/ClonedCache.cs | 13 +- src/Neo/Persistence/DataCache.cs | 13 +- src/Neo/Persistence/IReadOnlyStore.cs | 13 +- src/Neo/Persistence/ISnapshot.cs | 13 +- src/Neo/Persistence/IStore.cs | 13 +- src/Neo/Persistence/IStoreProvider.cs | 13 +- src/Neo/Persistence/MemorySnapshot.cs | 13 +- src/Neo/Persistence/MemoryStore.cs | 13 +- src/Neo/Persistence/SeekDirection.cs | 13 +- src/Neo/Persistence/SnapshotCache.cs | 13 +- src/Neo/Persistence/StoreFactory.cs | 13 +- src/Neo/Persistence/TrackState.cs | 13 +- src/Neo/Plugins/Plugin.cs | 13 +- src/Neo/Properties/AssemblyInfo.cs | 11 + src/Neo/ProtocolSettings.cs | 19 +- .../ApplicationEngine.Contract.cs | 13 +- .../SmartContract/ApplicationEngine.Crypto.cs | 13 +- .../ApplicationEngine.Iterator.cs | 13 +- .../ApplicationEngine.OpCodePrices.cs | 13 +- .../ApplicationEngine.Runtime.cs | 19 +- .../ApplicationEngine.Storage.cs | 13 +- src/Neo/SmartContract/ApplicationEngine.cs | 13 +- src/Neo/SmartContract/BinarySerializer.cs | 19 +- src/Neo/SmartContract/CallFlags.cs | 13 +- src/Neo/SmartContract/Contract.cs | 13 +- src/Neo/SmartContract/ContractParameter.cs | 13 +- .../SmartContract/ContractParameterType.cs | 13 +- .../ContractParametersContext.cs | 13 +- src/Neo/SmartContract/ContractState.cs | 13 +- src/Neo/SmartContract/ContractTask.cs | 13 +- src/Neo/SmartContract/ContractTaskAwaiter.cs | 13 +- .../ContractTaskMethodBuilder.cs | 13 +- src/Neo/SmartContract/DeployedContract.cs | 13 +- .../SmartContract/ExecutionContextState.cs | 13 +- src/Neo/SmartContract/FindOptions.cs | 13 +- src/Neo/SmartContract/Helper.cs | 13 +- .../IApplicationEngineProvider.cs | 13 +- src/Neo/SmartContract/IDiagnostic.cs | 13 +- src/Neo/SmartContract/IInteroperable.cs | 13 +- src/Neo/SmartContract/InteropDescriptor.cs | 13 +- .../InteropParameterDescriptor.cs | 13 +- src/Neo/SmartContract/Iterators/IIterator.cs | 13 +- .../Iterators/StorageIterator.cs | 13 +- src/Neo/SmartContract/JsonSerializer.cs | 13 +- src/Neo/SmartContract/KeyBuilder.cs | 13 +- src/Neo/SmartContract/LogEventArgs.cs | 13 +- src/Neo/SmartContract/Manifest/ContractAbi.cs | 13 +- .../Manifest/ContractEventDescriptor.cs | 13 +- .../SmartContract/Manifest/ContractGroup.cs | 13 +- .../Manifest/ContractManifest.cs | 17 +- .../Manifest/ContractMethodDescriptor.cs | 13 +- .../Manifest/ContractParameterDefinition.cs | 13 +- .../Manifest/ContractPermission.cs | 13 +- .../Manifest/ContractPermissionDescriptor.cs | 13 +- .../Manifest/WildCardContainer.cs | 13 +- src/Neo/SmartContract/MaxLengthAttribute.cs | 13 +- src/Neo/SmartContract/MethodToken.cs | 13 +- src/Neo/SmartContract/Native/AccountState.cs | 13 +- .../Native/ContractManagement.cs | 24 +- .../Native/ContractMethodAttribute.cs | 13 +- .../Native/ContractMethodMetadata.cs | 13 +- .../Native/CryptoLib.BLS12_381.cs | 11 + src/Neo/SmartContract/Native/CryptoLib.cs | 13 +- src/Neo/SmartContract/Native/FungibleToken.cs | 13 +- src/Neo/SmartContract/Native/GasToken.cs | 13 +- .../SmartContract/Native/HashIndexState.cs | 13 +- .../SmartContract/Native/InteroperableList.cs | 11 + .../SmartContract/Native/LedgerContract.cs | 13 +- src/Neo/SmartContract/Native/NamedCurve.cs | 13 +- .../SmartContract/Native/NativeContract.cs | 13 +- src/Neo/SmartContract/Native/NeoToken.cs | 23 +- .../SmartContract/Native/OracleContract.cs | 13 +- src/Neo/SmartContract/Native/OracleRequest.cs | 13 +- .../SmartContract/Native/PolicyContract.cs | 17 +- src/Neo/SmartContract/Native/Role.cs | 13 +- .../SmartContract/Native/RoleManagement.cs | 13 +- src/Neo/SmartContract/Native/StdLib.cs | 19 +- .../SmartContract/Native/TransactionState.cs | 13 +- src/Neo/SmartContract/Native/TrimmedBlock.cs | 13 +- src/Neo/SmartContract/NefFile.cs | 13 +- src/Neo/SmartContract/NotifyEventArgs.cs | 13 +- src/Neo/SmartContract/StorageContext.cs | 13 +- src/Neo/SmartContract/StorageItem.cs | 17 +- src/Neo/SmartContract/StorageKey.cs | 13 +- src/Neo/SmartContract/TriggerType.cs | 13 +- src/Neo/SmartContract/ValidatorAttribute.cs | 13 +- src/Neo/TimeProvider.cs | 13 +- src/Neo/UInt160.cs | 13 +- src/Neo/UInt256.cs | 13 +- src/Neo/Utility.cs | 13 +- src/Neo/VM/Helper.cs | 13 +- src/Neo/Wallets/AssetDescriptor.cs | 13 +- src/Neo/Wallets/Helper.cs | 13 +- src/Neo/Wallets/IWalletFactory.cs | 13 +- src/Neo/Wallets/IWalletProvider.cs | 13 +- src/Neo/Wallets/KeyPair.cs | 13 +- src/Neo/Wallets/NEP6/NEP6Account.cs | 13 +- src/Neo/Wallets/NEP6/NEP6Contract.cs | 13 +- src/Neo/Wallets/NEP6/NEP6Wallet.cs | 13 +- src/Neo/Wallets/NEP6/NEP6WalletFactory.cs | 13 +- src/Neo/Wallets/NEP6/ScryptParameters.cs | 13 +- src/Neo/Wallets/TransferOutput.cs | 13 +- src/Neo/Wallets/Wallet.cs | 61 ++-- src/Neo/Wallets/WalletAccount.cs | 13 +- .../CommandTokenTest.cs | 11 + tests/Neo.Json.UnitTests/UT_JArray.cs | 11 + tests/Neo.Json.UnitTests/UT_JBoolean.cs | 11 + tests/Neo.Json.UnitTests/UT_JNumber.cs | 11 + tests/Neo.Json.UnitTests/UT_JObject.cs | 11 + tests/Neo.Json.UnitTests/UT_JPath.cs | 11 + tests/Neo.Json.UnitTests/UT_JString.cs | 11 + .../UT_OrderedDictionary.cs | 11 + tests/Neo.Json.UnitTests/Usings.cs | 11 + .../Cryptography/ECC/UT_ECFieldElement.cs | 11 + .../Cryptography/ECC/UT_ECPoint.cs | 11 + tests/Neo.UnitTests/Cryptography/UT_Base58.cs | 11 + .../Cryptography/UT_BloomFilter.cs | 11 + tests/Neo.UnitTests/Cryptography/UT_Crypto.cs | 11 + .../Cryptography/UT_Cryptography_Helper.cs | 11 + .../Cryptography/UT_MerkleTree.cs | 11 + .../Cryptography/UT_MerkleTreeNode.cs | 13 +- .../Cryptography/UT_Murmur128.cs | 11 + .../Neo.UnitTests/Cryptography/UT_Murmur32.cs | 11 + tests/Neo.UnitTests/Cryptography/UT_SCrypt.cs | 11 + .../Extensions/NativeContractExtensions.cs | 11 + .../Nep17NativeContractExtensions.cs | 11 + tests/Neo.UnitTests/IO/Caching/UT_Cache.cs | 11 + .../Neo.UnitTests/IO/Caching/UT_CloneCache.cs | 11 + .../Neo.UnitTests/IO/Caching/UT_DataCache.cs | 13 +- .../IO/Caching/UT_ECPointCache.cs | 13 +- .../IO/Caching/UT_HashSetCache.cs | 11 + .../IO/Caching/UT_IndexedQueue.cs | 11 + .../IO/Caching/UT_ReflectionCache.cs | 11 + .../Neo.UnitTests/IO/Caching/UT_RelayCache.cs | 11 + .../Neo.UnitTests/IO/UT_ByteArrayComparer.cs | 11 + .../IO/UT_ByteArrayEqualityComparer.cs | 11 + tests/Neo.UnitTests/IO/UT_IOHelper.cs | 11 + tests/Neo.UnitTests/IO/UT_MemoryReader.cs | 11 + tests/Neo.UnitTests/Ledger/UT_Blockchain.cs | 11 + .../Neo.UnitTests/Ledger/UT_HashIndexState.cs | 11 + tests/Neo.UnitTests/Ledger/UT_MemoryPool.cs | 24 +- tests/Neo.UnitTests/Ledger/UT_PoolItem.cs | 11 + tests/Neo.UnitTests/Ledger/UT_StorageItem.cs | 11 + tests/Neo.UnitTests/Ledger/UT_StorageKey.cs | 11 + .../Ledger/UT_TransactionState.cs | 12 +- .../UT_TransactionVerificationContext.cs | 11 + tests/Neo.UnitTests/Ledger/UT_TrimmedBlock.cs | 11 + .../P2P/Capabilities/UT_FullNodeCapability.cs | 11 + .../P2P/Capabilities/UT_ServerCapability.cs | 11 + .../Network/P2P/Payloads/UT_AddrPayload.cs | 11 + .../Network/P2P/Payloads/UT_Block.cs | 11 + .../Network/P2P/Payloads/UT_Conflicts.cs | 15 +- .../P2P/Payloads/UT_ExtensiblePayload.cs | 11 + .../P2P/Payloads/UT_FilterAddPayload.cs | 11 + .../P2P/Payloads/UT_FilterLoadPayload.cs | 11 + .../P2P/Payloads/UT_GetBlockByIndexPayload.cs | 11 + .../P2P/Payloads/UT_GetBlocksPayload.cs | 11 + .../Network/P2P/Payloads/UT_Header.cs | 11 + .../Network/P2P/Payloads/UT_HeadersPayload.cs | 11 + .../P2P/Payloads/UT_HighPriorityAttribute.cs | 11 + .../Network/P2P/Payloads/UT_InvPayload.cs | 11 + .../P2P/Payloads/UT_MerkleBlockPayload.cs | 11 + .../P2P/Payloads/UT_NetworkAddressWithTime.cs | 11 + .../Network/P2P/Payloads/UT_NotValidBefore.cs | 11 + .../Network/P2P/Payloads/UT_Signers.cs | 11 + .../Network/P2P/Payloads/UT_Transaction.cs | 11 + .../Network/P2P/Payloads/UT_VersionPayload.cs | 11 + .../Network/P2P/Payloads/UT_Witness.cs | 11 + .../P2P/Payloads/UT_WitnessContition.cs | 11 + .../Network/P2P/UT_ChannelsConfig.cs | 11 + .../Neo.UnitTests/Network/P2P/UT_LocalNode.cs | 11 + tests/Neo.UnitTests/Network/P2P/UT_Message.cs | 11 + .../Network/P2P/UT_RemoteNode.cs | 11 + .../Network/P2P/UT_RemoteNodeMailbox.cs | 11 + .../Network/P2P/UT_TaskManagerMailbox.cs | 11 + .../Network/P2P/UT_TaskSession.cs | 11 + tests/Neo.UnitTests/Network/UT_UPnP.cs | 11 + .../Persistence/UT_MemoryStore.cs | 11 + tests/Neo.UnitTests/Plugins/TestPlugin.cs | 11 + tests/Neo.UnitTests/Plugins/UT_Plugin.cs | 11 + .../Iterators/UT_StorageIterator.cs | 11 + .../Manifest/UT_ContractEventDescriptor.cs | 11 + .../Manifest/UT_ContractGroup.cs | 11 + .../Manifest/UT_ContractManifest.cs | 13 +- .../Manifest/UT_ContractPermission.cs | 11 + .../UT_ContractPermissionDescriptor.cs | 11 + .../Manifest/UT_WildCardContainer.cs | 13 +- .../SmartContract/Native/UT_CryptoLib.cs | 12 +- .../SmartContract/Native/UT_FungibleToken.cs | 11 + .../SmartContract/Native/UT_GasToken.cs | 19 +- .../SmartContract/Native/UT_NativeContract.cs | 11 + .../SmartContract/Native/UT_NeoToken.cs | 17 +- .../SmartContract/Native/UT_PolicyContract.cs | 17 +- .../SmartContract/Native/UT_RoleManagement.cs | 11 + .../SmartContract/Native/UT_StdLib.cs | 11 + .../UT_ApplicationEngine.Contract.cs | 11 + .../UT_ApplicationEngine.Runtime.cs | 11 + .../SmartContract/UT_ApplicationEngine.cs | 17 +- .../UT_ApplicationEngineProvider.cs | 11 + .../SmartContract/UT_BinarySerializer.cs | 11 + .../SmartContract/UT_Contract.cs | 11 + .../SmartContract/UT_ContractParameter.cs | 11 + .../UT_ContractParameterContext.cs | 11 + .../SmartContract/UT_ContractState.cs | 13 +- .../SmartContract/UT_DeployedContract.cs | 11 + .../Neo.UnitTests/SmartContract/UT_Helper.cs | 11 + .../SmartContract/UT_InteropPrices.cs | 11 + .../SmartContract/UT_InteropService.NEO.cs | 11 + .../SmartContract/UT_InteropService.cs | 11 + .../SmartContract/UT_JsonSerializer.cs | 11 + .../SmartContract/UT_KeyBuilder.cs | 11 + .../SmartContract/UT_LogEventArgs.cs | 11 + .../SmartContract/UT_MethodToken.cs | 11 + .../Neo.UnitTests/SmartContract/UT_NefFile.cs | 11 + .../SmartContract/UT_NotifyEventArgs.cs | 11 + .../SmartContract/UT_OpCodePrices.cs | 11 + .../SmartContract/UT_SmartContractHelper.cs | 11 + .../SmartContract/UT_Syscalls.cs | 11 + tests/Neo.UnitTests/TestBlockchain.cs | 13 +- tests/Neo.UnitTests/TestProtocolSettings.cs | 14 +- tests/Neo.UnitTests/TestUtils.cs | 11 + tests/Neo.UnitTests/TestVerifiable.cs | 13 +- tests/Neo.UnitTests/TestWalletAccount.cs | 11 + tests/Neo.UnitTests/UT_BigDecimal.cs | 11 + tests/Neo.UnitTests/UT_DataCache.cs | 11 + tests/Neo.UnitTests/UT_Helper.cs | 11 + tests/Neo.UnitTests/UT_NeoSystem.cs | 11 + tests/Neo.UnitTests/UT_ProtocolSettings.cs | 13 +- tests/Neo.UnitTests/UT_UInt160.cs | 11 + tests/Neo.UnitTests/UT_UInt256.cs | 11 + tests/Neo.UnitTests/UT_UIntBenchmarks.cs | 11 + tests/Neo.UnitTests/VM/UT_Helper.cs | 11 + .../Wallets/NEP6/UT_NEP6Account.cs | 11 + .../Wallets/NEP6/UT_NEP6Contract.cs | 11 + .../Wallets/NEP6/UT_NEP6Wallet.cs | 11 + .../Wallets/NEP6/UT_ScryptParameters.cs | 11 + .../Wallets/UT_AssetDescriptor.cs | 11 + tests/Neo.UnitTests/Wallets/UT_KeyPair.cs | 13 +- tests/Neo.UnitTests/Wallets/UT_Wallet.cs | 11 + .../Neo.UnitTests/Wallets/UT_WalletAccount.cs | 11 + .../Wallets/UT_Wallets_Helper.cs | 11 + .../Converters/ScriptConverter.cs | 12 +- .../Neo.VM.Tests/Converters/UppercaseEnum.cs | 11 + .../Neo.VM.Tests/Extensions/JsonExtensions.cs | 11 + .../Extensions/StringExtensions.cs | 11 + tests/Neo.VM.Tests/Helpers/RandomHelper.cs | 11 + tests/Neo.VM.Tests/Types/TestEngine.cs | 13 +- tests/Neo.VM.Tests/Types/VMUT.cs | 11 + tests/Neo.VM.Tests/Types/VMUTActionType.cs | 11 + tests/Neo.VM.Tests/Types/VMUTEntry.cs | 11 + .../Types/VMUTExecutionContextState.cs | 11 + .../Types/VMUTExecutionEngineState.cs | 11 + tests/Neo.VM.Tests/Types/VMUTStackItem.cs | 11 + tests/Neo.VM.Tests/Types/VMUTStackItemType.cs | 11 + tests/Neo.VM.Tests/Types/VMUTStep.cs | 11 + tests/Neo.VM.Tests/UtDebugger.cs | 11 + tests/Neo.VM.Tests/UtEvaluationStack.cs | 11 + tests/Neo.VM.Tests/UtExecutionContext.cs | 11 + tests/Neo.VM.Tests/UtReferenceCounter.cs | 11 + tests/Neo.VM.Tests/UtScript.cs | 11 + tests/Neo.VM.Tests/UtScriptBuilder.cs | 11 + tests/Neo.VM.Tests/UtSlot.cs | 13 +- tests/Neo.VM.Tests/UtStackItem.cs | 11 + tests/Neo.VM.Tests/UtStruct.cs | 11 + tests/Neo.VM.Tests/UtUnsafe.cs | 11 + tests/Neo.VM.Tests/UtUtility.cs | 15 +- tests/Neo.VM.Tests/UtVMJson.cs | 17 +- tests/Neo.VM.Tests/VMJsonTestBase.cs | 11 + 503 files changed, 4579 insertions(+), 2035 deletions(-) create mode 100644 SpellingExclusions.dic diff --git a/.editorconfig b/.editorconfig index 175ec7b14e..269a7e444b 100644 --- a/.editorconfig +++ b/.editorconfig @@ -6,14 +6,297 @@ # dotnet tool update -g dotnet-format # remember to have: git config --global core.autocrlf false #(which is usually default) +# top-most EditorConfig file root = true -# Every file - +# Don't use tabs for indentation. [*] +indent_style = space insert_final_newline = true trim_trailing_whitespace = true charset = utf-8 end_of_line = lf +# (Please don't specify an indent_size here; that has too many unintended consequences.) +spelling_exclusion_path = SpellingExclusions.dic + +# Code files +[*.{cs,csx,vb,vbx}] +indent_size = 4 +insert_final_newline = true +trim_trailing_whitespace = true +charset = utf-8 + +# XML project files +[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}] +indent_size = 2 + +# XML config files +[*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}] +indent_size = 2 + +# JSON files +[*.json] +indent_size = 2 + +# Powershell files +[*.ps1] +indent_size = 2 + +# Shell script files +[*.sh] +end_of_line = lf +indent_size = 2 + +# Dotnet code style settings: +[*.{cs,vb}] +# Member can be made 'readonly' +csharp_style_prefer_readonly_struct_member = true +dotnet_diagnostic.IDE0251.severity = warning +dotnet_diagnostic.IDE0044.severity = warning + dotnet_diagnostic.CS1591.severity = silent + +# Sort using and Import directives with System.* appearing first +dotnet_sort_system_directives_first = false +dotnet_separate_import_directive_groups = false +# Avoid "this." and "Me." if not necessary +dotnet_style_qualification_for_field = false:refactoring +dotnet_style_qualification_for_property = false:refactoring +dotnet_style_qualification_for_method = false:refactoring +dotnet_style_qualification_for_event = false:refactoring + +# Use language keywords instead of framework type names for type references +dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion +dotnet_style_predefined_type_for_member_access = true:suggestion + +# Suggest more modern language features when available +dotnet_style_object_initializer = true:suggestion +dotnet_style_collection_initializer = true:suggestion +dotnet_style_coalesce_expression = true:suggestion +dotnet_style_null_propagation = true:suggestion +dotnet_style_explicit_tuple_names = true:suggestion + +# Whitespace options +dotnet_style_allow_multiple_blank_lines_experimental = false + +# Non-private static fields are PascalCase +dotnet_naming_rule.non_private_static_fields_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.non_private_static_fields_should_be_pascal_case.symbols = non_private_static_fields +dotnet_naming_rule.non_private_static_fields_should_be_pascal_case.style = non_private_static_field_style + +dotnet_naming_symbols.non_private_static_fields.applicable_kinds = field +dotnet_naming_symbols.non_private_static_fields.applicable_accessibilities = public, protected, internal, protected_internal, private_protected +dotnet_naming_symbols.non_private_static_fields.required_modifiers = static + +dotnet_naming_style.non_private_static_field_style.capitalization = pascal_case + +# Non-private readonly fields are PascalCase +dotnet_naming_rule.non_private_readonly_fields_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.non_private_readonly_fields_should_be_pascal_case.symbols = non_private_readonly_fields +dotnet_naming_rule.non_private_readonly_fields_should_be_pascal_case.style = non_private_readonly_field_style + +dotnet_naming_symbols.non_private_readonly_fields.applicable_kinds = field +dotnet_naming_symbols.non_private_readonly_fields.applicable_accessibilities = public, protected, internal, protected_internal, private_protected +dotnet_naming_symbols.non_private_readonly_fields.required_modifiers = readonly + +dotnet_naming_style.non_private_readonly_field_style.capitalization = pascal_case + +# Constants are PascalCase +dotnet_naming_rule.constants_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.constants_should_be_pascal_case.symbols = constants +dotnet_naming_rule.constants_should_be_pascal_case.style = constant_style + +dotnet_naming_symbols.constants.applicable_kinds = field, local +dotnet_naming_symbols.constants.required_modifiers = const + +dotnet_naming_style.constant_style.capitalization = pascal_case + +# Static fields are camelCase and start with s_ +dotnet_naming_rule.static_fields_should_be_camel_case.severity = suggestion +dotnet_naming_rule.static_fields_should_be_camel_case.symbols = static_fields +dotnet_naming_rule.static_fields_should_be_camel_case.style = static_field_style + +dotnet_naming_symbols.static_fields.applicable_kinds = field +dotnet_naming_symbols.static_fields.required_modifiers = static + +dotnet_naming_style.static_field_style.capitalization = camel_case +dotnet_naming_style.static_field_style.required_prefix = s_ + +# Instance fields are camelCase and start with _ +dotnet_naming_rule.instance_fields_should_be_camel_case.severity = suggestion +dotnet_naming_rule.instance_fields_should_be_camel_case.symbols = instance_fields +dotnet_naming_rule.instance_fields_should_be_camel_case.style = instance_field_style + +dotnet_naming_symbols.instance_fields.applicable_kinds = field + +dotnet_naming_style.instance_field_style.capitalization = camel_case +dotnet_naming_style.instance_field_style.required_prefix = _ + +# Locals and parameters are camelCase +dotnet_naming_rule.locals_should_be_camel_case.severity = suggestion +dotnet_naming_rule.locals_should_be_camel_case.symbols = locals_and_parameters +dotnet_naming_rule.locals_should_be_camel_case.style = camel_case_style + +dotnet_naming_symbols.locals_and_parameters.applicable_kinds = parameter, local + +dotnet_naming_style.camel_case_style.capitalization = camel_case + +# Local functions are PascalCase +dotnet_naming_rule.local_functions_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.local_functions_should_be_pascal_case.symbols = local_functions +dotnet_naming_rule.local_functions_should_be_pascal_case.style = local_function_style + +dotnet_naming_symbols.local_functions.applicable_kinds = local_function + +dotnet_naming_style.local_function_style.capitalization = pascal_case + +# By default, name items with PascalCase +dotnet_naming_rule.members_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.members_should_be_pascal_case.symbols = all_members +dotnet_naming_rule.members_should_be_pascal_case.style = pascal_case_style + +dotnet_naming_symbols.all_members.applicable_kinds = * + +dotnet_naming_style.pascal_case_style.capitalization = pascal_case + +file_header_template = Copyright (C) 2015-2024 The Neo Project.\n\n{fileName} file belongs to the neo project and is free\nsoftware distributed under the MIT software license, see the\naccompanying file LICENSE in the main directory of the\nrepository or http://www.opensource.org/licenses/mit-license.php\nfor more details.\n\nRedistribution and use in source and binary forms with or without\nmodifications are permitted. + +# Require file header +dotnet_diagnostic.IDE0073.severity = error + +# RS0016: Only enable if API files are present +dotnet_public_api_analyzer.require_api_files = true + +# IDE0055: Fix formatting +# Workaround for https://github.com/dotnet/roslyn/issues/70570 +dotnet_diagnostic.IDE0055.severity = warning + +# CSharp code style settings: +[*.cs] +# Newline settings +csharp_new_line_before_open_brace = all +csharp_new_line_before_else = true +csharp_new_line_before_catch = true +csharp_new_line_before_finally = true +csharp_new_line_before_members_in_object_initializers = true +csharp_new_line_before_members_in_anonymous_types = true +csharp_new_line_between_query_expression_clauses = true + +# Indentation preferences +csharp_indent_block_contents = true +csharp_indent_braces = false +csharp_indent_case_contents = true +csharp_indent_case_contents_when_block = true +csharp_indent_switch_labels = true +csharp_indent_labels = flush_left + +# Whitespace options +csharp_style_allow_embedded_statements_on_same_line_experimental = false +csharp_style_allow_blank_lines_between_consecutive_braces_experimental = false +csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = false +csharp_style_allow_blank_line_after_token_in_conditional_expression_experimental = false +csharp_style_allow_blank_line_after_token_in_arrow_expression_clause_experimental = false + +# Prefer "var" everywhere +csharp_style_var_for_built_in_types = true:suggestion +csharp_style_var_when_type_is_apparent = true:suggestion +csharp_style_var_elsewhere = true:suggestion + +# Prefer method-like constructs to have a block body +csharp_style_expression_bodied_methods = false:none +csharp_style_expression_bodied_constructors = false:none +csharp_style_expression_bodied_operators = false:none + +# Prefer property-like constructs to have an expression-body +csharp_style_expression_bodied_properties = true:none +csharp_style_expression_bodied_indexers = true:none +csharp_style_expression_bodied_accessors = true:none + +# Suggest more modern language features when available +csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion +csharp_style_pattern_matching_over_as_with_null_check = true:suggestion +csharp_style_inlined_variable_declaration = true:suggestion +csharp_style_throw_expression = true:suggestion +csharp_style_conditional_delegate_call = true:suggestion +csharp_style_prefer_extended_property_pattern = true:suggestion + +# Space preferences +csharp_space_after_cast = false +csharp_space_after_colon_in_inheritance_clause = true +csharp_space_after_comma = true +csharp_space_after_dot = false +csharp_space_after_keywords_in_control_flow_statements = true +csharp_space_after_semicolon_in_for_statement = true +csharp_space_around_binary_operators = before_and_after +csharp_space_around_declaration_statements = do_not_ignore +csharp_space_before_colon_in_inheritance_clause = true +csharp_space_before_comma = false +csharp_space_before_dot = false +csharp_space_before_open_square_brackets = false +csharp_space_before_semicolon_in_for_statement = false +csharp_space_between_empty_square_brackets = false +csharp_space_between_method_call_empty_parameter_list_parentheses = false +csharp_space_between_method_call_name_and_opening_parenthesis = false +csharp_space_between_method_call_parameter_list_parentheses = false +csharp_space_between_method_declaration_empty_parameter_list_parentheses = false +csharp_space_between_method_declaration_name_and_open_parenthesis = false +csharp_space_between_method_declaration_parameter_list_parentheses = false +csharp_space_between_parentheses = false +csharp_space_between_square_brackets = false + +# Blocks are allowed +csharp_prefer_braces = true:silent +csharp_preserve_single_line_blocks = true +csharp_preserve_single_line_statements = true + +# IDE0060: Remove unused parameter +dotnet_diagnostic.IDE0060.severity = none + +[src/{Analyzers,CodeStyle,Features,Workspaces,EditorFeatures,VisualStudio}/**/*.{cs,vb}] + +# IDE0011: Add braces +csharp_prefer_braces = when_multiline:warning +# NOTE: We need the below severity entry for Add Braces due to https://github.com/dotnet/roslyn/issues/44201 +dotnet_diagnostic.IDE0011.severity = warning + +# IDE0040: Add accessibility modifiers +dotnet_diagnostic.IDE0040.severity = warning + +# IDE0052: Remove unread private member +dotnet_diagnostic.IDE0052.severity = warning + +# IDE0059: Unnecessary assignment to a value +dotnet_diagnostic.IDE0059.severity = warning + +# CA1012: Abstract types should not have public constructors +dotnet_diagnostic.CA1012.severity = warning + +# CA1822: Make member static +dotnet_diagnostic.CA1822.severity = warning + +# Prefer "var" everywhere +dotnet_diagnostic.IDE0007.severity = warning +csharp_style_var_for_built_in_types = true:warning +csharp_style_var_when_type_is_apparent = true:warning +csharp_style_var_elsewhere = true:warning + +# csharp_style_allow_embedded_statements_on_same_line_experimental +dotnet_diagnostic.IDE2001.severity = warning + +# csharp_style_allow_blank_lines_between_consecutive_braces_experimental +dotnet_diagnostic.IDE2002.severity = warning + +# csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental +dotnet_diagnostic.IDE2004.severity = warning + +# csharp_style_allow_blank_line_after_token_in_conditional_expression_experimental +dotnet_diagnostic.IDE2005.severity = warning + +# csharp_style_allow_blank_line_after_token_in_arrow_expression_clause_experimental +dotnet_diagnostic.IDE2006.severity = warning + +[src/{VisualStudio}/**/*.{cs,vb}] +# CA1822: Make member static +# There is a risk of accidentally breaking an internal API that partners rely on though IVT. +dotnet_code_quality.CA1822.api_surface = private \ No newline at end of file diff --git a/SpellingExclusions.dic b/SpellingExclusions.dic new file mode 100644 index 0000000000..e69de29bb2 diff --git a/benchmarks/Neo.Benchmarks/Benchmarks.cs b/benchmarks/Neo.Benchmarks/Benchmarks.cs index fa524c26c7..d55dc64391 100644 --- a/benchmarks/Neo.Benchmarks/Benchmarks.cs +++ b/benchmarks/Neo.Benchmarks/Benchmarks.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Benchmarks.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.Payloads; using Neo.SmartContract; using Neo.VM; diff --git a/benchmarks/Neo.Benchmarks/Program.cs b/benchmarks/Neo.Benchmarks/Program.cs index 002fff2761..9d4125bb9f 100644 --- a/benchmarks/Neo.Benchmarks/Program.cs +++ b/benchmarks/Neo.Benchmarks/Program.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Program.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; using System.Reflection; diff --git a/benchmarks/Neo.VM.Benchmarks/Benchmarks.cs b/benchmarks/Neo.VM.Benchmarks/Benchmarks.cs index dd7df7d3d1..6eab691a7d 100644 --- a/benchmarks/Neo.VM.Benchmarks/Benchmarks.cs +++ b/benchmarks/Neo.VM.Benchmarks/Benchmarks.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Benchmarks.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.Diagnostics; namespace Neo.VM diff --git a/benchmarks/Neo.VM.Benchmarks/Program.cs b/benchmarks/Neo.VM.Benchmarks/Program.cs index 4ab0a66926..a9c86f405d 100644 --- a/benchmarks/Neo.VM.Benchmarks/Program.cs +++ b/benchmarks/Neo.VM.Benchmarks/Program.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Program.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; using System.Reflection; diff --git a/src/Neo.CLI/CLI/ConsolePercent.cs b/src/Neo.CLI/CLI/ConsolePercent.cs index 8c5e2a137d..703ca38740 100644 --- a/src/Neo.CLI/CLI/ConsolePercent.cs +++ b/src/Neo.CLI/CLI/ConsolePercent.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-cli is free software distributed under the MIT software -// license, see the accompanying file LICENSE in the main directory of -// the project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// ConsolePercent.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. diff --git a/src/Neo.CLI/CLI/Helper.cs b/src/Neo.CLI/CLI/Helper.cs index d0bc4e8d34..e33f075539 100644 --- a/src/Neo.CLI/CLI/Helper.cs +++ b/src/Neo.CLI/CLI/Helper.cs @@ -1,15 +1,16 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-cli is free software distributed under the MIT software -// license, see the accompanying file LICENSE in the main directory of -// the project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// Helper.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 Neo.SmartContract.Manifest; +using System; namespace Neo.CLI { diff --git a/src/Neo.CLI/CLI/MainService.Blockchain.cs b/src/Neo.CLI/CLI/MainService.Blockchain.cs index f85368ec37..4f896d63e3 100644 --- a/src/Neo.CLI/CLI/MainService.Blockchain.cs +++ b/src/Neo.CLI/CLI/MainService.Blockchain.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-cli is free software distributed under the MIT software -// license, see the accompanying file LICENSE in the main directory of -// the project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// MainService.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. diff --git a/src/Neo.CLI/CLI/MainService.Contracts.cs b/src/Neo.CLI/CLI/MainService.Contracts.cs index f60faddf04..e2aecbb598 100644 --- a/src/Neo.CLI/CLI/MainService.Contracts.cs +++ b/src/Neo.CLI/CLI/MainService.Contracts.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-cli is free software distributed under the MIT software -// license, see the accompanying file LICENSE in the main directory of -// the project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// MainService.Contracts.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. diff --git a/src/Neo.CLI/CLI/MainService.Logger.cs b/src/Neo.CLI/CLI/MainService.Logger.cs index 47a813d7e2..80624779c7 100644 --- a/src/Neo.CLI/CLI/MainService.Logger.cs +++ b/src/Neo.CLI/CLI/MainService.Logger.cs @@ -1,8 +1,9 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-cli is free software distributed under the MIT software -// license, see the accompanying file LICENSE in the main directory of -// the project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// MainService.Logger.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 diff --git a/src/Neo.CLI/CLI/MainService.NEP17.cs b/src/Neo.CLI/CLI/MainService.NEP17.cs index 17d62ff4d2..cd0356e81b 100644 --- a/src/Neo.CLI/CLI/MainService.NEP17.cs +++ b/src/Neo.CLI/CLI/MainService.NEP17.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-cli is free software distributed under the MIT software -// license, see the accompanying file LICENSE in the main directory of -// the project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// MainService.NEP17.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. diff --git a/src/Neo.CLI/CLI/MainService.Native.cs b/src/Neo.CLI/CLI/MainService.Native.cs index 0cdf1ca45c..b7562f3368 100644 --- a/src/Neo.CLI/CLI/MainService.Native.cs +++ b/src/Neo.CLI/CLI/MainService.Native.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-cli is free software distributed under the MIT software -// license, see the accompanying file LICENSE in the main directory of -// the project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// MainService.Native.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. diff --git a/src/Neo.CLI/CLI/MainService.Network.cs b/src/Neo.CLI/CLI/MainService.Network.cs index b09bd5aeda..38d6fd1d28 100644 --- a/src/Neo.CLI/CLI/MainService.Network.cs +++ b/src/Neo.CLI/CLI/MainService.Network.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-cli is free software distributed under the MIT software -// license, see the accompanying file LICENSE in the main directory of -// the project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// MainService.Network.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. diff --git a/src/Neo.CLI/CLI/MainService.Node.cs b/src/Neo.CLI/CLI/MainService.Node.cs index 9752dfd5ea..5dd16f53e8 100644 --- a/src/Neo.CLI/CLI/MainService.Node.cs +++ b/src/Neo.CLI/CLI/MainService.Node.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-cli is free software distributed under the MIT software -// license, see the accompanying file LICENSE in the main directory of -// the project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// MainService.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. diff --git a/src/Neo.CLI/CLI/MainService.Plugins.cs b/src/Neo.CLI/CLI/MainService.Plugins.cs index 169df18a25..b8bc739e85 100644 --- a/src/Neo.CLI/CLI/MainService.Plugins.cs +++ b/src/Neo.CLI/CLI/MainService.Plugins.cs @@ -1,7 +1,9 @@ -// Copyright (C) 2016-2023 The Neo Project. -// The neo-cli is free software distributed under the MIT software -// license, see the accompanying file LICENSE in the main directory of -// the project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// MainService.Plugins.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 diff --git a/src/Neo.CLI/CLI/MainService.Tools.cs b/src/Neo.CLI/CLI/MainService.Tools.cs index 870f0261a9..f4a5b762a9 100644 --- a/src/Neo.CLI/CLI/MainService.Tools.cs +++ b/src/Neo.CLI/CLI/MainService.Tools.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-cli is free software distributed under the MIT software -// license, see the accompanying file LICENSE in the main directory of -// the project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// MainService.Tools.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. diff --git a/src/Neo.CLI/CLI/MainService.Vote.cs b/src/Neo.CLI/CLI/MainService.Vote.cs index 67f37b648e..12cd48b3a9 100644 --- a/src/Neo.CLI/CLI/MainService.Vote.cs +++ b/src/Neo.CLI/CLI/MainService.Vote.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-cli is free software distributed under the MIT software -// license, see the accompanying file LICENSE in the main directory of -// the project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// MainService.Vote.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. diff --git a/src/Neo.CLI/CLI/MainService.Wallet.cs b/src/Neo.CLI/CLI/MainService.Wallet.cs index 48531f1f4e..041aab3a0c 100644 --- a/src/Neo.CLI/CLI/MainService.Wallet.cs +++ b/src/Neo.CLI/CLI/MainService.Wallet.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-cli is free software distributed under the MIT software -// license, see the accompanying file LICENSE in the main directory of -// the project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// MainService.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. diff --git a/src/Neo.CLI/CLI/MainService.cs b/src/Neo.CLI/CLI/MainService.cs index c097176340..54b56d3d9a 100644 --- a/src/Neo.CLI/CLI/MainService.cs +++ b/src/Neo.CLI/CLI/MainService.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-cli is free software distributed under the MIT software -// license, see the accompanying file LICENSE in the main directory of -// the project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// MainService.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. diff --git a/src/Neo.CLI/Extensions.cs b/src/Neo.CLI/Extensions.cs index dec28a8e0d..b8331201be 100644 --- a/src/Neo.CLI/Extensions.cs +++ b/src/Neo.CLI/Extensions.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-cli is free software distributed under the MIT software -// license, see the accompanying file LICENSE in the main directory of -// the project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// Extensions.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. diff --git a/src/Neo.CLI/Program.cs b/src/Neo.CLI/Program.cs index 8a12b7dddb..b2a0f1b45c 100644 --- a/src/Neo.CLI/Program.cs +++ b/src/Neo.CLI/Program.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-cli is free software distributed under the MIT software -// license, see the accompanying file LICENSE in the main directory of -// the project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// Program.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. diff --git a/src/Neo.CLI/Settings.cs b/src/Neo.CLI/Settings.cs index df67a91237..cc7ec54fea 100644 --- a/src/Neo.CLI/Settings.cs +++ b/src/Neo.CLI/Settings.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-cli is free software distributed under the MIT software -// license, see the accompanying file LICENSE in the main directory of -// the project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// Settings.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. diff --git a/src/Neo.ConsoleService/CommandQuoteToken.cs b/src/Neo.ConsoleService/CommandQuoteToken.cs index 497a956a7f..865b7560d0 100644 --- a/src/Neo.ConsoleService/CommandQuoteToken.cs +++ b/src/Neo.ConsoleService/CommandQuoteToken.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The Neo.ConsoleService is free software distributed under the MIT -// software license, see the accompanying file LICENSE in the main directory -// of the project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// CommandQuoteToken.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. diff --git a/src/Neo.ConsoleService/CommandSpaceToken.cs b/src/Neo.ConsoleService/CommandSpaceToken.cs index 9a59f14410..87080d1983 100644 --- a/src/Neo.ConsoleService/CommandSpaceToken.cs +++ b/src/Neo.ConsoleService/CommandSpaceToken.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The Neo.ConsoleService is free software distributed under the MIT -// software license, see the accompanying file LICENSE in the main directory -// of the project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// CommandSpaceToken.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. diff --git a/src/Neo.ConsoleService/CommandStringToken.cs b/src/Neo.ConsoleService/CommandStringToken.cs index f4ee1e6c97..49a5702756 100644 --- a/src/Neo.ConsoleService/CommandStringToken.cs +++ b/src/Neo.ConsoleService/CommandStringToken.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The Neo.ConsoleService is free software distributed under the MIT -// software license, see the accompanying file LICENSE in the main directory -// of the project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// CommandStringToken.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. diff --git a/src/Neo.ConsoleService/CommandToken.cs b/src/Neo.ConsoleService/CommandToken.cs index d4088e8c9b..10e8336ecc 100644 --- a/src/Neo.ConsoleService/CommandToken.cs +++ b/src/Neo.ConsoleService/CommandToken.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The Neo.ConsoleService is free software distributed under the MIT -// software license, see the accompanying file LICENSE in the main directory -// of the project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// CommandToken.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. diff --git a/src/Neo.ConsoleService/CommandTokenType.cs b/src/Neo.ConsoleService/CommandTokenType.cs index 828ea34b4e..2e522c000a 100644 --- a/src/Neo.ConsoleService/CommandTokenType.cs +++ b/src/Neo.ConsoleService/CommandTokenType.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The Neo.ConsoleService is free software distributed under the MIT -// software license, see the accompanying file LICENSE in the main directory -// of the project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// CommandTokenType.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. diff --git a/src/Neo.ConsoleService/ConsoleColorSet.cs b/src/Neo.ConsoleService/ConsoleColorSet.cs index 465ab39f98..8e5c7f7b45 100644 --- a/src/Neo.ConsoleService/ConsoleColorSet.cs +++ b/src/Neo.ConsoleService/ConsoleColorSet.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The Neo.ConsoleService is free software distributed under the MIT -// software license, see the accompanying file LICENSE in the main directory -// of the project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// ConsoleColorSet.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. diff --git a/src/Neo.ConsoleService/ConsoleCommandAttribute.cs b/src/Neo.ConsoleService/ConsoleCommandAttribute.cs index 0d18a5d1db..c7831d617d 100644 --- a/src/Neo.ConsoleService/ConsoleCommandAttribute.cs +++ b/src/Neo.ConsoleService/ConsoleCommandAttribute.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The Neo.ConsoleService is free software distributed under the MIT -// software license, see the accompanying file LICENSE in the main directory -// of the project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// ConsoleCommandAttribute.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. diff --git a/src/Neo.ConsoleService/ConsoleCommandMethod.cs b/src/Neo.ConsoleService/ConsoleCommandMethod.cs index 55176ecbc3..3455d21bb4 100644 --- a/src/Neo.ConsoleService/ConsoleCommandMethod.cs +++ b/src/Neo.ConsoleService/ConsoleCommandMethod.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The Neo.ConsoleService is free software distributed under the MIT -// software license, see the accompanying file LICENSE in the main directory -// of the project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// ConsoleCommandMethod.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. diff --git a/src/Neo.ConsoleService/ConsoleHelper.cs b/src/Neo.ConsoleService/ConsoleHelper.cs index fdf6f180cd..19bfcd155a 100644 --- a/src/Neo.ConsoleService/ConsoleHelper.cs +++ b/src/Neo.ConsoleService/ConsoleHelper.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// ConsoleHelper.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; namespace Neo.ConsoleService diff --git a/src/Neo.ConsoleService/ConsoleServiceBase.cs b/src/Neo.ConsoleService/ConsoleServiceBase.cs index 8b4a54bdf3..5598dcaa45 100644 --- a/src/Neo.ConsoleService/ConsoleServiceBase.cs +++ b/src/Neo.ConsoleService/ConsoleServiceBase.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The Neo.ConsoleService is free software distributed under the MIT -// software license, see the accompanying file LICENSE in the main directory -// of the project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// ConsoleServiceBase.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. diff --git a/src/Neo.ConsoleService/Properties/AssemblyInfo.cs b/src/Neo.ConsoleService/Properties/AssemblyInfo.cs index 661513fb43..efa7107713 100644 --- a/src/Neo.ConsoleService/Properties/AssemblyInfo.cs +++ b/src/Neo.ConsoleService/Properties/AssemblyInfo.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The Neo.ConsoleService is free software distributed under the MIT -// software license, see the accompanying file LICENSE in the main directory -// of the project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// AssemblyInfo.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. diff --git a/src/Neo.ConsoleService/ServiceProxy.cs b/src/Neo.ConsoleService/ServiceProxy.cs index c8060f0d47..97a14601c7 100644 --- a/src/Neo.ConsoleService/ServiceProxy.cs +++ b/src/Neo.ConsoleService/ServiceProxy.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The Neo.ConsoleService is free software distributed under the MIT -// software license, see the accompanying file LICENSE in the main directory -// of the project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// ServiceProxy.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. diff --git a/src/Neo.GUI/GUI/BulkPayDialog.cs b/src/Neo.GUI/GUI/BulkPayDialog.cs index b33cb9edec..b67f9ae61c 100644 --- a/src/Neo.GUI/GUI/BulkPayDialog.cs +++ b/src/Neo.GUI/GUI/BulkPayDialog.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-gui is free software distributed under the MIT software -// license, see the accompanying file LICENSE in the main directory of -// the project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// BulkPayDialog.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. diff --git a/src/Neo.GUI/GUI/ChangePasswordDialog.cs b/src/Neo.GUI/GUI/ChangePasswordDialog.cs index 7bda7e93a1..f6ea079e41 100644 --- a/src/Neo.GUI/GUI/ChangePasswordDialog.cs +++ b/src/Neo.GUI/GUI/ChangePasswordDialog.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-gui is free software distributed under the MIT software -// license, see the accompanying file LICENSE in the main directory of -// the project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// ChangePasswordDialog.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. diff --git a/src/Neo.GUI/GUI/ConsoleForm.cs b/src/Neo.GUI/GUI/ConsoleForm.cs index 55deace519..79121608fd 100644 --- a/src/Neo.GUI/GUI/ConsoleForm.cs +++ b/src/Neo.GUI/GUI/ConsoleForm.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-gui is free software distributed under the MIT software -// license, see the accompanying file LICENSE in the main directory of -// the project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// ConsoleForm.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. diff --git a/src/Neo.GUI/GUI/CreateMultiSigContractDialog.cs b/src/Neo.GUI/GUI/CreateMultiSigContractDialog.cs index b94e6c5b1f..5dd10f858f 100644 --- a/src/Neo.GUI/GUI/CreateMultiSigContractDialog.cs +++ b/src/Neo.GUI/GUI/CreateMultiSigContractDialog.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-gui is free software distributed under the MIT software -// license, see the accompanying file LICENSE in the main directory of -// the project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// CreateMultiSigContractDialog.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. diff --git a/src/Neo.GUI/GUI/CreateWalletDialog.cs b/src/Neo.GUI/GUI/CreateWalletDialog.cs index 4573dad6d4..770cd07cac 100644 --- a/src/Neo.GUI/GUI/CreateWalletDialog.cs +++ b/src/Neo.GUI/GUI/CreateWalletDialog.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-gui is free software distributed under the MIT software -// license, see the accompanying file LICENSE in the main directory of -// the project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// CreateWalletDialog.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. diff --git a/src/Neo.GUI/GUI/DeployContractDialog.cs b/src/Neo.GUI/GUI/DeployContractDialog.cs index aa415ddd90..31ca5e6636 100644 --- a/src/Neo.GUI/GUI/DeployContractDialog.cs +++ b/src/Neo.GUI/GUI/DeployContractDialog.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-gui is free software distributed under the MIT software -// license, see the accompanying file LICENSE in the main directory of -// the project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// DeployContractDialog.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. diff --git a/src/Neo.GUI/GUI/DeveloperToolsForm.ContractParameters.cs b/src/Neo.GUI/GUI/DeveloperToolsForm.ContractParameters.cs index 8fc35b7b88..1912fe9152 100644 --- a/src/Neo.GUI/GUI/DeveloperToolsForm.ContractParameters.cs +++ b/src/Neo.GUI/GUI/DeveloperToolsForm.ContractParameters.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-gui is free software distributed under the MIT software -// license, see the accompanying file LICENSE in the main directory of -// the project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// DeveloperToolsForm.ContractParameters.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. diff --git a/src/Neo.GUI/GUI/DeveloperToolsForm.TxBuilder.cs b/src/Neo.GUI/GUI/DeveloperToolsForm.TxBuilder.cs index eabb5812b6..b8844fd85d 100644 --- a/src/Neo.GUI/GUI/DeveloperToolsForm.TxBuilder.cs +++ b/src/Neo.GUI/GUI/DeveloperToolsForm.TxBuilder.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-gui is free software distributed under the MIT software -// license, see the accompanying file LICENSE in the main directory of -// the project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// DeveloperToolsForm.TxBuilder.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. diff --git a/src/Neo.GUI/GUI/DeveloperToolsForm.cs b/src/Neo.GUI/GUI/DeveloperToolsForm.cs index c921599945..3c5d6ec952 100644 --- a/src/Neo.GUI/GUI/DeveloperToolsForm.cs +++ b/src/Neo.GUI/GUI/DeveloperToolsForm.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-gui is free software distributed under the MIT software -// license, see the accompanying file LICENSE in the main directory of -// the project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// DeveloperToolsForm.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. diff --git a/src/Neo.GUI/GUI/ElectionDialog.cs b/src/Neo.GUI/GUI/ElectionDialog.cs index c28bbfa068..ddc730589e 100644 --- a/src/Neo.GUI/GUI/ElectionDialog.cs +++ b/src/Neo.GUI/GUI/ElectionDialog.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-gui is free software distributed under the MIT software -// license, see the accompanying file LICENSE in the main directory of -// the project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// ElectionDialog.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. diff --git a/src/Neo.GUI/GUI/Helper.cs b/src/Neo.GUI/GUI/Helper.cs index 73897f63ca..fe06e78429 100644 --- a/src/Neo.GUI/GUI/Helper.cs +++ b/src/Neo.GUI/GUI/Helper.cs @@ -1,15 +1,15 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-gui is free software distributed under the MIT software -// license, see the accompanying file LICENSE in the main directory of -// the project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// Helper.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.Network.P2P; using Neo.Network.P2P.Payloads; using Neo.Properties; using Neo.SmartContract; diff --git a/src/Neo.GUI/GUI/ImportCustomContractDialog.cs b/src/Neo.GUI/GUI/ImportCustomContractDialog.cs index aa3eef48dc..b8df534699 100644 --- a/src/Neo.GUI/GUI/ImportCustomContractDialog.cs +++ b/src/Neo.GUI/GUI/ImportCustomContractDialog.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-gui is free software distributed under the MIT software -// license, see the accompanying file LICENSE in the main directory of -// the project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// ImportCustomContractDialog.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. diff --git a/src/Neo.GUI/GUI/ImportPrivateKeyDialog.cs b/src/Neo.GUI/GUI/ImportPrivateKeyDialog.cs index 30390eb9ce..9379f45900 100644 --- a/src/Neo.GUI/GUI/ImportPrivateKeyDialog.cs +++ b/src/Neo.GUI/GUI/ImportPrivateKeyDialog.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-gui is free software distributed under the MIT software -// license, see the accompanying file LICENSE in the main directory of -// the project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// ImportPrivateKeyDialog.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. diff --git a/src/Neo.GUI/GUI/InformationBox.cs b/src/Neo.GUI/GUI/InformationBox.cs index 7cdd881255..41516fd9db 100644 --- a/src/Neo.GUI/GUI/InformationBox.cs +++ b/src/Neo.GUI/GUI/InformationBox.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-gui is free software distributed under the MIT software -// license, see the accompanying file LICENSE in the main directory of -// the project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// InformationBox.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. diff --git a/src/Neo.GUI/GUI/InputBox.cs b/src/Neo.GUI/GUI/InputBox.cs index cdfc5a63eb..51884b3212 100644 --- a/src/Neo.GUI/GUI/InputBox.cs +++ b/src/Neo.GUI/GUI/InputBox.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-gui is free software distributed under the MIT software -// license, see the accompanying file LICENSE in the main directory of -// the project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// InputBox.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. diff --git a/src/Neo.GUI/GUI/InvokeContractDialog.cs b/src/Neo.GUI/GUI/InvokeContractDialog.cs index 3a92b5afda..4e46799f5c 100644 --- a/src/Neo.GUI/GUI/InvokeContractDialog.cs +++ b/src/Neo.GUI/GUI/InvokeContractDialog.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-gui is free software distributed under the MIT software -// license, see the accompanying file LICENSE in the main directory of -// the project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// InvokeContractDialog.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. diff --git a/src/Neo.GUI/GUI/MainForm.cs b/src/Neo.GUI/GUI/MainForm.cs index d8e89c083a..3114e542b6 100644 --- a/src/Neo.GUI/GUI/MainForm.cs +++ b/src/Neo.GUI/GUI/MainForm.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-gui is free software distributed under the MIT software -// license, see the accompanying file LICENSE in the main directory of -// the project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// MainForm.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. diff --git a/src/Neo.GUI/GUI/OpenWalletDialog.cs b/src/Neo.GUI/GUI/OpenWalletDialog.cs index aaeaa0bfd1..a43352a9ed 100644 --- a/src/Neo.GUI/GUI/OpenWalletDialog.cs +++ b/src/Neo.GUI/GUI/OpenWalletDialog.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-gui is free software distributed under the MIT software -// license, see the accompanying file LICENSE in the main directory of -// the project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// OpenWalletDialog.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. diff --git a/src/Neo.GUI/GUI/ParametersEditor.cs b/src/Neo.GUI/GUI/ParametersEditor.cs index 6a42f8d934..19eac82c31 100644 --- a/src/Neo.GUI/GUI/ParametersEditor.cs +++ b/src/Neo.GUI/GUI/ParametersEditor.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-gui is free software distributed under the MIT software -// license, see the accompanying file LICENSE in the main directory of -// the project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// ParametersEditor.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. diff --git a/src/Neo.GUI/GUI/PayToDialog.cs b/src/Neo.GUI/GUI/PayToDialog.cs index b4dc3abdbd..ad024b7ca5 100644 --- a/src/Neo.GUI/GUI/PayToDialog.cs +++ b/src/Neo.GUI/GUI/PayToDialog.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-gui is free software distributed under the MIT software -// license, see the accompanying file LICENSE in the main directory of -// the project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// PayToDialog.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. diff --git a/src/Neo.GUI/GUI/QueueReader.cs b/src/Neo.GUI/GUI/QueueReader.cs index 12f1260f3f..eac36f35f4 100644 --- a/src/Neo.GUI/GUI/QueueReader.cs +++ b/src/Neo.GUI/GUI/QueueReader.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-gui is free software distributed under the MIT software -// license, see the accompanying file LICENSE in the main directory of -// the project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// QueueReader.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. diff --git a/src/Neo.GUI/GUI/SigningDialog.cs b/src/Neo.GUI/GUI/SigningDialog.cs index f94d92c438..d235d9691a 100644 --- a/src/Neo.GUI/GUI/SigningDialog.cs +++ b/src/Neo.GUI/GUI/SigningDialog.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-gui is free software distributed under the MIT software -// license, see the accompanying file LICENSE in the main directory of -// the project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// SigningDialog.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. diff --git a/src/Neo.GUI/GUI/SigningTxDialog.cs b/src/Neo.GUI/GUI/SigningTxDialog.cs index 718cf07b63..16e79efe58 100644 --- a/src/Neo.GUI/GUI/SigningTxDialog.cs +++ b/src/Neo.GUI/GUI/SigningTxDialog.cs @@ -1,15 +1,15 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-gui is free software distributed under the MIT software -// license, see the accompanying file LICENSE in the main directory of -// the project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// SigningTxDialog.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.Network.P2P; using Neo.Network.P2P.Payloads; using Neo.Properties; using Neo.SmartContract; diff --git a/src/Neo.GUI/GUI/TextBoxWriter.cs b/src/Neo.GUI/GUI/TextBoxWriter.cs index c8be8a86ed..bf1bfc9c40 100644 --- a/src/Neo.GUI/GUI/TextBoxWriter.cs +++ b/src/Neo.GUI/GUI/TextBoxWriter.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-gui is free software distributed under the MIT software -// license, see the accompanying file LICENSE in the main directory of -// the project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// TextBoxWriter.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. diff --git a/src/Neo.GUI/GUI/TransferDialog.cs b/src/Neo.GUI/GUI/TransferDialog.cs index 16f7764d68..357dacb04a 100644 --- a/src/Neo.GUI/GUI/TransferDialog.cs +++ b/src/Neo.GUI/GUI/TransferDialog.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-gui is free software distributed under the MIT software -// license, see the accompanying file LICENSE in the main directory of -// the project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// TransferDialog.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. diff --git a/src/Neo.GUI/GUI/TxOutListBox.cs b/src/Neo.GUI/GUI/TxOutListBox.cs index 8157c7c252..d2e314ecaf 100644 --- a/src/Neo.GUI/GUI/TxOutListBox.cs +++ b/src/Neo.GUI/GUI/TxOutListBox.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-gui is free software distributed under the MIT software -// license, see the accompanying file LICENSE in the main directory of -// the project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// TxOutListBox.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. diff --git a/src/Neo.GUI/GUI/TxOutListBoxItem.cs b/src/Neo.GUI/GUI/TxOutListBoxItem.cs index 40356aa8ef..dfbb431ec2 100644 --- a/src/Neo.GUI/GUI/TxOutListBoxItem.cs +++ b/src/Neo.GUI/GUI/TxOutListBoxItem.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-gui is free software distributed under the MIT software -// license, see the accompanying file LICENSE in the main directory of -// the project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// TxOutListBoxItem.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. diff --git a/src/Neo.GUI/GUI/UpdateDialog.cs b/src/Neo.GUI/GUI/UpdateDialog.cs index c058c4dcb7..215d19d855 100644 --- a/src/Neo.GUI/GUI/UpdateDialog.cs +++ b/src/Neo.GUI/GUI/UpdateDialog.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-gui is free software distributed under the MIT software -// license, see the accompanying file LICENSE in the main directory of -// the project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// UpdateDialog.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. diff --git a/src/Neo.GUI/GUI/ViewContractDialog.cs b/src/Neo.GUI/GUI/ViewContractDialog.cs index ada56ef90f..00ea963328 100644 --- a/src/Neo.GUI/GUI/ViewContractDialog.cs +++ b/src/Neo.GUI/GUI/ViewContractDialog.cs @@ -1,17 +1,18 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-gui is free software distributed under the MIT software -// license, see the accompanying file LICENSE in the main directory of -// the project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// ViewContractDialog.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.Wallets; using System.Linq; using System.Windows.Forms; -using Neo.Wallets; namespace Neo.GUI { diff --git a/src/Neo.GUI/GUI/ViewPrivateKeyDialog.cs b/src/Neo.GUI/GUI/ViewPrivateKeyDialog.cs index f273595210..7beaa56271 100644 --- a/src/Neo.GUI/GUI/ViewPrivateKeyDialog.cs +++ b/src/Neo.GUI/GUI/ViewPrivateKeyDialog.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-gui is free software distributed under the MIT software -// license, see the accompanying file LICENSE in the main directory of -// the project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// ViewPrivateKeyDialog.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. diff --git a/src/Neo.GUI/GUI/VotingDialog.cs b/src/Neo.GUI/GUI/VotingDialog.cs index 9b827eb00e..d289cc48ca 100644 --- a/src/Neo.GUI/GUI/VotingDialog.cs +++ b/src/Neo.GUI/GUI/VotingDialog.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-gui is free software distributed under the MIT software -// license, see the accompanying file LICENSE in the main directory of -// the project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// VotingDialog.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. diff --git a/src/Neo.GUI/GUI/Wrappers/HexConverter.cs b/src/Neo.GUI/GUI/Wrappers/HexConverter.cs index 724af82b66..757bfd3b97 100644 --- a/src/Neo.GUI/GUI/Wrappers/HexConverter.cs +++ b/src/Neo.GUI/GUI/Wrappers/HexConverter.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-gui is free software distributed under the MIT software -// license, see the accompanying file LICENSE in the main directory of -// the project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// HexConverter.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. diff --git a/src/Neo.GUI/GUI/Wrappers/ScriptEditor.cs b/src/Neo.GUI/GUI/Wrappers/ScriptEditor.cs index 199c33b6f4..20bc894786 100644 --- a/src/Neo.GUI/GUI/Wrappers/ScriptEditor.cs +++ b/src/Neo.GUI/GUI/Wrappers/ScriptEditor.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-gui is free software distributed under the MIT software -// license, see the accompanying file LICENSE in the main directory of -// the project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// ScriptEditor.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. diff --git a/src/Neo.GUI/GUI/Wrappers/SignerWrapper.cs b/src/Neo.GUI/GUI/Wrappers/SignerWrapper.cs index 70f9d4a045..e022ae7746 100644 --- a/src/Neo.GUI/GUI/Wrappers/SignerWrapper.cs +++ b/src/Neo.GUI/GUI/Wrappers/SignerWrapper.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-gui is free software distributed under the MIT software -// license, see the accompanying file LICENSE in the main directory of -// the project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// SignerWrapper.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. diff --git a/src/Neo.GUI/GUI/Wrappers/TransactionAttributeWrapper.cs b/src/Neo.GUI/GUI/Wrappers/TransactionAttributeWrapper.cs index bb42f9e761..a348eb98d1 100644 --- a/src/Neo.GUI/GUI/Wrappers/TransactionAttributeWrapper.cs +++ b/src/Neo.GUI/GUI/Wrappers/TransactionAttributeWrapper.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-gui is free software distributed under the MIT software -// license, see the accompanying file LICENSE in the main directory of -// the project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// TransactionAttributeWrapper.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. diff --git a/src/Neo.GUI/GUI/Wrappers/TransactionWrapper.cs b/src/Neo.GUI/GUI/Wrappers/TransactionWrapper.cs index e1aeef4e96..86e84e9c87 100644 --- a/src/Neo.GUI/GUI/Wrappers/TransactionWrapper.cs +++ b/src/Neo.GUI/GUI/Wrappers/TransactionWrapper.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-gui is free software distributed under the MIT software -// license, see the accompanying file LICENSE in the main directory of -// the project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// TransactionWrapper.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. diff --git a/src/Neo.GUI/GUI/Wrappers/UIntBaseConverter.cs b/src/Neo.GUI/GUI/Wrappers/UIntBaseConverter.cs index 20d458577f..2def7ea4ab 100644 --- a/src/Neo.GUI/GUI/Wrappers/UIntBaseConverter.cs +++ b/src/Neo.GUI/GUI/Wrappers/UIntBaseConverter.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-gui is free software distributed under the MIT software -// license, see the accompanying file LICENSE in the main directory of -// the project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// UIntBaseConverter.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. diff --git a/src/Neo.GUI/GUI/Wrappers/WitnessWrapper.cs b/src/Neo.GUI/GUI/Wrappers/WitnessWrapper.cs index bc5ffddc09..1c78a34dd1 100644 --- a/src/Neo.GUI/GUI/Wrappers/WitnessWrapper.cs +++ b/src/Neo.GUI/GUI/Wrappers/WitnessWrapper.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-gui is free software distributed under the MIT software -// license, see the accompanying file LICENSE in the main directory of -// the project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// WitnessWrapper.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. diff --git a/src/Neo.GUI/IO/Actors/EventWrapper.cs b/src/Neo.GUI/IO/Actors/EventWrapper.cs index 77562aa6f4..67c488dc28 100644 --- a/src/Neo.GUI/IO/Actors/EventWrapper.cs +++ b/src/Neo.GUI/IO/Actors/EventWrapper.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-gui is free software distributed under the MIT software -// license, see the accompanying file LICENSE in the main directory of -// the project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// EventWrapper.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. diff --git a/src/Neo.GUI/Program.cs b/src/Neo.GUI/Program.cs index f872706ff5..fe8211975e 100644 --- a/src/Neo.GUI/Program.cs +++ b/src/Neo.GUI/Program.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-gui is free software distributed under the MIT software -// license, see the accompanying file LICENSE in the main directory of -// the project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// Program.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. diff --git a/src/Neo.Json/JArray.cs b/src/Neo.Json/JArray.cs index 0263c77a3a..30ac7c83a2 100644 --- a/src/Neo.Json/JArray.cs +++ b/src/Neo.Json/JArray.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The Neo.Json is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// JArray.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. diff --git a/src/Neo.Json/JBoolean.cs b/src/Neo.Json/JBoolean.cs index feb3d16b1d..0ca4901a86 100644 --- a/src/Neo.Json/JBoolean.cs +++ b/src/Neo.Json/JBoolean.cs @@ -1,8 +1,9 @@ -// Copyright (C) 2015-2022 The Neo Project. +// Copyright (C) 2015-2024 The Neo Project. // -// The Neo.Json is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// JBoolean.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 diff --git a/src/Neo.Json/JContainer.cs b/src/Neo.Json/JContainer.cs index 429fe68d81..5cc1bc7263 100644 --- a/src/Neo.Json/JContainer.cs +++ b/src/Neo.Json/JContainer.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The Neo.Json is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// JContainer.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. diff --git a/src/Neo.Json/JNumber.cs b/src/Neo.Json/JNumber.cs index 65f4991cd8..6c73a01b37 100644 --- a/src/Neo.Json/JNumber.cs +++ b/src/Neo.Json/JNumber.cs @@ -1,8 +1,9 @@ -// Copyright (C) 2015-2022 The Neo Project. +// Copyright (C) 2015-2024 The Neo Project. // -// The Neo.Json is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// JNumber.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 diff --git a/src/Neo.Json/JObject.cs b/src/Neo.Json/JObject.cs index dc26463210..adc6755b5e 100644 --- a/src/Neo.Json/JObject.cs +++ b/src/Neo.Json/JObject.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The Neo.Json is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// JObject.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. diff --git a/src/Neo.Json/JPathToken.cs b/src/Neo.Json/JPathToken.cs index b2d8a867fe..40054a1fb0 100644 --- a/src/Neo.Json/JPathToken.cs +++ b/src/Neo.Json/JPathToken.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The Neo.Json is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// JPathToken.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. diff --git a/src/Neo.Json/JPathTokenType.cs b/src/Neo.Json/JPathTokenType.cs index 7ec540372e..ea25a3609d 100644 --- a/src/Neo.Json/JPathTokenType.cs +++ b/src/Neo.Json/JPathTokenType.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The Neo.Json is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// JPathTokenType.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. diff --git a/src/Neo.Json/JString.cs b/src/Neo.Json/JString.cs index 42bc63937c..f6c5d155f3 100644 --- a/src/Neo.Json/JString.cs +++ b/src/Neo.Json/JString.cs @@ -1,8 +1,9 @@ -// Copyright (C) 2015-2022 The Neo Project. +// Copyright (C) 2015-2024 The Neo Project. // -// The Neo.Json is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// JString.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 diff --git a/src/Neo.Json/JToken.cs b/src/Neo.Json/JToken.cs index 8c38fb9bc4..bb6a510a69 100644 --- a/src/Neo.Json/JToken.cs +++ b/src/Neo.Json/JToken.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The Neo.Json is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// JToken.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. diff --git a/src/Neo.Json/OrderedDictionary.KeyCollection.cs b/src/Neo.Json/OrderedDictionary.KeyCollection.cs index bdc79411f3..13fbd62e85 100644 --- a/src/Neo.Json/OrderedDictionary.KeyCollection.cs +++ b/src/Neo.Json/OrderedDictionary.KeyCollection.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The Neo.Json is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// OrderedDictionary.KeyCollection.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. diff --git a/src/Neo.Json/OrderedDictionary.ValueCollection.cs b/src/Neo.Json/OrderedDictionary.ValueCollection.cs index f10425aca8..f7bb0c4359 100644 --- a/src/Neo.Json/OrderedDictionary.ValueCollection.cs +++ b/src/Neo.Json/OrderedDictionary.ValueCollection.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The Neo.Json is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// OrderedDictionary.ValueCollection.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. diff --git a/src/Neo.Json/OrderedDictionary.cs b/src/Neo.Json/OrderedDictionary.cs index 261b15a725..244121f304 100644 --- a/src/Neo.Json/OrderedDictionary.cs +++ b/src/Neo.Json/OrderedDictionary.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The Neo.Json is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// OrderedDictionary.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. diff --git a/src/Neo.Json/Properties/AssemblyInfo.cs b/src/Neo.Json/Properties/AssemblyInfo.cs index 1d0d02140b..9c3afc5d2e 100644 --- a/src/Neo.Json/Properties/AssemblyInfo.cs +++ b/src/Neo.Json/Properties/AssemblyInfo.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// AssemblyInfo.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.Runtime.CompilerServices; [assembly: InternalsVisibleTo("Neo.Json.UnitTests")] diff --git a/src/Neo.Json/Utility.cs b/src/Neo.Json/Utility.cs index 711ba25901..6fff7211ca 100644 --- a/src/Neo.Json/Utility.cs +++ b/src/Neo.Json/Utility.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The Neo.Json is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// Utility.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. diff --git a/src/Neo.VM/BadScriptException.cs b/src/Neo.VM/BadScriptException.cs index fcf4b9f2b4..1e7b250291 100644 --- a/src/Neo.VM/BadScriptException.cs +++ b/src/Neo.VM/BadScriptException.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-vm is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// BadScriptException.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. diff --git a/src/Neo.VM/CatchableException.cs b/src/Neo.VM/CatchableException.cs index 9235ac5c31..b4fd3f1655 100644 --- a/src/Neo.VM/CatchableException.cs +++ b/src/Neo.VM/CatchableException.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-vm is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// CatchableException.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. diff --git a/src/Neo.VM/Collections/OrderedDictionary.cs b/src/Neo.VM/Collections/OrderedDictionary.cs index 5f2d593067..92d8e8f3ad 100644 --- a/src/Neo.VM/Collections/OrderedDictionary.cs +++ b/src/Neo.VM/Collections/OrderedDictionary.cs @@ -1,8 +1,9 @@ -// Copyright (C) 2016-2023 The Neo Project. +// Copyright (C) 2015-2024 The Neo Project. // -// The neo-vm is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// OrderedDictionary.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 diff --git a/src/Neo.VM/Cryptography/BitOperations.cs b/src/Neo.VM/Cryptography/BitOperations.cs index 40fc0171af..c947b4de98 100644 --- a/src/Neo.VM/Cryptography/BitOperations.cs +++ b/src/Neo.VM/Cryptography/BitOperations.cs @@ -1,8 +1,9 @@ -// Copyright (C) 2016-2023 The Neo Project. +// Copyright (C) 2015-2024 The Neo Project. // -// The neo-vm is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// BitOperations.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 diff --git a/src/Neo.VM/Cryptography/Murmur32.cs b/src/Neo.VM/Cryptography/Murmur32.cs index 5cfa22d9b7..cfb6f8ccd1 100644 --- a/src/Neo.VM/Cryptography/Murmur32.cs +++ b/src/Neo.VM/Cryptography/Murmur32.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-vm is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// Murmur32.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. diff --git a/src/Neo.VM/Debugger.cs b/src/Neo.VM/Debugger.cs index fef4d87e75..a19ae7d64e 100644 --- a/src/Neo.VM/Debugger.cs +++ b/src/Neo.VM/Debugger.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-vm is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// Debugger.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. diff --git a/src/Neo.VM/EvaluationStack.cs b/src/Neo.VM/EvaluationStack.cs index 97b2a7f371..e038f38625 100644 --- a/src/Neo.VM/EvaluationStack.cs +++ b/src/Neo.VM/EvaluationStack.cs @@ -1,8 +1,9 @@ -// Copyright (C) 2016-2023 The Neo Project. +// Copyright (C) 2015-2024 The Neo Project. // -// The neo-vm is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// EvaluationStack.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 diff --git a/src/Neo.VM/ExceptionHandlingContext.cs b/src/Neo.VM/ExceptionHandlingContext.cs index dd3f03823e..a0c48c0b97 100644 --- a/src/Neo.VM/ExceptionHandlingContext.cs +++ b/src/Neo.VM/ExceptionHandlingContext.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-vm is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// ExceptionHandlingContext.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. diff --git a/src/Neo.VM/ExceptionHandlingState.cs b/src/Neo.VM/ExceptionHandlingState.cs index ea3a484a9c..119307a29d 100644 --- a/src/Neo.VM/ExceptionHandlingState.cs +++ b/src/Neo.VM/ExceptionHandlingState.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-vm is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// ExceptionHandlingState.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. diff --git a/src/Neo.VM/ExecutionContext.SharedStates.cs b/src/Neo.VM/ExecutionContext.SharedStates.cs index 0e037fcf0a..9903d50adf 100644 --- a/src/Neo.VM/ExecutionContext.SharedStates.cs +++ b/src/Neo.VM/ExecutionContext.SharedStates.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-vm is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// ExecutionContext.SharedStates.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. diff --git a/src/Neo.VM/ExecutionContext.cs b/src/Neo.VM/ExecutionContext.cs index be83be823e..5f3a18e077 100644 --- a/src/Neo.VM/ExecutionContext.cs +++ b/src/Neo.VM/ExecutionContext.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-vm is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// ExecutionContext.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. diff --git a/src/Neo.VM/ExecutionEngine.cs b/src/Neo.VM/ExecutionEngine.cs index ab344b32ef..9996e2c46d 100644 --- a/src/Neo.VM/ExecutionEngine.cs +++ b/src/Neo.VM/ExecutionEngine.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-vm is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// ExecutionEngine.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. diff --git a/src/Neo.VM/ExecutionEngineLimits.cs b/src/Neo.VM/ExecutionEngineLimits.cs index f31b40e5a1..6670572fb4 100644 --- a/src/Neo.VM/ExecutionEngineLimits.cs +++ b/src/Neo.VM/ExecutionEngineLimits.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-vm is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// ExecutionEngineLimits.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. diff --git a/src/Neo.VM/GlobalSuppressions.cs b/src/Neo.VM/GlobalSuppressions.cs index 12194f733e..acf6e71c9c 100644 --- a/src/Neo.VM/GlobalSuppressions.cs +++ b/src/Neo.VM/GlobalSuppressions.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-vm is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// GlobalSuppressions.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. diff --git a/src/Neo.VM/Instruction.cs b/src/Neo.VM/Instruction.cs index 48b48c94a3..b92e9e3bec 100644 --- a/src/Neo.VM/Instruction.cs +++ b/src/Neo.VM/Instruction.cs @@ -1,8 +1,9 @@ -// Copyright (C) 2016-2023 The Neo Project. +// Copyright (C) 2015-2024 The Neo Project. // -// The neo-vm is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Instruction.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 diff --git a/src/Neo.VM/IsExternalInit.cs b/src/Neo.VM/IsExternalInit.cs index 874f5f76ce..cf4ea93da2 100644 --- a/src/Neo.VM/IsExternalInit.cs +++ b/src/Neo.VM/IsExternalInit.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// IsExternalInit.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. + #if !NET5_0_OR_GREATER using System.ComponentModel; diff --git a/src/Neo.VM/OpCode.cs b/src/Neo.VM/OpCode.cs index 313e04a7d1..dd5f1574ea 100644 --- a/src/Neo.VM/OpCode.cs +++ b/src/Neo.VM/OpCode.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-vm is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// OpCode.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. diff --git a/src/Neo.VM/OperandSizeAttribute.cs b/src/Neo.VM/OperandSizeAttribute.cs index 1240989bb8..592c0a716a 100644 --- a/src/Neo.VM/OperandSizeAttribute.cs +++ b/src/Neo.VM/OperandSizeAttribute.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-vm is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// OperandSizeAttribute.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. diff --git a/src/Neo.VM/Properties/AssemblyInfo.cs b/src/Neo.VM/Properties/AssemblyInfo.cs index b25e1d9752..71329c03a1 100644 --- a/src/Neo.VM/Properties/AssemblyInfo.cs +++ b/src/Neo.VM/Properties/AssemblyInfo.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-vm is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// AssemblyInfo.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. diff --git a/src/Neo.VM/ReferenceCounter.cs b/src/Neo.VM/ReferenceCounter.cs index 63732646cd..be7844dac8 100644 --- a/src/Neo.VM/ReferenceCounter.cs +++ b/src/Neo.VM/ReferenceCounter.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-vm is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// ReferenceCounter.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. diff --git a/src/Neo.VM/ReferenceEqualityComparer.cs b/src/Neo.VM/ReferenceEqualityComparer.cs index 7c9d68ad64..4e8eec9d2d 100644 --- a/src/Neo.VM/ReferenceEqualityComparer.cs +++ b/src/Neo.VM/ReferenceEqualityComparer.cs @@ -1,8 +1,9 @@ -// Copyright (C) 2016-2023 The Neo Project. +// Copyright (C) 2015-2024 The Neo Project. // -// The neo-vm is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// ReferenceEqualityComparer.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 diff --git a/src/Neo.VM/Script.cs b/src/Neo.VM/Script.cs index 863fec9576..5f6b29c5b7 100644 --- a/src/Neo.VM/Script.cs +++ b/src/Neo.VM/Script.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-vm is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// Script.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. diff --git a/src/Neo.VM/ScriptBuilder.cs b/src/Neo.VM/ScriptBuilder.cs index d2cb995532..3b2f83171a 100644 --- a/src/Neo.VM/ScriptBuilder.cs +++ b/src/Neo.VM/ScriptBuilder.cs @@ -1,8 +1,9 @@ -// Copyright (C) 2016-2023 The Neo Project. +// Copyright (C) 2015-2024 The Neo Project. // -// The neo-vm is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// ScriptBuilder.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 diff --git a/src/Neo.VM/Slot.cs b/src/Neo.VM/Slot.cs index 9f4609f792..33b221a381 100644 --- a/src/Neo.VM/Slot.cs +++ b/src/Neo.VM/Slot.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-vm is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// Slot.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. diff --git a/src/Neo.VM/StronglyConnectedComponents/Tarjan.cs b/src/Neo.VM/StronglyConnectedComponents/Tarjan.cs index 6fe867cd80..5cb7531ab6 100644 --- a/src/Neo.VM/StronglyConnectedComponents/Tarjan.cs +++ b/src/Neo.VM/StronglyConnectedComponents/Tarjan.cs @@ -1,8 +1,9 @@ -// Copyright (C) 2016-2023 The Neo Project. +// Copyright (C) 2015-2024 The Neo Project. // -// The neo-vm is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Tarjan.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 diff --git a/src/Neo.VM/Types/Array.cs b/src/Neo.VM/Types/Array.cs index 780521415b..e15358a881 100644 --- a/src/Neo.VM/Types/Array.cs +++ b/src/Neo.VM/Types/Array.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-vm is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// Array.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. diff --git a/src/Neo.VM/Types/Boolean.cs b/src/Neo.VM/Types/Boolean.cs index 56f620438d..3b736c174e 100644 --- a/src/Neo.VM/Types/Boolean.cs +++ b/src/Neo.VM/Types/Boolean.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-vm is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// Boolean.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. diff --git a/src/Neo.VM/Types/Buffer.cs b/src/Neo.VM/Types/Buffer.cs index d80eecd4f5..5c71ce45f8 100644 --- a/src/Neo.VM/Types/Buffer.cs +++ b/src/Neo.VM/Types/Buffer.cs @@ -1,8 +1,9 @@ -// Copyright (C) 2016-2023 The Neo Project. +// Copyright (C) 2015-2024 The Neo Project. // -// The neo-vm is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Buffer.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 diff --git a/src/Neo.VM/Types/ByteString.cs b/src/Neo.VM/Types/ByteString.cs index ddfe062210..a22dff75b9 100644 --- a/src/Neo.VM/Types/ByteString.cs +++ b/src/Neo.VM/Types/ByteString.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-vm is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// ByteString.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. diff --git a/src/Neo.VM/Types/CompoundType.cs b/src/Neo.VM/Types/CompoundType.cs index b3592a1e8b..0050cc7e13 100644 --- a/src/Neo.VM/Types/CompoundType.cs +++ b/src/Neo.VM/Types/CompoundType.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-vm is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// CompoundType.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. diff --git a/src/Neo.VM/Types/Integer.cs b/src/Neo.VM/Types/Integer.cs index 04489fc54f..67bbc05efa 100644 --- a/src/Neo.VM/Types/Integer.cs +++ b/src/Neo.VM/Types/Integer.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-vm is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// Integer.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. diff --git a/src/Neo.VM/Types/InteropInterface.cs b/src/Neo.VM/Types/InteropInterface.cs index 44edf11b0f..c6d88af753 100644 --- a/src/Neo.VM/Types/InteropInterface.cs +++ b/src/Neo.VM/Types/InteropInterface.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-vm is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// InteropInterface.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. diff --git a/src/Neo.VM/Types/Map.cs b/src/Neo.VM/Types/Map.cs index 6be029614b..5df66fb897 100644 --- a/src/Neo.VM/Types/Map.cs +++ b/src/Neo.VM/Types/Map.cs @@ -1,8 +1,9 @@ -// Copyright (C) 2016-2023 The Neo Project. +// Copyright (C) 2015-2024 The Neo Project. // -// The neo-vm is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Map.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 diff --git a/src/Neo.VM/Types/Null.cs b/src/Neo.VM/Types/Null.cs index d342f422e3..9088a30b5d 100644 --- a/src/Neo.VM/Types/Null.cs +++ b/src/Neo.VM/Types/Null.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-vm is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// Null.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. diff --git a/src/Neo.VM/Types/Pointer.cs b/src/Neo.VM/Types/Pointer.cs index 5af77ed414..633a8fbadf 100644 --- a/src/Neo.VM/Types/Pointer.cs +++ b/src/Neo.VM/Types/Pointer.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-vm is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// Pointer.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. diff --git a/src/Neo.VM/Types/PrimitiveType.cs b/src/Neo.VM/Types/PrimitiveType.cs index 794804dcc9..8415b8a45c 100644 --- a/src/Neo.VM/Types/PrimitiveType.cs +++ b/src/Neo.VM/Types/PrimitiveType.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-vm is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// PrimitiveType.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. diff --git a/src/Neo.VM/Types/StackItem.Vertex.cs b/src/Neo.VM/Types/StackItem.Vertex.cs index 6458a568d8..a988d5db32 100644 --- a/src/Neo.VM/Types/StackItem.Vertex.cs +++ b/src/Neo.VM/Types/StackItem.Vertex.cs @@ -1,13 +1,15 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-vm is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// StackItem.Vertex.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.Linq; @@ -31,5 +33,8 @@ internal class ObjectReferenceEntry internal IEnumerable Successors => ObjectReferences?.Values.Where(p => p.References > 0).Select(p => p.Item) ?? System.Array.Empty(); internal void Reset() => (DFN, LowLink, OnStack) = (-1, 0, false); + + public override int GetHashCode() => + HashCode.Combine(GetSpan().ToArray()); } } diff --git a/src/Neo.VM/Types/StackItem.cs b/src/Neo.VM/Types/StackItem.cs index 94c39aee40..2d85becacc 100644 --- a/src/Neo.VM/Types/StackItem.cs +++ b/src/Neo.VM/Types/StackItem.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-vm is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// StackItem.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. diff --git a/src/Neo.VM/Types/StackItemType.cs b/src/Neo.VM/Types/StackItemType.cs index 47a8407a83..c65921e1ac 100644 --- a/src/Neo.VM/Types/StackItemType.cs +++ b/src/Neo.VM/Types/StackItemType.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-vm is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// StackItemType.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. diff --git a/src/Neo.VM/Types/Struct.cs b/src/Neo.VM/Types/Struct.cs index 07b21ba540..8170414363 100644 --- a/src/Neo.VM/Types/Struct.cs +++ b/src/Neo.VM/Types/Struct.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-vm is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// Struct.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. diff --git a/src/Neo.VM/Unsafe.cs b/src/Neo.VM/Unsafe.cs index 71d31311ae..e3f4366be2 100644 --- a/src/Neo.VM/Unsafe.cs +++ b/src/Neo.VM/Unsafe.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-vm is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// Unsafe.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. diff --git a/src/Neo.VM/Utility.cs b/src/Neo.VM/Utility.cs index 6601df9400..940c98d7d9 100644 --- a/src/Neo.VM/Utility.cs +++ b/src/Neo.VM/Utility.cs @@ -1,8 +1,9 @@ -// Copyright (C) 2016-2023 The Neo Project. +// Copyright (C) 2015-2024 The Neo Project. // -// The neo-vm is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Utility.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 diff --git a/src/Neo.VM/VMState.cs b/src/Neo.VM/VMState.cs index 6d441120bb..b9b0fa22d8 100644 --- a/src/Neo.VM/VMState.cs +++ b/src/Neo.VM/VMState.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-vm is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// VMState.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. diff --git a/src/Neo.VM/VMUnhandledException.cs b/src/Neo.VM/VMUnhandledException.cs index 7d3da757c5..78377059ae 100644 --- a/src/Neo.VM/VMUnhandledException.cs +++ b/src/Neo.VM/VMUnhandledException.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2016-2023 The Neo Project. -// -// The neo-vm is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// VMUnhandledException.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. diff --git a/src/Neo/BigDecimal.cs b/src/Neo/BigDecimal.cs index 0086ca8afb..1658ea9c8e 100644 --- a/src/Neo/BigDecimal.cs +++ b/src/Neo/BigDecimal.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// BigDecimal.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. @@ -24,17 +25,17 @@ public struct BigDecimal : IComparable, IEquatable /// /// The value of the number. /// - public BigInteger Value => value; + public readonly BigInteger Value => value; /// /// The number of decimal places for this number. /// - public byte Decimals => decimals; + public readonly byte Decimals => decimals; /// /// The sign of the number. /// - public int Sign => value.Sign; + public readonly int Sign => value.Sign; /// /// Initializes a new instance of the struct. @@ -92,7 +93,7 @@ public unsafe BigDecimal(decimal value, byte decimals) /// /// The new decimals field. /// The that has the new number of decimal places. - public BigDecimal ChangeDecimals(byte decimals) + public readonly BigDecimal ChangeDecimals(byte decimals) { if (this.decimals == decimals) return this; BigInteger value; @@ -128,7 +129,7 @@ public static BigDecimal Parse(string s, byte decimals) /// Gets a representing the number. /// /// The representing the number. - public override string ToString() + public override readonly string ToString() { BigInteger divisor = BigInteger.Pow(10, decimals); BigInteger result = BigInteger.DivRem(value, divisor, out BigInteger remainder); @@ -181,7 +182,7 @@ public static bool TryParse(string s, byte decimals, out BigDecimal result) return true; } - public int CompareTo(BigDecimal other) + public readonly int CompareTo(BigDecimal other) { BigInteger left = value, right = other.value; if (decimals < other.decimals) @@ -191,18 +192,18 @@ public int CompareTo(BigDecimal other) return left.CompareTo(right); } - public override bool Equals(object obj) + public override readonly bool Equals(object obj) { if (obj is not BigDecimal @decimal) return false; return Equals(@decimal); } - public bool Equals(BigDecimal other) + public readonly bool Equals(BigDecimal other) { return CompareTo(other) == 0; } - public override int GetHashCode() + public override readonly int GetHashCode() { BigInteger divisor = BigInteger.Pow(10, decimals); BigInteger result = BigInteger.DivRem(value, divisor, out BigInteger remainder); diff --git a/src/Neo/Cryptography/Base58.cs b/src/Neo/Cryptography/Base58.cs index 248c581059..adecc8b631 100644 --- a/src/Neo/Cryptography/Base58.cs +++ b/src/Neo/Cryptography/Base58.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// Base58.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. diff --git a/src/Neo/Cryptography/BloomFilter.cs b/src/Neo/Cryptography/BloomFilter.cs index 584d46bf0d..a1639678e5 100644 --- a/src/Neo/Cryptography/BloomFilter.cs +++ b/src/Neo/Cryptography/BloomFilter.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// BloomFilter.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. diff --git a/src/Neo/Cryptography/Crypto.cs b/src/Neo/Cryptography/Crypto.cs index b96ee1cc3c..e09b556d82 100644 --- a/src/Neo/Cryptography/Crypto.cs +++ b/src/Neo/Cryptography/Crypto.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// Crypto.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. diff --git a/src/Neo/Cryptography/ECC/ECCurve.cs b/src/Neo/Cryptography/ECC/ECCurve.cs index 8b4416d108..7da6c5f3b8 100644 --- a/src/Neo/Cryptography/ECC/ECCurve.cs +++ b/src/Neo/Cryptography/ECC/ECCurve.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// ECCurve.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. diff --git a/src/Neo/Cryptography/ECC/ECFieldElement.cs b/src/Neo/Cryptography/ECC/ECFieldElement.cs index 31bdb435e6..c00a779315 100644 --- a/src/Neo/Cryptography/ECC/ECFieldElement.cs +++ b/src/Neo/Cryptography/ECC/ECFieldElement.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// ECFieldElement.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. diff --git a/src/Neo/Cryptography/ECC/ECPoint.cs b/src/Neo/Cryptography/ECC/ECPoint.cs index d49a0641da..6b74232c81 100644 --- a/src/Neo/Cryptography/ECC/ECPoint.cs +++ b/src/Neo/Cryptography/ECC/ECPoint.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// ECPoint.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. diff --git a/src/Neo/Cryptography/Helper.cs b/src/Neo/Cryptography/Helper.cs index 6b78c665f8..2f0ad0ce35 100644 --- a/src/Neo/Cryptography/Helper.cs +++ b/src/Neo/Cryptography/Helper.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// Helper.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. diff --git a/src/Neo/Cryptography/MerkleTree.cs b/src/Neo/Cryptography/MerkleTree.cs index e813ec5e02..58d3856b2c 100644 --- a/src/Neo/Cryptography/MerkleTree.cs +++ b/src/Neo/Cryptography/MerkleTree.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// MerkleTree.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. diff --git a/src/Neo/Cryptography/MerkleTreeNode.cs b/src/Neo/Cryptography/MerkleTreeNode.cs index 189d0ef2ce..8fcc2dd5ce 100644 --- a/src/Neo/Cryptography/MerkleTreeNode.cs +++ b/src/Neo/Cryptography/MerkleTreeNode.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// MerkleTreeNode.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. diff --git a/src/Neo/Cryptography/Murmur128.cs b/src/Neo/Cryptography/Murmur128.cs index 490b707814..18e67a91ac 100644 --- a/src/Neo/Cryptography/Murmur128.cs +++ b/src/Neo/Cryptography/Murmur128.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// Murmur128.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. diff --git a/src/Neo/Cryptography/Murmur32.cs b/src/Neo/Cryptography/Murmur32.cs index c18d36847f..a48c5d6750 100644 --- a/src/Neo/Cryptography/Murmur32.cs +++ b/src/Neo/Cryptography/Murmur32.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// Murmur32.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. diff --git a/src/Neo/Cryptography/RIPEMD160Managed.cs b/src/Neo/Cryptography/RIPEMD160Managed.cs index 0b61ac295e..932c1cfea6 100644 --- a/src/Neo/Cryptography/RIPEMD160Managed.cs +++ b/src/Neo/Cryptography/RIPEMD160Managed.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// RIPEMD160Managed.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. diff --git a/src/Neo/Hardfork.cs b/src/Neo/Hardfork.cs index 5a9aef6b5c..a5decc1d0c 100644 --- a/src/Neo/Hardfork.cs +++ b/src/Neo/Hardfork.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// Hardfork.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. diff --git a/src/Neo/Helper.cs b/src/Neo/Helper.cs index 49e4e8efd4..00099bc148 100644 --- a/src/Neo/Helper.cs +++ b/src/Neo/Helper.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// Helper.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. diff --git a/src/Neo/IO/Actors/Idle.cs b/src/Neo/IO/Actors/Idle.cs index 8292bb9779..e722d057ee 100644 --- a/src/Neo/IO/Actors/Idle.cs +++ b/src/Neo/IO/Actors/Idle.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// Idle.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. diff --git a/src/Neo/IO/Actors/PriorityMailbox.cs b/src/Neo/IO/Actors/PriorityMailbox.cs index a5fa0bd2b0..0b08c04d70 100644 --- a/src/Neo/IO/Actors/PriorityMailbox.cs +++ b/src/Neo/IO/Actors/PriorityMailbox.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// PriorityMailbox.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. diff --git a/src/Neo/IO/Actors/PriorityMessageQueue.cs b/src/Neo/IO/Actors/PriorityMessageQueue.cs index 81aba26cd0..225720ec97 100644 --- a/src/Neo/IO/Actors/PriorityMessageQueue.cs +++ b/src/Neo/IO/Actors/PriorityMessageQueue.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// PriorityMessageQueue.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. diff --git a/src/Neo/IO/ByteArrayComparer.cs b/src/Neo/IO/ByteArrayComparer.cs index 13d8c30bd1..872052095c 100644 --- a/src/Neo/IO/ByteArrayComparer.cs +++ b/src/Neo/IO/ByteArrayComparer.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// ByteArrayComparer.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. diff --git a/src/Neo/IO/ByteArrayEqualityComparer.cs b/src/Neo/IO/ByteArrayEqualityComparer.cs index 2085bd2291..ffb5ad0e63 100644 --- a/src/Neo/IO/ByteArrayEqualityComparer.cs +++ b/src/Neo/IO/ByteArrayEqualityComparer.cs @@ -1,8 +1,9 @@ -// Copyright (C) 2015-2022 The Neo Project. +// Copyright (C) 2015-2024 The Neo Project. // -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// ByteArrayEqualityComparer.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 diff --git a/src/Neo/IO/Caching/Cache.cs b/src/Neo/IO/Caching/Cache.cs index f0c52774b9..5d89dd59b1 100644 --- a/src/Neo/IO/Caching/Cache.cs +++ b/src/Neo/IO/Caching/Cache.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// Cache.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. diff --git a/src/Neo/IO/Caching/ECPointCache.cs b/src/Neo/IO/Caching/ECPointCache.cs index 01e7a1ad16..a32671d30f 100644 --- a/src/Neo/IO/Caching/ECPointCache.cs +++ b/src/Neo/IO/Caching/ECPointCache.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// ECPointCache.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. diff --git a/src/Neo/IO/Caching/FIFOCache.cs b/src/Neo/IO/Caching/FIFOCache.cs index 755afb400a..af3e5e469d 100644 --- a/src/Neo/IO/Caching/FIFOCache.cs +++ b/src/Neo/IO/Caching/FIFOCache.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// FIFOCache.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. diff --git a/src/Neo/IO/Caching/HashSetCache.cs b/src/Neo/IO/Caching/HashSetCache.cs index 89bef03d2a..8870e0ecf0 100644 --- a/src/Neo/IO/Caching/HashSetCache.cs +++ b/src/Neo/IO/Caching/HashSetCache.cs @@ -1,8 +1,9 @@ -// Copyright (C) 2015-2022 The Neo Project. +// Copyright (C) 2015-2024 The Neo Project. // -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// HashSetCache.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 diff --git a/src/Neo/IO/Caching/IndexedQueue.cs b/src/Neo/IO/Caching/IndexedQueue.cs index 0db5f98ed9..54440a871b 100644 --- a/src/Neo/IO/Caching/IndexedQueue.cs +++ b/src/Neo/IO/Caching/IndexedQueue.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// IndexedQueue.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. diff --git a/src/Neo/IO/Caching/KeyedCollectionSlim.cs b/src/Neo/IO/Caching/KeyedCollectionSlim.cs index 935faf36b2..a24dd87e4c 100644 --- a/src/Neo/IO/Caching/KeyedCollectionSlim.cs +++ b/src/Neo/IO/Caching/KeyedCollectionSlim.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// KeyedCollectionSlim.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; diff --git a/src/Neo/IO/Caching/ReflectionCache.cs b/src/Neo/IO/Caching/ReflectionCache.cs index 590efc5c36..2fd8f5fceb 100644 --- a/src/Neo/IO/Caching/ReflectionCache.cs +++ b/src/Neo/IO/Caching/ReflectionCache.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// ReflectionCache.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. diff --git a/src/Neo/IO/Caching/ReflectionCacheAttribute.cs b/src/Neo/IO/Caching/ReflectionCacheAttribute.cs index 6281d9a52d..20aeb91320 100644 --- a/src/Neo/IO/Caching/ReflectionCacheAttribute.cs +++ b/src/Neo/IO/Caching/ReflectionCacheAttribute.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// ReflectionCacheAttribute.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. diff --git a/src/Neo/IO/Caching/RelayCache.cs b/src/Neo/IO/Caching/RelayCache.cs index 4442f17bd6..0f617f4d24 100644 --- a/src/Neo/IO/Caching/RelayCache.cs +++ b/src/Neo/IO/Caching/RelayCache.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// RelayCache.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. diff --git a/src/Neo/IO/Helper.cs b/src/Neo/IO/Helper.cs index adaf127081..7449dbfab9 100644 --- a/src/Neo/IO/Helper.cs +++ b/src/Neo/IO/Helper.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// Helper.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. diff --git a/src/Neo/IO/ISerializable.cs b/src/Neo/IO/ISerializable.cs index 614854edd0..3d90009a09 100644 --- a/src/Neo/IO/ISerializable.cs +++ b/src/Neo/IO/ISerializable.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// ISerializable.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. diff --git a/src/Neo/IO/MemoryReader.cs b/src/Neo/IO/MemoryReader.cs index d29eaae01d..ece7cb56be 100644 --- a/src/Neo/IO/MemoryReader.cs +++ b/src/Neo/IO/MemoryReader.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// MemoryReader.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. @@ -20,7 +21,7 @@ public ref struct MemoryReader private readonly ReadOnlySpan span; private int pos = 0; - public int Position => pos; + public readonly int Position => pos; public MemoryReader(ReadOnlyMemory memory) { @@ -29,13 +30,13 @@ public MemoryReader(ReadOnlyMemory memory) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void EnsurePosition(int move) + private readonly void EnsurePosition(int move) { if (pos + move > span.Length) throw new FormatException(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public byte Peek() + public readonly byte Peek() { EnsurePosition(1); return span[pos]; diff --git a/src/Neo/Ledger/Blockchain.ApplicationExecuted.cs b/src/Neo/Ledger/Blockchain.ApplicationExecuted.cs index c2bb6cf5b5..211ac14117 100644 --- a/src/Neo/Ledger/Blockchain.ApplicationExecuted.cs +++ b/src/Neo/Ledger/Blockchain.ApplicationExecuted.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// Blockchain.ApplicationExecuted.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. diff --git a/src/Neo/Ledger/Blockchain.cs b/src/Neo/Ledger/Blockchain.cs index b44595f722..d9fc3e1b3f 100644 --- a/src/Neo/Ledger/Blockchain.cs +++ b/src/Neo/Ledger/Blockchain.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// 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. diff --git a/src/Neo/Ledger/HeaderCache.cs b/src/Neo/Ledger/HeaderCache.cs index 4286fa2b3a..ac2208011f 100644 --- a/src/Neo/Ledger/HeaderCache.cs +++ b/src/Neo/Ledger/HeaderCache.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// HeaderCache.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. diff --git a/src/Neo/Ledger/MemoryPool.cs b/src/Neo/Ledger/MemoryPool.cs index a966835fc3..8e4ec64b22 100644 --- a/src/Neo/Ledger/MemoryPool.cs +++ b/src/Neo/Ledger/MemoryPool.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// MemoryPool.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. diff --git a/src/Neo/Ledger/PoolItem.cs b/src/Neo/Ledger/PoolItem.cs index 2fc7eda0b9..f8451c1cd9 100644 --- a/src/Neo/Ledger/PoolItem.cs +++ b/src/Neo/Ledger/PoolItem.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// PoolItem.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. diff --git a/src/Neo/Ledger/TransactionRemovalReason.cs b/src/Neo/Ledger/TransactionRemovalReason.cs index fa66b60981..42e11b3f75 100644 --- a/src/Neo/Ledger/TransactionRemovalReason.cs +++ b/src/Neo/Ledger/TransactionRemovalReason.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// TransactionRemovalReason.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. diff --git a/src/Neo/Ledger/TransactionRemovedEventArgs.cs b/src/Neo/Ledger/TransactionRemovedEventArgs.cs index de35dd115e..403b24a195 100644 --- a/src/Neo/Ledger/TransactionRemovedEventArgs.cs +++ b/src/Neo/Ledger/TransactionRemovedEventArgs.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// TransactionRemovedEventArgs.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. diff --git a/src/Neo/Ledger/TransactionRouter.cs b/src/Neo/Ledger/TransactionRouter.cs index 442cf91ccb..9cc0ed8a9e 100644 --- a/src/Neo/Ledger/TransactionRouter.cs +++ b/src/Neo/Ledger/TransactionRouter.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// TransactionRouter.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. diff --git a/src/Neo/Ledger/TransactionVerificationContext.cs b/src/Neo/Ledger/TransactionVerificationContext.cs index 5b6cc6cc9c..2300c6da30 100644 --- a/src/Neo/Ledger/TransactionVerificationContext.cs +++ b/src/Neo/Ledger/TransactionVerificationContext.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// TransactionVerificationContext.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. diff --git a/src/Neo/Ledger/VerifyResult.cs b/src/Neo/Ledger/VerifyResult.cs index 94c9e78bf8..b218288efa 100644 --- a/src/Neo/Ledger/VerifyResult.cs +++ b/src/Neo/Ledger/VerifyResult.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// VerifyResult.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. diff --git a/src/Neo/LogLevel.cs b/src/Neo/LogLevel.cs index ab794a1b18..5e3acca37c 100644 --- a/src/Neo/LogLevel.cs +++ b/src/Neo/LogLevel.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// LogLevel.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. diff --git a/src/Neo/NeoSystem.cs b/src/Neo/NeoSystem.cs index 11590377ad..09c78e3e9c 100644 --- a/src/Neo/NeoSystem.cs +++ b/src/Neo/NeoSystem.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// NeoSystem.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. diff --git a/src/Neo/Network/P2P/Capabilities/FullNodeCapability.cs b/src/Neo/Network/P2P/Capabilities/FullNodeCapability.cs index 6e29a05f0b..52bc765d7c 100644 --- a/src/Neo/Network/P2P/Capabilities/FullNodeCapability.cs +++ b/src/Neo/Network/P2P/Capabilities/FullNodeCapability.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// FullNodeCapability.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. diff --git a/src/Neo/Network/P2P/Capabilities/NodeCapability.cs b/src/Neo/Network/P2P/Capabilities/NodeCapability.cs index 880ec09750..7ff1d46e3f 100644 --- a/src/Neo/Network/P2P/Capabilities/NodeCapability.cs +++ b/src/Neo/Network/P2P/Capabilities/NodeCapability.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// NodeCapability.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. diff --git a/src/Neo/Network/P2P/Capabilities/NodeCapabilityType.cs b/src/Neo/Network/P2P/Capabilities/NodeCapabilityType.cs index f89bb2e6f3..94f37dfb4a 100644 --- a/src/Neo/Network/P2P/Capabilities/NodeCapabilityType.cs +++ b/src/Neo/Network/P2P/Capabilities/NodeCapabilityType.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// NodeCapabilityType.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. diff --git a/src/Neo/Network/P2P/Capabilities/ServerCapability.cs b/src/Neo/Network/P2P/Capabilities/ServerCapability.cs index a4f4a0ebf0..d2df4e9efd 100644 --- a/src/Neo/Network/P2P/Capabilities/ServerCapability.cs +++ b/src/Neo/Network/P2P/Capabilities/ServerCapability.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// ServerCapability.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. diff --git a/src/Neo/Network/P2P/ChannelsConfig.cs b/src/Neo/Network/P2P/ChannelsConfig.cs index a8d3861024..512a5ebb45 100644 --- a/src/Neo/Network/P2P/ChannelsConfig.cs +++ b/src/Neo/Network/P2P/ChannelsConfig.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// ChannelsConfig.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. diff --git a/src/Neo/Network/P2P/Connection.cs b/src/Neo/Network/P2P/Connection.cs index 9633879ead..15a74f06b4 100644 --- a/src/Neo/Network/P2P/Connection.cs +++ b/src/Neo/Network/P2P/Connection.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// Connection.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. diff --git a/src/Neo/Network/P2P/Helper.cs b/src/Neo/Network/P2P/Helper.cs index 1ac9a5d245..f171a7b0a3 100644 --- a/src/Neo/Network/P2P/Helper.cs +++ b/src/Neo/Network/P2P/Helper.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// Helper.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. diff --git a/src/Neo/Network/P2P/LocalNode.cs b/src/Neo/Network/P2P/LocalNode.cs index 5c980a957f..f0bce492d5 100644 --- a/src/Neo/Network/P2P/LocalNode.cs +++ b/src/Neo/Network/P2P/LocalNode.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// LocalNode.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. diff --git a/src/Neo/Network/P2P/Message.cs b/src/Neo/Network/P2P/Message.cs index 00242c5fec..9d3c63a85b 100644 --- a/src/Neo/Network/P2P/Message.cs +++ b/src/Neo/Network/P2P/Message.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// Message.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. diff --git a/src/Neo/Network/P2P/MessageCommand.cs b/src/Neo/Network/P2P/MessageCommand.cs index 1205903f2c..e0a5444dd5 100644 --- a/src/Neo/Network/P2P/MessageCommand.cs +++ b/src/Neo/Network/P2P/MessageCommand.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// MessageCommand.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. diff --git a/src/Neo/Network/P2P/MessageFlags.cs b/src/Neo/Network/P2P/MessageFlags.cs index 63413bee22..69466c9606 100644 --- a/src/Neo/Network/P2P/MessageFlags.cs +++ b/src/Neo/Network/P2P/MessageFlags.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// MessageFlags.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. diff --git a/src/Neo/Network/P2P/Payloads/AddrPayload.cs b/src/Neo/Network/P2P/Payloads/AddrPayload.cs index f038a01a8a..ebdceb65ec 100644 --- a/src/Neo/Network/P2P/Payloads/AddrPayload.cs +++ b/src/Neo/Network/P2P/Payloads/AddrPayload.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// AddrPayload.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. diff --git a/src/Neo/Network/P2P/Payloads/Block.cs b/src/Neo/Network/P2P/Payloads/Block.cs index 955bf98bf6..3c727b9886 100644 --- a/src/Neo/Network/P2P/Payloads/Block.cs +++ b/src/Neo/Network/P2P/Payloads/Block.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// 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. diff --git a/src/Neo/Network/P2P/Payloads/Conditions/AndCondition.cs b/src/Neo/Network/P2P/Payloads/Conditions/AndCondition.cs index 87bef93068..e395b10d5d 100644 --- a/src/Neo/Network/P2P/Payloads/Conditions/AndCondition.cs +++ b/src/Neo/Network/P2P/Payloads/Conditions/AndCondition.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// AndCondition.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. diff --git a/src/Neo/Network/P2P/Payloads/Conditions/BooleanCondition.cs b/src/Neo/Network/P2P/Payloads/Conditions/BooleanCondition.cs index 8fee03cf07..e7609fcbaf 100644 --- a/src/Neo/Network/P2P/Payloads/Conditions/BooleanCondition.cs +++ b/src/Neo/Network/P2P/Payloads/Conditions/BooleanCondition.cs @@ -1,20 +1,20 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// BooleanCondition.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.IO; using Neo.IO; using Neo.Json; using Neo.SmartContract; using Neo.VM; using Neo.VM.Types; +using System.IO; namespace Neo.Network.P2P.Payloads.Conditions { diff --git a/src/Neo/Network/P2P/Payloads/Conditions/CalledByContractCondition.cs b/src/Neo/Network/P2P/Payloads/Conditions/CalledByContractCondition.cs index 0c2a98b86c..f853743b72 100644 --- a/src/Neo/Network/P2P/Payloads/Conditions/CalledByContractCondition.cs +++ b/src/Neo/Network/P2P/Payloads/Conditions/CalledByContractCondition.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// CalledByContractCondition.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. @@ -13,7 +14,6 @@ using Neo.SmartContract; using Neo.VM; using Neo.VM.Types; -using System; using System.IO; namespace Neo.Network.P2P.Payloads.Conditions diff --git a/src/Neo/Network/P2P/Payloads/Conditions/CalledByEntryCondition.cs b/src/Neo/Network/P2P/Payloads/Conditions/CalledByEntryCondition.cs index 7e309f4e29..8f8e21f80a 100644 --- a/src/Neo/Network/P2P/Payloads/Conditions/CalledByEntryCondition.cs +++ b/src/Neo/Network/P2P/Payloads/Conditions/CalledByEntryCondition.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// CalledByEntryCondition.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. diff --git a/src/Neo/Network/P2P/Payloads/Conditions/CalledByGroupCondition.cs b/src/Neo/Network/P2P/Payloads/Conditions/CalledByGroupCondition.cs index 5c91c8bebd..82dab60fcf 100644 --- a/src/Neo/Network/P2P/Payloads/Conditions/CalledByGroupCondition.cs +++ b/src/Neo/Network/P2P/Payloads/Conditions/CalledByGroupCondition.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// CalledByGroupCondition.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. @@ -15,7 +16,6 @@ using Neo.SmartContract.Native; using Neo.VM; using Neo.VM.Types; -using System; using System.IO; using System.Linq; diff --git a/src/Neo/Network/P2P/Payloads/Conditions/GroupCondition.cs b/src/Neo/Network/P2P/Payloads/Conditions/GroupCondition.cs index 44299a751c..ee937aff8b 100644 --- a/src/Neo/Network/P2P/Payloads/Conditions/GroupCondition.cs +++ b/src/Neo/Network/P2P/Payloads/Conditions/GroupCondition.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// GroupCondition.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. @@ -15,7 +16,6 @@ using Neo.SmartContract.Native; using Neo.VM; using Neo.VM.Types; -using System; using System.IO; using System.Linq; diff --git a/src/Neo/Network/P2P/Payloads/Conditions/NotCondition.cs b/src/Neo/Network/P2P/Payloads/Conditions/NotCondition.cs index 6bb2c2c9de..83ecd4d973 100644 --- a/src/Neo/Network/P2P/Payloads/Conditions/NotCondition.cs +++ b/src/Neo/Network/P2P/Payloads/Conditions/NotCondition.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// NotCondition.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. diff --git a/src/Neo/Network/P2P/Payloads/Conditions/OrCondition.cs b/src/Neo/Network/P2P/Payloads/Conditions/OrCondition.cs index 99fb0490cf..b06fc922a8 100644 --- a/src/Neo/Network/P2P/Payloads/Conditions/OrCondition.cs +++ b/src/Neo/Network/P2P/Payloads/Conditions/OrCondition.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// OrCondition.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. diff --git a/src/Neo/Network/P2P/Payloads/Conditions/ScriptHashCondition.cs b/src/Neo/Network/P2P/Payloads/Conditions/ScriptHashCondition.cs index 84109b6a99..9199e1a9a2 100644 --- a/src/Neo/Network/P2P/Payloads/Conditions/ScriptHashCondition.cs +++ b/src/Neo/Network/P2P/Payloads/Conditions/ScriptHashCondition.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// ScriptHashCondition.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. @@ -13,7 +14,6 @@ using Neo.SmartContract; using Neo.VM; using Neo.VM.Types; -using System; using System.IO; namespace Neo.Network.P2P.Payloads.Conditions diff --git a/src/Neo/Network/P2P/Payloads/Conditions/WitnessCondition.cs b/src/Neo/Network/P2P/Payloads/Conditions/WitnessCondition.cs index eaed8ff02f..7738a6d4a8 100644 --- a/src/Neo/Network/P2P/Payloads/Conditions/WitnessCondition.cs +++ b/src/Neo/Network/P2P/Payloads/Conditions/WitnessCondition.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// WitnessCondition.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. diff --git a/src/Neo/Network/P2P/Payloads/Conditions/WitnessConditionType.cs b/src/Neo/Network/P2P/Payloads/Conditions/WitnessConditionType.cs index 63023ed50d..e86f7fc343 100644 --- a/src/Neo/Network/P2P/Payloads/Conditions/WitnessConditionType.cs +++ b/src/Neo/Network/P2P/Payloads/Conditions/WitnessConditionType.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// WitnessConditionType.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. diff --git a/src/Neo/Network/P2P/Payloads/Conflicts.cs b/src/Neo/Network/P2P/Payloads/Conflicts.cs index f8ef364365..082de2014d 100644 --- a/src/Neo/Network/P2P/Payloads/Conflicts.cs +++ b/src/Neo/Network/P2P/Payloads/Conflicts.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Conflicts.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.IO; using Neo.Json; using Neo.Persistence; diff --git a/src/Neo/Network/P2P/Payloads/ExtensiblePayload.cs b/src/Neo/Network/P2P/Payloads/ExtensiblePayload.cs index faf96626d1..306f6327ab 100644 --- a/src/Neo/Network/P2P/Payloads/ExtensiblePayload.cs +++ b/src/Neo/Network/P2P/Payloads/ExtensiblePayload.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// ExtensiblePayload.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. diff --git a/src/Neo/Network/P2P/Payloads/FilterAddPayload.cs b/src/Neo/Network/P2P/Payloads/FilterAddPayload.cs index 0e73e4e2b0..ff4aa1287b 100644 --- a/src/Neo/Network/P2P/Payloads/FilterAddPayload.cs +++ b/src/Neo/Network/P2P/Payloads/FilterAddPayload.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// FilterAddPayload.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. diff --git a/src/Neo/Network/P2P/Payloads/FilterLoadPayload.cs b/src/Neo/Network/P2P/Payloads/FilterLoadPayload.cs index dd0562df3c..2608e0e7b0 100644 --- a/src/Neo/Network/P2P/Payloads/FilterLoadPayload.cs +++ b/src/Neo/Network/P2P/Payloads/FilterLoadPayload.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// FilterLoadPayload.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. diff --git a/src/Neo/Network/P2P/Payloads/GetBlockByIndexPayload.cs b/src/Neo/Network/P2P/Payloads/GetBlockByIndexPayload.cs index 115bc14c3d..9d8d2b6b6c 100644 --- a/src/Neo/Network/P2P/Payloads/GetBlockByIndexPayload.cs +++ b/src/Neo/Network/P2P/Payloads/GetBlockByIndexPayload.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// GetBlockByIndexPayload.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. diff --git a/src/Neo/Network/P2P/Payloads/GetBlocksPayload.cs b/src/Neo/Network/P2P/Payloads/GetBlocksPayload.cs index ef1555a464..d12c8ae2cd 100644 --- a/src/Neo/Network/P2P/Payloads/GetBlocksPayload.cs +++ b/src/Neo/Network/P2P/Payloads/GetBlocksPayload.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// GetBlocksPayload.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. diff --git a/src/Neo/Network/P2P/Payloads/Header.cs b/src/Neo/Network/P2P/Payloads/Header.cs index d971ac2aaa..9519c1432c 100644 --- a/src/Neo/Network/P2P/Payloads/Header.cs +++ b/src/Neo/Network/P2P/Payloads/Header.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// Header.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. diff --git a/src/Neo/Network/P2P/Payloads/HeadersPayload.cs b/src/Neo/Network/P2P/Payloads/HeadersPayload.cs index 13be7cc82f..152ba32857 100644 --- a/src/Neo/Network/P2P/Payloads/HeadersPayload.cs +++ b/src/Neo/Network/P2P/Payloads/HeadersPayload.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// HeadersPayload.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. diff --git a/src/Neo/Network/P2P/Payloads/HighPriorityAttribute.cs b/src/Neo/Network/P2P/Payloads/HighPriorityAttribute.cs index 0891dba181..cf4d3eb77e 100644 --- a/src/Neo/Network/P2P/Payloads/HighPriorityAttribute.cs +++ b/src/Neo/Network/P2P/Payloads/HighPriorityAttribute.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// HighPriorityAttribute.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. diff --git a/src/Neo/Network/P2P/Payloads/IInventory.cs b/src/Neo/Network/P2P/Payloads/IInventory.cs index 43d42e2895..cab68da91e 100644 --- a/src/Neo/Network/P2P/Payloads/IInventory.cs +++ b/src/Neo/Network/P2P/Payloads/IInventory.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// IInventory.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. diff --git a/src/Neo/Network/P2P/Payloads/IVerifiable.cs b/src/Neo/Network/P2P/Payloads/IVerifiable.cs index 63a5c49f53..c39661bb61 100644 --- a/src/Neo/Network/P2P/Payloads/IVerifiable.cs +++ b/src/Neo/Network/P2P/Payloads/IVerifiable.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// IVerifiable.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. diff --git a/src/Neo/Network/P2P/Payloads/InvPayload.cs b/src/Neo/Network/P2P/Payloads/InvPayload.cs index 0959ecc145..aa4d340d99 100644 --- a/src/Neo/Network/P2P/Payloads/InvPayload.cs +++ b/src/Neo/Network/P2P/Payloads/InvPayload.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// InvPayload.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. diff --git a/src/Neo/Network/P2P/Payloads/InventoryType.cs b/src/Neo/Network/P2P/Payloads/InventoryType.cs index 3e20cc5c79..e2aee0ca6f 100644 --- a/src/Neo/Network/P2P/Payloads/InventoryType.cs +++ b/src/Neo/Network/P2P/Payloads/InventoryType.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// InventoryType.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. diff --git a/src/Neo/Network/P2P/Payloads/MerkleBlockPayload.cs b/src/Neo/Network/P2P/Payloads/MerkleBlockPayload.cs index fba40f192a..aebb17d5d9 100644 --- a/src/Neo/Network/P2P/Payloads/MerkleBlockPayload.cs +++ b/src/Neo/Network/P2P/Payloads/MerkleBlockPayload.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// MerkleBlockPayload.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. diff --git a/src/Neo/Network/P2P/Payloads/NetworkAddressWithTime.cs b/src/Neo/Network/P2P/Payloads/NetworkAddressWithTime.cs index 4e64d26661..d3cfd15f66 100644 --- a/src/Neo/Network/P2P/Payloads/NetworkAddressWithTime.cs +++ b/src/Neo/Network/P2P/Payloads/NetworkAddressWithTime.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// NetworkAddressWithTime.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. diff --git a/src/Neo/Network/P2P/Payloads/NotValidBefore.cs b/src/Neo/Network/P2P/Payloads/NotValidBefore.cs index e77693813b..382a60e8fc 100644 --- a/src/Neo/Network/P2P/Payloads/NotValidBefore.cs +++ b/src/Neo/Network/P2P/Payloads/NotValidBefore.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// NotValidBefore.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.IO; using Neo.Json; using Neo.Persistence; diff --git a/src/Neo/Network/P2P/Payloads/OracleResponse.cs b/src/Neo/Network/P2P/Payloads/OracleResponse.cs index 0babd9933a..2770f556a8 100644 --- a/src/Neo/Network/P2P/Payloads/OracleResponse.cs +++ b/src/Neo/Network/P2P/Payloads/OracleResponse.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// OracleResponse.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. diff --git a/src/Neo/Network/P2P/Payloads/OracleResponseCode.cs b/src/Neo/Network/P2P/Payloads/OracleResponseCode.cs index e2a09b205d..e94d9b1d96 100644 --- a/src/Neo/Network/P2P/Payloads/OracleResponseCode.cs +++ b/src/Neo/Network/P2P/Payloads/OracleResponseCode.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// OracleResponseCode.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. diff --git a/src/Neo/Network/P2P/Payloads/PingPayload.cs b/src/Neo/Network/P2P/Payloads/PingPayload.cs index d744702c3a..f6296a7713 100644 --- a/src/Neo/Network/P2P/Payloads/PingPayload.cs +++ b/src/Neo/Network/P2P/Payloads/PingPayload.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// PingPayload.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. diff --git a/src/Neo/Network/P2P/Payloads/Signer.cs b/src/Neo/Network/P2P/Payloads/Signer.cs index 321f5e16ec..2f96047323 100644 --- a/src/Neo/Network/P2P/Payloads/Signer.cs +++ b/src/Neo/Network/P2P/Payloads/Signer.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// Signer.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. diff --git a/src/Neo/Network/P2P/Payloads/Transaction.cs b/src/Neo/Network/P2P/Payloads/Transaction.cs index 73ae25bac8..69a1b179e9 100644 --- a/src/Neo/Network/P2P/Payloads/Transaction.cs +++ b/src/Neo/Network/P2P/Payloads/Transaction.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// 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. diff --git a/src/Neo/Network/P2P/Payloads/TransactionAttribute.cs b/src/Neo/Network/P2P/Payloads/TransactionAttribute.cs index 0da87a94f4..34af3453fe 100644 --- a/src/Neo/Network/P2P/Payloads/TransactionAttribute.cs +++ b/src/Neo/Network/P2P/Payloads/TransactionAttribute.cs @@ -1,20 +1,21 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// TransactionAttribute.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.IO; using Neo.IO; using Neo.IO.Caching; using Neo.Json; using Neo.Persistence; using Neo.SmartContract.Native; +using System; +using System.IO; namespace Neo.Network.P2P.Payloads { diff --git a/src/Neo/Network/P2P/Payloads/TransactionAttributeType.cs b/src/Neo/Network/P2P/Payloads/TransactionAttributeType.cs index 66dccb340b..116f136c07 100644 --- a/src/Neo/Network/P2P/Payloads/TransactionAttributeType.cs +++ b/src/Neo/Network/P2P/Payloads/TransactionAttributeType.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// TransactionAttributeType.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. diff --git a/src/Neo/Network/P2P/Payloads/VersionPayload.cs b/src/Neo/Network/P2P/Payloads/VersionPayload.cs index cde644b143..8cec6278e7 100644 --- a/src/Neo/Network/P2P/Payloads/VersionPayload.cs +++ b/src/Neo/Network/P2P/Payloads/VersionPayload.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// VersionPayload.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. diff --git a/src/Neo/Network/P2P/Payloads/Witness.cs b/src/Neo/Network/P2P/Payloads/Witness.cs index e8733bd9e2..34932cc7fb 100644 --- a/src/Neo/Network/P2P/Payloads/Witness.cs +++ b/src/Neo/Network/P2P/Payloads/Witness.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// Witness.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. diff --git a/src/Neo/Network/P2P/Payloads/WitnessRule.cs b/src/Neo/Network/P2P/Payloads/WitnessRule.cs index 15152776c2..3bac09e7f5 100644 --- a/src/Neo/Network/P2P/Payloads/WitnessRule.cs +++ b/src/Neo/Network/P2P/Payloads/WitnessRule.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// WitnessRule.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. diff --git a/src/Neo/Network/P2P/Payloads/WitnessRuleAction.cs b/src/Neo/Network/P2P/Payloads/WitnessRuleAction.cs index 24bed76f69..9b73879e69 100644 --- a/src/Neo/Network/P2P/Payloads/WitnessRuleAction.cs +++ b/src/Neo/Network/P2P/Payloads/WitnessRuleAction.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// WitnessRuleAction.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. diff --git a/src/Neo/Network/P2P/Payloads/WitnessScope.cs b/src/Neo/Network/P2P/Payloads/WitnessScope.cs index 1ac2815af2..c43dfa0f22 100644 --- a/src/Neo/Network/P2P/Payloads/WitnessScope.cs +++ b/src/Neo/Network/P2P/Payloads/WitnessScope.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// WitnessScope.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. diff --git a/src/Neo/Network/P2P/Peer.cs b/src/Neo/Network/P2P/Peer.cs index 54872640d7..3648b59086 100644 --- a/src/Neo/Network/P2P/Peer.cs +++ b/src/Neo/Network/P2P/Peer.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// Peer.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. diff --git a/src/Neo/Network/P2P/RemoteNode.ProtocolHandler.cs b/src/Neo/Network/P2P/RemoteNode.ProtocolHandler.cs index ffbc53c1cb..afd37e2d17 100644 --- a/src/Neo/Network/P2P/RemoteNode.ProtocolHandler.cs +++ b/src/Neo/Network/P2P/RemoteNode.ProtocolHandler.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// RemoteNode.ProtocolHandler.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. diff --git a/src/Neo/Network/P2P/RemoteNode.cs b/src/Neo/Network/P2P/RemoteNode.cs index 845455aa53..b38dd0a16a 100644 --- a/src/Neo/Network/P2P/RemoteNode.cs +++ b/src/Neo/Network/P2P/RemoteNode.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// RemoteNode.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. diff --git a/src/Neo/Network/P2P/TaskManager.cs b/src/Neo/Network/P2P/TaskManager.cs index 23d5941df1..1d24597154 100644 --- a/src/Neo/Network/P2P/TaskManager.cs +++ b/src/Neo/Network/P2P/TaskManager.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// TaskManager.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. diff --git a/src/Neo/Network/P2P/TaskSession.cs b/src/Neo/Network/P2P/TaskSession.cs index e7bea39107..a18db540af 100644 --- a/src/Neo/Network/P2P/TaskSession.cs +++ b/src/Neo/Network/P2P/TaskSession.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// TaskSession.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. diff --git a/src/Neo/Network/UPnP.cs b/src/Neo/Network/UPnP.cs index 3c1ea9c5a2..a80e6e69fb 100644 --- a/src/Neo/Network/UPnP.cs +++ b/src/Neo/Network/UPnP.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// UPnP.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. diff --git a/src/Neo/Persistence/ClonedCache.cs b/src/Neo/Persistence/ClonedCache.cs index 169dfc7e35..e2629e385d 100644 --- a/src/Neo/Persistence/ClonedCache.cs +++ b/src/Neo/Persistence/ClonedCache.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// ClonedCache.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. diff --git a/src/Neo/Persistence/DataCache.cs b/src/Neo/Persistence/DataCache.cs index 3c82c63eea..6a1a5236bc 100644 --- a/src/Neo/Persistence/DataCache.cs +++ b/src/Neo/Persistence/DataCache.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// DataCache.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. diff --git a/src/Neo/Persistence/IReadOnlyStore.cs b/src/Neo/Persistence/IReadOnlyStore.cs index 0dbf633726..4b6c3fe0ec 100644 --- a/src/Neo/Persistence/IReadOnlyStore.cs +++ b/src/Neo/Persistence/IReadOnlyStore.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// IReadOnlyStore.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. diff --git a/src/Neo/Persistence/ISnapshot.cs b/src/Neo/Persistence/ISnapshot.cs index 961e31ef0d..29f1577048 100644 --- a/src/Neo/Persistence/ISnapshot.cs +++ b/src/Neo/Persistence/ISnapshot.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// ISnapshot.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. diff --git a/src/Neo/Persistence/IStore.cs b/src/Neo/Persistence/IStore.cs index 0d91f45ad2..37ccdf2a83 100644 --- a/src/Neo/Persistence/IStore.cs +++ b/src/Neo/Persistence/IStore.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// IStore.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. diff --git a/src/Neo/Persistence/IStoreProvider.cs b/src/Neo/Persistence/IStoreProvider.cs index ef316e90c3..3714ef1e76 100644 --- a/src/Neo/Persistence/IStoreProvider.cs +++ b/src/Neo/Persistence/IStoreProvider.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// IStoreProvider.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. diff --git a/src/Neo/Persistence/MemorySnapshot.cs b/src/Neo/Persistence/MemorySnapshot.cs index 586ee72e26..756a4c83b2 100644 --- a/src/Neo/Persistence/MemorySnapshot.cs +++ b/src/Neo/Persistence/MemorySnapshot.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// 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. diff --git a/src/Neo/Persistence/MemoryStore.cs b/src/Neo/Persistence/MemoryStore.cs index 200c704ad0..91d542a94b 100644 --- a/src/Neo/Persistence/MemoryStore.cs +++ b/src/Neo/Persistence/MemoryStore.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// MemoryStore.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. diff --git a/src/Neo/Persistence/SeekDirection.cs b/src/Neo/Persistence/SeekDirection.cs index e7a0ea8a2e..4155ace94f 100644 --- a/src/Neo/Persistence/SeekDirection.cs +++ b/src/Neo/Persistence/SeekDirection.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// SeekDirection.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. diff --git a/src/Neo/Persistence/SnapshotCache.cs b/src/Neo/Persistence/SnapshotCache.cs index e05d9e8fcc..e441f977c0 100644 --- a/src/Neo/Persistence/SnapshotCache.cs +++ b/src/Neo/Persistence/SnapshotCache.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// SnapshotCache.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. diff --git a/src/Neo/Persistence/StoreFactory.cs b/src/Neo/Persistence/StoreFactory.cs index c6e9fd34dc..66d600f546 100644 --- a/src/Neo/Persistence/StoreFactory.cs +++ b/src/Neo/Persistence/StoreFactory.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// StoreFactory.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. diff --git a/src/Neo/Persistence/TrackState.cs b/src/Neo/Persistence/TrackState.cs index 73684252af..a2780d62a8 100644 --- a/src/Neo/Persistence/TrackState.cs +++ b/src/Neo/Persistence/TrackState.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// TrackState.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. diff --git a/src/Neo/Plugins/Plugin.cs b/src/Neo/Plugins/Plugin.cs index be6bb9b4f6..248301af56 100644 --- a/src/Neo/Plugins/Plugin.cs +++ b/src/Neo/Plugins/Plugin.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// Plugin.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. diff --git a/src/Neo/Properties/AssemblyInfo.cs b/src/Neo/Properties/AssemblyInfo.cs index c82a7bcfc2..8d07419cae 100644 --- a/src/Neo/Properties/AssemblyInfo.cs +++ b/src/Neo/Properties/AssemblyInfo.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// AssemblyInfo.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.Runtime.CompilerServices; [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")] diff --git a/src/Neo/ProtocolSettings.cs b/src/Neo/ProtocolSettings.cs index 74807e4d97..f38e169d33 100644 --- a/src/Neo/ProtocolSettings.cs +++ b/src/Neo/ProtocolSettings.cs @@ -1,20 +1,21 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// ProtocolSettings.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 Neo.Cryptography.ECC; +using Neo.Network.P2P.Payloads; using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; -using Microsoft.Extensions.Configuration; -using Neo.Cryptography.ECC; -using Neo.Network.P2P.Payloads; namespace Neo { diff --git a/src/Neo/SmartContract/ApplicationEngine.Contract.cs b/src/Neo/SmartContract/ApplicationEngine.Contract.cs index 059c9eef07..5e45ba4645 100644 --- a/src/Neo/SmartContract/ApplicationEngine.Contract.cs +++ b/src/Neo/SmartContract/ApplicationEngine.Contract.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// ApplicationEngine.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. diff --git a/src/Neo/SmartContract/ApplicationEngine.Crypto.cs b/src/Neo/SmartContract/ApplicationEngine.Crypto.cs index 7d7f1ec8d4..1a8b2c7d6d 100644 --- a/src/Neo/SmartContract/ApplicationEngine.Crypto.cs +++ b/src/Neo/SmartContract/ApplicationEngine.Crypto.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// ApplicationEngine.Crypto.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. diff --git a/src/Neo/SmartContract/ApplicationEngine.Iterator.cs b/src/Neo/SmartContract/ApplicationEngine.Iterator.cs index d9d6f54f18..2ac9df7474 100644 --- a/src/Neo/SmartContract/ApplicationEngine.Iterator.cs +++ b/src/Neo/SmartContract/ApplicationEngine.Iterator.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// ApplicationEngine.Iterator.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. diff --git a/src/Neo/SmartContract/ApplicationEngine.OpCodePrices.cs b/src/Neo/SmartContract/ApplicationEngine.OpCodePrices.cs index 5d8ea68016..fb3835e14d 100644 --- a/src/Neo/SmartContract/ApplicationEngine.OpCodePrices.cs +++ b/src/Neo/SmartContract/ApplicationEngine.OpCodePrices.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// ApplicationEngine.OpCodePrices.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. diff --git a/src/Neo/SmartContract/ApplicationEngine.Runtime.cs b/src/Neo/SmartContract/ApplicationEngine.Runtime.cs index 5fde33e6b5..4314952eec 100644 --- a/src/Neo/SmartContract/ApplicationEngine.Runtime.cs +++ b/src/Neo/SmartContract/ApplicationEngine.Runtime.cs @@ -1,24 +1,25 @@ -// Copyright (C) 2015-2023 The Neo Project. +// Copyright (C) 2015-2024 The Neo Project. // -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// ApplicationEngine.Runtime.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.IO; -using System.Linq; -using System.Numerics; using Neo.Cryptography.ECC; using Neo.IO; using Neo.Network.P2P.Payloads; using Neo.SmartContract.Native; using Neo.VM; using Neo.VM.Types; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Numerics; using Array = Neo.VM.Types.Array; namespace Neo.SmartContract diff --git a/src/Neo/SmartContract/ApplicationEngine.Storage.cs b/src/Neo/SmartContract/ApplicationEngine.Storage.cs index cfa323e227..2d57388d11 100644 --- a/src/Neo/SmartContract/ApplicationEngine.Storage.cs +++ b/src/Neo/SmartContract/ApplicationEngine.Storage.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// ApplicationEngine.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. diff --git a/src/Neo/SmartContract/ApplicationEngine.cs b/src/Neo/SmartContract/ApplicationEngine.cs index a67b622200..ba161e6951 100644 --- a/src/Neo/SmartContract/ApplicationEngine.cs +++ b/src/Neo/SmartContract/ApplicationEngine.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// ApplicationEngine.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. diff --git a/src/Neo/SmartContract/BinarySerializer.cs b/src/Neo/SmartContract/BinarySerializer.cs index 8febeb25e2..2bdeced678 100644 --- a/src/Neo/SmartContract/BinarySerializer.cs +++ b/src/Neo/SmartContract/BinarySerializer.cs @@ -1,21 +1,22 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// BinarySerializer.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.IO; +using Neo.VM; +using Neo.VM.Types; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Numerics; -using Neo.IO; -using Neo.VM; -using Neo.VM.Types; using Array = Neo.VM.Types.Array; using Boolean = Neo.VM.Types.Boolean; using Buffer = Neo.VM.Types.Buffer; diff --git a/src/Neo/SmartContract/CallFlags.cs b/src/Neo/SmartContract/CallFlags.cs index b79aa8fa80..eb0d0de92d 100644 --- a/src/Neo/SmartContract/CallFlags.cs +++ b/src/Neo/SmartContract/CallFlags.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// CallFlags.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. diff --git a/src/Neo/SmartContract/Contract.cs b/src/Neo/SmartContract/Contract.cs index 6396d3a5a2..dc60c42d50 100644 --- a/src/Neo/SmartContract/Contract.cs +++ b/src/Neo/SmartContract/Contract.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// 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. diff --git a/src/Neo/SmartContract/ContractParameter.cs b/src/Neo/SmartContract/ContractParameter.cs index ba8583934b..027fa50e00 100644 --- a/src/Neo/SmartContract/ContractParameter.cs +++ b/src/Neo/SmartContract/ContractParameter.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// ContractParameter.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. diff --git a/src/Neo/SmartContract/ContractParameterType.cs b/src/Neo/SmartContract/ContractParameterType.cs index 5c030d0cf3..037927a7f0 100644 --- a/src/Neo/SmartContract/ContractParameterType.cs +++ b/src/Neo/SmartContract/ContractParameterType.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// ContractParameterType.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. diff --git a/src/Neo/SmartContract/ContractParametersContext.cs b/src/Neo/SmartContract/ContractParametersContext.cs index b042f4e263..f6a18e081d 100644 --- a/src/Neo/SmartContract/ContractParametersContext.cs +++ b/src/Neo/SmartContract/ContractParametersContext.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// ContractParametersContext.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. diff --git a/src/Neo/SmartContract/ContractState.cs b/src/Neo/SmartContract/ContractState.cs index 53f90cd30a..83ac9d3353 100644 --- a/src/Neo/SmartContract/ContractState.cs +++ b/src/Neo/SmartContract/ContractState.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// ContractState.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. diff --git a/src/Neo/SmartContract/ContractTask.cs b/src/Neo/SmartContract/ContractTask.cs index 56cd06368c..523b8b115a 100644 --- a/src/Neo/SmartContract/ContractTask.cs +++ b/src/Neo/SmartContract/ContractTask.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// ContractTask.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. diff --git a/src/Neo/SmartContract/ContractTaskAwaiter.cs b/src/Neo/SmartContract/ContractTaskAwaiter.cs index e3b93cca02..a0a0c9a1bb 100644 --- a/src/Neo/SmartContract/ContractTaskAwaiter.cs +++ b/src/Neo/SmartContract/ContractTaskAwaiter.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// ContractTaskAwaiter.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. diff --git a/src/Neo/SmartContract/ContractTaskMethodBuilder.cs b/src/Neo/SmartContract/ContractTaskMethodBuilder.cs index 0234950cb7..83090bf583 100644 --- a/src/Neo/SmartContract/ContractTaskMethodBuilder.cs +++ b/src/Neo/SmartContract/ContractTaskMethodBuilder.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// ContractTaskMethodBuilder.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. diff --git a/src/Neo/SmartContract/DeployedContract.cs b/src/Neo/SmartContract/DeployedContract.cs index 9096f95870..0587a029e5 100644 --- a/src/Neo/SmartContract/DeployedContract.cs +++ b/src/Neo/SmartContract/DeployedContract.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// DeployedContract.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. diff --git a/src/Neo/SmartContract/ExecutionContextState.cs b/src/Neo/SmartContract/ExecutionContextState.cs index 5e3aa3ef42..8b61ff1197 100644 --- a/src/Neo/SmartContract/ExecutionContextState.cs +++ b/src/Neo/SmartContract/ExecutionContextState.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// ExecutionContextState.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. diff --git a/src/Neo/SmartContract/FindOptions.cs b/src/Neo/SmartContract/FindOptions.cs index ab23d3bff5..28445c9142 100644 --- a/src/Neo/SmartContract/FindOptions.cs +++ b/src/Neo/SmartContract/FindOptions.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// FindOptions.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. diff --git a/src/Neo/SmartContract/Helper.cs b/src/Neo/SmartContract/Helper.cs index 73b19f9616..5045c74717 100644 --- a/src/Neo/SmartContract/Helper.cs +++ b/src/Neo/SmartContract/Helper.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// Helper.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. diff --git a/src/Neo/SmartContract/IApplicationEngineProvider.cs b/src/Neo/SmartContract/IApplicationEngineProvider.cs index cc440016b7..ef06c6b92c 100644 --- a/src/Neo/SmartContract/IApplicationEngineProvider.cs +++ b/src/Neo/SmartContract/IApplicationEngineProvider.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// IApplicationEngineProvider.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. diff --git a/src/Neo/SmartContract/IDiagnostic.cs b/src/Neo/SmartContract/IDiagnostic.cs index 9fee923b8f..4c888b805a 100644 --- a/src/Neo/SmartContract/IDiagnostic.cs +++ b/src/Neo/SmartContract/IDiagnostic.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// IDiagnostic.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. diff --git a/src/Neo/SmartContract/IInteroperable.cs b/src/Neo/SmartContract/IInteroperable.cs index 11be45a118..5254898efe 100644 --- a/src/Neo/SmartContract/IInteroperable.cs +++ b/src/Neo/SmartContract/IInteroperable.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// IInteroperable.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. diff --git a/src/Neo/SmartContract/InteropDescriptor.cs b/src/Neo/SmartContract/InteropDescriptor.cs index e6f066a1d1..29c88f46ed 100644 --- a/src/Neo/SmartContract/InteropDescriptor.cs +++ b/src/Neo/SmartContract/InteropDescriptor.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// InteropDescriptor.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. diff --git a/src/Neo/SmartContract/InteropParameterDescriptor.cs b/src/Neo/SmartContract/InteropParameterDescriptor.cs index e7cdb94893..6a65beb93f 100644 --- a/src/Neo/SmartContract/InteropParameterDescriptor.cs +++ b/src/Neo/SmartContract/InteropParameterDescriptor.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// InteropParameterDescriptor.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. diff --git a/src/Neo/SmartContract/Iterators/IIterator.cs b/src/Neo/SmartContract/Iterators/IIterator.cs index dc576e735d..78c42f1abd 100644 --- a/src/Neo/SmartContract/Iterators/IIterator.cs +++ b/src/Neo/SmartContract/Iterators/IIterator.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// IIterator.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. diff --git a/src/Neo/SmartContract/Iterators/StorageIterator.cs b/src/Neo/SmartContract/Iterators/StorageIterator.cs index 08f6b13643..397333ad7c 100644 --- a/src/Neo/SmartContract/Iterators/StorageIterator.cs +++ b/src/Neo/SmartContract/Iterators/StorageIterator.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// StorageIterator.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. diff --git a/src/Neo/SmartContract/JsonSerializer.cs b/src/Neo/SmartContract/JsonSerializer.cs index 06eb1d5c22..4d77104a6e 100644 --- a/src/Neo/SmartContract/JsonSerializer.cs +++ b/src/Neo/SmartContract/JsonSerializer.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// JsonSerializer.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. diff --git a/src/Neo/SmartContract/KeyBuilder.cs b/src/Neo/SmartContract/KeyBuilder.cs index 617c8879d1..4648b9baa9 100644 --- a/src/Neo/SmartContract/KeyBuilder.cs +++ b/src/Neo/SmartContract/KeyBuilder.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// KeyBuilder.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. diff --git a/src/Neo/SmartContract/LogEventArgs.cs b/src/Neo/SmartContract/LogEventArgs.cs index 623b8dc3d5..1614438dea 100644 --- a/src/Neo/SmartContract/LogEventArgs.cs +++ b/src/Neo/SmartContract/LogEventArgs.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// LogEventArgs.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. diff --git a/src/Neo/SmartContract/Manifest/ContractAbi.cs b/src/Neo/SmartContract/Manifest/ContractAbi.cs index 709668391c..3660d1a99e 100644 --- a/src/Neo/SmartContract/Manifest/ContractAbi.cs +++ b/src/Neo/SmartContract/Manifest/ContractAbi.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// ContractAbi.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. diff --git a/src/Neo/SmartContract/Manifest/ContractEventDescriptor.cs b/src/Neo/SmartContract/Manifest/ContractEventDescriptor.cs index 1b6bd24fe7..90227dd78d 100644 --- a/src/Neo/SmartContract/Manifest/ContractEventDescriptor.cs +++ b/src/Neo/SmartContract/Manifest/ContractEventDescriptor.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// ContractEventDescriptor.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. diff --git a/src/Neo/SmartContract/Manifest/ContractGroup.cs b/src/Neo/SmartContract/Manifest/ContractGroup.cs index ebb0dbd12c..231354327c 100644 --- a/src/Neo/SmartContract/Manifest/ContractGroup.cs +++ b/src/Neo/SmartContract/Manifest/ContractGroup.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// ContractGroup.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. diff --git a/src/Neo/SmartContract/Manifest/ContractManifest.cs b/src/Neo/SmartContract/Manifest/ContractManifest.cs index a1d3f62fd9..078e8fd35e 100644 --- a/src/Neo/SmartContract/Manifest/ContractManifest.cs +++ b/src/Neo/SmartContract/Manifest/ContractManifest.cs @@ -1,19 +1,20 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// ContractManifest.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.Linq; using Neo.IO; using Neo.Json; using Neo.VM; using Neo.VM.Types; +using System; +using System.Linq; using Array = Neo.VM.Types.Array; namespace Neo.SmartContract.Manifest diff --git a/src/Neo/SmartContract/Manifest/ContractMethodDescriptor.cs b/src/Neo/SmartContract/Manifest/ContractMethodDescriptor.cs index 45041d54b3..646ee76c46 100644 --- a/src/Neo/SmartContract/Manifest/ContractMethodDescriptor.cs +++ b/src/Neo/SmartContract/Manifest/ContractMethodDescriptor.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// ContractMethodDescriptor.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. diff --git a/src/Neo/SmartContract/Manifest/ContractParameterDefinition.cs b/src/Neo/SmartContract/Manifest/ContractParameterDefinition.cs index f54abd8c90..a393bb02b1 100644 --- a/src/Neo/SmartContract/Manifest/ContractParameterDefinition.cs +++ b/src/Neo/SmartContract/Manifest/ContractParameterDefinition.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// ContractParameterDefinition.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. diff --git a/src/Neo/SmartContract/Manifest/ContractPermission.cs b/src/Neo/SmartContract/Manifest/ContractPermission.cs index a99c63c52b..44c67fd9a1 100644 --- a/src/Neo/SmartContract/Manifest/ContractPermission.cs +++ b/src/Neo/SmartContract/Manifest/ContractPermission.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// ContractPermission.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. diff --git a/src/Neo/SmartContract/Manifest/ContractPermissionDescriptor.cs b/src/Neo/SmartContract/Manifest/ContractPermissionDescriptor.cs index 41dc7ca816..ce85889423 100644 --- a/src/Neo/SmartContract/Manifest/ContractPermissionDescriptor.cs +++ b/src/Neo/SmartContract/Manifest/ContractPermissionDescriptor.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// ContractPermissionDescriptor.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. diff --git a/src/Neo/SmartContract/Manifest/WildCardContainer.cs b/src/Neo/SmartContract/Manifest/WildCardContainer.cs index 847090cbb1..3002042d04 100644 --- a/src/Neo/SmartContract/Manifest/WildCardContainer.cs +++ b/src/Neo/SmartContract/Manifest/WildCardContainer.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// WildCardContainer.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. diff --git a/src/Neo/SmartContract/MaxLengthAttribute.cs b/src/Neo/SmartContract/MaxLengthAttribute.cs index 73e46b3cf4..9ab982e5e2 100644 --- a/src/Neo/SmartContract/MaxLengthAttribute.cs +++ b/src/Neo/SmartContract/MaxLengthAttribute.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// MaxLengthAttribute.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. diff --git a/src/Neo/SmartContract/MethodToken.cs b/src/Neo/SmartContract/MethodToken.cs index 09ed7b1eac..1b391edd32 100644 --- a/src/Neo/SmartContract/MethodToken.cs +++ b/src/Neo/SmartContract/MethodToken.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// MethodToken.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. diff --git a/src/Neo/SmartContract/Native/AccountState.cs b/src/Neo/SmartContract/Native/AccountState.cs index dc38d6f1fc..031b37f8eb 100644 --- a/src/Neo/SmartContract/Native/AccountState.cs +++ b/src/Neo/SmartContract/Native/AccountState.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// AccountState.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. diff --git a/src/Neo/SmartContract/Native/ContractManagement.cs b/src/Neo/SmartContract/Native/ContractManagement.cs index 75984754af..0f846a37cc 100644 --- a/src/Neo/SmartContract/Native/ContractManagement.cs +++ b/src/Neo/SmartContract/Native/ContractManagement.cs @@ -1,27 +1,27 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// ContractManagement.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. #pragma warning disable IDE0051 -using System; -using System.Buffers.Binary; -using System.Collections.Generic; -using System.Linq; -using System.Numerics; using Neo.IO; using Neo.Network.P2P.Payloads; using Neo.Persistence; using Neo.SmartContract.Iterators; using Neo.SmartContract.Manifest; -using Neo.VM; using Neo.VM.Types; +using System; +using System.Buffers.Binary; +using System.Collections.Generic; +using System.Linq; +using System.Numerics; namespace Neo.SmartContract.Native { diff --git a/src/Neo/SmartContract/Native/ContractMethodAttribute.cs b/src/Neo/SmartContract/Native/ContractMethodAttribute.cs index c4f12ed229..55940f2eb3 100644 --- a/src/Neo/SmartContract/Native/ContractMethodAttribute.cs +++ b/src/Neo/SmartContract/Native/ContractMethodAttribute.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// ContractMethodAttribute.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. diff --git a/src/Neo/SmartContract/Native/ContractMethodMetadata.cs b/src/Neo/SmartContract/Native/ContractMethodMetadata.cs index e0b342aea1..83c24191fd 100644 --- a/src/Neo/SmartContract/Native/ContractMethodMetadata.cs +++ b/src/Neo/SmartContract/Native/ContractMethodMetadata.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// ContractMethodMetadata.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. diff --git a/src/Neo/SmartContract/Native/CryptoLib.BLS12_381.cs b/src/Neo/SmartContract/Native/CryptoLib.BLS12_381.cs index 28e1c063b7..f966a73fd1 100644 --- a/src/Neo/SmartContract/Native/CryptoLib.BLS12_381.cs +++ b/src/Neo/SmartContract/Native/CryptoLib.BLS12_381.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// CryptoLib.BLS12_381.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.BLS12_381; using Neo.VM.Types; using System; diff --git a/src/Neo/SmartContract/Native/CryptoLib.cs b/src/Neo/SmartContract/Native/CryptoLib.cs index 16ec960a27..257deaa72f 100644 --- a/src/Neo/SmartContract/Native/CryptoLib.cs +++ b/src/Neo/SmartContract/Native/CryptoLib.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// CryptoLib.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. diff --git a/src/Neo/SmartContract/Native/FungibleToken.cs b/src/Neo/SmartContract/Native/FungibleToken.cs index 068011fad4..1a3a2ac532 100644 --- a/src/Neo/SmartContract/Native/FungibleToken.cs +++ b/src/Neo/SmartContract/Native/FungibleToken.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// FungibleToken.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. diff --git a/src/Neo/SmartContract/Native/GasToken.cs b/src/Neo/SmartContract/Native/GasToken.cs index a791c891b8..0c5a721edc 100644 --- a/src/Neo/SmartContract/Native/GasToken.cs +++ b/src/Neo/SmartContract/Native/GasToken.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// GasToken.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. diff --git a/src/Neo/SmartContract/Native/HashIndexState.cs b/src/Neo/SmartContract/Native/HashIndexState.cs index 88ece82d98..229458ffdd 100644 --- a/src/Neo/SmartContract/Native/HashIndexState.cs +++ b/src/Neo/SmartContract/Native/HashIndexState.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// HashIndexState.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. diff --git a/src/Neo/SmartContract/Native/InteroperableList.cs b/src/Neo/SmartContract/Native/InteroperableList.cs index 2f62ef13b0..e118db7621 100644 --- a/src/Neo/SmartContract/Native/InteroperableList.cs +++ b/src/Neo/SmartContract/Native/InteroperableList.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// InteroperableList.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; using Neo.VM.Types; using System.Collections; diff --git a/src/Neo/SmartContract/Native/LedgerContract.cs b/src/Neo/SmartContract/Native/LedgerContract.cs index b95c518518..3bb7568adf 100644 --- a/src/Neo/SmartContract/Native/LedgerContract.cs +++ b/src/Neo/SmartContract/Native/LedgerContract.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// LedgerContract.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. diff --git a/src/Neo/SmartContract/Native/NamedCurve.cs b/src/Neo/SmartContract/Native/NamedCurve.cs index 8bff2bbb57..9e97472cfc 100644 --- a/src/Neo/SmartContract/Native/NamedCurve.cs +++ b/src/Neo/SmartContract/Native/NamedCurve.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// NamedCurve.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. diff --git a/src/Neo/SmartContract/Native/NativeContract.cs b/src/Neo/SmartContract/Native/NativeContract.cs index 8c8ffe986f..0229582310 100644 --- a/src/Neo/SmartContract/Native/NativeContract.cs +++ b/src/Neo/SmartContract/Native/NativeContract.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// NativeContract.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. diff --git a/src/Neo/SmartContract/Native/NeoToken.cs b/src/Neo/SmartContract/Native/NeoToken.cs index 74fe70db37..2fd26d04a7 100644 --- a/src/Neo/SmartContract/Native/NeoToken.cs +++ b/src/Neo/SmartContract/Native/NeoToken.cs @@ -1,20 +1,16 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// NeoToken.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. #pragma warning disable IDE0051 -using System; -using System.Buffers.Binary; -using System.Collections.Generic; -using System.Linq; -using System.Numerics; using Neo.Cryptography.ECC; using Neo.IO; using Neo.Persistence; @@ -22,6 +18,11 @@ using Neo.SmartContract.Manifest; using Neo.VM; using Neo.VM.Types; +using System; +using System.Buffers.Binary; +using System.Collections.Generic; +using System.Linq; +using System.Numerics; namespace Neo.SmartContract.Native { diff --git a/src/Neo/SmartContract/Native/OracleContract.cs b/src/Neo/SmartContract/Native/OracleContract.cs index 99c9be9f23..42f41f5720 100644 --- a/src/Neo/SmartContract/Native/OracleContract.cs +++ b/src/Neo/SmartContract/Native/OracleContract.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// OracleContract.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. diff --git a/src/Neo/SmartContract/Native/OracleRequest.cs b/src/Neo/SmartContract/Native/OracleRequest.cs index c02af2da38..d18968ef00 100644 --- a/src/Neo/SmartContract/Native/OracleRequest.cs +++ b/src/Neo/SmartContract/Native/OracleRequest.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// OracleRequest.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. diff --git a/src/Neo/SmartContract/Native/PolicyContract.cs b/src/Neo/SmartContract/Native/PolicyContract.cs index c754a15a93..c633cb7309 100644 --- a/src/Neo/SmartContract/Native/PolicyContract.cs +++ b/src/Neo/SmartContract/Native/PolicyContract.cs @@ -1,19 +1,20 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// PolicyContract.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. #pragma warning disable IDE0051 -using System; -using System.Numerics; using Neo.Network.P2P.Payloads; using Neo.Persistence; +using System; +using System.Numerics; namespace Neo.SmartContract.Native { diff --git a/src/Neo/SmartContract/Native/Role.cs b/src/Neo/SmartContract/Native/Role.cs index 270861ef8f..c0954d8fcd 100644 --- a/src/Neo/SmartContract/Native/Role.cs +++ b/src/Neo/SmartContract/Native/Role.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// Role.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. diff --git a/src/Neo/SmartContract/Native/RoleManagement.cs b/src/Neo/SmartContract/Native/RoleManagement.cs index 5a32f10f32..1c2fa0a299 100644 --- a/src/Neo/SmartContract/Native/RoleManagement.cs +++ b/src/Neo/SmartContract/Native/RoleManagement.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// RoleManagement.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. diff --git a/src/Neo/SmartContract/Native/StdLib.cs b/src/Neo/SmartContract/Native/StdLib.cs index 9f7d0108da..3ca836a3ec 100644 --- a/src/Neo/SmartContract/Native/StdLib.cs +++ b/src/Neo/SmartContract/Native/StdLib.cs @@ -1,21 +1,22 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// StdLib.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. #pragma warning disable IDE0051 -using System; -using System.Globalization; -using System.Numerics; using Neo.Cryptography; using Neo.Json; using Neo.VM.Types; +using System; +using System.Globalization; +using System.Numerics; namespace Neo.SmartContract.Native { diff --git a/src/Neo/SmartContract/Native/TransactionState.cs b/src/Neo/SmartContract/Native/TransactionState.cs index 8994a7acd5..b17296b42d 100644 --- a/src/Neo/SmartContract/Native/TransactionState.cs +++ b/src/Neo/SmartContract/Native/TransactionState.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// TransactionState.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. diff --git a/src/Neo/SmartContract/Native/TrimmedBlock.cs b/src/Neo/SmartContract/Native/TrimmedBlock.cs index 0fd8aea5f8..4cc4c39c0f 100644 --- a/src/Neo/SmartContract/Native/TrimmedBlock.cs +++ b/src/Neo/SmartContract/Native/TrimmedBlock.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// TrimmedBlock.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. diff --git a/src/Neo/SmartContract/NefFile.cs b/src/Neo/SmartContract/NefFile.cs index 6df8e4a589..1ffa7baf20 100644 --- a/src/Neo/SmartContract/NefFile.cs +++ b/src/Neo/SmartContract/NefFile.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// NefFile.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. diff --git a/src/Neo/SmartContract/NotifyEventArgs.cs b/src/Neo/SmartContract/NotifyEventArgs.cs index 994962f134..0a509101c1 100644 --- a/src/Neo/SmartContract/NotifyEventArgs.cs +++ b/src/Neo/SmartContract/NotifyEventArgs.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// NotifyEventArgs.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. diff --git a/src/Neo/SmartContract/StorageContext.cs b/src/Neo/SmartContract/StorageContext.cs index 81222b9810..5c88d1f06c 100644 --- a/src/Neo/SmartContract/StorageContext.cs +++ b/src/Neo/SmartContract/StorageContext.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// StorageContext.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. diff --git a/src/Neo/SmartContract/StorageItem.cs b/src/Neo/SmartContract/StorageItem.cs index e7dcc8ead6..0f13c3c1f0 100644 --- a/src/Neo/SmartContract/StorageItem.cs +++ b/src/Neo/SmartContract/StorageItem.cs @@ -1,18 +1,19 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// StorageItem.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.IO; +using Neo.VM; using System; using System.IO; using System.Numerics; -using Neo.IO; -using Neo.VM; namespace Neo.SmartContract { diff --git a/src/Neo/SmartContract/StorageKey.cs b/src/Neo/SmartContract/StorageKey.cs index 2dc5f49c63..21d7a64191 100644 --- a/src/Neo/SmartContract/StorageKey.cs +++ b/src/Neo/SmartContract/StorageKey.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// StorageKey.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. diff --git a/src/Neo/SmartContract/TriggerType.cs b/src/Neo/SmartContract/TriggerType.cs index 94fbfabddc..1e93417968 100644 --- a/src/Neo/SmartContract/TriggerType.cs +++ b/src/Neo/SmartContract/TriggerType.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// TriggerType.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. diff --git a/src/Neo/SmartContract/ValidatorAttribute.cs b/src/Neo/SmartContract/ValidatorAttribute.cs index c5218da4b0..23e785fc52 100644 --- a/src/Neo/SmartContract/ValidatorAttribute.cs +++ b/src/Neo/SmartContract/ValidatorAttribute.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// ValidatorAttribute.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. diff --git a/src/Neo/TimeProvider.cs b/src/Neo/TimeProvider.cs index ae999add71..6a4542f9a2 100644 --- a/src/Neo/TimeProvider.cs +++ b/src/Neo/TimeProvider.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// TimeProvider.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. diff --git a/src/Neo/UInt160.cs b/src/Neo/UInt160.cs index 1e005c1113..8dfd6bf70c 100644 --- a/src/Neo/UInt160.cs +++ b/src/Neo/UInt160.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// UInt160.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. diff --git a/src/Neo/UInt256.cs b/src/Neo/UInt256.cs index 718bbdb01c..7c4d996339 100644 --- a/src/Neo/UInt256.cs +++ b/src/Neo/UInt256.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// UInt256.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. diff --git a/src/Neo/Utility.cs b/src/Neo/Utility.cs index c159a54924..6883c69a26 100644 --- a/src/Neo/Utility.cs +++ b/src/Neo/Utility.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// Utility.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. diff --git a/src/Neo/VM/Helper.cs b/src/Neo/VM/Helper.cs index 7ff36e1ed5..4a82041ea5 100644 --- a/src/Neo/VM/Helper.cs +++ b/src/Neo/VM/Helper.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// Helper.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. diff --git a/src/Neo/Wallets/AssetDescriptor.cs b/src/Neo/Wallets/AssetDescriptor.cs index 9885138757..4eb84e938d 100644 --- a/src/Neo/Wallets/AssetDescriptor.cs +++ b/src/Neo/Wallets/AssetDescriptor.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// AssetDescriptor.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. diff --git a/src/Neo/Wallets/Helper.cs b/src/Neo/Wallets/Helper.cs index d1a143e6a5..cced44aa9d 100644 --- a/src/Neo/Wallets/Helper.cs +++ b/src/Neo/Wallets/Helper.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// Helper.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. diff --git a/src/Neo/Wallets/IWalletFactory.cs b/src/Neo/Wallets/IWalletFactory.cs index 54409712f1..5c69b56262 100644 --- a/src/Neo/Wallets/IWalletFactory.cs +++ b/src/Neo/Wallets/IWalletFactory.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// IWalletFactory.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. diff --git a/src/Neo/Wallets/IWalletProvider.cs b/src/Neo/Wallets/IWalletProvider.cs index 6f3ff593d8..a4edc17692 100644 --- a/src/Neo/Wallets/IWalletProvider.cs +++ b/src/Neo/Wallets/IWalletProvider.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// IWalletProvider.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. diff --git a/src/Neo/Wallets/KeyPair.cs b/src/Neo/Wallets/KeyPair.cs index f7566408cd..d0842242d8 100644 --- a/src/Neo/Wallets/KeyPair.cs +++ b/src/Neo/Wallets/KeyPair.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// KeyPair.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. diff --git a/src/Neo/Wallets/NEP6/NEP6Account.cs b/src/Neo/Wallets/NEP6/NEP6Account.cs index 55bbc603c2..7998b9ea29 100644 --- a/src/Neo/Wallets/NEP6/NEP6Account.cs +++ b/src/Neo/Wallets/NEP6/NEP6Account.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// NEP6Account.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. diff --git a/src/Neo/Wallets/NEP6/NEP6Contract.cs b/src/Neo/Wallets/NEP6/NEP6Contract.cs index 289ef4387c..cecc80be7e 100644 --- a/src/Neo/Wallets/NEP6/NEP6Contract.cs +++ b/src/Neo/Wallets/NEP6/NEP6Contract.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// NEP6Contract.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. diff --git a/src/Neo/Wallets/NEP6/NEP6Wallet.cs b/src/Neo/Wallets/NEP6/NEP6Wallet.cs index 5a22f5f32a..b600fe6dcd 100644 --- a/src/Neo/Wallets/NEP6/NEP6Wallet.cs +++ b/src/Neo/Wallets/NEP6/NEP6Wallet.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// NEP6Wallet.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. diff --git a/src/Neo/Wallets/NEP6/NEP6WalletFactory.cs b/src/Neo/Wallets/NEP6/NEP6WalletFactory.cs index 75cf0c7cf8..759ab98de6 100644 --- a/src/Neo/Wallets/NEP6/NEP6WalletFactory.cs +++ b/src/Neo/Wallets/NEP6/NEP6WalletFactory.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// NEP6WalletFactory.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. diff --git a/src/Neo/Wallets/NEP6/ScryptParameters.cs b/src/Neo/Wallets/NEP6/ScryptParameters.cs index aaa6e04b89..ab720b3a08 100644 --- a/src/Neo/Wallets/NEP6/ScryptParameters.cs +++ b/src/Neo/Wallets/NEP6/ScryptParameters.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// ScryptParameters.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. diff --git a/src/Neo/Wallets/TransferOutput.cs b/src/Neo/Wallets/TransferOutput.cs index d562062a64..7f7d7777a1 100644 --- a/src/Neo/Wallets/TransferOutput.cs +++ b/src/Neo/Wallets/TransferOutput.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// TransferOutput.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. diff --git a/src/Neo/Wallets/Wallet.cs b/src/Neo/Wallets/Wallet.cs index d908530987..ecffe85366 100644 --- a/src/Neo/Wallets/Wallet.cs +++ b/src/Neo/Wallets/Wallet.cs @@ -1,20 +1,14 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// 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 System; -using System.Collections.Generic; -using System.Linq; -using System.Numerics; -using System.Security.Cryptography; -using System.Security.Cryptography.X509Certificates; -using System.Text; using Neo.Cryptography; using Neo.IO; using Neo.Network.P2P.Payloads; @@ -24,6 +18,13 @@ using Neo.VM; using Neo.Wallets.NEP6; using Org.BouncyCastle.Crypto.Generators; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Numerics; +using System.Security.Cryptography; +using System.Security.Cryptography.X509Certificates; +using System.Text; using static Neo.SmartContract.Helper; using static Neo.Wallets.Helper; using ECPoint = Neo.Cryptography.ECC.ECPoint; @@ -126,8 +127,8 @@ public abstract class Wallet /// The to be used by the wallet. protected Wallet(string path, ProtocolSettings settings) { - this.ProtocolSettings = settings; - this.Path = path; + ProtocolSettings = settings; + Path = path; } /// @@ -136,24 +137,26 @@ protected Wallet(string path, ProtocolSettings settings) /// The created account. public WalletAccount CreateAccount() { - byte[] privateKey = new byte[32]; - generate: - try + var privateKey = new byte[32]; + using var rng = RandomNumberGenerator.Create(); + + do { - using (RandomNumberGenerator rng = RandomNumberGenerator.Create()) + try { rng.GetBytes(privateKey); + return CreateAccount(privateKey); + } + catch (ArgumentException) + { + // Try again + } + finally + { + Array.Clear(privateKey, 0, privateKey.Length); } - return CreateAccount(privateKey); - } - catch (ArgumentException) - { - goto generate; - } - finally - { - Array.Clear(privateKey, 0, privateKey.Length); } + while (true); } /// @@ -171,7 +174,7 @@ public WalletAccount CreateAccount(Contract contract, byte[] privateKey) private static List<(UInt160 Account, BigInteger Value)> FindPayingAccounts(List<(UInt160 Account, BigInteger Value)> orderedAccounts, BigInteger amount) { var result = new List<(UInt160 Account, BigInteger Value)>(); - BigInteger sum_balance = orderedAccounts.Select(p => p.Value).Sum(); + var sum_balance = orderedAccounts.Select(p => p.Value).Sum(); if (sum_balance == amount) { result.AddRange(orderedAccounts); diff --git a/src/Neo/Wallets/WalletAccount.cs b/src/Neo/Wallets/WalletAccount.cs index 9f03beea4f..148f272bc1 100644 --- a/src/Neo/Wallets/WalletAccount.cs +++ b/src/Neo/Wallets/WalletAccount.cs @@ -1,10 +1,11 @@ -// Copyright (C) 2015-2022 The Neo Project. -// -// The neo is free software distributed under the MIT software license, -// see the accompanying file LICENSE in the main directory of the -// project or http://www.opensource.org/licenses/mit-license.php +// Copyright (C) 2015-2024 The Neo Project. +// +// WalletAccount.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. diff --git a/tests/Neo.ConsoleService.Tests/CommandTokenTest.cs b/tests/Neo.ConsoleService.Tests/CommandTokenTest.cs index 233e486f81..b5f43f9d04 100644 --- a/tests/Neo.ConsoleService.Tests/CommandTokenTest.cs +++ b/tests/Neo.ConsoleService.Tests/CommandTokenTest.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// CommandTokenTest.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 System.Linq; diff --git a/tests/Neo.Json.UnitTests/UT_JArray.cs b/tests/Neo.Json.UnitTests/UT_JArray.cs index e838be9c92..40388d11fc 100644 --- a/tests/Neo.Json.UnitTests/UT_JArray.cs +++ b/tests/Neo.Json.UnitTests/UT_JArray.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_JArray.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.Collections; namespace Neo.Json.UnitTests diff --git a/tests/Neo.Json.UnitTests/UT_JBoolean.cs b/tests/Neo.Json.UnitTests/UT_JBoolean.cs index e03654f8b9..3ab19bd1b3 100644 --- a/tests/Neo.Json.UnitTests/UT_JBoolean.cs +++ b/tests/Neo.Json.UnitTests/UT_JBoolean.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_JBoolean.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.Json.UnitTests { [TestClass] diff --git a/tests/Neo.Json.UnitTests/UT_JNumber.cs b/tests/Neo.Json.UnitTests/UT_JNumber.cs index 8435e0ad47..6eb0598fd3 100644 --- a/tests/Neo.Json.UnitTests/UT_JNumber.cs +++ b/tests/Neo.Json.UnitTests/UT_JNumber.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_JNumber.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.Json.UnitTests { enum Woo diff --git a/tests/Neo.Json.UnitTests/UT_JObject.cs b/tests/Neo.Json.UnitTests/UT_JObject.cs index 2ff3d25c02..a3d5bc01b4 100644 --- a/tests/Neo.Json.UnitTests/UT_JObject.cs +++ b/tests/Neo.Json.UnitTests/UT_JObject.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_JObject.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.Json.UnitTests { [TestClass] diff --git a/tests/Neo.Json.UnitTests/UT_JPath.cs b/tests/Neo.Json.UnitTests/UT_JPath.cs index be2733c4ff..9d958b1cde 100644 --- a/tests/Neo.Json.UnitTests/UT_JPath.cs +++ b/tests/Neo.Json.UnitTests/UT_JPath.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_JPath.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.Json.UnitTests { [TestClass] diff --git a/tests/Neo.Json.UnitTests/UT_JString.cs b/tests/Neo.Json.UnitTests/UT_JString.cs index 54e87ad49f..7e2bec9834 100644 --- a/tests/Neo.Json.UnitTests/UT_JString.cs +++ b/tests/Neo.Json.UnitTests/UT_JString.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_JString.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.Json.UnitTests { [TestClass] diff --git a/tests/Neo.Json.UnitTests/UT_OrderedDictionary.cs b/tests/Neo.Json.UnitTests/UT_OrderedDictionary.cs index e8b112b711..83a5c2c2f7 100644 --- a/tests/Neo.Json.UnitTests/UT_OrderedDictionary.cs +++ b/tests/Neo.Json.UnitTests/UT_OrderedDictionary.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_OrderedDictionary.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.Collections; namespace Neo.Json.UnitTests diff --git a/tests/Neo.Json.UnitTests/Usings.cs b/tests/Neo.Json.UnitTests/Usings.cs index 6f971bbc56..e79662735c 100644 --- a/tests/Neo.Json.UnitTests/Usings.cs +++ b/tests/Neo.Json.UnitTests/Usings.cs @@ -1,2 +1,13 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Usings.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. + global using FluentAssertions; global using Microsoft.VisualStudio.TestTools.UnitTesting; diff --git a/tests/Neo.UnitTests/Cryptography/ECC/UT_ECFieldElement.cs b/tests/Neo.UnitTests/Cryptography/ECC/UT_ECFieldElement.cs index 94fe8a77ec..3d4e4c56f2 100644 --- a/tests/Neo.UnitTests/Cryptography/ECC/UT_ECFieldElement.cs +++ b/tests/Neo.UnitTests/Cryptography/ECC/UT_ECFieldElement.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_ECFieldElement.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.Cryptography.ECC; diff --git a/tests/Neo.UnitTests/Cryptography/ECC/UT_ECPoint.cs b/tests/Neo.UnitTests/Cryptography/ECC/UT_ECPoint.cs index 886677203d..ee56b3c57e 100644 --- a/tests/Neo.UnitTests/Cryptography/ECC/UT_ECPoint.cs +++ b/tests/Neo.UnitTests/Cryptography/ECC/UT_ECPoint.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_ECPoint.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.Cryptography.ECC; diff --git a/tests/Neo.UnitTests/Cryptography/UT_Base58.cs b/tests/Neo.UnitTests/Cryptography/UT_Base58.cs index fbf29ba888..e7cb467dfa 100644 --- a/tests/Neo.UnitTests/Cryptography/UT_Base58.cs +++ b/tests/Neo.UnitTests/Cryptography/UT_Base58.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_Base58.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.Cryptography; diff --git a/tests/Neo.UnitTests/Cryptography/UT_BloomFilter.cs b/tests/Neo.UnitTests/Cryptography/UT_BloomFilter.cs index 7ed470e3e1..907a5df2b9 100644 --- a/tests/Neo.UnitTests/Cryptography/UT_BloomFilter.cs +++ b/tests/Neo.UnitTests/Cryptography/UT_BloomFilter.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_BloomFilter.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.Cryptography; diff --git a/tests/Neo.UnitTests/Cryptography/UT_Crypto.cs b/tests/Neo.UnitTests/Cryptography/UT_Crypto.cs index cf54ed16ad..31c4a7ce49 100644 --- a/tests/Neo.UnitTests/Cryptography/UT_Crypto.cs +++ b/tests/Neo.UnitTests/Cryptography/UT_Crypto.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_Crypto.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.Cryptography; diff --git a/tests/Neo.UnitTests/Cryptography/UT_Cryptography_Helper.cs b/tests/Neo.UnitTests/Cryptography/UT_Cryptography_Helper.cs index e0c8bf3149..01022baab9 100644 --- a/tests/Neo.UnitTests/Cryptography/UT_Cryptography_Helper.cs +++ b/tests/Neo.UnitTests/Cryptography/UT_Cryptography_Helper.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_Cryptography_Helper.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.Cryptography; diff --git a/tests/Neo.UnitTests/Cryptography/UT_MerkleTree.cs b/tests/Neo.UnitTests/Cryptography/UT_MerkleTree.cs index 612a013923..f8a6b19b34 100644 --- a/tests/Neo.UnitTests/Cryptography/UT_MerkleTree.cs +++ b/tests/Neo.UnitTests/Cryptography/UT_MerkleTree.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_MerkleTree.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.Cryptography; diff --git a/tests/Neo.UnitTests/Cryptography/UT_MerkleTreeNode.cs b/tests/Neo.UnitTests/Cryptography/UT_MerkleTreeNode.cs index 7ae6f7658b..8defb8d6c7 100644 --- a/tests/Neo.UnitTests/Cryptography/UT_MerkleTreeNode.cs +++ b/tests/Neo.UnitTests/Cryptography/UT_MerkleTreeNode.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_MerkleTreeNode.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.Cryptography; @@ -8,7 +19,7 @@ namespace Neo.UnitTests.Cryptography [TestClass] public class UT_MerkleTreeNode { - private MerkleTreeNode node = new MerkleTreeNode(); + private readonly MerkleTreeNode node = new MerkleTreeNode(); [TestInitialize] public void TestSetup() diff --git a/tests/Neo.UnitTests/Cryptography/UT_Murmur128.cs b/tests/Neo.UnitTests/Cryptography/UT_Murmur128.cs index 49f6657696..f33dd7110a 100644 --- a/tests/Neo.UnitTests/Cryptography/UT_Murmur128.cs +++ b/tests/Neo.UnitTests/Cryptography/UT_Murmur128.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_Murmur128.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.Cryptography; diff --git a/tests/Neo.UnitTests/Cryptography/UT_Murmur32.cs b/tests/Neo.UnitTests/Cryptography/UT_Murmur32.cs index 1b5b2fc218..1c885dbd08 100644 --- a/tests/Neo.UnitTests/Cryptography/UT_Murmur32.cs +++ b/tests/Neo.UnitTests/Cryptography/UT_Murmur32.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_Murmur32.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.Cryptography; diff --git a/tests/Neo.UnitTests/Cryptography/UT_SCrypt.cs b/tests/Neo.UnitTests/Cryptography/UT_SCrypt.cs index f0934b8138..c3a3127ff0 100644 --- a/tests/Neo.UnitTests/Cryptography/UT_SCrypt.cs +++ b/tests/Neo.UnitTests/Cryptography/UT_SCrypt.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_SCrypt.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 Org.BouncyCastle.Crypto.Generators; diff --git a/tests/Neo.UnitTests/Extensions/NativeContractExtensions.cs b/tests/Neo.UnitTests/Extensions/NativeContractExtensions.cs index 437f98bbe4..9e72fc7ec3 100644 --- a/tests/Neo.UnitTests/Extensions/NativeContractExtensions.cs +++ b/tests/Neo.UnitTests/Extensions/NativeContractExtensions.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// NativeContractExtensions.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.Payloads; using Neo.Persistence; using Neo.SmartContract; diff --git a/tests/Neo.UnitTests/Extensions/Nep17NativeContractExtensions.cs b/tests/Neo.UnitTests/Extensions/Nep17NativeContractExtensions.cs index 89c4f66f17..a3f33f26a7 100644 --- a/tests/Neo.UnitTests/Extensions/Nep17NativeContractExtensions.cs +++ b/tests/Neo.UnitTests/Extensions/Nep17NativeContractExtensions.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Nep17NativeContractExtensions.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.IO; using Neo.Network.P2P.Payloads; diff --git a/tests/Neo.UnitTests/IO/Caching/UT_Cache.cs b/tests/Neo.UnitTests/IO/Caching/UT_Cache.cs index 529ac66a9e..a622cc3767 100644 --- a/tests/Neo.UnitTests/IO/Caching/UT_Cache.cs +++ b/tests/Neo.UnitTests/IO/Caching/UT_Cache.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_Cache.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.Caching; diff --git a/tests/Neo.UnitTests/IO/Caching/UT_CloneCache.cs b/tests/Neo.UnitTests/IO/Caching/UT_CloneCache.cs index 990b21ea59..4d57da62b9 100644 --- a/tests/Neo.UnitTests/IO/Caching/UT_CloneCache.cs +++ b/tests/Neo.UnitTests/IO/Caching/UT_CloneCache.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_CloneCache.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; diff --git a/tests/Neo.UnitTests/IO/Caching/UT_DataCache.cs b/tests/Neo.UnitTests/IO/Caching/UT_DataCache.cs index 32d6fcd408..5235b99c70 100644 --- a/tests/Neo.UnitTests/IO/Caching/UT_DataCache.cs +++ b/tests/Neo.UnitTests/IO/Caching/UT_DataCache.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_DataCache.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; @@ -13,7 +24,7 @@ namespace Neo.UnitTests.IO.Caching [TestClass] public class UT_DataCache { - private MemoryStore store = new(); + private readonly MemoryStore store = new(); private SnapshotCache myDataCache; private static readonly StorageKey key1 = new() { Id = 0, Key = Encoding.UTF8.GetBytes("key1") }; diff --git a/tests/Neo.UnitTests/IO/Caching/UT_ECPointCache.cs b/tests/Neo.UnitTests/IO/Caching/UT_ECPointCache.cs index dc36bdb96f..87be485ab6 100644 --- a/tests/Neo.UnitTests/IO/Caching/UT_ECPointCache.cs +++ b/tests/Neo.UnitTests/IO/Caching/UT_ECPointCache.cs @@ -1,9 +1,18 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_ECPointCache.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.Cryptography.ECC; using Neo.IO.Caching; -using Neo.Network.P2P.Payloads; -using System; namespace Neo.UnitTests.IO.Caching { diff --git a/tests/Neo.UnitTests/IO/Caching/UT_HashSetCache.cs b/tests/Neo.UnitTests/IO/Caching/UT_HashSetCache.cs index ceb51130d2..9357aeb418 100644 --- a/tests/Neo.UnitTests/IO/Caching/UT_HashSetCache.cs +++ b/tests/Neo.UnitTests/IO/Caching/UT_HashSetCache.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_HashSetCache.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.Caching; diff --git a/tests/Neo.UnitTests/IO/Caching/UT_IndexedQueue.cs b/tests/Neo.UnitTests/IO/Caching/UT_IndexedQueue.cs index e09726924c..4c7cc0697e 100644 --- a/tests/Neo.UnitTests/IO/Caching/UT_IndexedQueue.cs +++ b/tests/Neo.UnitTests/IO/Caching/UT_IndexedQueue.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_IndexedQueue.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.Caching; diff --git a/tests/Neo.UnitTests/IO/Caching/UT_ReflectionCache.cs b/tests/Neo.UnitTests/IO/Caching/UT_ReflectionCache.cs index 726b751946..57e466d837 100644 --- a/tests/Neo.UnitTests/IO/Caching/UT_ReflectionCache.cs +++ b/tests/Neo.UnitTests/IO/Caching/UT_ReflectionCache.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_ReflectionCache.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; diff --git a/tests/Neo.UnitTests/IO/Caching/UT_RelayCache.cs b/tests/Neo.UnitTests/IO/Caching/UT_RelayCache.cs index 659b7f5797..a6c5ea3939 100644 --- a/tests/Neo.UnitTests/IO/Caching/UT_RelayCache.cs +++ b/tests/Neo.UnitTests/IO/Caching/UT_RelayCache.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_RelayCache.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.Caching; diff --git a/tests/Neo.UnitTests/IO/UT_ByteArrayComparer.cs b/tests/Neo.UnitTests/IO/UT_ByteArrayComparer.cs index 89c0c621d7..5efba80cb3 100644 --- a/tests/Neo.UnitTests/IO/UT_ByteArrayComparer.cs +++ b/tests/Neo.UnitTests/IO/UT_ByteArrayComparer.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_ByteArrayComparer.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; diff --git a/tests/Neo.UnitTests/IO/UT_ByteArrayEqualityComparer.cs b/tests/Neo.UnitTests/IO/UT_ByteArrayEqualityComparer.cs index 6b7152c239..ea5ae86be4 100644 --- a/tests/Neo.UnitTests/IO/UT_ByteArrayEqualityComparer.cs +++ b/tests/Neo.UnitTests/IO/UT_ByteArrayEqualityComparer.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_ByteArrayEqualityComparer.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 System; diff --git a/tests/Neo.UnitTests/IO/UT_IOHelper.cs b/tests/Neo.UnitTests/IO/UT_IOHelper.cs index 80fd3c3105..4b74a495b5 100644 --- a/tests/Neo.UnitTests/IO/UT_IOHelper.cs +++ b/tests/Neo.UnitTests/IO/UT_IOHelper.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_IOHelper.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; diff --git a/tests/Neo.UnitTests/IO/UT_MemoryReader.cs b/tests/Neo.UnitTests/IO/UT_MemoryReader.cs index 065bb37e51..a045a0b688 100644 --- a/tests/Neo.UnitTests/IO/UT_MemoryReader.cs +++ b/tests/Neo.UnitTests/IO/UT_MemoryReader.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_MemoryReader.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 System.IO; diff --git a/tests/Neo.UnitTests/Ledger/UT_Blockchain.cs b/tests/Neo.UnitTests/Ledger/UT_Blockchain.cs index 0237b76e3d..6102b88938 100644 --- a/tests/Neo.UnitTests/Ledger/UT_Blockchain.cs +++ b/tests/Neo.UnitTests/Ledger/UT_Blockchain.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_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.TestKit; using Akka.TestKit.Xunit2; using Microsoft.VisualStudio.TestTools.UnitTesting; diff --git a/tests/Neo.UnitTests/Ledger/UT_HashIndexState.cs b/tests/Neo.UnitTests/Ledger/UT_HashIndexState.cs index 7099512326..5351f17268 100644 --- a/tests/Neo.UnitTests/Ledger/UT_HashIndexState.cs +++ b/tests/Neo.UnitTests/Ledger/UT_HashIndexState.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_HashIndexState.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; diff --git a/tests/Neo.UnitTests/Ledger/UT_MemoryPool.cs b/tests/Neo.UnitTests/Ledger/UT_MemoryPool.cs index abe054f4f2..06324b6675 100644 --- a/tests/Neo.UnitTests/Ledger/UT_MemoryPool.cs +++ b/tests/Neo.UnitTests/Ledger/UT_MemoryPool.cs @@ -1,9 +1,14 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Numerics; -using System.Threading.Tasks; +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_MemoryPool.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.TestKit.Xunit2; using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -15,7 +20,12 @@ using Neo.Persistence; using Neo.SmartContract; using Neo.SmartContract.Native; -using Neo.VM; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Numerics; +using System.Threading.Tasks; namespace Neo.UnitTests.Ledger { diff --git a/tests/Neo.UnitTests/Ledger/UT_PoolItem.cs b/tests/Neo.UnitTests/Ledger/UT_PoolItem.cs index 6933bfb292..683291eda9 100644 --- a/tests/Neo.UnitTests/Ledger/UT_PoolItem.cs +++ b/tests/Neo.UnitTests/Ledger/UT_PoolItem.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_PoolItem.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 Moq; diff --git a/tests/Neo.UnitTests/Ledger/UT_StorageItem.cs b/tests/Neo.UnitTests/Ledger/UT_StorageItem.cs index 7140023889..8ee55919da 100644 --- a/tests/Neo.UnitTests/Ledger/UT_StorageItem.cs +++ b/tests/Neo.UnitTests/Ledger/UT_StorageItem.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_StorageItem.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; diff --git a/tests/Neo.UnitTests/Ledger/UT_StorageKey.cs b/tests/Neo.UnitTests/Ledger/UT_StorageKey.cs index b37ab78061..f2d9300fee 100644 --- a/tests/Neo.UnitTests/Ledger/UT_StorageKey.cs +++ b/tests/Neo.UnitTests/Ledger/UT_StorageKey.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_StorageKey.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.SmartContract; diff --git a/tests/Neo.UnitTests/Ledger/UT_TransactionState.cs b/tests/Neo.UnitTests/Ledger/UT_TransactionState.cs index 117f9b2a1f..0a5f1a102d 100644 --- a/tests/Neo.UnitTests/Ledger/UT_TransactionState.cs +++ b/tests/Neo.UnitTests/Ledger/UT_TransactionState.cs @@ -1,6 +1,16 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_TransactionState.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.Cryptography; using Neo.IO; using Neo.Network.P2P.Payloads; using Neo.SmartContract; diff --git a/tests/Neo.UnitTests/Ledger/UT_TransactionVerificationContext.cs b/tests/Neo.UnitTests/Ledger/UT_TransactionVerificationContext.cs index 522b964ff9..32a0bd6237 100644 --- a/tests/Neo.UnitTests/Ledger/UT_TransactionVerificationContext.cs +++ b/tests/Neo.UnitTests/Ledger/UT_TransactionVerificationContext.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_TransactionVerificationContext.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 Moq; diff --git a/tests/Neo.UnitTests/Ledger/UT_TrimmedBlock.cs b/tests/Neo.UnitTests/Ledger/UT_TrimmedBlock.cs index 9a8d7e1caa..7942847f94 100644 --- a/tests/Neo.UnitTests/Ledger/UT_TrimmedBlock.cs +++ b/tests/Neo.UnitTests/Ledger/UT_TrimmedBlock.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_TrimmedBlock.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; diff --git a/tests/Neo.UnitTests/Network/P2P/Capabilities/UT_FullNodeCapability.cs b/tests/Neo.UnitTests/Network/P2P/Capabilities/UT_FullNodeCapability.cs index f03134bd3e..c3c5c2c86f 100644 --- a/tests/Neo.UnitTests/Network/P2P/Capabilities/UT_FullNodeCapability.cs +++ b/tests/Neo.UnitTests/Network/P2P/Capabilities/UT_FullNodeCapability.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_FullNodeCapability.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; diff --git a/tests/Neo.UnitTests/Network/P2P/Capabilities/UT_ServerCapability.cs b/tests/Neo.UnitTests/Network/P2P/Capabilities/UT_ServerCapability.cs index 8e8d6dd8c0..bdc5cc8adc 100644 --- a/tests/Neo.UnitTests/Network/P2P/Capabilities/UT_ServerCapability.cs +++ b/tests/Neo.UnitTests/Network/P2P/Capabilities/UT_ServerCapability.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_ServerCapability.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; diff --git a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_AddrPayload.cs b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_AddrPayload.cs index fa19860ff2..6e189ad3ec 100644 --- a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_AddrPayload.cs +++ b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_AddrPayload.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_AddrPayload.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; diff --git a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Block.cs b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Block.cs index 2c1c72ca25..2021e5a187 100644 --- a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Block.cs +++ b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Block.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_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 FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.IO; diff --git a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Conflicts.cs b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Conflicts.cs index bbf46920aa..ce46c5106d 100644 --- a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Conflicts.cs +++ b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Conflicts.cs @@ -1,9 +1,20 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_Conflicts.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.Network.P2P.Payloads; -using Neo.SmartContract.Native; using Neo.SmartContract; +using Neo.SmartContract.Native; using Neo.VM; using System; @@ -13,7 +24,7 @@ namespace Neo.UnitTests.Network.P2P.Payloads public class UT_Conflicts { private const byte Prefix_Transaction = 11; - private static UInt256 _u = new UInt256(new byte[32] { + private static readonly UInt256 _u = new UInt256(new byte[32] { 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, diff --git a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_ExtensiblePayload.cs b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_ExtensiblePayload.cs index 77663bda41..1a0ad19a9a 100644 --- a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_ExtensiblePayload.cs +++ b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_ExtensiblePayload.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_ExtensiblePayload.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; diff --git a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_FilterAddPayload.cs b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_FilterAddPayload.cs index d0553fcc5a..76eff8e198 100644 --- a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_FilterAddPayload.cs +++ b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_FilterAddPayload.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_FilterAddPayload.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; diff --git a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_FilterLoadPayload.cs b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_FilterLoadPayload.cs index aa832fe427..f73e9b5595 100644 --- a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_FilterLoadPayload.cs +++ b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_FilterLoadPayload.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_FilterLoadPayload.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; diff --git a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_GetBlockByIndexPayload.cs b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_GetBlockByIndexPayload.cs index 76ed1df9f9..3aa4049d87 100644 --- a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_GetBlockByIndexPayload.cs +++ b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_GetBlockByIndexPayload.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_GetBlockByIndexPayload.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; diff --git a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_GetBlocksPayload.cs b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_GetBlocksPayload.cs index 4c09147d8d..6752525ac0 100644 --- a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_GetBlocksPayload.cs +++ b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_GetBlocksPayload.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_GetBlocksPayload.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; diff --git a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Header.cs b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Header.cs index 8bf065eef8..df33505965 100644 --- a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Header.cs +++ b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Header.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_Header.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; diff --git a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_HeadersPayload.cs b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_HeadersPayload.cs index b099403429..2ac486ef06 100644 --- a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_HeadersPayload.cs +++ b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_HeadersPayload.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_HeadersPayload.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; diff --git a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_HighPriorityAttribute.cs b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_HighPriorityAttribute.cs index 8a41aa0135..76808072d5 100644 --- a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_HighPriorityAttribute.cs +++ b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_HighPriorityAttribute.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_HighPriorityAttribute.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; diff --git a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_InvPayload.cs b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_InvPayload.cs index 9bd5127af9..4735fddfe1 100644 --- a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_InvPayload.cs +++ b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_InvPayload.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_InvPayload.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; diff --git a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_MerkleBlockPayload.cs b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_MerkleBlockPayload.cs index ac658954e3..f491d46749 100644 --- a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_MerkleBlockPayload.cs +++ b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_MerkleBlockPayload.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_MerkleBlockPayload.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; diff --git a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_NetworkAddressWithTime.cs b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_NetworkAddressWithTime.cs index 239896acf8..2ed86e4da7 100644 --- a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_NetworkAddressWithTime.cs +++ b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_NetworkAddressWithTime.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_NetworkAddressWithTime.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; diff --git a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_NotValidBefore.cs b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_NotValidBefore.cs index e47159d9ff..0b51550f83 100644 --- a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_NotValidBefore.cs +++ b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_NotValidBefore.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_NotValidBefore.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; diff --git a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Signers.cs b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Signers.cs index 8b1adae4ee..44d337fd1c 100644 --- a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Signers.cs +++ b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Signers.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_Signers.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.Cryptography.ECC; diff --git a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs index d2241c43bf..ecb6d1874b 100644 --- a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs +++ b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_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 FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.Cryptography.ECC; diff --git a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_VersionPayload.cs b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_VersionPayload.cs index 30fdb1f5a8..a77740a1e5 100644 --- a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_VersionPayload.cs +++ b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_VersionPayload.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_VersionPayload.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; diff --git a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Witness.cs b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Witness.cs index f73f24cb0a..74898eb4fb 100644 --- a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Witness.cs +++ b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Witness.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_Witness.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; diff --git a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_WitnessContition.cs b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_WitnessContition.cs index 21260c39b2..113d667296 100644 --- a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_WitnessContition.cs +++ b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_WitnessContition.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_WitnessContition.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.ECC; using Neo.Json; diff --git a/tests/Neo.UnitTests/Network/P2P/UT_ChannelsConfig.cs b/tests/Neo.UnitTests/Network/P2P/UT_ChannelsConfig.cs index 5613364319..9de77eccf6 100644 --- a/tests/Neo.UnitTests/Network/P2P/UT_ChannelsConfig.cs +++ b/tests/Neo.UnitTests/Network/P2P/UT_ChannelsConfig.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_ChannelsConfig.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.Network.P2P; diff --git a/tests/Neo.UnitTests/Network/P2P/UT_LocalNode.cs b/tests/Neo.UnitTests/Network/P2P/UT_LocalNode.cs index 1e4da7590b..ac1aa7d378 100644 --- a/tests/Neo.UnitTests/Network/P2P/UT_LocalNode.cs +++ b/tests/Neo.UnitTests/Network/P2P/UT_LocalNode.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_LocalNode.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.TestKit.Xunit2; using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.Network.P2P; diff --git a/tests/Neo.UnitTests/Network/P2P/UT_Message.cs b/tests/Neo.UnitTests/Network/P2P/UT_Message.cs index b1afb98533..35f99fc44f 100644 --- a/tests/Neo.UnitTests/Network/P2P/UT_Message.cs +++ b/tests/Neo.UnitTests/Network/P2P/UT_Message.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_Message.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.IO; using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; diff --git a/tests/Neo.UnitTests/Network/P2P/UT_RemoteNode.cs b/tests/Neo.UnitTests/Network/P2P/UT_RemoteNode.cs index 2366e92f2f..9f114e2708 100644 --- a/tests/Neo.UnitTests/Network/P2P/UT_RemoteNode.cs +++ b/tests/Neo.UnitTests/Network/P2P/UT_RemoteNode.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_RemoteNode.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.IO; using Akka.TestKit.Xunit2; using FluentAssertions; diff --git a/tests/Neo.UnitTests/Network/P2P/UT_RemoteNodeMailbox.cs b/tests/Neo.UnitTests/Network/P2P/UT_RemoteNodeMailbox.cs index a5174d6cfe..23e0dad367 100644 --- a/tests/Neo.UnitTests/Network/P2P/UT_RemoteNodeMailbox.cs +++ b/tests/Neo.UnitTests/Network/P2P/UT_RemoteNodeMailbox.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_RemoteNodeMailbox.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.IO; using Akka.TestKit.Xunit2; using FluentAssertions; diff --git a/tests/Neo.UnitTests/Network/P2P/UT_TaskManagerMailbox.cs b/tests/Neo.UnitTests/Network/P2P/UT_TaskManagerMailbox.cs index 755bf979c1..41b4635d8c 100644 --- a/tests/Neo.UnitTests/Network/P2P/UT_TaskManagerMailbox.cs +++ b/tests/Neo.UnitTests/Network/P2P/UT_TaskManagerMailbox.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_TaskManagerMailbox.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.TestKit.Xunit2; using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; diff --git a/tests/Neo.UnitTests/Network/P2P/UT_TaskSession.cs b/tests/Neo.UnitTests/Network/P2P/UT_TaskSession.cs index bee2bc8efe..4614ba47aa 100644 --- a/tests/Neo.UnitTests/Network/P2P/UT_TaskSession.cs +++ b/tests/Neo.UnitTests/Network/P2P/UT_TaskSession.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_TaskSession.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.Network.P2P; using Neo.Network.P2P.Capabilities; diff --git a/tests/Neo.UnitTests/Network/UT_UPnP.cs b/tests/Neo.UnitTests/Network/UT_UPnP.cs index 897d48ffa2..f63fb43d93 100644 --- a/tests/Neo.UnitTests/Network/UT_UPnP.cs +++ b/tests/Neo.UnitTests/Network/UT_UPnP.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_UPnP.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.Network; using System; diff --git a/tests/Neo.UnitTests/Persistence/UT_MemoryStore.cs b/tests/Neo.UnitTests/Persistence/UT_MemoryStore.cs index 7dd698e1c2..50da353f7c 100644 --- a/tests/Neo.UnitTests/Persistence/UT_MemoryStore.cs +++ b/tests/Neo.UnitTests/Persistence/UT_MemoryStore.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_MemoryStore.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; diff --git a/tests/Neo.UnitTests/Plugins/TestPlugin.cs b/tests/Neo.UnitTests/Plugins/TestPlugin.cs index f2d0606923..dde500b927 100644 --- a/tests/Neo.UnitTests/Plugins/TestPlugin.cs +++ b/tests/Neo.UnitTests/Plugins/TestPlugin.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// TestPlugin.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 Neo.Plugins; diff --git a/tests/Neo.UnitTests/Plugins/UT_Plugin.cs b/tests/Neo.UnitTests/Plugins/UT_Plugin.cs index 0ed00ac658..e5e8cb6e49 100644 --- a/tests/Neo.UnitTests/Plugins/UT_Plugin.cs +++ b/tests/Neo.UnitTests/Plugins/UT_Plugin.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_Plugin.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.Plugins; diff --git a/tests/Neo.UnitTests/SmartContract/Iterators/UT_StorageIterator.cs b/tests/Neo.UnitTests/SmartContract/Iterators/UT_StorageIterator.cs index 9abef9fb52..16f6b11973 100644 --- a/tests/Neo.UnitTests/SmartContract/Iterators/UT_StorageIterator.cs +++ b/tests/Neo.UnitTests/SmartContract/Iterators/UT_StorageIterator.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_StorageIterator.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.SmartContract; diff --git a/tests/Neo.UnitTests/SmartContract/Manifest/UT_ContractEventDescriptor.cs b/tests/Neo.UnitTests/SmartContract/Manifest/UT_ContractEventDescriptor.cs index a829354e34..c04f4a009e 100644 --- a/tests/Neo.UnitTests/SmartContract/Manifest/UT_ContractEventDescriptor.cs +++ b/tests/Neo.UnitTests/SmartContract/Manifest/UT_ContractEventDescriptor.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_ContractEventDescriptor.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.Manifest; diff --git a/tests/Neo.UnitTests/SmartContract/Manifest/UT_ContractGroup.cs b/tests/Neo.UnitTests/SmartContract/Manifest/UT_ContractGroup.cs index 27094d8cef..e2715d8ceb 100644 --- a/tests/Neo.UnitTests/SmartContract/Manifest/UT_ContractGroup.cs +++ b/tests/Neo.UnitTests/SmartContract/Manifest/UT_ContractGroup.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_ContractGroup.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.SmartContract; diff --git a/tests/Neo.UnitTests/SmartContract/Manifest/UT_ContractManifest.cs b/tests/Neo.UnitTests/SmartContract/Manifest/UT_ContractManifest.cs index 1cde958f4e..4e2e866281 100644 --- a/tests/Neo.UnitTests/SmartContract/Manifest/UT_ContractManifest.cs +++ b/tests/Neo.UnitTests/SmartContract/Manifest/UT_ContractManifest.cs @@ -1,4 +1,14 @@ -using System; +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_ContractManifest.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.ECC; using Neo.IO; @@ -6,6 +16,7 @@ using Neo.SmartContract; using Neo.SmartContract.Manifest; using Neo.VM; +using System; namespace Neo.UnitTests.SmartContract.Manifest { diff --git a/tests/Neo.UnitTests/SmartContract/Manifest/UT_ContractPermission.cs b/tests/Neo.UnitTests/SmartContract/Manifest/UT_ContractPermission.cs index 18ba983751..972a06d56d 100644 --- a/tests/Neo.UnitTests/SmartContract/Manifest/UT_ContractPermission.cs +++ b/tests/Neo.UnitTests/SmartContract/Manifest/UT_ContractPermission.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_ContractPermission.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.ECC; using Neo.SmartContract; diff --git a/tests/Neo.UnitTests/SmartContract/Manifest/UT_ContractPermissionDescriptor.cs b/tests/Neo.UnitTests/SmartContract/Manifest/UT_ContractPermissionDescriptor.cs index 972911b296..0dee8b0f67 100644 --- a/tests/Neo.UnitTests/SmartContract/Manifest/UT_ContractPermissionDescriptor.cs +++ b/tests/Neo.UnitTests/SmartContract/Manifest/UT_ContractPermissionDescriptor.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_ContractPermissionDescriptor.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.Manifest; using Neo.Wallets; diff --git a/tests/Neo.UnitTests/SmartContract/Manifest/UT_WildCardContainer.cs b/tests/Neo.UnitTests/SmartContract/Manifest/UT_WildCardContainer.cs index 9bd8dc111f..610126485c 100644 --- a/tests/Neo.UnitTests/SmartContract/Manifest/UT_WildCardContainer.cs +++ b/tests/Neo.UnitTests/SmartContract/Manifest/UT_WildCardContainer.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_WildCardContainer.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.Json; @@ -59,7 +70,7 @@ public void TestGetItem() public void TestGetEnumerator() { string[] s = null; - IReadOnlyList rs = (IReadOnlyList)new string[0]; + IReadOnlyList rs = new string[0]; WildcardContainer container = WildcardContainer.Create(s); IEnumerator enumerator = container.GetEnumerator(); enumerator.Should().Be(rs.GetEnumerator()); diff --git a/tests/Neo.UnitTests/SmartContract/Native/UT_CryptoLib.cs b/tests/Neo.UnitTests/SmartContract/Native/UT_CryptoLib.cs index f6e142500a..9e36488031 100644 --- a/tests/Neo.UnitTests/SmartContract/Native/UT_CryptoLib.cs +++ b/tests/Neo.UnitTests/SmartContract/Native/UT_CryptoLib.cs @@ -1,10 +1,20 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_CryptoLib.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.Cryptography.BLS12_381; using Neo.SmartContract; using Neo.SmartContract.Native; using Neo.VM; -using System.Security.Cryptography; namespace Neo.UnitTests.SmartContract.Native { diff --git a/tests/Neo.UnitTests/SmartContract/Native/UT_FungibleToken.cs b/tests/Neo.UnitTests/SmartContract/Native/UT_FungibleToken.cs index 966f0b460c..5d6d00986e 100644 --- a/tests/Neo.UnitTests/SmartContract/Native/UT_FungibleToken.cs +++ b/tests/Neo.UnitTests/SmartContract/Native/UT_FungibleToken.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_FungibleToken.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.TestKit.Xunit2; using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; diff --git a/tests/Neo.UnitTests/SmartContract/Native/UT_GasToken.cs b/tests/Neo.UnitTests/SmartContract/Native/UT_GasToken.cs index 8f623de719..51617b6744 100644 --- a/tests/Neo.UnitTests/SmartContract/Native/UT_GasToken.cs +++ b/tests/Neo.UnitTests/SmartContract/Native/UT_GasToken.cs @@ -1,7 +1,14 @@ -using System; -using System.Linq; -using System.Numerics; -using System.Threading.Tasks; +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_GasToken.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; @@ -10,6 +17,10 @@ using Neo.SmartContract; using Neo.SmartContract.Native; using Neo.UnitTests.Extensions; +using System; +using System.Linq; +using System.Numerics; +using System.Threading.Tasks; namespace Neo.UnitTests.SmartContract.Native { diff --git a/tests/Neo.UnitTests/SmartContract/Native/UT_NativeContract.cs b/tests/Neo.UnitTests/SmartContract/Native/UT_NativeContract.cs index 710502bef5..5f4b5b43e0 100644 --- a/tests/Neo.UnitTests/SmartContract/Native/UT_NativeContract.cs +++ b/tests/Neo.UnitTests/SmartContract/Native/UT_NativeContract.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_NativeContract.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.Native; diff --git a/tests/Neo.UnitTests/SmartContract/Native/UT_NeoToken.cs b/tests/Neo.UnitTests/SmartContract/Native/UT_NeoToken.cs index e09b5e8743..73cf286652 100644 --- a/tests/Neo.UnitTests/SmartContract/Native/UT_NeoToken.cs +++ b/tests/Neo.UnitTests/SmartContract/Native/UT_NeoToken.cs @@ -1,6 +1,14 @@ -using System; -using System.Linq; -using System.Numerics; +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_NeoToken.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.Cryptography.ECC; @@ -12,6 +20,9 @@ using Neo.UnitTests.Extensions; using Neo.VM; using Neo.Wallets; +using System; +using System.Linq; +using System.Numerics; using static Neo.SmartContract.Native.NeoToken; namespace Neo.UnitTests.SmartContract.Native diff --git a/tests/Neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs b/tests/Neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs index 6793c27614..32da3b1602 100644 --- a/tests/Neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs +++ b/tests/Neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs @@ -1,6 +1,14 @@ -using System; -using System.Linq; -using System.Numerics; +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_PolicyContract.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; @@ -9,6 +17,9 @@ using Neo.SmartContract; using Neo.SmartContract.Native; using Neo.UnitTests.Extensions; +using System; +using System.Linq; +using System.Numerics; namespace Neo.UnitTests.SmartContract.Native { diff --git a/tests/Neo.UnitTests/SmartContract/Native/UT_RoleManagement.cs b/tests/Neo.UnitTests/SmartContract/Native/UT_RoleManagement.cs index ffea2d6044..419ce213fc 100644 --- a/tests/Neo.UnitTests/SmartContract/Native/UT_RoleManagement.cs +++ b/tests/Neo.UnitTests/SmartContract/Native/UT_RoleManagement.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_RoleManagement.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.Cryptography.ECC; diff --git a/tests/Neo.UnitTests/SmartContract/Native/UT_StdLib.cs b/tests/Neo.UnitTests/SmartContract/Native/UT_StdLib.cs index 3251f67014..f36fa2cfa4 100644 --- a/tests/Neo.UnitTests/SmartContract/Native/UT_StdLib.cs +++ b/tests/Neo.UnitTests/SmartContract/Native/UT_StdLib.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_StdLib.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.SmartContract.Native; diff --git a/tests/Neo.UnitTests/SmartContract/UT_ApplicationEngine.Contract.cs b/tests/Neo.UnitTests/SmartContract/UT_ApplicationEngine.Contract.cs index 1614e5e32d..f9dc5e7b46 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_ApplicationEngine.Contract.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_ApplicationEngine.Contract.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_ApplicationEngine.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 FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.SmartContract; diff --git a/tests/Neo.UnitTests/SmartContract/UT_ApplicationEngine.Runtime.cs b/tests/Neo.UnitTests/SmartContract/UT_ApplicationEngine.Runtime.cs index 7d4faee5b5..80bbf45e9d 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_ApplicationEngine.Runtime.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_ApplicationEngine.Runtime.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_ApplicationEngine.Runtime.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.Network.P2P.Payloads; diff --git a/tests/Neo.UnitTests/SmartContract/UT_ApplicationEngine.cs b/tests/Neo.UnitTests/SmartContract/UT_ApplicationEngine.cs index 5656fc2799..7639377fe1 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_ApplicationEngine.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_ApplicationEngine.cs @@ -1,9 +1,20 @@ -using System; -using System.Collections.Immutable; -using System.Linq; +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_ApplicationEngine.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.SmartContract; +using System; +using System.Collections.Immutable; +using System.Linq; using Array = Neo.VM.Types.Array; namespace Neo.UnitTests.SmartContract diff --git a/tests/Neo.UnitTests/SmartContract/UT_ApplicationEngineProvider.cs b/tests/Neo.UnitTests/SmartContract/UT_ApplicationEngineProvider.cs index bcac4305c0..f4e99e6936 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_ApplicationEngineProvider.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_ApplicationEngineProvider.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_ApplicationEngineProvider.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.Network.P2P.Payloads; diff --git a/tests/Neo.UnitTests/SmartContract/UT_BinarySerializer.cs b/tests/Neo.UnitTests/SmartContract/UT_BinarySerializer.cs index c8182bc82b..6202c8336b 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_BinarySerializer.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_BinarySerializer.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_BinarySerializer.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.SmartContract; diff --git a/tests/Neo.UnitTests/SmartContract/UT_Contract.cs b/tests/Neo.UnitTests/SmartContract/UT_Contract.cs index 1661203d82..faf3c1fde4 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_Contract.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_Contract.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_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 FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.Network.P2P.Payloads; diff --git a/tests/Neo.UnitTests/SmartContract/UT_ContractParameter.cs b/tests/Neo.UnitTests/SmartContract/UT_ContractParameter.cs index 6a6db9e8dd..3c567ca5bc 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_ContractParameter.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_ContractParameter.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_ContractParameter.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.Cryptography.ECC; diff --git a/tests/Neo.UnitTests/SmartContract/UT_ContractParameterContext.cs b/tests/Neo.UnitTests/SmartContract/UT_ContractParameterContext.cs index 3413039fb5..aba90cc6f0 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_ContractParameterContext.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_ContractParameterContext.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_ContractParameterContext.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.Cryptography.ECC; diff --git a/tests/Neo.UnitTests/SmartContract/UT_ContractState.cs b/tests/Neo.UnitTests/SmartContract/UT_ContractState.cs index 4e1eab87fe..d0e52ae234 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_ContractState.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_ContractState.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_ContractState.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.Json; @@ -12,7 +23,7 @@ namespace Neo.UnitTests.SmartContract public class UT_ContractState { ContractState contract; - byte[] script = { 0x01 }; + readonly byte[] script = { 0x01 }; ContractManifest manifest; [TestInitialize] diff --git a/tests/Neo.UnitTests/SmartContract/UT_DeployedContract.cs b/tests/Neo.UnitTests/SmartContract/UT_DeployedContract.cs index b1571868bc..b5f8bbde0e 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_DeployedContract.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_DeployedContract.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_DeployedContract.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 System; diff --git a/tests/Neo.UnitTests/SmartContract/UT_Helper.cs b/tests/Neo.UnitTests/SmartContract/UT_Helper.cs index 67d637392e..3d682a4ee9 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_Helper.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_Helper.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_Helper.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.ECC; using Neo.Network.P2P.Payloads; diff --git a/tests/Neo.UnitTests/SmartContract/UT_InteropPrices.cs b/tests/Neo.UnitTests/SmartContract/UT_InteropPrices.cs index 96b20779e9..a55db382df 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_InteropPrices.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_InteropPrices.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_InteropPrices.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.SmartContract; diff --git a/tests/Neo.UnitTests/SmartContract/UT_InteropService.NEO.cs b/tests/Neo.UnitTests/SmartContract/UT_InteropService.NEO.cs index b4233bc6a9..49d7690188 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_InteropService.NEO.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_InteropService.NEO.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_InteropService.NEO.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.Cryptography; diff --git a/tests/Neo.UnitTests/SmartContract/UT_InteropService.cs b/tests/Neo.UnitTests/SmartContract/UT_InteropService.cs index d1c518aaa1..909ecd2457 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_InteropService.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_InteropService.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_InteropService.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.TestKit.Xunit2; using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; diff --git a/tests/Neo.UnitTests/SmartContract/UT_JsonSerializer.cs b/tests/Neo.UnitTests/SmartContract/UT_JsonSerializer.cs index bf608bc57e..3ab32ad7a5 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_JsonSerializer.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_JsonSerializer.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_JsonSerializer.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.Json; using Neo.SmartContract; diff --git a/tests/Neo.UnitTests/SmartContract/UT_KeyBuilder.cs b/tests/Neo.UnitTests/SmartContract/UT_KeyBuilder.cs index d03a411b4d..b16c061494 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_KeyBuilder.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_KeyBuilder.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_KeyBuilder.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; diff --git a/tests/Neo.UnitTests/SmartContract/UT_LogEventArgs.cs b/tests/Neo.UnitTests/SmartContract/UT_LogEventArgs.cs index 8dc3699c82..4e587a2246 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_LogEventArgs.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_LogEventArgs.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_LogEventArgs.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.Network.P2P.Payloads; using Neo.SmartContract; diff --git a/tests/Neo.UnitTests/SmartContract/UT_MethodToken.cs b/tests/Neo.UnitTests/SmartContract/UT_MethodToken.cs index 8d530eefd9..9d687e1053 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_MethodToken.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_MethodToken.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_MethodToken.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.SmartContract; diff --git a/tests/Neo.UnitTests/SmartContract/UT_NefFile.cs b/tests/Neo.UnitTests/SmartContract/UT_NefFile.cs index 24eff0cba2..40142e93be 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_NefFile.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_NefFile.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_NefFile.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; diff --git a/tests/Neo.UnitTests/SmartContract/UT_NotifyEventArgs.cs b/tests/Neo.UnitTests/SmartContract/UT_NotifyEventArgs.cs index e83f8fd7fc..fdaeb9106e 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_NotifyEventArgs.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_NotifyEventArgs.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_NotifyEventArgs.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.Network.P2P.Payloads; diff --git a/tests/Neo.UnitTests/SmartContract/UT_OpCodePrices.cs b/tests/Neo.UnitTests/SmartContract/UT_OpCodePrices.cs index fa82f194d2..13209618e3 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_OpCodePrices.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_OpCodePrices.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_OpCodePrices.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; diff --git a/tests/Neo.UnitTests/SmartContract/UT_SmartContractHelper.cs b/tests/Neo.UnitTests/SmartContract/UT_SmartContractHelper.cs index c4b55384a8..c14b15c241 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_SmartContractHelper.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_SmartContractHelper.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_SmartContractHelper.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.Network.P2P.Payloads; diff --git a/tests/Neo.UnitTests/SmartContract/UT_Syscalls.cs b/tests/Neo.UnitTests/SmartContract/UT_Syscalls.cs index 77c4f7d5ef..0a98b5fd66 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_Syscalls.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_Syscalls.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_Syscalls.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.TestKit.Xunit2; using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.Cryptography.ECC; diff --git a/tests/Neo.UnitTests/TestBlockchain.cs b/tests/Neo.UnitTests/TestBlockchain.cs index e2fdad04c2..5e24aca099 100644 --- a/tests/Neo.UnitTests/TestBlockchain.cs +++ b/tests/Neo.UnitTests/TestBlockchain.cs @@ -1,5 +1,16 @@ -using System; +// 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 Neo.Persistence; +using System; namespace Neo.UnitTests { diff --git a/tests/Neo.UnitTests/TestProtocolSettings.cs b/tests/Neo.UnitTests/TestProtocolSettings.cs index 88f3be2c52..b12f5c9a85 100644 --- a/tests/Neo.UnitTests/TestProtocolSettings.cs +++ b/tests/Neo.UnitTests/TestProtocolSettings.cs @@ -1,6 +1,14 @@ -using Neo.Persistence; -using System; -using System.Collections.Immutable; +// 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.UnitTests diff --git a/tests/Neo.UnitTests/TestUtils.cs b/tests/Neo.UnitTests/TestUtils.cs index 1425919608..f8f63de53a 100644 --- a/tests/Neo.UnitTests/TestUtils.cs +++ b/tests/Neo.UnitTests/TestUtils.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// TestUtils.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.Cryptography; using Neo.Cryptography.ECC; diff --git a/tests/Neo.UnitTests/TestVerifiable.cs b/tests/Neo.UnitTests/TestVerifiable.cs index e21178f84f..12dc7992f6 100644 --- a/tests/Neo.UnitTests/TestVerifiable.cs +++ b/tests/Neo.UnitTests/TestVerifiable.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// TestVerifiable.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.IO; using Neo.Network.P2P.Payloads; using Neo.Persistence; @@ -40,7 +51,7 @@ public void Serialize(BinaryWriter writer) public void SerializeUnsigned(BinaryWriter writer) { - writer.Write((string)testStr); + writer.Write(testStr); } } } diff --git a/tests/Neo.UnitTests/TestWalletAccount.cs b/tests/Neo.UnitTests/TestWalletAccount.cs index a36e26fc96..08686cf70b 100644 --- a/tests/Neo.UnitTests/TestWalletAccount.cs +++ b/tests/Neo.UnitTests/TestWalletAccount.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// TestWalletAccount.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 Moq; using Neo.SmartContract; using Neo.Wallets; diff --git a/tests/Neo.UnitTests/UT_BigDecimal.cs b/tests/Neo.UnitTests/UT_BigDecimal.cs index 9dc21f5b34..9e3c50a9db 100644 --- a/tests/Neo.UnitTests/UT_BigDecimal.cs +++ b/tests/Neo.UnitTests/UT_BigDecimal.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_BigDecimal.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 System; diff --git a/tests/Neo.UnitTests/UT_DataCache.cs b/tests/Neo.UnitTests/UT_DataCache.cs index ee6e05249d..008f166b6f 100644 --- a/tests/Neo.UnitTests/UT_DataCache.cs +++ b/tests/Neo.UnitTests/UT_DataCache.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_DataCache.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; diff --git a/tests/Neo.UnitTests/UT_Helper.cs b/tests/Neo.UnitTests/UT_Helper.cs index d4a08469eb..b7dc4f1681 100644 --- a/tests/Neo.UnitTests/UT_Helper.cs +++ b/tests/Neo.UnitTests/UT_Helper.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_Helper.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.Caching; diff --git a/tests/Neo.UnitTests/UT_NeoSystem.cs b/tests/Neo.UnitTests/UT_NeoSystem.cs index 646d214f6c..a88498b504 100644 --- a/tests/Neo.UnitTests/UT_NeoSystem.cs +++ b/tests/Neo.UnitTests/UT_NeoSystem.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_NeoSystem.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; diff --git a/tests/Neo.UnitTests/UT_ProtocolSettings.cs b/tests/Neo.UnitTests/UT_ProtocolSettings.cs index 74b529738a..28817bb482 100644 --- a/tests/Neo.UnitTests/UT_ProtocolSettings.cs +++ b/tests/Neo.UnitTests/UT_ProtocolSettings.cs @@ -1,8 +1,19 @@ -using System; +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_ProtocolSettings.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.Cryptography.ECC; using Neo.Wallets; +using System; namespace Neo.UnitTests { diff --git a/tests/Neo.UnitTests/UT_UInt160.cs b/tests/Neo.UnitTests/UT_UInt160.cs index 701eec0408..4799a80d19 100644 --- a/tests/Neo.UnitTests/UT_UInt160.cs +++ b/tests/Neo.UnitTests/UT_UInt160.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_UInt160.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. + #pragma warning disable CS1718 using FluentAssertions; diff --git a/tests/Neo.UnitTests/UT_UInt256.cs b/tests/Neo.UnitTests/UT_UInt256.cs index 1caa047a09..b2bd02dac3 100644 --- a/tests/Neo.UnitTests/UT_UInt256.cs +++ b/tests/Neo.UnitTests/UT_UInt256.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_UInt256.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. + #pragma warning disable CS1718 using FluentAssertions; diff --git a/tests/Neo.UnitTests/UT_UIntBenchmarks.cs b/tests/Neo.UnitTests/UT_UIntBenchmarks.cs index 882b5647ae..460588e1f1 100644 --- a/tests/Neo.UnitTests/UT_UIntBenchmarks.cs +++ b/tests/Neo.UnitTests/UT_UIntBenchmarks.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_UIntBenchmarks.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 System; diff --git a/tests/Neo.UnitTests/VM/UT_Helper.cs b/tests/Neo.UnitTests/VM/UT_Helper.cs index 539c5df028..fbe12fc787 100644 --- a/tests/Neo.UnitTests/VM/UT_Helper.cs +++ b/tests/Neo.UnitTests/VM/UT_Helper.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_Helper.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.Cryptography.ECC; diff --git a/tests/Neo.UnitTests/Wallets/NEP6/UT_NEP6Account.cs b/tests/Neo.UnitTests/Wallets/NEP6/UT_NEP6Account.cs index 3aac2f8f48..65ec90ab7e 100644 --- a/tests/Neo.UnitTests/Wallets/NEP6/UT_NEP6Account.cs +++ b/tests/Neo.UnitTests/Wallets/NEP6/UT_NEP6Account.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_NEP6Account.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.Cryptography; diff --git a/tests/Neo.UnitTests/Wallets/NEP6/UT_NEP6Contract.cs b/tests/Neo.UnitTests/Wallets/NEP6/UT_NEP6Contract.cs index 73262e390e..37f816c240 100644 --- a/tests/Neo.UnitTests/Wallets/NEP6/UT_NEP6Contract.cs +++ b/tests/Neo.UnitTests/Wallets/NEP6/UT_NEP6Contract.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_NEP6Contract.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.Json; diff --git a/tests/Neo.UnitTests/Wallets/NEP6/UT_NEP6Wallet.cs b/tests/Neo.UnitTests/Wallets/NEP6/UT_NEP6Wallet.cs index 098a6e1933..aff3561a75 100644 --- a/tests/Neo.UnitTests/Wallets/NEP6/UT_NEP6Wallet.cs +++ b/tests/Neo.UnitTests/Wallets/NEP6/UT_NEP6Wallet.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_NEP6Wallet.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.Json; diff --git a/tests/Neo.UnitTests/Wallets/NEP6/UT_ScryptParameters.cs b/tests/Neo.UnitTests/Wallets/NEP6/UT_ScryptParameters.cs index 0c3aba328c..8a468f9f41 100644 --- a/tests/Neo.UnitTests/Wallets/NEP6/UT_ScryptParameters.cs +++ b/tests/Neo.UnitTests/Wallets/NEP6/UT_ScryptParameters.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_ScryptParameters.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.Json; diff --git a/tests/Neo.UnitTests/Wallets/UT_AssetDescriptor.cs b/tests/Neo.UnitTests/Wallets/UT_AssetDescriptor.cs index a8d8308145..8d938492bc 100644 --- a/tests/Neo.UnitTests/Wallets/UT_AssetDescriptor.cs +++ b/tests/Neo.UnitTests/Wallets/UT_AssetDescriptor.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_AssetDescriptor.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.SmartContract.Native; diff --git a/tests/Neo.UnitTests/Wallets/UT_KeyPair.cs b/tests/Neo.UnitTests/Wallets/UT_KeyPair.cs index 5e5996ff0a..7ae84960c7 100644 --- a/tests/Neo.UnitTests/Wallets/UT_KeyPair.cs +++ b/tests/Neo.UnitTests/Wallets/UT_KeyPair.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_KeyPair.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.Cryptography; @@ -69,7 +80,7 @@ public void TestEqualsWithObj() for (int i = 0; i < privateKey.Length; i++) privateKey[i] = (byte)random.Next(256); KeyPair keyPair = new KeyPair(privateKey); - Object keyPair2 = keyPair as Object; + Object keyPair2 = keyPair; keyPair.Equals(keyPair2).Should().BeTrue(); } diff --git a/tests/Neo.UnitTests/Wallets/UT_Wallet.cs b/tests/Neo.UnitTests/Wallets/UT_Wallet.cs index 63a9d3e372..17604cd75c 100644 --- a/tests/Neo.UnitTests/Wallets/UT_Wallet.cs +++ b/tests/Neo.UnitTests/Wallets/UT_Wallet.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_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.Cryptography.ECC; diff --git a/tests/Neo.UnitTests/Wallets/UT_WalletAccount.cs b/tests/Neo.UnitTests/Wallets/UT_WalletAccount.cs index 6ad53945d9..26a8464a7f 100644 --- a/tests/Neo.UnitTests/Wallets/UT_WalletAccount.cs +++ b/tests/Neo.UnitTests/Wallets/UT_WalletAccount.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_WalletAccount.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.SmartContract; diff --git a/tests/Neo.UnitTests/Wallets/UT_Wallets_Helper.cs b/tests/Neo.UnitTests/Wallets/UT_Wallets_Helper.cs index 4fa35dc1a0..843eeae192 100644 --- a/tests/Neo.UnitTests/Wallets/UT_Wallets_Helper.cs +++ b/tests/Neo.UnitTests/Wallets/UT_Wallets_Helper.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_Wallets_Helper.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.Cryptography; diff --git a/tests/Neo.VM.Tests/Converters/ScriptConverter.cs b/tests/Neo.VM.Tests/Converters/ScriptConverter.cs index c0610a573c..064df4fb30 100644 --- a/tests/Neo.VM.Tests/Converters/ScriptConverter.cs +++ b/tests/Neo.VM.Tests/Converters/ScriptConverter.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// ScriptConverter.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.Test.Extensions; using Neo.VM; @@ -5,7 +16,6 @@ using Newtonsoft.Json.Linq; using System; using System.Linq; -using System.Text.RegularExpressions; namespace Neo.Test.Converters { diff --git a/tests/Neo.VM.Tests/Converters/UppercaseEnum.cs b/tests/Neo.VM.Tests/Converters/UppercaseEnum.cs index b1b168a3be..0da336e698 100644 --- a/tests/Neo.VM.Tests/Converters/UppercaseEnum.cs +++ b/tests/Neo.VM.Tests/Converters/UppercaseEnum.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UppercaseEnum.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 Newtonsoft.Json; using System; diff --git a/tests/Neo.VM.Tests/Extensions/JsonExtensions.cs b/tests/Neo.VM.Tests/Extensions/JsonExtensions.cs index 6f0c4d73d5..01dd057ca8 100644 --- a/tests/Neo.VM.Tests/Extensions/JsonExtensions.cs +++ b/tests/Neo.VM.Tests/Extensions/JsonExtensions.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// JsonExtensions.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 Newtonsoft.Json; using Newtonsoft.Json.Converters; using Newtonsoft.Json.Serialization; diff --git a/tests/Neo.VM.Tests/Extensions/StringExtensions.cs b/tests/Neo.VM.Tests/Extensions/StringExtensions.cs index cab595568b..4263d271c4 100644 --- a/tests/Neo.VM.Tests/Extensions/StringExtensions.cs +++ b/tests/Neo.VM.Tests/Extensions/StringExtensions.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// StringExtensions.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.Globalization; diff --git a/tests/Neo.VM.Tests/Helpers/RandomHelper.cs b/tests/Neo.VM.Tests/Helpers/RandomHelper.cs index 53085b44d5..77dc999145 100644 --- a/tests/Neo.VM.Tests/Helpers/RandomHelper.cs +++ b/tests/Neo.VM.Tests/Helpers/RandomHelper.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// RandomHelper.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; namespace Neo.Test.Helpers diff --git a/tests/Neo.VM.Tests/Types/TestEngine.cs b/tests/Neo.VM.Tests/Types/TestEngine.cs index 832e9a7fb4..07aa89a09f 100644 --- a/tests/Neo.VM.Tests/Types/TestEngine.cs +++ b/tests/Neo.VM.Tests/Types/TestEngine.cs @@ -1,6 +1,17 @@ -using System; +// Copyright (C) 2015-2024 The Neo Project. +// +// TestEngine.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; using Neo.VM.Types; +using System; namespace Neo.Test.Types { diff --git a/tests/Neo.VM.Tests/Types/VMUT.cs b/tests/Neo.VM.Tests/Types/VMUT.cs index a018d05c29..b24255d372 100644 --- a/tests/Neo.VM.Tests/Types/VMUT.cs +++ b/tests/Neo.VM.Tests/Types/VMUT.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// VMUT.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 Newtonsoft.Json; namespace Neo.Test.Types diff --git a/tests/Neo.VM.Tests/Types/VMUTActionType.cs b/tests/Neo.VM.Tests/Types/VMUTActionType.cs index a90691a6ad..5ac8b5b48e 100644 --- a/tests/Neo.VM.Tests/Types/VMUTActionType.cs +++ b/tests/Neo.VM.Tests/Types/VMUTActionType.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// VMUTActionType.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.Test.Types { public enum VMUTActionType diff --git a/tests/Neo.VM.Tests/Types/VMUTEntry.cs b/tests/Neo.VM.Tests/Types/VMUTEntry.cs index 64c1e76d94..7761b08de5 100644 --- a/tests/Neo.VM.Tests/Types/VMUTEntry.cs +++ b/tests/Neo.VM.Tests/Types/VMUTEntry.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// VMUTEntry.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.Test.Converters; using Newtonsoft.Json; diff --git a/tests/Neo.VM.Tests/Types/VMUTExecutionContextState.cs b/tests/Neo.VM.Tests/Types/VMUTExecutionContextState.cs index b0d20ae2f9..101142dc3a 100644 --- a/tests/Neo.VM.Tests/Types/VMUTExecutionContextState.cs +++ b/tests/Neo.VM.Tests/Types/VMUTExecutionContextState.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// VMUTExecutionContextState.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.Test.Converters; using Neo.VM; using Newtonsoft.Json; diff --git a/tests/Neo.VM.Tests/Types/VMUTExecutionEngineState.cs b/tests/Neo.VM.Tests/Types/VMUTExecutionEngineState.cs index 235654b0a4..3f931b3c32 100644 --- a/tests/Neo.VM.Tests/Types/VMUTExecutionEngineState.cs +++ b/tests/Neo.VM.Tests/Types/VMUTExecutionEngineState.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// VMUTExecutionEngineState.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.Test.Converters; using Neo.VM; using Newtonsoft.Json; diff --git a/tests/Neo.VM.Tests/Types/VMUTStackItem.cs b/tests/Neo.VM.Tests/Types/VMUTStackItem.cs index 5bbca0ff9f..5ce55bbfd3 100644 --- a/tests/Neo.VM.Tests/Types/VMUTStackItem.cs +++ b/tests/Neo.VM.Tests/Types/VMUTStackItem.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// VMUTStackItem.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 Newtonsoft.Json; using Newtonsoft.Json.Linq; diff --git a/tests/Neo.VM.Tests/Types/VMUTStackItemType.cs b/tests/Neo.VM.Tests/Types/VMUTStackItemType.cs index c11c5c86b9..845c062a02 100644 --- a/tests/Neo.VM.Tests/Types/VMUTStackItemType.cs +++ b/tests/Neo.VM.Tests/Types/VMUTStackItemType.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// VMUTStackItemType.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.Test.Types { public enum VMUTStackItemType diff --git a/tests/Neo.VM.Tests/Types/VMUTStep.cs b/tests/Neo.VM.Tests/Types/VMUTStep.cs index d0d88e0ca4..ad49606d4b 100644 --- a/tests/Neo.VM.Tests/Types/VMUTStep.cs +++ b/tests/Neo.VM.Tests/Types/VMUTStep.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// VMUTStep.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 Newtonsoft.Json; namespace Neo.Test.Types diff --git a/tests/Neo.VM.Tests/UtDebugger.cs b/tests/Neo.VM.Tests/UtDebugger.cs index 7b7f582416..13d33a7443 100644 --- a/tests/Neo.VM.Tests/UtDebugger.cs +++ b/tests/Neo.VM.Tests/UtDebugger.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UtDebugger.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.VM; diff --git a/tests/Neo.VM.Tests/UtEvaluationStack.cs b/tests/Neo.VM.Tests/UtEvaluationStack.cs index 03f1294d66..23526bc5de 100644 --- a/tests/Neo.VM.Tests/UtEvaluationStack.cs +++ b/tests/Neo.VM.Tests/UtEvaluationStack.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UtEvaluationStack.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.VM; using Neo.VM.Types; diff --git a/tests/Neo.VM.Tests/UtExecutionContext.cs b/tests/Neo.VM.Tests/UtExecutionContext.cs index cad2bc0f3e..0cf5c0224f 100644 --- a/tests/Neo.VM.Tests/UtExecutionContext.cs +++ b/tests/Neo.VM.Tests/UtExecutionContext.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UtExecutionContext.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.VM; using System; diff --git a/tests/Neo.VM.Tests/UtReferenceCounter.cs b/tests/Neo.VM.Tests/UtReferenceCounter.cs index 3a877eac83..32169d0dd6 100644 --- a/tests/Neo.VM.Tests/UtReferenceCounter.cs +++ b/tests/Neo.VM.Tests/UtReferenceCounter.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UtReferenceCounter.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.VM; using Neo.VM.Types; diff --git a/tests/Neo.VM.Tests/UtScript.cs b/tests/Neo.VM.Tests/UtScript.cs index 7e5c401488..3cc4280829 100644 --- a/tests/Neo.VM.Tests/UtScript.cs +++ b/tests/Neo.VM.Tests/UtScript.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UtScript.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.VM; using System; diff --git a/tests/Neo.VM.Tests/UtScriptBuilder.cs b/tests/Neo.VM.Tests/UtScriptBuilder.cs index 006e8f0acd..08701c6bd7 100644 --- a/tests/Neo.VM.Tests/UtScriptBuilder.cs +++ b/tests/Neo.VM.Tests/UtScriptBuilder.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UtScriptBuilder.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.Test.Extensions; using Neo.Test.Helpers; diff --git a/tests/Neo.VM.Tests/UtSlot.cs b/tests/Neo.VM.Tests/UtSlot.cs index 1e3403d650..49c81727d1 100644 --- a/tests/Neo.VM.Tests/UtSlot.cs +++ b/tests/Neo.VM.Tests/UtSlot.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UtSlot.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.VM; using Neo.VM.Types; @@ -77,7 +88,7 @@ public void TestEnumerable() // Test IEnumerable - enumerable = (IEnumerable)slot; + enumerable = slot; enumerator = enumerable.GetEnumerator(); CollectionAssert.AreEqual(System.Array.Empty(), GetEnumerable(enumerator).Cast().ToArray()); diff --git a/tests/Neo.VM.Tests/UtStackItem.cs b/tests/Neo.VM.Tests/UtStackItem.cs index 5ca73ae796..6eb50603d7 100644 --- a/tests/Neo.VM.Tests/UtStackItem.cs +++ b/tests/Neo.VM.Tests/UtStackItem.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UtStackItem.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.VM; using Neo.VM.Types; diff --git a/tests/Neo.VM.Tests/UtStruct.cs b/tests/Neo.VM.Tests/UtStruct.cs index eb66ca934b..ca1f5cb05f 100644 --- a/tests/Neo.VM.Tests/UtStruct.cs +++ b/tests/Neo.VM.Tests/UtStruct.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UtStruct.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.VM; using Neo.VM.Types; diff --git a/tests/Neo.VM.Tests/UtUnsafe.cs b/tests/Neo.VM.Tests/UtUnsafe.cs index 50c5ce59af..1ad0a6fc22 100644 --- a/tests/Neo.VM.Tests/UtUnsafe.cs +++ b/tests/Neo.VM.Tests/UtUnsafe.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UtUnsafe.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.VM; diff --git a/tests/Neo.VM.Tests/UtUtility.cs b/tests/Neo.VM.Tests/UtUtility.cs index d833a57fdf..fd039a6e5d 100644 --- a/tests/Neo.VM.Tests/UtUtility.cs +++ b/tests/Neo.VM.Tests/UtUtility.cs @@ -1,7 +1,18 @@ -using System; -using System.Numerics; +// Copyright (C) 2015-2024 The Neo Project. +// +// UtUtility.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.VM; +using System; +using System.Numerics; namespace Neo.Test { diff --git a/tests/Neo.VM.Tests/UtVMJson.cs b/tests/Neo.VM.Tests/UtVMJson.cs index a80395b9c5..fbed156d45 100644 --- a/tests/Neo.VM.Tests/UtVMJson.cs +++ b/tests/Neo.VM.Tests/UtVMJson.cs @@ -1,9 +1,20 @@ -using System; -using System.IO; -using System.Text; +// Copyright (C) 2015-2024 The Neo Project. +// +// UtVMJson.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.Test.Extensions; using Neo.Test.Types; +using System; +using System.IO; +using System.Text; namespace Neo.Test { diff --git a/tests/Neo.VM.Tests/VMJsonTestBase.cs b/tests/Neo.VM.Tests/VMJsonTestBase.cs index ac8e1494f6..85882b7a8e 100644 --- a/tests/Neo.VM.Tests/VMJsonTestBase.cs +++ b/tests/Neo.VM.Tests/VMJsonTestBase.cs @@ -1,3 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// VMJsonTestBase.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.Test.Extensions; using Neo.Test.Types; From 1b2c41b3082e76f849e30b01b2c1fef5526b0f39 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Tue, 2 Jan 2024 17:09:23 +0800 Subject: [PATCH 036/168] set timeout for tests (#3046) 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 768cdc56ef..f9ab69d94e 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -11,7 +11,8 @@ env: jobs: Test: - strategy: + timeout-minutes: 10 + strategy: matrix: os: [ubuntu-latest, windows-latest, macos-latest] runs-on: ${{ matrix.os }} From 9f50e372bf82d7f40c0a8442be8b1803493b5b62 Mon Sep 17 00:00:00 2001 From: Christopher Schuchardt Date: Tue, 2 Jan 2024 04:17:52 -0500 Subject: [PATCH 037/168] Removes `WebSocket`s from the network layer (#3039) * fixes #3038 * removed websocket port from configs * Removed wsport from settings * Remove obsolete warnings --------- Co-authored-by: Shargon --- src/Neo.CLI/CLI/MainService.cs | 1 - src/Neo.CLI/Settings.cs | 4 +- src/Neo.CLI/config.fs.mainnet.json | 1 - src/Neo.CLI/config.fs.testnet.json | 1 - src/Neo.CLI/config.json | 1 - src/Neo.CLI/config.mainnet.json | 1 - src/Neo.CLI/config.testnet.json | 1 - .../P2P/Capabilities/NodeCapability.cs | 2 + .../P2P/Capabilities/NodeCapabilityType.cs | 3 + .../P2P/Capabilities/ServerCapability.cs | 2 + src/Neo/Network/P2P/ChannelsConfig.cs | 5 -- src/Neo/Network/P2P/Connection.cs | 39 ------------ src/Neo/Network/P2P/Peer.cs | 59 +------------------ src/Neo/Network/P2P/RemoteNode.cs | 1 - .../P2P/Capabilities/UT_ServerCapability.cs | 6 +- .../Network/P2P/UT_ChannelsConfig.cs | 5 +- .../Neo.UnitTests/Network/P2P/UT_LocalNode.cs | 1 - 17 files changed, 16 insertions(+), 117 deletions(-) diff --git a/src/Neo.CLI/CLI/MainService.cs b/src/Neo.CLI/CLI/MainService.cs index 54b56d3d9a..dbccd2b28e 100644 --- a/src/Neo.CLI/CLI/MainService.cs +++ b/src/Neo.CLI/CLI/MainService.cs @@ -410,7 +410,6 @@ public async void Start(string[] args) NeoSystem.StartNode(new ChannelsConfig { Tcp = new IPEndPoint(IPAddress.Any, Settings.Default.P2P.Port), - WebSocket = new IPEndPoint(IPAddress.Any, Settings.Default.P2P.WsPort), MinDesiredConnections = Settings.Default.P2P.MinDesiredConnections, MaxConnections = Settings.Default.P2P.MaxConnections, MaxConnectionsPerAddress = Settings.Default.P2P.MaxConnectionsPerAddress diff --git a/src/Neo.CLI/Settings.cs b/src/Neo.CLI/Settings.cs index cc7ec54fea..3c3a8a76d6 100644 --- a/src/Neo.CLI/Settings.cs +++ b/src/Neo.CLI/Settings.cs @@ -87,15 +87,13 @@ public StorageSettings(IConfigurationSection section) public class P2PSettings { public ushort Port { get; } - public ushort WsPort { get; } public int MinDesiredConnections { get; } public int MaxConnections { get; } public int MaxConnectionsPerAddress { get; } public P2PSettings(IConfigurationSection section) { - this.Port = ushort.Parse(section.GetValue("Port", "10333")!); - this.WsPort = ushort.Parse(section.GetValue("WsPort", "10334")!); + this.Port = ushort.Parse(section.GetValue("Port", "10333")); this.MinDesiredConnections = section.GetValue("MinDesiredConnections", Peer.DefaultMinDesiredConnections); this.MaxConnections = section.GetValue("MaxConnections", Peer.DefaultMaxConnections); this.MaxConnectionsPerAddress = section.GetValue("MaxConnectionsPerAddress", 3); diff --git a/src/Neo.CLI/config.fs.mainnet.json b/src/Neo.CLI/config.fs.mainnet.json index 1e1b5fc92d..57bf751406 100644 --- a/src/Neo.CLI/config.fs.mainnet.json +++ b/src/Neo.CLI/config.fs.mainnet.json @@ -11,7 +11,6 @@ }, "P2P": { "Port": 40333, - "WsPort": 40334, "MinDesiredConnections": 10, "MaxConnections": 40, "MaxConnectionsPerAddress": 3 diff --git a/src/Neo.CLI/config.fs.testnet.json b/src/Neo.CLI/config.fs.testnet.json index 5e827a8480..a7a930c28b 100644 --- a/src/Neo.CLI/config.fs.testnet.json +++ b/src/Neo.CLI/config.fs.testnet.json @@ -11,7 +11,6 @@ }, "P2P": { "Port": 50333, - "WsPort": 50334, "MinDesiredConnections": 10, "MaxConnections": 40, "MaxConnectionsPerAddress": 3 diff --git a/src/Neo.CLI/config.json b/src/Neo.CLI/config.json index 6c9423ed05..897e33afab 100644 --- a/src/Neo.CLI/config.json +++ b/src/Neo.CLI/config.json @@ -11,7 +11,6 @@ }, "P2P": { "Port": 10333, - "WsPort": 10334, "MinDesiredConnections": 10, "MaxConnections": 40, "MaxConnectionsPerAddress": 3 diff --git a/src/Neo.CLI/config.mainnet.json b/src/Neo.CLI/config.mainnet.json index 6c9423ed05..897e33afab 100644 --- a/src/Neo.CLI/config.mainnet.json +++ b/src/Neo.CLI/config.mainnet.json @@ -11,7 +11,6 @@ }, "P2P": { "Port": 10333, - "WsPort": 10334, "MinDesiredConnections": 10, "MaxConnections": 40, "MaxConnectionsPerAddress": 3 diff --git a/src/Neo.CLI/config.testnet.json b/src/Neo.CLI/config.testnet.json index 1d118016a3..e3bcb7ce95 100644 --- a/src/Neo.CLI/config.testnet.json +++ b/src/Neo.CLI/config.testnet.json @@ -11,7 +11,6 @@ }, "P2P": { "Port": 20333, - "WsPort": 20334, "MinDesiredConnections": 10, "MaxConnections": 40, "MaxConnectionsPerAddress": 3 diff --git a/src/Neo/Network/P2P/Capabilities/NodeCapability.cs b/src/Neo/Network/P2P/Capabilities/NodeCapability.cs index 7ff1d46e3f..18ec61c38d 100644 --- a/src/Neo/Network/P2P/Capabilities/NodeCapability.cs +++ b/src/Neo/Network/P2P/Capabilities/NodeCapability.cs @@ -56,7 +56,9 @@ public static NodeCapability DeserializeFrom(ref MemoryReader reader) NodeCapabilityType type = (NodeCapabilityType)reader.ReadByte(); NodeCapability capability = type switch { +#pragma warning disable CS0612 // Type or member is obsolete NodeCapabilityType.TcpServer or NodeCapabilityType.WsServer => new ServerCapability(type), +#pragma warning restore CS0612 // Type or member is obsolete NodeCapabilityType.FullNode => new FullNodeCapability(), _ => throw new FormatException(), }; diff --git a/src/Neo/Network/P2P/Capabilities/NodeCapabilityType.cs b/src/Neo/Network/P2P/Capabilities/NodeCapabilityType.cs index 94f37dfb4a..419d086fa9 100644 --- a/src/Neo/Network/P2P/Capabilities/NodeCapabilityType.cs +++ b/src/Neo/Network/P2P/Capabilities/NodeCapabilityType.cs @@ -9,6 +9,8 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using System; + namespace Neo.Network.P2P.Capabilities { /// @@ -26,6 +28,7 @@ public enum NodeCapabilityType : byte /// /// Indicates that the node is listening on a WebSocket port. /// + [Obsolete] WsServer = 0x02, #endregion diff --git a/src/Neo/Network/P2P/Capabilities/ServerCapability.cs b/src/Neo/Network/P2P/Capabilities/ServerCapability.cs index d2df4e9efd..e8c2d110df 100644 --- a/src/Neo/Network/P2P/Capabilities/ServerCapability.cs +++ b/src/Neo/Network/P2P/Capabilities/ServerCapability.cs @@ -36,7 +36,9 @@ public class ServerCapability : NodeCapability /// The port that the node is listening on. public ServerCapability(NodeCapabilityType type, ushort port = 0) : base(type) { +#pragma warning disable CS0612 // Type or member is obsolete if (type != NodeCapabilityType.TcpServer && type != NodeCapabilityType.WsServer) +#pragma warning restore CS0612 // Type or member is obsolete { throw new ArgumentException(nameof(type)); } diff --git a/src/Neo/Network/P2P/ChannelsConfig.cs b/src/Neo/Network/P2P/ChannelsConfig.cs index 512a5ebb45..cc64242066 100644 --- a/src/Neo/Network/P2P/ChannelsConfig.cs +++ b/src/Neo/Network/P2P/ChannelsConfig.cs @@ -23,11 +23,6 @@ public class ChannelsConfig /// public IPEndPoint Tcp { get; set; } - /// - /// Web socket configuration. - /// - public IPEndPoint WebSocket { get; set; } - /// /// Minimum desired connections. /// diff --git a/src/Neo/Network/P2P/Connection.cs b/src/Neo/Network/P2P/Connection.cs index 15a74f06b4..53e30a2bde 100644 --- a/src/Neo/Network/P2P/Connection.cs +++ b/src/Neo/Network/P2P/Connection.cs @@ -13,8 +13,6 @@ using Akka.IO; using System; using System.Net; -using System.Net.WebSockets; -using System.Threading; namespace Neo.Network.P2P { @@ -48,7 +46,6 @@ internal class Close { public bool Abort; } private ICancelable timer; private readonly IActorRef tcp; - private readonly WebSocket ws; private bool disconnected = false; /// @@ -67,33 +64,9 @@ protected Connection(object connection, IPEndPoint remote, IPEndPoint local) case IActorRef tcp: this.tcp = tcp; break; - case WebSocket ws: - this.ws = ws; - WsReceive(); - break; } } - private void WsReceive() - { - byte[] buffer = new byte[512]; - ws.ReceiveAsync(buffer, CancellationToken.None).PipeTo(Self, - success: p => - { - switch (p.MessageType) - { - case WebSocketMessageType.Binary: - return new Tcp.Received(ByteString.FromBytes(buffer, 0, p.Count)); - case WebSocketMessageType.Close: - return Tcp.PeerClosed.Instance; - default: - ws.Abort(); - return Tcp.Aborted.Instance; - } - }, - failure: ex => new Tcp.ErrorClosed(ex.Message)); - } - /// /// Disconnect from the remote node. /// @@ -105,10 +78,6 @@ public void Disconnect(bool abort = false) { tcp.Tell(abort ? Tcp.Abort.Instance : Tcp.Close.Instance); } - else - { - ws.Abort(); - } Context.Stop(Self); } @@ -163,7 +132,6 @@ protected override void PostStop() if (!disconnected) tcp?.Tell(Tcp.Close.Instance); timer.CancelIfNotNull(); - ws?.Dispose(); base.PostStop(); } @@ -177,13 +145,6 @@ protected void SendData(ByteString data) { tcp.Tell(Tcp.Write.Create(data, Ack.Instance)); } - else - { - ArraySegment segment = new(data.ToArray()); - ws.SendAsync(segment, WebSocketMessageType.Binary, true, CancellationToken.None).PipeTo(Self, - success: () => Ack.Instance, - failure: ex => new Tcp.ErrorClosed(ex.Message)); - } } } } diff --git a/src/Neo/Network/P2P/Peer.cs b/src/Neo/Network/P2P/Peer.cs index 3648b59086..767d747b1d 100644 --- a/src/Neo/Network/P2P/Peer.cs +++ b/src/Neo/Network/P2P/Peer.cs @@ -11,9 +11,6 @@ using Akka.Actor; using Akka.IO; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Http; using Neo.IO; using System; using System.Buffers.Binary; @@ -24,8 +21,6 @@ using System.Net; using System.Net.NetworkInformation; using System.Net.Sockets; -using System.Net.WebSockets; -using System.Threading.Tasks; namespace Neo.Network.P2P { @@ -62,7 +57,6 @@ public class Connect } private class Timer { } - private class WsConnected { public WebSocket Socket; public IPEndPoint Remote; public IPEndPoint Local; } /// /// The default minimum number of desired connections. @@ -76,7 +70,6 @@ private class WsConnected { public WebSocket Socket; public IPEndPoint Remote; p private static readonly IActorRef tcp_manager = Context.System.Tcp(); private IActorRef tcp_listener; - private IWebHost ws_host; private ICancelable timer; private static readonly HashSet localAddresses = new(); @@ -109,11 +102,6 @@ private class WsConnected { public WebSocket Socket; public IPEndPoint Remote; p /// public int ListenerTcpPort { get; private set; } - /// - /// The port listened by the local WebSocket server. - /// - public int ListenerWsPort { get; private set; } - /// /// Indicates the maximum number of connections with the same address. /// @@ -221,9 +209,6 @@ protected override void OnReceive(object message) case Connect connect: ConnectToPeer(connect.EndPoint, connect.IsTrusted); break; - case WsConnected ws: - OnWsConnected(ws.Socket, ws.Remote, ws.Local); - break; case Tcp.Connected connected: OnTcpConnected(((IPEndPoint)connected.RemoteAddress).Unmap(), ((IPEndPoint)connected.LocalAddress).Unmap()); break; @@ -242,7 +227,6 @@ protected override void OnReceive(object message) private void OnStart(ChannelsConfig config) { ListenerTcpPort = config.Tcp?.Port ?? 0; - ListenerWsPort = config.WebSocket?.Port ?? 0; MinDesiredConnections = config.MinDesiredConnections; MaxConnections = config.MaxConnections; @@ -250,7 +234,7 @@ private void OnStart(ChannelsConfig config) // schedule time to trigger `OnTimer` event every TimerMillisecondsInterval ms timer = Context.System.Scheduler.ScheduleTellRepeatedlyCancelable(0, 5000, Context.Self, new Timer(), ActorRefs.NoSender); - if ((ListenerTcpPort > 0 || ListenerWsPort > 0) + if ((ListenerTcpPort > 0) && localAddresses.All(p => !p.IsIPv4MappedToIPv6 || IsIntranetAddress(p)) && UPnP.Discover()) { @@ -259,7 +243,6 @@ private void OnStart(ChannelsConfig config) localAddresses.Add(UPnP.GetExternalIP()); if (ListenerTcpPort > 0) UPnP.ForwardPort(ListenerTcpPort, ProtocolType.Tcp, "NEO Tcp"); - if (ListenerWsPort > 0) UPnP.ForwardPort(ListenerWsPort, ProtocolType.Tcp, "NEO WebSocket"); } catch { } } @@ -267,19 +250,6 @@ private void OnStart(ChannelsConfig config) { tcp_manager.Tell(new Tcp.Bind(Self, config.Tcp, options: new[] { new Inet.SO.ReuseAddress(true) })); } - if (ListenerWsPort > 0) - { - var host = "*"; - - if (!config.WebSocket.Address.GetAddressBytes().SequenceEqual(IPAddress.Any.GetAddressBytes())) - { - // Is not for all interfaces - host = config.WebSocket.Address.ToString(); - } - - ws_host = new WebHostBuilder().UseKestrel().UseUrls($"http://{host}:{ListenerWsPort}").Configure(app => app.UseWebSockets().Run(ProcessWebSocketAsync)).Build(); - ws_host.Start(); - } } /// @@ -368,40 +338,13 @@ private void OnTimer() } } - private void OnWsConnected(WebSocket ws, IPEndPoint remote, IPEndPoint local) - { - ConnectedAddresses.TryGetValue(remote.Address, out int count); - if (count >= MaxConnectionsPerAddress) - { - ws.Abort(); - } - else - { - ConnectedAddresses[remote.Address] = count + 1; - Context.ActorOf(ProtocolProps(ws, remote, local), $"connection_{Guid.NewGuid()}"); - } - } - protected override void PostStop() { timer.CancelIfNotNull(); - ws_host?.Dispose(); tcp_listener?.Tell(Tcp.Unbind.Instance); base.PostStop(); } - private async Task ProcessWebSocketAsync(HttpContext context) - { - if (!context.WebSockets.IsWebSocketRequest) return; - WebSocket ws = await context.WebSockets.AcceptWebSocketAsync(); - Self.Tell(new WsConnected - { - Socket = ws, - Remote = new IPEndPoint(context.Connection.RemoteIpAddress, context.Connection.RemotePort), - Local = new IPEndPoint(context.Connection.LocalIpAddress, context.Connection.LocalPort) - }); - } - /// /// Gets a object used for creating the protocol actor. /// diff --git a/src/Neo/Network/P2P/RemoteNode.cs b/src/Neo/Network/P2P/RemoteNode.cs index b38dd0a16a..6aa2c742a8 100644 --- a/src/Neo/Network/P2P/RemoteNode.cs +++ b/src/Neo/Network/P2P/RemoteNode.cs @@ -209,7 +209,6 @@ private void OnStartProtocol() }; if (localNode.ListenerTcpPort > 0) capabilities.Add(new ServerCapability(NodeCapabilityType.TcpServer, (ushort)localNode.ListenerTcpPort)); - if (localNode.ListenerWsPort > 0) capabilities.Add(new ServerCapability(NodeCapabilityType.WsServer, (ushort)localNode.ListenerWsPort)); SendMessage(Message.Create(MessageCommand.Version, VersionPayload.Create(system.Settings.Network, LocalNode.Nonce, LocalNode.UserAgent, capabilities.ToArray()))); } diff --git a/tests/Neo.UnitTests/Network/P2P/Capabilities/UT_ServerCapability.cs b/tests/Neo.UnitTests/Network/P2P/Capabilities/UT_ServerCapability.cs index bdc5cc8adc..b113d59da7 100644 --- a/tests/Neo.UnitTests/Network/P2P/Capabilities/UT_ServerCapability.cs +++ b/tests/Neo.UnitTests/Network/P2P/Capabilities/UT_ServerCapability.cs @@ -26,13 +26,16 @@ public void Size_Get() var test = new ServerCapability(NodeCapabilityType.TcpServer) { Port = 1 }; test.Size.Should().Be(3); +#pragma warning disable CS0612 // Type or member is obsolete test = new ServerCapability(NodeCapabilityType.WsServer) { Port = 2 }; +#pragma warning restore CS0612 // Type or member is obsolete test.Size.Should().Be(3); } [TestMethod] public void DeserializeAndSerialize() { +#pragma warning disable CS0612 // Type or member is obsolete var test = new ServerCapability(NodeCapabilityType.WsServer) { Port = 2 }; var buffer = test.ToArray(); @@ -43,6 +46,7 @@ public void DeserializeAndSerialize() Assert.AreEqual(test.Type, clone.Type); clone = new ServerCapability(NodeCapabilityType.WsServer, 123); +#pragma warning restore CS0612 // Type or member is obsolete br = new MemoryReader(buffer); ((ISerializable)clone).Deserialize(ref br); @@ -61,7 +65,7 @@ public void DeserializeAndSerialize() _ = new ServerCapability(NodeCapabilityType.FullNode); }); - // Wrog type + // Wrong type buffer[0] = 0xFF; Assert.ThrowsException(() => { diff --git a/tests/Neo.UnitTests/Network/P2P/UT_ChannelsConfig.cs b/tests/Neo.UnitTests/Network/P2P/UT_ChannelsConfig.cs index 9de77eccf6..5180f33c88 100644 --- a/tests/Neo.UnitTests/Network/P2P/UT_ChannelsConfig.cs +++ b/tests/Neo.UnitTests/Network/P2P/UT_ChannelsConfig.cs @@ -25,17 +25,16 @@ public void CreateTest() var config = new ChannelsConfig(); config.Tcp.Should().BeNull(); - config.WebSocket.Should().BeNull(); config.MinDesiredConnections.Should().Be(10); config.MaxConnections.Should().Be(40); config.MaxConnectionsPerAddress.Should().Be(3); - config.Tcp = config.WebSocket = new IPEndPoint(IPAddress.Any, 21); + config.Tcp = config.Tcp = new IPEndPoint(IPAddress.Any, 21); config.MaxConnectionsPerAddress++; config.MaxConnections++; config.MinDesiredConnections++; - config.Tcp.Should().BeSameAs(config.WebSocket); + config.Tcp.Should().BeSameAs(config.Tcp); config.Tcp.Address.Should().BeEquivalentTo(IPAddress.Any); config.Tcp.Port.Should().Be(21); config.MinDesiredConnections.Should().Be(11); diff --git a/tests/Neo.UnitTests/Network/P2P/UT_LocalNode.cs b/tests/Neo.UnitTests/Network/P2P/UT_LocalNode.cs index ac1aa7d378..cd307cdc51 100644 --- a/tests/Neo.UnitTests/Network/P2P/UT_LocalNode.cs +++ b/tests/Neo.UnitTests/Network/P2P/UT_LocalNode.cs @@ -37,7 +37,6 @@ public void TestDefaults() var localnode = senderProbe.ExpectMsg(); Assert.AreEqual(0, localnode.ListenerTcpPort); - Assert.AreEqual(0, localnode.ListenerWsPort); Assert.AreEqual(3, localnode.MaxConnectionsPerAddress); Assert.AreEqual(10, localnode.MinDesiredConnections); Assert.AreEqual(40, localnode.MaxConnections); From 5c9699ea48484d1b69836163a94aaef6753e5540 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Wed, 3 Jan 2024 17:12:55 +0800 Subject: [PATCH 038/168] Fix: specify the error message (#3030) * specify the error message * Update src/Neo/SmartContract/ApplicationEngine.Storage.cs --------- Co-authored-by: Shargon --- src/Neo.VM/ExecutionEngine.cs | 4 ++-- src/Neo/SmartContract/ApplicationEngine.Storage.cs | 7 ++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Neo.VM/ExecutionEngine.cs b/src/Neo.VM/ExecutionEngine.cs index 9996e2c46d..f67cc9caec 100644 --- a/src/Neo.VM/ExecutionEngine.cs +++ b/src/Neo.VM/ExecutionEngine.cs @@ -72,7 +72,7 @@ public VMState State { return state; } - internal protected set + protected internal set { if (state != value) { @@ -1459,7 +1459,7 @@ private void ExecuteLoadFromSlot(Slot? slot, int index) /// /// Execute the next instruction. /// - internal protected void ExecuteNext() + protected internal void ExecuteNext() { if (InvocationStack.Count == 0) { diff --git a/src/Neo/SmartContract/ApplicationEngine.Storage.cs b/src/Neo/SmartContract/ApplicationEngine.Storage.cs index 2d57388d11..3a8bb9d122 100644 --- a/src/Neo/SmartContract/ApplicationEngine.Storage.cs +++ b/src/Neo/SmartContract/ApplicationEngine.Storage.cs @@ -106,7 +106,7 @@ protected internal StorageContext GetReadOnlyContext() /// /// The storage context to convert. /// The readonly storage context. - internal protected static StorageContext AsReadOnly(StorageContext context) + protected internal static StorageContext AsReadOnly(StorageContext context) { if (!context.IsReadOnly) context = new StorageContext @@ -167,8 +167,9 @@ protected internal IIterator Find(StorageContext context, byte[] prefix, FindOpt /// The value of the entry. protected internal void Put(StorageContext context, byte[] key, byte[] value) { - if (key.Length > MaxStorageKeySize || value.Length > MaxStorageValueSize || context.IsReadOnly) - throw new ArgumentException(); + if (key.Length > MaxStorageKeySize) throw new ArgumentException("Key length too big", nameof(key)); + if (value.Length > MaxStorageValueSize) throw new ArgumentException("Value length too big", nameof(value)); + if (context.IsReadOnly) throw new ArgumentException("StorageContext is readonly", nameof(context)); int newDataSize; StorageKey skey = new() From 5873dc6c2071dae5b7dd2c7f4988160c7b64759d Mon Sep 17 00:00:00 2001 From: Christopher Schuchardt Date: Wed, 3 Jan 2024 04:21:18 -0500 Subject: [PATCH 039/168] Fixed workflow timeout-minutes (#3048) 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 f9ab69d94e..44dac993db 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -11,7 +11,7 @@ env: jobs: Test: - timeout-minutes: 10 + timeout-minutes: 15 strategy: matrix: os: [ubuntu-latest, windows-latest, macos-latest] From e5cebae87fd258c475b15c00603887785546d4e7 Mon Sep 17 00:00:00 2001 From: Shargon Date: Thu, 4 Jan 2024 10:26:47 -0800 Subject: [PATCH 040/168] Remove some warnings (#3057) * Remove warnings * Update src/Neo.CLI/Settings.cs Co-authored-by: Christopher Schuchardt --------- Co-authored-by: Jimmy Co-authored-by: Christopher Schuchardt --- src/Neo.CLI/Settings.cs | 20 +++++------ .../SmartContract/UT_InteropService.cs | 36 +++++++++---------- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/src/Neo.CLI/Settings.cs b/src/Neo.CLI/Settings.cs index 3c3a8a76d6..ba884fa56f 100644 --- a/src/Neo.CLI/Settings.cs +++ b/src/Neo.CLI/Settings.cs @@ -22,12 +22,12 @@ public class Settings public P2PSettings P2P { get; } public UnlockWalletSettings UnlockWallet { get; } - static Settings? _default; + static Settings? s_default; static bool UpdateDefault(IConfiguration configuration) { var settings = new Settings(configuration.GetSection("ApplicationConfiguration")); - return null == Interlocked.CompareExchange(ref _default, settings, null); + return null == Interlocked.CompareExchange(ref s_default, settings, null); } public static bool Initialize(IConfiguration configuration) @@ -39,22 +39,22 @@ public static Settings Default { get { - if (_default == null) + if (s_default == null) { - IConfigurationRoot config = new ConfigurationBuilder().AddJsonFile("config.json", optional: true).Build(); + var config = new ConfigurationBuilder().AddJsonFile("config.json", optional: true).Build(); Initialize(config); } - return _default!; + return s_default!; } } public Settings(IConfigurationSection section) { - this.Logger = new LoggerSettings(section.GetSection("Logger")); - this.Storage = new StorageSettings(section.GetSection("Storage")); - this.P2P = new P2PSettings(section.GetSection("P2P")); - this.UnlockWallet = new UnlockWalletSettings(section.GetSection("UnlockWallet")); + this.Logger = new(section.GetSection("Logger")); + this.Storage = new(section.GetSection("Storage")); + this.P2P = new(section.GetSection("P2P")); + this.UnlockWallet = new(section.GetSection("UnlockWallet")); } } @@ -93,7 +93,7 @@ public class P2PSettings public P2PSettings(IConfigurationSection section) { - this.Port = ushort.Parse(section.GetValue("Port", "10333")); + this.Port = section.GetValue("Port", 10333); this.MinDesiredConnections = section.GetValue("MinDesiredConnections", Peer.DefaultMinDesiredConnections); this.MaxConnections = section.GetValue("MaxConnections", Peer.DefaultMaxConnections); this.MaxConnectionsPerAddress = section.GetValue("MaxConnectionsPerAddress", 3); diff --git a/tests/Neo.UnitTests/SmartContract/UT_InteropService.cs b/tests/Neo.UnitTests/SmartContract/UT_InteropService.cs index 909ecd2457..3798eab327 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_InteropService.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_InteropService.cs @@ -56,7 +56,7 @@ public void Runtime_GetNotifications_Test() scriptHash2 = script.ToArray().ToScriptHash(); snapshot.DeleteContract(scriptHash2); - ContractState contract = TestUtils.GetContract(script.ToArray(), TestUtils.CreateManifest("test", ContractParameterType.Any, ContractParameterType.Integer, ContractParameterType.Integer)); + var contract = TestUtils.GetContract(script.ToArray(), TestUtils.CreateManifest("test", ContractParameterType.Any, ContractParameterType.Integer, ContractParameterType.Integer)); contract.Manifest.Abi.Events = new[] { new ContractEventDescriptor @@ -294,8 +294,8 @@ public void TestRuntime_CheckWitness() { byte[] privateKey = { 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}; - KeyPair keyPair = new(privateKey); - ECPoint pubkey = keyPair.PublicKey; + var keyPair = new KeyPair(privateKey); + var pubkey = keyPair.PublicKey; var engine = GetEngine(true); ((Transaction)engine.ScriptContainer).Signers[0].Account = Contract.CreateSignatureRedeemScript(pubkey).ToScriptHash(); @@ -316,8 +316,8 @@ public void TestRuntime_CheckWitness_Null_ScriptContainer() { byte[] privateKey = { 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}; - KeyPair keyPair = new(privateKey); - ECPoint pubkey = keyPair.PublicKey; + var keyPair = new KeyPair(privateKey); + var pubkey = keyPair.PublicKey; var engine = GetEngine(); @@ -328,7 +328,7 @@ public void TestRuntime_CheckWitness_Null_ScriptContainer() public void TestRuntime_Log() { var engine = GetEngine(true); - string message = "hello"; + var message = "hello"; ApplicationEngine.Log += LogEvent; engine.RuntimeLog(Encoding.UTF8.GetBytes(message)); ((Transaction)engine.ScriptContainer).Script.Span.ToHexString().Should().Be(new byte[] { 0x01, 0x02, 0x03 }.ToHexString()); @@ -396,16 +396,16 @@ public void TestRuntime_GetCurrentSigners_SysCall() public void TestCrypto_Verify() { var engine = GetEngine(true); - IVerifiable iv = engine.ScriptContainer; - byte[] message = iv.GetSignData(TestProtocolSettings.Default.Network); + var iv = engine.ScriptContainer; + var message = iv.GetSignData(TestProtocolSettings.Default.Network); byte[] privateKey = { 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}; KeyPair keyPair = new(privateKey); - ECPoint pubkey = keyPair.PublicKey; - byte[] signature = Crypto.Sign(message, privateKey, pubkey.EncodePoint(false).Skip(1).ToArray()); + var pubkey = keyPair.PublicKey; + var signature = Crypto.Sign(message, privateKey, pubkey.EncodePoint(false).Skip(1).ToArray()); engine.CheckSig(pubkey.EncodePoint(false), signature).Should().BeTrue(); - byte[] wrongkey = pubkey.EncodePoint(false); + var wrongkey = pubkey.EncodePoint(false); wrongkey[0] = 5; Assert.ThrowsException(() => engine.CheckSig(wrongkey, signature)); } @@ -424,7 +424,7 @@ public void TestBlockchain_GetBlock() NativeContract.Ledger.GetBlock(engine.Snapshot, UInt256.Zero).Should().BeNull(); - byte[] data1 = new byte[] { 0x01, 0x01, 0x01 ,0x01, 0x01, 0x01, 0x01, 0x01, + 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}; @@ -436,7 +436,7 @@ public void TestBlockchain_GetBlock() public void TestBlockchain_GetTransaction() { var engine = GetEngine(true, true); - byte[] data1 = new byte[] { 0x01, 0x01, 0x01 ,0x01, 0x01, 0x01, 0x01, 0x01, + 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}; @@ -469,7 +469,7 @@ public void TestBlockchain_GetTransactionHeight() public void TestBlockchain_GetContract() { var engine = GetEngine(true, true); - byte[] data1 = new byte[] { 0x01, 0x01, 0x01 ,0x01, 0x01, + var data1 = new byte[] { 0x01, 0x01, 0x01 ,0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }; @@ -638,7 +638,7 @@ public void TestStorageContext_AsReadOnly() public void TestContract_Call() { var snapshot = TestBlockchain.GetTestSnapshot(); - string method = "method"; + var method = "method"; var args = new VM.Types.Array { 0, 1 }; var state = TestUtils.GetContract(method, args.Count); @@ -696,13 +696,13 @@ public void TestContract_Destroy() [TestMethod] public void TestContract_CreateStandardAccount() { - ECPoint pubkey = ECPoint.Parse("024b817ef37f2fc3d4a33fe36687e592d9f30fe24b3e28187dc8f12b3b3b2b839e", ECCurve.Secp256r1); + var pubkey = ECPoint.Parse("024b817ef37f2fc3d4a33fe36687e592d9f30fe24b3e28187dc8f12b3b3b2b839e", ECCurve.Secp256r1); GetEngine().CreateStandardAccount(pubkey).ToArray().ToHexString().Should().Be("c44ea575c5f79638f0e73f39d7bd4b3337c81691"); } public static void LogEvent(object sender, LogEventArgs args) { - Transaction tx = (Transaction)args.ScriptContainer; + var tx = (Transaction)args.ScriptContainer; tx.Script = new byte[] { 0x01, 0x02, 0x03 }; } @@ -711,7 +711,7 @@ private static ApplicationEngine GetEngine(bool hasContainer = false, bool hasSn var tx = hasContainer ? TestUtils.GetTransaction(UInt160.Zero) : null; var snapshot = hasSnapshot ? TestBlockchain.GetTestSnapshot() : null; var block = hasBlock ? new Block { Header = new Header() } : null; - ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Application, tx, snapshot, block, TestBlockchain.TheNeoSystem.Settings, gas: gas); + var engine = ApplicationEngine.Create(TriggerType.Application, tx, snapshot, block, TestBlockchain.TheNeoSystem.Settings, gas: gas); if (addScript) engine.LoadScript(new byte[] { 0x01 }); return engine; } From 99a48d7a558fb5f3be470da9f1449b6663f575ba Mon Sep 17 00:00:00 2001 From: Christopher Schuchardt Date: Fri, 5 Jan 2024 03:58:54 -0500 Subject: [PATCH 041/168] Enforce Line Endings in `.editorconfig` (#3060) * before line ending change * Normalized line endings * added .gitattribtes to enforce line endings * before line ending change * Normalized line endings * before line ending change --------- Co-authored-by: Shargon --- .gitattributes | 64 +++++++++++++++++++ .../Neo.Benchmarks/Neo.Benchmarks.csproj | 30 ++++----- global.json | 12 ++-- src/Neo.Json/Neo.Json.csproj | 18 +++--- src/README.md | 44 ++++++------- .../Neo.Json.UnitTests.csproj | 30 ++++----- 6 files changed, 131 insertions(+), 67 deletions(-) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000..0c37abbc2d --- /dev/null +++ b/.gitattributes @@ -0,0 +1,64 @@ +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* text eol=lf + +############################################################################### +# Set default behavior for command prompt diff. +# +# This is need for earlier builds of msysgit that does not have it on by +# default for csharp files. +# Note: This is only used by command line +############################################################################### +*.cs diff=csharp + +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just uncomment the entries below +############################################################################### +*.sln text eol=crlf +#*.csproj text eol=crlf +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +############################################################################### +# behavior for image files +# +# image files are treated as binary by default. +############################################################################### +*.jpg binary +*.png binary +*.gif binary +*.ico binary + +############################################################################### +# diff behavior for common document formats +# +# Convert binary document formats to text before diffing them. This feature +# is only available from the command line. Turn it on by uncommenting the +# entries below. +############################################################################### +#*.doc diff=astextplain +#*.DOC diff=astextplain +#*.docx diff=astextplain +#*.DOCX diff=astextplain +#*.dot diff=astextplain +#*.DOT diff=astextplain +#*.pdf diff=astextplain +#*.PDF diff=astextplain +#*.rtf diff=astextplain +#*.RTF diff=astextplain diff --git a/benchmarks/Neo.Benchmarks/Neo.Benchmarks.csproj b/benchmarks/Neo.Benchmarks/Neo.Benchmarks.csproj index 12b6e861e4..12d32a3361 100644 --- a/benchmarks/Neo.Benchmarks/Neo.Benchmarks.csproj +++ b/benchmarks/Neo.Benchmarks/Neo.Benchmarks.csproj @@ -1,15 +1,15 @@ - - - - Exe - net7.0 - Neo - enable - false - - - - - - - + + + + Exe + net7.0 + Neo + enable + false + + + + + + + diff --git a/global.json b/global.json index 943dd9e463..423c2e2269 100644 --- a/global.json +++ b/global.json @@ -1,7 +1,7 @@ -{ - "sdk": { - "version": "7.0.404", - "rollForward": "latestFeature", - "allowPrerelease": false - } +{ + "sdk": { + "version": "7.0.404", + "rollForward": "latestFeature", + "allowPrerelease": false + } } diff --git a/src/Neo.Json/Neo.Json.csproj b/src/Neo.Json/Neo.Json.csproj index 94943d4402..b814851216 100644 --- a/src/Neo.Json/Neo.Json.csproj +++ b/src/Neo.Json/Neo.Json.csproj @@ -1,9 +1,9 @@ - - - - enable - enable - NEO;JSON - - - + + + + enable + enable + NEO;JSON + + + diff --git a/src/README.md b/src/README.md index 58a2cf66b5..c3738b18b9 100644 --- a/src/README.md +++ b/src/README.md @@ -1,25 +1,25 @@ -## Overview -This repository contain main classes of the [Neo](https://www.neo.org) blockchain. +## Overview +This repository contain main classes of the [Neo](https://www.neo.org) blockchain. Visit the [documentation](https://docs.neo.org/docs/en-us/index.html) to get started. -## Related projects -Code references are provided for all platform building blocks. That includes the base library, the VM, a command line application and the compiler. - -- [neo:](https://github.com/neo-project/neo/) Neo core library, contains base classes, including ledger, p2p and IO modules. -- [neo-modules:](https://github.com/neo-project/neo-modules/) Neo modules include additional tools and plugins to be used with Neo. -- [neo-devpack-dotnet:](https://github.com/neo-project/neo-devpack-dotnet/) These are the official tools used to convert a C# smart-contract into a *neo executable file*. - -## Opening a new issue -Please feel free to create new issues to suggest features or ask questions. - -- [Feature request](https://github.com/neo-project/neo/issues/new?assignees=&labels=discussion&template=feature-or-enhancement-request.md&title=) -- [Bug report](https://github.com/neo-project/neo/issues/new?assignees=&labels=&template=bug_report.md&title=) -- [Questions](https://github.com/neo-project/neo/issues/new?assignees=&labels=question&template=questions.md&title=) - -If you found a security issue, please refer to our [security policy](https://github.com/neo-project/neo/security/policy). - -## Bounty program -You can be rewarded by finding security issues. Please refer to our [bounty program page](https://neo.org/bounty) for more information. - -## License +## Related projects +Code references are provided for all platform building blocks. That includes the base library, the VM, a command line application and the compiler. + +- [neo:](https://github.com/neo-project/neo/) Neo core library, contains base classes, including ledger, p2p and IO modules. +- [neo-modules:](https://github.com/neo-project/neo-modules/) Neo modules include additional tools and plugins to be used with Neo. +- [neo-devpack-dotnet:](https://github.com/neo-project/neo-devpack-dotnet/) These are the official tools used to convert a C# smart-contract into a *neo executable file*. + +## Opening a new issue +Please feel free to create new issues to suggest features or ask questions. + +- [Feature request](https://github.com/neo-project/neo/issues/new?assignees=&labels=discussion&template=feature-or-enhancement-request.md&title=) +- [Bug report](https://github.com/neo-project/neo/issues/new?assignees=&labels=&template=bug_report.md&title=) +- [Questions](https://github.com/neo-project/neo/issues/new?assignees=&labels=question&template=questions.md&title=) + +If you found a security issue, please refer to our [security policy](https://github.com/neo-project/neo/security/policy). + +## Bounty program +You can be rewarded by finding security issues. Please refer to our [bounty program page](https://neo.org/bounty) for more information. + +## License The NEO project is licensed under the [MIT license](http://www.opensource.org/licenses/mit-license.php). diff --git a/tests/Neo.Json.UnitTests/Neo.Json.UnitTests.csproj b/tests/Neo.Json.UnitTests/Neo.Json.UnitTests.csproj index a7671e8430..893602f33c 100644 --- a/tests/Neo.Json.UnitTests/Neo.Json.UnitTests.csproj +++ b/tests/Neo.Json.UnitTests/Neo.Json.UnitTests.csproj @@ -1,15 +1,15 @@ - - - - enable - - - - - - - - - - - + + + + enable + + + + + + + + + + + From 87863c6236d60cf3f7e85b90cf7bcbbd898036ae Mon Sep 17 00:00:00 2001 From: Christopher Schuchardt Date: Sat, 6 Jan 2024 03:11:44 -0500 Subject: [PATCH 042/168] Removed asp.net core (#3065) --- src/Neo/Neo.csproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Neo/Neo.csproj b/src/Neo/Neo.csproj index 2d3a8a04cc..9ac4fd758b 100644 --- a/src/Neo/Neo.csproj +++ b/src/Neo/Neo.csproj @@ -5,14 +5,14 @@ NEO;AntShares;Blockchain;Smart Contract - - - - + + + + From 25f6297fcaaf3b4eeafd18176dfc2284e4dc63d5 Mon Sep 17 00:00:00 2001 From: Shargon Date: Mon, 8 Jan 2024 05:32:22 -0800 Subject: [PATCH 043/168] Make public ReadUserInput (#3068) * Make public ReadUserInput * LF --- src/Neo.CLI/CLI/MainService.Contracts.cs | 6 +- src/Neo.CLI/CLI/MainService.NEP17.cs | 2 +- src/Neo.CLI/CLI/MainService.Wallet.cs | 32 +++---- src/Neo.CLI/CLI/MainService.cs | 2 +- src/Neo.ConsoleService/ConsoleHelper.cs | 87 ++++++++++++++++++++ src/Neo.ConsoleService/ConsoleServiceBase.cs | 84 ------------------- src/Neo.GUI/GUI/ConsoleForm.cs | 3 +- 7 files changed, 110 insertions(+), 106 deletions(-) diff --git a/src/Neo.CLI/CLI/MainService.Contracts.cs b/src/Neo.CLI/CLI/MainService.Contracts.cs index e2aecbb598..b2a90dda11 100644 --- a/src/Neo.CLI/CLI/MainService.Contracts.cs +++ b/src/Neo.CLI/CLI/MainService.Contracts.cs @@ -49,7 +49,7 @@ private void OnDeployCommand(string filePath, string? manifestPath = null, JObje ConsoleHelper.Info("Gas consumed: ", $"{new BigDecimal((BigInteger)tx.SystemFee, NativeContract.GAS.Decimals)}"); ConsoleHelper.Info("Network fee: ", $"{new BigDecimal((BigInteger)tx.NetworkFee, NativeContract.GAS.Decimals)}"); ConsoleHelper.Info("Total fee: ", $"{new BigDecimal((BigInteger)(tx.SystemFee + tx.NetworkFee), NativeContract.GAS.Decimals)} GAS"); - if (!ReadUserInput("Relay tx? (no|yes)").IsYes()) // Add this in case just want to get hash but not relay + if (!ConsoleHelper.ReadUserInput("Relay tx? (no|yes)").IsYes()) // Add this in case just want to get hash but not relay { return; } @@ -111,7 +111,7 @@ private void OnUpdateCommand(UInt160 scriptHash, string filePath, string manifes ConsoleHelper.Info("Gas consumed: ", $"{new BigDecimal((BigInteger)tx.SystemFee, NativeContract.GAS.Decimals)}"); ConsoleHelper.Info("Network fee: ", $"{new BigDecimal((BigInteger)tx.NetworkFee, NativeContract.GAS.Decimals)}"); ConsoleHelper.Info("Total fee: ", $"{new BigDecimal((BigInteger)(tx.SystemFee + tx.NetworkFee), NativeContract.GAS.Decimals)} GAS"); - if (!ReadUserInput("Relay tx? (no|yes)").IsYes()) // Add this in case just want to get hash but not relay + if (!ConsoleHelper.ReadUserInput("Relay tx? (no|yes)").IsYes()) // Add this in case just want to get hash but not relay { return; } @@ -173,7 +173,7 @@ private void OnInvokeCommand(UInt160 scriptHash, string operation, JArray? contr $"{new BigDecimal((BigInteger)tx.NetworkFee, NativeContract.GAS.Decimals)}\t", "Total fee: ", $"{new BigDecimal((BigInteger)(tx.SystemFee + tx.NetworkFee), NativeContract.GAS.Decimals)} GAS"); - if (!ReadUserInput("Relay tx? (no|yes)").IsYes()) + if (!ConsoleHelper.ReadUserInput("Relay tx? (no|yes)").IsYes()) { return; } diff --git a/src/Neo.CLI/CLI/MainService.NEP17.cs b/src/Neo.CLI/CLI/MainService.NEP17.cs index cd0356e81b..131d171dc6 100644 --- a/src/Neo.CLI/CLI/MainService.NEP17.cs +++ b/src/Neo.CLI/CLI/MainService.NEP17.cs @@ -67,7 +67,7 @@ private void OnTransferCommand(UInt160 tokenHash, UInt160 to, decimal amount, UI ConsoleHelper.Error(GetExceptionMessage(e)); return; } - if (!ReadUserInput("Relay tx(no|yes)").IsYes()) + if (!ConsoleHelper.ReadUserInput("Relay tx(no|yes)").IsYes()) { return; } diff --git a/src/Neo.CLI/CLI/MainService.Wallet.cs b/src/Neo.CLI/CLI/MainService.Wallet.cs index 041aab3a0c..e74273bff4 100644 --- a/src/Neo.CLI/CLI/MainService.Wallet.cs +++ b/src/Neo.CLI/CLI/MainService.Wallet.cs @@ -44,7 +44,7 @@ private void OnOpenWallet(string path) ConsoleHelper.Error("File does not exist"); return; } - string password = ReadUserInput("password", true); + string password = ConsoleHelper.ReadUserInput("password", true); if (password.Length == 0) { ConsoleHelper.Info("Cancelled"); @@ -87,7 +87,7 @@ private void OnUpgradeWalletCommand(string path) ConsoleHelper.Error("File does not exist."); return; } - string password = ReadUserInput("password", true); + string password = ConsoleHelper.ReadUserInput("password", true); if (password.Length == 0) { ConsoleHelper.Info("Cancelled"); @@ -114,7 +114,7 @@ private void OnCreateAddressCommand(ushort count = 1) string path = "address.txt"; if (File.Exists(path)) { - if (!ReadUserInput($"The file '{path}' already exists, do you want to overwrite it? (yes|no)", false).IsYes()) + if (!ConsoleHelper.ReadUserInput($"The file '{path}' already exists, do you want to overwrite it? (yes|no)", false).IsYes()) { return; } @@ -150,7 +150,7 @@ private void OnDeleteAddressCommand(UInt160 address) { if (NoWallet()) return; - if (ReadUserInput($"Warning: Irrevocable operation!\nAre you sure to delete account {address.ToAddress(NeoSystem.Settings.AddressVersion)}? (no|yes)").IsYes()) + if (ConsoleHelper.ReadUserInput($"Warning: Irrevocable operation!\nAre you sure to delete account {address.ToAddress(NeoSystem.Settings.AddressVersion)}? (no|yes)").IsYes()) { if (CurrentWallet!.DeleteAccount(address)) { @@ -181,7 +181,7 @@ private void OnExportKeyCommand(string? path = null, UInt160? scriptHash = null) ConsoleHelper.Error($"File '{path}' already exists"); return; } - string password = ReadUserInput("password", true); + string password = ConsoleHelper.ReadUserInput("password", true); if (password.Length == 0) { ConsoleHelper.Info("Cancelled"); @@ -213,13 +213,13 @@ private void OnExportKeyCommand(string? path = null, UInt160? scriptHash = null) [ConsoleCommand("create wallet", Category = "Wallet Commands")] private void OnCreateWalletCommand(string path, string? wifOrFile = null) { - string password = ReadUserInput("password", true); + string password = ConsoleHelper.ReadUserInput("password", true); if (password.Length == 0) { ConsoleHelper.Info("Cancelled"); return; } - string password2 = ReadUserInput("repeat password", true); + string password2 = ConsoleHelper.ReadUserInput("repeat password", true); if (password != password2) { ConsoleHelper.Error("Two passwords not match."); @@ -287,7 +287,7 @@ private void OnImportKeyCommand(string wifOrFile) if (wifOrFile.Length > 1024 * 1024) { - if (!ReadUserInput($"The file '{fileInfo.FullName}' is too big, do you want to continue? (yes|no)", false).IsYes()) + if (!ConsoleHelper.ReadUserInput($"The file '{fileInfo.FullName}' is too big, do you want to continue? (yes|no)", false).IsYes()) { return; } @@ -344,7 +344,7 @@ private void OnImportWatchOnlyCommand(string addressOrFile) if (fileInfo.Length > 1024 * 1024) { - if (!ReadUserInput($"The file '{fileInfo.FullName}' is too big, do you want to continue? (yes|no)", false).IsYes()) + if (!ConsoleHelper.ReadUserInput($"The file '{fileInfo.FullName}' is too big, do you want to continue? (yes|no)", false).IsYes()) { return; } @@ -500,7 +500,7 @@ private void OnSignCommand(JObject jsonObjectToSign) private void OnSendCommand(UInt160 asset, UInt160 to, string amount, UInt160? from = null, string? data = null, UInt160[]? signerAccounts = null) { if (NoWallet()) return; - string password = ReadUserInput("password", true); + string password = ConsoleHelper.ReadUserInput("password", true); if (password.Length == 0) { ConsoleHelper.Info("Cancelled"); @@ -554,7 +554,7 @@ private void OnSendCommand(UInt160 asset, UInt160 to, string amount, UInt160? fr $"{new BigDecimal((BigInteger)tx.NetworkFee, NativeContract.GAS.Decimals)}\t", "Total fee: ", $"{new BigDecimal((BigInteger)(tx.SystemFee + tx.NetworkFee), NativeContract.GAS.Decimals)} GAS"); - if (!ReadUserInput("Relay tx? (no|yes)").IsYes()) + if (!ConsoleHelper.ReadUserInput("Relay tx? (no|yes)").IsYes()) { return; } @@ -625,7 +625,7 @@ private void OnCancelCommand(UInt256 txid, UInt160? sender = null, UInt160[]? si { var snapshot = NeoSystem.StoreView; AssetDescriptor descriptor = new(snapshot, NeoSystem.Settings, NativeContract.GAS.Hash); - string extracFee = ReadUserInput("This tx is not in mempool, please input extra fee manually"); + string extracFee = ConsoleHelper.ReadUserInput("This tx is not in mempool, please input extra fee manually"); if (!BigDecimal.TryParse(extracFee, descriptor.Decimals, out BigDecimal decimalExtraFee) || decimalExtraFee.Sign <= 0) { ConsoleHelper.Error("Incorrect Amount Format"); @@ -638,7 +638,7 @@ private void OnCancelCommand(UInt256 txid, UInt160? sender = null, UInt160[]? si $"{new BigDecimal((BigInteger)tx.NetworkFee, NativeContract.GAS.Decimals)}\t", "Total fee: ", $"{new BigDecimal((BigInteger)(tx.SystemFee + tx.NetworkFee), NativeContract.GAS.Decimals)} GAS"); - if (!ReadUserInput("Relay tx? (no|yes)").IsYes()) + if (!ConsoleHelper.ReadUserInput("Relay tx? (no|yes)").IsYes()) { return; } @@ -667,7 +667,7 @@ private void OnShowGasCommand() private void OnChangePasswordCommand() { if (NoWallet()) return; - string oldPassword = ReadUserInput("password", true); + string oldPassword = ConsoleHelper.ReadUserInput("password", true); if (oldPassword.Length == 0) { ConsoleHelper.Info("Cancelled"); @@ -678,8 +678,8 @@ private void OnChangePasswordCommand() ConsoleHelper.Error("Incorrect password"); return; } - string newPassword = ReadUserInput("New password", true); - string newPasswordReEntered = ReadUserInput("Re-Enter Password", true); + string newPassword = ConsoleHelper.ReadUserInput("New password", true); + string newPasswordReEntered = ConsoleHelper.ReadUserInput("Re-Enter Password", true); if (!newPassword.Equals(newPasswordReEntered)) { ConsoleHelper.Error("Two passwords entered are inconsistent!"); diff --git a/src/Neo.CLI/CLI/MainService.cs b/src/Neo.CLI/CLI/MainService.cs index dbccd2b28e..1340c68cdd 100644 --- a/src/Neo.CLI/CLI/MainService.cs +++ b/src/Neo.CLI/CLI/MainService.cs @@ -537,7 +537,7 @@ private void SendTransaction(byte[] script, UInt160? account = null, long gas = if (engine.State == VMState.FAULT) return; } - if (!ReadUserInput("Relay tx(no|yes)").IsYes()) + if (!ConsoleHelper.ReadUserInput("Relay tx(no|yes)").IsYes()) { return; } diff --git a/src/Neo.ConsoleService/ConsoleHelper.cs b/src/Neo.ConsoleService/ConsoleHelper.cs index 19bfcd155a..78f170a3af 100644 --- a/src/Neo.ConsoleService/ConsoleHelper.cs +++ b/src/Neo.ConsoleService/ConsoleHelper.cs @@ -10,6 +10,8 @@ // modifications are permitted. using System; +using System.Security; +using System.Text; namespace Neo.ConsoleService { @@ -19,6 +21,8 @@ public static class ConsoleHelper private static readonly ConsoleColorSet WarningColor = new(ConsoleColor.Yellow); private static readonly ConsoleColorSet ErrorColor = new(ConsoleColor.Red); + public static bool ReadingPassword { get; private set; } = false; + /// /// Info handles message in the format of "[tag]:[message]", /// avoid using Info if the `tag` is too long @@ -72,5 +76,88 @@ private static void Log(string tag, ConsoleColorSet colorSet, string msg) currentColor.Apply(); Console.WriteLine(msg); } + + public static string ReadUserInput(string prompt, bool password = false) + { + const string t = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; + var sb = new StringBuilder(); + + if (!string.IsNullOrEmpty(prompt)) + { + Console.Write(prompt + ": "); + } + + if (password) ReadingPassword = true; + var prevForeground = Console.ForegroundColor; + Console.ForegroundColor = ConsoleColor.Yellow; + + if (Console.IsInputRedirected) + { + // neo-gui Console require it + sb.Append(Console.ReadLine()); + } + else + { + ConsoleKeyInfo key; + do + { + key = Console.ReadKey(true); + + if (t.IndexOf(key.KeyChar) != -1) + { + sb.Append(key.KeyChar); + Console.Write(password ? '*' : key.KeyChar); + } + else if (key.Key == ConsoleKey.Backspace && sb.Length > 0) + { + sb.Length--; + Console.Write("\b \b"); + } + } while (key.Key != ConsoleKey.Enter); + } + + Console.ForegroundColor = prevForeground; + if (password) ReadingPassword = false; + Console.WriteLine(); + return sb.ToString(); + } + + public static SecureString ReadSecureString(string prompt) + { + const string t = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; + SecureString securePwd = new SecureString(); + ConsoleKeyInfo key; + + if (!string.IsNullOrEmpty(prompt)) + { + Console.Write(prompt + ": "); + } + + ReadingPassword = true; + Console.ForegroundColor = ConsoleColor.Yellow; + + do + { + key = Console.ReadKey(true); + if (t.IndexOf(key.KeyChar) != -1) + { + securePwd.AppendChar(key.KeyChar); + Console.Write('*'); + } + else if (key.Key == ConsoleKey.Backspace && securePwd.Length > 0) + { + securePwd.RemoveAt(securePwd.Length - 1); + Console.Write(key.KeyChar); + Console.Write(' '); + Console.Write(key.KeyChar); + } + } while (key.Key != ConsoleKey.Enter); + + Console.ForegroundColor = ConsoleColor.White; + ReadingPassword = false; + Console.WriteLine(); + securePwd.MakeReadOnly(); + return securePwd; + } } } diff --git a/src/Neo.ConsoleService/ConsoleServiceBase.cs b/src/Neo.ConsoleService/ConsoleServiceBase.cs index 5598dcaa45..4702cf28ed 100644 --- a/src/Neo.ConsoleService/ConsoleServiceBase.cs +++ b/src/Neo.ConsoleService/ConsoleServiceBase.cs @@ -33,7 +33,6 @@ public abstract class ConsoleServiceBase public abstract string ServiceName { get; } protected bool ShowPrompt { get; set; } = true; - public bool ReadingPassword { get; set; } = false; private bool _running; private readonly CancellationTokenSource _shutdownTokenSource = new(); @@ -298,89 +297,6 @@ public virtual void OnStop() _shutdownAcknowledged.Signal(); } - public string ReadUserInput(string prompt, bool password = false) - { - const string t = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; - var sb = new StringBuilder(); - - if (!string.IsNullOrEmpty(prompt)) - { - Console.Write(prompt + ": "); - } - - if (password) ReadingPassword = true; - var prevForeground = Console.ForegroundColor; - Console.ForegroundColor = ConsoleColor.Yellow; - - if (Console.IsInputRedirected) - { - // neo-gui Console require it - sb.Append(Console.ReadLine()); - } - else - { - ConsoleKeyInfo key; - do - { - key = Console.ReadKey(true); - - if (t.IndexOf(key.KeyChar) != -1) - { - sb.Append(key.KeyChar); - Console.Write(password ? '*' : key.KeyChar); - } - else if (key.Key == ConsoleKey.Backspace && sb.Length > 0) - { - sb.Length--; - Console.Write("\b \b"); - } - } while (key.Key != ConsoleKey.Enter); - } - - Console.ForegroundColor = prevForeground; - if (password) ReadingPassword = false; - Console.WriteLine(); - return sb.ToString(); - } - - public SecureString ReadSecureString(string prompt) - { - const string t = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; - SecureString securePwd = new SecureString(); - ConsoleKeyInfo key; - - if (!string.IsNullOrEmpty(prompt)) - { - Console.Write(prompt + ": "); - } - - ReadingPassword = true; - Console.ForegroundColor = ConsoleColor.Yellow; - - do - { - key = Console.ReadKey(true); - if (t.IndexOf(key.KeyChar) != -1) - { - securePwd.AppendChar(key.KeyChar); - Console.Write('*'); - } - else if (key.Key == ConsoleKey.Backspace && securePwd.Length > 0) - { - securePwd.RemoveAt(securePwd.Length - 1); - Console.Write(key.KeyChar); - Console.Write(' '); - Console.Write(key.KeyChar); - } - } while (key.Key != ConsoleKey.Enter); - - Console.ForegroundColor = ConsoleColor.White; - ReadingPassword = false; - Console.WriteLine(); - securePwd.MakeReadOnly(); - return securePwd; - } - private void TriggerGracefulShutdown() { if (!_running) return; diff --git a/src/Neo.GUI/GUI/ConsoleForm.cs b/src/Neo.GUI/GUI/ConsoleForm.cs index 79121608fd..ae1543980e 100644 --- a/src/Neo.GUI/GUI/ConsoleForm.cs +++ b/src/Neo.GUI/GUI/ConsoleForm.cs @@ -9,6 +9,7 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using Neo.ConsoleService; using System; using System.IO; using System.Threading; @@ -50,7 +51,7 @@ private void textBox2_KeyDown(object sender, KeyEventArgs e) { e.SuppressKeyPress = true; string line = $"{textBox2.Text}{Environment.NewLine}"; - textBox1.AppendText(Program.Service.ReadingPassword ? "***" : line); + textBox1.AppendText(ConsoleHelper.ReadingPassword ? "***" : line); switch (textBox2.Text.ToLower()) { case "clear": From 7b928451e4460c6be347c4f897ec3bd178b9ea57 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Tue, 9 Jan 2024 23:07:44 +0800 Subject: [PATCH 044/168] add hash verification for OnImport (#3070) Co-authored-by: Shargon --- src/Neo/Network/P2P/Payloads/Header.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Neo/Network/P2P/Payloads/Header.cs b/src/Neo/Network/P2P/Payloads/Header.cs index 9519c1432c..9e1d77fb8a 100644 --- a/src/Neo/Network/P2P/Payloads/Header.cs +++ b/src/Neo/Network/P2P/Payloads/Header.cs @@ -243,6 +243,7 @@ internal bool Verify(ProtocolSettings settings, DataCache snapshot) TrimmedBlock prev = NativeContract.Ledger.GetTrimmedBlock(snapshot, prevHash); if (prev is null) return false; if (prev.Index + 1 != index) return false; + if (prev.Hash != prevHash) return false; if (prev.Header.timestamp >= timestamp) return false; if (!this.VerifyWitnesses(settings, snapshot, 3_00000000L)) return false; return true; From 9420b97093dd5b47bd2c8081d1efd9a277c76d57 Mon Sep 17 00:00:00 2001 From: Christopher Schuchardt Date: Tue, 9 Jan 2024 10:11:47 -0500 Subject: [PATCH 045/168] Updated unit-test (#3073) Co-authored-by: Shargon --- tests/Neo.UnitTests/Neo.UnitTests.csproj | 8 -------- 1 file changed, 8 deletions(-) diff --git a/tests/Neo.UnitTests/Neo.UnitTests.csproj b/tests/Neo.UnitTests/Neo.UnitTests.csproj index 909c3c53e3..8c1216740b 100644 --- a/tests/Neo.UnitTests/Neo.UnitTests.csproj +++ b/tests/Neo.UnitTests/Neo.UnitTests.csproj @@ -20,12 +20,4 @@ - - - - - - - - From e62e40248be73958fa4fc2f2afaefd833479c80d Mon Sep 17 00:00:00 2001 From: Christopher Schuchardt Date: Tue, 9 Jan 2024 10:15:29 -0500 Subject: [PATCH 046/168] Removed `MyGet` (#3071) * Removed MyGet from github workflow * Remove my-get from nuget.config * fix? --------- Co-authored-by: Shargon --- .github/workflows/main.yml | 75 +++++++++++++++++++------------------- NuGet.Config | 3 +- 2 files changed, 39 insertions(+), 39 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 44dac993db..521cbc5611 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -37,43 +37,44 @@ jobs: with: github-token: ${{ secrets.GITHUB_TOKEN }} - PublishMyGet: - if: github.ref == 'refs/heads/master' && startsWith(github.repository, 'neo-project/') - needs: Test - runs-on: ubuntu-latest - steps: - - 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: Set Version - run: git rev-list --count HEAD | xargs printf 'CI%05d' | xargs -I{} echo 'VERSION_SUFFIX={}' >> $GITHUB_ENV - - name : Pack (Neo) - run: | - dotnet pack \ - --configuration Debug \ - --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 MyGet - working-directory: ./out - run: | - for filename in *.nupkg; do - dotnet nuget push "${filename}" \ - --source https://www.myget.org/F/neo/api/v3/index.json \ - --api-key "${{ secrets.MYGET_TOKEN }}" \ - --disable-buffering \ - --no-service-endpoint; - done; - shell: bash + # MyGet isn't working + # PublishMyGet: + # if: github.ref == 'refs/heads/master' && startsWith(github.repository, 'neo-project/') + # needs: Test + # runs-on: ubuntu-latest + # steps: + # - 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: Set Version + # run: git rev-list --count HEAD | xargs printf 'CI%05d' | xargs -I{} echo 'VERSION_SUFFIX={}' >> $GITHUB_ENV + # - name : Pack (Neo) + # run: | + # dotnet pack \ + # --configuration Debug \ + # --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 MyGet + # working-directory: ./out + # run: | + # for filename in *.nupkg; do + # dotnet nuget push "${filename}" \ + # --source https://www.myget.org/F/neo/api/v3/index.json \ + # --api-key "${{ secrets.MYGET_TOKEN }}" \ + # --disable-buffering \ + # --no-service-endpoint; + # done; + # shell: bash Release: if: github.ref == 'refs/heads/master' && startsWith(github.repository, 'neo-project/') diff --git a/NuGet.Config b/NuGet.Config index c06788942f..5922e754af 100644 --- a/NuGet.Config +++ b/NuGet.Config @@ -2,7 +2,6 @@ - - \ No newline at end of file + From 3feca2ae15cf41ebe97672ce04a3c7642b317935 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Wed, 10 Jan 2024 12:22:58 +0800 Subject: [PATCH 047/168] avoid nonsense exception messages. (#3063) Co-authored-by: Shargon --- src/Neo/Ledger/Blockchain.cs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/Neo/Ledger/Blockchain.cs b/src/Neo/Ledger/Blockchain.cs index d9fc3e1b3f..1186a12474 100644 --- a/src/Neo/Ledger/Blockchain.cs +++ b/src/Neo/Ledger/Blockchain.cs @@ -409,7 +409,12 @@ private void Persist(Block block) using (ApplicationEngine engine = ApplicationEngine.Create(TriggerType.OnPersist, null, snapshot, block, system.Settings, 0)) { engine.LoadScript(onPersistScript); - if (engine.Execute() != VMState.HALT) throw new InvalidOperationException(); + if (engine.Execute() != VMState.HALT) + { + if (engine.FaultException != null) + throw engine.FaultException; + throw new InvalidOperationException(); + } ApplicationExecuted application_executed = new(engine); Context.System.EventStream.Publish(application_executed); all_application_executed.Add(application_executed); @@ -438,7 +443,12 @@ private void Persist(Block block) using (ApplicationEngine engine = ApplicationEngine.Create(TriggerType.PostPersist, null, snapshot, block, system.Settings, 0)) { engine.LoadScript(postPersistScript); - if (engine.Execute() != VMState.HALT) throw new InvalidOperationException(); + if (engine.Execute() != VMState.HALT) + { + if (engine.FaultException != null) + throw engine.FaultException; + throw new InvalidOperationException(); + } ApplicationExecuted application_executed = new(engine); Context.System.EventStream.Publish(application_executed); all_application_executed.Add(application_executed); From 73d36e3be43b236d9125efdd43f0630123a8fef4 Mon Sep 17 00:00:00 2001 From: Christopher Schuchardt Date: Wed, 10 Jan 2024 02:11:36 -0500 Subject: [PATCH 048/168] Updated BLS12_381 (#3074) --- src/Neo/Neo.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Neo/Neo.csproj b/src/Neo/Neo.csproj index 9ac4fd758b..f798cf1701 100644 --- a/src/Neo/Neo.csproj +++ b/src/Neo/Neo.csproj @@ -13,7 +13,7 @@ - + From 27df5ce9e45ae224258c7515d9e239a7ceb6d4a7 Mon Sep 17 00:00:00 2001 From: Christopher Schuchardt Date: Wed, 10 Jan 2024 03:12:38 -0500 Subject: [PATCH 049/168] Fixed asp.net core project (#3067) * Fixed asp.net core project * delete * add asp.net core to Neo.GUI --- src/Neo.CLI/Neo.CLI.csproj | 4 ++++ src/Neo.GUI/Neo.GUI.csproj | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/src/Neo.CLI/Neo.CLI.csproj b/src/Neo.CLI/Neo.CLI.csproj index cd1b75fbc0..757a8ea64e 100644 --- a/src/Neo.CLI/Neo.CLI.csproj +++ b/src/Neo.CLI/Neo.CLI.csproj @@ -11,6 +11,10 @@ enable + + + + diff --git a/src/Neo.GUI/Neo.GUI.csproj b/src/Neo.GUI/Neo.GUI.csproj index 3921bb12b1..7b1a8bc981 100644 --- a/src/Neo.GUI/Neo.GUI.csproj +++ b/src/Neo.GUI/Neo.GUI.csproj @@ -12,6 +12,10 @@ neo.ico + + + + From b733a9dd85f08192f2d8295205cb3ecce3a2fa46 Mon Sep 17 00:00:00 2001 From: Shargon Date: Wed, 10 Jan 2024 03:39:18 -0800 Subject: [PATCH 050/168] Clean usings (#3078) --- src/Neo.ConsoleService/ConsoleServiceBase.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Neo.ConsoleService/ConsoleServiceBase.cs b/src/Neo.ConsoleService/ConsoleServiceBase.cs index 4702cf28ed..2ca62db2a2 100644 --- a/src/Neo.ConsoleService/ConsoleServiceBase.cs +++ b/src/Neo.ConsoleService/ConsoleServiceBase.cs @@ -17,9 +17,7 @@ using System.Net; using System.Reflection; using System.Runtime.Loader; -using System.Security; using System.ServiceProcess; -using System.Text; using System.Threading; using System.Threading.Tasks; From d98b0afff0465be966fd02bce7b207617062cc79 Mon Sep 17 00:00:00 2001 From: Shargon Date: Wed, 10 Jan 2024 05:50:23 -0800 Subject: [PATCH 051/168] Avoid IsExternalInit (#3079) * Avoid IsExternalInit * clean changes * clean if! --- src/Directory.Build.props | 4 ++++ src/{Neo.VM => }/IsExternalInit.cs | 0 2 files changed, 4 insertions(+) rename src/{Neo.VM => }/IsExternalInit.cs (100%) diff --git a/src/Directory.Build.props b/src/Directory.Build.props index ed3a744939..ff4bd977bf 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -22,4 +22,8 @@ + + + + diff --git a/src/Neo.VM/IsExternalInit.cs b/src/IsExternalInit.cs similarity index 100% rename from src/Neo.VM/IsExternalInit.cs rename to src/IsExternalInit.cs From cfffe4f8cb40d8f8789756e09dc24f502922534c Mon Sep 17 00:00:00 2001 From: Christopher Schuchardt Date: Wed, 10 Jan 2024 09:36:02 -0500 Subject: [PATCH 052/168] Convert to Neo.Json and Neo.ConsoleService to `dotnet` standard 2.1 (#3044) * fixes #3038 * removed websocket port from configs * Removed wsport from settings * Converted neo.json to dotnet standard 2.1 * fix tests * fix workflow * added false to tests * removed unused files * Fixed TryGetValue * converted Neo.ConsoleService to standard * fixed warning * fixes for dotnet * fixed warning * Fixed header * Fixed settings and added in shargons request * convert neto to standard * fixed getBit size * Fixed bitlen and Murmur128 * fixes * contractask update * Remove IsExternalInit * Unify LangVersion * Remove comments * Remove more comments * Revert main.yml * Revert neo changes * fix targetFramework * revert revert main.yml --------- Co-authored-by: Shargon --- .github/workflows/main.yml | 1 + src/Directory.Build.props | 2 +- src/Neo.CLI/Neo.CLI.csproj | 1 + src/Neo.CLI/Settings.cs | 42 +++++++++---------- src/Neo.ConsoleService/ConsoleServiceBase.cs | 4 +- .../Neo.ConsoleService.csproj | 1 + src/Neo.Json/JArray.cs | 2 +- src/Neo.Json/JBoolean.cs | 2 +- src/Neo.Json/JNumber.cs | 2 +- src/Neo.Json/JObject.cs | 2 +- src/Neo.Json/JString.cs | 4 +- src/Neo.Json/Neo.Json.csproj | 5 +++ src/Neo.Json/OrderedDictionary.cs | 4 ++ src/Neo.VM/Neo.VM.csproj | 1 - src/Neo/Neo.csproj | 1 + .../Neo.ConsoleService.Tests.csproj | 2 + .../Neo.Json.UnitTests.csproj | 2 + tests/Neo.Json.UnitTests/UT_JObject.cs | 2 +- tests/Neo.UnitTests/Neo.UnitTests.csproj | 2 + tests/Neo.VM.Tests/Neo.VM.Tests.csproj | 1 - 20 files changed, 51 insertions(+), 32 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 521cbc5611..781a2b8dce 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -36,6 +36,7 @@ jobs: uses: coverallsapp/github-action@master with: github-token: ${{ secrets.GITHUB_TOKEN }} + path-to-lcov: ./coverage/lcov.net7.0.info # MyGet isn't working # PublishMyGet: diff --git a/src/Directory.Build.props b/src/Directory.Build.props index ff4bd977bf..35a8fa289c 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -4,8 +4,8 @@ 2015-2023 The Neo Project 3.6.2 + 11.0 The Neo Project - net7.0 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 757a8ea64e..8c638d6c2a 100644 --- a/src/Neo.CLI/Neo.CLI.csproj +++ b/src/Neo.CLI/Neo.CLI.csproj @@ -1,6 +1,7 @@ + net7.0 Neo.CLI neo-cli Exe diff --git a/src/Neo.CLI/Settings.cs b/src/Neo.CLI/Settings.cs index ba884fa56f..7625db58f5 100644 --- a/src/Neo.CLI/Settings.cs +++ b/src/Neo.CLI/Settings.cs @@ -51,10 +51,10 @@ public static Settings Default public Settings(IConfigurationSection section) { - this.Logger = new(section.GetSection("Logger")); - this.Storage = new(section.GetSection("Storage")); - this.P2P = new(section.GetSection("P2P")); - this.UnlockWallet = new(section.GetSection("UnlockWallet")); + Logger = new(section.GetSection(nameof(Logger))); + Storage = new(section.GetSection(nameof(Storage))); + P2P = new(section.GetSection(nameof(P2P))); + UnlockWallet = new(section.GetSection(nameof(UnlockWallet))); } } @@ -66,21 +66,21 @@ public class LoggerSettings public LoggerSettings(IConfigurationSection section) { - this.Path = section.GetValue("Path", "Logs")!; - this.ConsoleOutput = section.GetValue("ConsoleOutput", false); - this.Active = section.GetValue("Active", false); + Path = section.GetValue(nameof(Path), "Logs")!; + ConsoleOutput = section.GetValue(nameof(ConsoleOutput), false); + Active = section.GetValue(nameof(Active), false); } } public class StorageSettings { - public string Engine { get; } - public string Path { get; } + public string Engine { get; } = string.Empty; + public string Path { get; } = string.Empty; public StorageSettings(IConfigurationSection section) { - this.Engine = section.GetValue("Engine", "LevelDBStore")!; - this.Path = section.GetValue("Path", "Data_LevelDB_{0}")!; + Engine = section.GetValue(nameof(Engine), "LevelDBStore")!; + Path = section.GetValue(nameof(Path), "Data_LevelDB_{0}")!; } } @@ -93,26 +93,26 @@ public class P2PSettings public P2PSettings(IConfigurationSection section) { - this.Port = section.GetValue("Port", 10333); - this.MinDesiredConnections = section.GetValue("MinDesiredConnections", Peer.DefaultMinDesiredConnections); - this.MaxConnections = section.GetValue("MaxConnections", Peer.DefaultMaxConnections); - this.MaxConnectionsPerAddress = section.GetValue("MaxConnectionsPerAddress", 3); + Port = section.GetValue(nameof(Port), 10333); + MinDesiredConnections = section.GetValue(nameof(MinDesiredConnections), Peer.DefaultMinDesiredConnections); + MaxConnections = section.GetValue(nameof(MaxConnections), Peer.DefaultMaxConnections); + MaxConnectionsPerAddress = section.GetValue(nameof(MaxConnectionsPerAddress), 3); } } public class UnlockWalletSettings { - public string? Path { get; } - public string? Password { get; } - public bool IsActive { get; } + public string Path { get; } = string.Empty; + public string Password { get; } = string.Empty; + public bool IsActive { get; } = false; public UnlockWalletSettings(IConfigurationSection section) { if (section.Exists()) { - this.Path = section.GetValue("Path", ""); - this.Password = section.GetValue("Password", ""); - this.IsActive = bool.Parse(section.GetValue("IsActive", "false")!); + Path = section.GetValue(nameof(Path), string.Empty)!; + Password = section.GetValue(nameof(Password), string.Empty)!; + IsActive = section.GetValue(nameof(IsActive), false); } } } diff --git a/src/Neo.ConsoleService/ConsoleServiceBase.cs b/src/Neo.ConsoleService/ConsoleServiceBase.cs index 2ca62db2a2..daa9d9f061 100644 --- a/src/Neo.ConsoleService/ConsoleServiceBase.cs +++ b/src/Neo.ConsoleService/ConsoleServiceBase.cs @@ -489,8 +489,10 @@ public void Run(string[] args) } else { - Debug.Assert(OperatingSystem.IsWindows()); + Debug.Assert(Environment.OSVersion.Platform == PlatformID.Win32NT); +#pragma warning disable CA1416 ServiceBase.Run(new ServiceProxy(this)); +#pragma warning restore CA1416 } } diff --git a/src/Neo.ConsoleService/Neo.ConsoleService.csproj b/src/Neo.ConsoleService/Neo.ConsoleService.csproj index 5c2fd653ad..1971a40790 100644 --- a/src/Neo.ConsoleService/Neo.ConsoleService.csproj +++ b/src/Neo.ConsoleService/Neo.ConsoleService.csproj @@ -1,6 +1,7 @@ + netstandard2.1;net7.0 Neo.ConsoleService enable diff --git a/src/Neo.Json/JArray.cs b/src/Neo.Json/JArray.cs index 30ac7c83a2..903f29941b 100644 --- a/src/Neo.Json/JArray.cs +++ b/src/Neo.Json/JArray.cs @@ -123,7 +123,7 @@ internal override void Write(Utf8JsonWriter writer) writer.WriteEndArray(); } - public override JArray Clone() + public override JToken Clone() { var cloned = new JArray(); diff --git a/src/Neo.Json/JBoolean.cs b/src/Neo.Json/JBoolean.cs index 0ca4901a86..05cb36a89d 100644 --- a/src/Neo.Json/JBoolean.cs +++ b/src/Neo.Json/JBoolean.cs @@ -63,7 +63,7 @@ internal override void Write(Utf8JsonWriter writer) writer.WriteBooleanValue(Value); } - public override JBoolean Clone() + public override JToken Clone() { return this; } diff --git a/src/Neo.Json/JNumber.cs b/src/Neo.Json/JNumber.cs index 6c73a01b37..479303cfb5 100644 --- a/src/Neo.Json/JNumber.cs +++ b/src/Neo.Json/JNumber.cs @@ -109,7 +109,7 @@ internal override void Write(Utf8JsonWriter writer) writer.WriteNumberValue(Value); } - public override JNumber Clone() + public override JToken Clone() { return this; } diff --git a/src/Neo.Json/JObject.cs b/src/Neo.Json/JObject.cs index adc6755b5e..c5666e9112 100644 --- a/src/Neo.Json/JObject.cs +++ b/src/Neo.Json/JObject.cs @@ -76,7 +76,7 @@ internal override void Write(Utf8JsonWriter writer) /// Creates a copy of the current JSON object. /// /// A copy of the current JSON object. - public override JObject Clone() + public override JToken Clone() { var cloned = new JObject(); diff --git a/src/Neo.Json/JString.cs b/src/Neo.Json/JString.cs index f6c5d155f3..c9466c26a6 100644 --- a/src/Neo.Json/JString.cs +++ b/src/Neo.Json/JString.cs @@ -70,7 +70,7 @@ public override T AsEnum(T defaultValue = default, bool ignoreCase = false) public override T GetEnum(bool ignoreCase = false) { T result = Enum.Parse(Value, ignoreCase); - if (!Enum.IsDefined(result)) throw new InvalidCastException(); + if (!Enum.IsDefined(typeof(T), result)) throw new InvalidCastException(); return result; } @@ -79,7 +79,7 @@ internal override void Write(Utf8JsonWriter writer) writer.WriteStringValue(Value); } - public override JString Clone() + public override JToken Clone() { return this; } diff --git a/src/Neo.Json/Neo.Json.csproj b/src/Neo.Json/Neo.Json.csproj index b814851216..0687960683 100644 --- a/src/Neo.Json/Neo.Json.csproj +++ b/src/Neo.Json/Neo.Json.csproj @@ -1,9 +1,14 @@ + netstandard2.1;net7.0 enable enable NEO;JSON + + + + diff --git a/src/Neo.Json/OrderedDictionary.cs b/src/Neo.Json/OrderedDictionary.cs index 244121f304..0913bda44e 100644 --- a/src/Neo.Json/OrderedDictionary.cs +++ b/src/Neo.Json/OrderedDictionary.cs @@ -90,6 +90,8 @@ public bool Remove(TKey key) return collection.Remove(key); } +#pragma warning disable CS8767 + public bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value) { if (collection.TryGetValue(key, out var entry)) @@ -101,6 +103,8 @@ public bool TryGetValue(TKey key, [MaybeNullWhen(false)] out TValue value) return false; } +#pragma warning restore CS8767 + void ICollection>.Add(KeyValuePair item) { Add(item.Key, item.Value); diff --git a/src/Neo.VM/Neo.VM.csproj b/src/Neo.VM/Neo.VM.csproj index add3762a3e..5e7e071b22 100644 --- a/src/Neo.VM/Neo.VM.csproj +++ b/src/Neo.VM/Neo.VM.csproj @@ -2,7 +2,6 @@ netstandard2.1;net7.0 - 9.0 true enable diff --git a/src/Neo/Neo.csproj b/src/Neo/Neo.csproj index f798cf1701..d15345dcbf 100644 --- a/src/Neo/Neo.csproj +++ b/src/Neo/Neo.csproj @@ -1,6 +1,7 @@ + net7.0 true NEO;AntShares;Blockchain;Smart Contract diff --git a/tests/Neo.ConsoleService.Tests/Neo.ConsoleService.Tests.csproj b/tests/Neo.ConsoleService.Tests/Neo.ConsoleService.Tests.csproj index b4b29127f6..3b3ae00b49 100644 --- a/tests/Neo.ConsoleService.Tests/Neo.ConsoleService.Tests.csproj +++ b/tests/Neo.ConsoleService.Tests/Neo.ConsoleService.Tests.csproj @@ -1,7 +1,9 @@ + net7.0 neo_cli.Tests + false diff --git a/tests/Neo.Json.UnitTests/Neo.Json.UnitTests.csproj b/tests/Neo.Json.UnitTests/Neo.Json.UnitTests.csproj index 893602f33c..eeb3177eb8 100644 --- a/tests/Neo.Json.UnitTests/Neo.Json.UnitTests.csproj +++ b/tests/Neo.Json.UnitTests/Neo.Json.UnitTests.csproj @@ -1,7 +1,9 @@ + net7.0 enable + false diff --git a/tests/Neo.Json.UnitTests/UT_JObject.cs b/tests/Neo.Json.UnitTests/UT_JObject.cs index a3d5bc01b4..e3660a7d3e 100644 --- a/tests/Neo.Json.UnitTests/UT_JObject.cs +++ b/tests/Neo.Json.UnitTests/UT_JObject.cs @@ -117,7 +117,7 @@ public void TestGetNull() [TestMethod] public void TestClone() { - var bobClone = bob.Clone(); + var bobClone = (JObject)bob.Clone(); bobClone.Should().NotBeSameAs(bob); foreach (var key in bobClone.Properties.Keys) { diff --git a/tests/Neo.UnitTests/Neo.UnitTests.csproj b/tests/Neo.UnitTests/Neo.UnitTests.csproj index 8c1216740b..e39fc1d6fb 100644 --- a/tests/Neo.UnitTests/Neo.UnitTests.csproj +++ b/tests/Neo.UnitTests/Neo.UnitTests.csproj @@ -1,7 +1,9 @@ + net7.0 true + false diff --git a/tests/Neo.VM.Tests/Neo.VM.Tests.csproj b/tests/Neo.VM.Tests/Neo.VM.Tests.csproj index b86f27296a..1020d1c55a 100644 --- a/tests/Neo.VM.Tests/Neo.VM.Tests.csproj +++ b/tests/Neo.VM.Tests/Neo.VM.Tests.csproj @@ -2,7 +2,6 @@ net7.0 - 9.0 Neo.Test true false From ff989a9c909ec7de57a0e86383f868ecd99e4630 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Thu, 11 Jan 2024 02:22:41 +0800 Subject: [PATCH 053/168] Add: add a new verify result status code (#3076) * add a new verify result status code * Use AlreadyInPool * More fixes * Rename * Rename * fix rename ... * Fix UT --------- Co-authored-by: Fernando Diaz Toledano --- src/Neo/ContainsTransactionType.cs | 20 ++++++++++++++ src/Neo/Ledger/Blockchain.cs | 27 ++++++++++++++----- src/Neo/Ledger/MemoryPool.cs | 2 +- src/Neo/Ledger/VerifyResult.cs | 5 ++++ src/Neo/NeoSystem.cs | 7 ++--- .../Network/P2P/RemoteNode.ProtocolHandler.cs | 2 +- tests/Neo.UnitTests/Ledger/UT_Blockchain.cs | 2 +- 7 files changed, 53 insertions(+), 12 deletions(-) create mode 100644 src/Neo/ContainsTransactionType.cs diff --git a/src/Neo/ContainsTransactionType.cs b/src/Neo/ContainsTransactionType.cs new file mode 100644 index 0000000000..cb91eb303f --- /dev/null +++ b/src/Neo/ContainsTransactionType.cs @@ -0,0 +1,20 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// ContainsTransactionType.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 +{ + public enum ContainsTransactionType + { + NotExist, + ExistsInPool, + ExistsInLedger + } +} diff --git a/src/Neo/Ledger/Blockchain.cs b/src/Neo/Ledger/Blockchain.cs index 1186a12474..ff9c8e29d8 100644 --- a/src/Neo/Ledger/Blockchain.cs +++ b/src/Neo/Ledger/Blockchain.cs @@ -339,7 +339,11 @@ private VerifyResult OnNewExtensiblePayload(ExtensiblePayload payload) private VerifyResult OnNewTransaction(Transaction transaction) { - if (system.ContainsTransaction(transaction.Hash)) return VerifyResult.AlreadyExists; + switch (system.ContainsTransaction(transaction.Hash)) + { + case ContainsTransactionType.ExistsInPool: return VerifyResult.AlreadyInPool; + case ContainsTransactionType.ExistsInLedger: return VerifyResult.AlreadyExists; + } if (system.ContainsConflictHash(transaction.Hash, transaction.Signers.Select(s => s.Account))) return VerifyResult.HasConflicts; return system.MemPool.TryAdd(transaction, system.StoreView); } @@ -393,11 +397,22 @@ protected override void OnReceive(object message) private void OnTransaction(Transaction tx) { - if (system.ContainsTransaction(tx.Hash)) - SendRelayResult(tx, VerifyResult.AlreadyExists); - else if (system.ContainsConflictHash(tx.Hash, tx.Signers.Select(s => s.Account))) - SendRelayResult(tx, VerifyResult.HasConflicts); - else system.TxRouter.Forward(new TransactionRouter.Preverify(tx, true)); + switch (system.ContainsTransaction(tx.Hash)) + { + case ContainsTransactionType.ExistsInPool: + SendRelayResult(tx, VerifyResult.AlreadyInPool); + break; + case ContainsTransactionType.ExistsInLedger: + SendRelayResult(tx, VerifyResult.AlreadyExists); + break; + default: + { + if (system.ContainsConflictHash(tx.Hash, tx.Signers.Select(s => s.Account))) + SendRelayResult(tx, VerifyResult.HasConflicts); + else system.TxRouter.Forward(new TransactionRouter.Preverify(tx, true)); + break; + } + } } private void Persist(Block block) diff --git a/src/Neo/Ledger/MemoryPool.cs b/src/Neo/Ledger/MemoryPool.cs index 8e4ec64b22..23eb711e87 100644 --- a/src/Neo/Ledger/MemoryPool.cs +++ b/src/Neo/Ledger/MemoryPool.cs @@ -293,7 +293,7 @@ internal VerifyResult TryAdd(Transaction tx, DataCache snapshot) { var poolItem = new PoolItem(tx); - if (_unsortedTransactions.ContainsKey(tx.Hash)) return VerifyResult.AlreadyExists; + if (_unsortedTransactions.ContainsKey(tx.Hash)) return VerifyResult.AlreadyInPool; List removedTransactions = null; _txRwLock.EnterWriteLock(); diff --git a/src/Neo/Ledger/VerifyResult.cs b/src/Neo/Ledger/VerifyResult.cs index b218288efa..7a242b4c60 100644 --- a/src/Neo/Ledger/VerifyResult.cs +++ b/src/Neo/Ledger/VerifyResult.cs @@ -28,6 +28,11 @@ public enum VerifyResult : byte /// AlreadyExists, + /// + /// Indicates that an with the same hash already exists in the memory pool. + /// + AlreadyInPool, + /// /// Indicates that the is full and the transaction cannot be verified. /// diff --git a/src/Neo/NeoSystem.cs b/src/Neo/NeoSystem.cs index 09c78e3e9c..3a148d612d 100644 --- a/src/Neo/NeoSystem.cs +++ b/src/Neo/NeoSystem.cs @@ -274,10 +274,11 @@ public SnapshotCache GetSnapshot() /// /// The hash of the transaction /// if the transaction exists; otherwise, . - public bool ContainsTransaction(UInt256 hash) + public ContainsTransactionType ContainsTransaction(UInt256 hash) { - if (MemPool.ContainsKey(hash)) return true; - return NativeContract.Ledger.ContainsTransaction(StoreView, hash); + if (MemPool.ContainsKey(hash)) return ContainsTransactionType.ExistsInPool; + return NativeContract.Ledger.ContainsTransaction(StoreView, hash) ? + ContainsTransactionType.ExistsInLedger : ContainsTransactionType.NotExist; } /// diff --git a/src/Neo/Network/P2P/RemoteNode.ProtocolHandler.cs b/src/Neo/Network/P2P/RemoteNode.ProtocolHandler.cs index afd37e2d17..4606723cd0 100644 --- a/src/Neo/Network/P2P/RemoteNode.ProtocolHandler.cs +++ b/src/Neo/Network/P2P/RemoteNode.ProtocolHandler.cs @@ -319,7 +319,7 @@ private void OnInventoryReceived(IInventory inventory) switch (inventory) { case Transaction transaction: - if (!(system.ContainsTransaction(transaction.Hash) || system.ContainsConflictHash(transaction.Hash, transaction.Signers.Select(s => s.Account)))) + if (!(system.ContainsTransaction(transaction.Hash) != ContainsTransactionType.NotExist || system.ContainsConflictHash(transaction.Hash, transaction.Signers.Select(s => s.Account)))) system.TxRouter.Tell(new TransactionRouter.Preverify(transaction, true)); break; case Block block: diff --git a/tests/Neo.UnitTests/Ledger/UT_Blockchain.cs b/tests/Neo.UnitTests/Ledger/UT_Blockchain.cs index 6102b88938..c6e818cdf7 100644 --- a/tests/Neo.UnitTests/Ledger/UT_Blockchain.cs +++ b/tests/Neo.UnitTests/Ledger/UT_Blockchain.cs @@ -70,7 +70,7 @@ public void TestValidTransaction() senderProbe.ExpectMsg(p => p.Result == VerifyResult.Succeed); senderProbe.Send(system.Blockchain, tx); - senderProbe.ExpectMsg(p => p.Result == VerifyResult.AlreadyExists); + senderProbe.ExpectMsg(p => p.Result == VerifyResult.AlreadyInPool); } internal static StorageKey CreateStorageKey(byte prefix, byte[] key = null) From 49ced83be9366f85ce1de9a0c57b4bd4bcaeb8f1 Mon Sep 17 00:00:00 2001 From: Shargon Date: Thu, 11 Jan 2024 08:53:11 +0300 Subject: [PATCH 054/168] Move to monorepo: Neo.Cryptography.BLS12_381 (#3077) * Move BLS * Pack Neo.Cryptography.BLS12_381 * Add file headers --------- Co-authored-by: Jimmy --- .github/workflows/main.yml | 6 + neo.sln | 14 + src/Neo.Cryptography.BLS12_381/Bls12.Adder.cs | 71 ++ src/Neo.Cryptography.BLS12_381/Bls12.cs | 31 + .../ConstantTimeUtility.cs | 42 + src/Neo.Cryptography.BLS12_381/Constants.cs | 18 + src/Neo.Cryptography.BLS12_381/Fp.cs | 491 +++++++++++ src/Neo.Cryptography.BLS12_381/Fp12.cs | 218 +++++ src/Neo.Cryptography.BLS12_381/Fp2.cs | 274 ++++++ src/Neo.Cryptography.BLS12_381/Fp6.cs | 308 +++++++ src/Neo.Cryptography.BLS12_381/FpConstants.cs | 84 ++ src/Neo.Cryptography.BLS12_381/G1Affine.cs | 181 ++++ src/Neo.Cryptography.BLS12_381/G1Constants.cs | 55 ++ .../G1Projective.cs | 294 +++++++ src/Neo.Cryptography.BLS12_381/G2Affine.cs | 225 +++++ src/Neo.Cryptography.BLS12_381/G2Constants.cs | 112 +++ .../G2Prepared.Adder.cs | 74 ++ src/Neo.Cryptography.BLS12_381/G2Prepared.cs | 31 + .../G2Projective.cs | 377 ++++++++ .../GlobalSuppressions.cs | 14 + src/Neo.Cryptography.BLS12_381/Gt.cs | 135 +++ src/Neo.Cryptography.BLS12_381/GtConstants.cs | 115 +++ .../IMillerLoopDriver.cs | 21 + src/Neo.Cryptography.BLS12_381/INumber.cs | 70 ++ src/Neo.Cryptography.BLS12_381/MathUtility.cs | 67 ++ .../MillerLoopResult.cs | 143 +++ .../MillerLoopUtility.cs | 120 +++ .../Neo.Cryptography.BLS12_381.csproj | 15 + .../Properties/AssemblyInfo.cs | 14 + src/Neo.Cryptography.BLS12_381/Scalar.cs | 513 +++++++++++ .../ScalarConstants.cs | 96 ++ src/Neo/Neo.csproj | 2 +- .../Neo.Cryptography.BLS12_381.Tests.csproj | 24 + .../Neo.Cryptography.BLS12_381.Tests/UT_Fp.cs | 353 ++++++++ .../UT_Fp12.cs | 347 ++++++++ .../UT_Fp2.cs | 493 +++++++++++ .../UT_Fp6.cs | 179 ++++ .../Neo.Cryptography.BLS12_381.Tests/UT_G1.cs | 603 +++++++++++++ .../Neo.Cryptography.BLS12_381.Tests/UT_G2.cs | 823 ++++++++++++++++++ .../UT_Pairings.cs | 69 ++ .../UT_Scalar.cs | 411 +++++++++ .../Usings.cs | 12 + 42 files changed, 7544 insertions(+), 1 deletion(-) create mode 100644 src/Neo.Cryptography.BLS12_381/Bls12.Adder.cs create mode 100644 src/Neo.Cryptography.BLS12_381/Bls12.cs create mode 100644 src/Neo.Cryptography.BLS12_381/ConstantTimeUtility.cs create mode 100644 src/Neo.Cryptography.BLS12_381/Constants.cs create mode 100644 src/Neo.Cryptography.BLS12_381/Fp.cs create mode 100644 src/Neo.Cryptography.BLS12_381/Fp12.cs create mode 100644 src/Neo.Cryptography.BLS12_381/Fp2.cs create mode 100644 src/Neo.Cryptography.BLS12_381/Fp6.cs create mode 100644 src/Neo.Cryptography.BLS12_381/FpConstants.cs create mode 100644 src/Neo.Cryptography.BLS12_381/G1Affine.cs create mode 100644 src/Neo.Cryptography.BLS12_381/G1Constants.cs create mode 100644 src/Neo.Cryptography.BLS12_381/G1Projective.cs create mode 100644 src/Neo.Cryptography.BLS12_381/G2Affine.cs create mode 100644 src/Neo.Cryptography.BLS12_381/G2Constants.cs create mode 100644 src/Neo.Cryptography.BLS12_381/G2Prepared.Adder.cs create mode 100644 src/Neo.Cryptography.BLS12_381/G2Prepared.cs create mode 100644 src/Neo.Cryptography.BLS12_381/G2Projective.cs create mode 100644 src/Neo.Cryptography.BLS12_381/GlobalSuppressions.cs create mode 100644 src/Neo.Cryptography.BLS12_381/Gt.cs create mode 100644 src/Neo.Cryptography.BLS12_381/GtConstants.cs create mode 100644 src/Neo.Cryptography.BLS12_381/IMillerLoopDriver.cs create mode 100644 src/Neo.Cryptography.BLS12_381/INumber.cs create mode 100644 src/Neo.Cryptography.BLS12_381/MathUtility.cs create mode 100644 src/Neo.Cryptography.BLS12_381/MillerLoopResult.cs create mode 100644 src/Neo.Cryptography.BLS12_381/MillerLoopUtility.cs create mode 100644 src/Neo.Cryptography.BLS12_381/Neo.Cryptography.BLS12_381.csproj create mode 100644 src/Neo.Cryptography.BLS12_381/Properties/AssemblyInfo.cs create mode 100644 src/Neo.Cryptography.BLS12_381/Scalar.cs create mode 100644 src/Neo.Cryptography.BLS12_381/ScalarConstants.cs create mode 100644 tests/Neo.Cryptography.BLS12_381.Tests/Neo.Cryptography.BLS12_381.Tests.csproj create mode 100644 tests/Neo.Cryptography.BLS12_381.Tests/UT_Fp.cs create mode 100644 tests/Neo.Cryptography.BLS12_381.Tests/UT_Fp12.cs create mode 100644 tests/Neo.Cryptography.BLS12_381.Tests/UT_Fp2.cs create mode 100644 tests/Neo.Cryptography.BLS12_381.Tests/UT_Fp6.cs create mode 100644 tests/Neo.Cryptography.BLS12_381.Tests/UT_G1.cs create mode 100644 tests/Neo.Cryptography.BLS12_381.Tests/UT_G2.cs create mode 100644 tests/Neo.Cryptography.BLS12_381.Tests/UT_Pairings.cs create mode 100644 tests/Neo.Cryptography.BLS12_381.Tests/UT_Scalar.cs create mode 100644 tests/Neo.Cryptography.BLS12_381.Tests/Usings.cs diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 781a2b8dce..bce1dc7c79 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -131,6 +131,12 @@ jobs: 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/neo.sln b/neo.sln index 2168c241b3..dc50d0f4d7 100644 --- a/neo.sln +++ b/neo.sln @@ -32,6 +32,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Neo.CLI", "src\Neo.CLI\Neo. EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Neo.ConsoleService.Tests", "tests\Neo.ConsoleService.Tests\Neo.ConsoleService.Tests.csproj", "{B40F8584-5AFB-452C-AEFA-009C80CC23A9}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.Cryptography.BLS12_381", "src\Neo.Cryptography.BLS12_381\Neo.Cryptography.BLS12_381.csproj", "{D48C1FAB-3471-4CA0-8688-25E6F43F2C25}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.Cryptography.BLS12_381.Tests", "tests\Neo.Cryptography.BLS12_381.Tests\Neo.Cryptography.BLS12_381.Tests.csproj", "{387CCF6C-9A26-43F6-A639-0A82E91E10D8}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -86,6 +90,14 @@ Global {B40F8584-5AFB-452C-AEFA-009C80CC23A9}.Debug|Any CPU.Build.0 = Debug|Any CPU {B40F8584-5AFB-452C-AEFA-009C80CC23A9}.Release|Any CPU.ActiveCfg = Release|Any CPU {B40F8584-5AFB-452C-AEFA-009C80CC23A9}.Release|Any CPU.Build.0 = Release|Any CPU + {D48C1FAB-3471-4CA0-8688-25E6F43F2C25}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D48C1FAB-3471-4CA0-8688-25E6F43F2C25}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D48C1FAB-3471-4CA0-8688-25E6F43F2C25}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D48C1FAB-3471-4CA0-8688-25E6F43F2C25}.Release|Any CPU.Build.0 = Release|Any CPU + {387CCF6C-9A26-43F6-A639-0A82E91E10D8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {387CCF6C-9A26-43F6-A639-0A82E91E10D8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {387CCF6C-9A26-43F6-A639-0A82E91E10D8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {387CCF6C-9A26-43F6-A639-0A82E91E10D8}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -103,6 +115,8 @@ Global {02ABDE42-9880-43B4-B6F7-8D618602A277} = {B5339DF7-5D1D-43BA-B332-74B825E1770E} {BDFBE455-4C1F-4FC4-B5FC-1387B93A8687} = {B5339DF7-5D1D-43BA-B332-74B825E1770E} {B40F8584-5AFB-452C-AEFA-009C80CC23A9} = {EDE05FA8-8E73-4924-BC63-DD117127EEE1} + {D48C1FAB-3471-4CA0-8688-25E6F43F2C25} = {B5339DF7-5D1D-43BA-B332-74B825E1770E} + {387CCF6C-9A26-43F6-A639-0A82E91E10D8} = {EDE05FA8-8E73-4924-BC63-DD117127EEE1} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {BCBA19D9-F868-4C6D-8061-A2B91E06E3EC} diff --git a/src/Neo.Cryptography.BLS12_381/Bls12.Adder.cs b/src/Neo.Cryptography.BLS12_381/Bls12.Adder.cs new file mode 100644 index 0000000000..3981f19a1b --- /dev/null +++ b/src/Neo.Cryptography.BLS12_381/Bls12.Adder.cs @@ -0,0 +1,71 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Bls12.Adder.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.Runtime.CompilerServices; +using static Neo.Cryptography.BLS12_381.MillerLoopUtility; + +namespace Neo.Cryptography.BLS12_381; + +partial class Bls12 +{ + class Adder : IMillerLoopDriver + { + public G2Projective Curve; + public readonly G2Affine Base; + public readonly G1Affine P; + + public Adder(in G1Affine p, in G2Affine q) + { + Curve = new(q); + Base = q; + P = p; + } + + Fp12 IMillerLoopDriver.DoublingStep(in Fp12 f) + { + var coeffs = DoublingStep(ref Curve); + return Ell(in f, in coeffs, in P); + } + + Fp12 IMillerLoopDriver.AdditionStep(in Fp12 f) + { + var coeffs = AdditionStep(ref Curve, in Base); + return Ell(in f, in coeffs, in P); + } + + #region IMillerLoopDriver + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Fp12 Square(in Fp12 f) => f.Square(); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Fp12 Conjugate(in Fp12 f) => f.Conjugate(); + + public static Fp12 One + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => Fp12.One; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + Fp12 IMillerLoopDriver.Square(in Fp12 f) => Adder.Square(f); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + Fp12 IMillerLoopDriver.Conjugate(in Fp12 f) => Adder.Conjugate(f); + Fp12 IMillerLoopDriver.One + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => Adder.One; + } + + #endregion + } +} diff --git a/src/Neo.Cryptography.BLS12_381/Bls12.cs b/src/Neo.Cryptography.BLS12_381/Bls12.cs new file mode 100644 index 0000000000..10022ded4d --- /dev/null +++ b/src/Neo.Cryptography.BLS12_381/Bls12.cs @@ -0,0 +1,31 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Bls12.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 static Neo.Cryptography.BLS12_381.ConstantTimeUtility; +using static Neo.Cryptography.BLS12_381.MillerLoopUtility; + +namespace Neo.Cryptography.BLS12_381; + +public static partial class Bls12 +{ + public static Gt Pairing(in G1Affine p, in G2Affine q) + { + var either_identity = p.IsIdentity | q.IsIdentity; + var p2 = ConditionalSelect(in p, in G1Affine.Generator, either_identity); + var q2 = ConditionalSelect(in q, in G2Affine.Generator, either_identity); + + var adder = new Adder(p2, q2); + + var tmp = MillerLoop(adder); + var tmp2 = new MillerLoopResult(ConditionalSelect(in tmp, in Fp12.One, either_identity)); + return tmp2.FinalExponentiation(); + } +} diff --git a/src/Neo.Cryptography.BLS12_381/ConstantTimeUtility.cs b/src/Neo.Cryptography.BLS12_381/ConstantTimeUtility.cs new file mode 100644 index 0000000000..70517edeb1 --- /dev/null +++ b/src/Neo.Cryptography.BLS12_381/ConstantTimeUtility.cs @@ -0,0 +1,42 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// ConstantTimeUtility.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.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace Neo.Cryptography.BLS12_381; + +public static class ConstantTimeUtility +{ + public static bool ConstantTimeEq(in T a, in T b) where T : unmanaged + { + ReadOnlySpan a_bytes = MemoryMarshal.AsBytes(MemoryMarshal.CreateReadOnlySpan(ref Unsafe.AsRef(in a), 1)); + ReadOnlySpan b_bytes = MemoryMarshal.AsBytes(MemoryMarshal.CreateReadOnlySpan(ref Unsafe.AsRef(in b), 1)); + ReadOnlySpan a_u64 = MemoryMarshal.Cast(a_bytes); + ReadOnlySpan b_u64 = MemoryMarshal.Cast(b_bytes); + ulong f = 0; + for (int i = 0; i < a_u64.Length; i++) + f |= a_u64[i] ^ b_u64[i]; + for (int i = a_u64.Length * sizeof(ulong); i < a_bytes.Length; i++) + f |= (ulong)a_bytes[i] ^ a_bytes[i]; + return f == 0; + } + + public static T ConditionalSelect(in T a, in T b, bool choice) where T : unmanaged + { + return choice ? b : a; + } + + public static void ConditionalAssign(this ref T self, in T other, bool choice) where T : unmanaged + { + self = ConditionalSelect(in self, in other, choice); + } +} diff --git a/src/Neo.Cryptography.BLS12_381/Constants.cs b/src/Neo.Cryptography.BLS12_381/Constants.cs new file mode 100644 index 0000000000..457b4d720b --- /dev/null +++ b/src/Neo.Cryptography.BLS12_381/Constants.cs @@ -0,0 +1,18 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Constants.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.Cryptography.BLS12_381; + +static class Constants +{ + public const ulong BLS_X = 0xd201_0000_0001_0000; + public const bool BLS_X_IS_NEGATIVE = true; +} diff --git a/src/Neo.Cryptography.BLS12_381/Fp.cs b/src/Neo.Cryptography.BLS12_381/Fp.cs new file mode 100644 index 0000000000..4b30b4fa5c --- /dev/null +++ b/src/Neo.Cryptography.BLS12_381/Fp.cs @@ -0,0 +1,491 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Fp.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.Buffers.Binary; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Security.Cryptography; +using static Neo.Cryptography.BLS12_381.ConstantTimeUtility; +using static Neo.Cryptography.BLS12_381.FpConstants; +using static Neo.Cryptography.BLS12_381.MathUtility; + +namespace Neo.Cryptography.BLS12_381; + +[StructLayout(LayoutKind.Explicit, Size = Size)] +public readonly struct Fp : IEquatable, INumber +{ + public const int Size = 48; + public const int SizeL = Size / sizeof(ulong); + + private static readonly Fp _zero = new(); + + public static ref readonly Fp Zero => ref _zero; + public static ref readonly Fp One => ref R; + + public bool IsZero => this == Zero; + + public static Fp FromBytes(ReadOnlySpan data) + { + if (data.Length != Size) + throw new FormatException($"The argument `{nameof(data)}` must contain {Size} bytes."); + + Span tmp = stackalloc ulong[SizeL]; + BinaryPrimitives.TryReadUInt64BigEndian(data[0..8], out tmp[5]); + BinaryPrimitives.TryReadUInt64BigEndian(data[8..16], out tmp[4]); + BinaryPrimitives.TryReadUInt64BigEndian(data[16..24], out tmp[3]); + BinaryPrimitives.TryReadUInt64BigEndian(data[24..32], out tmp[2]); + BinaryPrimitives.TryReadUInt64BigEndian(data[32..40], out tmp[1]); + BinaryPrimitives.TryReadUInt64BigEndian(data[40..48], out tmp[0]); + ReadOnlySpan span = MemoryMarshal.Cast(tmp); + + try + { + return span[0] * R2; + } + finally + { + ulong borrow; + (_, borrow) = Sbb(tmp[0], MODULUS[0], 0); + (_, borrow) = Sbb(tmp[1], MODULUS[1], borrow); + (_, borrow) = Sbb(tmp[2], MODULUS[2], borrow); + (_, borrow) = Sbb(tmp[3], MODULUS[3], borrow); + (_, borrow) = Sbb(tmp[4], MODULUS[4], borrow); + (_, borrow) = Sbb(tmp[5], MODULUS[5], borrow); + if (borrow == 0) + { + // If the element is smaller than MODULUS then the subtraction will underflow. + // Otherwise, throws. + // Why not throw before return? + // Because we want to run the method in a constant time. + throw new FormatException(); + } + } + } + + internal static Fp FromRawUnchecked(ulong[] values) + { + if (values.Length != SizeL) + throw new FormatException($"The argument `{nameof(values)}` must contain {SizeL} entries."); + + return MemoryMarshal.Cast(values)[0]; + } + + public static Fp Random(RandomNumberGenerator rng) + { + Span buffer = stackalloc byte[Size * 2]; + rng.GetBytes(buffer); + Span d = MemoryMarshal.Cast(buffer); + return d[0] * R2 + d[1] * R3; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private ReadOnlySpan GetSpan() + { + return MemoryMarshal.AsBytes(MemoryMarshal.CreateReadOnlySpan(ref Unsafe.AsRef(in this), 1)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private Span GetSpanU64() + { + return MemoryMarshal.Cast(MemoryMarshal.CreateSpan(ref Unsafe.AsRef(in this), 1)); + } + + public static bool operator ==(in Fp left, in Fp right) + { + return ConstantTimeEq(in left, in right); + } + + public static bool operator !=(in Fp left, in Fp right) + { + return !(left == right); + } + + public override bool Equals([NotNullWhen(true)] object? obj) + { + if (obj is not Fp other) return false; + return this == other; + } + + public bool Equals(Fp other) + { + return this == other; + } + + public override int GetHashCode() + { + return base.GetHashCode(); + } + + public byte[] ToArray() + { + byte[] result = new byte[Size]; + TryWrite(result); + return result; + } + + public bool TryWrite(Span buffer) + { + if (buffer.Length < Size) return false; + + ReadOnlySpan u64 = GetSpanU64(); + Fp tmp = MontgomeryReduce(u64[0], u64[1], u64[2], u64[3], u64[4], u64[5], 0, 0, 0, 0, 0, 0); + u64 = tmp.GetSpanU64(); + + BinaryPrimitives.WriteUInt64BigEndian(buffer[0..8], u64[5]); + BinaryPrimitives.WriteUInt64BigEndian(buffer[8..16], u64[4]); + BinaryPrimitives.WriteUInt64BigEndian(buffer[16..24], u64[3]); + BinaryPrimitives.WriteUInt64BigEndian(buffer[24..32], u64[2]); + BinaryPrimitives.WriteUInt64BigEndian(buffer[32..40], u64[1]); + BinaryPrimitives.WriteUInt64BigEndian(buffer[40..48], u64[0]); + + return true; + } + + public override string ToString() + { + var output = string.Empty; + foreach (var b in ToArray()) + output += b.ToString("x2"); + + return "0x" + output; + } + + public bool LexicographicallyLargest() + { + ReadOnlySpan s = GetSpanU64(); + Fp tmp = MontgomeryReduce(s[0], s[1], s[2], s[3], s[4], s[5], 0, 0, 0, 0, 0, 0); + ReadOnlySpan t = tmp.GetSpanU64(); + ulong borrow; + + (_, borrow) = Sbb(t[0], 0xdcff_7fff_ffff_d556, 0); + (_, borrow) = Sbb(t[1], 0x0f55_ffff_58a9_ffff, borrow); + (_, borrow) = Sbb(t[2], 0xb398_6950_7b58_7b12, borrow); + (_, borrow) = Sbb(t[3], 0xb23b_a5c2_79c2_895f, borrow); + (_, borrow) = Sbb(t[4], 0x258d_d3db_21a5_d66b, borrow); + (_, borrow) = Sbb(t[5], 0x0d00_88f5_1cbf_f34d, borrow); + + return borrow == 0; + } + + public Fp Sqrt() + { + // We use Shank's method, as p = 3 (mod 4). This means + // we only need to exponentiate by (p + 1) / 4. This only + // works for elements that are actually quadratic residue, + // so we check that we got the correct result at the end. + Fp result = this.PowVartime(P_1_4); + if (result.Square() != this) throw new ArithmeticException(); + return result; + } + + public Fp Invert() + { + if (!TryInvert(out Fp result)) + throw new DivideByZeroException(); + return result; + } + + public bool TryInvert(out Fp result) + { + // Exponentiate by p - 2 + result = this.PowVartime(P_2); + + // Why not return before Pow() if IsZero? + // Because we want to run the method in a constant time. + return !IsZero; + } + + private Fp SubtractP() + { + Fp result; + ReadOnlySpan s = GetSpanU64(); + Span r = result.GetSpanU64(); + ulong borrow; + + (r[0], borrow) = Sbb(s[0], MODULUS[0], 0); + (r[1], borrow) = Sbb(s[1], MODULUS[1], borrow); + (r[2], borrow) = Sbb(s[2], MODULUS[2], borrow); + (r[3], borrow) = Sbb(s[3], MODULUS[3], borrow); + (r[4], borrow) = Sbb(s[4], MODULUS[4], borrow); + (r[5], borrow) = Sbb(s[5], MODULUS[5], borrow); + + borrow = borrow == 0 ? ulong.MinValue : ulong.MaxValue; + r[0] = (s[0] & borrow) | (r[0] & ~borrow); + r[1] = (s[1] & borrow) | (r[1] & ~borrow); + r[2] = (s[2] & borrow) | (r[2] & ~borrow); + r[3] = (s[3] & borrow) | (r[3] & ~borrow); + r[4] = (s[4] & borrow) | (r[4] & ~borrow); + r[5] = (s[5] & borrow) | (r[5] & ~borrow); + + return result; + } + + public static Fp operator +(in Fp a, in Fp b) + { + Fp result; + ReadOnlySpan s = a.GetSpanU64(), r = b.GetSpanU64(); + Span d = result.GetSpanU64(); + + ulong carry = 0; + (d[0], carry) = Adc(s[0], r[0], carry); + (d[1], carry) = Adc(s[1], r[1], carry); + (d[2], carry) = Adc(s[2], r[2], carry); + (d[3], carry) = Adc(s[3], r[3], carry); + (d[4], carry) = Adc(s[4], r[4], carry); + (d[5], _) = Adc(s[5], r[5], carry); + + return result.SubtractP(); + } + + public static Fp operator -(in Fp a) + { + Fp result; + ReadOnlySpan self = a.GetSpanU64(); + Span d = result.GetSpanU64(); + + ulong borrow = 0; + (d[0], borrow) = Sbb(MODULUS[0], self[0], borrow); + (d[1], borrow) = Sbb(MODULUS[1], self[1], borrow); + (d[2], borrow) = Sbb(MODULUS[2], self[2], borrow); + (d[3], borrow) = Sbb(MODULUS[3], self[3], borrow); + (d[4], borrow) = Sbb(MODULUS[4], self[4], borrow); + (d[5], _) = Sbb(MODULUS[5], self[5], borrow); + + ulong mask = a.IsZero ? ulong.MinValue : ulong.MaxValue; + d[0] &= mask; + d[1] &= mask; + d[2] &= mask; + d[3] &= mask; + d[4] &= mask; + d[5] &= mask; + + return result; + } + + public static Fp operator -(in Fp a, in Fp b) + { + return -b + a; + } + + public static Fp SumOfProducts(ReadOnlySpan a, ReadOnlySpan b) + { + int length = a.Length; + if (length != b.Length) + throw new ArgumentException("The lengths of the two arrays must be the same."); + + Fp result; + ReadOnlySpan au = MemoryMarshal.Cast(a); + ReadOnlySpan bu = MemoryMarshal.Cast(b); + Span u = result.GetSpanU64(); + + for (int j = 0; j < 6; j++) + { + ulong carry; + + var (t0, t1, t2, t3, t4, t5, t6) = (u[0], u[1], u[2], u[3], u[4], u[5], 0ul); + for (int i = 0; i < length; i++) + { + (t0, carry) = Mac(t0, au[i * SizeL + j], bu[i * SizeL + 0], 0); + (t1, carry) = Mac(t1, au[i * SizeL + j], bu[i * SizeL + 1], carry); + (t2, carry) = Mac(t2, au[i * SizeL + j], bu[i * SizeL + 2], carry); + (t3, carry) = Mac(t3, au[i * SizeL + j], bu[i * SizeL + 3], carry); + (t4, carry) = Mac(t4, au[i * SizeL + j], bu[i * SizeL + 4], carry); + (t5, carry) = Mac(t5, au[i * SizeL + j], bu[i * SizeL + 5], carry); + (t6, _) = Adc(t6, 0, carry); + } + + ulong k = unchecked(t0 * INV); + (_, carry) = Mac(t0, k, MODULUS[0], 0); + (u[0], carry) = Mac(t1, k, MODULUS[1], carry); + (u[1], carry) = Mac(t2, k, MODULUS[2], carry); + (u[2], carry) = Mac(t3, k, MODULUS[3], carry); + (u[3], carry) = Mac(t4, k, MODULUS[4], carry); + (u[4], carry) = Mac(t5, k, MODULUS[5], carry); + (u[5], _) = Adc(t6, 0, carry); + } + + return result.SubtractP(); + } + + private static Fp MontgomeryReduce(ulong r0, ulong r1, ulong r2, ulong r3, ulong r4, ulong r5, ulong r6, ulong r7, ulong r8, ulong r9, ulong r10, ulong r11) + { + ulong carry, carry2; + + ulong k = unchecked(r0 * INV); + (_, carry) = Mac(r0, k, MODULUS[0], 0); + (r1, carry) = Mac(r1, k, MODULUS[1], carry); + (r2, carry) = Mac(r2, k, MODULUS[2], carry); + (r3, carry) = Mac(r3, k, MODULUS[3], carry); + (r4, carry) = Mac(r4, k, MODULUS[4], carry); + (r5, carry) = Mac(r5, k, MODULUS[5], carry); + (r6, carry2) = Adc(r6, 0, carry); + + k = unchecked(r1 * INV); + (_, carry) = Mac(r1, k, MODULUS[0], 0); + (r2, carry) = Mac(r2, k, MODULUS[1], carry); + (r3, carry) = Mac(r3, k, MODULUS[2], carry); + (r4, carry) = Mac(r4, k, MODULUS[3], carry); + (r5, carry) = Mac(r5, k, MODULUS[4], carry); + (r6, carry) = Mac(r6, k, MODULUS[5], carry); + (r7, carry2) = Adc(r7, carry2, carry); + + k = unchecked(r2 * INV); + (_, carry) = Mac(r2, k, MODULUS[0], 0); + (r3, carry) = Mac(r3, k, MODULUS[1], carry); + (r4, carry) = Mac(r4, k, MODULUS[2], carry); + (r5, carry) = Mac(r5, k, MODULUS[3], carry); + (r6, carry) = Mac(r6, k, MODULUS[4], carry); + (r7, carry) = Mac(r7, k, MODULUS[5], carry); + (r8, carry2) = Adc(r8, carry2, carry); + + k = unchecked(r3 * INV); + (_, carry) = Mac(r3, k, MODULUS[0], 0); + (r4, carry) = Mac(r4, k, MODULUS[1], carry); + (r5, carry) = Mac(r5, k, MODULUS[2], carry); + (r6, carry) = Mac(r6, k, MODULUS[3], carry); + (r7, carry) = Mac(r7, k, MODULUS[4], carry); + (r8, carry) = Mac(r8, k, MODULUS[5], carry); + (r9, carry2) = Adc(r9, carry2, carry); + + k = unchecked(r4 * INV); + (_, carry) = Mac(r4, k, MODULUS[0], 0); + (r5, carry) = Mac(r5, k, MODULUS[1], carry); + (r6, carry) = Mac(r6, k, MODULUS[2], carry); + (r7, carry) = Mac(r7, k, MODULUS[3], carry); + (r8, carry) = Mac(r8, k, MODULUS[4], carry); + (r9, carry) = Mac(r9, k, MODULUS[5], carry); + (r10, carry2) = Adc(r10, carry2, carry); + + k = unchecked(r5 * INV); + (_, carry) = Mac(r5, k, MODULUS[0], 0); + (r6, carry) = Mac(r6, k, MODULUS[1], carry); + (r7, carry) = Mac(r7, k, MODULUS[2], carry); + (r8, carry) = Mac(r8, k, MODULUS[3], carry); + (r9, carry) = Mac(r9, k, MODULUS[4], carry); + (r10, carry) = Mac(r10, k, MODULUS[5], carry); + (r11, _) = Adc(r11, carry2, carry); + + ReadOnlySpan tmp = stackalloc[] { r6, r7, r8, r9, r10, r11 }; + return MemoryMarshal.Cast(tmp)[0].SubtractP(); + } + + public static Fp operator *(in Fp a, in Fp b) + { + ReadOnlySpan s = a.GetSpanU64(), r = b.GetSpanU64(); + Span t = stackalloc ulong[SizeL * 2]; + ulong carry; + + (t[0], carry) = Mac(0, s[0], r[0], 0); + (t[1], carry) = Mac(0, s[0], r[1], carry); + (t[2], carry) = Mac(0, s[0], r[2], carry); + (t[3], carry) = Mac(0, s[0], r[3], carry); + (t[4], carry) = Mac(0, s[0], r[4], carry); + (t[5], t[6]) = Mac(0, s[0], r[5], carry); + + (t[1], carry) = Mac(t[1], s[1], r[0], 0); + (t[2], carry) = Mac(t[2], s[1], r[1], carry); + (t[3], carry) = Mac(t[3], s[1], r[2], carry); + (t[4], carry) = Mac(t[4], s[1], r[3], carry); + (t[5], carry) = Mac(t[5], s[1], r[4], carry); + (t[6], t[7]) = Mac(t[6], s[1], r[5], carry); + + (t[2], carry) = Mac(t[2], s[2], r[0], 0); + (t[3], carry) = Mac(t[3], s[2], r[1], carry); + (t[4], carry) = Mac(t[4], s[2], r[2], carry); + (t[5], carry) = Mac(t[5], s[2], r[3], carry); + (t[6], carry) = Mac(t[6], s[2], r[4], carry); + (t[7], t[8]) = Mac(t[7], s[2], r[5], carry); + (t[3], carry) = Mac(t[3], s[3], r[0], 0); + (t[4], carry) = Mac(t[4], s[3], r[1], carry); + (t[5], carry) = Mac(t[5], s[3], r[2], carry); + (t[6], carry) = Mac(t[6], s[3], r[3], carry); + (t[7], carry) = Mac(t[7], s[3], r[4], carry); + (t[8], t[9]) = Mac(t[8], s[3], r[5], carry); + (t[4], carry) = Mac(t[4], s[4], r[0], 0); + (t[5], carry) = Mac(t[5], s[4], r[1], carry); + (t[6], carry) = Mac(t[6], s[4], r[2], carry); + (t[7], carry) = Mac(t[7], s[4], r[3], carry); + (t[8], carry) = Mac(t[8], s[4], r[4], carry); + (t[9], t[10]) = Mac(t[9], s[4], r[5], carry); + (t[5], carry) = Mac(t[5], s[5], r[0], 0); + (t[6], carry) = Mac(t[6], s[5], r[1], carry); + (t[7], carry) = Mac(t[7], s[5], r[2], carry); + (t[8], carry) = Mac(t[8], s[5], r[3], carry); + (t[9], carry) = Mac(t[9], s[5], r[4], carry); + (t[10], t[11]) = Mac(t[10], s[5], r[5], carry); + + return MontgomeryReduce(t[0], t[1], t[2], t[3], t[4], t[5], t[6], t[7], t[8], t[9], t[10], t[11]); + } + + public Fp Square() + { + ReadOnlySpan self = GetSpanU64(); + ulong t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11; + ulong carry; + + (t1, carry) = Mac(0, self[0], self[1], 0); + (t2, carry) = Mac(0, self[0], self[2], carry); + (t3, carry) = Mac(0, self[0], self[3], carry); + (t4, carry) = Mac(0, self[0], self[4], carry); + (t5, t6) = Mac(0, self[0], self[5], carry); + + (t3, carry) = Mac(t3, self[1], self[2], 0); + (t4, carry) = Mac(t4, self[1], self[3], carry); + (t5, carry) = Mac(t5, self[1], self[4], carry); + (t6, t7) = Mac(t6, self[1], self[5], carry); + + (t5, carry) = Mac(t5, self[2], self[3], 0); + (t6, carry) = Mac(t6, self[2], self[4], carry); + (t7, t8) = Mac(t7, self[2], self[5], carry); + + (t7, carry) = Mac(t7, self[3], self[4], 0); + (t8, t9) = Mac(t8, self[3], self[5], carry); + + (t9, t10) = Mac(t9, self[4], self[5], 0); + + t11 = t10 >> 63; + t10 = (t10 << 1) | (t9 >> 63); + t9 = (t9 << 1) | (t8 >> 63); + t8 = (t8 << 1) | (t7 >> 63); + t7 = (t7 << 1) | (t6 >> 63); + t6 = (t6 << 1) | (t5 >> 63); + t5 = (t5 << 1) | (t4 >> 63); + t4 = (t4 << 1) | (t3 >> 63); + t3 = (t3 << 1) | (t2 >> 63); + t2 = (t2 << 1) | (t1 >> 63); + t1 <<= 1; + + (t0, carry) = Mac(0, self[0], self[0], 0); + (t1, carry) = Adc(t1, carry, 0); + (t2, carry) = Mac(t2, self[1], self[1], carry); + (t3, carry) = Adc(t3, carry, 0); + (t4, carry) = Mac(t4, self[2], self[2], carry); + (t5, carry) = Adc(t5, carry, 0); + (t6, carry) = Mac(t6, self[3], self[3], carry); + (t7, carry) = Adc(t7, carry, 0); + (t8, carry) = Mac(t8, self[4], self[4], carry); + (t9, carry) = Adc(t9, carry, 0); + (t10, carry) = Mac(t10, self[5], self[5], carry); + (t11, _) = Adc(t11, carry, 0); + + return MontgomeryReduce(t0, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11); + } + + #region Instance math methods + + public Fp Negate() => -this; + public Fp Multiply(in Fp value) => this * value; + public Fp Sum(in Fp value) => this + value; + public Fp Subtract(in Fp value) => this - value; + + #endregion +} diff --git a/src/Neo.Cryptography.BLS12_381/Fp12.cs b/src/Neo.Cryptography.BLS12_381/Fp12.cs new file mode 100644 index 0000000000..2ed7ee988a --- /dev/null +++ b/src/Neo.Cryptography.BLS12_381/Fp12.cs @@ -0,0 +1,218 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Fp12.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.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; +using System.Security.Cryptography; + +namespace Neo.Cryptography.BLS12_381; + +[StructLayout(LayoutKind.Explicit, Size = Size)] +public readonly struct Fp12 : IEquatable, INumber +{ + [FieldOffset(0)] + public readonly Fp6 C0; + [FieldOffset(Fp6.Size)] + public readonly Fp6 C1; + + public const int Size = Fp6.Size * 2; + + private static readonly Fp12 _zero = new(); + private static readonly Fp12 _one = new(in Fp6.One); + + public static ref readonly Fp12 Zero => ref _zero; + public static ref readonly Fp12 One => ref _one; + + public bool IsZero => C0.IsZero & C1.IsZero; + + public Fp12(in Fp f) + : this(new Fp6(in f), in Fp6.Zero) + { + } + + public Fp12(in Fp2 f) + : this(new Fp6(in f), in Fp6.Zero) + { + } + + public Fp12(in Fp6 f) + : this(in f, in Fp6.Zero) + { + } + + public Fp12(in Fp6 c0, in Fp6 c1) + { + C0 = c0; + C1 = c1; + } + + public static Fp12 FromBytes(ReadOnlySpan data) + { + if (data.Length != Size) + throw new FormatException($"The argument `{nameof(data)}` must contain {Size} bytes."); + Fp6 c0 = Fp6.FromBytes(data[Fp6.Size..]); + Fp6 c1 = Fp6.FromBytes(data[..Fp6.Size]); + return new(in c0, in c1); + } + + public static bool operator ==(in Fp12 a, in Fp12 b) + { + return a.C0 == b.C0 & a.C1 == b.C1; + } + + public static bool operator !=(in Fp12 a, in Fp12 b) + { + return !(a == b); + } + + public override bool Equals([NotNullWhen(true)] object? obj) + { + if (obj is not Fp12 other) return false; + return this == other; + } + + public bool Equals(Fp12 other) + { + return this == other; + } + + public override int GetHashCode() + { + return C0.GetHashCode() ^ C1.GetHashCode(); + } + + public byte[] ToArray() + { + byte[] result = new byte[Size]; + TryWrite(result); + return result; + } + + public bool TryWrite(Span buffer) + { + if (buffer.Length < Size) return false; + C0.TryWrite(buffer[Fp6.Size..Size]); + C1.TryWrite(buffer[0..Fp6.Size]); + return true; + } + + public static Fp12 Random(RandomNumberGenerator rng) + { + return new(Fp6.Random(rng), Fp6.Random(rng)); + } + + internal Fp12 MulBy_014(in Fp2 c0, in Fp2 c1, in Fp2 c4) + { + var aa = C0.MulBy_01(in c0, in c1); + var bb = C1.MulBy_1(in c4); + var o = c1 + c4; + var _c1 = C1 + C0; + _c1 = _c1.MulBy_01(in c0, in o); + _c1 = _c1 - aa - bb; + var _c0 = bb; + _c0 = _c0.MulByNonresidue(); + _c0 += aa; + + return new Fp12(in _c0, in _c1); + } + + public Fp12 Conjugate() + { + return new Fp12(in C0, -C1); + } + + public Fp12 FrobeniusMap() + { + var c0 = C0.FrobeniusMap(); + var c1 = C1.FrobeniusMap(); + + // c1 = c1 * (u + 1)^((p - 1) / 6) + c1 *= new Fp6(new Fp2( + Fp.FromRawUnchecked(new ulong[] + { + 0x0708_9552_b319_d465, + 0xc669_5f92_b50a_8313, + 0x97e8_3ccc_d117_228f, + 0xa35b_aeca_b2dc_29ee, + 0x1ce3_93ea_5daa_ce4d, + 0x08f2_220f_b0fb_66eb + }), Fp.FromRawUnchecked(new ulong[] + { + 0xb2f6_6aad_4ce5_d646, + 0x5842_a06b_fc49_7cec, + 0xcf48_95d4_2599_d394, + 0xc11b_9cba_40a8_e8d0, + 0x2e38_13cb_e5a0_de89, + 0x110e_efda_8884_7faf + }))); + + return new Fp12(in c0, in c1); + } + + public Fp12 Square() + { + var ab = C0 * C1; + var c0c1 = C0 + C1; + var c0 = C1.MulByNonresidue(); + c0 += C0; + c0 *= c0c1; + c0 -= ab; + var c1 = ab + ab; + c0 -= ab.MulByNonresidue(); + + return new Fp12(in c0, in c1); + } + + public Fp12 Invert() + { + Fp6 t = (C0.Square() - C1.Square().MulByNonresidue()).Invert(); + return new Fp12(C0 * t, C1 * -t); + } + + public static Fp12 operator -(in Fp12 a) + { + return new Fp12(-a.C0, -a.C1); + } + + public static Fp12 operator +(in Fp12 a, in Fp12 b) + { + return new Fp12(a.C0 + b.C0, a.C1 + b.C1); + } + + public static Fp12 operator -(in Fp12 a, in Fp12 b) + { + return new Fp12(a.C0 - b.C0, a.C1 - b.C1); + } + + public static Fp12 operator *(in Fp12 a, in Fp12 b) + { + var aa = a.C0 * b.C0; + var bb = a.C1 * b.C1; + var o = b.C0 + b.C1; + var c1 = a.C1 + a.C0; + c1 *= o; + c1 -= aa; + c1 -= bb; + var c0 = bb.MulByNonresidue(); + c0 += aa; + + return new Fp12(in c0, in c1); + } + + #region Instance math methods + + public Fp12 Negate() => -this; + public Fp12 Multiply(in Fp12 value) => this * value; + public Fp12 Sum(in Fp12 value) => this + value; + public Fp12 Subtract(in Fp12 value) => this - value; + + #endregion +} diff --git a/src/Neo.Cryptography.BLS12_381/Fp2.cs b/src/Neo.Cryptography.BLS12_381/Fp2.cs new file mode 100644 index 0000000000..4ca3830970 --- /dev/null +++ b/src/Neo.Cryptography.BLS12_381/Fp2.cs @@ -0,0 +1,274 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Fp2.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.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; +using System.Security.Cryptography; +using static Neo.Cryptography.BLS12_381.ConstantTimeUtility; + +namespace Neo.Cryptography.BLS12_381; + +[StructLayout(LayoutKind.Explicit, Size = Size)] +public readonly struct Fp2 : IEquatable, INumber +{ + [FieldOffset(0)] + public readonly Fp C0; + [FieldOffset(Fp.Size)] + public readonly Fp C1; + + public const int Size = Fp.Size * 2; + + private static readonly Fp2 _zero = new(); + private static readonly Fp2 _one = new(in Fp.One); + + public static ref readonly Fp2 Zero => ref _zero; + public static ref readonly Fp2 One => ref _one; + + public bool IsZero => C0.IsZero & C1.IsZero; + + public Fp2(in Fp f) + : this(in f, in Fp.Zero) + { + } + + public Fp2(in Fp c0, in Fp c1) + { + C0 = c0; + C1 = c1; + } + + public static Fp2 FromBytes(ReadOnlySpan data) + { + if (data.Length != Size) + throw new FormatException($"The argument `{nameof(data)}` must contain {Size} bytes."); + Fp c0 = Fp.FromBytes(data[Fp.Size..]); + Fp c1 = Fp.FromBytes(data[..Fp.Size]); + return new(in c0, in c1); + } + + public static Fp2 Random(RandomNumberGenerator rng) + { + return new(Fp.Random(rng), Fp.Random(rng)); + } + + public static bool operator ==(in Fp2 a, in Fp2 b) + { + return a.C0 == b.C0 & a.C1 == b.C1; + } + + public static bool operator !=(in Fp2 a, in Fp2 b) + { + return !(a == b); + } + + public override bool Equals([NotNullWhen(true)] object? obj) + { + if (obj is not Fp2 other) return false; + return this == other; + } + + public bool Equals(Fp2 other) + { + return this == other; + } + + public override int GetHashCode() + { + return C0.GetHashCode() ^ C1.GetHashCode(); + } + + public byte[] ToArray() + { + byte[] result = new byte[Size]; + TryWrite(result); + return result; + } + + public bool TryWrite(Span buffer) + { + if (buffer.Length < Size) return false; + C0.TryWrite(buffer[Fp.Size..Size]); + C1.TryWrite(buffer[0..Fp.Size]); + return true; + } + + public Fp2 FrobeniusMap() + { + // This is always just a conjugation. If you're curious why, here's + // an article about it: https://alicebob.cryptoland.net/the-frobenius-endomorphism-with-finite-fields/ + return Conjugate(); + } + + public Fp2 Conjugate() + { + return new(in C0, -C1); + } + + public Fp2 MulByNonresidue() + { + // Multiply a + bu by u + 1, getting + // au + a + bu^2 + bu + // and because u^2 = -1, we get + // (a - b) + (a + b)u + + return new(C0 - C1, C0 + C1); + } + + public bool LexicographicallyLargest() + { + // If this element's c1 coefficient is lexicographically largest + // then it is lexicographically largest. Otherwise, in the event + // the c1 coefficient is zero and the c0 coefficient is + // lexicographically largest, then this element is lexicographically + // largest. + + return C1.LexicographicallyLargest() | (C1.IsZero & C0.LexicographicallyLargest()); + } + + public Fp2 Square() + { + // Complex squaring: + // + // v0 = c0 * c1 + // c0' = (c0 + c1) * (c0 + \beta*c1) - v0 - \beta * v0 + // c1' = 2 * v0 + // + // In BLS12-381's F_{p^2}, our \beta is -1 so we + // can modify this formula: + // + // c0' = (c0 + c1) * (c0 - c1) + // c1' = 2 * c0 * c1 + + var a = C0 + C1; + var b = C0 - C1; + var c = C0 + C0; + + return new(a * b, c * C1); + } + + public static Fp2 operator *(in Fp2 a, in Fp2 b) + { + // F_{p^2} x F_{p^2} multiplication implemented with operand scanning (schoolbook) + // computes the result as: + // + // a·b = (a_0 b_0 + a_1 b_1 β) + (a_0 b_1 + a_1 b_0)i + // + // In BLS12-381's F_{p^2}, our β is -1, so the resulting F_{p^2} element is: + // + // c_0 = a_0 b_0 - a_1 b_1 + // c_1 = a_0 b_1 + a_1 b_0 + // + // Each of these is a "sum of products", which we can compute efficiently. + + return new( + Fp.SumOfProducts(stackalloc[] { a.C0, -a.C1 }, stackalloc[] { b.C0, b.C1 }), + Fp.SumOfProducts(stackalloc[] { a.C0, a.C1 }, stackalloc[] { b.C1, b.C0 }) + ); + } + + public static Fp2 operator +(in Fp2 a, in Fp2 b) + { + return new(a.C0 + b.C0, a.C1 + b.C1); + } + + public static Fp2 operator -(in Fp2 a, in Fp2 b) + { + return new(a.C0 - b.C0, a.C1 - b.C1); + } + + public static Fp2 operator -(in Fp2 a) + { + return new(-a.C0, -a.C1); + } + + public Fp2 Sqrt() + { + // Algorithm 9, https://eprint.iacr.org/2012/685.pdf + // with constant time modifications. + + // a1 = self^((p - 3) / 4) + var a1 = this.PowVartime(new ulong[] + { + 0xee7f_bfff_ffff_eaaa, + 0x07aa_ffff_ac54_ffff, + 0xd9cc_34a8_3dac_3d89, + 0xd91d_d2e1_3ce1_44af, + 0x92c6_e9ed_90d2_eb35, + 0x0680_447a_8e5f_f9a6 + }); + + // alpha = a1^2 * self = self^((p - 3) / 2 + 1) = self^((p - 1) / 2) + var alpha = a1.Square() * this; + + // x0 = self^((p + 1) / 4) + var x0 = a1 * this; + + // (1 + alpha)^((q - 1) // 2) * x0 + var sqrt = (alpha + One).PowVartime(new ulong[] { + 0xdcff_7fff_ffff_d555, + 0x0f55_ffff_58a9_ffff, + 0xb398_6950_7b58_7b12, + 0xb23b_a5c2_79c2_895f, + 0x258d_d3db_21a5_d66b, + 0x0d00_88f5_1cbf_f34d, + }) * x0; + + // In the event that alpha = -1, the element is order p - 1 and so + // we're just trying to get the square of an element of the subfield + // Fp. This is given by x0 * u, since u = sqrt(-1). Since the element + // x0 = a + bu has b = 0, the solution is therefore au. + sqrt = ConditionalSelect(in sqrt, new(-x0.C1, in x0.C0), alpha == -One); + + sqrt = ConditionalSelect(in sqrt, in Zero, IsZero); + + // Only return the result if it's really the square root (and so + // self is actually quadratic nonresidue) + if (sqrt.Square() != this) throw new ArithmeticException(); + return sqrt; + } + + public Fp2 Invert() + { + if (!TryInvert(out Fp2 result)) + throw new DivideByZeroException(); + return result; + } + + public bool TryInvert(out Fp2 result) + { + // We wish to find the multiplicative inverse of a nonzero + // element a + bu in Fp2. We leverage an identity + // + // (a + bu)(a - bu) = a^2 + b^2 + // + // which holds because u^2 = -1. This can be rewritten as + // + // (a + bu)(a - bu)/(a^2 + b^2) = 1 + // + // because a^2 + b^2 = 0 has no nonzero solutions for (a, b). + // This gives that (a - bu)/(a^2 + b^2) is the inverse + // of (a + bu). Importantly, this can be computing using + // only a single inversion in Fp. + + bool s = (C0.Square() + C1.Square()).TryInvert(out Fp t); + result = new Fp2(C0 * t, C1 * -t); + return s; + } + + #region Instance math methods + + public Fp2 Negate() => -this; + public Fp2 Multiply(in Fp2 value) => this * value; + public Fp2 Sum(in Fp2 value) => this + value; + public Fp2 Subtract(in Fp2 value) => this - value; + + #endregion +} diff --git a/src/Neo.Cryptography.BLS12_381/Fp6.cs b/src/Neo.Cryptography.BLS12_381/Fp6.cs new file mode 100644 index 0000000000..540bfc8a36 --- /dev/null +++ b/src/Neo.Cryptography.BLS12_381/Fp6.cs @@ -0,0 +1,308 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Fp6.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.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; +using System.Security.Cryptography; + +namespace Neo.Cryptography.BLS12_381; + +[StructLayout(LayoutKind.Explicit, Size = Size)] +public readonly struct Fp6 : IEquatable, INumber +{ + [FieldOffset(0)] + public readonly Fp2 C0; + [FieldOffset(Fp2.Size)] + public readonly Fp2 C1; + [FieldOffset(Fp2.Size * 2)] + public readonly Fp2 C2; + + public const int Size = Fp2.Size * 3; + + private static readonly Fp6 _zero = new(); + private static readonly Fp6 _one = new(in Fp2.One); + + public static ref readonly Fp6 Zero => ref _zero; + public static ref readonly Fp6 One => ref _one; + + public bool IsZero => C0.IsZero & C1.IsZero & C2.IsZero; + + public Fp6(in Fp f) + : this(new Fp2(in f), in Fp2.Zero, in Fp2.Zero) + { + } + + public Fp6(in Fp2 f) + : this(in f, in Fp2.Zero, in Fp2.Zero) + { + } + + public Fp6(in Fp2 c0, in Fp2 c1, in Fp2 c2) + { + C0 = c0; + C1 = c1; + C2 = c2; + } + + public static Fp6 FromBytes(ReadOnlySpan data) + { + if (data.Length != Size) + throw new FormatException($"The argument `{nameof(data)}` must contain {Size} bytes."); + Fp2 c0 = Fp2.FromBytes(data[(Fp2.Size * 2)..]); + Fp2 c1 = Fp2.FromBytes(data[Fp2.Size..(Fp2.Size * 2)]); + Fp2 c2 = Fp2.FromBytes(data[..Fp2.Size]); + return new(in c0, in c1, in c2); + } + + public static bool operator ==(in Fp6 a, in Fp6 b) + { + return a.C0 == b.C0 & a.C1 == b.C1 & a.C2 == b.C2; + } + + public static bool operator !=(in Fp6 a, in Fp6 b) + { + return !(a == b); + } + + public override bool Equals([NotNullWhen(true)] object? obj) + { + if (obj is not Fp6 other) return false; + return this == other; + } + + public bool Equals(Fp6 other) + { + return this == other; + } + + public override int GetHashCode() + { + return C0.GetHashCode() ^ C1.GetHashCode() ^ C2.GetHashCode(); + } + + public byte[] ToArray() + { + byte[] result = new byte[Size]; + TryWrite(result); + return result; + } + + public bool TryWrite(Span buffer) + { + if (buffer.Length < Size) return false; + C0.TryWrite(buffer[(Fp2.Size * 2)..Size]); + C1.TryWrite(buffer[Fp2.Size..(Fp2.Size * 2)]); + C2.TryWrite(buffer[0..Fp2.Size]); + return true; + } + + public static Fp6 Random(RandomNumberGenerator rng) + { + return new(Fp2.Random(rng), Fp2.Random(rng), Fp2.Random(rng)); + } + + internal Fp6 MulBy_1(in Fp2 c1) + { + var b_b = C1 * c1; + + var t1 = (C1 + C2) * c1 - b_b; + t1 = t1.MulByNonresidue(); + + var t2 = (C0 + C1) * c1 - b_b; + + return new Fp6(in t1, in t2, in b_b); + } + + internal Fp6 MulBy_01(in Fp2 c0, in Fp2 c1) + { + var a_a = C0 * c0; + var b_b = C1 * c1; + + var t1 = (C1 + C2) * c1 - b_b; + t1 = t1.MulByNonresidue() + a_a; + + var t2 = (c0 + c1) * (C0 + C1) - a_a - b_b; + + var t3 = (C0 + C2) * c0 - a_a + b_b; + + return new Fp6(in t1, in t2, in t3); + } + + public Fp6 MulByNonresidue() + { + // Given a + bv + cv^2, this produces + // av + bv^2 + cv^3 + // but because v^3 = u + 1, we have + // c(u + 1) + av + v^2 + + return new Fp6(C2.MulByNonresidue(), in C0, in C1); + } + + public Fp6 FrobeniusMap() + { + var c0 = C0.FrobeniusMap(); + var c1 = C1.FrobeniusMap(); + var c2 = C2.FrobeniusMap(); + + // c1 = c1 * (u + 1)^((p - 1) / 3) + c1 *= new Fp2(in Fp.Zero, Fp.FromRawUnchecked(new ulong[] + { + 0xcd03_c9e4_8671_f071, + 0x5dab_2246_1fcd_a5d2, + 0x5870_42af_d385_1b95, + 0x8eb6_0ebe_01ba_cb9e, + 0x03f9_7d6e_83d0_50d2, + 0x18f0_2065_5463_8741 + })); + + // c2 = c2 * (u + 1)^((2p - 2) / 3) + c2 *= new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0x890d_c9e4_8675_45c3, + 0x2af3_2253_3285_a5d5, + 0x5088_0866_309b_7e2c, + 0xa20d_1b8c_7e88_1024, + 0x14e4_f04f_e2db_9068, + 0x14e5_6d3f_1564_853a + }), in Fp.Zero); + + return new Fp6(c0, c1, c2); + } + + public Fp6 Square() + { + var s0 = C0.Square(); + var ab = C0 * C1; + var s1 = ab + ab; + var s2 = (C0 - C1 + C2).Square(); + var bc = C1 * C2; + var s3 = bc + bc; + var s4 = C2.Square(); + + return new Fp6( + s3.MulByNonresidue() + s0, + s4.MulByNonresidue() + s1, + s1 + s2 + s3 - s0 - s4 + ); + } + + public Fp6 Invert() + { + var c0 = (C1 * C2).MulByNonresidue(); + c0 = C0.Square() - c0; + + var c1 = C2.Square().MulByNonresidue(); + c1 -= C0 * C1; + + var c2 = C1.Square(); + c2 -= C0 * C2; + + var t = (C1 * c2 + C2 * c1).MulByNonresidue(); + t += C0 * c0; + + t = t.Invert(); + return new Fp6(t * c0, t * c1, t * c2); + } + + public static Fp6 operator -(in Fp6 a) + { + return new Fp6(-a.C0, -a.C1, -a.C2); + } + + public static Fp6 operator +(in Fp6 a, in Fp6 b) + { + return new Fp6(a.C0 + b.C0, a.C1 + b.C1, a.C2 + b.C2); + } + + public static Fp6 operator -(in Fp6 a, in Fp6 b) + { + return new Fp6(a.C0 - b.C0, a.C1 - b.C1, a.C2 - b.C2); + } + + public static Fp6 operator *(in Fp6 a, in Fp6 b) + { + // The intuition for this algorithm is that we can look at F_p^6 as a direct + // extension of F_p^2, and express the overall operations down to the base field + // F_p instead of only over F_p^2. This enables us to interleave multiplications + // and reductions, ensuring that we don't require double-width intermediate + // representations (with around twice as many limbs as F_p elements). + + // We want to express the multiplication c = a x b, where a = (a_0, a_1, a_2) is + // an element of F_p^6, and a_i = (a_i,0, a_i,1) is an element of F_p^2. The fully + // expanded multiplication is given by (2022-376 §5): + // + // c_0,0 = a_0,0 b_0,0 - a_0,1 b_0,1 + a_1,0 b_2,0 - a_1,1 b_2,1 + a_2,0 b_1,0 - a_2,1 b_1,1 + // - a_1,0 b_2,1 - a_1,1 b_2,0 - a_2,0 b_1,1 - a_2,1 b_1,0. + // = a_0,0 b_0,0 - a_0,1 b_0,1 + a_1,0 (b_2,0 - b_2,1) - a_1,1 (b_2,0 + b_2,1) + // + a_2,0 (b_1,0 - b_1,1) - a_2,1 (b_1,0 + b_1,1). + // + // c_0,1 = a_0,0 b_0,1 + a_0,1 b_0,0 + a_1,0 b_2,1 + a_1,1 b_2,0 + a_2,0 b_1,1 + a_2,1 b_1,0 + // + a_1,0 b_2,0 - a_1,1 b_2,1 + a_2,0 b_1,0 - a_2,1 b_1,1. + // = a_0,0 b_0,1 + a_0,1 b_0,0 + a_1,0(b_2,0 + b_2,1) + a_1,1(b_2,0 - b_2,1) + // + a_2,0(b_1,0 + b_1,1) + a_2,1(b_1,0 - b_1,1). + // + // c_1,0 = a_0,0 b_1,0 - a_0,1 b_1,1 + a_1,0 b_0,0 - a_1,1 b_0,1 + a_2,0 b_2,0 - a_2,1 b_2,1 + // - a_2,0 b_2,1 - a_2,1 b_2,0. + // = a_0,0 b_1,0 - a_0,1 b_1,1 + a_1,0 b_0,0 - a_1,1 b_0,1 + a_2,0(b_2,0 - b_2,1) + // - a_2,1(b_2,0 + b_2,1). + // + // c_1,1 = a_0,0 b_1,1 + a_0,1 b_1,0 + a_1,0 b_0,1 + a_1,1 b_0,0 + a_2,0 b_2,1 + a_2,1 b_2,0 + // + a_2,0 b_2,0 - a_2,1 b_2,1 + // = a_0,0 b_1,1 + a_0,1 b_1,0 + a_1,0 b_0,1 + a_1,1 b_0,0 + a_2,0(b_2,0 + b_2,1) + // + a_2,1(b_2,0 - b_2,1). + // + // c_2,0 = a_0,0 b_2,0 - a_0,1 b_2,1 + a_1,0 b_1,0 - a_1,1 b_1,1 + a_2,0 b_0,0 - a_2,1 b_0,1. + // c_2,1 = a_0,0 b_2,1 + a_0,1 b_2,0 + a_1,0 b_1,1 + a_1,1 b_1,0 + a_2,0 b_0,1 + a_2,1 b_0,0. + // + // Each of these is a "sum of products", which we can compute efficiently. + + var b10_p_b11 = b.C1.C0 + b.C1.C1; + var b10_m_b11 = b.C1.C0 - b.C1.C1; + var b20_p_b21 = b.C2.C0 + b.C2.C1; + var b20_m_b21 = b.C2.C0 - b.C2.C1; + + return new Fp6(new Fp2( + Fp.SumOfProducts( + stackalloc[] { a.C0.C0, -a.C0.C1, a.C1.C0, -a.C1.C1, a.C2.C0, -a.C2.C1 }, + stackalloc[] { b.C0.C0, b.C0.C1, b20_m_b21, b20_p_b21, b10_m_b11, b10_p_b11 } + ), + Fp.SumOfProducts( + stackalloc[] { a.C0.C0, a.C0.C1, a.C1.C0, a.C1.C1, a.C2.C0, a.C2.C1 }, + stackalloc[] { b.C0.C1, b.C0.C0, b20_p_b21, b20_m_b21, b10_p_b11, b10_m_b11 } + )), new Fp2( + Fp.SumOfProducts( + stackalloc[] { a.C0.C0, -a.C0.C1, a.C1.C0, -a.C1.C1, a.C2.C0, -a.C2.C1 }, + stackalloc[] { b.C1.C0, b.C1.C1, b.C0.C0, b.C0.C1, b20_m_b21, b20_p_b21 } + ), + Fp.SumOfProducts( + stackalloc[] { a.C0.C0, a.C0.C1, a.C1.C0, a.C1.C1, a.C2.C0, a.C2.C1 }, + stackalloc[] { b.C1.C1, b.C1.C0, b.C0.C1, b.C0.C0, b20_p_b21, b20_m_b21 } + )), new Fp2( + Fp.SumOfProducts( + stackalloc[] { a.C0.C0, -a.C0.C1, a.C1.C0, -a.C1.C1, a.C2.C0, -a.C2.C1 }, + stackalloc[] { b.C2.C0, b.C2.C1, b.C1.C0, b.C1.C1, b.C0.C0, b.C0.C1 } + ), + Fp.SumOfProducts( + stackalloc[] { a.C0.C0, a.C0.C1, a.C1.C0, a.C1.C1, a.C2.C0, a.C2.C1 }, + stackalloc[] { b.C2.C1, b.C2.C0, b.C1.C1, b.C1.C0, b.C0.C1, b.C0.C0 } + )) + ); + } + + #region Instance math methods + + public Fp6 Negate() => -this; + public Fp6 Multiply(in Fp6 value) => this * value; + public Fp6 Sum(in Fp6 value) => this + value; + public Fp6 Subtract(in Fp6 value) => this - value; + + #endregion +} diff --git a/src/Neo.Cryptography.BLS12_381/FpConstants.cs b/src/Neo.Cryptography.BLS12_381/FpConstants.cs new file mode 100644 index 0000000000..dd9f7ece9f --- /dev/null +++ b/src/Neo.Cryptography.BLS12_381/FpConstants.cs @@ -0,0 +1,84 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// FpConstants.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.Cryptography.BLS12_381; + +static class FpConstants +{ + // p = 4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787 + public static readonly ulong[] MODULUS = + { + 0xb9fe_ffff_ffff_aaab, + 0x1eab_fffe_b153_ffff, + 0x6730_d2a0_f6b0_f624, + 0x6477_4b84_f385_12bf, + 0x4b1b_a7b6_434b_acd7, + 0x1a01_11ea_397f_e69a + }; + + // p - 2 + public static readonly ulong[] P_2 = + { + 0xb9fe_ffff_ffff_aaa9, + 0x1eab_fffe_b153_ffff, + 0x6730_d2a0_f6b0_f624, + 0x6477_4b84_f385_12bf, + 0x4b1b_a7b6_434b_acd7, + 0x1a01_11ea_397f_e69a + }; + + // (p + 1) / 4 + public static readonly ulong[] P_1_4 = + { + 0xee7f_bfff_ffff_eaab, + 0x07aa_ffff_ac54_ffff, + 0xd9cc_34a8_3dac_3d89, + 0xd91d_d2e1_3ce1_44af, + 0x92c6_e9ed_90d2_eb35, + 0x0680_447a_8e5f_f9a6 + }; + + // INV = -(p^{-1} mod 2^64) mod 2^64 + public const ulong INV = 0x89f3_fffc_fffc_fffd; + + // R = 2^384 mod p + public static readonly Fp R = Fp.FromRawUnchecked(new ulong[] + { + 0x7609_0000_0002_fffd, + 0xebf4_000b_c40c_0002, + 0x5f48_9857_53c7_58ba, + 0x77ce_5853_7052_5745, + 0x5c07_1a97_a256_ec6d, + 0x15f6_5ec3_fa80_e493 + }); + + // R2 = 2^(384*2) mod p + public static readonly Fp R2 = Fp.FromRawUnchecked(new ulong[] + { + 0xf4df_1f34_1c34_1746, + 0x0a76_e6a6_09d1_04f1, + 0x8de5_476c_4c95_b6d5, + 0x67eb_88a9_939d_83c0, + 0x9a79_3e85_b519_952d, + 0x1198_8fe5_92ca_e3aa + }); + + // R3 = 2^(384*3) mod p + public static readonly Fp R3 = Fp.FromRawUnchecked(new ulong[] + { + 0xed48_ac6b_d94c_a1e0, + 0x315f_831e_03a7_adf8, + 0x9a53_352a_615e_29dd, + 0x34c0_4e5e_921e_1761, + 0x2512_d435_6572_4728, + 0x0aa6_3460_9175_5d4d + }); +} diff --git a/src/Neo.Cryptography.BLS12_381/G1Affine.cs b/src/Neo.Cryptography.BLS12_381/G1Affine.cs new file mode 100644 index 0000000000..cbed66bc8f --- /dev/null +++ b/src/Neo.Cryptography.BLS12_381/G1Affine.cs @@ -0,0 +1,181 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// G1Affine.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.Diagnostics.CodeAnalysis; +using static Neo.Cryptography.BLS12_381.ConstantTimeUtility; +using static Neo.Cryptography.BLS12_381.G1Constants; + +namespace Neo.Cryptography.BLS12_381; + +public readonly struct G1Affine : IEquatable +{ + public readonly Fp X; + public readonly Fp Y; + public readonly bool Infinity; + + public static readonly G1Affine Identity = new(in Fp.Zero, in Fp.One, true); + public static readonly G1Affine Generator = new(in GeneratorX, in GeneratorY, false); + + public bool IsIdentity => Infinity; + public bool IsTorsionFree => -new G1Projective(this).MulByX().MulByX() == new G1Projective(Endomorphism()); + public bool IsOnCurve => ((Y.Square() - (X.Square() * X)) == B) | Infinity; + + public G1Affine(in Fp x, in Fp y) + : this(in x, in y, false) + { + } + + private G1Affine(in Fp x, in Fp y, bool infinity) + { + X = x; + Y = y; + Infinity = infinity; + } + + public G1Affine(in G1Projective p) + { + bool s = p.Z.TryInvert(out Fp zinv); + + zinv = ConditionalSelect(in Fp.Zero, in zinv, s); + Fp x = p.X * zinv; + Fp y = p.Y * zinv; + + G1Affine tmp = new(in x, in y, false); + this = ConditionalSelect(in tmp, in Identity, !s); + } + + public static G1Affine FromUncompressed(ReadOnlySpan data) + { + return FromBytes(data, false, true); + } + + public static G1Affine FromCompressed(ReadOnlySpan data) + { + return FromBytes(data, true, true); + } + + private static G1Affine FromBytes(ReadOnlySpan data, bool compressed, bool check) + { + bool compression_flag_set = (data[0] & 0x80) != 0; + bool infinity_flag_set = (data[0] & 0x40) != 0; + bool sort_flag_set = (data[0] & 0x20) != 0; + byte[] tmp = data[0..48].ToArray(); + tmp[0] &= 0b0001_1111; + Fp x = Fp.FromBytes(tmp); + if (compressed) + { + Fp y = ((x.Square() * x) + B).Sqrt(); + y = ConditionalSelect(in y, -y, y.LexicographicallyLargest() ^ sort_flag_set); + G1Affine result = new(in x, in y, infinity_flag_set); + result = ConditionalSelect(in result, in Identity, infinity_flag_set); + if (check) + { + bool _checked = (!infinity_flag_set | (infinity_flag_set & !sort_flag_set & x.IsZero)) + & compression_flag_set; + _checked &= result.IsTorsionFree; + if (!_checked) throw new FormatException(); + } + return result; + } + else + { + Fp y = Fp.FromBytes(data[48..96]); + G1Affine result = ConditionalSelect(new(in x, in y, infinity_flag_set), in Identity, infinity_flag_set); + if (check) + { + bool _checked = (!infinity_flag_set | (infinity_flag_set & x.IsZero & y.IsZero)) + & !compression_flag_set + & !sort_flag_set; + _checked &= result.IsOnCurve & result.IsTorsionFree; + if (!_checked) throw new FormatException(); + } + return result; + } + } + + public static bool operator ==(in G1Affine a, in G1Affine b) + { + return (a.Infinity & b.Infinity) | (!a.Infinity & !b.Infinity & a.X == b.X & a.Y == b.Y); + } + + public static bool operator !=(in G1Affine a, in G1Affine b) + { + return !(a == b); + } + + public override bool Equals([NotNullWhen(true)] object? obj) + { + if (obj is not G1Affine other) return false; + return this == other; + } + + public bool Equals(G1Affine other) + { + return this == other; + } + + public override int GetHashCode() + { + if (Infinity) return Infinity.GetHashCode(); + return X.GetHashCode() ^ Y.GetHashCode(); + } + + public static G1Affine operator -(in G1Affine p) + { + return new G1Affine(in p.X, ConditionalSelect(-p.Y, in Fp.One, p.Infinity), p.Infinity); + } + + public byte[] ToCompressed() + { + byte[] res = ConditionalSelect(in X, in Fp.Zero, Infinity).ToArray(); + + // This point is in compressed form, so we set the most significant bit. + res[0] |= 0x80; + + // Is this point at infinity? If so, set the second-most significant bit. + res[0] |= ConditionalSelect((byte)0, (byte)0x40, Infinity); + + // Is the y-coordinate the lexicographically largest of the two associated with the + // x-coordinate? If so, set the third-most significant bit so long as this is not + // the point at infinity. + res[0] |= ConditionalSelect((byte)0, (byte)0x20, !Infinity & Y.LexicographicallyLargest()); + + return res; + } + + public byte[] ToUncompressed() + { + byte[] res = new byte[96]; + + ConditionalSelect(in X, in Fp.Zero, Infinity).TryWrite(res.AsSpan(0..48)); + ConditionalSelect(in Y, in Fp.Zero, Infinity).TryWrite(res.AsSpan(48..96)); + + // Is this point at infinity? If so, set the second-most significant bit. + res[0] |= ConditionalSelect((byte)0, (byte)0x40, Infinity); + + return res; + } + + public G1Projective ToCurve() + { + return new(this); + } + + private G1Affine Endomorphism() + { + return new(X * BETA, in Y, Infinity); + } + + public static G1Projective operator *(in G1Affine a, in Scalar b) + { + return new G1Projective(in a) * b.ToArray(); + } +} diff --git a/src/Neo.Cryptography.BLS12_381/G1Constants.cs b/src/Neo.Cryptography.BLS12_381/G1Constants.cs new file mode 100644 index 0000000000..1c07bb0900 --- /dev/null +++ b/src/Neo.Cryptography.BLS12_381/G1Constants.cs @@ -0,0 +1,55 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// G1Constants.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.Cryptography.BLS12_381; + +static class G1Constants +{ + public static readonly Fp GeneratorX = Fp.FromRawUnchecked(new ulong[] + { + 0x5cb3_8790_fd53_0c16, + 0x7817_fc67_9976_fff5, + 0x154f_95c7_143b_a1c1, + 0xf0ae_6acd_f3d0_e747, + 0xedce_6ecc_21db_f440, + 0x1201_7741_9e0b_fb75 + }); + + public static readonly Fp GeneratorY = Fp.FromRawUnchecked(new ulong[] + { + 0xbaac_93d5_0ce7_2271, + 0x8c22_631a_7918_fd8e, + 0xdd59_5f13_5707_25ce, + 0x51ac_5829_5040_5194, + 0x0e1c_8c3f_ad00_59c0, + 0x0bbc_3efc_5008_a26a + }); + + public static readonly Fp B = Fp.FromRawUnchecked(new ulong[] + { + 0xaa27_0000_000c_fff3, + 0x53cc_0032_fc34_000a, + 0x478f_e97a_6b0a_807f, + 0xb1d3_7ebe_e6ba_24d7, + 0x8ec9_733b_bf78_ab2f, + 0x09d6_4551_3d83_de7e + }); + + public static readonly Fp BETA = Fp.FromRawUnchecked(new ulong[] + { + 0x30f1_361b_798a_64e8, + 0xf3b8_ddab_7ece_5a2a, + 0x16a8_ca3a_c615_77f7, + 0xc26a_2ff8_74fd_029b, + 0x3636_b766_6070_1c6e, + 0x051b_a4ab_241b_6160 + }); +} diff --git a/src/Neo.Cryptography.BLS12_381/G1Projective.cs b/src/Neo.Cryptography.BLS12_381/G1Projective.cs new file mode 100644 index 0000000000..95600af135 --- /dev/null +++ b/src/Neo.Cryptography.BLS12_381/G1Projective.cs @@ -0,0 +1,294 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// G1Projective.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.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; +using static Neo.Cryptography.BLS12_381.Constants; +using static Neo.Cryptography.BLS12_381.ConstantTimeUtility; +using static Neo.Cryptography.BLS12_381.G1Constants; + +namespace Neo.Cryptography.BLS12_381; + +[StructLayout(LayoutKind.Explicit, Size = Fp.Size * 3)] +public readonly struct G1Projective : IEquatable +{ + [FieldOffset(0)] + public readonly Fp X; + [FieldOffset(Fp.Size)] + public readonly Fp Y; + [FieldOffset(Fp.Size * 2)] + public readonly Fp Z; + + public static readonly G1Projective Identity = new(in Fp.Zero, in Fp.One, in Fp.Zero); + public static readonly G1Projective Generator = new(in GeneratorX, in GeneratorY, in Fp.One); + + public bool IsIdentity => Z.IsZero; + public bool IsOnCurve => ((Y.Square() * Z) == (X.Square() * X + Z.Square() * Z * B)) | Z.IsZero; + + public G1Projective(in Fp x, in Fp y, in Fp z) + { + X = x; + Y = y; + Z = z; + } + + public G1Projective(in G1Affine p) + : this(in p.X, in p.Y, ConditionalSelect(in Fp.One, in Fp.Zero, p.Infinity)) + { + } + + public static bool operator ==(in G1Projective a, in G1Projective b) + { + // Is (xz, yz, z) equal to (x'z', y'z', z') when converted to affine? + + Fp x1 = a.X * b.Z; + Fp x2 = b.X * a.Z; + + Fp y1 = a.Y * b.Z; + Fp y2 = b.Y * a.Z; + + bool self_is_zero = a.Z.IsZero; + bool other_is_zero = b.Z.IsZero; + + // Both point at infinity. Or neither point at infinity, coordinates are the same. + return (self_is_zero & other_is_zero) | ((!self_is_zero) & (!other_is_zero) & x1 == x2 & y1 == y2); + } + + public static bool operator !=(in G1Projective a, in G1Projective b) + { + return !(a == b); + } + + public override bool Equals([NotNullWhen(true)] object? obj) + { + if (obj is not G1Projective other) return false; + return this == other; + } + + public bool Equals(G1Projective other) + { + return this == other; + } + + public override int GetHashCode() + { + return X.GetHashCode() ^ Y.GetHashCode() ^ Z.GetHashCode(); + } + + public static G1Projective operator -(in G1Projective p) + { + return new G1Projective(in p.X, -p.Y, in p.Z); + } + + private static Fp MulBy3B(in Fp a) + { + Fp b = a + a; + b += b; + return b + b + b; + } + + public G1Projective Double() + { + Fp t0 = Y.Square(); + Fp z3 = t0 + t0; + z3 += z3; + z3 += z3; + Fp t1 = Y * Z; + Fp t2 = Z.Square(); + t2 = MulBy3B(in t2); + Fp x3 = t2 * z3; + Fp y3 = t0 + t2; + z3 = t1 * z3; + t1 = t2 + t2; + t2 = t1 + t2; + t0 -= t2; + y3 = t0 * y3; + y3 = x3 + y3; + t1 = X * Y; + x3 = t0 * t1; + x3 += x3; + + G1Projective tmp = new(in x3, in y3, in z3); + return ConditionalSelect(in tmp, in Identity, IsIdentity); + } + + public static G1Projective operator +(in G1Projective a, in G1Projective b) + { + Fp t0 = a.X * b.X; + Fp t1 = a.Y * b.Y; + Fp t2 = a.Z * b.Z; + Fp t3 = a.X + a.Y; + Fp t4 = b.X + b.Y; + t3 *= t4; + t4 = t0 + t1; + t3 -= t4; + t4 = a.Y + a.Z; + Fp x3 = b.Y + b.Z; + t4 *= x3; + x3 = t1 + t2; + t4 -= x3; + x3 = a.X + a.Z; + Fp y3 = b.X + b.Z; + x3 *= y3; + y3 = t0 + t2; + y3 = x3 - y3; + x3 = t0 + t0; + t0 = x3 + t0; + t2 = MulBy3B(in t2); + Fp z3 = t1 + t2; + t1 -= t2; + y3 = MulBy3B(in y3); + x3 = t4 * y3; + t2 = t3 * t1; + x3 = t2 - x3; + y3 *= t0; + t1 *= z3; + y3 = t1 + y3; + t0 *= t3; + z3 *= t4; + z3 += t0; + + return new G1Projective(in x3, in y3, in z3); + } + + public static G1Projective operator +(in G1Projective a, in G1Affine b) + { + Fp t0 = a.X * b.X; + Fp t1 = a.Y * b.Y; + Fp t3 = b.X + b.Y; + Fp t4 = a.X + a.Y; + t3 *= t4; + t4 = t0 + t1; + t3 -= t4; + t4 = b.Y * a.Z; + t4 += a.Y; + Fp y3 = b.X * a.Z; + y3 += a.X; + Fp x3 = t0 + t0; + t0 = x3 + t0; + Fp t2 = MulBy3B(in a.Z); + Fp z3 = t1 + t2; + t1 -= t2; + y3 = MulBy3B(in y3); + x3 = t4 * y3; + t2 = t3 * t1; + x3 = t2 - x3; + y3 *= t0; + t1 *= z3; + y3 = t1 + y3; + t0 *= t3; + z3 *= t4; + z3 += t0; + + G1Projective tmp = new(in x3, in y3, in z3); + return ConditionalSelect(in tmp, in a, b.IsIdentity); + } + + public static G1Projective operator +(in G1Affine a, in G1Projective b) + { + return b + a; + } + + public static G1Projective operator -(in G1Projective a, in G1Projective b) + { + return a + -b; + } + + public static G1Projective operator -(in G1Projective a, in G1Affine b) + { + return a + -b; + } + + public static G1Projective operator -(in G1Affine a, in G1Projective b) + { + return -b + a; + } + + public static G1Projective operator *(in G1Projective a, byte[] b) + { + int length = b.Length; + if (length != 32) + throw new ArgumentException($"The argument {nameof(b)} must be 32 bytes."); + + G1Projective acc = Identity; + + foreach (bool bit in b + .SelectMany(p => Enumerable.Range(0, 8).Select(q => ((p >> q) & 1) == 1)) + .Reverse() + .Skip(1)) + { + acc = acc.Double(); + acc = ConditionalSelect(in acc, acc + a, bit); + } + + return acc; + } + + public static G1Projective operator *(in G1Projective a, in Scalar b) + { + return a * b.ToArray(); + } + + internal G1Projective MulByX() + { + G1Projective xself = Identity; + + ulong x = BLS_X >> 1; + G1Projective tmp = this; + while (x > 0) + { + tmp = tmp.Double(); + + if (x % 2 == 1) + { + xself += tmp; + } + x >>= 1; + } + + if (BLS_X_IS_NEGATIVE) + { + xself = -xself; + } + return xself; + } + + public G1Projective ClearCofactor() + { + return this - MulByX(); + } + + public static void BatchNormalize(ReadOnlySpan p, Span q) + { + int length = p.Length; + if (length != q.Length) + throw new ArgumentException($"{nameof(p)} and {nameof(q)} must have the same length."); + + Span x = stackalloc Fp[length]; + Fp acc = Fp.One; + for (int i = 0; i < length; i++) + { + x[i] = acc; + acc = ConditionalSelect(acc * p[i].Z, in acc, p[i].IsIdentity); + } + + acc = acc.Invert(); + + for (int i = length - 1; i >= 0; i--) + { + bool skip = p[i].IsIdentity; + Fp tmp = x[i] * acc; + acc = ConditionalSelect(acc * p[i].Z, in acc, skip); + G1Affine qi = new(p[i].X * tmp, p[i].Y * tmp); + q[i] = ConditionalSelect(in qi, in G1Affine.Identity, skip); + } + } +} diff --git a/src/Neo.Cryptography.BLS12_381/G2Affine.cs b/src/Neo.Cryptography.BLS12_381/G2Affine.cs new file mode 100644 index 0000000000..97256d02c7 --- /dev/null +++ b/src/Neo.Cryptography.BLS12_381/G2Affine.cs @@ -0,0 +1,225 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// G2Affine.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.Diagnostics.CodeAnalysis; +using static Neo.Cryptography.BLS12_381.ConstantTimeUtility; +using static Neo.Cryptography.BLS12_381.G2Constants; + +namespace Neo.Cryptography.BLS12_381; + +public readonly struct G2Affine : IEquatable +{ + public readonly Fp2 X; + public readonly Fp2 Y; + public readonly bool Infinity; + + public static readonly G2Affine Identity = new(in Fp2.Zero, in Fp2.One, true); + public static readonly G2Affine Generator = new(in GeneratorX, in GeneratorY, false); + + public bool IsIdentity => Infinity; + public bool IsTorsionFree + { + get + { + // Algorithm from Section 4 of https://eprint.iacr.org/2021/1130 + // Updated proof of correctness in https://eprint.iacr.org/2022/352 + // + // Check that psi(P) == [x] P + var p = new G2Projective(this); + return p.Psi() == p.MulByX(); + } + } + public bool IsOnCurve => ((Y.Square() - X.Square() * X) == B) | Infinity; // y^2 - x^3 ?= 4(u + 1) + + public G2Affine(in Fp2 x, in Fp2 y) + : this(in x, in y, false) + { + } + + private G2Affine(in Fp2 x, in Fp2 y, bool infinity) + { + X = x; + Y = y; + Infinity = infinity; + } + + public G2Affine(in G2Projective p) + { + bool s = p.Z.TryInvert(out Fp2 zinv); + + zinv = ConditionalSelect(in Fp2.Zero, in zinv, s); + Fp2 x = p.X * zinv; + Fp2 y = p.Y * zinv; + + G2Affine tmp = new(in x, in y, false); + this = ConditionalSelect(in tmp, in Identity, !s); + } + + public static bool operator ==(in G2Affine a, in G2Affine b) + { + // The only cases in which two points are equal are + // 1. infinity is set on both + // 2. infinity is not set on both, and their coordinates are equal + + return (a.Infinity & b.Infinity) | (!a.Infinity & !b.Infinity & a.X == b.X & a.Y == b.Y); + } + + public static bool operator !=(in G2Affine a, in G2Affine b) + { + return !(a == b); + } + + public override bool Equals([NotNullWhen(true)] object? obj) + { + if (obj is not G2Affine other) return false; + return this == other; + } + + public bool Equals(G2Affine other) + { + return this == other; + } + + public override int GetHashCode() + { + if (Infinity) return Infinity.GetHashCode(); + return X.GetHashCode() ^ Y.GetHashCode(); + } + + public static G2Affine operator -(in G2Affine a) + { + return new G2Affine( + in a.X, + ConditionalSelect(-a.Y, in Fp2.One, a.Infinity), + a.Infinity + ); + } + + public static G2Projective operator *(in G2Affine a, in Scalar b) + { + return new G2Projective(a) * b.ToArray(); + } + + public byte[] ToCompressed() + { + // Strictly speaking, self.x is zero already when self.infinity is true, but + // to guard against implementation mistakes we do not assume this. + var x = ConditionalSelect(in X, in Fp2.Zero, Infinity); + + var res = new byte[96]; + + x.C1.TryWrite(res.AsSpan(0..48)); + x.C0.TryWrite(res.AsSpan(48..96)); + + // This point is in compressed form, so we set the most significant bit. + res[0] |= 0x80; + + // Is this point at infinity? If so, set the second-most significant bit. + res[0] |= ConditionalSelect((byte)0, (byte)0x40, Infinity); + + // Is the y-coordinate the lexicographically largest of the two associated with the + // x-coordinate? If so, set the third-most significant bit so long as this is not + // the point at infinity. + res[0] |= ConditionalSelect((byte)0, (byte)0x20, !Infinity & Y.LexicographicallyLargest()); + + return res; + } + + public byte[] ToUncompressed() + { + var res = new byte[192]; + + var x = ConditionalSelect(in X, in Fp2.Zero, Infinity); + var y = ConditionalSelect(in Y, in Fp2.Zero, Infinity); + + x.C1.TryWrite(res.AsSpan(0..48)); + x.C0.TryWrite(res.AsSpan(48..96)); + y.C1.TryWrite(res.AsSpan(96..144)); + y.C0.TryWrite(res.AsSpan(144..192)); + + // Is this point at infinity? If so, set the second-most significant bit. + res[0] |= ConditionalSelect((byte)0, (byte)0x40, Infinity); + + return res; + } + + public static G2Affine FromUncompressed(ReadOnlySpan bytes) + { + return FromBytes(bytes, false, true); + } + + public static G2Affine FromCompressed(ReadOnlySpan bytes) + { + return FromBytes(bytes, true, true); + } + + private static G2Affine FromBytes(ReadOnlySpan bytes, bool compressed, bool check) + { + // Obtain the three flags from the start of the byte sequence + bool compression_flag_set = (bytes[0] & 0x80) != 0; + bool infinity_flag_set = (bytes[0] & 0x40) != 0; + bool sort_flag_set = (bytes[0] & 0x20) != 0; + + // Attempt to obtain the x-coordinate + var tmp = bytes[0..48].ToArray(); + tmp[0] &= 0b0001_1111; + var xc1 = Fp.FromBytes(tmp); + var xc0 = Fp.FromBytes(bytes[48..96]); + var x = new Fp2(in xc0, in xc1); + + if (compressed) + { + // Recover a y-coordinate given x by y = sqrt(x^3 + 4) + var y = ((x.Square() * x) + B).Sqrt(); + y = ConditionalSelect(in y, -y, y.LexicographicallyLargest() ^ sort_flag_set); + G2Affine result = new(in x, in y, infinity_flag_set); + result = ConditionalSelect(in result, in Identity, infinity_flag_set); + if (check) + { + bool _checked = (!infinity_flag_set | (infinity_flag_set & !sort_flag_set & x.IsZero)) + & compression_flag_set; + _checked &= result.IsTorsionFree; + if (!_checked) throw new FormatException(); + } + return result; + } + else + { + // Attempt to obtain the y-coordinate + var yc1 = Fp.FromBytes(bytes[96..144]); + var yc0 = Fp.FromBytes(bytes[144..192]); + var y = new Fp2(in yc0, in yc1); + + // Create a point representing this value + var p = ConditionalSelect(new G2Affine(in x, in y, infinity_flag_set), in Identity, infinity_flag_set); + + if (check) + { + bool _checked = + // If the infinity flag is set, the x and y coordinates should have been zero. + ((!infinity_flag_set) | (infinity_flag_set & x.IsZero & y.IsZero)) & + // The compression flag should not have been set, as this is an uncompressed element + (!compression_flag_set) & + // The sort flag should not have been set, as this is an uncompressed element + (!sort_flag_set); + _checked &= p.IsOnCurve & p.IsTorsionFree; + if (!_checked) throw new FormatException(); + } + + return p; + } + } + + public G2Projective ToCurve() + { + return new(this); + } +} diff --git a/src/Neo.Cryptography.BLS12_381/G2Constants.cs b/src/Neo.Cryptography.BLS12_381/G2Constants.cs new file mode 100644 index 0000000000..045ad43a93 --- /dev/null +++ b/src/Neo.Cryptography.BLS12_381/G2Constants.cs @@ -0,0 +1,112 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// G2Constants.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.Cryptography.BLS12_381; + +static class G2Constants +{ + public static readonly Fp2 GeneratorX = new(Fp.FromRawUnchecked(new ulong[] + { + 0xf5f2_8fa2_0294_0a10, + 0xb3f5_fb26_87b4_961a, + 0xa1a8_93b5_3e2a_e580, + 0x9894_999d_1a3c_aee9, + 0x6f67_b763_1863_366b, + 0x0581_9192_4350_bcd7 + }), Fp.FromRawUnchecked(new ulong[] + { + 0xa5a9_c075_9e23_f606, + 0xaaa0_c59d_bccd_60c3, + 0x3bb1_7e18_e286_7806, + 0x1b1a_b6cc_8541_b367, + 0xc2b6_ed0e_f215_8547, + 0x1192_2a09_7360_edf3 + })); + + public static readonly Fp2 GeneratorY = new(Fp.FromRawUnchecked(new ulong[] + { + 0x4c73_0af8_6049_4c4a, + 0x597c_fa1f_5e36_9c5a, + 0xe7e6_856c_aa0a_635a, + 0xbbef_b5e9_6e0d_495f, + 0x07d3_a975_f0ef_25a2, + 0x0083_fd8e_7e80_dae5 + }), Fp.FromRawUnchecked(new ulong[] + { + 0xadc0_fc92_df64_b05d, + 0x18aa_270a_2b14_61dc, + 0x86ad_ac6a_3be4_eba0, + 0x7949_5c4e_c93d_a33a, + 0xe717_5850_a43c_caed, + 0x0b2b_c2a1_63de_1bf2 + })); + + public static readonly Fp2 B = new(Fp.FromRawUnchecked(new ulong[] + { + 0xaa27_0000_000c_fff3, + 0x53cc_0032_fc34_000a, + 0x478f_e97a_6b0a_807f, + 0xb1d3_7ebe_e6ba_24d7, + 0x8ec9_733b_bf78_ab2f, + 0x09d6_4551_3d83_de7e + }), Fp.FromRawUnchecked(new ulong[] + { + 0xaa27_0000_000c_fff3, + 0x53cc_0032_fc34_000a, + 0x478f_e97a_6b0a_807f, + 0xb1d3_7ebe_e6ba_24d7, + 0x8ec9_733b_bf78_ab2f, + 0x09d6_4551_3d83_de7e + })); + + public static readonly Fp2 B3 = B + B + B; + + // 1 / ((u+1) ^ ((q-1)/3)) + public static readonly Fp2 PsiCoeffX = new(in Fp.Zero, Fp.FromRawUnchecked(new ulong[] + { + 0x890dc9e4867545c3, + 0x2af322533285a5d5, + 0x50880866309b7e2c, + 0xa20d1b8c7e881024, + 0x14e4f04fe2db9068, + 0x14e56d3f1564853a + })); + + // 1 / ((u+1) ^ (p-1)/2) + public static readonly Fp2 PsiCoeffY = new(Fp.FromRawUnchecked(new ulong[] + { + 0x3e2f585da55c9ad1, + 0x4294213d86c18183, + 0x382844c88b623732, + 0x92ad2afd19103e18, + 0x1d794e4fac7cf0b9, + 0x0bd592fc7d825ec8 + }), Fp.FromRawUnchecked(new ulong[] + { + 0x7bcfa7a25aa30fda, + 0xdc17dec12a927e7c, + 0x2f088dd86b4ebef1, + 0xd1ca2087da74d4a7, + 0x2da2596696cebc1d, + 0x0e2b7eedbbfd87d2 + })); + + // 1 / 2 ^ ((q-1)/3) + public static readonly Fp2 Psi2CoeffX = new(Fp.FromRawUnchecked(new ulong[] + { + 0xcd03c9e48671f071, + 0x5dab22461fcda5d2, + 0x587042afd3851b95, + 0x8eb60ebe01bacb9e, + 0x03f97d6e83d050d2, + 0x18f0206554638741 + }), in Fp.Zero); +} diff --git a/src/Neo.Cryptography.BLS12_381/G2Prepared.Adder.cs b/src/Neo.Cryptography.BLS12_381/G2Prepared.Adder.cs new file mode 100644 index 0000000000..c28b8889cb --- /dev/null +++ b/src/Neo.Cryptography.BLS12_381/G2Prepared.Adder.cs @@ -0,0 +1,74 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// G2Prepared.Adder.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.Runtime.CompilerServices; +using static Neo.Cryptography.BLS12_381.MillerLoopUtility; + +namespace Neo.Cryptography.BLS12_381; + +partial class G2Prepared +{ + class Adder : IMillerLoopDriver + { + public G2Projective Curve; + public readonly G2Affine Base; + public readonly List<(Fp2, Fp2, Fp2)> Coeffs; + + public Adder(in G2Affine q) + { + Curve = new G2Projective(in q); + Base = q; + Coeffs = new(68); + } + + object? IMillerLoopDriver.DoublingStep(in object? f) + { + var coeffs = DoublingStep(ref Curve); + Coeffs.Add(coeffs); + return null; + } + + object? IMillerLoopDriver.AdditionStep(in object? f) + { + var coeffs = AdditionStep(ref Curve, in Base); + Coeffs.Add(coeffs); + return null; + } + + #region IMillerLoopDriver + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static object? Square(in object? f) => null; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static object? Conjugate(in object? f) => null; + + public static object? One + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => null; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + object? IMillerLoopDriver.Square(in object? f) => null; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + object? IMillerLoopDriver.Conjugate(in object? f) => null; + + object? IMillerLoopDriver.One + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => null; + } + + #endregion + } +} diff --git a/src/Neo.Cryptography.BLS12_381/G2Prepared.cs b/src/Neo.Cryptography.BLS12_381/G2Prepared.cs new file mode 100644 index 0000000000..38e8bdc902 --- /dev/null +++ b/src/Neo.Cryptography.BLS12_381/G2Prepared.cs @@ -0,0 +1,31 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// G2Prepared.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 static Neo.Cryptography.BLS12_381.ConstantTimeUtility; +using static Neo.Cryptography.BLS12_381.MillerLoopUtility; + +namespace Neo.Cryptography.BLS12_381; + +partial class G2Prepared +{ + public readonly bool Infinity; + public readonly List<(Fp2, Fp2, Fp2)> Coeffs; + + public G2Prepared(in G2Affine q) + { + Infinity = q.IsIdentity; + var q2 = ConditionalSelect(in q, in G2Affine.Generator, Infinity); + var adder = new Adder(q2); + MillerLoop(adder); + Coeffs = adder.Coeffs; + if (Coeffs.Count != 68) throw new InvalidOperationException(); + } +} diff --git a/src/Neo.Cryptography.BLS12_381/G2Projective.cs b/src/Neo.Cryptography.BLS12_381/G2Projective.cs new file mode 100644 index 0000000000..08e0fd4593 --- /dev/null +++ b/src/Neo.Cryptography.BLS12_381/G2Projective.cs @@ -0,0 +1,377 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// G2Projective.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.Buffers.Binary; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; +using System.Security.Cryptography; +using static Neo.Cryptography.BLS12_381.Constants; +using static Neo.Cryptography.BLS12_381.ConstantTimeUtility; +using static Neo.Cryptography.BLS12_381.G2Constants; + +namespace Neo.Cryptography.BLS12_381; + +[StructLayout(LayoutKind.Explicit, Size = Fp2.Size * 3)] +public readonly struct G2Projective : IEquatable +{ + [FieldOffset(0)] + public readonly Fp2 X; + [FieldOffset(Fp2.Size)] + public readonly Fp2 Y; + [FieldOffset(Fp2.Size * 2)] + public readonly Fp2 Z; + + public static readonly G2Projective Identity = new(in Fp2.Zero, in Fp2.One, in Fp2.Zero); + public static readonly G2Projective Generator = new(in GeneratorX, in GeneratorY, in Fp2.One); + + public bool IsIdentity => Z.IsZero; + public bool IsOnCurve => ((Y.Square() * Z) == (X.Square() * X + Z.Square() * Z * B)) | Z.IsZero; // Y^2 Z = X^3 + b Z^3 + + public G2Projective(in Fp2 x, in Fp2 y, in Fp2 z) + { + X = x; + Y = y; + Z = z; + } + + public G2Projective(in G2Affine p) + { + X = p.X; + Y = p.Y; + Z = ConditionalSelect(in Fp2.One, in Fp2.Zero, p.Infinity); + } + + public static bool operator ==(in G2Projective a, in G2Projective b) + { + // Is (xz, yz, z) equal to (x'z', y'z', z') when converted to affine? + + var x1 = a.X * b.Z; + var x2 = b.X * a.Z; + + var y1 = a.Y * b.Z; + var y2 = b.Y * a.Z; + + var self_is_zero = a.Z.IsZero; + var other_is_zero = b.Z.IsZero; + + return (self_is_zero & other_is_zero) // Both point at infinity + | ((!self_is_zero) & (!other_is_zero) & x1 == x2 & y1 == y2); + // Neither point at infinity, coordinates are the same + } + + public static bool operator !=(in G2Projective a, in G2Projective b) + { + return !(a == b); + } + + public override bool Equals([NotNullWhen(true)] object? obj) + { + if (obj is not G2Projective other) return false; + return this == other; + } + + public bool Equals(G2Projective other) + { + return this == other; + } + + public override int GetHashCode() + { + return X.GetHashCode() ^ Y.GetHashCode() ^ Z.GetHashCode(); + } + + public static G2Projective operator -(in G2Projective a) + { + return new(in a.X, -a.Y, in a.Z); + } + + public static G2Projective operator +(in G2Projective a, in G2Projective b) + { + // Algorithm 7, https://eprint.iacr.org/2015/1060.pdf + + var t0 = a.X * b.X; + var t1 = a.Y * b.Y; + var t2 = a.Z * b.Z; + var t3 = a.X + a.Y; + var t4 = b.X + b.Y; + t3 *= t4; + t4 = t0 + t1; + t3 -= t4; + t4 = a.Y + a.Z; + var x3 = b.Y + b.Z; + t4 *= x3; + x3 = t1 + t2; + t4 -= x3; + x3 = a.X + a.Z; + var y3 = b.X + b.Z; + x3 *= y3; + y3 = t0 + t2; + y3 = x3 - y3; + x3 = t0 + t0; + t0 = x3 + t0; + t2 = MulBy3B(t2); + var z3 = t1 + t2; + t1 -= t2; + y3 = MulBy3B(y3); + x3 = t4 * y3; + t2 = t3 * t1; + x3 = t2 - x3; + y3 *= t0; + t1 *= z3; + y3 = t1 + y3; + t0 *= t3; + z3 *= t4; + z3 += t0; + + return new G2Projective(in x3, in y3, in z3); + } + + public static G2Projective operator +(in G2Affine a, in G2Projective b) + { + return b + a; + } + + public static G2Projective operator +(in G2Projective a, in G2Affine b) + { + // Algorithm 8, https://eprint.iacr.org/2015/1060.pdf + + var t0 = a.X * b.X; + var t1 = a.Y * b.Y; + var t3 = b.X + b.Y; + var t4 = a.X + a.Y; + t3 *= t4; + t4 = t0 + t1; + t3 -= t4; + t4 = b.Y * a.Z; + t4 += a.Y; + var y3 = b.X * a.Z; + y3 += a.X; + var x3 = t0 + t0; + t0 = x3 + t0; + var t2 = MulBy3B(a.Z); + var z3 = t1 + t2; + t1 -= t2; + y3 = MulBy3B(y3); + x3 = t4 * y3; + t2 = t3 * t1; + x3 = t2 - x3; + y3 *= t0; + t1 *= z3; + y3 = t1 + y3; + t0 *= t3; + z3 *= t4; + z3 += t0; + + var tmp = new G2Projective(in x3, in y3, in z3); + + return ConditionalSelect(in tmp, in a, b.IsIdentity); + } + + public static G2Projective operator -(in G2Projective a, in G2Projective b) + { + return a + -b; + } + + public static G2Projective operator -(in G2Affine a, in G2Projective b) + { + return a + -b; + } + + public static G2Projective operator -(in G2Projective a, in G2Affine b) + { + return a + -b; + } + + public static G2Projective operator *(in G2Projective a, in Scalar b) + { + return a * b.ToArray(); + } + + public static G2Projective operator *(in G2Projective a, byte[] b) + { + var acc = Identity; + + // This is a simple double-and-add implementation of point + // multiplication, moving from most significant to least + // significant bit of the scalar. + // + // We skip the leading bit because it's always unset for Fq + // elements. + foreach (bool bit in b + .SelectMany(p => Enumerable.Range(0, 8).Select(q => ((p >> q) & 1) == 1)) + .Reverse() + .Skip(1)) + { + acc = acc.Double(); + acc = ConditionalSelect(in acc, acc + a, bit); + } + + return acc; + } + + private static Fp2 MulBy3B(Fp2 x) + { + return x * B3; + } + + public G2Projective Double() + { + // Algorithm 9, https://eprint.iacr.org/2015/1060.pdf + + var t0 = Y.Square(); + var z3 = t0 + t0; + z3 += z3; + z3 += z3; + var t1 = Y * Z; + var t2 = Z.Square(); + t2 = MulBy3B(t2); + var x3 = t2 * z3; + var y3 = t0 + t2; + z3 = t1 * z3; + t1 = t2 + t2; + t2 = t1 + t2; + t0 -= t2; + y3 = t0 * y3; + y3 = x3 + y3; + t1 = X * Y; + x3 = t0 * t1; + x3 += x3; + + var tmp = new G2Projective(in x3, in y3, in z3); + + return ConditionalSelect(in tmp, in Identity, IsIdentity); + } + + internal G2Projective Psi() + { + return new G2Projective( + // x = frobenius(x)/((u+1)^((p-1)/3)) + X.FrobeniusMap() * PsiCoeffX, + // y = frobenius(y)/(u+1)^((p-1)/2) + Y.FrobeniusMap() * PsiCoeffY, + // z = frobenius(z) + Z.FrobeniusMap() + ); + } + + internal G2Projective Psi2() + { + return new G2Projective( + // x = frobenius^2(x)/2^((p-1)/3); note that q^2 is the order of the field. + X * Psi2CoeffX, + // y = -frobenius^2(y); note that q^2 is the order of the field. + -Y, + // z = z + in Z + ); + } + + internal G2Projective MulByX() + { + var xself = Identity; + // NOTE: in BLS12-381 we can just skip the first bit. + var x = BLS_X >> 1; + var acc = this; + while (x != 0) + { + acc = acc.Double(); + if (x % 2 == 1) + { + xself += acc; + } + x >>= 1; + } + // finally, flip the sign + if (BLS_X_IS_NEGATIVE) + { + xself = -xself; + } + return xself; + } + + public G2Projective ClearCofactor() + { + var t1 = MulByX(); // [x] P + var t2 = Psi(); // psi(P) + + return Double().Psi2() // psi^2(2P) + + (t1 + t2).MulByX() // psi^2(2P) + [x^2] P + [x] psi(P) + - t1 // psi^2(2P) + [x^2 - x] P + [x] psi(P) + - t2 // psi^2(2P) + [x^2 - x] P + [x - 1] psi(P) + - this; // psi^2(2P) + [x^2 - x - 1] P + [x - 1] psi(P) + } + + public static void BatchNormalize(ReadOnlySpan p, Span q) + { + int length = p.Length; + if (length != q.Length) + throw new ArgumentException($"{nameof(p)} and {nameof(q)} must have the same length."); + + Span x = stackalloc Fp2[length]; + Fp2 acc = Fp2.One; + for (int i = 0; i < length; i++) + { + // We use the `x` field of `G2Affine` to store the product + // of previous z-coordinates seen. + x[i] = acc; + + // We will end up skipping all identities in p + acc = ConditionalSelect(acc * p[i].Z, in acc, p[i].IsIdentity); + } + + // This is the inverse, as all z-coordinates are nonzero and the ones + // that are not are skipped. + acc = acc.Invert(); + + for (int i = length - 1; i >= 0; i--) + { + bool skip = p[i].IsIdentity; + + // Compute tmp = 1/z + var tmp = x[i] * acc; + + // Cancel out z-coordinate in denominator of `acc` + acc = ConditionalSelect(acc * p[i].Z, in acc, skip); + + // Set the coordinates to the correct value + G2Affine qi = new(p[i].X * tmp, p[i].Y * tmp); + + q[i] = ConditionalSelect(in qi, in G2Affine.Identity, skip); + } + } + + public static G2Projective Random(RandomNumberGenerator rng) + { + Span buffer = stackalloc byte[sizeof(uint)]; + while (true) + { + var x = Fp2.Random(rng); + rng.GetBytes(buffer); + var flip_sign = BinaryPrimitives.ReadUInt32LittleEndian(buffer) % 2 != 0; + + // Obtain the corresponding y-coordinate given x as y = sqrt(x^3 + 4) + var y = ((x.Square() * x) + B).Sqrt(); + + G2Affine p; + try + { + p = new G2Affine(in x, flip_sign ? -y : y); + } + catch + { + continue; + } + + var result = p.ToCurve().ClearCofactor(); + if (!result.IsIdentity) return result; + } + } +} diff --git a/src/Neo.Cryptography.BLS12_381/GlobalSuppressions.cs b/src/Neo.Cryptography.BLS12_381/GlobalSuppressions.cs new file mode 100644 index 0000000000..97ff6376ff --- /dev/null +++ b/src/Neo.Cryptography.BLS12_381/GlobalSuppressions.cs @@ -0,0 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// GlobalSuppressions.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.Diagnostics.CodeAnalysis; + +[assembly: SuppressMessage("Usage", "CA2219")] diff --git a/src/Neo.Cryptography.BLS12_381/Gt.cs b/src/Neo.Cryptography.BLS12_381/Gt.cs new file mode 100644 index 0000000000..e6c33b18d5 --- /dev/null +++ b/src/Neo.Cryptography.BLS12_381/Gt.cs @@ -0,0 +1,135 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Gt.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.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; +using System.Security.Cryptography; +using static Neo.Cryptography.BLS12_381.ConstantTimeUtility; +using static Neo.Cryptography.BLS12_381.GtConstants; + +namespace Neo.Cryptography.BLS12_381; + +public readonly struct Gt : IEquatable +{ + public readonly Fp12 Value; + + public static readonly Gt Identity = new(in Fp12.One); + public static readonly Gt Generator = new(in GeneratorValue); + + public bool IsIdentity => this == Identity; + + public Gt(in Fp12 f) + { + Value = f; + } + + public static Gt FromBytes(ReadOnlySpan data) + { + return new(Fp12.FromBytes(data)); + } + + public static bool operator ==(in Gt a, in Gt b) + { + return a.Value == b.Value; + } + + public static bool operator !=(in Gt a, in Gt b) + { + return !(a == b); + } + + public override bool Equals([NotNullWhen(true)] object? obj) + { + if (obj is not Gt other) return false; + return this == other; + } + + public bool Equals(Gt other) + { + return this == other; + } + + public override int GetHashCode() + { + return Value.GetHashCode(); + } + + public byte[] ToArray() + { + return Value.ToArray(); + } + + public bool TryWrite(Span buffer) + { + return Value.TryWrite(buffer); + } + + public static Gt Random(RandomNumberGenerator rng) + { + while (true) + { + var inner = Fp12.Random(rng); + + // Not all elements of Fp12 are elements of the prime-order multiplicative + // subgroup. We run the random element through final_exponentiation to obtain + // a valid element, which requires that it is non-zero. + if (!inner.IsZero) + { + ref MillerLoopResult result = ref Unsafe.As(ref inner); + return result.FinalExponentiation(); + } + } + } + + public Gt Double() + { + return new(Value.Square()); + } + + public static Gt operator -(in Gt a) + { + // The element is unitary, so we just conjugate. + return new(a.Value.Conjugate()); + } + + public static Gt operator +(in Gt a, in Gt b) + { + return new(a.Value * b.Value); + } + + public static Gt operator -(in Gt a, in Gt b) + { + return a + -b; + } + + public static Gt operator *(in Gt a, in Scalar b) + { + var acc = Identity; + + // This is a simple double-and-add implementation of group element + // multiplication, moving from most significant to least + // significant bit of the scalar. + // + // We skip the leading bit because it's always unset for Fq + // elements. + foreach (bool bit in b + .ToArray() + .SelectMany(p => Enumerable.Range(0, 8).Select(q => ((p >> q) & 1) == 1)) + .Reverse() + .Skip(1)) + { + acc = acc.Double(); + acc = ConditionalSelect(in acc, acc + a, bit); + } + + return acc; + } +} diff --git a/src/Neo.Cryptography.BLS12_381/GtConstants.cs b/src/Neo.Cryptography.BLS12_381/GtConstants.cs new file mode 100644 index 0000000000..ca76083fe8 --- /dev/null +++ b/src/Neo.Cryptography.BLS12_381/GtConstants.cs @@ -0,0 +1,115 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// GtConstants.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.Cryptography.BLS12_381; + +static class GtConstants +{ + // pairing(&G1Affine.generator(), &G2Affine.generator()) + public static readonly Fp12 GeneratorValue = new(new Fp6(new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0x1972_e433_a01f_85c5, + 0x97d3_2b76_fd77_2538, + 0xc8ce_546f_c96b_cdf9, + 0xcef6_3e73_66d4_0614, + 0xa611_3427_8184_3780, + 0x13f3_448a_3fc6_d825 + }), Fp.FromRawUnchecked(new ulong[] + { + 0xd263_31b0_2e9d_6995, + 0x9d68_a482_f779_7e7d, + 0x9c9b_2924_8d39_ea92, + 0xf480_1ca2_e131_07aa, + 0xa16c_0732_bdbc_b066, + 0x083c_a4af_ba36_0478 + })), new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0x59e2_61db_0916_b641, + 0x2716_b6f4_b23e_960d, + 0xc8e5_5b10_a0bd_9c45, + 0x0bdb_0bd9_9c4d_eda8, + 0x8cf8_9ebf_57fd_aac5, + 0x12d6_b792_9e77_7a5e + }), Fp.FromRawUnchecked(new ulong[] + { + 0x5fc8_5188_b0e1_5f35, + 0x34a0_6e3a_8f09_6365, + 0xdb31_26a6_e02a_d62c, + 0xfc6f_5aa9_7d9a_990b, + 0xa12f_55f5_eb89_c210, + 0x1723_703a_926f_8889 + })), new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0x9358_8f29_7182_8778, + 0x43f6_5b86_11ab_7585, + 0x3183_aaf5_ec27_9fdf, + 0xfa73_d7e1_8ac9_9df6, + 0x64e1_76a6_a64c_99b0, + 0x179f_a78c_5838_8f1f + }), Fp.FromRawUnchecked(new ulong[] + { + 0x672a_0a11_ca2a_ef12, + 0x0d11_b9b5_2aa3_f16b, + 0xa444_12d0_699d_056e, + 0xc01d_0177_221a_5ba5, + 0x66e0_cede_6c73_5529, + 0x05f5_a71e_9fdd_c339 + }))), new Fp6(new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0xd30a_88a1_b062_c679, + 0x5ac5_6a5d_35fc_8304, + 0xd0c8_34a6_a81f_290d, + 0xcd54_30c2_da37_07c7, + 0xf0c2_7ff7_8050_0af0, + 0x0924_5da6_e2d7_2eae + }), + Fp.FromRawUnchecked(new ulong[] + { + 0x9f2e_0676_791b_5156, + 0xe2d1_c823_4918_fe13, + 0x4c9e_459f_3c56_1bf4, + 0xa3e8_5e53_b9d3_e3c1, + 0x820a_121e_21a7_0020, + 0x15af_6183_41c5_9acc + })), new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0x7c95_658c_2499_3ab1, + 0x73eb_3872_1ca8_86b9, + 0x5256_d749_4774_34bc, + 0x8ba4_1902_ea50_4a8b, + 0x04a3_d3f8_0c86_ce6d, + 0x18a6_4a87_fb68_6eaa + }), Fp.FromRawUnchecked(new ulong[] + { + 0xbb83_e71b_b920_cf26, + 0x2a52_77ac_92a7_3945, + 0xfc0e_e59f_94f0_46a0, + 0x7158_cdf3_7860_58f7, + 0x7cc1_061b_82f9_45f6, + 0x03f8_47aa_9fdb_e567 + })), new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0x8078_dba5_6134_e657, + 0x1cd7_ec9a_4399_8a6e, + 0xb1aa_599a_1a99_3766, + 0xc9a0_f62f_0842_ee44, + 0x8e15_9be3_b605_dffa, + 0x0c86_ba0d_4af1_3fc2 + }), Fp.FromRawUnchecked(new ulong[] + { + 0xe80f_f2a0_6a52_ffb1, + 0x7694_ca48_721a_906c, + 0x7583_183e_03b0_8514, + 0xf567_afdd_40ce_e4e2, + 0x9a6d_96d2_e526_a5fc, + 0x197e_9f49_861f_2242 + })))); +} diff --git a/src/Neo.Cryptography.BLS12_381/IMillerLoopDriver.cs b/src/Neo.Cryptography.BLS12_381/IMillerLoopDriver.cs new file mode 100644 index 0000000000..0d0d3ac9df --- /dev/null +++ b/src/Neo.Cryptography.BLS12_381/IMillerLoopDriver.cs @@ -0,0 +1,21 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// IMillerLoopDriver.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.Cryptography.BLS12_381; + +interface IMillerLoopDriver +{ + public T DoublingStep(in T f); + public T AdditionStep(in T f); + public T Square(in T f); + public T Conjugate(in T f); + public T One { get; } +} diff --git a/src/Neo.Cryptography.BLS12_381/INumber.cs b/src/Neo.Cryptography.BLS12_381/INumber.cs new file mode 100644 index 0000000000..f328a77c2e --- /dev/null +++ b/src/Neo.Cryptography.BLS12_381/INumber.cs @@ -0,0 +1,70 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// INumber.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.Runtime.CompilerServices; + +namespace Neo.Cryptography.BLS12_381; + +interface INumber where T : unmanaged, INumber +{ + //static abstract int Size { get; } + //static abstract ref readonly T Zero { get; } + //static abstract ref readonly T One { get; } + + //static abstract T operator -(in T x); + //static abstract T operator +(in T x, in T y); + //static abstract T operator -(in T x, in T y); + //static abstract T operator *(in T x, in T y); + + T Negate(); + T Sum(in T value); + T Subtract(in T value); + T Multiply(in T value); + + abstract T Square(); +} + +static class NumberExtensions +{ + private static T PowVartime(T one, T self, ulong[] by) where T : unmanaged, INumber + { + // Although this is labeled "vartime", it is only + // variable time with respect to the exponent. + var res = one; + for (int j = by.Length - 1; j >= 0; j--) + { + for (int i = 63; i >= 0; i--) + { + res = res.Square(); + if (((by[j] >> i) & 1) == 1) + { + res = res.Multiply(self); + } + } + } + return res; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Fp PowVartime(this Fp self, ulong[] by) => PowVartime(Fp.One, self, by); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Fp2 PowVartime(this Fp2 self, ulong[] by) => PowVartime(Fp2.One, self, by); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Fp6 PowVartime(this Fp6 self, ulong[] by) => PowVartime(Fp6.One, self, by); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Fp12 PowVartime(this Fp12 self, ulong[] by) => PowVartime(Fp12.One, self, by); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Scalar PowVartime(this Scalar self, ulong[] by) => PowVartime(Scalar.One, self, by); +} diff --git a/src/Neo.Cryptography.BLS12_381/MathUtility.cs b/src/Neo.Cryptography.BLS12_381/MathUtility.cs new file mode 100644 index 0000000000..3721b482cc --- /dev/null +++ b/src/Neo.Cryptography.BLS12_381/MathUtility.cs @@ -0,0 +1,67 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// MathUtility.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.Cryptography.BLS12_381; + +static class MathUtility +{ + public static (ulong result, ulong carry) Adc(ulong a, ulong b, ulong carry) + { + ulong result = unchecked(a + b + carry); + carry = ((a & b) | ((a | b) & (~result))) >> 63; + return (result, carry); + } + + public static (ulong result, ulong borrow) Sbb(ulong a, ulong b, ulong borrow) + { + ulong result = unchecked(a - b - borrow); + borrow = (((~a) & b) | (~(a ^ b)) & result) >> 63; + return (result, borrow); + } + + public static (ulong low, ulong high) Mac(ulong z, ulong x, ulong y, ulong carry) + { + ulong high = BigMul(x, y, out ulong low); + (low, carry) = Adc(low, carry, 0); + (high, _) = Adc(high, 0, carry); + (low, carry) = Adc(low, z, 0); + (high, _) = Adc(high, 0, carry); + return (low, high); + } + + /// Produces the full product of two unsigned 64-bit numbers. + /// The first number to multiply. + /// The second number to multiply. + /// The low 64-bit of the product of the specified numbers. + /// The high 64-bit of the product of the specified numbers. + public static ulong BigMul(ulong a, ulong b, out ulong low) + { + // Adaptation of algorithm for multiplication + // of 32-bit unsigned integers described + // in Hacker's Delight by Henry S. Warren, Jr. (ISBN 0-201-91465-4), Chapter 8 + // Basically, it's an optimized version of FOIL method applied to + // low and high dwords of each operand + + // Use 32-bit uints to optimize the fallback for 32-bit platforms. + uint al = (uint)a; + uint ah = (uint)(a >> 32); + uint bl = (uint)b; + uint bh = (uint)(b >> 32); + + ulong mull = ((ulong)al) * bl; + ulong t = ((ulong)ah) * bl + (mull >> 32); + ulong tl = ((ulong)al) * bh + (uint)t; + + low = tl << 32 | (uint)mull; + + return ((ulong)ah) * bh + (t >> 32) + (tl >> 32); + } +} diff --git a/src/Neo.Cryptography.BLS12_381/MillerLoopResult.cs b/src/Neo.Cryptography.BLS12_381/MillerLoopResult.cs new file mode 100644 index 0000000000..7f9bdfbb60 --- /dev/null +++ b/src/Neo.Cryptography.BLS12_381/MillerLoopResult.cs @@ -0,0 +1,143 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// MillerLoopResult.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.Runtime.InteropServices; +using static Neo.Cryptography.BLS12_381.Constants; + +namespace Neo.Cryptography.BLS12_381; + +[StructLayout(LayoutKind.Explicit, Size = Fp12.Size)] +readonly struct MillerLoopResult +{ + [FieldOffset(0)] + private readonly Fp12 v; + + public MillerLoopResult(in Fp12 v) + { + this.v = v; + } + + public Gt FinalExponentiation() + { + static (Fp2, Fp2) Fp4Square(in Fp2 a, in Fp2 b) + { + var t0 = a.Square(); + var t1 = b.Square(); + var t2 = t1.MulByNonresidue(); + var c0 = t2 + t0; + t2 = a + b; + t2 = t2.Square(); + t2 -= t0; + var c1 = t2 - t1; + + return (c0, c1); + } + + static Fp12 CyclotomicSquare(in Fp12 f) + { + var z0 = f.C0.C0; + var z4 = f.C0.C1; + var z3 = f.C0.C2; + var z2 = f.C1.C0; + var z1 = f.C1.C1; + var z5 = f.C1.C2; + + var (t0, t1) = Fp4Square(in z0, in z1); + + // For A + z0 = t0 - z0; + z0 = z0 + z0 + t0; + + z1 = t1 + z1; + z1 = z1 + z1 + t1; + + (t0, t1) = Fp4Square(in z2, in z3); + var (t2, t3) = Fp4Square(in z4, in z5); + + // For C + z4 = t0 - z4; + z4 = z4 + z4 + t0; + + z5 = t1 + z5; + z5 = z5 + z5 + t1; + + // For B + t0 = t3.MulByNonresidue(); + z2 = t0 + z2; + z2 = z2 + z2 + t0; + + z3 = t2 - z3; + z3 = z3 + z3 + t2; + + return new Fp12(new Fp6(in z0, in z4, in z3), new Fp6(in z2, in z1, in z5)); + } + + static Fp12 CycolotomicExp(in Fp12 f) + { + var x = BLS_X; + var tmp = Fp12.One; + var found_one = false; + foreach (bool i in Enumerable.Range(0, 64).Select(b => ((x >> b) & 1) == 1).Reverse()) + { + if (found_one) + tmp = CyclotomicSquare(tmp); + else + found_one = i; + + if (i) + tmp *= f; + } + + return tmp.Conjugate(); + } + + var f = v; + var t0 = f + .FrobeniusMap() + .FrobeniusMap() + .FrobeniusMap() + .FrobeniusMap() + .FrobeniusMap() + .FrobeniusMap(); + var t1 = f.Invert(); + var t2 = t0 * t1; + t1 = t2; + t2 = t2.FrobeniusMap().FrobeniusMap(); + t2 *= t1; + t1 = CyclotomicSquare(t2).Conjugate(); + var t3 = CycolotomicExp(t2); + var t4 = CyclotomicSquare(t3); + var t5 = t1 * t3; + t1 = CycolotomicExp(t5); + t0 = CycolotomicExp(t1); + var t6 = CycolotomicExp(t0); + t6 *= t4; + t4 = CycolotomicExp(t6); + t5 = t5.Conjugate(); + t4 *= t5 * t2; + t5 = t2.Conjugate(); + t1 *= t2; + t1 = t1.FrobeniusMap().FrobeniusMap().FrobeniusMap(); + t6 *= t5; + t6 = t6.FrobeniusMap(); + t3 *= t0; + t3 = t3.FrobeniusMap().FrobeniusMap(); + t3 *= t1; + t3 *= t6; + f = t3 * t4; + return new Gt(f); + } + + public static MillerLoopResult operator +(in MillerLoopResult a, in MillerLoopResult b) + { + return new(a.v * b.v); + } +} diff --git a/src/Neo.Cryptography.BLS12_381/MillerLoopUtility.cs b/src/Neo.Cryptography.BLS12_381/MillerLoopUtility.cs new file mode 100644 index 0000000000..03187b7944 --- /dev/null +++ b/src/Neo.Cryptography.BLS12_381/MillerLoopUtility.cs @@ -0,0 +1,120 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// MillerLoopUtility.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 static Neo.Cryptography.BLS12_381.Constants; + +namespace Neo.Cryptography.BLS12_381; + +static class MillerLoopUtility +{ + public static T MillerLoop(D driver) where D : IMillerLoopDriver + { + var f = driver.One; + + var found_one = false; + foreach (var i in Enumerable.Range(0, 64).Reverse().Select(b => ((BLS_X >> 1 >> b) & 1) == 1)) + { + if (!found_one) + { + found_one = i; + continue; + } + + f = driver.DoublingStep(f); + + if (i) + f = driver.AdditionStep(f); + + f = driver.Square(f); + } + + f = driver.DoublingStep(f); + + if (BLS_X_IS_NEGATIVE) + f = driver.Conjugate(f); + + return f; + } + + public static Fp12 Ell(in Fp12 f, in (Fp2 X, Fp2 Y, Fp2 Z) coeffs, in G1Affine p) + { + var c0 = new Fp2(coeffs.X.C0 * p.Y, coeffs.X.C1 * p.Y); + var c1 = new Fp2(coeffs.Y.C0 * p.X, coeffs.Y.C1 * p.X); + return f.MulBy_014(in coeffs.Z, in c1, in c0); + } + + public static (Fp2, Fp2, Fp2) DoublingStep(ref G2Projective r) + { + // Adaptation of Algorithm 26, https://eprint.iacr.org/2010/354.pdf + var tmp0 = r.X.Square(); + var tmp1 = r.Y.Square(); + var tmp2 = tmp1.Square(); + var tmp3 = (tmp1 + r.X).Square() - tmp0 - tmp2; + tmp3 += tmp3; + var tmp4 = tmp0 + tmp0 + tmp0; + var tmp6 = r.X + tmp4; + var tmp5 = tmp4.Square(); + var zsquared = r.Z.Square(); + var x = tmp5 - tmp3 - tmp3; + var z = (r.Z + r.Y).Square() - tmp1 - zsquared; + var y = (tmp3 - x) * tmp4; + tmp2 += tmp2; + tmp2 += tmp2; + tmp2 += tmp2; + y -= tmp2; + r = new(in x, in y, in z); + tmp3 = tmp4 * zsquared; + tmp3 += tmp3; + tmp3 = -tmp3; + tmp6 = tmp6.Square() - tmp0 - tmp5; + tmp1 += tmp1; + tmp1 += tmp1; + tmp6 -= tmp1; + tmp0 = r.Z * zsquared; + tmp0 += tmp0; + + return (tmp0, tmp3, tmp6); + } + + public static (Fp2, Fp2, Fp2) AdditionStep(ref G2Projective r, in G2Affine q) + { + // Adaptation of Algorithm 27, https://eprint.iacr.org/2010/354.pdf + var zsquared = r.Z.Square(); + var ysquared = q.Y.Square(); + var t0 = zsquared * q.X; + var t1 = ((q.Y + r.Z).Square() - ysquared - zsquared) * zsquared; + var t2 = t0 - r.X; + var t3 = t2.Square(); + var t4 = t3 + t3; + t4 += t4; + var t5 = t4 * t2; + var t6 = t1 - r.Y - r.Y; + var t9 = t6 * q.X; + var t7 = t4 * r.X; + var x = t6.Square() - t5 - t7 - t7; + var z = (r.Z + t2).Square() - zsquared - t3; + var t10 = q.Y + z; + var t8 = (t7 - x) * t6; + t0 = r.Y * t5; + t0 += t0; + var y = t8 - t0; + r = new(in x, in y, in z); + t10 = t10.Square() - ysquared; + var ztsquared = r.Z.Square(); + t10 -= ztsquared; + t9 = t9 + t9 - t10; + t10 = r.Z + r.Z; + t6 = -t6; + t1 = t6 + t6; + + return (t10, t1, t9); + } +} diff --git a/src/Neo.Cryptography.BLS12_381/Neo.Cryptography.BLS12_381.csproj b/src/Neo.Cryptography.BLS12_381/Neo.Cryptography.BLS12_381.csproj new file mode 100644 index 0000000000..d5861b2e45 --- /dev/null +++ b/src/Neo.Cryptography.BLS12_381/Neo.Cryptography.BLS12_381.csproj @@ -0,0 +1,15 @@ + + + + 0.3.0 + netstandard2.1;net7.0 + enable + enable + 11.0 + + + + + + + diff --git a/src/Neo.Cryptography.BLS12_381/Properties/AssemblyInfo.cs b/src/Neo.Cryptography.BLS12_381/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..998a53f179 --- /dev/null +++ b/src/Neo.Cryptography.BLS12_381/Properties/AssemblyInfo.cs @@ -0,0 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// AssemblyInfo.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.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("Neo.Cryptography.BLS12_381.Tests")] diff --git a/src/Neo.Cryptography.BLS12_381/Scalar.cs b/src/Neo.Cryptography.BLS12_381/Scalar.cs new file mode 100644 index 0000000000..ef40e9b817 --- /dev/null +++ b/src/Neo.Cryptography.BLS12_381/Scalar.cs @@ -0,0 +1,513 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Scalar.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.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Security.Cryptography; +using System.Text; +using static Neo.Cryptography.BLS12_381.ConstantTimeUtility; +using static Neo.Cryptography.BLS12_381.MathUtility; +using static Neo.Cryptography.BLS12_381.ScalarConstants; + +namespace Neo.Cryptography.BLS12_381; + +[StructLayout(LayoutKind.Explicit, Size = Size)] +public readonly struct Scalar : IEquatable, INumber +{ + public const int Size = 32; + public const int SizeL = Size / sizeof(ulong); + public static readonly Scalar Default = new(); + + public static ref readonly Scalar Zero => ref Default; + public static ref readonly Scalar One => ref R; + + public bool IsZero => this == Zero; + + internal Scalar(ulong[] values) + { + if (values.Length != SizeL) + throw new FormatException($"The argument `{nameof(values)}` must contain {SizeL} entries."); + + // This internal method is only used by the constants classes. + // The data must be in the correct format. + // So, there is no need to do any additional checks. + this = Unsafe.As(ref MemoryMarshal.GetReference(MemoryMarshal.Cast(values))); + } + + public Scalar(ulong value) + { + Span data = stackalloc ulong[SizeL]; + data[0] = value; + this = FromRaw(data); + } + + public Scalar(RandomNumberGenerator rng) + { + Span buffer = stackalloc byte[Size * 2]; + rng.GetBytes(buffer); + this = FromBytesWide(buffer); + } + + public static Scalar FromBytes(ReadOnlySpan data) + { + if (data.Length != Size) + throw new FormatException($"The argument `{nameof(data)}` must contain {Size} bytes."); + + ref readonly Scalar ref_ = ref Unsafe.As(ref MemoryMarshal.GetReference(data)); + + try + { + return ref_ * R2; + } + finally + { + ReadOnlySpan u64 = MemoryMarshal.Cast(data); + ulong borrow = 0; + (_, borrow) = Sbb(u64[0], MODULUS_LIMBS_64[0], borrow); + (_, borrow) = Sbb(u64[1], MODULUS_LIMBS_64[1], borrow); + (_, borrow) = Sbb(u64[2], MODULUS_LIMBS_64[2], borrow); + (_, borrow) = Sbb(u64[3], MODULUS_LIMBS_64[3], borrow); + if (borrow == 0) + { + // If the element is smaller than MODULUS then the subtraction will underflow. + // Otherwise, throws. + // Why not throw before return? + // Because we want to run the method in a constant time. + throw new FormatException(); + } + } + } + + public static Scalar FromBytesWide(ReadOnlySpan data) + { + if (data.Length != Size * 2) + throw new FormatException($"The argument `{nameof(data)}` must contain {Size * 2} bytes."); + + ReadOnlySpan d = MemoryMarshal.Cast(data); + return d[0] * R2 + d[1] * R3; + } + + public static Scalar FromRaw(ReadOnlySpan data) + { + if (data.Length != SizeL) + throw new FormatException($"The argument `{nameof(data)}` must contain {SizeL} entries."); + + ReadOnlySpan span = MemoryMarshal.Cast(data); + return span[0] * R2; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private ReadOnlySpan GetSpan() + { + return MemoryMarshal.AsBytes(MemoryMarshal.CreateReadOnlySpan(ref Unsafe.AsRef(in this), 1)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private Span GetSpanU64() + { + return MemoryMarshal.Cast(MemoryMarshal.CreateSpan(ref Unsafe.AsRef(in this), 1)); + } + + public override string ToString() + { + byte[] bytes = ToArray(); + StringBuilder sb = new(); + sb.Append("0x"); + for (int i = bytes.Length - 1; i >= 0; i--) + sb.AppendFormat("{0:x2}", bytes[i]); + return sb.ToString(); + } + + public static bool operator ==(in Scalar a, in Scalar b) + { + return ConstantTimeEq(in a, in b); + } + + public static bool operator !=(in Scalar a, in Scalar b) + { + return !(a == b); + } + + public override bool Equals([NotNullWhen(true)] object? obj) + { + if (obj is not Scalar other) return false; + return this == other; + } + + public bool Equals(Scalar other) + { + return this == other; + } + + public override int GetHashCode() + { + return base.GetHashCode(); + } + + public Scalar Double() + { + return this + this; + } + + public byte[] ToArray() + { + ReadOnlySpan self = GetSpanU64(); + + // Turn into canonical form by computing + // (a.R) / R = a + Scalar result = MontgomeryReduce(self[0], self[1], self[2], self[3], 0, 0, 0, 0); + return result.GetSpan().ToArray(); + } + + public Scalar Square() + { + ReadOnlySpan self = GetSpanU64(); + ulong r0, r1, r2, r3, r4, r5, r6, r7; + ulong carry; + + (r1, carry) = Mac(0, self[0], self[1], 0); + (r2, carry) = Mac(0, self[0], self[2], carry); + (r3, r4) = Mac(0, self[0], self[3], carry); + + (r3, carry) = Mac(r3, self[1], self[2], 0); + (r4, r5) = Mac(r4, self[1], self[3], carry); + + (r5, r6) = Mac(r5, self[2], self[3], 0); + + r7 = r6 >> 63; + r6 = (r6 << 1) | (r5 >> 63); + r5 = (r5 << 1) | (r4 >> 63); + r4 = (r4 << 1) | (r3 >> 63); + r3 = (r3 << 1) | (r2 >> 63); + r2 = (r2 << 1) | (r1 >> 63); + r1 <<= 1; + + (r0, carry) = Mac(0, self[0], self[0], 0); + (r1, carry) = Adc(r1, carry, 0); + (r2, carry) = Mac(r2, self[1], self[1], carry); + (r3, carry) = Adc(r3, carry, 0); + (r4, carry) = Mac(r4, self[2], self[2], carry); + (r5, carry) = Adc(r5, carry, 0); + (r6, carry) = Mac(r6, self[3], self[3], carry); + (r7, _) = Adc(r7, carry, 0); + + return MontgomeryReduce(r0, r1, r2, r3, r4, r5, r6, r7); + } + + public Scalar Sqrt() + { + // Tonelli-Shank's algorithm for q mod 16 = 1 + // https://eprint.iacr.org/2012/685.pdf (page 12, algorithm 5) + + // w = self^((t - 1) // 2) + // = self^6104339283789297388802252303364915521546564123189034618274734669823 + var w = this.PowVartime(new ulong[] + { + 0x7fff_2dff_7fff_ffff, + 0x04d0_ec02_a9de_d201, + 0x94ce_bea4_199c_ec04, + 0x0000_0000_39f6_d3a9 + }); + + var v = S; + var x = this * w; + var b = x * w; + + // Initialize z as the 2^S root of unity. + var z = ROOT_OF_UNITY; + + for (uint max_v = S; max_v >= 1; max_v--) + { + uint k = 1; + var tmp = b.Square(); + var j_less_than_v = true; + + for (uint j = 2; j < max_v; j++) + { + var tmp_is_one = tmp == One; + var squared = ConditionalSelect(in tmp, in z, tmp_is_one).Square(); + tmp = ConditionalSelect(in squared, in tmp, tmp_is_one); + var new_z = ConditionalSelect(in z, in squared, tmp_is_one); + j_less_than_v &= j != v; + k = ConditionalSelect(j, k, tmp_is_one); + z = ConditionalSelect(in z, in new_z, j_less_than_v); + } + + var result = x * z; + x = ConditionalSelect(in result, in x, b == One); + z = z.Square(); + b *= z; + v = k; + } + + if (x * x != this) throw new ArithmeticException(); + return x; + } + + public Scalar Pow(ulong[] by) + { + if (by.Length != SizeL) + throw new ArgumentException($"The length of the parameter `{nameof(by)}` must be {SizeL}."); + + var res = One; + for (int j = by.Length - 1; j >= 0; j--) + { + for (int i = 63; i >= 0; i--) + { + res = res.Square(); + var tmp = res; + tmp *= this; + res.ConditionalAssign(in tmp, ((by[j] >> i) & 1) == 1); + } + } + return res; + } + + public Scalar Invert() + { + static void SquareAssignMulti(ref Scalar n, int num_times) + { + for (int i = 0; i < num_times; i++) + { + n = n.Square(); + } + } + + var t0 = Square(); + var t1 = t0 * this; + var t16 = t0.Square(); + var t6 = t16.Square(); + var t5 = t6 * t0; + t0 = t6 * t16; + var t12 = t5 * t16; + var t2 = t6.Square(); + var t7 = t5 * t6; + var t15 = t0 * t5; + var t17 = t12.Square(); + t1 *= t17; + var t3 = t7 * t2; + var t8 = t1 * t17; + var t4 = t8 * t2; + var t9 = t8 * t7; + t7 = t4 * t5; + var t11 = t4 * t17; + t5 = t9 * t17; + var t14 = t7 * t15; + var t13 = t11 * t12; + t12 = t11 * t17; + t15 *= t12; + t16 *= t15; + t3 *= t16; + t17 *= t3; + t0 *= t17; + t6 *= t0; + t2 *= t6; + SquareAssignMulti(ref t0, 8); + t0 *= t17; + SquareAssignMulti(ref t0, 9); + t0 *= t16; + SquareAssignMulti(ref t0, 9); + t0 *= t15; + SquareAssignMulti(ref t0, 9); + t0 *= t15; + SquareAssignMulti(ref t0, 7); + t0 *= t14; + SquareAssignMulti(ref t0, 7); + t0 *= t13; + SquareAssignMulti(ref t0, 10); + t0 *= t12; + SquareAssignMulti(ref t0, 9); + t0 *= t11; + SquareAssignMulti(ref t0, 8); + t0 *= t8; + SquareAssignMulti(ref t0, 8); + t0 *= this; + SquareAssignMulti(ref t0, 14); + t0 *= t9; + SquareAssignMulti(ref t0, 10); + t0 *= t8; + SquareAssignMulti(ref t0, 15); + t0 *= t7; + SquareAssignMulti(ref t0, 10); + t0 *= t6; + SquareAssignMulti(ref t0, 8); + t0 *= t5; + SquareAssignMulti(ref t0, 16); + t0 *= t3; + SquareAssignMulti(ref t0, 8); + t0 *= t2; + SquareAssignMulti(ref t0, 7); + t0 *= t4; + SquareAssignMulti(ref t0, 9); + t0 *= t2; + SquareAssignMulti(ref t0, 8); + t0 *= t3; + SquareAssignMulti(ref t0, 8); + t0 *= t2; + SquareAssignMulti(ref t0, 8); + t0 *= t2; + SquareAssignMulti(ref t0, 8); + t0 *= t2; + SquareAssignMulti(ref t0, 8); + t0 *= t3; + SquareAssignMulti(ref t0, 8); + t0 *= t2; + SquareAssignMulti(ref t0, 8); + t0 *= t2; + SquareAssignMulti(ref t0, 5); + t0 *= t1; + SquareAssignMulti(ref t0, 5); + t0 *= t1; + + if (this == Zero) throw new DivideByZeroException(); + return t0; + } + + private static Scalar MontgomeryReduce(ulong r0, ulong r1, ulong r2, ulong r3, ulong r4, ulong r5, ulong r6, ulong r7) + { + // The Montgomery reduction here is based on Algorithm 14.32 in + // Handbook of Applied Cryptography + // . + + ulong carry, carry2; + + var k = unchecked(r0 * INV); + (_, carry) = Mac(r0, k, MODULUS_LIMBS_64[0], 0); + (r1, carry) = Mac(r1, k, MODULUS_LIMBS_64[1], carry); + (r2, carry) = Mac(r2, k, MODULUS_LIMBS_64[2], carry); + (r3, carry) = Mac(r3, k, MODULUS_LIMBS_64[3], carry); + (r4, carry2) = Adc(r4, 0, carry); + + k = unchecked(r1 * INV); + (_, carry) = Mac(r1, k, MODULUS_LIMBS_64[0], 0); + (r2, carry) = Mac(r2, k, MODULUS_LIMBS_64[1], carry); + (r3, carry) = Mac(r3, k, MODULUS_LIMBS_64[2], carry); + (r4, carry) = Mac(r4, k, MODULUS_LIMBS_64[3], carry); + (r5, carry2) = Adc(r5, carry2, carry); + + k = unchecked(r2 * INV); + (_, carry) = Mac(r2, k, MODULUS_LIMBS_64[0], 0); + (r3, carry) = Mac(r3, k, MODULUS_LIMBS_64[1], carry); + (r4, carry) = Mac(r4, k, MODULUS_LIMBS_64[2], carry); + (r5, carry) = Mac(r5, k, MODULUS_LIMBS_64[3], carry); + (r6, carry2) = Adc(r6, carry2, carry); + + k = unchecked(r3 * INV); + (_, carry) = Mac(r3, k, MODULUS_LIMBS_64[0], 0); + (r4, carry) = Mac(r4, k, MODULUS_LIMBS_64[1], carry); + (r5, carry) = Mac(r5, k, MODULUS_LIMBS_64[2], carry); + (r6, carry) = Mac(r6, k, MODULUS_LIMBS_64[3], carry); + (r7, _) = Adc(r7, carry2, carry); + + // Result may be within MODULUS of the correct value + ReadOnlySpan tmp = stackalloc[] { r4, r5, r6, r7 }; + return MemoryMarshal.Cast(tmp)[0] - MODULUS; + } + + public static Scalar operator *(in Scalar a, in Scalar b) + { + ReadOnlySpan self = a.GetSpanU64(), rhs = b.GetSpanU64(); + ulong r0, r1, r2, r3, r4, r5, r6, r7; + ulong carry; + + (r0, carry) = Mac(0, self[0], rhs[0], 0); + (r1, carry) = Mac(0, self[0], rhs[1], carry); + (r2, carry) = Mac(0, self[0], rhs[2], carry); + (r3, r4) = Mac(0, self[0], rhs[3], carry); + + (r1, carry) = Mac(r1, self[1], rhs[0], 0); + (r2, carry) = Mac(r2, self[1], rhs[1], carry); + (r3, carry) = Mac(r3, self[1], rhs[2], carry); + (r4, r5) = Mac(r4, self[1], rhs[3], carry); + + (r2, carry) = Mac(r2, self[2], rhs[0], 0); + (r3, carry) = Mac(r3, self[2], rhs[1], carry); + (r4, carry) = Mac(r4, self[2], rhs[2], carry); + (r5, r6) = Mac(r5, self[2], rhs[3], carry); + + (r3, carry) = Mac(r3, self[3], rhs[0], 0); + (r4, carry) = Mac(r4, self[3], rhs[1], carry); + (r5, carry) = Mac(r5, self[3], rhs[2], carry); + (r6, r7) = Mac(r6, self[3], rhs[3], carry); + + return MontgomeryReduce(r0, r1, r2, r3, r4, r5, r6, r7); + } + + public static Scalar operator -(in Scalar a, in Scalar b) + { + ReadOnlySpan self = a.GetSpanU64(), rhs = b.GetSpanU64(); + ulong d0, d1, d2, d3; + ulong carry, borrow; + + (d0, borrow) = Sbb(self[0], rhs[0], 0); + (d1, borrow) = Sbb(self[1], rhs[1], borrow); + (d2, borrow) = Sbb(self[2], rhs[2], borrow); + (d3, borrow) = Sbb(self[3], rhs[3], borrow); + + borrow = borrow == 0 ? ulong.MinValue : ulong.MaxValue; + (d0, carry) = Adc(d0, MODULUS_LIMBS_64[0] & borrow, 0); + (d1, carry) = Adc(d1, MODULUS_LIMBS_64[1] & borrow, carry); + (d2, carry) = Adc(d2, MODULUS_LIMBS_64[2] & borrow, carry); + (d3, _) = Adc(d3, MODULUS_LIMBS_64[3] & borrow, carry); + + ReadOnlySpan tmp = stackalloc[] { d0, d1, d2, d3 }; + return MemoryMarshal.Cast(tmp)[0]; + } + + public static Scalar operator +(in Scalar a, in Scalar b) + { + ReadOnlySpan self = a.GetSpanU64(), rhs = b.GetSpanU64(); + ulong d0, d1, d2, d3; + ulong carry; + + (d0, carry) = Adc(self[0], rhs[0], 0); + (d1, carry) = Adc(self[1], rhs[1], carry); + (d2, carry) = Adc(self[2], rhs[2], carry); + (d3, _) = Adc(self[3], rhs[3], carry); + + // Attempt to subtract the modulus, to ensure the value + // is smaller than the modulus. + ReadOnlySpan tmp = stackalloc[] { d0, d1, d2, d3 }; + return MemoryMarshal.Cast(tmp)[0] - MODULUS; + } + + public static Scalar operator -(in Scalar a) + { + ReadOnlySpan self = a.GetSpanU64(); + ulong d0, d1, d2, d3; + ulong borrow; + + // Subtract `self` from `MODULUS` to negate. Ignore the final + // borrow because it cannot underflow; self is guaranteed to + // be in the field. + (d0, borrow) = Sbb(MODULUS_LIMBS_64[0], self[0], 0); + (d1, borrow) = Sbb(MODULUS_LIMBS_64[1], self[1], borrow); + (d2, borrow) = Sbb(MODULUS_LIMBS_64[2], self[2], borrow); + (d3, _) = Sbb(MODULUS_LIMBS_64[3], self[3], borrow); + + // `tmp` could be `MODULUS` if `self` was zero. Create a mask that is + // zero if `self` was zero, and `u64::max_value()` if self was nonzero. + ulong mask = a.IsZero ? ulong.MinValue : ulong.MaxValue; + + ReadOnlySpan tmp = stackalloc[] { d0 & mask, d1 & mask, d2 & mask, d3 & mask }; + return MemoryMarshal.Cast(tmp)[0]; + } + + #region Instance math methods + + public Scalar Negate() => -this; + public Scalar Multiply(in Scalar value) => this * value; + public Scalar Sum(in Scalar value) => this + value; + public Scalar Subtract(in Scalar value) => this - value; + + #endregion +} diff --git a/src/Neo.Cryptography.BLS12_381/ScalarConstants.cs b/src/Neo.Cryptography.BLS12_381/ScalarConstants.cs new file mode 100644 index 0000000000..56bab5b067 --- /dev/null +++ b/src/Neo.Cryptography.BLS12_381/ScalarConstants.cs @@ -0,0 +1,96 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// ScalarConstants.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.Cryptography.BLS12_381; + +static class ScalarConstants +{ + // The modulus as u32 limbs. + public static readonly uint[] MODULUS_LIMBS_32 = + { + 0x0000_0001, + 0xffff_ffff, + 0xfffe_5bfe, + 0x53bd_a402, + 0x09a1_d805, + 0x3339_d808, + 0x299d_7d48, + 0x73ed_a753 + }; + + // The modulus as u64 limbs. + public static readonly ulong[] MODULUS_LIMBS_64 = + { + 0xffff_ffff_0000_0001, + 0x53bd_a402_fffe_5bfe, + 0x3339_d808_09a1_d805, + 0x73ed_a753_299d_7d48 + }; + + // q = 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001 + public static readonly Scalar MODULUS = new(MODULUS_LIMBS_64); + + // The number of bits needed to represent the modulus. + public const uint MODULUS_BITS = 255; + + // GENERATOR = 7 (multiplicative generator of r-1 order, that is also quadratic nonresidue) + public static readonly Scalar GENERATOR = new(new ulong[] + { + 0x0000_000e_ffff_fff1, + 0x17e3_63d3_0018_9c0f, + 0xff9c_5787_6f84_57b0, + 0x3513_3220_8fc5_a8c4 + }); + + // INV = -(q^{-1} mod 2^64) mod 2^64 + public const ulong INV = 0xffff_fffe_ffff_ffff; + + // R = 2^256 mod q + public static readonly Scalar R = new(new ulong[] + { + 0x0000_0001_ffff_fffe, + 0x5884_b7fa_0003_4802, + 0x998c_4fef_ecbc_4ff5, + 0x1824_b159_acc5_056f + }); + + // R^2 = 2^512 mod q + public static readonly Scalar R2 = new(new ulong[] + { + 0xc999_e990_f3f2_9c6d, + 0x2b6c_edcb_8792_5c23, + 0x05d3_1496_7254_398f, + 0x0748_d9d9_9f59_ff11 + }); + + // R^3 = 2^768 mod q + public static readonly Scalar R3 = new(new ulong[] + { + 0xc62c_1807_439b_73af, + 0x1b3e_0d18_8cf0_6990, + 0x73d1_3c71_c7b5_f418, + 0x6e2a_5bb9_c8db_33e9 + }); + + // 2^S * t = MODULUS - 1 with t odd + public const uint S = 32; + + // GENERATOR^t where t * 2^s + 1 = q with t odd. + // In other words, this is a 2^s root of unity. + // `GENERATOR = 7 mod q` is a generator of the q - 1 order multiplicative subgroup. + public static readonly Scalar ROOT_OF_UNITY = new(new ulong[] + { + 0xb9b5_8d8c_5f0e_466a, + 0x5b1b_4c80_1819_d7ec, + 0x0af5_3ae3_52a3_1e64, + 0x5bf3_adda_19e9_b27b + }); +} diff --git a/src/Neo/Neo.csproj b/src/Neo/Neo.csproj index d15345dcbf..7d1778d712 100644 --- a/src/Neo/Neo.csproj +++ b/src/Neo/Neo.csproj @@ -14,10 +14,10 @@ - + 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 new file mode 100644 index 0000000000..f3b71df777 --- /dev/null +++ b/tests/Neo.Cryptography.BLS12_381.Tests/Neo.Cryptography.BLS12_381.Tests.csproj @@ -0,0 +1,24 @@ + + + + net7.0 + enable + enable + false + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + diff --git a/tests/Neo.Cryptography.BLS12_381.Tests/UT_Fp.cs b/tests/Neo.Cryptography.BLS12_381.Tests/UT_Fp.cs new file mode 100644 index 0000000000..bc9cd480f2 --- /dev/null +++ b/tests/Neo.Cryptography.BLS12_381.Tests/UT_Fp.cs @@ -0,0 +1,353 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_Fp.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.Collections; +using System.Runtime.InteropServices; +using static Neo.Cryptography.BLS12_381.ConstantTimeUtility; + +namespace Neo.Cryptography.BLS12_381.Tests; + +[TestClass] +public class UT_Fp +{ + [TestMethod] + public void TestSize() + { + Assert.AreEqual(Fp.Size, Marshal.SizeOf()); + } + + [TestMethod] + public void TestEquality() + { + static bool IsEqual(in Fp a, in Fp b) + { + bool eq = StructuralComparisons.StructuralEqualityComparer.Equals(a, b); + bool ct_eq = a == b; + Assert.AreEqual(eq, ct_eq); + return eq; + } + + Assert.IsTrue(IsEqual(Fp.FromRawUnchecked(new ulong[] { 1, 2, 3, 4, 5, 6 }), Fp.FromRawUnchecked(new ulong[] { 1, 2, 3, 4, 5, 6 }))); + + Assert.IsFalse(IsEqual(Fp.FromRawUnchecked(new ulong[] { 7, 2, 3, 4, 5, 6 }), Fp.FromRawUnchecked(new ulong[] { 1, 2, 3, 4, 5, 6 }))); + Assert.IsFalse(IsEqual(Fp.FromRawUnchecked(new ulong[] { 1, 7, 3, 4, 5, 6 }), Fp.FromRawUnchecked(new ulong[] { 1, 2, 3, 4, 5, 6 }))); + Assert.IsFalse(IsEqual(Fp.FromRawUnchecked(new ulong[] { 1, 2, 7, 4, 5, 6 }), Fp.FromRawUnchecked(new ulong[] { 1, 2, 3, 4, 5, 6 }))); + Assert.IsFalse(IsEqual(Fp.FromRawUnchecked(new ulong[] { 1, 2, 3, 7, 5, 6 }), Fp.FromRawUnchecked(new ulong[] { 1, 2, 3, 4, 5, 6 }))); + Assert.IsFalse(IsEqual(Fp.FromRawUnchecked(new ulong[] { 1, 2, 3, 4, 7, 6 }), Fp.FromRawUnchecked(new ulong[] { 1, 2, 3, 4, 5, 6 }))); + Assert.IsFalse(IsEqual(Fp.FromRawUnchecked(new ulong[] { 1, 2, 3, 4, 5, 7 }), Fp.FromRawUnchecked(new ulong[] { 1, 2, 3, 4, 5, 6 }))); + } + + [TestMethod] + public void TestConditionalSelection() + { + Fp a = Fp.FromRawUnchecked(new ulong[] { 1, 2, 3, 4, 5, 6 }); + Fp b = Fp.FromRawUnchecked(new ulong[] { 7, 8, 9, 10, 11, 12 }); + + Assert.AreEqual(a, ConditionalSelect(in a, in b, false)); + Assert.AreEqual(b, ConditionalSelect(in a, in b, true)); + } + + [TestMethod] + public void TestSquaring() + { + Fp a = Fp.FromRawUnchecked(new ulong[] + { + 0xd215_d276_8e83_191b, + 0x5085_d80f_8fb2_8261, + 0xce9a_032d_df39_3a56, + 0x3e9c_4fff_2ca0_c4bb, + 0x6436_b6f7_f4d9_5dfb, + 0x1060_6628_ad4a_4d90 + }); + Fp b = Fp.FromRawUnchecked(new ulong[] + { + 0x33d9_c42a_3cb3_e235, + 0xdad1_1a09_4c4c_d455, + 0xa2f1_44bd_729a_aeba, + 0xd415_0932_be9f_feac, + 0xe27b_c7c4_7d44_ee50, + 0x14b6_a78d_3ec7_a560 + }); + + Assert.AreEqual(b, a.Square()); + } + + [TestMethod] + public void TestMultiplication() + { + Fp a = Fp.FromRawUnchecked(new ulong[] + { + 0x0397_a383_2017_0cd4, + 0x734c_1b2c_9e76_1d30, + 0x5ed2_55ad_9a48_beb5, + 0x095a_3c6b_22a7_fcfc, + 0x2294_ce75_d4e2_6a27, + 0x1333_8bd8_7001_1ebb + }); + Fp b = Fp.FromRawUnchecked(new ulong[] + { + 0xb9c3_c7c5_b119_6af7, + 0x2580_e208_6ce3_35c1, + 0xf49a_ed3d_8a57_ef42, + 0x41f2_81e4_9846_e878, + 0xe076_2346_c384_52ce, + 0x0652_e893_26e5_7dc0 + }); + Fp c = Fp.FromRawUnchecked(new ulong[] + { + 0xf96e_f3d7_11ab_5355, + 0xe8d4_59ea_00f1_48dd, + 0x53f7_354a_5f00_fa78, + 0x9e34_a4f3_125c_5f83, + 0x3fbe_0c47_ca74_c19e, + 0x01b0_6a8b_bd4a_dfe4 + }); + + Assert.AreEqual(c, a * b); + } + + [TestMethod] + public void TestAddition() + { + Fp a = Fp.FromRawUnchecked(new ulong[] + { + 0x5360_bb59_7867_8032, + 0x7dd2_75ae_799e_128e, + 0x5c5b_5071_ce4f_4dcf, + 0xcdb2_1f93_078d_bb3e, + 0xc323_65c5_e73f_474a, + 0x115a_2a54_89ba_be5b + }); + Fp b = Fp.FromRawUnchecked(new ulong[] + { + 0x9fd2_8773_3d23_dda0, + 0xb16b_f2af_738b_3554, + 0x3e57_a75b_d3cc_6d1d, + 0x900b_c0bd_627f_d6d6, + 0xd319_a080_efb2_45fe, + 0x15fd_caa4_e4bb_2091 + }); + Fp c = Fp.FromRawUnchecked(new ulong[] + { + 0x3934_42cc_b58b_b327, + 0x1092_685f_3bd5_47e3, + 0x3382_252c_ab6a_c4c9, + 0xf946_94cb_7688_7f55, + 0x4b21_5e90_93a5_e071, + 0x0d56_e30f_34f5_f853 + }); + + Assert.AreEqual(c, a + b); + } + + [TestMethod] + public void TestSubtraction() + { + Fp a = Fp.FromRawUnchecked(new ulong[] + { + 0x5360_bb59_7867_8032, + 0x7dd2_75ae_799e_128e, + 0x5c5b_5071_ce4f_4dcf, + 0xcdb2_1f93_078d_bb3e, + 0xc323_65c5_e73f_474a, + 0x115a_2a54_89ba_be5b + }); + Fp b = Fp.FromRawUnchecked(new ulong[] + { + 0x9fd2_8773_3d23_dda0, + 0xb16b_f2af_738b_3554, + 0x3e57_a75b_d3cc_6d1d, + 0x900b_c0bd_627f_d6d6, + 0xd319_a080_efb2_45fe, + 0x15fd_caa4_e4bb_2091 + }); + Fp c = Fp.FromRawUnchecked(new ulong[] + { + 0x6d8d_33e6_3b43_4d3d, + 0xeb12_82fd_b766_dd39, + 0x8534_7bb6_f133_d6d5, + 0xa21d_aa5a_9892_f727, + 0x3b25_6cfb_3ad8_ae23, + 0x155d_7199_de7f_8464 + }); + + Assert.AreEqual(c, a - b); + } + + [TestMethod] + public void TestNegation() + { + Fp a = Fp.FromRawUnchecked(new ulong[] + { + 0x5360_bb59_7867_8032, + 0x7dd2_75ae_799e_128e, + 0x5c5b_5071_ce4f_4dcf, + 0xcdb2_1f93_078d_bb3e, + 0xc323_65c5_e73f_474a, + 0x115a_2a54_89ba_be5b + }); + Fp b = Fp.FromRawUnchecked(new ulong[] + { + 0x669e_44a6_8798_2a79, + 0xa0d9_8a50_37b5_ed71, + 0x0ad5_822f_2861_a854, + 0x96c5_2bf1_ebf7_5781, + 0x87f8_41f0_5c0c_658c, + 0x08a6_e795_afc5_283e + }); + + Assert.AreEqual(b, -a); + } + + [TestMethod] + public void TestToString() + { + Fp a = Fp.FromRawUnchecked(new ulong[] + { + 0x5360_bb59_7867_8032, + 0x7dd2_75ae_799e_128e, + 0x5c5b_5071_ce4f_4dcf, + 0xcdb2_1f93_078d_bb3e, + 0xc323_65c5_e73f_474a, + 0x115a_2a54_89ba_be5b + }); + + Assert.AreEqual("0x104bf052ad3bc99bcb176c24a06a6c3aad4eaf2308fc4d282e106c84a757d061052630515305e59bdddf8111bfdeb704", a.ToString()); + } + + [TestMethod] + public void TestConstructor() + { + Fp a = Fp.FromRawUnchecked(new ulong[] + { + 0xdc90_6d9b_e3f9_5dc8, + 0x8755_caf7_4596_91a1, + 0xcff1_a7f4_e958_3ab3, + 0x9b43_821f_849e_2284, + 0xf575_54f3_a297_4f3f, + 0x085d_bea8_4ed4_7f79 + }); + + for (int i = 0; i < 100; i++) + { + a = a.Square(); + byte[] tmp = a.ToArray(); + Fp b = Fp.FromBytes(tmp); + + Assert.AreEqual(b, a); + } + + Assert.AreEqual(-Fp.One, Fp.FromBytes(new byte[] + { + 26, 1, 17, 234, 57, 127, 230, 154, 75, 27, 167, 182, 67, 75, 172, 215, 100, 119, 75, + 132, 243, 133, 18, 191, 103, 48, 210, 160, 246, 176, 246, 36, 30, 171, 255, 254, 177, + 83, 255, 255, 185, 254, 255, 255, 255, 255, 170, 170 + })); + + Assert.ThrowsException(() => Fp.FromBytes(new byte[] + { + 27, 1, 17, 234, 57, 127, 230, 154, 75, 27, 167, 182, 67, 75, 172, 215, 100, 119, 75, + 132, 243, 133, 18, 191, 103, 48, 210, 160, 246, 176, 246, 36, 30, 171, 255, 254, 177, + 83, 255, 255, 185, 254, 255, 255, 255, 255, 170, 170 + })); + + Assert.ThrowsException(() => Fp.FromBytes(Enumerable.Repeat(0xff, 48).ToArray())); + } + + [TestMethod] + public void TestSqrt() + { + // a = 4 + Fp a = Fp.FromRawUnchecked(new ulong[] + { + 0xaa27_0000_000c_fff3, + 0x53cc_0032_fc34_000a, + 0x478f_e97a_6b0a_807f, + 0xb1d3_7ebe_e6ba_24d7, + 0x8ec9_733b_bf78_ab2f, + 0x09d6_4551_3d83_de7e + }); + + // b = 2 + Fp b = Fp.FromRawUnchecked(new ulong[] + { + 0x3213_0000_0006_554f, + 0xb93c_0018_d6c4_0005, + 0x5760_5e0d_b0dd_bb51, + 0x8b25_6521_ed1f_9bcb, + 0x6cf2_8d79_0162_2c03, + 0x11eb_ab9d_bb81_e28c + }); + + // sqrt(4) = -2 + Assert.AreEqual(b, -a.Sqrt()); + } + + [TestMethod] + public void TestInversion() + { + Fp a = Fp.FromRawUnchecked(new ulong[] + { + 0x43b4_3a50_78ac_2076, + 0x1ce0_7630_46f8_962b, + 0x724a_5276_486d_735c, + 0x6f05_c2a6_282d_48fd, + 0x2095_bd5b_b4ca_9331, + 0x03b3_5b38_94b0_f7da + }); + Fp b = Fp.FromRawUnchecked(new ulong[] + { + 0x69ec_d704_0952_148f, + 0x985c_cc20_2219_0f55, + 0xe19b_ba36_a9ad_2f41, + 0x19bb_16c9_5219_dbd8, + 0x14dc_acfd_fb47_8693, + 0x115f_f58a_fff9_a8e1 + }); + + Assert.AreEqual(b, a.Invert()); + Assert.ThrowsException(() => Fp.Zero.Invert()); + } + + [TestMethod] + public void TestLexicographicLargest() + { + Assert.IsFalse(Fp.Zero.LexicographicallyLargest()); + Assert.IsFalse(Fp.One.LexicographicallyLargest()); + Assert.IsFalse(Fp.FromRawUnchecked(new ulong[] + { + 0xa1fa_ffff_fffe_5557, + 0x995b_fff9_76a3_fffe, + 0x03f4_1d24_d174_ceb4, + 0xf654_7998_c199_5dbd, + 0x778a_468f_507a_6034, + 0x0205_5993_1f7f_8103 + }).LexicographicallyLargest()); + Assert.IsTrue(Fp.FromRawUnchecked(new ulong[] + { + 0x1804_0000_0001_5554, + 0x8550_0005_3ab0_0001, + 0x633c_b57c_253c_276f, + 0x6e22_d1ec_31eb_b502, + 0xd391_6126_f2d1_4ca2, + 0x17fb_b857_1a00_6596 + }).LexicographicallyLargest()); + Assert.IsTrue(Fp.FromRawUnchecked(new ulong[] + { + 0x43f5_ffff_fffc_aaae, + 0x32b7_fff2_ed47_fffd, + 0x07e8_3a49_a2e9_9d69, + 0xeca8_f331_8332_bb7a, + 0xef14_8d1e_a0f4_c069, + 0x040a_b326_3eff_0206 + }).LexicographicallyLargest()); + } +} diff --git a/tests/Neo.Cryptography.BLS12_381.Tests/UT_Fp12.cs b/tests/Neo.Cryptography.BLS12_381.Tests/UT_Fp12.cs new file mode 100644 index 0000000000..238a20c6c6 --- /dev/null +++ b/tests/Neo.Cryptography.BLS12_381.Tests/UT_Fp12.cs @@ -0,0 +1,347 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_Fp12.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.Cryptography.BLS12_381.Tests; + +[TestClass] +public class UT_Fp12 +{ + [TestMethod] + public void TestArithmetic() + { + var a = new Fp12(new Fp6(new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0x47f9_cb98_b1b8_2d58, + 0x5fe9_11eb_a3aa_1d9d, + 0x96bf_1b5f_4dd8_1db3, + 0x8100_d27c_c925_9f5b, + 0xafa2_0b96_7464_0eab, + 0x09bb_cea7_d8d9_497d + }), Fp.FromRawUnchecked(new ulong[] + { + 0x0303_cb98_b166_2daa, + 0xd931_10aa_0a62_1d5a, + 0xbfa9_820c_5be4_a468, + 0x0ba3_643e_cb05_a348, + 0xdc35_34bb_1f1c_25a6, + 0x06c3_05bb_19c0_e1c1 + })), new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0x46f9_cb98_b162_d858, + 0x0be9_109c_f7aa_1d57, + 0xc791_bc55_fece_41d2, + 0xf84c_5770_4e38_5ec2, + 0xcb49_c1d9_c010_e60f, + 0x0acd_b8e1_58bf_e3c8 + }), Fp.FromRawUnchecked(new ulong[] + { + 0x8aef_cb98_b15f_8306, + 0x3ea1_108f_e4f2_1d54, + 0xcf79_f69f_a1b7_df3b, + 0xe4f5_4aa1_d16b_1a3c, + 0xba5e_4ef8_6105_a679, + 0x0ed8_6c07_97be_e5cf + })), new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0xcee5_cb98_b15c_2db4, + 0x7159_1082_d23a_1d51, + 0xd762_30e9_44a1_7ca4, + 0xd19e_3dd3_549d_d5b6, + 0xa972_dc17_01fa_66e3, + 0x12e3_1f2d_d6bd_e7d6 + }), Fp.FromRawUnchecked(new ulong[] + { + 0xad2a_cb98_b173_2d9d, + 0x2cfd_10dd_0696_1d64, + 0x0739_6b86_c6ef_24e8, + 0xbd76_e2fd_b1bf_c820, + 0x6afe_a7f6_de94_d0d5, + 0x1099_4b0c_5744_c040 + }))), new Fp6(new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0x47f9_cb98_b1b8_2d58, + 0x5fe9_11eb_a3aa_1d9d, + 0x96bf_1b5f_4dd8_1db3, + 0x8100_d27c_c925_9f5b, + 0xafa2_0b96_7464_0eab, + 0x09bb_cea7_d8d9_497d + }), Fp.FromRawUnchecked(new ulong[] + { + 0x0303_cb98_b166_2daa, + 0xd931_10aa_0a62_1d5a, + 0xbfa9_820c_5be4_a468, + 0x0ba3_643e_cb05_a348, + 0xdc35_34bb_1f1c_25a6, + 0x06c3_05bb_19c0_e1c1 + })), new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0x46f9_cb98_b162_d858, + 0x0be9_109c_f7aa_1d57, + 0xc791_bc55_fece_41d2, + 0xf84c_5770_4e38_5ec2, + 0xcb49_c1d9_c010_e60f, + 0x0acd_b8e1_58bf_e3c8 + }), Fp.FromRawUnchecked(new ulong[] + { + 0x8aef_cb98_b15f_8306, + 0x3ea1_108f_e4f2_1d54, + 0xcf79_f69f_a1b7_df3b, + 0xe4f5_4aa1_d16b_1a3c, + 0xba5e_4ef8_6105_a679, + 0x0ed8_6c07_97be_e5cf + })), new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0xcee5_cb98_b15c_2db4, + 0x7159_1082_d23a_1d51, + 0xd762_30e9_44a1_7ca4, + 0xd19e_3dd3_549d_d5b6, + 0xa972_dc17_01fa_66e3, + 0x12e3_1f2d_d6bd_e7d6 + }), Fp.FromRawUnchecked(new ulong[] + { + 0xad2a_cb98_b173_2d9d, + 0x2cfd_10dd_0696_1d64, + 0x0739_6b86_c6ef_24e8, + 0xbd76_e2fd_b1bf_c820, + 0x6afe_a7f6_de94_d0d5, + 0x1099_4b0c_5744_c040 + })))); + + var b = new Fp12(new Fp6(new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0x47f9_cb98_b1b8_2d58, + 0x5fe9_11eb_a3aa_1d9d, + 0x96bf_1b5f_4dd8_1db3, + 0x8100_d272_c925_9f5b, + 0xafa2_0b96_7464_0eab, + 0x09bb_cea7_d8d9_497d + }), Fp.FromRawUnchecked(new ulong[] + { + 0x0303_cb98_b166_2daa, + 0xd931_10aa_0a62_1d5a, + 0xbfa9_820c_5be4_a468, + 0x0ba3_643e_cb05_a348, + 0xdc35_34bb_1f1c_25a6, + 0x06c3_05bb_19c0_e1c1 + })), new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0x46f9_cb98_b162_d858, + 0x0be9_109c_f7aa_1d57, + 0xc791_bc55_fece_41d2, + 0xf84c_5770_4e38_5ec2, + 0xcb49_c1d9_c010_e60f, + 0x0acd_b8e1_58bf_e348 + }), Fp.FromRawUnchecked(new ulong[] + { + 0x8aef_cb98_b15f_8306, + 0x3ea1_108f_e4f2_1d54, + 0xcf79_f69f_a1b7_df3b, + 0xe4f5_4aa1_d16b_1a3c, + 0xba5e_4ef8_6105_a679, + 0x0ed8_6c07_97be_e5cf + })), new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0xcee5_cb98_b15c_2db4, + 0x7159_1082_d23a_1d51, + 0xd762_30e9_44a1_7ca4, + 0xd19e_3dd3_549d_d5b6, + 0xa972_dc17_01fa_66e3, + 0x12e3_1f2d_d6bd_e7d6 + }), Fp.FromRawUnchecked(new ulong[] + { + 0xad2a_cb98_b173_2d9d, + 0x2cfd_10dd_0696_1d64, + 0x0739_6b86_c6ef_24e8, + 0xbd76_e2fd_b1bf_c820, + 0x6afe_a7f6_de94_d0d5, + 0x1099_4b0c_5744_c040 + }))), new Fp6(new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0x47f9_cb98_b1b8_2d58, + 0x5fe9_11eb_a3aa_1d9d, + 0x96bf_1b5f_4dd2_1db3, + 0x8100_d27c_c925_9f5b, + 0xafa2_0b96_7464_0eab, + 0x09bb_cea7_d8d9_497d + }), Fp.FromRawUnchecked(new ulong[] + { + 0x0303_cb98_b166_2daa, + 0xd931_10aa_0a62_1d5a, + 0xbfa9_820c_5be4_a468, + 0x0ba3_643e_cb05_a348, + 0xdc35_34bb_1f1c_25a6, + 0x06c3_05bb_19c0_e1c1 + })), new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0x46f9_cb98_b162_d858, + 0x0be9_109c_f7aa_1d57, + 0xc791_bc55_fece_41d2, + 0xf84c_5770_4e38_5ec2, + 0xcb49_c1d9_c010_e60f, + 0x0acd_b8e1_58bf_e3c8 + }), Fp.FromRawUnchecked(new ulong[] + { + 0x8aef_cb98_b15f_8306, + 0x3ea1_108f_e4f2_1d54, + 0xcf79_f69f_a117_df3b, + 0xe4f5_4aa1_d16b_1a3c, + 0xba5e_4ef8_6105_a679, + 0x0ed8_6c07_97be_e5cf + })), new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0xcee5_cb98_b15c_2db4, + 0x7159_1082_d23a_1d51, + 0xd762_30e9_44a1_7ca4, + 0xd19e_3dd3_549d_d5b6, + 0xa972_dc17_01fa_66e3, + 0x12e3_1f2d_d6bd_e7d6 + }), Fp.FromRawUnchecked(new ulong[] + { + 0xad2a_cb98_b173_2d9d, + 0x2cfd_10dd_0696_1d64, + 0x0739_6b86_c6ef_24e8, + 0xbd76_e2fd_b1bf_c820, + 0x6afe_a7f6_de94_d0d5, + 0x1099_4b0c_5744_c040 + })))); + + var c = new Fp12(new Fp6(new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0x47f9_cb98_71b8_2d58, + 0x5fe9_11eb_a3aa_1d9d, + 0x96bf_1b5f_4dd8_1db3, + 0x8100_d27c_c925_9f5b, + 0xafa2_0b96_7464_0eab, + 0x09bb_cea7_d8d9_497d + }), Fp.FromRawUnchecked(new ulong[] + { + 0x0303_cb98_b166_2daa, + 0xd931_10aa_0a62_1d5a, + 0xbfa9_820c_5be4_a468, + 0x0ba3_643e_cb05_a348, + 0xdc35_34bb_1f1c_25a6, + 0x06c3_05bb_19c0_e1c1 + })), new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0x46f9_cb98_b162_d858, + 0x0be9_109c_f7aa_1d57, + 0x7791_bc55_fece_41d2, + 0xf84c_5770_4e38_5ec2, + 0xcb49_c1d9_c010_e60f, + 0x0acd_b8e1_58bf_e3c8 + }), Fp.FromRawUnchecked(new ulong[] + { + 0x8aef_cb98_b15f_8306, + 0x3ea1_108f_e4f2_1d54, + 0xcf79_f69f_a1b7_df3b, + 0xe4f5_4aa1_d16b_133c, + 0xba5e_4ef8_6105_a679, + 0x0ed8_6c07_97be_e5cf + })), new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0xcee5_cb98_b15c_2db4, + 0x7159_1082_d23a_1d51, + 0xd762_40e9_44a1_7ca4, + 0xd19e_3dd3_549d_d5b6, + 0xa972_dc17_01fa_66e3, + 0x12e3_1f2d_d6bd_e7d6 + }), Fp.FromRawUnchecked(new ulong[] + { + 0xad2a_cb98_b173_2d9d, + 0x2cfd_10dd_0696_1d64, + 0x0739_6b86_c6ef_24e8, + 0xbd76_e2fd_b1bf_c820, + 0x6afe_a7f6_de94_d0d5, + 0x1099_4b0c_1744_c040 + }))), new Fp6(new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0x47f9_cb98_b1b8_2d58, + 0x5fe9_11eb_a3aa_1d9d, + 0x96bf_1b5f_4dd8_1db3, + 0x8100_d27c_c925_9f5b, + 0xafa2_0b96_7464_0eab, + 0x09bb_cea7_d8d9_497d + }), Fp.FromRawUnchecked(new ulong[] + { + 0x0303_cb98_b166_2daa, + 0xd931_10aa_0a62_1d5a, + 0xbfa9_820c_5be4_a468, + 0x0ba3_643e_cb05_a348, + 0xdc35_34bb_1f1c_25a6, + 0x06c3_05bb_19c0_e1c1 + })), new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0x46f9_cb98_b162_d858, + 0x0be9_109c_f7aa_1d57, + 0xc791_bc55_fece_41d2, + 0xf84c_5770_4e38_5ec2, + 0xcb49_c1d3_c010_e60f, + 0x0acd_b8e1_58bf_e3c8 + }), Fp.FromRawUnchecked(new ulong[] + { + 0x8aef_cb98_b15f_8306, + 0x3ea1_108f_e4f2_1d54, + 0xcf79_f69f_a1b7_df3b, + 0xe4f5_4aa1_d16b_1a3c, + 0xba5e_4ef8_6105_a679, + 0x0ed8_6c07_97be_e5cf + })), new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0xcee5_cb98_b15c_2db4, + 0x7159_1082_d23a_1d51, + 0xd762_30e9_44a1_7ca4, + 0xd19e_3dd3_549d_d5b6, + 0xa972_dc17_01fa_66e3, + 0x12e3_1f2d_d6bd_e7d6 + }), Fp.FromRawUnchecked(new ulong[] + { + 0xad2a_cb98_b173_2d9d, + 0x2cfd_10dd_0696_1d64, + 0x0739_6b86_c6ef_24e8, + 0xbd76_e2fd_b1bf_c820, + 0x6afe_a7f6_de94_d0d5, + 0x1099_4b0c_5744_1040 + })))); + + // because a and b and c are similar to each other and + // I was lazy, this is just some arbitrary way to make + // them a little more different + a = a.Square().Invert().Square() + c; + b = b.Square().Invert().Square() + a; + c = c.Square().Invert().Square() + b; + + Assert.AreEqual(a * a, a.Square()); + Assert.AreEqual(b * b, b.Square()); + Assert.AreEqual(c * c, c.Square()); + + Assert.AreEqual((a + b) * c.Square(), (c * c * a) + (c * c * b)); + + Assert.AreEqual(a.Invert() * b.Invert(), (a * b).Invert()); + Assert.AreEqual(Fp12.One, a.Invert() * a); + + Assert.AreNotEqual(a, a.FrobeniusMap()); + Assert.AreEqual( + a, + a.FrobeniusMap() + .FrobeniusMap() + .FrobeniusMap() + .FrobeniusMap() + .FrobeniusMap() + .FrobeniusMap() + .FrobeniusMap() + .FrobeniusMap() + .FrobeniusMap() + .FrobeniusMap() + .FrobeniusMap() + .FrobeniusMap() + ); + } +} diff --git a/tests/Neo.Cryptography.BLS12_381.Tests/UT_Fp2.cs b/tests/Neo.Cryptography.BLS12_381.Tests/UT_Fp2.cs new file mode 100644 index 0000000000..8e8781b834 --- /dev/null +++ b/tests/Neo.Cryptography.BLS12_381.Tests/UT_Fp2.cs @@ -0,0 +1,493 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_Fp2.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.Collections; +using static Neo.Cryptography.BLS12_381.ConstantTimeUtility; + +namespace Neo.Cryptography.BLS12_381.Tests; + +[TestClass] +public class UT_Fp2 +{ + [TestMethod] + public void TestConditionalSelection() + { + var a = new Fp2( + Fp.FromRawUnchecked(new ulong[] { 1, 2, 3, 4, 5, 6 }), + Fp.FromRawUnchecked(new ulong[] { 7, 8, 9, 10, 11, 12 }) + ); + var b = new Fp2( + Fp.FromRawUnchecked(new ulong[] { 13, 14, 15, 16, 17, 18 }), + Fp.FromRawUnchecked(new ulong[] { 19, 20, 21, 22, 23, 24 }) + ); + + Assert.AreEqual(a, ConditionalSelect(in a, in b, false)); + Assert.AreEqual(b, ConditionalSelect(in a, in b, true)); + } + + [TestMethod] + public void TestEquality() + { + static bool IsEqual(in Fp2 a, in Fp2 b) + { + var eq = StructuralComparisons.StructuralEqualityComparer.Equals(a, b); + var ct_eq = a == b; + Assert.AreEqual(eq, ct_eq); + return eq; + } + + Assert.IsTrue(IsEqual( + new Fp2(Fp.FromRawUnchecked(new ulong[] { 1, 2, 3, 4, 5, 6 }), Fp.FromRawUnchecked(new ulong[] { 7, 8, 9, 10, 11, 12 })), + new Fp2(Fp.FromRawUnchecked(new ulong[] { 1, 2, 3, 4, 5, 6 }), Fp.FromRawUnchecked(new ulong[] { 7, 8, 9, 10, 11, 12 })) + )); + + Assert.IsFalse(IsEqual( + new Fp2(Fp.FromRawUnchecked(new ulong[] { 2, 2, 3, 4, 5, 6 }), Fp.FromRawUnchecked(new ulong[] { 7, 8, 9, 10, 11, 12 })), + new Fp2(Fp.FromRawUnchecked(new ulong[] { 1, 2, 3, 4, 5, 6 }), Fp.FromRawUnchecked(new ulong[] { 7, 8, 9, 10, 11, 12 })) + )); + + Assert.IsFalse(IsEqual( + new Fp2(Fp.FromRawUnchecked(new ulong[] { 1, 2, 3, 4, 5, 6 }), Fp.FromRawUnchecked(new ulong[] { 2, 8, 9, 10, 11, 12 })), + new Fp2(Fp.FromRawUnchecked(new ulong[] { 1, 2, 3, 4, 5, 6 }), Fp.FromRawUnchecked(new ulong[] { 7, 8, 9, 10, 11, 12 })) + )); + } + + [TestMethod] + public void TestSquaring() + { + var a = new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0xc9a2_1831_63ee_70d4, + 0xbc37_70a7_196b_5c91, + 0xa247_f8c1_304c_5f44, + 0xb01f_c2a3_726c_80b5, + 0xe1d2_93e5_bbd9_19c9, + 0x04b7_8e80_020e_f2ca, + }), Fp.FromRawUnchecked(new ulong[] + { + 0x952e_a446_0462_618f, + 0x238d_5edd_f025_c62f, + 0xf6c9_4b01_2ea9_2e72, + 0x03ce_24ea_c1c9_3808, + 0x0559_50f9_45da_483c, + 0x010a_768d_0df4_eabc, + })); + var b = new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0xa1e0_9175_a4d2_c1fe, + 0x8b33_acfc_204e_ff12, + 0xe244_15a1_1b45_6e42, + 0x61d9_96b1_b6ee_1936, + 0x1164_dbe8_667c_853c, + 0x0788_557a_cc7d_9c79, + }), Fp.FromRawUnchecked(new ulong[] + { + 0xda6a_87cc_6f48_fa36, + 0x0fc7_b488_277c_1903, + 0x9445_ac4a_dc44_8187, + 0x0261_6d5b_c909_9209, + 0xdbed_4677_2db5_8d48, + 0x11b9_4d50_76c7_b7b1, + })); + + Assert.AreEqual(a.Square(), b); + } + + [TestMethod] + public void TestMultiplication() + { + var a = new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0xc9a2_1831_63ee_70d4, + 0xbc37_70a7_196b_5c91, + 0xa247_f8c1_304c_5f44, + 0xb01f_c2a3_726c_80b5, + 0xe1d2_93e5_bbd9_19c9, + 0x04b7_8e80_020e_f2ca, + }), Fp.FromRawUnchecked(new ulong[] + { + 0x952e_a446_0462_618f, + 0x238d_5edd_f025_c62f, + 0xf6c9_4b01_2ea9_2e72, + 0x03ce_24ea_c1c9_3808, + 0x0559_50f9_45da_483c, + 0x010a_768d_0df4_eabc, + })); + var b = new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0xa1e0_9175_a4d2_c1fe, + 0x8b33_acfc_204e_ff12, + 0xe244_15a1_1b45_6e42, + 0x61d9_96b1_b6ee_1936, + 0x1164_dbe8_667c_853c, + 0x0788_557a_cc7d_9c79, + }), Fp.FromRawUnchecked(new ulong[] + { + 0xda6a_87cc_6f48_fa36, + 0x0fc7_b488_277c_1903, + 0x9445_ac4a_dc44_8187, + 0x0261_6d5b_c909_9209, + 0xdbed_4677_2db5_8d48, + 0x11b9_4d50_76c7_b7b1, + })); + var c = new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0xf597_483e_27b4_e0f7, + 0x610f_badf_811d_ae5f, + 0x8432_af91_7714_327a, + 0x6a9a_9603_cf88_f09e, + 0xf05a_7bf8_bad0_eb01, + 0x0954_9131_c003_ffae, + }), Fp.FromRawUnchecked(new ulong[] + { + 0x963b_02d0_f93d_37cd, + 0xc95c_e1cd_b30a_73d4, + 0x3087_25fa_3126_f9b8, + 0x56da_3c16_7fab_0d50, + 0x6b50_86b5_f4b6_d6af, + 0x09c3_9f06_2f18_e9f2, + })); + + Assert.AreEqual(c, a * b); + } + + [TestMethod] + public void TestAddition() + { + var a = new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0xc9a2_1831_63ee_70d4, + 0xbc37_70a7_196b_5c91, + 0xa247_f8c1_304c_5f44, + 0xb01f_c2a3_726c_80b5, + 0xe1d2_93e5_bbd9_19c9, + 0x04b7_8e80_020e_f2ca, + }), Fp.FromRawUnchecked(new ulong[] + { + 0x952e_a446_0462_618f, + 0x238d_5edd_f025_c62f, + 0xf6c9_4b01_2ea9_2e72, + 0x03ce_24ea_c1c9_3808, + 0x0559_50f9_45da_483c, + 0x010a_768d_0df4_eabc, + })); + var b = new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0xa1e0_9175_a4d2_c1fe, + 0x8b33_acfc_204e_ff12, + 0xe244_15a1_1b45_6e42, + 0x61d9_96b1_b6ee_1936, + 0x1164_dbe8_667c_853c, + 0x0788_557a_cc7d_9c79, + }), Fp.FromRawUnchecked(new ulong[] + { + 0xda6a_87cc_6f48_fa36, + 0x0fc7_b488_277c_1903, + 0x9445_ac4a_dc44_8187, + 0x0261_6d5b_c909_9209, + 0xdbed_4677_2db5_8d48, + 0x11b9_4d50_76c7_b7b1, + })); + var c = new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0x6b82_a9a7_08c1_32d2, + 0x476b_1da3_39ba_5ba4, + 0x848c_0e62_4b91_cd87, + 0x11f9_5955_295a_99ec, + 0xf337_6fce_2255_9f06, + 0x0c3f_e3fa_ce8c_8f43, + }), Fp.FromRawUnchecked(new ulong[] + { + 0x6f99_2c12_73ab_5bc5, + 0x3355_1366_17a1_df33, + 0x8b0e_f74c_0aed_aff9, + 0x062f_9246_8ad2_ca12, + 0xe146_9770_738f_d584, + 0x12c3_c3dd_84bc_a26d, + })); + + Assert.AreEqual(a + b, c); + } + + [TestMethod] + public void TestSubtraction() + { + var a = new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0xc9a2_1831_63ee_70d4, + 0xbc37_70a7_196b_5c91, + 0xa247_f8c1_304c_5f44, + 0xb01f_c2a3_726c_80b5, + 0xe1d2_93e5_bbd9_19c9, + 0x04b7_8e80_020e_f2ca, + }), Fp.FromRawUnchecked(new ulong[] + { + 0x952e_a446_0462_618f, + 0x238d_5edd_f025_c62f, + 0xf6c9_4b01_2ea9_2e72, + 0x03ce_24ea_c1c9_3808, + 0x0559_50f9_45da_483c, + 0x010a_768d_0df4_eabc, + })); + var b = new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0xa1e0_9175_a4d2_c1fe, + 0x8b33_acfc_204e_ff12, + 0xe244_15a1_1b45_6e42, + 0x61d9_96b1_b6ee_1936, + 0x1164_dbe8_667c_853c, + 0x0788_557a_cc7d_9c79, + }), Fp.FromRawUnchecked(new ulong[] + { + 0xda6a_87cc_6f48_fa36, + 0x0fc7_b488_277c_1903, + 0x9445_ac4a_dc44_8187, + 0x0261_6d5b_c909_9209, + 0xdbed_4677_2db5_8d48, + 0x11b9_4d50_76c7_b7b1, + })); + var c = new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0xe1c0_86bb_bf1b_5981, + 0x4faf_c3a9_aa70_5d7e, + 0x2734_b5c1_0bb7_e726, + 0xb2bd_7776_af03_7a3e, + 0x1b89_5fb3_98a8_4164, + 0x1730_4aef_6f11_3cec, + }), Fp.FromRawUnchecked(new ulong[] + { + 0x74c3_1c79_9519_1204, + 0x3271_aa54_79fd_ad2b, + 0xc9b4_7157_4915_a30f, + 0x65e4_0313_ec44_b8be, + 0x7487_b238_5b70_67cb, + 0x0952_3b26_d0ad_19a4, + })); + + Assert.AreEqual(c, a - b); + } + + [TestMethod] + public void TestNegation() + { + var a = new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0xc9a2_1831_63ee_70d4, + 0xbc37_70a7_196b_5c91, + 0xa247_f8c1_304c_5f44, + 0xb01f_c2a3_726c_80b5, + 0xe1d2_93e5_bbd9_19c9, + 0x04b7_8e80_020e_f2ca, + }), Fp.FromRawUnchecked(new ulong[] + { + 0x952e_a446_0462_618f, + 0x238d_5edd_f025_c62f, + 0xf6c9_4b01_2ea9_2e72, + 0x03ce_24ea_c1c9_3808, + 0x0559_50f9_45da_483c, + 0x010a_768d_0df4_eabc, + })); + var b = new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0xf05c_e7ce_9c11_39d7, + 0x6274_8f57_97e8_a36d, + 0xc4e8_d9df_c664_96df, + 0xb457_88e1_8118_9209, + 0x6949_13d0_8772_930d, + 0x1549_836a_3770_f3cf, + }), Fp.FromRawUnchecked(new ulong[] + { + 0x24d0_5bb9_fb9d_491c, + 0xfb1e_a120_c12e_39d0, + 0x7067_879f_c807_c7b1, + 0x60a9_269a_31bb_dab6, + 0x45c2_56bc_fd71_649b, + 0x18f6_9b5d_2b8a_fbde, + })); + + Assert.AreEqual(b, -a); + } + + [TestMethod] + public void TestSqrt() + { + // a = 1488924004771393321054797166853618474668089414631333405711627789629391903630694737978065425271543178763948256226639*u + 784063022264861764559335808165825052288770346101304131934508881646553551234697082295473567906267937225174620141295 + var a = new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0x2bee_d146_27d7_f9e9, + 0xb661_4e06_660e_5dce, + 0x06c4_cc7c_2f91_d42c, + 0x996d_7847_4b7a_63cc, + 0xebae_bc4c_820d_574e, + 0x1886_5e12_d93f_d845, + }), Fp.FromRawUnchecked(new ulong[] + { + 0x7d82_8664_baf4_f566, + 0xd17e_6639_96ec_7339, + 0x679e_ad55_cb40_78d0, + 0xfe3b_2260_e001_ec28, + 0x3059_93d0_43d9_1b68, + 0x0626_f03c_0489_b72d, + })); + + Assert.AreEqual(a, a.Sqrt().Square()); + + // b = 5, which is a generator of the p - 1 order + // multiplicative subgroup + var b = new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0x6631_0000_0010_5545, + 0x2114_0040_0eec_000d, + 0x3fa7_af30_c820_e316, + 0xc52a_8b8d_6387_695d, + 0x9fb4_e61d_1e83_eac5, + 0x005c_b922_afe8_4dc7, + }), Fp.Zero); + + Assert.AreEqual(b, b.Sqrt().Square()); + + // c = 25, which is a generator of the (p - 1) / 2 order + // multiplicative subgroup + var c = new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0x44f6_0000_0051_ffae, + 0x86b8_0141_9948_0043, + 0xd715_9952_f1f3_794a, + 0x755d_6e3d_fe1f_fc12, + 0xd36c_d6db_5547_e905, + 0x02f8_c8ec_bf18_67bb, + }), Fp.Zero); + + Assert.AreEqual(c, c.Sqrt().Square()); + + // 2155129644831861015726826462986972654175647013268275306775721078997042729172900466542651176384766902407257452753362*u + 2796889544896299244102912275102369318775038861758288697415827248356648685135290329705805931514906495247464901062529 + // is nonsquare. + Assert.ThrowsException(() => + new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0xc5fa_1bc8_fd00_d7f6, + 0x3830_ca45_4606_003b, + 0x2b28_7f11_04b1_02da, + 0xa7fb_30f2_8230_f23e, + 0x339c_db9e_e953_dbf0, + 0x0d78_ec51_d989_fc57, + }), Fp.FromRawUnchecked(new ulong[]{ + 0x27ec_4898_cf87_f613, + 0x9de1_394e_1abb_05a5, + 0x0947_f85d_c170_fc14, + 0x586f_bc69_6b61_14b7, + 0x2b34_75a4_077d_7169, + 0x13e1_c895_cc4b_6c22, + })).Sqrt()); + } + + [TestMethod] + public void TestInversion() + { + var a = new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0x1128_ecad_6754_9455, + 0x9e7a_1cff_3a4e_a1a8, + 0xeb20_8d51_e08b_cf27, + 0xe98a_d408_11f5_fc2b, + 0x736c_3a59_232d_511d, + 0x10ac_d42d_29cf_cbb6, + }), Fp.FromRawUnchecked(new ulong[] + { + 0xd328_e37c_c2f5_8d41, + 0x948d_f085_8a60_5869, + 0x6032_f9d5_6f93_a573, + 0x2be4_83ef_3fff_dc87, + 0x30ef_61f8_8f48_3c2a, + 0x1333_f55a_3572_5be0, + })); + + var b = new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0x0581_a133_3d4f_48a6, + 0x5824_2f6e_f074_8500, + 0x0292_c955_349e_6da5, + 0xba37_721d_dd95_fcd0, + 0x70d1_6790_3aa5_dfc5, + 0x1189_5e11_8b58_a9d5, + }), Fp.FromRawUnchecked(new ulong[] + { + 0x0eda_09d2_d7a8_5d17, + 0x8808_e137_a7d1_a2cf, + 0x43ae_2625_c1ff_21db, + 0xf85a_c9fd_f7a7_4c64, + 0x8fcc_dda5_b8da_9738, + 0x08e8_4f0c_b32c_d17d, + })); + Assert.AreEqual(b, a.Invert()); + + Assert.ThrowsException(() => Fp2.Zero.Invert()); + } + + [TestMethod] + public void TestLexicographicLargest() + { + Assert.IsFalse(Fp2.Zero.LexicographicallyLargest()); + Assert.IsFalse(Fp2.One.LexicographicallyLargest()); + Assert.IsTrue(new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0x1128_ecad_6754_9455, + 0x9e7a_1cff_3a4e_a1a8, + 0xeb20_8d51_e08b_cf27, + 0xe98a_d408_11f5_fc2b, + 0x736c_3a59_232d_511d, + 0x10ac_d42d_29cf_cbb6, + }), Fp.FromRawUnchecked(new ulong[] + { + 0xd328_e37c_c2f5_8d41, + 0x948d_f085_8a60_5869, + 0x6032_f9d5_6f93_a573, + 0x2be4_83ef_3fff_dc87, + 0x30ef_61f8_8f48_3c2a, + 0x1333_f55a_3572_5be0, + })).LexicographicallyLargest()); + Assert.IsFalse(new Fp2(-Fp.FromRawUnchecked(new ulong[] + { + 0x1128_ecad_6754_9455, + 0x9e7a_1cff_3a4e_a1a8, + 0xeb20_8d51_e08b_cf27, + 0xe98a_d408_11f5_fc2b, + 0x736c_3a59_232d_511d, + 0x10ac_d42d_29cf_cbb6, + }), -Fp.FromRawUnchecked(new ulong[] + { + 0xd328_e37c_c2f5_8d41, + 0x948d_f085_8a60_5869, + 0x6032_f9d5_6f93_a573, + 0x2be4_83ef_3fff_dc87, + 0x30ef_61f8_8f48_3c2a, + 0x1333_f55a_3572_5be0, + })).LexicographicallyLargest()); + Assert.IsFalse(new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0x1128_ecad_6754_9455, + 0x9e7a_1cff_3a4e_a1a8, + 0xeb20_8d51_e08b_cf27, + 0xe98a_d408_11f5_fc2b, + 0x736c_3a59_232d_511d, + 0x10ac_d42d_29cf_cbb6, + }), Fp.Zero).LexicographicallyLargest()); + Assert.IsTrue(new Fp2(-Fp.FromRawUnchecked(new ulong[] + { + 0x1128_ecad_6754_9455, + 0x9e7a_1cff_3a4e_a1a8, + 0xeb20_8d51_e08b_cf27, + 0xe98a_d408_11f5_fc2b, + 0x736c_3a59_232d_511d, + 0x10ac_d42d_29cf_cbb6, + }), Fp.Zero).LexicographicallyLargest()); + } +} diff --git a/tests/Neo.Cryptography.BLS12_381.Tests/UT_Fp6.cs b/tests/Neo.Cryptography.BLS12_381.Tests/UT_Fp6.cs new file mode 100644 index 0000000000..6fcc63fc97 --- /dev/null +++ b/tests/Neo.Cryptography.BLS12_381.Tests/UT_Fp6.cs @@ -0,0 +1,179 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_Fp6.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.Cryptography.BLS12_381.Tests; + +[TestClass] +public class UT_Fp6 +{ + [TestMethod] + public void TestArithmetic() + { + var a = new Fp6(new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0x47f9_cb98_b1b8_2d58, + 0x5fe9_11eb_a3aa_1d9d, + 0x96bf_1b5f_4dd8_1db3, + 0x8100_d27c_c925_9f5b, + 0xafa2_0b96_7464_0eab, + 0x09bb_cea7_d8d9_497d + }), c1: Fp.FromRawUnchecked(new ulong[] + { + 0x0303_cb98_b166_2daa, + 0xd931_10aa_0a62_1d5a, + 0xbfa9_820c_5be4_a468, + 0x0ba3_643e_cb05_a348, + 0xdc35_34bb_1f1c_25a6, + 0x06c3_05bb_19c0_e1c1 + })), c1: new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0x46f9_cb98_b162_d858, + 0x0be9_109c_f7aa_1d57, + 0xc791_bc55_fece_41d2, + 0xf84c_5770_4e38_5ec2, + 0xcb49_c1d9_c010_e60f, + 0x0acd_b8e1_58bf_e3c8 + }), c1: Fp.FromRawUnchecked(new ulong[] + { + 0x8aef_cb98_b15f_8306, + 0x3ea1_108f_e4f2_1d54, + 0xcf79_f69f_a1b7_df3b, + 0xe4f5_4aa1_d16b_1a3c, + 0xba5e_4ef8_6105_a679, + 0x0ed8_6c07_97be_e5cf + })), c2: new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0xcee5_cb98_b15c_2db4, + 0x7159_1082_d23a_1d51, + 0xd762_30e9_44a1_7ca4, + 0xd19e_3dd3_549d_d5b6, + 0xa972_dc17_01fa_66e3, + 0x12e3_1f2d_d6bd_e7d6 + }), c1: Fp.FromRawUnchecked(new ulong[] + { + 0xad2a_cb98_b173_2d9d, + 0x2cfd_10dd_0696_1d64, + 0x0739_6b86_c6ef_24e8, + 0xbd76_e2fd_b1bf_c820, + 0x6afe_a7f6_de94_d0d5, + 0x1099_4b0c_5744_c040 + }))); + + var b = new Fp6(new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0xf120_cb98_b16f_d84b, + 0x5fb5_10cf_f3de_1d61, + 0x0f21_a5d0_69d8_c251, + 0xaa1f_d62f_34f2_839a, + 0x5a13_3515_7f89_913f, + 0x14a3_fe32_9643_c247 + }), c1: Fp.FromRawUnchecked(new ulong[] + { + 0x3516_cb98_b16c_82f9, + 0x926d_10c2_e126_1d5f, + 0x1709_e01a_0cc2_5fba, + 0x96c8_c960_b825_3f14, + 0x4927_c234_207e_51a9, + 0x18ae_b158_d542_c44e + })), c1: new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0xbf0d_cb98_b169_82fc, + 0xa679_10b7_1d1a_1d5c, + 0xb7c1_47c2_b8fb_06ff, + 0x1efa_710d_47d2_e7ce, + 0xed20_a79c_7e27_653c, + 0x02b8_5294_dac1_dfba + }), c1: Fp.FromRawUnchecked(new ulong[] + { + 0x9d52_cb98_b180_82e5, + 0x621d_1111_5176_1d6f, + 0xe798_8260_3b48_af43, + 0x0ad3_1637_a4f4_da37, + 0xaeac_737c_5ac1_cf2e, + 0x006e_7e73_5b48_b824 + })), c2: new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0xe148_cb98_b17d_2d93, + 0x94d5_1104_3ebe_1d6c, + 0xef80_bca9_de32_4cac, + 0xf77c_0969_2827_95b1, + 0x9dc1_009a_fbb6_8f97, + 0x0479_3199_9a47_ba2b + }), c1: Fp.FromRawUnchecked(new ulong[] + { + 0x253e_cb98_b179_d841, + 0xc78d_10f7_2c06_1d6a, + 0xf768_f6f3_811b_ea15, + 0xe424_fc9a_ab5a_512b, + 0x8cd5_8db9_9cab_5001, + 0x0883_e4bf_d946_bc32 + }))); + + var c = new Fp6(new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0x6934_cb98_b176_82ef, + 0xfa45_10ea_194e_1d67, + 0xff51_313d_2405_877e, + 0xd0cd_efcc_2e8d_0ca5, + 0x7bea_1ad8_3da0_106b, + 0x0c8e_97e6_1845_be39 + }), c1: Fp.FromRawUnchecked(new ulong[] + { + 0x4779_cb98_b18d_82d8, + 0xb5e9_1144_4daa_1d7a, + 0x2f28_6bda_a653_2fc2, + 0xbca6_94f6_8bae_ff0f, + 0x3d75_e6b8_1a3a_7a5d, + 0x0a44_c3c4_98cc_96a3 + })), c1: new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0x8b6f_cb98_b18a_2d86, + 0xe8a1_1137_3af2_1d77, + 0x3710_a624_493c_cd2b, + 0xa94f_8828_0ee1_ba89, + 0x2c8a_73d6_bb2f_3ac7, + 0x0e4f_76ea_d7cb_98aa + }), c1: Fp.FromRawUnchecked(new ulong[] + { + 0xcf65_cb98_b186_d834, + 0x1b59_112a_283a_1d74, + 0x3ef8_e06d_ec26_6a95, + 0x95f8_7b59_9214_7603, + 0x1b9f_00f5_5c23_fb31, + 0x125a_2a11_16ca_9ab1 + })), c2: new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0x135b_cb98_b183_82e2, + 0x4e11_111d_1582_1d72, + 0x46e1_1ab7_8f10_07fe, + 0x82a1_6e8b_1547_317d, + 0x0ab3_8e13_fd18_bb9b, + 0x1664_dd37_55c9_9cb8 + }), c1: Fp.FromRawUnchecked(new ulong[] + { + 0xce65_cb98_b131_8334, + 0xc759_0fdb_7c3a_1d2e, + 0x6fcb_8164_9d1c_8eb3, + 0x0d44_004d_1727_356a, + 0x3746_b738_a7d0_d296, + 0x136c_144a_96b1_34fc + }))); + + Assert.AreEqual(a * a, a.Square()); + Assert.AreEqual(b * b, b.Square()); + Assert.AreEqual(c * c, c.Square()); + + Assert.AreEqual((a + b) * c.Square(), (c * c * a) + (c * c * b)); + + Assert.AreEqual(a.Invert() * b.Invert(), (a * b).Invert()); + Assert.AreEqual(Fp6.One, a.Invert() * a); + } +} diff --git a/tests/Neo.Cryptography.BLS12_381.Tests/UT_G1.cs b/tests/Neo.Cryptography.BLS12_381.Tests/UT_G1.cs new file mode 100644 index 0000000000..ab1a598b3c --- /dev/null +++ b/tests/Neo.Cryptography.BLS12_381.Tests/UT_G1.cs @@ -0,0 +1,603 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_G1.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 static Neo.Cryptography.BLS12_381.Constants; +using static Neo.Cryptography.BLS12_381.ConstantTimeUtility; +using static Neo.Cryptography.BLS12_381.G1Constants; + +namespace Neo.Cryptography.BLS12_381.Tests; + +[TestClass] +public class UT_G1 +{ + [TestMethod] + public void TestBeta() + { + Assert.AreEqual(Fp.FromBytes(new byte[] + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x19, 0x67, 0x2f, 0xdf, 0x76, + 0xce, 0x51, 0xba, 0x69, 0xc6, 0x07, 0x6a, 0x0f, 0x77, 0xea, 0xdd, 0xb3, 0xa9, 0x3b, + 0xe6, 0xf8, 0x96, 0x88, 0xde, 0x17, 0xd8, 0x13, 0x62, 0x0a, 0x00, 0x02, 0x2e, 0x01, + 0xff, 0xff, 0xff, 0xfe, 0xff, 0xfe + }), BETA); + Assert.AreNotEqual(Fp.One, BETA); + Assert.AreNotEqual(Fp.One, BETA * BETA); + Assert.AreEqual(Fp.One, BETA * BETA * BETA); + } + + [TestMethod] + public void TestIsOnCurve() + { + Assert.IsTrue(G1Affine.Identity.IsOnCurve); + Assert.IsTrue(G1Affine.Generator.IsOnCurve); + Assert.IsTrue(G1Projective.Identity.IsOnCurve); + Assert.IsTrue(G1Projective.Generator.IsOnCurve); + + Fp z = Fp.FromRawUnchecked(new ulong[] + { + 0xba7a_fa1f_9a6f_e250, + 0xfa0f_5b59_5eaf_e731, + 0x3bdc_4776_94c3_06e7, + 0x2149_be4b_3949_fa24, + 0x64aa_6e06_49b2_078c, + 0x12b1_08ac_3364_3c3e + }); + + var gen = G1Affine.Generator; + G1Projective test = new(gen.X * z, gen.Y * z, in z); + + Assert.IsTrue(test.IsOnCurve); + + test = new(in z, in test.Y, in test.Z); + Assert.IsFalse(test.IsOnCurve); + } + + [TestMethod] + public void TestAffinePointEquality() + { + var a = G1Affine.Generator; + var b = G1Affine.Identity; + + Assert.AreEqual(a, a); + Assert.AreEqual(b, b); + Assert.AreNotEqual(a, b); + } + + [TestMethod] + public void TestProjectivePointEquality() + { + var a = G1Projective.Generator; + var b = G1Projective.Identity; + + Assert.AreEqual(a, a); + Assert.AreEqual(b, b); + Assert.AreNotEqual(a, b); + + Fp z = Fp.FromRawUnchecked(new ulong[] + { + 0xba7a_fa1f_9a6f_e250, + 0xfa0f_5b59_5eaf_e731, + 0x3bdc_4776_94c3_06e7, + 0x2149_be4b_3949_fa24, + 0x64aa_6e06_49b2_078c, + 0x12b1_08ac_3364_3c3e + }); + + G1Projective c = new(a.X * z, a.Y * z, in z); + Assert.IsTrue(c.IsOnCurve); + + Assert.AreEqual(a, c); + Assert.AreNotEqual(b, c); + + c = new(in c.X, -c.Y, in c.Z); + Assert.IsTrue(c.IsOnCurve); + + Assert.AreNotEqual(a, c); + Assert.AreNotEqual(b, c); + + c = new(in z, -c.Y, in c.Z); + Assert.IsFalse(c.IsOnCurve); + Assert.AreNotEqual(a, b); + Assert.AreNotEqual(a, c); + Assert.AreNotEqual(b, c); + } + + [TestMethod] + public void TestConditionallySelectAffine() + { + var a = G1Affine.Generator; + var b = G1Affine.Identity; + + Assert.AreEqual(a, ConditionalSelect(in a, in b, false)); + Assert.AreEqual(b, ConditionalSelect(in a, in b, true)); + } + + [TestMethod] + public void TestConditionallySelectProjective() + { + var a = G1Projective.Generator; + var b = G1Projective.Identity; + + Assert.AreEqual(a, ConditionalSelect(in a, in b, false)); + Assert.AreEqual(b, ConditionalSelect(in a, in b, true)); + } + + [TestMethod] + public void TestProjectiveToAffine() + { + var a = G1Projective.Generator; + var b = G1Projective.Identity; + + Assert.IsTrue(new G1Affine(a).IsOnCurve); + Assert.IsFalse(new G1Affine(a).IsIdentity); + Assert.IsTrue(new G1Affine(b).IsOnCurve); + Assert.IsTrue(new G1Affine(b).IsIdentity); + + Fp z = Fp.FromRawUnchecked(new ulong[] + { + 0xba7a_fa1f_9a6f_e250, + 0xfa0f_5b59_5eaf_e731, + 0x3bdc_4776_94c3_06e7, + 0x2149_be4b_3949_fa24, + 0x64aa_6e06_49b2_078c, + 0x12b1_08ac_3364_3c3e + }); + + G1Projective c = new(a.X * z, a.Y * z, in z); + + Assert.AreEqual(G1Affine.Generator, new G1Affine(c)); + } + + [TestMethod] + public void TestAffineToProjective() + { + var a = G1Affine.Generator; + var b = G1Affine.Identity; + + Assert.IsTrue(new G1Projective(a).IsOnCurve); + Assert.IsFalse(new G1Projective(a).IsIdentity); + Assert.IsTrue(new G1Projective(b).IsOnCurve); + Assert.IsTrue(new G1Projective(b).IsIdentity); + } + + [TestMethod] + public void TestDoubling() + { + { + var tmp = G1Projective.Identity.Double(); + Assert.IsTrue(tmp.IsIdentity); + Assert.IsTrue(tmp.IsOnCurve); + } + { + var tmp = G1Projective.Generator.Double(); + Assert.IsFalse(tmp.IsIdentity); + Assert.IsTrue(tmp.IsOnCurve); + + Assert.AreEqual(new G1Affine(Fp.FromRawUnchecked(new ulong[] + { + 0x53e9_78ce_58a9_ba3c, + 0x3ea0_583c_4f3d_65f9, + 0x4d20_bb47_f001_2960, + 0xa54c_664a_e5b2_b5d9, + 0x26b5_52a3_9d7e_b21f, + 0x0008_895d_26e6_8785 + }), Fp.FromRawUnchecked(new ulong[] + { + 0x7011_0b32_9829_3940, + 0xda33_c539_3f1f_6afc, + 0xb86e_dfd1_6a5a_a785, + 0xaec6_d1c9_e7b1_c895, + 0x25cf_c2b5_22d1_1720, + 0x0636_1c83_f8d0_9b15 + })), new G1Affine(tmp)); + } + } + + [TestMethod] + public void TestProjectiveAddition() + { + { + var a = G1Projective.Identity; + var b = G1Projective.Identity; + var c = a + b; + Assert.IsTrue(c.IsIdentity); + Assert.IsTrue(c.IsOnCurve); + } + { + var a = G1Projective.Identity; + var b = G1Projective.Generator; + + Fp z = Fp.FromRawUnchecked(new ulong[] + { + 0xba7a_fa1f_9a6f_e250, + 0xfa0f_5b59_5eaf_e731, + 0x3bdc_4776_94c3_06e7, + 0x2149_be4b_3949_fa24, + 0x64aa_6e06_49b2_078c, + 0x12b1_08ac_3364_3c3e + }); + + b = new(b.X * z, b.Y * z, in z); + var c = a + b; + Assert.IsFalse(c.IsIdentity); + Assert.IsTrue(c.IsOnCurve); + Assert.AreEqual(G1Projective.Generator, c); + } + { + var a = G1Projective.Identity; + var b = G1Projective.Generator; + + Fp z = Fp.FromRawUnchecked(new ulong[] + { + 0xba7a_fa1f_9a6f_e250, + 0xfa0f_5b59_5eaf_e731, + 0x3bdc_4776_94c3_06e7, + 0x2149_be4b_3949_fa24, + 0x64aa_6e06_49b2_078c, + 0x12b1_08ac_3364_3c3e + }); + + b = new(b.X * z, b.Y * z, in z); + var c = b + a; + Assert.IsFalse(c.IsIdentity); + Assert.IsTrue(c.IsOnCurve); + Assert.AreEqual(G1Projective.Generator, c); + } + { + var a = G1Projective.Generator.Double().Double(); // 4P + var b = G1Projective.Generator.Double(); // 2P + var c = a + b; + + var d = G1Projective.Generator; + for (int i = 0; i < 5; i++) + { + d += G1Projective.Generator; + } + Assert.IsFalse(c.IsIdentity); + Assert.IsTrue(c.IsOnCurve); + Assert.IsFalse(d.IsIdentity); + Assert.IsTrue(d.IsOnCurve); + Assert.AreEqual(c, d); + } + { + Fp beta = Fp.FromRawUnchecked(new ulong[] + { + 0xcd03_c9e4_8671_f071, + 0x5dab_2246_1fcd_a5d2, + 0x5870_42af_d385_1b95, + 0x8eb6_0ebe_01ba_cb9e, + 0x03f9_7d6e_83d0_50d2, + 0x18f0_2065_5463_8741 + }); + beta = beta.Square(); + var a = G1Projective.Generator.Double().Double(); + var b = new G1Projective(a.X * beta, -a.Y, in a.Z); + Assert.IsTrue(a.IsOnCurve); + Assert.IsTrue(b.IsOnCurve); + + var c = a + b; + Assert.AreEqual(new G1Affine(new G1Projective(Fp.FromRawUnchecked(new ulong[] + { + 0x29e1_e987_ef68_f2d0, + 0xc5f3_ec53_1db0_3233, + 0xacd6_c4b6_ca19_730f, + 0x18ad_9e82_7bc2_bab7, + 0x46e3_b2c5_785c_c7a9, + 0x07e5_71d4_2d22_ddd6 + }), Fp.FromRawUnchecked(new ulong[] + { + 0x94d1_17a7_e5a5_39e7, + 0x8e17_ef67_3d4b_5d22, + 0x9d74_6aaf_508a_33ea, + 0x8c6d_883d_2516_c9a2, + 0x0bc3_b8d5_fb04_47f7, + 0x07bf_a4c7_210f_4f44, + }), in Fp.One)), new G1Affine(c)); + Assert.IsFalse(c.IsIdentity); + Assert.IsTrue(c.IsOnCurve); + } + } + + [TestMethod] + public void TestMixedAddition() + { + { + var a = G1Affine.Identity; + var b = G1Projective.Identity; + var c = a + b; + Assert.IsTrue(c.IsIdentity); + Assert.IsTrue(c.IsOnCurve); + } + { + var a = G1Affine.Identity; + var b = G1Projective.Generator; + + Fp z = Fp.FromRawUnchecked(new ulong[] + { + 0xba7a_fa1f_9a6f_e250, + 0xfa0f_5b59_5eaf_e731, + 0x3bdc_4776_94c3_06e7, + 0x2149_be4b_3949_fa24, + 0x64aa_6e06_49b2_078c, + 0x12b1_08ac_3364_3c3e + }); + + b = new(b.X * z, b.Y * z, in z); + var c = a + b; + Assert.IsFalse(c.IsIdentity); + Assert.IsTrue(c.IsOnCurve); + Assert.AreEqual(G1Projective.Generator, c); + } + { + var a = G1Affine.Identity; + var b = G1Projective.Generator; + + Fp z = Fp.FromRawUnchecked(new ulong[] + { + 0xba7a_fa1f_9a6f_e250, + 0xfa0f_5b59_5eaf_e731, + 0x3bdc_4776_94c3_06e7, + 0x2149_be4b_3949_fa24, + 0x64aa_6e06_49b2_078c, + 0x12b1_08ac_3364_3c3e + }); + + b = new(b.X * z, b.Y * z, in z); + var c = b + a; + Assert.IsFalse(c.IsIdentity); + Assert.IsTrue(c.IsOnCurve); + Assert.AreEqual(G1Projective.Generator, c); + } + { + var a = G1Projective.Generator.Double().Double(); // 4P + var b = G1Projective.Generator.Double(); // 2P + var c = a + b; + + var d = G1Projective.Generator; + for (int i = 0; i < 5; i++) + { + d += G1Affine.Generator; + } + Assert.IsFalse(c.IsIdentity); + Assert.IsTrue(c.IsOnCurve); + Assert.IsFalse(d.IsIdentity); + Assert.IsTrue(d.IsOnCurve); + Assert.AreEqual(c, d); + } + { + Fp beta = Fp.FromRawUnchecked(new ulong[] + { + 0xcd03_c9e4_8671_f071, + 0x5dab_2246_1fcd_a5d2, + 0x5870_42af_d385_1b95, + 0x8eb6_0ebe_01ba_cb9e, + 0x03f9_7d6e_83d0_50d2, + 0x18f0_2065_5463_8741 + }); + beta = beta.Square(); + var a = G1Projective.Generator.Double().Double(); + var b = new G1Projective(a.X * beta, -a.Y, in a.Z); + var a2 = new G1Affine(a); + Assert.IsTrue(a2.IsOnCurve); + Assert.IsTrue(b.IsOnCurve); + + var c = a2 + b; + Assert.AreEqual(new G1Affine(new G1Projective(Fp.FromRawUnchecked(new ulong[] + { + 0x29e1_e987_ef68_f2d0, + 0xc5f3_ec53_1db0_3233, + 0xacd6_c4b6_ca19_730f, + 0x18ad_9e82_7bc2_bab7, + 0x46e3_b2c5_785c_c7a9, + 0x07e5_71d4_2d22_ddd6 + }), Fp.FromRawUnchecked(new ulong[] + { + 0x94d1_17a7_e5a5_39e7, + 0x8e17_ef67_3d4b_5d22, + 0x9d74_6aaf_508a_33ea, + 0x8c6d_883d_2516_c9a2, + 0x0bc3_b8d5_fb04_47f7, + 0x07bf_a4c7_210f_4f44 + }), Fp.One)), new G1Affine(c)); + Assert.IsFalse(c.IsIdentity); + Assert.IsTrue(c.IsOnCurve); + } + } + + [TestMethod] + public void TestProjectiveNegationAndSubtraction() + { + var a = G1Projective.Generator.Double(); + Assert.AreEqual(a + (-a), G1Projective.Identity); + Assert.AreEqual(a + (-a), a - a); + } + + [TestMethod] + public void TestAffineNegationAndSubtraction() + { + var a = G1Affine.Generator; + Assert.AreEqual(G1Projective.Identity, new G1Projective(a) + (-a)); + Assert.AreEqual(new G1Projective(a) + (-a), new G1Projective(a) - a); + } + + [TestMethod] + public void TestProjectiveScalarMultiplication() + { + var g = G1Projective.Generator; + var a = Scalar.FromRaw(new ulong[] + { + 0x2b56_8297_a56d_a71c, + 0xd8c3_9ecb_0ef3_75d1, + 0x435c_38da_67bf_bf96, + 0x8088_a050_26b6_59b2 + }); + var b = Scalar.FromRaw(new ulong[] + { + 0x785f_dd9b_26ef_8b85, + 0xc997_f258_3769_5c18, + 0x4c8d_bc39_e7b7_56c1, + 0x70d9_b6cc_6d87_df20 + }); + var c = a * b; + + Assert.AreEqual(g * a * b, g * c); + } + + [TestMethod] + public void TestAffineScalarMultiplication() + { + var g = G1Affine.Generator; + var a = Scalar.FromRaw(new ulong[] + { + 0x2b56_8297_a56d_a71c, + 0xd8c3_9ecb_0ef3_75d1, + 0x435c_38da_67bf_bf96, + 0x8088_a050_26b6_59b2 + }); + var b = Scalar.FromRaw(new ulong[] + { + 0x785f_dd9b_26ef_8b85, + 0xc997_f258_3769_5c18, + 0x4c8d_bc39_e7b7_56c1, + 0x70d9_b6cc_6d87_df20 + }); + var c = a * b; + + Assert.AreEqual(new G1Affine(g * a) * b, g * c); + } + + [TestMethod] + public void TestIsTorsionFree() + { + var a = new G1Affine(Fp.FromRawUnchecked(new ulong[] + { + 0x0aba_f895_b97e_43c8, + 0xba4c_6432_eb9b_61b0, + 0x1250_6f52_adfe_307f, + 0x7502_8c34_3933_6b72, + 0x8474_4f05_b8e9_bd71, + 0x113d_554f_b095_54f7 + }), Fp.FromRawUnchecked(new ulong[] + { + 0x73e9_0e88_f5cf_01c0, + 0x3700_7b65_dd31_97e2, + 0x5cf9_a199_2f0d_7c78, + 0x4f83_c10b_9eb3_330d, + 0xf6a6_3f6f_07f6_0961, + 0x0c53_b5b9_7e63_4df3 + })); + Assert.IsFalse(a.IsTorsionFree); + + Assert.IsTrue(G1Affine.Identity.IsTorsionFree); + Assert.IsTrue(G1Affine.Generator.IsTorsionFree); + } + + [TestMethod] + public void TestMulByX() + { + // multiplying by `x` a point in G1 is the same as multiplying by + // the equivalent scalar. + var generator = G1Projective.Generator; + var x = BLS_X_IS_NEGATIVE ? -new Scalar(BLS_X) : new Scalar(BLS_X); + Assert.AreEqual(generator.MulByX(), generator * x); + + var point = G1Projective.Generator * new Scalar(42); + Assert.AreEqual(point.MulByX(), point * x); + } + + [TestMethod] + public void TestClearCofactor() + { + // the generator (and the identity) are always on the curve, + // even after clearing the cofactor + var generator = G1Projective.Generator; + Assert.IsTrue(generator.ClearCofactor().IsOnCurve); + var id = G1Projective.Identity; + Assert.IsTrue(id.ClearCofactor().IsOnCurve); + + var z = Fp.FromRawUnchecked(new ulong[] + { + 0x3d2d1c670671394e, + 0x0ee3a800a2f7c1ca, + 0x270f4f21da2e5050, + 0xe02840a53f1be768, + 0x55debeb597512690, + 0x08bd25353dc8f791 + }); + + var point = new G1Projective(Fp.FromRawUnchecked(new ulong[] + { + 0x48af5ff540c817f0, + 0xd73893acaf379d5a, + 0xe6c43584e18e023c, + 0x1eda39c30f188b3e, + 0xf618c6d3ccc0f8d8, + 0x0073542cd671e16c + }) * z, Fp.FromRawUnchecked(new ulong[] + { + 0x57bf8be79461d0ba, + 0xfc61459cee3547c3, + 0x0d23567df1ef147b, + 0x0ee187bcce1d9b64, + 0xb0c8cfbe9dc8fdc1, + 0x1328661767ef368b + }), z.Square() * z); + + Assert.IsTrue(point.IsOnCurve); + Assert.IsFalse(new G1Affine(point).IsTorsionFree); + var cleared_point = point.ClearCofactor(); + Assert.IsTrue(cleared_point.IsOnCurve); + Assert.IsTrue(new G1Affine(cleared_point).IsTorsionFree); + + // in BLS12-381 the cofactor in G1 can be + // cleared multiplying by (1-x) + var h_eff = new Scalar(1) + new Scalar(BLS_X); + Assert.AreEqual(point.ClearCofactor(), point * h_eff); + } + + [TestMethod] + public void TestBatchNormalize() + { + var a = G1Projective.Generator.Double(); + var b = a.Double(); + var c = b.Double(); + + foreach (bool a_identity in new[] { false, true }) + { + foreach (bool b_identity in new[] { false, true }) + { + foreach (bool c_identity in new[] { false, true }) + { + var v = new[] { a, b, c }; + if (a_identity) + { + v[0] = G1Projective.Identity; + } + if (b_identity) + { + v[1] = G1Projective.Identity; + } + if (c_identity) + { + v[2] = G1Projective.Identity; + } + + var t = new G1Affine[3]; + var expected = new[] { new G1Affine(v[0]), new G1Affine(v[1]), new G1Affine(v[2]) }; + + G1Projective.BatchNormalize(v, t); + + CollectionAssert.AreEqual(expected, t); + } + } + } + } +} diff --git a/tests/Neo.Cryptography.BLS12_381.Tests/UT_G2.cs b/tests/Neo.Cryptography.BLS12_381.Tests/UT_G2.cs new file mode 100644 index 0000000000..7b8cadb90e --- /dev/null +++ b/tests/Neo.Cryptography.BLS12_381.Tests/UT_G2.cs @@ -0,0 +1,823 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_G2.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 static Neo.Cryptography.BLS12_381.Constants; +using static Neo.Cryptography.BLS12_381.ConstantTimeUtility; + +namespace Neo.Cryptography.BLS12_381.Tests; + +[TestClass] +public class UT_G2 +{ + [TestMethod] + public void TestIsOnCurve() + { + Assert.IsTrue(G2Affine.Identity.IsOnCurve); + Assert.IsTrue(G2Affine.Generator.IsOnCurve); + Assert.IsTrue(G2Projective.Identity.IsOnCurve); + Assert.IsTrue(G2Projective.Generator.IsOnCurve); + + var z = new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0xba7a_fa1f_9a6f_e250, + 0xfa0f_5b59_5eaf_e731, + 0x3bdc_4776_94c3_06e7, + 0x2149_be4b_3949_fa24, + 0x64aa_6e06_49b2_078c, + 0x12b1_08ac_3364_3c3e + }), Fp.FromRawUnchecked(new ulong[] + { + 0x1253_25df_3d35_b5a8, + 0xdc46_9ef5_555d_7fe3, + 0x02d7_16d2_4431_06a9, + 0x05a1_db59_a6ff_37d0, + 0x7cf7_784e_5300_bb8f, + 0x16a8_8922_c7a5_e844 + })); + + var gen = G2Affine.Generator; + var test = new G2Projective(gen.X * z, gen.Y * z, z); + + Assert.IsTrue(test.IsOnCurve); + + test = new(in z, in test.Y, in test.Z); + Assert.IsFalse(test.IsOnCurve); + } + + [TestMethod] + public void TestAffinePointEquality() + { + var a = G2Affine.Generator; + var b = G2Affine.Identity; + + Assert.AreEqual(a, a); + Assert.AreEqual(b, b); + Assert.AreNotEqual(a, b); + } + + [TestMethod] + public void TestProjectivePointEquality() + { + var a = G2Projective.Generator; + var b = G2Projective.Identity; + + Assert.AreEqual(a, a); + Assert.AreEqual(b, b); + Assert.AreNotEqual(a, b); + + var z = new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0xba7a_fa1f_9a6f_e250, + 0xfa0f_5b59_5eaf_e731, + 0x3bdc_4776_94c3_06e7, + 0x2149_be4b_3949_fa24, + 0x64aa_6e06_49b2_078c, + 0x12b1_08ac_3364_3c3e + }), Fp.FromRawUnchecked(new ulong[] + { + 0x1253_25df_3d35_b5a8, + 0xdc46_9ef5_555d_7fe3, + 0x02d7_16d2_4431_06a9, + 0x05a1_db59_a6ff_37d0, + 0x7cf7_784e_5300_bb8f, + 0x16a8_8922_c7a5_e844 + })); + + var c = new G2Projective(a.X * z, a.Y * z, in z); + Assert.IsTrue(c.IsOnCurve); + + Assert.AreEqual(a, c); + Assert.AreNotEqual(b, c); + + c = new(in c.X, -c.Y, in c.Z); + Assert.IsTrue(c.IsOnCurve); + + Assert.AreNotEqual(a, c); + Assert.AreNotEqual(b, c); + + c = new(in z, -c.Y, in c.Z); + Assert.IsFalse(c.IsOnCurve); + Assert.AreNotEqual(a, b); + Assert.AreNotEqual(a, c); + Assert.AreNotEqual(b, c); + } + + [TestMethod] + public void TestConditionallySelectAffine() + { + var a = G2Affine.Generator; + var b = G2Affine.Identity; + + Assert.AreEqual(a, ConditionalSelect(in a, in b, false)); + Assert.AreEqual(b, ConditionalSelect(in a, in b, true)); + } + + [TestMethod] + public void TestConditionallySelectProjective() + { + var a = G2Projective.Generator; + var b = G2Projective.Identity; + + Assert.AreEqual(a, ConditionalSelect(in a, in b, false)); + Assert.AreEqual(b, ConditionalSelect(in a, in b, true)); + } + + [TestMethod] + public void TestProjectiveToAffine() + { + var a = G2Projective.Generator; + var b = G2Projective.Identity; + + Assert.IsTrue(new G2Affine(a).IsOnCurve); + Assert.IsFalse(new G2Affine(a).IsIdentity); + Assert.IsTrue(new G2Affine(b).IsOnCurve); + Assert.IsTrue(new G2Affine(b).IsIdentity); + + var z = new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0xba7a_fa1f_9a6f_e250, + 0xfa0f_5b59_5eaf_e731, + 0x3bdc_4776_94c3_06e7, + 0x2149_be4b_3949_fa24, + 0x64aa_6e06_49b2_078c, + 0x12b1_08ac_3364_3c3e + }), Fp.FromRawUnchecked(new ulong[] + { + 0x1253_25df_3d35_b5a8, + 0xdc46_9ef5_555d_7fe3, + 0x02d7_16d2_4431_06a9, + 0x05a1_db59_a6ff_37d0, + 0x7cf7_784e_5300_bb8f, + 0x16a8_8922_c7a5_e844 + })); + + var c = new G2Projective(a.X * z, a.Y * z, in z); + + Assert.AreEqual(G2Affine.Generator, new G2Affine(c)); + } + + [TestMethod] + public void TestAffineToProjective() + { + var a = G2Affine.Generator; + var b = G2Affine.Identity; + + Assert.IsTrue(new G2Projective(a).IsOnCurve); + Assert.IsFalse(new G2Projective(a).IsIdentity); + Assert.IsTrue(new G2Projective(b).IsOnCurve); + Assert.IsTrue(new G2Projective(b).IsIdentity); + } + + [TestMethod] + public void TestDoubling() + { + { + var tmp = G2Projective.Identity.Double(); + Assert.IsTrue(tmp.IsIdentity); + Assert.IsTrue(tmp.IsOnCurve); + } + { + var tmp = G2Projective.Generator.Double(); + Assert.IsFalse(tmp.IsIdentity); + Assert.IsTrue(tmp.IsOnCurve); + + Assert.AreEqual(new G2Affine(tmp), new G2Affine(new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0xe9d9_e2da_9620_f98b, + 0x54f1_1993_46b9_7f36, + 0x3db3_b820_376b_ed27, + 0xcfdb_31c9_b0b6_4f4c, + 0x41d7_c127_8635_4493, + 0x0571_0794_c255_c064 + }), Fp.FromRawUnchecked(new ulong[] + { + 0xd6c1_d3ca_6ea0_d06e, + 0xda0c_bd90_5595_489f, + 0x4f53_52d4_3479_221d, + 0x8ade_5d73_6f8c_97e0, + 0x48cc_8433_925e_f70e, + 0x08d7_ea71_ea91_ef81 + })), new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0x15ba_26eb_4b0d_186f, + 0x0d08_6d64_b7e9_e01e, + 0xc8b8_48dd_652f_4c78, + 0xeecf_46a6_123b_ae4f, + 0x255e_8dd8_b6dc_812a, + 0x1641_42af_21dc_f93f + }), Fp.FromRawUnchecked(new ulong[] + { + 0xf9b4_a1a8_9598_4db4, + 0xd417_b114_cccf_f748, + 0x6856_301f_c89f_086e, + 0x41c7_7787_8931_e3da, + 0x3556_b155_066a_2105, + 0x00ac_f7d3_25cb_89cf + })))); + } + } + + [TestMethod] + public void TestProjectiveAddition() + { + { + var a = G2Projective.Identity; + var b = G2Projective.Identity; + var c = a + b; + Assert.IsTrue(c.IsIdentity); + Assert.IsTrue(c.IsOnCurve); + } + { + var a = G2Projective.Identity; + var b = G2Projective.Generator; + { + var z = new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0xba7a_fa1f_9a6f_e250, + 0xfa0f_5b59_5eaf_e731, + 0x3bdc_4776_94c3_06e7, + 0x2149_be4b_3949_fa24, + 0x64aa_6e06_49b2_078c, + 0x12b1_08ac_3364_3c3e + }), Fp.FromRawUnchecked(new ulong[] + { + 0x1253_25df_3d35_b5a8, + 0xdc46_9ef5_555d_7fe3, + 0x02d7_16d2_4431_06a9, + 0x05a1_db59_a6ff_37d0, + 0x7cf7_784e_5300_bb8f, + 0x16a8_8922_c7a5_e844 + })); + + b = new G2Projective(b.X * z, b.Y * z, in z); + } + var c = a + b; + Assert.IsFalse(c.IsIdentity); + Assert.IsTrue(c.IsOnCurve); + Assert.AreEqual(G2Projective.Generator, c); + } + { + var a = G2Projective.Identity; + var b = G2Projective.Generator; + { + var z = new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0xba7a_fa1f_9a6f_e250, + 0xfa0f_5b59_5eaf_e731, + 0x3bdc_4776_94c3_06e7, + 0x2149_be4b_3949_fa24, + 0x64aa_6e06_49b2_078c, + 0x12b1_08ac_3364_3c3e + }), Fp.FromRawUnchecked(new ulong[] + { + 0x1253_25df_3d35_b5a8, + 0xdc46_9ef5_555d_7fe3, + 0x02d7_16d2_4431_06a9, + 0x05a1_db59_a6ff_37d0, + 0x7cf7_784e_5300_bb8f, + 0x16a8_8922_c7a5_e844 + })); + + b = new G2Projective(b.X * z, b.Y * z, in z); + } + var c = b + a; + Assert.IsFalse(c.IsIdentity); + Assert.IsTrue(c.IsOnCurve); + Assert.AreEqual(G2Projective.Generator, c); + } + { + var a = G2Projective.Generator.Double().Double(); // 4P + var b = G2Projective.Generator.Double(); // 2P + var c = a + b; + + var d = G2Projective.Generator; + for (int i = 0; i < 5; i++) + { + d += G2Projective.Generator; + } + Assert.IsFalse(c.IsIdentity); + Assert.IsTrue(c.IsOnCurve); + Assert.IsFalse(d.IsIdentity); + Assert.IsTrue(d.IsOnCurve); + Assert.AreEqual(c, d); + } + + // Degenerate case + { + var beta = new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0xcd03_c9e4_8671_f071, + 0x5dab_2246_1fcd_a5d2, + 0x5870_42af_d385_1b95, + 0x8eb6_0ebe_01ba_cb9e, + 0x03f9_7d6e_83d0_50d2, + 0x18f0_2065_5463_8741 + }), Fp.Zero); + beta = beta.Square(); + var a = G2Projective.Generator.Double().Double(); + var b = new G2Projective(a.X * beta, -a.Y, in a.Z); + Assert.IsTrue(a.IsOnCurve); + Assert.IsTrue(b.IsOnCurve); + + var c = a + b; + Assert.AreEqual( + new G2Affine(c), + new G2Affine(new G2Projective(new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0x705a_bc79_9ca7_73d3, + 0xfe13_2292_c1d4_bf08, + 0xf37e_ce3e_07b2_b466, + 0x887e_1c43_f447_e301, + 0x1e09_70d0_33bc_77e8, + 0x1985_c81e_20a6_93f2 + }), Fp.FromRawUnchecked(new ulong[] + { + 0x1d79_b25d_b36a_b924, + 0x2394_8e4d_5296_39d3, + 0x471b_a7fb_0d00_6297, + 0x2c36_d4b4_465d_c4c0, + 0x82bb_c3cf_ec67_f538, + 0x051d_2728_b67b_f952 + })), new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0x41b1_bbf6_576c_0abf, + 0xb6cc_9371_3f7a_0f9a, + 0x6b65_b43e_48f3_f01f, + 0xfb7a_4cfc_af81_be4f, + 0x3e32_dadc_6ec2_2cb6, + 0x0bb0_fc49_d798_07e3 + }), Fp.FromRawUnchecked(new ulong[] + { + 0x7d13_9778_8f5f_2ddf, + 0xab29_0714_4ff0_d8e8, + 0x5b75_73e0_cdb9_1f92, + 0x4cb8_932d_d31d_af28, + 0x62bb_fac6_db05_2a54, + 0x11f9_5c16_d14c_3bbe + })), Fp2.One))); + Assert.IsFalse(c.IsIdentity); + Assert.IsTrue(c.IsOnCurve); + } + } + + [TestMethod] + public void TestMixedAddition() + { + { + var a = G2Affine.Identity; + var b = G2Projective.Identity; + var c = a + b; + Assert.IsTrue(c.IsIdentity); + Assert.IsTrue(c.IsOnCurve); + } + { + var a = G2Affine.Identity; + var b = G2Projective.Generator; + { + var z = new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0xba7a_fa1f_9a6f_e250, + 0xfa0f_5b59_5eaf_e731, + 0x3bdc_4776_94c3_06e7, + 0x2149_be4b_3949_fa24, + 0x64aa_6e06_49b2_078c, + 0x12b1_08ac_3364_3c3e + }), Fp.FromRawUnchecked(new ulong[] + { + 0x1253_25df_3d35_b5a8, + 0xdc46_9ef5_555d_7fe3, + 0x02d7_16d2_4431_06a9, + 0x05a1_db59_a6ff_37d0, + 0x7cf7_784e_5300_bb8f, + 0x16a8_8922_c7a5_e844 + })); + + b = new G2Projective(b.X * z, b.Y * z, in z); + } + var c = a + b; + Assert.IsFalse(c.IsIdentity); + Assert.IsTrue(c.IsOnCurve); + Assert.AreEqual(G2Projective.Generator, c); + } + { + var a = G2Affine.Identity; + var b = G2Projective.Generator; + { + var z = new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0xba7a_fa1f_9a6f_e250, + 0xfa0f_5b59_5eaf_e731, + 0x3bdc_4776_94c3_06e7, + 0x2149_be4b_3949_fa24, + 0x64aa_6e06_49b2_078c, + 0x12b1_08ac_3364_3c3e + }), Fp.FromRawUnchecked(new ulong[] + { + 0x1253_25df_3d35_b5a8, + 0xdc46_9ef5_555d_7fe3, + 0x02d7_16d2_4431_06a9, + 0x05a1_db59_a6ff_37d0, + 0x7cf7_784e_5300_bb8f, + 0x16a8_8922_c7a5_e844 + })); + + b = new G2Projective(b.X * z, b.Y * z, in z); + } + var c = b + a; + Assert.IsFalse(c.IsIdentity); + Assert.IsTrue(c.IsOnCurve); + Assert.AreEqual(G2Projective.Generator, c); + } + { + var a = G2Projective.Generator.Double().Double(); // 4P + var b = G2Projective.Generator.Double(); // 2P + var c = a + b; + + var d = G2Projective.Generator; + for (int i = 0; i < 5; i++) + { + d += G2Affine.Generator; + } + Assert.IsFalse(c.IsIdentity); + Assert.IsTrue(c.IsOnCurve); + Assert.IsFalse(d.IsIdentity); + Assert.IsTrue(d.IsOnCurve); + Assert.AreEqual(c, d); + } + + // Degenerate case + { + var beta = new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0xcd03_c9e4_8671_f071, + 0x5dab_2246_1fcd_a5d2, + 0x5870_42af_d385_1b95, + 0x8eb6_0ebe_01ba_cb9e, + 0x03f9_7d6e_83d0_50d2, + 0x18f0_2065_5463_8741 + }), Fp.Zero); + beta = beta.Square(); + var _a = G2Projective.Generator.Double().Double(); + var b = new G2Projective(_a.X * beta, -_a.Y, in _a.Z); + var a = new G2Affine(_a); + Assert.IsTrue((a.IsOnCurve)); + Assert.IsTrue((b.IsOnCurve)); + + var c = a + b; + Assert.AreEqual(new G2Affine(new G2Projective(new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0x705a_bc79_9ca7_73d3, + 0xfe13_2292_c1d4_bf08, + 0xf37e_ce3e_07b2_b466, + 0x887e_1c43_f447_e301, + 0x1e09_70d0_33bc_77e8, + 0x1985_c81e_20a6_93f2 + }), Fp.FromRawUnchecked(new ulong[] + { + 0x1d79_b25d_b36a_b924, + 0x2394_8e4d_5296_39d3, + 0x471b_a7fb_0d00_6297, + 0x2c36_d4b4_465d_c4c0, + 0x82bb_c3cf_ec67_f538, + 0x051d_2728_b67b_f952 + })), new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0x41b1_bbf6_576c_0abf, + 0xb6cc_9371_3f7a_0f9a, + 0x6b65_b43e_48f3_f01f, + 0xfb7a_4cfc_af81_be4f, + 0x3e32_dadc_6ec2_2cb6, + 0x0bb0_fc49_d798_07e3 + }), Fp.FromRawUnchecked(new ulong[] + { + 0x7d13_9778_8f5f_2ddf, + 0xab29_0714_4ff0_d8e8, + 0x5b75_73e0_cdb9_1f92, + 0x4cb8_932d_d31d_af28, + 0x62bb_fac6_db05_2a54, + 0x11f9_5c16_d14c_3bbe + })), Fp2.One)), new G2Affine(c)); + Assert.IsFalse(c.IsIdentity); + Assert.IsTrue(c.IsOnCurve); + } + } + + [TestMethod] + public void TestProjectiveNegationAndSubtraction() + { + var a = G2Projective.Generator.Double(); + Assert.AreEqual(G2Projective.Identity, a + (-a)); + Assert.AreEqual(a - a, a + (-a)); + } + + [TestMethod] + public void TestAffineNegationAndSubtraction() + { + var a = G2Affine.Generator; + Assert.AreEqual(G2Projective.Identity, new G2Projective(a) + (-a)); + Assert.AreEqual(new G2Projective(a) - a, new G2Projective(a) + (-a)); + } + + [TestMethod] + public void TestProjectiveScalarMultiplication() + { + var g = G2Projective.Generator; + var a = Scalar.FromRaw(new ulong[] + { + 0x2b56_8297_a56d_a71c, + 0xd8c3_9ecb_0ef3_75d1, + 0x435c_38da_67bf_bf96, + 0x8088_a050_26b6_59b2 + }); + var b = Scalar.FromRaw(new ulong[] + { + 0x785f_dd9b_26ef_8b85, + 0xc997_f258_3769_5c18, + 0x4c8d_bc39_e7b7_56c1, + 0x70d9_b6cc_6d87_df20 + }); + var c = a * b; + + Assert.AreEqual(g * c, g * a * b); + } + + [TestMethod] + public void TestAffineScalarMultiplication() + { + var g = G2Affine.Generator; + var a = Scalar.FromRaw(new ulong[] + { + 0x2b56_8297_a56d_a71c, + 0xd8c3_9ecb_0ef3_75d1, + 0x435c_38da_67bf_bf96, + 0x8088_a050_26b6_59b2 + }); + var b = Scalar.FromRaw(new ulong[] + { + 0x785f_dd9b_26ef_8b85, + 0xc997_f258_3769_5c18, + 0x4c8d_bc39_e7b7_56c1, + 0x70d9_b6cc_6d87_df20 + }); + var c = a * b; + + Assert.AreEqual(g * c, new G2Affine(g * a) * b); + } + + [TestMethod] + public void TestIsTorsionFree() + { + var a = new G2Affine(new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0x89f5_50c8_13db_6431, + 0xa50b_e8c4_56cd_8a1a, + 0xa45b_3741_14ca_e851, + 0xbb61_90f5_bf7f_ff63, + 0x970c_a02c_3ba8_0bc7, + 0x02b8_5d24_e840_fbac + }), + Fp.FromRawUnchecked(new ulong[] + { + 0x6888_bc53_d707_16dc, + 0x3dea_6b41_1768_2d70, + 0xd8f5_f930_500c_a354, + 0x6b5e_cb65_56f5_c155, + 0xc96b_ef04_3477_8ab0, + 0x0508_1505_5150_06ad + })), new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0x3cf1_ea0d_434b_0f40, + 0x1a0d_c610_e603_e333, + 0x7f89_9561_60c7_2fa0, + 0x25ee_03de_cf64_31c5, + 0xeee8_e206_ec0f_e137, + 0x0975_92b2_26df_ef28 + }), Fp.FromRawUnchecked(new ulong[] + { + 0x71e8_bb5f_2924_7367, + 0xa5fe_049e_2118_31ce, + 0x0ce6_b354_502a_3896, + 0x93b0_1200_0997_314e, + 0x6759_f3b6_aa5b_42ac, + 0x1569_44c4_dfe9_2bbb + }))); + Assert.IsFalse(a.IsTorsionFree); + + Assert.IsTrue(G2Affine.Identity.IsTorsionFree); + Assert.IsTrue(G2Affine.Generator.IsTorsionFree); + } + + [TestMethod] + public void TestMulByX() + { + // multiplying by `x` a point in G2 is the same as multiplying by + // the equivalent scalar. + var generator = G2Projective.Generator; + var x = BLS_X_IS_NEGATIVE ? -new Scalar(BLS_X) : new Scalar(BLS_X); + Assert.AreEqual(generator * x, generator.MulByX()); + + var point = G2Projective.Generator * new Scalar(42); + Assert.AreEqual(point * x, point.MulByX()); + } + + [TestMethod] + public void TestPsi() + { + var generator = G2Projective.Generator; + + var z = new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0x0ef2ddffab187c0a, + 0x2424522b7d5ecbfc, + 0xc6f341a3398054f4, + 0x5523ddf409502df0, + 0xd55c0b5a88e0dd97, + 0x066428d704923e52 + }), Fp.FromRawUnchecked(new ulong[] + { + 0x538bbe0c95b4878d, + 0xad04a50379522881, + 0x6d5c05bf5c12fb64, + 0x4ce4a069a2d34787, + 0x59ea6c8d0dffaeaf, + 0x0d42a083a75bd6f3 + })); + + // `point` is a random point in the curve + var point = new G2Projective(new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0xee4c8cb7c047eaf2, + 0x44ca22eee036b604, + 0x33b3affb2aefe101, + 0x15d3e45bbafaeb02, + 0x7bfc2154cd7419a4, + 0x0a2d0c2b756e5edc + }), Fp.FromRawUnchecked(new ulong[] + { + 0xfc224361029a8777, + 0x4cbf2baab8740924, + 0xc5008c6ec6592c89, + 0xecc2c57b472a9c2d, + 0x8613eafd9d81ffb1, + 0x10fe54daa2d3d495 + })) * z, new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0x7de7edc43953b75c, + 0x58be1d2de35e87dc, + 0x5731d30b0e337b40, + 0xbe93b60cfeaae4c9, + 0x8b22c203764bedca, + 0x01616c8d1033b771 + }), Fp.FromRawUnchecked(new ulong[] + { + 0xea126fe476b5733b, + 0x85cee68b5dae1652, + 0x98247779f7272b04, + 0xa649c8b468c6e808, + 0xb5b9a62dff0c4e45, + 0x1555b67fc7bbe73d + })), z.Square() * z); + Assert.IsTrue(point.IsOnCurve); + + // psi2(P) = psi(psi(P)) + Assert.AreEqual(generator.Psi2(), generator.Psi().Psi()); + Assert.AreEqual(point.Psi2(), point.Psi().Psi()); + // psi(P) is a morphism + Assert.AreEqual(generator.Double().Psi(), generator.Psi().Double()); + Assert.AreEqual(point.Psi() + generator.Psi(), (point + generator).Psi()); + // psi(P) behaves in the same way on the same projective point + var normalized_points = new G2Affine[1]; + G2Projective.BatchNormalize(new[] { point }, normalized_points); + var normalized_point = new G2Projective(normalized_points[0]); + Assert.AreEqual(point.Psi(), normalized_point.Psi()); + Assert.AreEqual(point.Psi2(), normalized_point.Psi2()); + } + + [TestMethod] + public void TestClearCofactor() + { + var z = new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0x0ef2ddffab187c0a, + 0x2424522b7d5ecbfc, + 0xc6f341a3398054f4, + 0x5523ddf409502df0, + 0xd55c0b5a88e0dd97, + 0x066428d704923e52 + }), Fp.FromRawUnchecked(new ulong[] + { + 0x538bbe0c95b4878d, + 0xad04a50379522881, + 0x6d5c05bf5c12fb64, + 0x4ce4a069a2d34787, + 0x59ea6c8d0dffaeaf, + 0x0d42a083a75bd6f3 + })); + + // `point` is a random point in the curve + var point = new G2Projective(new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0xee4c8cb7c047eaf2, + 0x44ca22eee036b604, + 0x33b3affb2aefe101, + 0x15d3e45bbafaeb02, + 0x7bfc2154cd7419a4, + 0x0a2d0c2b756e5edc + }), Fp.FromRawUnchecked(new ulong[] + { + 0xfc224361029a8777, + 0x4cbf2baab8740924, + 0xc5008c6ec6592c89, + 0xecc2c57b472a9c2d, + 0x8613eafd9d81ffb1, + 0x10fe54daa2d3d495 + })) * z, new Fp2(Fp.FromRawUnchecked(new ulong[] + { + 0x7de7edc43953b75c, + 0x58be1d2de35e87dc, + 0x5731d30b0e337b40, + 0xbe93b60cfeaae4c9, + 0x8b22c203764bedca, + 0x01616c8d1033b771 + }), Fp.FromRawUnchecked(new ulong[] + { + 0xea126fe476b5733b, + 0x85cee68b5dae1652, + 0x98247779f7272b04, + 0xa649c8b468c6e808, + 0xb5b9a62dff0c4e45, + 0x1555b67fc7bbe73d + })), z.Square() * z); + + Assert.IsTrue(point.IsOnCurve); + Assert.IsFalse(new G2Affine(point).IsTorsionFree); + var cleared_point = point.ClearCofactor(); + + Assert.IsTrue(cleared_point.IsOnCurve); + Assert.IsTrue(new G2Affine(cleared_point).IsTorsionFree); + + // the generator (and the identity) are always on the curve, + // even after clearing the cofactor + var generator = G2Projective.Generator; + Assert.IsTrue(generator.ClearCofactor().IsOnCurve); + var id = G2Projective.Identity; + Assert.IsTrue(id.ClearCofactor().IsOnCurve); + + // test the effect on q-torsion points multiplying by h_eff modulo |Scalar| + // h_eff % q = 0x2b116900400069009a40200040001ffff + byte[] h_eff_modq = + { + 0xff, 0xff, 0x01, 0x00, 0x04, 0x00, 0x02, 0xa4, 0x09, 0x90, 0x06, 0x00, 0x04, 0x90, 0x16, + 0xb1, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00 + }; + Assert.AreEqual(generator * h_eff_modq, generator.ClearCofactor()); + Assert.AreEqual(cleared_point * h_eff_modq, cleared_point.ClearCofactor()); + } + + [TestMethod] + public void TestBatchNormalize() + { + var a = G2Projective.Generator.Double(); + var b = a.Double(); + var c = b.Double(); + + foreach (bool a_identity in new[] { false, true }) + { + foreach (bool b_identity in new[] { false, true }) + { + foreach (bool c_identity in new[] { false, true }) + { + var v = new[] { a, b, c }; + if (a_identity) + { + v[0] = G2Projective.Identity; + } + if (b_identity) + { + v[1] = G2Projective.Identity; + } + if (c_identity) + { + v[2] = G2Projective.Identity; + } + + var t = new G2Affine[3]; + var expected = new[] { new G2Affine(v[0]), new G2Affine(v[1]), new G2Affine(v[2]) }; + + G2Projective.BatchNormalize(v, t); + + CollectionAssert.AreEqual(t, expected); + } + } + } + } +} diff --git a/tests/Neo.Cryptography.BLS12_381.Tests/UT_Pairings.cs b/tests/Neo.Cryptography.BLS12_381.Tests/UT_Pairings.cs new file mode 100644 index 0000000000..9019477a8f --- /dev/null +++ b/tests/Neo.Cryptography.BLS12_381.Tests/UT_Pairings.cs @@ -0,0 +1,69 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_Pairings.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.Cryptography.BLS12_381.Tests; + +[TestClass] +public class UT_Pairings +{ + [TestMethod] + public void TestGtGenerator() + { + Assert.AreEqual( + Gt.Generator, + Bls12.Pairing(in G1Affine.Generator, in G2Affine.Generator) + ); + } + + [TestMethod] + public void TestBilinearity() + { + var a = Scalar.FromRaw(new ulong[] { 1, 2, 3, 4 }).Invert().Square(); + var b = Scalar.FromRaw(new ulong[] { 5, 6, 7, 8 }).Invert().Square(); + var c = a * b; + + var g = new G1Affine(G1Affine.Generator * a); + var h = new G2Affine(G2Affine.Generator * b); + var p = Bls12.Pairing(in g, in h); + + Assert.AreNotEqual(Gt.Identity, p); + + var expected = new G1Affine(G1Affine.Generator * c); + + Assert.AreEqual(p, Bls12.Pairing(in expected, in G2Affine.Generator)); + Assert.AreEqual( + p, + Bls12.Pairing(in G1Affine.Generator, in G2Affine.Generator) * c + ); + } + + [TestMethod] + public void TestUnitary() + { + var g = G1Affine.Generator; + var h = G2Affine.Generator; + var p = -Bls12.Pairing(in g, in h); + var q = Bls12.Pairing(in g, -h); + var r = Bls12.Pairing(-g, in h); + + Assert.AreEqual(p, q); + Assert.AreEqual(q, r); + } + + [TestMethod] + public void TestMillerLoopResultDefault() + { + Assert.AreEqual( + Gt.Identity, + new MillerLoopResult(Fp12.One).FinalExponentiation() + ); + } +} diff --git a/tests/Neo.Cryptography.BLS12_381.Tests/UT_Scalar.cs b/tests/Neo.Cryptography.BLS12_381.Tests/UT_Scalar.cs new file mode 100644 index 0000000000..03c1526a7b --- /dev/null +++ b/tests/Neo.Cryptography.BLS12_381.Tests/UT_Scalar.cs @@ -0,0 +1,411 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_Scalar.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 static Neo.Cryptography.BLS12_381.ScalarConstants; + +namespace Neo.Cryptography.BLS12_381.Tests; + +[TestClass] +public class UT_Scalar +{ + private static readonly Scalar LARGEST = new(new ulong[] + { + 0xffff_ffff_0000_0000, + 0x53bd_a402_fffe_5bfe, + 0x3339_d808_09a1_d805, + 0x73ed_a753_299d_7d48 + }); + + [TestMethod] + public void TestInv() + { + // Compute -(q^{-1} mod 2^64) mod 2^64 by exponentiating + // by totient(2**64) - 1 + + var inv = 1ul; + for (int i = 0; i < 63; i++) + { + inv = unchecked(inv * inv); + inv = unchecked(inv * MODULUS_LIMBS_64[0]); + } + inv = unchecked(~inv + 1); + + Assert.AreEqual(INV, inv); + } + + [TestMethod] + public void TestToString() + { + Assert.AreEqual("0x0000000000000000000000000000000000000000000000000000000000000000", Scalar.Zero.ToString()); + Assert.AreEqual("0x0000000000000000000000000000000000000000000000000000000000000001", Scalar.One.ToString()); + Assert.AreEqual("0x1824b159acc5056f998c4fefecbc4ff55884b7fa0003480200000001fffffffe", R2.ToString()); + } + + [TestMethod] + public void TestEquality() + { + Assert.AreEqual(Scalar.Zero, Scalar.Zero); + Assert.AreEqual(Scalar.One, Scalar.One); + Assert.AreEqual(R2, R2); + + Assert.AreNotEqual(Scalar.Zero, Scalar.One); + Assert.AreNotEqual(Scalar.One, R2); + } + + [TestMethod] + public void TestToBytes() + { + CollectionAssert.AreEqual(new byte[] + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0 + }, Scalar.Zero.ToArray()); + + CollectionAssert.AreEqual(new byte[] + { + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0 + }, Scalar.One.ToArray()); + + CollectionAssert.AreEqual(new byte[] + { + 254, 255, 255, 255, 1, 0, 0, 0, 2, 72, 3, 0, 250, 183, 132, 88, 245, 79, 188, 236, 239, + 79, 140, 153, 111, 5, 197, 172, 89, 177, 36, 24 + }, R2.ToArray()); + + CollectionAssert.AreEqual(new byte[] + { + 0, 0, 0, 0, 255, 255, 255, 255, 254, 91, 254, 255, 2, 164, 189, 83, 5, 216, 161, 9, 8, + 216, 57, 51, 72, 125, 157, 41, 83, 167, 237, 115 + }, (-Scalar.One).ToArray()); + } + + [TestMethod] + public void TestFromBytes() + { + Assert.AreEqual(Scalar.Zero, Scalar.FromBytes(new byte[] + { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0 + })); + + Assert.AreEqual(Scalar.One, Scalar.FromBytes(new byte[] + { + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0 + })); + + Assert.AreEqual(R2, Scalar.FromBytes(new byte[] + { + 254, 255, 255, 255, 1, 0, 0, 0, 2, 72, 3, 0, 250, 183, 132, 88, 245, 79, 188, 236, 239, + 79, 140, 153, 111, 5, 197, 172, 89, 177, 36, 24 + })); + + // -1 should work + Scalar.FromBytes(new byte[] + { + 0, 0, 0, 0, 255, 255, 255, 255, 254, 91, 254, 255, 2, 164, 189, 83, 5, 216, 161, 9, 8, + 216, 57, 51, 72, 125, 157, 41, 83, 167, 237, 115 + }); + + // modulus is invalid + Assert.ThrowsException(() => Scalar.FromBytes(new byte[] + { + 1, 0, 0, 0, 255, 255, 255, 255, 254, 91, 254, 255, 2, 164, 189, 83, 5, 216, 161, 9, 8, + 216, 57, 51, 72, 125, 157, 41, 83, 167, 237, 115 + })); + + // Anything larger than the modulus is invalid + Assert.ThrowsException(() => Scalar.FromBytes(new byte[] + { + 2, 0, 0, 0, 255, 255, 255, 255, 254, 91, 254, 255, 2, 164, 189, 83, 5, 216, 161, 9, 8, + 216, 57, 51, 72, 125, 157, 41, 83, 167, 237, 115 + })); + Assert.ThrowsException(() => Scalar.FromBytes(new byte[] + { + 1, 0, 0, 0, 255, 255, 255, 255, 254, 91, 254, 255, 2, 164, 189, 83, 5, 216, 161, 9, 8, + 216, 58, 51, 72, 125, 157, 41, 83, 167, 237, 115 + })); + Assert.ThrowsException(() => Scalar.FromBytes(new byte[] + { + 1, 0, 0, 0, 255, 255, 255, 255, 254, 91, 254, 255, 2, 164, 189, 83, 5, 216, 161, 9, 8, + 216, 57, 51, 72, 125, 157, 41, 83, 167, 237, 116 + })); + } + + [TestMethod] + public void TestFromBytesWideR2() + { + Assert.AreEqual(R2, Scalar.FromBytesWide(new byte[] + { + 254, 255, 255, 255, 1, 0, 0, 0, 2, 72, 3, 0, 250, 183, 132, 88, 245, 79, 188, 236, 239, + 79, 140, 153, 111, 5, 197, 172, 89, 177, 36, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + })); + } + + [TestMethod] + public void TestFromBytesWideNegativeOne() + { + Assert.AreEqual(-Scalar.One, Scalar.FromBytesWide(new byte[] + { + 0, 0, 0, 0, 255, 255, 255, 255, 254, 91, 254, 255, 2, 164, 189, 83, 5, 216, 161, 9, 8, + 216, 57, 51, 72, 125, 157, 41, 83, 167, 237, 115, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + })); + } + + [TestMethod] + public void TestFromBytesWideMaximum() + { + Assert.AreEqual(new Scalar(new ulong[] + { + 0xc62c_1805_439b_73b1, + 0xc2b9_551e_8ced_218e, + 0xda44_ec81_daf9_a422, + 0x5605_aa60_1c16_2e79 + }), Scalar.FromBytesWide(Enumerable.Repeat(0xff, 64).ToArray())); + } + + [TestMethod] + public void TestZero() + { + Assert.AreEqual(Scalar.Zero, -Scalar.Zero); + Assert.AreEqual(Scalar.Zero, Scalar.Zero + Scalar.Zero); + Assert.AreEqual(Scalar.Zero, Scalar.Zero - Scalar.Zero); + Assert.AreEqual(Scalar.Zero, Scalar.Zero * Scalar.Zero); + } + + [TestMethod] + public void TestAddition() + { + var tmp = LARGEST; + tmp += LARGEST; + + Assert.AreEqual(new Scalar(new ulong[] + { + 0xffff_fffe_ffff_ffff, + 0x53bd_a402_fffe_5bfe, + 0x3339_d808_09a1_d805, + 0x73ed_a753_299d_7d48 + }), tmp); + + tmp = LARGEST; + tmp += new Scalar(new ulong[] { 1, 0, 0, 0 }); + + Assert.AreEqual(Scalar.Zero, tmp); + } + + [TestMethod] + public void TestNegation() + { + var tmp = -LARGEST; + + Assert.AreEqual(new Scalar(new ulong[] { 1, 0, 0, 0 }), tmp); + + tmp = -Scalar.Zero; + Assert.AreEqual(Scalar.Zero, tmp); + tmp = -new Scalar(new ulong[] { 1, 0, 0, 0 }); + Assert.AreEqual(LARGEST, tmp); + } + + [TestMethod] + public void TestSubtraction() + { + var tmp = LARGEST; + tmp -= LARGEST; + + Assert.AreEqual(Scalar.Zero, tmp); + + tmp = Scalar.Zero; + tmp -= LARGEST; + + var tmp2 = MODULUS; + tmp2 -= LARGEST; + + Assert.AreEqual(tmp, tmp2); + } + + [TestMethod] + public void TestMultiplication() + { + var cur = LARGEST; + + for (int i = 0; i < 100; i++) + { + var tmp = cur; + tmp *= cur; + + var tmp2 = Scalar.Zero; + foreach (bool b in cur + .ToArray() + .SelectMany(p => Enumerable.Range(0, 8).Select(q => ((p >> q) & 1) == 1)) + .Reverse()) + { + var tmp3 = tmp2; + tmp2 += tmp3; + + if (b) + { + tmp2 += cur; + } + } + + Assert.AreEqual(tmp, tmp2); + + cur += LARGEST; + } + } + + [TestMethod] + public void TestSquaring() + { + var cur = LARGEST; + + for (int i = 0; i < 100; i++) + { + var tmp = cur; + tmp = tmp.Square(); + + var tmp2 = Scalar.Zero; + foreach (bool b in cur + .ToArray() + .SelectMany(p => Enumerable.Range(0, 8).Select(q => ((p >> q) & 1) == 1)) + .Reverse()) + { + var tmp3 = tmp2; + tmp2 += tmp3; + + if (b) + { + tmp2 += cur; + } + } + + Assert.AreEqual(tmp, tmp2); + + cur += LARGEST; + } + } + + [TestMethod] + public void TestInversion() + { + Assert.ThrowsException(() => Scalar.Zero.Invert()); + Assert.AreEqual(Scalar.One, Scalar.One.Invert()); + Assert.AreEqual(-Scalar.One, (-Scalar.One).Invert()); + + var tmp = R2; + + for (int i = 0; i < 100; i++) + { + var tmp2 = tmp.Invert(); + tmp2 *= tmp; + + Assert.AreEqual(Scalar.One, tmp2); + + tmp += R2; + } + } + + [TestMethod] + public void TestInvertIsPow() + { + ulong[] q_minus_2 = + { + 0xffff_fffe_ffff_ffff, + 0x53bd_a402_fffe_5bfe, + 0x3339_d808_09a1_d805, + 0x73ed_a753_299d_7d48 + }; + + var r1 = R; + var r2 = R; + var r3 = R; + + for (int i = 0; i < 100; i++) + { + r1 = r1.Invert(); + r2 = r2.PowVartime(q_minus_2); + r3 = r3.Pow(q_minus_2); + + Assert.AreEqual(r1, r2); + Assert.AreEqual(r2, r3); + // Add R so we check something different next time around + r1 += R; + r2 = r1; + r3 = r1; + } + } + + [TestMethod] + public void TestSqrt() + { + Assert.AreEqual(Scalar.Zero.Sqrt(), Scalar.Zero); + + var square = new Scalar(new ulong[] + { + 0x46cd_85a5_f273_077e, + 0x1d30_c47d_d68f_c735, + 0x77f6_56f6_0bec_a0eb, + 0x494a_a01b_df32_468d + }); + + var none_count = 0; + + for (int i = 0; i < 100; i++) + { + Scalar square_root; + try + { + square_root = square.Sqrt(); + Assert.AreEqual(square, square_root * square_root); + } + catch (ArithmeticException) + { + none_count++; + } + square -= Scalar.One; + } + + Assert.AreEqual(49, none_count); + } + + [TestMethod] + public void TestFromRaw() + { + Assert.AreEqual(Scalar.FromRaw(new ulong[] + { + 0x0001_ffff_fffd, + 0x5884_b7fa_0003_4802, + 0x998c_4fef_ecbc_4ff5, + 0x1824_b159_acc5_056f + }), Scalar.FromRaw(Enumerable.Repeat(0xffff_ffff_ffff_ffff, 4).ToArray())); + + Assert.AreEqual(Scalar.Zero, Scalar.FromRaw(MODULUS_LIMBS_64)); + + Assert.AreEqual(R, Scalar.FromRaw(new ulong[] { 1, 0, 0, 0 })); + } + + [TestMethod] + public void TestDouble() + { + var a = Scalar.FromRaw(new ulong[] + { + 0x1fff_3231_233f_fffd, + 0x4884_b7fa_0003_4802, + 0x998c_4fef_ecbc_4ff3, + 0x1824_b159_acc5_0562 + }); + + Assert.AreEqual(a + a, a.Double()); + } +} diff --git a/tests/Neo.Cryptography.BLS12_381.Tests/Usings.cs b/tests/Neo.Cryptography.BLS12_381.Tests/Usings.cs new file mode 100644 index 0000000000..d35553e8ae --- /dev/null +++ b/tests/Neo.Cryptography.BLS12_381.Tests/Usings.cs @@ -0,0 +1,12 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Usings.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. + +global using Microsoft.VisualStudio.TestTools.UnitTesting; From e04da14d77adb6a26dee7fdea142b7d7800185eb Mon Sep 17 00:00:00 2001 From: Jimmy Date: Thu, 11 Jan 2024 14:14:36 +0800 Subject: [PATCH 055/168] Add: add pull request template (#3081) * add pull request template * Update PULL_REQUEST_TEMPLATE.md --------- Co-authored-by: Shargon --- .github/PULL_REQUEST_TEMPLATE.md | 35 ++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 .github/PULL_REQUEST_TEMPLATE.md diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000000..7b043f14a7 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,35 @@ +# Description + + + +Fixes # (issue) + +## Type of change + + + +- [ ] Bug fix (non-breaking change which fixes an issue) +- [ ] New feature (non-breaking change which adds functionality) +- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) +- [ ] This change requires a documentation update + +# How Has This Been Tested? + + + +- [ ] Test A +- [ ] Test B + +**Test Configuration**: + + +# Checklist: + +- [ ] My code follows the style guidelines of this project +- [ ] I have performed a self-review of my code +- [ ] I have commented my code, particularly in hard-to-understand areas +- [ ] I have made corresponding changes to the documentation +- [ ] My changes generate no new warnings +- [ ] I have added tests that prove my fix is effective or that my feature works +- [ ] New and existing unit tests pass locally with my changes +- [ ] Any dependent changes have been merged and published in downstream modules From de7fc938b6460b2c1002262f4660844901035051 Mon Sep 17 00:00:00 2001 From: Christopher Schuchardt Date: Thu, 11 Jan 2024 07:21:36 -0500 Subject: [PATCH 056/168] Adding NNS to `neo-cli` (#3032) * Add NNS to UInt160 parameters for neo-cli * Fixed typo * Update src/Neo.ConsoleService/ConsoleServiceBase.cs * Added NNS hashes to config files. Updated code to reflect the changes * Updated support for neofs * Added ReadOnly Call Flag to the contract call * Updated to allow all domains * Update src/Neo.CLI/Settings.cs * null check * Update config.testnet.json with contract hash * Fixes * fixed wallet * Update src/Neo.CLI/Settings.cs Two vs one in this discussion * Update Settings.cs * Update Settings.cs * Refactor NNS definition * clean new * Show NNS Fault error --------- Co-authored-by: Shargon --- src/Neo.CLI/CLI/MainService.Wallet.cs | 9 ++-- src/Neo.CLI/CLI/MainService.cs | 47 +++++++++++++++++++- src/Neo.CLI/Settings.cs | 21 +++++++++ src/Neo.CLI/config.fs.mainnet.json | 3 ++ src/Neo.CLI/config.fs.testnet.json | 3 ++ src/Neo.CLI/config.json | 3 ++ src/Neo.CLI/config.mainnet.json | 3 ++ src/Neo.CLI/config.testnet.json | 3 ++ src/Neo.ConsoleService/ConsoleServiceBase.cs | 3 +- 9 files changed, 89 insertions(+), 6 deletions(-) diff --git a/src/Neo.CLI/CLI/MainService.Wallet.cs b/src/Neo.CLI/CLI/MainService.Wallet.cs index e74273bff4..4f65390f85 100644 --- a/src/Neo.CLI/CLI/MainService.Wallet.cs +++ b/src/Neo.CLI/CLI/MainService.Wallet.cs @@ -511,6 +511,7 @@ private void OnSendCommand(UInt160 asset, UInt160 to, string amount, UInt160? fr ConsoleHelper.Error("Incorrect password"); return; } + var snapshot = NeoSystem.StoreView; Transaction tx; AssetDescriptor descriptor = new(snapshot, NeoSystem.Settings, asset); @@ -550,10 +551,10 @@ private void OnSendCommand(UInt160 asset, UInt160 to, string amount, UInt160? fr return; } - ConsoleHelper.Info("Network fee: ", - $"{new BigDecimal((BigInteger)tx.NetworkFee, NativeContract.GAS.Decimals)}\t", - "Total fee: ", - $"{new BigDecimal((BigInteger)(tx.SystemFee + tx.NetworkFee), NativeContract.GAS.Decimals)} GAS"); + ConsoleHelper.Info( + "Send To: ", $"{to.ToAddress(NeoSystem.Settings.AddressVersion)}\n", + "Network fee: ", $"{new BigDecimal((BigInteger)tx.NetworkFee, NativeContract.GAS.Decimals)}\t", + "Total fee: ", $"{new BigDecimal((BigInteger)(tx.SystemFee + tx.NetworkFee), NativeContract.GAS.Decimals)} GAS"); if (!ConsoleHelper.ReadUserInput("Relay tx? (no|yes)").IsYes()) { return; diff --git a/src/Neo.CLI/CLI/MainService.cs b/src/Neo.CLI/CLI/MainService.cs index 1340c68cdd..e924d6478b 100644 --- a/src/Neo.CLI/CLI/MainService.cs +++ b/src/Neo.CLI/CLI/MainService.cs @@ -96,7 +96,7 @@ public MainService() : base() Initialize_Logger(); } - internal static UInt160 StringToAddress(string input, byte version) + internal UInt160 StringToAddress(string input, byte version) { switch (input.ToLowerInvariant()) { @@ -104,6 +104,11 @@ internal static UInt160 StringToAddress(string input, byte version) case "gas": return NativeContract.GAS.Hash; } + if (input.IndexOf('.') > 0 && input.LastIndexOf('.') < input.Length) + { + return ResolveNeoNameServiceAddress(input); + } + // Try to parse as UInt160 if (UInt160.TryParse(input, out var addr)) @@ -636,5 +641,45 @@ static string GetExceptionMessage(Exception exception) return exception.Message; } + + public UInt160 ResolveNeoNameServiceAddress(string domain) + { + if (Settings.Default.Contracts.NeoNameService == UInt160.Zero) + throw new Exception("Neo Name Service (NNS): is disabled on this network."); + + using var sb = new ScriptBuilder(); + sb.EmitDynamicCall(Settings.Default.Contracts.NeoNameService, "resolve", CallFlags.ReadOnly, domain, 16); + + using var appEng = ApplicationEngine.Run(sb.ToArray(), NeoSystem.StoreView, settings: NeoSystem.Settings); + if (appEng.State == VMState.HALT) + { + var data = appEng.ResultStack.Pop(); + if (data is ByteString) + { + try + { + var addressData = data.GetString(); + if (UInt160.TryParse(addressData, out var address)) + return address; + else + return addressData.ToScriptHash(NeoSystem.Settings.AddressVersion); + } + catch { } + } + else if (data is Null) + { + throw new Exception($"Neo Name Service (NNS): \"{domain}\" domain not found."); + } + throw new Exception("Neo Name Service (NNS): Record invalid address format."); + } + else + { + if (appEng.FaultException is not null) + { + throw new Exception($"Neo Name Service (NNS): \"{appEng.FaultException.Message}\"."); + } + } + throw new Exception($"Neo Name Service (NNS): \"{domain}\" domain not found."); + } } } diff --git a/src/Neo.CLI/Settings.cs b/src/Neo.CLI/Settings.cs index 7625db58f5..54067da747 100644 --- a/src/Neo.CLI/Settings.cs +++ b/src/Neo.CLI/Settings.cs @@ -11,6 +11,7 @@ using Microsoft.Extensions.Configuration; using Neo.Network.P2P; +using System; using System.Threading; namespace Neo @@ -21,6 +22,7 @@ public class Settings public StorageSettings Storage { get; } public P2PSettings P2P { get; } public UnlockWalletSettings UnlockWallet { get; } + public ContractsSettings Contracts { get; } static Settings? s_default; @@ -51,6 +53,7 @@ public static Settings Default public Settings(IConfigurationSection section) { + Contracts = new(section.GetSection(nameof(Contracts))); Logger = new(section.GetSection(nameof(Logger))); Storage = new(section.GetSection(nameof(Storage))); P2P = new(section.GetSection(nameof(P2P))); @@ -116,4 +119,22 @@ public UnlockWalletSettings(IConfigurationSection section) } } } + + public class ContractsSettings + { + public UInt160 NeoNameService { get; } = UInt160.Zero; + + public ContractsSettings(IConfigurationSection section) + { + if (section.Exists()) + { + if (UInt160.TryParse(section.GetValue(nameof(NeoNameService), string.Empty), out var hash)) + { + NeoNameService = hash; + } + else + throw new ArgumentException("Neo Name Service (NNS): NeoNameService hash is invalid. Check your config.json.", nameof(NeoNameService)); + } + } + } } diff --git a/src/Neo.CLI/config.fs.mainnet.json b/src/Neo.CLI/config.fs.mainnet.json index 57bf751406..248a2a8956 100644 --- a/src/Neo.CLI/config.fs.mainnet.json +++ b/src/Neo.CLI/config.fs.mainnet.json @@ -19,6 +19,9 @@ "Path": "", "Password": "", "IsActive": false + }, + "Contracts": { + "NeoNameService": "0x7061fbd31562664b58f422c3dee4acfd70dba8af" } }, "ProtocolConfiguration": { diff --git a/src/Neo.CLI/config.fs.testnet.json b/src/Neo.CLI/config.fs.testnet.json index a7a930c28b..88a03f7413 100644 --- a/src/Neo.CLI/config.fs.testnet.json +++ b/src/Neo.CLI/config.fs.testnet.json @@ -19,6 +19,9 @@ "Path": "", "Password": "", "IsActive": false + }, + "Contracts": { + "NeoNameService": "0xfb08ccf30ab534a871b7b092a49fe70c154ed678" } }, "ProtocolConfiguration": { diff --git a/src/Neo.CLI/config.json b/src/Neo.CLI/config.json index 897e33afab..5ff5dbb2bb 100644 --- a/src/Neo.CLI/config.json +++ b/src/Neo.CLI/config.json @@ -19,6 +19,9 @@ "Path": "", "Password": "", "IsActive": false + }, + "Contracts": { + "NeoNameService": "0x50ac1c37690cc2cfc594472833cf57505d5f46de" } }, "ProtocolConfiguration": { diff --git a/src/Neo.CLI/config.mainnet.json b/src/Neo.CLI/config.mainnet.json index 897e33afab..5ff5dbb2bb 100644 --- a/src/Neo.CLI/config.mainnet.json +++ b/src/Neo.CLI/config.mainnet.json @@ -19,6 +19,9 @@ "Path": "", "Password": "", "IsActive": false + }, + "Contracts": { + "NeoNameService": "0x50ac1c37690cc2cfc594472833cf57505d5f46de" } }, "ProtocolConfiguration": { diff --git a/src/Neo.CLI/config.testnet.json b/src/Neo.CLI/config.testnet.json index e3bcb7ce95..c6d771ef3a 100644 --- a/src/Neo.CLI/config.testnet.json +++ b/src/Neo.CLI/config.testnet.json @@ -19,6 +19,9 @@ "Path": "", "Password": "", "IsActive": false + }, + "Contracts": { + "NeoNameService": "0x50ac1c37690cc2cfc594472833cf57505d5f46de" } }, "ProtocolConfiguration": { diff --git a/src/Neo.ConsoleService/ConsoleServiceBase.cs b/src/Neo.ConsoleService/ConsoleServiceBase.cs index daa9d9f061..8b169fb808 100644 --- a/src/Neo.ConsoleService/ConsoleServiceBase.cs +++ b/src/Neo.ConsoleService/ConsoleServiceBase.cs @@ -88,10 +88,11 @@ private bool OnCommand(string commandLine) availableCommands.Add((command, arguments.ToArray())); } - catch + catch (Exception ex) { // Skip parse errors possibleHelp = command.Key; + ConsoleHelper.Error($"{ex.InnerException?.Message ?? ex.Message}"); } } } From 5febc4983efeb167b28196d18e0dcb7e3bdf3305 Mon Sep 17 00:00:00 2001 From: Shargon Date: Thu, 11 Jan 2024 21:36:01 +0300 Subject: [PATCH 057/168] Update & Consolidate nugets (#3083) * Update & Consolidate * Change Directory.build.props * Clean files * Rever akka update --- src/Neo.ConsoleService/Neo.ConsoleService.csproj | 2 +- src/Neo.Json/Neo.Json.csproj | 2 +- src/Neo/Neo.csproj | 2 +- tests/Directory.Build.props | 2 +- .../Neo.ConsoleService.Tests.csproj | 1 + .../Neo.Cryptography.BLS12_381.Tests.csproj | 10 ---------- tests/Neo.Json.UnitTests/Neo.Json.UnitTests.csproj | 4 ---- tests/Neo.UnitTests/Neo.UnitTests.csproj | 3 ++- 8 files changed, 7 insertions(+), 19 deletions(-) diff --git a/src/Neo.ConsoleService/Neo.ConsoleService.csproj b/src/Neo.ConsoleService/Neo.ConsoleService.csproj index 1971a40790..0139d2a0f5 100644 --- a/src/Neo.ConsoleService/Neo.ConsoleService.csproj +++ b/src/Neo.ConsoleService/Neo.ConsoleService.csproj @@ -8,7 +8,7 @@ - + diff --git a/src/Neo.Json/Neo.Json.csproj b/src/Neo.Json/Neo.Json.csproj index 0687960683..d2ce18e430 100644 --- a/src/Neo.Json/Neo.Json.csproj +++ b/src/Neo.Json/Neo.Json.csproj @@ -8,7 +8,7 @@ - + diff --git a/src/Neo/Neo.csproj b/src/Neo/Neo.csproj index 7d1778d712..de628a66de 100644 --- a/src/Neo/Neo.csproj +++ b/src/Neo/Neo.csproj @@ -12,7 +12,7 @@ - + diff --git a/tests/Directory.Build.props b/tests/Directory.Build.props index 875c10b42b..83fe17740a 100644 --- a/tests/Directory.Build.props +++ b/tests/Directory.Build.props @@ -8,7 +8,7 @@ - + diff --git a/tests/Neo.ConsoleService.Tests/Neo.ConsoleService.Tests.csproj b/tests/Neo.ConsoleService.Tests/Neo.ConsoleService.Tests.csproj index 3b3ae00b49..0b12c476c8 100644 --- a/tests/Neo.ConsoleService.Tests/Neo.ConsoleService.Tests.csproj +++ b/tests/Neo.ConsoleService.Tests/Neo.ConsoleService.Tests.csproj @@ -9,4 +9,5 @@ + 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 f3b71df777..a56621448c 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 @@ -7,16 +7,6 @@ false - - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - diff --git a/tests/Neo.Json.UnitTests/Neo.Json.UnitTests.csproj b/tests/Neo.Json.UnitTests/Neo.Json.UnitTests.csproj index eeb3177eb8..f8dec3e7d5 100644 --- a/tests/Neo.Json.UnitTests/Neo.Json.UnitTests.csproj +++ b/tests/Neo.Json.UnitTests/Neo.Json.UnitTests.csproj @@ -10,8 +10,4 @@ - - - - diff --git a/tests/Neo.UnitTests/Neo.UnitTests.csproj b/tests/Neo.UnitTests/Neo.UnitTests.csproj index e39fc1d6fb..2e61bedbcc 100644 --- a/tests/Neo.UnitTests/Neo.UnitTests.csproj +++ b/tests/Neo.UnitTests/Neo.UnitTests.csproj @@ -9,7 +9,7 @@ - + @@ -22,4 +22,5 @@ + From 3d0d27eb4e2745409520533d40d81e19db2cd299 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vitor=20Naz=C3=A1rio=20Coelho?= Date: Thu, 11 Jan 2024 15:39:17 -0300 Subject: [PATCH 058/168] Adding Devcontainer and link to codespace (#3075) * Adding simple dev container * Link on Readme * Update .devcontainer/devcontainer.json Co-authored-by: Shargon --------- Co-authored-by: Shargon --- .devcontainer/devcontainer.json | 14 ++++++++++++++ README.md | 6 +++++- 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 .devcontainer/devcontainer.json diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000000..07843745db --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,14 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the +// README at: https://github.com/devcontainers/templates/tree/main/src/dotnet +{ + "name": "C# (.NET)", + "image": "mcr.microsoft.com/devcontainers/dotnet:1-7.0-jammy", + "postCreateCommand": "dotnet restore && dotnet build", + "customizations": { + "vscode": { + "extensions": [ + "ms-dotnettools.csdevkit" + ] + } + } +} \ No newline at end of file diff --git a/README.md b/README.md index 8f64dcc854..37d1f00827 100644 --- a/README.md +++ b/README.md @@ -88,7 +88,11 @@

- +

+ + Open in GitHub Codespaces. + +

## Table of Contents From a294c9c455045e56ac7b7a0e380e01f3b2c3fffe Mon Sep 17 00:00:00 2001 From: Christopher Schuchardt Date: Fri, 12 Jan 2024 08:08:30 -0500 Subject: [PATCH 059/168] Made `MemoryStore` the default whithout `config.json` for `neo-cli` (#3085) * Made MemoryStore the default for `neo-cli` * Remove nullable Engine --------- Co-authored-by: Shargon --- src/Neo.CLI/Settings.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Neo.CLI/Settings.cs b/src/Neo.CLI/Settings.cs index 54067da747..d0d1e0ca13 100644 --- a/src/Neo.CLI/Settings.cs +++ b/src/Neo.CLI/Settings.cs @@ -11,6 +11,7 @@ using Microsoft.Extensions.Configuration; using Neo.Network.P2P; +using Neo.Persistence; using System; using System.Threading; @@ -77,13 +78,13 @@ public LoggerSettings(IConfigurationSection section) public class StorageSettings { - public string Engine { get; } = string.Empty; + public string Engine { get; } = nameof(MemoryStore); public string Path { get; } = string.Empty; public StorageSettings(IConfigurationSection section) { - Engine = section.GetValue(nameof(Engine), "LevelDBStore")!; - Path = section.GetValue(nameof(Path), "Data_LevelDB_{0}")!; + Engine = section.GetValue(nameof(Engine), nameof(MemoryStore))!; + Path = section.GetValue(nameof(Path), string.Empty)!; } } From a47832901f37c5ca2703f7741aab06d5f8a285ef Mon Sep 17 00:00:00 2001 From: Jimmy Date: Sat, 13 Jan 2024 13:33:39 +0800 Subject: [PATCH 060/168] Update: list all existing pligins when checking plugin list, not just installed (#3080) * list all existing pligins when checking plugin list, not just installed * Update MainService.Plugins.cs Co-authored-by: Shargon * udate format * Clean notifications and code --------- Co-authored-by: Shargon --- src/Neo.CLI/CLI/MainService.Plugins.cs | 108 ++++++++++++++++--------- 1 file changed, 72 insertions(+), 36 deletions(-) diff --git a/src/Neo.CLI/CLI/MainService.Plugins.cs b/src/Neo.CLI/CLI/MainService.Plugins.cs index b8bc739e85..101df01d66 100644 --- a/src/Neo.CLI/CLI/MainService.Plugins.cs +++ b/src/Neo.CLI/CLI/MainService.Plugins.cs @@ -9,8 +9,10 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using Akka.Util.Internal; using Microsoft.Extensions.Configuration; using Neo.ConsoleService; +using Neo.Cryptography; using Neo.Json; using Neo.Plugins; using System; @@ -20,7 +22,6 @@ using System.Linq; using System.Net; using System.Net.Http; -using System.Security.Cryptography; using System.Threading.Tasks; namespace Neo.CLI @@ -70,19 +71,21 @@ private async Task DownloadPluginAsync(string pluginName) var url = $"https://github.com/neo-project/neo-modules/releases/download/v{typeof(Plugin).Assembly.GetVersion()}/{pluginName}.zip"; using HttpClient http = new(); - HttpResponseMessage response = await http.GetAsync(url); + var response = await http.GetAsync(url); if (response.StatusCode == HttpStatusCode.NotFound) { response.Dispose(); - Version versionCore = typeof(Plugin).Assembly.GetName().Version!; + var versionCore = typeof(Plugin).Assembly.GetName().Version!; HttpRequestMessage request = new(HttpMethod.Get, "https://api.github.com/repos/neo-project/neo-modules/releases"); request.Headers.UserAgent.ParseAdd( $"{GetType().Assembly.GetName().Name}/{GetType().Assembly.GetVersion()}"); - using HttpResponseMessage responseApi = await http.SendAsync(request); - byte[] buffer = await responseApi.Content.ReadAsByteArrayAsync(); - if (JToken.Parse(buffer) is not JArray arr) throw new Exception("Plugin doesn't exist."); - var asset = arr + using var responseApi = await http.SendAsync(request); + var buffer = await responseApi.Content.ReadAsByteArrayAsync(); + if (JToken.Parse(buffer) is not JArray arr) + throw new Exception("Plugin doesn't exist."); + + var asset = (arr .Where(p => p?["tag_name"] is not null && p?["assets"] is not null) .Where(p => !p!["tag_name"]!.GetString().Contains('-')) .Select(p => new @@ -92,25 +95,25 @@ private async Task DownloadPluginAsync(string pluginName) }) .OrderByDescending(p => p.Version) .First(p => p.Version <= versionCore).Assets? - .FirstOrDefault(p => p?["name"]?.GetString() == $"{pluginName}.zip"); - if (asset is null) throw new Exception("Plugin doesn't exist."); + .FirstOrDefault(p => p?["name"]?.GetString() == $"{pluginName}.zip")) + ?? throw new Exception("Plugin doesn't exist."); response = await http.GetAsync(asset["browser_download_url"]?.GetString()); } using (response) { var totalRead = 0L; - byte[] buffer = new byte[1024]; + var buffer = new byte[1024]; int read; - await using Stream stream = await response.Content.ReadAsStreamAsync(); - ConsoleHelper.Info("From ", $"{url}"); + await using var stream = await response.Content.ReadAsStreamAsync(); + ConsoleHelper.Info("From ", url); var output = new MemoryStream(); while ((read = await stream.ReadAsync(buffer)) > 0) { output.Write(buffer, 0, read); totalRead += read; Console.Write( - $"\rDownloading {pluginName}.zip {totalRead / 1024}KB/{response.Content.Headers.ContentLength / 1024}KB {(totalRead * 100) / response.Content.Headers.ContentLength}%"); + $"\rDownloading {pluginName}.zip {totalRead / 1024}KB/{response.Content.Headers.ContentLength / 1024}KB {totalRead * 100 / response.Content.Headers.ContentLength}%"); } Console.WriteLine(); @@ -131,17 +134,14 @@ private async Task InstallPluginAsync(string pluginName, HashSet? instal if (!installed.Add(pluginName)) return; if (!overWrite && PluginExists(pluginName)) return; - await using MemoryStream stream = await DownloadPluginAsync(pluginName); - using (SHA256 sha256 = SHA256.Create()) - { - ConsoleHelper.Info("SHA256: ", $"{sha256.ComputeHash(stream.ToArray()).ToHexString()}"); - } + await using var stream = await DownloadPluginAsync(pluginName); + ConsoleHelper.Info("SHA256: ", $"{stream.ToArray().Sha256().ToHexString()}"); - using ZipArchive zip = new(stream, ZipArchiveMode.Read); - ZipArchiveEntry? entry = zip.Entries.FirstOrDefault(p => p.Name == "config.json"); + 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 Stream es = entry.Open(); + await using var es = entry.Open(); await InstallDependenciesAsync(es, installed); } zip.ExtractToDirectory("./", true); @@ -154,7 +154,7 @@ private async Task InstallPluginAsync(string pluginName, HashSet? instal /// Dependency set private async Task InstallDependenciesAsync(Stream config, HashSet installed) { - IConfigurationSection dependency = new ConfigurationBuilder() + var dependency = new ConfigurationBuilder() .AddJsonStream(config) .Build() .GetSection("Dependency"); @@ -163,7 +163,7 @@ private async Task InstallDependenciesAsync(Stream config, HashSet insta var dependencies = dependency.GetChildren().Select(p => p.Get()).ToArray(); if (dependencies.Length == 0) return; - foreach (string? plugin in dependencies.Where(p => p is not null && !PluginExists(p))) + foreach (var plugin in dependencies.Where(p => p is not null && !PluginExists(p))) { ConsoleHelper.Info($"Installing dependency: {plugin}"); await InstallPluginAsync(plugin!, installed); @@ -228,21 +228,57 @@ private void OnUnInstallCommand(string pluginName) /// Process "plugins" command ///
[ConsoleCommand("plugins", Category = "Plugin Commands")] - private void OnPluginsCommand() + private async void OnPluginsCommandAsync() { - if (Plugin.Plugins.Count > 0) - { - Console.WriteLine("Loaded plugins:"); - foreach (Plugin plugin in Plugin.Plugins) + var plugins = await GetPluginListAsync(); + var installed = Plugin.Plugins.Select(p => p.Name.ToLowerInvariant()); + plugins.ForEach( + p => { - var name = $"{plugin.Name}@{plugin.Version}"; - Console.WriteLine($"\t{name,-25}{plugin.Description}"); - } - } - else - { - ConsoleHelper.Warning("No loaded plugins"); - } + if (p.Contains(".zip")) p = p.Substring(0, p.Length - 4); + var installedPlugin = Plugin.Plugins.Where(pp => string.Equals(pp.Name, p, StringComparison.CurrentCultureIgnoreCase)).ToArray(); + if (installedPlugin.Length == 1) + { + var plugin = $"(installed) {p}"; + plugin = plugin.PadLeft(25); + Console.WriteLine($"\t{plugin,-25} @{installedPlugin[0].Version} {installedPlugin[0].Description}"); + } + else + { + var plugin = $"{p}"; + plugin = plugin.PadLeft(25); + Console.ForegroundColor = ConsoleColor.Gray; + Console.WriteLine($"\t{plugin,-25}"); + Console.ForegroundColor = ConsoleColor.Yellow; + } + }); + } + + private async Task?> GetPluginListAsync() + { + using HttpClient http = new(); + + var versionCore = typeof(Plugin).Assembly.GetName().Version!; + var request = new HttpRequestMessage(HttpMethod.Get, + "https://api.github.com/repos/neo-project/neo-modules/releases"); + request.Headers.UserAgent.ParseAdd( + $"{GetType().Assembly.GetName().Name}/{GetType().Assembly.GetVersion()}"); + using var responseApi = await http.SendAsync(request); + var buffer = await responseApi.Content.ReadAsByteArrayAsync(); + if (JToken.Parse(buffer) is not JArray arr) + throw new Exception("Plugin doesn't exist."); + return arr + .Where(p => p?["tag_name"] is not null && p["assets"] is not null) + .Where(p => !p!["tag_name"]!.GetString().Contains('-')) + .Select(p => new + { + Version = Version.Parse(p!["tag_name"]!.GetString().TrimStart('v')), + Assets = p["assets"] as JArray + }) + .OrderByDescending(p => p.Version) + .First(p => p.Version <= versionCore).Assets? + .Where(p => p?["name"]?.GetString() is not null) + .Select(p => p!["name"]!.GetString()); } } } From d018ccd4d646d6c0b9d0d791f62bb29d7f12fc05 Mon Sep 17 00:00:00 2001 From: Christopher Schuchardt Date: Sun, 14 Jan 2024 08:30:56 -0500 Subject: [PATCH 061/168] `Bug Fix`| Signers not being set in `neo-cli` with Invoke Command (#3090) * Fixed #3088 * Removed variable --- .gitignore | 1 + src/Neo.CLI/CLI/MainService.Contracts.cs | 30 ++++++++++++++---------- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/.gitignore b/.gitignore index cb49b769de..1358af3bde 100644 --- a/.gitignore +++ b/.gitignore @@ -256,3 +256,4 @@ paket-files/ PublishProfiles /.vscode +launchSettings.json diff --git a/src/Neo.CLI/CLI/MainService.Contracts.cs b/src/Neo.CLI/CLI/MainService.Contracts.cs index b2a90dda11..94fbe32f89 100644 --- a/src/Neo.CLI/CLI/MainService.Contracts.cs +++ b/src/Neo.CLI/CLI/MainService.Contracts.cs @@ -133,21 +133,27 @@ private void OnInvokeCommand(UInt160 scriptHash, string operation, JArray? contr { var gas = new BigDecimal(maxGas, NativeContract.GAS.Decimals); Signer[] signers = Array.Empty(); - if (!NoWallet() && sender != null) + if (!NoWallet()) { - if (signerAccounts == null) - signerAccounts = new UInt160[1] { sender }; - else if (signerAccounts.Contains(sender) && signerAccounts[0] != sender) - { - var signersList = signerAccounts.ToList(); - signersList.Remove(sender); - signerAccounts = signersList.Prepend(sender).ToArray(); - } - else if (!signerAccounts.Contains(sender)) + if (sender == null) + sender = CurrentWallet!.GetDefaultAccount()?.ScriptHash; + + if (sender != null) { - signerAccounts = signerAccounts.Prepend(sender).ToArray(); + if (signerAccounts == null) + signerAccounts = new UInt160[1] { sender }; + else if (signerAccounts.Contains(sender) && signerAccounts[0] != sender) + { + var signersList = signerAccounts.ToList(); + signersList.Remove(sender); + signerAccounts = signersList.Prepend(sender).ToArray(); + } + else if (!signerAccounts.Contains(sender)) + { + signerAccounts = signerAccounts.Prepend(sender).ToArray(); + } + signers = signerAccounts.Select(p => new Signer() { Account = p, Scopes = WitnessScope.CalledByEntry }).ToArray(); } - signers = signerAccounts.Select(p => new Signer() { Account = p, Scopes = WitnessScope.CalledByEntry }).ToArray(); } Transaction tx = new Transaction From a7db45c5364453b828445a541e4ce1d2dcaf9aec Mon Sep 17 00:00:00 2001 From: Jimmy Date: Tue, 16 Jan 2024 21:26:27 +0800 Subject: [PATCH 062/168] Config: Add comments to json config (#3086) * use xml to replace json * fix ut * hopefully this can revert everything * fix ut --- src/Neo.CLI/config.fs.mainnet.json | 4 ++-- src/Neo.CLI/config.fs.testnet.json | 4 ++-- src/Neo.CLI/config.json | 4 ++-- src/Neo.CLI/config.mainnet.json | 4 ++-- src/Neo.CLI/config.testnet.json | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Neo.CLI/config.fs.mainnet.json b/src/Neo.CLI/config.fs.mainnet.json index 248a2a8956..2646978dae 100644 --- a/src/Neo.CLI/config.fs.mainnet.json +++ b/src/Neo.CLI/config.fs.mainnet.json @@ -6,8 +6,8 @@ "Active": false }, "Storage": { - "Engine": "LevelDBStore", - "Path": "Data_LevelDB_{0}" + "Engine": "LevelDBStore", // Candidates [MemoryStore, LevelDBStore, RocksDBStore] + "Path": "Data_LevelDB_{0}" // {0} is a placeholder for the network id }, "P2P": { "Port": 40333, diff --git a/src/Neo.CLI/config.fs.testnet.json b/src/Neo.CLI/config.fs.testnet.json index 88a03f7413..d01c661c87 100644 --- a/src/Neo.CLI/config.fs.testnet.json +++ b/src/Neo.CLI/config.fs.testnet.json @@ -6,8 +6,8 @@ "Active": false }, "Storage": { - "Engine": "LevelDBStore", - "Path": "Data_LevelDB_{0}" + "Engine": "LevelDBStore", // Candidates [MemoryStore, LevelDBStore, RocksDBStore] + "Path": "Data_LevelDB_{0}" // {0} is a placeholder for the network id }, "P2P": { "Port": 50333, diff --git a/src/Neo.CLI/config.json b/src/Neo.CLI/config.json index 5ff5dbb2bb..01471e4c76 100644 --- a/src/Neo.CLI/config.json +++ b/src/Neo.CLI/config.json @@ -6,8 +6,8 @@ "Active": false }, "Storage": { - "Engine": "LevelDBStore", - "Path": "Data_LevelDB_{0}" + "Engine": "LevelDBStore", // Candidates [MemoryStore, LevelDBStore, RocksDBStore] + "Path": "Data_LevelDB_{0}" // {0} is a placeholder for the network id }, "P2P": { "Port": 10333, diff --git a/src/Neo.CLI/config.mainnet.json b/src/Neo.CLI/config.mainnet.json index 5ff5dbb2bb..01471e4c76 100644 --- a/src/Neo.CLI/config.mainnet.json +++ b/src/Neo.CLI/config.mainnet.json @@ -6,8 +6,8 @@ "Active": false }, "Storage": { - "Engine": "LevelDBStore", - "Path": "Data_LevelDB_{0}" + "Engine": "LevelDBStore", // Candidates [MemoryStore, LevelDBStore, RocksDBStore] + "Path": "Data_LevelDB_{0}" // {0} is a placeholder for the network id }, "P2P": { "Port": 10333, diff --git a/src/Neo.CLI/config.testnet.json b/src/Neo.CLI/config.testnet.json index c6d771ef3a..430cca52f2 100644 --- a/src/Neo.CLI/config.testnet.json +++ b/src/Neo.CLI/config.testnet.json @@ -6,8 +6,8 @@ "Active": false }, "Storage": { - "Engine": "LevelDBStore", - "Path": "Data_LevelDB_{0}" + "Engine": "LevelDBStore", // Candidates [MemoryStore, LevelDBStore, RocksDBStore] + "Path": "Data_LevelDB_{0}" // {0} is a placeholder for the network id }, "P2P": { "Port": 20333, From 38218bbee5bbe8b33cd8f9453465a19381c9a547 Mon Sep 17 00:00:00 2001 From: Shargon Date: Tue, 23 Jan 2024 04:32:08 -0800 Subject: [PATCH 063/168] Update feature-or-enhancement-request.md (#3106) --- .github/ISSUE_TEMPLATE/feature-or-enhancement-request.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/feature-or-enhancement-request.md b/.github/ISSUE_TEMPLATE/feature-or-enhancement-request.md index 4c2e7a8977..9b98d24f99 100644 --- a/.github/ISSUE_TEMPLATE/feature-or-enhancement-request.md +++ b/.github/ISSUE_TEMPLATE/feature-or-enhancement-request.md @@ -12,10 +12,6 @@ A summary of the problem you want to solve or metric you want to improve **Do you have any solution you want to propose?** A clear and concise description of what you expect with this change. -**Neo Version** -- Neo 2 -- Neo 3 - **Where in the software does this update applies to?** - Compiler - Consensus From 569b614a84ff2f12f6a36119932eaf9a7863f988 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Thu, 1 Feb 2024 17:51:56 +0800 Subject: [PATCH 064/168] Add: enable command line command (#3040) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * enable command line command * fix GUI * update format * remove network config * Fix conflicts * Remove Settings messages * My review * Add NoVerify check in IsValid * Clean using * format * move config * Revert "move config" This reverts commit 7d54c5dfd9ababb663f41955fa5d116d4469fcba. * fix config * update plugins install command * format * fix build error * Update src/Neo.CLI/CLI/MainService.cs Co-authored-by: Shargon * Fix Contracts --------- Co-authored-by: Christopher Schuchardt Co-authored-by: Shargon Co-authored-by: Vitor Nazário Coelho --- src/Neo.CLI/CLI/CommandLineOption.cs | 36 +++++++++ src/Neo.CLI/CLI/MainService.CommandLine.cs | 93 ++++++++++++++++++++++ src/Neo.CLI/CLI/MainService.cs | 25 +++--- src/Neo.CLI/Neo.CLI.csproj | 5 ++ src/Neo.CLI/Settings.cs | 52 ++++++++---- src/Neo.GUI/Program.cs | 2 +- src/Neo/ProtocolSettings.cs | 4 +- 7 files changed, 187 insertions(+), 30 deletions(-) create mode 100644 src/Neo.CLI/CLI/CommandLineOption.cs create mode 100644 src/Neo.CLI/CLI/MainService.CommandLine.cs diff --git a/src/Neo.CLI/CLI/CommandLineOption.cs b/src/Neo.CLI/CLI/CommandLineOption.cs new file mode 100644 index 0000000000..617856cee9 --- /dev/null +++ b/src/Neo.CLI/CLI/CommandLineOption.cs @@ -0,0 +1,36 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// CommandLineOption.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.CLI +{ + public class CommandLineOptions + { + public string? Config { get; init; } + public string? Wallet { get; init; } + public string? Password { get; init; } + public string[]? Plugins { get; set; } + public string? DBEngine { get; init; } + public string? DBPath { get; init; } + public bool? NoVerify { get; init; } + + /// + /// Check if CommandLineOptions was configured + /// + public bool IsValid => + !string.IsNullOrEmpty(Config) || + !string.IsNullOrEmpty(Wallet) || + !string.IsNullOrEmpty(Password) || + !string.IsNullOrEmpty(DBEngine) || + !string.IsNullOrEmpty(DBPath) || + (Plugins?.Length > 0) || + NoVerify is not null; + } +} diff --git a/src/Neo.CLI/CLI/MainService.CommandLine.cs b/src/Neo.CLI/CLI/MainService.CommandLine.cs new file mode 100644 index 0000000000..074f252f35 --- /dev/null +++ b/src/Neo.CLI/CLI/MainService.CommandLine.cs @@ -0,0 +1,93 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// MainService.CommandLine.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 System.CommandLine; +using System.CommandLine.Invocation; +using System.CommandLine.NamingConventionBinder; +using System.Reflection; + +namespace Neo.CLI +{ + public partial class MainService + { + public int OnStartWithCommandLine(string[] args) + { + RootCommand rootCommand = new(Assembly.GetExecutingAssembly().GetCustomAttribute()!.Title) + { + new Option(new[] { "-c", "--config","/config" }, "Specifies the config file."), + new Option(new[] { "-w", "--wallet","/wallet" }, "The path of the neo3 wallet [*.json]."), + new Option(new[] { "-p", "--password" ,"/password" }, "Password to decrypt the wallet, either from the command line or config file."), + new Option(new[] { "--db-engine","/db-engine" }, "Specify the db engine."), + new Option(new[] { "--db-path","/db-path" }, "Specify the db path."), + new Option(new[] { "--noverify","/noverify" }, "Indicates whether the blocks need to be verified when importing."), + new Option(new[] { "--plugins","/plugins" }, "The list of plugins, if not present, will be installed [plugin1 plugin2]."), + }; + + rootCommand.Handler = CommandHandler.Create(Handle); + return rootCommand.Invoke(args); + } + + private void Handle(RootCommand command, CommandLineOptions options, InvocationContext context) + { + Start(options); + } + + private static void CustomProtocolSettings(CommandLineOptions options, ProtocolSettings settings) + { + var tempSetting = settings; + // if specified config, then load the config and check the network + if (!string.IsNullOrEmpty(options.Config)) + { + tempSetting = ProtocolSettings.Load(options.Config); + } + + var customSetting = new ProtocolSettings + { + Network = tempSetting.Network, + AddressVersion = tempSetting.AddressVersion, + StandbyCommittee = tempSetting.StandbyCommittee, + ValidatorsCount = tempSetting.ValidatorsCount, + SeedList = tempSetting.SeedList, + MillisecondsPerBlock = tempSetting.MillisecondsPerBlock, + MaxTransactionsPerBlock = tempSetting.MaxTransactionsPerBlock, + MemoryPoolMaxTransactions = tempSetting.MemoryPoolMaxTransactions, + MaxTraceableBlocks = tempSetting.MaxTraceableBlocks, + InitialGasDistribution = tempSetting.InitialGasDistribution, + Hardforks = tempSetting.Hardforks + }; + + if (!string.IsNullOrEmpty(options.Config)) ProtocolSettings.Custom = customSetting; + } + + private static void CustomApplicationSettings(CommandLineOptions options, Settings settings) + { + var tempSetting = string.IsNullOrEmpty(options.Config) ? settings : new Settings(new ConfigurationBuilder().AddJsonFile(options.Config, optional: true).Build().GetSection("ApplicationConfiguration")); + var customSetting = new Settings + { + Logger = tempSetting.Logger, + Storage = new StorageSettings + { + Engine = options.DBEngine ?? tempSetting.Storage.Engine, + Path = options.DBPath ?? tempSetting.Storage.Path + }, + P2P = tempSetting.P2P, + UnlockWallet = new UnlockWalletSettings + { + Path = options.Wallet ?? tempSetting.UnlockWallet.Path, + Password = options.Password ?? tempSetting.UnlockWallet.Password + }, + Contracts = tempSetting.Contracts + }; + if (options.IsValid) Settings.Custom = customSetting; + } + } +} diff --git a/src/Neo.CLI/CLI/MainService.cs b/src/Neo.CLI/CLI/MainService.cs index e924d6478b..68b82de8cc 100644 --- a/src/Neo.CLI/CLI/MainService.cs +++ b/src/Neo.CLI/CLI/MainService.cs @@ -35,6 +35,7 @@ using System.Reflection; using System.Text.RegularExpressions; using System.Threading; +using System.Threading.Tasks; using Array = System.Array; namespace Neo.CLI @@ -347,7 +348,8 @@ private byte[] LoadUpdateScript(UInt160 scriptHash, string nefFilePath, string m public override void OnStart(string[] args) { base.OnStart(args); - Start(args); + OnStartWithCommandLine(args); + } public override void OnStop() @@ -366,26 +368,25 @@ public void OpenWallet(string path, string password) CurrentWallet = Wallet.Open(path, password, NeoSystem.Settings) ?? throw new NotSupportedException(); } - public async void Start(string[] args) + public async void Start(CommandLineOptions options) { if (NeoSystem != null) return; - bool verifyImport = true; - for (int i = 0; i < args.Length; i++) - switch (args[i]) - { - case "/noverify": - case "--noverify": - verifyImport = false; - break; - } + bool verifyImport = !(options.NoVerify ?? false); 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"))); NeoSystem.AddService(this); LocalNode = NeoSystem.LocalNode.Ask(new LocalNode.GetInstance()).Result; + // installing plugins + var installTasks = options.Plugins?.Select(p => p).Where(p => !string.IsNullOrEmpty(p)).ToList().Select(p => InstallPluginAsync(p)); + if (installTasks is not null) + { + await Task.WhenAll(installTasks); + } foreach (var plugin in Plugin.Plugins) { // Register plugins commands diff --git a/src/Neo.CLI/Neo.CLI.csproj b/src/Neo.CLI/Neo.CLI.csproj index 8c638d6c2a..0fa76ee2c9 100644 --- a/src/Neo.CLI/Neo.CLI.csproj +++ b/src/Neo.CLI/Neo.CLI.csproj @@ -32,4 +32,9 @@ + + + + + diff --git a/src/Neo.CLI/Settings.cs b/src/Neo.CLI/Settings.cs index d0d1e0ca13..4390a4ce36 100644 --- a/src/Neo.CLI/Settings.cs +++ b/src/Neo.CLI/Settings.cs @@ -19,11 +19,11 @@ namespace Neo { public class Settings { - public LoggerSettings Logger { get; } - public StorageSettings Storage { get; } - public P2PSettings P2P { get; } - public UnlockWalletSettings UnlockWallet { get; } - public ContractsSettings Contracts { get; } + public LoggerSettings Logger { get; init; } + public StorageSettings Storage { get; init; } + public P2PSettings P2P { get; init; } + public UnlockWalletSettings UnlockWallet { get; init; } + public ContractsSettings Contracts { get; init; } static Settings? s_default; @@ -47,11 +47,12 @@ public static Settings Default var config = new ConfigurationBuilder().AddJsonFile("config.json", optional: true).Build(); Initialize(config); } - - return s_default!; + return Custom ?? s_default!; } } + public static Settings? Custom { get; set; } + public Settings(IConfigurationSection section) { Contracts = new(section.GetSection(nameof(Contracts))); @@ -60,13 +61,22 @@ public Settings(IConfigurationSection section) P2P = new(section.GetSection(nameof(P2P))); UnlockWallet = new(section.GetSection(nameof(UnlockWallet))); } + + public Settings() + { + Logger = new LoggerSettings(); + Storage = new StorageSettings(); + P2P = new P2PSettings(); + UnlockWallet = new UnlockWalletSettings(); + Contracts = new ContractsSettings(); + } } public class LoggerSettings { - public string Path { get; } - public bool ConsoleOutput { get; } - public bool Active { get; } + public string Path { get; init; } = string.Empty; + public bool ConsoleOutput { get; init; } + public bool Active { get; init; } public LoggerSettings(IConfigurationSection section) { @@ -74,18 +84,22 @@ public LoggerSettings(IConfigurationSection section) ConsoleOutput = section.GetValue(nameof(ConsoleOutput), false); Active = section.GetValue(nameof(Active), false); } + + public LoggerSettings() { } } public class StorageSettings { - public string Engine { get; } = nameof(MemoryStore); - public string Path { get; } = string.Empty; + public string Engine { get; init; } = nameof(MemoryStore); + public string Path { get; init; } = string.Empty; public StorageSettings(IConfigurationSection section) { Engine = section.GetValue(nameof(Engine), nameof(MemoryStore))!; Path = section.GetValue(nameof(Path), string.Empty)!; } + + public StorageSettings() { } } public class P2PSettings @@ -102,13 +116,15 @@ public P2PSettings(IConfigurationSection section) MaxConnections = section.GetValue(nameof(MaxConnections), Peer.DefaultMaxConnections); MaxConnectionsPerAddress = section.GetValue(nameof(MaxConnectionsPerAddress), 3); } + + public P2PSettings() { } } public class UnlockWalletSettings { - public string Path { get; } = string.Empty; - public string Password { get; } = string.Empty; - public bool IsActive { get; } = false; + public string? Path { get; init; } = string.Empty; + public string? Password { get; init; } = string.Empty; + public bool IsActive { get; init; } = false; public UnlockWalletSettings(IConfigurationSection section) { @@ -119,11 +135,13 @@ public UnlockWalletSettings(IConfigurationSection section) IsActive = section.GetValue(nameof(IsActive), false); } } + + public UnlockWalletSettings() { } } public class ContractsSettings { - public UInt160 NeoNameService { get; } = UInt160.Zero; + public UInt160 NeoNameService { get; init; } = UInt160.Zero; public ContractsSettings(IConfigurationSection section) { @@ -137,5 +155,7 @@ public ContractsSettings(IConfigurationSection section) throw new ArgumentException("Neo Name Service (NNS): NeoNameService hash is invalid. Check your config.json.", nameof(NeoNameService)); } } + + public ContractsSettings() { } } } diff --git a/src/Neo.GUI/Program.cs b/src/Neo.GUI/Program.cs index fe8211975e..1317c4c793 100644 --- a/src/Neo.GUI/Program.cs +++ b/src/Neo.GUI/Program.cs @@ -68,7 +68,7 @@ static void Main(string[] args) return; } } - Service.Start(args); + Service.OnStartWithCommandLine(args); Application.Run(MainForm = new MainForm(xdoc)); Service.Stop(); } diff --git a/src/Neo/ProtocolSettings.cs b/src/Neo/ProtocolSettings.cs index f38e169d33..defbab9994 100644 --- a/src/Neo/ProtocolSettings.cs +++ b/src/Neo/ProtocolSettings.cs @@ -103,7 +103,7 @@ public record ProtocolSettings /// /// The default protocol settings for NEO MainNet. /// - public static ProtocolSettings Default { get; } = new ProtocolSettings + public static ProtocolSettings Default { get; } = Custom ?? new ProtocolSettings { Network = 0u, AddressVersion = 0x35, @@ -118,6 +118,8 @@ public record ProtocolSettings Hardforks = ImmutableDictionary.Empty }; + public static ProtocolSettings? Custom { get; set; } + /// /// Loads the at the specified path. /// From 7c59fe8d4639b546f169d8ea91b01c3e9aaf8821 Mon Sep 17 00:00:00 2001 From: Christopher Schuchardt Date: Thu, 1 Feb 2024 06:00:08 -0500 Subject: [PATCH 065/168] [`neo-cli`]: Plugin(s) Download Config File & Bug Fixes & Output Formatting (#3092) * Bug Fixes * Update config files * Fixed reinstall * Revert "Fixed reinstall" This reverts commit 4ccb6e38ccd0b222c18a84cd3c8390227e371175. * Delete src/Neo.CLI/Properties/launchSettings.json * Update src/Neo.CLI/CLI/MainService.Plugins.cs * Fixed ordering and GetPluginList and Added Prerelease fetch * Added error handling to List plugins command and change to use tag name * fixed tabing and spacing * format * Added version and prerelease for debug build only. * Default constructor * Update Settings.cs --------- Co-authored-by: Jimmy Co-authored-by: Shargon --- src/Neo.CLI/CLI/MainService.Plugins.cs | 222 ++++++++++++------------- src/Neo.CLI/Settings.cs | 25 +++ src/Neo.CLI/config.fs.mainnet.json | 3 + src/Neo.CLI/config.fs.testnet.json | 3 + src/Neo.CLI/config.json | 3 + src/Neo.CLI/config.mainnet.json | 3 + src/Neo.CLI/config.testnet.json | 3 + 7 files changed, 145 insertions(+), 117 deletions(-) diff --git a/src/Neo.CLI/CLI/MainService.Plugins.cs b/src/Neo.CLI/CLI/MainService.Plugins.cs index 101df01d66..5b346fc33c 100644 --- a/src/Neo.CLI/CLI/MainService.Plugins.cs +++ b/src/Neo.CLI/CLI/MainService.Plugins.cs @@ -12,16 +12,16 @@ using Akka.Util.Internal; using Microsoft.Extensions.Configuration; using Neo.ConsoleService; -using Neo.Cryptography; -using Neo.Json; using Neo.Plugins; using System; using System.Collections.Generic; using System.IO; using System.IO.Compression; using System.Linq; -using System.Net; using System.Net.Http; +using System.Net.Http.Json; +using System.Reflection; +using System.Text.Json.Nodes; using System.Threading.Tasks; namespace Neo.CLI @@ -33,7 +33,7 @@ partial class MainService ///
/// Plugin name [ConsoleCommand("install", Category = "Plugin Commands")] - private async Task OnInstallCommandAsync(string pluginName) + private void OnInstallCommand(string pluginName) { if (PluginExists(pluginName)) { @@ -41,8 +41,12 @@ private async Task OnInstallCommandAsync(string pluginName) return; } - await InstallPluginAsync(pluginName); - ConsoleHelper.Warning("Install successful, please restart neo-cli."); + var result = InstallPluginAsync(pluginName).GetAwaiter().GetResult(); + if (result) + { + var asmName = Assembly.GetExecutingAssembly().GetName().Name; + ConsoleHelper.Info("", $"Install successful, please restart \"{asmName}\"."); + } } /// @@ -52,10 +56,14 @@ private async Task OnInstallCommandAsync(string pluginName) /// /// name of the plugin [ConsoleCommand("reinstall", Category = "Plugin Commands", Description = "Overwrite existing plugin by force.")] - private async Task OnReinstallCommand(string pluginName) + private void OnReinstallCommand(string pluginName) { - await InstallPluginAsync(pluginName, overWrite: true); - ConsoleHelper.Warning("Reinstall successful, please restart neo-cli."); + var result = InstallPluginAsync(pluginName, overWrite: true).GetAwaiter().GetResult(); + if (result) + { + var asmName = Assembly.GetExecutingAssembly().GetName().Name; + ConsoleHelper.Info("", $"Reinstall successful, please restart \"{asmName}\"."); + } } /// @@ -65,60 +73,37 @@ private async Task OnReinstallCommand(string pluginName) /// might be added in the future. /// /// name of the plugin + /// + /// /// Downloaded content - private async Task DownloadPluginAsync(string pluginName) + private static async Task DownloadPluginAsync(string pluginName, Version pluginVersion, bool prerelease = false) { - var url = - $"https://github.com/neo-project/neo-modules/releases/download/v{typeof(Plugin).Assembly.GetVersion()}/{pluginName}.zip"; - using HttpClient http = new(); - var response = await http.GetAsync(url); - if (response.StatusCode == HttpStatusCode.NotFound) - { - response.Dispose(); - var versionCore = typeof(Plugin).Assembly.GetName().Version!; - HttpRequestMessage request = new(HttpMethod.Get, - "https://api.github.com/repos/neo-project/neo-modules/releases"); - request.Headers.UserAgent.ParseAdd( - $"{GetType().Assembly.GetName().Name}/{GetType().Assembly.GetVersion()}"); - using var responseApi = await http.SendAsync(request); - var buffer = await responseApi.Content.ReadAsByteArrayAsync(); - if (JToken.Parse(buffer) is not JArray arr) - throw new Exception("Plugin doesn't exist."); + using var httpClient = new HttpClient(); - var asset = (arr - .Where(p => p?["tag_name"] is not null && p?["assets"] is not null) - .Where(p => !p!["tag_name"]!.GetString().Contains('-')) - .Select(p => new - { - Version = Version.Parse(p!["tag_name"]!.GetString().TrimStart('v')), - Assets = p["assets"] as JArray - }) - .OrderByDescending(p => p.Version) - .First(p => p.Version <= versionCore).Assets? - .FirstOrDefault(p => p?["name"]?.GetString() == $"{pluginName}.zip")) - ?? throw new Exception("Plugin doesn't exist."); - response = await http.GetAsync(asset["browser_download_url"]?.GetString()); - } + var asmName = Assembly.GetExecutingAssembly().GetName(); + httpClient.DefaultRequestHeaders.UserAgent.Add(new(asmName.Name!, asmName.Version!.ToString(3))); - using (response) - { - var totalRead = 0L; - var buffer = new byte[1024]; - int read; - await using var stream = await response.Content.ReadAsStreamAsync(); - ConsoleHelper.Info("From ", url); - var output = new MemoryStream(); - while ((read = await stream.ReadAsync(buffer)) > 0) - { - output.Write(buffer, 0, read); - totalRead += read; - Console.Write( - $"\rDownloading {pluginName}.zip {totalRead / 1024}KB/{response.Content.Headers.ContentLength / 1024}KB {totalRead * 100 / response.Content.Headers.ContentLength}%"); - } + var json = await httpClient.GetFromJsonAsync(Settings.Default.Plugins.DownloadUrl) ?? throw new HttpRequestException($"Failed: {Settings.Default.Plugins.DownloadUrl}"); + var jsonRelease = json.AsArray() + .SingleOrDefault(s => + s != null && + s["tag_name"]!.GetValue() == $"v{pluginVersion.ToString(3)}" && + s["prerelease"]!.GetValue() == prerelease) ?? throw new Exception($"Could not find Release {pluginVersion}"); - Console.WriteLine(); - return output; - } + var jsonAssets = jsonRelease + .AsObject() + .SingleOrDefault(s => s.Key == "assets").Value ?? throw new Exception("Could not find any Plugins"); + + var jsonPlugin = jsonAssets + .AsArray() + .SingleOrDefault(s => + Path.GetFileNameWithoutExtension( + s!["name"]!.GetValue()).Equals(pluginName, StringComparison.InvariantCultureIgnoreCase)) + ?? throw new Exception($"Could not find {pluginName}"); + + var downloadUrl = jsonPlugin["browser_download_url"]!.GetValue(); + + return await httpClient.GetStreamAsync(downloadUrl); } /// @@ -127,24 +112,35 @@ private async Task DownloadPluginAsync(string pluginName) /// Name of the plugin /// Dependency set /// Install by force for `update` - private async Task InstallPluginAsync(string pluginName, HashSet? installed = null, + private async Task InstallPluginAsync( + string pluginName, + HashSet? installed = null, bool overWrite = false) { installed ??= new HashSet(); - if (!installed.Add(pluginName)) return; - if (!overWrite && PluginExists(pluginName)) return; + if (!installed.Add(pluginName)) return false; + if (!overWrite && PluginExists(pluginName)) return false; - await using var stream = await DownloadPluginAsync(pluginName); - ConsoleHelper.Info("SHA256: ", $"{stream.ToArray().Sha256().ToHexString()}"); + try + { + + using var stream = await DownloadPluginAsync(pluginName, Settings.Default.Plugins.Version, 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) + 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); + } + zip.ExtractToDirectory("./", true); + return true; + } + catch (Exception ex) { - await using var es = entry.Open(); - await InstallDependenciesAsync(es, installed); + ConsoleHelper.Error(ex?.InnerException?.Message ?? ex!.Message); } - zip.ExtractToDirectory("./", true); + return false; } /// @@ -189,7 +185,7 @@ private void OnUnInstallCommand(string pluginName) { if (!PluginExists(pluginName)) { - ConsoleHelper.Warning("Plugin not found"); + ConsoleHelper.Error("Plugin not found"); return; } @@ -197,17 +193,17 @@ private void OnUnInstallCommand(string pluginName) { try { - using var reader = File.OpenRead($"./Plugins/{p.Name}/config.json"); + using var reader = File.OpenRead($"Plugins/{p.Name}/config.json"); if (new ConfigurationBuilder() .AddJsonStream(reader) .Build() .GetSection("Dependency") .GetChildren() - .Select(d => d.Get()) - .Any(v => v is not null && v.Equals(pluginName, StringComparison.InvariantCultureIgnoreCase))) + .Select(s => s.Get()) + .Any(a => a is not null && a.Equals(pluginName, StringComparison.InvariantCultureIgnoreCase))) { - ConsoleHelper.Error( - $"Can not uninstall. Other plugins depend on this plugin, try `reinstall {pluginName}` if the plugin is broken."); + ConsoleHelper.Error($"{pluginName} is required by other plugins."); + ConsoleHelper.Info("Info: ", $"If plugin is damaged try to reinstall."); return; } } @@ -221,64 +217,56 @@ private void OnUnInstallCommand(string pluginName) Directory.Delete($"Plugins/{pluginName}", true); } catch (IOException) { } - ConsoleHelper.Info("Uninstall successful, please restart neo-cli."); + ConsoleHelper.Info("", "Uninstall successful, please restart neo-cli."); } /// /// Process "plugins" command /// [ConsoleCommand("plugins", Category = "Plugin Commands")] - private async void OnPluginsCommandAsync() + private void OnPluginsCommand() { - var plugins = await GetPluginListAsync(); - var installed = Plugin.Plugins.Select(p => p.Name.ToLowerInvariant()); - plugins.ForEach( - p => + try + { + var plugins = GetPluginListAsync().GetAwaiter().GetResult(); + if (plugins == null) return; + plugins + .Order() + .ForEach(f => { - if (p.Contains(".zip")) p = p.Substring(0, p.Length - 4); - var installedPlugin = Plugin.Plugins.Where(pp => string.Equals(pp.Name, p, StringComparison.CurrentCultureIgnoreCase)).ToArray(); - if (installedPlugin.Length == 1) + var installedPlugin = Plugin.Plugins.SingleOrDefault(pp => string.Equals(pp.Name, f, StringComparison.CurrentCultureIgnoreCase)); + if (installedPlugin != null) { - var plugin = $"(installed) {p}"; - plugin = plugin.PadLeft(25); - Console.WriteLine($"\t{plugin,-25} @{installedPlugin[0].Version} {installedPlugin[0].Description}"); + var maxLength = plugins.Select(s => s.Length).OrderDescending().First(); + string tabs = string.Empty; + if (f.Length < maxLength) + tabs = "\t"; + ConsoleHelper.Info("", $"[Installed]\t {f,6}{tabs}", " @", $"{installedPlugin.Version.ToString(3)} {installedPlugin.Description}"); } else - { - var plugin = $"{p}"; - plugin = plugin.PadLeft(25); - Console.ForegroundColor = ConsoleColor.Gray; - Console.WriteLine($"\t{plugin,-25}"); - Console.ForegroundColor = ConsoleColor.Yellow; - } + ConsoleHelper.Info($"[Not Installed]\t {f}"); }); + } + catch (Exception ex) + { + ConsoleHelper.Error(ex!.InnerException?.Message ?? ex!.Message); + } } - private async Task?> GetPluginListAsync() + private async Task> GetPluginListAsync() { - using HttpClient http = new(); + using var httpClient = new HttpClient(); - var versionCore = typeof(Plugin).Assembly.GetName().Version!; - var request = new HttpRequestMessage(HttpMethod.Get, - "https://api.github.com/repos/neo-project/neo-modules/releases"); - request.Headers.UserAgent.ParseAdd( - $"{GetType().Assembly.GetName().Name}/{GetType().Assembly.GetVersion()}"); - using var responseApi = await http.SendAsync(request); - var buffer = await responseApi.Content.ReadAsByteArrayAsync(); - if (JToken.Parse(buffer) is not JArray arr) - throw new Exception("Plugin doesn't exist."); - return arr - .Where(p => p?["tag_name"] is not null && p["assets"] is not null) - .Where(p => !p!["tag_name"]!.GetString().Contains('-')) - .Select(p => new - { - Version = Version.Parse(p!["tag_name"]!.GetString().TrimStart('v')), - Assets = p["assets"] as JArray - }) - .OrderByDescending(p => p.Version) - .First(p => p.Version <= versionCore).Assets? - .Where(p => p?["name"]?.GetString() is not null) - .Select(p => p!["name"]!.GetString()); + 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}"); + 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())); } } } diff --git a/src/Neo.CLI/Settings.cs b/src/Neo.CLI/Settings.cs index 4390a4ce36..ecc38115c3 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.Reflection; using System.Threading; namespace Neo @@ -24,6 +25,7 @@ public class Settings public P2PSettings P2P { get; init; } public UnlockWalletSettings UnlockWallet { get; init; } public ContractsSettings Contracts { get; init; } + public PluginsSettings Plugins { get; init; } static Settings? s_default; @@ -60,6 +62,7 @@ public Settings(IConfigurationSection section) Storage = new(section.GetSection(nameof(Storage))); P2P = new(section.GetSection(nameof(P2P))); UnlockWallet = new(section.GetSection(nameof(UnlockWallet))); + Plugins = new(section.GetSection(nameof(Plugins))); } public Settings() @@ -69,6 +72,7 @@ public Settings() P2P = new P2PSettings(); UnlockWallet = new UnlockWalletSettings(); Contracts = new ContractsSettings(); + Plugins = new PluginsSettings(); } } @@ -158,4 +162,25 @@ public ContractsSettings(IConfigurationSection section) public ContractsSettings() { } } + + public class PluginsSettings + { + public Uri DownloadUrl { get; init; } = new("https://api.github.com/repos/neo-project/neo-modules/releases"); + public bool Prerelease { get; init; } = false; + public Version Version { get; init; } = Assembly.GetExecutingAssembly().GetName().Version!; + + public PluginsSettings(IConfigurationSection section) + { + if (section.Exists()) + { + DownloadUrl = section.GetValue(nameof(DownloadUrl), DownloadUrl)!; +#if DEBUG + Prerelease = section.GetValue(nameof(Prerelease), Prerelease); + Version = section.GetValue(nameof(Version), Version)!; +#endif + } + } + + public PluginsSettings() { } + } } diff --git a/src/Neo.CLI/config.fs.mainnet.json b/src/Neo.CLI/config.fs.mainnet.json index 2646978dae..fad987209a 100644 --- a/src/Neo.CLI/config.fs.mainnet.json +++ b/src/Neo.CLI/config.fs.mainnet.json @@ -22,6 +22,9 @@ }, "Contracts": { "NeoNameService": "0x7061fbd31562664b58f422c3dee4acfd70dba8af" + }, + "Plugins": { + "DownloadUrl": "https://api.github.com/repos/neo-project/neo-modules/releases" } }, "ProtocolConfiguration": { diff --git a/src/Neo.CLI/config.fs.testnet.json b/src/Neo.CLI/config.fs.testnet.json index d01c661c87..b167f35b81 100644 --- a/src/Neo.CLI/config.fs.testnet.json +++ b/src/Neo.CLI/config.fs.testnet.json @@ -22,6 +22,9 @@ }, "Contracts": { "NeoNameService": "0xfb08ccf30ab534a871b7b092a49fe70c154ed678" + }, + "Plugins": { + "DownloadUrl": "https://api.github.com/repos/neo-project/neo-modules/releases" } }, "ProtocolConfiguration": { diff --git a/src/Neo.CLI/config.json b/src/Neo.CLI/config.json index 01471e4c76..b4800b80ea 100644 --- a/src/Neo.CLI/config.json +++ b/src/Neo.CLI/config.json @@ -22,6 +22,9 @@ }, "Contracts": { "NeoNameService": "0x50ac1c37690cc2cfc594472833cf57505d5f46de" + }, + "Plugins": { + "DownloadUrl": "https://api.github.com/repos/neo-project/neo-modules/releases" } }, "ProtocolConfiguration": { diff --git a/src/Neo.CLI/config.mainnet.json b/src/Neo.CLI/config.mainnet.json index 01471e4c76..b4800b80ea 100644 --- a/src/Neo.CLI/config.mainnet.json +++ b/src/Neo.CLI/config.mainnet.json @@ -22,6 +22,9 @@ }, "Contracts": { "NeoNameService": "0x50ac1c37690cc2cfc594472833cf57505d5f46de" + }, + "Plugins": { + "DownloadUrl": "https://api.github.com/repos/neo-project/neo-modules/releases" } }, "ProtocolConfiguration": { diff --git a/src/Neo.CLI/config.testnet.json b/src/Neo.CLI/config.testnet.json index 430cca52f2..19a9ca1442 100644 --- a/src/Neo.CLI/config.testnet.json +++ b/src/Neo.CLI/config.testnet.json @@ -22,6 +22,9 @@ }, "Contracts": { "NeoNameService": "0x50ac1c37690cc2cfc594472833cf57505d5f46de" + }, + "Plugins": { + "DownloadUrl": "https://api.github.com/repos/neo-project/neo-modules/releases" } }, "ProtocolConfiguration": { From 2dd972d67bfdb94f68a584657762a913d19a8779 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Fri, 2 Feb 2024 19:42:53 +0800 Subject: [PATCH 066/168] fix the benchmark (#3109) Co-authored-by: Shargon --- benchmarks/Neo.Benchmarks/Benchmarks.cs | 2 +- .../Neo.Benchmarks/Neo.Benchmarks.csproj | 7 ++ benchmarks/Neo.Benchmarks/config.json | 71 +++++++++++++++++++ 3 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 benchmarks/Neo.Benchmarks/config.json diff --git a/benchmarks/Neo.Benchmarks/Benchmarks.cs b/benchmarks/Neo.Benchmarks/Benchmarks.cs index d55dc64391..3df349e61e 100644 --- a/benchmarks/Neo.Benchmarks/Benchmarks.cs +++ b/benchmarks/Neo.Benchmarks/Benchmarks.cs @@ -18,7 +18,7 @@ namespace Neo; static class Benchmarks { - private static readonly ProtocolSettings protocol = ProtocolSettings.Default; + private static readonly ProtocolSettings protocol = ProtocolSettings.Load("config.json"); private static readonly NeoSystem system = new(protocol); public static void NeoIssue2725() diff --git a/benchmarks/Neo.Benchmarks/Neo.Benchmarks.csproj b/benchmarks/Neo.Benchmarks/Neo.Benchmarks.csproj index 12d32a3361..17698eed98 100644 --- a/benchmarks/Neo.Benchmarks/Neo.Benchmarks.csproj +++ b/benchmarks/Neo.Benchmarks/Neo.Benchmarks.csproj @@ -12,4 +12,11 @@ + + + PreserveNewest + PreserveNewest + + + diff --git a/benchmarks/Neo.Benchmarks/config.json b/benchmarks/Neo.Benchmarks/config.json new file mode 100644 index 0000000000..01471e4c76 --- /dev/null +++ b/benchmarks/Neo.Benchmarks/config.json @@ -0,0 +1,71 @@ +{ + "ApplicationConfiguration": { + "Logger": { + "Path": "Logs", + "ConsoleOutput": false, + "Active": false + }, + "Storage": { + "Engine": "LevelDBStore", // Candidates [MemoryStore, LevelDBStore, RocksDBStore] + "Path": "Data_LevelDB_{0}" // {0} is a placeholder for the network id + }, + "P2P": { + "Port": 10333, + "MinDesiredConnections": 10, + "MaxConnections": 40, + "MaxConnectionsPerAddress": 3 + }, + "UnlockWallet": { + "Path": "", + "Password": "", + "IsActive": false + }, + "Contracts": { + "NeoNameService": "0x50ac1c37690cc2cfc594472833cf57505d5f46de" + } + }, + "ProtocolConfiguration": { + "Network": 860833102, + "AddressVersion": 53, + "MillisecondsPerBlock": 15000, + "MaxTransactionsPerBlock": 512, + "MemoryPoolMaxTransactions": 50000, + "MaxTraceableBlocks": 2102400, + "Hardforks": { + "HF_Aspidochelone": 1730000, + "HF_Basilisk": 4120000 + }, + "InitialGasDistribution": 5200000000000000, + "ValidatorsCount": 7, + "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" + ] + } +} From 92d487c1b04e44b41c485045682f7f0f6a32b6cc Mon Sep 17 00:00:00 2001 From: Jimmy Date: Sat, 3 Feb 2024 01:18:40 +0800 Subject: [PATCH 067/168] Fix: specify log exception. (#3089) * specify log exception. * add sender exception specification * format * fix check --------- Co-authored-by: Shargon --- src/Neo/Network/P2P/Payloads/Transaction.cs | 1 + src/Neo/SmartContract/ApplicationEngine.Runtime.cs | 13 ++++++++++--- .../SmartContract/UT_ApplicationEngine.Runtime.cs | 12 ++++++++++++ 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/Neo/Network/P2P/Payloads/Transaction.cs b/src/Neo/Network/P2P/Payloads/Transaction.cs index 69a1b179e9..16417beb43 100644 --- a/src/Neo/Network/P2P/Payloads/Transaction.cs +++ b/src/Neo/Network/P2P/Payloads/Transaction.cs @@ -458,6 +458,7 @@ public virtual VerifyResult VerifyStateIndependent(ProtocolSettings settings) public StackItem ToStackItem(ReferenceCounter referenceCounter) { + if (_signers == null || _signers.Length == 0) throw new ArgumentException("Sender is not specified in the transaction."); return new Array(referenceCounter, new StackItem[] { // Computed properties diff --git a/src/Neo/SmartContract/ApplicationEngine.Runtime.cs b/src/Neo/SmartContract/ApplicationEngine.Runtime.cs index 4314952eec..293b245bd7 100644 --- a/src/Neo/SmartContract/ApplicationEngine.Runtime.cs +++ b/src/Neo/SmartContract/ApplicationEngine.Runtime.cs @@ -327,9 +327,16 @@ protected internal BigInteger GetRandom() /// The message of the log. protected internal void RuntimeLog(byte[] state) { - if (state.Length > MaxNotificationSize) throw new ArgumentException(null, nameof(state)); - string message = Utility.StrictUTF8.GetString(state); - Log?.Invoke(this, new LogEventArgs(ScriptContainer, CurrentScriptHash, message)); + if (state.Length > MaxNotificationSize) throw new ArgumentException("Message is too long.", nameof(state)); + try + { + string message = Utility.StrictUTF8.GetString(state); + Log?.Invoke(this, new LogEventArgs(ScriptContainer, CurrentScriptHash, message)); + } + catch + { + throw new ArgumentException("Failed to convert byte array to string: Invalid or non-printable UTF-8 sequence detected.", nameof(state)); + } } /// diff --git a/tests/Neo.UnitTests/SmartContract/UT_ApplicationEngine.Runtime.cs b/tests/Neo.UnitTests/SmartContract/UT_ApplicationEngine.Runtime.cs index 80bbf45e9d..75e6e7b6da 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_ApplicationEngine.Runtime.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_ApplicationEngine.Runtime.cs @@ -175,5 +175,17 @@ public void TestGetRandomDifferentBlock() rand_4.Should().NotBe(rand_9); rand_5.Should().NotBe(rand_10); } + + [TestMethod] + public void TestInvalidUtf8LogMessage() + { + var tx_1 = TestUtils.GetTransaction(UInt160.Zero); + using var engine = ApplicationEngine.Create(TriggerType.Application, tx_1, null, TestBlockchain.TheNeoSystem.GenesisBlock, settings: TestBlockchain.TheNeoSystem.Settings, gas: 1100_00000000); + var msg = new byte[] + { + 68, 216, 160, 6, 89, 102, 86, 72, 37, 15, 132, 45, 76, 221, 170, 21, 128, 51, 34, 168, 205, 56, 10, 228, 51, 114, 4, 218, 245, 155, 172, 132 + }; + Assert.ThrowsException(() => engine.RuntimeLog(msg)); + } } } From a1291a6c38e01c4f322c2131f49ff31c2e2633a0 Mon Sep 17 00:00:00 2001 From: Shargon Date: Tue, 6 Feb 2024 17:33:31 +0100 Subject: [PATCH 068/168] Fix ut (#3113) * Fix ut * Clean code * clean * Rename to Clear * Revert remove * Clean using * Rename to Reset * AggressiveInlining --------- Co-authored-by: Jimmy --- benchmarks/Neo.Benchmarks/Benchmarks.cs | 3 +- src/Neo.CLI/CLI/MainService.cs | 4 ++- src/Neo/NeoSystem.cs | 11 +++---- src/Neo/Persistence/MemoryStore.cs | 30 +++++++++++++------ src/Neo/Persistence/StoreFactory.cs | 14 ++++++++- tests/Neo.UnitTests/Ledger/UT_Blockchain.cs | 6 ++++ tests/Neo.UnitTests/Ledger/UT_MemoryPool.cs | 4 +-- .../Network/P2P/Payloads/UT_Transaction.cs | 6 ++++ .../SmartContract/Native/UT_RoleManagement.cs | 6 ++++ tests/Neo.UnitTests/TestBlockchain.cs | 11 ++++++- tests/Neo.UnitTests/Wallets/UT_Wallet.cs | 9 ------ 11 files changed, 73 insertions(+), 31 deletions(-) diff --git a/benchmarks/Neo.Benchmarks/Benchmarks.cs b/benchmarks/Neo.Benchmarks/Benchmarks.cs index 3df349e61e..5c3389407c 100644 --- a/benchmarks/Neo.Benchmarks/Benchmarks.cs +++ b/benchmarks/Neo.Benchmarks/Benchmarks.cs @@ -10,6 +10,7 @@ // modifications are permitted. using Neo.Network.P2P.Payloads; +using Neo.Persistence; using Neo.SmartContract; using Neo.VM; using System.Diagnostics; @@ -19,7 +20,7 @@ namespace Neo; static class Benchmarks { private static readonly ProtocolSettings protocol = ProtocolSettings.Load("config.json"); - private static readonly NeoSystem system = new(protocol); + private static readonly NeoSystem system = new(protocol, new MemoryStore()); public static void NeoIssue2725() { diff --git a/src/Neo.CLI/CLI/MainService.cs b/src/Neo.CLI/CLI/MainService.cs index 68b82de8cc..abd23121f7 100644 --- a/src/Neo.CLI/CLI/MainService.cs +++ b/src/Neo.CLI/CLI/MainService.cs @@ -17,6 +17,7 @@ using Neo.Ledger; using Neo.Network.P2P; using Neo.Network.P2P.Payloads; +using Neo.Persistence; using Neo.Plugins; using Neo.SmartContract; using Neo.SmartContract.Manifest; @@ -376,7 +377,8 @@ 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"))); + var store = StoreFactory.GetStore(Settings.Default.Storage.Engine, string.Format(Settings.Default.Storage.Path, protocol.Network.ToString("X8"))); + NeoSystem = new NeoSystem(protocol, store); NeoSystem.AddService(this); LocalNode = NeoSystem.LocalNode.Ask(new LocalNode.GetInstance()).Result; diff --git a/src/Neo/NeoSystem.cs b/src/Neo/NeoSystem.cs index 3a148d612d..4713c284ff 100644 --- a/src/Neo/NeoSystem.cs +++ b/src/Neo/NeoSystem.cs @@ -97,7 +97,6 @@ public class NeoSystem : IDisposable internal RelayCache RelayCache { get; } = new(100); private ImmutableList services = ImmutableList.Empty; - private readonly string storage_engine; private readonly IStore store; private ChannelsConfig start_message = null; private int suspend = 0; @@ -114,14 +113,12 @@ static NeoSystem() /// Initializes a new instance of the class. /// /// The protocol settings of the . - /// The storage engine used to create the objects. If this parameter is , a default in-memory storage engine will be used. - /// The path of the storage. If is the default in-memory storage engine, this parameter is ignored. - public NeoSystem(ProtocolSettings settings, string storageEngine = null, string storagePath = null) + /// The to use. + public NeoSystem(ProtocolSettings settings, IStore storage) { this.Settings = settings; this.GenesisBlock = CreateGenesisBlock(settings); - this.storage_engine = storageEngine ?? nameof(MemoryStore); - this.store = LoadStore(storagePath); + this.store = storage; this.MemPool = new MemoryPool(this); this.Blockchain = ActorSystem.ActorOf(Ledger.Blockchain.Props(this)); this.LocalNode = ActorSystem.ActorOf(Network.P2P.LocalNode.Props(this)); @@ -218,7 +215,7 @@ public void EnsureStopped(IActorRef actor) /// The loaded . public IStore LoadStore(string path) { - return StoreFactory.GetStore(storage_engine, path); + return StoreFactory.GetStore(store.GetType().Name, path); } /// diff --git a/src/Neo/Persistence/MemoryStore.cs b/src/Neo/Persistence/MemoryStore.cs index 91d542a94b..191b89ea4f 100644 --- a/src/Neo/Persistence/MemoryStore.cs +++ b/src/Neo/Persistence/MemoryStore.cs @@ -13,6 +13,7 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; +using System.Runtime.CompilerServices; namespace Neo.Persistence { @@ -21,33 +22,36 @@ namespace Neo.Persistence /// public class MemoryStore : IStore { - private readonly ConcurrentDictionary innerData = new(ByteArrayEqualityComparer.Default); + private readonly ConcurrentDictionary _innerData = new(ByteArrayEqualityComparer.Default); + [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Delete(byte[] key) { - innerData.TryRemove(key, out _); + _innerData.TryRemove(key, out _); } public void Dispose() { } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public ISnapshot GetSnapshot() { - return new MemorySnapshot(innerData); + return new MemorySnapshot(_innerData); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Put(byte[] key, byte[] value) { - innerData[key[..]] = value[..]; + _innerData[key[..]] = value[..]; } public IEnumerable<(byte[] Key, byte[] Value)> Seek(byte[] keyOrPrefix, SeekDirection direction = SeekDirection.Forward) { if (direction == SeekDirection.Backward && keyOrPrefix?.Length == 0) yield break; - ByteArrayComparer comparer = direction == SeekDirection.Forward ? ByteArrayComparer.Default : ByteArrayComparer.Reverse; - IEnumerable> records = innerData; + var comparer = direction == SeekDirection.Forward ? ByteArrayComparer.Default : ByteArrayComparer.Reverse; + IEnumerable> records = _innerData; if (keyOrPrefix?.Length > 0) records = records.Where(p => comparer.Compare(p.Key, keyOrPrefix) >= 0); records = records.OrderBy(p => p.Key, comparer); @@ -55,15 +59,23 @@ public void Put(byte[] key, byte[] value) yield return (pair.Key[..], pair.Value[..]); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public byte[] TryGet(byte[] key) { - innerData.TryGetValue(key, out byte[] value); - return value?[..]; + if (!_innerData.TryGetValue(key, out byte[] value)) return null; + return value[..]; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Contains(byte[] key) { - return innerData.ContainsKey(key); + return _innerData.ContainsKey(key); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void Reset() + { + _innerData.Clear(); } } } diff --git a/src/Neo/Persistence/StoreFactory.cs b/src/Neo/Persistence/StoreFactory.cs index 66d600f546..622c152acf 100644 --- a/src/Neo/Persistence/StoreFactory.cs +++ b/src/Neo/Persistence/StoreFactory.cs @@ -25,7 +25,13 @@ private class MemoryStoreProvider : IStoreProvider static StoreFactory() { - RegisterProvider(new MemoryStoreProvider()); + var memProvider = new MemoryStoreProvider(); + RegisterProvider(memProvider); + + // Default cases + + providers.Add("", memProvider); + providers.Add(null, memProvider); } public static void RegisterProvider(IStoreProvider provider) @@ -33,6 +39,12 @@ public static void RegisterProvider(IStoreProvider provider) providers.Add(provider.Name, provider); } + /// + /// Get store from name + /// + /// The storage engine used to create the objects. If this parameter is , a default in-memory storage engine will be used. + /// The path of the storage. If is the default in-memory storage engine, this parameter is ignored. + /// The storage engine. public static IStore GetStore(string storageEngine, string path) { return providers[storageEngine].GetStore(path); diff --git a/tests/Neo.UnitTests/Ledger/UT_Blockchain.cs b/tests/Neo.UnitTests/Ledger/UT_Blockchain.cs index c6e818cdf7..491b4fe21e 100644 --- a/tests/Neo.UnitTests/Ledger/UT_Blockchain.cs +++ b/tests/Neo.UnitTests/Ledger/UT_Blockchain.cs @@ -48,6 +48,12 @@ public void Initialize() system.MemPool.TryAdd(txSample, TestBlockchain.GetTestSnapshot()); } + [TestCleanup] + public void Clean() + { + TestBlockchain.ResetStore(); + } + [TestMethod] public void TestValidTransaction() { diff --git a/tests/Neo.UnitTests/Ledger/UT_MemoryPool.cs b/tests/Neo.UnitTests/Ledger/UT_MemoryPool.cs index 06324b6675..784a1d9b5e 100644 --- a/tests/Neo.UnitTests/Ledger/UT_MemoryPool.cs +++ b/tests/Neo.UnitTests/Ledger/UT_MemoryPool.cs @@ -57,7 +57,7 @@ public void TestSetup() TimeProvider.ResetToDefault(); // Create a MemoryPool with capacity of 100 - _unit = new MemoryPool(new NeoSystem(TestProtocolSettings.Default with { MemoryPoolMaxTransactions = 100 })); + _unit = new MemoryPool(new NeoSystem(TestProtocolSettings.Default with { MemoryPoolMaxTransactions = 100 }, new MemoryStore())); // Verify capacity equals the amount specified _unit.Capacity.Should().Be(100); @@ -648,7 +648,7 @@ public void TestGetVerifiedTransactions() [TestMethod] public void TestReVerifyTopUnverifiedTransactionsIfNeeded() { - _unit = new MemoryPool(new NeoSystem(TestProtocolSettings.Default with { MemoryPoolMaxTransactions = 600 })); + _unit = new MemoryPool(new NeoSystem(TestProtocolSettings.Default with { MemoryPoolMaxTransactions = 600 }, new MemoryStore())); AddTransaction(CreateTransaction(100000001)); AddTransaction(CreateTransaction(100000001)); diff --git a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs index ecb6d1874b..43755374d3 100644 --- a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs +++ b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs @@ -38,6 +38,12 @@ public void TestSetup() uut = new Transaction(); } + [TestCleanup] + public void Clean() + { + TestBlockchain.ResetStore(); + } + [TestMethod] public void Script_Get() { diff --git a/tests/Neo.UnitTests/SmartContract/Native/UT_RoleManagement.cs b/tests/Neo.UnitTests/SmartContract/Native/UT_RoleManagement.cs index 419ce213fc..a87c630194 100644 --- a/tests/Neo.UnitTests/SmartContract/Native/UT_RoleManagement.cs +++ b/tests/Neo.UnitTests/SmartContract/Native/UT_RoleManagement.cs @@ -36,6 +36,12 @@ public void TestSetup() _snapshot = TestBlockchain.GetTestSnapshot(); } + [TestCleanup] + public void Clean() + { + TestBlockchain.ResetStore(); + } + [TestMethod] public void TestSetAndGet() { diff --git a/tests/Neo.UnitTests/TestBlockchain.cs b/tests/Neo.UnitTests/TestBlockchain.cs index 5e24aca099..cbdd6c1c12 100644 --- a/tests/Neo.UnitTests/TestBlockchain.cs +++ b/tests/Neo.UnitTests/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; @@ -18,11 +20,18 @@ public static class TestBlockchain { public static readonly NeoSystem TheNeoSystem; public static readonly UInt160[] DefaultExtensibleWitnessWhiteList; + private static readonly MemoryStore Store = new(); static TestBlockchain() { Console.WriteLine("initialize NeoSystem"); - TheNeoSystem = new NeoSystem(TestProtocolSettings.Default, null, null); + TheNeoSystem = new NeoSystem(TestProtocolSettings.Default, Store); + } + + internal static void ResetStore() + { + Store.Reset(); + TheNeoSystem.Blockchain.Ask(new Blockchain.Initialize()).Wait(); } internal static DataCache GetTestSnapshot() diff --git a/tests/Neo.UnitTests/Wallets/UT_Wallet.cs b/tests/Neo.UnitTests/Wallets/UT_Wallet.cs index 17604cd75c..d134c6aed3 100644 --- a/tests/Neo.UnitTests/Wallets/UT_Wallet.cs +++ b/tests/Neo.UnitTests/Wallets/UT_Wallet.cs @@ -221,13 +221,11 @@ public void TestGetAvailable() var key = NativeContract.GAS.CreateStorageKey(20, account.ScriptHash); var entry = snapshot.GetAndChange(key, () => new StorageItem(new AccountState())); entry.GetInteroperable().Balance = 10000 * NativeContract.GAS.Factor; - snapshot.Commit(); wallet.GetAvailable(snapshot, NativeContract.GAS.Hash).Should().Be(new BigDecimal(new BigInteger(1000000000000M), 8)); entry = snapshot.GetAndChange(key, () => new StorageItem(new AccountState())); entry.GetInteroperable().Balance = 0; - snapshot.Commit(); } [TestMethod] @@ -243,14 +241,12 @@ public void TestGetBalance() var key = NativeContract.GAS.CreateStorageKey(20, account.ScriptHash); var entry = snapshot.GetAndChange(key, () => new StorageItem(new AccountState())); entry.GetInteroperable().Balance = 10000 * NativeContract.GAS.Factor; - snapshot.Commit(); 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)); entry = snapshot.GetAndChange(key, () => new StorageItem(new AccountState())); entry.GetInteroperable().Balance = 0; - snapshot.Commit(); } [TestMethod] @@ -345,8 +341,6 @@ public void TestMakeTransaction1() var entry2 = snapshot.GetAndChange(key, () => new StorageItem(new NeoToken.NeoAccountState())); entry2.GetInteroperable().Balance = 10000 * NativeContract.NEO.Factor; - snapshot.Commit(); - var tx = wallet.MakeTransaction(snapshot, new TransferOutput[] { new TransferOutput() @@ -374,7 +368,6 @@ public void TestMakeTransaction1() entry2 = snapshot.GetAndChange(key, () => new StorageItem(new AccountState())); entry1.GetInteroperable().Balance = 0; entry2.GetInteroperable().Balance = 0; - snapshot.Commit(); } [TestMethod] @@ -393,7 +386,6 @@ public void TestMakeTransaction2() var key = NativeContract.GAS.CreateStorageKey(20, account.ScriptHash); var entry = snapshot.GetAndChange(key, () => new StorageItem(new AccountState())); entry.GetInteroperable().Balance = 1000000 * NativeContract.GAS.Factor; - snapshot.Commit(); var tx = wallet.MakeTransaction(snapshot, Array.Empty(), account.ScriptHash, new[]{ new Signer() { @@ -408,7 +400,6 @@ public void TestMakeTransaction2() entry = snapshot.GetAndChange(key, () => new StorageItem(new AccountState())); entry.GetInteroperable().Balance = 0; - snapshot.Commit(); } [TestMethod] From 968121979cd9401fcceb7afa13d927885e6fe490 Mon Sep 17 00:00:00 2001 From: Shargon Date: Wed, 7 Feb 2024 10:16:47 +0100 Subject: [PATCH 069/168] Neo as dotnet standard (#3082) * neo as dotnet standard * More changes * Clean usings * More changes * Awaits * Fix ContractTask * Fix UT * Remove extra method * Clean changes * More clean changes * Use cschuchardt88 GetBitLength version * Add comments * Remove compiler directive * Remove duplicate code * Add UT * NotImplemented * Copy Sqrt exception * var clean * Rename * Try algorithm * @cschuchardt88 solution * Max Size * Fix limits * clean code * Check match * Possible solution (ut not fixed) * Limit to 256 bits * Compiler directive * Add comment * Fix comment * Fix ut * Revert change * Revert indent * add -1 * fix * Revert to same logic * Jimmy's feedback --------- Co-authored-by: Jimmy --- src/Neo.VM/Utility.cs | 34 ++++++++--- src/Neo/BigDecimal.cs | 4 +- src/Neo/Cryptography/ECC/ECCurve.cs | 2 +- src/Neo/Cryptography/ECC/ECFieldElement.cs | 4 +- src/Neo/Cryptography/ECC/ECPoint.cs | 4 +- src/Neo/Cryptography/Helper.cs | 27 ++++++++- src/Neo/Cryptography/Murmur128.cs | 14 ++--- src/Neo/Cryptography/Murmur32.cs | 8 +-- src/Neo/IO/Helper.cs | 4 +- src/Neo/Neo.csproj | 2 +- src/Neo/Network/UPnP.cs | 4 +- src/Neo/SmartContract/ContractTask.cs | 10 +--- .../ContractTaskMethodBuilder.cs | 2 +- .../Manifest/ContractMethodDescriptor.cs | 2 +- .../Manifest/ContractParameterDefinition.cs | 2 +- src/Neo/SmartContract/StorageKey.cs | 2 +- tests/Neo.VM.Tests/UtUtility.cs | 58 +++++++++++++++++++ 17 files changed, 139 insertions(+), 44 deletions(-) diff --git a/src/Neo.VM/Utility.cs b/src/Neo.VM/Utility.cs index 940c98d7d9..32f6f157dd 100644 --- a/src/Neo.VM/Utility.cs +++ b/src/Neo.VM/Utility.cs @@ -16,7 +16,7 @@ namespace Neo.VM { - internal static class Utility + public static class Utility { public static Encoding StrictUTF8 { get; } @@ -34,11 +34,11 @@ public static BigInteger ModInverse(this BigInteger value, BigInteger modulus) BigInteger r = value, old_r = modulus, s = 1, old_s = 0; while (r > 0) { - BigInteger q = old_r / r; + var q = old_r / r; (old_r, r) = (r, old_r % r); (old_s, s) = (s, old_s - q * s); } - BigInteger result = old_s % modulus; + var result = old_s % modulus; if (result < 0) result += modulus; if (!(value * result % modulus).IsOne) throw new InvalidOperationException(); return result; @@ -61,17 +61,33 @@ public static BigInteger Sqrt(this BigInteger value) return z; } -#if !NET5_0_OR_GREATER - static int GetBitLength(this BigInteger i) + /// + /// Gets the number of bits required for shortest two's complement representation of the current instance without the sign bit. + /// + /// The minimum non-negative number of bits in two's complement notation without the sign bit. + /// This method returns 0 if the value of current object is equal to or . For positive integers the return value is equal to the ordinary binary representation string length. + public static long GetBitLength(this BigInteger value) { - byte[] b = i.ToByteArray(); - return (b.Length - 1) * 8 + BitLen(i.Sign > 0 ? b[b.Length - 1] : 255 - b[b.Length - 1]); +#if NET5_0_OR_GREATER + return value.GetBitLength(); +#else + if (value == 0 || value == BigInteger.MinusOne) return 0; + + // Note: This method is imprecise and might not work as expected with integers larger than 256 bits. + var b = value.ToByteArray(); + if (b.Length == 1 || (b.Length == 2 && b[1] == 0)) + { + return BitLen(value.Sign > 0 ? b[0] : (byte)(255 - b[0])); + } + return (b.Length - 1) * 8 + BitLen(value.Sign > 0 ? b[^1] : 255 - b[^1]); +#endif } +#if !NET5_0_OR_GREATER [MethodImpl(MethodImplOptions.AggressiveInlining)] static int BitLen(int w) { - return (w < 1 << 15 ? (w < 1 << 7 + 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 @@ -83,7 +99,7 @@ static int BitLen(int w) ? (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))))); + : (w < 1 << 29 ? (w < 1 << 28 ? 28 : 29) : (w < 1 << 30 ? 30 : 31)))); } #endif } diff --git a/src/Neo/BigDecimal.cs b/src/Neo/BigDecimal.cs index 1658ea9c8e..05cdf86626 100644 --- a/src/Neo/BigDecimal.cs +++ b/src/Neo/BigDecimal.cs @@ -55,7 +55,7 @@ public BigDecimal(BigInteger value, byte decimals) public unsafe BigDecimal(decimal value) { Span span = stackalloc int[4]; - decimal.GetBits(value, span); + span = decimal.GetBits(value); fixed (int* p = span) { ReadOnlySpan buffer = new(p, 16); @@ -73,7 +73,7 @@ public unsafe BigDecimal(decimal value) public unsafe BigDecimal(decimal value, byte decimals) { Span span = stackalloc int[4]; - decimal.GetBits(value, span); + span = decimal.GetBits(value); fixed (int* p = span) { ReadOnlySpan buffer = new(p, 16); diff --git a/src/Neo/Cryptography/ECC/ECCurve.cs b/src/Neo/Cryptography/ECC/ECCurve.cs index 7da6c5f3b8..b228f7ab31 100644 --- a/src/Neo/Cryptography/ECC/ECCurve.cs +++ b/src/Neo/Cryptography/ECC/ECCurve.cs @@ -37,7 +37,7 @@ public class ECCurve private ECCurve(BigInteger Q, BigInteger A, BigInteger B, BigInteger N, byte[] G) { this.Q = Q; - this.ExpectedECPointLength = ((int)Q.GetBitLength() + 7) / 8; + this.ExpectedECPointLength = ((int)VM.Utility.GetBitLength(Q) + 7) / 8; this.A = new ECFieldElement(A, this); this.B = new ECFieldElement(B, this); this.N = N; diff --git a/src/Neo/Cryptography/ECC/ECFieldElement.cs b/src/Neo/Cryptography/ECC/ECFieldElement.cs index c00a779315..e08b5bb71f 100644 --- a/src/Neo/Cryptography/ECC/ECFieldElement.cs +++ b/src/Neo/Cryptography/ECC/ECFieldElement.cs @@ -54,7 +54,7 @@ public bool Equals(ECFieldElement other) private static BigInteger[] FastLucasSequence(BigInteger p, BigInteger P, BigInteger Q, BigInteger k) { - int n = (int)k.GetBitLength(); + int n = (int)VM.Utility.GetBitLength(k); int s = k.GetLowestSetBit(); BigInteger Uh = 1; @@ -126,7 +126,7 @@ public ECFieldElement Sqrt() BigInteger P; do { - P = rand.NextBigInteger((int)curve.Q.GetBitLength()); + P = rand.NextBigInteger((int)VM.Utility.GetBitLength(curve.Q)); } while (P >= curve.Q || BigInteger.ModPow(P * P - fourQ, legendreExponent, curve.Q) != qMinusOne); BigInteger[] result = FastLucasSequence(curve.Q, P, Q, k); diff --git a/src/Neo/Cryptography/ECC/ECPoint.cs b/src/Neo/Cryptography/ECC/ECPoint.cs index 6b74232c81..b2d44bf6cf 100644 --- a/src/Neo/Cryptography/ECC/ECPoint.cs +++ b/src/Neo/Cryptography/ECC/ECPoint.cs @@ -237,7 +237,7 @@ public override int GetHashCode() internal static ECPoint Multiply(ECPoint p, BigInteger k) { // floor(log2(k)) - int m = (int)k.GetBitLength(); + int m = (int)VM.Utility.GetBitLength(k); // width of the Window NAF sbyte width; @@ -391,7 +391,7 @@ internal ECPoint Twice() private static sbyte[] WindowNaf(sbyte width, BigInteger k) { - sbyte[] wnaf = new sbyte[k.GetBitLength() + 1]; + sbyte[] wnaf = new sbyte[VM.Utility.GetBitLength(k) + 1]; short pow2wB = (short)(1 << width); int i = 0; int length = 0; diff --git a/src/Neo/Cryptography/Helper.cs b/src/Neo/Cryptography/Helper.cs index 2f0ad0ce35..840b6ebb7b 100644 --- a/src/Neo/Cryptography/Helper.cs +++ b/src/Neo/Cryptography/Helper.cs @@ -18,6 +18,7 @@ using System; using System.Buffers.Binary; using System.Linq; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Security.Cryptography; using static Neo.Helper; @@ -99,7 +100,7 @@ public static byte[] Murmur128(this byte[] value, uint seed) /// The computed hash code. public static byte[] Murmur128(this ReadOnlySpan value, uint seed) { - byte[] buffer = GC.AllocateUninitializedArray(16); + byte[] buffer = new byte[16]; using Murmur128 murmur = new(seed); murmur.TryComputeHash(value, buffer, out _); return buffer; @@ -239,5 +240,29 @@ internal static bool Test(this BloomFilter filter, Transaction tx) return true; return false; } + + /// + /// Rotates the specified value left by the specified number of bits. + /// Similar in behavior to the x86 instruction ROL. + /// + /// The value to rotate. + /// The number of bits to rotate by. + /// Any value outside the range [0..31] is treated as congruent mod 32. + /// The rotated value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static uint RotateLeft(uint value, int offset) + => (value << offset) | (value >> (32 - offset)); + + /// + /// Rotates the specified value left by the specified number of bits. + /// Similar in behavior to the x86 instruction ROL. + /// + /// The value to rotate. + /// The number of bits to rotate by. + /// Any value outside the range [0..63] is treated as congruent mod 64. + /// The rotated value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ulong RotateLeft(ulong value, int offset) + => (value << offset) | (value >> (64 - offset)); } } diff --git a/src/Neo/Cryptography/Murmur128.cs b/src/Neo/Cryptography/Murmur128.cs index 18e67a91ac..3ee258b4a2 100644 --- a/src/Neo/Cryptography/Murmur128.cs +++ b/src/Neo/Cryptography/Murmur128.cs @@ -63,19 +63,19 @@ protected override void HashCore(ReadOnlySpan source) { ulong k1 = BinaryPrimitives.ReadUInt64LittleEndian(source[i..]); k1 *= c1; - k1 = BitOperations.RotateLeft(k1, r1); + k1 = Helper.RotateLeft(k1, r1); k1 *= c2; H1 ^= k1; - H1 = BitOperations.RotateLeft(H1, 27); + H1 = Helper.RotateLeft(H1, 27); H1 += H2; H1 = H1 * m + n1; ulong k2 = BinaryPrimitives.ReadUInt64LittleEndian(source[(i + 8)..]); k2 *= c2; - k2 = BitOperations.RotateLeft(k2, r2); + k2 = Helper.RotateLeft(k2, r2); k2 *= c1; H2 ^= k2; - H2 = BitOperations.RotateLeft(H2, 31); + H2 = Helper.RotateLeft(H2, 31); H2 += H1; H2 = H2 * m + n2; } @@ -102,14 +102,14 @@ protected override void HashCore(ReadOnlySpan source) case 1: remainingBytesL ^= (ulong)source[alignedLength] << 0; break; } - H2 ^= BitOperations.RotateLeft(remainingBytesH * c2, r2) * c1; - H1 ^= BitOperations.RotateLeft(remainingBytesL * c1, r1) * c2; + H2 ^= Helper.RotateLeft(remainingBytesH * c2, r2) * c1; + H1 ^= Helper.RotateLeft(remainingBytesL * c1, r1) * c2; } } protected override byte[] HashFinal() { - byte[] buffer = GC.AllocateUninitializedArray(sizeof(ulong) * 2); + byte[] buffer = new byte[sizeof(ulong) * 2]; TryHashFinal(buffer, out _); return buffer; } diff --git a/src/Neo/Cryptography/Murmur32.cs b/src/Neo/Cryptography/Murmur32.cs index a48c5d6750..8feaa92d37 100644 --- a/src/Neo/Cryptography/Murmur32.cs +++ b/src/Neo/Cryptography/Murmur32.cs @@ -56,10 +56,10 @@ protected override void HashCore(ReadOnlySpan source) { uint k = BinaryPrimitives.ReadUInt32LittleEndian(source); k *= c1; - k = BitOperations.RotateLeft(k, r1); + k = Helper.RotateLeft(k, r1); k *= c2; hash ^= k; - hash = BitOperations.RotateLeft(hash, r2); + hash = Helper.RotateLeft(hash, r2); hash = hash * m + n; } if (source.Length > 0) @@ -72,7 +72,7 @@ protected override void HashCore(ReadOnlySpan source) case 1: remainingBytes ^= source[0]; break; } remainingBytes *= c1; - remainingBytes = BitOperations.RotateLeft(remainingBytes, r1); + remainingBytes = Helper.RotateLeft(remainingBytes, r1); remainingBytes *= c2; hash ^= remainingBytes; } @@ -80,7 +80,7 @@ protected override void HashCore(ReadOnlySpan source) protected override byte[] HashFinal() { - byte[] buffer = GC.AllocateUninitializedArray(sizeof(uint)); + byte[] buffer = new byte[sizeof(uint)]; TryHashFinal(buffer, out _); return buffer; } diff --git a/src/Neo/IO/Helper.cs b/src/Neo/IO/Helper.cs index 7449dbfab9..2e6d362ee1 100644 --- a/src/Neo/IO/Helper.cs +++ b/src/Neo/IO/Helper.cs @@ -102,7 +102,7 @@ public static ISerializable AsSerializable(this ReadOnlyMemory value, Type public static ReadOnlyMemory CompressLz4(this ReadOnlySpan data) { int maxLength = LZ4Codec.MaximumOutputSize(data.Length); - byte[] buffer = GC.AllocateUninitializedArray(sizeof(uint) + maxLength); + byte[] buffer = new byte[sizeof(uint) + maxLength]; BinaryPrimitives.WriteInt32LittleEndian(buffer, data.Length); int length = LZ4Codec.Encode(data, buffer.AsSpan(sizeof(uint))); return buffer.AsMemory(0, sizeof(uint) + length); @@ -118,7 +118,7 @@ public static byte[] DecompressLz4(this ReadOnlySpan data, int maxOutput) { int length = BinaryPrimitives.ReadInt32LittleEndian(data); if (length < 0 || length > maxOutput) throw new FormatException(); - byte[] result = GC.AllocateUninitializedArray(length); + byte[] result = new byte[length]; if (LZ4Codec.Decode(data[4..], result) != length) throw new FormatException(); return result; diff --git a/src/Neo/Neo.csproj b/src/Neo/Neo.csproj index de628a66de..234fbc62c6 100644 --- a/src/Neo/Neo.csproj +++ b/src/Neo/Neo.csproj @@ -1,7 +1,7 @@ - net7.0 + netstandard2.1;net7.0 true NEO;AntShares;Blockchain;Smart Contract diff --git a/src/Neo/Network/UPnP.cs b/src/Neo/Network/UPnP.cs index a80e6e69fb..a0cd0ce78a 100644 --- a/src/Neo/Network/UPnP.cs +++ b/src/Neo/Network/UPnP.cs @@ -183,8 +183,8 @@ private static XmlDocument SOAPRequest(string url, string soap, string function) request.Headers.Add("Content-Type", "text/xml; charset=\"utf-8\""); request.Content = new StringContent(req); using HttpClient http = new(); - using HttpResponseMessage response = http.Send(request); - using Stream stream = response.EnsureSuccessStatusCode().Content.ReadAsStream(); + using HttpResponseMessage response = http.SendAsync(request).GetAwaiter().GetResult(); + using Stream stream = response.EnsureSuccessStatusCode().Content.ReadAsStreamAsync().GetAwaiter().GetResult(); XmlDocument resp = new() { XmlResolver = null }; resp.Load(stream); return resp; diff --git a/src/Neo/SmartContract/ContractTask.cs b/src/Neo/SmartContract/ContractTask.cs index 523b8b115a..6df3627c37 100644 --- a/src/Neo/SmartContract/ContractTask.cs +++ b/src/Neo/SmartContract/ContractTask.cs @@ -32,19 +32,15 @@ public ContractTask() } protected virtual ContractTaskAwaiter CreateAwaiter() => new(); - public virtual ContractTaskAwaiter GetAwaiter() => awaiter; - public virtual object GetResult() => null; } [AsyncMethodBuilder(typeof(ContractTaskMethodBuilder<>))] class ContractTask : ContractTask { - protected override ContractTaskAwaiter CreateAwaiter() => new(); - - public override ContractTaskAwaiter GetAwaiter() => (ContractTaskAwaiter)base.GetAwaiter(); - - public override object GetResult() => GetAwaiter().GetResult(); + protected override ContractTaskAwaiter CreateAwaiter() => new ContractTaskAwaiter(); + public override ContractTaskAwaiter GetAwaiter() => (ContractTaskAwaiter)base.GetAwaiter(); + public override object GetResult() => ((ContractTaskAwaiter)GetAwaiter()).GetResult(); } } diff --git a/src/Neo/SmartContract/ContractTaskMethodBuilder.cs b/src/Neo/SmartContract/ContractTaskMethodBuilder.cs index 83090bf583..bae1146f25 100644 --- a/src/Neo/SmartContract/ContractTaskMethodBuilder.cs +++ b/src/Neo/SmartContract/ContractTaskMethodBuilder.cs @@ -71,7 +71,7 @@ public void SetException(Exception exception) public void SetResult(T result) { - Task.GetAwaiter().SetResult(result); + ((ContractTaskAwaiter)Task.GetAwaiter()).SetResult(result); } public void AwaitOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine) diff --git a/src/Neo/SmartContract/Manifest/ContractMethodDescriptor.cs b/src/Neo/SmartContract/Manifest/ContractMethodDescriptor.cs index 646ee76c46..cc8d0a16d5 100644 --- a/src/Neo/SmartContract/Manifest/ContractMethodDescriptor.cs +++ b/src/Neo/SmartContract/Manifest/ContractMethodDescriptor.cs @@ -73,7 +73,7 @@ public override StackItem ToStackItem(ReferenceCounter referenceCounter) }; if (string.IsNullOrEmpty(descriptor.Name)) throw new FormatException(); _ = descriptor.Parameters.ToDictionary(p => p.Name); - if (!Enum.IsDefined(descriptor.ReturnType)) throw new FormatException(); + if (!Enum.IsDefined(typeof(ContractParameterType), descriptor.ReturnType)) throw new FormatException(); if (descriptor.Offset < 0) throw new FormatException(); return descriptor; } diff --git a/src/Neo/SmartContract/Manifest/ContractParameterDefinition.cs b/src/Neo/SmartContract/Manifest/ContractParameterDefinition.cs index a393bb02b1..61906558d0 100644 --- a/src/Neo/SmartContract/Manifest/ContractParameterDefinition.cs +++ b/src/Neo/SmartContract/Manifest/ContractParameterDefinition.cs @@ -57,7 +57,7 @@ public static ContractParameterDefinition FromJson(JObject json) }; if (string.IsNullOrEmpty(parameter.Name)) throw new FormatException(); - if (!Enum.IsDefined(parameter.Type) || parameter.Type == ContractParameterType.Void) + if (!Enum.IsDefined(typeof(ContractParameterType), parameter.Type) || parameter.Type == ContractParameterType.Void) throw new FormatException(); return parameter; } diff --git a/src/Neo/SmartContract/StorageKey.cs b/src/Neo/SmartContract/StorageKey.cs index 21d7a64191..a0136e4456 100644 --- a/src/Neo/SmartContract/StorageKey.cs +++ b/src/Neo/SmartContract/StorageKey.cs @@ -73,7 +73,7 @@ public byte[] ToArray() { if (cache is null) { - cache = GC.AllocateUninitializedArray(sizeof(int) + Key.Length); + cache = new byte[sizeof(int) + Key.Length]; BinaryPrimitives.WriteInt32LittleEndian(cache, Id); Key.CopyTo(cache.AsMemory(sizeof(int))); } diff --git a/tests/Neo.VM.Tests/UtUtility.cs b/tests/Neo.VM.Tests/UtUtility.cs index fd039a6e5d..47837d6f60 100644 --- a/tests/Neo.VM.Tests/UtUtility.cs +++ b/tests/Neo.VM.Tests/UtUtility.cs @@ -32,6 +32,64 @@ public void SqrtTest() Assert.AreEqual(new BigInteger(9), new BigInteger(81).Sqrt()); } + private static byte[] GetRandomByteArray(Random random) + { + var byteValue = random.Next(0, 32); + var value = new byte[byteValue]; + + random.NextBytes(value); + return value; + } + + private void VerifyGetBitLength(BigInteger value, long expected) + { + var result = value.GetBitLength(); + Assert.AreEqual(expected, value.GetBitLength(), "Native method has not the expected result"); + Assert.AreEqual(result, Utility.GetBitLength(value), "Result doesn't match"); + } + + [TestMethod] + public void GetBitLengthTest() + { + var random = new Random(); + + // Big Number (net standard didn't work) + VerifyGetBitLength(BigInteger.One << 32 << int.MaxValue, 2147483680); + + // Trivial cases + // sign bit|shortest two's complement + // string w/o sign bit + VerifyGetBitLength(0, 0); // 0| + VerifyGetBitLength(1, 1); // 0|1 + VerifyGetBitLength(-1, 0); // 1| + VerifyGetBitLength(2, 2); // 0|10 + VerifyGetBitLength(-2, 1); // 1|0 + VerifyGetBitLength(3, 2); // 0|11 + VerifyGetBitLength(-3, 2); // 1|01 + VerifyGetBitLength(4, 3); // 0|100 + VerifyGetBitLength(-4, 2); // 1|00 + VerifyGetBitLength(5, 3); // 0|101 + VerifyGetBitLength(-5, 3); // 1|011 + VerifyGetBitLength(6, 3); // 0|110 + VerifyGetBitLength(-6, 3); // 1|010 + VerifyGetBitLength(7, 3); // 0|111 + VerifyGetBitLength(-7, 3); // 1|001 + VerifyGetBitLength(8, 4); // 0|1000 + VerifyGetBitLength(-8, 3); // 1|000 + + // Random cases + for (uint i = 0; i < 1000; i++) + { + var bi = new BigInteger(GetRandomByteArray(random)); + Assert.AreEqual(bi.GetBitLength(), Utility.GetBitLength(bi), message: $"Error comparing: {bi}"); + } + + foreach (var bi in new[] { BigInteger.Zero, BigInteger.One, BigInteger.MinusOne, new BigInteger(ulong.MaxValue), new BigInteger(long.MinValue) }) + { + Assert.AreEqual(bi.GetBitLength(), Utility.GetBitLength(bi), message: $"Error comparing: {bi}"); + } + } + [TestMethod] public void ModInverseTest() { From d65c198ae0af25e53f65d3e68b330cfc9574cfe8 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Wed, 7 Feb 2024 18:54:22 +0800 Subject: [PATCH 070/168] [VM UT] update UT name (#3115) * update UT name * Update tests/Neo.VM.Tests/UT_StackItem.cs Co-authored-by: Owen Zhang <38493437+superboyiii@users.noreply.github.com> * Update tests/Neo.VM.Tests/UT_StackItem.cs Co-authored-by: Owen Zhang <38493437+superboyiii@users.noreply.github.com> * Update tests/Neo.VM.Tests/UT_StackItem.cs Co-authored-by: Owen Zhang <38493437+superboyiii@users.noreply.github.com> * Update tests/Neo.VM.Tests/UT_StackItem.cs Co-authored-by: Owen Zhang <38493437+superboyiii@users.noreply.github.com> * Update tests/Neo.VM.Tests/UT_StackItem.cs Co-authored-by: Owen Zhang <38493437+superboyiii@users.noreply.github.com> * Update tests/Neo.VM.Tests/UT_ExecutionContext.cs Co-authored-by: Christopher Schuchardt * Update tests/Neo.VM.Tests/UT_ScriptBuilder.cs * Update tests/Neo.VM.Tests/UT_EvaluationStack.cs * fix ut name --------- Co-authored-by: Owen Zhang <38493437+superboyiii@users.noreply.github.com> Co-authored-by: Shargon Co-authored-by: Christopher Schuchardt Co-authored-by: NGD Admin <154295625+NGDAdmin@users.noreply.github.com> --- .../Neo.VM.Tests/{UtDebugger.cs => UT_Debugger.cs} | 12 ++++++------ ...{UtEvaluationStack.cs => UT_EvaluationStack.cs} | 4 ++-- ...tExecutionContext.cs => UT_ExecutionContext.cs} | 6 +++--- ...tReferenceCounter.cs => UT_ReferenceCounter.cs} | 4 ++-- tests/Neo.VM.Tests/{UtScript.cs => UT_Script.cs} | 10 +++++----- .../{UtScriptBuilder.cs => UT_ScriptBuilder.cs} | 4 ++-- tests/Neo.VM.Tests/{UtSlot.cs => UT_Slot.cs} | 4 ++-- .../{UtStackItem.cs => UT_StackItem.cs} | 14 +++++++------- tests/Neo.VM.Tests/{UtStruct.cs => UT_Struct.cs} | 12 ++++++------ tests/Neo.VM.Tests/{UtUnsafe.cs => UT_Unsafe.cs} | 6 +++--- tests/Neo.VM.Tests/{UtUtility.cs => UT_Utility.cs} | 10 +++++----- tests/Neo.VM.Tests/{UtVMJson.cs => UT_VMJson.cs} | 4 ++-- 12 files changed, 45 insertions(+), 45 deletions(-) rename tests/Neo.VM.Tests/{UtDebugger.cs => UT_Debugger.cs} (97%) rename tests/Neo.VM.Tests/{UtEvaluationStack.cs => UT_EvaluationStack.cs} (98%) rename tests/Neo.VM.Tests/{UtExecutionContext.cs => UT_ExecutionContext.cs} (92%) rename tests/Neo.VM.Tests/{UtReferenceCounter.cs => UT_ReferenceCounter.cs} (98%) rename tests/Neo.VM.Tests/{UtScript.cs => UT_Script.cs} (94%) rename tests/Neo.VM.Tests/{UtScriptBuilder.cs => UT_ScriptBuilder.cs} (99%) rename tests/Neo.VM.Tests/{UtSlot.cs => UT_Slot.cs} (97%) rename tests/Neo.VM.Tests/{UtStackItem.cs => UT_StackItem.cs} (96%) rename tests/Neo.VM.Tests/{UtStruct.cs => UT_Struct.cs} (91%) rename tests/Neo.VM.Tests/{UtUnsafe.cs => UT_Unsafe.cs} (89%) rename tests/Neo.VM.Tests/{UtUtility.cs => UT_Utility.cs} (95%) rename tests/Neo.VM.Tests/{UtVMJson.cs => UT_VMJson.cs} (96%) diff --git a/tests/Neo.VM.Tests/UtDebugger.cs b/tests/Neo.VM.Tests/UT_Debugger.cs similarity index 97% rename from tests/Neo.VM.Tests/UtDebugger.cs rename to tests/Neo.VM.Tests/UT_Debugger.cs index 13d33a7443..64f543f65e 100644 --- a/tests/Neo.VM.Tests/UtDebugger.cs +++ b/tests/Neo.VM.Tests/UT_Debugger.cs @@ -1,6 +1,6 @@ // Copyright (C) 2015-2024 The Neo Project. // -// UtDebugger.cs file belongs to the neo project and is free +// UT_Debugger.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 @@ -15,7 +15,7 @@ namespace Neo.Test { [TestClass] - public class UtDebugger + public class UT_Debugger { [TestMethod] public void TestBreakPoint() @@ -97,10 +97,10 @@ public void TestStepOver() { using ExecutionEngine engine = new(); using ScriptBuilder script = new(); - /* ┌ CALL + /* ┌ CALL │ ┌> NOT │ │ RET - └> │ PUSH0 + └> │ PUSH0 └─┘ RET */ script.EmitCall(4); script.Emit(OpCode.NOT); @@ -135,7 +135,7 @@ public void TestStepInto() using ExecutionEngine engine = new(); using ScriptBuilder script = new(); /* ┌ CALL - │ ┌> NOT + │ ┌> NOT │ │ RET └> │ PUSH0 └─┘ RET */ @@ -185,7 +185,7 @@ public void TestBreakPointStepOver() { using ExecutionEngine engine = new(); using ScriptBuilder script = new(); - /* ┌ CALL + /* ┌ CALL │ ┌> NOT │ │ RET └>X│ PUSH0 diff --git a/tests/Neo.VM.Tests/UtEvaluationStack.cs b/tests/Neo.VM.Tests/UT_EvaluationStack.cs similarity index 98% rename from tests/Neo.VM.Tests/UtEvaluationStack.cs rename to tests/Neo.VM.Tests/UT_EvaluationStack.cs index 23526bc5de..c4a5d65914 100644 --- a/tests/Neo.VM.Tests/UtEvaluationStack.cs +++ b/tests/Neo.VM.Tests/UT_EvaluationStack.cs @@ -1,6 +1,6 @@ // Copyright (C) 2015-2024 The Neo Project. // -// UtEvaluationStack.cs file belongs to the neo project and is free +// UT_EvaluationStack.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 @@ -19,7 +19,7 @@ namespace Neo.Test { [TestClass] - public class UtEvaluationStack + public class UT_EvaluationStack { private static EvaluationStack CreateOrderedStack(int count) { diff --git a/tests/Neo.VM.Tests/UtExecutionContext.cs b/tests/Neo.VM.Tests/UT_ExecutionContext.cs similarity index 92% rename from tests/Neo.VM.Tests/UtExecutionContext.cs rename to tests/Neo.VM.Tests/UT_ExecutionContext.cs index 0cf5c0224f..b53003a7e6 100644 --- a/tests/Neo.VM.Tests/UtExecutionContext.cs +++ b/tests/Neo.VM.Tests/UT_ExecutionContext.cs @@ -1,6 +1,6 @@ // Copyright (C) 2015-2024 The Neo Project. // -// UtExecutionContext.cs file belongs to the neo project and is free +// UT_ExecutionContext.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.Test { [TestClass] - public class UtExecutionContext + public class UT_ExecutionContext { class TestState { @@ -25,7 +25,7 @@ class TestState } [TestMethod] - public void StateTest() + public void TestStateTest() { var context = new ExecutionContext(Array.Empty(), -1, new ReferenceCounter()); diff --git a/tests/Neo.VM.Tests/UtReferenceCounter.cs b/tests/Neo.VM.Tests/UT_ReferenceCounter.cs similarity index 98% rename from tests/Neo.VM.Tests/UtReferenceCounter.cs rename to tests/Neo.VM.Tests/UT_ReferenceCounter.cs index 32169d0dd6..b0ad90b673 100644 --- a/tests/Neo.VM.Tests/UtReferenceCounter.cs +++ b/tests/Neo.VM.Tests/UT_ReferenceCounter.cs @@ -1,6 +1,6 @@ // Copyright (C) 2015-2024 The Neo Project. // -// UtReferenceCounter.cs file belongs to the neo project and is free +// UT_ReferenceCounter.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 @@ -16,7 +16,7 @@ namespace Neo.Test { [TestClass] - public class UtReferenceCounter + public class UT_ReferenceCounter { [TestMethod] public void TestCircularReferences() diff --git a/tests/Neo.VM.Tests/UtScript.cs b/tests/Neo.VM.Tests/UT_Script.cs similarity index 94% rename from tests/Neo.VM.Tests/UtScript.cs rename to tests/Neo.VM.Tests/UT_Script.cs index 3cc4280829..c703d2685f 100644 --- a/tests/Neo.VM.Tests/UtScript.cs +++ b/tests/Neo.VM.Tests/UT_Script.cs @@ -1,6 +1,6 @@ // Copyright (C) 2015-2024 The Neo Project. // -// UtScript.cs file belongs to the neo project and is free +// UT_Script.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,10 +17,10 @@ namespace Neo.Test { [TestClass] - public class UtScript + public class UT_Script { [TestMethod] - public void Conversion() + public void TestConversion() { byte[] rawScript; using (var builder = new ScriptBuilder()) @@ -39,7 +39,7 @@ public void Conversion() } [TestMethod] - public void StrictMode() + public void TestStrictMode() { var rawScript = new byte[] { (byte)OpCode.PUSH0, 0xFF }; Assert.ThrowsException(() => new Script(rawScript, true)); @@ -58,7 +58,7 @@ public void StrictMode() } [TestMethod] - public void Parse() + public void TestParse() { Script script; diff --git a/tests/Neo.VM.Tests/UtScriptBuilder.cs b/tests/Neo.VM.Tests/UT_ScriptBuilder.cs similarity index 99% rename from tests/Neo.VM.Tests/UtScriptBuilder.cs rename to tests/Neo.VM.Tests/UT_ScriptBuilder.cs index 08701c6bd7..faa57f3345 100644 --- a/tests/Neo.VM.Tests/UtScriptBuilder.cs +++ b/tests/Neo.VM.Tests/UT_ScriptBuilder.cs @@ -1,6 +1,6 @@ // Copyright (C) 2015-2024 The Neo Project. // -// UtScriptBuilder.cs file belongs to the neo project and is free +// UT_ScriptBuilder.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 @@ -21,7 +21,7 @@ namespace Neo.Test { [TestClass] - public class UtScriptBuilder + public class UT_ScriptBuilder { [TestMethod] public void TestEmit() diff --git a/tests/Neo.VM.Tests/UtSlot.cs b/tests/Neo.VM.Tests/UT_Slot.cs similarity index 97% rename from tests/Neo.VM.Tests/UtSlot.cs rename to tests/Neo.VM.Tests/UT_Slot.cs index 49c81727d1..ea2f38029b 100644 --- a/tests/Neo.VM.Tests/UtSlot.cs +++ b/tests/Neo.VM.Tests/UT_Slot.cs @@ -1,6 +1,6 @@ // Copyright (C) 2015-2024 The Neo Project. // -// UtSlot.cs file belongs to the neo project and is free +// UT_Slot.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 @@ -20,7 +20,7 @@ namespace Neo.Test { [TestClass] - public class UtSlot + public class UT_Slot { private static Slot CreateOrderedSlot(int count) { diff --git a/tests/Neo.VM.Tests/UtStackItem.cs b/tests/Neo.VM.Tests/UT_StackItem.cs similarity index 96% rename from tests/Neo.VM.Tests/UtStackItem.cs rename to tests/Neo.VM.Tests/UT_StackItem.cs index 6eb50603d7..210fa0d433 100644 --- a/tests/Neo.VM.Tests/UtStackItem.cs +++ b/tests/Neo.VM.Tests/UT_StackItem.cs @@ -1,6 +1,6 @@ // Copyright (C) 2015-2024 The Neo Project. // -// UtStackItem.cs file belongs to the neo project and is free +// UT_StackItem.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,10 +17,10 @@ namespace Neo.Test { [TestClass] - public class UtStackItem + public class UT_StackItem { [TestMethod] - public void HashCodeTest() + public void TestHashCode() { StackItem itemA = "NEO"; StackItem itemB = "NEO"; @@ -80,7 +80,7 @@ public void HashCodeTest() } [TestMethod] - public void NullTest() + public void TestNull() { StackItem nullItem = System.Array.Empty(); Assert.AreNotEqual(StackItem.Null, nullItem); @@ -90,7 +90,7 @@ public void NullTest() } [TestMethod] - public void EqualTest() + public void TestEqual() { StackItem itemA = "NEO"; StackItem itemB = "NEO"; @@ -106,7 +106,7 @@ public void EqualTest() } [TestMethod] - public void CastTest() + public void TestCast() { // Signed byte @@ -187,7 +187,7 @@ public void CastTest() } [TestMethod] - public void DeepCopyTest() + public void TestDeepCopy() { Array a = new() { diff --git a/tests/Neo.VM.Tests/UtStruct.cs b/tests/Neo.VM.Tests/UT_Struct.cs similarity index 91% rename from tests/Neo.VM.Tests/UtStruct.cs rename to tests/Neo.VM.Tests/UT_Struct.cs index ca1f5cb05f..2e62650fc1 100644 --- a/tests/Neo.VM.Tests/UtStruct.cs +++ b/tests/Neo.VM.Tests/UT_Struct.cs @@ -1,6 +1,6 @@ // Copyright (C) 2015-2024 The Neo Project. // -// UtStruct.cs file belongs to the neo project and is free +// UT_Struct.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,11 +17,11 @@ namespace Neo.Test { [TestClass] - public class UtStruct + public class UT_Struct { private readonly Struct @struct; - public UtStruct() + public UT_Struct() { @struct = new Struct { 1 }; for (int i = 0; i < 20000; i++) @@ -29,7 +29,7 @@ public UtStruct() } [TestMethod] - public void Clone() + public void TestClone() { Struct s1 = new() { 1, new Struct { 2 } }; Struct s2 = s1.Clone(ExecutionEngineLimits.Default); @@ -41,7 +41,7 @@ public void Clone() } [TestMethod] - public void Equals() + public void TestEquals() { Struct s1 = new() { 1, new Struct { 2 } }; Struct s2 = new() { 1, new Struct { 2 } }; @@ -52,7 +52,7 @@ public void Equals() } [TestMethod] - public void EqualsDos() + public void TestEqualsDos() { string payloadStr = new string('h', 65535); Struct s1 = new(); diff --git a/tests/Neo.VM.Tests/UtUnsafe.cs b/tests/Neo.VM.Tests/UT_Unsafe.cs similarity index 89% rename from tests/Neo.VM.Tests/UtUnsafe.cs rename to tests/Neo.VM.Tests/UT_Unsafe.cs index 1ad0a6fc22..e3b4b8708f 100644 --- a/tests/Neo.VM.Tests/UtUnsafe.cs +++ b/tests/Neo.VM.Tests/UT_Unsafe.cs @@ -1,6 +1,6 @@ // Copyright (C) 2015-2024 The Neo Project. // -// UtUnsafe.cs file belongs to the neo project and is free +// UT_Unsafe.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 @@ -15,10 +15,10 @@ namespace Neo.Test { [TestClass] - public class UtUnsafe + public class UT_Unsafe { [TestMethod] - public void NotZero() + public void TestNotZero() { Assert.IsFalse(Unsafe.NotZero(System.Array.Empty())); Assert.IsFalse(Unsafe.NotZero(new byte[4])); diff --git a/tests/Neo.VM.Tests/UtUtility.cs b/tests/Neo.VM.Tests/UT_Utility.cs similarity index 95% rename from tests/Neo.VM.Tests/UtUtility.cs rename to tests/Neo.VM.Tests/UT_Utility.cs index 47837d6f60..e87bcbcda7 100644 --- a/tests/Neo.VM.Tests/UtUtility.cs +++ b/tests/Neo.VM.Tests/UT_Utility.cs @@ -1,6 +1,6 @@ // Copyright (C) 2015-2024 The Neo Project. // -// UtUtility.cs file belongs to the neo project and is free +// UT_Utility.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,10 +17,10 @@ namespace Neo.Test { [TestClass] - public class UtUtility + public class UT_Utility { [TestMethod] - public void SqrtTest() + public void TestSqrtTest() { Assert.ThrowsException(() => BigInteger.MinusOne.Sqrt()); @@ -49,7 +49,7 @@ private void VerifyGetBitLength(BigInteger value, long expected) } [TestMethod] - public void GetBitLengthTest() + public void TestGetBitLength() { var random = new Random(); @@ -91,7 +91,7 @@ public void GetBitLengthTest() } [TestMethod] - public void ModInverseTest() + public void TestModInverseTest() { Assert.ThrowsException(() => BigInteger.One.ModInverse(BigInteger.Zero)); Assert.ThrowsException(() => BigInteger.One.ModInverse(BigInteger.One)); diff --git a/tests/Neo.VM.Tests/UtVMJson.cs b/tests/Neo.VM.Tests/UT_VMJson.cs similarity index 96% rename from tests/Neo.VM.Tests/UtVMJson.cs rename to tests/Neo.VM.Tests/UT_VMJson.cs index fbed156d45..d91c4b3cad 100644 --- a/tests/Neo.VM.Tests/UtVMJson.cs +++ b/tests/Neo.VM.Tests/UT_VMJson.cs @@ -1,6 +1,6 @@ // Copyright (C) 2015-2024 The Neo Project. // -// UtVMJson.cs file belongs to the neo project and is free +// UT_VMJson.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 @@ -19,7 +19,7 @@ namespace Neo.Test { [TestClass] - public class UtVMJson : VMJsonTestBase + public class UT_VMJson : VMJsonTestBase { [TestMethod] public void TestOthers() => TestJson("./Tests/Others"); From e3707fd637f1f5a390f526d89125049a2231f7cb Mon Sep 17 00:00:00 2001 From: Shargon Date: Wed, 7 Feb 2024 12:39:49 +0100 Subject: [PATCH 071/168] Related to https://github.com/neo-project/neo/pull/3082#issuecomment-1931804852 (#3119) --- src/Neo.VM/Utility.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Neo.VM/Utility.cs b/src/Neo.VM/Utility.cs index 32f6f157dd..edb1c01ebc 100644 --- a/src/Neo.VM/Utility.cs +++ b/src/Neo.VM/Utility.cs @@ -77,15 +77,15 @@ public static long GetBitLength(this BigInteger value) var b = value.ToByteArray(); if (b.Length == 1 || (b.Length == 2 && b[1] == 0)) { - return BitLen(value.Sign > 0 ? b[0] : (byte)(255 - b[0])); + return BitCount(value.Sign > 0 ? b[0] : (byte)(255 - b[0])); } - return (b.Length - 1) * 8 + BitLen(value.Sign > 0 ? b[^1] : 255 - b[^1]); + return (b.Length - 1) * 8 + BitCount(value.Sign > 0 ? b[^1] : 255 - b[^1]); #endif } #if !NET5_0_OR_GREATER [MethodImpl(MethodImplOptions.AggressiveInlining)] - static int BitLen(int w) + private static int BitCount(int w) { return w < 1 << 15 ? (w < 1 << 7 ? (w < 1 << 3 ? (w < 1 << 1 From 76c368efffeb8e7d8595eb9c0eb82f12ad02caa0 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Thu, 8 Feb 2024 02:04:13 +0800 Subject: [PATCH 072/168] VM: avoid checking reference when the stack is not full. (#3107) * avoid checking reference when the stack is not full. * fix UT * Add UT --------- Co-authored-by: Fernando Diaz Toledano --- src/Neo.VM/ExecutionEngine.cs | 1 + tests/Neo.VM.Tests/UT_ReferenceCounter.cs | 78 +++++++++++++++++++++-- 2 files changed, 73 insertions(+), 6 deletions(-) diff --git a/src/Neo.VM/ExecutionEngine.cs b/src/Neo.VM/ExecutionEngine.cs index f67cc9caec..39051afff1 100644 --- a/src/Neo.VM/ExecutionEngine.cs +++ b/src/Neo.VM/ExecutionEngine.cs @@ -1681,6 +1681,7 @@ public T Pop() where T : StackItem /// protected virtual void PostExecuteInstruction(Instruction instruction) { + if (ReferenceCounter.Count < Limits.MaxStackSize) return; if (ReferenceCounter.CheckZeroReferred() > Limits.MaxStackSize) throw new InvalidOperationException($"MaxStackSize exceed: {ReferenceCounter.Count}"); } diff --git a/tests/Neo.VM.Tests/UT_ReferenceCounter.cs b/tests/Neo.VM.Tests/UT_ReferenceCounter.cs index b0ad90b673..f974670805 100644 --- a/tests/Neo.VM.Tests/UT_ReferenceCounter.cs +++ b/tests/Neo.VM.Tests/UT_ReferenceCounter.cs @@ -111,11 +111,11 @@ public void TestCircularReferences() Assert.AreEqual(VMState.BREAK, debugger.StepInto()); Assert.AreEqual(9, engine.ReferenceCounter.Count); Assert.AreEqual(VMState.BREAK, debugger.StepInto()); - Assert.AreEqual(3, engine.ReferenceCounter.Count); + Assert.AreEqual(6, engine.ReferenceCounter.Count); Assert.AreEqual(VMState.BREAK, debugger.StepInto()); - Assert.AreEqual(2, engine.ReferenceCounter.Count); + Assert.AreEqual(5, engine.ReferenceCounter.Count); Assert.AreEqual(VMState.HALT, debugger.Execute()); - Assert.AreEqual(0, engine.ReferenceCounter.Count); + Assert.AreEqual(4, engine.ReferenceCounter.Count); } [TestMethod] @@ -156,9 +156,75 @@ public void TestRemoveReferrer() Assert.AreEqual(VMState.BREAK, debugger.StepInto()); Assert.AreEqual(3, engine.ReferenceCounter.Count); Assert.AreEqual(VMState.BREAK, debugger.StepInto()); - Assert.AreEqual(1, engine.ReferenceCounter.Count); + Assert.AreEqual(2, engine.ReferenceCounter.Count); Assert.AreEqual(VMState.HALT, debugger.Execute()); - Assert.AreEqual(0, engine.ReferenceCounter.Count); + Assert.AreEqual(1, engine.ReferenceCounter.Count); + } + + [TestMethod] + public void TestCheckZeroReferredWithArray() + { + using ScriptBuilder sb = new(); + + sb.EmitPush(ExecutionEngineLimits.Default.MaxStackSize - 1); + sb.Emit(OpCode.NEWARRAY); + + // Good with MaxStackSize + + using (ExecutionEngine engine = new()) + { + engine.LoadScript(sb.ToArray()); + Assert.AreEqual(0, engine.ReferenceCounter.Count); + + Assert.AreEqual(VMState.HALT, engine.Execute()); + Assert.AreEqual((int)ExecutionEngineLimits.Default.MaxStackSize, engine.ReferenceCounter.Count); + } + + // Fault with MaxStackSize+1 + + sb.Emit(OpCode.PUSH1); + + using (ExecutionEngine engine = new()) + { + engine.LoadScript(sb.ToArray()); + Assert.AreEqual(0, engine.ReferenceCounter.Count); + + Assert.AreEqual(VMState.FAULT, engine.Execute()); + Assert.AreEqual((int)ExecutionEngineLimits.Default.MaxStackSize + 1, engine.ReferenceCounter.Count); + } + } + + [TestMethod] + public void TestCheckZeroReferred() + { + using ScriptBuilder sb = new(); + + for (int x = 0; x < ExecutionEngineLimits.Default.MaxStackSize; x++) + sb.Emit(OpCode.PUSH1); + + // Good with MaxStackSize + + using (ExecutionEngine engine = new()) + { + engine.LoadScript(sb.ToArray()); + Assert.AreEqual(0, engine.ReferenceCounter.Count); + + Assert.AreEqual(VMState.HALT, engine.Execute()); + Assert.AreEqual((int)ExecutionEngineLimits.Default.MaxStackSize, engine.ReferenceCounter.Count); + } + + // Fault with MaxStackSize+1 + + sb.Emit(OpCode.PUSH1); + + using (ExecutionEngine engine = new()) + { + engine.LoadScript(sb.ToArray()); + Assert.AreEqual(0, engine.ReferenceCounter.Count); + + Assert.AreEqual(VMState.FAULT, engine.Execute()); + Assert.AreEqual((int)ExecutionEngineLimits.Default.MaxStackSize + 1, engine.ReferenceCounter.Count); + } } [TestMethod] @@ -172,7 +238,7 @@ public void TestArrayNoPush() Array array = new(engine.ReferenceCounter, new StackItem[] { 1, 2, 3, 4 }); Assert.AreEqual(array.Count, engine.ReferenceCounter.Count); Assert.AreEqual(VMState.HALT, engine.Execute()); - Assert.AreEqual(0, engine.ReferenceCounter.Count); + Assert.AreEqual(array.Count, engine.ReferenceCounter.Count); } } } From 3e52756f3c76d5dede7cb801271a4acf19947f3e Mon Sep 17 00:00:00 2001 From: Jimmy Date: Thu, 8 Feb 2024 16:25:10 +0800 Subject: [PATCH 073/168] [Neo VM: FIX] the GetString() methods of bytestring requires strictUTF8 (#3110) * the GetString() methods of bytestring requires strictUTF8, but we can set it differently. * update UTF8 rule and add UT * add comment and prefix to base64 string * fix UT * Rename ToString to Print and move it to the unit test where it is needed. As it is a test method and only unit test will need it. * Update tests/Neo.VM.Tests/UtEvaluationStack.cs * Update src/Neo.VM/Utility.cs * Update tests/Neo.VM.Tests/UtEvaluationStack.cs * move try string to vm test * Centralize print * fix UT * fix base64 format * Override ToString * Clean using --------- Co-authored-by: Shargon --- src/Neo.VM/EvaluationStack.cs | 25 +++++------------------- src/Neo.VM/Types/Boolean.cs | 5 +++++ src/Neo.VM/Types/Buffer.cs | 5 +++++ src/Neo.VM/Types/ByteString.cs | 5 +++++ src/Neo.VM/Types/CompoundType.cs | 5 +++++ src/Neo.VM/Types/Integer.cs | 5 +++++ src/Neo.VM/Types/InteropInterface.cs | 5 +++++ src/Neo.VM/Types/Null.cs | 5 +++++ src/Neo.VM/Types/Pointer.cs | 5 +++++ src/Neo.VM/Utility.cs | 14 +++++++++++++ tests/Neo.VM.Tests/UT_EvaluationStack.cs | 12 +++++++++++- 11 files changed, 70 insertions(+), 21 deletions(-) diff --git a/src/Neo.VM/EvaluationStack.cs b/src/Neo.VM/EvaluationStack.cs index e038f38625..34517b2197 100644 --- a/src/Neo.VM/EvaluationStack.cs +++ b/src/Neo.VM/EvaluationStack.cs @@ -36,26 +36,6 @@ internal EvaluationStack(ReferenceCounter referenceCounter) /// public int Count => innerList.Count; - public override string ToString() - { - return $@"[{string.Join(", ", innerList.Select(p => - { - var value = p.Type switch - { - StackItemType.Pointer => $"({((Pointer)p).Position})", - StackItemType.Boolean => $"({p.GetBoolean()})", - StackItemType.Integer => $"({p.GetInteger()})", - StackItemType.ByteString => $"(\"{p.GetString()}\")", - StackItemType.Array - or StackItemType.Map - or StackItemType.Struct => $"({((CompoundType)p).Count})", - _ => "" - }; - return $"{p.Type.ToString()}{value}"; - } - ))}]"; - } - internal void Clear() { foreach (StackItem item in innerList) @@ -179,5 +159,10 @@ internal T Remove(int index) where T : StackItem referenceCounter.RemoveStackReference(item); return item; } + + public override string ToString() + { + return $"[{string.Join(", ", innerList.Select(p => $"{p.Type}({p})"))}]"; + } } } diff --git a/src/Neo.VM/Types/Boolean.cs b/src/Neo.VM/Types/Boolean.cs index 3b736c174e..e0a9864d92 100644 --- a/src/Neo.VM/Types/Boolean.cs +++ b/src/Neo.VM/Types/Boolean.cs @@ -67,5 +67,10 @@ public static implicit operator Boolean(bool value) { return value ? True : False; } + + public override string ToString() + { + return value.ToString(); + } } } diff --git a/src/Neo.VM/Types/Buffer.cs b/src/Neo.VM/Types/Buffer.cs index 5c71ce45f8..8d170577e6 100644 --- a/src/Neo.VM/Types/Buffer.cs +++ b/src/Neo.VM/Types/Buffer.cs @@ -107,5 +107,10 @@ public override ReadOnlySpan GetSpan() { return InnerBuffer.Span; } + + public override string ToString() + { + return GetSpan().TryGetString(out var str) ? $"(\"{str}\")" : $"(\"Base64: {Convert.ToBase64String(GetSpan())}\")"; + } } } diff --git a/src/Neo.VM/Types/ByteString.cs b/src/Neo.VM/Types/ByteString.cs index a22dff75b9..4d0e941dc1 100644 --- a/src/Neo.VM/Types/ByteString.cs +++ b/src/Neo.VM/Types/ByteString.cs @@ -133,5 +133,10 @@ public static implicit operator ByteString(string value) { return new ByteString(Utility.StrictUTF8.GetBytes(value)); } + + public override string ToString() + { + return GetSpan().TryGetString(out var str) ? $"\"{str}\"" : $"\"Base64: {Convert.ToBase64String(GetSpan())}\""; + } } } diff --git a/src/Neo.VM/Types/CompoundType.cs b/src/Neo.VM/Types/CompoundType.cs index 0050cc7e13..02323e3f2f 100644 --- a/src/Neo.VM/Types/CompoundType.cs +++ b/src/Neo.VM/Types/CompoundType.cs @@ -67,5 +67,10 @@ public override int GetHashCode() { throw new NotSupportedException(); } + + public override string ToString() + { + return Count.ToString(); + } } } diff --git a/src/Neo.VM/Types/Integer.cs b/src/Neo.VM/Types/Integer.cs index 67bbc05efa..4d997d6c5a 100644 --- a/src/Neo.VM/Types/Integer.cs +++ b/src/Neo.VM/Types/Integer.cs @@ -130,5 +130,10 @@ public static implicit operator Integer(BigInteger value) { return new Integer(value); } + + public override string ToString() + { + return value.ToString(); + } } } diff --git a/src/Neo.VM/Types/InteropInterface.cs b/src/Neo.VM/Types/InteropInterface.cs index c6d88af753..7dbdf55b8d 100644 --- a/src/Neo.VM/Types/InteropInterface.cs +++ b/src/Neo.VM/Types/InteropInterface.cs @@ -55,5 +55,10 @@ public override T GetInterface() if (_object is T t) return t; throw new InvalidCastException($"The item can't be casted to type {typeof(T)}"); } + + public override string ToString() + { + return _object.ToString() ?? "NULL"; + } } } diff --git a/src/Neo.VM/Types/Null.cs b/src/Neo.VM/Types/Null.cs index 9088a30b5d..238d8b2389 100644 --- a/src/Neo.VM/Types/Null.cs +++ b/src/Neo.VM/Types/Null.cs @@ -56,5 +56,10 @@ public override T GetInterface() { return null; } + + public override string ToString() + { + return "NULL"; + } } } diff --git a/src/Neo.VM/Types/Pointer.cs b/src/Neo.VM/Types/Pointer.cs index 633a8fbadf..1faa52ca74 100644 --- a/src/Neo.VM/Types/Pointer.cs +++ b/src/Neo.VM/Types/Pointer.cs @@ -59,5 +59,10 @@ public override int GetHashCode() { return HashCode.Combine(Script, Position); } + + public override string ToString() + { + return Position.ToString(); + } } } diff --git a/src/Neo.VM/Utility.cs b/src/Neo.VM/Utility.cs index edb1c01ebc..7c1852b7f9 100644 --- a/src/Neo.VM/Utility.cs +++ b/src/Neo.VM/Utility.cs @@ -27,6 +27,20 @@ static Utility() StrictUTF8.EncoderFallback = EncoderFallback.ExceptionFallback; } + public static bool TryGetString(this ReadOnlySpan bytes, out string? value) + { + try + { + value = StrictUTF8.GetString(bytes); + return true; + } + catch + { + value = default; + return false; + } + } + public static BigInteger ModInverse(this BigInteger value, BigInteger modulus) { if (value <= 0) throw new ArgumentOutOfRangeException(nameof(value)); diff --git a/tests/Neo.VM.Tests/UT_EvaluationStack.cs b/tests/Neo.VM.Tests/UT_EvaluationStack.cs index c4a5d65914..51df42ffc1 100644 --- a/tests/Neo.VM.Tests/UT_EvaluationStack.cs +++ b/tests/Neo.VM.Tests/UT_EvaluationStack.cs @@ -10,6 +10,8 @@ // modifications are permitted. using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Test.Extensions; +using Neo.Test.Helpers; using Neo.VM; using Neo.VM.Types; using System; @@ -200,7 +202,7 @@ public void TestReverse() } [TestMethod] - public void TestToString() + public void TestEvaluationStackPrint() { var stack = new EvaluationStack(new ReferenceCounter()); @@ -211,5 +213,13 @@ public void TestToString() Assert.AreEqual("[Boolean(True), ByteString(\"test\"), Integer(1), Integer(3)]", stack.ToString()); } + + [TestMethod] + public void TestPrintInvalidUTF8() + { + var stack = new EvaluationStack(new ReferenceCounter()); + stack.Insert(0, "4CC95219999D421243C8161E3FC0F4290C067845".FromHexString()); + Assert.AreEqual("[ByteString(\"Base64: TMlSGZmdQhJDyBYeP8D0KQwGeEU=\")]", stack.ToString()); + } } } From 95708b5c81661ecf7d78174d639d0f9971eed972 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Thu, 8 Feb 2024 19:11:10 +0800 Subject: [PATCH 074/168] [Neo Fix] fix the store crash issue (#3124) * fix the store crash issue * remove loadstore * Clean changes --------- Co-authored-by: Fernando Diaz Toledano --- src/Neo.CLI/CLI/MainService.cs | 3 +-- src/Neo/NeoSystem.cs | 20 ++++++++++---------- src/Neo/Persistence/StoreFactory.cs | 2 -- 3 files changed, 11 insertions(+), 14 deletions(-) diff --git a/src/Neo.CLI/CLI/MainService.cs b/src/Neo.CLI/CLI/MainService.cs index abd23121f7..4b0fccb343 100644 --- a/src/Neo.CLI/CLI/MainService.cs +++ b/src/Neo.CLI/CLI/MainService.cs @@ -377,8 +377,7 @@ public async void Start(CommandLineOptions options) ProtocolSettings protocol = ProtocolSettings.Load("config.json"); CustomProtocolSettings(options, protocol); CustomApplicationSettings(options, Settings.Default); - var store = StoreFactory.GetStore(Settings.Default.Storage.Engine, string.Format(Settings.Default.Storage.Path, protocol.Network.ToString("X8"))); - NeoSystem = new NeoSystem(protocol, store); + NeoSystem = new NeoSystem(protocol, Settings.Default.Storage.Engine, string.Format(Settings.Default.Storage.Path, protocol.Network.ToString("X8"))); NeoSystem.AddService(this); LocalNode = NeoSystem.LocalNode.Ask(new LocalNode.GetInstance()).Result; diff --git a/src/Neo/NeoSystem.cs b/src/Neo/NeoSystem.cs index 4713c284ff..77b982f0d4 100644 --- a/src/Neo/NeoSystem.cs +++ b/src/Neo/NeoSystem.cs @@ -109,6 +109,16 @@ static NeoSystem() Plugin.LoadPlugins(); } + /// + /// Initializes a new instance of the class. + /// + /// The protocol settings of the . + /// The storage engine used to create the objects. If this parameter is , a default in-memory storage engine will be used. + /// The path of the storage. If is the default in-memory storage engine, this parameter is ignored. + public NeoSystem(ProtocolSettings settings, string? storageEngine = null, string? storagePath = null) : this(settings, StoreFactory.GetStore(storageEngine ?? nameof(MemoryStore), storagePath)) + { + } + /// /// Initializes a new instance of the class. /// @@ -208,16 +218,6 @@ public void EnsureStopped(IActorRef actor) inbox.Receive(TimeSpan.FromMinutes(5)); } - /// - /// Loads an at the specified path. - /// - /// The path of the storage. - /// The loaded . - public IStore LoadStore(string path) - { - return StoreFactory.GetStore(store.GetType().Name, path); - } - /// /// Resumes the startup process of . /// diff --git a/src/Neo/Persistence/StoreFactory.cs b/src/Neo/Persistence/StoreFactory.cs index 622c152acf..d24e94960c 100644 --- a/src/Neo/Persistence/StoreFactory.cs +++ b/src/Neo/Persistence/StoreFactory.cs @@ -29,9 +29,7 @@ static StoreFactory() RegisterProvider(memProvider); // Default cases - providers.Add("", memProvider); - providers.Add(null, memProvider); } public static void RegisterProvider(IStoreProvider provider) From b4dadcb32e605df51d34dacaf8bbca34927d78e4 Mon Sep 17 00:00:00 2001 From: Shargon Date: Sat, 10 Feb 2024 14:35:31 +0100 Subject: [PATCH 075/168] Fix storage encoding (#3130) * Fix storage encoding * Remove unsafe methods * Revert BigEndian change * Fix ut * Revert change --- src/Neo/SmartContract/KeyBuilder.cs | 68 +++++++++++++++---- .../SmartContract/UT_KeyBuilder.cs | 11 +-- 2 files changed, 58 insertions(+), 21 deletions(-) diff --git a/src/Neo/SmartContract/KeyBuilder.cs b/src/Neo/SmartContract/KeyBuilder.cs index 4648b9baa9..cfd27cc6f8 100644 --- a/src/Neo/SmartContract/KeyBuilder.cs +++ b/src/Neo/SmartContract/KeyBuilder.cs @@ -11,6 +11,7 @@ using Neo.IO; using System; +using System.Buffers.Binary; using System.IO; namespace Neo.SmartContract @@ -29,8 +30,22 @@ public class KeyBuilder /// The prefix of the key. public KeyBuilder(int id, byte prefix) { - Add(id); - this.stream.WriteByte(prefix); + var data = new byte[sizeof(int)]; + BinaryPrimitives.WriteInt32LittleEndian(data, id); + + stream.Write(data); + stream.WriteByte(prefix); + } + + /// + /// Adds part of the key to the builder. + /// + /// Part of the key. + /// A reference to this instance after the add operation has completed. + public KeyBuilder Add(byte key) + { + stream.WriteByte(key); + return this; } /// @@ -60,28 +75,55 @@ public KeyBuilder Add(ISerializable key) } /// - /// Adds part of the key to the builder. + /// Adds part of the key to the builder in BigEndian. /// - /// The type of the parameter. /// Part of the key. /// A reference to this instance after the add operation has completed. - unsafe public KeyBuilder Add(T key) where T : unmanaged + public KeyBuilder AddBigEndian(int key) { - return Add(new ReadOnlySpan(&key, sizeof(T))); + var data = new byte[sizeof(int)]; + BinaryPrimitives.WriteInt32BigEndian(data, key); + + return Add(data); } /// - /// Adds part of the key to the builder with big-endian. + /// Adds part of the key to the builder in BigEndian. /// - /// The type of the parameter. /// Part of the key. /// A reference to this instance after the add operation has completed. - unsafe public KeyBuilder AddBigEndian(T key) where T : unmanaged + public KeyBuilder AddBigEndian(uint key) { - ReadOnlySpan buffer = new(&key, sizeof(T)); - for (int i = buffer.Length - 1; i >= 0; i--) - stream.WriteByte(buffer[i]); - return this; + var data = new byte[sizeof(uint)]; + BinaryPrimitives.WriteUInt32BigEndian(data, key); + + return Add(data); + } + + /// + /// Adds part of the key to the builder in BigEndian. + /// + /// Part of the key. + /// A reference to this instance after the add operation has completed. + public KeyBuilder AddBigEndian(long key) + { + var data = new byte[sizeof(long)]; + BinaryPrimitives.WriteInt64BigEndian(data, key); + + return Add(data); + } + + /// + /// Adds part of the key to the builder in BigEndian. + /// + /// Part of the key. + /// A reference to this instance after the add operation has completed. + public KeyBuilder AddBigEndian(ulong key) + { + var data = new byte[sizeof(ulong)]; + BinaryPrimitives.WriteUInt64BigEndian(data, key); + + return Add(data); } /// diff --git a/tests/Neo.UnitTests/SmartContract/UT_KeyBuilder.cs b/tests/Neo.UnitTests/SmartContract/UT_KeyBuilder.cs index b16c061494..3ff52c1324 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_KeyBuilder.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_KeyBuilder.cs @@ -17,11 +17,6 @@ namespace Neo.UnitTests.SmartContract [TestClass] public class UT_KeyBuilder { - private struct TestKey - { - public int Value; - } - [TestMethod] public void Test() { @@ -39,11 +34,11 @@ public void Test() Assert.AreEqual("010000000203040000000000000000000000000000000000000000", key.ToArray().ToHexString()); key = new KeyBuilder(1, 2); - key = key.Add(new TestKey { Value = 123 }); - Assert.AreEqual("01000000027b000000", key.ToArray().ToHexString()); + key = key.AddBigEndian(123); + Assert.AreEqual("01000000020000007b", key.ToArray().ToHexString()); key = new KeyBuilder(1, 0); - key = key.AddBigEndian(new TestKey { Value = 1 }); + key = key.AddBigEndian(1); Assert.AreEqual("010000000000000001", key.ToArray().ToHexString()); } } From 4a5a7f58567c1bf270d1c5515d90486c803b4e11 Mon Sep 17 00:00:00 2001 From: Shargon Date: Sun, 11 Feb 2024 12:51:05 +0100 Subject: [PATCH 076/168] Allow access TestingEngine to internal (#3134) * Change to public StorageKey constructor * cschuchardt88's feedback --- src/Neo/Neo.csproj | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Neo/Neo.csproj b/src/Neo/Neo.csproj index 234fbc62c6..130ff2a570 100644 --- a/src/Neo/Neo.csproj +++ b/src/Neo/Neo.csproj @@ -22,4 +22,8 @@ + + + + From 25ed6d6e98eee247aa73704a7980245c5fe147f0 Mon Sep 17 00:00:00 2001 From: Christopher Schuchardt Date: Wed, 14 Feb 2024 04:22:49 -0500 Subject: [PATCH 077/168] Added `publish` to `github packages` (#3072) * Added nuget packages source * test * Changed to windows * fixed version * fix * fix nuget * fixed nuget.config * Fixed test * Nuget fixes * git * working release * Added cron job * switch to keep 3 packages versions * Update .github/workflows/main.yml * Update .github/workflows/main.yml Co-authored-by: Shargon * change secret * change delete also --------- Co-authored-by: Jimmy Co-authored-by: Shargon --- .github/workflows/main.yml | 38 +++++++++++++++++++++++ .github/workflows/pkgs-delete.yml | 51 +++++++++++++++++++++++++++++++ NuGet.Config | 1 + 3 files changed, 90 insertions(+) create mode 100644 .github/workflows/pkgs-delete.yml diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index bce1dc7c79..4f7696cf6e 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -38,6 +38,44 @@ jobs: github-token: ${{ secrets.GITHUB_TOKEN }} path-to-lcov: ./coverage/lcov.net7.0.info + PublishGithub: + 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: Setup .NET Core + uses: actions/setup-dotnet@v4 + with: + dotnet-version: ${{ env.DOTNET_VERSION }} + + - name: Set Version + run: git rev-list --count HEAD | xargs printf 'CI%05d' | xargs -I{} echo 'VERSION_SUFFIX={}' >> $GITHUB_ENV + + - name : Pack (Neo) + 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: | + dotnet nuget push * \ + --source https://nuget.pkg.github.com/neo-project/index.json \ + --api-key "${{ secrets.GITHUB_TOKEN }}" \ + --disable-buffering \ + --no-service-endpoint; + # MyGet isn't working # PublishMyGet: # if: github.ref == 'refs/heads/master' && startsWith(github.repository, 'neo-project/') diff --git a/.github/workflows/pkgs-delete.yml b/.github/workflows/pkgs-delete.yml new file mode 100644 index 0000000000..16855f1070 --- /dev/null +++ b/.github/workflows/pkgs-delete.yml @@ -0,0 +1,51 @@ +name: Nuget Package Cleanup (github) + +on: + schedule: + - cron: '0 0 * * *' # Run every day at 24:00 + +jobs: + delete-pkgs: + name: Delete Old Nuget Packages + runs-on: ubuntu-latest + + steps: + - name: Delete Neo Package + uses: actions/delete-package-versions@v4 + with: + package-name: Neo + package-type: nuget + min-versions-to-keep: 3 + token: "${{ secrets.GITHUB_TOKEN }}" + + - name: Delete Neo.ConsoleService Package + uses: actions/delete-package-versions@v4 + with: + package-name: Neo.ConsoleService + package-type: nuget + min-versions-to-keep: 3 + token: "${{ secrets.GITHUB_TOKEN }}" + + - name: Delete Neo.ConsoleService Package + uses: actions/delete-package-versions@v4 + with: + package-name: Neo.ConsoleService + package-type: nuget + min-versions-to-keep: 3 + token: "${{ secrets.GITHUB_TOKEN }}" + + - name: Delete Neo.Json Package + uses: actions/delete-package-versions@v4 + with: + package-name: Neo.Json + package-type: nuget + min-versions-to-keep: 3 + token: "${{ secrets.GITHUB_TOKEN }}" + + - name: Delete Neo.VM Package + uses: actions/delete-package-versions@v4 + with: + package-name: Neo.VM + package-type: nuget + min-versions-to-keep: 3 + token: "${{ secrets.GITHUB_TOKEN }}" diff --git a/NuGet.Config b/NuGet.Config index 5922e754af..f7ce69db29 100644 --- a/NuGet.Config +++ b/NuGet.Config @@ -2,6 +2,7 @@ + From 4940501b28eac2a08fd5306a5371883ea5403f82 Mon Sep 17 00:00:00 2001 From: Shargon Date: Wed, 14 Feb 2024 14:23:40 +0100 Subject: [PATCH 078/168] Optimize opcode price charging (#3131) * Optimize price * Jimmy's review * CS0618 * Update tests/Neo.UnitTests/SmartContract/UT_OpCodePrices.cs * Avoid Obsolete --------- Co-authored-by: Jimmy --- .../ApplicationEngine.OpCodePrices.cs | 17 +++++++++++++++++ src/Neo/SmartContract/ApplicationEngine.cs | 2 +- src/Neo/SmartContract/Helper.cs | 12 ++++++------ .../Neo.UnitTests/SmartContract/UT_Contract.cs | 4 ++-- .../SmartContract/UT_OpCodePrices.cs | 15 ++++++++++++++- 5 files changed, 40 insertions(+), 10 deletions(-) diff --git a/src/Neo/SmartContract/ApplicationEngine.OpCodePrices.cs b/src/Neo/SmartContract/ApplicationEngine.OpCodePrices.cs index fb3835e14d..16a0a95944 100644 --- a/src/Neo/SmartContract/ApplicationEngine.OpCodePrices.cs +++ b/src/Neo/SmartContract/ApplicationEngine.OpCodePrices.cs @@ -10,6 +10,7 @@ // modifications are permitted. using Neo.VM; +using System; using System.Collections.Generic; namespace Neo.SmartContract @@ -19,6 +20,7 @@ partial class ApplicationEngine /// /// The prices of all the opcodes. /// + [Obsolete("You should use OpCodePriceTable")] public static readonly IReadOnlyDictionary OpCodePrices = new Dictionary { [OpCode.PUSHINT8] = 1 << 0, @@ -218,5 +220,20 @@ partial class ApplicationEngine [OpCode.ISTYPE] = 1 << 1, [OpCode.CONVERT] = 1 << 13, }; + + public static readonly long[] OpCodePriceTable = new long[byte.MaxValue]; + + /// + /// Init OpCodePrices + /// + static ApplicationEngine() + { +#pragma warning disable CS0618 // Type or member is obsolete + foreach (var entry in OpCodePrices) +#pragma warning restore CS0618 // Type or member is obsolete + { + OpCodePriceTable[(byte)entry.Key] = entry.Value; + } + } } } diff --git a/src/Neo/SmartContract/ApplicationEngine.cs b/src/Neo/SmartContract/ApplicationEngine.cs index ba161e6951..341e077ec3 100644 --- a/src/Neo/SmartContract/ApplicationEngine.cs +++ b/src/Neo/SmartContract/ApplicationEngine.cs @@ -529,7 +529,7 @@ protected virtual void OnSysCall(InteropDescriptor descriptor) protected override void PreExecuteInstruction(Instruction instruction) { Diagnostic?.PreExecuteInstruction(instruction); - AddGas(ExecFeeFactor * OpCodePrices[instruction.OpCode]); + AddGas(ExecFeeFactor * OpCodePriceTable[(byte)instruction.OpCode]); } protected override void PostExecuteInstruction(Instruction instruction) diff --git a/src/Neo/SmartContract/Helper.cs b/src/Neo/SmartContract/Helper.cs index 5045c74717..333ef77d7b 100644 --- a/src/Neo/SmartContract/Helper.cs +++ b/src/Neo/SmartContract/Helper.cs @@ -39,8 +39,8 @@ public static class Helper /// /// The calculated cost. public static long SignatureContractCost() => - ApplicationEngine.OpCodePrices[OpCode.PUSHDATA1] * 2 + - ApplicationEngine.OpCodePrices[OpCode.SYSCALL] + + ApplicationEngine.OpCodePriceTable[(byte)OpCode.PUSHDATA1] * 2 + + ApplicationEngine.OpCodePriceTable[(byte)OpCode.SYSCALL] + ApplicationEngine.CheckSigPrice; /// @@ -51,12 +51,12 @@ public static long SignatureContractCost() => /// The calculated cost. public static long MultiSignatureContractCost(int m, int n) { - long fee = ApplicationEngine.OpCodePrices[OpCode.PUSHDATA1] * (m + n); + long fee = ApplicationEngine.OpCodePriceTable[(byte)OpCode.PUSHDATA1] * (m + n); using (ScriptBuilder sb = new()) - fee += ApplicationEngine.OpCodePrices[(OpCode)sb.EmitPush(m).ToArray()[0]]; + fee += ApplicationEngine.OpCodePriceTable[(byte)(OpCode)sb.EmitPush(m).ToArray()[0]]; using (ScriptBuilder sb = new()) - fee += ApplicationEngine.OpCodePrices[(OpCode)sb.EmitPush(n).ToArray()[0]]; - fee += ApplicationEngine.OpCodePrices[OpCode.SYSCALL]; + fee += ApplicationEngine.OpCodePriceTable[(byte)(OpCode)sb.EmitPush(n).ToArray()[0]]; + fee += ApplicationEngine.OpCodePriceTable[(byte)OpCode.SYSCALL]; fee += ApplicationEngine.CheckSigPrice * n; return fee; } diff --git a/tests/Neo.UnitTests/SmartContract/UT_Contract.cs b/tests/Neo.UnitTests/SmartContract/UT_Contract.cs index faf3c1fde4..a263779282 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_Contract.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_Contract.cs @@ -164,7 +164,7 @@ public void TestSignatureRedeemScriptFee() byte[] verification = Contract.CreateSignatureRedeemScript(key.PublicKey); byte[] invocation = new ScriptBuilder().EmitPush(UInt160.Zero).ToArray(); - var fee = PolicyContract.DefaultExecFeeFactor * (ApplicationEngine.OpCodePrices[OpCode.PUSHDATA1] * 2 + ApplicationEngine.OpCodePrices[OpCode.SYSCALL] + ApplicationEngine.CheckSigPrice); + var fee = PolicyContract.DefaultExecFeeFactor * (ApplicationEngine.OpCodePriceTable[(byte)OpCode.PUSHDATA1] * 2 + ApplicationEngine.OpCodePriceTable[(byte)OpCode.SYSCALL] + ApplicationEngine.CheckSigPrice); using (ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Verification, new Transaction { Signers = Array.Empty(), Attributes = Array.Empty() }, null, settings: TestBlockchain.TheNeoSystem.Settings)) { @@ -192,7 +192,7 @@ public void TestCreateMultiSigRedeemScriptFee() byte[] verification = Contract.CreateMultiSigRedeemScript(2, publicKeys); byte[] invocation = new ScriptBuilder().EmitPush(UInt160.Zero).EmitPush(UInt160.Zero).ToArray(); - long fee = PolicyContract.DefaultExecFeeFactor * (ApplicationEngine.OpCodePrices[OpCode.PUSHDATA1] * (2 + 2) + ApplicationEngine.OpCodePrices[OpCode.PUSHINT8] * 2 + ApplicationEngine.OpCodePrices[OpCode.SYSCALL] + ApplicationEngine.CheckSigPrice * 2); + long fee = PolicyContract.DefaultExecFeeFactor * (ApplicationEngine.OpCodePriceTable[(byte)OpCode.PUSHDATA1] * (2 + 2) + ApplicationEngine.OpCodePriceTable[(byte)OpCode.PUSHINT8] * 2 + ApplicationEngine.OpCodePriceTable[(byte)OpCode.SYSCALL] + ApplicationEngine.CheckSigPrice * 2); using (ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Verification, new Transaction { Signers = Array.Empty(), Attributes = Array.Empty() }, null, settings: TestBlockchain.TheNeoSystem.Settings)) { diff --git a/tests/Neo.UnitTests/SmartContract/UT_OpCodePrices.cs b/tests/Neo.UnitTests/SmartContract/UT_OpCodePrices.cs index 13209618e3..c373930c6e 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_OpCodePrices.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_OpCodePrices.cs @@ -23,7 +23,20 @@ public class UT_OpCodePrices public void AllOpcodePriceAreSet() { foreach (OpCode opcode in Enum.GetValues(typeof(OpCode))) - Assert.IsTrue(ApplicationEngine.OpCodePrices.ContainsKey(opcode), opcode.ToString()); + { +#pragma warning disable CS0618 // Type or member is obsolete + Assert.IsTrue(ApplicationEngine.OpCodePrices.ContainsKey(opcode), opcode.ToString(), $"{opcode} without price"); + Assert.AreEqual(ApplicationEngine.OpCodePrices[opcode], ApplicationEngine.OpCodePriceTable[(byte)opcode], $"{opcode} price mismatch"); +#pragma warning restore CS0618 // Type or member is obsolete + + if (opcode == OpCode.RET || + opcode == OpCode.SYSCALL || + opcode == OpCode.ABORT || + opcode == OpCode.ABORTMSG) + continue; + + Assert.AreNotEqual(0, ApplicationEngine.OpCodePriceTable[(byte)opcode], $"{opcode} without price"); + } } } } From 6746665e07889c8575dfbf76b5060ff933647163 Mon Sep 17 00:00:00 2001 From: Christopher Schuchardt Date: Thu, 15 Feb 2024 02:48:23 -0500 Subject: [PATCH 079/168] Split `namespaces` into Different Libraries. (#3136) * INit * Update * Allow access internals * Update `github` actions workflow. * Add assmebly internals to test assemblies * Added `null` checking in `ByteArrayComparer.cs` * Updated unit test for ByteArrayComparer * Fixed `ByteArrayComparer.Compare` double checking. * Fixed iterate same `x`, `y` in `ByteArrayComparer.Compare` * Fixed test error in `ByteArrayComparer.Compare` * Fix redundant condition --------- Co-authored-by: Fernando Diaz Toledano --- .github/workflows/main.yml | 12 ++ neo.sln | 22 +++- src/{Neo => Neo.Extensions}/LogLevel.cs | 0 src/Neo.Extensions/Neo.Extensions.csproj | 19 ++++ src/{Neo => Neo.Extensions}/Utility.cs | 2 +- src/{Neo/IO => Neo.IO}/ByteArrayComparer.cs | 23 ++-- .../ByteArrayEqualityComparer.cs | 8 +- src/{Neo/IO => Neo.IO}/ISerializable.cs | 0 src/{Neo/IO => Neo.IO}/MemoryReader.cs | 104 +++++++++--------- src/Neo.IO/Neo.IO.csproj | 20 ++++ src/Neo/Neo.csproj | 2 + .../Neo.UnitTests/IO/UT_ByteArrayComparer.cs | 16 ++- 12 files changed, 156 insertions(+), 72 deletions(-) rename src/{Neo => Neo.Extensions}/LogLevel.cs (100%) create mode 100644 src/Neo.Extensions/Neo.Extensions.csproj rename src/{Neo => Neo.Extensions}/Utility.cs (97%) rename src/{Neo/IO => Neo.IO}/ByteArrayComparer.cs (62%) rename src/{Neo/IO => Neo.IO}/ByteArrayEqualityComparer.cs (90%) rename src/{Neo/IO => Neo.IO}/ISerializable.cs (100%) rename src/{Neo/IO => Neo.IO}/MemoryReader.cs (73%) create mode 100644 src/Neo.IO/Neo.IO.csproj diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 4f7696cf6e..aa935fd2d3 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -151,6 +151,18 @@ jobs: 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: | diff --git a/neo.sln b/neo.sln index dc50d0f4d7..b62de06a6e 100644 --- a/neo.sln +++ b/neo.sln @@ -24,18 +24,22 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.VM", "src\Neo.VM\Neo.VM EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.VM.Tests", "tests\Neo.VM.Tests\Neo.VM.Tests.csproj", "{005F84EB-EA2E-449F-930A-7B4173DDC7EC}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Neo.ConsoleService", "src\Neo.ConsoleService\Neo.ConsoleService.csproj", "{9E886812-7243-48D8-BEAF-47AADC11C054}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.ConsoleService", "src\Neo.ConsoleService\Neo.ConsoleService.csproj", "{9E886812-7243-48D8-BEAF-47AADC11C054}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Neo.GUI", "src\Neo.GUI\Neo.GUI.csproj", "{02ABDE42-9880-43B4-B6F7-8D618602A277}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.GUI", "src\Neo.GUI\Neo.GUI.csproj", "{02ABDE42-9880-43B4-B6F7-8D618602A277}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Neo.CLI", "src\Neo.CLI\Neo.CLI.csproj", "{BDFBE455-4C1F-4FC4-B5FC-1387B93A8687}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.CLI", "src\Neo.CLI\Neo.CLI.csproj", "{BDFBE455-4C1F-4FC4-B5FC-1387B93A8687}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Neo.ConsoleService.Tests", "tests\Neo.ConsoleService.Tests\Neo.ConsoleService.Tests.csproj", "{B40F8584-5AFB-452C-AEFA-009C80CC23A9}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.ConsoleService.Tests", "tests\Neo.ConsoleService.Tests\Neo.ConsoleService.Tests.csproj", "{B40F8584-5AFB-452C-AEFA-009C80CC23A9}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.Cryptography.BLS12_381", "src\Neo.Cryptography.BLS12_381\Neo.Cryptography.BLS12_381.csproj", "{D48C1FAB-3471-4CA0-8688-25E6F43F2C25}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.Cryptography.BLS12_381.Tests", "tests\Neo.Cryptography.BLS12_381.Tests\Neo.Cryptography.BLS12_381.Tests.csproj", "{387CCF6C-9A26-43F6-A639-0A82E91E10D8}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Neo.IO", "src\Neo.IO\Neo.IO.csproj", "{4CDAC1AA-45C6-4157-8D8E-199050433048}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Neo.Extensions", "src\Neo.Extensions\Neo.Extensions.csproj", "{9C5213D6-3833-4570-8AE2-47E9F9017A8F}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -98,6 +102,14 @@ Global {387CCF6C-9A26-43F6-A639-0A82E91E10D8}.Debug|Any CPU.Build.0 = Debug|Any CPU {387CCF6C-9A26-43F6-A639-0A82E91E10D8}.Release|Any CPU.ActiveCfg = Release|Any CPU {387CCF6C-9A26-43F6-A639-0A82E91E10D8}.Release|Any CPU.Build.0 = Release|Any CPU + {4CDAC1AA-45C6-4157-8D8E-199050433048}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4CDAC1AA-45C6-4157-8D8E-199050433048}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4CDAC1AA-45C6-4157-8D8E-199050433048}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4CDAC1AA-45C6-4157-8D8E-199050433048}.Release|Any CPU.Build.0 = Release|Any CPU + {9C5213D6-3833-4570-8AE2-47E9F9017A8F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9C5213D6-3833-4570-8AE2-47E9F9017A8F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9C5213D6-3833-4570-8AE2-47E9F9017A8F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9C5213D6-3833-4570-8AE2-47E9F9017A8F}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -117,6 +129,8 @@ Global {B40F8584-5AFB-452C-AEFA-009C80CC23A9} = {EDE05FA8-8E73-4924-BC63-DD117127EEE1} {D48C1FAB-3471-4CA0-8688-25E6F43F2C25} = {B5339DF7-5D1D-43BA-B332-74B825E1770E} {387CCF6C-9A26-43F6-A639-0A82E91E10D8} = {EDE05FA8-8E73-4924-BC63-DD117127EEE1} + {4CDAC1AA-45C6-4157-8D8E-199050433048} = {B5339DF7-5D1D-43BA-B332-74B825E1770E} + {9C5213D6-3833-4570-8AE2-47E9F9017A8F} = {B5339DF7-5D1D-43BA-B332-74B825E1770E} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {BCBA19D9-F868-4C6D-8061-A2B91E06E3EC} diff --git a/src/Neo/LogLevel.cs b/src/Neo.Extensions/LogLevel.cs similarity index 100% rename from src/Neo/LogLevel.cs rename to src/Neo.Extensions/LogLevel.cs diff --git a/src/Neo.Extensions/Neo.Extensions.csproj b/src/Neo.Extensions/Neo.Extensions.csproj new file mode 100644 index 0000000000..7552a56311 --- /dev/null +++ b/src/Neo.Extensions/Neo.Extensions.csproj @@ -0,0 +1,19 @@ + + + + netstandard2.1;net7.0 + enable + NEO;Blockchain;Extensions + + + + + + + + + + + + + diff --git a/src/Neo/Utility.cs b/src/Neo.Extensions/Utility.cs similarity index 97% rename from src/Neo/Utility.cs rename to src/Neo.Extensions/Utility.cs index 6883c69a26..fca164a4f2 100644 --- a/src/Neo/Utility.cs +++ b/src/Neo.Extensions/Utility.cs @@ -31,7 +31,7 @@ public Logger() } } - public static event LogEventHandler Logging; + public static event LogEventHandler? Logging; /// /// A strict UTF8 encoding used in NEO system. diff --git a/src/Neo/IO/ByteArrayComparer.cs b/src/Neo.IO/ByteArrayComparer.cs similarity index 62% rename from src/Neo/IO/ByteArrayComparer.cs rename to src/Neo.IO/ByteArrayComparer.cs index 872052095c..f9d44e24d6 100644 --- a/src/Neo/IO/ByteArrayComparer.cs +++ b/src/Neo.IO/ByteArrayComparer.cs @@ -20,27 +20,32 @@ internal class ByteArrayComparer : IComparer public static readonly ByteArrayComparer Default = new(1); public static readonly ByteArrayComparer Reverse = new(-1); - private readonly int direction; + private readonly int _direction; private ByteArrayComparer(int direction) { - this.direction = direction; + _direction = direction; } - public int Compare(byte[] x, byte[] y) + public int Compare(byte[]? x, byte[]? y) { - return direction > 0 - ? CompareInternal(x, y) - : -CompareInternal(x, y); + if (x == y) return 0; + if (x is null && y is not null) + return _direction > 0 ? -y.Length : y.Length; + if (y is null && x is not null) + return _direction > 0 ? x.Length : -x.Length; + return _direction > 0 ? + CompareInternal(x!, y!) : + -CompareInternal(x!, y!); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static int CompareInternal(byte[] x, byte[] y) { - int length = Math.Min(x.Length, y.Length); - for (int i = 0; i < length; i++) + var length = Math.Min(x.Length, y.Length); + for (var i = 0; i < length; i++) { - int r = x[i].CompareTo(y[i]); + var r = x[i].CompareTo(y[i]); if (r != 0) return r; } return x.Length.CompareTo(y.Length); diff --git a/src/Neo/IO/ByteArrayEqualityComparer.cs b/src/Neo.IO/ByteArrayEqualityComparer.cs similarity index 90% rename from src/Neo/IO/ByteArrayEqualityComparer.cs rename to src/Neo.IO/ByteArrayEqualityComparer.cs index ffb5ad0e63..2b6f01491c 100644 --- a/src/Neo/IO/ByteArrayEqualityComparer.cs +++ b/src/Neo.IO/ByteArrayEqualityComparer.cs @@ -17,11 +17,11 @@ internal class ByteArrayEqualityComparer : IEqualityComparer { public static readonly ByteArrayEqualityComparer Default = new(); - public unsafe bool Equals(byte[] x, byte[] y) + public unsafe bool Equals(byte[]? x, byte[]? y) { if (ReferenceEquals(x, y)) return true; if (x is null || y is null) return false; - int len = x.Length; + var len = x.Length; if (len != y.Length) return false; if (len == 0) return true; fixed (byte* xp = x, yp = y) @@ -48,8 +48,8 @@ public int GetHashCode(byte[] obj) { unchecked { - int hash = 17; - foreach (byte element in obj) + var hash = 17; + foreach (var element in obj) hash = hash * 31 + element; return hash; } diff --git a/src/Neo/IO/ISerializable.cs b/src/Neo.IO/ISerializable.cs similarity index 100% rename from src/Neo/IO/ISerializable.cs rename to src/Neo.IO/ISerializable.cs diff --git a/src/Neo/IO/MemoryReader.cs b/src/Neo.IO/MemoryReader.cs similarity index 73% rename from src/Neo/IO/MemoryReader.cs rename to src/Neo.IO/MemoryReader.cs index ece7cb56be..df8afbb3d3 100644 --- a/src/Neo/IO/MemoryReader.cs +++ b/src/Neo.IO/MemoryReader.cs @@ -17,29 +17,29 @@ namespace Neo.IO { public ref struct MemoryReader { - private readonly ReadOnlyMemory memory; - private readonly ReadOnlySpan span; - private int pos = 0; + private readonly ReadOnlyMemory _memory; + private readonly ReadOnlySpan _span; + private int _pos = 0; - public readonly int Position => pos; + public readonly int Position => _pos; public MemoryReader(ReadOnlyMemory memory) { - this.memory = memory; - this.span = memory.Span; + _memory = memory; + _span = memory.Span; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private readonly void EnsurePosition(int move) { - if (pos + move > span.Length) throw new FormatException(); + if (_pos + move > _span.Length) throw new FormatException(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly byte Peek() { EnsurePosition(1); - return span[pos]; + return _span[_pos]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -57,7 +57,7 @@ public bool ReadBoolean() public sbyte ReadSByte() { EnsurePosition(1); - byte b = span[pos++]; + var b = _span[_pos++]; return unchecked((sbyte)b); } @@ -65,15 +65,15 @@ public sbyte ReadSByte() public byte ReadByte() { EnsurePosition(1); - return span[pos++]; + return _span[_pos++]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public short ReadInt16() { EnsurePosition(sizeof(short)); - var result = BinaryPrimitives.ReadInt16LittleEndian(span[pos..]); - pos += sizeof(short); + var result = BinaryPrimitives.ReadInt16LittleEndian(_span[_pos..]); + _pos += sizeof(short); return result; } @@ -81,8 +81,8 @@ public short ReadInt16() public short ReadInt16BigEndian() { EnsurePosition(sizeof(short)); - var result = BinaryPrimitives.ReadInt16BigEndian(span[pos..]); - pos += sizeof(short); + var result = BinaryPrimitives.ReadInt16BigEndian(_span[_pos..]); + _pos += sizeof(short); return result; } @@ -90,8 +90,8 @@ public short ReadInt16BigEndian() public ushort ReadUInt16() { EnsurePosition(sizeof(ushort)); - var result = BinaryPrimitives.ReadUInt16LittleEndian(span[pos..]); - pos += sizeof(ushort); + var result = BinaryPrimitives.ReadUInt16LittleEndian(_span[_pos..]); + _pos += sizeof(ushort); return result; } @@ -99,8 +99,8 @@ public ushort ReadUInt16() public ushort ReadUInt16BigEndian() { EnsurePosition(sizeof(ushort)); - var result = BinaryPrimitives.ReadUInt16BigEndian(span[pos..]); - pos += sizeof(ushort); + var result = BinaryPrimitives.ReadUInt16BigEndian(_span[_pos..]); + _pos += sizeof(ushort); return result; } @@ -108,8 +108,8 @@ public ushort ReadUInt16BigEndian() public int ReadInt32() { EnsurePosition(sizeof(int)); - var result = BinaryPrimitives.ReadInt32LittleEndian(span[pos..]); - pos += sizeof(int); + var result = BinaryPrimitives.ReadInt32LittleEndian(_span[_pos..]); + _pos += sizeof(int); return result; } @@ -117,8 +117,8 @@ public int ReadInt32() public int ReadInt32BigEndian() { EnsurePosition(sizeof(int)); - var result = BinaryPrimitives.ReadInt32BigEndian(span[pos..]); - pos += sizeof(int); + var result = BinaryPrimitives.ReadInt32BigEndian(_span[_pos..]); + _pos += sizeof(int); return result; } @@ -126,8 +126,8 @@ public int ReadInt32BigEndian() public uint ReadUInt32() { EnsurePosition(sizeof(uint)); - var result = BinaryPrimitives.ReadUInt32LittleEndian(span[pos..]); - pos += sizeof(uint); + var result = BinaryPrimitives.ReadUInt32LittleEndian(_span[_pos..]); + _pos += sizeof(uint); return result; } @@ -135,8 +135,8 @@ public uint ReadUInt32() public uint ReadUInt32BigEndian() { EnsurePosition(sizeof(uint)); - var result = BinaryPrimitives.ReadUInt32BigEndian(span[pos..]); - pos += sizeof(uint); + var result = BinaryPrimitives.ReadUInt32BigEndian(_span[_pos..]); + _pos += sizeof(uint); return result; } @@ -144,8 +144,8 @@ public uint ReadUInt32BigEndian() public long ReadInt64() { EnsurePosition(sizeof(long)); - var result = BinaryPrimitives.ReadInt64LittleEndian(span[pos..]); - pos += sizeof(long); + var result = BinaryPrimitives.ReadInt64LittleEndian(_span[_pos..]); + _pos += sizeof(long); return result; } @@ -153,8 +153,8 @@ public long ReadInt64() public long ReadInt64BigEndian() { EnsurePosition(sizeof(long)); - var result = BinaryPrimitives.ReadInt64BigEndian(span[pos..]); - pos += sizeof(long); + var result = BinaryPrimitives.ReadInt64BigEndian(_span[_pos..]); + _pos += sizeof(long); return result; } @@ -162,8 +162,8 @@ public long ReadInt64BigEndian() public ulong ReadUInt64() { EnsurePosition(sizeof(ulong)); - var result = BinaryPrimitives.ReadUInt64LittleEndian(span[pos..]); - pos += sizeof(ulong); + var result = BinaryPrimitives.ReadUInt64LittleEndian(_span[_pos..]); + _pos += sizeof(ulong); return result; } @@ -171,16 +171,16 @@ public ulong ReadUInt64() public ulong ReadUInt64BigEndian() { EnsurePosition(sizeof(ulong)); - var result = BinaryPrimitives.ReadUInt64BigEndian(span[pos..]); - pos += sizeof(ulong); + var result = BinaryPrimitives.ReadUInt64BigEndian(_span[_pos..]); + _pos += sizeof(ulong); return result; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public ulong ReadVarInt(ulong max = ulong.MaxValue) { - byte b = ReadByte(); - ulong value = b switch + var b = ReadByte(); + var value = b switch { 0xfd => ReadUInt16(), 0xfe => ReadUInt32(), @@ -195,24 +195,24 @@ public ulong ReadVarInt(ulong max = ulong.MaxValue) public string ReadFixedString(int length) { EnsurePosition(length); - int end = pos + length; - int i = pos; - while (i < end && span[i] != 0) i++; - ReadOnlySpan data = span[pos..i]; + var end = _pos + length; + var i = _pos; + while (i < end && _span[i] != 0) i++; + var data = _span[_pos..i]; for (; i < end; i++) - if (span[i] != 0) + if (_span[i] != 0) throw new FormatException(); - pos = end; + _pos = end; return Utility.StrictUTF8.GetString(data); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public string ReadVarString(int max = 0x1000000) { - int length = (int)ReadVarInt((ulong)max); + var length = (int)ReadVarInt((ulong)max); EnsurePosition(length); - ReadOnlySpan data = span.Slice(pos, length); - pos += length; + var data = _span.Slice(_pos, length); + _pos += length; return Utility.StrictUTF8.GetString(data); } @@ -220,22 +220,20 @@ public string ReadVarString(int max = 0x1000000) public ReadOnlyMemory ReadMemory(int count) { EnsurePosition(count); - ReadOnlyMemory result = memory.Slice(pos, count); - pos += count; + var result = _memory.Slice(_pos, count); + _pos += count; return result; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ReadOnlyMemory ReadVarMemory(int max = 0x1000000) - { - return ReadMemory((int)ReadVarInt((ulong)max)); - } + public ReadOnlyMemory ReadVarMemory(int max = 0x1000000) => + ReadMemory((int)ReadVarInt((ulong)max)); [MethodImpl(MethodImplOptions.AggressiveInlining)] public ReadOnlyMemory ReadToEnd() { - ReadOnlyMemory result = memory[pos..]; - pos = memory.Length; + var result = _memory[_pos..]; + _pos = _memory.Length; return result; } } diff --git a/src/Neo.IO/Neo.IO.csproj b/src/Neo.IO/Neo.IO.csproj new file mode 100644 index 0000000000..05bc305a67 --- /dev/null +++ b/src/Neo.IO/Neo.IO.csproj @@ -0,0 +1,20 @@ + + + + netstandard2.1;net7.0 + true + enable + NEO;Blockchain;IO + + + + + + + + + + + + + diff --git a/src/Neo/Neo.csproj b/src/Neo/Neo.csproj index 130ff2a570..75541f9091 100644 --- a/src/Neo/Neo.csproj +++ b/src/Neo/Neo.csproj @@ -18,6 +18,8 @@ + + diff --git a/tests/Neo.UnitTests/IO/UT_ByteArrayComparer.cs b/tests/Neo.UnitTests/IO/UT_ByteArrayComparer.cs index 5efba80cb3..19c3fafcd6 100644 --- a/tests/Neo.UnitTests/IO/UT_ByteArrayComparer.cs +++ b/tests/Neo.UnitTests/IO/UT_ByteArrayComparer.cs @@ -12,6 +12,7 @@ using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.IO; +using System; namespace Neo.UnitTests.IO { @@ -22,10 +23,23 @@ public class UT_ByteArrayComparer public void TestCompare() { ByteArrayComparer comparer = ByteArrayComparer.Default; - byte[] x = new byte[0], y = new byte[0]; + byte[] x = null, y = null; comparer.Compare(x, y).Should().Be(0); + x = new byte[] { 1, 2, 3, 4, 5 }; + y = x; + comparer.Compare(x, y).Should().Be(0); + comparer.Compare(x, x).Should().Be(0); + + y = null; + comparer.Compare(x, y).Should().Be(5); + + y = x; + x = null; + comparer.Compare(x, y).Should().Be(-5); + x = new byte[] { 1 }; + y = Array.Empty(); comparer.Compare(x, y).Should().Be(1); y = x; comparer.Compare(x, y).Should().Be(0); From fd3d68d527322d150cd9d850440418ac7644c8b3 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Thu, 15 Feb 2024 19:04:06 +0800 Subject: [PATCH 080/168] add loadstore back (#3141) --- src/Neo/NeoSystem.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/Neo/NeoSystem.cs b/src/Neo/NeoSystem.cs index 77b982f0d4..25a3d60062 100644 --- a/src/Neo/NeoSystem.cs +++ b/src/Neo/NeoSystem.cs @@ -218,6 +218,16 @@ public void EnsureStopped(IActorRef actor) inbox.Receive(TimeSpan.FromMinutes(5)); } + /// + /// Loads an at the specified path. + /// + /// The path of the storage. + /// The loaded . + public IStore LoadStore(string path) + { + return StoreFactory.GetStore(store.GetType().Name, path); + } + /// /// Resumes the startup process of . /// From 3f002a657bd7272f551eb6d4eafa5552cf0ac88a Mon Sep 17 00:00:00 2001 From: Shargon Date: Fri, 16 Feb 2024 12:06:32 +0100 Subject: [PATCH 081/168] Update InteropInterface (#3143) * Update InteropInterface core-add-interop-check * Update src/Neo.VM/Types/InteropInterface.cs * Update Neo.VM.csproj --- src/Neo.VM/Neo.VM.csproj | 4 ++++ src/Neo.VM/Types/InteropInterface.cs | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/src/Neo.VM/Neo.VM.csproj b/src/Neo.VM/Neo.VM.csproj index 5e7e071b22..7f2119c943 100644 --- a/src/Neo.VM/Neo.VM.csproj +++ b/src/Neo.VM/Neo.VM.csproj @@ -6,4 +6,8 @@ enable + + + + diff --git a/src/Neo.VM/Types/InteropInterface.cs b/src/Neo.VM/Types/InteropInterface.cs index 7dbdf55b8d..ee1998316a 100644 --- a/src/Neo.VM/Types/InteropInterface.cs +++ b/src/Neo.VM/Types/InteropInterface.cs @@ -56,6 +56,11 @@ public override T GetInterface() throw new InvalidCastException($"The item can't be casted to type {typeof(T)}"); } + internal object GetInterface() + { + return _object; + } + public override string ToString() { return _object.ToString() ?? "NULL"; From ffa56fe2b28171f86c53ea9912f0c1a4cad9e11a Mon Sep 17 00:00:00 2001 From: Shargon Date: Tue, 20 Feb 2024 09:17:42 +0100 Subject: [PATCH 082/168] Fix: Screen Rendering on Invalid Arguments (#3148) * Fix #3135 * clean * check base --- src/Neo.CLI/CLI/MainService.cs | 7 +++---- src/Neo.ConsoleService/ConsoleServiceBase.cs | 10 +++++----- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/Neo.CLI/CLI/MainService.cs b/src/Neo.CLI/CLI/MainService.cs index 4b0fccb343..b8d52a6a02 100644 --- a/src/Neo.CLI/CLI/MainService.cs +++ b/src/Neo.CLI/CLI/MainService.cs @@ -346,11 +346,10 @@ private byte[] LoadUpdateScript(UInt160 scriptHash, string nefFilePath, string m } } - public override void OnStart(string[] args) + public override bool OnStart(string[] args) { - base.OnStart(args); - OnStartWithCommandLine(args); - + if (!base.OnStart(args)) return false; + return OnStartWithCommandLine(args) != 1; } public override void OnStop() diff --git a/src/Neo.ConsoleService/ConsoleServiceBase.cs b/src/Neo.ConsoleService/ConsoleServiceBase.cs index 8b169fb808..1da87354fb 100644 --- a/src/Neo.ConsoleService/ConsoleServiceBase.cs +++ b/src/Neo.ConsoleService/ConsoleServiceBase.cs @@ -283,12 +283,13 @@ protected void OnExit() #endregion - public virtual void OnStart(string[] args) + public virtual bool OnStart(string[] args) { // Register sigterm event handler AssemblyLoadContext.Default.Unloading += SigTermEventHandler; // Register sigint event handler Console.CancelKeyPress += CancelHandler; + return true; } public virtual void OnStop() @@ -428,7 +429,7 @@ public void Run(string[] args) { if (Environment.UserInteractive) { - if (args.Length > 0 && args[0] == "/install") + if (args.Length == 1 && args[0] == "/install") { if (Environment.OSVersion.Platform != PlatformID.Win32NT) { @@ -457,7 +458,7 @@ public void Run(string[] args) Console.Write(process.StandardOutput.ReadToEnd()); } } - else if (args.Length > 0 && args[0] == "/uninstall") + else if (args.Length == 1 && args[0] == "/uninstall") { if (Environment.OSVersion.Platform != PlatformID.Win32NT) { @@ -483,8 +484,7 @@ public void Run(string[] args) } else { - OnStart(args); - RunConsole(); + if (OnStart(args)) RunConsole(); OnStop(); } } From 2e7e1e4295ce01c3499f7147124c61d8312a31d1 Mon Sep 17 00:00:00 2001 From: Shargon Date: Wed, 21 Feb 2024 01:00:20 +0100 Subject: [PATCH 083/168] Update pkgs-delete.yml (#3150) * Update pkgs-delete.yml * Update main.yml --- .github/workflows/main.yml | 48 +++----------- .github/workflows/pkgs-delete.yml | 101 ++++++++++++++++++++++++++---- 2 files changed, 98 insertions(+), 51 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index aa935fd2d3..4b483510c3 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -38,7 +38,7 @@ jobs: github-token: ${{ secrets.GITHUB_TOKEN }} path-to-lcov: ./coverage/lcov.net7.0.info - PublishGithub: + PublishPackage: if: github.ref == 'refs/heads/master' && startsWith(github.repository, 'neo-project/') needs: Test runs-on: ubuntu-latest @@ -76,44 +76,14 @@ jobs: --disable-buffering \ --no-service-endpoint; - # MyGet isn't working - # PublishMyGet: - # if: github.ref == 'refs/heads/master' && startsWith(github.repository, 'neo-project/') - # needs: Test - # runs-on: ubuntu-latest - # steps: - # - 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: Set Version - # run: git rev-list --count HEAD | xargs printf 'CI%05d' | xargs -I{} echo 'VERSION_SUFFIX={}' >> $GITHUB_ENV - # - name : Pack (Neo) - # run: | - # dotnet pack \ - # --configuration Debug \ - # --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 MyGet - # working-directory: ./out - # run: | - # for filename in *.nupkg; do - # dotnet nuget push "${filename}" \ - # --source https://www.myget.org/F/neo/api/v3/index.json \ - # --api-key "${{ secrets.MYGET_TOKEN }}" \ - # --disable-buffering \ - # --no-service-endpoint; - # done; - # shell: bash + - name: Publish to myGet + working-directory: ./out + run: | + dotnet nuget push * \ + --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/') diff --git a/.github/workflows/pkgs-delete.yml b/.github/workflows/pkgs-delete.yml index 16855f1070..cf3471b551 100644 --- a/.github/workflows/pkgs-delete.yml +++ b/.github/workflows/pkgs-delete.yml @@ -1,51 +1,128 @@ -name: Nuget Package Cleanup (github) +name: Package Cleanup on: schedule: - cron: '0 0 * * *' # Run every day at 24:00 jobs: - delete-pkgs: + + delete-myget-pkgs: + name: Delete Old MyGet Packages + runs-on: ubuntu-latest + steps: + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: '3.x' + - name: Install Requests + run: pip install requests + - name: Install Packaging + run: pip install packaging + - name: Delete versions below 3.6.1 + env: + MYGET_FEED: 'neo' + PACKAGE_NAMES: 'Neo.VM,Neo.Json,Neo.IO,Neo,Neo.ConsoleService,Neo.Extensions' # Neo.Cryptography.BLS12_381 version is 0.x + MYGET_API_KEY: ${{ secrets.MYGET_TOKEN }} + run: | + import requests + from packaging import version + import os + + def get_versions(feed, package_name, api_key): + url = f"https://www.myget.org/F/{feed}/api/v2/Packages?$select=Version&$filter=Id eq '{package_name}'&$format=json" + headers = {'Accept': 'application/json'} + response = requests.get(url, headers=headers) + if response.status_code == 200: + versions = response.json()['d']['results'] + return [ver['Version'] for ver in versions] + else: + return [] + + def delete_version(feed, package_name, ver, api_key): + url = f"https://www.myget.org/F/{feed}/api/v2/package/{package_name}/{ver}?hardDelete=true" + headers = {"X-NuGet-ApiKey": api_key} + response = requests.delete(url, headers=headers) + return response.status_code == 200 # Success + + feed = os.environ['MYGET_FEED'] + package_names = os.environ['PACKAGE_NAMES'].split(',') + api_key = os.environ['MYGET_API_KEY'] + + for package_name in package_names: + versions_to_delete = get_versions(feed, package_name, api_key) + for ver in versions_to_delete: + if version.parse(ver.split("-", 1)[0]) >= version.Version("3.6.1"): + print(f"Omited {ver} of package {package_name}.") + continue + if delete_version(feed, package_name, ver, api_key): + print(f"Deleted version {ver} of package {package_name}.") + else: + print(f"Failed to delete version {ver} of package {package_name}.") + + shell: python + + delete-git-pkgs: name: Delete Old Nuget Packages runs-on: ubuntu-latest steps: - - name: Delete Neo Package + - name: Delete Neo.Cryptography.BLS12_381 Package uses: actions/delete-package-versions@v4 with: - package-name: Neo + package-name: Neo.Cryptography.BLS12_381 package-type: nuget min-versions-to-keep: 3 + delete-only-pre-release-versions: "true" token: "${{ secrets.GITHUB_TOKEN }}" - - name: Delete Neo.ConsoleService Package + - name: Delete Neo.VM Package uses: actions/delete-package-versions@v4 with: - package-name: Neo.ConsoleService + package-name: Neo.VM package-type: nuget min-versions-to-keep: 3 + delete-only-pre-release-versions: "true" token: "${{ secrets.GITHUB_TOKEN }}" - - name: Delete Neo.ConsoleService Package + - name: Delete Neo.Json Package uses: actions/delete-package-versions@v4 with: - package-name: Neo.ConsoleService + package-name: Neo.Json package-type: nuget min-versions-to-keep: 3 + delete-only-pre-release-versions: "true" token: "${{ secrets.GITHUB_TOKEN }}" - - name: Delete Neo.Json Package + - name: Delete Neo.IO Package uses: actions/delete-package-versions@v4 with: - package-name: Neo.Json + package-name: Neo.IO package-type: nuget min-versions-to-keep: 3 + delete-only-pre-release-versions: "true" token: "${{ secrets.GITHUB_TOKEN }}" - - name: Delete Neo.VM Package + - name: Delete Neo Package uses: actions/delete-package-versions@v4 with: - package-name: Neo.VM + package-name: Neo + package-type: nuget + min-versions-to-keep: 3 + delete-only-pre-release-versions: "true" + token: "${{ secrets.GITHUB_TOKEN }}" + - name: Delete Neo.ConsoleService Package + uses: actions/delete-package-versions@v4 + with: + package-name: Neo.ConsoleService + package-type: nuget + 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: + package-name: Neo.Extensions package-type: nuget min-versions-to-keep: 3 + delete-only-pre-release-versions: "true" token: "${{ secrets.GITHUB_TOKEN }}" From a6803cf1bc5507cffa113d0bc5712d4a1d765e1f Mon Sep 17 00:00:00 2001 From: Shargon Date: Wed, 21 Feb 2024 08:33:31 +0100 Subject: [PATCH 084/168] Update NuGet.Config (#3151) --- NuGet.Config | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/NuGet.Config b/NuGet.Config index f7ce69db29..53fc635420 100644 --- a/NuGet.Config +++ b/NuGet.Config @@ -2,7 +2,8 @@ - + + From febcc2153ccf83ca8118a72ede4d5f05ce8b67ea Mon Sep 17 00:00:00 2001 From: Shargon Date: Wed, 21 Feb 2024 08:59:36 +0100 Subject: [PATCH 085/168] Fix package version and frameworks (#3152) * Fix package version and frameworks Credits to @Jim8y * It seems that was already build --- .github/workflows/main.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 4b483510c3..ee31065ab2 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -45,6 +45,8 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4 + with: + fetch-depth: 0 - name: Setup .NET Core uses: actions/setup-dotnet@v4 From ffa90648c8f6269f2b157564fb2203f5278114c8 Mon Sep 17 00:00:00 2001 From: Shargon Date: Wed, 21 Feb 2024 10:16:18 +0100 Subject: [PATCH 086/168] Fix store (#3149) --- benchmarks/Neo.Benchmarks/Benchmarks.cs | 3 +- src/Neo/NeoSystem.cs | 18 +++++++----- src/Neo/Persistence/MemoryStoreProvider.cs | 19 ++++++++++++ src/Neo/Persistence/StoreFactory.cs | 29 ++++++++++++------- tests/Neo.UnitTests/Ledger/UT_MemoryPool.cs | 4 +-- .../Persistence/UT_MemoryStore.cs | 6 ++++ tests/Neo.UnitTests/TestBlockchain.cs | 9 +++++- 7 files changed, 66 insertions(+), 22 deletions(-) create mode 100644 src/Neo/Persistence/MemoryStoreProvider.cs diff --git a/benchmarks/Neo.Benchmarks/Benchmarks.cs b/benchmarks/Neo.Benchmarks/Benchmarks.cs index 5c3389407c..081f806622 100644 --- a/benchmarks/Neo.Benchmarks/Benchmarks.cs +++ b/benchmarks/Neo.Benchmarks/Benchmarks.cs @@ -10,7 +10,6 @@ // modifications are permitted. using Neo.Network.P2P.Payloads; -using Neo.Persistence; using Neo.SmartContract; using Neo.VM; using System.Diagnostics; @@ -20,7 +19,7 @@ namespace Neo; static class Benchmarks { private static readonly ProtocolSettings protocol = ProtocolSettings.Load("config.json"); - private static readonly NeoSystem system = new(protocol, new MemoryStore()); + private static readonly NeoSystem system = new(protocol, (string)null); public static void NeoIssue2725() { diff --git a/src/Neo/NeoSystem.cs b/src/Neo/NeoSystem.cs index 25a3d60062..d299f8de12 100644 --- a/src/Neo/NeoSystem.cs +++ b/src/Neo/NeoSystem.cs @@ -98,6 +98,7 @@ public class NeoSystem : IDisposable private ImmutableList services = ImmutableList.Empty; private readonly IStore store; + private readonly IStoreProvider storageProvider; private ChannelsConfig start_message = null; private int suspend = 0; @@ -113,9 +114,10 @@ static NeoSystem() /// Initializes a new instance of the class. /// /// The protocol settings of the . - /// The storage engine used to create the objects. If this parameter is , a default in-memory storage engine will be used. - /// The path of the storage. If is the default in-memory storage engine, this parameter is ignored. - public NeoSystem(ProtocolSettings settings, string? storageEngine = null, string? storagePath = null) : this(settings, StoreFactory.GetStore(storageEngine ?? nameof(MemoryStore), storagePath)) + /// The storage engine used to create the objects. If this parameter is , a default in-memory storage engine will be used. + /// The path of the storage. If is the default in-memory storage engine, this parameter is ignored. + public NeoSystem(ProtocolSettings settings, string? storageProvider = null, string? storagePath = null) : + this(settings, StoreFactory.GetStoreProvider(storageProvider ?? nameof(MemoryStore)), storagePath) { } @@ -123,12 +125,14 @@ public NeoSystem(ProtocolSettings settings, string? storageEngine = null, string /// Initializes a new instance of the class. /// /// The protocol settings of the . - /// The to use. - public NeoSystem(ProtocolSettings settings, IStore storage) + /// The to use. + /// The path of the storage. If is the default in-memory storage engine, this parameter is ignored. + public NeoSystem(ProtocolSettings settings, IStoreProvider storageProvider, string? storagePath = null) { this.Settings = settings; this.GenesisBlock = CreateGenesisBlock(settings); - this.store = storage; + this.storageProvider = storageProvider; + this.store = storageProvider.GetStore(storagePath); this.MemPool = new MemoryPool(this); this.Blockchain = ActorSystem.ActorOf(Ledger.Blockchain.Props(this)); this.LocalNode = ActorSystem.ActorOf(Network.P2P.LocalNode.Props(this)); @@ -225,7 +229,7 @@ public void EnsureStopped(IActorRef actor) /// The loaded . public IStore LoadStore(string path) { - return StoreFactory.GetStore(store.GetType().Name, path); + return storageProvider.GetStore(path); } /// diff --git a/src/Neo/Persistence/MemoryStoreProvider.cs b/src/Neo/Persistence/MemoryStoreProvider.cs new file mode 100644 index 0000000000..23276bce96 --- /dev/null +++ b/src/Neo/Persistence/MemoryStoreProvider.cs @@ -0,0 +1,19 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// MemoryStoreProvider.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.Persistence +{ + internal class MemoryStoreProvider : IStoreProvider + { + public string Name => nameof(MemoryStore); + public IStore GetStore(string path) => new MemoryStore(); + } +} diff --git a/src/Neo/Persistence/StoreFactory.cs b/src/Neo/Persistence/StoreFactory.cs index d24e94960c..2764366f06 100644 --- a/src/Neo/Persistence/StoreFactory.cs +++ b/src/Neo/Persistence/StoreFactory.cs @@ -15,12 +15,6 @@ namespace Neo.Persistence; public static class StoreFactory { - private class MemoryStoreProvider : IStoreProvider - { - public string Name => nameof(MemoryStore); - public IStore GetStore(string path) => new MemoryStore(); - } - private static readonly Dictionary providers = new(); static StoreFactory() @@ -37,14 +31,29 @@ public static void RegisterProvider(IStoreProvider provider) providers.Add(provider.Name, provider); } + /// + /// Get store provider by name + /// + /// Name + /// Store provider + public static IStoreProvider? GetStoreProvider(string name) + { + if (providers.TryGetValue(name, out var provider)) + { + return provider; + } + + return null; + } + /// /// Get store from name /// - /// The storage engine used to create the objects. If this parameter is , a default in-memory storage engine will be used. - /// The path of the storage. If is the default in-memory storage engine, this parameter is ignored. + /// The storage engine used to create the objects. If this parameter is , a default in-memory storage engine will be used. + /// The path of the storage. If is the default in-memory storage engine, this parameter is ignored. /// The storage engine. - public static IStore GetStore(string storageEngine, string path) + public static IStore GetStore(string storageProvider, string path) { - return providers[storageEngine].GetStore(path); + return providers[storageProvider].GetStore(path); } } diff --git a/tests/Neo.UnitTests/Ledger/UT_MemoryPool.cs b/tests/Neo.UnitTests/Ledger/UT_MemoryPool.cs index 784a1d9b5e..1063413073 100644 --- a/tests/Neo.UnitTests/Ledger/UT_MemoryPool.cs +++ b/tests/Neo.UnitTests/Ledger/UT_MemoryPool.cs @@ -57,7 +57,7 @@ public void TestSetup() TimeProvider.ResetToDefault(); // Create a MemoryPool with capacity of 100 - _unit = new MemoryPool(new NeoSystem(TestProtocolSettings.Default with { MemoryPoolMaxTransactions = 100 }, new MemoryStore())); + _unit = new MemoryPool(new NeoSystem(TestProtocolSettings.Default with { MemoryPoolMaxTransactions = 100 }, storageProvider: (string)null)); // Verify capacity equals the amount specified _unit.Capacity.Should().Be(100); @@ -648,7 +648,7 @@ public void TestGetVerifiedTransactions() [TestMethod] public void TestReVerifyTopUnverifiedTransactionsIfNeeded() { - _unit = new MemoryPool(new NeoSystem(TestProtocolSettings.Default with { MemoryPoolMaxTransactions = 600 }, new MemoryStore())); + _unit = new MemoryPool(new NeoSystem(TestProtocolSettings.Default with { MemoryPoolMaxTransactions = 600 }, storageProvider: (string)null)); AddTransaction(CreateTransaction(100000001)); AddTransaction(CreateTransaction(100000001)); diff --git a/tests/Neo.UnitTests/Persistence/UT_MemoryStore.cs b/tests/Neo.UnitTests/Persistence/UT_MemoryStore.cs index 50da353f7c..88d48ba548 100644 --- a/tests/Neo.UnitTests/Persistence/UT_MemoryStore.cs +++ b/tests/Neo.UnitTests/Persistence/UT_MemoryStore.cs @@ -19,6 +19,12 @@ namespace Neo.UnitTests.Persistence [TestClass] public class UT_MemoryStore { + [TestMethod] + public void LoadStoreTest() + { + Assert.IsInstanceOfType(TestBlockchain.TheNeoSystem.LoadStore("abc")); + } + [TestMethod] public void StoreTest() { diff --git a/tests/Neo.UnitTests/TestBlockchain.cs b/tests/Neo.UnitTests/TestBlockchain.cs index cbdd6c1c12..f7e06d0595 100644 --- a/tests/Neo.UnitTests/TestBlockchain.cs +++ b/tests/Neo.UnitTests/TestBlockchain.cs @@ -22,10 +22,17 @@ public static class TestBlockchain public static readonly UInt160[] DefaultExtensibleWitnessWhiteList; private static readonly MemoryStore Store = new(); + private class StoreProvider : IStoreProvider + { + public string Name => "TestProvider"; + + public IStore GetStore(string path) => Store; + } + static TestBlockchain() { Console.WriteLine("initialize NeoSystem"); - TheNeoSystem = new NeoSystem(TestProtocolSettings.Default, Store); + TheNeoSystem = new NeoSystem(TestProtocolSettings.Default, new StoreProvider()); } internal static void ResetStore() From d8af2c622e33cd643ff361bc73b8afbf7c1361a4 Mon Sep 17 00:00:00 2001 From: Shargon Date: Fri, 23 Feb 2024 01:43:59 +0100 Subject: [PATCH 087/168] Decouple calculate fee from Wallet (#3147) * Decouple calculate fee from Wallet * clean iff * Convert into extension * Update src/Neo/Wallets/Helper.cs --- src/Neo/Wallets/Helper.cs | 90 +++++++++++++++++++++++++++++++++++++++ src/Neo/Wallets/Wallet.cs | 89 +------------------------------------- 2 files changed, 91 insertions(+), 88 deletions(-) diff --git a/src/Neo/Wallets/Helper.cs b/src/Neo/Wallets/Helper.cs index cced44aa9d..960baa27af 100644 --- a/src/Neo/Wallets/Helper.cs +++ b/src/Neo/Wallets/Helper.cs @@ -13,7 +13,12 @@ using Neo.IO; using Neo.Network.P2P; using Neo.Network.P2P.Payloads; +using Neo.Persistence; +using Neo.SmartContract; +using Neo.SmartContract.Native; +using Neo.VM; using System; +using static Neo.SmartContract.Helper; namespace Neo.Wallets { @@ -72,5 +77,90 @@ internal static byte[] XOR(byte[] x, byte[] y) r[i] = (byte)(x[i] ^ y[i]); return r; } + + /// + /// Calculates the network fee for the specified transaction. + /// + /// The transaction to calculate. + /// The snapshot used to read data. + /// Thr protocol settings to use. + /// Function to retrive the script's account from a hash. + /// The maximum cost that can be spent when a contract is executed. + /// The network fee of the transaction. + public static long CalculateNetworkFee(this Transaction tx, DataCache snapshot, ProtocolSettings settings, Func accountScript, long maxExecutionCost = ApplicationEngine.TestModeGas) + { + UInt160[] hashes = tx.GetScriptHashesForVerifying(snapshot); + + // base size for transaction: includes const_header + signers + attributes + script + hashes + int size = Transaction.HeaderSize + tx.Signers.GetVarSize() + tx.Attributes.GetVarSize() + tx.Script.GetVarSize() + IO.Helper.GetVarSize(hashes.Length), index = -1; + uint exec_fee_factor = NativeContract.Policy.GetExecFeeFactor(snapshot); + long networkFee = 0; + foreach (UInt160 hash in hashes) + { + index++; + byte[] witnessScript = accountScript(hash); + byte[] invocationScript = null; + + if (tx.Witnesses != null && witnessScript is null) + { + // Try to find the script in the witnesses + Witness witness = tx.Witnesses[index]; + witnessScript = witness?.VerificationScript.ToArray(); + + if (witnessScript is null || witnessScript.Length == 0) + { + // Then it's a contract-based witness, so try to get the corresponding invocation script for it + invocationScript = witness?.InvocationScript.ToArray(); + } + } + + if (witnessScript is null || witnessScript.Length == 0) + { + var contract = NativeContract.ContractManagement.GetContract(snapshot, hash); + if (contract is null) + throw new ArgumentException($"The smart contract or address {hash} is not found"); + var md = contract.Manifest.Abi.GetMethod("verify", -1); + if (md is null) + throw new ArgumentException($"The smart contract {contract.Hash} haven't got verify method"); + if (md.ReturnType != ContractParameterType.Boolean) + throw new ArgumentException("The verify method doesn't return boolean value."); + if (md.Parameters.Length > 0 && invocationScript is null) + throw new ArgumentException("The verify method requires parameters that need to be passed via the witness' invocation script."); + + // Empty verification and non-empty invocation scripts + var invSize = invocationScript?.GetVarSize() ?? Array.Empty().GetVarSize(); + size += Array.Empty().GetVarSize() + invSize; + + // Check verify cost + using ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Verification, tx, snapshot.CreateSnapshot(), 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."); + if (!engine.ResultStack.Pop().GetBoolean()) throw new ArgumentException($"Smart contract {contract.Hash} returns false."); + + maxExecutionCost -= engine.GasConsumed; + if (maxExecutionCost <= 0) throw new InvalidOperationException("Insufficient GAS."); + networkFee += engine.GasConsumed; + } + else if (IsSignatureContract(witnessScript)) + { + size += 67 + witnessScript.GetVarSize(); + networkFee += exec_fee_factor * SignatureContractCost(); + } + else if (IsMultiSigContract(witnessScript, out int m, out int n)) + { + int size_inv = 66 * m; + size += IO.Helper.GetVarSize(size_inv) + size_inv + witnessScript.GetVarSize(); + networkFee += exec_fee_factor * MultiSignatureContractCost(m, n); + } + // We can support more contract types in the future. + } + networkFee += size * NativeContract.Policy.GetFeePerByte(snapshot); + foreach (TransactionAttribute attr in tx.Attributes) + { + networkFee += attr.CalculateNetworkFee(snapshot, tx); + } + return networkFee; + } } } diff --git a/src/Neo/Wallets/Wallet.cs b/src/Neo/Wallets/Wallet.cs index ecffe85366..761b0b1999 100644 --- a/src/Neo/Wallets/Wallet.cs +++ b/src/Neo/Wallets/Wallet.cs @@ -578,99 +578,12 @@ private Transaction MakeTransaction(DataCache snapshot, ReadOnlyMemory scr tx.SystemFee = engine.GasConsumed; } - tx.NetworkFee = CalculateNetworkFee(snapshot, tx, maxGas); + tx.NetworkFee = tx.CalculateNetworkFee(snapshot, ProtocolSettings, (a) => GetAccount(a)?.Contract?.Script, maxGas); if (value >= tx.SystemFee + tx.NetworkFee) return tx; } throw new InvalidOperationException("Insufficient GAS"); } - /// - /// Calculates the network fee for the specified transaction. - /// - /// The snapshot used to read data. - /// The transaction to calculate. - /// The maximum cost that can be spent when a contract is executed. - /// The network fee of the transaction. - public long CalculateNetworkFee(DataCache snapshot, Transaction tx, long maxExecutionCost = ApplicationEngine.TestModeGas) - { - UInt160[] hashes = tx.GetScriptHashesForVerifying(snapshot); - - // base size for transaction: includes const_header + signers + attributes + script + hashes - int size = Transaction.HeaderSize + tx.Signers.GetVarSize() + tx.Attributes.GetVarSize() + tx.Script.GetVarSize() + IO.Helper.GetVarSize(hashes.Length); - uint exec_fee_factor = NativeContract.Policy.GetExecFeeFactor(snapshot); - long networkFee = 0; - int index = -1; - foreach (UInt160 hash in hashes) - { - index++; - byte[] witness_script = GetAccount(hash)?.Contract?.Script; - byte[] invocationScript = null; - - if (tx.Witnesses != null) - { - if (witness_script is null) - { - // Try to find the script in the witnesses - Witness witness = tx.Witnesses[index]; - witness_script = witness?.VerificationScript.ToArray(); - - if (witness_script is null || witness_script.Length == 0) - { - // Then it's a contract-based witness, so try to get the corresponding invocation script for it - invocationScript = witness?.InvocationScript.ToArray(); - } - } - } - - if (witness_script is null || witness_script.Length == 0) - { - var contract = NativeContract.ContractManagement.GetContract(snapshot, hash); - if (contract is null) - throw new ArgumentException($"The smart contract or address {hash} is not found"); - var md = contract.Manifest.Abi.GetMethod("verify", -1); - if (md is null) - throw new ArgumentException($"The smart contract {contract.Hash} haven't got verify method"); - if (md.ReturnType != ContractParameterType.Boolean) - throw new ArgumentException("The verify method doesn't return boolean value."); - if (md.Parameters.Length > 0 && invocationScript is null) - throw new ArgumentException("The verify method requires parameters that need to be passed via the witness' invocation script."); - - // Empty verification and non-empty invocation scripts - var invSize = invocationScript?.GetVarSize() ?? Array.Empty().GetVarSize(); - size += Array.Empty().GetVarSize() + invSize; - - // Check verify cost - using ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Verification, tx, snapshot.CreateSnapshot(), settings: ProtocolSettings, 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."); - if (!engine.ResultStack.Pop().GetBoolean()) throw new ArgumentException($"Smart contract {contract.Hash} returns false."); - - maxExecutionCost -= engine.GasConsumed; - if (maxExecutionCost <= 0) throw new InvalidOperationException("Insufficient GAS."); - networkFee += engine.GasConsumed; - } - else if (IsSignatureContract(witness_script)) - { - size += 67 + witness_script.GetVarSize(); - networkFee += exec_fee_factor * SignatureContractCost(); - } - else if (IsMultiSigContract(witness_script, out int m, out int n)) - { - int size_inv = 66 * m; - size += IO.Helper.GetVarSize(size_inv) + size_inv + witness_script.GetVarSize(); - networkFee += exec_fee_factor * MultiSignatureContractCost(m, n); - } - // We can support more contract types in the future. - } - networkFee += size * NativeContract.Policy.GetFeePerByte(snapshot); - foreach (TransactionAttribute attr in tx.Attributes) - { - networkFee += attr.CalculateNetworkFee(snapshot, tx); - } - return networkFee; - } - /// /// Signs the in the specified with the wallet. /// From de39a36c96a83e2d791ddac435c96cbed61fd763 Mon Sep 17 00:00:00 2001 From: Shargon Date: Fri, 23 Feb 2024 01:50:32 +0100 Subject: [PATCH 088/168] Fix coverage (#3155) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update main.yml * Update main.yml * Update main.yml * Change format * Update .github/workflows/main.yml * Update main.yml * Update .github/workflows/main.yml * Update main.yml * Update .github/workflows/main.yml * Update main.yml * Update .github/workflows/main.yml * Update .github/workflows/main.yml * Avoid add package in other os * Update main.yml * Update main.yml * Final fix * Update .github/workflows/main.yml * Update main.yml * Update main.yml * Update .github/workflows/main.yml * Update .github/workflows/main.yml * Remove rm In windows fail --------- Co-authored-by: Vitor Nazário Coelho --- .github/workflows/main.yml | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ee31065ab2..e643529a27 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -27,16 +27,24 @@ jobs: if: matrix.os == 'ubuntu-latest' run: | dotnet format --verify-no-changes --verbosity diagnostic - - name: Test + - name: Prepare coverage + if: matrix.os == 'ubuntu-latest' run: | find tests -name *.csproj | xargs -I % dotnet add % package coverlet.msbuild - dotnet test /p:CollectCoverage=true /p:CoverletOutputFormat=lcov /p:CoverletOutput=${GITHUB_WORKSPACE}/coverage/lcov + - name: Test + run: | + dotnet test ./tests/Neo.ConsoleService.Tests /p:CollectCoverage=true /p:CoverletOutput=${GITHUB_WORKSPACE}/coverage-join/ + dotnet test ./tests/Neo.Cryptography.BLS12_381.Tests /p:CollectCoverage=true /p:CoverletOutput=${GITHUB_WORKSPACE}/coverage-join/ /p:MergeWith=${GITHUB_WORKSPACE}/coverage-join/coverage.net7.0.json + dotnet test ./tests/Neo.UnitTests /p:CollectCoverage=true /p:CoverletOutput=${GITHUB_WORKSPACE}/coverage-join/ /p:MergeWith=${GITHUB_WORKSPACE}/coverage-join/coverage.net7.0.json + dotnet test ./tests/Neo.VM.Tests /p:CollectCoverage=true /p:CoverletOutput=${GITHUB_WORKSPACE}/coverage-join/ /p:MergeWith=${GITHUB_WORKSPACE}/coverage-join/coverage.net7.0.json + dotnet test ./tests/Neo.Json.UnitTests /p:CollectCoverage=true /p:CoverletOutput=${GITHUB_WORKSPACE}/coverage/lcov /p:MergeWith=${GITHUB_WORKSPACE}/coverage-join/coverage.net7.0.json /p:CoverletOutputFormat=lcov - name: Coveralls if: matrix.os == 'ubuntu-latest' - uses: coverallsapp/github-action@master + uses: coverallsapp/github-action@v2.2.3 with: github-token: ${{ secrets.GITHUB_TOKEN }} - path-to-lcov: ./coverage/lcov.net7.0.info + format: lcov + file: ${GITHUB_WORKSPACE}/coverage/lcov.net7.0.info PublishPackage: if: github.ref == 'refs/heads/master' && startsWith(github.repository, 'neo-project/') From 1fffb959446bff52f33248be02279f11220c615f Mon Sep 17 00:00:00 2001 From: Shargon Date: Fri, 23 Feb 2024 11:19:09 +0100 Subject: [PATCH 089/168] VM - Jump table (#3120) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Jump table * Types * Splice * revert partial * More control * Remove attribute * ApplicationEngine logic * Stack * Bitwisee * clean using * Numeric * Prepare * AggressiveInlining * one left * Compound * Slot * Allow to override invalid opcode * Specify jumpTable according to block * Fix syscall * Rename to UnloadContext * Revert "Rename to UnloadContext" This reverts commit 5a551da79897b6377473755c50f048925d1b87ff. * Rename * Update JumpTable.Control.cs * Update src/Neo.VM/JumpTable/JumpTable.cs * Rename methods * Update src/Neo.VM/JumpTable/JumpTable.Push.cs Co-authored-by: Jimmy * Update src/Neo.VM/ExecutionEngine.cs Co-authored-by: Christopher Schuchardt * Update src/Neo.VM/ExecutionEngine.cs Co-authored-by: Christopher Schuchardt * Update src/Neo.VM/ExecutionEngine.cs Co-authored-by: Christopher Schuchardt * Update src/Neo/SmartContract/ApplicationEngine.cs Co-authored-by: Christopher Schuchardt * use internal * Allow previous constructor * prevent new jumptTable if default * Update src/Neo.VM/JumpTable/JumpTable.cs --------- Co-authored-by: Jimmy Co-authored-by: Christopher Schuchardt Co-authored-by: Vitor Nazário Coelho --- src/Neo.VM/ExecutionEngine.cs | 1476 +---------------- src/Neo.VM/JumpTable/JumpTable.Bitwisee.cs | 65 + src/Neo.VM/JumpTable/JumpTable.Compound.cs | 390 +++++ src/Neo.VM/JumpTable/JumpTable.Control.cs | 396 +++++ src/Neo.VM/JumpTable/JumpTable.Numeric.cs | 265 +++ src/Neo.VM/JumpTable/JumpTable.Push.cs | 213 +++ src/Neo.VM/JumpTable/JumpTable.Slot.cs | 363 ++++ src/Neo.VM/JumpTable/JumpTable.Splice.cs | 106 ++ src/Neo.VM/JumpTable/JumpTable.Stack.cs | 124 ++ src/Neo.VM/JumpTable/JumpTable.Types.cs | 60 + src/Neo.VM/JumpTable/JumpTable.cs | 71 + src/Neo.VM/Neo.VM.csproj | 1 + src/Neo/SmartContract/ApplicationEngine.cs | 93 +- .../IApplicationEngineProvider.cs | 4 +- .../UT_ApplicationEngineProvider.cs | 9 +- tests/Neo.VM.Tests/Types/TestEngine.cs | 19 +- 16 files changed, 2178 insertions(+), 1477 deletions(-) create mode 100644 src/Neo.VM/JumpTable/JumpTable.Bitwisee.cs create mode 100644 src/Neo.VM/JumpTable/JumpTable.Compound.cs create mode 100644 src/Neo.VM/JumpTable/JumpTable.Control.cs create mode 100644 src/Neo.VM/JumpTable/JumpTable.Numeric.cs create mode 100644 src/Neo.VM/JumpTable/JumpTable.Push.cs create mode 100644 src/Neo.VM/JumpTable/JumpTable.Slot.cs create mode 100644 src/Neo.VM/JumpTable/JumpTable.Splice.cs create mode 100644 src/Neo.VM/JumpTable/JumpTable.Stack.cs create mode 100644 src/Neo.VM/JumpTable/JumpTable.Types.cs create mode 100644 src/Neo.VM/JumpTable/JumpTable.cs diff --git a/src/Neo.VM/ExecutionEngine.cs b/src/Neo.VM/ExecutionEngine.cs index 39051afff1..de268d1030 100644 --- a/src/Neo.VM/ExecutionEngine.cs +++ b/src/Neo.VM/ExecutionEngine.cs @@ -12,11 +12,7 @@ using Neo.VM.Types; using System; using System.Collections.Generic; -using System.Linq; -using System.Numerics; using System.Runtime.CompilerServices; -using Buffer = Neo.VM.Types.Buffer; -using VMArray = Neo.VM.Types.Array; namespace Neo.VM { @@ -26,7 +22,9 @@ namespace Neo.VM public class ExecutionEngine : IDisposable { private VMState state = VMState.BREAK; - private bool isJumping = false; + internal bool isJumping = false; + + public JumpTable JumpTable { get; } /// /// Restrictions on the VM. @@ -61,7 +59,7 @@ public class ExecutionEngine : IDisposable /// /// The VM object representing the uncaught exception. /// - public StackItem? UncaughtException { get; private set; } + public StackItem? UncaughtException { get; internal set; } /// /// The current state of the VM. @@ -85,45 +83,24 @@ protected internal set /// /// Initializes a new instance of the class. /// - public ExecutionEngine() : this(new ReferenceCounter(), ExecutionEngineLimits.Default) + public ExecutionEngine(JumpTable? jumpTable = null) : this(jumpTable, new ReferenceCounter(), ExecutionEngineLimits.Default) { } /// /// Initializes a new instance of the class with the specified and . /// + /// The jump table to be used. /// The reference counter to be used. /// Restrictions on the VM. - protected ExecutionEngine(ReferenceCounter referenceCounter, ExecutionEngineLimits limits) + protected ExecutionEngine(JumpTable? jumpTable, ReferenceCounter referenceCounter, ExecutionEngineLimits limits) { + this.JumpTable = jumpTable ?? JumpTable.Default; this.Limits = limits; this.ReferenceCounter = referenceCounter; this.ResultStack = new EvaluationStack(referenceCounter); } - /// - /// Called when a context is unloaded. - /// - /// The context being unloaded. - protected virtual void ContextUnloaded(ExecutionContext context) - { - if (InvocationStack.Count == 0) - { - CurrentContext = null; - EntryContext = null; - } - else - { - CurrentContext = InvocationStack.Peek(); - } - if (context.StaticFields != null && context.StaticFields != CurrentContext?.StaticFields) - { - context.StaticFields.ClearReferences(); - } - context.LocalVariables?.ClearReferences(); - context.Arguments?.ClearReferences(); - } - public virtual void Dispose() { InvocationStack.Clear(); @@ -142,1320 +119,6 @@ public virtual VMState Execute() return State; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void ExecuteCall(int position) - { - LoadContext(CurrentContext!.Clone(position)); - } - - private void ExecuteInstruction(Instruction instruction) - { - switch (instruction.OpCode) - { - //Push - case OpCode.PUSHINT8: - case OpCode.PUSHINT16: - case OpCode.PUSHINT32: - case OpCode.PUSHINT64: - case OpCode.PUSHINT128: - case OpCode.PUSHINT256: - { - Push(new BigInteger(instruction.Operand.Span)); - break; - } - case OpCode.PUSHT: - { - Push(StackItem.True); - break; - } - case OpCode.PUSHF: - { - Push(StackItem.False); - break; - } - case OpCode.PUSHA: - { - int position = checked(CurrentContext!.InstructionPointer + instruction.TokenI32); - if (position < 0 || position > CurrentContext.Script.Length) - throw new InvalidOperationException($"Bad pointer address: {position}"); - Push(new Pointer(CurrentContext.Script, position)); - break; - } - case OpCode.PUSHNULL: - { - Push(StackItem.Null); - break; - } - case OpCode.PUSHDATA1: - case OpCode.PUSHDATA2: - case OpCode.PUSHDATA4: - { - Limits.AssertMaxItemSize(instruction.Operand.Length); - Push(instruction.Operand); - break; - } - case OpCode.PUSHM1: - case OpCode.PUSH0: - case OpCode.PUSH1: - case OpCode.PUSH2: - case OpCode.PUSH3: - case OpCode.PUSH4: - case OpCode.PUSH5: - case OpCode.PUSH6: - case OpCode.PUSH7: - case OpCode.PUSH8: - case OpCode.PUSH9: - case OpCode.PUSH10: - case OpCode.PUSH11: - case OpCode.PUSH12: - case OpCode.PUSH13: - case OpCode.PUSH14: - case OpCode.PUSH15: - case OpCode.PUSH16: - { - Push((int)instruction.OpCode - (int)OpCode.PUSH0); - break; - } - - // Control - case OpCode.NOP: break; - case OpCode.JMP: - { - ExecuteJumpOffset(instruction.TokenI8); - break; - } - case OpCode.JMP_L: - { - ExecuteJumpOffset(instruction.TokenI32); - break; - } - case OpCode.JMPIF: - { - if (Pop().GetBoolean()) - ExecuteJumpOffset(instruction.TokenI8); - break; - } - case OpCode.JMPIF_L: - { - if (Pop().GetBoolean()) - ExecuteJumpOffset(instruction.TokenI32); - break; - } - case OpCode.JMPIFNOT: - { - if (!Pop().GetBoolean()) - ExecuteJumpOffset(instruction.TokenI8); - break; - } - case OpCode.JMPIFNOT_L: - { - if (!Pop().GetBoolean()) - ExecuteJumpOffset(instruction.TokenI32); - break; - } - case OpCode.JMPEQ: - { - var x2 = Pop().GetInteger(); - var x1 = Pop().GetInteger(); - if (x1 == x2) - ExecuteJumpOffset(instruction.TokenI8); - break; - } - case OpCode.JMPEQ_L: - { - var x2 = Pop().GetInteger(); - var x1 = Pop().GetInteger(); - if (x1 == x2) - ExecuteJumpOffset(instruction.TokenI32); - break; - } - case OpCode.JMPNE: - { - var x2 = Pop().GetInteger(); - var x1 = Pop().GetInteger(); - if (x1 != x2) - ExecuteJumpOffset(instruction.TokenI8); - break; - } - case OpCode.JMPNE_L: - { - var x2 = Pop().GetInteger(); - var x1 = Pop().GetInteger(); - if (x1 != x2) - ExecuteJumpOffset(instruction.TokenI32); - break; - } - case OpCode.JMPGT: - { - var x2 = Pop().GetInteger(); - var x1 = Pop().GetInteger(); - if (x1 > x2) - ExecuteJumpOffset(instruction.TokenI8); - break; - } - case OpCode.JMPGT_L: - { - var x2 = Pop().GetInteger(); - var x1 = Pop().GetInteger(); - if (x1 > x2) - ExecuteJumpOffset(instruction.TokenI32); - break; - } - case OpCode.JMPGE: - { - var x2 = Pop().GetInteger(); - var x1 = Pop().GetInteger(); - if (x1 >= x2) - ExecuteJumpOffset(instruction.TokenI8); - break; - } - case OpCode.JMPGE_L: - { - var x2 = Pop().GetInteger(); - var x1 = Pop().GetInteger(); - if (x1 >= x2) - ExecuteJumpOffset(instruction.TokenI32); - break; - } - case OpCode.JMPLT: - { - var x2 = Pop().GetInteger(); - var x1 = Pop().GetInteger(); - if (x1 < x2) - ExecuteJumpOffset(instruction.TokenI8); - break; - } - case OpCode.JMPLT_L: - { - var x2 = Pop().GetInteger(); - var x1 = Pop().GetInteger(); - if (x1 < x2) - ExecuteJumpOffset(instruction.TokenI32); - break; - } - case OpCode.JMPLE: - { - var x2 = Pop().GetInteger(); - var x1 = Pop().GetInteger(); - if (x1 <= x2) - ExecuteJumpOffset(instruction.TokenI8); - break; - } - case OpCode.JMPLE_L: - { - var x2 = Pop().GetInteger(); - var x1 = Pop().GetInteger(); - if (x1 <= x2) - ExecuteJumpOffset(instruction.TokenI32); - break; - } - case OpCode.CALL: - { - ExecuteCall(checked(CurrentContext!.InstructionPointer + instruction.TokenI8)); - break; - } - case OpCode.CALL_L: - { - ExecuteCall(checked(CurrentContext!.InstructionPointer + instruction.TokenI32)); - break; - } - case OpCode.CALLA: - { - var x = Pop(); - if (x.Script != CurrentContext!.Script) - throw new InvalidOperationException("Pointers can't be shared between scripts"); - ExecuteCall(x.Position); - break; - } - case OpCode.CALLT: - { - LoadToken(instruction.TokenU16); - break; - } - case OpCode.ABORT: - { - throw new Exception($"{OpCode.ABORT} is executed."); - } - case OpCode.ASSERT: - { - var x = Pop().GetBoolean(); - if (!x) - throw new Exception($"{OpCode.ASSERT} is executed with false result."); - break; - } - case OpCode.THROW: - { - ExecuteThrow(Pop()); - break; - } - case OpCode.TRY: - { - int catchOffset = instruction.TokenI8; - int finallyOffset = instruction.TokenI8_1; - ExecuteTry(catchOffset, finallyOffset); - break; - } - case OpCode.TRY_L: - { - int catchOffset = instruction.TokenI32; - int finallyOffset = instruction.TokenI32_1; - ExecuteTry(catchOffset, finallyOffset); - break; - } - case OpCode.ENDTRY: - { - int endOffset = instruction.TokenI8; - ExecuteEndTry(endOffset); - break; - } - case OpCode.ENDTRY_L: - { - int endOffset = instruction.TokenI32; - ExecuteEndTry(endOffset); - break; - } - case OpCode.ENDFINALLY: - { - if (CurrentContext!.TryStack is null) - throw new InvalidOperationException($"The corresponding TRY block cannot be found."); - if (!CurrentContext.TryStack.TryPop(out ExceptionHandlingContext? currentTry)) - throw new InvalidOperationException($"The corresponding TRY block cannot be found."); - - if (UncaughtException is null) - CurrentContext.InstructionPointer = currentTry.EndPointer; - else - HandleException(); - - isJumping = true; - break; - } - case OpCode.RET: - { - ExecutionContext context_pop = InvocationStack.Pop(); - EvaluationStack stack_eval = InvocationStack.Count == 0 ? ResultStack : InvocationStack.Peek().EvaluationStack; - if (context_pop.EvaluationStack != stack_eval) - { - if (context_pop.RVCount >= 0 && context_pop.EvaluationStack.Count != context_pop.RVCount) - throw new InvalidOperationException("RVCount doesn't match with EvaluationStack"); - context_pop.EvaluationStack.CopyTo(stack_eval); - } - if (InvocationStack.Count == 0) - State = VMState.HALT; - ContextUnloaded(context_pop); - isJumping = true; - break; - } - case OpCode.SYSCALL: - { - OnSysCall(instruction.TokenU32); - break; - } - - // Stack ops - case OpCode.DEPTH: - { - Push(CurrentContext!.EvaluationStack.Count); - break; - } - case OpCode.DROP: - { - Pop(); - break; - } - case OpCode.NIP: - { - CurrentContext!.EvaluationStack.Remove(1); - break; - } - case OpCode.XDROP: - { - int n = (int)Pop().GetInteger(); - if (n < 0) - throw new InvalidOperationException($"The negative value {n} is invalid for OpCode.{instruction.OpCode}."); - CurrentContext!.EvaluationStack.Remove(n); - break; - } - case OpCode.CLEAR: - { - CurrentContext!.EvaluationStack.Clear(); - break; - } - case OpCode.DUP: - { - Push(Peek()); - break; - } - case OpCode.OVER: - { - Push(Peek(1)); - break; - } - case OpCode.PICK: - { - int n = (int)Pop().GetInteger(); - if (n < 0) - throw new InvalidOperationException($"The negative value {n} is invalid for OpCode.{instruction.OpCode}."); - Push(Peek(n)); - break; - } - case OpCode.TUCK: - { - CurrentContext!.EvaluationStack.Insert(2, Peek()); - break; - } - case OpCode.SWAP: - { - var x = CurrentContext!.EvaluationStack.Remove(1); - Push(x); - break; - } - case OpCode.ROT: - { - var x = CurrentContext!.EvaluationStack.Remove(2); - Push(x); - break; - } - case OpCode.ROLL: - { - int n = (int)Pop().GetInteger(); - if (n < 0) - throw new InvalidOperationException($"The negative value {n} is invalid for OpCode.{instruction.OpCode}."); - if (n == 0) break; - var x = CurrentContext!.EvaluationStack.Remove(n); - Push(x); - break; - } - case OpCode.REVERSE3: - { - CurrentContext!.EvaluationStack.Reverse(3); - break; - } - case OpCode.REVERSE4: - { - CurrentContext!.EvaluationStack.Reverse(4); - break; - } - case OpCode.REVERSEN: - { - int n = (int)Pop().GetInteger(); - CurrentContext!.EvaluationStack.Reverse(n); - break; - } - - //Slot - case OpCode.INITSSLOT: - { - if (CurrentContext!.StaticFields != null) - throw new InvalidOperationException($"{instruction.OpCode} cannot be executed twice."); - if (instruction.TokenU8 == 0) - throw new InvalidOperationException($"The operand {instruction.TokenU8} is invalid for OpCode.{instruction.OpCode}."); - CurrentContext.StaticFields = new Slot(instruction.TokenU8, ReferenceCounter); - break; - } - case OpCode.INITSLOT: - { - if (CurrentContext!.LocalVariables != null || CurrentContext.Arguments != null) - throw new InvalidOperationException($"{instruction.OpCode} cannot be executed twice."); - if (instruction.TokenU16 == 0) - throw new InvalidOperationException($"The operand {instruction.TokenU16} is invalid for OpCode.{instruction.OpCode}."); - if (instruction.TokenU8 > 0) - { - CurrentContext.LocalVariables = new Slot(instruction.TokenU8, ReferenceCounter); - } - if (instruction.TokenU8_1 > 0) - { - StackItem[] items = new StackItem[instruction.TokenU8_1]; - for (int i = 0; i < instruction.TokenU8_1; i++) - { - items[i] = Pop(); - } - CurrentContext.Arguments = new Slot(items, ReferenceCounter); - } - break; - } - case OpCode.LDSFLD0: - case OpCode.LDSFLD1: - case OpCode.LDSFLD2: - case OpCode.LDSFLD3: - case OpCode.LDSFLD4: - case OpCode.LDSFLD5: - case OpCode.LDSFLD6: - { - ExecuteLoadFromSlot(CurrentContext!.StaticFields, instruction.OpCode - OpCode.LDSFLD0); - break; - } - case OpCode.LDSFLD: - { - ExecuteLoadFromSlot(CurrentContext!.StaticFields, instruction.TokenU8); - break; - } - case OpCode.STSFLD0: - case OpCode.STSFLD1: - case OpCode.STSFLD2: - case OpCode.STSFLD3: - case OpCode.STSFLD4: - case OpCode.STSFLD5: - case OpCode.STSFLD6: - { - ExecuteStoreToSlot(CurrentContext!.StaticFields, instruction.OpCode - OpCode.STSFLD0); - break; - } - case OpCode.STSFLD: - { - ExecuteStoreToSlot(CurrentContext!.StaticFields, instruction.TokenU8); - break; - } - case OpCode.LDLOC0: - case OpCode.LDLOC1: - case OpCode.LDLOC2: - case OpCode.LDLOC3: - case OpCode.LDLOC4: - case OpCode.LDLOC5: - case OpCode.LDLOC6: - { - ExecuteLoadFromSlot(CurrentContext!.LocalVariables, instruction.OpCode - OpCode.LDLOC0); - break; - } - case OpCode.LDLOC: - { - ExecuteLoadFromSlot(CurrentContext!.LocalVariables, instruction.TokenU8); - break; - } - case OpCode.STLOC0: - case OpCode.STLOC1: - case OpCode.STLOC2: - case OpCode.STLOC3: - case OpCode.STLOC4: - case OpCode.STLOC5: - case OpCode.STLOC6: - { - ExecuteStoreToSlot(CurrentContext!.LocalVariables, instruction.OpCode - OpCode.STLOC0); - break; - } - case OpCode.STLOC: - { - ExecuteStoreToSlot(CurrentContext!.LocalVariables, instruction.TokenU8); - break; - } - case OpCode.LDARG0: - case OpCode.LDARG1: - case OpCode.LDARG2: - case OpCode.LDARG3: - case OpCode.LDARG4: - case OpCode.LDARG5: - case OpCode.LDARG6: - { - ExecuteLoadFromSlot(CurrentContext!.Arguments, instruction.OpCode - OpCode.LDARG0); - break; - } - case OpCode.LDARG: - { - ExecuteLoadFromSlot(CurrentContext!.Arguments, instruction.TokenU8); - break; - } - case OpCode.STARG0: - case OpCode.STARG1: - case OpCode.STARG2: - case OpCode.STARG3: - case OpCode.STARG4: - case OpCode.STARG5: - case OpCode.STARG6: - { - ExecuteStoreToSlot(CurrentContext!.Arguments, instruction.OpCode - OpCode.STARG0); - break; - } - case OpCode.STARG: - { - ExecuteStoreToSlot(CurrentContext!.Arguments, instruction.TokenU8); - break; - } - - // Splice - case OpCode.NEWBUFFER: - { - int length = (int)Pop().GetInteger(); - Limits.AssertMaxItemSize(length); - Push(new Buffer(length)); - break; - } - case OpCode.MEMCPY: - { - int count = (int)Pop().GetInteger(); - if (count < 0) - throw new InvalidOperationException($"The value {count} is out of range."); - int si = (int)Pop().GetInteger(); - if (si < 0) - throw new InvalidOperationException($"The value {si} is out of range."); - ReadOnlySpan src = Pop().GetSpan(); - if (checked(si + count) > src.Length) - throw new InvalidOperationException($"The value {count} is out of range."); - int di = (int)Pop().GetInteger(); - if (di < 0) - throw new InvalidOperationException($"The value {di} is out of range."); - Buffer dst = Pop(); - if (checked(di + count) > dst.Size) - throw new InvalidOperationException($"The value {count} is out of range."); - src.Slice(si, count).CopyTo(dst.InnerBuffer.Span[di..]); - break; - } - case OpCode.CAT: - { - var x2 = Pop().GetSpan(); - var x1 = Pop().GetSpan(); - int length = x1.Length + x2.Length; - Limits.AssertMaxItemSize(length); - Buffer result = new(length, false); - x1.CopyTo(result.InnerBuffer.Span); - x2.CopyTo(result.InnerBuffer.Span[x1.Length..]); - Push(result); - break; - } - case OpCode.SUBSTR: - { - int count = (int)Pop().GetInteger(); - if (count < 0) - throw new InvalidOperationException($"The value {count} is out of range."); - int index = (int)Pop().GetInteger(); - if (index < 0) - throw new InvalidOperationException($"The value {index} is out of range."); - var x = Pop().GetSpan(); - if (index + count > x.Length) - throw new InvalidOperationException($"The value {count} is out of range."); - Buffer result = new(count, false); - x.Slice(index, count).CopyTo(result.InnerBuffer.Span); - Push(result); - break; - } - case OpCode.LEFT: - { - int count = (int)Pop().GetInteger(); - if (count < 0) - throw new InvalidOperationException($"The value {count} is out of range."); - var x = Pop().GetSpan(); - if (count > x.Length) - throw new InvalidOperationException($"The value {count} is out of range."); - Buffer result = new(count, false); - x[..count].CopyTo(result.InnerBuffer.Span); - Push(result); - break; - } - case OpCode.RIGHT: - { - int count = (int)Pop().GetInteger(); - if (count < 0) - throw new InvalidOperationException($"The value {count} is out of range."); - var x = Pop().GetSpan(); - if (count > x.Length) - throw new InvalidOperationException($"The value {count} is out of range."); - Buffer result = new(count, false); - x[^count..^0].CopyTo(result.InnerBuffer.Span); - Push(result); - break; - } - - // Bitwise logic - case OpCode.INVERT: - { - var x = Pop().GetInteger(); - Push(~x); - break; - } - case OpCode.AND: - { - var x2 = Pop().GetInteger(); - var x1 = Pop().GetInteger(); - Push(x1 & x2); - break; - } - case OpCode.OR: - { - var x2 = Pop().GetInteger(); - var x1 = Pop().GetInteger(); - Push(x1 | x2); - break; - } - case OpCode.XOR: - { - var x2 = Pop().GetInteger(); - var x1 = Pop().GetInteger(); - Push(x1 ^ x2); - break; - } - case OpCode.EQUAL: - { - StackItem x2 = Pop(); - StackItem x1 = Pop(); - Push(x1.Equals(x2, Limits)); - break; - } - case OpCode.NOTEQUAL: - { - StackItem x2 = Pop(); - StackItem x1 = Pop(); - Push(!x1.Equals(x2, Limits)); - break; - } - - // Numeric - case OpCode.SIGN: - { - var x = Pop().GetInteger(); - Push(x.Sign); - break; - } - case OpCode.ABS: - { - var x = Pop().GetInteger(); - Push(BigInteger.Abs(x)); - break; - } - case OpCode.NEGATE: - { - var x = Pop().GetInteger(); - Push(-x); - break; - } - case OpCode.INC: - { - var x = Pop().GetInteger(); - Push(x + 1); - break; - } - case OpCode.DEC: - { - var x = Pop().GetInteger(); - Push(x - 1); - break; - } - case OpCode.ADD: - { - var x2 = Pop().GetInteger(); - var x1 = Pop().GetInteger(); - Push(x1 + x2); - break; - } - case OpCode.SUB: - { - var x2 = Pop().GetInteger(); - var x1 = Pop().GetInteger(); - Push(x1 - x2); - break; - } - case OpCode.MUL: - { - var x2 = Pop().GetInteger(); - var x1 = Pop().GetInteger(); - Push(x1 * x2); - break; - } - case OpCode.DIV: - { - var x2 = Pop().GetInteger(); - var x1 = Pop().GetInteger(); - Push(x1 / x2); - break; - } - case OpCode.MOD: - { - var x2 = Pop().GetInteger(); - var x1 = Pop().GetInteger(); - Push(x1 % x2); - break; - } - case OpCode.POW: - { - var exponent = (int)Pop().GetInteger(); - Limits.AssertShift(exponent); - var value = Pop().GetInteger(); - Push(BigInteger.Pow(value, exponent)); - break; - } - case OpCode.SQRT: - { - Push(Pop().GetInteger().Sqrt()); - break; - } - case OpCode.MODMUL: - { - var modulus = Pop().GetInteger(); - var x2 = Pop().GetInteger(); - var x1 = Pop().GetInteger(); - Push(x1 * x2 % modulus); - break; - } - case OpCode.MODPOW: - { - var modulus = Pop().GetInteger(); - var exponent = Pop().GetInteger(); - var value = Pop().GetInteger(); - var result = exponent == -1 - ? value.ModInverse(modulus) - : BigInteger.ModPow(value, exponent, modulus); - Push(result); - break; - } - case OpCode.SHL: - { - int shift = (int)Pop().GetInteger(); - Limits.AssertShift(shift); - if (shift == 0) break; - var x = Pop().GetInteger(); - Push(x << shift); - break; - } - case OpCode.SHR: - { - int shift = (int)Pop().GetInteger(); - Limits.AssertShift(shift); - if (shift == 0) break; - var x = Pop().GetInteger(); - Push(x >> shift); - break; - } - case OpCode.NOT: - { - var x = Pop().GetBoolean(); - Push(!x); - break; - } - case OpCode.BOOLAND: - { - var x2 = Pop().GetBoolean(); - var x1 = Pop().GetBoolean(); - Push(x1 && x2); - break; - } - case OpCode.BOOLOR: - { - var x2 = Pop().GetBoolean(); - var x1 = Pop().GetBoolean(); - Push(x1 || x2); - break; - } - case OpCode.NZ: - { - var x = Pop().GetInteger(); - Push(!x.IsZero); - break; - } - case OpCode.NUMEQUAL: - { - var x2 = Pop().GetInteger(); - var x1 = Pop().GetInteger(); - Push(x1 == x2); - break; - } - case OpCode.NUMNOTEQUAL: - { - var x2 = Pop().GetInteger(); - var x1 = Pop().GetInteger(); - Push(x1 != x2); - break; - } - case OpCode.LT: - { - var x2 = Pop(); - var x1 = Pop(); - if (x1.IsNull || x2.IsNull) - Push(false); - else - Push(x1.GetInteger() < x2.GetInteger()); - break; - } - case OpCode.LE: - { - var x2 = Pop(); - var x1 = Pop(); - if (x1.IsNull || x2.IsNull) - Push(false); - else - Push(x1.GetInteger() <= x2.GetInteger()); - break; - } - case OpCode.GT: - { - var x2 = Pop(); - var x1 = Pop(); - if (x1.IsNull || x2.IsNull) - Push(false); - else - Push(x1.GetInteger() > x2.GetInteger()); - break; - } - case OpCode.GE: - { - var x2 = Pop(); - var x1 = Pop(); - if (x1.IsNull || x2.IsNull) - Push(false); - else - Push(x1.GetInteger() >= x2.GetInteger()); - break; - } - case OpCode.MIN: - { - var x2 = Pop().GetInteger(); - var x1 = Pop().GetInteger(); - Push(BigInteger.Min(x1, x2)); - break; - } - case OpCode.MAX: - { - var x2 = Pop().GetInteger(); - var x1 = Pop().GetInteger(); - Push(BigInteger.Max(x1, x2)); - break; - } - case OpCode.WITHIN: - { - BigInteger b = Pop().GetInteger(); - BigInteger a = Pop().GetInteger(); - var x = Pop().GetInteger(); - Push(a <= x && x < b); - break; - } - - // Compound-type - case OpCode.PACKMAP: - { - int size = (int)Pop().GetInteger(); - if (size < 0 || size * 2 > CurrentContext!.EvaluationStack.Count) - throw new InvalidOperationException($"The value {size} is out of range."); - Map map = new(ReferenceCounter); - for (int i = 0; i < size; i++) - { - PrimitiveType key = Pop(); - StackItem value = Pop(); - map[key] = value; - } - Push(map); - break; - } - case OpCode.PACKSTRUCT: - { - int size = (int)Pop().GetInteger(); - if (size < 0 || size > CurrentContext!.EvaluationStack.Count) - throw new InvalidOperationException($"The value {size} is out of range."); - Struct @struct = new(ReferenceCounter); - for (int i = 0; i < size; i++) - { - StackItem item = Pop(); - @struct.Add(item); - } - Push(@struct); - break; - } - case OpCode.PACK: - { - int size = (int)Pop().GetInteger(); - if (size < 0 || size > CurrentContext!.EvaluationStack.Count) - throw new InvalidOperationException($"The value {size} is out of range."); - VMArray array = new(ReferenceCounter); - for (int i = 0; i < size; i++) - { - StackItem item = Pop(); - array.Add(item); - } - Push(array); - break; - } - case OpCode.UNPACK: - { - CompoundType compound = Pop(); - switch (compound) - { - case Map map: - foreach (var (key, value) in map.Reverse()) - { - Push(value); - Push(key); - } - break; - case VMArray array: - for (int i = array.Count - 1; i >= 0; i--) - { - Push(array[i]); - } - break; - default: - throw new InvalidOperationException($"Invalid type for {instruction.OpCode}: {compound.Type}"); - } - Push(compound.Count); - break; - } - case OpCode.NEWARRAY0: - { - Push(new VMArray(ReferenceCounter)); - break; - } - case OpCode.NEWARRAY: - case OpCode.NEWARRAY_T: - { - int n = (int)Pop().GetInteger(); - if (n < 0 || n > Limits.MaxStackSize) - throw new InvalidOperationException($"MaxStackSize exceed: {n}"); - StackItem item; - if (instruction.OpCode == OpCode.NEWARRAY_T) - { - StackItemType type = (StackItemType)instruction.TokenU8; - if (!Enum.IsDefined(typeof(StackItemType), type)) - throw new InvalidOperationException($"Invalid type for {instruction.OpCode}: {instruction.TokenU8}"); - item = instruction.TokenU8 switch - { - (byte)StackItemType.Boolean => StackItem.False, - (byte)StackItemType.Integer => Integer.Zero, - (byte)StackItemType.ByteString => ByteString.Empty, - _ => StackItem.Null - }; - } - else - { - item = StackItem.Null; - } - Push(new VMArray(ReferenceCounter, Enumerable.Repeat(item, n))); - break; - } - case OpCode.NEWSTRUCT0: - { - Push(new Struct(ReferenceCounter)); - break; - } - case OpCode.NEWSTRUCT: - { - int n = (int)Pop().GetInteger(); - if (n < 0 || n > Limits.MaxStackSize) - throw new InvalidOperationException($"MaxStackSize exceed: {n}"); - Struct result = new(ReferenceCounter); - for (var i = 0; i < n; i++) - result.Add(StackItem.Null); - Push(result); - break; - } - case OpCode.NEWMAP: - { - Push(new Map(ReferenceCounter)); - break; - } - case OpCode.SIZE: - { - var x = Pop(); - switch (x) - { - case CompoundType compound: - Push(compound.Count); - break; - case PrimitiveType primitive: - Push(primitive.Size); - break; - case Buffer buffer: - Push(buffer.Size); - break; - default: - throw new InvalidOperationException($"Invalid type for {instruction.OpCode}: {x.Type}"); - } - break; - } - case OpCode.HASKEY: - { - PrimitiveType key = Pop(); - var x = Pop(); - switch (x) - { - case VMArray array: - { - int index = (int)key.GetInteger(); - if (index < 0) - throw new InvalidOperationException($"The negative value {index} is invalid for OpCode.{instruction.OpCode}."); - Push(index < array.Count); - break; - } - case Map map: - { - Push(map.ContainsKey(key)); - break; - } - case Buffer buffer: - { - int index = (int)key.GetInteger(); - if (index < 0) - throw new InvalidOperationException($"The negative value {index} is invalid for OpCode.{instruction.OpCode}."); - Push(index < buffer.Size); - break; - } - case ByteString array: - { - int index = (int)key.GetInteger(); - if (index < 0) - throw new InvalidOperationException($"The negative value {index} is invalid for OpCode.{instruction.OpCode}."); - Push(index < array.Size); - break; - } - default: - throw new InvalidOperationException($"Invalid type for {instruction.OpCode}: {x.Type}"); - } - break; - } - case OpCode.KEYS: - { - Map map = Pop(); - Push(new VMArray(ReferenceCounter, map.Keys)); - break; - } - case OpCode.VALUES: - { - var x = Pop(); - IEnumerable values = x switch - { - VMArray array => array, - Map map => map.Values, - _ => throw new InvalidOperationException($"Invalid type for {instruction.OpCode}: {x.Type}"), - }; - VMArray newArray = new(ReferenceCounter); - foreach (StackItem item in values) - if (item is Struct s) - newArray.Add(s.Clone(Limits)); - else - newArray.Add(item); - Push(newArray); - break; - } - case OpCode.PICKITEM: - { - PrimitiveType key = Pop(); - var x = Pop(); - switch (x) - { - case VMArray array: - { - int index = (int)key.GetInteger(); - if (index < 0 || index >= array.Count) - throw new CatchableException($"The value {index} is out of range."); - Push(array[index]); - break; - } - case Map map: - { - if (!map.TryGetValue(key, out StackItem? value)) - throw new CatchableException($"Key not found in {nameof(Map)}"); - Push(value); - break; - } - case PrimitiveType primitive: - { - ReadOnlySpan byteArray = primitive.GetSpan(); - int index = (int)key.GetInteger(); - if (index < 0 || index >= byteArray.Length) - throw new CatchableException($"The value {index} is out of range."); - Push((BigInteger)byteArray[index]); - break; - } - case Buffer buffer: - { - int index = (int)key.GetInteger(); - if (index < 0 || index >= buffer.Size) - throw new CatchableException($"The value {index} is out of range."); - Push((BigInteger)buffer.InnerBuffer.Span[index]); - break; - } - default: - throw new InvalidOperationException($"Invalid type for {instruction.OpCode}: {x.Type}"); - } - break; - } - case OpCode.APPEND: - { - StackItem newItem = Pop(); - VMArray array = Pop(); - if (newItem is Struct s) newItem = s.Clone(Limits); - array.Add(newItem); - break; - } - case OpCode.SETITEM: - { - StackItem value = Pop(); - if (value is Struct s) value = s.Clone(Limits); - PrimitiveType key = Pop(); - var x = Pop(); - switch (x) - { - case VMArray array: - { - int index = (int)key.GetInteger(); - if (index < 0 || index >= array.Count) - throw new CatchableException($"The value {index} is out of range."); - array[index] = value; - break; - } - case Map map: - { - map[key] = value; - break; - } - case Buffer buffer: - { - int index = (int)key.GetInteger(); - if (index < 0 || index >= buffer.Size) - throw new CatchableException($"The value {index} is out of range."); - if (value is not PrimitiveType p) - throw new InvalidOperationException($"Value must be a primitive type in {instruction.OpCode}"); - int b = (int)p.GetInteger(); - if (b < sbyte.MinValue || b > byte.MaxValue) - throw new InvalidOperationException($"Overflow in {instruction.OpCode}, {b} is not a byte type."); - buffer.InnerBuffer.Span[index] = (byte)b; - break; - } - default: - throw new InvalidOperationException($"Invalid type for {instruction.OpCode}: {x.Type}"); - } - break; - } - case OpCode.REVERSEITEMS: - { - var x = Pop(); - switch (x) - { - case VMArray array: - array.Reverse(); - break; - case Buffer buffer: - buffer.InnerBuffer.Span.Reverse(); - break; - default: - throw new InvalidOperationException($"Invalid type for {instruction.OpCode}: {x.Type}"); - } - break; - } - case OpCode.REMOVE: - { - PrimitiveType key = Pop(); - var x = Pop(); - switch (x) - { - case VMArray array: - int index = (int)key.GetInteger(); - if (index < 0 || index >= array.Count) - throw new InvalidOperationException($"The value {index} is out of range."); - array.RemoveAt(index); - break; - case Map map: - map.Remove(key); - break; - default: - throw new InvalidOperationException($"Invalid type for {instruction.OpCode}: {x.Type}"); - } - break; - } - case OpCode.CLEARITEMS: - { - CompoundType x = Pop(); - x.Clear(); - break; - } - case OpCode.POPITEM: - { - VMArray x = Pop(); - int index = x.Count - 1; - Push(x[index]); - x.RemoveAt(index); - break; - } - - //Types - case OpCode.ISNULL: - { - var x = Pop(); - Push(x.IsNull); - break; - } - case OpCode.ISTYPE: - { - var x = Pop(); - StackItemType type = (StackItemType)instruction.TokenU8; - if (type == StackItemType.Any || !Enum.IsDefined(typeof(StackItemType), type)) - throw new InvalidOperationException($"Invalid type: {type}"); - Push(x.Type == type); - break; - } - case OpCode.CONVERT: - { - var x = Pop(); - Push(x.ConvertTo((StackItemType)instruction.TokenU8)); - break; - } - case OpCode.ABORTMSG: - { - var msg = Pop().GetString(); - throw new Exception($"{OpCode.ABORTMSG} is executed. Reason: {msg}"); - } - case OpCode.ASSERTMSG: - { - var msg = Pop().GetString(); - var x = Pop().GetBoolean(); - if (!x) - throw new Exception($"{OpCode.ASSERTMSG} is executed with false result. Reason: {msg}"); - break; - } - default: throw new InvalidOperationException($"Opcode {instruction.OpCode} is undefined."); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void ExecuteEndTry(int endOffset) - { - if (CurrentContext!.TryStack is null) - throw new InvalidOperationException($"The corresponding TRY block cannot be found."); - if (!CurrentContext.TryStack.TryPeek(out ExceptionHandlingContext? currentTry)) - throw new InvalidOperationException($"The corresponding TRY block cannot be found."); - if (currentTry.State == ExceptionHandlingState.Finally) - throw new InvalidOperationException($"The opcode {OpCode.ENDTRY} can't be executed in a FINALLY block."); - - int endPointer = checked(CurrentContext.InstructionPointer + endOffset); - if (currentTry.HasFinally) - { - currentTry.State = ExceptionHandlingState.Finally; - currentTry.EndPointer = endPointer; - CurrentContext.InstructionPointer = currentTry.FinallyPointer; - } - else - { - CurrentContext.TryStack.Pop(); - CurrentContext.InstructionPointer = endPointer; - } - isJumping = true; - } - - /// - /// Jump to the specified position. - /// - /// The position to jump to. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - protected void ExecuteJump(int position) - { - if (position < 0 || position >= CurrentContext!.Script.Length) - throw new ArgumentOutOfRangeException($"Jump out of range for position: {position}"); - CurrentContext.InstructionPointer = position; - isJumping = true; - } - - /// - /// Jump to the specified offset from the current position. - /// - /// The offset from the current position to jump to. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - protected void ExecuteJumpOffset(int offset) - { - ExecuteJump(checked(CurrentContext!.InstructionPointer + offset)); - } - - private void ExecuteLoadFromSlot(Slot? slot, int index) - { - if (slot is null) - throw new InvalidOperationException("Slot has not been initialized."); - if (index < 0 || index >= slot.Count) - throw new InvalidOperationException($"Index out of range when loading from slot: {index}"); - Push(slot[index]); - } - /// /// Execute the next instruction. /// @@ -1474,11 +137,11 @@ protected internal void ExecuteNext() PreExecuteInstruction(instruction); try { - ExecuteInstruction(instruction); + JumpTable[instruction.OpCode](this, instruction); } catch (CatchableException ex) when (Limits.CatchEngineExceptions) { - ExecuteThrow(ex.Message); + JumpTable.ExecuteThrow(this, ex.Message); } PostExecuteInstruction(instruction); if (!isJumping) context.MoveNext(); @@ -1491,84 +154,11 @@ protected internal void ExecuteNext() } } - private void ExecuteStoreToSlot(Slot? slot, int index) - { - if (slot is null) - throw new InvalidOperationException("Slot has not been initialized."); - if (index < 0 || index >= slot.Count) - throw new InvalidOperationException($"Index out of range when storing to slot: {index}"); - slot[index] = Pop(); - } - - /// - /// Throws a specified exception in the VM. - /// - /// The exception to be thrown. - protected void ExecuteThrow(StackItem ex) - { - UncaughtException = ex; - HandleException(); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void ExecuteTry(int catchOffset, int finallyOffset) - { - if (catchOffset == 0 && finallyOffset == 0) - throw new InvalidOperationException($"catchOffset and finallyOffset can't be 0 in a TRY block"); - if (CurrentContext!.TryStack is null) - CurrentContext.TryStack = new Stack(); - else if (CurrentContext.TryStack.Count >= Limits.MaxTryNestingDepth) - throw new InvalidOperationException("MaxTryNestingDepth exceed."); - int catchPointer = catchOffset == 0 ? -1 : checked(CurrentContext.InstructionPointer + catchOffset); - int finallyPointer = finallyOffset == 0 ? -1 : checked(CurrentContext.InstructionPointer + finallyOffset); - CurrentContext.TryStack.Push(new ExceptionHandlingContext(catchPointer, finallyPointer)); - } - - private void HandleException() - { - int pop = 0; - foreach (var executionContext in InvocationStack) - { - if (executionContext.TryStack != null) - { - while (executionContext.TryStack.TryPeek(out var tryContext)) - { - if (tryContext.State == ExceptionHandlingState.Finally || (tryContext.State == ExceptionHandlingState.Catch && !tryContext.HasFinally)) - { - executionContext.TryStack.Pop(); - continue; - } - for (int i = 0; i < pop; i++) - { - ContextUnloaded(InvocationStack.Pop()); - } - if (tryContext.State == ExceptionHandlingState.Try && tryContext.HasCatch) - { - tryContext.State = ExceptionHandlingState.Catch; - Push(UncaughtException!); - executionContext.InstructionPointer = tryContext.CatchPointer; - UncaughtException = null; - } - else - { - tryContext.State = ExceptionHandlingState.Finally; - executionContext.InstructionPointer = tryContext.FinallyPointer; - } - isJumping = true; - return; - } - } - ++pop; - } - - throw new VMUnhandledException(UncaughtException!); - } - /// /// Loads the specified context into the invocation stack. /// /// The context to load. - protected virtual void LoadContext(ExecutionContext context) + internal virtual void LoadContext(ExecutionContext context) { if (InvocationStack.Count >= Limits.MaxInvocationStackSize) throw new InvalidOperationException($"MaxInvocationStackSize exceed: {InvocationStack.Count}"); @@ -1577,6 +167,29 @@ protected virtual void LoadContext(ExecutionContext context) CurrentContext = context; } + /// + /// Called when a context is unloaded. + /// + /// The context being unloaded. + internal virtual void UnloadContext(ExecutionContext context) + { + if (InvocationStack.Count == 0) + { + CurrentContext = null; + EntryContext = null; + } + else + { + CurrentContext = InvocationStack.Peek(); + } + if (context.StaticFields != null && context.StaticFields != CurrentContext?.StaticFields) + { + context.StaticFields.ClearReferences(); + } + context.LocalVariables?.ClearReferences(); + context.Arguments?.ClearReferences(); + } + /// /// Create a new context with the specified script without loading. /// @@ -1607,17 +220,6 @@ public ExecutionContext LoadScript(Script script, int rvcount = -1, int initialP return context; } - /// - /// When overridden in a derived class, loads the specified method token. - /// Called when is executed. - /// - /// The method token to be loaded. - /// The created context. - protected virtual ExecutionContext LoadToken(ushort token) - { - throw new InvalidOperationException($"Token not found: {token}"); - } - /// /// Called when an exception that cannot be caught by the VM is thrown. /// @@ -1634,16 +236,6 @@ protected virtual void OnStateChanged() { } - /// - /// When overridden in a derived class, invokes the specified system call. - /// Called when is executed. - /// - /// The system call to be invoked. - protected virtual void OnSysCall(uint method) - { - throw new InvalidOperationException($"Syscall not found: {method}"); - } - /// /// Returns the item at the specified index from the top of the current stack without removing it. /// diff --git a/src/Neo.VM/JumpTable/JumpTable.Bitwisee.cs b/src/Neo.VM/JumpTable/JumpTable.Bitwisee.cs new file mode 100644 index 0000000000..65a8e490d1 --- /dev/null +++ b/src/Neo.VM/JumpTable/JumpTable.Bitwisee.cs @@ -0,0 +1,65 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// JumpTable.Bitwisee.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.Runtime.CompilerServices; + +namespace Neo.VM +{ + public partial class JumpTable + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Invert(ExecutionEngine engine, Instruction instruction) + { + var x = engine.Pop().GetInteger(); + engine.Push(~x); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void And(ExecutionEngine engine, Instruction instruction) + { + var x2 = engine.Pop().GetInteger(); + var x1 = engine.Pop().GetInteger(); + engine.Push(x1 & x2); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Or(ExecutionEngine engine, Instruction instruction) + { + var x2 = engine.Pop().GetInteger(); + var x1 = engine.Pop().GetInteger(); + engine.Push(x1 | x2); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void XOr(ExecutionEngine engine, Instruction instruction) + { + var x2 = engine.Pop().GetInteger(); + var x1 = engine.Pop().GetInteger(); + engine.Push(x1 ^ x2); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Equal(ExecutionEngine engine, Instruction instruction) + { + var x2 = engine.Pop(); + var x1 = engine.Pop(); + engine.Push(x1.Equals(x2, engine.Limits)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void NotEqual(ExecutionEngine engine, Instruction instruction) + { + var x2 = engine.Pop(); + var x1 = engine.Pop(); + engine.Push(!x1.Equals(x2, engine.Limits)); + } + } +} diff --git a/src/Neo.VM/JumpTable/JumpTable.Compound.cs b/src/Neo.VM/JumpTable/JumpTable.Compound.cs new file mode 100644 index 0000000000..916caf02b8 --- /dev/null +++ b/src/Neo.VM/JumpTable/JumpTable.Compound.cs @@ -0,0 +1,390 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// JumpTable.Compound.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; +using System.Linq; +using System.Numerics; +using System.Runtime.CompilerServices; +using VMArray = Neo.VM.Types.Array; + +namespace Neo.VM +{ + public partial class JumpTable + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void PackMap(ExecutionEngine engine, Instruction instruction) + { + var size = (int)engine.Pop().GetInteger(); + if (size < 0 || size * 2 > engine.CurrentContext!.EvaluationStack.Count) + throw new InvalidOperationException($"The value {size} is out of range."); + Map map = new(engine.ReferenceCounter); + for (var i = 0; i < size; i++) + { + var key = engine.Pop(); + var value = engine.Pop(); + map[key] = value; + } + engine.Push(map); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void PackStruct(ExecutionEngine engine, Instruction instruction) + { + var size = (int)engine.Pop().GetInteger(); + if (size < 0 || size > engine.CurrentContext!.EvaluationStack.Count) + throw new InvalidOperationException($"The value {size} is out of range."); + Struct @struct = new(engine.ReferenceCounter); + for (var i = 0; i < size; i++) + { + var item = engine.Pop(); + @struct.Add(item); + } + engine.Push(@struct); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Pack(ExecutionEngine engine, Instruction instruction) + { + var size = (int)engine.Pop().GetInteger(); + if (size < 0 || size > engine.CurrentContext!.EvaluationStack.Count) + throw new InvalidOperationException($"The value {size} is out of range."); + VMArray array = new(engine.ReferenceCounter); + for (var i = 0; i < size; i++) + { + var item = engine.Pop(); + array.Add(item); + } + engine.Push(array); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Unpack(ExecutionEngine engine, Instruction instruction) + { + var compound = engine.Pop(); + switch (compound) + { + case Map map: + foreach (var (key, value) in map.Reverse()) + { + engine.Push(value); + engine.Push(key); + } + break; + case VMArray array: + for (var i = array.Count - 1; i >= 0; i--) + { + engine.Push(array[i]); + } + break; + default: + throw new InvalidOperationException($"Invalid type for {instruction.OpCode}: {compound.Type}"); + } + engine.Push(compound.Count); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void NewArray0(ExecutionEngine engine, Instruction instruction) + { + engine.Push(new VMArray(engine.ReferenceCounter)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void NewArray(ExecutionEngine engine, Instruction instruction) + { + var n = (int)engine.Pop().GetInteger(); + if (n < 0 || n > engine.Limits.MaxStackSize) + throw new InvalidOperationException($"MaxStackSize exceed: {n}"); + + engine.Push(new VMArray(engine.ReferenceCounter, Enumerable.Repeat(StackItem.Null, n))); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void NewArray_T(ExecutionEngine engine, Instruction instruction) + { + var n = (int)engine.Pop().GetInteger(); + if (n < 0 || n > engine.Limits.MaxStackSize) + throw new InvalidOperationException($"MaxStackSize exceed: {n}"); + + var type = (StackItemType)instruction.TokenU8; + if (!Enum.IsDefined(typeof(StackItemType), type)) + throw new InvalidOperationException($"Invalid type for {instruction.OpCode}: {instruction.TokenU8}"); + + var item = instruction.TokenU8 switch + { + (byte)StackItemType.Boolean => StackItem.False, + (byte)StackItemType.Integer => Integer.Zero, + (byte)StackItemType.ByteString => ByteString.Empty, + _ => StackItem.Null + }; + + engine.Push(new VMArray(engine.ReferenceCounter, Enumerable.Repeat(item, n))); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void NewStruct0(ExecutionEngine engine, Instruction instruction) + { + engine.Push(new Struct(engine.ReferenceCounter)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void NewStruct(ExecutionEngine engine, Instruction instruction) + { + var n = (int)engine.Pop().GetInteger(); + if (n < 0 || n > engine.Limits.MaxStackSize) + throw new InvalidOperationException($"MaxStackSize exceed: {n}"); + Struct result = new(engine.ReferenceCounter); + for (var i = 0; i < n; i++) + result.Add(StackItem.Null); + engine.Push(result); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void NewMap(ExecutionEngine engine, Instruction instruction) + { + engine.Push(new Map(engine.ReferenceCounter)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Size(ExecutionEngine engine, Instruction instruction) + { + var x = engine.Pop(); + switch (x) + { + case CompoundType compound: + engine.Push(compound.Count); + break; + case PrimitiveType primitive: + engine.Push(primitive.Size); + break; + case Types.Buffer buffer: + engine.Push(buffer.Size); + break; + default: + throw new InvalidOperationException($"Invalid type for {instruction.OpCode}: {x.Type}"); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void HasKey(ExecutionEngine engine, Instruction instruction) + { + var key = engine.Pop(); + var x = engine.Pop(); + switch (x) + { + case VMArray array: + { + var index = (int)key.GetInteger(); + if (index < 0) + throw new InvalidOperationException($"The negative value {index} is invalid for OpCode.{instruction.OpCode}."); + engine.Push(index < array.Count); + break; + } + case Map map: + { + engine.Push(map.ContainsKey(key)); + break; + } + case Types.Buffer buffer: + { + var index = (int)key.GetInteger(); + if (index < 0) + throw new InvalidOperationException($"The negative value {index} is invalid for OpCode.{instruction.OpCode}."); + engine.Push(index < buffer.Size); + break; + } + case ByteString array: + { + var index = (int)key.GetInteger(); + if (index < 0) + throw new InvalidOperationException($"The negative value {index} is invalid for OpCode.{instruction.OpCode}."); + engine.Push(index < array.Size); + break; + } + default: + throw new InvalidOperationException($"Invalid type for {instruction.OpCode}: {x.Type}"); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Keys(ExecutionEngine engine, Instruction instruction) + { + var map = engine.Pop(); + engine.Push(new VMArray(engine.ReferenceCounter, map.Keys)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Values(ExecutionEngine engine, Instruction instruction) + { + var x = engine.Pop(); + var values = x switch + { + VMArray array => array, + Map map => map.Values, + _ => throw new InvalidOperationException($"Invalid type for {instruction.OpCode}: {x.Type}"), + }; + VMArray newArray = new(engine.ReferenceCounter); + foreach (var item in values) + if (item is Struct s) + newArray.Add(s.Clone(engine.Limits)); + else + newArray.Add(item); + engine.Push(newArray); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void PickItem(ExecutionEngine engine, Instruction instruction) + { + var key = engine.Pop(); + var x = engine.Pop(); + switch (x) + { + case VMArray array: + { + var index = (int)key.GetInteger(); + if (index < 0 || index >= array.Count) + throw new CatchableException($"The value {index} is out of range."); + engine.Push(array[index]); + break; + } + case Map map: + { + if (!map.TryGetValue(key, out var value)) + throw new CatchableException($"Key not found in {nameof(Map)}"); + engine.Push(value); + break; + } + case PrimitiveType primitive: + { + var byteArray = primitive.GetSpan(); + var index = (int)key.GetInteger(); + if (index < 0 || index >= byteArray.Length) + throw new CatchableException($"The value {index} is out of range."); + engine.Push((BigInteger)byteArray[index]); + break; + } + case Types.Buffer buffer: + { + var index = (int)key.GetInteger(); + if (index < 0 || index >= buffer.Size) + throw new CatchableException($"The value {index} is out of range."); + engine.Push((BigInteger)buffer.InnerBuffer.Span[index]); + break; + } + default: + throw new InvalidOperationException($"Invalid type for {instruction.OpCode}: {x.Type}"); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Append(ExecutionEngine engine, Instruction instruction) + { + var newItem = engine.Pop(); + var array = engine.Pop(); + if (newItem is Struct s) newItem = s.Clone(engine.Limits); + array.Add(newItem); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void SetItem(ExecutionEngine engine, Instruction instruction) + { + var value = engine.Pop(); + if (value is Struct s) value = s.Clone(engine.Limits); + var key = engine.Pop(); + var x = engine.Pop(); + switch (x) + { + case VMArray array: + { + var index = (int)key.GetInteger(); + if (index < 0 || index >= array.Count) + throw new CatchableException($"The value {index} is out of range."); + array[index] = value; + break; + } + case Map map: + { + map[key] = value; + break; + } + case Types.Buffer buffer: + { + var index = (int)key.GetInteger(); + if (index < 0 || index >= buffer.Size) + throw new CatchableException($"The value {index} is out of range."); + if (value is not PrimitiveType p) + throw new InvalidOperationException($"Value must be a primitive type in {instruction.OpCode}"); + var b = (int)p.GetInteger(); + if (b < sbyte.MinValue || b > byte.MaxValue) + throw new InvalidOperationException($"Overflow in {instruction.OpCode}, {b} is not a byte type."); + buffer.InnerBuffer.Span[index] = (byte)b; + break; + } + default: + throw new InvalidOperationException($"Invalid type for {instruction.OpCode}: {x.Type}"); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void ReverseItems(ExecutionEngine engine, Instruction instruction) + { + var x = engine.Pop(); + switch (x) + { + case VMArray array: + array.Reverse(); + break; + case Types.Buffer buffer: + buffer.InnerBuffer.Span.Reverse(); + break; + default: + throw new InvalidOperationException($"Invalid type for {instruction.OpCode}: {x.Type}"); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Remove(ExecutionEngine engine, Instruction instruction) + { + var key = engine.Pop(); + var x = engine.Pop(); + switch (x) + { + case VMArray array: + var index = (int)key.GetInteger(); + if (index < 0 || index >= array.Count) + throw new InvalidOperationException($"The value {index} is out of range."); + array.RemoveAt(index); + break; + case Map map: + map.Remove(key); + break; + default: + throw new InvalidOperationException($"Invalid type for {instruction.OpCode}: {x.Type}"); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void ClearItems(ExecutionEngine engine, Instruction instruction) + { + var x = engine.Pop(); + x.Clear(); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void PopItem(ExecutionEngine engine, Instruction instruction) + { + var x = engine.Pop(); + var index = x.Count - 1; + engine.Push(x[index]); + x.RemoveAt(index); + } + } +} diff --git a/src/Neo.VM/JumpTable/JumpTable.Control.cs b/src/Neo.VM/JumpTable/JumpTable.Control.cs new file mode 100644 index 0000000000..2415f1e614 --- /dev/null +++ b/src/Neo.VM/JumpTable/JumpTable.Control.cs @@ -0,0 +1,396 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// JumpTable.Control.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; +using System.Collections.Generic; +using System.Runtime.CompilerServices; + +namespace Neo.VM +{ + public partial class JumpTable + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Nop(ExecutionEngine engine, Instruction instruction) + { + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Jmp(ExecutionEngine engine, Instruction instruction) + { + ExecuteJumpOffset(engine, instruction.TokenI8); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Jmp_L(ExecutionEngine engine, Instruction instruction) + { + ExecuteJumpOffset(engine, instruction.TokenI32); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void JmpIf(ExecutionEngine engine, Instruction instruction) + { + if (engine.Pop().GetBoolean()) + ExecuteJumpOffset(engine, instruction.TokenI8); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void JmpIf_L(ExecutionEngine engine, Instruction instruction) + { + if (engine.Pop().GetBoolean()) + ExecuteJumpOffset(engine, instruction.TokenI32); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void JmpIfNot(ExecutionEngine engine, Instruction instruction) + { + if (!engine.Pop().GetBoolean()) + ExecuteJumpOffset(engine, instruction.TokenI8); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void JmpIfNot_L(ExecutionEngine engine, Instruction instruction) + { + if (!engine.Pop().GetBoolean()) + ExecuteJumpOffset(engine, instruction.TokenI32); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void JmpEq(ExecutionEngine engine, Instruction instruction) + { + var x2 = engine.Pop().GetInteger(); + var x1 = engine.Pop().GetInteger(); + if (x1 == x2) + ExecuteJumpOffset(engine, instruction.TokenI8); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void JmpEq_L(ExecutionEngine engine, Instruction instruction) + { + var x2 = engine.Pop().GetInteger(); + var x1 = engine.Pop().GetInteger(); + if (x1 == x2) + ExecuteJumpOffset(engine, instruction.TokenI32); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void JmpNe(ExecutionEngine engine, Instruction instruction) + { + var x2 = engine.Pop().GetInteger(); + var x1 = engine.Pop().GetInteger(); + if (x1 != x2) + ExecuteJumpOffset(engine, instruction.TokenI8); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void JmpNe_L(ExecutionEngine engine, Instruction instruction) + { + var x2 = engine.Pop().GetInteger(); + var x1 = engine.Pop().GetInteger(); + if (x1 != x2) + ExecuteJumpOffset(engine, instruction.TokenI32); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void JmpGt(ExecutionEngine engine, Instruction instruction) + { + var x2 = engine.Pop().GetInteger(); + var x1 = engine.Pop().GetInteger(); + if (x1 > x2) + ExecuteJumpOffset(engine, instruction.TokenI8); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void JmpGt_L(ExecutionEngine engine, Instruction instruction) + { + var x2 = engine.Pop().GetInteger(); + var x1 = engine.Pop().GetInteger(); + if (x1 > x2) + ExecuteJumpOffset(engine, instruction.TokenI32); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void JmpGe(ExecutionEngine engine, Instruction instruction) + { + var x2 = engine.Pop().GetInteger(); + var x1 = engine.Pop().GetInteger(); + if (x1 >= x2) + ExecuteJumpOffset(engine, instruction.TokenI8); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void JmpGe_L(ExecutionEngine engine, Instruction instruction) + { + var x2 = engine.Pop().GetInteger(); + var x1 = engine.Pop().GetInteger(); + if (x1 >= x2) + ExecuteJumpOffset(engine, instruction.TokenI32); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void JmpLt(ExecutionEngine engine, Instruction instruction) + { + var x2 = engine.Pop().GetInteger(); + var x1 = engine.Pop().GetInteger(); + if (x1 < x2) + ExecuteJumpOffset(engine, instruction.TokenI8); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void JmpLt_L(ExecutionEngine engine, Instruction instruction) + { + var x2 = engine.Pop().GetInteger(); + var x1 = engine.Pop().GetInteger(); + if (x1 < x2) + ExecuteJumpOffset(engine, instruction.TokenI32); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void JmpLe(ExecutionEngine engine, Instruction instruction) + { + var x2 = engine.Pop().GetInteger(); + var x1 = engine.Pop().GetInteger(); + if (x1 <= x2) + ExecuteJumpOffset(engine, instruction.TokenI8); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void JMPLE_L(ExecutionEngine engine, Instruction instruction) + { + var x2 = engine.Pop().GetInteger(); + var x1 = engine.Pop().GetInteger(); + if (x1 <= x2) + ExecuteJumpOffset(engine, instruction.TokenI32); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Call(ExecutionEngine engine, Instruction instruction) + { + ExecuteCall(engine, checked(engine.CurrentContext!.InstructionPointer + instruction.TokenI8)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Call_L(ExecutionEngine engine, Instruction instruction) + { + ExecuteCall(engine, checked(engine.CurrentContext!.InstructionPointer + instruction.TokenI32)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void CallA(ExecutionEngine engine, Instruction instruction) + { + var x = engine.Pop(); + if (x.Script != engine.CurrentContext!.Script) + throw new InvalidOperationException("Pointers can't be shared between scripts"); + ExecuteCall(engine, x.Position); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void CallT(ExecutionEngine engine, Instruction instruction) + { + throw new InvalidOperationException($"Token not found: {instruction.TokenU16}"); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Abort(ExecutionEngine engine, Instruction instruction) + { + throw new Exception($"{OpCode.ABORT} is executed."); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Assert(ExecutionEngine engine, Instruction instruction) + { + var x = engine.Pop().GetBoolean(); + if (!x) + throw new Exception($"{OpCode.ASSERT} is executed with false result."); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Throw(ExecutionEngine engine, Instruction instruction) + { + ExecuteThrow(engine, engine.Pop()); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Try(ExecutionEngine engine, Instruction instruction) + { + int catchOffset = instruction.TokenI8; + int finallyOffset = instruction.TokenI8_1; + ExecuteTry(engine, catchOffset, finallyOffset); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Try_L(ExecutionEngine engine, Instruction instruction) + { + var catchOffset = instruction.TokenI32; + var finallyOffset = instruction.TokenI32_1; + ExecuteTry(engine, catchOffset, finallyOffset); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void EndTry(ExecutionEngine engine, Instruction instruction) + { + var endOffset = instruction.TokenI8; + ExecuteEndTry(engine, endOffset); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void EndTry_L(ExecutionEngine engine, Instruction instruction) + { + var endOffset = instruction.TokenI32; + ExecuteEndTry(engine, endOffset); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void EndFinally(ExecutionEngine engine, Instruction instruction) + { + if (engine.CurrentContext!.TryStack is null) + throw new InvalidOperationException($"The corresponding TRY block cannot be found."); + if (!engine.CurrentContext.TryStack.TryPop(out var currentTry)) + throw new InvalidOperationException($"The corresponding TRY block cannot be found."); + + if (engine.UncaughtException is null) + engine.CurrentContext.InstructionPointer = currentTry.EndPointer; + else + ExecuteThrow(engine, engine.UncaughtException); + + engine.isJumping = true; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Ret(ExecutionEngine engine, Instruction instruction) + { + var context_pop = engine.InvocationStack.Pop(); + var stack_eval = engine.InvocationStack.Count == 0 ? engine.ResultStack : engine.InvocationStack.Peek().EvaluationStack; + if (context_pop.EvaluationStack != stack_eval) + { + if (context_pop.RVCount >= 0 && context_pop.EvaluationStack.Count != context_pop.RVCount) + throw new InvalidOperationException("RVCount doesn't match with EvaluationStack"); + context_pop.EvaluationStack.CopyTo(stack_eval); + } + if (engine.InvocationStack.Count == 0) + engine.State = VMState.HALT; + engine.UnloadContext(context_pop); + engine.isJumping = true; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Syscall(ExecutionEngine engine, Instruction instruction) + { + throw new InvalidOperationException($"Syscall not found: {instruction.TokenU32}"); + } + + #region Execute methods + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void ExecuteCall(ExecutionEngine engine, int position) + { + engine.LoadContext(engine.CurrentContext!.Clone(position)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void ExecuteEndTry(ExecutionEngine engine, int endOffset) + { + if (engine.CurrentContext!.TryStack is null) + throw new InvalidOperationException($"The corresponding TRY block cannot be found."); + if (!engine.CurrentContext.TryStack.TryPeek(out var currentTry)) + throw new InvalidOperationException($"The corresponding TRY block cannot be found."); + if (currentTry.State == ExceptionHandlingState.Finally) + throw new InvalidOperationException($"The opcode {OpCode.ENDTRY} can't be executed in a FINALLY block."); + + var endPointer = checked(engine.CurrentContext.InstructionPointer + endOffset); + if (currentTry.HasFinally) + { + currentTry.State = ExceptionHandlingState.Finally; + currentTry.EndPointer = endPointer; + engine.CurrentContext.InstructionPointer = currentTry.FinallyPointer; + } + else + { + engine.CurrentContext.TryStack.Pop(); + engine.CurrentContext.InstructionPointer = endPointer; + } + engine.isJumping = true; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void ExecuteJump(ExecutionEngine engine, int position) + { + if (position < 0 || position >= engine.CurrentContext!.Script.Length) + throw new ArgumentOutOfRangeException($"Jump out of range for position: {position}"); + engine.CurrentContext.InstructionPointer = position; + engine.isJumping = true; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void ExecuteJumpOffset(ExecutionEngine engine, int offset) + { + ExecuteJump(engine, checked(engine.CurrentContext!.InstructionPointer + offset)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void ExecuteTry(ExecutionEngine engine, int catchOffset, int finallyOffset) + { + if (catchOffset == 0 && finallyOffset == 0) + throw new InvalidOperationException($"catchOffset and finallyOffset can't be 0 in a TRY block"); + if (engine.CurrentContext!.TryStack is null) + engine.CurrentContext.TryStack = new Stack(); + else if (engine.CurrentContext.TryStack.Count >= engine.Limits.MaxTryNestingDepth) + throw new InvalidOperationException("MaxTryNestingDepth exceed."); + var catchPointer = catchOffset == 0 ? -1 : checked(engine.CurrentContext.InstructionPointer + catchOffset); + var finallyPointer = finallyOffset == 0 ? -1 : checked(engine.CurrentContext.InstructionPointer + finallyOffset); + engine.CurrentContext.TryStack.Push(new ExceptionHandlingContext(catchPointer, finallyPointer)); + } + + public virtual void ExecuteThrow(ExecutionEngine engine, StackItem? ex) + { + engine.UncaughtException = ex; + + var pop = 0; + foreach (var executionContext in engine.InvocationStack) + { + if (executionContext.TryStack != null) + { + while (executionContext.TryStack.TryPeek(out var tryContext)) + { + if (tryContext.State == ExceptionHandlingState.Finally || (tryContext.State == ExceptionHandlingState.Catch && !tryContext.HasFinally)) + { + executionContext.TryStack.Pop(); + continue; + } + for (var i = 0; i < pop; i++) + { + engine.UnloadContext(engine.InvocationStack.Pop()); + } + if (tryContext.State == ExceptionHandlingState.Try && tryContext.HasCatch) + { + tryContext.State = ExceptionHandlingState.Catch; + engine.Push(engine.UncaughtException!); + executionContext.InstructionPointer = tryContext.CatchPointer; + engine.UncaughtException = null; + } + else + { + tryContext.State = ExceptionHandlingState.Finally; + executionContext.InstructionPointer = tryContext.FinallyPointer; + } + engine.isJumping = true; + return; + } + } + ++pop; + } + + throw new VMUnhandledException(engine.UncaughtException!); + } + + #endregion + } +} diff --git a/src/Neo.VM/JumpTable/JumpTable.Numeric.cs b/src/Neo.VM/JumpTable/JumpTable.Numeric.cs new file mode 100644 index 0000000000..60586cb77e --- /dev/null +++ b/src/Neo.VM/JumpTable/JumpTable.Numeric.cs @@ -0,0 +1,265 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// JumpTable.Numeric.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.Numerics; +using System.Runtime.CompilerServices; + +namespace Neo.VM +{ + public partial class JumpTable + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Sign(ExecutionEngine engine, Instruction instruction) + { + var x = engine.Pop().GetInteger(); + engine.Push(x.Sign); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Abs(ExecutionEngine engine, Instruction instruction) + { + var x = engine.Pop().GetInteger(); + engine.Push(BigInteger.Abs(x)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Negate(ExecutionEngine engine, Instruction instruction) + { + var x = engine.Pop().GetInteger(); + engine.Push(-x); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Inc(ExecutionEngine engine, Instruction instruction) + { + var x = engine.Pop().GetInteger(); + engine.Push(x + 1); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Dec(ExecutionEngine engine, Instruction instruction) + { + var x = engine.Pop().GetInteger(); + engine.Push(x - 1); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Add(ExecutionEngine engine, Instruction instruction) + { + var x2 = engine.Pop().GetInteger(); + var x1 = engine.Pop().GetInteger(); + engine.Push(x1 + x2); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Sub(ExecutionEngine engine, Instruction instruction) + { + var x2 = engine.Pop().GetInteger(); + var x1 = engine.Pop().GetInteger(); + engine.Push(x1 - x2); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Mul(ExecutionEngine engine, Instruction instruction) + { + var x2 = engine.Pop().GetInteger(); + var x1 = engine.Pop().GetInteger(); + engine.Push(x1 * x2); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Div(ExecutionEngine engine, Instruction instruction) + { + var x2 = engine.Pop().GetInteger(); + var x1 = engine.Pop().GetInteger(); + engine.Push(x1 / x2); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Mod(ExecutionEngine engine, Instruction instruction) + { + var x2 = engine.Pop().GetInteger(); + var x1 = engine.Pop().GetInteger(); + engine.Push(x1 % x2); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Pow(ExecutionEngine engine, Instruction instruction) + { + var exponent = (int)engine.Pop().GetInteger(); + engine.Limits.AssertShift(exponent); + var value = engine.Pop().GetInteger(); + engine.Push(BigInteger.Pow(value, exponent)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Sqrt(ExecutionEngine engine, Instruction instruction) + { + engine.Push(engine.Pop().GetInteger().Sqrt()); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void ModMul(ExecutionEngine engine, Instruction instruction) + { + var modulus = engine.Pop().GetInteger(); + var x2 = engine.Pop().GetInteger(); + var x1 = engine.Pop().GetInteger(); + engine.Push(x1 * x2 % modulus); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void ModPow(ExecutionEngine engine, Instruction instruction) + { + var modulus = engine.Pop().GetInteger(); + var exponent = engine.Pop().GetInteger(); + var value = engine.Pop().GetInteger(); + var result = exponent == -1 + ? value.ModInverse(modulus) + : BigInteger.ModPow(value, exponent, modulus); + engine.Push(result); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Shl(ExecutionEngine engine, Instruction instruction) + { + var shift = (int)engine.Pop().GetInteger(); + engine.Limits.AssertShift(shift); + if (shift == 0) return; + var x = engine.Pop().GetInteger(); + engine.Push(x << shift); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Shr(ExecutionEngine engine, Instruction instruction) + { + var shift = (int)engine.Pop().GetInteger(); + engine.Limits.AssertShift(shift); + if (shift == 0) return; + var x = engine.Pop().GetInteger(); + engine.Push(x >> shift); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Not(ExecutionEngine engine, Instruction instruction) + { + var x = engine.Pop().GetBoolean(); + engine.Push(!x); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void BoolAnd(ExecutionEngine engine, Instruction instruction) + { + var x2 = engine.Pop().GetBoolean(); + var x1 = engine.Pop().GetBoolean(); + engine.Push(x1 && x2); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void BoolOr(ExecutionEngine engine, Instruction instruction) + { + var x2 = engine.Pop().GetBoolean(); + var x1 = engine.Pop().GetBoolean(); + engine.Push(x1 || x2); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Nz(ExecutionEngine engine, Instruction instruction) + { + var x = engine.Pop().GetInteger(); + engine.Push(!x.IsZero); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void NumEqual(ExecutionEngine engine, Instruction instruction) + { + var x2 = engine.Pop().GetInteger(); + var x1 = engine.Pop().GetInteger(); + engine.Push(x1 == x2); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void NumNotEqual(ExecutionEngine engine, Instruction instruction) + { + var x2 = engine.Pop().GetInteger(); + var x1 = engine.Pop().GetInteger(); + engine.Push(x1 != x2); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Lt(ExecutionEngine engine, Instruction instruction) + { + var x2 = engine.Pop(); + var x1 = engine.Pop(); + if (x1.IsNull || x2.IsNull) + engine.Push(false); + else + engine.Push(x1.GetInteger() < x2.GetInteger()); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Le(ExecutionEngine engine, Instruction instruction) + { + var x2 = engine.Pop(); + var x1 = engine.Pop(); + if (x1.IsNull || x2.IsNull) + engine.Push(false); + else + engine.Push(x1.GetInteger() <= x2.GetInteger()); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Gt(ExecutionEngine engine, Instruction instruction) + { + var x2 = engine.Pop(); + var x1 = engine.Pop(); + if (x1.IsNull || x2.IsNull) + engine.Push(false); + else + engine.Push(x1.GetInteger() > x2.GetInteger()); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Ge(ExecutionEngine engine, Instruction instruction) + { + var x2 = engine.Pop(); + var x1 = engine.Pop(); + if (x1.IsNull || x2.IsNull) + engine.Push(false); + else + engine.Push(x1.GetInteger() >= x2.GetInteger()); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Min(ExecutionEngine engine, Instruction instruction) + { + var x2 = engine.Pop().GetInteger(); + var x1 = engine.Pop().GetInteger(); + engine.Push(BigInteger.Min(x1, x2)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Max(ExecutionEngine engine, Instruction instruction) + { + var x2 = engine.Pop().GetInteger(); + var x1 = engine.Pop().GetInteger(); + engine.Push(BigInteger.Max(x1, x2)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Within(ExecutionEngine engine, Instruction instruction) + { + var b = engine.Pop().GetInteger(); + var a = engine.Pop().GetInteger(); + var x = engine.Pop().GetInteger(); + engine.Push(a <= x && x < b); + } + } +} diff --git a/src/Neo.VM/JumpTable/JumpTable.Push.cs b/src/Neo.VM/JumpTable/JumpTable.Push.cs new file mode 100644 index 0000000000..066330f5bb --- /dev/null +++ b/src/Neo.VM/JumpTable/JumpTable.Push.cs @@ -0,0 +1,213 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// JumpTable.Push.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; +using System.Numerics; +using System.Runtime.CompilerServices; + +namespace Neo.VM +{ + public partial class JumpTable + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void PushInt8(ExecutionEngine engine, Instruction instruction) + { + engine.Push(new BigInteger(instruction.Operand.Span)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void PushInt16(ExecutionEngine engine, Instruction instruction) + { + engine.Push(new BigInteger(instruction.Operand.Span)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void PushInt32(ExecutionEngine engine, Instruction instruction) + { + engine.Push(new BigInteger(instruction.Operand.Span)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void PushInt64(ExecutionEngine engine, Instruction instruction) + { + engine.Push(new BigInteger(instruction.Operand.Span)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void PushInt128(ExecutionEngine engine, Instruction instruction) + { + engine.Push(new BigInteger(instruction.Operand.Span)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void PushInt256(ExecutionEngine engine, Instruction instruction) + { + engine.Push(new BigInteger(instruction.Operand.Span)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void PushT(ExecutionEngine engine, Instruction instruction) + { + engine.Push(StackItem.True); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void PushF(ExecutionEngine engine, Instruction instruction) + { + engine.Push(StackItem.False); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void PushA(ExecutionEngine engine, Instruction instruction) + { + var position = checked(engine.CurrentContext!.InstructionPointer + instruction.TokenI32); + if (position < 0 || position > engine.CurrentContext.Script.Length) + throw new InvalidOperationException($"Bad pointer address(Instruction instruction) {position}"); + engine.Push(new Pointer(engine.CurrentContext.Script, position)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void PushNull(ExecutionEngine engine, Instruction instruction) + { + engine.Push(StackItem.Null); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void PushData1(ExecutionEngine engine, Instruction instruction) + { + engine.Limits.AssertMaxItemSize(instruction.Operand.Length); + engine.Push(instruction.Operand); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void PushData2(ExecutionEngine engine, Instruction instruction) + { + engine.Limits.AssertMaxItemSize(instruction.Operand.Length); + engine.Push(instruction.Operand); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void PushData4(ExecutionEngine engine, Instruction instruction) + { + engine.Limits.AssertMaxItemSize(instruction.Operand.Length); + engine.Push(instruction.Operand); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void PushM1(ExecutionEngine engine, Instruction instruction) + { + engine.Push(-1); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Push0(ExecutionEngine engine, Instruction instruction) + { + engine.Push(0); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Push1(ExecutionEngine engine, Instruction instruction) + { + engine.Push(1); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Push2(ExecutionEngine engine, Instruction instruction) + { + engine.Push(2); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Push3(ExecutionEngine engine, Instruction instruction) + { + engine.Push(3); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Push4(ExecutionEngine engine, Instruction instruction) + { + engine.Push(4); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Push5(ExecutionEngine engine, Instruction instruction) + { + engine.Push(5); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Push6(ExecutionEngine engine, Instruction instruction) + { + engine.Push(6); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Push7(ExecutionEngine engine, Instruction instruction) + { + engine.Push(7); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Push8(ExecutionEngine engine, Instruction instruction) + { + engine.Push(8); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Push9(ExecutionEngine engine, Instruction instruction) + { + engine.Push(9); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Push10(ExecutionEngine engine, Instruction instruction) + { + engine.Push(10); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Push11(ExecutionEngine engine, Instruction instruction) + { + engine.Push(11); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Push12(ExecutionEngine engine, Instruction instruction) + { + engine.Push(12); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Push13(ExecutionEngine engine, Instruction instruction) + { + engine.Push(13); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Push14(ExecutionEngine engine, Instruction instruction) + { + engine.Push(14); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Push15(ExecutionEngine engine, Instruction instruction) + { + engine.Push(15); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Push16(ExecutionEngine engine, Instruction instruction) + { + engine.Push(16); + } + } +} diff --git a/src/Neo.VM/JumpTable/JumpTable.Slot.cs b/src/Neo.VM/JumpTable/JumpTable.Slot.cs new file mode 100644 index 0000000000..1305701e98 --- /dev/null +++ b/src/Neo.VM/JumpTable/JumpTable.Slot.cs @@ -0,0 +1,363 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// JumpTable.Slot.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; +using Neo.VM.Types; +using System; +using System.Runtime.CompilerServices; + +namespace Neo.VM +{ + public partial class JumpTable + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void InitSSlot(ExecutionEngine engine, Instruction instruction) + { + if (engine.CurrentContext!.StaticFields != null) + throw new InvalidOperationException($"{instruction.OpCode} cannot be executed twice."); + if (instruction.TokenU8 == 0) + throw new InvalidOperationException($"The operand {instruction.TokenU8} is invalid for OpCode.{instruction.OpCode}."); + engine.CurrentContext.StaticFields = new Slot(instruction.TokenU8, engine.ReferenceCounter); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void InitSlot(ExecutionEngine engine, Instruction instruction) + { + if (engine.CurrentContext!.LocalVariables != null || engine.CurrentContext.Arguments != null) + throw new InvalidOperationException($"{instruction.OpCode} cannot be executed twice."); + if (instruction.TokenU16 == 0) + throw new InvalidOperationException($"The operand {instruction.TokenU16} is invalid for OpCode.{instruction.OpCode}."); + if (instruction.TokenU8 > 0) + { + engine.CurrentContext.LocalVariables = new Slot(instruction.TokenU8, engine.ReferenceCounter); + } + if (instruction.TokenU8_1 > 0) + { + var items = new StackItem[instruction.TokenU8_1]; + for (var i = 0; i < instruction.TokenU8_1; i++) + { + items[i] = engine.Pop(); + } + engine.CurrentContext.Arguments = new Slot(items, engine.ReferenceCounter); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void LdSFld0(ExecutionEngine engine, Instruction instruction) + { + ExecuteLoadFromSlot(engine, engine.CurrentContext!.StaticFields, 0); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void LdSFld1(ExecutionEngine engine, Instruction instruction) + { + ExecuteLoadFromSlot(engine, engine.CurrentContext!.StaticFields, 1); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void LdSFld2(ExecutionEngine engine, Instruction instruction) + { + ExecuteLoadFromSlot(engine, engine.CurrentContext!.StaticFields, 2); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void LdSFld3(ExecutionEngine engine, Instruction instruction) + { + ExecuteLoadFromSlot(engine, engine.CurrentContext!.StaticFields, 3); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void LdSFld4(ExecutionEngine engine, Instruction instruction) + { + ExecuteLoadFromSlot(engine, engine.CurrentContext!.StaticFields, 4); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void LdSFld5(ExecutionEngine engine, Instruction instruction) + { + ExecuteLoadFromSlot(engine, engine.CurrentContext!.StaticFields, 5); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void LdSFld6(ExecutionEngine engine, Instruction instruction) + { + ExecuteLoadFromSlot(engine, engine.CurrentContext!.StaticFields, 6); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void LdSFld(ExecutionEngine engine, Instruction instruction) + { + ExecuteLoadFromSlot(engine, engine.CurrentContext!.StaticFields, instruction.TokenU8); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void StSFld0(ExecutionEngine engine, Instruction instruction) + { + ExecuteStoreToSlot(engine, engine.CurrentContext!.StaticFields, 0); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void StSFld1(ExecutionEngine engine, Instruction instruction) + { + ExecuteStoreToSlot(engine, engine.CurrentContext!.StaticFields, 1); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void StSFld2(ExecutionEngine engine, Instruction instruction) + { + ExecuteStoreToSlot(engine, engine.CurrentContext!.StaticFields, 2); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void StSFld3(ExecutionEngine engine, Instruction instruction) + { + ExecuteStoreToSlot(engine, engine.CurrentContext!.StaticFields, 3); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void StSFld4(ExecutionEngine engine, Instruction instruction) + { + ExecuteStoreToSlot(engine, engine.CurrentContext!.StaticFields, 4); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void StSFld5(ExecutionEngine engine, Instruction instruction) + { + ExecuteStoreToSlot(engine, engine.CurrentContext!.StaticFields, 5); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void StSFld6(ExecutionEngine engine, Instruction instruction) + { + ExecuteStoreToSlot(engine, engine.CurrentContext!.StaticFields, 6); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void StSFld(ExecutionEngine engine, Instruction instruction) + { + ExecuteStoreToSlot(engine, engine.CurrentContext!.StaticFields, instruction.TokenU8); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void LdLoc0(ExecutionEngine engine, Instruction instruction) + { + ExecuteLoadFromSlot(engine, engine.CurrentContext!.LocalVariables, 0); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void LdLoc1(ExecutionEngine engine, Instruction instruction) + { + ExecuteLoadFromSlot(engine, engine.CurrentContext!.LocalVariables, 1); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void LdLoc2(ExecutionEngine engine, Instruction instruction) + { + ExecuteLoadFromSlot(engine, engine.CurrentContext!.LocalVariables, 2); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void LdLoc3(ExecutionEngine engine, Instruction instruction) + { + ExecuteLoadFromSlot(engine, engine.CurrentContext!.LocalVariables, 3); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void LdLoc4(ExecutionEngine engine, Instruction instruction) + { + ExecuteLoadFromSlot(engine, engine.CurrentContext!.LocalVariables, 4); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void LdLoc5(ExecutionEngine engine, Instruction instruction) + { + ExecuteLoadFromSlot(engine, engine.CurrentContext!.LocalVariables, 5); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void LdLoc6(ExecutionEngine engine, Instruction instruction) + { + ExecuteLoadFromSlot(engine, engine.CurrentContext!.LocalVariables, 6); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void LdLoc(ExecutionEngine engine, Instruction instruction) + { + ExecuteLoadFromSlot(engine, engine.CurrentContext!.LocalVariables, instruction.TokenU8); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void StLoc0(ExecutionEngine engine, Instruction instruction) + { + ExecuteStoreToSlot(engine, engine.CurrentContext!.LocalVariables, 0); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void StLoc1(ExecutionEngine engine, Instruction instruction) + { + ExecuteStoreToSlot(engine, engine.CurrentContext!.LocalVariables, 1); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void StLoc2(ExecutionEngine engine, Instruction instruction) + { + ExecuteStoreToSlot(engine, engine.CurrentContext!.LocalVariables, 2); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void StLoc3(ExecutionEngine engine, Instruction instruction) + { + ExecuteStoreToSlot(engine, engine.CurrentContext!.LocalVariables, 3); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void StLoc4(ExecutionEngine engine, Instruction instruction) + { + ExecuteStoreToSlot(engine, engine.CurrentContext!.LocalVariables, 4); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void StLoc5(ExecutionEngine engine, Instruction instruction) + { + ExecuteStoreToSlot(engine, engine.CurrentContext!.LocalVariables, 5); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void StLoc6(ExecutionEngine engine, Instruction instruction) + { + ExecuteStoreToSlot(engine, engine.CurrentContext!.LocalVariables, 6); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void StLoc(ExecutionEngine engine, Instruction instruction) + { + ExecuteStoreToSlot(engine, engine.CurrentContext!.LocalVariables, instruction.TokenU8); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void LdArg0(ExecutionEngine engine, Instruction instruction) + { + ExecuteLoadFromSlot(engine, engine.CurrentContext!.Arguments, 0); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void LdArg1(ExecutionEngine engine, Instruction instruction) + { + ExecuteLoadFromSlot(engine, engine.CurrentContext!.Arguments, 1); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void LdArg2(ExecutionEngine engine, Instruction instruction) + { + ExecuteLoadFromSlot(engine, engine.CurrentContext!.Arguments, 2); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void LdArg3(ExecutionEngine engine, Instruction instruction) + { + ExecuteLoadFromSlot(engine, engine.CurrentContext!.Arguments, 3); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void LdArg4(ExecutionEngine engine, Instruction instruction) + { + ExecuteLoadFromSlot(engine, engine.CurrentContext!.Arguments, 4); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void LdArg5(ExecutionEngine engine, Instruction instruction) + { + ExecuteLoadFromSlot(engine, engine.CurrentContext!.Arguments, 5); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void LdArg6(ExecutionEngine engine, Instruction instruction) + { + ExecuteLoadFromSlot(engine, engine.CurrentContext!.Arguments, 6); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void LdArg(ExecutionEngine engine, Instruction instruction) + { + ExecuteLoadFromSlot(engine, engine.CurrentContext!.Arguments, instruction.TokenU8); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void StArg0(ExecutionEngine engine, Instruction instruction) + { + ExecuteStoreToSlot(engine, engine.CurrentContext!.Arguments, 0); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void StArg1(ExecutionEngine engine, Instruction instruction) + { + ExecuteStoreToSlot(engine, engine.CurrentContext!.Arguments, 1); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void StArg2(ExecutionEngine engine, Instruction instruction) + { + ExecuteStoreToSlot(engine, engine.CurrentContext!.Arguments, 2); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void StArg3(ExecutionEngine engine, Instruction instruction) + { + ExecuteStoreToSlot(engine, engine.CurrentContext!.Arguments, 3); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void StArg4(ExecutionEngine engine, Instruction instruction) + { + ExecuteStoreToSlot(engine, engine.CurrentContext!.Arguments, 4); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void StArg5(ExecutionEngine engine, Instruction instruction) + { + ExecuteStoreToSlot(engine, engine.CurrentContext!.Arguments, 5); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void StArg6(ExecutionEngine engine, Instruction instruction) + { + ExecuteStoreToSlot(engine, engine.CurrentContext!.Arguments, 6); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void StArg(ExecutionEngine engine, Instruction instruction) + { + ExecuteStoreToSlot(engine, engine.CurrentContext!.Arguments, instruction.TokenU8); + } + + #region Execute methods + + public virtual void ExecuteStoreToSlot(ExecutionEngine engine, Slot? slot, int index) + { + if (slot is null) + throw new InvalidOperationException("Slot has not been initialized."); + if (index < 0 || index >= slot.Count) + throw new InvalidOperationException($"Index out of range when storing to slot: {index}"); + slot[index] = engine.Pop(); + } + + public virtual void ExecuteLoadFromSlot(ExecutionEngine engine, Slot? slot, int index) + { + if (slot is null) + throw new InvalidOperationException("Slot has not been initialized."); + if (index < 0 || index >= slot.Count) + throw new InvalidOperationException($"Index out of range when loading from slot: {index}"); + engine.Push(slot[index]); + } + + #endregion + } +} diff --git a/src/Neo.VM/JumpTable/JumpTable.Splice.cs b/src/Neo.VM/JumpTable/JumpTable.Splice.cs new file mode 100644 index 0000000000..95bad5314f --- /dev/null +++ b/src/Neo.VM/JumpTable/JumpTable.Splice.cs @@ -0,0 +1,106 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// JumpTable.Splice.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.Runtime.CompilerServices; + +namespace Neo.VM +{ + public partial class JumpTable + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void NewBuffer(ExecutionEngine engine, Instruction instruction) + { + int length = (int)engine.Pop().GetInteger(); + engine.Limits.AssertMaxItemSize(length); + engine.Push(new Types.Buffer(length)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Memcpy(ExecutionEngine engine, Instruction instruction) + { + int count = (int)engine.Pop().GetInteger(); + if (count < 0) + throw new InvalidOperationException($"The value {count} is out of range."); + int si = (int)engine.Pop().GetInteger(); + if (si < 0) + throw new InvalidOperationException($"The value {si} is out of range."); + ReadOnlySpan src = engine.Pop().GetSpan(); + if (checked(si + count) > src.Length) + throw new InvalidOperationException($"The value {count} is out of range."); + int di = (int)engine.Pop().GetInteger(); + if (di < 0) + throw new InvalidOperationException($"The value {di} is out of range."); + Types.Buffer dst = engine.Pop(); + if (checked(di + count) > dst.Size) + throw new InvalidOperationException($"The value {count} is out of range."); + src.Slice(si, count).CopyTo(dst.InnerBuffer.Span[di..]); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Cat(ExecutionEngine engine, Instruction instruction) + { + var x2 = engine.Pop().GetSpan(); + var x1 = engine.Pop().GetSpan(); + int length = x1.Length + x2.Length; + engine.Limits.AssertMaxItemSize(length); + Types.Buffer result = new(length, false); + x1.CopyTo(result.InnerBuffer.Span); + x2.CopyTo(result.InnerBuffer.Span[x1.Length..]); + engine.Push(result); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void SubStr(ExecutionEngine engine, Instruction instruction) + { + int count = (int)engine.Pop().GetInteger(); + if (count < 0) + throw new InvalidOperationException($"The value {count} is out of range."); + int index = (int)engine.Pop().GetInteger(); + if (index < 0) + throw new InvalidOperationException($"The value {index} is out of range."); + var x = engine.Pop().GetSpan(); + if (index + count > x.Length) + throw new InvalidOperationException($"The value {count} is out of range."); + Types.Buffer result = new(count, false); + x.Slice(index, count).CopyTo(result.InnerBuffer.Span); + engine.Push(result); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Left(ExecutionEngine engine, Instruction instruction) + { + int count = (int)engine.Pop().GetInteger(); + if (count < 0) + throw new InvalidOperationException($"The value {count} is out of range."); + var x = engine.Pop().GetSpan(); + if (count > x.Length) + throw new InvalidOperationException($"The value {count} is out of range."); + Types.Buffer result = new(count, false); + x[..count].CopyTo(result.InnerBuffer.Span); + engine.Push(result); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Right(ExecutionEngine engine, Instruction instruction) + { + int count = (int)engine.Pop().GetInteger(); + if (count < 0) + throw new InvalidOperationException($"The value {count} is out of range."); + var x = engine.Pop().GetSpan(); + if (count > x.Length) + throw new InvalidOperationException($"The value {count} is out of range."); + Types.Buffer result = new(count, false); + x[^count..^0].CopyTo(result.InnerBuffer.Span); + engine.Push(result); + } + } +} diff --git a/src/Neo.VM/JumpTable/JumpTable.Stack.cs b/src/Neo.VM/JumpTable/JumpTable.Stack.cs new file mode 100644 index 0000000000..0f623c26ce --- /dev/null +++ b/src/Neo.VM/JumpTable/JumpTable.Stack.cs @@ -0,0 +1,124 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// JumpTable.Stack.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; +using System.Runtime.CompilerServices; + +namespace Neo.VM +{ + public partial class JumpTable + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Depth(ExecutionEngine engine, Instruction instruction) + { + engine.Push(engine.CurrentContext!.EvaluationStack.Count); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Drop(ExecutionEngine engine, Instruction instruction) + { + engine.Pop(); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Nip(ExecutionEngine engine, Instruction instruction) + { + engine.CurrentContext!.EvaluationStack.Remove(1); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void XDrop(ExecutionEngine engine, Instruction instruction) + { + var n = (int)engine.Pop().GetInteger(); + if (n < 0) + throw new InvalidOperationException($"The negative value {n} is invalid for OpCode.{instruction.OpCode}."); + engine.CurrentContext!.EvaluationStack.Remove(n); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Clear(ExecutionEngine engine, Instruction instruction) + { + engine.CurrentContext!.EvaluationStack.Clear(); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Dup(ExecutionEngine engine, Instruction instruction) + { + engine.Push(engine.Peek()); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Over(ExecutionEngine engine, Instruction instruction) + { + engine.Push(engine.Peek(1)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Pick(ExecutionEngine engine, Instruction instruction) + { + var n = (int)engine.Pop().GetInteger(); + if (n < 0) + throw new InvalidOperationException($"The negative value {n} is invalid for OpCode.{instruction.OpCode}."); + engine.Push(engine.Peek(n)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Tuck(ExecutionEngine engine, Instruction instruction) + { + engine.CurrentContext!.EvaluationStack.Insert(2, engine.Peek()); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Swap(ExecutionEngine engine, Instruction instruction) + { + var x = engine.CurrentContext!.EvaluationStack.Remove(1); + engine.Push(x); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Rot(ExecutionEngine engine, Instruction instruction) + { + var x = engine.CurrentContext!.EvaluationStack.Remove(2); + engine.Push(x); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Roll(ExecutionEngine engine, Instruction instruction) + { + var n = (int)engine.Pop().GetInteger(); + if (n < 0) + throw new InvalidOperationException($"The negative value {n} is invalid for OpCode.{instruction.OpCode}."); + if (n == 0) return; + var x = engine.CurrentContext!.EvaluationStack.Remove(n); + engine.Push(x); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Reverse3(ExecutionEngine engine, Instruction instruction) + { + engine.CurrentContext!.EvaluationStack.Reverse(3); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Reverse4(ExecutionEngine engine, Instruction instruction) + { + engine.CurrentContext!.EvaluationStack.Reverse(4); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void ReverseN(ExecutionEngine engine, Instruction instruction) + { + var n = (int)engine.Pop().GetInteger(); + engine.CurrentContext!.EvaluationStack.Reverse(n); + } + } +} diff --git a/src/Neo.VM/JumpTable/JumpTable.Types.cs b/src/Neo.VM/JumpTable/JumpTable.Types.cs new file mode 100644 index 0000000000..6c3b1cbb61 --- /dev/null +++ b/src/Neo.VM/JumpTable/JumpTable.Types.cs @@ -0,0 +1,60 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// JumpTable.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 Neo.VM.Types; +using System; +using System.Runtime.CompilerServices; + +namespace Neo.VM +{ + public partial class JumpTable + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void IsNull(ExecutionEngine engine, Instruction instruction) + { + var x = engine.Pop(); + engine.Push(x.IsNull); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void IsType(ExecutionEngine engine, Instruction instruction) + { + var x = engine.Pop(); + var type = (StackItemType)instruction.TokenU8; + if (type == StackItemType.Any || !Enum.IsDefined(typeof(StackItemType), type)) + throw new InvalidOperationException($"Invalid type: {type}"); + engine.Push(x.Type == type); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void Convert(ExecutionEngine engine, Instruction instruction) + { + var x = engine.Pop(); + engine.Push(x.ConvertTo((StackItemType)instruction.TokenU8)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void AbortMsg(ExecutionEngine engine, Instruction instruction) + { + var msg = engine.Pop().GetString(); + throw new Exception($"{OpCode.ABORTMSG} is executed. Reason: {msg}"); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public virtual void AssertMsg(ExecutionEngine engine, Instruction instruction) + { + var msg = engine.Pop().GetString(); + var x = engine.Pop().GetBoolean(); + if (!x) + throw new Exception($"{OpCode.ASSERTMSG} is executed with false result. Reason: {msg}"); + } + } +} diff --git a/src/Neo.VM/JumpTable/JumpTable.cs b/src/Neo.VM/JumpTable/JumpTable.cs new file mode 100644 index 0000000000..0c387e7c9b --- /dev/null +++ b/src/Neo.VM/JumpTable/JumpTable.cs @@ -0,0 +1,71 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// JumpTable.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.Runtime.CompilerServices; + +namespace Neo.VM +{ + public partial class JumpTable + { + /// + /// Default JumpTable + /// + public static readonly JumpTable Default = new(); + + public delegate void DelAction(ExecutionEngine engine, Instruction instruction); + protected readonly DelAction[] Table = new DelAction[byte.MaxValue]; + + public DelAction this[OpCode opCode] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => Table[(byte)opCode]; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set { Table[(byte)opCode] = value; } + } + + /// + /// Jump table constructor + /// + /// Throw an exception if the opcode was already set + public JumpTable() + { + // Fill defined + + foreach (var mi in GetType().GetMethods()) + { + if (Enum.TryParse(mi.Name, true, out var opCode)) + { + if (Table[(byte)opCode] is not null) + { + throw new InvalidOperationException($"Opcode {opCode} is already defined."); + } + + Table[(byte)opCode] = (DelAction)mi.CreateDelegate(typeof(DelAction), this); + } + } + + // Fill with undefined + + for (var x = 0; x < Table.Length; x++) + { + if (Table[x] is not null) continue; + + Table[x] = InvalidOpcode; + } + } + + public virtual void InvalidOpcode(ExecutionEngine engine, Instruction instruction) + { + throw new InvalidOperationException($"Opcode {instruction.OpCode} is undefined."); + } + } +} diff --git a/src/Neo.VM/Neo.VM.csproj b/src/Neo.VM/Neo.VM.csproj index 7f2119c943..66f4682c64 100644 --- a/src/Neo.VM/Neo.VM.csproj +++ b/src/Neo.VM/Neo.VM.csproj @@ -7,6 +7,7 @@ + diff --git a/src/Neo/SmartContract/ApplicationEngine.cs b/src/Neo/SmartContract/ApplicationEngine.cs index 341e077ec3..1331ff2608 100644 --- a/src/Neo/SmartContract/ApplicationEngine.cs +++ b/src/Neo/SmartContract/ApplicationEngine.cs @@ -32,6 +32,8 @@ namespace Neo.SmartContract /// public partial class ApplicationEngine : ExecutionEngine { + private static readonly JumpTable DefaultJumpTable = ComposeDefaultJumpTable(); + /// /// The maximum cost that can be spent when a contract is executed in test mode. /// @@ -155,7 +157,11 @@ public UInt160 CallingScriptHash /// The used by the engine. /// The maximum gas used in this execution. The execution will fail when the gas is exhausted. /// The diagnostic to be used by the . - protected unsafe ApplicationEngine(TriggerType trigger, IVerifiable container, DataCache snapshot, Block persistingBlock, ProtocolSettings settings, long gas, IDiagnostic diagnostic) + /// The jump table to be used by the . + protected unsafe ApplicationEngine( + TriggerType trigger, IVerifiable container, DataCache snapshot, Block persistingBlock, + ProtocolSettings settings, long gas, IDiagnostic diagnostic, JumpTable jumpTable = null) + : base(jumpTable ?? DefaultJumpTable) { this.Trigger = trigger; this.ScriptContainer = container; @@ -177,6 +183,58 @@ protected unsafe ApplicationEngine(TriggerType trigger, IVerifiable container, D diagnostic?.Initialized(this); } + #region JumpTable + + private static JumpTable ComposeDefaultJumpTable() + { + var table = new JumpTable(); + + table[OpCode.SYSCALL] = OnSysCall; + table[OpCode.CALLT] = OnCallT; + + return table; + } + + private static void OnCallT(ExecutionEngine engine, Instruction instruction) + { + if (engine is ApplicationEngine app) + { + uint tokenId = instruction.TokenU16; + + app.ValidateCallFlags(CallFlags.ReadStates | CallFlags.AllowCall); + ContractState contract = app.CurrentContext.GetState().Contract; + if (contract is null || tokenId >= contract.Nef.Tokens.Length) + throw new InvalidOperationException(); + MethodToken token = contract.Nef.Tokens[tokenId]; + if (token.ParametersCount > app.CurrentContext.EvaluationStack.Count) + throw new InvalidOperationException(); + StackItem[] args = new StackItem[token.ParametersCount]; + for (int i = 0; i < token.ParametersCount; i++) + args[i] = app.Pop(); + app.CallContractInternal(token.Hash, token.Method, token.CallFlags, token.HasReturnValue, args); + } + else + { + throw new InvalidOperationException(); + } + } + + private static void OnSysCall(ExecutionEngine engine, Instruction instruction) + { + if (engine is ApplicationEngine app) + { + uint method = instruction.TokenU32; + + app.OnSysCall(services[method]); + } + else + { + throw new InvalidOperationException(); + } + } + + #endregion + /// /// Adds GAS to and checks if it has exceeded the maximum limit. /// @@ -270,9 +328,9 @@ internal ContractTask CallFromNativeContract(UInt160 callingScriptHash, UI return task; } - protected override void ContextUnloaded(ExecutionContext context) + internal override void UnloadContext(ExecutionContext context) { - base.ContextUnloaded(context); + base.UnloadContext(context); if (context.Script != CurrentContext?.Script) { ExecutionContextState state = context.GetState(); @@ -320,11 +378,14 @@ protected override void ContextUnloaded(ExecutionContext context) /// The engine instance created. public static ApplicationEngine Create(TriggerType trigger, IVerifiable container, DataCache snapshot, Block persistingBlock = null, ProtocolSettings settings = null, long gas = TestModeGas, IDiagnostic diagnostic = null) { - return Provider?.Create(trigger, container, snapshot, persistingBlock, settings, gas, diagnostic) - ?? new ApplicationEngine(trigger, container, snapshot, persistingBlock, settings, gas, diagnostic); + // Adjust jump table according persistingBlock + var jumpTable = ApplicationEngine.DefaultJumpTable; + + return Provider?.Create(trigger, container, snapshot, persistingBlock, settings, gas, diagnostic, jumpTable) + ?? new ApplicationEngine(trigger, container, snapshot, persistingBlock, settings, gas, diagnostic, jumpTable); } - protected override void LoadContext(ExecutionContext context) + internal override void LoadContext(ExecutionContext context) { // Set default execution context state var state = context.GetState(); @@ -391,21 +452,6 @@ public ExecutionContext LoadScript(Script script, int rvcount = -1, int initialP return context; } - protected override ExecutionContext LoadToken(ushort tokenId) - { - ValidateCallFlags(CallFlags.ReadStates | CallFlags.AllowCall); - ContractState contract = CurrentContext.GetState().Contract; - if (contract is null || tokenId >= contract.Nef.Tokens.Length) - throw new InvalidOperationException(); - MethodToken token = contract.Nef.Tokens[tokenId]; - if (token.ParametersCount > CurrentContext.EvaluationStack.Count) - throw new InvalidOperationException(); - StackItem[] args = new StackItem[token.ParametersCount]; - for (int i = 0; i < token.ParametersCount; i++) - args[i] = Pop(); - return CallContractInternal(token.Hash, token.Method, token.CallFlags, token.HasReturnValue, args); - } - /// /// Converts an to a that used in the virtual machine. /// @@ -503,11 +549,6 @@ internal protected void ValidateCallFlags(CallFlags requiredCallFlags) throw new InvalidOperationException($"Cannot call this SYSCALL with the flag {state.CallFlags}."); } - protected override void OnSysCall(uint method) - { - OnSysCall(services[method]); - } - /// /// Invokes the specified interoperable service. /// diff --git a/src/Neo/SmartContract/IApplicationEngineProvider.cs b/src/Neo/SmartContract/IApplicationEngineProvider.cs index ef06c6b92c..ba7866739c 100644 --- a/src/Neo/SmartContract/IApplicationEngineProvider.cs +++ b/src/Neo/SmartContract/IApplicationEngineProvider.cs @@ -11,6 +11,7 @@ using Neo.Network.P2P.Payloads; using Neo.Persistence; +using Neo.VM; namespace Neo.SmartContract { @@ -29,7 +30,8 @@ public interface IApplicationEngineProvider /// The used by the engine. /// The maximum gas 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 . /// The engine instance created. - ApplicationEngine Create(TriggerType trigger, IVerifiable container, DataCache snapshot, Block persistingBlock, ProtocolSettings settings, long gas, IDiagnostic diagnostic); + ApplicationEngine Create(TriggerType trigger, IVerifiable container, DataCache snapshot, Block persistingBlock, ProtocolSettings settings, long gas, IDiagnostic diagnostic, JumpTable jumpTable); } } diff --git a/tests/Neo.UnitTests/SmartContract/UT_ApplicationEngineProvider.cs b/tests/Neo.UnitTests/SmartContract/UT_ApplicationEngineProvider.cs index f4e99e6936..75fc558669 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_ApplicationEngineProvider.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_ApplicationEngineProvider.cs @@ -14,6 +14,7 @@ using Neo.Network.P2P.Payloads; using Neo.Persistence; using Neo.SmartContract; +using Neo.VM; namespace Neo.UnitTests.SmartContract { @@ -50,16 +51,16 @@ public void TestDefaultAppEngineProvider() class TestProvider : IApplicationEngineProvider { - public ApplicationEngine Create(TriggerType trigger, IVerifiable container, DataCache snapshot, Block persistingBlock, ProtocolSettings settings, long gas, IDiagnostic diagnostic) + public ApplicationEngine Create(TriggerType trigger, IVerifiable container, DataCache snapshot, Block persistingBlock, ProtocolSettings settings, long gas, IDiagnostic diagnostic, JumpTable jumpTable) { - return new TestEngine(trigger, container, snapshot, persistingBlock, settings, gas, diagnostic); + return new TestEngine(trigger, container, snapshot, persistingBlock, settings, gas, diagnostic, jumpTable); } } class TestEngine : ApplicationEngine { - public TestEngine(TriggerType trigger, IVerifiable container, DataCache snapshot, Block persistingBlock, ProtocolSettings settings, long gas, IDiagnostic diagnostic) - : base(trigger, container, snapshot, persistingBlock, settings, gas, diagnostic) + 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) { } } diff --git a/tests/Neo.VM.Tests/Types/TestEngine.cs b/tests/Neo.VM.Tests/Types/TestEngine.cs index 07aa89a09f..cf99314892 100644 --- a/tests/Neo.VM.Tests/Types/TestEngine.cs +++ b/tests/Neo.VM.Tests/Types/TestEngine.cs @@ -19,21 +19,32 @@ class TestEngine : ExecutionEngine { public Exception FaultException { get; private set; } - protected override void OnSysCall(uint method) + public TestEngine() : base(ComposeJumpTable()) { } + + private static JumpTable ComposeJumpTable() { + JumpTable jumpTable = new JumpTable(); + jumpTable[OpCode.SYSCALL] = OnSysCall; + return jumpTable; + } + + private static void OnSysCall(ExecutionEngine engine, Instruction instruction) + { + uint method = instruction.TokenU32; + if (method == 0x77777777) { - CurrentContext.EvaluationStack.Push(StackItem.FromInterface(new object())); + engine.CurrentContext.EvaluationStack.Push(StackItem.FromInterface(new object())); return; } if (method == 0xaddeadde) { - ExecuteThrow("error"); + engine.JumpTable.ExecuteThrow(engine, "error"); return; } - throw new System.Exception(); + throw new Exception(); } protected override void OnFault(Exception ex) From b467613884ef4196283f9f303897dedb0c3de36d Mon Sep 17 00:00:00 2001 From: Shargon Date: Fri, 23 Feb 2024 12:31:38 +0100 Subject: [PATCH 090/168] Allow Native Contracts to be updated (#2942) * Update manifest * Fix comment * Format & fix methods * Fix new * Initialize storage fixes * Fix IsInitializeBlock * Fix update * Fix GetContractState * Optimize * Fix first invoke without sync * Remove current methods * Clean usings * Improve reading Initialize * Clean OnManifestCompose * Use cache for all native contracts * Fix ut * Move cache to ApplicationEngine * Clean code * Allow nullable attribute * Update src/Neo/SmartContract/Native/ContractEventAttribute.cs * Add base call * Fix one https://github.com/neo-project/neo/pull/2941#discussion_r1382434903 * Fix IsInitializeBlock https://github.com/neo-project/neo/pull/2941#discussion_r1382434903 * Add ContractEventAttribute constructors for ActiveIn * Ensure ommited hfs * Rename * Case insensitive hf config * Increase coverage * More uts * Rename * Update src/Neo/SmartContract/Native/ContractManagement.cs * format code * Fix ProtocolSettings * Update src/Neo/SmartContract/ApplicationEngine.cs * format * reorder using * Fix UT * Adding keccak256 (#2925) * Create codeql.yml * Keccak256 * Delete .github/workflows/codeql.yml * Update src/Neo/SmartContract/Native/CryptoLib.cs * add more keccak256 test cases as required * Create codeql.yml * Keccak256 * Delete .github/workflows/codeql.yml * Update src/Neo/SmartContract/Native/CryptoLib.cs * add more keccak256 test cases as required * HF_Manticore * Fix copyright * Create codeql.yml * Keccak256 * Delete .github/workflows/codeql.yml * Update src/Neo/SmartContract/Native/CryptoLib.cs * add more keccak256 test cases as required * Create codeql.yml * Keccak256 * Delete .github/workflows/codeql.yml * Update src/Neo/SmartContract/Native/CryptoLib.cs * add more keccak256 test cases as required * HF_Manticore * Fix copyright * HF_Manticore * Update CryptoLib.cs * Update CryptoLib.cs * Update UT_CryptoLib.cs * Apply suggestions from code review * clean usings --------- Co-authored-by: Shargon * Fix net standard * Add ut * Fix update * Fix update --------- Co-authored-by: Jimmy --- src/Neo/Hardfork.cs | 3 +- src/Neo/NeoSystem.cs | 3 +- src/Neo/Persistence/DataCache.cs | 2 +- src/Neo/ProtocolSettings.cs | 52 +++++- src/Neo/SmartContract/ApplicationEngine.cs | 45 ++--- .../Native/ContractEventAttribute.cs | 165 +++++++++++++++++ .../Native/ContractManagement.cs | 89 ++++----- .../Native/ContractMethodAttribute.cs | 10 + .../Native/ContractMethodMetadata.cs | 4 + src/Neo/SmartContract/Native/CryptoLib.cs | 18 +- src/Neo/SmartContract/Native/FungibleToken.cs | 40 +--- src/Neo/SmartContract/Native/GasToken.cs | 10 +- .../SmartContract/Native/LedgerContract.cs | 4 +- .../SmartContract/Native/NativeContract.cs | 171 ++++++++++++++---- src/Neo/SmartContract/Native/NeoToken.cs | 85 +++------ .../SmartContract/Native/OracleContract.cs | 71 ++------ .../SmartContract/Native/PolicyContract.cs | 15 +- .../SmartContract/Native/RoleManagement.cs | 31 +--- src/Neo/SmartContract/Native/StdLib.cs | 2 +- src/Neo/SmartContract/StorageItem.cs | 10 + .../Native/UT_ContractEventAttribute.cs | 151 ++++++++++++++++ .../Native/UT_ContractMethodAttribute.cs | 32 ++++ .../SmartContract/Native/UT_CryptoLib.cs | 93 ++++++++++ .../SmartContract/Native/UT_NativeContract.cs | 21 +++ .../SmartContract/UT_InteropService.cs | 6 +- .../SmartContract/UT_JsonSerializer.cs | 6 +- tests/Neo.UnitTests/UT_ProtocolSettings.cs | 127 +++++++++++++ 27 files changed, 949 insertions(+), 317 deletions(-) create mode 100644 src/Neo/SmartContract/Native/ContractEventAttribute.cs create mode 100644 tests/Neo.UnitTests/SmartContract/Native/UT_ContractEventAttribute.cs create mode 100644 tests/Neo.UnitTests/SmartContract/Native/UT_ContractMethodAttribute.cs diff --git a/src/Neo/Hardfork.cs b/src/Neo/Hardfork.cs index a5decc1d0c..9ef6a63c1c 100644 --- a/src/Neo/Hardfork.cs +++ b/src/Neo/Hardfork.cs @@ -14,6 +14,7 @@ namespace Neo public enum Hardfork : byte { HF_Aspidochelone, - HF_Basilisk + HF_Basilisk, + HF_Cockatrice } } diff --git a/src/Neo/NeoSystem.cs b/src/Neo/NeoSystem.cs index d299f8de12..1303770a3f 100644 --- a/src/Neo/NeoSystem.cs +++ b/src/Neo/NeoSystem.cs @@ -117,7 +117,8 @@ static NeoSystem() /// The storage engine used to create the objects. If this parameter is , a default in-memory storage engine will be used. /// The path of the storage. If is the default in-memory storage engine, this parameter is ignored. public NeoSystem(ProtocolSettings settings, string? storageProvider = null, string? storagePath = null) : - this(settings, StoreFactory.GetStoreProvider(storageProvider ?? nameof(MemoryStore)), storagePath) + this(settings, StoreFactory.GetStoreProvider(storageProvider ?? nameof(MemoryStore)) + ?? throw new ArgumentException($"Can't find the storage provider {storageProvider}", nameof(storageProvider)), storagePath) { } diff --git a/src/Neo/Persistence/DataCache.cs b/src/Neo/Persistence/DataCache.cs index 6a1a5236bc..86fbd69961 100644 --- a/src/Neo/Persistence/DataCache.cs +++ b/src/Neo/Persistence/DataCache.cs @@ -96,7 +96,7 @@ public void Add(StorageKey key, StorageItem value) { TrackState.Deleted => TrackState.Changed, TrackState.NotFound => TrackState.Added, - _ => throw new ArgumentException() + _ => throw new ArgumentException($"The element currently has state {trackable.State}") }; } else diff --git a/src/Neo/ProtocolSettings.cs b/src/Neo/ProtocolSettings.cs index defbab9994..1b7367a6a2 100644 --- a/src/Neo/ProtocolSettings.cs +++ b/src/Neo/ProtocolSettings.cs @@ -24,6 +24,8 @@ namespace Neo /// public record ProtocolSettings { + private static readonly IList AllHardforks = Enum.GetValues(typeof(Hardfork)).Cast().ToArray(); + /// /// The magic number of the NEO network. /// @@ -115,7 +117,7 @@ public record ProtocolSettings MemoryPoolMaxTransactions = 50_000, MaxTraceableBlocks = 2_102_400, InitialGasDistribution = 52_000_000_00000000, - Hardforks = ImmutableDictionary.Empty + Hardforks = EnsureOmmitedHardforks(new Dictionary()).ToImmutableDictionary() }; public static ProtocolSettings? Custom { get; set; } @@ -159,17 +161,39 @@ public static ProtocolSettings Load(IConfigurationSection section) MaxTraceableBlocks = section.GetValue("MaxTraceableBlocks", Default.MaxTraceableBlocks), InitialGasDistribution = section.GetValue("InitialGasDistribution", Default.InitialGasDistribution), Hardforks = section.GetSection("Hardforks").Exists() - ? section.GetSection("Hardforks").GetChildren().ToImmutableDictionary(p => Enum.Parse(p.Key), p => uint.Parse(p.Value)) + ? EnsureOmmitedHardforks(section.GetSection("Hardforks").GetChildren().ToDictionary(p => Enum.Parse(p.Key, true), p => uint.Parse(p.Value))).ToImmutableDictionary() : Default.Hardforks }; } + /// + /// Explicitly set the height of all old omitted hardforks to 0 for proper IsHardforkEnabled behaviour. + /// + /// HardForks + /// Processed hardfork configuration + private static Dictionary EnsureOmmitedHardforks(Dictionary hardForks) + { + foreach (Hardfork hf in AllHardforks) + { + if (!hardForks.ContainsKey(hf)) + { + hardForks[hf] = 0; + } + else + { + break; + } + } + + return hardForks; + } + private static void CheckingHardfork(ProtocolSettings settings) { var allHardforks = Enum.GetValues(typeof(Hardfork)).Cast().ToList(); // Check for continuity in configured hardforks var sortedHardforks = settings.Hardforks.Keys - .OrderBy(h => allHardforks.IndexOf(h)) + .OrderBy(allHardforks.IndexOf) .ToList(); for (int i = 0; i < sortedHardforks.Count - 1; i++) @@ -179,7 +203,7 @@ private static void CheckingHardfork(ProtocolSettings settings) // If they aren't consecutive, return false. if (nextIndex - currentIndex > 1) - throw new Exception("Hardfork configuration is not continuous."); + throw new ArgumentException("Hardfork configuration is not continuous."); } // Check that block numbers are not higher in earlier hardforks than in later ones for (int i = 0; i < sortedHardforks.Count - 1; i++) @@ -187,9 +211,27 @@ private static void CheckingHardfork(ProtocolSettings settings) if (settings.Hardforks[sortedHardforks[i]] > settings.Hardforks[sortedHardforks[i + 1]]) { // This means the block number for the current hardfork is greater than the next one, which should not be allowed. - throw new Exception($"The Hardfork configuration for {sortedHardforks[i]} is greater than for {sortedHardforks[i + 1]}"); + throw new ArgumentException($"The Hardfork configuration for {sortedHardforks[i]} is greater than for {sortedHardforks[i + 1]}"); } } } + + /// + /// Check if the Hardfork is Enabled + /// + /// Hardfork + /// Block index + /// True if enabled + public bool IsHardforkEnabled(Hardfork hardfork, uint index) + { + if (Hardforks.TryGetValue(hardfork, out uint height)) + { + // If the hardfork has a specific height in the configuration, check the block height. + return index >= height; + } + + // If the hardfork isn't specified in the configuration, return false. + return false; + } } } diff --git a/src/Neo/SmartContract/ApplicationEngine.cs b/src/Neo/SmartContract/ApplicationEngine.cs index 1331ff2608..63cbde9960 100644 --- a/src/Neo/SmartContract/ApplicationEngine.cs +++ b/src/Neo/SmartContract/ApplicationEngine.cs @@ -49,7 +49,6 @@ public partial class ApplicationEngine : ExecutionEngine /// public static event EventHandler Log; - private static readonly IList AllHardforks = Enum.GetValues(typeof(Hardfork)).Cast().ToArray(); private static Dictionary services; private readonly long gas_amount; private Dictionary states; @@ -647,6 +646,25 @@ public T GetState() return (T)state; } + public T GetState(Func factory) + { + if (states is null) + { + T state = factory(); + SetState(state); + return state; + } + else + { + if (!states.TryGetValue(typeof(T), out object state)) + { + state = factory(); + SetState(state); + } + return (T)state; + } + } + public void SetState(T state) { states ??= new Dictionary(); @@ -655,28 +673,11 @@ public void SetState(T state) public bool IsHardforkEnabled(Hardfork hardfork) { - // Return true if there's no specific configuration or PersistingBlock is null - if (PersistingBlock is null || ProtocolSettings.Hardforks.Count == 0) - return true; - - // If the hardfork isn't specified in the configuration, check if it's a new one. - if (!ProtocolSettings.Hardforks.ContainsKey(hardfork)) - { - int currentHardforkIndex = AllHardforks.IndexOf(hardfork); - int lastConfiguredHardforkIndex = AllHardforks.IndexOf(ProtocolSettings.Hardforks.Keys.Last()); + // Return true if PersistingBlock is null and Hardfork is enabled + if (PersistingBlock is null) + return ProtocolSettings.Hardforks.ContainsKey(hardfork); - // If it's a newer hardfork compared to the ones in the configuration, disable it. - if (currentHardforkIndex > lastConfiguredHardforkIndex) - return false; - } - - if (ProtocolSettings.Hardforks.TryGetValue(hardfork, out uint height)) - { - // If the hardfork has a specific height in the configuration, check the block height. - return PersistingBlock.Index >= height; - } - // If no specific conditions are met, return true. - return true; + return ProtocolSettings.IsHardforkEnabled(hardfork, PersistingBlock.Index); } } } diff --git a/src/Neo/SmartContract/Native/ContractEventAttribute.cs b/src/Neo/SmartContract/Native/ContractEventAttribute.cs new file mode 100644 index 0000000000..656ecef725 --- /dev/null +++ b/src/Neo/SmartContract/Native/ContractEventAttribute.cs @@ -0,0 +1,165 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// ContractEventAttribute.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.Manifest; +using System; +using System.Diagnostics; + +namespace Neo.SmartContract.Native +{ + [DebuggerDisplay("{Descriptor.Name}")] + [AttributeUsage(AttributeTargets.Constructor, AllowMultiple = true)] + internal class ContractEventAttribute : Attribute + { + public int Order { get; init; } + public ContractEventDescriptor Descriptor { get; set; } + public Hardfork? ActiveIn { get; init; } = null; + + public ContractEventAttribute(Hardfork activeIn, int order, string name, + string arg1Name, ContractParameterType arg1Value) : this(order, name, arg1Name, arg1Value) + { + ActiveIn = activeIn; + } + + public ContractEventAttribute(int order, string name, string arg1Name, ContractParameterType arg1Value) + { + Order = order; + Descriptor = new ContractEventDescriptor() + { + Name = name, + Parameters = new ContractParameterDefinition[] + { + new ContractParameterDefinition() + { + Name = arg1Name, + Type = arg1Value + } + } + }; + } + + public ContractEventAttribute(Hardfork activeIn, int order, string name, + string arg1Name, ContractParameterType arg1Value, + string arg2Name, ContractParameterType arg2Value) : this(order, name, arg1Name, arg1Value, arg2Name, arg2Value) + { + ActiveIn = activeIn; + } + + public ContractEventAttribute(int order, string name, + string arg1Name, ContractParameterType arg1Value, + string arg2Name, ContractParameterType arg2Value) + { + Order = order; + Descriptor = new ContractEventDescriptor() + { + Name = name, + Parameters = new ContractParameterDefinition[] + { + new ContractParameterDefinition() + { + Name = arg1Name, + Type = arg1Value + }, + new ContractParameterDefinition() + { + Name = arg2Name, + Type = arg2Value + } + } + }; + } + + public ContractEventAttribute(Hardfork activeIn, int order, string name, + string arg1Name, ContractParameterType arg1Value, + string arg2Name, ContractParameterType arg2Value, + string arg3Name, ContractParameterType arg3Value) : this(order, name, arg1Name, arg1Value, arg2Name, arg2Value, arg3Name, arg3Value) + { + ActiveIn = activeIn; + } + + public ContractEventAttribute(int order, string name, + string arg1Name, ContractParameterType arg1Value, + string arg2Name, ContractParameterType arg2Value, + string arg3Name, ContractParameterType arg3Value + ) + { + Order = order; + Descriptor = new ContractEventDescriptor() + { + Name = name, + Parameters = new ContractParameterDefinition[] + { + new ContractParameterDefinition() + { + Name = arg1Name, + Type = arg1Value + }, + new ContractParameterDefinition() + { + Name = arg2Name, + Type = arg2Value + }, + new ContractParameterDefinition() + { + Name = arg3Name, + Type = arg3Value + } + } + }; + } + + public ContractEventAttribute(Hardfork activeIn, int order, string name, + string arg1Name, ContractParameterType arg1Value, + string arg2Name, ContractParameterType arg2Value, + string arg3Name, ContractParameterType arg3Value, + string arg4Name, ContractParameterType arg4Value) : this(order, name, arg1Name, arg1Value, arg2Name, arg2Value, arg3Name, arg3Value, arg4Name, arg4Value) + { + ActiveIn = activeIn; + } + + public ContractEventAttribute(int order, string name, + string arg1Name, ContractParameterType arg1Value, + string arg2Name, ContractParameterType arg2Value, + string arg3Name, ContractParameterType arg3Value, + string arg4Name, ContractParameterType arg4Value + ) + { + Order = order; + Descriptor = new ContractEventDescriptor() + { + Name = name, + Parameters = new ContractParameterDefinition[] + { + new ContractParameterDefinition() + { + Name = arg1Name, + Type = arg1Value + }, + new ContractParameterDefinition() + { + Name = arg2Name, + Type = arg2Value + }, + new ContractParameterDefinition() + { + Name = arg3Name, + Type = arg3Value + }, + new ContractParameterDefinition() + { + Name = arg4Name, + Type = arg4Value + } + } + }; + } + } +} diff --git a/src/Neo/SmartContract/Native/ContractManagement.cs b/src/Neo/SmartContract/Native/ContractManagement.cs index 0f846a37cc..3347163a6c 100644 --- a/src/Neo/SmartContract/Native/ContractManagement.cs +++ b/src/Neo/SmartContract/Native/ContractManagement.cs @@ -35,50 +35,10 @@ public sealed class ContractManagement : NativeContract private const byte Prefix_Contract = 8; private const byte Prefix_ContractHash = 12; - internal ContractManagement() - { - var events = new List(Manifest.Abi.Events) - { - new ContractEventDescriptor - { - Name = "Deploy", - Parameters = new ContractParameterDefinition[] - { - new ContractParameterDefinition() - { - Name = "Hash", - Type = ContractParameterType.Hash160 - } - } - }, - new ContractEventDescriptor - { - Name = "Update", - Parameters = new ContractParameterDefinition[] - { - new ContractParameterDefinition() - { - Name = "Hash", - Type = ContractParameterType.Hash160 - } - } - }, - new ContractEventDescriptor - { - Name = "Destroy", - Parameters = new ContractParameterDefinition[] - { - new ContractParameterDefinition() - { - Name = "Hash", - Type = ContractParameterType.Hash160 - } - } - } - }; - - Manifest.Abi.Events = events.ToArray(); - } + [ContractEvent(0, name: "Deploy", "Hash", ContractParameterType.Hash160)] + [ContractEvent(1, name: "Update", "Hash", ContractParameterType.Hash160)] + [ContractEvent(2, name: "Destroy", "Hash", ContractParameterType.Hash160)] + internal ContractManagement() : base() { } private int GetNextAvailableId(DataCache snapshot) { @@ -88,10 +48,13 @@ private int GetNextAvailableId(DataCache snapshot) return value; } - internal override ContractTask Initialize(ApplicationEngine engine) + internal override ContractTask Initialize(ApplicationEngine engine, Hardfork? hardfork) { - engine.Snapshot.Add(CreateStorageKey(Prefix_MinimumDeploymentFee), new StorageItem(10_00000000)); - engine.Snapshot.Add(CreateStorageKey(Prefix_NextAvailableId), new StorageItem(1)); + if (hardfork == ActiveIn) + { + engine.Snapshot.Add(CreateStorageKey(Prefix_MinimumDeploymentFee), new StorageItem(10_00000000)); + engine.Snapshot.Add(CreateStorageKey(Prefix_NextAvailableId), new StorageItem(1)); + } return ContractTask.CompletedTask; } @@ -107,17 +70,31 @@ internal override async ContractTask OnPersist(ApplicationEngine engine) { foreach (NativeContract contract in Contracts) { - if (contract.IsInitializeBlock(engine.ProtocolSettings, engine.PersistingBlock.Index)) + if (contract.IsInitializeBlock(engine.ProtocolSettings, engine.PersistingBlock.Index, out Hardfork? hf)) { - engine.Snapshot.Add(CreateStorageKey(Prefix_Contract).Add(contract.Hash), new StorageItem(new ContractState + ContractState contractState = contract.GetContractState(engine.ProtocolSettings, engine.PersistingBlock.Index); + StorageItem state = engine.Snapshot.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())); + } + else { - Id = contract.Id, - Nef = contract.Nef, - Hash = contract.Hash, - Manifest = contract.Manifest - })); - engine.Snapshot.Add(CreateStorageKey(Prefix_ContractHash).AddBigEndian(contract.Id), new StorageItem(contract.Hash.ToArray())); - await contract.Initialize(engine); + // Parse old contract + var oldContract = state.GetInteroperable(); + // Increase the update counter + oldContract.UpdateCounter++; + // Modify nef and manifest + oldContract.Nef = contractState.Nef; + oldContract.Manifest = contractState.Manifest; + } + + await contract.Initialize(engine, hf); + // Emit native contract notification + engine.SendNotification(Hash, state is null ? "Deploy" : "Update", new VM.Types.Array(engine.ReferenceCounter) { contract.Hash.ToArray() }); } } } diff --git a/src/Neo/SmartContract/Native/ContractMethodAttribute.cs b/src/Neo/SmartContract/Native/ContractMethodAttribute.cs index 55940f2eb3..cd8f7de59e 100644 --- a/src/Neo/SmartContract/Native/ContractMethodAttribute.cs +++ b/src/Neo/SmartContract/Native/ContractMethodAttribute.cs @@ -10,9 +10,11 @@ // modifications are permitted. using System; +using System.Diagnostics; namespace Neo.SmartContract.Native { + [DebuggerDisplay("{Name}")] [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, AllowMultiple = false)] internal class ContractMethodAttribute : Attribute { @@ -20,5 +22,13 @@ internal class ContractMethodAttribute : Attribute public CallFlags RequiredCallFlags { get; init; } public long CpuFee { get; init; } public long StorageFee { get; init; } + public Hardfork? ActiveIn { get; init; } = null; + + public ContractMethodAttribute() { } + + public ContractMethodAttribute(Hardfork activeIn) + { + ActiveIn = activeIn; + } } } diff --git a/src/Neo/SmartContract/Native/ContractMethodMetadata.cs b/src/Neo/SmartContract/Native/ContractMethodMetadata.cs index 83c24191fd..9f83eb20fc 100644 --- a/src/Neo/SmartContract/Native/ContractMethodMetadata.cs +++ b/src/Neo/SmartContract/Native/ContractMethodMetadata.cs @@ -15,6 +15,7 @@ using Neo.SmartContract.Manifest; using Neo.VM.Types; using System; +using System.Diagnostics; using System.Linq; using System.Numerics; using System.Reflection; @@ -22,6 +23,7 @@ namespace Neo.SmartContract.Native { + [DebuggerDisplay("{Name}")] internal class ContractMethodMetadata { public string Name { get; } @@ -33,6 +35,7 @@ internal class ContractMethodMetadata public long StorageFee { get; } public CallFlags RequiredCallFlags { get; } public ContractMethodDescriptor Descriptor { get; } + public Hardfork? ActiveIn { get; init; } = null; public ContractMethodMetadata(MemberInfo member, ContractMethodAttribute attribute) { @@ -56,6 +59,7 @@ public ContractMethodMetadata(MemberInfo member, ContractMethodAttribute attribu this.CpuFee = attribute.CpuFee; this.StorageFee = attribute.StorageFee; this.RequiredCallFlags = attribute.RequiredCallFlags; + this.ActiveIn = attribute.ActiveIn; this.Descriptor = new ContractMethodDescriptor { Name = Name, diff --git a/src/Neo/SmartContract/Native/CryptoLib.cs b/src/Neo/SmartContract/Native/CryptoLib.cs index 257deaa72f..a7b822e39c 100644 --- a/src/Neo/SmartContract/Native/CryptoLib.cs +++ b/src/Neo/SmartContract/Native/CryptoLib.cs @@ -11,6 +11,7 @@ using Neo.Cryptography; using Neo.Cryptography.ECC; +using Org.BouncyCastle.Crypto.Digests; using System; using System.Collections.Generic; @@ -27,7 +28,7 @@ public sealed partial class CryptoLib : NativeContract [NamedCurve.secp256r1] = ECCurve.Secp256r1 }; - internal CryptoLib() { } + internal CryptoLib() : base() { } /// /// Computes the hash value for the specified byte array using the ripemd160 algorithm. @@ -64,6 +65,21 @@ public static byte[] Murmur32(byte[] data, uint seed) return murmur.ComputeHash(data); } + /// + /// Computes the hash value for the specified byte array using the keccak256 algorithm. + /// + /// The input to compute the hash code for. + /// Computed hash + [ContractMethod(Hardfork.HF_Cockatrice, CpuFee = 1 << 15)] + public static byte[] Keccak256(byte[] data) + { + KeccakDigest keccak = new(256); + keccak.BlockUpdate(data, 0, data.Length); + byte[] result = new byte[keccak.GetDigestSize()]; + keccak.DoFinal(result, 0); + return result; + } + /// /// Verifies that a digital signature is appropriate for the provided key and message using the ECDSA algorithm. /// diff --git a/src/Neo/SmartContract/Native/FungibleToken.cs b/src/Neo/SmartContract/Native/FungibleToken.cs index 1a3a2ac532..6499c60c19 100644 --- a/src/Neo/SmartContract/Native/FungibleToken.cs +++ b/src/Neo/SmartContract/Native/FungibleToken.cs @@ -14,7 +14,6 @@ using Neo.SmartContract.Manifest; using Neo.VM.Types; using System; -using System.Collections.Generic; using System.Numerics; using Array = Neo.VM.Types.Array; @@ -57,39 +56,18 @@ public abstract class FungibleToken : NativeContract /// /// Initializes a new instance of the class. /// - protected FungibleToken() + [ContractEvent(0, name: "Transfer", + "from", ContractParameterType.Hash160, + "to", ContractParameterType.Hash160, + "amount", ContractParameterType.Integer)] + protected FungibleToken() : base() { this.Factor = BigInteger.Pow(10, Decimals); + } - Manifest.SupportedStandards = new[] { "NEP-17" }; - - var events = new List(Manifest.Abi.Events) - { - new ContractEventDescriptor - { - Name = "Transfer", - Parameters = new ContractParameterDefinition[] - { - new ContractParameterDefinition() - { - Name = "from", - Type = ContractParameterType.Hash160 - }, - new ContractParameterDefinition() - { - Name = "to", - Type = ContractParameterType.Hash160 - }, - new ContractParameterDefinition() - { - Name = "amount", - Type = ContractParameterType.Integer - } - } - } - }; - - Manifest.Abi.Events = events.ToArray(); + protected override void OnManifestCompose(ContractManifest manifest) + { + manifest.SupportedStandards = new[] { "NEP-17" }; } internal async ContractTask Mint(ApplicationEngine engine, UInt160 account, BigInteger amount, bool callOnPayment) diff --git a/src/Neo/SmartContract/Native/GasToken.cs b/src/Neo/SmartContract/Native/GasToken.cs index 0c5a721edc..ce2f77ad2c 100644 --- a/src/Neo/SmartContract/Native/GasToken.cs +++ b/src/Neo/SmartContract/Native/GasToken.cs @@ -26,10 +26,14 @@ internal GasToken() { } - internal override ContractTask Initialize(ApplicationEngine engine) + internal override ContractTask Initialize(ApplicationEngine engine, Hardfork? hardfork) { - UInt160 account = Contract.GetBFTAddress(engine.ProtocolSettings.StandbyValidators); - return Mint(engine, account, engine.ProtocolSettings.InitialGasDistribution, false); + if (hardfork == ActiveIn) + { + UInt160 account = Contract.GetBFTAddress(engine.ProtocolSettings.StandbyValidators); + return Mint(engine, account, engine.ProtocolSettings.InitialGasDistribution, false); + } + return ContractTask.CompletedTask; } internal override async ContractTask OnPersist(ApplicationEngine engine) diff --git a/src/Neo/SmartContract/Native/LedgerContract.cs b/src/Neo/SmartContract/Native/LedgerContract.cs index 3bb7568adf..d72f07c022 100644 --- a/src/Neo/SmartContract/Native/LedgerContract.cs +++ b/src/Neo/SmartContract/Native/LedgerContract.cs @@ -32,9 +32,7 @@ public sealed class LedgerContract : NativeContract private const byte Prefix_Block = 5; private const byte Prefix_Transaction = 11; - internal LedgerContract() - { - } + internal LedgerContract() : base() { } internal override ContractTask OnPersist(ApplicationEngine engine) { diff --git a/src/Neo/SmartContract/Native/NativeContract.cs b/src/Neo/SmartContract/Native/NativeContract.cs index 0229582310..6d5d105b7d 100644 --- a/src/Neo/SmartContract/Native/NativeContract.cs +++ b/src/Neo/SmartContract/Native/NativeContract.cs @@ -14,6 +14,8 @@ using Neo.VM; using System; using System.Collections.Generic; +using System.Collections.Immutable; +using System.Collections.ObjectModel; using System.Linq; using System.Reflection; @@ -24,9 +26,32 @@ namespace Neo.SmartContract.Native /// public abstract class NativeContract { + private class NativeContractsCache + { + public class CacheEntry + { + public Dictionary Methods { get; set; } + public byte[] Script { get; set; } + } + + internal Dictionary NativeContracts { get; set; } = new Dictionary(); + + public CacheEntry GetAllowedMethods(NativeContract native, ApplicationEngine engine) + { + if (NativeContracts.TryGetValue(native.Id, out var value)) return value; + + uint index = engine.PersistingBlock is null ? Ledger.CurrentIndex(engine.Snapshot) : engine.PersistingBlock.Index; + CacheEntry methods = native.GetAllowedMethods(engine.ProtocolSettings, index); + NativeContracts[native.Id] = methods; + return methods; + } + } + private static readonly List contractsList = new(); private static readonly Dictionary contractsDictionary = new(); - private readonly Dictionary methods = new(); + private readonly ImmutableHashSet usedHardforks; + private readonly ReadOnlyCollection methodDescriptors; + private readonly ReadOnlyCollection eventsDescriptors; private static int id_counter = 0; #region Named Native Contracts @@ -93,11 +118,6 @@ public abstract class NativeContract /// public virtual Hardfork? ActiveIn { get; } = null; - /// - /// The nef of the native contract. - /// - public NefFile Nef { get; } - /// /// The hash of the native contract. /// @@ -108,28 +128,58 @@ public abstract class NativeContract /// public int Id { get; } = --id_counter; - /// - /// The manifest of the native contract. - /// - public ContractManifest Manifest { get; } - /// /// Initializes a new instance of the class. /// protected NativeContract() { - List descriptors = new(); + this.Hash = Helper.GetContractHash(UInt160.Zero, 0, Name); + + // Reflection to get the methods + + List listMethods = new(); foreach (MemberInfo member in GetType().GetMembers(BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public)) { ContractMethodAttribute attribute = member.GetCustomAttribute(); if (attribute is null) continue; - descriptors.Add(new ContractMethodMetadata(member, attribute)); + listMethods.Add(new ContractMethodMetadata(member, attribute)); } - descriptors = descriptors.OrderBy(p => p.Name, StringComparer.Ordinal).ThenBy(p => p.Parameters.Length).ToList(); + methodDescriptors = listMethods.OrderBy(p => p.Name, StringComparer.Ordinal).ThenBy(p => p.Parameters.Length).ToList().AsReadOnly(); + + // Reflection to get the events + eventsDescriptors = + GetType().GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public, null, Array.Empty(), null)?. + GetCustomAttributes(). + OrderBy(p => p.Order).ToList().AsReadOnly(); + + // Calculate the initializations forks + usedHardforks = + methodDescriptors.Select(u => u.ActiveIn) + .Concat(eventsDescriptors.Select(u => u.ActiveIn)) + .Concat(new Hardfork?[] { ActiveIn }) + .Where(u => u is not null) + .OrderBy(u => (byte)u) + .Cast().ToImmutableHashSet(); + + contractsList.Add(this); + contractsDictionary.Add(Hash, this); + } + + /// + /// The allowed methods and his offsets. + /// + /// The where the HardForks are configured. + /// Block index + /// The . + private NativeContractsCache.CacheEntry GetAllowedMethods(ProtocolSettings settings, uint index) + { + Dictionary methods = new(); + + // Reflection to get the ContractMethods byte[] script; using (ScriptBuilder sb = new()) { - foreach (ContractMethodMetadata method in descriptors) + foreach (ContractMethodMetadata method in methodDescriptors.Where(u => u.ActiveIn is null || settings.IsHardforkEnabled(u.ActiveIn.Value, index))) { method.Descriptor.Offset = sb.Length; sb.EmitPush(0); //version @@ -139,49 +189,99 @@ protected NativeContract() } script = sb.ToArray(); } - this.Nef = new NefFile + + return new NativeContractsCache.CacheEntry() { Methods = methods, Script = script }; + } + + /// + /// The of the native contract. + /// + /// The where the HardForks are configured. + /// Block index + /// The . + internal ContractState GetContractState(ProtocolSettings settings, uint index) + { + // Get allowed methods and nef script + NativeContractsCache.CacheEntry allowedMethods = GetAllowedMethods(settings, index); + + // Compose nef file + NefFile nef = new() { Compiler = "neo-core-v3.0", Source = string.Empty, Tokens = Array.Empty(), - Script = script + Script = allowedMethods.Script }; - this.Nef.CheckSum = NefFile.ComputeChecksum(Nef); - this.Hash = Helper.GetContractHash(UInt160.Zero, 0, Name); - this.Manifest = new ContractManifest + nef.CheckSum = NefFile.ComputeChecksum(nef); + + // Compose manifest + ContractManifest manifest = new() { Name = Name, Groups = Array.Empty(), SupportedStandards = Array.Empty(), Abi = new ContractAbi() { - Events = Array.Empty(), - Methods = descriptors.Select(p => p.Descriptor).ToArray() + Events = eventsDescriptors + .Where(u => u.ActiveIn is null || settings.IsHardforkEnabled(u.ActiveIn.Value, index)) + .Select(p => p.Descriptor).ToArray(), + Methods = allowedMethods.Methods.Values + .Select(p => p.Descriptor).ToArray() }, Permissions = new[] { ContractPermission.DefaultPermission }, Trusts = WildcardContainer.Create(), Extra = null }; - contractsList.Add(this); - contractsDictionary.Add(Hash, this); + + OnManifestCompose(manifest); + + // Return ContractState + return new ContractState + { + Id = Id, + Nef = nef, + Hash = Hash, + Manifest = manifest + }; } + protected virtual void OnManifestCompose(ContractManifest manifest) { } + /// /// It is the initialize block /// /// The where the HardForks are configured. /// Block index + /// Active hardfork /// True if the native contract must be initialized - internal bool IsInitializeBlock(ProtocolSettings settings, uint index) + internal bool IsInitializeBlock(ProtocolSettings settings, uint index, out Hardfork? hardfork) { - if (ActiveIn is null) return index == 0; + // If is not configured, the Genesis is the a initialized block + if (index == 0 && ActiveIn is null) + { + hardfork = null; + return true; + } - if (!settings.Hardforks.TryGetValue(ActiveIn.Value, out var activeIn)) + // If is in the hardfork height, return true + foreach (Hardfork hf in usedHardforks) { - return false; + if (!settings.Hardforks.TryGetValue(hf, out var activeIn)) + { + // If is not set in the configuration is treated as enabled from the genesis + activeIn = 0; + } + + if (activeIn == index) + { + hardfork = hf; + return true; + } } - return activeIn == index; + // Initialized not required + hardfork = null; + return false; } /// @@ -196,7 +296,8 @@ internal bool IsActive(ProtocolSettings settings, uint index) if (!settings.Hardforks.TryGetValue(ActiveIn.Value, out var activeIn)) { - return false; + // If is not set in the configuration is treated as enabled from the genesis + activeIn = 0; } return activeIn <= index; @@ -235,8 +336,14 @@ internal async void Invoke(ApplicationEngine engine, byte version) { if (version != 0) throw new InvalidOperationException($"The native contract of version {version} is not active."); + // Get native contracts invocation cache + NativeContractsCache nativeContracts = engine.GetState(() => new NativeContractsCache()); + NativeContractsCache.CacheEntry currentAllowedMethods = nativeContracts.GetAllowedMethods(this, engine); + // Check if the method is allowed ExecutionContext context = engine.CurrentContext; - ContractMethodMetadata method = methods[context.InstructionPointer]; + ContractMethodMetadata method = currentAllowedMethods.Methods[context.InstructionPointer]; + if (method.ActiveIn is not null && !engine.IsHardforkEnabled(method.ActiveIn.Value)) + throw new InvalidOperationException($"Cannot call this method before hardfork {method.ActiveIn}."); ExecutionContextState state = context.GetState(); if (!state.CallFlags.HasFlag(method.RequiredCallFlags)) throw new InvalidOperationException($"Cannot call this method with the flag {state.CallFlags}."); @@ -277,7 +384,7 @@ public static bool IsNative(UInt160 hash) return contractsDictionary.ContainsKey(hash); } - internal virtual ContractTask Initialize(ApplicationEngine engine) + internal virtual ContractTask Initialize(ApplicationEngine engine, Hardfork? hardFork) { return ContractTask.CompletedTask; } diff --git a/src/Neo/SmartContract/Native/NeoToken.cs b/src/Neo/SmartContract/Native/NeoToken.cs index 2fd26d04a7..ed796a9756 100644 --- a/src/Neo/SmartContract/Native/NeoToken.cs +++ b/src/Neo/SmartContract/Native/NeoToken.cs @@ -15,7 +15,6 @@ using Neo.IO; using Neo.Persistence; using Neo.SmartContract.Iterators; -using Neo.SmartContract.Manifest; using Neo.VM; using Neo.VM.Types; using System; @@ -55,64 +54,18 @@ public sealed class NeoToken : FungibleToken private const byte CommitteeRewardRatio = 10; private const byte VoterRewardRatio = 80; - internal NeoToken() + [ContractEvent(1, name: "CandidateStateChanged", + "pubkey", ContractParameterType.PublicKey, + "registered", ContractParameterType.Boolean, + "votes", ContractParameterType.Integer)] + [ContractEvent(2, name: "Vote", + "account", ContractParameterType.Hash160, + "from", ContractParameterType.PublicKey, + "to", ContractParameterType.PublicKey, + "amount", ContractParameterType.Integer)] + internal NeoToken() : base() { this.TotalAmount = 100000000 * Factor; - - var events = new List(Manifest.Abi.Events) - { - new ContractEventDescriptor - { - Name = "CandidateStateChanged", - Parameters = new ContractParameterDefinition[] - { - new ContractParameterDefinition() - { - Name = "pubkey", - Type = ContractParameterType.PublicKey - }, - new ContractParameterDefinition() - { - Name = "registered", - Type = ContractParameterType.Boolean - }, - new ContractParameterDefinition() - { - Name = "votes", - Type = ContractParameterType.Integer - } - } - }, - new ContractEventDescriptor - { - Name = "Vote", - Parameters = new ContractParameterDefinition[] - { - new ContractParameterDefinition() - { - Name = "account", - Type = ContractParameterType.Hash160 - }, - new ContractParameterDefinition() - { - Name = "from", - Type = ContractParameterType.PublicKey - }, - new ContractParameterDefinition() - { - Name = "to", - Type = ContractParameterType.PublicKey - }, - new ContractParameterDefinition() - { - Name = "amount", - Type = ContractParameterType.Integer - } - } - } - }; - - Manifest.Abi.Events = events.ToArray(); } public override BigInteger TotalSupply(DataCache snapshot) @@ -220,14 +173,18 @@ private void CheckCandidate(DataCache snapshot, ECPoint pubkey, CandidateState c /// if the votes should be recounted; otherwise, . public static bool ShouldRefreshCommittee(uint height, int committeeMembersCount) => height % committeeMembersCount == 0; - internal override ContractTask Initialize(ApplicationEngine engine) + internal override ContractTask Initialize(ApplicationEngine engine, Hardfork? hardfork) { - 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)); - return Mint(engine, Contract.GetBFTAddress(engine.ProtocolSettings.StandbyValidators), TotalAmount, false); + 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)); + return Mint(engine, Contract.GetBFTAddress(engine.ProtocolSettings.StandbyValidators), TotalAmount, false); + } + return ContractTask.CompletedTask; } internal override ContractTask OnPersist(ApplicationEngine engine) diff --git a/src/Neo/SmartContract/Native/OracleContract.cs b/src/Neo/SmartContract/Native/OracleContract.cs index 42f41f5720..d8415fca21 100644 --- a/src/Neo/SmartContract/Native/OracleContract.cs +++ b/src/Neo/SmartContract/Native/OracleContract.cs @@ -15,7 +15,6 @@ using Neo.IO; using Neo.Network.P2P.Payloads; using Neo.Persistence; -using Neo.SmartContract.Manifest; using Neo.VM; using Neo.VM.Types; using System; @@ -41,58 +40,15 @@ public sealed class OracleContract : NativeContract private const byte Prefix_Request = 7; private const byte Prefix_IdList = 6; - internal OracleContract() - { - var events = new List(Manifest.Abi.Events) - { - new ContractEventDescriptor - { - Name = "OracleRequest", - Parameters = new ContractParameterDefinition[] - { - new ContractParameterDefinition() - { - Name = "Id", - Type = ContractParameterType.Integer - }, - new ContractParameterDefinition() - { - Name = "RequestContract", - Type = ContractParameterType.Hash160 - }, - new ContractParameterDefinition() - { - Name = "Url", - Type = ContractParameterType.String - }, - new ContractParameterDefinition() - { - Name = "Filter", - Type = ContractParameterType.String - } - } - }, - new ContractEventDescriptor - { - Name = "OracleResponse", - Parameters = new ContractParameterDefinition[] - { - new ContractParameterDefinition() - { - Name = "Id", - Type = ContractParameterType.Integer - }, - new ContractParameterDefinition() - { - Name = "OriginalTx", - Type = ContractParameterType.Hash256 - } - } - } - }; - - Manifest.Abi.Events = events.ToArray(); - } + [ContractEvent(0, name: "OracleRequest", + "Id", ContractParameterType.Integer, + "RequestContract", ContractParameterType.Hash160, + "Url", ContractParameterType.String, + "Filter", ContractParameterType.String)] + [ContractEvent(1, name: "OracleResponse", + "Id", ContractParameterType.Integer, + "OriginalTx", ContractParameterType.Hash256)] + internal OracleContract() : base() { } [ContractMethod(CpuFee = 1 << 15, RequiredCallFlags = CallFlags.States)] private void SetPrice(ApplicationEngine engine, long price) @@ -178,10 +134,13 @@ private static byte[] GetUrlHash(string url) return Crypto.Hash160(Utility.StrictUTF8.GetBytes(url)); } - internal override ContractTask Initialize(ApplicationEngine engine) + internal override ContractTask Initialize(ApplicationEngine engine, Hardfork? hardfork) { - engine.Snapshot.Add(CreateStorageKey(Prefix_RequestId), new StorageItem(BigInteger.Zero)); - engine.Snapshot.Add(CreateStorageKey(Prefix_Price), new StorageItem(0_50000000)); + if (hardfork == ActiveIn) + { + engine.Snapshot.Add(CreateStorageKey(Prefix_RequestId), new StorageItem(BigInteger.Zero)); + engine.Snapshot.Add(CreateStorageKey(Prefix_Price), new StorageItem(0_50000000)); + } return ContractTask.CompletedTask; } diff --git a/src/Neo/SmartContract/Native/PolicyContract.cs b/src/Neo/SmartContract/Native/PolicyContract.cs index c633cb7309..5b00af92ad 100644 --- a/src/Neo/SmartContract/Native/PolicyContract.cs +++ b/src/Neo/SmartContract/Native/PolicyContract.cs @@ -64,15 +64,16 @@ public sealed class PolicyContract : NativeContract private const byte Prefix_StoragePrice = 19; private const byte Prefix_AttributeFee = 20; - internal PolicyContract() - { - } + internal PolicyContract() : base() { } - internal override ContractTask Initialize(ApplicationEngine engine) + internal override ContractTask Initialize(ApplicationEngine engine, Hardfork? hardfork) { - 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)); + 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)); + } return ContractTask.CompletedTask; } diff --git a/src/Neo/SmartContract/Native/RoleManagement.cs b/src/Neo/SmartContract/Native/RoleManagement.cs index 1c2fa0a299..6e989b78cf 100644 --- a/src/Neo/SmartContract/Native/RoleManagement.cs +++ b/src/Neo/SmartContract/Native/RoleManagement.cs @@ -12,11 +12,9 @@ using Neo.Cryptography.ECC; using Neo.IO; using Neo.Persistence; -using Neo.SmartContract.Manifest; using Neo.VM; using Neo.VM.Types; using System; -using System.Collections.Generic; using System.Linq; namespace Neo.SmartContract.Native @@ -26,31 +24,10 @@ namespace Neo.SmartContract.Native /// public sealed class RoleManagement : NativeContract { - internal RoleManagement() - { - var events = new List(Manifest.Abi.Events) - { - new ContractEventDescriptor - { - Name = "Designation", - Parameters = new ContractParameterDefinition[] - { - new ContractParameterDefinition() - { - Name = "Role", - Type = ContractParameterType.Integer - }, - new ContractParameterDefinition() - { - Name = "BlockIndex", - Type = ContractParameterType.Integer - } - } - } - }; - - Manifest.Abi.Events = events.ToArray(); - } + [ContractEvent(0, name: "Designation", + "Role", ContractParameterType.Integer, + "BlockIndex", ContractParameterType.Integer)] + internal RoleManagement() : base() { } /// /// Gets the list of nodes for the specified role. diff --git a/src/Neo/SmartContract/Native/StdLib.cs b/src/Neo/SmartContract/Native/StdLib.cs index 3ca836a3ec..f8fa9efcc2 100644 --- a/src/Neo/SmartContract/Native/StdLib.cs +++ b/src/Neo/SmartContract/Native/StdLib.cs @@ -27,7 +27,7 @@ public sealed class StdLib : NativeContract { private const int MaxInputLength = 1024; - internal StdLib() { } + internal StdLib() : base() { } [ContractMethod(CpuFee = 1 << 12)] private static byte[] Serialize(ApplicationEngine engine, StackItem item) diff --git a/src/Neo/SmartContract/StorageItem.cs b/src/Neo/SmartContract/StorageItem.cs index 0f13c3c1f0..41486997de 100644 --- a/src/Neo/SmartContract/StorageItem.cs +++ b/src/Neo/SmartContract/StorageItem.cs @@ -160,6 +160,16 @@ public void Set(BigInteger integer) value = null; } + /// + /// Sets the interoperable value of the storage. + /// + /// The value of the . + public void Set(IInteroperable interoperable) + { + cache = interoperable; + value = null; + } + public static implicit operator BigInteger(StorageItem item) { item.cache ??= new BigInteger(item.value.Span); diff --git a/tests/Neo.UnitTests/SmartContract/Native/UT_ContractEventAttribute.cs b/tests/Neo.UnitTests/SmartContract/Native/UT_ContractEventAttribute.cs new file mode 100644 index 0000000000..ba8f703253 --- /dev/null +++ b/tests/Neo.UnitTests/SmartContract/Native/UT_ContractEventAttribute.cs @@ -0,0 +1,151 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_ContractEventAttribute.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.SmartContract.Native; + +namespace Neo.UnitTests.SmartContract.Native +{ + [TestClass] + public class UT_ContractEventAttribute + { + [TestMethod] + public void TestConstructorOneArg() + { + var arg = new ContractEventAttribute(Hardfork.HF_Basilisk, 0, "1", "a1", ContractParameterType.String); + + Assert.AreEqual(Hardfork.HF_Basilisk, arg.ActiveIn); + Assert.AreEqual(0, arg.Order); + Assert.AreEqual("1", arg.Descriptor.Name); + Assert.AreEqual(1, arg.Descriptor.Parameters.Length); + Assert.AreEqual("a1", arg.Descriptor.Parameters[0].Name); + Assert.AreEqual(ContractParameterType.String, arg.Descriptor.Parameters[0].Type); + + arg = new ContractEventAttribute(1, "1", "a1", ContractParameterType.String); + + Assert.IsNull(arg.ActiveIn); + Assert.AreEqual(1, arg.Order); + Assert.AreEqual("1", arg.Descriptor.Name); + Assert.AreEqual(1, arg.Descriptor.Parameters.Length); + Assert.AreEqual("a1", arg.Descriptor.Parameters[0].Name); + Assert.AreEqual(ContractParameterType.String, arg.Descriptor.Parameters[0].Type); + } + + [TestMethod] + public void TestConstructorTwoArg() + { + var arg = new ContractEventAttribute(Hardfork.HF_Basilisk, 0, "2", + "a1", ContractParameterType.String, + "a2", ContractParameterType.Integer); + + Assert.AreEqual(Hardfork.HF_Basilisk, arg.ActiveIn); + Assert.AreEqual(0, arg.Order); + Assert.AreEqual("2", arg.Descriptor.Name); + Assert.AreEqual(2, arg.Descriptor.Parameters.Length); + Assert.AreEqual("a1", arg.Descriptor.Parameters[0].Name); + Assert.AreEqual(ContractParameterType.String, arg.Descriptor.Parameters[0].Type); + Assert.AreEqual("a2", arg.Descriptor.Parameters[1].Name); + Assert.AreEqual(ContractParameterType.Integer, arg.Descriptor.Parameters[1].Type); + + arg = new ContractEventAttribute(1, "2", + "a1", ContractParameterType.String, + "a2", ContractParameterType.Integer); + + Assert.IsNull(arg.ActiveIn); + Assert.AreEqual(1, arg.Order); + Assert.AreEqual("2", arg.Descriptor.Name); + Assert.AreEqual(2, arg.Descriptor.Parameters.Length); + Assert.AreEqual("a1", arg.Descriptor.Parameters[0].Name); + Assert.AreEqual(ContractParameterType.String, arg.Descriptor.Parameters[0].Type); + Assert.AreEqual("a2", arg.Descriptor.Parameters[1].Name); + Assert.AreEqual(ContractParameterType.Integer, arg.Descriptor.Parameters[1].Type); + } + + [TestMethod] + public void TestConstructorThreeArg() + { + var arg = new ContractEventAttribute(Hardfork.HF_Basilisk, 0, "3", + "a1", ContractParameterType.String, + "a2", ContractParameterType.Integer, + "a3", ContractParameterType.Boolean); + + Assert.AreEqual(Hardfork.HF_Basilisk, arg.ActiveIn); + Assert.AreEqual(0, arg.Order); + Assert.AreEqual("3", arg.Descriptor.Name); + Assert.AreEqual(3, arg.Descriptor.Parameters.Length); + Assert.AreEqual("a1", arg.Descriptor.Parameters[0].Name); + Assert.AreEqual(ContractParameterType.String, arg.Descriptor.Parameters[0].Type); + Assert.AreEqual("a2", arg.Descriptor.Parameters[1].Name); + Assert.AreEqual(ContractParameterType.Integer, arg.Descriptor.Parameters[1].Type); + Assert.AreEqual("a3", arg.Descriptor.Parameters[2].Name); + Assert.AreEqual(ContractParameterType.Boolean, arg.Descriptor.Parameters[2].Type); + + arg = new ContractEventAttribute(1, "3", + "a1", ContractParameterType.String, + "a2", ContractParameterType.Integer, + "a3", ContractParameterType.Boolean); + + Assert.IsNull(arg.ActiveIn); + Assert.AreEqual(1, arg.Order); + Assert.AreEqual("3", arg.Descriptor.Name); + Assert.AreEqual(3, arg.Descriptor.Parameters.Length); + Assert.AreEqual("a1", arg.Descriptor.Parameters[0].Name); + Assert.AreEqual(ContractParameterType.String, arg.Descriptor.Parameters[0].Type); + Assert.AreEqual("a2", arg.Descriptor.Parameters[1].Name); + Assert.AreEqual(ContractParameterType.Integer, arg.Descriptor.Parameters[1].Type); + Assert.AreEqual("a3", arg.Descriptor.Parameters[2].Name); + Assert.AreEqual(ContractParameterType.Boolean, arg.Descriptor.Parameters[2].Type); + } + + [TestMethod] + public void TestConstructorFourArg() + { + var arg = new ContractEventAttribute(Hardfork.HF_Basilisk, 0, "4", + "a1", ContractParameterType.String, + "a2", ContractParameterType.Integer, + "a3", ContractParameterType.Boolean, + "a4", ContractParameterType.Array); + + Assert.AreEqual(Hardfork.HF_Basilisk, arg.ActiveIn); + Assert.AreEqual(0, arg.Order); + Assert.AreEqual("4", arg.Descriptor.Name); + Assert.AreEqual(4, arg.Descriptor.Parameters.Length); + Assert.AreEqual("a1", arg.Descriptor.Parameters[0].Name); + Assert.AreEqual(ContractParameterType.String, arg.Descriptor.Parameters[0].Type); + Assert.AreEqual("a2", arg.Descriptor.Parameters[1].Name); + Assert.AreEqual(ContractParameterType.Integer, arg.Descriptor.Parameters[1].Type); + Assert.AreEqual("a3", arg.Descriptor.Parameters[2].Name); + Assert.AreEqual(ContractParameterType.Boolean, arg.Descriptor.Parameters[2].Type); + Assert.AreEqual("a4", arg.Descriptor.Parameters[3].Name); + Assert.AreEqual(ContractParameterType.Array, arg.Descriptor.Parameters[3].Type); + + arg = new ContractEventAttribute(1, "4", + "a1", ContractParameterType.String, + "a2", ContractParameterType.Integer, + "a3", ContractParameterType.Boolean, + "a4", ContractParameterType.Array); + + Assert.IsNull(arg.ActiveIn); + Assert.AreEqual(1, arg.Order); + Assert.AreEqual("4", arg.Descriptor.Name); + Assert.AreEqual(4, arg.Descriptor.Parameters.Length); + Assert.AreEqual("a1", arg.Descriptor.Parameters[0].Name); + Assert.AreEqual(ContractParameterType.String, arg.Descriptor.Parameters[0].Type); + Assert.AreEqual("a2", arg.Descriptor.Parameters[1].Name); + Assert.AreEqual(ContractParameterType.Integer, arg.Descriptor.Parameters[1].Type); + Assert.AreEqual("a3", arg.Descriptor.Parameters[2].Name); + Assert.AreEqual(ContractParameterType.Boolean, arg.Descriptor.Parameters[2].Type); + Assert.AreEqual("a4", arg.Descriptor.Parameters[3].Name); + Assert.AreEqual(ContractParameterType.Array, arg.Descriptor.Parameters[3].Type); + } + } +} diff --git a/tests/Neo.UnitTests/SmartContract/Native/UT_ContractMethodAttribute.cs b/tests/Neo.UnitTests/SmartContract/Native/UT_ContractMethodAttribute.cs new file mode 100644 index 0000000000..a2b746d7c8 --- /dev/null +++ b/tests/Neo.UnitTests/SmartContract/Native/UT_ContractMethodAttribute.cs @@ -0,0 +1,32 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_ContractMethodAttribute.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.Native; + +namespace Neo.UnitTests.SmartContract.Native +{ + [TestClass] + public class UT_ContractMethodAttribute + { + [TestMethod] + public void TestConstructorOneArg() + { + var arg = new ContractMethodAttribute(); + + Assert.IsNull(arg.ActiveIn); + + arg = new ContractMethodAttribute(Hardfork.HF_Aspidochelone); + + Assert.AreEqual(Hardfork.HF_Aspidochelone, arg.ActiveIn); + } + } +} diff --git a/tests/Neo.UnitTests/SmartContract/Native/UT_CryptoLib.cs b/tests/Neo.UnitTests/SmartContract/Native/UT_CryptoLib.cs index 9e36488031..6f150cca12 100644 --- a/tests/Neo.UnitTests/SmartContract/Native/UT_CryptoLib.cs +++ b/tests/Neo.UnitTests/SmartContract/Native/UT_CryptoLib.cs @@ -15,6 +15,7 @@ using Neo.SmartContract; using Neo.SmartContract.Native; using Neo.VM; +using Org.BouncyCastle.Utilities.Encoders; namespace Neo.UnitTests.SmartContract.Native { @@ -334,5 +335,97 @@ public void TestBls12381ScalarMul_Compat() BLS12381PointType.G2Proj ); } + + /// + /// Keccak256 cases are verified in https://emn178.github.io/online-tools/keccak_256.html + /// + [TestMethod] + public void TestKeccak256_HelloWorld() + { + // Arrange + byte[] inputData = "Hello, World!"u8.ToArray(); + string expectedHashHex = "acaf3289d7b601cbd114fb36c4d29c85bbfd5e133f14cb355c3fd8d99367964f"; + + // Act + byte[] outputData = CryptoLib.Keccak256(inputData); + string outputHashHex = Hex.ToHexString(outputData); + + // Assert + Assert.AreEqual(expectedHashHex, outputHashHex, "Keccak256 hash did not match expected value for 'Hello, World!'."); + } + [TestMethod] + public void TestKeccak256_Keccak() + { + // Arrange + byte[] inputData = "Keccak"u8.ToArray(); + string expectedHashHex = "868c016b666c7d3698636ee1bd023f3f065621514ab61bf26f062c175fdbe7f2"; + + // Act + byte[] outputData = CryptoLib.Keccak256(inputData); + string outputHashHex = Hex.ToHexString(outputData); + + // Assert + Assert.AreEqual(expectedHashHex, outputHashHex, "Keccak256 hash did not match expected value for 'Keccak'."); + } + + [TestMethod] + public void TestKeccak256_Cryptography() + { + // Arrange + byte[] inputData = "Cryptography"u8.ToArray(); + string expectedHashHex = "53d49d225dd2cfe77d8c5e2112bcc9efe77bea1c7aa5e5ede5798a36e99e2d29"; + + // Act + byte[] outputData = CryptoLib.Keccak256(inputData); + string outputHashHex = Hex.ToHexString(outputData); + + // Assert + Assert.AreEqual(expectedHashHex, outputHashHex, "Keccak256 hash did not match expected value for 'Cryptography'."); + } + + [TestMethod] + public void TestKeccak256_Testing123() + { + // Arrange + byte[] inputData = "Testing123"u8.ToArray(); + string expectedHashHex = "3f82db7b16b0818a1c6b2c6152e265f682d5ebcf497c9aad776ad38bc39cb6ca"; + + // Act + byte[] outputData = CryptoLib.Keccak256(inputData); + string outputHashHex = Hex.ToHexString(outputData); + + // Assert + Assert.AreEqual(expectedHashHex, outputHashHex, "Keccak256 hash did not match expected value for 'Testing123'."); + } + + [TestMethod] + public void TestKeccak256_LongString() + { + // Arrange + byte[] inputData = "This is a longer string for Keccak256 testing purposes."u8.ToArray(); + string expectedHashHex = "24115e5c2359f85f6840b42acd2f7ea47bc239583e576d766fa173bf711bdd2f"; + + // Act + byte[] outputData = CryptoLib.Keccak256(inputData); + string outputHashHex = Hex.ToHexString(outputData); + + // Assert + Assert.AreEqual(expectedHashHex, outputHashHex, "Keccak256 hash did not match expected value for the longer string."); + } + + [TestMethod] + public void TestKeccak256_BlankString() + { + // Arrange + byte[] inputData = ""u8.ToArray(); + string expectedHashHex = "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"; + + // Act + byte[] outputData = CryptoLib.Keccak256(inputData); + string outputHashHex = Hex.ToHexString(outputData); + + // Assert + Assert.AreEqual(expectedHashHex, outputHashHex, "Keccak256 hash did not match expected value for blank string."); + } } } diff --git a/tests/Neo.UnitTests/SmartContract/Native/UT_NativeContract.cs b/tests/Neo.UnitTests/SmartContract/Native/UT_NativeContract.cs index 5f4b5b43e0..7f23519e9f 100644 --- a/tests/Neo.UnitTests/SmartContract/Native/UT_NativeContract.cs +++ b/tests/Neo.UnitTests/SmartContract/Native/UT_NativeContract.cs @@ -11,6 +11,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.SmartContract.Native; +using System.IO; namespace Neo.UnitTests.SmartContract.Native { @@ -22,5 +23,25 @@ public void TestGetContract() { Assert.IsTrue(NativeContract.NEO == NativeContract.GetContract(NativeContract.NEO.Hash)); } + + [TestMethod] + public void TestIsInitializeBlock() + { + 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.IsTrue(NativeContract.CryptoLib.IsInitializeBlock(settings, 0, out var hf)); + Assert.IsNull(hf); + + Assert.IsFalse(NativeContract.CryptoLib.IsInitializeBlock(settings, 1, out hf)); + Assert.IsNull(hf); + + Assert.IsTrue(NativeContract.CryptoLib.IsInitializeBlock(settings, 20, out hf)); + Assert.AreEqual(Hardfork.HF_Cockatrice, hf); + } } } diff --git a/tests/Neo.UnitTests/SmartContract/UT_InteropService.cs b/tests/Neo.UnitTests/SmartContract/UT_InteropService.cs index 3798eab327..a0ab12fdc3 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_InteropService.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_InteropService.cs @@ -76,7 +76,7 @@ public void Runtime_GetNotifications_Test() // Wrong length - using (var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot)) + using (var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, null, ProtocolSettings.Default)) using (var script = new ScriptBuilder()) { // Retrive @@ -93,7 +93,7 @@ public void Runtime_GetNotifications_Test() // All test - using (var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot)) + using (var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, null, ProtocolSettings.Default)) using (var script = new ScriptBuilder()) { // Notification @@ -162,7 +162,7 @@ public void Runtime_GetNotifications_Test() // Script notifications - using (var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot)) + using (var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, null, ProtocolSettings.Default)) using (var script = new ScriptBuilder()) { // Notification diff --git a/tests/Neo.UnitTests/SmartContract/UT_JsonSerializer.cs b/tests/Neo.UnitTests/SmartContract/UT_JsonSerializer.cs index 3ab32ad7a5..fc29c95c12 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_JsonSerializer.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_JsonSerializer.cs @@ -272,7 +272,7 @@ public void Serialize_Map_Test() [TestMethod] public void Deserialize_Map_Test() { - ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Application, null, null); + ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Application, null, null, null, ProtocolSettings.Default); var items = JsonSerializer.Deserialize(engine, JObject.Parse("{\"test1\":123,\"test2\":321}"), ExecutionEngineLimits.Default); Assert.IsInstanceOfType(items, typeof(Map)); @@ -302,7 +302,7 @@ public void Serialize_Array_Bool_Str_Num() [TestMethod] public void Deserialize_Array_Bool_Str_Num() { - ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Application, null, null); + ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Application, null, null, null, ProtocolSettings.Default); var items = JsonSerializer.Deserialize(engine, JObject.Parse("[true,\"test\",123,9.05E+28]"), ExecutionEngineLimits.Default); Assert.IsInstanceOfType(items, typeof(VM.Types.Array)); @@ -333,7 +333,7 @@ public void Serialize_Array_OfArray() [TestMethod] public void Deserialize_Array_OfArray() { - ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Application, null, null); + ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Application, null, null, null, ProtocolSettings.Default); var items = JsonSerializer.Deserialize(engine, JObject.Parse("[[true,\"test1\",123],[true,\"test2\",321]]"), ExecutionEngineLimits.Default); Assert.IsInstanceOfType(items, typeof(VM.Types.Array)); diff --git a/tests/Neo.UnitTests/UT_ProtocolSettings.cs b/tests/Neo.UnitTests/UT_ProtocolSettings.cs index 28817bb482..e5d829ef8b 100644 --- a/tests/Neo.UnitTests/UT_ProtocolSettings.cs +++ b/tests/Neo.UnitTests/UT_ProtocolSettings.cs @@ -14,6 +14,7 @@ using Neo.Cryptography.ECC; using Neo.Wallets; using System; +using System.IO; namespace Neo.UnitTests { @@ -48,6 +49,132 @@ public void TestGetMillisecondsPerBlock() TestProtocolSettings.Default.MillisecondsPerBlock.Should().Be(15000); } + [TestMethod] + public void HardForkTestBAndNotA() + { + string json = CreateHKSettings("\"HF_Basilisk\": 4120000"); + + var file = Path.GetTempFileName(); + File.WriteAllText(file, json); + ProtocolSettings settings = ProtocolSettings.Load(file, false); + File.Delete(file); + + settings.Hardforks[Hardfork.HF_Aspidochelone].Should().Be(0); + settings.Hardforks[Hardfork.HF_Basilisk].Should().Be(4120000); + + // Check IsHardforkEnabled + + settings.IsHardforkEnabled(Hardfork.HF_Aspidochelone, 0).Should().BeTrue(); + settings.IsHardforkEnabled(Hardfork.HF_Aspidochelone, 10).Should().BeTrue(); + settings.IsHardforkEnabled(Hardfork.HF_Basilisk, 0).Should().BeFalse(); + settings.IsHardforkEnabled(Hardfork.HF_Basilisk, 10).Should().BeFalse(); + settings.IsHardforkEnabled(Hardfork.HF_Basilisk, 4120000).Should().BeTrue(); + } + + [TestMethod] + public void HardForkTestAAndNotB() + { + string json = CreateHKSettings("\"HF_Aspidochelone\": 0"); + + var file = Path.GetTempFileName(); + File.WriteAllText(file, json); + ProtocolSettings settings = ProtocolSettings.Load(file, false); + File.Delete(file); + + settings.Hardforks[Hardfork.HF_Aspidochelone].Should().Be(0); + settings.Hardforks.ContainsKey(Hardfork.HF_Basilisk).Should().BeFalse(); + + // Check IsHardforkEnabled + + settings.IsHardforkEnabled(Hardfork.HF_Aspidochelone, 0).Should().BeTrue(); + settings.IsHardforkEnabled(Hardfork.HF_Aspidochelone, 10).Should().BeTrue(); + settings.IsHardforkEnabled(Hardfork.HF_Basilisk, 0).Should().BeFalse(); + settings.IsHardforkEnabled(Hardfork.HF_Basilisk, 10).Should().BeFalse(); + settings.IsHardforkEnabled(Hardfork.HF_Basilisk, 4120000).Should().BeFalse(); + } + + [TestMethod] + public void HardForkTestNone() + { + string json = CreateHKSettings(""); + + var file = Path.GetTempFileName(); + File.WriteAllText(file, json); + ProtocolSettings settings = ProtocolSettings.Load(file, false); + File.Delete(file); + + settings.Hardforks[Hardfork.HF_Aspidochelone].Should().Be(0); + settings.Hardforks[Hardfork.HF_Basilisk].Should().Be(0); + + // Check IsHardforkEnabled + + settings.IsHardforkEnabled(Hardfork.HF_Aspidochelone, 0).Should().BeTrue(); + settings.IsHardforkEnabled(Hardfork.HF_Aspidochelone, 10).Should().BeTrue(); + settings.IsHardforkEnabled(Hardfork.HF_Basilisk, 0).Should().BeTrue(); + settings.IsHardforkEnabled(Hardfork.HF_Basilisk, 10).Should().BeTrue(); + } + + [TestMethod] + public void HardForkTestAMoreThanB() + { + string json = CreateHKSettings("\"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) + { + return @" +{ + ""ProtocolConfiguration"": { + ""Network"": 860833102, + ""AddressVersion"": 53, + ""MillisecondsPerBlock"": 15000, + ""MaxTransactionsPerBlock"": 512, + ""MemoryPoolMaxTransactions"": 50000, + ""MaxTraceableBlocks"": 2102400, + ""Hardforks"": { + " + hf + @" + }, + ""InitialGasDistribution"": 5200000000000000, + ""ValidatorsCount"": 7, + ""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"" + ] + } +} +"; + } + [TestMethod] public void TestGetSeedList() { From 022a63e80ee72b07cc3b76e5e95ea14ea0f8d9b7 Mon Sep 17 00:00:00 2001 From: Shargon Date: Fri, 23 Feb 2024 14:14:15 +0100 Subject: [PATCH 091/168] Allow to override sobre properties (#3159) --- src/Neo/SmartContract/ApplicationEngine.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Neo/SmartContract/ApplicationEngine.cs b/src/Neo/SmartContract/ApplicationEngine.cs index 63cbde9960..2b78f62fe4 100644 --- a/src/Neo/SmartContract/ApplicationEngine.cs +++ b/src/Neo/SmartContract/ApplicationEngine.cs @@ -126,7 +126,7 @@ public partial class ApplicationEngine : ExecutionEngine /// /// The script hash of the calling contract. This field could be if the current context is the entry context. /// - public UInt160 CallingScriptHash + public virtual UInt160 CallingScriptHash { get { @@ -139,7 +139,7 @@ public UInt160 CallingScriptHash /// /// The script hash of the entry context. This field could be if no context is loaded to the engine. /// - public UInt160 EntryScriptHash => EntryContext?.GetScriptHash(); + public virtual UInt160 EntryScriptHash => EntryContext?.GetScriptHash(); /// /// The notifications sent during the execution. From 66ef246beb6bdc4b259cf503e345ff695725ebbb Mon Sep 17 00:00:00 2001 From: Shargon Date: Fri, 23 Feb 2024 14:42:54 +0100 Subject: [PATCH 092/168] Expose GetContractState (#3161) * Update NativeContract.cs * Update MemoryStoreProvider.cs * Update Neo.csproj --- src/Neo/Neo.csproj | 1 + src/Neo/Persistence/MemoryStoreProvider.cs | 2 +- src/Neo/SmartContract/Native/NativeContract.cs | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Neo/Neo.csproj b/src/Neo/Neo.csproj index 75541f9091..694f4e1c02 100644 --- a/src/Neo/Neo.csproj +++ b/src/Neo/Neo.csproj @@ -26,6 +26,7 @@ + diff --git a/src/Neo/Persistence/MemoryStoreProvider.cs b/src/Neo/Persistence/MemoryStoreProvider.cs index 23276bce96..e72a13c899 100644 --- a/src/Neo/Persistence/MemoryStoreProvider.cs +++ b/src/Neo/Persistence/MemoryStoreProvider.cs @@ -11,7 +11,7 @@ namespace Neo.Persistence { - internal class MemoryStoreProvider : IStoreProvider + public class MemoryStoreProvider : IStoreProvider { public string Name => nameof(MemoryStore); public IStore GetStore(string path) => new MemoryStore(); diff --git a/src/Neo/SmartContract/Native/NativeContract.cs b/src/Neo/SmartContract/Native/NativeContract.cs index 6d5d105b7d..8d5155ff92 100644 --- a/src/Neo/SmartContract/Native/NativeContract.cs +++ b/src/Neo/SmartContract/Native/NativeContract.cs @@ -199,7 +199,7 @@ private NativeContractsCache.CacheEntry GetAllowedMethods(ProtocolSettings setti /// The where the HardForks are configured. /// Block index /// The . - internal ContractState GetContractState(ProtocolSettings settings, uint index) + public ContractState GetContractState(ProtocolSettings settings, uint index) { // Get allowed methods and nef script NativeContractsCache.CacheEntry allowedMethods = GetAllowedMethods(settings, index); From 937375675e8927d55f7dd826302b3c8d571e181b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vitor=20Naz=C3=A1rio=20Coelho?= Date: Fri, 23 Feb 2024 11:40:23 -0300 Subject: [PATCH 093/168] BLS coverage result has a different name than the rest (#3162) * Update main.yml close https://github.com/neo-project/neo/issues/3160 * the file does not exist on others matrix.os * Update main.yml * Update main.yml * Update main.yml * Update .github/workflows/main.yml Co-authored-by: Shargon --------- Co-authored-by: Jimmy Co-authored-by: Shargon --- .github/workflows/main.yml | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index e643529a27..da9e47f20b 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -27,14 +27,16 @@ jobs: if: matrix.os == 'ubuntu-latest' run: | dotnet format --verify-no-changes --verbosity diagnostic - - name: Prepare coverage + - name: Test + if: matrix.os != 'ubuntu-latest' + run: | + dotnet test + - name: Test for coverall if: matrix.os == 'ubuntu-latest' run: | find tests -name *.csproj | xargs -I % dotnet add % package coverlet.msbuild - - name: Test - run: | - dotnet test ./tests/Neo.ConsoleService.Tests /p:CollectCoverage=true /p:CoverletOutput=${GITHUB_WORKSPACE}/coverage-join/ - dotnet test ./tests/Neo.Cryptography.BLS12_381.Tests /p:CollectCoverage=true /p:CoverletOutput=${GITHUB_WORKSPACE}/coverage-join/ /p:MergeWith=${GITHUB_WORKSPACE}/coverage-join/coverage.net7.0.json + dotnet test ./tests/Neo.Cryptography.BLS12_381.Tests /p:CollectCoverage=true /p:CoverletOutput=${GITHUB_WORKSPACE}/coverage-join/ + dotnet test ./tests/Neo.ConsoleService.Tests /p:CollectCoverage=true /p:CoverletOutput=${GITHUB_WORKSPACE}/coverage-join/ /p:MergeWith=${GITHUB_WORKSPACE}/coverage-join/coverage.json dotnet test ./tests/Neo.UnitTests /p:CollectCoverage=true /p:CoverletOutput=${GITHUB_WORKSPACE}/coverage-join/ /p:MergeWith=${GITHUB_WORKSPACE}/coverage-join/coverage.net7.0.json dotnet test ./tests/Neo.VM.Tests /p:CollectCoverage=true /p:CoverletOutput=${GITHUB_WORKSPACE}/coverage-join/ /p:MergeWith=${GITHUB_WORKSPACE}/coverage-join/coverage.net7.0.json dotnet test ./tests/Neo.Json.UnitTests /p:CollectCoverage=true /p:CoverletOutput=${GITHUB_WORKSPACE}/coverage/lcov /p:MergeWith=${GITHUB_WORKSPACE}/coverage-join/coverage.net7.0.json /p:CoverletOutputFormat=lcov From d4564d1570d14dd4a253a88b14910026432da42f Mon Sep 17 00:00:00 2001 From: Shargon Date: Sat, 24 Feb 2024 00:04:39 +0100 Subject: [PATCH 094/168] Add method in exception (#3164) --- src/Neo/SmartContract/ApplicationEngine.Contract.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Neo/SmartContract/ApplicationEngine.Contract.cs b/src/Neo/SmartContract/ApplicationEngine.Contract.cs index 5e45ba4645..1677396f1c 100644 --- a/src/Neo/SmartContract/ApplicationEngine.Contract.cs +++ b/src/Neo/SmartContract/ApplicationEngine.Contract.cs @@ -77,7 +77,7 @@ protected internal void CallContract(UInt160 contractHash, string method, CallFl throw new ArgumentOutOfRangeException(nameof(callFlags)); ContractState contract = NativeContract.ContractManagement.GetContract(Snapshot, contractHash); - if (contract is null) throw new InvalidOperationException($"Called Contract Does Not Exist: {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}."); bool hasReturnValue = md.ReturnType != ContractParameterType.Void; From 0de52d2ef7a3acb5daa2a0f7d8c480dabcf82705 Mon Sep 17 00:00:00 2001 From: Shargon Date: Mon, 26 Feb 2024 14:35:39 +0100 Subject: [PATCH 095/168] Add committee change events (#3158) * Add committee change events * Update src/Neo/SmartContract/Native/NeoToken.cs * Update src/Neo/SmartContract/Native/NeoToken.cs --- src/Neo/SmartContract/Native/NeoToken.cs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/Neo/SmartContract/Native/NeoToken.cs b/src/Neo/SmartContract/Native/NeoToken.cs index ed796a9756..72c92a14bc 100644 --- a/src/Neo/SmartContract/Native/NeoToken.cs +++ b/src/Neo/SmartContract/Native/NeoToken.cs @@ -63,6 +63,9 @@ public sealed class NeoToken : FungibleToken "from", ContractParameterType.PublicKey, "to", ContractParameterType.PublicKey, "amount", ContractParameterType.Integer)] + [ContractEvent(3, name: "CommitteeChanged", + "old", ContractParameterType.Array, + "new", ContractParameterType.Array)] internal NeoToken() : base() { this.TotalAmount = 100000000 * Factor; @@ -192,10 +195,23 @@ internal override ContractTask OnPersist(ApplicationEngine engine) // Set next committee if (ShouldRefreshCommittee(engine.PersistingBlock.Index, engine.ProtocolSettings.CommitteeMembersCount)) { - StorageItem storageItem = engine.Snapshot.GetAndChange(CreateStorageKey(Prefix_Committee)); + var storageItem = engine.Snapshot.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)); + + var newCommittee = cachedCommittee.Select(u => u.PublicKey).ToArray(); + + if (!newCommittee.SequenceEqual(prevCommittee)) + { + engine.SendNotification(Hash, "CommitteeChanged", new VM.Types.Array(engine.ReferenceCounter) { + new VM.Types.Array(engine.ReferenceCounter, prevCommittee.Select(u => (ByteString)u.ToArray())) , + new VM.Types.Array(engine.ReferenceCounter, newCommittee.Select(u => (ByteString)u.ToArray())) + }); + } } return ContractTask.CompletedTask; } From d3c91750cc64f16bacecec0eaebd52cf1a35f882 Mon Sep 17 00:00:00 2001 From: Shargon Date: Fri, 1 Mar 2024 16:01:14 -0800 Subject: [PATCH 096/168] Expose committee address (#3154) * Update manifest * Fix comment * Format & fix methods * Fix new * Initialize storage fixes * Fix IsInitializeBlock * Fix update * Fix GetContractState * Optimize * Fix first invoke without sync * Remove current methods * Clean usings * Improve reading Initialize * Clean OnManifestCompose * Use cache for all native contracts * Fix ut * Move cache to ApplicationEngine * Clean code * Allow nullable attribute * Update src/Neo/SmartContract/Native/ContractEventAttribute.cs * Add base call * Fix one https://github.com/neo-project/neo/pull/2941#discussion_r1382434903 * Fix IsInitializeBlock https://github.com/neo-project/neo/pull/2941#discussion_r1382434903 * Add ContractEventAttribute constructors for ActiveIn * Ensure ommited hfs * Rename * Case insensitive hf config * Increase coverage * More uts * Rename * Update src/Neo/SmartContract/Native/ContractManagement.cs * format code * Fix ProtocolSettings * Update src/Neo/SmartContract/ApplicationEngine.cs * format * reorder using * Fix UT * Adding keccak256 (#2925) * Create codeql.yml * Keccak256 * Delete .github/workflows/codeql.yml * Update src/Neo/SmartContract/Native/CryptoLib.cs * add more keccak256 test cases as required * Create codeql.yml * Keccak256 * Delete .github/workflows/codeql.yml * Update src/Neo/SmartContract/Native/CryptoLib.cs * add more keccak256 test cases as required * HF_Manticore * Fix copyright * Create codeql.yml * Keccak256 * Delete .github/workflows/codeql.yml * Update src/Neo/SmartContract/Native/CryptoLib.cs * add more keccak256 test cases as required * Create codeql.yml * Keccak256 * Delete .github/workflows/codeql.yml * Update src/Neo/SmartContract/Native/CryptoLib.cs * add more keccak256 test cases as required * HF_Manticore * Fix copyright * HF_Manticore * Update CryptoLib.cs * Update CryptoLib.cs * Update UT_CryptoLib.cs * Apply suggestions from code review * clean usings --------- Co-authored-by: Shargon * Fix net standard * Add ut * Fix update * Fix update * Expose `GetCommitteeAddress` * Update src/Neo/SmartContract/Native/NeoToken.cs --------- Co-authored-by: Jimmy --- src/Neo/SmartContract/Native/NeoToken.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Neo/SmartContract/Native/NeoToken.cs b/src/Neo/SmartContract/Native/NeoToken.cs index 72c92a14bc..96e362dd33 100644 --- a/src/Neo/SmartContract/Native/NeoToken.cs +++ b/src/Neo/SmartContract/Native/NeoToken.cs @@ -480,6 +480,7 @@ public NeoAccountState GetAccountState(DataCache snapshot, UInt160 account) /// /// The snapshot used to read data. /// The address of the committee. + [ContractMethod(Hardfork.HF_Cockatrice, CpuFee = 1 << 16, RequiredCallFlags = CallFlags.ReadStates)] public UInt160 GetCommitteeAddress(DataCache snapshot) { ECPoint[] committees = GetCommittee(snapshot); From 934b2e8004522be08cc41524b4e2d50068304f83 Mon Sep 17 00:00:00 2001 From: Shargon Date: Sun, 3 Mar 2024 12:59:41 -0800 Subject: [PATCH 097/168] Allow to get the native contract state without a projectSettings (#3171) * Allow to get the contract state without a projectSettings * AggressiveInlining --- .../SmartContract/Native/NativeContract.cs | 29 +++++++++++++------ 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/src/Neo/SmartContract/Native/NativeContract.cs b/src/Neo/SmartContract/Native/NativeContract.cs index 8d5155ff92..a07f0ac8ce 100644 --- a/src/Neo/SmartContract/Native/NativeContract.cs +++ b/src/Neo/SmartContract/Native/NativeContract.cs @@ -18,6 +18,7 @@ using System.Collections.ObjectModel; using System.Linq; using System.Reflection; +using System.Runtime.CompilerServices; namespace Neo.SmartContract.Native { @@ -41,12 +42,13 @@ 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; - CacheEntry methods = native.GetAllowedMethods(engine.ProtocolSettings, index); + CacheEntry methods = native.GetAllowedMethods(engine.ProtocolSettings.IsHardforkEnabled, index); NativeContracts[native.Id] = methods; return methods; } } + public delegate bool IsHardforkEnabledDelegate(Hardfork hf, uint index); private static readonly List contractsList = new(); private static readonly Dictionary contractsDictionary = new(); private readonly ImmutableHashSet usedHardforks; @@ -168,10 +170,10 @@ protected NativeContract() /// /// The allowed methods and his offsets. /// - /// The where the HardForks are configured. + /// Hardfork checker /// Block index /// The . - private NativeContractsCache.CacheEntry GetAllowedMethods(ProtocolSettings settings, uint index) + private NativeContractsCache.CacheEntry GetAllowedMethods(IsHardforkEnabledDelegate hfChecker, uint index) { Dictionary methods = new(); @@ -179,7 +181,7 @@ private NativeContractsCache.CacheEntry GetAllowedMethods(ProtocolSettings setti byte[] script; using (ScriptBuilder sb = new()) { - foreach (ContractMethodMetadata method in methodDescriptors.Where(u => u.ActiveIn is null || settings.IsHardforkEnabled(u.ActiveIn.Value, index))) + foreach (ContractMethodMetadata method in methodDescriptors.Where(u => u.ActiveIn is null || hfChecker(u.ActiveIn.Value, index))) { method.Descriptor.Offset = sb.Length; sb.EmitPush(0); //version @@ -199,13 +201,22 @@ private NativeContractsCache.CacheEntry GetAllowedMethods(ProtocolSettings setti /// The where the HardForks are configured. /// Block index /// The . - public ContractState GetContractState(ProtocolSettings settings, uint index) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ContractState GetContractState(ProtocolSettings settings, uint index) => GetContractState(settings.IsHardforkEnabled, index); + + /// + /// The of the native contract. + /// + /// Hardfork checker + /// Block index + /// The . + public ContractState GetContractState(IsHardforkEnabledDelegate hfChecker, uint index) { // Get allowed methods and nef script - NativeContractsCache.CacheEntry allowedMethods = GetAllowedMethods(settings, index); + var allowedMethods = GetAllowedMethods(hfChecker, index); // Compose nef file - NefFile nef = new() + var nef = new NefFile() { Compiler = "neo-core-v3.0", Source = string.Empty, @@ -215,7 +226,7 @@ public ContractState GetContractState(ProtocolSettings settings, uint index) nef.CheckSum = NefFile.ComputeChecksum(nef); // Compose manifest - ContractManifest manifest = new() + var manifest = new ContractManifest() { Name = Name, Groups = Array.Empty(), @@ -223,7 +234,7 @@ public ContractState GetContractState(ProtocolSettings settings, uint index) Abi = new ContractAbi() { Events = eventsDescriptors - .Where(u => u.ActiveIn is null || settings.IsHardforkEnabled(u.ActiveIn.Value, index)) + .Where(u => u.ActiveIn is null || hfChecker(u.ActiveIn.Value, index)) .Select(p => p.Descriptor).ToArray(), Methods = allowedMethods.Methods.Values .Select(p => p.Descriptor).ToArray() From 74562d57ff9b4e20968dd2bbfcfc9cfa66e5f08a Mon Sep 17 00:00:00 2001 From: Anna Shaleva Date: Mon, 4 Mar 2024 00:41:35 +0300 Subject: [PATCH 098/168] Add P2PNotary node role for native RoleManagement contract (#3172) * Add P2PNotary node role for native RoleManagement contract Close #2895. Signed-off-by: Anna Shaleva * Squash TestDesignateP2PNotary and TestGetSet of native RoleManagement Extend TestGetSet to check designation of all node roles, including P2PNotary role. TestDesignatedP2PNotary is not needed anymore. Signed-off-by: Anna Shaleva --------- Signed-off-by: Anna Shaleva Co-authored-by: Shargon --- src/Neo/SmartContract/Native/Role.cs | 7 +- .../SmartContract/Native/UT_RoleManagement.cs | 96 +++++++++++-------- 2 files changed, 60 insertions(+), 43 deletions(-) diff --git a/src/Neo/SmartContract/Native/Role.cs b/src/Neo/SmartContract/Native/Role.cs index c0954d8fcd..710cc6f390 100644 --- a/src/Neo/SmartContract/Native/Role.cs +++ b/src/Neo/SmartContract/Native/Role.cs @@ -29,6 +29,11 @@ public enum Role : byte /// /// NeoFS Alphabet nodes. /// - NeoFSAlphabetNode = 16 + NeoFSAlphabetNode = 16, + + /// + /// P2P Notary nodes used to process P2P notary requests. + /// + P2PNotary = 32 } } diff --git a/tests/Neo.UnitTests/SmartContract/Native/UT_RoleManagement.cs b/tests/Neo.UnitTests/SmartContract/Native/UT_RoleManagement.cs index a87c630194..25ca7ee0d6 100644 --- a/tests/Neo.UnitTests/SmartContract/Native/UT_RoleManagement.cs +++ b/tests/Neo.UnitTests/SmartContract/Native/UT_RoleManagement.cs @@ -18,6 +18,7 @@ using Neo.SmartContract; using Neo.SmartContract.Native; using Neo.UnitTests.Extensions; +using Neo.Wallets; using System; using System.Collections.Generic; using System.Linq; @@ -45,49 +46,60 @@ public void Clean() [TestMethod] public void TestSetAndGet() { - var snapshot1 = _snapshot.CreateSnapshot(); - UInt160 committeeMultiSigAddr = NativeContract.NEO.GetCommitteeAddress(snapshot1); - ECPoint[] validators = NativeContract.NEO.ComputeNextBlockValidators(snapshot1, TestProtocolSettings.Default); - List notifications = new List(); - EventHandler ev = (o, e) => notifications.Add(e); - ApplicationEngine.Notify += ev; - var ret = NativeContract.RoleManagement.Call( - snapshot1, - new Nep17NativeContractExtensions.ManualWitness(committeeMultiSigAddr), - new Block { Header = new Header() }, - "designateAsRole", - new ContractParameter(ContractParameterType.Integer) { Value = new BigInteger((int)Role.StateValidator) }, - new ContractParameter(ContractParameterType.Array) { Value = validators.Select(p => new ContractParameter(ContractParameterType.ByteArray) { Value = p.ToArray() }).ToList() } - ); - snapshot1.Commit(); - ApplicationEngine.Notify -= ev; - notifications.Count.Should().Be(1); - notifications[0].EventName.Should().Be("Designation"); - var snapshot2 = _snapshot.CreateSnapshot(); - ret = NativeContract.RoleManagement.Call( - snapshot2, - "getDesignatedByRole", - new ContractParameter(ContractParameterType.Integer) { Value = new BigInteger((int)Role.StateValidator) }, - new ContractParameter(ContractParameterType.Integer) { Value = new BigInteger(1u) } - ); - ret.Should().BeOfType(); - (ret as VM.Types.Array).Count.Should().Be(7); - (ret as VM.Types.Array)[0].GetSpan().ToHexString().Should().Be(validators[0].ToArray().ToHexString()); - (ret as VM.Types.Array)[1].GetSpan().ToHexString().Should().Be(validators[1].ToArray().ToHexString()); - (ret as VM.Types.Array)[2].GetSpan().ToHexString().Should().Be(validators[2].ToArray().ToHexString()); - (ret as VM.Types.Array)[3].GetSpan().ToHexString().Should().Be(validators[3].ToArray().ToHexString()); - (ret as VM.Types.Array)[4].GetSpan().ToHexString().Should().Be(validators[4].ToArray().ToHexString()); - (ret as VM.Types.Array)[5].GetSpan().ToHexString().Should().Be(validators[5].ToArray().ToHexString()); - (ret as VM.Types.Array)[6].GetSpan().ToHexString().Should().Be(validators[6].ToArray().ToHexString()); + byte[] privateKey1 = new byte[32]; + var rng1 = System.Security.Cryptography.RandomNumberGenerator.Create(); + rng1.GetBytes(privateKey1); + KeyPair key1 = new KeyPair(privateKey1); + byte[] privateKey2 = new byte[32]; + var rng2 = System.Security.Cryptography.RandomNumberGenerator.Create(); + rng2.GetBytes(privateKey2); + KeyPair key2 = new KeyPair(privateKey2); + ECPoint[] publicKeys = new ECPoint[2]; + publicKeys[0] = key1.PublicKey; + publicKeys[1] = key2.PublicKey; + publicKeys = publicKeys.OrderBy(p => p).ToArray(); - ret = NativeContract.RoleManagement.Call( - snapshot2, - "getDesignatedByRole", - new ContractParameter(ContractParameterType.Integer) { Value = new BigInteger((int)Role.StateValidator) }, - new ContractParameter(ContractParameterType.Integer) { Value = new BigInteger(0) } - ); - ret.Should().BeOfType(); - (ret as VM.Types.Array).Count.Should().Be(0); + List roles = new List() { Role.StateValidator, Role.Oracle, Role.NeoFSAlphabetNode, Role.P2PNotary }; + foreach (var role in roles) + { + var snapshot1 = _snapshot.CreateSnapshot(); + UInt160 committeeMultiSigAddr = NativeContract.NEO.GetCommitteeAddress(snapshot1); + List notifications = new List(); + EventHandler ev = (o, e) => notifications.Add(e); + ApplicationEngine.Notify += ev; + var ret = NativeContract.RoleManagement.Call( + snapshot1, + new Nep17NativeContractExtensions.ManualWitness(committeeMultiSigAddr), + new Block { Header = new Header() }, + "designateAsRole", + new ContractParameter(ContractParameterType.Integer) { Value = new BigInteger((int)role) }, + new ContractParameter(ContractParameterType.Array) { Value = publicKeys.Select(p => new ContractParameter(ContractParameterType.ByteArray) { Value = p.ToArray() }).ToList() } + ); + snapshot1.Commit(); + ApplicationEngine.Notify -= ev; + notifications.Count.Should().Be(1); + notifications[0].EventName.Should().Be("Designation"); + var snapshot2 = _snapshot.CreateSnapshot(); + ret = NativeContract.RoleManagement.Call( + snapshot2, + "getDesignatedByRole", + new ContractParameter(ContractParameterType.Integer) { Value = new BigInteger((int)role) }, + new ContractParameter(ContractParameterType.Integer) { Value = new BigInteger(1u) } + ); + ret.Should().BeOfType(); + (ret as VM.Types.Array).Count.Should().Be(2); + (ret as VM.Types.Array)[0].GetSpan().ToHexString().Should().Be(publicKeys[0].ToArray().ToHexString()); + (ret as VM.Types.Array)[1].GetSpan().ToHexString().Should().Be(publicKeys[1].ToArray().ToHexString()); + + ret = NativeContract.RoleManagement.Call( + snapshot2, + "getDesignatedByRole", + new ContractParameter(ContractParameterType.Integer) { Value = new BigInteger((int)role) }, + new ContractParameter(ContractParameterType.Integer) { Value = new BigInteger(0) } + ); + ret.Should().BeOfType(); + (ret as VM.Types.Array).Count.Should().Be(0); + } } private void ApplicationEngine_Notify(object sender, NotifyEventArgs e) From 199ffee46ba2364a1ca53ce6e4d0a8768c7625ef Mon Sep 17 00:00:00 2001 From: Shine Li Date: Thu, 7 Mar 2024 15:26:33 +0800 Subject: [PATCH 099/168] Optimize crypto (#3174) * init * fotmat * fifo cache * Clean * Fix ECPoint Bug * Fix UT --------- Co-authored-by: Shargon --- src/Neo/Cryptography/Crypto.cs | 47 +++++++++++++------ src/Neo/Cryptography/ECC/ECPoint.cs | 1 + src/Neo/IO/Caching/ECDsaCache.cs | 32 +++++++++++++ .../Cryptography/ECC/UT_ECPoint.cs | 4 +- 4 files changed, 68 insertions(+), 16 deletions(-) create mode 100644 src/Neo/IO/Caching/ECDsaCache.cs diff --git a/src/Neo/Cryptography/Crypto.cs b/src/Neo/Cryptography/Crypto.cs index e09b556d82..5d8a34939d 100644 --- a/src/Neo/Cryptography/Crypto.cs +++ b/src/Neo/Cryptography/Crypto.cs @@ -9,6 +9,7 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using Neo.IO.Caching; using System; using System.Runtime.InteropServices; using System.Security.Cryptography; @@ -20,6 +21,7 @@ namespace Neo.Cryptography /// public static class Crypto { + private static readonly ECDsaCache CacheECDsa = new(); private static readonly bool IsOSX = RuntimeInformation.IsOSPlatform(OSPlatform.OSX); /// @@ -94,24 +96,41 @@ public static bool VerifySignature(ReadOnlySpan message, ReadOnlySpan + /// Create and cache ECDsa objects + /// + /// + /// Cached ECDsa + /// + public static ECDsa CreateECDsa(ECC.ECPoint pubkey) + { + if (CacheECDsa.TryGet(pubkey, out var cache)) + { + return cache.value; + } + var curve = + pubkey.Curve == ECC.ECCurve.Secp256r1 ? ECCurve.NamedCurves.nistP256 : + pubkey.Curve == ECC.ECCurve.Secp256k1 ? ECCurve.CreateFromFriendlyName("secP256k1") : + throw new NotSupportedException(); + var buffer = pubkey.EncodePoint(false); + var ecdsa = ECDsa.Create(new ECParameters + { + Curve = curve, + Q = new ECPoint + { + X = buffer[1..33], + Y = buffer[33..] + } + }); + CacheECDsa.Add(new ECDsaCacheItem(pubkey, ecdsa)); + return ecdsa; + } + /// /// Verifies that a digital signature is appropriate for the provided key and message. /// diff --git a/src/Neo/Cryptography/ECC/ECPoint.cs b/src/Neo/Cryptography/ECC/ECPoint.cs index b2d44bf6cf..5986634d9d 100644 --- a/src/Neo/Cryptography/ECC/ECPoint.cs +++ b/src/Neo/Cryptography/ECC/ECPoint.cs @@ -202,6 +202,7 @@ public bool Equals(ECPoint other) { if (ReferenceEquals(this, other)) return true; if (other is null) return false; + if (!Curve.Equals(other.Curve)) return false; if (IsInfinity && other.IsInfinity) return true; if (IsInfinity || other.IsInfinity) return false; return X.Equals(other.X) && Y.Equals(other.Y); diff --git a/src/Neo/IO/Caching/ECDsaCache.cs b/src/Neo/IO/Caching/ECDsaCache.cs new file mode 100644 index 0000000000..f728195168 --- /dev/null +++ b/src/Neo/IO/Caching/ECDsaCache.cs @@ -0,0 +1,32 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// ECDsaCache.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; +using System; +using System.Collections.Generic; +using System.Security.Cryptography; +using System.Text; + +namespace Neo.IO.Caching +{ + record ECDsaCacheItem(Cryptography.ECC.ECPoint key, ECDsa value); + internal class ECDsaCache : FIFOCache + { + public ECDsaCache(int max_capacity = 20000) : base(max_capacity, EqualityComparer.Default) + { + } + + protected override Cryptography.ECC.ECPoint GetKeyForItem(ECDsaCacheItem item) + { + return item.key; + } + } +} diff --git a/tests/Neo.UnitTests/Cryptography/ECC/UT_ECPoint.cs b/tests/Neo.UnitTests/Cryptography/ECC/UT_ECPoint.cs index ee56b3c57e..4b0c7d484f 100644 --- a/tests/Neo.UnitTests/Cryptography/ECC/UT_ECPoint.cs +++ b/tests/Neo.UnitTests/Cryptography/ECC/UT_ECPoint.cs @@ -175,7 +175,7 @@ public void TestEquals() point.Equals(null).Should().BeFalse(); point = new ECPoint(null, null, ECCurve.Secp256k1); - point.Equals(new ECPoint(null, null, ECCurve.Secp256r1)).Should().BeTrue(); + point.Equals(new ECPoint(null, null, ECCurve.Secp256r1)).Should().BeFalse(); point.Equals(ECCurve.Secp256r1.G).Should().BeFalse(); ECCurve.Secp256r1.G.Equals(point).Should().BeFalse(); @@ -199,7 +199,7 @@ public void TestEqualsObject() point.Equals(1u).Should().BeFalse(); point = new ECPoint(null, null, ECCurve.Secp256k1); - point.Equals(new ECPoint(null, null, ECCurve.Secp256r1)).Should().BeTrue(); + point.Equals(new ECPoint(null, null, ECCurve.Secp256r1)).Should().BeFalse(); point.Equals(ECCurve.Secp256r1.G).Should().BeFalse(); ECCurve.Secp256r1.G.Equals(point).Should().BeFalse(); From 413cfc4c7d7fea073b0b88cae917791dfa4383c3 Mon Sep 17 00:00:00 2001 From: Shargon Date: Thu, 7 Mar 2024 01:19:09 -0800 Subject: [PATCH 100/168] Optimize contract calls (#3170) * Avoid load nefFile without some checksum * Core's feedback * Anna's feedback * Add defaults --- src/Neo/SmartContract/ContractState.cs | 13 ++++++--- .../SmartContract/IInteroperableVerifiable.cs | 29 +++++++++++++++++++ .../Native/ContractManagement.cs | 10 +++---- src/Neo/SmartContract/NefFile.cs | 25 ++++++++++++++-- src/Neo/SmartContract/StorageItem.cs | 18 ++++++++++++ 5 files changed, 83 insertions(+), 12 deletions(-) create mode 100644 src/Neo/SmartContract/IInteroperableVerifiable.cs diff --git a/src/Neo/SmartContract/ContractState.cs b/src/Neo/SmartContract/ContractState.cs index 83ac9d3353..5b413c41a4 100644 --- a/src/Neo/SmartContract/ContractState.cs +++ b/src/Neo/SmartContract/ContractState.cs @@ -23,7 +23,7 @@ namespace Neo.SmartContract /// /// Represents a deployed contract. /// - public class ContractState : IInteroperable + public class ContractState : IInteroperableVerifiable { /// /// The id of the contract. @@ -69,7 +69,7 @@ IInteroperable IInteroperable.Clone() void IInteroperable.FromReplica(IInteroperable replica) { - ContractState from = (ContractState)replica; + var from = (ContractState)replica; Id = from.Id; UpdateCounter = from.UpdateCounter; Hash = from.Hash; @@ -79,11 +79,16 @@ void IInteroperable.FromReplica(IInteroperable replica) void IInteroperable.FromStackItem(StackItem stackItem) { - Array array = (Array)stackItem; + ((IInteroperableVerifiable)this).FromStackItem(stackItem, true); + } + + void IInteroperableVerifiable.FromStackItem(StackItem stackItem, bool verify) + { + var array = (Array)stackItem; Id = (int)array[0].GetInteger(); UpdateCounter = (ushort)array[1].GetInteger(); Hash = new UInt160(array[2].GetSpan()); - Nef = ((ByteString)array[3]).Memory.AsSerializable(); + Nef = NefFile.Parse(((ByteString)array[3]).Memory, verify); Manifest = array[4].ToInteroperable(); } diff --git a/src/Neo/SmartContract/IInteroperableVerifiable.cs b/src/Neo/SmartContract/IInteroperableVerifiable.cs new file mode 100644 index 0000000000..c8af7b8a5e --- /dev/null +++ b/src/Neo/SmartContract/IInteroperableVerifiable.cs @@ -0,0 +1,29 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// IInteroperableVerifiable.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.SmartContract +{ + /// + /// Represents the object that can be converted to and from + /// and allows you to specify whether a verification is required. + /// + public interface IInteroperableVerifiable : IInteroperable + { + /// + /// Convert a to the current object. + /// + /// The to convert. + /// Verify the content + void FromStackItem(StackItem stackItem, bool verify = true); + } +} diff --git a/src/Neo/SmartContract/Native/ContractManagement.cs b/src/Neo/SmartContract/Native/ContractManagement.cs index 3347163a6c..28642a2db1 100644 --- a/src/Neo/SmartContract/Native/ContractManagement.cs +++ b/src/Neo/SmartContract/Native/ContractManagement.cs @@ -84,7 +84,7 @@ internal override async ContractTask OnPersist(ApplicationEngine engine) else { // Parse old contract - var oldContract = state.GetInteroperable(); + var oldContract = state.GetInteroperable(false); // Increase the update counter oldContract.UpdateCounter++; // Modify nef and manifest @@ -122,7 +122,7 @@ private void SetMinimumDeploymentFee(ApplicationEngine engine, BigInteger value) [ContractMethod(CpuFee = 1 << 15, RequiredCallFlags = CallFlags.ReadStates)] public ContractState GetContract(DataCache snapshot, UInt160 hash) { - return snapshot.TryGet(CreateStorageKey(Prefix_Contract).Add(hash))?.GetInteroperable(); + return snapshot.TryGet(CreateStorageKey(Prefix_Contract).Add(hash))?.GetInteroperable(false); } /// @@ -183,7 +183,7 @@ public bool HasMethod(DataCache snapshot, UInt160 hash, string method, int pcoun public IEnumerable ListContracts(DataCache snapshot) { byte[] listContractsPrefix = CreateStorageKey(Prefix_Contract).ToArray(); - return snapshot.Find(listContractsPrefix).Select(kvp => kvp.Value.GetInteroperable()); + return snapshot.Find(listContractsPrefix).Select(kvp => kvp.Value.GetInteroperable(false)); } [ContractMethod(RequiredCallFlags = CallFlags.All)] @@ -250,7 +250,7 @@ private ContractTask Update(ApplicationEngine engine, byte[] nefFile, byte[] man engine.AddGas(engine.StoragePrice * ((nefFile?.Length ?? 0) + (manifest?.Length ?? 0))); - var contract = engine.Snapshot.GetAndChange(CreateStorageKey(Prefix_Contract).Add(engine.CallingScriptHash))?.GetInteroperable(); + var contract = engine.Snapshot.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."); @@ -283,7 +283,7 @@ private void Destroy(ApplicationEngine engine) { UInt160 hash = engine.CallingScriptHash; StorageKey ckey = CreateStorageKey(Prefix_Contract).Add(hash); - ContractState contract = engine.Snapshot.TryGet(ckey)?.GetInteroperable(); + ContractState contract = engine.Snapshot.TryGet(ckey)?.GetInteroperable(false); if (contract is null) return; engine.Snapshot.Delete(ckey); engine.Snapshot.Delete(CreateStorageKey(Prefix_ContractHash).AddBigEndian(contract.Id)); diff --git a/src/Neo/SmartContract/NefFile.cs b/src/Neo/SmartContract/NefFile.cs index 1ffa7baf20..3e343d3be2 100644 --- a/src/Neo/SmartContract/NefFile.cs +++ b/src/Neo/SmartContract/NefFile.cs @@ -86,6 +86,20 @@ public class NefFile : ISerializable Script.GetVarSize() + // Script sizeof(uint); // Checksum + /// + /// Parse NefFile from memory + /// + /// Memory + /// Do checksum and MaxItemSize checks + /// NefFile + public static NefFile Parse(ReadOnlyMemory memory, bool verify = true) + { + var reader = new MemoryReader(memory); + var nef = new NefFile(); + nef.Deserialize(ref reader, verify); + return nef; + } + public void Serialize(BinaryWriter writer) { SerializeHeader(writer); @@ -103,7 +117,9 @@ private void SerializeHeader(BinaryWriter writer) writer.WriteFixedString(Compiler, 64); } - public void Deserialize(ref MemoryReader reader) + public void Deserialize(ref MemoryReader reader) => Deserialize(ref reader, true); + + public void Deserialize(ref MemoryReader reader, bool verify = true) { long startPosition = reader.Position; if (reader.ReadUInt32() != Magic) throw new FormatException("Wrong magic"); @@ -115,8 +131,11 @@ public void Deserialize(ref MemoryReader reader) Script = reader.ReadVarMemory((int)ExecutionEngineLimits.Default.MaxItemSize); if (Script.Length == 0) throw new ArgumentException($"Script can't be empty"); CheckSum = reader.ReadUInt32(); - if (CheckSum != ComputeChecksum(this)) throw new FormatException("CRC verification fail"); - if (reader.Position - startPosition > ExecutionEngineLimits.Default.MaxItemSize) throw new FormatException("Max vm item size exceed"); + if (verify) + { + if (CheckSum != ComputeChecksum(this)) throw new FormatException("CRC verification fail"); + if (reader.Position - startPosition > ExecutionEngineLimits.Default.MaxItemSize) throw new FormatException("Max vm item size exceed"); + } } /// diff --git a/src/Neo/SmartContract/StorageItem.cs b/src/Neo/SmartContract/StorageItem.cs index 41486997de..350e95e70a 100644 --- a/src/Neo/SmartContract/StorageItem.cs +++ b/src/Neo/SmartContract/StorageItem.cs @@ -145,6 +145,24 @@ public void FromReplica(StorageItem replica) return (T)cache; } + /// + /// Gets an from the storage. + /// + /// Verify deserialization + /// The type of the . + /// The in the storage. + public T GetInteroperable(bool verify = true) where T : IInteroperableVerifiable, new() + { + if (cache is null) + { + var interoperable = new T(); + interoperable.FromStackItem(BinarySerializer.Deserialize(value, ExecutionEngineLimits.Default), verify); + cache = interoperable; + } + value = null; + return (T)cache; + } + public void Serialize(BinaryWriter writer) { writer.Write(Value.Span); From b05501af882a0d1f2a1a7841c6ddc4d0504e5fc1 Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Fri, 8 Mar 2024 02:28:55 +0300 Subject: [PATCH 101/168] NEO: clear LastGasPerVote when voting for NULL, fix #2894 (#3173) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This value won't be used in any way, so save some bytes of storage. Signed-off-by: Roman Khimov Co-authored-by: Shargon Co-authored-by: Vitor Nazário Coelho --- src/Neo/SmartContract/Native/NeoToken.cs | 4 ++++ tests/Neo.UnitTests/SmartContract/Native/UT_NeoToken.cs | 3 +++ 2 files changed, 7 insertions(+) diff --git a/src/Neo/SmartContract/Native/NeoToken.cs b/src/Neo/SmartContract/Native/NeoToken.cs index 96e362dd33..c28a548d0e 100644 --- a/src/Neo/SmartContract/Native/NeoToken.cs +++ b/src/Neo/SmartContract/Native/NeoToken.cs @@ -393,6 +393,10 @@ private async ContractTask Vote(ApplicationEngine engine, UInt160 account, { validator_new.Votes += state_account.Balance; } + else + { + state_account.LastGasPerVote = 0; + } engine.SendNotification(Hash, "Vote", new VM.Types.Array(engine.ReferenceCounter) { account.ToArray(), from?.ToArray() ?? StackItem.Null, voteTo?.ToArray() ?? StackItem.Null, state_account.Balance }); if (gasDistribution is not null) diff --git a/tests/Neo.UnitTests/SmartContract/Native/UT_NeoToken.cs b/tests/Neo.UnitTests/SmartContract/Native/UT_NeoToken.cs index 73cf286652..0a19314153 100644 --- a/tests/Neo.UnitTests/SmartContract/Native/UT_NeoToken.cs +++ b/tests/Neo.UnitTests/SmartContract/Native/UT_NeoToken.cs @@ -192,11 +192,13 @@ public void Check_Vote_VoteToNull() var accountState = snapshot.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); ret.Result.Should().BeTrue(); ret.State.Should().BeTrue(); accountState = snapshot.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(); @@ -211,6 +213,7 @@ public void Check_Vote_VoteToNull() G_stateValidator.Votes.Should().Be(0); accountState = snapshot.TryGet(CreateStorageKey(20, from_Account)).GetInteroperable(); accountState.VoteTo.Should().Be(null); + accountState.LastGasPerVote.Should().Be(0); } [TestMethod] From a432e4b8dd30f7c8bdf3403f7c48099dbdf8327a Mon Sep 17 00:00:00 2001 From: Jimmy Date: Fri, 22 Mar 2024 16:34:50 +0800 Subject: [PATCH 102/168] [Crypto Add] add secp256K1 Sign (#3177) * add secp256K1 Sign * fix UT error * fix windows error * fix error * try linux * Remove PubKey from Sign * Update src/Neo/Cryptography/Crypto.cs * fix default curve --------- Co-authored-by: Fernando Diaz Toledano --- src/Neo.GUI/GUI/SigningDialog.cs | 2 +- src/Neo/Cryptography/Crypto.cs | 62 ++++++++++++------- src/Neo/Wallets/Helper.cs | 2 +- tests/Neo.UnitTests/Cryptography/UT_Crypto.cs | 12 ++-- .../Manifest/UT_ContractGroup.cs | 6 +- .../SmartContract/UT_InteropService.NEO.cs | 36 +++++------ .../SmartContract/UT_InteropService.cs | 2 +- 7 files changed, 71 insertions(+), 51 deletions(-) diff --git a/src/Neo.GUI/GUI/SigningDialog.cs b/src/Neo.GUI/GUI/SigningDialog.cs index d235d9691a..5b515a4365 100644 --- a/src/Neo.GUI/GUI/SigningDialog.cs +++ b/src/Neo.GUI/GUI/SigningDialog.cs @@ -87,7 +87,7 @@ private void button1_Click(object sender, EventArgs e) try { - signedData = Crypto.Sign(raw, keys.PrivateKey, keys.PublicKey.EncodePoint(false).Skip(1).ToArray()); + signedData = Crypto.Sign(raw, keys.PrivateKey); } catch (Exception err) { diff --git a/src/Neo/Cryptography/Crypto.cs b/src/Neo/Cryptography/Crypto.cs index 5d8a34939d..cb8c8e371e 100644 --- a/src/Neo/Cryptography/Crypto.cs +++ b/src/Neo/Cryptography/Crypto.cs @@ -10,6 +10,8 @@ // modifications are permitted. using Neo.IO.Caching; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; using System; using System.Runtime.InteropServices; using System.Security.Cryptography; @@ -48,20 +50,40 @@ public static byte[] Hash256(ReadOnlySpan message) /// Signs the specified message using the ECDSA algorithm. /// /// The message to be signed. - /// The private key to be used. - /// The public key to be used. + /// The private key to be used. + /// The curve of the signature, default is . /// The ECDSA signature for the specified message. - public static byte[] Sign(byte[] message, byte[] prikey, byte[] pubkey) + public static byte[] Sign(byte[] message, byte[] priKey, ECC.ECCurve ecCurve = null) { + if (IsOSX && ecCurve == ECC.ECCurve.Secp256k1) + { + var curveParameters = Org.BouncyCastle.Asn1.Sec.SecNamedCurves.GetByName("secp256k1"); + var domain = new ECDomainParameters(curveParameters.Curve, curveParameters.G, curveParameters.N, curveParameters.H); + var signer = new Org.BouncyCastle.Crypto.Signers.ECDsaSigner(); + var privateKey = new BigInteger(1, priKey); + var priKeyParameters = new ECPrivateKeyParameters(privateKey, domain); + signer.Init(true, priKeyParameters); + var signature = signer.GenerateSignature(message.Sha256()); + + var signatureBytes = new byte[64]; + var rBytes = signature[0].ToByteArrayUnsigned(); + var sBytes = signature[1].ToByteArrayUnsigned(); + + // Copy r and s into their respective parts of the signatureBytes array, aligning them to the right. + Buffer.BlockCopy(rBytes, 0, signatureBytes, 32 - rBytes.Length, rBytes.Length); + Buffer.BlockCopy(sBytes, 0, signatureBytes, 64 - sBytes.Length, sBytes.Length); + return signatureBytes; + } + + var curve = + ecCurve == null || ecCurve == ECC.ECCurve.Secp256r1 ? ECCurve.NamedCurves.nistP256 : + ecCurve == ECC.ECCurve.Secp256k1 ? ECCurve.CreateFromFriendlyName("secP256k1") : + throw new NotSupportedException(); + using var ecdsa = ECDsa.Create(new ECParameters { - Curve = ECCurve.NamedCurves.nistP256, - D = prikey, - Q = new ECPoint - { - X = pubkey[..32], - Y = pubkey[32..] - } + Curve = curve, + D = priKey, }); return ecdsa.SignData(message, HashAlgorithmName.SHA256); } @@ -80,25 +102,23 @@ public static bool VerifySignature(ReadOnlySpan message, ReadOnlySpan diff --git a/src/Neo/Wallets/Helper.cs b/src/Neo/Wallets/Helper.cs index 960baa27af..7589ae949a 100644 --- a/src/Neo/Wallets/Helper.cs +++ b/src/Neo/Wallets/Helper.cs @@ -36,7 +36,7 @@ public static class Helper /// The signature for the . public static byte[] Sign(this IVerifiable verifiable, KeyPair key, uint network) { - return Crypto.Sign(verifiable.GetSignData(network), key.PrivateKey, key.PublicKey.EncodePoint(false)[1..]); + return Crypto.Sign(verifiable.GetSignData(network), key.PrivateKey); } /// diff --git a/tests/Neo.UnitTests/Cryptography/UT_Crypto.cs b/tests/Neo.UnitTests/Cryptography/UT_Crypto.cs index 31c4a7ce49..189cf0f626 100644 --- a/tests/Neo.UnitTests/Cryptography/UT_Crypto.cs +++ b/tests/Neo.UnitTests/Cryptography/UT_Crypto.cs @@ -54,7 +54,7 @@ public void TestSetup() public void TestVerifySignature() { byte[] message = System.Text.Encoding.Default.GetBytes("HelloWorld"); - byte[] signature = Crypto.Sign(message, key.PrivateKey, key.PublicKey.EncodePoint(false).Skip(1).ToArray()); + byte[] signature = Crypto.Sign(message, key.PrivateKey); Crypto.VerifySignature(message, signature, key.PublicKey).Should().BeTrue(); byte[] wrongKey = new byte[33]; @@ -74,16 +74,16 @@ public void TestVerifySignature() [TestMethod] public void TestSecp256k1() { - byte[] message = System.Text.Encoding.Default.GetBytes("hello"); - byte[] signature = "5331be791532d157df5b5620620d938bcb622ad02c81cfc184c460efdad18e695480d77440c511e9ad02ea30d773cb54e88f8cbb069644aefa283957085f38b5".HexToBytes(); - byte[] pubKey = "03ea01cb94bdaf0cd1c01b159d474f9604f4af35a3e2196f6bdfdb33b2aa4961fa".HexToBytes(); + byte[] privkey = "7177f0d04c79fa0b8c91fe90c1cf1d44772d1fba6e5eb9b281a22cd3aafb51fe".HexToBytes(); + byte[] message = "2d46a712699bae19a634563d74d04cc2da497b841456da270dccb75ac2f7c4e7".HexToBytes(); + var signature = Crypto.Sign(message, privkey, Neo.Cryptography.ECC.ECCurve.Secp256k1); + byte[] pubKey = "04fd0a8c1ce5ae5570fdd46e7599c16b175bf0ebdfe9c178f1ab848fb16dac74a5d301b0534c7bcf1b3760881f0c420d17084907edd771e1c9c8e941bbf6ff9108".HexToBytes(); Crypto.VerifySignature(message, signature, pubKey, Neo.Cryptography.ECC.ECCurve.Secp256k1) .Should().BeTrue(); message = System.Text.Encoding.Default.GetBytes("world"); - signature = "b1e6ff4f40536fb7ed706b0f7567903cc227a5241a079fb86f3de51b8321c1e690f37ad0c788848605c1653567935845f0d35a8a1a37174dcbbd235caac8e969".HexToBytes(); - pubKey = "03661b86d54eb3a8e7ea2399e0db36ab65753f95fff661da53ae0121278b881ad0".HexToBytes(); + signature = Crypto.Sign(message, privkey, Neo.Cryptography.ECC.ECCurve.Secp256k1); Crypto.VerifySignature(message, signature, pubKey, Neo.Cryptography.ECC.ECCurve.Secp256k1) .Should().BeTrue(); diff --git a/tests/Neo.UnitTests/SmartContract/Manifest/UT_ContractGroup.cs b/tests/Neo.UnitTests/SmartContract/Manifest/UT_ContractGroup.cs index e2715d8ceb..264f90d13a 100644 --- a/tests/Neo.UnitTests/SmartContract/Manifest/UT_ContractGroup.cs +++ b/tests/Neo.UnitTests/SmartContract/Manifest/UT_ContractGroup.cs @@ -44,7 +44,7 @@ public void TestClone() public void TestIsValid() { Random random = new(); - byte[] privateKey = new byte[32]; + var privateKey = new byte[32]; random.NextBytes(privateKey); KeyPair keyPair = new(privateKey); ContractGroup contractGroup = new() @@ -55,11 +55,11 @@ public void TestIsValid() Assert.AreEqual(false, contractGroup.IsValid(UInt160.Zero)); - byte[] message = new byte[] { 0x01,0x01,0x01,0x01,0x01, + var message = new byte[] { 0x01,0x01,0x01,0x01,0x01, 0x01,0x01,0x01,0x01,0x01, 0x01,0x01,0x01,0x01,0x01, 0x01,0x01,0x01,0x01,0x01 }; - byte[] signature = Crypto.Sign(message, keyPair.PrivateKey, keyPair.PublicKey.EncodePoint(false).Skip(1).ToArray()); + var signature = Crypto.Sign(message, keyPair.PrivateKey); contractGroup = new ContractGroup { PubKey = keyPair.PublicKey, diff --git a/tests/Neo.UnitTests/SmartContract/UT_InteropService.NEO.cs b/tests/Neo.UnitTests/SmartContract/UT_InteropService.NEO.cs index 49d7690188..be50a550c8 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_InteropService.NEO.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_InteropService.NEO.cs @@ -33,13 +33,13 @@ public partial class UT_InteropService public void TestCheckSig() { var engine = GetEngine(true); - IVerifiable iv = engine.ScriptContainer; - byte[] message = iv.GetSignData(TestProtocolSettings.Default.Network); + var iv = engine.ScriptContainer; + var message = iv.GetSignData(TestProtocolSettings.Default.Network); byte[] privateKey = { 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}; - KeyPair keyPair = new KeyPair(privateKey); - ECPoint pubkey = keyPair.PublicKey; - byte[] signature = Crypto.Sign(message, privateKey, pubkey.EncodePoint(false).Skip(1).ToArray()); + var keyPair = new KeyPair(privateKey); + var pubkey = keyPair.PublicKey; + var signature = Crypto.Sign(message, privateKey); engine.CheckSig(pubkey.EncodePoint(false), signature).Should().BeTrue(); Action action = () => engine.CheckSig(new byte[70], signature); action.Should().Throw(); @@ -49,20 +49,20 @@ public void TestCheckSig() public void TestCrypto_CheckMultiSig() { var engine = GetEngine(true); - IVerifiable iv = engine.ScriptContainer; - byte[] message = iv.GetSignData(TestProtocolSettings.Default.Network); + var iv = engine.ScriptContainer; + var message = iv.GetSignData(TestProtocolSettings.Default.Network); byte[] privkey1 = { 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}; - KeyPair key1 = new KeyPair(privkey1); - ECPoint pubkey1 = key1.PublicKey; - byte[] signature1 = Crypto.Sign(message, privkey1, pubkey1.EncodePoint(false).Skip(1).ToArray()); + var key1 = new KeyPair(privkey1); + var pubkey1 = key1.PublicKey; + var signature1 = Crypto.Sign(message, privkey1); byte[] privkey2 = { 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, 0x02}; - KeyPair key2 = new KeyPair(privkey2); - ECPoint pubkey2 = key2.PublicKey; - byte[] signature2 = Crypto.Sign(message, privkey2, pubkey2.EncodePoint(false).Skip(1).ToArray()); + var key2 = new KeyPair(privkey2); + var pubkey2 = key2.PublicKey; + var signature2 = Crypto.Sign(message, privkey2); var pubkeys = new[] { @@ -168,7 +168,7 @@ public void TestContract_Update() Script = new[] { (byte)OpCode.RET }, Source = string.Empty, Compiler = "", - Tokens = System.Array.Empty() + Tokens = Array.Empty() }; nef.CheckSum = NefFile.ComputeChecksum(nef); Assert.ThrowsException(() => snapshot.UpdateContract(null, nef.ToArray(), new byte[0])); @@ -176,13 +176,13 @@ public void TestContract_Update() var manifest = TestUtils.CreateDefaultManifest(); byte[] privkey = { 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}; - KeyPair key = new KeyPair(privkey); - ECPoint pubkey = key.PublicKey; + var key = new KeyPair(privkey); + var pubkey = key.PublicKey; var state = TestUtils.GetContract(); - byte[] signature = Crypto.Sign(state.Hash.ToArray(), privkey, pubkey.EncodePoint(false).Skip(1).ToArray()); + var signature = Crypto.Sign(state.Hash.ToArray(), privkey); manifest.Groups = new ContractGroup[] { - new ContractGroup() + new() { PubKey = pubkey, Signature = signature diff --git a/tests/Neo.UnitTests/SmartContract/UT_InteropService.cs b/tests/Neo.UnitTests/SmartContract/UT_InteropService.cs index a0ab12fdc3..0e9916b7d5 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_InteropService.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_InteropService.cs @@ -402,7 +402,7 @@ public void TestCrypto_Verify() 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}; KeyPair keyPair = new(privateKey); var pubkey = keyPair.PublicKey; - var signature = Crypto.Sign(message, privateKey, pubkey.EncodePoint(false).Skip(1).ToArray()); + var signature = Crypto.Sign(message, privateKey); engine.CheckSig(pubkey.EncodePoint(false), signature).Should().BeTrue(); var wrongkey = pubkey.EncodePoint(false); From 127f74bc35d4b5749ccb6f1f9363be89ae5d8623 Mon Sep 17 00:00:00 2001 From: Shargon Date: Fri, 22 Mar 2024 09:35:49 -0700 Subject: [PATCH 103/168] Related to https://github.com/neo-project/neo/pull/3177#discussion_r1534917444 (#3179) --- src/Neo/Cryptography/Crypto.cs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/Neo/Cryptography/Crypto.cs b/src/Neo/Cryptography/Crypto.cs index cb8c8e371e..e419d268a2 100644 --- a/src/Neo/Cryptography/Crypto.cs +++ b/src/Neo/Cryptography/Crypto.cs @@ -10,6 +10,7 @@ // modifications are permitted. using Neo.IO.Caching; +using Org.BouncyCastle.Asn1.X9; using Org.BouncyCastle.Crypto.Parameters; using Org.BouncyCastle.Math; using System; @@ -25,6 +26,8 @@ public static class Crypto { private static readonly ECDsaCache CacheECDsa = new(); private static readonly bool IsOSX = RuntimeInformation.IsOSPlatform(OSPlatform.OSX); + private static readonly ECCurve secP256k1 = ECCurve.CreateFromFriendlyName("secP256k1"); + private static readonly X9ECParameters bouncySecp256k1 = Org.BouncyCastle.Asn1.Sec.SecNamedCurves.GetByName("secp256k1"); /// /// Calculates the 160-bit hash value of the specified message. @@ -57,8 +60,7 @@ public static byte[] Sign(byte[] message, byte[] priKey, ECC.ECCurve ecCurve = n { if (IsOSX && ecCurve == ECC.ECCurve.Secp256k1) { - var curveParameters = Org.BouncyCastle.Asn1.Sec.SecNamedCurves.GetByName("secp256k1"); - var domain = new ECDomainParameters(curveParameters.Curve, curveParameters.G, curveParameters.N, curveParameters.H); + var domain = new ECDomainParameters(bouncySecp256k1.Curve, bouncySecp256k1.G, bouncySecp256k1.N, bouncySecp256k1.H); var signer = new Org.BouncyCastle.Crypto.Signers.ECDsaSigner(); var privateKey = new BigInteger(1, priKey); var priKeyParameters = new ECPrivateKeyParameters(privateKey, domain); @@ -77,7 +79,7 @@ public static byte[] Sign(byte[] message, byte[] priKey, ECC.ECCurve ecCurve = n var curve = ecCurve == null || ecCurve == ECC.ECCurve.Secp256r1 ? ECCurve.NamedCurves.nistP256 : - ecCurve == ECC.ECCurve.Secp256k1 ? ECCurve.CreateFromFriendlyName("secP256k1") : + ecCurve == ECC.ECCurve.Secp256k1 ? secP256k1 : throw new NotSupportedException(); using var ecdsa = ECDsa.Create(new ECParameters @@ -101,9 +103,8 @@ public static bool VerifySignature(ReadOnlySpan message, ReadOnlySpan Date: Mon, 25 Mar 2024 05:44:36 -0400 Subject: [PATCH 104/168] Upgrade to `dotnet` 8.0 (#3180) * Upgrade to `dotnet` 8.0 * Fix misconfiguration issues * Configuration fixed * github workflow fixes * Test misconfigurations --- .devcontainer/devcontainer.json | 6 +++--- .github/workflows/main.yml | 14 +++++++------- benchmarks/Neo.Benchmarks/Neo.Benchmarks.csproj | 2 +- .../Neo.VM.Benchmarks/Neo.VM.Benchmarks.csproj | 2 +- global.json | 2 +- src/Directory.Build.props | 2 +- src/Neo.CLI/Neo.CLI.csproj | 2 +- .../Neo.ConsoleService.csproj | 2 +- .../Neo.Cryptography.BLS12_381.csproj | 2 +- src/Neo.Extensions/Neo.Extensions.csproj | 4 ++-- src/Neo.GUI/Neo.GUI.csproj | 2 +- src/Neo.IO/Neo.IO.csproj | 2 +- src/Neo.Json/Neo.Json.csproj | 4 ++-- src/Neo.VM/Neo.VM.csproj | 2 +- src/Neo/Neo.csproj | 6 +++--- tests/Directory.Build.props | 17 ----------------- .../Neo.ConsoleService.Tests.csproj | 13 ++++++++++++- .../Neo.Cryptography.BLS12_381.Tests.csproj | 13 ++++++++++++- .../Neo.Json.UnitTests.csproj | 13 ++++++++++++- tests/Neo.UnitTests/Neo.UnitTests.csproj | 17 ++++++++++++++--- tests/Neo.VM.Tests/Neo.VM.Tests.csproj | 13 ++++++++++++- 21 files changed, 89 insertions(+), 51 deletions(-) delete mode 100644 tests/Directory.Build.props diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 07843745db..00807d9b64 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -2,8 +2,8 @@ // README at: https://github.com/devcontainers/templates/tree/main/src/dotnet { "name": "C# (.NET)", - "image": "mcr.microsoft.com/devcontainers/dotnet:1-7.0-jammy", - "postCreateCommand": "dotnet restore && dotnet build", + "image": "mcr.microsoft.com/devcontainers/dotnet:1-8.0-jammy", + "postCreateCommand": "dotnet build", "customizations": { "vscode": { "extensions": [ @@ -11,4 +11,4 @@ ] } } -} \ No newline at end of file +} diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index da9e47f20b..95d27e8606 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -6,7 +6,7 @@ on: pull_request: env: - DOTNET_VERSION: 7.0.x + DOTNET_VERSION: 8.0.x jobs: @@ -35,18 +35,18 @@ jobs: if: matrix.os == 'ubuntu-latest' run: | find tests -name *.csproj | xargs -I % dotnet add % package coverlet.msbuild - dotnet test ./tests/Neo.Cryptography.BLS12_381.Tests /p:CollectCoverage=true /p:CoverletOutput=${GITHUB_WORKSPACE}/coverage-join/ - dotnet test ./tests/Neo.ConsoleService.Tests /p:CollectCoverage=true /p:CoverletOutput=${GITHUB_WORKSPACE}/coverage-join/ /p:MergeWith=${GITHUB_WORKSPACE}/coverage-join/coverage.json - dotnet test ./tests/Neo.UnitTests /p:CollectCoverage=true /p:CoverletOutput=${GITHUB_WORKSPACE}/coverage-join/ /p:MergeWith=${GITHUB_WORKSPACE}/coverage-join/coverage.net7.0.json - dotnet test ./tests/Neo.VM.Tests /p:CollectCoverage=true /p:CoverletOutput=${GITHUB_WORKSPACE}/coverage-join/ /p:MergeWith=${GITHUB_WORKSPACE}/coverage-join/coverage.net7.0.json - dotnet test ./tests/Neo.Json.UnitTests /p:CollectCoverage=true /p:CoverletOutput=${GITHUB_WORKSPACE}/coverage/lcov /p:MergeWith=${GITHUB_WORKSPACE}/coverage-join/coverage.net7.0.json /p:CoverletOutputFormat=lcov + dotnet test ./tests/Neo.Cryptography.BLS12_381.Tests --blame-hang --blame-hang-timeout 180000 /p:CollectCoverage=true /p:CoverletOutput=${GITHUB_WORKSPACE}/coverage-join/ /p:MergeWith=${GITHUB_WORKSPACE}/coverage-join/coverage.net8.0.json /p:CoverletOutputFormat=lcov + dotnet test ./tests/Neo.ConsoleService.Tests --blame-hang --blame-hang-timeout 180000 /p:CollectCoverage=true /p:CoverletOutput=${GITHUB_WORKSPACE}/coverage-join/ /p:MergeWith=${GITHUB_WORKSPACE}/coverage-join/coverage.net8.0.json /p:CoverletOutputFormat=lcov + dotnet test ./tests/Neo.UnitTests --blame-hang --blame-hang-timeout 180000 /p:CollectCoverage=true /p:CoverletOutput=${GITHUB_WORKSPACE}/coverage-join/ /p:MergeWith=${GITHUB_WORKSPACE}/coverage-join/coverage.net8.0.json /p:CoverletOutputFormat=lcov + dotnet test ./tests/Neo.VM.Tests --blame-hang --blame-hang-timeout 180000 /p:CollectCoverage=true /p:CoverletOutput=${GITHUB_WORKSPACE}/coverage-join/ /p:MergeWith=${GITHUB_WORKSPACE}/coverage-join/coverage.net8.0.json /p:CoverletOutputFormat=lcov + dotnet test ./tests/Neo.Json.UnitTests --blame-hang --blame-hang-timeout 180000 /p:CollectCoverage=true /p:CoverletOutput=${GITHUB_WORKSPACE}/coverage/lcov /p:MergeWith=${GITHUB_WORKSPACE}/coverage-join/coverage.net8.0.json /p:CoverletOutputFormat=lcov - name: Coveralls if: matrix.os == 'ubuntu-latest' uses: coverallsapp/github-action@v2.2.3 with: github-token: ${{ secrets.GITHUB_TOKEN }} format: lcov - file: ${GITHUB_WORKSPACE}/coverage/lcov.net7.0.info + file: ${GITHUB_WORKSPACE}/coverage/lcov.net8.0.info PublishPackage: if: github.ref == 'refs/heads/master' && startsWith(github.repository, 'neo-project/') diff --git a/benchmarks/Neo.Benchmarks/Neo.Benchmarks.csproj b/benchmarks/Neo.Benchmarks/Neo.Benchmarks.csproj index 17698eed98..85fd9cca25 100644 --- a/benchmarks/Neo.Benchmarks/Neo.Benchmarks.csproj +++ b/benchmarks/Neo.Benchmarks/Neo.Benchmarks.csproj @@ -2,7 +2,7 @@ Exe - net7.0 + net7.0;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 bdca77ae89..1247a1ea63 100644 --- a/benchmarks/Neo.VM.Benchmarks/Neo.VM.Benchmarks.csproj +++ b/benchmarks/Neo.VM.Benchmarks/Neo.VM.Benchmarks.csproj @@ -2,7 +2,7 @@ Exe - net7.0 + net7.0;net8.0 Neo.VM enable enable diff --git a/global.json b/global.json index 423c2e2269..beefe210a1 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "7.0.404", + "version": "8.0.202", "rollForward": "latestFeature", "allowPrerelease": false } diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 35a8fa289c..b04d3d34ae 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -4,7 +4,7 @@ 2015-2023 The Neo Project 3.6.2 - 11.0 + 12.0 The Neo Project neo.png https://github.com/neo-project/neo diff --git a/src/Neo.CLI/Neo.CLI.csproj b/src/Neo.CLI/Neo.CLI.csproj index 0fa76ee2c9..427d58494c 100644 --- a/src/Neo.CLI/Neo.CLI.csproj +++ b/src/Neo.CLI/Neo.CLI.csproj @@ -1,7 +1,7 @@ - net7.0 + net7.0;net8.0 Neo.CLI neo-cli Exe diff --git a/src/Neo.ConsoleService/Neo.ConsoleService.csproj b/src/Neo.ConsoleService/Neo.ConsoleService.csproj index 0139d2a0f5..81e3754687 100644 --- a/src/Neo.ConsoleService/Neo.ConsoleService.csproj +++ b/src/Neo.ConsoleService/Neo.ConsoleService.csproj @@ -1,7 +1,7 @@ - netstandard2.1;net7.0 + netstandard2.1;net7.0;net8.0 Neo.ConsoleService enable 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 d5861b2e45..899c5d242b 100644 --- a/src/Neo.Cryptography.BLS12_381/Neo.Cryptography.BLS12_381.csproj +++ b/src/Neo.Cryptography.BLS12_381/Neo.Cryptography.BLS12_381.csproj @@ -2,7 +2,7 @@ 0.3.0 - netstandard2.1;net7.0 + netstandard2.1 enable enable 11.0 diff --git a/src/Neo.Extensions/Neo.Extensions.csproj b/src/Neo.Extensions/Neo.Extensions.csproj index 7552a56311..8fef8e7139 100644 --- a/src/Neo.Extensions/Neo.Extensions.csproj +++ b/src/Neo.Extensions/Neo.Extensions.csproj @@ -1,13 +1,13 @@ - netstandard2.1;net7.0 + netstandard2.1;net7.0;net8.0 enable NEO;Blockchain;Extensions - + diff --git a/src/Neo.GUI/Neo.GUI.csproj b/src/Neo.GUI/Neo.GUI.csproj index 7b1a8bc981..5edc4e8768 100644 --- a/src/Neo.GUI/Neo.GUI.csproj +++ b/src/Neo.GUI/Neo.GUI.csproj @@ -4,7 +4,7 @@ 2016-2023 The Neo Project Neo.GUI WinExe - net7.0-windows + net7.0-windows;net8.0-windows true Neo true diff --git a/src/Neo.IO/Neo.IO.csproj b/src/Neo.IO/Neo.IO.csproj index 05bc305a67..ca146e9371 100644 --- a/src/Neo.IO/Neo.IO.csproj +++ b/src/Neo.IO/Neo.IO.csproj @@ -1,7 +1,7 @@ - netstandard2.1;net7.0 + netstandard2.1;net7.0;net8.0 true enable NEO;Blockchain;IO diff --git a/src/Neo.Json/Neo.Json.csproj b/src/Neo.Json/Neo.Json.csproj index d2ce18e430..111a187b4e 100644 --- a/src/Neo.Json/Neo.Json.csproj +++ b/src/Neo.Json/Neo.Json.csproj @@ -1,14 +1,14 @@ - netstandard2.1;net7.0 + netstandard2.1;net7.0;net8.0 enable enable NEO;JSON - + diff --git a/src/Neo.VM/Neo.VM.csproj b/src/Neo.VM/Neo.VM.csproj index 66f4682c64..e98411be05 100644 --- a/src/Neo.VM/Neo.VM.csproj +++ b/src/Neo.VM/Neo.VM.csproj @@ -1,7 +1,7 @@ - netstandard2.1;net7.0 + netstandard2.1;net7.0;net8.0 true enable diff --git a/src/Neo/Neo.csproj b/src/Neo/Neo.csproj index 694f4e1c02..80bb20db7a 100644 --- a/src/Neo/Neo.csproj +++ b/src/Neo/Neo.csproj @@ -1,15 +1,15 @@ - netstandard2.1;net7.0 + netstandard2.1;net7.0;net8.0 true NEO;AntShares;Blockchain;Smart Contract - + - + diff --git a/tests/Directory.Build.props b/tests/Directory.Build.props deleted file mode 100644 index 83fe17740a..0000000000 --- a/tests/Directory.Build.props +++ /dev/null @@ -1,17 +0,0 @@ - - - - - net7.0 - false - - - - - - - - - - - diff --git a/tests/Neo.ConsoleService.Tests/Neo.ConsoleService.Tests.csproj b/tests/Neo.ConsoleService.Tests/Neo.ConsoleService.Tests.csproj index 0b12c476c8..8df1042039 100644 --- a/tests/Neo.ConsoleService.Tests/Neo.ConsoleService.Tests.csproj +++ b/tests/Neo.ConsoleService.Tests/Neo.ConsoleService.Tests.csproj @@ -1,7 +1,7 @@ - net7.0 + net7.0;net8.0 neo_cli.Tests false @@ -10,4 +10,15 @@ + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + 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 a56621448c..5f274b7384 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 @@ -1,7 +1,7 @@ - net7.0 + net7.0;net8.0 enable enable false @@ -11,4 +11,15 @@ + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + diff --git a/tests/Neo.Json.UnitTests/Neo.Json.UnitTests.csproj b/tests/Neo.Json.UnitTests/Neo.Json.UnitTests.csproj index f8dec3e7d5..1c7374ce34 100644 --- a/tests/Neo.Json.UnitTests/Neo.Json.UnitTests.csproj +++ b/tests/Neo.Json.UnitTests/Neo.Json.UnitTests.csproj @@ -1,7 +1,7 @@ - net7.0 + net7.0;net8.0 enable false @@ -10,4 +10,15 @@ + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + diff --git a/tests/Neo.UnitTests/Neo.UnitTests.csproj b/tests/Neo.UnitTests/Neo.UnitTests.csproj index 2e61bedbcc..bcb3ea0088 100644 --- a/tests/Neo.UnitTests/Neo.UnitTests.csproj +++ b/tests/Neo.UnitTests/Neo.UnitTests.csproj @@ -1,14 +1,14 @@ - net7.0 + net7.0;net8.0 true false - - + + @@ -23,4 +23,15 @@ + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + diff --git a/tests/Neo.VM.Tests/Neo.VM.Tests.csproj b/tests/Neo.VM.Tests/Neo.VM.Tests.csproj index 1020d1c55a..e7b90e40d5 100644 --- a/tests/Neo.VM.Tests/Neo.VM.Tests.csproj +++ b/tests/Neo.VM.Tests/Neo.VM.Tests.csproj @@ -1,7 +1,7 @@ - net7.0 + net7.0;net8.0 Neo.Test true false @@ -17,4 +17,15 @@ + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + From b099b87dcf1705100ecf077e83516c874c1ccdbc Mon Sep 17 00:00:00 2001 From: Christopher Schuchardt Date: Mon, 25 Mar 2024 12:27:46 -0400 Subject: [PATCH 105/168] Remove `net7.0` framework (#3182) * Upgrade to `dotnet` 8.0 * Fix misconfiguration issues * Configuration fixed * github workflow fixes * Test misconfigurations * Removed `net7.0` * fix coverage * Revert "fix coverage" This reverts commit 551f19ee24329ac2de204e215e7c419192e6cf27. --- benchmarks/Neo.Benchmarks/Neo.Benchmarks.csproj | 2 +- benchmarks/Neo.VM.Benchmarks/Neo.VM.Benchmarks.csproj | 2 +- src/Neo.CLI/Neo.CLI.csproj | 2 +- src/Neo.ConsoleService/Neo.ConsoleService.csproj | 2 +- .../Neo.Cryptography.BLS12_381.csproj | 3 +-- 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 +- tests/Neo.ConsoleService.Tests/Neo.ConsoleService.Tests.csproj | 2 +- .../Neo.Cryptography.BLS12_381.Tests.csproj | 2 +- tests/Neo.Json.UnitTests/Neo.Json.UnitTests.csproj | 2 +- tests/Neo.UnitTests/Neo.UnitTests.csproj | 2 +- tests/Neo.VM.Tests/Neo.VM.Tests.csproj | 2 +- 16 files changed, 16 insertions(+), 17 deletions(-) diff --git a/benchmarks/Neo.Benchmarks/Neo.Benchmarks.csproj b/benchmarks/Neo.Benchmarks/Neo.Benchmarks.csproj index 85fd9cca25..476ef93060 100644 --- a/benchmarks/Neo.Benchmarks/Neo.Benchmarks.csproj +++ b/benchmarks/Neo.Benchmarks/Neo.Benchmarks.csproj @@ -2,7 +2,7 @@ Exe - net7.0;net8.0 + 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 1247a1ea63..7737c3ec0c 100644 --- a/benchmarks/Neo.VM.Benchmarks/Neo.VM.Benchmarks.csproj +++ b/benchmarks/Neo.VM.Benchmarks/Neo.VM.Benchmarks.csproj @@ -2,7 +2,7 @@ Exe - net7.0;net8.0 + net8.0 Neo.VM enable enable diff --git a/src/Neo.CLI/Neo.CLI.csproj b/src/Neo.CLI/Neo.CLI.csproj index 427d58494c..c3c051b4bf 100644 --- a/src/Neo.CLI/Neo.CLI.csproj +++ b/src/Neo.CLI/Neo.CLI.csproj @@ -1,7 +1,7 @@ - net7.0;net8.0 + net8.0 Neo.CLI neo-cli Exe diff --git a/src/Neo.ConsoleService/Neo.ConsoleService.csproj b/src/Neo.ConsoleService/Neo.ConsoleService.csproj index 81e3754687..206e18235e 100644 --- a/src/Neo.ConsoleService/Neo.ConsoleService.csproj +++ b/src/Neo.ConsoleService/Neo.ConsoleService.csproj @@ -1,7 +1,7 @@ - netstandard2.1;net7.0;net8.0 + netstandard2.1;net8.0 Neo.ConsoleService enable 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 899c5d242b..800699719f 100644 --- a/src/Neo.Cryptography.BLS12_381/Neo.Cryptography.BLS12_381.csproj +++ b/src/Neo.Cryptography.BLS12_381/Neo.Cryptography.BLS12_381.csproj @@ -2,10 +2,9 @@ 0.3.0 - netstandard2.1 + netstandard2.1;net8.0 enable enable - 11.0 diff --git a/src/Neo.Extensions/Neo.Extensions.csproj b/src/Neo.Extensions/Neo.Extensions.csproj index 8fef8e7139..d0d899cec3 100644 --- a/src/Neo.Extensions/Neo.Extensions.csproj +++ b/src/Neo.Extensions/Neo.Extensions.csproj @@ -1,7 +1,7 @@ - netstandard2.1;net7.0;net8.0 + netstandard2.1;net8.0 enable NEO;Blockchain;Extensions diff --git a/src/Neo.GUI/Neo.GUI.csproj b/src/Neo.GUI/Neo.GUI.csproj index 5edc4e8768..2c713957a8 100644 --- a/src/Neo.GUI/Neo.GUI.csproj +++ b/src/Neo.GUI/Neo.GUI.csproj @@ -4,7 +4,7 @@ 2016-2023 The Neo Project Neo.GUI WinExe - net7.0-windows;net8.0-windows + net8.0-windows true Neo true diff --git a/src/Neo.IO/Neo.IO.csproj b/src/Neo.IO/Neo.IO.csproj index ca146e9371..f920a40fd5 100644 --- a/src/Neo.IO/Neo.IO.csproj +++ b/src/Neo.IO/Neo.IO.csproj @@ -1,7 +1,7 @@ - netstandard2.1;net7.0;net8.0 + netstandard2.1;net8.0 true enable NEO;Blockchain;IO diff --git a/src/Neo.Json/Neo.Json.csproj b/src/Neo.Json/Neo.Json.csproj index 111a187b4e..cc3ea45278 100644 --- a/src/Neo.Json/Neo.Json.csproj +++ b/src/Neo.Json/Neo.Json.csproj @@ -1,7 +1,7 @@ - netstandard2.1;net7.0;net8.0 + netstandard2.1;net8.0 enable enable NEO;JSON diff --git a/src/Neo.VM/Neo.VM.csproj b/src/Neo.VM/Neo.VM.csproj index e98411be05..a9157f5bcf 100644 --- a/src/Neo.VM/Neo.VM.csproj +++ b/src/Neo.VM/Neo.VM.csproj @@ -1,7 +1,7 @@ - netstandard2.1;net7.0;net8.0 + netstandard2.1;net8.0 true enable diff --git a/src/Neo/Neo.csproj b/src/Neo/Neo.csproj index 80bb20db7a..02668fda95 100644 --- a/src/Neo/Neo.csproj +++ b/src/Neo/Neo.csproj @@ -1,7 +1,7 @@ - netstandard2.1;net7.0;net8.0 + netstandard2.1;net8.0 true NEO;AntShares;Blockchain;Smart Contract diff --git a/tests/Neo.ConsoleService.Tests/Neo.ConsoleService.Tests.csproj b/tests/Neo.ConsoleService.Tests/Neo.ConsoleService.Tests.csproj index 8df1042039..2465178817 100644 --- a/tests/Neo.ConsoleService.Tests/Neo.ConsoleService.Tests.csproj +++ b/tests/Neo.ConsoleService.Tests/Neo.ConsoleService.Tests.csproj @@ -1,7 +1,7 @@ - net7.0;net8.0 + net8.0 neo_cli.Tests false 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 5f274b7384..15896e0b0b 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 @@ -1,7 +1,7 @@ - net7.0;net8.0 + net8.0 enable enable false diff --git a/tests/Neo.Json.UnitTests/Neo.Json.UnitTests.csproj b/tests/Neo.Json.UnitTests/Neo.Json.UnitTests.csproj index 1c7374ce34..8b4999444b 100644 --- a/tests/Neo.Json.UnitTests/Neo.Json.UnitTests.csproj +++ b/tests/Neo.Json.UnitTests/Neo.Json.UnitTests.csproj @@ -1,7 +1,7 @@ - net7.0;net8.0 + net8.0 enable false diff --git a/tests/Neo.UnitTests/Neo.UnitTests.csproj b/tests/Neo.UnitTests/Neo.UnitTests.csproj index bcb3ea0088..4223a75ee6 100644 --- a/tests/Neo.UnitTests/Neo.UnitTests.csproj +++ b/tests/Neo.UnitTests/Neo.UnitTests.csproj @@ -1,7 +1,7 @@ - net7.0;net8.0 + net8.0 true false diff --git a/tests/Neo.VM.Tests/Neo.VM.Tests.csproj b/tests/Neo.VM.Tests/Neo.VM.Tests.csproj index e7b90e40d5..5f68e9aa7d 100644 --- a/tests/Neo.VM.Tests/Neo.VM.Tests.csproj +++ b/tests/Neo.VM.Tests/Neo.VM.Tests.csproj @@ -1,7 +1,7 @@ - net7.0;net8.0 + net8.0 Neo.Test true false From c550fc210a20ffa4b324b41cdd4cde33a9e4da93 Mon Sep 17 00:00:00 2001 From: Christopher Schuchardt Date: Wed, 27 Mar 2024 03:48:58 -0400 Subject: [PATCH 106/168] Repo Configuration Fixes (#3183) * Fixed `coverlet.msbuild` Fixed `glboal.json` version * Updated workflow to use `dotnet` `8.0.202` * Fixed test command * Changed `coverlet` path * Updated Paths and `dotnet test` command * Updated coverage path * Removed `compare-ref` and `compare-sha` * Removed `ls-l` command * Added ` -m:1` to command-line * Update removed `-m:1` --- .github/workflows/main.yml | 14 +++++++------- global.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 95d27e8606..fe43722e6f 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -6,7 +6,7 @@ on: pull_request: env: - DOTNET_VERSION: 8.0.x + DOTNET_VERSION: 8.0.202 jobs: @@ -35,18 +35,18 @@ jobs: if: matrix.os == 'ubuntu-latest' run: | find tests -name *.csproj | xargs -I % dotnet add % package coverlet.msbuild - dotnet test ./tests/Neo.Cryptography.BLS12_381.Tests --blame-hang --blame-hang-timeout 180000 /p:CollectCoverage=true /p:CoverletOutput=${GITHUB_WORKSPACE}/coverage-join/ /p:MergeWith=${GITHUB_WORKSPACE}/coverage-join/coverage.net8.0.json /p:CoverletOutputFormat=lcov - dotnet test ./tests/Neo.ConsoleService.Tests --blame-hang --blame-hang-timeout 180000 /p:CollectCoverage=true /p:CoverletOutput=${GITHUB_WORKSPACE}/coverage-join/ /p:MergeWith=${GITHUB_WORKSPACE}/coverage-join/coverage.net8.0.json /p:CoverletOutputFormat=lcov - dotnet test ./tests/Neo.UnitTests --blame-hang --blame-hang-timeout 180000 /p:CollectCoverage=true /p:CoverletOutput=${GITHUB_WORKSPACE}/coverage-join/ /p:MergeWith=${GITHUB_WORKSPACE}/coverage-join/coverage.net8.0.json /p:CoverletOutputFormat=lcov - dotnet test ./tests/Neo.VM.Tests --blame-hang --blame-hang-timeout 180000 /p:CollectCoverage=true /p:CoverletOutput=${GITHUB_WORKSPACE}/coverage-join/ /p:MergeWith=${GITHUB_WORKSPACE}/coverage-join/coverage.net8.0.json /p:CoverletOutputFormat=lcov - dotnet test ./tests/Neo.Json.UnitTests --blame-hang --blame-hang-timeout 180000 /p:CollectCoverage=true /p:CoverletOutput=${GITHUB_WORKSPACE}/coverage/lcov /p:MergeWith=${GITHUB_WORKSPACE}/coverage-join/coverage.net8.0.json /p:CoverletOutputFormat=lcov + dotnet test ./tests/Neo.Cryptography.BLS12_381.Tests /p:CollectCoverage=true /p:CoverletOutput='${{ github.workspace }}/TestResults/coverage/' + dotnet test ./tests/Neo.ConsoleService.Tests /p:CollectCoverage=true /p:CoverletOutput='${{ github.workspace }}/TestResults/coverage/' /p:MergeWith='${{ github.workspace }}/TestResults/coverage/coverage.net8.0.json' + dotnet test ./tests/Neo.UnitTests /p:CollectCoverage=true /p:CoverletOutput='${{ github.workspace }}/TestResults/coverage/' /p:MergeWith='${{ github.workspace }}/TestResults/coverage/coverage.net8.0.json' + dotnet test ./tests/Neo.VM.Tests /p:CollectCoverage=true /p:CoverletOutput='${{ github.workspace }}/TestResults/coverage/' /p:MergeWith='${{ github.workspace }}/TestResults/coverage/coverage.net8.0.json' + dotnet test ./tests/Neo.Json.UnitTests /p:CollectCoverage=true /p:CoverletOutput='${{ github.workspace }}/TestResults/coverage/' /p:MergeWith='${{ github.workspace }}/TestResults/coverage/coverage.net8.0.json' /p:CoverletOutputFormat='lcov' - name: Coveralls if: matrix.os == 'ubuntu-latest' uses: coverallsapp/github-action@v2.2.3 with: github-token: ${{ secrets.GITHUB_TOKEN }} format: lcov - file: ${GITHUB_WORKSPACE}/coverage/lcov.net8.0.info + file: ${{ github.workspace }}/TestResults/coverage/coverage.net8.0.info PublishPackage: if: github.ref == 'refs/heads/master' && startsWith(github.repository, 'neo-project/') diff --git a/global.json b/global.json index beefe210a1..2172ff52d4 100644 --- a/global.json +++ b/global.json @@ -1,7 +1,7 @@ { "sdk": { "version": "8.0.202", - "rollForward": "latestFeature", + "rollForward": "disable", "allowPrerelease": false } } From 183fd9fcdf4e26bd996e68d913a8e919c0ecb5c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=BF=97=E5=90=8C?= Date: Tue, 2 Apr 2024 15:39:58 +0800 Subject: [PATCH 107/168] comment for jumptable (#3187) * update * Update JumpTable.Push.cs * update * update * update * Update JumpTable.Compound.cs * add pop and push times * Update JumpTable.Push.cs --- src/Neo.VM/JumpTable/JumpTable.Bitwisee.cs | 45 +++ src/Neo.VM/JumpTable/JumpTable.Compound.cs | 162 +++++++++++ src/Neo.VM/JumpTable/JumpTable.Control.cs | 306 +++++++++++++++++++- src/Neo.VM/JumpTable/JumpTable.Numeric.cs | 212 ++++++++++++++ src/Neo.VM/JumpTable/JumpTable.Push.cs | 193 +++++++++++++ src/Neo.VM/JumpTable/JumpTable.Slot.cs | 321 +++++++++++++++++++++ src/Neo.VM/JumpTable/JumpTable.Splice.cs | 45 +++ src/Neo.VM/JumpTable/JumpTable.Stack.cs | 103 +++++++ src/Neo.VM/JumpTable/JumpTable.Types.cs | 38 +++ 9 files changed, 1424 insertions(+), 1 deletion(-) diff --git a/src/Neo.VM/JumpTable/JumpTable.Bitwisee.cs b/src/Neo.VM/JumpTable/JumpTable.Bitwisee.cs index 65a8e490d1..51fcd9c6f2 100644 --- a/src/Neo.VM/JumpTable/JumpTable.Bitwisee.cs +++ b/src/Neo.VM/JumpTable/JumpTable.Bitwisee.cs @@ -13,8 +13,18 @@ namespace Neo.VM { + /// + /// Partial class for performing bitwise and logical operations on integers within a jump table. + /// public partial class JumpTable { + /// + /// Flips all of the bits of an integer. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 1, Push 1 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Invert(ExecutionEngine engine, Instruction instruction) { @@ -22,6 +32,13 @@ public virtual void Invert(ExecutionEngine engine, Instruction instruction) engine.Push(~x); } + /// + /// Computes the bitwise AND of two integers. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 2, Push 1 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void And(ExecutionEngine engine, Instruction instruction) { @@ -30,6 +47,13 @@ public virtual void And(ExecutionEngine engine, Instruction instruction) engine.Push(x1 & x2); } + /// + /// Computes the bitwise OR of two integers. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 2, Push 1 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Or(ExecutionEngine engine, Instruction instruction) { @@ -38,6 +62,13 @@ public virtual void Or(ExecutionEngine engine, Instruction instruction) engine.Push(x1 | x2); } + /// + /// Computes the bitwise XOR (exclusive OR) of two integers. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 2, Push 1 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void XOr(ExecutionEngine engine, Instruction instruction) { @@ -46,6 +77,13 @@ public virtual void XOr(ExecutionEngine engine, Instruction instruction) engine.Push(x1 ^ x2); } + /// + /// Determines whether two objects are equal according to the execution engine's comparison rules. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 2, Push 1 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Equal(ExecutionEngine engine, Instruction instruction) { @@ -54,6 +92,13 @@ public virtual void Equal(ExecutionEngine engine, Instruction instruction) engine.Push(x1.Equals(x2, engine.Limits)); } + /// + /// Determines whether two objects are not equal according to the execution engine's comparison rules. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 2, Push 1 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void NotEqual(ExecutionEngine engine, Instruction instruction) { diff --git a/src/Neo.VM/JumpTable/JumpTable.Compound.cs b/src/Neo.VM/JumpTable/JumpTable.Compound.cs index 916caf02b8..aeb2047825 100644 --- a/src/Neo.VM/JumpTable/JumpTable.Compound.cs +++ b/src/Neo.VM/JumpTable/JumpTable.Compound.cs @@ -18,8 +18,18 @@ namespace Neo.VM { + /// + /// Partial class for manipulating compound types like maps, arrays, and structs within a jump table. + /// public partial class JumpTable { + /// + /// Packs a map from the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 2n+1, Push 1 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void PackMap(ExecutionEngine engine, Instruction instruction) { @@ -36,6 +46,13 @@ public virtual void PackMap(ExecutionEngine engine, Instruction instruction) engine.Push(map); } + /// + /// Packs a struct from the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop n+1, Push 1 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void PackStruct(ExecutionEngine engine, Instruction instruction) { @@ -51,6 +68,13 @@ public virtual void PackStruct(ExecutionEngine engine, Instruction instruction) engine.Push(@struct); } + /// + /// Packs an array from the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop n+1, Push 1 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Pack(ExecutionEngine engine, Instruction instruction) { @@ -66,6 +90,13 @@ public virtual void Pack(ExecutionEngine engine, Instruction instruction) engine.Push(array); } + /// + /// Unpacks a compound type from the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 1, Push 2n+1 or n+1 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Unpack(ExecutionEngine engine, Instruction instruction) { @@ -91,12 +122,29 @@ public virtual void Unpack(ExecutionEngine engine, Instruction instruction) engine.Push(compound.Count); } + /// + /// Creates a new empty array with zero elements on the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// + /// Pop 0, Push 1 + /// TODO: Change to NewNullArray method or add it? + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void NewArray0(ExecutionEngine engine, Instruction instruction) { engine.Push(new VMArray(engine.ReferenceCounter)); } + /// + /// Creates a new array with a specified number of elements on the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 1, Push 1 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void NewArray(ExecutionEngine engine, Instruction instruction) { @@ -107,6 +155,13 @@ public virtual void NewArray(ExecutionEngine engine, Instruction instruction) engine.Push(new VMArray(engine.ReferenceCounter, Enumerable.Repeat(StackItem.Null, n))); } + /// + /// Creates a new array with a specified number of elements and a specified type on the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 1, Push 1 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void NewArray_T(ExecutionEngine engine, Instruction instruction) { @@ -129,12 +184,26 @@ public virtual void NewArray_T(ExecutionEngine engine, Instruction instruction) engine.Push(new VMArray(engine.ReferenceCounter, Enumerable.Repeat(item, n))); } + /// + /// Creates a new empty struct with zero elements on the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 0, Push 1 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void NewStruct0(ExecutionEngine engine, Instruction instruction) { engine.Push(new Struct(engine.ReferenceCounter)); } + /// + /// Creates a new struct with a specified number of elements on the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 1, Push 1 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void NewStruct(ExecutionEngine engine, Instruction instruction) { @@ -147,12 +216,26 @@ public virtual void NewStruct(ExecutionEngine engine, Instruction instruction) engine.Push(result); } + /// + /// Creates a new empty map on the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 0, Push 1 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void NewMap(ExecutionEngine engine, Instruction instruction) { engine.Push(new Map(engine.ReferenceCounter)); } + /// + /// Gets the size of the top item on the evaluation stack and pushes it onto the stack. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 1, Push 1 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Size(ExecutionEngine engine, Instruction instruction) { @@ -173,36 +256,51 @@ public virtual void Size(ExecutionEngine engine, Instruction instruction) } } + /// + /// Checks whether the top item on the evaluation stack has the specified key. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 2, Push 1 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void HasKey(ExecutionEngine engine, Instruction instruction) { var key = engine.Pop(); var x = engine.Pop(); + // Check the type of the top item and perform the corresponding action. switch (x) { + // For arrays, check if the index is within bounds and push the result onto the stack. case VMArray array: { + // TODO: Overflow and underflow checking needs to be done. var index = (int)key.GetInteger(); if (index < 0) throw new InvalidOperationException($"The negative value {index} is invalid for OpCode.{instruction.OpCode}."); engine.Push(index < array.Count); break; } + // For maps, check if the key exists and push the result onto the stack. case Map map: { engine.Push(map.ContainsKey(key)); break; } + // For buffers, check if the index is within bounds and push the result onto the stack. case Types.Buffer buffer: { + // TODO: Overflow and underflow checking needs to be done. var index = (int)key.GetInteger(); if (index < 0) throw new InvalidOperationException($"The negative value {index} is invalid for OpCode.{instruction.OpCode}."); engine.Push(index < buffer.Size); break; } + // For byte strings, check if the index is within bounds and push the result onto the stack. case ByteString array: { + // TODO: Overflow and underflow checking needs to be done. var index = (int)key.GetInteger(); if (index < 0) throw new InvalidOperationException($"The negative value {index} is invalid for OpCode.{instruction.OpCode}."); @@ -214,6 +312,13 @@ public virtual void HasKey(ExecutionEngine engine, Instruction instruction) } } + /// + /// Retrieves the keys of a map and pushes them onto the evaluation stack as an array. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 1, Push 1 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Keys(ExecutionEngine engine, Instruction instruction) { @@ -221,6 +326,13 @@ public virtual void Keys(ExecutionEngine engine, Instruction instruction) engine.Push(new VMArray(engine.ReferenceCounter, map.Keys)); } + /// + /// Retrieves the values of a compound type and pushes them onto the evaluation stack as an array. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 1, Push 1 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Values(ExecutionEngine engine, Instruction instruction) { @@ -240,6 +352,14 @@ public virtual void Values(ExecutionEngine engine, Instruction instruction) engine.Push(newArray); } + /// + /// Retrieves the item from an array, map, buffer, or byte string based on the specified key, + /// and pushes it onto the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 2, Push 1 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void PickItem(ExecutionEngine engine, Instruction instruction) { @@ -284,6 +404,13 @@ public virtual void PickItem(ExecutionEngine engine, Instruction instruction) } } + /// + /// Appends an item to the end of the specified array. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 1, Push 1 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Append(ExecutionEngine engine, Instruction instruction) { @@ -293,6 +420,13 @@ public virtual void Append(ExecutionEngine engine, Instruction instruction) array.Add(newItem); } + /// + /// 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. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 3, Push 0 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void SetItem(ExecutionEngine engine, Instruction instruction) { @@ -333,6 +467,13 @@ public virtual void SetItem(ExecutionEngine engine, Instruction instruction) } } + /// + /// Reverses the order of items in the specified array or buffer. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 1, Push 0 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void ReverseItems(ExecutionEngine engine, Instruction instruction) { @@ -350,6 +491,13 @@ public virtual void ReverseItems(ExecutionEngine engine, Instruction instruction } } + /// + /// Removes the item at the specified index from the array or map. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 2, Push 0 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Remove(ExecutionEngine engine, Instruction instruction) { @@ -371,6 +519,13 @@ public virtual void Remove(ExecutionEngine engine, Instruction instruction) } } + /// + /// Clears all items from the compound type. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 1, Push 0 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void ClearItems(ExecutionEngine engine, Instruction instruction) { @@ -378,6 +533,13 @@ public virtual void ClearItems(ExecutionEngine engine, Instruction instruction) x.Clear(); } + /// + /// Removes and returns the item at the top of the specified array. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 1, Push 0 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void PopItem(ExecutionEngine engine, Instruction instruction) { diff --git a/src/Neo.VM/JumpTable/JumpTable.Control.cs b/src/Neo.VM/JumpTable/JumpTable.Control.cs index 2415f1e614..3c8448c050 100644 --- a/src/Neo.VM/JumpTable/JumpTable.Control.cs +++ b/src/Neo.VM/JumpTable/JumpTable.Control.cs @@ -16,25 +16,61 @@ namespace Neo.VM { + /// + /// Partial class for performing bitwise and logical operations on integers within a jump table. + /// + /// + /// For binary operations x1 and x2, x1 is the first pushed onto the evaluation stack (the second popped from the stack), + /// x2 is the second pushed onto the evaluation stack (the first popped from the stack) + /// public partial class JumpTable { + /// + /// No operation. Does nothing. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Nop(ExecutionEngine engine, Instruction instruction) { } + /// + /// Jumps to the specified offset from the current instruction pointer, + /// where the offset is obtained from the first operand of the instruction and interpreted as a signed byte. + /// + /// + /// The execution engine. + /// The instruction containing the offset as the first operand. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Jmp(ExecutionEngine engine, Instruction instruction) { ExecuteJumpOffset(engine, instruction.TokenI8); } + /// + /// Jumps to the specified offset from the current instruction pointer, + /// where the offset is obtained from the first operand of the instruction and interpreted as a 32-bit signed integer. + /// + /// + /// The execution engine. + /// The instruction containing the offset as the first operand. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Jmp_L(ExecutionEngine engine, Instruction instruction) { ExecuteJumpOffset(engine, instruction.TokenI32); } + /// + /// Jumps to the specified offset from the current instruction pointer + /// if the boolean result of popping the evaluation stack is true. + /// The offset is obtained from the instruction's first operand interpreted as a signed byte. + /// + /// + /// The execution engine. + /// The instruction containing the offset as the first operand. + /// Pop 1, Push 0 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void JmpIf(ExecutionEngine engine, Instruction instruction) { @@ -42,6 +78,15 @@ public virtual void JmpIf(ExecutionEngine engine, Instruction instruction) ExecuteJumpOffset(engine, instruction.TokenI8); } + /// + /// Jumps to the specified offset from the current instruction pointer + /// if the boolean result of popping the evaluation stack is true. + /// The offset is obtained from the instruction's first operand interpreted as a 32-bit signed integer. + /// + /// + /// The execution engine. + /// The instruction containing the offset as the first operand. + /// Pop 1, Push 0 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void JmpIf_L(ExecutionEngine engine, Instruction instruction) { @@ -49,6 +94,15 @@ public virtual void JmpIf_L(ExecutionEngine engine, Instruction instruction) ExecuteJumpOffset(engine, instruction.TokenI32); } + /// + /// Jumps to the specified offset from the current instruction pointer + /// if the boolean result of popping the evaluation stack is false. + /// The offset is obtained from the instruction's first operand interpreted as a signed byte. + /// + /// + /// The execution engine. + /// The instruction containing the offset as the first operand. + /// Pop 1, Push 0 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void JmpIfNot(ExecutionEngine engine, Instruction instruction) { @@ -56,6 +110,15 @@ public virtual void JmpIfNot(ExecutionEngine engine, Instruction instruction) ExecuteJumpOffset(engine, instruction.TokenI8); } + /// + /// Jumps to the specified offset from the current instruction pointer + /// if the boolean result of popping the evaluation stack is false. + /// The offset is obtained from the instruction's first operand interpreted as a 32-bit signed integer. + /// + /// + /// The execution engine. + /// The instruction containing the offset as the first operand. + /// Pop 1, Push 0 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void JmpIfNot_L(ExecutionEngine engine, Instruction instruction) { @@ -63,6 +126,15 @@ public virtual void JmpIfNot_L(ExecutionEngine engine, Instruction instruction) ExecuteJumpOffset(engine, instruction.TokenI32); } + /// + /// Jumps to the specified offset from the current instruction pointer + /// if the two integers popped from the evaluation stack are equal. + /// The offset is obtained from the instruction's first operand interpreted as a signed byte. + /// + /// + /// The execution engine. + /// The instruction containing the offset as the first operand. + /// Pop 2, Push 0 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void JmpEq(ExecutionEngine engine, Instruction instruction) { @@ -72,6 +144,15 @@ public virtual void JmpEq(ExecutionEngine engine, Instruction instruction) ExecuteJumpOffset(engine, instruction.TokenI8); } + /// + /// Jumps to the specified offset from the current instruction pointer + /// if the two integers popped from the evaluation stack are equal. + /// The offset is obtained from the instruction's first operand interpreted as a 32-bit signed integer. + /// + /// + /// The execution engine. + /// The instruction containing the offset as the first operand. + /// Pop 2, Push 0 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void JmpEq_L(ExecutionEngine engine, Instruction instruction) { @@ -81,6 +162,15 @@ public virtual void JmpEq_L(ExecutionEngine engine, Instruction instruction) ExecuteJumpOffset(engine, instruction.TokenI32); } + /// + /// Jumps to the specified offset from the current instruction pointer + /// if the two integers popped from the evaluation stack are not equal. + /// The offset is obtained from the instruction's first operand interpreted as a signed byte. + /// + /// + /// The execution engine. + /// The instruction containing the offset as the first operand. + /// Pop 2, Push 0 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void JmpNe(ExecutionEngine engine, Instruction instruction) { @@ -90,6 +180,15 @@ public virtual void JmpNe(ExecutionEngine engine, Instruction instruction) ExecuteJumpOffset(engine, instruction.TokenI8); } + /// + /// Jumps to the specified offset from the current instruction pointer + /// if the two integers popped from the evaluation stack are not equal. + /// The offset is obtained from the instruction's first operand interpreted as a 32-bit signed integer. + /// + /// + /// The execution engine. + /// The instruction containing the offset as the first operand. + /// Pop 2, Push 0 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void JmpNe_L(ExecutionEngine engine, Instruction instruction) { @@ -99,6 +198,15 @@ public virtual void JmpNe_L(ExecutionEngine engine, Instruction instruction) ExecuteJumpOffset(engine, instruction.TokenI32); } + /// + /// Jumps to the specified offset from the current instruction pointer + /// if the first integer pushed onto the evaluation stack is greater than the second integer. + /// The offset is obtained from the instruction's first operand interpreted as a signed byte. + /// + /// + /// The execution engine. + /// The instruction containing the offset as the first operand. + /// Pop 2, Push 0 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void JmpGt(ExecutionEngine engine, Instruction instruction) { @@ -108,6 +216,15 @@ public virtual void JmpGt(ExecutionEngine engine, Instruction instruction) ExecuteJumpOffset(engine, instruction.TokenI8); } + /// + /// Jumps to the specified offset from the current instruction pointer + /// if the first integer pushed onto the evaluation stack is greater than the second integer. + /// The offset is obtained from the instruction's first operand interpreted as a 32-bit signed integer. + /// + /// + /// The execution engine. + /// The instruction containing the offset as the first operand. + /// Pop 2, Push 0 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void JmpGt_L(ExecutionEngine engine, Instruction instruction) { @@ -117,6 +234,15 @@ public virtual void JmpGt_L(ExecutionEngine engine, Instruction instruction) ExecuteJumpOffset(engine, instruction.TokenI32); } + /// + /// Jumps to the specified offset from the current instruction pointer + /// if the first integer pushed onto the evaluation stack is greater than or equal to the second integer. + /// The offset is obtained from the instruction's first operand interpreted as a signed byte. + /// + /// + /// The execution engine. + /// The instruction containing the offset as the first operand. + /// Pop 2, Push 0 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void JmpGe(ExecutionEngine engine, Instruction instruction) { @@ -126,6 +252,15 @@ public virtual void JmpGe(ExecutionEngine engine, Instruction instruction) ExecuteJumpOffset(engine, instruction.TokenI8); } + /// + /// Jumps to the specified offset from the current instruction pointer + /// if the first integer pushed onto the evaluation stack is greater than or equal to the second integer. + /// The offset is obtained from the instruction's first operand interpreted as a 32-bit signed integer. + /// + /// + /// The execution engine. + /// The instruction containing the offset as the first operand. + /// Pop 2, Push 0 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void JmpGe_L(ExecutionEngine engine, Instruction instruction) { @@ -135,6 +270,15 @@ public virtual void JmpGe_L(ExecutionEngine engine, Instruction instruction) ExecuteJumpOffset(engine, instruction.TokenI32); } + /// + /// Jumps to the specified offset from the current instruction pointer + /// if the first integer pushed onto the evaluation stack is less than the second integer. + /// The offset is obtained from the instruction's first operand interpreted as a signed byte. + /// + /// + /// The execution engine. + /// The instruction containing the offset as the first operand. + /// Pop 2, Push 0 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void JmpLt(ExecutionEngine engine, Instruction instruction) { @@ -144,6 +288,15 @@ public virtual void JmpLt(ExecutionEngine engine, Instruction instruction) ExecuteJumpOffset(engine, instruction.TokenI8); } + /// + /// Jumps to the specified offset from the current instruction pointer + /// if the first integer pushed onto the evaluation stack is less than the second integer. + /// The offset is obtained from the instruction's first operand interpreted as a 32-bit signed integer. + /// + /// + /// The execution engine. + /// The instruction containing the offset as the first operand. + /// Pop 2, Push 0 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void JmpLt_L(ExecutionEngine engine, Instruction instruction) { @@ -153,6 +306,15 @@ public virtual void JmpLt_L(ExecutionEngine engine, Instruction instruction) ExecuteJumpOffset(engine, instruction.TokenI32); } + /// + /// Jumps to the specified offset from the current instruction pointer + /// if the first integer pushed onto the evaluation stack is less than or equal to the second integer. + /// The offset is obtained from the instruction's first operand interpreted as a signed byte. + /// + /// + /// The execution engine. + /// The instruction containing the offset as the first operand. + /// Pop 2, Push 0 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void JmpLe(ExecutionEngine engine, Instruction instruction) { @@ -162,8 +324,17 @@ public virtual void JmpLe(ExecutionEngine engine, Instruction instruction) ExecuteJumpOffset(engine, instruction.TokenI8); } + /// + /// Jumps to the specified offset from the current instruction pointer + /// if the first integer pushed onto the evaluation stack is less than or equal to the second integer. + /// The offset is obtained from the instruction's first operand interpreted as a 32-bit signed integer. + /// + /// + /// The execution engine. + /// The instruction containing the offset as the first operand. + /// Pop 2, Push 0 [MethodImpl(MethodImplOptions.AggressiveInlining)] - public virtual void JMPLE_L(ExecutionEngine engine, Instruction instruction) + public virtual void JmpLe_L(ExecutionEngine engine, Instruction instruction) { var x2 = engine.Pop().GetInteger(); var x1 = engine.Pop().GetInteger(); @@ -171,18 +342,40 @@ public virtual void JMPLE_L(ExecutionEngine engine, Instruction instruction) ExecuteJumpOffset(engine, instruction.TokenI32); } + /// + /// Calls a method specified by the offset from the current instruction pointer. + /// The offset is obtained from the instruction's first operand interpreted as a signed byte. + /// + /// + /// The execution engine. + /// The instruction containing the offset as the first operand. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Call(ExecutionEngine engine, Instruction instruction) { ExecuteCall(engine, checked(engine.CurrentContext!.InstructionPointer + instruction.TokenI8)); } + /// + /// Calls a method specified by the offset from the current instruction pointer. + /// The offset is obtained from the instruction's first operand interpreted as a 32-bit signed integer. + /// + /// + /// The execution engine. + /// The instruction containing the offset as the first operand. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Call_L(ExecutionEngine engine, Instruction instruction) { ExecuteCall(engine, checked(engine.CurrentContext!.InstructionPointer + instruction.TokenI32)); } + /// + /// Calls a method specified by the pointer pushed onto the evaluation stack. + /// It verifies if the pointer belongs to the current script. + /// + /// + /// The execution engine. + /// The current instruction. + /// Pop 1, Push 0 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void CallA(ExecutionEngine engine, Instruction instruction) { @@ -192,18 +385,37 @@ public virtual void CallA(ExecutionEngine engine, Instruction instruction) ExecuteCall(engine, x.Position); } + /// + /// Calls the function described by the token. + /// + /// + /// The execution engine. + /// The current instruction. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void CallT(ExecutionEngine engine, Instruction instruction) { throw new InvalidOperationException($"Token not found: {instruction.TokenU16}"); } + /// + /// Aborts the execution by turning the virtual machine state to FAULT immediately, and the exception cannot be caught. + /// + /// + /// The execution engine. + /// The current instruction. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Abort(ExecutionEngine engine, Instruction instruction) { throw new Exception($"{OpCode.ABORT} is executed."); } + /// + /// Pop the top value of the stack. If it's false, exit vm execution and set vm state to FAULT. + /// + /// + /// The execution engine. + /// The current instruction. + /// Pop 1, Push 0 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Assert(ExecutionEngine engine, Instruction instruction) { @@ -212,12 +424,28 @@ public virtual void Assert(ExecutionEngine engine, Instruction instruction) throw new Exception($"{OpCode.ASSERT} is executed with false result."); } + /// + /// Pop the top value of the stack, and throw it. + /// + /// + /// The execution engine. + /// The current instruction. + /// Pop 1, Push 0 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Throw(ExecutionEngine engine, Instruction instruction) { ExecuteThrow(engine, engine.Pop()); } + /// + /// Initiates a try block with the specified catch and finally offsets. + /// If there's no catch block, set CatchOffset to 0. If there's no finally block, set FinallyOffset to 0. + /// where the catch offset is obtained from the first operand of the instruction and interpreted as a signed byte, + /// the catch offset is obtained from the second operand of the instruction and interpreted as a signed byte. + /// + /// + /// The execution engine. + /// The current instruction. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Try(ExecutionEngine engine, Instruction instruction) { @@ -226,6 +454,15 @@ public virtual void Try(ExecutionEngine engine, Instruction instruction) ExecuteTry(engine, catchOffset, finallyOffset); } + /// + /// Initiates a try block with the specified catch and finally offsets. + /// If there's no catch block, set CatchOffset to 0. If there's no finally block, set FinallyOffset to 0. + /// where the catch offset is obtained from the first operand of the instruction and interpreted as a 32-bit signed integer, + /// the catch offset is obtained from the second operand of the instruction and interpreted as a 32-bit signed integer. + /// + /// + /// The execution engine. + /// The current instruction. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Try_L(ExecutionEngine engine, Instruction instruction) { @@ -234,6 +471,14 @@ public virtual void Try_L(ExecutionEngine engine, Instruction instruction) ExecuteTry(engine, catchOffset, finallyOffset); } + /// + /// Ensures that the appropriate surrounding finally blocks are executed, + /// then unconditionally transfers control to the specific target instruction represented as a 1-byte signed offset + /// from the beginning of the current instruction. + /// + /// + /// The execution engine. + /// The current instruction. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void EndTry(ExecutionEngine engine, Instruction instruction) { @@ -241,6 +486,14 @@ public virtual void EndTry(ExecutionEngine engine, Instruction instruction) ExecuteEndTry(engine, endOffset); } + /// + /// Ensures that the appropriate surrounding finally blocks are executed, + /// then unconditionally transfers control to the specific target instruction represented as a 4-byte signed offset + /// from the beginning of the current instruction. + /// + /// + /// The execution engine. + /// The current instruction. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void EndTry_L(ExecutionEngine engine, Instruction instruction) { @@ -248,6 +501,14 @@ public virtual void EndTry_L(ExecutionEngine engine, Instruction instruction) ExecuteEndTry(engine, endOffset); } + /// + /// Ends the finally block. If no exception occurs or is caught, + /// the VM jumps to the target instruction specified by ENDTRY/ENDTRY_L. + /// Otherwise, the VM rethrows the exception to the upper layer. + /// + /// + /// The execution engine. + /// The current instruction. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void EndFinally(ExecutionEngine engine, Instruction instruction) { @@ -264,6 +525,12 @@ public virtual void EndFinally(ExecutionEngine engine, Instruction instruction) engine.isJumping = true; } + /// + /// Returns from the current method. + /// + /// + /// The execution engine. + /// The current instruction. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Ret(ExecutionEngine engine, Instruction instruction) { @@ -281,6 +548,12 @@ public virtual void Ret(ExecutionEngine engine, Instruction instruction) engine.isJumping = true; } + /// + /// Calls to an interop service. + /// + /// + /// The execution engine. + /// The current instruction. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Syscall(ExecutionEngine engine, Instruction instruction) { @@ -289,12 +562,22 @@ public virtual void Syscall(ExecutionEngine engine, Instruction instruction) #region Execute methods + /// + /// Executes a call operation by loading a new execution context at the specified position. + /// + /// The execution engine. + /// The position to load the new execution context. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void ExecuteCall(ExecutionEngine engine, int position) { engine.LoadContext(engine.CurrentContext!.Clone(position)); } + /// + /// Executes the end of a try block, either popping it from the try stack or transitioning to the finally block. + /// + /// The execution engine. + /// The offset to the end of the try block. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void ExecuteEndTry(ExecutionEngine engine, int endOffset) { @@ -320,6 +603,11 @@ public virtual void ExecuteEndTry(ExecutionEngine engine, int endOffset) engine.isJumping = true; } + /// + /// Executes a jump operation to the specified position. + /// + /// The execution engine. + /// The position to jump to. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void ExecuteJump(ExecutionEngine engine, int position) { @@ -329,12 +617,23 @@ public virtual void ExecuteJump(ExecutionEngine engine, int position) engine.isJumping = true; } + /// + /// Executes a jump operation with the specified offset from the current instruction pointer. + /// + /// The execution engine. + /// The offset from the current instruction pointer. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void ExecuteJumpOffset(ExecutionEngine engine, int offset) { ExecuteJump(engine, checked(engine.CurrentContext!.InstructionPointer + offset)); } + /// + /// Executes a try block operation with the specified catch and finally offsets. + /// + /// The execution engine. + /// The catch block offset. + /// The finally block offset. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void ExecuteTry(ExecutionEngine engine, int catchOffset, int finallyOffset) { @@ -349,6 +648,11 @@ public virtual void ExecuteTry(ExecutionEngine engine, int catchOffset, int fina engine.CurrentContext.TryStack.Push(new ExceptionHandlingContext(catchPointer, finallyPointer)); } + /// + /// Executes a throw operation, handling any surrounding try-catch-finally blocks. + /// + /// The execution engine. + /// The exception to throw. public virtual void ExecuteThrow(ExecutionEngine engine, StackItem? ex) { engine.UncaughtException = ex; diff --git a/src/Neo.VM/JumpTable/JumpTable.Numeric.cs b/src/Neo.VM/JumpTable/JumpTable.Numeric.cs index 60586cb77e..989991a07c 100644 --- a/src/Neo.VM/JumpTable/JumpTable.Numeric.cs +++ b/src/Neo.VM/JumpTable/JumpTable.Numeric.cs @@ -14,8 +14,23 @@ namespace Neo.VM { + /// + /// Partial class for mathematical operations within a jump table. + /// + /// + /// For binary operations x1 and x2, x1 is the first pushed onto the evaluation stack (the second popped from the stack), + /// x2 is the second pushed onto the evaluation stack (the first popped from the stack) + /// public partial class JumpTable { + /// + /// Computes the sign of the specified integer. + /// If the value is negative, puts -1; if positive, puts 1; if zero, puts 0. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 1, Push 1 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Sign(ExecutionEngine engine, Instruction instruction) { @@ -23,6 +38,13 @@ public virtual void Sign(ExecutionEngine engine, Instruction instruction) engine.Push(x.Sign); } + /// + /// Computes the absolute value of the specified integer. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 1, Push 1 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Abs(ExecutionEngine engine, Instruction instruction) { @@ -30,6 +52,13 @@ public virtual void Abs(ExecutionEngine engine, Instruction instruction) engine.Push(BigInteger.Abs(x)); } + /// + /// Computes the negation of the specified integer. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 1, Push 1 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Negate(ExecutionEngine engine, Instruction instruction) { @@ -37,6 +66,13 @@ public virtual void Negate(ExecutionEngine engine, Instruction instruction) engine.Push(-x); } + /// + /// Increments the specified integer by one. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 1, Push 1 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Inc(ExecutionEngine engine, Instruction instruction) { @@ -44,6 +80,13 @@ public virtual void Inc(ExecutionEngine engine, Instruction instruction) engine.Push(x + 1); } + /// + /// Decrements the specified integer by one. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 1, Push 1 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Dec(ExecutionEngine engine, Instruction instruction) { @@ -51,6 +94,13 @@ public virtual void Dec(ExecutionEngine engine, Instruction instruction) engine.Push(x - 1); } + /// + /// Computes the sum of two integers. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 2, Push 1 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Add(ExecutionEngine engine, Instruction instruction) { @@ -59,6 +109,13 @@ public virtual void Add(ExecutionEngine engine, Instruction instruction) engine.Push(x1 + x2); } + /// + /// Computes the difference between two integers. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 2, Push 1 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Sub(ExecutionEngine engine, Instruction instruction) { @@ -67,6 +124,13 @@ public virtual void Sub(ExecutionEngine engine, Instruction instruction) engine.Push(x1 - x2); } + /// + /// Computes the product of two integers. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 2, Push 1 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Mul(ExecutionEngine engine, Instruction instruction) { @@ -75,6 +139,13 @@ public virtual void Mul(ExecutionEngine engine, Instruction instruction) engine.Push(x1 * x2); } + /// + /// Computes the quotient of two integers. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 2, Push 1 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Div(ExecutionEngine engine, Instruction instruction) { @@ -83,6 +154,13 @@ public virtual void Div(ExecutionEngine engine, Instruction instruction) engine.Push(x1 / x2); } + /// + /// Computes the result of raising a number to the specified power. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 2, Push 1 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Mod(ExecutionEngine engine, Instruction instruction) { @@ -91,6 +169,13 @@ public virtual void Mod(ExecutionEngine engine, Instruction instruction) engine.Push(x1 % x2); } + /// + /// Computes the square root of the specified integer. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 2, Push 1 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Pow(ExecutionEngine engine, Instruction instruction) { @@ -100,12 +185,26 @@ public virtual void Pow(ExecutionEngine engine, Instruction instruction) engine.Push(BigInteger.Pow(value, exponent)); } + /// + /// + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 1, Push 1 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Sqrt(ExecutionEngine engine, Instruction instruction) { engine.Push(engine.Pop().GetInteger().Sqrt()); } + /// + /// Computes the modular multiplication of two integers. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 3, Push 1 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void ModMul(ExecutionEngine engine, Instruction instruction) { @@ -115,6 +214,13 @@ public virtual void ModMul(ExecutionEngine engine, Instruction instruction) engine.Push(x1 * x2 % modulus); } + /// + /// Computes the modular exponentiation of an integer. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 3, Push 1 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void ModPow(ExecutionEngine engine, Instruction instruction) { @@ -127,6 +233,13 @@ public virtual void ModPow(ExecutionEngine engine, Instruction instruction) engine.Push(result); } + /// + /// Computes the left shift of an integer. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 2, Push 1 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Shl(ExecutionEngine engine, Instruction instruction) { @@ -137,6 +250,13 @@ public virtual void Shl(ExecutionEngine engine, Instruction instruction) engine.Push(x << shift); } + /// + /// Computes the right shift of an integer. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 2, Push 1 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Shr(ExecutionEngine engine, Instruction instruction) { @@ -147,6 +267,13 @@ public virtual void Shr(ExecutionEngine engine, Instruction instruction) engine.Push(x >> shift); } + /// + /// If the input is 0 or 1, it is flipped. Otherwise the output will be 0. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 1, Push 1 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Not(ExecutionEngine engine, Instruction instruction) { @@ -154,6 +281,13 @@ public virtual void Not(ExecutionEngine engine, Instruction instruction) engine.Push(!x); } + /// + /// Computes the logical AND of the top two stack items and pushes the result onto the stack. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 2, Push 1 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void BoolAnd(ExecutionEngine engine, Instruction instruction) { @@ -162,6 +296,13 @@ public virtual void BoolAnd(ExecutionEngine engine, Instruction instruction) engine.Push(x1 && x2); } + /// + /// Computes the logical OR of the top two stack items and pushes the result onto the stack. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 2, Push 1 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void BoolOr(ExecutionEngine engine, Instruction instruction) { @@ -170,6 +311,13 @@ public virtual void BoolOr(ExecutionEngine engine, Instruction instruction) engine.Push(x1 || x2); } + /// + /// Determines whether the top stack item is not zero and pushes the result onto the stack. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 1, Push 1 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Nz(ExecutionEngine engine, Instruction instruction) { @@ -177,6 +325,13 @@ public virtual void Nz(ExecutionEngine engine, Instruction instruction) engine.Push(!x.IsZero); } + /// + /// Determines whether the top two stack items are equal and pushes the result onto the stack. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 2, Push 1 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void NumEqual(ExecutionEngine engine, Instruction instruction) { @@ -185,6 +340,13 @@ public virtual void NumEqual(ExecutionEngine engine, Instruction instruction) engine.Push(x1 == x2); } + /// + /// Determines whether the top two stack items are not equal and pushes the result onto the stack. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 2, Push 1 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void NumNotEqual(ExecutionEngine engine, Instruction instruction) { @@ -193,6 +355,13 @@ public virtual void NumNotEqual(ExecutionEngine engine, Instruction instruction) engine.Push(x1 != x2); } + /// + /// Determines whether the two integer at the top of the stack, x1 are less than x2, and pushes the result onto the stack. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 2, Push 1 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Lt(ExecutionEngine engine, Instruction instruction) { @@ -204,6 +373,13 @@ public virtual void Lt(ExecutionEngine engine, Instruction instruction) engine.Push(x1.GetInteger() < x2.GetInteger()); } + /// + /// Determines whether the two integer at the top of the stack, x1 are less than or equal to x2, and pushes the result onto the stack. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 2, Push 1 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Le(ExecutionEngine engine, Instruction instruction) { @@ -215,6 +391,13 @@ public virtual void Le(ExecutionEngine engine, Instruction instruction) engine.Push(x1.GetInteger() <= x2.GetInteger()); } + /// + /// Determines whether the two integer at the top of the stack, x1 are greater than x2, and pushes the result onto the stack. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 2, Push 1 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Gt(ExecutionEngine engine, Instruction instruction) { @@ -226,6 +409,13 @@ public virtual void Gt(ExecutionEngine engine, Instruction instruction) engine.Push(x1.GetInteger() > x2.GetInteger()); } + /// + /// Determines whether the two integer at the top of the stack, x1 are greater than or equal to x2, and pushes the result onto the stack. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 2, Push 1 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Ge(ExecutionEngine engine, Instruction instruction) { @@ -237,6 +427,13 @@ public virtual void Ge(ExecutionEngine engine, Instruction instruction) engine.Push(x1.GetInteger() >= x2.GetInteger()); } + /// + /// Computes the minimum of the top two stack items and pushes the result onto the stack. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 2, Push 1 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Min(ExecutionEngine engine, Instruction instruction) { @@ -245,6 +442,13 @@ public virtual void Min(ExecutionEngine engine, Instruction instruction) engine.Push(BigInteger.Min(x1, x2)); } + /// + /// Computes the maximum of the top two stack items and pushes the result onto the stack. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 2, Push 1 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Max(ExecutionEngine engine, Instruction instruction) { @@ -253,6 +457,14 @@ public virtual void Max(ExecutionEngine engine, Instruction instruction) engine.Push(BigInteger.Max(x1, x2)); } + /// + /// Determines whether the top stack item is within the range specified by the next two top stack items + /// and pushes the result onto the stack. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 3, Push 1 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Within(ExecutionEngine engine, Instruction instruction) { diff --git a/src/Neo.VM/JumpTable/JumpTable.Push.cs b/src/Neo.VM/JumpTable/JumpTable.Push.cs index 066330f5bb..c0f1429b4d 100644 --- a/src/Neo.VM/JumpTable/JumpTable.Push.cs +++ b/src/Neo.VM/JumpTable/JumpTable.Push.cs @@ -16,56 +16,114 @@ namespace Neo.VM { + /// + /// Partial class for providing methods to push various data types onto the evaluation stack within a jump table. + /// + /// Pop 0, Push 1 public partial class JumpTable { + /// + /// Pushes an 8-bit signed integer onto the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void PushInt8(ExecutionEngine engine, Instruction instruction) { engine.Push(new BigInteger(instruction.Operand.Span)); } + /// + /// Pushes an 16-bit signed integer onto the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void PushInt16(ExecutionEngine engine, Instruction instruction) { engine.Push(new BigInteger(instruction.Operand.Span)); } + /// + /// Pushes an 32-bit signed integer onto the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void PushInt32(ExecutionEngine engine, Instruction instruction) { engine.Push(new BigInteger(instruction.Operand.Span)); } + /// + /// Pushes an 64-bit signed integer onto the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void PushInt64(ExecutionEngine engine, Instruction instruction) { engine.Push(new BigInteger(instruction.Operand.Span)); } + /// + /// Pushes an 128-bit signed integer onto the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void PushInt128(ExecutionEngine engine, Instruction instruction) { engine.Push(new BigInteger(instruction.Operand.Span)); } + /// + /// Pushes an 256-bit signed integer onto the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void PushInt256(ExecutionEngine engine, Instruction instruction) { engine.Push(new BigInteger(instruction.Operand.Span)); } + /// + /// Pushes a boolean value of true onto the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void PushT(ExecutionEngine engine, Instruction instruction) { engine.Push(StackItem.True); } + /// + /// Pushes a boolean value of false onto the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void PushF(ExecutionEngine engine, Instruction instruction) { engine.Push(StackItem.False); } + /// + /// Pushes the address of the specified instruction onto the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void PushA(ExecutionEngine engine, Instruction instruction) { @@ -75,12 +133,25 @@ public virtual void PushA(ExecutionEngine engine, Instruction instruction) engine.Push(new Pointer(engine.CurrentContext.Script, position)); } + /// + /// Pushes a null onto the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void PushNull(ExecutionEngine engine, Instruction instruction) { engine.Push(StackItem.Null); } + /// + /// Pushes a byte array with a length prefix onto the evaluation stack. + /// The length of the array is 1 byte. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void PushData1(ExecutionEngine engine, Instruction instruction) { @@ -88,6 +159,13 @@ public virtual void PushData1(ExecutionEngine engine, Instruction instruction) engine.Push(instruction.Operand); } + /// + /// Pushes a byte array with a length prefix onto the evaluation stack. + /// The length of the array is 1 bytes. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void PushData2(ExecutionEngine engine, Instruction instruction) { @@ -95,6 +173,13 @@ public virtual void PushData2(ExecutionEngine engine, Instruction instruction) engine.Push(instruction.Operand); } + /// + /// Pushes a byte array with a length prefix onto the evaluation stack. + /// The length of the array is 4 bytes. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void PushData4(ExecutionEngine engine, Instruction instruction) { @@ -102,108 +187,216 @@ public virtual void PushData4(ExecutionEngine engine, Instruction instruction) engine.Push(instruction.Operand); } + /// + /// Pushes the integer value of -1 onto the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void PushM1(ExecutionEngine engine, Instruction instruction) { engine.Push(-1); } + /// + /// Pushes the integer value of 0 onto the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Push0(ExecutionEngine engine, Instruction instruction) { engine.Push(0); } + /// + /// Pushes the integer value of 1 onto the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Push1(ExecutionEngine engine, Instruction instruction) { engine.Push(1); } + /// + /// Pushes the integer value of 2 onto the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Push2(ExecutionEngine engine, Instruction instruction) { engine.Push(2); } + /// + /// Pushes the integer value of 3 onto the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Push3(ExecutionEngine engine, Instruction instruction) { engine.Push(3); } + /// + /// Pushes the integer value of 4 onto the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Push4(ExecutionEngine engine, Instruction instruction) { engine.Push(4); } + /// + /// Pushes the integer value of 5 onto the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Push5(ExecutionEngine engine, Instruction instruction) { engine.Push(5); } + /// + /// Pushes the integer value of 6 onto the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Push6(ExecutionEngine engine, Instruction instruction) { engine.Push(6); } + /// + /// Pushes the integer value of 7 onto the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Push7(ExecutionEngine engine, Instruction instruction) { engine.Push(7); } + /// + /// Pushes the integer value of 8 onto the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Push8(ExecutionEngine engine, Instruction instruction) { engine.Push(8); } + /// + /// Pushes the integer value of 9 onto the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Push9(ExecutionEngine engine, Instruction instruction) { engine.Push(9); } + /// + /// Pushes the integer value of 10 onto the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Push10(ExecutionEngine engine, Instruction instruction) { engine.Push(10); } + /// + /// Pushes the integer value of 11 onto the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Push11(ExecutionEngine engine, Instruction instruction) { engine.Push(11); } + /// + /// Pushes the integer value of 12 onto the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Push12(ExecutionEngine engine, Instruction instruction) { engine.Push(12); } + /// + /// Pushes the integer value of 13 onto the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Push13(ExecutionEngine engine, Instruction instruction) { engine.Push(13); } + /// + /// Pushes the integer value of 14 onto the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Push14(ExecutionEngine engine, Instruction instruction) { engine.Push(14); } + /// + /// Pushes the integer value of 15 onto the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Push15(ExecutionEngine engine, Instruction instruction) { engine.Push(15); } + /// + /// Pushes the integer value of 16 onto the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Push16(ExecutionEngine engine, Instruction instruction) { diff --git a/src/Neo.VM/JumpTable/JumpTable.Slot.cs b/src/Neo.VM/JumpTable/JumpTable.Slot.cs index 1305701e98..b4e5c89e3e 100644 --- a/src/Neo.VM/JumpTable/JumpTable.Slot.cs +++ b/src/Neo.VM/JumpTable/JumpTable.Slot.cs @@ -16,8 +16,17 @@ namespace Neo.VM { + /// + /// Partial class representing a jump table for executing specific operations related to slot manipulation. + /// public partial class JumpTable { + /// + /// Initializes the static field slot in the current execution context. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void InitSSlot(ExecutionEngine engine, Instruction instruction) { @@ -28,6 +37,12 @@ public virtual void InitSSlot(ExecutionEngine engine, Instruction instruction) engine.CurrentContext.StaticFields = new Slot(instruction.TokenU8, engine.ReferenceCounter); } + /// + /// Initializes the local variable slot or the argument slot in the current execution context. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void InitSlot(ExecutionEngine engine, Instruction instruction) { @@ -50,288 +65,582 @@ public virtual void InitSlot(ExecutionEngine engine, Instruction instruction) } } + /// + /// Loads the value at index 0 from the static field slot onto the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void LdSFld0(ExecutionEngine engine, Instruction instruction) { ExecuteLoadFromSlot(engine, engine.CurrentContext!.StaticFields, 0); } + /// + /// Loads the value at index 1 from the static field slot onto the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void LdSFld1(ExecutionEngine engine, Instruction instruction) { ExecuteLoadFromSlot(engine, engine.CurrentContext!.StaticFields, 1); } + /// + /// Loads the value at index 2 from the static field slot onto the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void LdSFld2(ExecutionEngine engine, Instruction instruction) { ExecuteLoadFromSlot(engine, engine.CurrentContext!.StaticFields, 2); } + /// + /// Loads the value at index 3 from the static field slot onto the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void LdSFld3(ExecutionEngine engine, Instruction instruction) { ExecuteLoadFromSlot(engine, engine.CurrentContext!.StaticFields, 3); } + /// + /// Loads the value at index 4 from the static field slot onto the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void LdSFld4(ExecutionEngine engine, Instruction instruction) { ExecuteLoadFromSlot(engine, engine.CurrentContext!.StaticFields, 4); } + /// + /// Loads the value at index 5 from the static field slot onto the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void LdSFld5(ExecutionEngine engine, Instruction instruction) { ExecuteLoadFromSlot(engine, engine.CurrentContext!.StaticFields, 5); } + /// + /// Loads the value at index 6 from the static field slot onto the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void LdSFld6(ExecutionEngine engine, Instruction instruction) { ExecuteLoadFromSlot(engine, engine.CurrentContext!.StaticFields, 6); } + /// + /// Loads the static field at a specified index onto the evaluation stack. + /// The index is represented as a 1-byte unsigned integer. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void LdSFld(ExecutionEngine engine, Instruction instruction) { ExecuteLoadFromSlot(engine, engine.CurrentContext!.StaticFields, instruction.TokenU8); } + /// + /// Stores the value at index 0 from the evaluation stack into the static field slot. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void StSFld0(ExecutionEngine engine, Instruction instruction) { ExecuteStoreToSlot(engine, engine.CurrentContext!.StaticFields, 0); } + /// + /// Stores the value at index 1 from the evaluation stack into the static field slot. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void StSFld1(ExecutionEngine engine, Instruction instruction) { ExecuteStoreToSlot(engine, engine.CurrentContext!.StaticFields, 1); } + /// + /// Stores the value at index 2 from the evaluation stack into the static field slot. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void StSFld2(ExecutionEngine engine, Instruction instruction) { ExecuteStoreToSlot(engine, engine.CurrentContext!.StaticFields, 2); } + /// + /// Stores the value at index 3 from the evaluation stack into the static field slot. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void StSFld3(ExecutionEngine engine, Instruction instruction) { ExecuteStoreToSlot(engine, engine.CurrentContext!.StaticFields, 3); } + /// + /// Stores the value at index 4 from the evaluation stack into the static field slot. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void StSFld4(ExecutionEngine engine, Instruction instruction) { ExecuteStoreToSlot(engine, engine.CurrentContext!.StaticFields, 4); } + /// + /// Stores the value at index 5 from the evaluation stack into the static field slot. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void StSFld5(ExecutionEngine engine, Instruction instruction) { ExecuteStoreToSlot(engine, engine.CurrentContext!.StaticFields, 5); } + /// + /// Stores the value at index 6 from the evaluation stack into the static field slot. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void StSFld6(ExecutionEngine engine, Instruction instruction) { ExecuteStoreToSlot(engine, engine.CurrentContext!.StaticFields, 6); } + /// + /// 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. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void StSFld(ExecutionEngine engine, Instruction instruction) { ExecuteStoreToSlot(engine, engine.CurrentContext!.StaticFields, instruction.TokenU8); } + /// + /// Loads the local variable at index 0 onto the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void LdLoc0(ExecutionEngine engine, Instruction instruction) { ExecuteLoadFromSlot(engine, engine.CurrentContext!.LocalVariables, 0); } + /// + /// Loads the local variable at index 1 onto the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void LdLoc1(ExecutionEngine engine, Instruction instruction) { ExecuteLoadFromSlot(engine, engine.CurrentContext!.LocalVariables, 1); } + /// + /// Loads the local variable at index 2 onto the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void LdLoc2(ExecutionEngine engine, Instruction instruction) { ExecuteLoadFromSlot(engine, engine.CurrentContext!.LocalVariables, 2); } + /// + /// Loads the local variable at index 3 onto the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void LdLoc3(ExecutionEngine engine, Instruction instruction) { ExecuteLoadFromSlot(engine, engine.CurrentContext!.LocalVariables, 3); } + /// + /// Loads the local variable at index 4 onto the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void LdLoc4(ExecutionEngine engine, Instruction instruction) { ExecuteLoadFromSlot(engine, engine.CurrentContext!.LocalVariables, 4); } + /// + /// Loads the local variable at index 5 onto the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void LdLoc5(ExecutionEngine engine, Instruction instruction) { ExecuteLoadFromSlot(engine, engine.CurrentContext!.LocalVariables, 5); } + /// + /// Loads the local variable at index 6 onto the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void LdLoc6(ExecutionEngine engine, Instruction instruction) { ExecuteLoadFromSlot(engine, engine.CurrentContext!.LocalVariables, 6); } + /// + /// Loads the local variable at a specified index onto the evaluation stack. + /// The index is represented as a 1-byte unsigned integer. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void LdLoc(ExecutionEngine engine, Instruction instruction) { ExecuteLoadFromSlot(engine, engine.CurrentContext!.LocalVariables, instruction.TokenU8); } + /// + /// Stores the value on top of the evaluation stack in the local variable list at index 0. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void StLoc0(ExecutionEngine engine, Instruction instruction) { ExecuteStoreToSlot(engine, engine.CurrentContext!.LocalVariables, 0); } + /// + /// Stores the value on top of the evaluation stack in the local variable list at index 1. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void StLoc1(ExecutionEngine engine, Instruction instruction) { ExecuteStoreToSlot(engine, engine.CurrentContext!.LocalVariables, 1); } + /// + /// Stores the value on top of the evaluation stack in the local variable list at index 2. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void StLoc2(ExecutionEngine engine, Instruction instruction) { ExecuteStoreToSlot(engine, engine.CurrentContext!.LocalVariables, 2); } + /// + /// Stores the value on top of the evaluation stack in the local variable list at index 3. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void StLoc3(ExecutionEngine engine, Instruction instruction) { ExecuteStoreToSlot(engine, engine.CurrentContext!.LocalVariables, 3); } + /// + /// Stores the value on top of the evaluation stack in the local variable list at index 4. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void StLoc4(ExecutionEngine engine, Instruction instruction) { ExecuteStoreToSlot(engine, engine.CurrentContext!.LocalVariables, 4); } + /// + /// Stores the value on top of the evaluation stack in the local variable list at index 5. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void StLoc5(ExecutionEngine engine, Instruction instruction) { ExecuteStoreToSlot(engine, engine.CurrentContext!.LocalVariables, 5); } + /// + /// Stores the value on top of the evaluation stack in the local variable list at index 6. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void StLoc6(ExecutionEngine engine, Instruction instruction) { ExecuteStoreToSlot(engine, engine.CurrentContext!.LocalVariables, 6); } + /// + /// 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. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void StLoc(ExecutionEngine engine, Instruction instruction) { ExecuteStoreToSlot(engine, engine.CurrentContext!.LocalVariables, instruction.TokenU8); } + /// + /// Loads the argument at index 0 onto the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void LdArg0(ExecutionEngine engine, Instruction instruction) { ExecuteLoadFromSlot(engine, engine.CurrentContext!.Arguments, 0); } + /// + /// Loads the argument at index 1 onto the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void LdArg1(ExecutionEngine engine, Instruction instruction) { ExecuteLoadFromSlot(engine, engine.CurrentContext!.Arguments, 1); } + /// + /// Loads the argument at index 2 onto the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void LdArg2(ExecutionEngine engine, Instruction instruction) { ExecuteLoadFromSlot(engine, engine.CurrentContext!.Arguments, 2); } + /// + /// Loads the argument at index 3 onto the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void LdArg3(ExecutionEngine engine, Instruction instruction) { ExecuteLoadFromSlot(engine, engine.CurrentContext!.Arguments, 3); } + /// + /// Loads the argument at index 4 onto the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void LdArg4(ExecutionEngine engine, Instruction instruction) { ExecuteLoadFromSlot(engine, engine.CurrentContext!.Arguments, 4); } + /// + /// Loads the argument at index 5 onto the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void LdArg5(ExecutionEngine engine, Instruction instruction) { ExecuteLoadFromSlot(engine, engine.CurrentContext!.Arguments, 5); } + /// + /// Loads the argument at index 6 onto the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void LdArg6(ExecutionEngine engine, Instruction instruction) { ExecuteLoadFromSlot(engine, engine.CurrentContext!.Arguments, 6); } + /// + /// Loads the argument at a specified index onto the evaluation stack. + /// The index is represented as a 1-byte unsigned integer. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void LdArg(ExecutionEngine engine, Instruction instruction) { ExecuteLoadFromSlot(engine, engine.CurrentContext!.Arguments, instruction.TokenU8); } + /// + /// Stores the value on top of the evaluation stack in the argument slot at index 0. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void StArg0(ExecutionEngine engine, Instruction instruction) { ExecuteStoreToSlot(engine, engine.CurrentContext!.Arguments, 0); } + /// + /// Stores the value on top of the evaluation stack in the argument slot at index 1. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void StArg1(ExecutionEngine engine, Instruction instruction) { ExecuteStoreToSlot(engine, engine.CurrentContext!.Arguments, 1); } + /// + /// Stores the value on top of the evaluation stack in the argument slot at index 2. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void StArg2(ExecutionEngine engine, Instruction instruction) { ExecuteStoreToSlot(engine, engine.CurrentContext!.Arguments, 2); } + /// + /// Stores the value on top of the evaluation stack in the argument slot at index 3. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void StArg3(ExecutionEngine engine, Instruction instruction) { ExecuteStoreToSlot(engine, engine.CurrentContext!.Arguments, 3); } + /// + /// Stores the value on top of the evaluation stack in the argument slot at index 4. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void StArg4(ExecutionEngine engine, Instruction instruction) { ExecuteStoreToSlot(engine, engine.CurrentContext!.Arguments, 4); } + /// + /// Stores the value on top of the evaluation stack in the argument slot at index 5. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void StArg5(ExecutionEngine engine, Instruction instruction) { ExecuteStoreToSlot(engine, engine.CurrentContext!.Arguments, 5); } + /// + /// Stores the value on top of the evaluation stack in the argument slot at index 6. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void StArg6(ExecutionEngine engine, Instruction instruction) { ExecuteStoreToSlot(engine, engine.CurrentContext!.Arguments, 6); } + /// + /// 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. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void StArg(ExecutionEngine engine, Instruction instruction) { @@ -340,6 +649,12 @@ public virtual void StArg(ExecutionEngine engine, Instruction instruction) #region Execute methods + /// + /// Executes the store operation into the specified slot at the given index. + /// + /// The execution engine. + /// The slot to store the value. + /// The index within the slot. public virtual void ExecuteStoreToSlot(ExecutionEngine engine, Slot? slot, int index) { if (slot is null) @@ -349,6 +664,12 @@ public virtual void ExecuteStoreToSlot(ExecutionEngine engine, Slot? slot, int i slot[index] = engine.Pop(); } + /// + /// Executes the load operation from the specified slot at the given index onto the evaluation stack. + /// + /// The execution engine. + /// The slot to load the value from. + /// The index within the slot. public virtual void ExecuteLoadFromSlot(ExecutionEngine engine, Slot? slot, int index) { if (slot is null) diff --git a/src/Neo.VM/JumpTable/JumpTable.Splice.cs b/src/Neo.VM/JumpTable/JumpTable.Splice.cs index 95bad5314f..2f49ea0107 100644 --- a/src/Neo.VM/JumpTable/JumpTable.Splice.cs +++ b/src/Neo.VM/JumpTable/JumpTable.Splice.cs @@ -14,8 +14,18 @@ namespace Neo.VM { + /// + /// Partial class representing a jump table for executing specific operations related to string manipulation. + /// public partial class JumpTable { + /// + /// Creates a new buffer with the specified length and pushes it onto the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 1, Push 1 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void NewBuffer(ExecutionEngine engine, Instruction instruction) { @@ -24,6 +34,13 @@ public virtual void NewBuffer(ExecutionEngine engine, Instruction instruction) engine.Push(new Types.Buffer(length)); } + /// + /// Copies a specified number of bytes from one buffer to another buffer. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 5, Push 0 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Memcpy(ExecutionEngine engine, Instruction instruction) { @@ -45,6 +62,13 @@ public virtual void Memcpy(ExecutionEngine engine, Instruction instruction) src.Slice(si, count).CopyTo(dst.InnerBuffer.Span[di..]); } + /// + /// Concatenates two buffers and pushes the result onto the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 2, Push 1 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Cat(ExecutionEngine engine, Instruction instruction) { @@ -58,6 +82,13 @@ public virtual void Cat(ExecutionEngine engine, Instruction instruction) engine.Push(result); } + /// + /// Extracts a substring from the specified buffer and pushes it onto the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 3, Push 1 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void SubStr(ExecutionEngine engine, Instruction instruction) { @@ -75,6 +106,13 @@ public virtual void SubStr(ExecutionEngine engine, Instruction instruction) engine.Push(result); } + /// + /// Extracts a specified number of characters from the left side of the buffer and pushes them onto the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 2, Push 1 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Left(ExecutionEngine engine, Instruction instruction) { @@ -89,6 +127,13 @@ public virtual void Left(ExecutionEngine engine, Instruction instruction) engine.Push(result); } + /// + /// Extracts a specified number of characters from the right side of the buffer and pushes them onto the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 2, Push 1 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Right(ExecutionEngine engine, Instruction instruction) { diff --git a/src/Neo.VM/JumpTable/JumpTable.Stack.cs b/src/Neo.VM/JumpTable/JumpTable.Stack.cs index 0f623c26ce..45ee5565a7 100644 --- a/src/Neo.VM/JumpTable/JumpTable.Stack.cs +++ b/src/Neo.VM/JumpTable/JumpTable.Stack.cs @@ -15,26 +15,56 @@ namespace Neo.VM { + /// + /// Partial class for stack manipulation within a jump table in the execution engine. + /// public partial class JumpTable { + /// + /// Pushes the number of stack items in the evaluation stack onto the stack. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 0, Push 1 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Depth(ExecutionEngine engine, Instruction instruction) { engine.Push(engine.CurrentContext!.EvaluationStack.Count); } + /// + /// Removes the top item from the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 1, Push 0 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Drop(ExecutionEngine engine, Instruction instruction) { engine.Pop(); } + /// + /// + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Nip(ExecutionEngine engine, Instruction instruction) { engine.CurrentContext!.EvaluationStack.Remove(1); } + /// + /// Removes the nth item from the top of the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 1, Push 0 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void XDrop(ExecutionEngine engine, Instruction instruction) { @@ -44,24 +74,51 @@ public virtual void XDrop(ExecutionEngine engine, Instruction instruction) engine.CurrentContext!.EvaluationStack.Remove(n); } + /// + /// Clears all items from the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Clear(ExecutionEngine engine, Instruction instruction) { engine.CurrentContext!.EvaluationStack.Clear(); } + /// + /// Duplicates the item on the top of the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 0, Push 1 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Dup(ExecutionEngine engine, Instruction instruction) { engine.Push(engine.Peek()); } + /// + /// Copies the second item from the top of the evaluation stack and pushes the copy onto the stack. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 0, Push 1 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Over(ExecutionEngine engine, Instruction instruction) { engine.Push(engine.Peek(1)); } + /// + /// Copies the nth item from the top of the evaluation stack and pushes the copy onto the stack. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 1, Push 1 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Pick(ExecutionEngine engine, Instruction instruction) { @@ -71,12 +128,25 @@ public virtual void Pick(ExecutionEngine engine, Instruction instruction) engine.Push(engine.Peek(n)); } + /// + /// Copies the top item on the evaluation stack and inserts the copy between the first and second items. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Tuck(ExecutionEngine engine, Instruction instruction) { engine.CurrentContext!.EvaluationStack.Insert(2, engine.Peek()); } + /// + /// Swaps the top two items on the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 0, Push 1 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Swap(ExecutionEngine engine, Instruction instruction) { @@ -84,6 +154,13 @@ public virtual void Swap(ExecutionEngine engine, Instruction instruction) engine.Push(x); } + /// + /// Left rotates the top three items on the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 0, Push 1 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Rot(ExecutionEngine engine, Instruction instruction) { @@ -91,6 +168,13 @@ public virtual void Rot(ExecutionEngine engine, Instruction instruction) engine.Push(x); } + /// + /// The item n back in the stack is moved to the top. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 1, Push 1 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Roll(ExecutionEngine engine, Instruction instruction) { @@ -102,18 +186,37 @@ public virtual void Roll(ExecutionEngine engine, Instruction instruction) engine.Push(x); } + /// + /// Reverses the order of the top 3 items on the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Reverse3(ExecutionEngine engine, Instruction instruction) { engine.CurrentContext!.EvaluationStack.Reverse(3); } + /// + /// Reverses the order of the top 4 items on the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Reverse4(ExecutionEngine engine, Instruction instruction) { engine.CurrentContext!.EvaluationStack.Reverse(4); } + /// + /// Reverses the order of the top n items on the evaluation stack. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 1, Push 0 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void ReverseN(ExecutionEngine engine, Instruction instruction) { diff --git a/src/Neo.VM/JumpTable/JumpTable.Types.cs b/src/Neo.VM/JumpTable/JumpTable.Types.cs index 6c3b1cbb61..717d759979 100644 --- a/src/Neo.VM/JumpTable/JumpTable.Types.cs +++ b/src/Neo.VM/JumpTable/JumpTable.Types.cs @@ -15,8 +15,18 @@ namespace Neo.VM { + /// + /// Partial class for type operations in the execution engine within a jump table. + /// public partial class JumpTable { + /// + /// Determines whether the item on top of the evaluation stack is null. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 1, Push 1 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void IsNull(ExecutionEngine engine, Instruction instruction) { @@ -24,6 +34,13 @@ public virtual void IsNull(ExecutionEngine engine, Instruction instruction) engine.Push(x.IsNull); } + /// + /// Determines whether the item on top of the evaluation stack has a specified type. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 1, Push 1 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void IsType(ExecutionEngine engine, Instruction instruction) { @@ -34,6 +51,13 @@ public virtual void IsType(ExecutionEngine engine, Instruction instruction) engine.Push(x.Type == type); } + /// + /// Converts the item on top of the evaluation stack to a specified type. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 1, Push 1 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void Convert(ExecutionEngine engine, Instruction instruction) { @@ -41,6 +65,13 @@ public virtual void Convert(ExecutionEngine engine, Instruction instruction) engine.Push(x.ConvertTo((StackItemType)instruction.TokenU8)); } + /// + /// Aborts execution with a specified message. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 1, Push 0 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void AbortMsg(ExecutionEngine engine, Instruction instruction) { @@ -48,6 +79,13 @@ public virtual void AbortMsg(ExecutionEngine engine, Instruction instruction) throw new Exception($"{OpCode.ABORTMSG} is executed. Reason: {msg}"); } + /// + /// Asserts a condition with a specified message, throwing an exception if the condition is false. + /// + /// + /// The execution engine. + /// The instruction being executed. + /// Pop 2, Push 0 [MethodImpl(MethodImplOptions.AggressiveInlining)] public virtual void AssertMsg(ExecutionEngine engine, Instruction instruction) { From 020337c1df7043dba6e62433f57905bf4c6af665 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vitor=20Naz=C3=A1rio=20Coelho?= Date: Thu, 4 Apr 2024 04:58:15 -0300 Subject: [PATCH 108/168] Update global.json (#3189) Co-authored-by: Shargon --- global.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global.json b/global.json index 2172ff52d4..beefe210a1 100644 --- a/global.json +++ b/global.json @@ -1,7 +1,7 @@ { "sdk": { "version": "8.0.202", - "rollForward": "disable", + "rollForward": "latestFeature", "allowPrerelease": false } } From 711fe5233ce1f240e8e541229f8612be91a68ca2 Mon Sep 17 00:00:00 2001 From: Shargon Date: Mon, 8 Apr 2024 23:37:58 -0700 Subject: [PATCH 109/168] Fix generic contract tasks (#3190) * Fix contract tasks * Update src/Neo/SmartContract/ContractTask.cs * clean code --- src/Neo/SmartContract/ContractTask.cs | 20 ++++++++++++++----- .../InteropParameterDescriptor.cs | 12 +++++------ 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/src/Neo/SmartContract/ContractTask.cs b/src/Neo/SmartContract/ContractTask.cs index 6df3627c37..20c26d8236 100644 --- a/src/Neo/SmartContract/ContractTask.cs +++ b/src/Neo/SmartContract/ContractTask.cs @@ -16,7 +16,7 @@ namespace Neo.SmartContract [AsyncMethodBuilder(typeof(ContractTaskMethodBuilder))] class ContractTask { - private readonly ContractTaskAwaiter awaiter; + protected readonly ContractTaskAwaiter _awaiter; public static ContractTask CompletedTask { get; } @@ -28,19 +28,29 @@ static ContractTask() public ContractTask() { - awaiter = CreateAwaiter(); + _awaiter = CreateAwaiter(); } protected virtual ContractTaskAwaiter CreateAwaiter() => new(); - public virtual ContractTaskAwaiter GetAwaiter() => awaiter; + public ContractTaskAwaiter GetAwaiter() => _awaiter; public virtual object GetResult() => null; } [AsyncMethodBuilder(typeof(ContractTaskMethodBuilder<>))] class ContractTask : ContractTask { + public new static ContractTask CompletedTask { get; } + + static ContractTask() + { + CompletedTask = new ContractTask(); + CompletedTask.GetAwaiter().SetResult(); + } + protected override ContractTaskAwaiter CreateAwaiter() => new ContractTaskAwaiter(); - public override ContractTaskAwaiter GetAwaiter() => (ContractTaskAwaiter)base.GetAwaiter(); - public override object GetResult() => ((ContractTaskAwaiter)GetAwaiter()).GetResult(); +#pragma warning disable CS0108 // Member hides inherited member; missing new keyword + public ContractTaskAwaiter GetAwaiter() => (ContractTaskAwaiter)_awaiter; +#pragma warning restore CS0108 // Member hides inherited member; missing new keyword + public override object GetResult() => GetAwaiter().GetResult(); } } diff --git a/src/Neo/SmartContract/InteropParameterDescriptor.cs b/src/Neo/SmartContract/InteropParameterDescriptor.cs index 6a65beb93f..01f4dfa2e5 100644 --- a/src/Neo/SmartContract/InteropParameterDescriptor.cs +++ b/src/Neo/SmartContract/InteropParameterDescriptor.cs @@ -24,7 +24,7 @@ namespace Neo.SmartContract /// public class InteropParameterDescriptor { - private readonly ValidatorAttribute[] validators; + private readonly ValidatorAttribute[] _validators; /// /// The name of the parameter. @@ -80,15 +80,15 @@ public class InteropParameterDescriptor }; internal InteropParameterDescriptor(ParameterInfo parameterInfo) - : this(parameterInfo.ParameterType) + : this(parameterInfo.ParameterType, parameterInfo.GetCustomAttributes(true).ToArray()) { this.Name = parameterInfo.Name; - this.validators = parameterInfo.GetCustomAttributes(true).ToArray(); } - internal InteropParameterDescriptor(Type type) + internal InteropParameterDescriptor(Type type, params ValidatorAttribute[] validators) { - this.Type = type; + Type = type; + _validators = validators; if (IsEnum) { Converter = converters[type.GetEnumUnderlyingType()]; @@ -109,7 +109,7 @@ internal InteropParameterDescriptor(Type type) public void Validate(StackItem item) { - foreach (ValidatorAttribute validator in validators) + foreach (var validator in _validators) validator.Validate(item); } } From 3a12f3dd4d1400e842d58a12f0057607627e511e Mon Sep 17 00:00:00 2001 From: Jimmy Date: Thu, 11 Apr 2024 14:57:41 +0800 Subject: [PATCH 110/168] [VM ADD] add debug info (#3191) * add debug info * use VMPerf isnstead of debug to avoid workflow test output. * try debug again * still no DEBUG --- src/Neo.VM/ExecutionEngine.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Neo.VM/ExecutionEngine.cs b/src/Neo.VM/ExecutionEngine.cs index de268d1030..fcf7d34f90 100644 --- a/src/Neo.VM/ExecutionEngine.cs +++ b/src/Neo.VM/ExecutionEngine.cs @@ -135,6 +135,14 @@ protected internal void ExecuteNext() ExecutionContext context = CurrentContext!; Instruction instruction = context.CurrentInstruction ?? Instruction.RET; PreExecuteInstruction(instruction); +#if VMPERF + Console.WriteLine("op:[" + + this.CurrentContext.InstructionPointer.ToString("X04") + + "]" + + this.CurrentContext.CurrentInstruction?.OpCode + + " " + + this.CurrentContext.EvaluationStack); +#endif try { JumpTable[instruction.OpCode](this, instruction); From 25b08b08ce732fbe4039328e124bdc34e34fff6a Mon Sep 17 00:00:00 2001 From: Shargon Date: Thu, 11 Apr 2024 07:33:25 -0700 Subject: [PATCH 111/168] Clean usings (#3193) --- src/Neo.CLI/CLI/MainService.cs | 1 - src/Neo.VM/JumpTable/JumpTable.Slot.cs | 1 - src/Neo/Cryptography/Murmur128.cs | 1 - src/Neo/Cryptography/Murmur32.cs | 1 - src/Neo/IO/Caching/ECDsaCache.cs | 3 --- tests/Neo.UnitTests/Cryptography/UT_Crypto.cs | 1 - tests/Neo.UnitTests/SmartContract/Manifest/UT_ContractGroup.cs | 1 - tests/Neo.UnitTests/SmartContract/UT_InteropService.NEO.cs | 2 -- tests/Neo.VM.Tests/UT_EvaluationStack.cs | 1 - 9 files changed, 12 deletions(-) diff --git a/src/Neo.CLI/CLI/MainService.cs b/src/Neo.CLI/CLI/MainService.cs index b8d52a6a02..efe48b0165 100644 --- a/src/Neo.CLI/CLI/MainService.cs +++ b/src/Neo.CLI/CLI/MainService.cs @@ -17,7 +17,6 @@ using Neo.Ledger; using Neo.Network.P2P; using Neo.Network.P2P.Payloads; -using Neo.Persistence; using Neo.Plugins; using Neo.SmartContract; using Neo.SmartContract.Manifest; diff --git a/src/Neo.VM/JumpTable/JumpTable.Slot.cs b/src/Neo.VM/JumpTable/JumpTable.Slot.cs index b4e5c89e3e..22214924cf 100644 --- a/src/Neo.VM/JumpTable/JumpTable.Slot.cs +++ b/src/Neo.VM/JumpTable/JumpTable.Slot.cs @@ -9,7 +9,6 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. -using Neo.VM; using Neo.VM.Types; using System; using System.Runtime.CompilerServices; diff --git a/src/Neo/Cryptography/Murmur128.cs b/src/Neo/Cryptography/Murmur128.cs index 3ee258b4a2..15eca775cd 100644 --- a/src/Neo/Cryptography/Murmur128.cs +++ b/src/Neo/Cryptography/Murmur128.cs @@ -11,7 +11,6 @@ using System; using System.Buffers.Binary; -using System.Numerics; using System.Runtime.CompilerServices; using System.Security.Cryptography; diff --git a/src/Neo/Cryptography/Murmur32.cs b/src/Neo/Cryptography/Murmur32.cs index 8feaa92d37..0f2c1b828d 100644 --- a/src/Neo/Cryptography/Murmur32.cs +++ b/src/Neo/Cryptography/Murmur32.cs @@ -11,7 +11,6 @@ using System; using System.Buffers.Binary; -using System.Numerics; using System.Security.Cryptography; namespace Neo.Cryptography diff --git a/src/Neo/IO/Caching/ECDsaCache.cs b/src/Neo/IO/Caching/ECDsaCache.cs index f728195168..b25f29da8e 100644 --- a/src/Neo/IO/Caching/ECDsaCache.cs +++ b/src/Neo/IO/Caching/ECDsaCache.cs @@ -9,11 +9,8 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. -using Neo.Cryptography.ECC; -using System; using System.Collections.Generic; using System.Security.Cryptography; -using System.Text; namespace Neo.IO.Caching { diff --git a/tests/Neo.UnitTests/Cryptography/UT_Crypto.cs b/tests/Neo.UnitTests/Cryptography/UT_Crypto.cs index 189cf0f626..e311d6cafe 100644 --- a/tests/Neo.UnitTests/Cryptography/UT_Crypto.cs +++ b/tests/Neo.UnitTests/Cryptography/UT_Crypto.cs @@ -14,7 +14,6 @@ using Neo.Cryptography; using Neo.Wallets; using System; -using System.Linq; using System.Security.Cryptography; namespace Neo.UnitTests.Cryptography diff --git a/tests/Neo.UnitTests/SmartContract/Manifest/UT_ContractGroup.cs b/tests/Neo.UnitTests/SmartContract/Manifest/UT_ContractGroup.cs index 264f90d13a..b612714e7c 100644 --- a/tests/Neo.UnitTests/SmartContract/Manifest/UT_ContractGroup.cs +++ b/tests/Neo.UnitTests/SmartContract/Manifest/UT_ContractGroup.cs @@ -15,7 +15,6 @@ using Neo.SmartContract.Manifest; using Neo.Wallets; using System; -using System.Linq; namespace Neo.UnitTests.SmartContract.Manifest { diff --git a/tests/Neo.UnitTests/SmartContract/UT_InteropService.NEO.cs b/tests/Neo.UnitTests/SmartContract/UT_InteropService.NEO.cs index be50a550c8..4f0767bf2c 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_InteropService.NEO.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_InteropService.NEO.cs @@ -12,10 +12,8 @@ using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.Cryptography; -using Neo.Cryptography.ECC; using Neo.IO; using Neo.Network.P2P; -using Neo.Network.P2P.Payloads; using Neo.SmartContract; using Neo.SmartContract.Manifest; using Neo.SmartContract.Native; diff --git a/tests/Neo.VM.Tests/UT_EvaluationStack.cs b/tests/Neo.VM.Tests/UT_EvaluationStack.cs index 51df42ffc1..fb1f5e5813 100644 --- a/tests/Neo.VM.Tests/UT_EvaluationStack.cs +++ b/tests/Neo.VM.Tests/UT_EvaluationStack.cs @@ -11,7 +11,6 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.Test.Extensions; -using Neo.Test.Helpers; using Neo.VM; using Neo.VM.Types; using System; From 8ffbd4c1ef4ad0f6fd6abd1cf7e5ea7c2c0e3308 Mon Sep 17 00:00:00 2001 From: Shargon Date: Thu, 11 Apr 2024 07:52:03 -0700 Subject: [PATCH 112/168] Fix obsolete (#3192) --- src/Neo/SmartContract/IInteroperable.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Neo/SmartContract/IInteroperable.cs b/src/Neo/SmartContract/IInteroperable.cs index 5254898efe..2810d40d01 100644 --- a/src/Neo/SmartContract/IInteroperable.cs +++ b/src/Neo/SmartContract/IInteroperable.cs @@ -11,7 +11,7 @@ using Neo.VM; using Neo.VM.Types; -using System.Runtime.Serialization; +using System; namespace Neo.SmartContract { @@ -35,7 +35,7 @@ public interface IInteroperable public IInteroperable Clone() { - IInteroperable result = (IInteroperable)FormatterServices.GetUninitializedObject(GetType()); + var result = (IInteroperable)Activator.CreateInstance(GetType()); result.FromStackItem(ToStackItem(null)); return result; } From b2b1150983b790dfb1fa6cb846a7c9afd9492ba6 Mon Sep 17 00:00:00 2001 From: Anna Shaleva Date: Tue, 16 Apr 2024 11:03:50 +0300 Subject: [PATCH 113/168] SmartContract: fix native NEP-17 manifest construction (#3195) * SmartContract: fix native NEP-17 manifest construction Take into account event attributes declared onto the base class for native contracts. Close #3194. Signed-off-by: Anna Shaleva * SmartContract: add UT to check native contract states Ensure that contract states generated with all hardforks enabled match the expected values. Signed-off-by: Anna Shaleva * Update tests/Neo.UnitTests/SmartContract/Native/UT_NativeContract.cs * Update tests/Neo.UnitTests/SmartContract/Native/UT_NativeContract.cs --------- Signed-off-by: Anna Shaleva Co-authored-by: Shargon Co-authored-by: Jimmy --- .../SmartContract/Native/NativeContract.cs | 3 + .../SmartContract/Native/UT_NativeContract.cs | 112 ++++++++++++++++++ 2 files changed, 115 insertions(+) diff --git a/src/Neo/SmartContract/Native/NativeContract.cs b/src/Neo/SmartContract/Native/NativeContract.cs index a07f0ac8ce..2003962b87 100644 --- a/src/Neo/SmartContract/Native/NativeContract.cs +++ b/src/Neo/SmartContract/Native/NativeContract.cs @@ -152,6 +152,9 @@ protected NativeContract() eventsDescriptors = GetType().GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public, null, Array.Empty(), null)?. GetCustomAttributes(). + // Take into account not only the contract constructor, but also the base type constructor for proper FungibleToken events handling. + Concat(GetType().BaseType?.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public, null, Array.Empty(), null)?. + GetCustomAttributes()). OrderBy(p => p.Order).ToList().AsReadOnly(); // Calculate the initializations forks diff --git a/tests/Neo.UnitTests/SmartContract/Native/UT_NativeContract.cs b/tests/Neo.UnitTests/SmartContract/Native/UT_NativeContract.cs index 7f23519e9f..181ff139ec 100644 --- a/tests/Neo.UnitTests/SmartContract/Native/UT_NativeContract.cs +++ b/tests/Neo.UnitTests/SmartContract/Native/UT_NativeContract.cs @@ -9,15 +9,55 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Network.P2P.Payloads; +using Neo.Persistence; +using Neo.SmartContract; using Neo.SmartContract.Native; +using Neo.VM; +using System; +using System.Collections.Generic; using System.IO; +using System.Linq; +using System.Numerics; namespace Neo.UnitTests.SmartContract.Native { [TestClass] public class UT_NativeContract { + private DataCache _snapshot; + /// + /// _nativeStates contains a mapping from native contract name to expected native contract state + /// constructed with all hardforks enabled and marshalled in JSON. + /// + private Dictionary _nativeStates; + + [TestInitialize] + public void TestSetup() + { + _snapshot = TestBlockchain.GetTestSnapshot(); + _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}}""" }, + {"StdLib", """{"id":-2,"updatecounter":0,"hash":"0xacce6fd80d44e1796aa0c2c625e9e4e0ce39efc0","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dA","checksum":1991619121},"manifest":{"name":"StdLib","groups":[],"features":{},"supportedstandards":[],"abi":{"methods":[{"name":"atoi","parameters":[{"name":"value","type":"String"}],"returntype":"Integer","offset":0,"safe":true},{"name":"atoi","parameters":[{"name":"value","type":"String"},{"name":"base","type":"Integer"}],"returntype":"Integer","offset":7,"safe":true},{"name":"base58CheckDecode","parameters":[{"name":"s","type":"String"}],"returntype":"ByteArray","offset":14,"safe":true},{"name":"base58CheckEncode","parameters":[{"name":"data","type":"ByteArray"}],"returntype":"String","offset":21,"safe":true},{"name":"base58Decode","parameters":[{"name":"s","type":"String"}],"returntype":"ByteArray","offset":28,"safe":true},{"name":"base58Encode","parameters":[{"name":"data","type":"ByteArray"}],"returntype":"String","offset":35,"safe":true},{"name":"base64Decode","parameters":[{"name":"s","type":"String"}],"returntype":"ByteArray","offset":42,"safe":true},{"name":"base64Encode","parameters":[{"name":"data","type":"ByteArray"}],"returntype":"String","offset":49,"safe":true},{"name":"deserialize","parameters":[{"name":"data","type":"ByteArray"}],"returntype":"Any","offset":56,"safe":true},{"name":"itoa","parameters":[{"name":"value","type":"Integer"}],"returntype":"String","offset":63,"safe":true},{"name":"itoa","parameters":[{"name":"value","type":"Integer"},{"name":"base","type":"Integer"}],"returntype":"String","offset":70,"safe":true},{"name":"jsonDeserialize","parameters":[{"name":"json","type":"ByteArray"}],"returntype":"Any","offset":77,"safe":true},{"name":"jsonSerialize","parameters":[{"name":"item","type":"Any"}],"returntype":"ByteArray","offset":84,"safe":true},{"name":"memoryCompare","parameters":[{"name":"str1","type":"ByteArray"},{"name":"str2","type":"ByteArray"}],"returntype":"Integer","offset":91,"safe":true},{"name":"memorySearch","parameters":[{"name":"mem","type":"ByteArray"},{"name":"value","type":"ByteArray"}],"returntype":"Integer","offset":98,"safe":true},{"name":"memorySearch","parameters":[{"name":"mem","type":"ByteArray"},{"name":"value","type":"ByteArray"},{"name":"start","type":"Integer"}],"returntype":"Integer","offset":105,"safe":true},{"name":"memorySearch","parameters":[{"name":"mem","type":"ByteArray"},{"name":"value","type":"ByteArray"},{"name":"start","type":"Integer"},{"name":"backward","type":"Boolean"}],"returntype":"Integer","offset":112,"safe":true},{"name":"serialize","parameters":[{"name":"item","type":"Any"}],"returntype":"ByteArray","offset":119,"safe":true},{"name":"strLen","parameters":[{"name":"str","type":"String"}],"returntype":"Integer","offset":126,"safe":true},{"name":"stringSplit","parameters":[{"name":"str","type":"String"},{"name":"separator","type":"String"}],"returntype":"Array","offset":133,"safe":true},{"name":"stringSplit","parameters":[{"name":"str","type":"String"},{"name":"separator","type":"String"},{"name":"removeEmptyEntries","type":"Boolean"}],"returntype":"Array","offset":140,"safe":true}],"events":[]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"extra":null}}"""}, + {"CryptoLib", """{"id":-3,"updatecounter":0,"hash":"0x726cb6e0cd8628a1350a611384688911ab75f51b","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0A=","checksum":1094259016},"manifest":{"name":"CryptoLib","groups":[],"features":{},"supportedstandards":[],"abi":{"methods":[{"name":"bls12381Add","parameters":[{"name":"x","type":"InteropInterface"},{"name":"y","type":"InteropInterface"}],"returntype":"InteropInterface","offset":0,"safe":true},{"name":"bls12381Deserialize","parameters":[{"name":"data","type":"ByteArray"}],"returntype":"InteropInterface","offset":7,"safe":true},{"name":"bls12381Equal","parameters":[{"name":"x","type":"InteropInterface"},{"name":"y","type":"InteropInterface"}],"returntype":"Boolean","offset":14,"safe":true},{"name":"bls12381Mul","parameters":[{"name":"x","type":"InteropInterface"},{"name":"mul","type":"ByteArray"},{"name":"neg","type":"Boolean"}],"returntype":"InteropInterface","offset":21,"safe":true},{"name":"bls12381Pairing","parameters":[{"name":"g1","type":"InteropInterface"},{"name":"g2","type":"InteropInterface"}],"returntype":"InteropInterface","offset":28,"safe":true},{"name":"bls12381Serialize","parameters":[{"name":"g","type":"InteropInterface"}],"returntype":"ByteArray","offset":35,"safe":true},{"name":"keccak256","parameters":[{"name":"data","type":"ByteArray"}],"returntype":"ByteArray","offset":42,"safe":true},{"name":"murmur32","parameters":[{"name":"data","type":"ByteArray"},{"name":"seed","type":"Integer"}],"returntype":"ByteArray","offset":49,"safe":true},{"name":"ripemd160","parameters":[{"name":"data","type":"ByteArray"}],"returntype":"ByteArray","offset":56,"safe":true},{"name":"sha256","parameters":[{"name":"data","type":"ByteArray"}],"returntype":"ByteArray","offset":63,"safe":true},{"name":"verifyWithECDsa","parameters":[{"name":"message","type":"ByteArray"},{"name":"pubkey","type":"ByteArray"},{"name":"signature","type":"ByteArray"},{"name":"curve","type":"Integer"}],"returntype":"Boolean","offset":70,"safe":true}],"events":[]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"extra":null}}"""}, + {"LedgerContract", """{"id":-4,"updatecounter":0,"hash":"0xda65b600f7124ce6c79950c1772a36403104f2be","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0A=","checksum":1110259869},"manifest":{"name":"LedgerContract","groups":[],"features":{},"supportedstandards":[],"abi":{"methods":[{"name":"currentHash","parameters":[],"returntype":"Hash256","offset":0,"safe":true},{"name":"currentIndex","parameters":[],"returntype":"Integer","offset":7,"safe":true},{"name":"getBlock","parameters":[{"name":"indexOrHash","type":"ByteArray"}],"returntype":"Array","offset":14,"safe":true},{"name":"getTransaction","parameters":[{"name":"hash","type":"Hash256"}],"returntype":"Array","offset":21,"safe":true},{"name":"getTransactionFromBlock","parameters":[{"name":"blockIndexOrHash","type":"ByteArray"},{"name":"txIndex","type":"Integer"}],"returntype":"Array","offset":28,"safe":true},{"name":"getTransactionHeight","parameters":[{"name":"hash","type":"Hash256"}],"returntype":"Integer","offset":35,"safe":true},{"name":"getTransactionSigners","parameters":[{"name":"hash","type":"Hash256"}],"returntype":"Array","offset":42,"safe":true},{"name":"getTransactionVMState","parameters":[{"name":"hash","type":"Hash256"}],"returntype":"Integer","offset":49,"safe":true}],"events":[]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"extra":null}}"""}, + {"NeoToken", """{"id":-5,"updatecounter":0,"hash":"0xef4073a0f2b305a38ec4050e4d3d28bc40ea63f5","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0A=","checksum":1325686241},"manifest":{"name":"NeoToken","groups":[],"features":{},"supportedstandards":["NEP-17"],"abi":{"methods":[{"name":"balanceOf","parameters":[{"name":"account","type":"Hash160"}],"returntype":"Integer","offset":0,"safe":true},{"name":"decimals","parameters":[],"returntype":"Integer","offset":7,"safe":true},{"name":"getAccountState","parameters":[{"name":"account","type":"Hash160"}],"returntype":"Array","offset":14,"safe":true},{"name":"getAllCandidates","parameters":[],"returntype":"InteropInterface","offset":21,"safe":true},{"name":"getCandidateVote","parameters":[{"name":"pubKey","type":"PublicKey"}],"returntype":"Integer","offset":28,"safe":true},{"name":"getCandidates","parameters":[],"returntype":"Array","offset":35,"safe":true},{"name":"getCommittee","parameters":[],"returntype":"Array","offset":42,"safe":true},{"name":"getCommitteeAddress","parameters":[],"returntype":"Hash160","offset":49,"safe":true},{"name":"getGasPerBlock","parameters":[],"returntype":"Integer","offset":56,"safe":true},{"name":"getNextBlockValidators","parameters":[],"returntype":"Array","offset":63,"safe":true},{"name":"getRegisterPrice","parameters":[],"returntype":"Integer","offset":70,"safe":true},{"name":"registerCandidate","parameters":[{"name":"pubkey","type":"PublicKey"}],"returntype":"Boolean","offset":77,"safe":false},{"name":"setGasPerBlock","parameters":[{"name":"gasPerBlock","type":"Integer"}],"returntype":"Void","offset":84,"safe":false},{"name":"setRegisterPrice","parameters":[{"name":"registerPrice","type":"Integer"}],"returntype":"Void","offset":91,"safe":false},{"name":"symbol","parameters":[],"returntype":"String","offset":98,"safe":true},{"name":"totalSupply","parameters":[],"returntype":"Integer","offset":105,"safe":true},{"name":"transfer","parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"},{"name":"data","type":"Any"}],"returntype":"Boolean","offset":112,"safe":false},{"name":"unclaimedGas","parameters":[{"name":"account","type":"Hash160"},{"name":"end","type":"Integer"}],"returntype":"Integer","offset":119,"safe":true},{"name":"unregisterCandidate","parameters":[{"name":"pubkey","type":"PublicKey"}],"returntype":"Boolean","offset":126,"safe":false},{"name":"vote","parameters":[{"name":"account","type":"Hash160"},{"name":"voteTo","type":"PublicKey"}],"returntype":"Boolean","offset":133,"safe":false}],"events":[{"name":"Transfer","parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"}]},{"name":"CandidateStateChanged","parameters":[{"name":"pubkey","type":"PublicKey"},{"name":"registered","type":"Boolean"},{"name":"votes","type":"Integer"}]},{"name":"Vote","parameters":[{"name":"account","type":"Hash160"},{"name":"from","type":"PublicKey"},{"name":"to","type":"PublicKey"},{"name":"amount","type":"Integer"}]},{"name":"CommitteeChanged","parameters":[{"name":"old","type":"Array"},{"name":"new","type":"Array"}]}]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"extra":null}}"""}, + {"GasToken", """{"id":-6,"updatecounter":0,"hash":"0xd2a4cff31913016155e38e474a2c06d08be276cf","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0A=","checksum":2663858513},"manifest":{"name":"GasToken","groups":[],"features":{},"supportedstandards":["NEP-17"],"abi":{"methods":[{"name":"balanceOf","parameters":[{"name":"account","type":"Hash160"}],"returntype":"Integer","offset":0,"safe":true},{"name":"decimals","parameters":[],"returntype":"Integer","offset":7,"safe":true},{"name":"symbol","parameters":[],"returntype":"String","offset":14,"safe":true},{"name":"totalSupply","parameters":[],"returntype":"Integer","offset":21,"safe":true},{"name":"transfer","parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"},{"name":"data","type":"Any"}],"returntype":"Boolean","offset":28,"safe":false}],"events":[{"name":"Transfer","parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"}]}]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"extra":null}}"""}, + {"PolicyContract", """{"id":-7,"updatecounter":0,"hash":"0xcc5e4edd9f5f8dba8bb65734541df7a1c081c67b","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0A=","checksum":1094259016},"manifest":{"name":"PolicyContract","groups":[],"features":{},"supportedstandards":[],"abi":{"methods":[{"name":"blockAccount","parameters":[{"name":"account","type":"Hash160"}],"returntype":"Boolean","offset":0,"safe":false},{"name":"getAttributeFee","parameters":[{"name":"attributeType","type":"Integer"}],"returntype":"Integer","offset":7,"safe":true},{"name":"getExecFeeFactor","parameters":[],"returntype":"Integer","offset":14,"safe":true},{"name":"getFeePerByte","parameters":[],"returntype":"Integer","offset":21,"safe":true},{"name":"getStoragePrice","parameters":[],"returntype":"Integer","offset":28,"safe":true},{"name":"isBlocked","parameters":[{"name":"account","type":"Hash160"}],"returntype":"Boolean","offset":35,"safe":true},{"name":"setAttributeFee","parameters":[{"name":"attributeType","type":"Integer"},{"name":"value","type":"Integer"}],"returntype":"Void","offset":42,"safe":false},{"name":"setExecFeeFactor","parameters":[{"name":"value","type":"Integer"}],"returntype":"Void","offset":49,"safe":false},{"name":"setFeePerByte","parameters":[{"name":"value","type":"Integer"}],"returntype":"Void","offset":56,"safe":false},{"name":"setStoragePrice","parameters":[{"name":"value","type":"Integer"}],"returntype":"Void","offset":63,"safe":false},{"name":"unblockAccount","parameters":[{"name":"account","type":"Hash160"}],"returntype":"Boolean","offset":70,"safe":false}],"events":[]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"extra":null}}"""}, + {"RoleManagement", """{"id":-8,"updatecounter":0,"hash":"0x49cf4e5378ffcd4dec034fd98a174c5491e395e2","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0A=","checksum":983638438},"manifest":{"name":"RoleManagement","groups":[],"features":{},"supportedstandards":[],"abi":{"methods":[{"name":"designateAsRole","parameters":[{"name":"role","type":"Integer"},{"name":"nodes","type":"Array"}],"returntype":"Void","offset":0,"safe":false},{"name":"getDesignatedByRole","parameters":[{"name":"role","type":"Integer"},{"name":"index","type":"Integer"}],"returntype":"Array","offset":7,"safe":true}],"events":[{"name":"Designation","parameters":[{"name":"Role","type":"Integer"},{"name":"BlockIndex","type":"Integer"}]}]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"extra":null}}"""}, + {"OracleContract", """{"id":-9,"updatecounter":0,"hash":"0xfe924b7cfe89ddd271abaf7210a80a7e11178758","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0A=","checksum":2663858513},"manifest":{"name":"OracleContract","groups":[],"features":{},"supportedstandards":[],"abi":{"methods":[{"name":"finish","parameters":[],"returntype":"Void","offset":0,"safe":false},{"name":"getPrice","parameters":[],"returntype":"Integer","offset":7,"safe":true},{"name":"request","parameters":[{"name":"url","type":"String"},{"name":"filter","type":"String"},{"name":"callback","type":"String"},{"name":"userData","type":"Any"},{"name":"gasForResponse","type":"Integer"}],"returntype":"Void","offset":14,"safe":false},{"name":"setPrice","parameters":[{"name":"price","type":"Integer"}],"returntype":"Void","offset":21,"safe":false},{"name":"verify","parameters":[],"returntype":"Boolean","offset":28,"safe":true}],"events":[{"name":"OracleRequest","parameters":[{"name":"Id","type":"Integer"},{"name":"RequestContract","type":"Hash160"},{"name":"Url","type":"String"},{"name":"Filter","type":"String"}]},{"name":"OracleResponse","parameters":[{"name":"Id","type":"Integer"},{"name":"OriginalTx","type":"Hash256"}]}]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"extra":null}}"""}, + }; + } + + [TestCleanup] + public void Clean() + { + TestBlockchain.ResetStore(); + } + [TestMethod] public void TestGetContract() { @@ -43,5 +83,77 @@ public void TestIsInitializeBlock() Assert.IsTrue(NativeContract.CryptoLib.IsInitializeBlock(settings, 20, out hf)); Assert.AreEqual(Hardfork.HF_Cockatrice, hf); } + + [TestMethod] + public void TestGenesisNEP17Manifest() + { + var persistingBlock = new Block + { + Header = new Header + { + Index = 1, + MerkleRoot = UInt256.Zero, + NextConsensus = UInt160.Zero, + PrevHash = UInt256.Zero, + Witness = new Witness() { InvocationScript = Array.Empty(), VerificationScript = Array.Empty() } + }, + Transactions = [] + }; + var snapshot = _snapshot.CreateSnapshot(); + + // 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. + foreach (var h in new List() { NativeContract.GAS.Hash, NativeContract.NEO.Hash }) + { + var state = Call_GetContract(snapshot, h, persistingBlock); + Assert.IsTrue(state.Manifest.SupportedStandards.Contains("NEP-17")); + Assert.AreEqual(1, state.Manifest.Abi.Events.Where(e => e.Name == "Transfer").Count()); + } + } + + [TestMethod] + public void TestGenesisNativeState() + { + var persistingBlock = new Block + { + Header = new Header + { + Index = 1, + MerkleRoot = UInt256.Zero, + NextConsensus = UInt160.Zero, + PrevHash = UInt256.Zero, + Witness = new Witness() { InvocationScript = Array.Empty(), VerificationScript = Array.Empty() } + }, + Transactions = [] + }; + var snapshot = _snapshot.CreateSnapshot(); + + // Ensure that all native contracts have proper state generated with an assumption that + // all hardforks enabled. + foreach (var ctr in NativeContract.Contracts) + { + var state = Call_GetContract(snapshot, ctr.Hash, persistingBlock); + Assert.AreEqual(_nativeStates[ctr.Name], state.ToJson().ToString()); + } + } + + internal static ContractState Call_GetContract(DataCache snapshot, UInt160 address, Block persistingBlock) + { + using var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, persistingBlock, settings: TestBlockchain.TheNeoSystem.Settings); + + using var script = new ScriptBuilder(); + script.EmitDynamicCall(NativeContract.ContractManagement.Hash, "getContract", address); + engine.LoadScript(script.ToArray()); + + engine.Execute().Should().Be(VMState.HALT); + + var result = engine.ResultStack.Pop(); + result.Should().BeOfType(typeof(VM.Types.Array)); + + var cs = new ContractState(); + ((IInteroperable)cs).FromStackItem(result); + + return cs; + } } } From 13905e17b86c2e214abe18864e1506c95096b183 Mon Sep 17 00:00:00 2001 From: Christopher Schuchardt Date: Thu, 18 Apr 2024 02:15:07 -0400 Subject: [PATCH 114/168] Fixes (#3196) --- src/Neo/Cryptography/Helper.cs | 4 ++++ src/Neo/NeoSystem.cs | 4 ++-- src/Neo/Persistence/StoreFactory.cs | 2 +- src/Neo/ProtocolSettings.cs | 2 +- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/Neo/Cryptography/Helper.cs b/src/Neo/Cryptography/Helper.cs index 840b6ebb7b..a087620034 100644 --- a/src/Neo/Cryptography/Helper.cs +++ b/src/Neo/Cryptography/Helper.cs @@ -160,7 +160,9 @@ public static byte[] AES256Encrypt(this byte[] plainData, byte[] key, byte[] non var cipherBytes = new byte[plainData.Length]; if (!IsOSX) { +#pragma warning disable SYSLIB0053 // Type or member is obsolete using var cipher = new AesGcm(key); +#pragma warning restore SYSLIB0053 // Type or member is obsolete cipher.Encrypt(nonce, plainData, cipherBytes, tag, associatedData); } else @@ -188,7 +190,9 @@ public static byte[] AES256Decrypt(this byte[] encryptedData, byte[] key, byte[] var decryptedData = new byte[cipherBytes.Length]; if (!IsOSX) { +#pragma warning disable SYSLIB0053 // Type or member is obsolete using var cipher = new AesGcm(key); +#pragma warning restore SYSLIB0053 // Type or member is obsolete cipher.Decrypt(nonce, cipherBytes, tag, decryptedData, associatedData); } else diff --git a/src/Neo/NeoSystem.cs b/src/Neo/NeoSystem.cs index 1303770a3f..bfed791509 100644 --- a/src/Neo/NeoSystem.cs +++ b/src/Neo/NeoSystem.cs @@ -116,7 +116,7 @@ static NeoSystem() /// The protocol settings of the . /// The storage engine used to create the objects. If this parameter is , a default in-memory storage engine will be used. /// The path of the storage. If is the default in-memory storage engine, this parameter is ignored. - public NeoSystem(ProtocolSettings settings, string? storageProvider = null, string? storagePath = null) : + public NeoSystem(ProtocolSettings settings, string storageProvider = null, string storagePath = null) : this(settings, StoreFactory.GetStoreProvider(storageProvider ?? nameof(MemoryStore)) ?? throw new ArgumentException($"Can't find the storage provider {storageProvider}", nameof(storageProvider)), storagePath) { @@ -128,7 +128,7 @@ public NeoSystem(ProtocolSettings settings, string? storageProvider = null, stri /// The protocol settings of the . /// The to use. /// The path of the storage. If is the default in-memory storage engine, this parameter is ignored. - public NeoSystem(ProtocolSettings settings, IStoreProvider storageProvider, string? storagePath = null) + public NeoSystem(ProtocolSettings settings, IStoreProvider storageProvider, string storagePath = null) { this.Settings = settings; this.GenesisBlock = CreateGenesisBlock(settings); diff --git a/src/Neo/Persistence/StoreFactory.cs b/src/Neo/Persistence/StoreFactory.cs index 2764366f06..6fee81e9f3 100644 --- a/src/Neo/Persistence/StoreFactory.cs +++ b/src/Neo/Persistence/StoreFactory.cs @@ -36,7 +36,7 @@ public static void RegisterProvider(IStoreProvider provider) /// /// Name /// Store provider - public static IStoreProvider? GetStoreProvider(string name) + public static IStoreProvider GetStoreProvider(string name) { if (providers.TryGetValue(name, out var provider)) { diff --git a/src/Neo/ProtocolSettings.cs b/src/Neo/ProtocolSettings.cs index 1b7367a6a2..c3d8232afd 100644 --- a/src/Neo/ProtocolSettings.cs +++ b/src/Neo/ProtocolSettings.cs @@ -120,7 +120,7 @@ public record ProtocolSettings Hardforks = EnsureOmmitedHardforks(new Dictionary()).ToImmutableDictionary() }; - public static ProtocolSettings? Custom { get; set; } + public static ProtocolSettings Custom { get; set; } /// /// Loads the at the specified path. From 629baf819f9ebedec4b2e89e7b55a5adf1836597 Mon Sep 17 00:00:00 2001 From: Shargon Date: Fri, 19 Apr 2024 00:30:47 -0700 Subject: [PATCH 115/168] Check script null (#3198) --- src/Neo/SmartContract/ContractParametersContext.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Neo/SmartContract/ContractParametersContext.cs b/src/Neo/SmartContract/ContractParametersContext.cs index f6a18e081d..3bf98e981b 100644 --- a/src/Neo/SmartContract/ContractParametersContext.cs +++ b/src/Neo/SmartContract/ContractParametersContext.cs @@ -44,7 +44,7 @@ public ContextItem(Contract contract) public ContextItem(JObject json) { - this.Script = Convert.FromBase64String(json["script"].AsString()); + this.Script = json["script"] is JToken.Null ? null : Convert.FromBase64String(json["script"].AsString()); this.Parameters = ((JArray)json["parameters"]).Select(p => ContractParameter.FromJson((JObject)p)).ToArray(); this.Signatures = ((JObject)json["signatures"]).Properties.Select(p => new { @@ -56,7 +56,7 @@ public ContextItem(JObject json) public JObject ToJson() { JObject json = new(); - json["script"] = Convert.ToBase64String(Script); + json["script"] = Script == null ? null : Convert.ToBase64String(Script); json["parameters"] = new JArray(Parameters.Select(p => p.ToJson())); json["signatures"] = new JObject(); foreach (var signature in Signatures) From 429a081753e46d995829c5182a3f73bc55a63741 Mon Sep 17 00:00:00 2001 From: Shargon Date: Thu, 2 May 2024 00:19:58 -0700 Subject: [PATCH 116/168] Add `Async` to async method's name (#3206) * Add Async * Add more --- .../SmartContract/ApplicationEngine.Contract.cs | 16 ++++++++-------- src/Neo/SmartContract/ApplicationEngine.cs | 4 ++-- .../SmartContract/Native/ContractManagement.cs | 14 +++++++------- src/Neo/SmartContract/Native/FungibleToken.cs | 10 +++++----- src/Neo/SmartContract/Native/GasToken.cs | 4 ++-- src/Neo/SmartContract/Native/LedgerContract.cs | 4 ++-- src/Neo/SmartContract/Native/NativeContract.cs | 6 +++--- src/Neo/SmartContract/Native/NeoToken.cs | 10 +++++----- src/Neo/SmartContract/Native/OracleContract.cs | 6 +++--- src/Neo/SmartContract/Native/PolicyContract.cs | 2 +- .../SmartContract/Native/UT_PolicyContract.cs | 2 +- 11 files changed, 39 insertions(+), 39 deletions(-) diff --git a/src/Neo/SmartContract/ApplicationEngine.Contract.cs b/src/Neo/SmartContract/ApplicationEngine.Contract.cs index 1677396f1c..6f4b257016 100644 --- a/src/Neo/SmartContract/ApplicationEngine.Contract.cs +++ b/src/Neo/SmartContract/ApplicationEngine.Contract.cs @@ -54,13 +54,13 @@ partial class ApplicationEngine /// The of System.Contract.NativeOnPersist. /// /// Note: It is for internal use only. Do not use it directly in smart contracts. - public static readonly InteropDescriptor System_Contract_NativeOnPersist = Register("System.Contract.NativeOnPersist", nameof(NativeOnPersist), 0, CallFlags.States); + public static readonly InteropDescriptor System_Contract_NativeOnPersist = Register("System.Contract.NativeOnPersist", nameof(NativeOnPersistAsync), 0, CallFlags.States); /// /// The of System.Contract.NativePostPersist. /// /// Note: It is for internal use only. Do not use it directly in smart contracts. - public static readonly InteropDescriptor System_Contract_NativePostPersist = Register("System.Contract.NativePostPersist", nameof(NativePostPersist), 0, CallFlags.States); + public static readonly InteropDescriptor System_Contract_NativePostPersist = Register("System.Contract.NativePostPersist", nameof(NativePostPersistAsync), 0, CallFlags.States); /// /// The implementation of System.Contract.Call. @@ -145,9 +145,9 @@ internal protected UInt160 CreateMultisigAccount(int m, ECPoint[] pubKeys) /// /// The implementation of System.Contract.NativeOnPersist. - /// Calls to the of all native contracts. + /// Calls to the of all native contracts. /// - protected internal async void NativeOnPersist() + protected internal async void NativeOnPersistAsync() { try { @@ -156,7 +156,7 @@ protected internal async void NativeOnPersist() foreach (NativeContract contract in NativeContract.Contracts) { if (contract.IsActive(ProtocolSettings, PersistingBlock.Index)) - await contract.OnPersist(this); + await contract.OnPersistAsync(this); } } catch (Exception ex) @@ -167,9 +167,9 @@ protected internal async void NativeOnPersist() /// /// The implementation of System.Contract.NativePostPersist. - /// Calls to the of all native contracts. + /// Calls to the of all native contracts. /// - protected internal async void NativePostPersist() + protected internal async void NativePostPersistAsync() { try { @@ -178,7 +178,7 @@ protected internal async void NativePostPersist() foreach (NativeContract contract in NativeContract.Contracts) { if (contract.IsActive(ProtocolSettings, PersistingBlock.Index)) - await contract.PostPersist(this); + await contract.PostPersistAsync(this); } } catch (Exception ex) diff --git a/src/Neo/SmartContract/ApplicationEngine.cs b/src/Neo/SmartContract/ApplicationEngine.cs index 2b78f62fe4..f2c63fe3b3 100644 --- a/src/Neo/SmartContract/ApplicationEngine.cs +++ b/src/Neo/SmartContract/ApplicationEngine.cs @@ -307,7 +307,7 @@ private ExecutionContext CallContractInternal(ContractState contract, ContractMe return context_new; } - internal ContractTask CallFromNativeContract(UInt160 callingScriptHash, UInt160 hash, string method, params StackItem[] args) + internal ContractTask CallFromNativeContractAsync(UInt160 callingScriptHash, UInt160 hash, string method, params StackItem[] args) { ExecutionContext context_new = CallContractInternal(hash, method, CallFlags.All, false, args); ExecutionContextState state = context_new.GetState(); @@ -317,7 +317,7 @@ internal ContractTask CallFromNativeContract(UInt160 callingScriptHash, UInt160 return task; } - internal ContractTask CallFromNativeContract(UInt160 callingScriptHash, UInt160 hash, string method, params StackItem[] args) + internal ContractTask CallFromNativeContractAsync(UInt160 callingScriptHash, UInt160 hash, string method, params StackItem[] args) { ExecutionContext context_new = CallContractInternal(hash, method, CallFlags.All, true, args); ExecutionContextState state = context_new.GetState(); diff --git a/src/Neo/SmartContract/Native/ContractManagement.cs b/src/Neo/SmartContract/Native/ContractManagement.cs index 28642a2db1..e326421f91 100644 --- a/src/Neo/SmartContract/Native/ContractManagement.cs +++ b/src/Neo/SmartContract/Native/ContractManagement.cs @@ -48,7 +48,7 @@ private int GetNextAvailableId(DataCache snapshot) return value; } - internal override ContractTask Initialize(ApplicationEngine engine, Hardfork? hardfork) + internal override ContractTask InitializeAsync(ApplicationEngine engine, Hardfork? hardfork) { if (hardfork == ActiveIn) { @@ -58,15 +58,15 @@ internal override ContractTask Initialize(ApplicationEngine engine, Hardfork? ha return ContractTask.CompletedTask; } - private async ContractTask OnDeploy(ApplicationEngine engine, ContractState contract, StackItem data, bool update) + private async ContractTask OnDeployAsync(ApplicationEngine engine, ContractState contract, StackItem data, bool update) { ContractMethodDescriptor md = contract.Manifest.Abi.GetMethod("_deploy", 2); if (md is not null) - await engine.CallFromNativeContract(Hash, contract.Hash, md.Name, data, update); + await engine.CallFromNativeContractAsync(Hash, contract.Hash, md.Name, data, update); engine.SendNotification(Hash, update ? "Update" : "Deploy", new VM.Types.Array(engine.ReferenceCounter) { contract.Hash.ToArray() }); } - internal override async ContractTask OnPersist(ApplicationEngine engine) + internal override async ContractTask OnPersistAsync(ApplicationEngine engine) { foreach (NativeContract contract in Contracts) { @@ -92,7 +92,7 @@ internal override async ContractTask OnPersist(ApplicationEngine engine) oldContract.Manifest = contractState.Manifest; } - await contract.Initialize(engine, hf); + await contract.InitializeAsync(engine, hf); // Emit native contract notification engine.SendNotification(Hash, state is null ? "Deploy" : "Update", new VM.Types.Array(engine.ReferenceCounter) { contract.Hash.ToArray() }); } @@ -232,7 +232,7 @@ private async ContractTask Deploy(ApplicationEngine engine, byte[ engine.Snapshot.Add(key, new StorageItem(contract)); engine.Snapshot.Add(CreateStorageKey(Prefix_ContractHash).AddBigEndian(contract.Id), new StorageItem(hash.ToArray())); - await OnDeploy(engine, contract, data, false); + await OnDeployAsync(engine, contract, data, false); return contract; } @@ -275,7 +275,7 @@ private ContractTask Update(ApplicationEngine engine, byte[] nefFile, byte[] man } Helper.Check(new VM.Script(contract.Nef.Script, engine.IsHardforkEnabled(Hardfork.HF_Basilisk)), contract.Manifest.Abi); contract.UpdateCounter++; // Increase update counter - return OnDeploy(engine, contract, data, true); + return OnDeployAsync(engine, contract, data, true); } [ContractMethod(CpuFee = 1 << 15, RequiredCallFlags = CallFlags.States | CallFlags.AllowNotify)] diff --git a/src/Neo/SmartContract/Native/FungibleToken.cs b/src/Neo/SmartContract/Native/FungibleToken.cs index 6499c60c19..10e406dd07 100644 --- a/src/Neo/SmartContract/Native/FungibleToken.cs +++ b/src/Neo/SmartContract/Native/FungibleToken.cs @@ -80,7 +80,7 @@ internal async ContractTask Mint(ApplicationEngine engine, UInt160 account, BigI state.Balance += amount; storage = engine.Snapshot.GetAndChange(CreateStorageKey(Prefix_TotalSupply), () => new StorageItem(BigInteger.Zero)); storage.Add(amount); - await PostTransfer(engine, null, account, amount, StackItem.Null, callOnPayment); + await PostTransferAsync(engine, null, account, amount, StackItem.Null, callOnPayment); } internal async ContractTask Burn(ApplicationEngine engine, UInt160 account, BigInteger amount) @@ -98,7 +98,7 @@ internal async ContractTask Burn(ApplicationEngine engine, UInt160 account, BigI state.Balance -= amount; storage = engine.Snapshot.GetAndChange(CreateStorageKey(Prefix_TotalSupply)); storage.Add(-amount); - await PostTransfer(engine, account, null, amount, StackItem.Null, false); + await PostTransferAsync(engine, account, null, amount, StackItem.Null, false); } /// @@ -169,7 +169,7 @@ private protected async ContractTask Transfer(ApplicationEngine engine, UI state_to.Balance += amount; } } - await PostTransfer(engine, from, to, amount, data, true); + await PostTransferAsync(engine, from, to, amount, data, true); return true; } @@ -177,7 +177,7 @@ internal virtual void OnBalanceChanging(ApplicationEngine engine, UInt160 accoun { } - private protected virtual async ContractTask PostTransfer(ApplicationEngine engine, UInt160 from, UInt160 to, BigInteger amount, StackItem data, bool callOnPayment) + private protected virtual async ContractTask PostTransferAsync(ApplicationEngine engine, UInt160 from, UInt160 to, BigInteger amount, StackItem data, bool callOnPayment) { // Send notification @@ -190,7 +190,7 @@ private protected virtual async ContractTask PostTransfer(ApplicationEngine engi // Call onNEP17Payment method - await engine.CallFromNativeContract(Hash, to, "onNEP17Payment", from?.ToArray() ?? StackItem.Null, amount, data); + await engine.CallFromNativeContractAsync(Hash, to, "onNEP17Payment", from?.ToArray() ?? StackItem.Null, amount, data); } } } diff --git a/src/Neo/SmartContract/Native/GasToken.cs b/src/Neo/SmartContract/Native/GasToken.cs index ce2f77ad2c..b8a185b6f1 100644 --- a/src/Neo/SmartContract/Native/GasToken.cs +++ b/src/Neo/SmartContract/Native/GasToken.cs @@ -26,7 +26,7 @@ internal GasToken() { } - internal override ContractTask Initialize(ApplicationEngine engine, Hardfork? hardfork) + internal override ContractTask InitializeAsync(ApplicationEngine engine, Hardfork? hardfork) { if (hardfork == ActiveIn) { @@ -36,7 +36,7 @@ internal override ContractTask Initialize(ApplicationEngine engine, Hardfork? ha return ContractTask.CompletedTask; } - internal override async ContractTask OnPersist(ApplicationEngine engine) + internal override async ContractTask OnPersistAsync(ApplicationEngine engine) { long totalNetworkFee = 0; foreach (Transaction tx in engine.PersistingBlock.Transactions) diff --git a/src/Neo/SmartContract/Native/LedgerContract.cs b/src/Neo/SmartContract/Native/LedgerContract.cs index d72f07c022..ea757ba348 100644 --- a/src/Neo/SmartContract/Native/LedgerContract.cs +++ b/src/Neo/SmartContract/Native/LedgerContract.cs @@ -34,7 +34,7 @@ public sealed class LedgerContract : NativeContract internal LedgerContract() : base() { } - internal override ContractTask OnPersist(ApplicationEngine engine) + internal override ContractTask OnPersistAsync(ApplicationEngine engine) { TransactionState[] transactions = engine.PersistingBlock.Transactions.Select(p => new TransactionState { @@ -65,7 +65,7 @@ internal override ContractTask OnPersist(ApplicationEngine engine) return ContractTask.CompletedTask; } - internal override ContractTask PostPersist(ApplicationEngine engine) + internal override ContractTask PostPersistAsync(ApplicationEngine engine) { HashIndexState state = engine.Snapshot.GetAndChange(CreateStorageKey(Prefix_CurrentBlock), () => new StorageItem(new HashIndexState())).GetInteroperable(); state.Hash = engine.PersistingBlock.Hash; diff --git a/src/Neo/SmartContract/Native/NativeContract.cs b/src/Neo/SmartContract/Native/NativeContract.cs index 2003962b87..2b00fddfe2 100644 --- a/src/Neo/SmartContract/Native/NativeContract.cs +++ b/src/Neo/SmartContract/Native/NativeContract.cs @@ -398,17 +398,17 @@ public static bool IsNative(UInt160 hash) return contractsDictionary.ContainsKey(hash); } - internal virtual ContractTask Initialize(ApplicationEngine engine, Hardfork? hardFork) + internal virtual ContractTask InitializeAsync(ApplicationEngine engine, Hardfork? hardFork) { return ContractTask.CompletedTask; } - internal virtual ContractTask OnPersist(ApplicationEngine engine) + internal virtual ContractTask OnPersistAsync(ApplicationEngine engine) { return ContractTask.CompletedTask; } - internal virtual ContractTask PostPersist(ApplicationEngine engine) + internal virtual ContractTask PostPersistAsync(ApplicationEngine engine) { return ContractTask.CompletedTask; } diff --git a/src/Neo/SmartContract/Native/NeoToken.cs b/src/Neo/SmartContract/Native/NeoToken.cs index c28a548d0e..82ee1b9fcb 100644 --- a/src/Neo/SmartContract/Native/NeoToken.cs +++ b/src/Neo/SmartContract/Native/NeoToken.cs @@ -93,9 +93,9 @@ internal override void OnBalanceChanging(ApplicationEngine engine, UInt160 accou CheckCandidate(engine.Snapshot, state.VoteTo, candidate); } - private protected override async ContractTask PostTransfer(ApplicationEngine engine, UInt160 from, UInt160 to, BigInteger amount, StackItem data, bool callOnPayment) + private protected override async ContractTask PostTransferAsync(ApplicationEngine engine, UInt160 from, UInt160 to, BigInteger amount, StackItem data, bool callOnPayment) { - await base.PostTransfer(engine, from, to, amount, data, callOnPayment); + await base.PostTransferAsync(engine, from, to, amount, data, callOnPayment); var list = engine.CurrentContext.GetState>(); foreach (var distribution in list) await GAS.Mint(engine, distribution.Account, distribution.Amount, callOnPayment); @@ -176,7 +176,7 @@ private void CheckCandidate(DataCache snapshot, ECPoint pubkey, CandidateState c /// if the votes should be recounted; otherwise, . public static bool ShouldRefreshCommittee(uint height, int committeeMembersCount) => height % committeeMembersCount == 0; - internal override ContractTask Initialize(ApplicationEngine engine, Hardfork? hardfork) + internal override ContractTask InitializeAsync(ApplicationEngine engine, Hardfork? hardfork) { if (hardfork == ActiveIn) { @@ -190,7 +190,7 @@ internal override ContractTask Initialize(ApplicationEngine engine, Hardfork? ha return ContractTask.CompletedTask; } - internal override ContractTask OnPersist(ApplicationEngine engine) + internal override ContractTask OnPersistAsync(ApplicationEngine engine) { // Set next committee if (ShouldRefreshCommittee(engine.PersistingBlock.Index, engine.ProtocolSettings.CommitteeMembersCount)) @@ -216,7 +216,7 @@ internal override ContractTask OnPersist(ApplicationEngine engine) return ContractTask.CompletedTask; } - internal override async ContractTask PostPersist(ApplicationEngine engine) + internal override async ContractTask PostPersistAsync(ApplicationEngine engine) { // Distribute GAS for committee diff --git a/src/Neo/SmartContract/Native/OracleContract.cs b/src/Neo/SmartContract/Native/OracleContract.cs index d8415fca21..b391518733 100644 --- a/src/Neo/SmartContract/Native/OracleContract.cs +++ b/src/Neo/SmartContract/Native/OracleContract.cs @@ -82,7 +82,7 @@ private ContractTask Finish(ApplicationEngine engine) 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); - return engine.CallFromNativeContract(Hash, request.CallbackContract, request.CallbackMethod, request.Url, userData, (int)response.Code, response.Result); + return engine.CallFromNativeContractAsync(Hash, request.CallbackContract, request.CallbackMethod, request.Url, userData, (int)response.Code, response.Result); } private UInt256 GetOriginalTxid(ApplicationEngine engine) @@ -134,7 +134,7 @@ private static byte[] GetUrlHash(string url) return Crypto.Hash160(Utility.StrictUTF8.GetBytes(url)); } - internal override ContractTask Initialize(ApplicationEngine engine, Hardfork? hardfork) + internal override ContractTask InitializeAsync(ApplicationEngine engine, Hardfork? hardfork) { if (hardfork == ActiveIn) { @@ -144,7 +144,7 @@ internal override ContractTask Initialize(ApplicationEngine engine, Hardfork? ha return ContractTask.CompletedTask; } - internal override async ContractTask PostPersist(ApplicationEngine engine) + internal override async ContractTask PostPersistAsync(ApplicationEngine engine) { (UInt160 Account, BigInteger GAS)[] nodes = null; foreach (Transaction tx in engine.PersistingBlock.Transactions) diff --git a/src/Neo/SmartContract/Native/PolicyContract.cs b/src/Neo/SmartContract/Native/PolicyContract.cs index 5b00af92ad..7b921d191f 100644 --- a/src/Neo/SmartContract/Native/PolicyContract.cs +++ b/src/Neo/SmartContract/Native/PolicyContract.cs @@ -66,7 +66,7 @@ public sealed class PolicyContract : NativeContract internal PolicyContract() : base() { } - internal override ContractTask Initialize(ApplicationEngine engine, Hardfork? hardfork) + internal override ContractTask InitializeAsync(ApplicationEngine engine, Hardfork? hardfork) { if (hardfork == ActiveIn) { diff --git a/tests/Neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs b/tests/Neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs index 32da3b1602..703253364c 100644 --- a/tests/Neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs +++ b/tests/Neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs @@ -34,7 +34,7 @@ public void TestSetup() _snapshot = TestBlockchain.GetTestSnapshot(); ApplicationEngine engine = ApplicationEngine.Create(TriggerType.OnPersist, null, _snapshot, new Block { Header = new Header() }, settings: TestBlockchain.TheNeoSystem.Settings, gas: 0); - NativeContract.ContractManagement.OnPersist(engine); + NativeContract.ContractManagement.OnPersistAsync(engine); } [TestMethod] From f6c26cb059a0d940010844a980540f665e0532a7 Mon Sep 17 00:00:00 2001 From: Anna Shaleva Date: Sun, 5 May 2024 13:06:35 +0300 Subject: [PATCH 117/168] SmartContract: catch exception on multisignature contract parsing (#3211) IsMultiSigContract should return proper true/false result even if some garbage is provided as an input. Without this commit an exception is possible during IsMultiSigContract execution during subsequent public key decoding from compressed form: ``` Failed TestIsMultiSigContract [16 ms] Error Message: Test method Neo.UnitTests.SmartContract.UT_Helper.TestIsMultiSigContract threw exception: System.FormatException: Invalid point encoding 221 Stack Trace: at Neo.Cryptography.ECC.ECPoint.DecodePoint(ReadOnlySpan`1 encoded, ECCurve curve) in /home/anna/Documents/GitProjects/neo-project/neo/src/Neo/Cryptography/ECC/ECPoint.cs:line 98 at Neo.SmartContract.Helper.IsMultiSigContract(ReadOnlySpan`1 script, Int32& m, Int32& n, List`1 points) in /home/anna/Documents/GitProjects/neo-project/neo/src/Neo/SmartContract/Helper.cs:line 189 at Neo.SmartContract.Helper.IsMultiSigContract(ReadOnlySpan`1 script) in /home/anna/Documents/GitProjects/neo-project/neo/src/Neo/SmartContract/Helper.cs:line 123 at Neo.UnitTests.SmartContract.UT_Helper.TestIsMultiSigContract() in /home/anna/Documents/GitProjects/neo-project/neo/tests/Neo.UnitTests/SmartContract/UT_Helper.cs:line 65 at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor) at System.Reflection.MethodBaseInvoker.InvokeWithNoArgs(Object obj, BindingFlags invokeAttr) ``` Note that this change is compatible wrt the callers' behaviour. We need this change to properly handle non-Secp256r1-based witness scripts, ref. https://github.com/neo-project/neo/pull/3209. Signed-off-by: Anna Shaleva --- src/Neo/SmartContract/Helper.cs | 9 +++- .../Neo.UnitTests/SmartContract/UT_Helper.cs | 43 +++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/src/Neo/SmartContract/Helper.cs b/src/Neo/SmartContract/Helper.cs index 333ef77d7b..c0c694fc4e 100644 --- a/src/Neo/SmartContract/Helper.cs +++ b/src/Neo/SmartContract/Helper.cs @@ -184,7 +184,14 @@ private static bool IsMultiSigContract(ReadOnlySpan script, out int m, out { if (script.Length <= i + 35) return false; if (script[++i] != 33) return false; - points?.Add(ECPoint.DecodePoint(script.Slice(i + 1, 33), ECCurve.Secp256r1)); + try + { + points?.Add(ECPoint.DecodePoint(script.Slice(i + 1, 33), ECCurve.Secp256r1)); + } + catch (Exception) // Script may contain any data, thus exceptions are allowed on point decoding. + { + return false; + } i += 34; ++n; } diff --git a/tests/Neo.UnitTests/SmartContract/UT_Helper.cs b/tests/Neo.UnitTests/SmartContract/UT_Helper.cs index 3d682a4ee9..ffffc70728 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_Helper.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_Helper.cs @@ -17,6 +17,8 @@ using Neo.VM; using Neo.Wallets; using System; +using System.Collections.Generic; +using System.Linq; using static Neo.SmartContract.Helper; namespace Neo.UnitTests.SmartContract @@ -72,6 +74,47 @@ public void TestIsMultiSigContract() Assert.IsFalse(IsMultiSigContract(case2)); } + [TestMethod] + // TestIsMultiSigContract_WrongCurve checks that multisignature verification script based on points + // not from Secp256r1 curve fails IsMultiSigContract check without any exception. + public void TestIsMultiSigContract_WrongCurve() + { + // A set of points on Koblitz curve in uncompressed representation. One of the points + // (the first one) is specially selected, this point can't be restored on Secp256r1 + // from compressed form, whereas three other points can be restored on both Secp256r1 + // and Koblitz curves. + var pubs = new List() + { + ECPoint.Parse("047b4e72ae854b6a0955b3e02d92651ab7fa641a936066776ad438f95bb674a269a63ff98544691663d91a6cfcd215831f01bfb7a226363a6c5c67ef14541dba07", ECCurve.Secp256k1), + ECPoint.Parse("040486468683c112125978ffe876245b2006bfe739aca8539b67335079262cb27ad0dedc9e5583f99b61c6f46bf80b97eaec3654b87add0e5bd7106c69922a229d", ECCurve.Secp256k1), + ECPoint.Parse("040d26fc2ad3b1aae20f040b5f83380670f8ef5c2b2ac921ba3bdd79fd0af0525177715fd4370b1012ddd10579698d186ab342c223da3e884ece9cab9b6638c7bb", ECCurve.Secp256k1), + ECPoint.Parse("04a114d72fe2997cdac67427b6f39ea08ed46213c8bb6a461bbac2a6212cf43fb510f8adf59b0b087a7859f96d0288e5e94800eab8388f30f03f92b2e4d807dfce", ECCurve.Secp256k1) + }; + const int m = 3; + + var badScript = Contract.CreateMultiSigRedeemScript(m, pubs); + Assert.IsFalse(IsMultiSigContract(badScript, out _, out ECPoint[] _)); // enforce runtime point decoding by specifying ECPoint[] out variable. + Assert.IsTrue(IsMultiSigContract(badScript)); // this overload is unlucky since it doesn't perform ECPoint decoding. + + // Exclude the first special point and check one more time, both methods should return true. + var goodScript = Contract.CreateMultiSigRedeemScript(m, pubs.Skip(1).ToArray()); + Assert.IsTrue(IsMultiSigContract(goodScript, out _, out ECPoint[] _)); // enforce runtime point decoding by specifying ECPoint[] out variable. + Assert.IsTrue(IsMultiSigContract(goodScript)); // this overload is unlucky since it doesn't perform ECPoint decoding. + } + + [TestMethod] + // TestIsSignatureContract_WrongCurve checks that signature verification script based on point + // not from Secp256r1 curve passes IsSignatureContract check without any exception. + public void TestIsSignatureContract_WrongCurve() + { + // A special point on Koblitz curve that can't be restored at Secp256r1 from compressed form. + var pub = ECPoint.Parse("047b4e72ae854b6a0955b3e02d92651ab7fa641a936066776ad438f95bb674a269a63ff98544691663d91a6cfcd215831f01bfb7a226363a6c5c67ef14541dba07", ECCurve.Secp256k1); + var script = Contract.CreateSignatureRedeemScript(pub); + + // IsSignatureContract should pass since it doesn't perform ECPoint decoding. + Assert.IsTrue(IsSignatureContract(script)); + } + [TestMethod] public void TestSignatureContractCost() { From eacf16d208b45011e680f36f049d3da58f6ca86f Mon Sep 17 00:00:00 2001 From: Christopher Schuchardt Date: Tue, 7 May 2024 03:37:34 -0400 Subject: [PATCH 118/168] Remove`this.` keyword (#3215) --- .editorconfig | 13 ++++++++---- .gitattributes | 3 +++ src/Neo.ConsoleService/ServiceProxy.cs | 2 +- src/Neo.GUI/GUI/InputBox.cs | 2 +- src/Neo.Json/JBoolean.cs | 4 ++-- src/Neo.Json/JNumber.cs | 2 +- src/Neo.Json/JString.cs | 4 ++-- src/Neo.VM/Collections/OrderedDictionary.cs | 4 ++-- src/Neo.VM/ExceptionHandlingContext.cs | 4 ++-- src/Neo.VM/ExecutionContext.SharedStates.cs | 6 +++--- src/Neo.VM/ExecutionContext.cs | 4 ++-- src/Neo.VM/ExecutionEngine.cs | 8 ++++---- src/Neo.VM/Instruction.cs | 2 +- src/Neo.VM/Script.cs | 2 +- src/Neo.VM/Slot.cs | 2 +- src/Neo.VM/Types/ByteString.cs | 2 +- src/Neo.VM/Types/CompoundType.cs | 2 +- src/Neo.VM/Types/Pointer.cs | 4 ++-- src/Neo/BigDecimal.cs | 2 +- src/Neo/Cryptography/BloomFilter.cs | 16 +++++++-------- src/Neo/Cryptography/ECC/ECCurve.cs | 4 ++-- src/Neo/Cryptography/ECC/ECFieldElement.cs | 4 ++-- src/Neo/Cryptography/ECC/ECPoint.cs | 16 +++++++-------- src/Neo/Cryptography/MerkleTree.cs | 4 ++-- src/Neo/IO/Caching/Cache.cs | 8 ++++---- src/Neo/IO/Caching/HashSetCache.cs | 2 +- src/Neo/NeoSystem.cs | 16 +++++++-------- .../P2P/Capabilities/NodeCapability.cs | 2 +- src/Neo/Network/P2P/Connection.cs | 6 +++--- src/Neo/Network/P2P/LocalNode.cs | 2 +- src/Neo/Network/P2P/RemoteNode.cs | 4 ++-- src/Neo/Network/P2P/TaskManager.cs | 2 +- src/Neo/Network/P2P/TaskSession.cs | 4 ++-- src/Neo/Persistence/MemorySnapshot.cs | 4 ++-- src/Neo/Persistence/SnapshotCache.cs | 2 +- src/Neo/SmartContract/ApplicationEngine.cs | 20 +++++++++---------- src/Neo/SmartContract/ContractParameter.cs | 4 ++-- .../ContractParametersContext.cs | 20 +++++++++---------- .../InteropParameterDescriptor.cs | 2 +- src/Neo/SmartContract/LogEventArgs.cs | 6 +++--- .../Manifest/ContractPermissionDescriptor.cs | 4 ++-- .../Native/ContractMethodMetadata.cs | 20 +++++++++---------- src/Neo/SmartContract/Native/FungibleToken.cs | 2 +- .../SmartContract/Native/NativeContract.cs | 2 +- src/Neo/SmartContract/Native/NeoToken.cs | 2 +- src/Neo/SmartContract/NotifyEventArgs.cs | 8 ++++---- src/Neo/SmartContract/StorageItem.cs | 4 ++-- src/Neo/Wallets/AssetDescriptor.cs | 8 ++++---- src/Neo/Wallets/KeyPair.cs | 6 +++--- src/Neo/Wallets/NEP6/NEP6Wallet.cs | 12 +++++------ src/Neo/Wallets/NEP6/ScryptParameters.cs | 6 +++--- src/Neo/Wallets/WalletAccount.cs | 4 ++-- 52 files changed, 153 insertions(+), 145 deletions(-) diff --git a/.editorconfig b/.editorconfig index 269a7e444b..9a574425e9 100644 --- a/.editorconfig +++ b/.editorconfig @@ -60,11 +60,12 @@ dotnet_diagnostic.CS1591.severity = silent # Sort using and Import directives with System.* appearing first dotnet_sort_system_directives_first = false dotnet_separate_import_directive_groups = false + # Avoid "this." and "Me." if not necessary -dotnet_style_qualification_for_field = false:refactoring -dotnet_style_qualification_for_property = false:refactoring -dotnet_style_qualification_for_method = false:refactoring -dotnet_style_qualification_for_event = false:refactoring +dotnet_style_qualification_for_field = false:warning +dotnet_style_qualification_for_property = false:warning +dotnet_style_qualification_for_method = false:warning +dotnet_style_qualification_for_event = false:warning # Use language keywords instead of framework type names for type references dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion @@ -255,6 +256,10 @@ dotnet_diagnostic.IDE0060.severity = none [src/{Analyzers,CodeStyle,Features,Workspaces,EditorFeatures,VisualStudio}/**/*.{cs,vb}] +# Avoid "this." and "Me." if not necessary +dotnet_diagnostic.IDE0003.severity = warning +dotnet_diagnostic.IDE0009.severity = warning + # IDE0011: Add braces csharp_prefer_braces = when_multiline:warning # NOTE: We need the below severity entry for Add Braces due to https://github.com/dotnet/roslyn/issues/44201 diff --git a/.gitattributes b/.gitattributes index 0c37abbc2d..3bdf2f7093 100644 --- a/.gitattributes +++ b/.gitattributes @@ -2,6 +2,8 @@ # Set default behavior to automatically normalize line endings. ############################################################################### * text eol=lf +*.cs eol=lf +*.csproj eol=lf ############################################################################### # Set default behavior for command prompt diff. @@ -44,6 +46,7 @@ *.png binary *.gif binary *.ico binary +*.zip binary ############################################################################### # diff behavior for common document formats diff --git a/src/Neo.ConsoleService/ServiceProxy.cs b/src/Neo.ConsoleService/ServiceProxy.cs index 97a14601c7..25e7c8ae46 100644 --- a/src/Neo.ConsoleService/ServiceProxy.cs +++ b/src/Neo.ConsoleService/ServiceProxy.cs @@ -19,7 +19,7 @@ internal class ServiceProxy : ServiceBase public ServiceProxy(ConsoleServiceBase service) { - this._service = service; + _service = service; } protected override void OnStart(string[] args) diff --git a/src/Neo.GUI/GUI/InputBox.cs b/src/Neo.GUI/GUI/InputBox.cs index 51884b3212..8f301a8c99 100644 --- a/src/Neo.GUI/GUI/InputBox.cs +++ b/src/Neo.GUI/GUI/InputBox.cs @@ -18,7 +18,7 @@ internal partial class InputBox : Form private InputBox(string text, string caption, string content) { InitializeComponent(); - this.Text = caption; + Text = caption; groupBox1.Text = text; textBox1.Text = content; } diff --git a/src/Neo.Json/JBoolean.cs b/src/Neo.Json/JBoolean.cs index 05cb36a89d..3c2b025a54 100644 --- a/src/Neo.Json/JBoolean.cs +++ b/src/Neo.Json/JBoolean.cs @@ -29,7 +29,7 @@ public class JBoolean : JToken /// The value of the JSON token. public JBoolean(bool value = false) { - this.Value = value; + Value = value; } public override bool AsBoolean() @@ -91,7 +91,7 @@ public override bool Equals(object? obj) } if (obj is JBoolean other) { - return this.Value.Equals(other.Value); + return Value.Equals(other.Value); } return false; } diff --git a/src/Neo.Json/JNumber.cs b/src/Neo.Json/JNumber.cs index 479303cfb5..1ae5d6d0a2 100644 --- a/src/Neo.Json/JNumber.cs +++ b/src/Neo.Json/JNumber.cs @@ -41,7 +41,7 @@ public class JNumber : JToken public JNumber(double value = 0) { if (!double.IsFinite(value)) throw new FormatException(); - this.Value = value; + Value = value; } /// diff --git a/src/Neo.Json/JString.cs b/src/Neo.Json/JString.cs index c9466c26a6..215ebdf730 100644 --- a/src/Neo.Json/JString.cs +++ b/src/Neo.Json/JString.cs @@ -30,7 +30,7 @@ public class JString : JToken /// The value of the JSON token. public JString(string value) { - this.Value = value ?? throw new ArgumentNullException(nameof(value)); + Value = value ?? throw new ArgumentNullException(nameof(value)); } /// @@ -115,7 +115,7 @@ public override bool Equals(object? obj) } if (obj is string str) { - return this.Value == str; + return Value == str; } return false; } diff --git a/src/Neo.VM/Collections/OrderedDictionary.cs b/src/Neo.VM/Collections/OrderedDictionary.cs index 92d8e8f3ad..82eba05d7a 100644 --- a/src/Neo.VM/Collections/OrderedDictionary.cs +++ b/src/Neo.VM/Collections/OrderedDictionary.cs @@ -27,8 +27,8 @@ private class TItem public TItem(TKey key, TValue value) { - this.Key = key; - this.Value = value; + Key = key; + Value = value; } } diff --git a/src/Neo.VM/ExceptionHandlingContext.cs b/src/Neo.VM/ExceptionHandlingContext.cs index a0c48c0b97..38c321ed17 100644 --- a/src/Neo.VM/ExceptionHandlingContext.cs +++ b/src/Neo.VM/ExceptionHandlingContext.cs @@ -51,8 +51,8 @@ public sealed class ExceptionHandlingContext internal ExceptionHandlingContext(int catchPointer, int finallyPointer) { - this.CatchPointer = catchPointer; - this.FinallyPointer = finallyPointer; + CatchPointer = catchPointer; + FinallyPointer = finallyPointer; } } } diff --git a/src/Neo.VM/ExecutionContext.SharedStates.cs b/src/Neo.VM/ExecutionContext.SharedStates.cs index 9903d50adf..afa01d7995 100644 --- a/src/Neo.VM/ExecutionContext.SharedStates.cs +++ b/src/Neo.VM/ExecutionContext.SharedStates.cs @@ -25,9 +25,9 @@ private class SharedStates public SharedStates(Script script, ReferenceCounter referenceCounter) { - this.Script = script; - this.EvaluationStack = new EvaluationStack(referenceCounter); - this.States = new Dictionary(); + Script = script; + EvaluationStack = new EvaluationStack(referenceCounter); + States = new Dictionary(); } } } diff --git a/src/Neo.VM/ExecutionContext.cs b/src/Neo.VM/ExecutionContext.cs index 5f3a18e077..d1f9a54b1d 100644 --- a/src/Neo.VM/ExecutionContext.cs +++ b/src/Neo.VM/ExecutionContext.cs @@ -117,8 +117,8 @@ private ExecutionContext(SharedStates shared_states, int rvcount, int initialPos if (rvcount < -1 || rvcount > ushort.MaxValue) throw new ArgumentOutOfRangeException(nameof(rvcount)); this.shared_states = shared_states; - this.RVCount = rvcount; - this.InstructionPointer = initialPosition; + RVCount = rvcount; + InstructionPointer = initialPosition; } /// diff --git a/src/Neo.VM/ExecutionEngine.cs b/src/Neo.VM/ExecutionEngine.cs index fcf7d34f90..52dd057902 100644 --- a/src/Neo.VM/ExecutionEngine.cs +++ b/src/Neo.VM/ExecutionEngine.cs @@ -95,10 +95,10 @@ protected internal set /// Restrictions on the VM. protected ExecutionEngine(JumpTable? jumpTable, ReferenceCounter referenceCounter, ExecutionEngineLimits limits) { - this.JumpTable = jumpTable ?? JumpTable.Default; - this.Limits = limits; - this.ReferenceCounter = referenceCounter; - this.ResultStack = new EvaluationStack(referenceCounter); + JumpTable = jumpTable ?? JumpTable.Default; + Limits = limits; + ReferenceCounter = referenceCounter; + ResultStack = new EvaluationStack(referenceCounter); } public virtual void Dispose() diff --git a/src/Neo.VM/Instruction.cs b/src/Neo.VM/Instruction.cs index b92e9e3bec..f7f9d2d791 100644 --- a/src/Neo.VM/Instruction.cs +++ b/src/Neo.VM/Instruction.cs @@ -191,7 +191,7 @@ static Instruction() private Instruction(OpCode opcode) { - this.OpCode = opcode; + OpCode = opcode; if (!Enum.IsDefined(typeof(OpCode), opcode)) throw new BadScriptException(); } diff --git a/src/Neo.VM/Script.cs b/src/Neo.VM/Script.cs index 5f6b29c5b7..95307c94f4 100644 --- a/src/Neo.VM/Script.cs +++ b/src/Neo.VM/Script.cs @@ -72,7 +72,7 @@ public Script(ReadOnlyMemory script) : this(script, false) /// In strict mode, the script was found to contain bad instructions. public Script(ReadOnlyMemory script, bool strictMode) { - this._value = script; + _value = script; if (strictMode) { for (int ip = 0; ip < script.Length; ip += GetInstruction(ip).Size) { } diff --git a/src/Neo.VM/Slot.cs b/src/Neo.VM/Slot.cs index 33b221a381..7812694ce6 100644 --- a/src/Neo.VM/Slot.cs +++ b/src/Neo.VM/Slot.cs @@ -69,7 +69,7 @@ public Slot(StackItem[] items, ReferenceCounter referenceCounter) public Slot(int count, ReferenceCounter referenceCounter) { this.referenceCounter = referenceCounter; - this.items = new StackItem[count]; + items = new StackItem[count]; System.Array.Fill(items, StackItem.Null); referenceCounter.AddStackReference(StackItem.Null, count); } diff --git a/src/Neo.VM/Types/ByteString.cs b/src/Neo.VM/Types/ByteString.cs index 4d0e941dc1..2d2df2d862 100644 --- a/src/Neo.VM/Types/ByteString.cs +++ b/src/Neo.VM/Types/ByteString.cs @@ -41,7 +41,7 @@ public class ByteString : PrimitiveType /// The data to be contained in this . public ByteString(ReadOnlyMemory data) { - this.Memory = data; + Memory = data; } private bool Equals(ByteString other) diff --git a/src/Neo.VM/Types/CompoundType.cs b/src/Neo.VM/Types/CompoundType.cs index 02323e3f2f..ede743b881 100644 --- a/src/Neo.VM/Types/CompoundType.cs +++ b/src/Neo.VM/Types/CompoundType.cs @@ -32,7 +32,7 @@ public abstract class CompoundType : StackItem /// The reference counter to be used. protected CompoundType(ReferenceCounter? referenceCounter) { - this.ReferenceCounter = referenceCounter; + ReferenceCounter = referenceCounter; referenceCounter?.AddZeroReferred(this); } diff --git a/src/Neo.VM/Types/Pointer.cs b/src/Neo.VM/Types/Pointer.cs index 1faa52ca74..1f729c812f 100644 --- a/src/Neo.VM/Types/Pointer.cs +++ b/src/Neo.VM/Types/Pointer.cs @@ -39,8 +39,8 @@ public class Pointer : StackItem /// The position of the pointer in the script. public Pointer(Script script, int position) { - this.Script = script; - this.Position = position; + Script = script; + Position = position; } public override bool Equals(StackItem? other) diff --git a/src/Neo/BigDecimal.cs b/src/Neo/BigDecimal.cs index 05cdf86626..1d8cf5560e 100644 --- a/src/Neo/BigDecimal.cs +++ b/src/Neo/BigDecimal.cs @@ -61,7 +61,7 @@ public unsafe BigDecimal(decimal value) ReadOnlySpan buffer = new(p, 16); this.value = new BigInteger(buffer[..12], isUnsigned: true); if (buffer[15] != 0) this.value = -this.value; - this.decimals = buffer[14]; + decimals = buffer[14]; } } diff --git a/src/Neo/Cryptography/BloomFilter.cs b/src/Neo/Cryptography/BloomFilter.cs index a1639678e5..ffa626a546 100644 --- a/src/Neo/Cryptography/BloomFilter.cs +++ b/src/Neo/Cryptography/BloomFilter.cs @@ -47,10 +47,10 @@ public class BloomFilter public BloomFilter(int m, int k, uint nTweak) { if (k < 0 || m < 0) throw new ArgumentOutOfRangeException(); - this.seeds = Enumerable.Range(0, k).Select(p => (uint)p * 0xFBA4C795 + nTweak).ToArray(); - this.bits = new BitArray(m); - this.bits.Length = m; - this.Tweak = nTweak; + seeds = Enumerable.Range(0, k).Select(p => (uint)p * 0xFBA4C795 + nTweak).ToArray(); + bits = new BitArray(m); + bits.Length = m; + Tweak = nTweak; } /// @@ -63,10 +63,10 @@ public BloomFilter(int m, int k, uint nTweak) public BloomFilter(int m, int k, uint nTweak, ReadOnlyMemory elements) { if (k < 0 || m < 0) throw new ArgumentOutOfRangeException(); - this.seeds = Enumerable.Range(0, k).Select(p => (uint)p * 0xFBA4C795 + nTweak).ToArray(); - this.bits = new BitArray(elements.ToArray()); - this.bits.Length = m; - this.Tweak = nTweak; + seeds = Enumerable.Range(0, k).Select(p => (uint)p * 0xFBA4C795 + nTweak).ToArray(); + bits = new BitArray(elements.ToArray()); + bits.Length = m; + Tweak = nTweak; } /// diff --git a/src/Neo/Cryptography/ECC/ECCurve.cs b/src/Neo/Cryptography/ECC/ECCurve.cs index b228f7ab31..def1ee0cb1 100644 --- a/src/Neo/Cryptography/ECC/ECCurve.cs +++ b/src/Neo/Cryptography/ECC/ECCurve.cs @@ -37,11 +37,11 @@ public class ECCurve private ECCurve(BigInteger Q, BigInteger A, BigInteger B, BigInteger N, byte[] G) { this.Q = Q; - this.ExpectedECPointLength = ((int)VM.Utility.GetBitLength(Q) + 7) / 8; + ExpectedECPointLength = ((int)VM.Utility.GetBitLength(Q) + 7) / 8; this.A = new ECFieldElement(A, this); this.B = new ECFieldElement(B, this); this.N = N; - this.Infinity = new ECPoint(null, null, this); + Infinity = new ECPoint(null, null, this); this.G = ECPoint.DecodePoint(G, this); } diff --git a/src/Neo/Cryptography/ECC/ECFieldElement.cs b/src/Neo/Cryptography/ECC/ECFieldElement.cs index e08b5bb71f..47d8bfa274 100644 --- a/src/Neo/Cryptography/ECC/ECFieldElement.cs +++ b/src/Neo/Cryptography/ECC/ECFieldElement.cs @@ -25,7 +25,7 @@ public ECFieldElement(BigInteger value, ECCurve curve) throw new ArgumentNullException(nameof(curve)); if (value >= curve.Q) throw new ArgumentException("x value too large in field element"); - this.Value = value; + Value = value; this.curve = curve; } @@ -117,7 +117,7 @@ public ECFieldElement Sqrt() return null; BigInteger u = qMinusOne >> 2; BigInteger k = (u << 1) + 1; - BigInteger Q = this.Value; + BigInteger Q = Value; BigInteger fourQ = (Q << 2).Mod(curve.Q); BigInteger U, V; do diff --git a/src/Neo/Cryptography/ECC/ECPoint.cs b/src/Neo/Cryptography/ECC/ECPoint.cs index 5986634d9d..3b7bdcc885 100644 --- a/src/Neo/Cryptography/ECC/ECPoint.cs +++ b/src/Neo/Cryptography/ECC/ECPoint.cs @@ -49,9 +49,9 @@ internal ECPoint(ECFieldElement x, ECFieldElement y, ECCurve curve) { if ((x is null ^ y is null) || (curve is null)) throw new ArgumentException("Exactly one of the field elements is null"); - this.X = x; - this.Y = y; - this.Curve = curve; + X = x; + Y = y; + Curve = curve; } public int CompareTo(ECPoint other) @@ -378,15 +378,15 @@ public static bool TryParse(string value, ECCurve curve, out ECPoint point) internal ECPoint Twice() { - if (this.IsInfinity) + if (IsInfinity) return this; - if (this.Y.Value.Sign == 0) + if (Y.Value.Sign == 0) return Curve.Infinity; ECFieldElement TWO = new(2, Curve); ECFieldElement THREE = new(3, Curve); - ECFieldElement gamma = (this.X.Square() * THREE + Curve.A) / (Y * TWO); - ECFieldElement x3 = gamma.Square() - this.X * TWO; - ECFieldElement y3 = gamma * (this.X - x3) - this.Y; + ECFieldElement gamma = (X.Square() * THREE + Curve.A) / (Y * TWO); + ECFieldElement x3 = gamma.Square() - X * TWO; + ECFieldElement y3 = gamma * (X - x3) - Y; return new ECPoint(x3, y3, Curve); } diff --git a/src/Neo/Cryptography/MerkleTree.cs b/src/Neo/Cryptography/MerkleTree.cs index 58d3856b2c..ed25171ef8 100644 --- a/src/Neo/Cryptography/MerkleTree.cs +++ b/src/Neo/Cryptography/MerkleTree.cs @@ -32,12 +32,12 @@ public class MerkleTree internal MerkleTree(UInt256[] hashes) { - this.root = Build(hashes.Select(p => new MerkleTreeNode { Hash = p }).ToArray()); + root = Build(hashes.Select(p => new MerkleTreeNode { Hash = p }).ToArray()); if (root is null) return; int depth = 1; for (MerkleTreeNode i = root; i.LeftChild != null; i = i.LeftChild) depth++; - this.Depth = depth; + Depth = depth; } private static MerkleTreeNode Build(MerkleTreeNode[] leaves) diff --git a/src/Neo/IO/Caching/Cache.cs b/src/Neo/IO/Caching/Cache.cs index 5d89dd59b1..7895a8ca2d 100644 --- a/src/Neo/IO/Caching/Cache.cs +++ b/src/Neo/IO/Caching/Cache.cs @@ -27,9 +27,9 @@ protected class CacheItem public CacheItem(TKey key, TValue value) { - this.Key = key; - this.Value = value; - this.Time = TimeProvider.Current.UtcNow; + Key = key; + Value = value; + Time = TimeProvider.Current.UtcNow; } } @@ -76,7 +76,7 @@ public int Count public Cache(int max_capacity, IEqualityComparer comparer = null) { this.max_capacity = max_capacity; - this.InnerDictionary = new Dictionary(comparer); + InnerDictionary = new Dictionary(comparer); } public void Add(TValue item) diff --git a/src/Neo/IO/Caching/HashSetCache.cs b/src/Neo/IO/Caching/HashSetCache.cs index 8870e0ecf0..bdef1c5e3a 100644 --- a/src/Neo/IO/Caching/HashSetCache.cs +++ b/src/Neo/IO/Caching/HashSetCache.cs @@ -42,7 +42,7 @@ public HashSetCache(int bucketCapacity, int maxBucketCount = 10) if (bucketCapacity <= 0) throw new ArgumentOutOfRangeException($"{nameof(bucketCapacity)} should be greater than 0"); if (maxBucketCount <= 0) throw new ArgumentOutOfRangeException($"{nameof(maxBucketCount)} should be greater than 0"); - this.Count = 0; + Count = 0; this.bucketCapacity = bucketCapacity; this.maxBucketCount = maxBucketCount; sets.AddFirst(new HashSet()); diff --git a/src/Neo/NeoSystem.cs b/src/Neo/NeoSystem.cs index bfed791509..b752f16712 100644 --- a/src/Neo/NeoSystem.cs +++ b/src/Neo/NeoSystem.cs @@ -130,15 +130,15 @@ public NeoSystem(ProtocolSettings settings, string storageProvider = null, strin /// The path of the storage. If is the default in-memory storage engine, this parameter is ignored. public NeoSystem(ProtocolSettings settings, IStoreProvider storageProvider, string storagePath = null) { - this.Settings = settings; - this.GenesisBlock = CreateGenesisBlock(settings); + Settings = settings; + GenesisBlock = CreateGenesisBlock(settings); this.storageProvider = storageProvider; - this.store = storageProvider.GetStore(storagePath); - this.MemPool = new MemoryPool(this); - this.Blockchain = ActorSystem.ActorOf(Ledger.Blockchain.Props(this)); - this.LocalNode = ActorSystem.ActorOf(Network.P2P.LocalNode.Props(this)); - this.TaskManager = ActorSystem.ActorOf(Network.P2P.TaskManager.Props(this)); - this.TxRouter = ActorSystem.ActorOf(TransactionRouter.Props(this)); + store = storageProvider.GetStore(storagePath); + MemPool = new MemoryPool(this); + Blockchain = ActorSystem.ActorOf(Ledger.Blockchain.Props(this)); + LocalNode = ActorSystem.ActorOf(Network.P2P.LocalNode.Props(this)); + TaskManager = ActorSystem.ActorOf(Network.P2P.TaskManager.Props(this)); + TxRouter = ActorSystem.ActorOf(TransactionRouter.Props(this)); foreach (var plugin in Plugin.Plugins) plugin.OnSystemLoaded(this); Blockchain.Ask(new Blockchain.Initialize()).Wait(); diff --git a/src/Neo/Network/P2P/Capabilities/NodeCapability.cs b/src/Neo/Network/P2P/Capabilities/NodeCapability.cs index 18ec61c38d..c47f238a4f 100644 --- a/src/Neo/Network/P2P/Capabilities/NodeCapability.cs +++ b/src/Neo/Network/P2P/Capabilities/NodeCapability.cs @@ -33,7 +33,7 @@ public abstract class NodeCapability : ISerializable /// The type of the . protected NodeCapability(NodeCapabilityType type) { - this.Type = type; + Type = type; } void ISerializable.Deserialize(ref MemoryReader reader) diff --git a/src/Neo/Network/P2P/Connection.cs b/src/Neo/Network/P2P/Connection.cs index 53e30a2bde..66d12183f0 100644 --- a/src/Neo/Network/P2P/Connection.cs +++ b/src/Neo/Network/P2P/Connection.cs @@ -56,9 +56,9 @@ internal class Close { public bool Abort; } /// The address of the local node. protected Connection(object connection, IPEndPoint remote, IPEndPoint local) { - this.Remote = remote; - this.Local = local; - this.timer = Context.System.Scheduler.ScheduleTellOnceCancelable(TimeSpan.FromSeconds(connectionTimeoutLimitStart), Self, new Close { Abort = true }, ActorRefs.NoSender); + Remote = remote; + Local = local; + timer = Context.System.Scheduler.ScheduleTellOnceCancelable(TimeSpan.FromSeconds(connectionTimeoutLimitStart), Self, new Close { Abort = true }, ActorRefs.NoSender); switch (connection) { case IActorRef tcp: diff --git a/src/Neo/Network/P2P/LocalNode.cs b/src/Neo/Network/P2P/LocalNode.cs index f0bce492d5..78a967047c 100644 --- a/src/Neo/Network/P2P/LocalNode.cs +++ b/src/Neo/Network/P2P/LocalNode.cs @@ -88,7 +88,7 @@ static LocalNode() public LocalNode(NeoSystem system) { this.system = system; - this.SeedList = new IPEndPoint[system.Settings.SeedList.Length]; + SeedList = new IPEndPoint[system.Settings.SeedList.Length]; // Start dns resolution in parallel string[] seedList = system.Settings.SeedList; diff --git a/src/Neo/Network/P2P/RemoteNode.cs b/src/Neo/Network/P2P/RemoteNode.cs index 6aa2c742a8..a4bf0cc089 100644 --- a/src/Neo/Network/P2P/RemoteNode.cs +++ b/src/Neo/Network/P2P/RemoteNode.cs @@ -83,8 +83,8 @@ public RemoteNode(NeoSystem system, LocalNode localNode, object connection, IPEn { this.system = system; this.localNode = localNode; - this.knownHashes = new HashSetCache(system.MemPool.Capacity * 2 / 5); - this.sentHashes = new HashSetCache(system.MemPool.Capacity * 2 / 5); + knownHashes = new HashSetCache(system.MemPool.Capacity * 2 / 5); + sentHashes = new HashSetCache(system.MemPool.Capacity * 2 / 5); localNode.RemoteNodes.TryAdd(Self, this); } diff --git a/src/Neo/Network/P2P/TaskManager.cs b/src/Neo/Network/P2P/TaskManager.cs index 1d24597154..e9c12e58a4 100644 --- a/src/Neo/Network/P2P/TaskManager.cs +++ b/src/Neo/Network/P2P/TaskManager.cs @@ -74,7 +74,7 @@ private class Timer { } public TaskManager(NeoSystem system) { this.system = system; - this.knownHashes = new HashSetCache(system.MemPool.Capacity * 2 / 5); + knownHashes = new HashSetCache(system.MemPool.Capacity * 2 / 5); Context.System.EventStream.Subscribe(Self, typeof(Blockchain.PersistCompleted)); Context.System.EventStream.Subscribe(Self, typeof(Blockchain.RelayResult)); } diff --git a/src/Neo/Network/P2P/TaskSession.cs b/src/Neo/Network/P2P/TaskSession.cs index a18db540af..a22ac7f0b4 100644 --- a/src/Neo/Network/P2P/TaskSession.cs +++ b/src/Neo/Network/P2P/TaskSession.cs @@ -31,8 +31,8 @@ internal class TaskSession public TaskSession(VersionPayload version) { var fullNode = version.Capabilities.OfType().FirstOrDefault(); - this.IsFullNode = fullNode != null; - this.LastBlockIndex = fullNode?.StartHeight ?? 0; + IsFullNode = fullNode != null; + LastBlockIndex = fullNode?.StartHeight ?? 0; } } } diff --git a/src/Neo/Persistence/MemorySnapshot.cs b/src/Neo/Persistence/MemorySnapshot.cs index 756a4c83b2..096431552c 100644 --- a/src/Neo/Persistence/MemorySnapshot.cs +++ b/src/Neo/Persistence/MemorySnapshot.cs @@ -26,8 +26,8 @@ internal class MemorySnapshot : ISnapshot public MemorySnapshot(ConcurrentDictionary innerData) { this.innerData = innerData; - this.immutableData = innerData.ToImmutableDictionary(ByteArrayEqualityComparer.Default); - this.writeBatch = new ConcurrentDictionary(ByteArrayEqualityComparer.Default); + immutableData = innerData.ToImmutableDictionary(ByteArrayEqualityComparer.Default); + writeBatch = new ConcurrentDictionary(ByteArrayEqualityComparer.Default); } public void Commit() diff --git a/src/Neo/Persistence/SnapshotCache.cs b/src/Neo/Persistence/SnapshotCache.cs index e441f977c0..24036b41dc 100644 --- a/src/Neo/Persistence/SnapshotCache.cs +++ b/src/Neo/Persistence/SnapshotCache.cs @@ -32,7 +32,7 @@ public class SnapshotCache : DataCache, IDisposable public SnapshotCache(IReadOnlyStore store) { this.store = store; - this.snapshot = store as ISnapshot; + snapshot = store as ISnapshot; } protected override void AddInternal(StorageKey key, StorageItem value) diff --git a/src/Neo/SmartContract/ApplicationEngine.cs b/src/Neo/SmartContract/ApplicationEngine.cs index f2c63fe3b3..0c57b771e5 100644 --- a/src/Neo/SmartContract/ApplicationEngine.cs +++ b/src/Neo/SmartContract/ApplicationEngine.cs @@ -162,16 +162,16 @@ protected unsafe ApplicationEngine( ProtocolSettings settings, long gas, IDiagnostic diagnostic, JumpTable jumpTable = null) : base(jumpTable ?? DefaultJumpTable) { - this.Trigger = trigger; - this.ScriptContainer = container; - this.originalSnapshot = snapshot; - this.PersistingBlock = persistingBlock; - this.ProtocolSettings = settings; - this.gas_amount = gas; - this.Diagnostic = diagnostic; - this.ExecFeeFactor = snapshot is null || persistingBlock?.Index == 0 ? PolicyContract.DefaultExecFeeFactor : NativeContract.Policy.GetExecFeeFactor(snapshot); - this.StoragePrice = snapshot is null || persistingBlock?.Index == 0 ? PolicyContract.DefaultStoragePrice : NativeContract.Policy.GetStoragePrice(snapshot); - this.nonceData = container is Transaction tx ? tx.Hash.ToArray()[..16] : new byte[16]; + Trigger = trigger; + ScriptContainer = container; + originalSnapshot = snapshot; + PersistingBlock = persistingBlock; + ProtocolSettings = settings; + gas_amount = 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); + nonceData = container is Transaction tx ? tx.Hash.ToArray()[..16] : new byte[16]; if (persistingBlock is not null) { fixed (byte* p = nonceData) diff --git a/src/Neo/SmartContract/ContractParameter.cs b/src/Neo/SmartContract/ContractParameter.cs index 027fa50e00..4abc7aa985 100644 --- a/src/Neo/SmartContract/ContractParameter.cs +++ b/src/Neo/SmartContract/ContractParameter.cs @@ -45,8 +45,8 @@ public ContractParameter() { } /// The type of the parameter. public ContractParameter(ContractParameterType type) { - this.Type = type; - this.Value = type switch + Type = type; + Value = type switch { ContractParameterType.Any => null, ContractParameterType.Signature => new byte[64], diff --git a/src/Neo/SmartContract/ContractParametersContext.cs b/src/Neo/SmartContract/ContractParametersContext.cs index 3bf98e981b..e8bf3ceec9 100644 --- a/src/Neo/SmartContract/ContractParametersContext.cs +++ b/src/Neo/SmartContract/ContractParametersContext.cs @@ -37,16 +37,16 @@ private class ContextItem public ContextItem(Contract contract) { - this.Script = contract.Script; - this.Parameters = contract.ParameterList.Select(p => new ContractParameter { Type = p }).ToArray(); - this.Signatures = new Dictionary(); + Script = contract.Script; + Parameters = contract.ParameterList.Select(p => new ContractParameter { Type = p }).ToArray(); + Signatures = new Dictionary(); } public ContextItem(JObject json) { - this.Script = json["script"] is JToken.Null ? null : Convert.FromBase64String(json["script"].AsString()); - this.Parameters = ((JArray)json["parameters"]).Select(p => ContractParameter.FromJson((JObject)p)).ToArray(); - this.Signatures = ((JObject)json["signatures"]).Properties.Select(p => new + Script = json["script"] is JToken.Null ? null : Convert.FromBase64String(json["script"].AsString()); + Parameters = ((JArray)json["parameters"]).Select(p => ContractParameter.FromJson((JObject)p)).ToArray(); + Signatures = ((JObject)json["signatures"]).Properties.Select(p => new { PublicKey = ECPoint.Parse(p.Key, ECCurve.Secp256r1), Signature = Convert.FromBase64String(p.Value.AsString()) @@ -109,10 +109,10 @@ public bool Completed /// The magic number of the network. public ContractParametersContext(DataCache snapshot, IVerifiable verifiable, uint network) { - this.Verifiable = verifiable; - this.Snapshot = snapshot; - this.ContextItems = new Dictionary(); - this.Network = network; + Verifiable = verifiable; + Snapshot = snapshot; + ContextItems = new Dictionary(); + Network = network; } /// diff --git a/src/Neo/SmartContract/InteropParameterDescriptor.cs b/src/Neo/SmartContract/InteropParameterDescriptor.cs index 01f4dfa2e5..24e103afc5 100644 --- a/src/Neo/SmartContract/InteropParameterDescriptor.cs +++ b/src/Neo/SmartContract/InteropParameterDescriptor.cs @@ -82,7 +82,7 @@ public class InteropParameterDescriptor internal InteropParameterDescriptor(ParameterInfo parameterInfo) : this(parameterInfo.ParameterType, parameterInfo.GetCustomAttributes(true).ToArray()) { - this.Name = parameterInfo.Name; + Name = parameterInfo.Name; } internal InteropParameterDescriptor(Type type, params ValidatorAttribute[] validators) diff --git a/src/Neo/SmartContract/LogEventArgs.cs b/src/Neo/SmartContract/LogEventArgs.cs index 1614438dea..fb1d656732 100644 --- a/src/Neo/SmartContract/LogEventArgs.cs +++ b/src/Neo/SmartContract/LogEventArgs.cs @@ -42,9 +42,9 @@ public class LogEventArgs : EventArgs /// The message of the log. public LogEventArgs(IVerifiable container, UInt160 script_hash, string message) { - this.ScriptContainer = container; - this.ScriptHash = script_hash; - this.Message = message; + ScriptContainer = container; + ScriptHash = script_hash; + Message = message; } } } diff --git a/src/Neo/SmartContract/Manifest/ContractPermissionDescriptor.cs b/src/Neo/SmartContract/Manifest/ContractPermissionDescriptor.cs index ce85889423..f1f22d99d8 100644 --- a/src/Neo/SmartContract/Manifest/ContractPermissionDescriptor.cs +++ b/src/Neo/SmartContract/Manifest/ContractPermissionDescriptor.cs @@ -49,8 +49,8 @@ public class ContractPermissionDescriptor : IEquatable span) diff --git a/src/Neo/SmartContract/Native/ContractMethodMetadata.cs b/src/Neo/SmartContract/Native/ContractMethodMetadata.cs index 9f83eb20fc..0688a0dac2 100644 --- a/src/Neo/SmartContract/Native/ContractMethodMetadata.cs +++ b/src/Neo/SmartContract/Native/ContractMethodMetadata.cs @@ -39,28 +39,28 @@ internal class ContractMethodMetadata public ContractMethodMetadata(MemberInfo member, ContractMethodAttribute attribute) { - this.Name = attribute.Name ?? member.Name.ToLower()[0] + member.Name[1..]; - this.Handler = member switch + Name = attribute.Name ?? member.Name.ToLower()[0] + member.Name[1..]; + Handler = member switch { MethodInfo m => m, PropertyInfo p => p.GetMethod, _ => throw new ArgumentException(null, nameof(member)) }; - ParameterInfo[] parameterInfos = this.Handler.GetParameters(); + ParameterInfo[] parameterInfos = Handler.GetParameters(); if (parameterInfos.Length > 0) { NeedApplicationEngine = parameterInfos[0].ParameterType.IsAssignableFrom(typeof(ApplicationEngine)); NeedSnapshot = parameterInfos[0].ParameterType.IsAssignableFrom(typeof(DataCache)); } if (NeedApplicationEngine || NeedSnapshot) - this.Parameters = parameterInfos.Skip(1).Select(p => new InteropParameterDescriptor(p)).ToArray(); + Parameters = parameterInfos.Skip(1).Select(p => new InteropParameterDescriptor(p)).ToArray(); else - this.Parameters = parameterInfos.Select(p => new InteropParameterDescriptor(p)).ToArray(); - this.CpuFee = attribute.CpuFee; - this.StorageFee = attribute.StorageFee; - this.RequiredCallFlags = attribute.RequiredCallFlags; - this.ActiveIn = attribute.ActiveIn; - this.Descriptor = new ContractMethodDescriptor + Parameters = parameterInfos.Select(p => new InteropParameterDescriptor(p)).ToArray(); + CpuFee = attribute.CpuFee; + StorageFee = attribute.StorageFee; + RequiredCallFlags = attribute.RequiredCallFlags; + ActiveIn = attribute.ActiveIn; + Descriptor = new ContractMethodDescriptor { Name = Name, ReturnType = ToParameterType(Handler.ReturnType), diff --git a/src/Neo/SmartContract/Native/FungibleToken.cs b/src/Neo/SmartContract/Native/FungibleToken.cs index 10e406dd07..4ab0f01589 100644 --- a/src/Neo/SmartContract/Native/FungibleToken.cs +++ b/src/Neo/SmartContract/Native/FungibleToken.cs @@ -62,7 +62,7 @@ public abstract class FungibleToken : NativeContract "amount", ContractParameterType.Integer)] protected FungibleToken() : base() { - this.Factor = BigInteger.Pow(10, Decimals); + Factor = BigInteger.Pow(10, Decimals); } protected override void OnManifestCompose(ContractManifest manifest) diff --git a/src/Neo/SmartContract/Native/NativeContract.cs b/src/Neo/SmartContract/Native/NativeContract.cs index 2b00fddfe2..bde1f8ac00 100644 --- a/src/Neo/SmartContract/Native/NativeContract.cs +++ b/src/Neo/SmartContract/Native/NativeContract.cs @@ -135,7 +135,7 @@ public CacheEntry GetAllowedMethods(NativeContract native, ApplicationEngine eng /// protected NativeContract() { - this.Hash = Helper.GetContractHash(UInt160.Zero, 0, Name); + Hash = Helper.GetContractHash(UInt160.Zero, 0, Name); // Reflection to get the methods diff --git a/src/Neo/SmartContract/Native/NeoToken.cs b/src/Neo/SmartContract/Native/NeoToken.cs index 82ee1b9fcb..1ff9aa2fdb 100644 --- a/src/Neo/SmartContract/Native/NeoToken.cs +++ b/src/Neo/SmartContract/Native/NeoToken.cs @@ -68,7 +68,7 @@ public sealed class NeoToken : FungibleToken "new", ContractParameterType.Array)] internal NeoToken() : base() { - this.TotalAmount = 100000000 * Factor; + TotalAmount = 100000000 * Factor; } public override BigInteger TotalSupply(DataCache snapshot) diff --git a/src/Neo/SmartContract/NotifyEventArgs.cs b/src/Neo/SmartContract/NotifyEventArgs.cs index 0a509101c1..93c124ea88 100644 --- a/src/Neo/SmartContract/NotifyEventArgs.cs +++ b/src/Neo/SmartContract/NotifyEventArgs.cs @@ -52,10 +52,10 @@ public class NotifyEventArgs : EventArgs, IInteroperable /// The arguments of the event. public NotifyEventArgs(IVerifiable container, UInt160 script_hash, string eventName, Array state) { - this.ScriptContainer = container; - this.ScriptHash = script_hash; - this.EventName = eventName; - this.State = state; + ScriptContainer = container; + ScriptHash = script_hash; + EventName = eventName; + State = state; } public void FromStackItem(StackItem stackItem) diff --git a/src/Neo/SmartContract/StorageItem.cs b/src/Neo/SmartContract/StorageItem.cs index 350e95e70a..133a8fa1dd 100644 --- a/src/Neo/SmartContract/StorageItem.cs +++ b/src/Neo/SmartContract/StorageItem.cs @@ -69,7 +69,7 @@ public StorageItem(byte[] value) /// The integer value of the . public StorageItem(BigInteger value) { - this.cache = value; + cache = value; } /// @@ -78,7 +78,7 @@ public StorageItem(BigInteger value) /// The value of the . public StorageItem(IInteroperable interoperable) { - this.cache = interoperable; + cache = interoperable; } /// diff --git a/src/Neo/Wallets/AssetDescriptor.cs b/src/Neo/Wallets/AssetDescriptor.cs index 4eb84e938d..7b9be7b16b 100644 --- a/src/Neo/Wallets/AssetDescriptor.cs +++ b/src/Neo/Wallets/AssetDescriptor.cs @@ -62,10 +62,10 @@ public AssetDescriptor(DataCache snapshot, ProtocolSettings settings, UInt160 as } using ApplicationEngine engine = ApplicationEngine.Run(script, snapshot, settings: settings, gas: 0_30000000L); if (engine.State != VMState.HALT) throw new ArgumentException(null, nameof(asset_id)); - this.AssetId = asset_id; - this.AssetName = contract.Manifest.Name; - this.Symbol = engine.ResultStack.Pop().GetString(); - this.Decimals = (byte)engine.ResultStack.Pop().GetInteger(); + AssetId = asset_id; + AssetName = contract.Manifest.Name; + Symbol = engine.ResultStack.Pop().GetString(); + Decimals = (byte)engine.ResultStack.Pop().GetInteger(); } public override string ToString() diff --git a/src/Neo/Wallets/KeyPair.cs b/src/Neo/Wallets/KeyPair.cs index d0842242d8..7b15c0bbd0 100644 --- a/src/Neo/Wallets/KeyPair.cs +++ b/src/Neo/Wallets/KeyPair.cs @@ -48,14 +48,14 @@ public KeyPair(byte[] privateKey) { if (privateKey.Length != 32 && privateKey.Length != 96 && privateKey.Length != 104) throw new ArgumentException(null, nameof(privateKey)); - this.PrivateKey = privateKey[^32..]; + PrivateKey = privateKey[^32..]; if (privateKey.Length == 32) { - this.PublicKey = Cryptography.ECC.ECCurve.Secp256r1.G * privateKey; + PublicKey = Cryptography.ECC.ECCurve.Secp256r1.G * privateKey; } else { - this.PublicKey = Cryptography.ECC.ECPoint.FromBytes(privateKey, Cryptography.ECC.ECCurve.Secp256r1); + PublicKey = Cryptography.ECC.ECPoint.FromBytes(privateKey, Cryptography.ECC.ECCurve.Secp256r1); } } diff --git a/src/Neo/Wallets/NEP6/NEP6Wallet.cs b/src/Neo/Wallets/NEP6/NEP6Wallet.cs index b600fe6dcd..cede8e0efa 100644 --- a/src/Neo/Wallets/NEP6/NEP6Wallet.cs +++ b/src/Neo/Wallets/NEP6/NEP6Wallet.cs @@ -63,10 +63,10 @@ public NEP6Wallet(string path, string password, ProtocolSettings settings, strin else { this.name = name; - this.version = Version.Parse("1.0"); - this.Scrypt = ScryptParameters.Default; - this.accounts = new Dictionary(); - this.extra = JToken.Null; + version = Version.Parse("1.0"); + Scrypt = ScryptParameters.Default; + accounts = new Dictionary(); + extra = JToken.Null; } } @@ -85,8 +85,8 @@ public NEP6Wallet(string path, string password, ProtocolSettings settings, JObje private void LoadFromJson(JObject wallet, out ScryptParameters scrypt, out Dictionary accounts, out JToken extra) { - this.version = Version.Parse(wallet["version"].AsString()); - this.name = wallet["name"]?.AsString(); + version = Version.Parse(wallet["version"].AsString()); + name = wallet["name"]?.AsString(); scrypt = ScryptParameters.FromJson((JObject)wallet["scrypt"]); accounts = ((JArray)wallet["accounts"]).Select(p => NEP6Account.FromJson((JObject)p, this)).ToDictionary(p => p.ScriptHash); extra = wallet["extra"]; diff --git a/src/Neo/Wallets/NEP6/ScryptParameters.cs b/src/Neo/Wallets/NEP6/ScryptParameters.cs index ab720b3a08..d8e076272a 100644 --- a/src/Neo/Wallets/NEP6/ScryptParameters.cs +++ b/src/Neo/Wallets/NEP6/ScryptParameters.cs @@ -46,9 +46,9 @@ public class ScryptParameters /// Parallelization parameter. public ScryptParameters(int n, int r, int p) { - this.N = n; - this.R = r; - this.P = p; + N = n; + R = r; + P = p; } /// diff --git a/src/Neo/Wallets/WalletAccount.cs b/src/Neo/Wallets/WalletAccount.cs index 148f272bc1..62bcd85ec1 100644 --- a/src/Neo/Wallets/WalletAccount.cs +++ b/src/Neo/Wallets/WalletAccount.cs @@ -76,8 +76,8 @@ public abstract class WalletAccount /// The to be used by the wallet. protected WalletAccount(UInt160 scriptHash, ProtocolSettings settings) { - this.ProtocolSettings = settings; - this.ScriptHash = scriptHash; + ProtocolSettings = settings; + ScriptHash = scriptHash; } } } From 6f40f002bd5e85bdf6513996e47914193a893583 Mon Sep 17 00:00:00 2001 From: Christopher Schuchardt Date: Tue, 7 May 2024 04:25:11 -0400 Subject: [PATCH 119/168] Changed to `Use collection expression for array` (#3217) Co-authored-by: Shargon --- .editorconfig | 7 +++++-- src/Neo/Cryptography/BloomFilter.cs | 12 +++++++---- src/Neo/Network/P2P/Payloads/Signer.cs | 8 +++++--- .../UT_OrderedDictionary.cs | 10 ++++++---- .../Network/P2P/Payloads/UT_NotValidBefore.cs | 6 ++++-- .../SmartContract/UT_ContractParameter.cs | 6 ++++-- tests/Neo.UnitTests/VM/UT_Helper.cs | 20 +++++++++++-------- 7 files changed, 44 insertions(+), 25 deletions(-) diff --git a/.editorconfig b/.editorconfig index 9a574425e9..f24ccd45a8 100644 --- a/.editorconfig +++ b/.editorconfig @@ -72,8 +72,8 @@ dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion dotnet_style_predefined_type_for_member_access = true:suggestion # Suggest more modern language features when available -dotnet_style_object_initializer = true:suggestion -dotnet_style_collection_initializer = true:suggestion +dotnet_style_object_initializer = true:warning +dotnet_style_collection_initializer = true:warning dotnet_style_coalesce_expression = true:suggestion dotnet_style_null_propagation = true:suggestion dotnet_style_explicit_tuple_names = true:suggestion @@ -256,6 +256,9 @@ dotnet_diagnostic.IDE0060.severity = none [src/{Analyzers,CodeStyle,Features,Workspaces,EditorFeatures,VisualStudio}/**/*.{cs,vb}] +# Use collection expression for array +dotnet_diagnostic.IDE0300.severity = warning + # Avoid "this." and "Me." if not necessary dotnet_diagnostic.IDE0003.severity = warning dotnet_diagnostic.IDE0009.severity = warning diff --git a/src/Neo/Cryptography/BloomFilter.cs b/src/Neo/Cryptography/BloomFilter.cs index ffa626a546..73141d9e11 100644 --- a/src/Neo/Cryptography/BloomFilter.cs +++ b/src/Neo/Cryptography/BloomFilter.cs @@ -48,8 +48,10 @@ public BloomFilter(int m, int k, uint nTweak) { if (k < 0 || m < 0) throw new ArgumentOutOfRangeException(); seeds = Enumerable.Range(0, k).Select(p => (uint)p * 0xFBA4C795 + nTweak).ToArray(); - bits = new BitArray(m); - bits.Length = m; + bits = new BitArray(m) + { + Length = m + }; Tweak = nTweak; } @@ -64,8 +66,10 @@ public BloomFilter(int m, int k, uint nTweak, ReadOnlyMemory elements) { if (k < 0 || m < 0) throw new ArgumentOutOfRangeException(); seeds = Enumerable.Range(0, k).Select(p => (uint)p * 0xFBA4C795 + nTweak).ToArray(); - bits = new BitArray(elements.ToArray()); - bits.Length = m; + bits = new BitArray(elements.ToArray()) + { + Length = m + }; Tweak = nTweak; } diff --git a/src/Neo/Network/P2P/Payloads/Signer.cs b/src/Neo/Network/P2P/Payloads/Signer.cs index 2f96047323..9a68640880 100644 --- a/src/Neo/Network/P2P/Payloads/Signer.cs +++ b/src/Neo/Network/P2P/Payloads/Signer.cs @@ -153,9 +153,11 @@ public void Serialize(BinaryWriter writer) /// The converted signer. public static Signer FromJson(JObject json) { - Signer signer = new(); - signer.Account = UInt160.Parse(json["account"].GetString()); - signer.Scopes = Enum.Parse(json["scopes"].GetString()); + Signer signer = new() + { + Account = UInt160.Parse(json["account"].GetString()), + Scopes = Enum.Parse(json["scopes"].GetString()) + }; if (signer.Scopes.HasFlag(WitnessScope.CustomContracts)) signer.AllowedContracts = ((JArray)json["allowedcontracts"]).Select(p => UInt160.Parse(p.GetString())).ToArray(); if (signer.Scopes.HasFlag(WitnessScope.CustomGroups)) diff --git a/tests/Neo.Json.UnitTests/UT_OrderedDictionary.cs b/tests/Neo.Json.UnitTests/UT_OrderedDictionary.cs index 83a5c2c2f7..0f73afae95 100644 --- a/tests/Neo.Json.UnitTests/UT_OrderedDictionary.cs +++ b/tests/Neo.Json.UnitTests/UT_OrderedDictionary.cs @@ -21,10 +21,12 @@ public class UT_OrderedDictionary [TestInitialize] public void SetUp() { - od = new OrderedDictionary(); - od.Add("a", 1); - od.Add("b", 2); - od.Add("c", 3); + od = new OrderedDictionary + { + { "a", 1 }, + { "b", 2 }, + { "c", 3 } + }; } [TestMethod] diff --git a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_NotValidBefore.cs b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_NotValidBefore.cs index 0b51550f83..8e7ad9087b 100644 --- a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_NotValidBefore.cs +++ b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_NotValidBefore.cs @@ -31,8 +31,10 @@ public void Size_Get() [TestMethod] public void ToJson() { - var test = new NotValidBefore(); - test.Height = 42; + var test = new NotValidBefore + { + Height = 42 + }; var json = test.ToJson().ToString(); Assert.AreEqual(@"{""type"":""NotValidBefore"",""height"":42}", json); } diff --git a/tests/Neo.UnitTests/SmartContract/UT_ContractParameter.cs b/tests/Neo.UnitTests/SmartContract/UT_ContractParameter.cs index 3c567ca5bc..6618a918e7 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_ContractParameter.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_ContractParameter.cs @@ -187,8 +187,10 @@ public void TestToString() ContractParameter contractParameter1 = new(); Assert.AreEqual("(null)", contractParameter1.ToString()); - ContractParameter contractParameter2 = new(ContractParameterType.ByteArray); - contractParameter2.Value = new byte[1]; + ContractParameter contractParameter2 = new(ContractParameterType.ByteArray) + { + Value = new byte[1] + }; Assert.AreEqual("00", contractParameter2.ToString()); ContractParameter contractParameter3 = new(ContractParameterType.Array); diff --git a/tests/Neo.UnitTests/VM/UT_Helper.cs b/tests/Neo.UnitTests/VM/UT_Helper.cs index fbe12fc787..c5bf61d152 100644 --- a/tests/Neo.UnitTests/VM/UT_Helper.cs +++ b/tests/Neo.UnitTests/VM/UT_Helper.cs @@ -40,11 +40,13 @@ public void TestEmit() [TestMethod] public void TestToJson() { - var item = new VM.Types.Array(); - item.Add(5); - item.Add("hello world"); - item.Add(new byte[] { 1, 2, 3 }); - item.Add(true); + var item = new VM.Types.Array + { + 5, + "hello world", + new byte[] { 1, 2, 3 }, + true + }; Assert.AreEqual("{\"type\":\"Integer\",\"value\":\"5\"}", item[0].ToJson().ToString()); Assert.AreEqual("{\"type\":\"ByteString\",\"value\":\"aGVsbG8gd29ybGQ=\"}", item[1].ToJson().ToString()); @@ -274,9 +276,11 @@ private void TestEmitPush2Array() { ScriptBuilder sb = new ScriptBuilder(); ContractParameter parameter = new ContractParameter(ContractParameterType.Array); - IList values = new List(); - values.Add(new ContractParameter(ContractParameterType.Integer)); - values.Add(new ContractParameter(ContractParameterType.Integer)); + IList values = new List + { + new ContractParameter(ContractParameterType.Integer), + new ContractParameter(ContractParameterType.Integer) + }; parameter.Value = values; sb.EmitPush(parameter); byte[] tempArray = new byte[4]; From 8b3c59a4070eb09f8d447854bd37eef8f54fa811 Mon Sep 17 00:00:00 2001 From: Christopher Schuchardt Date: Tue, 7 May 2024 06:48:42 -0400 Subject: [PATCH 120/168] [`Refactor`] Test Projects (#3214) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fixes tests projects * Update Directory.Build.props * Update Neo.ConsoleService.Tests.csproj * Update Neo.Cryptography.BLS12_381.Tests.csproj * Update Neo.Json.UnitTests.csproj * Update Neo.UnitTests.csproj * Update Neo.VM.Tests.csproj --------- Co-authored-by: Shargon Co-authored-by: Vitor Nazário Coelho --- .github/workflows/main.yml | 1 - tests/Directory.Build.props | 23 +++++++++++++++++++ .../Neo.ConsoleService.Tests.csproj | 6 ----- .../Neo.Cryptography.BLS12_381.Tests.csproj | 6 ----- .../Neo.Json.UnitTests.csproj | 6 ----- tests/Neo.UnitTests/Neo.UnitTests.csproj | 6 ----- tests/Neo.VM.Tests/Neo.VM.Tests.csproj | 6 ----- 7 files changed, 23 insertions(+), 31 deletions(-) create mode 100644 tests/Directory.Build.props diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index fe43722e6f..ee5dd904a1 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -34,7 +34,6 @@ jobs: - name: Test for coverall if: matrix.os == 'ubuntu-latest' run: | - find tests -name *.csproj | xargs -I % dotnet add % package coverlet.msbuild dotnet test ./tests/Neo.Cryptography.BLS12_381.Tests /p:CollectCoverage=true /p:CoverletOutput='${{ github.workspace }}/TestResults/coverage/' dotnet test ./tests/Neo.ConsoleService.Tests /p:CollectCoverage=true /p:CoverletOutput='${{ github.workspace }}/TestResults/coverage/' /p:MergeWith='${{ github.workspace }}/TestResults/coverage/coverage.net8.0.json' dotnet test ./tests/Neo.UnitTests /p:CollectCoverage=true /p:CoverletOutput='${{ github.workspace }}/TestResults/coverage/' /p:MergeWith='${{ github.workspace }}/TestResults/coverage/coverage.net8.0.json' diff --git a/tests/Directory.Build.props b/tests/Directory.Build.props new file mode 100644 index 0000000000..7ba3905160 --- /dev/null +++ b/tests/Directory.Build.props @@ -0,0 +1,23 @@ + + + + + 12.0 + false + false + true + 0 + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + diff --git a/tests/Neo.ConsoleService.Tests/Neo.ConsoleService.Tests.csproj b/tests/Neo.ConsoleService.Tests/Neo.ConsoleService.Tests.csproj index 2465178817..c2a2adcf84 100644 --- a/tests/Neo.ConsoleService.Tests/Neo.ConsoleService.Tests.csproj +++ b/tests/Neo.ConsoleService.Tests/Neo.ConsoleService.Tests.csproj @@ -3,7 +3,6 @@ net8.0 neo_cli.Tests - false @@ -11,11 +10,6 @@ - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - 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 15896e0b0b..c6aeac41ae 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 @@ -4,7 +4,6 @@ net8.0 enable enable - false @@ -12,11 +11,6 @@ - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - diff --git a/tests/Neo.Json.UnitTests/Neo.Json.UnitTests.csproj b/tests/Neo.Json.UnitTests/Neo.Json.UnitTests.csproj index 8b4999444b..b26a47c6fa 100644 --- a/tests/Neo.Json.UnitTests/Neo.Json.UnitTests.csproj +++ b/tests/Neo.Json.UnitTests/Neo.Json.UnitTests.csproj @@ -3,7 +3,6 @@ net8.0 enable - false @@ -11,11 +10,6 @@ - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - diff --git a/tests/Neo.UnitTests/Neo.UnitTests.csproj b/tests/Neo.UnitTests/Neo.UnitTests.csproj index 4223a75ee6..e2ab6dc14e 100644 --- a/tests/Neo.UnitTests/Neo.UnitTests.csproj +++ b/tests/Neo.UnitTests/Neo.UnitTests.csproj @@ -3,7 +3,6 @@ net8.0 true - false @@ -24,11 +23,6 @@ - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - diff --git a/tests/Neo.VM.Tests/Neo.VM.Tests.csproj b/tests/Neo.VM.Tests/Neo.VM.Tests.csproj index 5f68e9aa7d..aeb0d826b9 100644 --- a/tests/Neo.VM.Tests/Neo.VM.Tests.csproj +++ b/tests/Neo.VM.Tests/Neo.VM.Tests.csproj @@ -4,7 +4,6 @@ net8.0 Neo.Test true - false @@ -18,11 +17,6 @@ - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - From 200693838df66dc80fa1bc831b92870c71ecc2e9 Mon Sep 17 00:00:00 2001 From: Christopher Schuchardt Date: Tue, 7 May 2024 06:52:01 -0400 Subject: [PATCH 121/168] Added missing `github` workflows changes from #3189 (#3213) 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 ee5dd904a1..92aa1f9332 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -6,7 +6,7 @@ on: pull_request: env: - DOTNET_VERSION: 8.0.202 + DOTNET_VERSION: 8.0.x jobs: From ef117692231f8c6ef06b76784b3aea6947e9d6e9 Mon Sep 17 00:00:00 2001 From: Anna Shaleva Date: Fri, 10 May 2024 05:36:06 +0300 Subject: [PATCH 122/168] Support Koblitz-based and Keccak256-based custom witness verification (#3209) * Native: extend CryptoLib's verifyWithECDsa with hasher parameter A port of https://github.com/nspcc-dev/neo-go/pull/3425/commits/1e2b438b5580ca9ada7b452130b95a249733d31a. This commit contains minor protocol extension needed for custom Koblitz-based verification scripts (an alternative to https://github.com/neo-project/neo/pull/3205). Replace native CryptoLib's verifyWithECDsa `curve` parameter by `curveHash` parameter which is a enum over supported pairs of named curves and hash functions. NamedCurve enum mark as deprecated and replaced by NamedCurveHash with compatible behaviour. Even though this change is a compatible extension of the protocol, it changes the genesis state due to parameter renaming (CryptoLib's manifest is changed). But we're going to resync chain in 3.7 release anyway, so it's not a big deal. Also, we need to check mainnet and testnet compatibility in case if anyone has ever called verifyWithECDsa with 24 or 25 `curve` value. Signed-off-by: Anna Shaleva * SmartContract: add extension to ScriptBuilder for System.Contract.Call Group the set of common operations required to emit System.Contract.Call appcall. Signed-off-by: Anna Shaleva * Native: add an example of custom Koblitz signature verification Koblitz-based and Keccak-based transaction witness verification for single signature and multisignature ported from https://github.com/nspcc-dev/neo-go/pull/3425. An alternative to https://github.com/neo-project/neo/pull/3205. Signed-off-by: Anna Shaleva * SmartContract: make multisig koblitz easier to parse 1. Make prologue be exactly the same as regular CheckMultisig. 2. But instead of "SYSCALL System.Crypto.CheckMultisig" do INITSLOT and K check. 3. This makes all of the code from INITSLOT below be independent of N/M, so one can parse the script beginning in the same way CheckMultisig is parsed and then just compare the rest of it with some known-good blob. 4. The script becomes a tiny bit larger now, but properties above are too good. Ported from https://github.com/nspcc-dev/neo-go/pull/3425/commits/34ee29408663c51aefefd258b8ab44207c915868. Signed-off-by: Anna Shaleva * SmartContract: use ABORT in Koblitz multisig Make the script a bit shorter. ABORTMSG would cost a bit more. Ported from https://github.com/nspcc-dev/neo-go/pull/3425/commits/fb16891e2ae84f601624ec1797a5f85f8d05cb47. Ref. https://github.com/nspcc-dev/neo-go/pull/3425#discussion_r1588972899. Signed-off-by: Anna Shaleva * SmartContract: reduce callflag scope for Koblitz verification scripts All flag is too wide. A port of https://github.com/nspcc-dev/neo-go/pull/3425/commits/fe292f3f39d2e388be0c408fbc22107e9ce09515. Ref. https://github.com/nspcc-dev/neo-go/pull/3425#discussion_r1589240074. Signed-off-by: Anna Shaleva * Native: add tests for CryptoLib's verifyWithECDsa No functional changes, just add more unit-tests. Signed-off-by: Anna Shaleva * Native: update NamedCurveHash values for Keccak256 hasher Use 122 and 123 respectively for secp256k1Keccak256 and secp256r1Keccak256. Signed-off-by: Anna Shaleva * SmartContract: move EmitAppCallNoArgs to the testing code We're not going to implement custom Koblitz witness generation at the core, and thus, the only user of this API is testing code. Signed-off-by: Anna Shaleva * Apply suggestions from code review clean ut lines * fix names * Cryptography: cache ECDomainParameters for Secp256r1 and Secp256k1 Signed-off-by: Anna Shaleva * Update tests/Neo.UnitTests/SmartContract/Native/UT_CryptoLib.cs * Update tests/Neo.UnitTests/SmartContract/Native/UT_CryptoLib.cs * Update tests/Neo.UnitTests/SmartContract/Native/UT_CryptoLib.cs * Update tests/Neo.UnitTests/SmartContract/Native/UT_CryptoLib.cs * Update tests/Neo.UnitTests/SmartContract/Native/UT_CryptoLib.cs * Update tests/Neo.UnitTests/SmartContract/Native/UT_CryptoLib.cs * Update tests/Neo.UnitTests/SmartContract/Native/UT_CryptoLib.cs * Update tests/Neo.UnitTests/SmartContract/Native/UT_CryptoLib.cs * Update tests/Neo.UnitTests/SmartContract/Native/UT_CryptoLib.cs * Update tests/Neo.UnitTests/SmartContract/Native/UT_CryptoLib.cs * Update tests/Neo.UnitTests/SmartContract/Native/UT_CryptoLib.cs * Update tests/Neo.UnitTests/SmartContract/Native/UT_CryptoLib.cs * Update tests/Neo.UnitTests/SmartContract/Native/UT_CryptoLib.cs * Update tests/Neo.UnitTests/SmartContract/Native/UT_CryptoLib.cs * Update tests/Neo.UnitTests/SmartContract/Native/UT_CryptoLib.cs --------- Signed-off-by: Anna Shaleva Co-authored-by: Shargon Co-authored-by: Jimmy --- src/Neo/Cryptography/Crypto.cs | 71 ++- src/Neo/Cryptography/Hasher.cs | 29 ++ src/Neo/Cryptography/Helper.cs | 35 ++ src/Neo/SmartContract/Native/CryptoLib.cs | 22 +- src/Neo/SmartContract/Native/NamedCurve.cs | 8 +- .../SmartContract/Native/NamedCurveHash.cs | 40 ++ .../SmartContract/Native/UT_CryptoLib.cs | 478 ++++++++++++++++++ .../SmartContract/Native/UT_NativeContract.cs | 2 +- 8 files changed, 655 insertions(+), 30 deletions(-) create mode 100644 src/Neo/Cryptography/Hasher.cs create mode 100644 src/Neo/SmartContract/Native/NamedCurveHash.cs diff --git a/src/Neo/Cryptography/Crypto.cs b/src/Neo/Cryptography/Crypto.cs index e419d268a2..85ed0411a8 100644 --- a/src/Neo/Cryptography/Crypto.cs +++ b/src/Neo/Cryptography/Crypto.cs @@ -28,6 +28,17 @@ public static class Crypto private static readonly bool IsOSX = RuntimeInformation.IsOSPlatform(OSPlatform.OSX); private static readonly ECCurve secP256k1 = ECCurve.CreateFromFriendlyName("secP256k1"); private static readonly X9ECParameters bouncySecp256k1 = Org.BouncyCastle.Asn1.Sec.SecNamedCurves.GetByName("secp256k1"); + private static readonly X9ECParameters bouncySecp256r1 = Org.BouncyCastle.Asn1.Sec.SecNamedCurves.GetByName("secp256r1"); + + /// + /// Holds domain parameters for Secp256r1 elliptic curve. + /// + private static readonly ECDomainParameters secp256r1DomainParams = new ECDomainParameters(bouncySecp256r1.Curve, bouncySecp256r1.G, bouncySecp256r1.N, bouncySecp256r1.H); + + /// + /// Holds domain parameters for Secp256k1 elliptic curve. + /// + private static readonly ECDomainParameters secp256k1DomainParams = new ECDomainParameters(bouncySecp256k1.Curve, bouncySecp256k1.G, bouncySecp256k1.N, bouncySecp256k1.H); /// /// Calculates the 160-bit hash value of the specified message. @@ -50,22 +61,30 @@ public static byte[] Hash256(ReadOnlySpan message) } /// - /// Signs the specified message using the ECDSA algorithm. + /// Signs the specified message using the ECDSA algorithm and specified hash algorithm. /// /// The message to be signed. /// The private key to be used. /// The curve of the signature, default is . + /// The hash algorithm to hash the message, default is SHA256. /// The ECDSA signature for the specified message. - public static byte[] Sign(byte[] message, byte[] priKey, ECC.ECCurve ecCurve = null) + public static byte[] Sign(byte[] message, byte[] priKey, ECC.ECCurve ecCurve = null, Hasher hasher = Hasher.SHA256) { - if (IsOSX && ecCurve == ECC.ECCurve.Secp256k1) + if (hasher == Hasher.Keccak256 || (IsOSX && ecCurve == ECC.ECCurve.Secp256k1)) { - var domain = new ECDomainParameters(bouncySecp256k1.Curve, bouncySecp256k1.G, bouncySecp256k1.N, bouncySecp256k1.H); + var domain = + ecCurve == null || ecCurve == ECC.ECCurve.Secp256r1 ? secp256r1DomainParams : + ecCurve == ECC.ECCurve.Secp256k1 ? secp256k1DomainParams : + throw new NotSupportedException(nameof(ecCurve)); var signer = new Org.BouncyCastle.Crypto.Signers.ECDsaSigner(); var privateKey = new BigInteger(1, priKey); var priKeyParameters = new ECPrivateKeyParameters(privateKey, domain); signer.Init(true, priKeyParameters); - var signature = signer.GenerateSignature(message.Sha256()); + var messageHash = + hasher == Hasher.SHA256 ? message.Sha256() : + hasher == Hasher.Keccak256 ? message.Keccak256() : + throw new NotSupportedException(nameof(hasher)); + var signature = signer.GenerateSignature(messageHash); var signatureBytes = new byte[64]; var rBytes = signature[0].ToByteArrayUnsigned(); @@ -87,24 +106,35 @@ public static byte[] Sign(byte[] message, byte[] priKey, ECC.ECCurve ecCurve = n Curve = curve, D = priKey, }); - return ecdsa.SignData(message, HashAlgorithmName.SHA256); + var hashAlg = + hasher == Hasher.SHA256 ? HashAlgorithmName.SHA256 : + throw new NotSupportedException(nameof(hasher)); + return ecdsa.SignData(message, hashAlg); } /// - /// Verifies that a digital signature is appropriate for the provided key and message. + /// Verifies that a digital signature is appropriate for the provided key, message and hash algorithm. /// /// The signed message. /// The signature to be verified. /// The public key to be used. + /// The hash algorithm to be used to hash the message, the default is SHA256. /// if the signature is valid; otherwise, . - public static bool VerifySignature(ReadOnlySpan message, ReadOnlySpan signature, ECC.ECPoint pubkey) + public static bool VerifySignature(ReadOnlySpan message, ReadOnlySpan signature, ECC.ECPoint pubkey, Hasher hasher = Hasher.SHA256) { if (signature.Length != 64) return false; - if (IsOSX && pubkey.Curve == ECC.ECCurve.Secp256k1) + if (hasher == Hasher.Keccak256 || (IsOSX && pubkey.Curve == ECC.ECCurve.Secp256k1)) { - var domain = new ECDomainParameters(bouncySecp256k1.Curve, bouncySecp256k1.G, bouncySecp256k1.N, bouncySecp256k1.H); - var point = bouncySecp256k1.Curve.CreatePoint( + var domain = + pubkey.Curve == ECC.ECCurve.Secp256r1 ? secp256r1DomainParams : + pubkey.Curve == ECC.ECCurve.Secp256k1 ? secp256k1DomainParams : + throw new NotSupportedException(nameof(pubkey.Curve)); + var curve = + pubkey.Curve == ECC.ECCurve.Secp256r1 ? bouncySecp256r1.Curve : + bouncySecp256k1.Curve; + + var point = curve.CreatePoint( new BigInteger(pubkey.X.Value.ToString()), new BigInteger(pubkey.Y.Value.ToString())); var pubKey = new ECPublicKeyParameters("ECDSA", point, domain); @@ -115,11 +145,19 @@ public static bool VerifySignature(ReadOnlySpan message, ReadOnlySpan @@ -153,16 +191,17 @@ public static ECDsa CreateECDsa(ECC.ECPoint pubkey) } /// - /// Verifies that a digital signature is appropriate for the provided key and message. + /// Verifies that a digital signature is appropriate for the provided key, curve, message and hasher. /// /// The signed message. /// The signature to be verified. /// The public key to be used. /// The curve to be used by the ECDSA algorithm. + /// The hash algorithm to be used hash the message, the default is SHA256. /// if the signature is valid; otherwise, . - public static bool VerifySignature(ReadOnlySpan message, ReadOnlySpan signature, ReadOnlySpan pubkey, ECC.ECCurve curve) + public static bool VerifySignature(ReadOnlySpan message, ReadOnlySpan signature, ReadOnlySpan pubkey, ECC.ECCurve curve, Hasher hasher = Hasher.SHA256) { - return VerifySignature(message, signature, ECC.ECPoint.DecodePoint(pubkey, curve)); + return VerifySignature(message, signature, ECC.ECPoint.DecodePoint(pubkey, curve), hasher); } } } diff --git a/src/Neo/Cryptography/Hasher.cs b/src/Neo/Cryptography/Hasher.cs new file mode 100644 index 0000000000..21c5fef6a8 --- /dev/null +++ b/src/Neo/Cryptography/Hasher.cs @@ -0,0 +1,29 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Hasher.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.Cryptography +{ + /// + /// Represents hash function identifiers supported by ECDSA message signature and verification. + /// + public enum Hasher : byte + { + /// + /// The SHA256 hash algorithm. + /// + SHA256 = 0x00, + + /// + /// The Keccak256 hash algorithm. + /// + Keccak256 = 0x01, + } +} diff --git a/src/Neo/Cryptography/Helper.cs b/src/Neo/Cryptography/Helper.cs index a087620034..f13fa08118 100644 --- a/src/Neo/Cryptography/Helper.cs +++ b/src/Neo/Cryptography/Helper.cs @@ -12,6 +12,7 @@ using Neo.IO; using Neo.Network.P2P.Payloads; using Neo.Wallets; +using Org.BouncyCastle.Crypto.Digests; using Org.BouncyCastle.Crypto.Engines; using Org.BouncyCastle.Crypto.Modes; using Org.BouncyCastle.Crypto.Parameters; @@ -153,6 +154,40 @@ public static byte[] Sha256(this Span value) return Sha256((ReadOnlySpan)value); } + /// + /// Computes the hash value for the specified byte array using the keccak256 algorithm. + /// + /// The input to compute the hash code for. + /// The computed hash code. + public static byte[] Keccak256(this byte[] value) + { + KeccakDigest keccak = new(256); + keccak.BlockUpdate(value, 0, value.Length); + byte[] result = new byte[keccak.GetDigestSize()]; + keccak.DoFinal(result, 0); + return result; + } + + /// + /// Computes the hash value for the specified byte array using the keccak256 algorithm. + /// + /// The input to compute the hash code for. + /// The computed hash code. + public static byte[] Keccak256(this ReadOnlySpan value) + { + return Keccak256(value.ToArray()); + } + + /// + /// Computes the hash value for the specified byte array using the keccak256 algorithm. + /// + /// The input to compute the hash code for. + /// The computed hash code. + public static byte[] Keccak256(this Span value) + { + return Keccak256(value.ToArray()); + } + public static byte[] AES256Encrypt(this byte[] plainData, byte[] key, byte[] nonce, byte[] associatedData = null) { if (nonce.Length != 12) throw new ArgumentOutOfRangeException(nameof(nonce)); diff --git a/src/Neo/SmartContract/Native/CryptoLib.cs b/src/Neo/SmartContract/Native/CryptoLib.cs index a7b822e39c..6e2876a860 100644 --- a/src/Neo/SmartContract/Native/CryptoLib.cs +++ b/src/Neo/SmartContract/Native/CryptoLib.cs @@ -11,7 +11,6 @@ using Neo.Cryptography; using Neo.Cryptography.ECC; -using Org.BouncyCastle.Crypto.Digests; using System; using System.Collections.Generic; @@ -22,10 +21,12 @@ namespace Neo.SmartContract.Native /// public sealed partial class CryptoLib : NativeContract { - private static readonly Dictionary curves = new() + private static readonly Dictionary s_curves = new() { - [NamedCurve.secp256k1] = ECCurve.Secp256k1, - [NamedCurve.secp256r1] = ECCurve.Secp256r1 + [NamedCurveHash.secp256k1SHA256] = (ECCurve.Secp256k1, Hasher.SHA256), + [NamedCurveHash.secp256r1SHA256] = (ECCurve.Secp256r1, Hasher.SHA256), + [NamedCurveHash.secp256k1Keccak256] = (ECCurve.Secp256k1, Hasher.Keccak256), + [NamedCurveHash.secp256r1Keccak256] = (ECCurve.Secp256r1, Hasher.Keccak256), }; internal CryptoLib() : base() { } @@ -73,11 +74,7 @@ public static byte[] Murmur32(byte[] data, uint seed) [ContractMethod(Hardfork.HF_Cockatrice, CpuFee = 1 << 15)] public static byte[] Keccak256(byte[] data) { - KeccakDigest keccak = new(256); - keccak.BlockUpdate(data, 0, data.Length); - byte[] result = new byte[keccak.GetDigestSize()]; - keccak.DoFinal(result, 0); - return result; + return data.Keccak256(); } /// @@ -86,14 +83,15 @@ public static byte[] Keccak256(byte[] data) /// The signed message. /// The public key to be used. /// The signature to be verified. - /// The curve to be used by the ECDSA algorithm. + /// A pair of the curve to be used by the ECDSA algorithm and the hasher function to be used to hash message. /// if the signature is valid; otherwise, . [ContractMethod(CpuFee = 1 << 15)] - public static bool VerifyWithECDsa(byte[] message, byte[] pubkey, byte[] signature, NamedCurve curve) + public static bool VerifyWithECDsa(byte[] message, byte[] pubkey, byte[] signature, NamedCurveHash curveHash) { try { - return Crypto.VerifySignature(message, signature, pubkey, curves[curve]); + var ch = s_curves[curveHash]; + return Crypto.VerifySignature(message, signature, pubkey, ch.Curve, ch.Hasher); } catch (ArgumentException) { diff --git a/src/Neo/SmartContract/Native/NamedCurve.cs b/src/Neo/SmartContract/Native/NamedCurve.cs index 9e97472cfc..8c7a9107e9 100644 --- a/src/Neo/SmartContract/Native/NamedCurve.cs +++ b/src/Neo/SmartContract/Native/NamedCurve.cs @@ -9,24 +9,30 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using System; + namespace Neo.SmartContract.Native { /// - /// Represents the named curve used in ECDSA. + /// Represents the named curve used in ECDSA. This enum is obsolete + /// and will be removed in future versions. Please, use an extended instead. /// /// /// https://tools.ietf.org/html/rfc4492#section-5.1.1 /// + [Obsolete("NamedCurve enum is obsolete and will be removed in future versions. Please, use an extended NamedCurveHash instead.")] public enum NamedCurve : byte { /// /// The secp256k1 curve. /// + [Obsolete("secp256k1 value is obsolete and will be removed in future versions. Please, use NamedCurveHash.secp256k1SHA256 for compatible behaviour.")] secp256k1 = 22, /// /// The secp256r1 curve, which known as prime256v1 or nistP-256. /// + [Obsolete("secp256r1 value is obsolete and will be removed in future versions. Please, use NamedCurveHash.secp256r1SHA256 for compatible behaviour.")] secp256r1 = 23 } } diff --git a/src/Neo/SmartContract/Native/NamedCurveHash.cs b/src/Neo/SmartContract/Native/NamedCurveHash.cs new file mode 100644 index 0000000000..8bd63bf874 --- /dev/null +++ b/src/Neo/SmartContract/Native/NamedCurveHash.cs @@ -0,0 +1,40 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// NamedCurveHash.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 +{ + /// + /// Represents a pair of the named curve used in ECDSA and a hash algorithm used to hash message. + /// This is a compatible extension of an obsolete enum. + /// + public enum NamedCurveHash : byte + { + /// + /// The secp256k1 curve and SHA256 hash algorithm. + /// + secp256k1SHA256 = 22, + + /// + /// The secp256r1 curve, which known as prime256v1 or nistP-256, and SHA256 hash algorithm. + /// + secp256r1SHA256 = 23, + + /// + /// The secp256k1 curve and Keccak256 hash algorithm. + /// + secp256k1Keccak256 = 122, + + /// + /// The secp256r1 curve, which known as prime256v1 or nistP-256, and Keccak256 hash algorithm. + /// + secp256r1Keccak256 = 123 + } +} diff --git a/tests/Neo.UnitTests/SmartContract/Native/UT_CryptoLib.cs b/tests/Neo.UnitTests/SmartContract/Native/UT_CryptoLib.cs index 6f150cca12..f65e061093 100644 --- a/tests/Neo.UnitTests/SmartContract/Native/UT_CryptoLib.cs +++ b/tests/Neo.UnitTests/SmartContract/Native/UT_CryptoLib.cs @@ -11,11 +11,20 @@ using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Cryptography; using Neo.Cryptography.BLS12_381; +using Neo.Cryptography.ECC; +using Neo.IO; +using Neo.Ledger; +using Neo.Network.P2P; +using Neo.Network.P2P.Payloads; using Neo.SmartContract; using Neo.SmartContract.Native; using Neo.VM; using Org.BouncyCastle.Utilities.Encoders; +using System; +using System.Collections.Generic; +using System.Linq; namespace Neo.UnitTests.SmartContract.Native { @@ -427,5 +436,474 @@ public void TestKeccak256_BlankString() // Assert Assert.AreEqual(expectedHashHex, outputHashHex, "Keccak256 hash did not match expected value for blank string."); } + + // TestVerifyWithECDsa_CustomTxWitness_SingleSig builds custom witness verification script for single Koblitz public key + // and ensures witness check is passed for the following message: + // + // keccak256([4-bytes-network-magic-LE, txHash-bytes-BE]) + // + // The proposed witness verification script has 110 bytes length, verification costs 2154270 * 10e-8GAS including Invocation script execution. + // The user has to sign the keccak256([4-bytes-network-magic-LE, txHash-bytes-BE]). + [TestMethod] + public void TestVerifyWithECDsa_CustomTxWitness_SingleSig() + { + byte[] privkey = "7177f0d04c79fa0b8c91fe90c1cf1d44772d1fba6e5eb9b281a22cd3aafb51fe".HexToBytes(); + ECPoint pubKey = ECPoint.Parse("04fd0a8c1ce5ae5570fdd46e7599c16b175bf0ebdfe9c178f1ab848fb16dac74a5d301b0534c7bcf1b3760881f0c420d17084907edd771e1c9c8e941bbf6ff9108", ECCurve.Secp256k1); + + // vrf is a builder of witness verification script corresponding to the public key. + using ScriptBuilder vrf = new(); + vrf.EmitPush((byte)NamedCurveHash.secp256k1Keccak256); // push Koblitz curve identifier and Keccak256 hasher. + vrf.Emit(OpCode.SWAP); // swap curve identifier with the signature. + vrf.EmitPush(pubKey.EncodePoint(true)); // emit the caller's public key. + + // Construct and push the signed message. The signed message is effectively the network-dependent transaction hash, + // i.e. msg = [4-network-magic-bytes-LE, tx-hash-BE] + // Firstly, retrieve network magic (it's uint32 wrapped into BigInteger and represented as Integer stackitem on stack). + vrf.EmitSysCall(ApplicationEngine.System_Runtime_GetNetwork); // push network magic (Integer stackitem), can have 0-5 bytes length serialized. + + // Convert network magic to 4-bytes-length LE byte array representation. + vrf.EmitPush(0x100000000); // push 0x100000000. + vrf.Emit(OpCode.ADD, // the result is some new number that is 5 bytes at least when serialized, but first 4 bytes are intact network value (LE). + OpCode.PUSH4, OpCode.LEFT); // cut the first 4 bytes out of a number that is at least 5 bytes long, the result is 4-bytes-length LE network representation. + + // Retrieve executing transaction hash. + vrf.EmitSysCall(ApplicationEngine.System_Runtime_GetScriptContainer); // push the script container (executing transaction, actually). + vrf.Emit(OpCode.PUSH0, OpCode.PICKITEM); // pick 0-th transaction item (the transaction hash). + + // Concatenate network magic and transaction hash. + vrf.Emit(OpCode.CAT); // this instruction will convert network magic to bytes using BigInteger rules of conversion. + + // Continue construction of 'verifyWithECDsa' call. + vrf.Emit(OpCode.PUSH4, OpCode.PACK); // pack arguments for 'verifyWithECDsa' call. + EmitAppCallNoArgs(vrf, CryptoLib.CryptoLib.Hash, "verifyWithECDsa", CallFlags.None); // emit the call to 'verifyWithECDsa' itself. + + // Account is a hash of verification script. + var vrfScript = vrf.ToArray(); + var acc = vrfScript.ToScriptHash(); + + var tx = new Transaction + { + Attributes = [], + NetworkFee = 1_0000_0000, + Nonce = (uint)Environment.TickCount, + Script = new byte[Transaction.MaxTransactionSize / 100], + Signers = [new Signer { Account = acc }], + SystemFee = 0, + ValidUntilBlock = 10, + Version = 0, + Witnesses = [] + }; + var tx_signature = Crypto.Sign(tx.GetSignData(TestBlockchain.TheNeoSystem.Settings.Network), privkey, ECCurve.Secp256k1, Hasher.Keccak256); + + // inv is a builder of witness invocation script corresponding to the public key. + using ScriptBuilder inv = new(); + inv.EmitPush(tx_signature); // push signature. + + tx.Witnesses = + [ + new Witness { InvocationScript = inv.ToArray(), VerificationScript = vrfScript } + ]; + + tx.VerifyStateIndependent(TestProtocolSettings.Default).Should().Be(VerifyResult.Succeed); + + var snapshot = TestBlockchain.GetTestSnapshot(); + + // Create fake balance to pay the fees. + ApplicationEngine 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(); + + var txVrfContext = new TransactionVerificationContext(); + var conflicts = new List(); + tx.VerifyStateDependent(TestProtocolSettings.Default, snapshot, txVrfContext, conflicts).Should().Be(VerifyResult.Succeed); + + // The resulting witness verification cost is 2154270 * 10e-8GAS. + // The resulting witness Invocation script (66 bytes length): + // NEO-VM > loadbase64 DEARoaaEjM/3VulrBDUod7eiZgWQS2iXIM0+I24iyJYmffhosZoQjfnnRymF/7+FaBPb9qvQwxLLSVo9ROlrdFdC + // READY: loaded 66 instructions + // NEO-VM 0 > ops + // INDEX OPCODE PARAMETER + // 0 PUSHDATA1 11a1a6848ccff756e96b04352877b7a26605904b689720cd3e236e22c896267df868b19a108df9e7472985ffbf856813dbf6abd0c312cb495a3d44e96b745742 << + // + // + // The resulting witness verificaiton script (110 bytes): + // NEO-VM 0 > loadbase64 ABhQDCEC/QqMHOWuVXD91G51mcFrF1vw69/pwXjxq4SPsW2sdKVBxfug4AMAAAAAAQAAAJ4UjUEtUQgwEM6LFMAfDA92ZXJpZnlXaXRoRUNEc2EMFBv1dasRiWiEE2EKNaEohs3gtmxyQWJ9W1I= + // READY: loaded 110 instructions + // NEO-VM 0 > pos + // Error: No help topic for 'pos' + // NEO-VM 0 > ops + // INDEX OPCODE PARAMETER + // 0 PUSHINT8 122 (7a) << + // 2 SWAP + // 3 PUSHDATA1 02fd0a8c1ce5ae5570fdd46e7599c16b175bf0ebdfe9c178f1ab848fb16dac74a5 + // 38 SYSCALL System.Runtime.GetNetwork (c5fba0e0) + // 43 PUSHINT64 4294967296 (0000000001000000) + // 52 ADD + // 53 PUSH4 + // 54 LEFT + // 55 SYSCALL System.Runtime.GetScriptContainer (2d510830) + // 60 PUSH0 + // 61 PICKITEM + // 62 CAT + // 63 PUSH4 + // 64 PACK + // 65 PUSH0 + // 66 PUSHDATA1 766572696679576974684543447361 ("verifyWithECDsa") + // 83 PUSHDATA1 1bf575ab1189688413610a35a12886cde0b66c72 ("NNToUmdQBe5n8o53BTzjTFAnSEcpouyy3B", "0x726cb6e0cd8628a1350a611384688911ab75f51b") + // 105 SYSCALL System.Contract.Call (627d5b52) + } + + // TestVerifyWithECDsa_CustomTxWitness_MultiSig builds custom multisignature witness verification script for Koblitz public keys + // and ensures witness check is passed for the M out of N multisignature of message: + // + // keccak256([4-bytes-network-magic-LE, txHash-bytes-BE]) + // + // The proposed witness verification script has 264 bytes length, verification costs 8390070 * 10e-8GAS including Invocation script execution. + // The users have to sign the keccak256([4-bytes-network-magic-LE, txHash-bytes-BE]). + [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)>() + { + (privkey1, pubKey1), + (privkey2, pubKey2), + (privkey3, pubKey3), + (privkey4, pubKey4), + }.OrderBy(k => k.Item2).ToList(); + + // Consider 4 users willing to sign 3/4 multisignature transaction with their Secp256k1 private keys. + var m = 3; + var n = keys.Count(); + + // Must ensure the following conditions are met before verification script construction: + n.Should().BeGreaterThan(0); + m.Should().BeLessThanOrEqualTo(n); + keys.Select(k => k.Item2).Distinct().Count().Should().Be(n); + + // In fact, the following algorithm is implemented via NeoVM instructions: + // + // func Check(sigs []interop.Signature) bool { + // if m != len(sigs) { + // return false + // } + // var pubs []interop.PublicKey = []interop.PublicKey{...} + // msg := append(convert.ToBytes(runtime.GetNetwork()), runtime.GetScriptContainer().Hash...) + // var sigCnt = 0 + // var pubCnt = 0 + // for ; sigCnt < m && pubCnt < n; { // sigs must be sorted by pub + // sigCnt += crypto.VerifyWithECDsa(msg, pubs[pubCnt], sigs[sigCnt], crypto.Secp256k1Keccak256) + // pubCnt++ + // } + // return sigCnt == m + // } + + // 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. + vrf.EmitPush(m); // push m. + foreach (var tuple in keys) + { + vrf.EmitPush(tuple.Item2.EncodePoint(true)); // push public keys in compressed form. + } + vrf.EmitPush(n); // push n. + + // Initialize slots for local variables. Locals slot scheme: + // LOC0 -> sigs + // LOC1 -> pubs + // LOC2 -> msg (ByteString) + // LOC3 -> sigCnt (Integer) + // LOC4 -> pubCnt (Integer) + // LOC5 -> n + // LOC6 -> m + vrf.Emit(OpCode.INITSLOT, new ReadOnlySpan([7, 0])); // 7 locals, no args. + + // Store n. + vrf.Emit(OpCode.STLOC5); + + // Pack public keys and store at LOC1. + vrf.Emit(OpCode.LDLOC5, // load n. + OpCode.PACK, OpCode.STLOC1); // pack pubs and store. + + // Store m. + vrf.Emit(OpCode.STLOC6); + + // Check the number of signatures is m. Abort the execution if not. + vrf.Emit(OpCode.DEPTH); // push the number of signatures onto stack. + vrf.Emit(OpCode.LDLOC6); // load m. + vrf.Emit(OpCode.JMPEQ, new ReadOnlySpan([0])); // here and below short jumps are sufficient. Offset will be filled later. + var sigsLenCheckEndOffset = vrf.Length; + vrf.Emit(OpCode.ABORT); // abort the execution if length of the signatures not equal to m. + + // Start the verification itself. + var checkStartOffset = vrf.Length; + + // Pack signatures and store at LOC0. + vrf.Emit(OpCode.LDLOC6); // load m. + vrf.Emit(OpCode.PACK, OpCode.STLOC0); + + // Get message and store it at LOC2. + // msg = [4-network-magic-bytes-LE, tx-hash-BE] + vrf.EmitSysCall(ApplicationEngine.System_Runtime_GetNetwork); // push network magic (Integer stackitem), can have 0-5 bytes length serialized. + // Convert network magic to 4-bytes-length LE byte array representation. + vrf.EmitPush(0x100000000); // push 0x100000000. + vrf.Emit(OpCode.ADD, // the result is some new number that is 5 bytes at least when serialized, but first 4 bytes are intact network value (LE). + OpCode.PUSH4, OpCode.LEFT); // cut the first 4 bytes out of a number that is at least 5 bytes long, the result is 4-bytes-length LE network representation. + // Retrieve executing transaction hash. + vrf.EmitSysCall(ApplicationEngine.System_Runtime_GetScriptContainer); // push the script container (executing transaction, actually). + vrf.Emit(OpCode.PUSH0, OpCode.PICKITEM); // pick 0-th transaction item (the transaction hash). + // Concatenate network magic and transaction hash. + vrf.Emit(OpCode.CAT); // this instruction will convert network magic to bytes using BigInteger rules of conversion. + vrf.Emit(OpCode.STLOC2); // store msg as a local variable #2. + + // Initialize local variables: sigCnt, pubCnt. + vrf.Emit(OpCode.PUSH0, OpCode.STLOC3, // initialize sigCnt. + OpCode.PUSH0, OpCode.STLOC4); // initialize pubCnt. + + // Loop condition check. + var loopStartOffset = vrf.Length; + vrf.Emit(OpCode.LDLOC3); // load sigCnt. + vrf.Emit(OpCode.LDLOC6); // load m. + vrf.Emit(OpCode.GE, // sigCnt >= m + OpCode.LDLOC4); // load pubCnt + vrf.Emit(OpCode.LDLOC5); // load n. + vrf.Emit(OpCode.GE, // pubCnt >= n + OpCode.OR); // sigCnt >= m || pubCnt >= n + vrf.Emit(OpCode.JMPIF, new ReadOnlySpan([0])); // jump to the end of the script if (sigCnt >= m || pubCnt >= n). + var loopConditionOffset = vrf.Length; + + // Loop start. Prepare arguments and call CryptoLib's verifyWithECDsa. + vrf.EmitPush((byte)NamedCurveHash.secp256k1Keccak256); // push Koblitz curve identifier and Keccak256 hasher. + vrf.Emit(OpCode.LDLOC0, // load signatures. + OpCode.LDLOC3, // load sigCnt. + OpCode.PICKITEM, // pick signature at index sigCnt. + OpCode.LDLOC1, // load pubs. + OpCode.LDLOC4, // load pubCnt. + OpCode.PICKITEM, // pick pub at index pubCnt. + OpCode.LDLOC2, // load msg. + OpCode.PUSH4, OpCode.PACK); // pack 4 arguments for 'verifyWithECDsa' call. + EmitAppCallNoArgs(vrf, CryptoLib.CryptoLib.Hash, "verifyWithECDsa", CallFlags.None); // emit the call to 'verifyWithECDsa' itself. + + // Update loop variables. + vrf.Emit(OpCode.LDLOC3, OpCode.ADD, OpCode.STLOC3, // increment sigCnt if signature is valid. + OpCode.LDLOC4, OpCode.INC, OpCode.STLOC4); // increment pubCnt. + + // End of the loop. + vrf.Emit(OpCode.JMP, new ReadOnlySpan([0])); // jump to the start of cycle. + var loopEndOffset = vrf.Length; + // Return condition: the number of valid signatures should be equal to m. + var progRetOffset = vrf.Length; + vrf.Emit(OpCode.LDLOC3); // load sigCnt. + vrf.Emit(OpCode.LDLOC6); // load m. + vrf.Emit(OpCode.NUMEQUAL); // push m == sigCnt. + + var vrfScript = vrf.ToArray(); + + // Set JMP* instructions offsets. "-1" is for short JMP parameter offset. JMP parameters + // are relative offsets. + vrfScript[sigsLenCheckEndOffset - 1] = (byte)(checkStartOffset - sigsLenCheckEndOffset + 2); + vrfScript[loopEndOffset - 1] = (byte)(loopStartOffset - loopEndOffset + 2); + vrfScript[loopConditionOffset - 1] = (byte)(progRetOffset - loopConditionOffset + 2); + + // Account is a hash of verification script. + var acc = vrfScript.ToScriptHash(); + + var tx = new Transaction + { + Attributes = [], + NetworkFee = 1_0000_0000, + Nonce = (uint)Environment.TickCount, + Script = new byte[Transaction.MaxTransactionSize / 100], + Signers = [new Signer { Account = acc }], + SystemFee = 0, + ValidUntilBlock = 10, + Version = 0, + Witnesses = [] + }; + // inv is a builder of witness invocation script corresponding to the public key. + using ScriptBuilder inv = new(); + for (var i = 0; i < n; i++) + { + if (i == 1) // Skip one key since we need only 3 signatures. + continue; + var sig = Crypto.Sign(tx.GetSignData(TestBlockchain.TheNeoSystem.Settings.Network), keys[i].Item1, ECCurve.Secp256k1, Hasher.Keccak256); + inv.EmitPush(sig); + } + + tx.Witnesses = + [ + new Witness { InvocationScript = inv.ToArray(), VerificationScript = vrfScript } + ]; + + tx.VerifyStateIndependent(TestProtocolSettings.Default).Should().Be(VerifyResult.Succeed); + + var snapshot = TestBlockchain.GetTestSnapshot(); + + // Create fake balance to pay the fees. + ApplicationEngine 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(); + + // Check that witness verification passes. + var txVrfContext = new TransactionVerificationContext(); + var conflicts = new List(); + tx.VerifyStateDependent(TestProtocolSettings.Default, snapshot, 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): + // NEO-VM 0 > loadbase64 DEDM23XByPvDK9XRAHRhfGH7/Mp5jdaci3/GpTZ3D9SZx2Zw89tAaOtmQSIutXbCxRQA1kSeUD4AteJGoNXFhFzIDECgeHoey0rYdlFyTVfDJSsuS+VwzC5OtYGCVR2V/MttmLXWA/FWZH/MjmU0obgQXa9zoBxqYQUUJKefivZFxVcTDEAZT6L6ZFybeXbm8+RlVNS7KshusT54d2ImQ6vFvxETphhJOwcQ0yNL6qJKsrLAKAnzicY4az3ct0G35mI17/gQ + // READY: loaded 198 instructions + // NEO-VM 0 > ops + // INDEX OPCODE PARAMETER + // 0 PUSHDATA1 ccdb75c1c8fbc32bd5d10074617c61fbfcca798dd69c8b7fc6a536770fd499c76670f3db4068eb6641222eb576c2c51400d6449e503e00b5e246a0d5c5845cc8 << + // 66 PUSHDATA1 a0787a1ecb4ad87651724d57c3252b2e4be570cc2e4eb58182551d95fccb6d98b5d603f156647fcc8e6534a1b8105daf73a01c6a61051424a79f8af645c55713 + // 132 PUSHDATA1 194fa2fa645c9b7976e6f3e46554d4bb2ac86eb13e7877622643abc5bf1113a618493b0710d3234beaa24ab2b2c02809f389c6386b3ddcb741b7e66235eff810 + // + // + // Resulting witness verification script (266 bytes for 3/4 multisig): + // NEO-VM 0 > loadbase64 EwwhAwSGRoaDwRISWXj/6HYkWyAGv+c5rKhTm2czUHkmLLJ6DCEDDSb8KtOxquIPBAtfgzgGcPjvXCsqySG6O915/QrwUlEMIQN7TnKuhUtqCVWz4C2SZRq3+mQak2Bmd2rUOPlbtnSiaQwhArYqxMijUqiS/s6xjX4uOmLIwey6rlUj2J10ewIZJ24iFFcHAHVtwHF2Q24oAzhuwHBBxfug4AMAAAAAAQAAAJ4UjUEtUQgwEM6LchBzEHRrbrhsbbiSJEIAGGhrzmlszmoUwB8MD3ZlcmlmeVdpdGhFQ0RzYQwUG/V1qxGJaIQTYQo1oSiGzeC2bHJBYn1bUmuec2ycdCK5a26z + // READY: loaded 264 instructions + // NEO-VM 0 > ops + // INDEX OPCODE PARAMETER + // 0 PUSH3 << + // 1 PUSHDATA1 030486468683c112125978ffe876245b2006bfe739aca8539b67335079262cb27a + // 36 PUSHDATA1 030d26fc2ad3b1aae20f040b5f83380670f8ef5c2b2ac921ba3bdd79fd0af05251 + // 71 PUSHDATA1 037b4e72ae854b6a0955b3e02d92651ab7fa641a936066776ad438f95bb674a269 + // 106 PUSHDATA1 02b62ac4c8a352a892feceb18d7e2e3a62c8c1ecbaae5523d89d747b0219276e22 + // 141 PUSH4 + // 142 INITSLOT 7 local, 0 arg + // 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 + // 158 SYSCALL System.Runtime.GetNetwork (c5fba0e0) + // 163 PUSHINT64 4294967296 (0000000001000000) + // 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 + // 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 + // 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 + // 259 JMP 188 (-71/b9) + // 261 LDLOC3 + // 262 LDLOC6 + // 263 NUMEQUAL + } + + // EmitAppCallNoArgs is a helper method that emits all parameters of System.Contract.Call interop + // except the method arguments. + private static ScriptBuilder EmitAppCallNoArgs(ScriptBuilder builder, UInt160 contractHash, string method, CallFlags f) + { + builder.EmitPush((byte)f); + builder.EmitPush(method); + builder.EmitPush(contractHash); + builder.EmitSysCall(ApplicationEngine.System_Contract_Call); + return builder; + } + + [TestMethod] + public void TestVerifyWithECDsa() + { + byte[] privR1 = "6e63fda41e9e3aba9bb5696d58a75731f044a9bdc48fe546da571543b2fa460e".HexToBytes(); + ECPoint pubR1 = ECPoint.Parse("04cae768e1cf58d50260cab808da8d6d83d5d3ab91eac41cdce577ce5862d736413643bdecd6d21c3b66f122ab080f9219204b10aa8bbceb86c1896974768648f3", ECCurve.Secp256r1); + byte[] privK1 = "0b5fb3a050385196b327be7d86cbce6e40a04c8832445af83ad19c82103b3ed9".HexToBytes(); + ECPoint pubK1 = ECPoint.Parse("04b6363b353c3ee1620c5af58594458aa00abf43a6d134d7c4cb2d901dc0f474fd74c94740bd7169aa0b1ef7bc657e824b1d7f4283c547e7ec18c8576acf84418a", ECCurve.Secp256k1); + byte[] message = System.Text.Encoding.Default.GetBytes("HelloWorld"); + + // secp256r1 + SHA256 + byte[] signature = Crypto.Sign(message, privR1, ECCurve.Secp256r1, Hasher.SHA256); + Crypto.VerifySignature(message, signature, pubR1).Should().BeTrue(); // SHA256 hash is used by default. + CallVerifyWithECDsa(message, pubR1, signature, NamedCurveHash.secp256r1SHA256).Should().Be(true); + + // secp256r1 + Keccak256 + signature = Crypto.Sign(message, privR1, ECCurve.Secp256r1, Hasher.Keccak256); + Crypto.VerifySignature(message, signature, pubR1, Hasher.Keccak256).Should().BeTrue(); + CallVerifyWithECDsa(message, pubR1, signature, NamedCurveHash.secp256r1Keccak256).Should().Be(true); + + // secp256k1 + SHA256 + signature = Crypto.Sign(message, privK1, ECCurve.Secp256k1, Hasher.SHA256); + Crypto.VerifySignature(message, signature, pubK1).Should().BeTrue(); // SHA256 hash is used by default. + CallVerifyWithECDsa(message, pubK1, signature, NamedCurveHash.secp256k1SHA256).Should().Be(true); + + // secp256k1 + Keccak256 + signature = Crypto.Sign(message, privK1, ECCurve.Secp256k1, Hasher.Keccak256); + Crypto.VerifySignature(message, signature, pubK1, Hasher.Keccak256).Should().BeTrue(); + CallVerifyWithECDsa(message, pubK1, signature, NamedCurveHash.secp256k1Keccak256).Should().Be(true); + } + + private bool CallVerifyWithECDsa(byte[] message, ECPoint pub, byte[] signature, NamedCurveHash curveHash) + { + var snapshot = TestBlockchain.GetTestSnapshot(); + using (ScriptBuilder script = new()) + { + script.EmitPush((int)curveHash); + script.EmitPush(signature); + script.EmitPush(pub.EncodePoint(true)); + script.EmitPush(message); + script.EmitPush(4); + script.Emit(OpCode.PACK); + script.EmitPush(CallFlags.All); + script.EmitPush("verifyWithECDsa"); + script.EmitPush(NativeContract.CryptoLib.Hash); + script.EmitSysCall(ApplicationEngine.System_Contract_Call); + + using var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, settings: TestBlockchain.TheNeoSystem.Settings); + engine.LoadScript(script.ToArray()); + Assert.AreEqual(VMState.HALT, engine.Execute()); + return engine.ResultStack.Pop().GetBoolean(); + } + } } } diff --git a/tests/Neo.UnitTests/SmartContract/Native/UT_NativeContract.cs b/tests/Neo.UnitTests/SmartContract/Native/UT_NativeContract.cs index 181ff139ec..d7be3b4dcd 100644 --- a/tests/Neo.UnitTests/SmartContract/Native/UT_NativeContract.cs +++ b/tests/Neo.UnitTests/SmartContract/Native/UT_NativeContract.cs @@ -42,7 +42,7 @@ public void TestSetup() { {"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}}""" }, {"StdLib", """{"id":-2,"updatecounter":0,"hash":"0xacce6fd80d44e1796aa0c2c625e9e4e0ce39efc0","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dA","checksum":1991619121},"manifest":{"name":"StdLib","groups":[],"features":{},"supportedstandards":[],"abi":{"methods":[{"name":"atoi","parameters":[{"name":"value","type":"String"}],"returntype":"Integer","offset":0,"safe":true},{"name":"atoi","parameters":[{"name":"value","type":"String"},{"name":"base","type":"Integer"}],"returntype":"Integer","offset":7,"safe":true},{"name":"base58CheckDecode","parameters":[{"name":"s","type":"String"}],"returntype":"ByteArray","offset":14,"safe":true},{"name":"base58CheckEncode","parameters":[{"name":"data","type":"ByteArray"}],"returntype":"String","offset":21,"safe":true},{"name":"base58Decode","parameters":[{"name":"s","type":"String"}],"returntype":"ByteArray","offset":28,"safe":true},{"name":"base58Encode","parameters":[{"name":"data","type":"ByteArray"}],"returntype":"String","offset":35,"safe":true},{"name":"base64Decode","parameters":[{"name":"s","type":"String"}],"returntype":"ByteArray","offset":42,"safe":true},{"name":"base64Encode","parameters":[{"name":"data","type":"ByteArray"}],"returntype":"String","offset":49,"safe":true},{"name":"deserialize","parameters":[{"name":"data","type":"ByteArray"}],"returntype":"Any","offset":56,"safe":true},{"name":"itoa","parameters":[{"name":"value","type":"Integer"}],"returntype":"String","offset":63,"safe":true},{"name":"itoa","parameters":[{"name":"value","type":"Integer"},{"name":"base","type":"Integer"}],"returntype":"String","offset":70,"safe":true},{"name":"jsonDeserialize","parameters":[{"name":"json","type":"ByteArray"}],"returntype":"Any","offset":77,"safe":true},{"name":"jsonSerialize","parameters":[{"name":"item","type":"Any"}],"returntype":"ByteArray","offset":84,"safe":true},{"name":"memoryCompare","parameters":[{"name":"str1","type":"ByteArray"},{"name":"str2","type":"ByteArray"}],"returntype":"Integer","offset":91,"safe":true},{"name":"memorySearch","parameters":[{"name":"mem","type":"ByteArray"},{"name":"value","type":"ByteArray"}],"returntype":"Integer","offset":98,"safe":true},{"name":"memorySearch","parameters":[{"name":"mem","type":"ByteArray"},{"name":"value","type":"ByteArray"},{"name":"start","type":"Integer"}],"returntype":"Integer","offset":105,"safe":true},{"name":"memorySearch","parameters":[{"name":"mem","type":"ByteArray"},{"name":"value","type":"ByteArray"},{"name":"start","type":"Integer"},{"name":"backward","type":"Boolean"}],"returntype":"Integer","offset":112,"safe":true},{"name":"serialize","parameters":[{"name":"item","type":"Any"}],"returntype":"ByteArray","offset":119,"safe":true},{"name":"strLen","parameters":[{"name":"str","type":"String"}],"returntype":"Integer","offset":126,"safe":true},{"name":"stringSplit","parameters":[{"name":"str","type":"String"},{"name":"separator","type":"String"}],"returntype":"Array","offset":133,"safe":true},{"name":"stringSplit","parameters":[{"name":"str","type":"String"},{"name":"separator","type":"String"},{"name":"removeEmptyEntries","type":"Boolean"}],"returntype":"Array","offset":140,"safe":true}],"events":[]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"extra":null}}"""}, - {"CryptoLib", """{"id":-3,"updatecounter":0,"hash":"0x726cb6e0cd8628a1350a611384688911ab75f51b","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0A=","checksum":1094259016},"manifest":{"name":"CryptoLib","groups":[],"features":{},"supportedstandards":[],"abi":{"methods":[{"name":"bls12381Add","parameters":[{"name":"x","type":"InteropInterface"},{"name":"y","type":"InteropInterface"}],"returntype":"InteropInterface","offset":0,"safe":true},{"name":"bls12381Deserialize","parameters":[{"name":"data","type":"ByteArray"}],"returntype":"InteropInterface","offset":7,"safe":true},{"name":"bls12381Equal","parameters":[{"name":"x","type":"InteropInterface"},{"name":"y","type":"InteropInterface"}],"returntype":"Boolean","offset":14,"safe":true},{"name":"bls12381Mul","parameters":[{"name":"x","type":"InteropInterface"},{"name":"mul","type":"ByteArray"},{"name":"neg","type":"Boolean"}],"returntype":"InteropInterface","offset":21,"safe":true},{"name":"bls12381Pairing","parameters":[{"name":"g1","type":"InteropInterface"},{"name":"g2","type":"InteropInterface"}],"returntype":"InteropInterface","offset":28,"safe":true},{"name":"bls12381Serialize","parameters":[{"name":"g","type":"InteropInterface"}],"returntype":"ByteArray","offset":35,"safe":true},{"name":"keccak256","parameters":[{"name":"data","type":"ByteArray"}],"returntype":"ByteArray","offset":42,"safe":true},{"name":"murmur32","parameters":[{"name":"data","type":"ByteArray"},{"name":"seed","type":"Integer"}],"returntype":"ByteArray","offset":49,"safe":true},{"name":"ripemd160","parameters":[{"name":"data","type":"ByteArray"}],"returntype":"ByteArray","offset":56,"safe":true},{"name":"sha256","parameters":[{"name":"data","type":"ByteArray"}],"returntype":"ByteArray","offset":63,"safe":true},{"name":"verifyWithECDsa","parameters":[{"name":"message","type":"ByteArray"},{"name":"pubkey","type":"ByteArray"},{"name":"signature","type":"ByteArray"},{"name":"curve","type":"Integer"}],"returntype":"Boolean","offset":70,"safe":true}],"events":[]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"extra":null}}"""}, + {"CryptoLib", """{"id":-3,"updatecounter":0,"hash":"0x726cb6e0cd8628a1350a611384688911ab75f51b","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0A=","checksum":1094259016},"manifest":{"name":"CryptoLib","groups":[],"features":{},"supportedstandards":[],"abi":{"methods":[{"name":"bls12381Add","parameters":[{"name":"x","type":"InteropInterface"},{"name":"y","type":"InteropInterface"}],"returntype":"InteropInterface","offset":0,"safe":true},{"name":"bls12381Deserialize","parameters":[{"name":"data","type":"ByteArray"}],"returntype":"InteropInterface","offset":7,"safe":true},{"name":"bls12381Equal","parameters":[{"name":"x","type":"InteropInterface"},{"name":"y","type":"InteropInterface"}],"returntype":"Boolean","offset":14,"safe":true},{"name":"bls12381Mul","parameters":[{"name":"x","type":"InteropInterface"},{"name":"mul","type":"ByteArray"},{"name":"neg","type":"Boolean"}],"returntype":"InteropInterface","offset":21,"safe":true},{"name":"bls12381Pairing","parameters":[{"name":"g1","type":"InteropInterface"},{"name":"g2","type":"InteropInterface"}],"returntype":"InteropInterface","offset":28,"safe":true},{"name":"bls12381Serialize","parameters":[{"name":"g","type":"InteropInterface"}],"returntype":"ByteArray","offset":35,"safe":true},{"name":"keccak256","parameters":[{"name":"data","type":"ByteArray"}],"returntype":"ByteArray","offset":42,"safe":true},{"name":"murmur32","parameters":[{"name":"data","type":"ByteArray"},{"name":"seed","type":"Integer"}],"returntype":"ByteArray","offset":49,"safe":true},{"name":"ripemd160","parameters":[{"name":"data","type":"ByteArray"}],"returntype":"ByteArray","offset":56,"safe":true},{"name":"sha256","parameters":[{"name":"data","type":"ByteArray"}],"returntype":"ByteArray","offset":63,"safe":true},{"name":"verifyWithECDsa","parameters":[{"name":"message","type":"ByteArray"},{"name":"pubkey","type":"ByteArray"},{"name":"signature","type":"ByteArray"},{"name":"curveHash","type":"Integer"}],"returntype":"Boolean","offset":70,"safe":true}],"events":[]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"extra":null}}"""}, {"LedgerContract", """{"id":-4,"updatecounter":0,"hash":"0xda65b600f7124ce6c79950c1772a36403104f2be","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0A=","checksum":1110259869},"manifest":{"name":"LedgerContract","groups":[],"features":{},"supportedstandards":[],"abi":{"methods":[{"name":"currentHash","parameters":[],"returntype":"Hash256","offset":0,"safe":true},{"name":"currentIndex","parameters":[],"returntype":"Integer","offset":7,"safe":true},{"name":"getBlock","parameters":[{"name":"indexOrHash","type":"ByteArray"}],"returntype":"Array","offset":14,"safe":true},{"name":"getTransaction","parameters":[{"name":"hash","type":"Hash256"}],"returntype":"Array","offset":21,"safe":true},{"name":"getTransactionFromBlock","parameters":[{"name":"blockIndexOrHash","type":"ByteArray"},{"name":"txIndex","type":"Integer"}],"returntype":"Array","offset":28,"safe":true},{"name":"getTransactionHeight","parameters":[{"name":"hash","type":"Hash256"}],"returntype":"Integer","offset":35,"safe":true},{"name":"getTransactionSigners","parameters":[{"name":"hash","type":"Hash256"}],"returntype":"Array","offset":42,"safe":true},{"name":"getTransactionVMState","parameters":[{"name":"hash","type":"Hash256"}],"returntype":"Integer","offset":49,"safe":true}],"events":[]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"extra":null}}"""}, {"NeoToken", """{"id":-5,"updatecounter":0,"hash":"0xef4073a0f2b305a38ec4050e4d3d28bc40ea63f5","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0A=","checksum":1325686241},"manifest":{"name":"NeoToken","groups":[],"features":{},"supportedstandards":["NEP-17"],"abi":{"methods":[{"name":"balanceOf","parameters":[{"name":"account","type":"Hash160"}],"returntype":"Integer","offset":0,"safe":true},{"name":"decimals","parameters":[],"returntype":"Integer","offset":7,"safe":true},{"name":"getAccountState","parameters":[{"name":"account","type":"Hash160"}],"returntype":"Array","offset":14,"safe":true},{"name":"getAllCandidates","parameters":[],"returntype":"InteropInterface","offset":21,"safe":true},{"name":"getCandidateVote","parameters":[{"name":"pubKey","type":"PublicKey"}],"returntype":"Integer","offset":28,"safe":true},{"name":"getCandidates","parameters":[],"returntype":"Array","offset":35,"safe":true},{"name":"getCommittee","parameters":[],"returntype":"Array","offset":42,"safe":true},{"name":"getCommitteeAddress","parameters":[],"returntype":"Hash160","offset":49,"safe":true},{"name":"getGasPerBlock","parameters":[],"returntype":"Integer","offset":56,"safe":true},{"name":"getNextBlockValidators","parameters":[],"returntype":"Array","offset":63,"safe":true},{"name":"getRegisterPrice","parameters":[],"returntype":"Integer","offset":70,"safe":true},{"name":"registerCandidate","parameters":[{"name":"pubkey","type":"PublicKey"}],"returntype":"Boolean","offset":77,"safe":false},{"name":"setGasPerBlock","parameters":[{"name":"gasPerBlock","type":"Integer"}],"returntype":"Void","offset":84,"safe":false},{"name":"setRegisterPrice","parameters":[{"name":"registerPrice","type":"Integer"}],"returntype":"Void","offset":91,"safe":false},{"name":"symbol","parameters":[],"returntype":"String","offset":98,"safe":true},{"name":"totalSupply","parameters":[],"returntype":"Integer","offset":105,"safe":true},{"name":"transfer","parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"},{"name":"data","type":"Any"}],"returntype":"Boolean","offset":112,"safe":false},{"name":"unclaimedGas","parameters":[{"name":"account","type":"Hash160"},{"name":"end","type":"Integer"}],"returntype":"Integer","offset":119,"safe":true},{"name":"unregisterCandidate","parameters":[{"name":"pubkey","type":"PublicKey"}],"returntype":"Boolean","offset":126,"safe":false},{"name":"vote","parameters":[{"name":"account","type":"Hash160"},{"name":"voteTo","type":"PublicKey"}],"returntype":"Boolean","offset":133,"safe":false}],"events":[{"name":"Transfer","parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"}]},{"name":"CandidateStateChanged","parameters":[{"name":"pubkey","type":"PublicKey"},{"name":"registered","type":"Boolean"},{"name":"votes","type":"Integer"}]},{"name":"Vote","parameters":[{"name":"account","type":"Hash160"},{"name":"from","type":"PublicKey"},{"name":"to","type":"PublicKey"},{"name":"amount","type":"Integer"}]},{"name":"CommitteeChanged","parameters":[{"name":"old","type":"Array"},{"name":"new","type":"Array"}]}]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"extra":null}}"""}, {"GasToken", """{"id":-6,"updatecounter":0,"hash":"0xd2a4cff31913016155e38e474a2c06d08be276cf","nef":{"magic":860243278,"compiler":"neo-core-v3.0","source":"","tokens":[],"script":"EEEa93tnQBBBGvd7Z0AQQRr3e2dAEEEa93tnQBBBGvd7Z0A=","checksum":2663858513},"manifest":{"name":"GasToken","groups":[],"features":{},"supportedstandards":["NEP-17"],"abi":{"methods":[{"name":"balanceOf","parameters":[{"name":"account","type":"Hash160"}],"returntype":"Integer","offset":0,"safe":true},{"name":"decimals","parameters":[],"returntype":"Integer","offset":7,"safe":true},{"name":"symbol","parameters":[],"returntype":"String","offset":14,"safe":true},{"name":"totalSupply","parameters":[],"returntype":"Integer","offset":21,"safe":true},{"name":"transfer","parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"},{"name":"data","type":"Any"}],"returntype":"Boolean","offset":28,"safe":false}],"events":[{"name":"Transfer","parameters":[{"name":"from","type":"Hash160"},{"name":"to","type":"Hash160"},{"name":"amount","type":"Integer"}]}]},"permissions":[{"contract":"*","methods":"*"}],"trusts":[],"extra":null}}"""}, From 1e6404b2a300f28597bee3326d74485f367fd400 Mon Sep 17 00:00:00 2001 From: Shargon Date: Thu, 9 May 2024 19:41:47 -0700 Subject: [PATCH 123/168] Perform native contract initialization for the set of hardforks (#3202) * Close https://github.com/neo-project/neo/issues/3200 * Anna's review * All Hfs when genesis * fix * Update src/Neo/SmartContract/Native/NativeContract.cs Co-authored-by: Anna Shaleva * possible fix * always Initialize with null * Revert "always Initialize with null" This reverts commit 68c285cd97395ca73c4e41ee75998014df103fbd. * Call with null during deploy * Update src/Neo/SmartContract/Native/ContractManagement.cs Co-authored-by: Anna Shaleva * Update src/Neo/SmartContract/Native/ContractManagement.cs Co-authored-by: Anna Shaleva * Update src/Neo/SmartContract/Native/ContractManagement.cs Co-authored-by: Anna Shaleva * Native: adjust failing TestIsInitializeBlock According to new logic, an empty set of hard-forks will be returned in case of genesis initialization with all hardforks disabled. Ref. https://github.com/neo-project/neo/pull/3202#discussion_r1590270244. Signed-off-by: Anna Shaleva --------- Signed-off-by: Anna Shaleva Co-authored-by: Anna Shaleva Co-authored-by: Jimmy --- .../Native/ContractManagement.cs | 20 +++++++++-- .../SmartContract/Native/NativeContract.cs | 34 ++++++++++++------- .../SmartContract/Native/UT_NativeContract.cs | 6 ++-- 3 files changed, 43 insertions(+), 17 deletions(-) diff --git a/src/Neo/SmartContract/Native/ContractManagement.cs b/src/Neo/SmartContract/Native/ContractManagement.cs index e326421f91..e7a7e122f2 100644 --- a/src/Neo/SmartContract/Native/ContractManagement.cs +++ b/src/Neo/SmartContract/Native/ContractManagement.cs @@ -70,7 +70,7 @@ internal override async ContractTask OnPersistAsync(ApplicationEngine engine) { foreach (NativeContract contract in Contracts) { - if (contract.IsInitializeBlock(engine.ProtocolSettings, engine.PersistingBlock.Index, out Hardfork? hf)) + 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)); @@ -80,6 +80,13 @@ internal override async ContractTask OnPersistAsync(ApplicationEngine engine) // 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())); + + // 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. + if (contract.ActiveIn is null) + { + await contract.InitializeAsync(engine, null); + } } else { @@ -92,7 +99,16 @@ internal override async ContractTask OnPersistAsync(ApplicationEngine engine) oldContract.Manifest = contractState.Manifest; } - await contract.InitializeAsync(engine, hf); + // Initialize native contract for all hardforks that are active starting from the persisting block. + // If the contract is active starting from some non-nil hardfork, then this hardfork is also included into hfs. + if (hfs?.Length > 0) + { + foreach (var hf in hfs) + { + await contract.InitializeAsync(engine, hf); + } + } + // Emit native contract notification engine.SendNotification(Hash, state is null ? "Deploy" : "Update", new VM.Types.Array(engine.ReferenceCounter) { contract.Hash.ToArray() }); } diff --git a/src/Neo/SmartContract/Native/NativeContract.cs b/src/Neo/SmartContract/Native/NativeContract.cs index bde1f8ac00..70f67de538 100644 --- a/src/Neo/SmartContract/Native/NativeContract.cs +++ b/src/Neo/SmartContract/Native/NativeContract.cs @@ -266,19 +266,14 @@ protected virtual void OnManifestCompose(ContractManifest manifest) { } /// /// The where the HardForks are configured. /// Block index - /// Active hardfork + /// Active hardforks /// True if the native contract must be initialized - internal bool IsInitializeBlock(ProtocolSettings settings, uint index, out Hardfork? hardfork) + internal bool IsInitializeBlock(ProtocolSettings settings, uint index, out Hardfork[] hardforks) { - // If is not configured, the Genesis is the a initialized block - if (index == 0 && ActiveIn is null) - { - hardfork = null; - return true; - } + var hfs = new List(); - // If is in the hardfork height, return true - foreach (Hardfork hf in usedHardforks) + // If is in the hardfork height, add them to return array + foreach (var hf in usedHardforks) { if (!settings.Hardforks.TryGetValue(hf, out var activeIn)) { @@ -288,13 +283,26 @@ internal bool IsInitializeBlock(ProtocolSettings settings, uint index, out Hardf if (activeIn == index) { - hardfork = hf; - return true; + hfs.Add(hf); } } + // Return all initialize hardforks + if (hfs.Count > 0) + { + hardforks = hfs.ToArray(); + return true; + } + + // If is not configured, the Genesis is an initialization block. + if (index == 0 && ActiveIn is null) + { + hardforks = hfs.ToArray(); + return true; + } + // Initialized not required - hardfork = null; + hardforks = null; return false; } diff --git a/tests/Neo.UnitTests/SmartContract/Native/UT_NativeContract.cs b/tests/Neo.UnitTests/SmartContract/Native/UT_NativeContract.cs index d7be3b4dcd..1989b4323b 100644 --- a/tests/Neo.UnitTests/SmartContract/Native/UT_NativeContract.cs +++ b/tests/Neo.UnitTests/SmartContract/Native/UT_NativeContract.cs @@ -75,13 +75,15 @@ public void TestIsInitializeBlock() File.Delete(file); Assert.IsTrue(NativeContract.CryptoLib.IsInitializeBlock(settings, 0, out var hf)); - Assert.IsNull(hf); + Assert.IsNotNull(hf); + Assert.AreEqual(0, hf.Length); Assert.IsFalse(NativeContract.CryptoLib.IsInitializeBlock(settings, 1, out hf)); Assert.IsNull(hf); Assert.IsTrue(NativeContract.CryptoLib.IsInitializeBlock(settings, 20, out hf)); - Assert.AreEqual(Hardfork.HF_Cockatrice, hf); + Assert.AreEqual(1, hf.Length); + Assert.AreEqual(Hardfork.HF_Cockatrice, hf[0]); } [TestMethod] From d713d2bc30ed22fd20620fd84ab72b58d6b93dd6 Mon Sep 17 00:00:00 2001 From: Shargon Date: Thu, 9 May 2024 19:47:05 -0700 Subject: [PATCH 124/168] Fix signers `IInteroperable.ToStackItem` (#3221) * Fix signers * roma's feedback --------- Co-authored-by: NGD Admin <154295625+NGDAdmin@users.noreply.github.com> --- src/Neo/Network/P2P/Payloads/Signer.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Neo/Network/P2P/Payloads/Signer.cs b/src/Neo/Network/P2P/Payloads/Signer.cs index 9a68640880..79065408f4 100644 --- a/src/Neo/Network/P2P/Payloads/Signer.cs +++ b/src/Neo/Network/P2P/Payloads/Signer.cs @@ -192,14 +192,14 @@ void IInteroperable.FromStackItem(VM.Types.StackItem stackItem) VM.Types.StackItem IInteroperable.ToStackItem(ReferenceCounter referenceCounter) { - return new VM.Types.Array(referenceCounter, new VM.Types.StackItem[] - { + return new VM.Types.Array(referenceCounter, + [ Account.ToArray(), (byte)Scopes, - new VM.Types.Array(referenceCounter, AllowedContracts.Select(u => new VM.Types.ByteString(u.ToArray()))), - new VM.Types.Array(referenceCounter, AllowedGroups.Select(u => new VM.Types.ByteString(u.ToArray()))), - new VM.Types.Array(referenceCounter, Rules.Select(u => u.ToStackItem(referenceCounter))) - }); + Scopes.HasFlag(WitnessScope.CustomContracts) ? new VM.Types.Array(referenceCounter, AllowedContracts.Select(u => new VM.Types.ByteString(u.ToArray()))) : new VM.Types.Array(referenceCounter), + Scopes.HasFlag(WitnessScope.CustomGroups) ? new VM.Types.Array(referenceCounter, AllowedGroups.Select(u => new VM.Types.ByteString(u.ToArray()))) : new VM.Types.Array(referenceCounter), + Scopes.HasFlag(WitnessScope.WitnessRules) ? new VM.Types.Array(referenceCounter, Rules.Select(u => u.ToStackItem(referenceCounter))) : new VM.Types.Array(referenceCounter) + ]); } } } From bc86f6a500bc98f7f7f86118f354312a3801bfb0 Mon Sep 17 00:00:00 2001 From: Owen <38493437+superboyiii@users.noreply.github.com> Date: Fri, 10 May 2024 16:21:05 +0800 Subject: [PATCH 125/168] v3.7.0 (#3222) --- README.md | 4 ++-- src/Directory.Build.props | 4 ++-- src/Neo.CLI/Dockerfile | 6 +++--- src/Neo.CLI/config.json | 3 ++- src/Neo.CLI/config.mainnet.json | 3 ++- src/Neo.CLI/config.testnet.json | 3 ++- src/Neo.GUI/GUI/BulkPayDialog.Designer.cs | 2 +- src/Neo.GUI/GUI/ChangePasswordDialog.Designer.cs | 2 +- src/Neo.GUI/GUI/ConsoleForm.Designer.cs | 8 ++++---- src/Neo.GUI/GUI/CreateMultiSigContractDialog.Designer.cs | 2 +- src/Neo.GUI/GUI/CreateWalletDialog.designer.cs | 2 +- src/Neo.GUI/GUI/DeployContractDialog.Designer.cs | 2 +- src/Neo.GUI/GUI/DeveloperToolsForm.Designer.cs | 2 +- src/Neo.GUI/GUI/ElectionDialog.Designer.cs | 2 +- src/Neo.GUI/GUI/ImportCustomContractDialog.Designer.cs | 2 +- src/Neo.GUI/GUI/ImportPrivateKeyDialog.designer.cs | 2 +- src/Neo.GUI/GUI/InformationBox.Designer.cs | 2 +- src/Neo.GUI/GUI/InputBox.Designer.cs | 2 +- src/Neo.GUI/GUI/InvokeContractDialog.Designer.cs | 2 +- src/Neo.GUI/GUI/MainForm.Designer.cs | 2 +- src/Neo.GUI/GUI/OpenWalletDialog.designer.cs | 2 +- src/Neo.GUI/GUI/ParametersEditor.Designer.cs | 2 +- src/Neo.GUI/GUI/PayToDialog.Designer.cs | 2 +- src/Neo.GUI/GUI/SigningDialog.Designer.cs | 2 +- src/Neo.GUI/GUI/SigningTxDialog.Designer.cs | 2 +- src/Neo.GUI/GUI/TransferDialog.Designer.cs | 2 +- src/Neo.GUI/GUI/TxOutListBox.Designer.cs | 2 +- src/Neo.GUI/GUI/UpdateDialog.Designer.cs | 2 +- src/Neo.GUI/GUI/ViewContractDialog.Designer.cs | 2 +- src/Neo.GUI/GUI/ViewPrivateKeyDialog.designer.cs | 2 +- src/Neo.GUI/GUI/VotingDialog.Designer.cs | 2 +- 31 files changed, 41 insertions(+), 38 deletions(-) diff --git a/README.md b/README.md index 37d1f00827..407bd6a837 100644 --- a/README.md +++ b/README.md @@ -105,8 +105,8 @@ ## Overview This repository contain main classes of the -[Neo](https://www.neo.org) blockchain. -Visit the [documentation](https://docs.neo.org/docs/en-us/index.html) to get started. +[Neo](https://neo.org) blockchain. +Visit the [tutorials](https://developers.neo.org) to get started. ## Project structure diff --git a/src/Directory.Build.props b/src/Directory.Build.props index b04d3d34ae..18f77050d5 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -2,8 +2,8 @@ - 2015-2023 The Neo Project - 3.6.2 + 2015-2024 The Neo Project + 3.7.0 12.0 The Neo Project neo.png diff --git a/src/Neo.CLI/Dockerfile b/src/Neo.CLI/Dockerfile index 7b67a6812d..5863e9a74d 100644 --- a/src/Neo.CLI/Dockerfile +++ b/src/Neo.CLI/Dockerfile @@ -1,13 +1,13 @@ -FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:7.0 AS Build +FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0 AS Build # Run this from the repository root folder COPY src . COPY NuGet.Config /Neo.CLI WORKDIR /Neo.CLI -RUN dotnet restore && dotnet publish -f net7.0 -c Release -o /app +RUN dotnet restore && dotnet publish -f net8.0 -c Release -o /app -FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/aspnet:7.0 AS Final +FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/aspnet:8.0 AS Final RUN apt-get update && apt-get install -y \ screen \ libleveldb-dev \ diff --git a/src/Neo.CLI/config.json b/src/Neo.CLI/config.json index b4800b80ea..fb73c3f8d8 100644 --- a/src/Neo.CLI/config.json +++ b/src/Neo.CLI/config.json @@ -36,7 +36,8 @@ "MaxTraceableBlocks": 2102400, "Hardforks": { "HF_Aspidochelone": 1730000, - "HF_Basilisk": 4120000 + "HF_Basilisk": 4120000, + "HF_Cockatrice": 5420000 }, "InitialGasDistribution": 5200000000000000, "ValidatorsCount": 7, diff --git a/src/Neo.CLI/config.mainnet.json b/src/Neo.CLI/config.mainnet.json index b4800b80ea..fb73c3f8d8 100644 --- a/src/Neo.CLI/config.mainnet.json +++ b/src/Neo.CLI/config.mainnet.json @@ -36,7 +36,8 @@ "MaxTraceableBlocks": 2102400, "Hardforks": { "HF_Aspidochelone": 1730000, - "HF_Basilisk": 4120000 + "HF_Basilisk": 4120000, + "HF_Cockatrice": 5420000 }, "InitialGasDistribution": 5200000000000000, "ValidatorsCount": 7, diff --git a/src/Neo.CLI/config.testnet.json b/src/Neo.CLI/config.testnet.json index 19a9ca1442..6e566c7ce1 100644 --- a/src/Neo.CLI/config.testnet.json +++ b/src/Neo.CLI/config.testnet.json @@ -36,7 +36,8 @@ "MaxTraceableBlocks": 2102400, "Hardforks": { "HF_Aspidochelone": 210000, - "HF_Basilisk": 2680000 + "HF_Basilisk": 2680000, + "HF_Cockatrice": 3967000 }, "InitialGasDistribution": 5200000000000000, "ValidatorsCount": 7, diff --git a/src/Neo.GUI/GUI/BulkPayDialog.Designer.cs b/src/Neo.GUI/GUI/BulkPayDialog.Designer.cs index 41ad15e57a..12af8811ff 100644 --- a/src/Neo.GUI/GUI/BulkPayDialog.Designer.cs +++ b/src/Neo.GUI/GUI/BulkPayDialog.Designer.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2016-2023 The Neo Project. +// Copyright (C) 2016-2024 The Neo Project. // // The neo-gui is free software distributed under the MIT software // license, see the accompanying file LICENSE in the main directory of diff --git a/src/Neo.GUI/GUI/ChangePasswordDialog.Designer.cs b/src/Neo.GUI/GUI/ChangePasswordDialog.Designer.cs index 0d9c6ea80c..bcf044ecc9 100644 --- a/src/Neo.GUI/GUI/ChangePasswordDialog.Designer.cs +++ b/src/Neo.GUI/GUI/ChangePasswordDialog.Designer.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2016-2023 The Neo Project. +// Copyright (C) 2016-2024 The Neo Project. // // The neo-gui is free software distributed under the MIT software // license, see the accompanying file LICENSE in the main directory of diff --git a/src/Neo.GUI/GUI/ConsoleForm.Designer.cs b/src/Neo.GUI/GUI/ConsoleForm.Designer.cs index e3fd639db0..b93f503075 100644 --- a/src/Neo.GUI/GUI/ConsoleForm.Designer.cs +++ b/src/Neo.GUI/GUI/ConsoleForm.Designer.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2016-2023 The Neo Project. +// Copyright (C) 2016-2024 The Neo Project. // // The neo-gui is free software distributed under the MIT software // license, see the accompanying file LICENSE in the main directory of @@ -44,8 +44,8 @@ private void InitializeComponent() // // textBox1 // - this.textBox1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left) + this.textBox1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.textBox1.Location = new System.Drawing.Point(12, 12); this.textBox1.Font = new System.Drawing.Font("Consolas", 11.0f); @@ -59,7 +59,7 @@ private void InitializeComponent() // // textBox2 // - this.textBox2.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) + this.textBox2.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.textBox2.Location = new System.Drawing.Point(12, 385); this.textBox2.Font = new System.Drawing.Font("Consolas", 11.0f); diff --git a/src/Neo.GUI/GUI/CreateMultiSigContractDialog.Designer.cs b/src/Neo.GUI/GUI/CreateMultiSigContractDialog.Designer.cs index e91c25c9b7..1fa9aba600 100644 --- a/src/Neo.GUI/GUI/CreateMultiSigContractDialog.Designer.cs +++ b/src/Neo.GUI/GUI/CreateMultiSigContractDialog.Designer.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2016-2023 The Neo Project. +// Copyright (C) 2016-2024 The Neo Project. // // The neo-gui is free software distributed under the MIT software // license, see the accompanying file LICENSE in the main directory of diff --git a/src/Neo.GUI/GUI/CreateWalletDialog.designer.cs b/src/Neo.GUI/GUI/CreateWalletDialog.designer.cs index c4f41b6573..1ea5451ff1 100644 --- a/src/Neo.GUI/GUI/CreateWalletDialog.designer.cs +++ b/src/Neo.GUI/GUI/CreateWalletDialog.designer.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2016-2023 The Neo Project. +// Copyright (C) 2016-2024 The Neo Project. // // The neo-gui is free software distributed under the MIT software // license, see the accompanying file LICENSE in the main directory of diff --git a/src/Neo.GUI/GUI/DeployContractDialog.Designer.cs b/src/Neo.GUI/GUI/DeployContractDialog.Designer.cs index 629b5e96dd..8d29fbc1d3 100644 --- a/src/Neo.GUI/GUI/DeployContractDialog.Designer.cs +++ b/src/Neo.GUI/GUI/DeployContractDialog.Designer.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2016-2023 The Neo Project. +// Copyright (C) 2016-2024 The Neo Project. // // The neo-gui is free software distributed under the MIT software // license, see the accompanying file LICENSE in the main directory of diff --git a/src/Neo.GUI/GUI/DeveloperToolsForm.Designer.cs b/src/Neo.GUI/GUI/DeveloperToolsForm.Designer.cs index 31faf836d9..a18dcdb108 100644 --- a/src/Neo.GUI/GUI/DeveloperToolsForm.Designer.cs +++ b/src/Neo.GUI/GUI/DeveloperToolsForm.Designer.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2016-2023 The Neo Project. +// Copyright (C) 2016-2024 The Neo Project. // // The neo-gui is free software distributed under the MIT software // license, see the accompanying file LICENSE in the main directory of diff --git a/src/Neo.GUI/GUI/ElectionDialog.Designer.cs b/src/Neo.GUI/GUI/ElectionDialog.Designer.cs index 512c24643a..5085e1db1f 100644 --- a/src/Neo.GUI/GUI/ElectionDialog.Designer.cs +++ b/src/Neo.GUI/GUI/ElectionDialog.Designer.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2016-2023 The Neo Project. +// Copyright (C) 2016-2024 The Neo Project. // // The neo-gui is free software distributed under the MIT software // license, see the accompanying file LICENSE in the main directory of diff --git a/src/Neo.GUI/GUI/ImportCustomContractDialog.Designer.cs b/src/Neo.GUI/GUI/ImportCustomContractDialog.Designer.cs index d06a03890e..43e1a0cad3 100644 --- a/src/Neo.GUI/GUI/ImportCustomContractDialog.Designer.cs +++ b/src/Neo.GUI/GUI/ImportCustomContractDialog.Designer.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2016-2023 The Neo Project. +// Copyright (C) 2016-2024 The Neo Project. // // The neo-gui is free software distributed under the MIT software // license, see the accompanying file LICENSE in the main directory of diff --git a/src/Neo.GUI/GUI/ImportPrivateKeyDialog.designer.cs b/src/Neo.GUI/GUI/ImportPrivateKeyDialog.designer.cs index e0df823ec7..06b1001288 100644 --- a/src/Neo.GUI/GUI/ImportPrivateKeyDialog.designer.cs +++ b/src/Neo.GUI/GUI/ImportPrivateKeyDialog.designer.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2016-2023 The Neo Project. +// Copyright (C) 2016-2024 The Neo Project. // // The neo-gui is free software distributed under the MIT software // license, see the accompanying file LICENSE in the main directory of diff --git a/src/Neo.GUI/GUI/InformationBox.Designer.cs b/src/Neo.GUI/GUI/InformationBox.Designer.cs index 8b41144a9b..92bf89bc78 100644 --- a/src/Neo.GUI/GUI/InformationBox.Designer.cs +++ b/src/Neo.GUI/GUI/InformationBox.Designer.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2016-2023 The Neo Project. +// Copyright (C) 2016-2024 The Neo Project. // // The neo-gui is free software distributed under the MIT software // license, see the accompanying file LICENSE in the main directory of diff --git a/src/Neo.GUI/GUI/InputBox.Designer.cs b/src/Neo.GUI/GUI/InputBox.Designer.cs index aa376ca91f..163438b8e7 100644 --- a/src/Neo.GUI/GUI/InputBox.Designer.cs +++ b/src/Neo.GUI/GUI/InputBox.Designer.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2016-2023 The Neo Project. +// Copyright (C) 2016-2024 The Neo Project. // // The neo-gui is free software distributed under the MIT software // license, see the accompanying file LICENSE in the main directory of diff --git a/src/Neo.GUI/GUI/InvokeContractDialog.Designer.cs b/src/Neo.GUI/GUI/InvokeContractDialog.Designer.cs index 04f845def9..44454c0306 100644 --- a/src/Neo.GUI/GUI/InvokeContractDialog.Designer.cs +++ b/src/Neo.GUI/GUI/InvokeContractDialog.Designer.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2016-2023 The Neo Project. +// Copyright (C) 2016-2024 The Neo Project. // // The neo-gui is free software distributed under the MIT software // license, see the accompanying file LICENSE in the main directory of diff --git a/src/Neo.GUI/GUI/MainForm.Designer.cs b/src/Neo.GUI/GUI/MainForm.Designer.cs index 2f4da98d9c..4ea5e2e5f6 100644 --- a/src/Neo.GUI/GUI/MainForm.Designer.cs +++ b/src/Neo.GUI/GUI/MainForm.Designer.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2016-2023 The Neo Project. +// Copyright (C) 2016-2024 The Neo Project. // // The neo-gui is free software distributed under the MIT software // license, see the accompanying file LICENSE in the main directory of diff --git a/src/Neo.GUI/GUI/OpenWalletDialog.designer.cs b/src/Neo.GUI/GUI/OpenWalletDialog.designer.cs index 9db0ac01b8..a1cc1a1308 100644 --- a/src/Neo.GUI/GUI/OpenWalletDialog.designer.cs +++ b/src/Neo.GUI/GUI/OpenWalletDialog.designer.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2016-2023 The Neo Project. +// Copyright (C) 2016-2024 The Neo Project. // // The neo-gui is free software distributed under the MIT software // license, see the accompanying file LICENSE in the main directory of diff --git a/src/Neo.GUI/GUI/ParametersEditor.Designer.cs b/src/Neo.GUI/GUI/ParametersEditor.Designer.cs index 5d6d92d268..6f0b2432e4 100644 --- a/src/Neo.GUI/GUI/ParametersEditor.Designer.cs +++ b/src/Neo.GUI/GUI/ParametersEditor.Designer.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2016-2023 The Neo Project. +// Copyright (C) 2016-2024 The Neo Project. // // The neo-gui is free software distributed under the MIT software // license, see the accompanying file LICENSE in the main directory of diff --git a/src/Neo.GUI/GUI/PayToDialog.Designer.cs b/src/Neo.GUI/GUI/PayToDialog.Designer.cs index 100d32f50d..2bf4e075c0 100644 --- a/src/Neo.GUI/GUI/PayToDialog.Designer.cs +++ b/src/Neo.GUI/GUI/PayToDialog.Designer.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2016-2023 The Neo Project. +// Copyright (C) 2016-2024 The Neo Project. // // The neo-gui is free software distributed under the MIT software // license, see the accompanying file LICENSE in the main directory of diff --git a/src/Neo.GUI/GUI/SigningDialog.Designer.cs b/src/Neo.GUI/GUI/SigningDialog.Designer.cs index 8c03f84901..dabb436d23 100644 --- a/src/Neo.GUI/GUI/SigningDialog.Designer.cs +++ b/src/Neo.GUI/GUI/SigningDialog.Designer.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2016-2023 The Neo Project. +// Copyright (C) 2016-2024 The Neo Project. // // The neo-gui is free software distributed under the MIT software // license, see the accompanying file LICENSE in the main directory of diff --git a/src/Neo.GUI/GUI/SigningTxDialog.Designer.cs b/src/Neo.GUI/GUI/SigningTxDialog.Designer.cs index 45ecb20563..a8bb11f2c2 100644 --- a/src/Neo.GUI/GUI/SigningTxDialog.Designer.cs +++ b/src/Neo.GUI/GUI/SigningTxDialog.Designer.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2016-2023 The Neo Project. +// Copyright (C) 2016-2024 The Neo Project. // // The neo-gui is free software distributed under the MIT software // license, see the accompanying file LICENSE in the main directory of diff --git a/src/Neo.GUI/GUI/TransferDialog.Designer.cs b/src/Neo.GUI/GUI/TransferDialog.Designer.cs index 2d19a83fce..8d18bb5316 100644 --- a/src/Neo.GUI/GUI/TransferDialog.Designer.cs +++ b/src/Neo.GUI/GUI/TransferDialog.Designer.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2016-2023 The Neo Project. +// Copyright (C) 2016-2024 The Neo Project. // // The neo-gui is free software distributed under the MIT software // license, see the accompanying file LICENSE in the main directory of diff --git a/src/Neo.GUI/GUI/TxOutListBox.Designer.cs b/src/Neo.GUI/GUI/TxOutListBox.Designer.cs index ad9f54d846..df23b5b8c0 100644 --- a/src/Neo.GUI/GUI/TxOutListBox.Designer.cs +++ b/src/Neo.GUI/GUI/TxOutListBox.Designer.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2016-2023 The Neo Project. +// Copyright (C) 2016-2024 The Neo Project. // // The neo-gui is free software distributed under the MIT software // license, see the accompanying file LICENSE in the main directory of diff --git a/src/Neo.GUI/GUI/UpdateDialog.Designer.cs b/src/Neo.GUI/GUI/UpdateDialog.Designer.cs index 6af087d42b..a443304ffa 100644 --- a/src/Neo.GUI/GUI/UpdateDialog.Designer.cs +++ b/src/Neo.GUI/GUI/UpdateDialog.Designer.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2016-2023 The Neo Project. +// Copyright (C) 2016-2024 The Neo Project. // // The neo-gui is free software distributed under the MIT software // license, see the accompanying file LICENSE in the main directory of diff --git a/src/Neo.GUI/GUI/ViewContractDialog.Designer.cs b/src/Neo.GUI/GUI/ViewContractDialog.Designer.cs index 5adbe25451..05706aa7ef 100644 --- a/src/Neo.GUI/GUI/ViewContractDialog.Designer.cs +++ b/src/Neo.GUI/GUI/ViewContractDialog.Designer.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2016-2023 The Neo Project. +// Copyright (C) 2016-2024 The Neo Project. // // The neo-gui is free software distributed under the MIT software // license, see the accompanying file LICENSE in the main directory of diff --git a/src/Neo.GUI/GUI/ViewPrivateKeyDialog.designer.cs b/src/Neo.GUI/GUI/ViewPrivateKeyDialog.designer.cs index 2ba3d9773f..306904a85e 100644 --- a/src/Neo.GUI/GUI/ViewPrivateKeyDialog.designer.cs +++ b/src/Neo.GUI/GUI/ViewPrivateKeyDialog.designer.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2016-2023 The Neo Project. +// Copyright (C) 2016-2024 The Neo Project. // // The neo-gui is free software distributed under the MIT software // license, see the accompanying file LICENSE in the main directory of diff --git a/src/Neo.GUI/GUI/VotingDialog.Designer.cs b/src/Neo.GUI/GUI/VotingDialog.Designer.cs index 0ce4b7ee30..706b1a5bbf 100644 --- a/src/Neo.GUI/GUI/VotingDialog.Designer.cs +++ b/src/Neo.GUI/GUI/VotingDialog.Designer.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2016-2023 The Neo Project. +// Copyright (C) 2016-2024 The Neo Project. // // The neo-gui is free software distributed under the MIT software // license, see the accompanying file LICENSE in the main directory of From 20ba8fa8823d208211d74f21a5d3a5e3f1787fc6 Mon Sep 17 00:00:00 2001 From: Shargon Date: Fri, 10 May 2024 01:34:07 -0700 Subject: [PATCH 126/168] skip duplicate nuget versions (#3223) --skip-duplicate --- .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 92aa1f9332..83726be426 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -171,6 +171,6 @@ jobs: - 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} + dotnet nuget push out/*.nupkg -s https://api.nuget.org/v3/index.json -k ${NUGET_TOKEN} --skip-duplicate env: NUGET_TOKEN: ${{ secrets.NUGET_TOKEN }} From 1d957922a1aec90d0ec852402dc6eca496841ed4 Mon Sep 17 00:00:00 2001 From: Owen <38493437+superboyiii@users.noreply.github.com> Date: Fri, 10 May 2024 19:48:09 +0800 Subject: [PATCH 127/168] v3.7.1 (#3224) * v3.7.1 Fix dotnet build on CLI from TargetFramework https://learn.microsoft.com/en-us/dotnet/standard/frameworks#how-to-specify-a-target-framework * v3.7.1 * fix * try * Update main.yml * Update main.yml --------- Co-authored-by: Shargon --- .github/workflows/main.yml | 14 +++++++++----- src/Directory.Build.props | 2 +- src/Neo.CLI/Neo.CLI.csproj | 2 +- src/Neo.GUI/Neo.GUI.csproj | 6 +++--- .../Neo.ConsoleService.Tests.csproj | 2 +- .../Neo.Cryptography.BLS12_381.Tests.csproj | 2 +- tests/Neo.Json.UnitTests/Neo.Json.UnitTests.csproj | 2 +- tests/Neo.UnitTests/Neo.UnitTests.csproj | 2 +- tests/Neo.VM.Tests/Neo.VM.Tests.csproj | 2 +- 9 files changed, 19 insertions(+), 15 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 83726be426..5ac5e3dc65 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -27,6 +27,10 @@ jobs: if: matrix.os == 'ubuntu-latest' run: | dotnet format --verify-no-changes --verbosity diagnostic + - name: Build CLI + if: matrix.os == 'ubuntu-latest' + run: | + dotnet publish ./src/Neo.CLI - name: Test if: matrix.os != 'ubuntu-latest' run: | @@ -35,17 +39,17 @@ jobs: if: matrix.os == 'ubuntu-latest' run: | dotnet test ./tests/Neo.Cryptography.BLS12_381.Tests /p:CollectCoverage=true /p:CoverletOutput='${{ github.workspace }}/TestResults/coverage/' - dotnet test ./tests/Neo.ConsoleService.Tests /p:CollectCoverage=true /p:CoverletOutput='${{ github.workspace }}/TestResults/coverage/' /p:MergeWith='${{ github.workspace }}/TestResults/coverage/coverage.net8.0.json' - dotnet test ./tests/Neo.UnitTests /p:CollectCoverage=true /p:CoverletOutput='${{ github.workspace }}/TestResults/coverage/' /p:MergeWith='${{ github.workspace }}/TestResults/coverage/coverage.net8.0.json' - dotnet test ./tests/Neo.VM.Tests /p:CollectCoverage=true /p:CoverletOutput='${{ github.workspace }}/TestResults/coverage/' /p:MergeWith='${{ github.workspace }}/TestResults/coverage/coverage.net8.0.json' - dotnet test ./tests/Neo.Json.UnitTests /p:CollectCoverage=true /p:CoverletOutput='${{ github.workspace }}/TestResults/coverage/' /p:MergeWith='${{ github.workspace }}/TestResults/coverage/coverage.net8.0.json' /p:CoverletOutputFormat='lcov' + dotnet test ./tests/Neo.ConsoleService.Tests /p:CollectCoverage=true /p:CoverletOutput='${{ github.workspace }}/TestResults/coverage/' /p:MergeWith='${{ github.workspace }}/TestResults/coverage/coverage.json' + dotnet test ./tests/Neo.UnitTests /p:CollectCoverage=true /p:CoverletOutput='${{ github.workspace }}/TestResults/coverage/' /p:MergeWith='${{ github.workspace }}/TestResults/coverage/coverage.json' + dotnet test ./tests/Neo.VM.Tests /p:CollectCoverage=true /p:CoverletOutput='${{ github.workspace }}/TestResults/coverage/' /p:MergeWith='${{ github.workspace }}/TestResults/coverage/coverage.json' + dotnet test ./tests/Neo.Json.UnitTests /p:CollectCoverage=true /p:CoverletOutput='${{ github.workspace }}/TestResults/coverage/' /p:MergeWith='${{ github.workspace }}/TestResults/coverage/coverage.json' /p:CoverletOutputFormat='lcov' - name: Coveralls if: matrix.os == 'ubuntu-latest' uses: coverallsapp/github-action@v2.2.3 with: github-token: ${{ secrets.GITHUB_TOKEN }} format: lcov - file: ${{ github.workspace }}/TestResults/coverage/coverage.net8.0.info + file: ${{ github.workspace }}/TestResults/coverage/coverage.info PublishPackage: if: github.ref == 'refs/heads/master' && startsWith(github.repository, 'neo-project/') diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 18f77050d5..92bc5b006a 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -3,7 +3,7 @@ 2015-2024 The Neo Project - 3.7.0 + 3.7.1 12.0 The Neo Project neo.png diff --git a/src/Neo.CLI/Neo.CLI.csproj b/src/Neo.CLI/Neo.CLI.csproj index c3c051b4bf..bb52675ec4 100644 --- a/src/Neo.CLI/Neo.CLI.csproj +++ b/src/Neo.CLI/Neo.CLI.csproj @@ -1,7 +1,7 @@ - net8.0 + net8.0 Neo.CLI neo-cli Exe diff --git a/src/Neo.GUI/Neo.GUI.csproj b/src/Neo.GUI/Neo.GUI.csproj index 2c713957a8..34e515b159 100644 --- a/src/Neo.GUI/Neo.GUI.csproj +++ b/src/Neo.GUI/Neo.GUI.csproj @@ -1,10 +1,10 @@ - 2016-2023 The Neo Project + 2016-2024 The Neo Project Neo.GUI WinExe - net8.0-windows + net8.0-windows true Neo true @@ -15,7 +15,7 @@ - + diff --git a/tests/Neo.ConsoleService.Tests/Neo.ConsoleService.Tests.csproj b/tests/Neo.ConsoleService.Tests/Neo.ConsoleService.Tests.csproj index c2a2adcf84..03e67d6f78 100644 --- a/tests/Neo.ConsoleService.Tests/Neo.ConsoleService.Tests.csproj +++ b/tests/Neo.ConsoleService.Tests/Neo.ConsoleService.Tests.csproj @@ -1,7 +1,7 @@ - net8.0 + net8.0 neo_cli.Tests 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 c6aeac41ae..5c4a8f5951 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 @@ -1,7 +1,7 @@ - net8.0 + net8.0 enable enable diff --git a/tests/Neo.Json.UnitTests/Neo.Json.UnitTests.csproj b/tests/Neo.Json.UnitTests/Neo.Json.UnitTests.csproj index b26a47c6fa..1e66e0ce65 100644 --- a/tests/Neo.Json.UnitTests/Neo.Json.UnitTests.csproj +++ b/tests/Neo.Json.UnitTests/Neo.Json.UnitTests.csproj @@ -1,7 +1,7 @@ - net8.0 + net8.0 enable diff --git a/tests/Neo.UnitTests/Neo.UnitTests.csproj b/tests/Neo.UnitTests/Neo.UnitTests.csproj index e2ab6dc14e..6ac259db7b 100644 --- a/tests/Neo.UnitTests/Neo.UnitTests.csproj +++ b/tests/Neo.UnitTests/Neo.UnitTests.csproj @@ -1,7 +1,7 @@ - net8.0 + net8.0 true diff --git a/tests/Neo.VM.Tests/Neo.VM.Tests.csproj b/tests/Neo.VM.Tests/Neo.VM.Tests.csproj index aeb0d826b9..6b3dab4177 100644 --- a/tests/Neo.VM.Tests/Neo.VM.Tests.csproj +++ b/tests/Neo.VM.Tests/Neo.VM.Tests.csproj @@ -1,7 +1,7 @@ - net8.0 + net8.0 Neo.Test true From 1dec0c73dc73127d9703b2f0c1c7a62d614db403 Mon Sep 17 00:00:00 2001 From: Hecate2 <2474101468@qq.com> Date: Mon, 13 May 2024 18:28:38 +0800 Subject: [PATCH 128/168] protected OnSysCall and OnCallT methods (#3225) * protected OnCallT and OnSysCall methods * protected DefaultJumpTable --- src/Neo/SmartContract/ApplicationEngine.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Neo/SmartContract/ApplicationEngine.cs b/src/Neo/SmartContract/ApplicationEngine.cs index 0c57b771e5..66d53deb73 100644 --- a/src/Neo/SmartContract/ApplicationEngine.cs +++ b/src/Neo/SmartContract/ApplicationEngine.cs @@ -32,7 +32,7 @@ namespace Neo.SmartContract /// public partial class ApplicationEngine : ExecutionEngine { - private static readonly JumpTable DefaultJumpTable = ComposeDefaultJumpTable(); + protected static readonly JumpTable DefaultJumpTable = ComposeDefaultJumpTable(); /// /// The maximum cost that can be spent when a contract is executed in test mode. @@ -194,7 +194,7 @@ private static JumpTable ComposeDefaultJumpTable() return table; } - private static void OnCallT(ExecutionEngine engine, Instruction instruction) + protected static void OnCallT(ExecutionEngine engine, Instruction instruction) { if (engine is ApplicationEngine app) { @@ -218,7 +218,7 @@ private static void OnCallT(ExecutionEngine engine, Instruction instruction) } } - private static void OnSysCall(ExecutionEngine engine, Instruction instruction) + protected static void OnSysCall(ExecutionEngine engine, Instruction instruction) { if (engine is ApplicationEngine app) { From d56d4eb706f472ba1c15ed96489e5b6514a65a64 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Thu, 16 May 2024 16:09:51 +0800 Subject: [PATCH 129/168] fix hardfork issues (#3234) * fix hardfork issues * fix hardfork for 3172 * fix 3195 * set custom setting if load from config. * fix hf index * fix UT * Revert "fix 3195" This reverts commit c1af44340f664a2e14632b10788b8cb9aef3ea57. * revert role fix * fix manifest * format * revert role UT --- src/Neo/ProtocolSettings.cs | 3 ++- .../Native/ContractMethodAttribute.cs | 7 ++++++ .../Native/ContractMethodMetadata.cs | 2 ++ src/Neo/SmartContract/Native/CryptoLib.cs | 22 ++++++++++++++++++- .../SmartContract/Native/NativeContract.cs | 12 +++++++++- src/Neo/SmartContract/Native/NeoToken.cs | 22 ++++++++++++------- 6 files changed, 57 insertions(+), 11 deletions(-) diff --git a/src/Neo/ProtocolSettings.cs b/src/Neo/ProtocolSettings.cs index c3d8232afd..f03e5ffaf9 100644 --- a/src/Neo/ProtocolSettings.cs +++ b/src/Neo/ProtocolSettings.cs @@ -144,7 +144,7 @@ public static ProtocolSettings Load(string path, bool optional = true) /// The loaded . public static ProtocolSettings Load(IConfigurationSection section) { - return new ProtocolSettings + Custom = new ProtocolSettings { Network = section.GetValue("Network", Default.Network), AddressVersion = section.GetValue("AddressVersion", Default.AddressVersion), @@ -164,6 +164,7 @@ public static ProtocolSettings Load(IConfigurationSection section) ? EnsureOmmitedHardforks(section.GetSection("Hardforks").GetChildren().ToDictionary(p => Enum.Parse(p.Key, true), p => uint.Parse(p.Value))).ToImmutableDictionary() : Default.Hardforks }; + return Custom; } /// diff --git a/src/Neo/SmartContract/Native/ContractMethodAttribute.cs b/src/Neo/SmartContract/Native/ContractMethodAttribute.cs index cd8f7de59e..7caa27c8b0 100644 --- a/src/Neo/SmartContract/Native/ContractMethodAttribute.cs +++ b/src/Neo/SmartContract/Native/ContractMethodAttribute.cs @@ -23,6 +23,7 @@ internal class ContractMethodAttribute : Attribute public long CpuFee { get; init; } public long StorageFee { get; init; } public Hardfork? ActiveIn { get; init; } = null; + public Hardfork? DeprecatedIn { get; init; } = null; public ContractMethodAttribute() { } @@ -30,5 +31,11 @@ public ContractMethodAttribute(Hardfork activeIn) { ActiveIn = activeIn; } + + public ContractMethodAttribute(bool isDeprecated, Hardfork deprecatedIn) + { + if (!isDeprecated) throw new ArgumentException("isDeprecated must be true", nameof(isDeprecated)); + DeprecatedIn = deprecatedIn; + } } } diff --git a/src/Neo/SmartContract/Native/ContractMethodMetadata.cs b/src/Neo/SmartContract/Native/ContractMethodMetadata.cs index 0688a0dac2..30874efb47 100644 --- a/src/Neo/SmartContract/Native/ContractMethodMetadata.cs +++ b/src/Neo/SmartContract/Native/ContractMethodMetadata.cs @@ -36,6 +36,7 @@ internal class ContractMethodMetadata public CallFlags RequiredCallFlags { get; } public ContractMethodDescriptor Descriptor { get; } public Hardfork? ActiveIn { get; init; } = null; + public Hardfork? DeprecatedIn { get; init; } = null; public ContractMethodMetadata(MemberInfo member, ContractMethodAttribute attribute) { @@ -60,6 +61,7 @@ public ContractMethodMetadata(MemberInfo member, ContractMethodAttribute attribu StorageFee = attribute.StorageFee; RequiredCallFlags = attribute.RequiredCallFlags; ActiveIn = attribute.ActiveIn; + DeprecatedIn = attribute.DeprecatedIn; Descriptor = new ContractMethodDescriptor { Name = Name, diff --git a/src/Neo/SmartContract/Native/CryptoLib.cs b/src/Neo/SmartContract/Native/CryptoLib.cs index 6e2876a860..452dd31faa 100644 --- a/src/Neo/SmartContract/Native/CryptoLib.cs +++ b/src/Neo/SmartContract/Native/CryptoLib.cs @@ -21,6 +21,12 @@ namespace Neo.SmartContract.Native /// public sealed partial class CryptoLib : NativeContract { + private static readonly Dictionary curves = new() + { + [NamedCurve.secp256k1] = ECCurve.Secp256k1, + [NamedCurve.secp256r1] = ECCurve.Secp256r1, + }; + private static readonly Dictionary s_curves = new() { [NamedCurveHash.secp256k1SHA256] = (ECCurve.Secp256k1, Hasher.SHA256), @@ -85,7 +91,7 @@ public static byte[] Keccak256(byte[] data) /// The signature to be verified. /// A pair of the curve to be used by the ECDSA algorithm and the hasher function to be used to hash message. /// if the signature is valid; otherwise, . - [ContractMethod(CpuFee = 1 << 15)] + [ContractMethod(Hardfork.HF_Cockatrice, CpuFee = 1 << 15)] public static bool VerifyWithECDsa(byte[] message, byte[] pubkey, byte[] signature, NamedCurveHash curveHash) { try @@ -98,5 +104,19 @@ public static bool VerifyWithECDsa(byte[] message, byte[] pubkey, byte[] signatu return false; } } + + // This is for solving the hardfork issue in https://github.com/neo-project/neo/pull/3209 + [ContractMethod(true, Hardfork.HF_Cockatrice, CpuFee = 1 << 15)] + public static bool VerifyWithECDsa(byte[] message, byte[] pubkey, byte[] signature, NamedCurve curve) + { + try + { + return Crypto.VerifySignature(message, signature, pubkey, curves[curve]); + } + catch (ArgumentException) + { + return false; + } + } } } diff --git a/src/Neo/SmartContract/Native/NativeContract.cs b/src/Neo/SmartContract/Native/NativeContract.cs index 70f67de538..55e88b2ec6 100644 --- a/src/Neo/SmartContract/Native/NativeContract.cs +++ b/src/Neo/SmartContract/Native/NativeContract.cs @@ -184,7 +184,15 @@ private NativeContractsCache.CacheEntry GetAllowedMethods(IsHardforkEnabledDeleg byte[] script; using (ScriptBuilder sb = new()) { - foreach (ContractMethodMetadata method in methodDescriptors.Where(u => u.ActiveIn is null || hfChecker(u.ActiveIn.Value, index))) + 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, index) == false || + // active method hardfork is involved + u.ActiveIn is not null && hfChecker(u.ActiveIn.Value, index)) + ) { method.Descriptor.Offset = sb.Length; sb.EmitPush(0); //version @@ -366,6 +374,8 @@ internal async void Invoke(ApplicationEngine engine, byte version) ContractMethodMetadata method = currentAllowedMethods.Methods[context.InstructionPointer]; if (method.ActiveIn is not null && !engine.IsHardforkEnabled(method.ActiveIn.Value)) throw new InvalidOperationException($"Cannot call this method before hardfork {method.ActiveIn}."); + if (method.DeprecatedIn is not null && engine.IsHardforkEnabled(method.DeprecatedIn.Value)) + throw new InvalidOperationException($"Cannot call this method after hardfork {method.DeprecatedIn}."); ExecutionContextState state = context.GetState(); if (!state.CallFlags.HasFlag(method.RequiredCallFlags)) throw new InvalidOperationException($"Cannot call this method with the flag {state.CallFlags}."); diff --git a/src/Neo/SmartContract/Native/NeoToken.cs b/src/Neo/SmartContract/Native/NeoToken.cs index 1ff9aa2fdb..1fbf07204e 100644 --- a/src/Neo/SmartContract/Native/NeoToken.cs +++ b/src/Neo/SmartContract/Native/NeoToken.cs @@ -63,7 +63,7 @@ public sealed class NeoToken : FungibleToken "from", ContractParameterType.PublicKey, "to", ContractParameterType.PublicKey, "amount", ContractParameterType.Integer)] - [ContractEvent(3, name: "CommitteeChanged", + [ContractEvent(Hardfork.HF_Cockatrice, 3, name: "CommitteeChanged", "old", ContractParameterType.Array, "new", ContractParameterType.Array)] internal NeoToken() : base() @@ -203,14 +203,20 @@ internal override ContractTask OnPersistAsync(ApplicationEngine engine) cachedCommittee.Clear(); cachedCommittee.AddRange(ComputeCommitteeMembers(engine.Snapshot, engine.ProtocolSettings)); - var newCommittee = cachedCommittee.Select(u => u.PublicKey).ToArray(); - - if (!newCommittee.SequenceEqual(prevCommittee)) + // 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); + if (engine.ProtocolSettings.IsHardforkEnabled(Hardfork.HF_Cockatrice, index)) { - engine.SendNotification(Hash, "CommitteeChanged", new VM.Types.Array(engine.ReferenceCounter) { - new VM.Types.Array(engine.ReferenceCounter, prevCommittee.Select(u => (ByteString)u.ToArray())) , - new VM.Types.Array(engine.ReferenceCounter, newCommittee.Select(u => (ByteString)u.ToArray())) - }); + var newCommittee = cachedCommittee.Select(u => u.PublicKey).ToArray(); + + if (!newCommittee.SequenceEqual(prevCommittee)) + { + engine.SendNotification(Hash, "CommitteeChanged", new VM.Types.Array(engine.ReferenceCounter) { + new VM.Types.Array(engine.ReferenceCounter, prevCommittee.Select(u => (ByteString)u.ToArray())) , + new VM.Types.Array(engine.ReferenceCounter, newCommittee.Select(u => (ByteString)u.ToArray())) + }); + } } } return ContractTask.CompletedTask; From 7f227a3026fadeb9723280e6f961b6f29b0f8a7a Mon Sep 17 00:00:00 2001 From: Owen <38493437+superboyiii@users.noreply.github.com> Date: Thu, 16 May 2024 16:55:39 +0800 Subject: [PATCH 130/168] v3.7.4 (#3237) * v3.7.4 * change HF height --- src/Directory.Build.props | 2 +- src/Neo.CLI/config.json | 2 +- src/Neo.CLI/config.mainnet.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 92bc5b006a..816760b50b 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -3,7 +3,7 @@ 2015-2024 The Neo Project - 3.7.1 + 3.7.4 12.0 The Neo Project neo.png diff --git a/src/Neo.CLI/config.json b/src/Neo.CLI/config.json index fb73c3f8d8..c9544a337f 100644 --- a/src/Neo.CLI/config.json +++ b/src/Neo.CLI/config.json @@ -37,7 +37,7 @@ "Hardforks": { "HF_Aspidochelone": 1730000, "HF_Basilisk": 4120000, - "HF_Cockatrice": 5420000 + "HF_Cockatrice": 5450000 }, "InitialGasDistribution": 5200000000000000, "ValidatorsCount": 7, diff --git a/src/Neo.CLI/config.mainnet.json b/src/Neo.CLI/config.mainnet.json index fb73c3f8d8..c9544a337f 100644 --- a/src/Neo.CLI/config.mainnet.json +++ b/src/Neo.CLI/config.mainnet.json @@ -37,7 +37,7 @@ "Hardforks": { "HF_Aspidochelone": 1730000, "HF_Basilisk": 4120000, - "HF_Cockatrice": 5420000 + "HF_Cockatrice": 5450000 }, "InitialGasDistribution": 5200000000000000, "ValidatorsCount": 7, From 4da5d6beadcac2b0e1f5c04646691c03ce1723f7 Mon Sep 17 00:00:00 2001 From: Anna Shaleva Date: Mon, 20 May 2024 11:46:37 +0300 Subject: [PATCH 131/168] Neo.CLI: enable hardforks for NeoFS mainnet (#3240) Otherwise this configuration file is broken. Port changes from https://github.com/nspcc-dev/neo-go/pull/3446. Signed-off-by: Anna Shaleva --- src/Neo.CLI/config.fs.mainnet.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Neo.CLI/config.fs.mainnet.json b/src/Neo.CLI/config.fs.mainnet.json index fad987209a..e79a31c312 100644 --- a/src/Neo.CLI/config.fs.mainnet.json +++ b/src/Neo.CLI/config.fs.mainnet.json @@ -36,6 +36,11 @@ "MaxTraceableBlocks": 2102400, "InitialGasDistribution": 5200000000000000, "ValidatorsCount": 7, + "Hardforks": { + "HF_Aspidochelone": 3000000, + "HF_Basilisk": 4500000, + "HF_Cockatrice": 5800000 + }, "StandbyCommittee": [ "026fa34ec057d74c2fdf1a18e336d0bd597ea401a0b2ad57340d5c220d09f44086", "039a9db2a30942b1843db673aeb0d4fd6433f74cec1d879de6343cb9fcf7628fa4", From ee10929f1bd36c05056594f739b7f0e8779c3190 Mon Sep 17 00:00:00 2001 From: Shargon Date: Mon, 20 May 2024 02:09:16 -0700 Subject: [PATCH 132/168] Fix https://github.com/neo-project/neo/issues/3239 (#3242) --- src/Neo.VM/ExecutionEngine.cs | 2 +- src/Neo/SmartContract/ApplicationEngine.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Neo.VM/ExecutionEngine.cs b/src/Neo.VM/ExecutionEngine.cs index 52dd057902..38a2dccb07 100644 --- a/src/Neo.VM/ExecutionEngine.cs +++ b/src/Neo.VM/ExecutionEngine.cs @@ -166,7 +166,7 @@ protected internal void ExecuteNext() /// Loads the specified context into the invocation stack. /// /// The context to load. - internal virtual void LoadContext(ExecutionContext context) + protected internal virtual void LoadContext(ExecutionContext context) { if (InvocationStack.Count >= Limits.MaxInvocationStackSize) throw new InvalidOperationException($"MaxInvocationStackSize exceed: {InvocationStack.Count}"); diff --git a/src/Neo/SmartContract/ApplicationEngine.cs b/src/Neo/SmartContract/ApplicationEngine.cs index 66d53deb73..8dd5c27a1e 100644 --- a/src/Neo/SmartContract/ApplicationEngine.cs +++ b/src/Neo/SmartContract/ApplicationEngine.cs @@ -384,7 +384,7 @@ public static ApplicationEngine Create(TriggerType trigger, IVerifiable containe ?? new ApplicationEngine(trigger, container, snapshot, persistingBlock, settings, gas, diagnostic, jumpTable); } - internal override void LoadContext(ExecutionContext context) + protected internal override void LoadContext(ExecutionContext context) { // Set default execution context state var state = context.GetState(); From 8b687b67612c355dd373c8bc65f8352c316efcee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=BF=97=E5=90=8C?= Date: Mon, 20 May 2024 17:17:47 +0800 Subject: [PATCH 133/168] improve parse method in neo-cli (#3204) * Update MainService.Tools.cs * format * Update MainService.Tools.cs * Update MainService.Tools.cs * Update MainService.Tools.cs * Update MainService.Tools.cs * Update MainService.Tools.cs * Update MainService.Tools.cs * Update MainService.Tools.cs * update * Update MainService.Tools.cs * Update MainService.Tools.cs * Update MainService.Tools.cs * format * Update MainService.Tools.cs * Review * fixedbug * Update MainService.Tools.cs --------- Co-authored-by: Christopher Schuchardt Co-authored-by: Shargon Co-authored-by: Jimmy --- src/Neo.CLI/CLI/MainService.Tools.cs | 476 ++++++++++++---------- src/Neo.CLI/CLI/ParseFunctionAttribute.cs | 25 ++ 2 files changed, 278 insertions(+), 223 deletions(-) create mode 100644 src/Neo.CLI/CLI/ParseFunctionAttribute.cs diff --git a/src/Neo.CLI/CLI/MainService.Tools.cs b/src/Neo.CLI/CLI/MainService.Tools.cs index f4a5b762a9..66723d7df9 100644 --- a/src/Neo.CLI/CLI/MainService.Tools.cs +++ b/src/Neo.CLI/CLI/MainService.Tools.cs @@ -10,12 +10,18 @@ // modifications are permitted. using Neo.ConsoleService; +using Neo.Cryptography.ECC; using Neo.IO; +using Neo.SmartContract; +using Neo.VM; using Neo.Wallets; using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Numerics; +using System.Reflection; +using System.Text; namespace Neo.CLI { @@ -27,23 +33,21 @@ partial class MainService [ConsoleCommand("parse", Category = "Base Commands", Description = "Parse a value to its possible conversions.")] private void OnParseCommand(string value) { - var parseFunctions = new Dictionary>() - { - { "Address to ScriptHash", AddressToScripthash }, - { "Address to Base64", AddressToBase64 }, - { "ScriptHash to Address", ScripthashToAddress }, - { "Base64 to Address", Base64ToAddress }, - { "Base64 to String", Base64ToString }, - { "Base64 to Big Integer", Base64ToNumber }, - { "Big Integer to Hex String", NumberToHex }, - { "Big Integer to Base64", NumberToBase64 }, - { "Hex String to String", HexToString }, - { "Hex String to Big Integer", HexToNumber }, - { "String to Hex String", StringToHex }, - { "String to Base64", StringToBase64 } - }; - - bool any = false; + value = Base64Fixed(value); + + var parseFunctions = new Dictionary>(); + var methods = GetType().GetMethods(BindingFlags.NonPublic | BindingFlags.Instance); + + foreach (var method in methods) + { + var attribute = method.GetCustomAttribute(); + if (attribute != null) + { + parseFunctions.Add(attribute.Description, (Func)Delegate.CreateDelegate(typeof(Func), this, method)); + } + } + + var any = false; foreach (var pair in parseFunctions) { @@ -64,50 +68,38 @@ private void OnParseCommand(string value) } /// - /// Converts an hexadecimal value to an UTF-8 string + /// Little-endian to Big-endian + /// input: ce616f7f74617e0fc4b805583af2602a238df63f + /// output: 0x3ff68d232a60f23a5805b8c40f7e61747f6f61ce /// - /// - /// Hexadecimal value to be converted - /// - /// - /// Returns null when is not possible to parse the hexadecimal value to a UTF-8 - /// string or when the converted string is not printable; otherwise, returns - /// the string represented by the hexadecimal value - /// - private string? HexToString(string hexString) + [ParseFunction("Little-endian to Big-endian")] + private string? LittleEndianToBigEndian(string hex) { try { - var clearHexString = ClearHexString(hexString); - var bytes = clearHexString.HexToBytes(); - var utf8String = Utility.StrictUTF8.GetString(bytes); - return IsPrintable(utf8String) ? utf8String : null; + if (!IsHex(hex)) return null; + return "0x" + hex.HexToBytes().Reverse().ToArray().ToHexString(); } - catch + catch (FormatException) { return null; } } /// - /// Converts an hex value to a big integer + /// Big-endian to Little-endian + /// input: 0x3ff68d232a60f23a5805b8c40f7e61747f6f61ce + /// output: ce616f7f74617e0fc4b805583af2602a238df63f /// - /// - /// Hexadecimal value to be converted - /// - /// - /// Returns null when is not possible to parse the hex value to big integer value; - /// otherwise, returns the string that represents the converted big integer. - /// - private string? HexToNumber(string hexString) + [ParseFunction("Big-endian to Little-endian")] + private string? BigEndianToLittleEndian(string hex) { try { - var clearHexString = ClearHexString(hexString); - var bytes = clearHexString.HexToBytes(); - var number = new BigInteger(bytes); - - return number.ToString(); + var hasHexPrefix = hex.StartsWith("0x", StringComparison.InvariantCultureIgnoreCase); + hex = hasHexPrefix ? hex[2..] : hex; + if (!hasHexPrefix || !IsHex(hex)) return null; + return hex.HexToBytes().Reverse().ToArray().ToHexString(); } catch { @@ -116,66 +108,17 @@ private void OnParseCommand(string value) } /// - /// Formats a string value to a default hexadecimal representation of a byte array + /// String to Base64 + /// input: Hello World! + /// output: SGVsbG8gV29ybGQh /// - /// - /// The string value to be formatted - /// - /// - /// Returns the formatted string. - /// - /// - /// Throw when is the string is not a valid hex representation of a byte array. - /// - private string ClearHexString(string hexString) - { - bool hasHexPrefix = hexString.StartsWith("0x", StringComparison.InvariantCultureIgnoreCase); - - try - { - if (hasHexPrefix) - { - hexString = hexString.Substring(2); - } - - if (hexString.Length % 2 == 1) - { - // if the length is an odd number, it cannot be parsed to a byte array - // it may be a valid hex string, so include a leading zero to parse correctly - hexString = "0" + hexString; - } - - if (hasHexPrefix) - { - // if the input value starts with '0x', the first byte is the less significant - // to parse correctly, reverse the byte array - return hexString.HexToBytes().Reverse().ToArray().ToHexString(); - } - } - catch (FormatException) - { - throw new ArgumentException(); - } - - return hexString; - } - - /// - /// Converts a string in a hexadecimal value - /// - /// - /// String value to be converted - /// - /// - /// Returns null when it is not possible to parse the string value to a hexadecimal - /// value; otherwise returns the hexadecimal value that represents the converted string - /// - private string? StringToHex(string strParam) + [ParseFunction("String to Base64")] + private string? StringToBase64(string strParam) { try { - var bytesParam = Utility.StrictUTF8.GetBytes(strParam); - return bytesParam.ToHexString(); + var bytearray = Utility.StrictUTF8.GetBytes(strParam); + return Convert.ToBase64String(bytearray.AsSpan()); } catch { @@ -184,25 +127,21 @@ private string ClearHexString(string hexString) } /// - /// Converts a string in Base64 string + /// Big Integer to Base64 + /// input: 123456 + /// output: QOIB /// - /// - /// String value to be converted - /// - /// - /// Returns null when is not possible to parse the string value to a Base64 value; - /// otherwise returns the Base64 value that represents the converted string - /// - /// - /// Throw . - /// - private string? StringToBase64(string strParam) + [ParseFunction("Big Integer to Base64")] + private string? NumberToBase64(string strParam) { try { - byte[] bytearray = Utility.StrictUTF8.GetBytes(strParam); - string base64 = Convert.ToBase64String(bytearray.AsSpan()); - return base64; + if (!BigInteger.TryParse(strParam, out var number)) + { + return null; + } + var bytearray = number.ToByteArray(); + return Convert.ToBase64String(bytearray.AsSpan()); } catch { @@ -210,56 +149,56 @@ private string ClearHexString(string hexString) } } + private static bool IsHex(string str) => str.Length % 2 == 0 && str.All(c => (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')); + /// - /// Converts a string number in hexadecimal format + /// Fix for Base64 strings containing unicode + /// input: DCECbzTesnBofh/Xng1SofChKkBC7jhVmLxCN1vk\u002B49xa2pBVuezJw== + /// output: DCECbzTesnBofh/Xng1SofChKkBC7jhVmLxCN1vk+49xa2pBVuezJw== /// - /// - /// String that represents the number to be converted - /// - /// - /// Returns null when the string does not represent a big integer value or when - /// it is not possible to parse the big integer value to hexadecimal; otherwise, - /// returns the string that represents the converted hexadecimal value - /// - private string? NumberToHex(string strParam) + /// Base64 strings containing unicode + /// Correct Base64 string + private static string Base64Fixed(string str) { - try + var sb = new StringBuilder(); + for (var i = 0; i < str.Length; i++) { - if (!BigInteger.TryParse(strParam, out var numberParam)) + if (str[i] == '\\' && i + 5 < str.Length && str[i + 1] == 'u') { - return null; + var hex = str.Substring(i + 2, 4); + if (IsHex(hex)) + { + var bts = new byte[2]; + bts[0] = (byte)int.Parse(hex.Substring(2, 2), NumberStyles.HexNumber); + bts[1] = (byte)int.Parse(hex.Substring(0, 2), NumberStyles.HexNumber); + sb.Append(Encoding.Unicode.GetString(bts)); + i += 5; + } + else + { + sb.Append(str[i]); + } + } + else + { + sb.Append(str[i]); } - return numberParam.ToByteArray().ToHexString(); - } - catch - { - return null; } + return sb.ToString(); } /// - /// Converts a string number in Base64 byte array + /// Address to ScriptHash (big-endian) + /// input: NejD7DJWzD48ZG4gXKDVZt3QLf1fpNe1PF + /// output: 0x3ff68d232a60f23a5805b8c40f7e61747f6f61ce /// - /// - /// String that represents the number to be converted - /// - /// - /// Returns null when the string does not represent a big integer value or when - /// it is not possible to parse the big integer value to Base64 value; otherwise, - /// returns the string that represents the converted Base64 value - /// - private string? NumberToBase64(string strParam) + [ParseFunction("Address to ScriptHash (big-endian)")] + private string? AddressToScripthash(string address) { try { - if (!BigInteger.TryParse(strParam, out var number)) - { - return null; - } - byte[] bytearray = number.ToByteArray(); - string base64 = Convert.ToBase64String(bytearray.AsSpan()); - - return base64; + var bigEndScript = address.ToScriptHash(NeoSystem.Settings.AddressVersion); + return bigEndScript.ToString(); } catch { @@ -268,23 +207,17 @@ private string ClearHexString(string hexString) } /// - /// Converts an address to its corresponding scripthash + /// Address to ScriptHash (blittleig-endian) + /// input: NejD7DJWzD48ZG4gXKDVZt3QLf1fpNe1PF + /// output: ce616f7f74617e0fc4b805583af2602a238df63f /// - /// - /// String that represents the address to be converted - /// - /// - /// Returns null when the string does not represent an address or when - /// it is not possible to parse the address to scripthash; otherwise returns - /// the string that represents the converted scripthash - /// - private string? AddressToScripthash(string address) + [ParseFunction("Address to ScriptHash (little-endian)")] + private string? AddressToScripthashLE(string address) { try { var bigEndScript = address.ToScriptHash(NeoSystem.Settings.AddressVersion); - - return bigEndScript.ToString(); + return bigEndScript.ToArray().ToHexString(); } catch { @@ -293,24 +226,17 @@ private string ClearHexString(string hexString) } /// - /// Converts an address to Base64 byte array + /// Address to Base64 + /// input: NejD7DJWzD48ZG4gXKDVZt3QLf1fpNe1PF + /// output: zmFvf3Rhfg/EuAVYOvJgKiON9j8= /// - /// - /// String that represents the address to be converted - /// - /// - /// Returns null when the string does not represent an address or when it is - /// not possible to parse the address to Base64 value; otherwise returns - /// the string that represents the converted Base64 value. - /// + [ParseFunction("Address to Base64")] private string? AddressToBase64(string address) { try { var script = address.ToScriptHash(NeoSystem.Settings.AddressVersion); - string base64 = Convert.ToBase64String(script.ToArray().AsSpan()); - - return base64; + return Convert.ToBase64String(script.ToArray().AsSpan()); } catch { @@ -319,15 +245,11 @@ private string ClearHexString(string hexString) } /// - /// Converts a big end script hash to its equivalent address + /// ScriptHash to Address + /// input: 0x3ff68d232a60f23a5805b8c40f7e61747f6f61ce + /// output: NejD7DJWzD48ZG4gXKDVZt3QLf1fpNe1PF /// - /// - /// String that represents the scripthash to be converted - /// - /// - /// Returns null when the string does not represent an scripthash; - /// otherwise, returns the string that represents the converted address - /// + [ParseFunction("ScriptHash to Address")] private string? ScripthashToAddress(string script) { try @@ -346,15 +268,14 @@ private string ClearHexString(string hexString) { return null; } - string bigEndScript = littleEndScript.ToArray().ToHexString(); + var bigEndScript = littleEndScript.ToArray().ToHexString(); if (!UInt160.TryParse(bigEndScript, out scriptHash)) { return null; } } - var hexScript = scriptHash.ToAddress(NeoSystem.Settings.AddressVersion); - return hexScript; + return scriptHash.ToAddress(NeoSystem.Settings.AddressVersion); } catch { @@ -363,30 +284,24 @@ private string ClearHexString(string hexString) } /// - /// Converts an Base64 byte array to address + /// Base64 to Address + /// input: zmFvf3Rhfg/EuAVYOvJgKiON9j8= + /// output: NejD7DJWzD48ZG4gXKDVZt3QLf1fpNe1PF /// - /// - /// String that represents the Base64 value - /// - /// - /// Returns null when the string does not represent an Base64 value or when - /// it is not possible to parse the Base64 value to address; otherwise, - /// returns the string that represents the converted address - /// + [ParseFunction("Base64 to Address")] private string? Base64ToAddress(string bytearray) { try { - byte[] result = Convert.FromBase64String(bytearray).Reverse().ToArray(); - string hex = result.ToHexString(); + var result = Convert.FromBase64String(bytearray).Reverse().ToArray(); + var hex = result.ToHexString(); if (!UInt160.TryParse(hex, out var scripthash)) { return null; } - string address = scripthash.ToAddress(NeoSystem.Settings.AddressVersion); - return address; + return scripthash.ToAddress(NeoSystem.Settings.AddressVersion); } catch { @@ -395,23 +310,17 @@ private string ClearHexString(string hexString) } /// - /// Converts an Base64 hex string to string + /// Base64 to String + /// input: SGVsbG8gV29ybGQh + /// output: Hello World! /// - /// - /// String that represents the Base64 value - /// - /// - /// Returns null when the string does not represent an Base64 value or when - /// it is not possible to parse the Base64 value to string value or the converted - /// string is not printable; otherwise, returns the string that represents - /// the Base64 value. - /// + [ParseFunction("Base64 to String")] private string? Base64ToString(string bytearray) { try { - byte[] result = Convert.FromBase64String(bytearray); - string utf8String = Utility.StrictUTF8.GetString(result); + var result = Convert.FromBase64String(bytearray); + var utf8String = Utility.StrictUTF8.GetString(result); return IsPrintable(utf8String) ? utf8String : null; } catch @@ -421,16 +330,11 @@ private string ClearHexString(string hexString) } /// - /// Converts an Base64 hex string to big integer value + /// Base64 to Big Integer + /// input: QOIB + /// output: 123456 /// - /// - /// String that represents the Base64 value - /// - /// - /// Returns null when the string does not represent an Base64 value or when - /// it is not possible to parse the Base64 value to big integer value; otherwise - /// returns the string that represents the converted big integer - /// + [ParseFunction("Base64 to Big Integer")] private string? Base64ToNumber(string bytearray) { try @@ -445,6 +349,132 @@ private string ClearHexString(string hexString) } } + /// + /// Public Key to Address + /// input: 03dab84c1243ec01ab2500e1a8c7a1546a26d734628180b0cf64e72bf776536997 + /// output: NU7RJrzNgCSnoPLxmcY7C72fULkpaGiSpJ + /// + [ParseFunction("Public Key to Address")] + private string? PublicKeyToAddress(string pubKey) + { + if (ECPoint.TryParse(pubKey, ECCurve.Secp256r1, out var publicKey) == false) + return null; + return Contract.CreateSignatureContract(publicKey) + .ScriptHash + .ToAddress(NeoSystem.Settings.AddressVersion); + } + + /// + /// WIF to Public Key + /// + [ParseFunction("WIF to Public Key")] + private string? WIFToPublicKey(string wif) + { + try + { + var privateKey = Wallet.GetPrivateKeyFromWIF(wif); + var account = new KeyPair(privateKey); + return account.PublicKey.ToArray().ToHexString(); + } + catch (Exception) + { + return null; + } + } + + /// + /// WIF to Address + /// + [ParseFunction("WIF to Address")] + private string? WIFToAddress(string wif) + { + try + { + var pubKey = WIFToPublicKey(wif); + return Contract.CreateSignatureContract(ECPoint.Parse(pubKey, ECCurve.Secp256r1)).ScriptHash.ToAddress(NeoSystem.Settings.AddressVersion); + } + catch (Exception) + { + return null; + } + } + + /// + /// Base64 Smart Contract Script Analysis + /// input: DARkYXRhAgBlzR0MFPdcrAXPVptVduMEs2lf1jQjxKIKDBT3XKwFz1abVXbjBLNpX9Y0I8SiChTAHwwIdHJhbnNmZXIMFKNSbimM12LkFYX/8KGvm2ttFxulQWJ9W1I= + /// output: + /// PUSHDATA1 data + /// PUSHINT32 500000000 + /// PUSHDATA1 0x0aa2c42334d65f69b304e376559b56cf05ac5cf7 + /// PUSHDATA1 0x0aa2c42334d65f69b304e376559b56cf05ac5cf7 + /// PUSH4 + /// PACK + /// PUSH15 + /// PUSHDATA1 transfer + /// PUSHDATA1 0xa51b176d6b9bafa1f0ff8515e462d78c296e52a3 + /// SYSCALL System.Contract.Call + /// + [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); + } + + 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) + { + 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)}"); + } + else + { + result.Add($"{op}"); + } + } + } + return Environment.NewLine + string.Join("\r\n", result.ToArray()); + } + /// /// Checks if the string is null or cannot be printed. /// @@ -455,7 +485,7 @@ private string ClearHexString(string hexString) /// Returns false if the string is null, or if it is empty, or if each character cannot be printed; /// otherwise, returns true. /// - private bool IsPrintable(string value) + private static bool IsPrintable(string value) { return !string.IsNullOrWhiteSpace(value) && value.Any(c => !char.IsControl(c)); } diff --git a/src/Neo.CLI/CLI/ParseFunctionAttribute.cs b/src/Neo.CLI/CLI/ParseFunctionAttribute.cs new file mode 100644 index 0000000000..7dc92c661a --- /dev/null +++ b/src/Neo.CLI/CLI/ParseFunctionAttribute.cs @@ -0,0 +1,25 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// ParseFunctionAttribute.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; + +namespace Neo.CLI +{ + internal class ParseFunctionAttribute : Attribute + { + public string Description { get; } + + public ParseFunctionAttribute(string description) + { + Description = description; + } + } +} From 08f2dfc56762bb43be33e873bc3659bad368d4d6 Mon Sep 17 00:00:00 2001 From: Christopher Schuchardt Date: Mon, 20 May 2024 15:39:46 -0400 Subject: [PATCH 134/168] Make `ApplicationEngine.LoadContext` protection level `public` (#3243) --- src/Neo.VM/ExecutionEngine.cs | 2 +- src/Neo/SmartContract/ApplicationEngine.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Neo.VM/ExecutionEngine.cs b/src/Neo.VM/ExecutionEngine.cs index 38a2dccb07..c7c3f86ce9 100644 --- a/src/Neo.VM/ExecutionEngine.cs +++ b/src/Neo.VM/ExecutionEngine.cs @@ -166,7 +166,7 @@ protected internal void ExecuteNext() /// Loads the specified context into the invocation stack. /// /// The context to load. - protected internal virtual void LoadContext(ExecutionContext context) + public virtual void LoadContext(ExecutionContext context) { if (InvocationStack.Count >= Limits.MaxInvocationStackSize) throw new InvalidOperationException($"MaxInvocationStackSize exceed: {InvocationStack.Count}"); diff --git a/src/Neo/SmartContract/ApplicationEngine.cs b/src/Neo/SmartContract/ApplicationEngine.cs index 8dd5c27a1e..14dedf8e7c 100644 --- a/src/Neo/SmartContract/ApplicationEngine.cs +++ b/src/Neo/SmartContract/ApplicationEngine.cs @@ -384,7 +384,7 @@ public static ApplicationEngine Create(TriggerType trigger, IVerifiable containe ?? new ApplicationEngine(trigger, container, snapshot, persistingBlock, settings, gas, diagnostic, jumpTable); } - protected internal override void LoadContext(ExecutionContext context) + public override void LoadContext(ExecutionContext context) { // Set default execution context state var state = context.GetState(); From 0f04c7f1c460ea88b8d081b8241ab28e23d02a85 Mon Sep 17 00:00:00 2001 From: Christopher Schuchardt Date: Tue, 21 May 2024 04:01:41 -0400 Subject: [PATCH 135/168] [**Part-1**] `neo-module/master` (#3232) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Moved `neo-modules` to `neo` * Configured module projects * Configured Test Projects * Dotnet format * Update github workflow for tests * removed dupes in `.editorconfig` * remove dupe file * Fixed waarning * fixed `macOS` workflow for leveldb * Added `EXCLUDED_TESTS` for `Neo.Plugins.Storage` on `macOS` and `Windows` * Fixed workflow tests for `windows` * Fixed `char` ecsape for tests on `windows` * Fixed tests * Fixed tests * Apply suggestions from code review Not related to the PR * Apply suggestions from code review * Update .editorconfig * Update .editorconfig * Changed for @vncoelho request * Added @vncoelho changes * Moved `RpcClient` to `src\plugins` * fixed rpc tests * Update .github/workflows/main.yml Co-authored-by: Shargon * Update .github/workflows/main.yml * Update .github/workflows/main.yml --------- Co-authored-by: Shargon Co-authored-by: Vitor Nazário Coelho --- .editorconfig | 2 +- .gitattributes | 2 + .github/workflows/main.yml | 12 +- {src => .neo}/README.md | 0 {src => .neo}/neo.png | Bin neo.sln | 135 +- src/Directory.Build.props | 4 +- .../ApplicationLogs/ApplicationLogs.csproj | 16 + src/Plugins/ApplicationLogs/LogReader.cs | 457 +++ src/Plugins/ApplicationLogs/Settings.cs | 39 + .../ApplicationLogs/Store/LogStorageStore.cs | 415 ++ .../Store/Models/ApplicationEngineLogModel.cs | 28 + .../Store/Models/BlockchainEventModel.cs | 48 + .../Store/Models/BlockchainExecutionModel.cs | 40 + src/Plugins/ApplicationLogs/Store/NeoStore.cs | 308 ++ .../Store/States/BlockLogState.cs | 72 + .../Store/States/ContractLogState.cs | 74 + .../Store/States/EngineLogState.cs | 66 + .../Store/States/ExecutionLogState.cs | 94 + .../Store/States/NotifyLogState.cs | 87 + .../Store/States/TransactionEngineLogState.cs | 71 + .../Store/States/TransactionLogState.cs | 72 + src/Plugins/ApplicationLogs/config.json | 11 + .../Consensus/ConsensusContext.Get.cs | 117 + .../Consensus/ConsensusContext.MakePayload.cs | 176 + .../DBFTPlugin/Consensus/ConsensusContext.cs | 323 ++ .../Consensus/ConsensusService.Check.cs | 102 + .../Consensus/ConsensusService.OnMessage.cs | 317 ++ .../DBFTPlugin/Consensus/ConsensusService.cs | 344 ++ src/Plugins/DBFTPlugin/DBFTPlugin.cs | 101 + src/Plugins/DBFTPlugin/DBFTPlugin.csproj | 13 + src/Plugins/DBFTPlugin/Messages/ChangeView.cs | 56 + src/Plugins/DBFTPlugin/Messages/Commit.cs | 38 + .../DBFTPlugin/Messages/ConsensusMessage.cs | 69 + .../DBFTPlugin/Messages/PrepareRequest.cs | 64 + .../DBFTPlugin/Messages/PrepareResponse.cs | 37 + ...ecoveryMessage.ChangeViewPayloadCompact.cs | 50 + .../RecoveryMessage.CommitPayloadCompact.cs | 50 + ...coveryMessage.PreparationPayloadCompact.cs | 42 + .../RecoveryMessage/RecoveryMessage.cs | 131 + .../RecoveryMessage/RecoveryRequest.cs | 43 + src/Plugins/DBFTPlugin/Settings.cs | 35 + .../DBFTPlugin/Types/ChangeViewReason.cs | 23 + .../DBFTPlugin/Types/ConsensusMessageType.cs | 25 + src/Plugins/DBFTPlugin/config.json | 10 + src/Plugins/Directory.Build.props | 21 + .../LevelDBStore/IO/Data/LevelDB/DB.cs | 114 + .../LevelDBStore/IO/Data/LevelDB/Helper.cs | 63 + .../LevelDBStore/IO/Data/LevelDB/Iterator.cs | 86 + .../IO/Data/LevelDB/LevelDBException.cs | 23 + .../LevelDBStore/IO/Data/LevelDB/Native.cs | 264 ++ .../LevelDBStore/IO/Data/LevelDB/Options.cs | 98 + .../IO/Data/LevelDB/ReadOptions.cs | 50 + .../LevelDBStore/IO/Data/LevelDB/Snapshot.cs | 35 + .../IO/Data/LevelDB/WriteBatch.cs | 40 + .../IO/Data/LevelDB/WriteOptions.cs | 36 + src/Plugins/LevelDBStore/LevelDBStore.csproj | 10 + .../Plugins/Storage/LevelDBStore.cs | 35 + .../LevelDBStore/Plugins/Storage/Snapshot.cs | 69 + .../LevelDBStore/Plugins/Storage/Store.cs | 67 + .../MPTTrie/Cryptography/MPTTrie/Cache.cs | 126 + .../MPTTrie/Cryptography/MPTTrie/Helper.cs | 28 + .../Cryptography/MPTTrie/Node.Branch.cs | 69 + .../Cryptography/MPTTrie/Node.Extension.cs | 55 + .../MPTTrie/Cryptography/MPTTrie/Node.Hash.cs | 43 + .../MPTTrie/Cryptography/MPTTrie/Node.Leaf.cs | 48 + .../MPTTrie/Cryptography/MPTTrie/Node.cs | 230 ++ .../MPTTrie/Cryptography/MPTTrie/NodeType.cs | 22 + .../Cryptography/MPTTrie/Trie.Delete.cs | 136 + .../MPTTrie/Cryptography/MPTTrie/Trie.Find.cs | 170 + .../MPTTrie/Cryptography/MPTTrie/Trie.Get.cs | 90 + .../Cryptography/MPTTrie/Trie.Proof.cs | 95 + .../MPTTrie/Cryptography/MPTTrie/Trie.Put.cs | 159 + .../MPTTrie/Cryptography/MPTTrie/Trie.cs | 62 + .../MPTTrie/IO/ByteArrayEqualityComparer.cs | 58 + src/Plugins/MPTTrie/MPTTrie.csproj | 10 + src/Plugins/OracleService/Helper.cs | 52 + src/Plugins/OracleService/OracleService.cs | 584 +++ .../OracleService/OracleService.csproj | 20 + .../Protocols/IOracleProtocol.cs | 24 + .../Protocols/OracleHttpsProtocol.cs | 115 + .../Protocols/OracleNeoFSProtocol.cs | 155 + src/Plugins/OracleService/Settings.cs | 72 + src/Plugins/OracleService/config.json | 21 + .../RocksDBStore/Plugins/Storage/Options.cs | 36 + .../Plugins/Storage/RocksDBStore.cs | 34 + .../RocksDBStore/Plugins/Storage/Snapshot.cs | 82 + .../RocksDBStore/Plugins/Storage/Store.cs | 77 + src/Plugins/RocksDBStore/RocksDBStore.csproj | 13 + src/Plugins/RpcClient/ContractClient.cs | 77 + src/Plugins/RpcClient/Models/RpcAccount.cs | 48 + .../RpcClient/Models/RpcApplicationLog.cs | 118 + src/Plugins/RpcClient/Models/RpcBlock.cs | 43 + .../RpcClient/Models/RpcBlockHeader.cs | 43 + .../RpcClient/Models/RpcContractState.cs | 42 + .../RpcClient/Models/RpcFoundStates.cs | 44 + .../RpcClient/Models/RpcInvokeResult.cs | 100 + .../RpcClient/Models/RpcMethodToken.cs | 32 + src/Plugins/RpcClient/Models/RpcNefFile.cs | 33 + .../RpcClient/Models/RpcNep17Balances.cs | 73 + .../RpcClient/Models/RpcNep17TokenInfo.cs | 26 + .../RpcClient/Models/RpcNep17Transfers.cs | 92 + src/Plugins/RpcClient/Models/RpcPeers.cs | 68 + src/Plugins/RpcClient/Models/RpcPlugin.cs | 44 + src/Plugins/RpcClient/Models/RpcRawMemPool.cs | 45 + src/Plugins/RpcClient/Models/RpcRequest.cs | 48 + src/Plugins/RpcClient/Models/RpcResponse.cs | 83 + src/Plugins/RpcClient/Models/RpcStateRoot.cs | 36 + .../RpcClient/Models/RpcTransaction.cs | 62 + .../RpcClient/Models/RpcTransferOut.cs | 45 + .../RpcClient/Models/RpcUnclaimedGas.cs | 39 + .../Models/RpcValidateAddressResult.cs | 39 + src/Plugins/RpcClient/Models/RpcValidator.cs | 40 + src/Plugins/RpcClient/Models/RpcVersion.cs | 113 + src/Plugins/RpcClient/Nep17API.cs | 182 + src/Plugins/RpcClient/PolicyAPI.cs | 71 + .../RpcClient/Properties/AssemblyInfo.cs | 14 + src/Plugins/RpcClient/RpcClient.cs | 712 ++++ src/Plugins/RpcClient/RpcClient.csproj | 13 + src/Plugins/RpcClient/RpcException.cs | 23 + src/Plugins/RpcClient/StateAPI.cs | 88 + src/Plugins/RpcClient/TransactionManager.cs | 215 ++ .../RpcClient/TransactionManagerFactory.cs | 71 + src/Plugins/RpcClient/Utility.cs | 298 ++ src/Plugins/RpcClient/WalletAPI.cs | 225 ++ src/Plugins/RpcServer/Diagnostic.cs | 53 + src/Plugins/RpcServer/Result.cs | 116 + src/Plugins/RpcServer/RpcError.cs | 103 + src/Plugins/RpcServer/RpcErrorFactory.cs | 43 + src/Plugins/RpcServer/RpcException.cs | 23 + src/Plugins/RpcServer/RpcMethodAttribute.cs | 21 + src/Plugins/RpcServer/RpcServer.Blockchain.cs | 339 ++ src/Plugins/RpcServer/RpcServer.Node.cs | 168 + .../RpcServer/RpcServer.SmartContract.cs | 297 ++ src/Plugins/RpcServer/RpcServer.Utilities.cs | 55 + src/Plugins/RpcServer/RpcServer.Wallet.cs | 423 +++ src/Plugins/RpcServer/RpcServer.cs | 312 ++ src/Plugins/RpcServer/RpcServer.csproj | 12 + src/Plugins/RpcServer/RpcServerPlugin.cs | 85 + src/Plugins/RpcServer/Session.cs | 58 + src/Plugins/RpcServer/Settings.cs | 105 + src/Plugins/RpcServer/Tree.cs | 36 + src/Plugins/RpcServer/TreeNode.cs | 45 + src/Plugins/RpcServer/Utility.cs | 36 + src/Plugins/RpcServer/config.json | 29 + src/Plugins/SQLiteWallet/Account.cs | 18 + src/Plugins/SQLiteWallet/Address.cs | 17 + src/Plugins/SQLiteWallet/Contract.cs | 21 + src/Plugins/SQLiteWallet/Key.cs | 18 + src/Plugins/SQLiteWallet/SQLiteWallet.cs | 416 ++ src/Plugins/SQLiteWallet/SQLiteWallet.csproj | 14 + .../SQLiteWallet/SQLiteWalletAccount.cs | 29 + .../SQLiteWallet/SQLiteWalletFactory.cs | 41 + .../SQLiteWallet/VerificationContract.cs | 56 + src/Plugins/SQLiteWallet/WalletDataContext.cs | 64 + .../StateService/Network/MessageType.cs | 19 + src/Plugins/StateService/Network/StateRoot.cs | 123 + src/Plugins/StateService/Network/Vote.cs | 40 + src/Plugins/StateService/README.md | 70 + src/Plugins/StateService/Settings.cs | 40 + src/Plugins/StateService/StatePlugin.cs | 359 ++ src/Plugins/StateService/StateService.csproj | 15 + src/Plugins/StateService/Storage/Keys.cs | 30 + .../StateService/Storage/StateSnapshot.cs | 92 + .../StateService/Storage/StateStore.cs | 188 + .../Verification/VerificationContext.cs | 177 + .../Verification/VerificationService.cs | 170 + src/Plugins/StateService/config.json | 12 + src/Plugins/StatesDumper/PersistActions.cs | 21 + src/Plugins/StatesDumper/Settings.cs | 58 + src/Plugins/StatesDumper/StatesDumper.cs | 167 + src/Plugins/StatesDumper/StatesDumper.csproj | 12 + src/Plugins/StatesDumper/config.json | 9 + src/Plugins/StorageDumper/Settings.cs | 47 + src/Plugins/StorageDumper/StorageDumper.cs | 182 + .../StorageDumper/StorageDumper.csproj | 14 + src/Plugins/StorageDumper/config.json | 7 + src/Plugins/TokensTracker/Extensions.cs | 67 + src/Plugins/TokensTracker/TokensTracker.cs | 102 + .../TokensTracker/TokensTracker.csproj | 12 + .../Trackers/NEP-11/Nep11BalanceKey.cs | 81 + .../Trackers/NEP-11/Nep11Tracker.cs | 321 ++ .../Trackers/NEP-11/Nep11TransferKey.cs | 80 + .../Trackers/NEP-17/Nep17BalanceKey.cs | 75 + .../Trackers/NEP-17/Nep17Tracker.cs | 256 ++ .../Trackers/NEP-17/Nep17TransferKey.cs | 59 + .../TokensTracker/Trackers/TokenBalance.cs | 39 + .../TokensTracker/Trackers/TokenTransfer.cs | 47 + .../Trackers/TokenTransferKey.cs | 57 + .../TokensTracker/Trackers/TrackerBase.cs | 162 + src/Plugins/TokensTracker/config.json | 12 + .../Cryptography/MPTTrie/Helper.cs | 32 + .../Cryptography/MPTTrie/UT_Cache.cs | 235 ++ .../Cryptography/MPTTrie/UT_Helper.cs | 37 + .../Cryptography/MPTTrie/UT_Node.cs | 216 ++ .../Cryptography/MPTTrie/UT_Trie.cs | 573 +++ .../Neo.Cryptography.MPTTrie.Tests.csproj | 18 + .../Neo.Network.RPC.Tests.csproj | 26 + tests/Neo.Network.RPC.Tests/RpcTestCases.json | 3340 +++++++++++++++++ tests/Neo.Network.RPC.Tests/TestUtils.cs | 95 + .../UT_ContractClient.cs | 81 + tests/Neo.Network.RPC.Tests/UT_Nep17API.cs | 168 + tests/Neo.Network.RPC.Tests/UT_PolicyAPI.cs | 79 + tests/Neo.Network.RPC.Tests/UT_RpcClient.cs | 525 +++ tests/Neo.Network.RPC.Tests/UT_RpcModels.cs | 175 + .../UT_TransactionManager.cs | 267 ++ tests/Neo.Network.RPC.Tests/UT_Utility.cs | 87 + tests/Neo.Network.RPC.Tests/UT_WalletAPI.cs | 181 + .../Neo.Plugins.OracleService.Tests.csproj | 28 + .../TestBlockchain.cs | 36 + .../TestUtils.cs | 32 + .../UT_OracleService.cs | 118 + .../config.json | 74 + .../Neo.Plugins.RpcServer.Tests.csproj | 19 + .../UT_RpcError.cs | 48 + .../UT_RpcServer.cs | 20 + .../Neo.Plugins.Storage.Tests.csproj | 19 + tests/Neo.Plugins.Storage.Tests/StoreTest.cs | 200 + 218 files changed, 24259 insertions(+), 6 deletions(-) rename {src => .neo}/README.md (100%) rename {src => .neo}/neo.png (100%) create mode 100644 src/Plugins/ApplicationLogs/ApplicationLogs.csproj create mode 100644 src/Plugins/ApplicationLogs/LogReader.cs create mode 100644 src/Plugins/ApplicationLogs/Settings.cs create mode 100644 src/Plugins/ApplicationLogs/Store/LogStorageStore.cs create mode 100644 src/Plugins/ApplicationLogs/Store/Models/ApplicationEngineLogModel.cs create mode 100644 src/Plugins/ApplicationLogs/Store/Models/BlockchainEventModel.cs create mode 100644 src/Plugins/ApplicationLogs/Store/Models/BlockchainExecutionModel.cs create mode 100644 src/Plugins/ApplicationLogs/Store/NeoStore.cs create mode 100644 src/Plugins/ApplicationLogs/Store/States/BlockLogState.cs create mode 100644 src/Plugins/ApplicationLogs/Store/States/ContractLogState.cs create mode 100644 src/Plugins/ApplicationLogs/Store/States/EngineLogState.cs create mode 100644 src/Plugins/ApplicationLogs/Store/States/ExecutionLogState.cs create mode 100644 src/Plugins/ApplicationLogs/Store/States/NotifyLogState.cs create mode 100644 src/Plugins/ApplicationLogs/Store/States/TransactionEngineLogState.cs create mode 100644 src/Plugins/ApplicationLogs/Store/States/TransactionLogState.cs create mode 100644 src/Plugins/ApplicationLogs/config.json create mode 100644 src/Plugins/DBFTPlugin/Consensus/ConsensusContext.Get.cs create mode 100644 src/Plugins/DBFTPlugin/Consensus/ConsensusContext.MakePayload.cs create mode 100644 src/Plugins/DBFTPlugin/Consensus/ConsensusContext.cs create mode 100644 src/Plugins/DBFTPlugin/Consensus/ConsensusService.Check.cs create mode 100644 src/Plugins/DBFTPlugin/Consensus/ConsensusService.OnMessage.cs create mode 100644 src/Plugins/DBFTPlugin/Consensus/ConsensusService.cs create mode 100644 src/Plugins/DBFTPlugin/DBFTPlugin.cs create mode 100644 src/Plugins/DBFTPlugin/DBFTPlugin.csproj create mode 100644 src/Plugins/DBFTPlugin/Messages/ChangeView.cs create mode 100644 src/Plugins/DBFTPlugin/Messages/Commit.cs create mode 100644 src/Plugins/DBFTPlugin/Messages/ConsensusMessage.cs create mode 100644 src/Plugins/DBFTPlugin/Messages/PrepareRequest.cs create mode 100644 src/Plugins/DBFTPlugin/Messages/PrepareResponse.cs create mode 100644 src/Plugins/DBFTPlugin/Messages/RecoveryMessage/RecoveryMessage.ChangeViewPayloadCompact.cs create mode 100644 src/Plugins/DBFTPlugin/Messages/RecoveryMessage/RecoveryMessage.CommitPayloadCompact.cs create mode 100644 src/Plugins/DBFTPlugin/Messages/RecoveryMessage/RecoveryMessage.PreparationPayloadCompact.cs create mode 100644 src/Plugins/DBFTPlugin/Messages/RecoveryMessage/RecoveryMessage.cs create mode 100644 src/Plugins/DBFTPlugin/Messages/RecoveryMessage/RecoveryRequest.cs create mode 100644 src/Plugins/DBFTPlugin/Settings.cs create mode 100644 src/Plugins/DBFTPlugin/Types/ChangeViewReason.cs create mode 100644 src/Plugins/DBFTPlugin/Types/ConsensusMessageType.cs create mode 100644 src/Plugins/DBFTPlugin/config.json create mode 100644 src/Plugins/Directory.Build.props create mode 100644 src/Plugins/LevelDBStore/IO/Data/LevelDB/DB.cs create mode 100644 src/Plugins/LevelDBStore/IO/Data/LevelDB/Helper.cs create mode 100644 src/Plugins/LevelDBStore/IO/Data/LevelDB/Iterator.cs create mode 100644 src/Plugins/LevelDBStore/IO/Data/LevelDB/LevelDBException.cs create mode 100644 src/Plugins/LevelDBStore/IO/Data/LevelDB/Native.cs create mode 100644 src/Plugins/LevelDBStore/IO/Data/LevelDB/Options.cs create mode 100644 src/Plugins/LevelDBStore/IO/Data/LevelDB/ReadOptions.cs create mode 100644 src/Plugins/LevelDBStore/IO/Data/LevelDB/Snapshot.cs create mode 100644 src/Plugins/LevelDBStore/IO/Data/LevelDB/WriteBatch.cs create mode 100644 src/Plugins/LevelDBStore/IO/Data/LevelDB/WriteOptions.cs create mode 100644 src/Plugins/LevelDBStore/LevelDBStore.csproj create mode 100644 src/Plugins/LevelDBStore/Plugins/Storage/LevelDBStore.cs create mode 100644 src/Plugins/LevelDBStore/Plugins/Storage/Snapshot.cs create mode 100644 src/Plugins/LevelDBStore/Plugins/Storage/Store.cs create mode 100644 src/Plugins/MPTTrie/Cryptography/MPTTrie/Cache.cs create mode 100644 src/Plugins/MPTTrie/Cryptography/MPTTrie/Helper.cs create mode 100644 src/Plugins/MPTTrie/Cryptography/MPTTrie/Node.Branch.cs create mode 100644 src/Plugins/MPTTrie/Cryptography/MPTTrie/Node.Extension.cs create mode 100644 src/Plugins/MPTTrie/Cryptography/MPTTrie/Node.Hash.cs create mode 100644 src/Plugins/MPTTrie/Cryptography/MPTTrie/Node.Leaf.cs create mode 100644 src/Plugins/MPTTrie/Cryptography/MPTTrie/Node.cs create mode 100644 src/Plugins/MPTTrie/Cryptography/MPTTrie/NodeType.cs create mode 100644 src/Plugins/MPTTrie/Cryptography/MPTTrie/Trie.Delete.cs create mode 100644 src/Plugins/MPTTrie/Cryptography/MPTTrie/Trie.Find.cs create mode 100644 src/Plugins/MPTTrie/Cryptography/MPTTrie/Trie.Get.cs create mode 100644 src/Plugins/MPTTrie/Cryptography/MPTTrie/Trie.Proof.cs create mode 100644 src/Plugins/MPTTrie/Cryptography/MPTTrie/Trie.Put.cs create mode 100644 src/Plugins/MPTTrie/Cryptography/MPTTrie/Trie.cs create mode 100644 src/Plugins/MPTTrie/IO/ByteArrayEqualityComparer.cs create mode 100644 src/Plugins/MPTTrie/MPTTrie.csproj create mode 100644 src/Plugins/OracleService/Helper.cs create mode 100644 src/Plugins/OracleService/OracleService.cs create mode 100644 src/Plugins/OracleService/OracleService.csproj create mode 100644 src/Plugins/OracleService/Protocols/IOracleProtocol.cs create mode 100644 src/Plugins/OracleService/Protocols/OracleHttpsProtocol.cs create mode 100644 src/Plugins/OracleService/Protocols/OracleNeoFSProtocol.cs create mode 100644 src/Plugins/OracleService/Settings.cs create mode 100644 src/Plugins/OracleService/config.json create mode 100644 src/Plugins/RocksDBStore/Plugins/Storage/Options.cs create mode 100644 src/Plugins/RocksDBStore/Plugins/Storage/RocksDBStore.cs create mode 100644 src/Plugins/RocksDBStore/Plugins/Storage/Snapshot.cs create mode 100644 src/Plugins/RocksDBStore/Plugins/Storage/Store.cs create mode 100644 src/Plugins/RocksDBStore/RocksDBStore.csproj create mode 100644 src/Plugins/RpcClient/ContractClient.cs create mode 100644 src/Plugins/RpcClient/Models/RpcAccount.cs create mode 100644 src/Plugins/RpcClient/Models/RpcApplicationLog.cs create mode 100644 src/Plugins/RpcClient/Models/RpcBlock.cs create mode 100644 src/Plugins/RpcClient/Models/RpcBlockHeader.cs create mode 100644 src/Plugins/RpcClient/Models/RpcContractState.cs create mode 100644 src/Plugins/RpcClient/Models/RpcFoundStates.cs create mode 100644 src/Plugins/RpcClient/Models/RpcInvokeResult.cs create mode 100644 src/Plugins/RpcClient/Models/RpcMethodToken.cs create mode 100644 src/Plugins/RpcClient/Models/RpcNefFile.cs create mode 100644 src/Plugins/RpcClient/Models/RpcNep17Balances.cs create mode 100644 src/Plugins/RpcClient/Models/RpcNep17TokenInfo.cs create mode 100644 src/Plugins/RpcClient/Models/RpcNep17Transfers.cs create mode 100644 src/Plugins/RpcClient/Models/RpcPeers.cs create mode 100644 src/Plugins/RpcClient/Models/RpcPlugin.cs create mode 100644 src/Plugins/RpcClient/Models/RpcRawMemPool.cs create mode 100644 src/Plugins/RpcClient/Models/RpcRequest.cs create mode 100644 src/Plugins/RpcClient/Models/RpcResponse.cs create mode 100644 src/Plugins/RpcClient/Models/RpcStateRoot.cs create mode 100644 src/Plugins/RpcClient/Models/RpcTransaction.cs create mode 100644 src/Plugins/RpcClient/Models/RpcTransferOut.cs create mode 100644 src/Plugins/RpcClient/Models/RpcUnclaimedGas.cs create mode 100644 src/Plugins/RpcClient/Models/RpcValidateAddressResult.cs create mode 100644 src/Plugins/RpcClient/Models/RpcValidator.cs create mode 100644 src/Plugins/RpcClient/Models/RpcVersion.cs create mode 100644 src/Plugins/RpcClient/Nep17API.cs create mode 100644 src/Plugins/RpcClient/PolicyAPI.cs create mode 100644 src/Plugins/RpcClient/Properties/AssemblyInfo.cs create mode 100644 src/Plugins/RpcClient/RpcClient.cs create mode 100644 src/Plugins/RpcClient/RpcClient.csproj create mode 100644 src/Plugins/RpcClient/RpcException.cs create mode 100644 src/Plugins/RpcClient/StateAPI.cs create mode 100644 src/Plugins/RpcClient/TransactionManager.cs create mode 100644 src/Plugins/RpcClient/TransactionManagerFactory.cs create mode 100644 src/Plugins/RpcClient/Utility.cs create mode 100644 src/Plugins/RpcClient/WalletAPI.cs create mode 100644 src/Plugins/RpcServer/Diagnostic.cs create mode 100644 src/Plugins/RpcServer/Result.cs create mode 100644 src/Plugins/RpcServer/RpcError.cs create mode 100644 src/Plugins/RpcServer/RpcErrorFactory.cs create mode 100644 src/Plugins/RpcServer/RpcException.cs create mode 100644 src/Plugins/RpcServer/RpcMethodAttribute.cs create mode 100644 src/Plugins/RpcServer/RpcServer.Blockchain.cs create mode 100644 src/Plugins/RpcServer/RpcServer.Node.cs create mode 100644 src/Plugins/RpcServer/RpcServer.SmartContract.cs create mode 100644 src/Plugins/RpcServer/RpcServer.Utilities.cs create mode 100644 src/Plugins/RpcServer/RpcServer.Wallet.cs create mode 100644 src/Plugins/RpcServer/RpcServer.cs create mode 100644 src/Plugins/RpcServer/RpcServer.csproj create mode 100644 src/Plugins/RpcServer/RpcServerPlugin.cs create mode 100644 src/Plugins/RpcServer/Session.cs create mode 100644 src/Plugins/RpcServer/Settings.cs create mode 100644 src/Plugins/RpcServer/Tree.cs create mode 100644 src/Plugins/RpcServer/TreeNode.cs create mode 100644 src/Plugins/RpcServer/Utility.cs create mode 100644 src/Plugins/RpcServer/config.json create mode 100644 src/Plugins/SQLiteWallet/Account.cs create mode 100644 src/Plugins/SQLiteWallet/Address.cs create mode 100644 src/Plugins/SQLiteWallet/Contract.cs create mode 100644 src/Plugins/SQLiteWallet/Key.cs create mode 100644 src/Plugins/SQLiteWallet/SQLiteWallet.cs create mode 100644 src/Plugins/SQLiteWallet/SQLiteWallet.csproj create mode 100644 src/Plugins/SQLiteWallet/SQLiteWalletAccount.cs create mode 100644 src/Plugins/SQLiteWallet/SQLiteWalletFactory.cs create mode 100644 src/Plugins/SQLiteWallet/VerificationContract.cs create mode 100644 src/Plugins/SQLiteWallet/WalletDataContext.cs create mode 100644 src/Plugins/StateService/Network/MessageType.cs create mode 100644 src/Plugins/StateService/Network/StateRoot.cs create mode 100644 src/Plugins/StateService/Network/Vote.cs create mode 100644 src/Plugins/StateService/README.md create mode 100644 src/Plugins/StateService/Settings.cs create mode 100644 src/Plugins/StateService/StatePlugin.cs create mode 100644 src/Plugins/StateService/StateService.csproj create mode 100644 src/Plugins/StateService/Storage/Keys.cs create mode 100644 src/Plugins/StateService/Storage/StateSnapshot.cs create mode 100644 src/Plugins/StateService/Storage/StateStore.cs create mode 100644 src/Plugins/StateService/Verification/VerificationContext.cs create mode 100644 src/Plugins/StateService/Verification/VerificationService.cs create mode 100644 src/Plugins/StateService/config.json create mode 100644 src/Plugins/StatesDumper/PersistActions.cs create mode 100644 src/Plugins/StatesDumper/Settings.cs create mode 100644 src/Plugins/StatesDumper/StatesDumper.cs create mode 100644 src/Plugins/StatesDumper/StatesDumper.csproj create mode 100644 src/Plugins/StatesDumper/config.json create mode 100644 src/Plugins/StorageDumper/Settings.cs create mode 100644 src/Plugins/StorageDumper/StorageDumper.cs create mode 100644 src/Plugins/StorageDumper/StorageDumper.csproj create mode 100644 src/Plugins/StorageDumper/config.json create mode 100644 src/Plugins/TokensTracker/Extensions.cs create mode 100644 src/Plugins/TokensTracker/TokensTracker.cs create mode 100644 src/Plugins/TokensTracker/TokensTracker.csproj create mode 100644 src/Plugins/TokensTracker/Trackers/NEP-11/Nep11BalanceKey.cs create mode 100644 src/Plugins/TokensTracker/Trackers/NEP-11/Nep11Tracker.cs create mode 100644 src/Plugins/TokensTracker/Trackers/NEP-11/Nep11TransferKey.cs create mode 100644 src/Plugins/TokensTracker/Trackers/NEP-17/Nep17BalanceKey.cs create mode 100644 src/Plugins/TokensTracker/Trackers/NEP-17/Nep17Tracker.cs create mode 100644 src/Plugins/TokensTracker/Trackers/NEP-17/Nep17TransferKey.cs create mode 100644 src/Plugins/TokensTracker/Trackers/TokenBalance.cs create mode 100644 src/Plugins/TokensTracker/Trackers/TokenTransfer.cs create mode 100644 src/Plugins/TokensTracker/Trackers/TokenTransferKey.cs create mode 100644 src/Plugins/TokensTracker/Trackers/TrackerBase.cs create mode 100644 src/Plugins/TokensTracker/config.json create mode 100644 tests/Neo.Cryptography.MPTTrie.Tests/Cryptography/MPTTrie/Helper.cs create mode 100644 tests/Neo.Cryptography.MPTTrie.Tests/Cryptography/MPTTrie/UT_Cache.cs create mode 100644 tests/Neo.Cryptography.MPTTrie.Tests/Cryptography/MPTTrie/UT_Helper.cs create mode 100644 tests/Neo.Cryptography.MPTTrie.Tests/Cryptography/MPTTrie/UT_Node.cs create mode 100644 tests/Neo.Cryptography.MPTTrie.Tests/Cryptography/MPTTrie/UT_Trie.cs create mode 100644 tests/Neo.Cryptography.MPTTrie.Tests/Neo.Cryptography.MPTTrie.Tests.csproj create mode 100644 tests/Neo.Network.RPC.Tests/Neo.Network.RPC.Tests.csproj create mode 100644 tests/Neo.Network.RPC.Tests/RpcTestCases.json create mode 100644 tests/Neo.Network.RPC.Tests/TestUtils.cs create mode 100644 tests/Neo.Network.RPC.Tests/UT_ContractClient.cs create mode 100644 tests/Neo.Network.RPC.Tests/UT_Nep17API.cs create mode 100644 tests/Neo.Network.RPC.Tests/UT_PolicyAPI.cs create mode 100644 tests/Neo.Network.RPC.Tests/UT_RpcClient.cs create mode 100644 tests/Neo.Network.RPC.Tests/UT_RpcModels.cs create mode 100644 tests/Neo.Network.RPC.Tests/UT_TransactionManager.cs create mode 100644 tests/Neo.Network.RPC.Tests/UT_Utility.cs create mode 100644 tests/Neo.Network.RPC.Tests/UT_WalletAPI.cs create mode 100644 tests/Neo.Plugins.OracleService.Tests/Neo.Plugins.OracleService.Tests.csproj create mode 100644 tests/Neo.Plugins.OracleService.Tests/TestBlockchain.cs create mode 100644 tests/Neo.Plugins.OracleService.Tests/TestUtils.cs create mode 100644 tests/Neo.Plugins.OracleService.Tests/UT_OracleService.cs create mode 100644 tests/Neo.Plugins.OracleService.Tests/config.json create mode 100644 tests/Neo.Plugins.RpcServer.Tests/Neo.Plugins.RpcServer.Tests.csproj create mode 100644 tests/Neo.Plugins.RpcServer.Tests/UT_RpcError.cs create mode 100644 tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.cs create mode 100644 tests/Neo.Plugins.Storage.Tests/Neo.Plugins.Storage.Tests.csproj create mode 100644 tests/Neo.Plugins.Storage.Tests/StoreTest.cs diff --git a/.editorconfig b/.editorconfig index f24ccd45a8..c8247e5496 100644 --- a/.editorconfig +++ b/.editorconfig @@ -307,4 +307,4 @@ dotnet_diagnostic.IDE2006.severity = warning [src/{VisualStudio}/**/*.{cs,vb}] # CA1822: Make member static # There is a risk of accidentally breaking an internal API that partners rely on though IVT. -dotnet_code_quality.CA1822.api_surface = private \ No newline at end of file +dotnet_code_quality.CA1822.api_surface = private diff --git a/.gitattributes b/.gitattributes index 3bdf2f7093..95c6696127 100644 --- a/.gitattributes +++ b/.gitattributes @@ -4,6 +4,8 @@ * text eol=lf *.cs eol=lf *.csproj eol=lf +*.props eol=lf +*.json eol=lf ############################################################################### # Set default behavior for command prompt diff. diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 5ac5e3dc65..6f7f9867c8 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -34,15 +34,25 @@ jobs: - 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: | + sudo apt-get --assume-yes install libleveldb-dev librocksdb-dev dotnet test ./tests/Neo.Cryptography.BLS12_381.Tests /p:CollectCoverage=true /p:CoverletOutput='${{ github.workspace }}/TestResults/coverage/' dotnet test ./tests/Neo.ConsoleService.Tests /p:CollectCoverage=true /p:CoverletOutput='${{ github.workspace }}/TestResults/coverage/' /p:MergeWith='${{ github.workspace }}/TestResults/coverage/coverage.json' dotnet test ./tests/Neo.UnitTests /p:CollectCoverage=true /p:CoverletOutput='${{ github.workspace }}/TestResults/coverage/' /p:MergeWith='${{ github.workspace }}/TestResults/coverage/coverage.json' dotnet test ./tests/Neo.VM.Tests /p:CollectCoverage=true /p:CoverletOutput='${{ github.workspace }}/TestResults/coverage/' /p:MergeWith='${{ github.workspace }}/TestResults/coverage/coverage.json' - dotnet test ./tests/Neo.Json.UnitTests /p:CollectCoverage=true /p:CoverletOutput='${{ github.workspace }}/TestResults/coverage/' /p:MergeWith='${{ github.workspace }}/TestResults/coverage/coverage.json' /p:CoverletOutputFormat='lcov' + dotnet test ./tests/Neo.Json.UnitTests /p:CollectCoverage=true /p:CoverletOutput='${{ github.workspace }}/TestResults/coverage/' /p:MergeWith='${{ github.workspace }}/TestResults/coverage/coverage.json' + + # Plugins + dotnet test ./tests/Neo.Cryptography.MPTTrie.Tests /p:CollectCoverage=true /p:CoverletOutput='${{ github.workspace }}/TestResults/coverage/' /p:MergeWith='${{ github.workspace }}/TestResults/coverage/coverage.json' + dotnet test ./tests/Neo.Network.RPC.Tests /p:CollectCoverage=true /p:CoverletOutput='${{ github.workspace }}/TestResults/coverage/' /p:MergeWith='${{ github.workspace }}/TestResults/coverage/coverage.json' + dotnet test ./tests/Neo.Plugins.OracleService.Tests /p:CollectCoverage=true /p:CoverletOutput='${{ github.workspace }}/TestResults/coverage/' /p:MergeWith='${{ github.workspace }}/TestResults/coverage/coverage.json' + dotnet test ./tests/Neo.Plugins.RpcServer.Tests /p:CollectCoverage=true /p:CoverletOutput='${{ github.workspace }}/TestResults/coverage/' /p:MergeWith='${{ github.workspace }}/TestResults/coverage/coverage.json' + dotnet test ./tests/Neo.Plugins.Storage.Tests /p:CollectCoverage=true /p:CoverletOutput='${{ github.workspace }}/TestResults/coverage/' /p:MergeWith='${{ github.workspace }}/TestResults/coverage/coverage.json' /p:CoverletOutputFormat='lcov' + - name: Coveralls if: matrix.os == 'ubuntu-latest' uses: coverallsapp/github-action@v2.2.3 diff --git a/src/README.md b/.neo/README.md similarity index 100% rename from src/README.md rename to .neo/README.md diff --git a/src/neo.png b/.neo/neo.png similarity index 100% rename from src/neo.png rename to .neo/neo.png diff --git a/neo.sln b/neo.sln index b62de06a6e..46ff7c64e8 100644 --- a/neo.sln +++ b/neo.sln @@ -36,9 +36,49 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.Cryptography.BLS12_381" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.Cryptography.BLS12_381.Tests", "tests\Neo.Cryptography.BLS12_381.Tests\Neo.Cryptography.BLS12_381.Tests.csproj", "{387CCF6C-9A26-43F6-A639-0A82E91E10D8}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Neo.IO", "src\Neo.IO\Neo.IO.csproj", "{4CDAC1AA-45C6-4157-8D8E-199050433048}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.IO", "src\Neo.IO\Neo.IO.csproj", "{4CDAC1AA-45C6-4157-8D8E-199050433048}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Neo.Extensions", "src\Neo.Extensions\Neo.Extensions.csproj", "{9C5213D6-3833-4570-8AE2-47E9F9017A8F}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.Extensions", "src\Neo.Extensions\Neo.Extensions.csproj", "{9C5213D6-3833-4570-8AE2-47E9F9017A8F}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "plugins", "plugins", "{C2DC830A-327A-42A7-807D-295216D30DBB}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.Cryptography.MPTTrie.Tests", "tests\Neo.Cryptography.MPTTrie.Tests\Neo.Cryptography.MPTTrie.Tests.csproj", "{FAF5D8AC-B6B3-4CD4-879D-0E5F6211480F}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.Network.RPC.Tests", "tests\Neo.Network.RPC.Tests\Neo.Network.RPC.Tests.csproj", "{0E92F219-1225-4DD0-8C4A-98840985D59C}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.Plugins.OracleService.Tests", "tests\Neo.Plugins.OracleService.Tests\Neo.Plugins.OracleService.Tests.csproj", "{5D9764FB-827D-4DDE-84E3-3C05FD8ABC89}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.Plugins.RpcServer.Tests", "tests\Neo.Plugins.RpcServer.Tests\Neo.Plugins.RpcServer.Tests.csproj", "{2CBD2311-BA2E-4921-A000-FDDA59B74958}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Neo.Plugins.Storage.Tests", "tests\Neo.Plugins.Storage.Tests\Neo.Plugins.Storage.Tests.csproj", "{EF01E062-DBBC-47AF-AF3B-9EDEB00CFF7C}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{7F257712-D033-47FF-B439-9D4320D06599}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ApplicationLogs", "src\Plugins\ApplicationLogs\ApplicationLogs.csproj", "{22E2CE64-080B-4138-885F-7FA74A9159FB}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DBFTPlugin", "src\Plugins\DBFTPlugin\DBFTPlugin.csproj", "{4C39E872-FC37-4BFD-AE4C-3E3F0546B726}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LevelDBStore", "src\Plugins\LevelDBStore\LevelDBStore.csproj", "{4C4D8180-9326-486C-AECF-8368BBD0766A}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MPTTrie", "src\Plugins\MPTTrie\MPTTrie.csproj", "{80DA3CE7-9770-4F00-9179-0DA91DABFDFA}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OracleService", "src\Plugins\OracleService\OracleService.csproj", "{DE0FB77E-3099-4C88-BB7D-BFAED75D813E}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RocksDBStore", "src\Plugins\RocksDBStore\RocksDBStore.csproj", "{3DE59148-59D6-4CD3-8086-0BC74E3D4E0B}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RpcServer", "src\Plugins\RpcServer\RpcServer.csproj", "{A3941551-E72C-42D7-8C4D-5122CB60D73D}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SQLiteWallet", "src\Plugins\SQLiteWallet\SQLiteWallet.csproj", "{F53D5FF0-5D3D-4E8B-A44F-C4C5D9B563B1}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StatesDumper", "src\Plugins\StatesDumper\StatesDumper.csproj", "{90CCA7D4-C277-4112-A036-BBB90C3FE3BE}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StateService", "src\Plugins\StateService\StateService.csproj", "{88975A8D-4797-45A4-BC3E-15962A425A54}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StorageDumper", "src\Plugins\StorageDumper\StorageDumper.csproj", "{FF76D8A4-356B-461A-8471-BC1B83E57BBC}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TokensTracker", "src\Plugins\TokensTracker\TokensTracker.csproj", "{5E4947F3-05D3-4806-B0F3-30DAC71B5986}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RpcClient", "src\Plugins\RpcClient\RpcClient.csproj", "{185ADAFC-BFC6-413D-BC2E-97F9FB0A8AF0}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -110,6 +150,78 @@ Global {9C5213D6-3833-4570-8AE2-47E9F9017A8F}.Debug|Any CPU.Build.0 = Debug|Any CPU {9C5213D6-3833-4570-8AE2-47E9F9017A8F}.Release|Any CPU.ActiveCfg = Release|Any CPU {9C5213D6-3833-4570-8AE2-47E9F9017A8F}.Release|Any CPU.Build.0 = Release|Any CPU + {FAF5D8AC-B6B3-4CD4-879D-0E5F6211480F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FAF5D8AC-B6B3-4CD4-879D-0E5F6211480F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FAF5D8AC-B6B3-4CD4-879D-0E5F6211480F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FAF5D8AC-B6B3-4CD4-879D-0E5F6211480F}.Release|Any CPU.Build.0 = Release|Any CPU + {0E92F219-1225-4DD0-8C4A-98840985D59C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0E92F219-1225-4DD0-8C4A-98840985D59C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0E92F219-1225-4DD0-8C4A-98840985D59C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0E92F219-1225-4DD0-8C4A-98840985D59C}.Release|Any CPU.Build.0 = Release|Any CPU + {5D9764FB-827D-4DDE-84E3-3C05FD8ABC89}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5D9764FB-827D-4DDE-84E3-3C05FD8ABC89}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5D9764FB-827D-4DDE-84E3-3C05FD8ABC89}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5D9764FB-827D-4DDE-84E3-3C05FD8ABC89}.Release|Any CPU.Build.0 = Release|Any CPU + {2CBD2311-BA2E-4921-A000-FDDA59B74958}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2CBD2311-BA2E-4921-A000-FDDA59B74958}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2CBD2311-BA2E-4921-A000-FDDA59B74958}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2CBD2311-BA2E-4921-A000-FDDA59B74958}.Release|Any CPU.Build.0 = Release|Any CPU + {EF01E062-DBBC-47AF-AF3B-9EDEB00CFF7C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EF01E062-DBBC-47AF-AF3B-9EDEB00CFF7C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EF01E062-DBBC-47AF-AF3B-9EDEB00CFF7C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EF01E062-DBBC-47AF-AF3B-9EDEB00CFF7C}.Release|Any CPU.Build.0 = Release|Any CPU + {22E2CE64-080B-4138-885F-7FA74A9159FB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {22E2CE64-080B-4138-885F-7FA74A9159FB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {22E2CE64-080B-4138-885F-7FA74A9159FB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {22E2CE64-080B-4138-885F-7FA74A9159FB}.Release|Any CPU.Build.0 = Release|Any CPU + {4C39E872-FC37-4BFD-AE4C-3E3F0546B726}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4C39E872-FC37-4BFD-AE4C-3E3F0546B726}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4C39E872-FC37-4BFD-AE4C-3E3F0546B726}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4C39E872-FC37-4BFD-AE4C-3E3F0546B726}.Release|Any CPU.Build.0 = Release|Any CPU + {4C4D8180-9326-486C-AECF-8368BBD0766A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4C4D8180-9326-486C-AECF-8368BBD0766A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4C4D8180-9326-486C-AECF-8368BBD0766A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4C4D8180-9326-486C-AECF-8368BBD0766A}.Release|Any CPU.Build.0 = Release|Any CPU + {80DA3CE7-9770-4F00-9179-0DA91DABFDFA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {80DA3CE7-9770-4F00-9179-0DA91DABFDFA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {80DA3CE7-9770-4F00-9179-0DA91DABFDFA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {80DA3CE7-9770-4F00-9179-0DA91DABFDFA}.Release|Any CPU.Build.0 = Release|Any CPU + {DE0FB77E-3099-4C88-BB7D-BFAED75D813E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DE0FB77E-3099-4C88-BB7D-BFAED75D813E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DE0FB77E-3099-4C88-BB7D-BFAED75D813E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DE0FB77E-3099-4C88-BB7D-BFAED75D813E}.Release|Any CPU.Build.0 = Release|Any CPU + {3DE59148-59D6-4CD3-8086-0BC74E3D4E0B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3DE59148-59D6-4CD3-8086-0BC74E3D4E0B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3DE59148-59D6-4CD3-8086-0BC74E3D4E0B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3DE59148-59D6-4CD3-8086-0BC74E3D4E0B}.Release|Any CPU.Build.0 = Release|Any CPU + {A3941551-E72C-42D7-8C4D-5122CB60D73D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A3941551-E72C-42D7-8C4D-5122CB60D73D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A3941551-E72C-42D7-8C4D-5122CB60D73D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A3941551-E72C-42D7-8C4D-5122CB60D73D}.Release|Any CPU.Build.0 = Release|Any CPU + {F53D5FF0-5D3D-4E8B-A44F-C4C5D9B563B1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F53D5FF0-5D3D-4E8B-A44F-C4C5D9B563B1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F53D5FF0-5D3D-4E8B-A44F-C4C5D9B563B1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F53D5FF0-5D3D-4E8B-A44F-C4C5D9B563B1}.Release|Any CPU.Build.0 = Release|Any CPU + {90CCA7D4-C277-4112-A036-BBB90C3FE3BE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {90CCA7D4-C277-4112-A036-BBB90C3FE3BE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {90CCA7D4-C277-4112-A036-BBB90C3FE3BE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {90CCA7D4-C277-4112-A036-BBB90C3FE3BE}.Release|Any CPU.Build.0 = Release|Any CPU + {88975A8D-4797-45A4-BC3E-15962A425A54}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {88975A8D-4797-45A4-BC3E-15962A425A54}.Debug|Any CPU.Build.0 = Debug|Any CPU + {88975A8D-4797-45A4-BC3E-15962A425A54}.Release|Any CPU.ActiveCfg = Release|Any CPU + {88975A8D-4797-45A4-BC3E-15962A425A54}.Release|Any CPU.Build.0 = Release|Any CPU + {FF76D8A4-356B-461A-8471-BC1B83E57BBC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FF76D8A4-356B-461A-8471-BC1B83E57BBC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FF76D8A4-356B-461A-8471-BC1B83E57BBC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FF76D8A4-356B-461A-8471-BC1B83E57BBC}.Release|Any CPU.Build.0 = Release|Any CPU + {5E4947F3-05D3-4806-B0F3-30DAC71B5986}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5E4947F3-05D3-4806-B0F3-30DAC71B5986}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5E4947F3-05D3-4806-B0F3-30DAC71B5986}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5E4947F3-05D3-4806-B0F3-30DAC71B5986}.Release|Any CPU.Build.0 = Release|Any CPU + {185ADAFC-BFC6-413D-BC2E-97F9FB0A8AF0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {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 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -131,6 +243,25 @@ Global {387CCF6C-9A26-43F6-A639-0A82E91E10D8} = {EDE05FA8-8E73-4924-BC63-DD117127EEE1} {4CDAC1AA-45C6-4157-8D8E-199050433048} = {B5339DF7-5D1D-43BA-B332-74B825E1770E} {9C5213D6-3833-4570-8AE2-47E9F9017A8F} = {B5339DF7-5D1D-43BA-B332-74B825E1770E} + {FAF5D8AC-B6B3-4CD4-879D-0E5F6211480F} = {7F257712-D033-47FF-B439-9D4320D06599} + {0E92F219-1225-4DD0-8C4A-98840985D59C} = {7F257712-D033-47FF-B439-9D4320D06599} + {5D9764FB-827D-4DDE-84E3-3C05FD8ABC89} = {7F257712-D033-47FF-B439-9D4320D06599} + {2CBD2311-BA2E-4921-A000-FDDA59B74958} = {7F257712-D033-47FF-B439-9D4320D06599} + {EF01E062-DBBC-47AF-AF3B-9EDEB00CFF7C} = {7F257712-D033-47FF-B439-9D4320D06599} + {7F257712-D033-47FF-B439-9D4320D06599} = {C2DC830A-327A-42A7-807D-295216D30DBB} + {22E2CE64-080B-4138-885F-7FA74A9159FB} = {C2DC830A-327A-42A7-807D-295216D30DBB} + {4C39E872-FC37-4BFD-AE4C-3E3F0546B726} = {C2DC830A-327A-42A7-807D-295216D30DBB} + {4C4D8180-9326-486C-AECF-8368BBD0766A} = {C2DC830A-327A-42A7-807D-295216D30DBB} + {80DA3CE7-9770-4F00-9179-0DA91DABFDFA} = {C2DC830A-327A-42A7-807D-295216D30DBB} + {DE0FB77E-3099-4C88-BB7D-BFAED75D813E} = {C2DC830A-327A-42A7-807D-295216D30DBB} + {3DE59148-59D6-4CD3-8086-0BC74E3D4E0B} = {C2DC830A-327A-42A7-807D-295216D30DBB} + {A3941551-E72C-42D7-8C4D-5122CB60D73D} = {C2DC830A-327A-42A7-807D-295216D30DBB} + {F53D5FF0-5D3D-4E8B-A44F-C4C5D9B563B1} = {C2DC830A-327A-42A7-807D-295216D30DBB} + {90CCA7D4-C277-4112-A036-BBB90C3FE3BE} = {C2DC830A-327A-42A7-807D-295216D30DBB} + {88975A8D-4797-45A4-BC3E-15962A425A54} = {C2DC830A-327A-42A7-807D-295216D30DBB} + {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} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {BCBA19D9-F868-4C6D-8061-A2B91E06E3EC} diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 816760b50b..d3de66b478 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -19,8 +19,8 @@ - - + + diff --git a/src/Plugins/ApplicationLogs/ApplicationLogs.csproj b/src/Plugins/ApplicationLogs/ApplicationLogs.csproj new file mode 100644 index 0000000000..2079abfcff --- /dev/null +++ b/src/Plugins/ApplicationLogs/ApplicationLogs.csproj @@ -0,0 +1,16 @@ + + + net8.0 + Neo.Plugins.ApplicationLogs + Neo.Plugins + enable + + + + + + false + runtime + + + \ No newline at end of file diff --git a/src/Plugins/ApplicationLogs/LogReader.cs b/src/Plugins/ApplicationLogs/LogReader.cs new file mode 100644 index 0000000000..56163ef4f1 --- /dev/null +++ b/src/Plugins/ApplicationLogs/LogReader.cs @@ -0,0 +1,457 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// LogReader.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 ApplicationLogs.Store; +using ApplicationLogs.Store.Models; +using Neo.ConsoleService; +using Neo.IO; +using Neo.Json; +using Neo.Ledger; +using Neo.Network.P2P.Payloads; +using Neo.Persistence; +using Neo.SmartContract; +using Neo.SmartContract.Native; +using Neo.VM; +using System.Numerics; +using static System.IO.Path; + +namespace Neo.Plugins +{ + public class LogReader : Plugin + { + #region Globals + + private NeoStore _neostore; + private NeoSystem _neosystem; + private readonly List _logEvents; + + #endregion + + public override string Name => "ApplicationLogs"; + public override string Description => "Synchronizes smart contract VM executions and notificatons (NotifyLog) on blockchain."; + + #region Ctor + + public LogReader() + { + _logEvents = new(); + Blockchain.Committing += OnCommitting; + Blockchain.Committed += OnCommitted; + } + + #endregion + + #region Override Methods + + public override void Dispose() + { + Blockchain.Committing -= OnCommitting; + Blockchain.Committed -= OnCommitted; + if (Settings.Default.Debug) + ApplicationEngine.Log -= OnApplicationEngineLog; + GC.SuppressFinalize(this); + } + + protected override void Configure() + { + Settings.Load(GetConfiguration()); + } + + protected override void OnSystemLoaded(NeoSystem system) + { + if (system.Settings.Network != Settings.Default.Network) + return; + string path = string.Format(Settings.Default.Path, Settings.Default.Network.ToString("X8")); + var store = system.LoadStore(GetFullPath(path)); + _neostore = new NeoStore(store); + _neosystem = system; + RpcServerPlugin.RegisterMethods(this, Settings.Default.Network); + + if (Settings.Default.Debug) + ApplicationEngine.Log += OnApplicationEngineLog; + } + + #endregion + + #region JSON RPC Methods + + [RpcMethod] + public JToken GetApplicationLog(JArray _params) + { + if (_params == null || _params.Count == 0) + throw new RpcException(RpcError.InvalidParams); + if (UInt256.TryParse(_params[0].AsString(), out var hash)) + { + var raw = BlockToJObject(hash); + if (raw == null) + raw = TransactionToJObject(hash); + if (raw == null) + throw new RpcException(RpcError.InvalidParams.WithData("Unknown transaction/blockhash")); + + if (_params.Count >= 2 && Enum.TryParse(_params[1].AsString(), true, out TriggerType triggerType)) + { + var executions = raw["executions"] as JArray; + for (int i = 0; i < executions.Count;) + { + if (executions[i]["trigger"].AsString().Equals(triggerType.ToString(), StringComparison.OrdinalIgnoreCase) == false) + executions.RemoveAt(i); + else + i++; + } + } + + return raw ?? JToken.Null; + } + else + throw new RpcException(RpcError.InvalidParams); + } + + #endregion + + #region Console Commands + + [ConsoleCommand("log block", Category = "ApplicationLog Commands")] + private void OnGetBlockCommand(string blockHashOrIndex, string eventName = null) + { + UInt256 blockhash; + if (uint.TryParse(blockHashOrIndex, out var blockIndex)) + { + blockhash = NativeContract.Ledger.GetBlockHash(_neosystem.StoreView, blockIndex); + } + else if (UInt256.TryParse(blockHashOrIndex, out blockhash) == false) + { + ConsoleHelper.Error("Invalid block hash or index."); + return; + } + + var blockOnPersist = string.IsNullOrEmpty(eventName) ? + _neostore.GetBlockLog(blockhash, TriggerType.OnPersist) : + _neostore.GetBlockLog(blockhash, TriggerType.OnPersist, eventName); + var blockPostPersist = string.IsNullOrEmpty(eventName) ? + _neostore.GetBlockLog(blockhash, TriggerType.PostPersist) : + _neostore.GetBlockLog(blockhash, TriggerType.PostPersist, eventName); + + if (blockOnPersist == null && blockOnPersist == null) + ConsoleHelper.Error($"No logs."); + if (blockOnPersist != null) + PrintExecutionToConsole(blockOnPersist); + if (blockPostPersist != null) + { + ConsoleHelper.Info("--------------------------------"); + PrintExecutionToConsole(blockPostPersist); + } + } + + [ConsoleCommand("log tx", Category = "ApplicationLog Commands")] + private void OnGetTransactionCommand(UInt256 txhash, string eventName = null) + { + var txApplication = string.IsNullOrEmpty(eventName) ? + _neostore.GetTransactionLog(txhash) : + _neostore.GetTransactionLog(txhash, eventName); + + if (txApplication == null) + ConsoleHelper.Error($"No logs."); + else + PrintExecutionToConsole(txApplication); + } + + [ConsoleCommand("log contract", Category = "ApplicationLog Commands")] + private void OnGetContractCommand(UInt160 scripthash, uint page = 1, uint pageSize = 1, string eventName = null) + { + if (page == 0) + { + ConsoleHelper.Error("Page is invalid. Pick a number 1 and above."); + return; + } + + if (pageSize == 0) + { + ConsoleHelper.Error("PageSize is invalid. Pick a number between 1 and 10."); + return; + } + + var txContract = string.IsNullOrEmpty(eventName) ? + _neostore.GetContractLog(scripthash, TriggerType.Application, page, pageSize) : + _neostore.GetContractLog(scripthash, TriggerType.Application, eventName, page, pageSize); + + if (txContract.Count == 0) + ConsoleHelper.Error($"No logs."); + else + PrintEventModelToConsole(txContract); + } + + + #endregion + + #region Blockchain Events + + private void OnCommitting(NeoSystem system, Block block, DataCache snapshot, IReadOnlyList applicationExecutedList) + { + if (system.Settings.Network != Settings.Default.Network) + return; + + if (_neostore is null) + return; + _neostore.StartBlockLogBatch(); + _neostore.PutBlockLog(block, applicationExecutedList); + if (Settings.Default.Debug) + { + foreach (var appEng in applicationExecutedList.Where(w => w.Transaction != null)) + { + var logs = _logEvents.Where(w => w.ScriptContainer.Hash == appEng.Transaction.Hash).ToList(); + if (logs.Any()) + _neostore.PutTransactionEngineLogState(appEng.Transaction.Hash, logs); + } + _logEvents.Clear(); + } + } + + private void OnCommitted(NeoSystem system, Block block) + { + if (system.Settings.Network != Settings.Default.Network) + return; + if (_neostore is null) + return; + _neostore.CommitBlockLog(); + } + + private void OnApplicationEngineLog(object sender, LogEventArgs e) + { + if (Settings.Default.Debug == false) + return; + + if (_neosystem.Settings.Network != Settings.Default.Network) + return; + + if (e.ScriptContainer == null) + return; + + _logEvents.Add(e); + } + + #endregion + + #region Private Methods + + private void PrintExecutionToConsole(BlockchainExecutionModel model) + { + ConsoleHelper.Info("Trigger: ", $"{model.Trigger}"); + ConsoleHelper.Info("VM State: ", $"{model.VmState}"); + if (string.IsNullOrEmpty(model.Exception) == false) + ConsoleHelper.Error($"Exception: {model.Exception}"); + else + ConsoleHelper.Info("Exception: ", "null"); + ConsoleHelper.Info("Gas Consumed: ", $"{new BigDecimal((BigInteger)model.GasConsumed, NativeContract.GAS.Decimals)}"); + if (model.Stack.Length == 0) + ConsoleHelper.Info("Stack: ", "[]"); + else + { + ConsoleHelper.Info("Stack: "); + for (int i = 0; i < model.Stack.Length; i++) + ConsoleHelper.Info($" {i}: ", $"{model.Stack[i].ToJson()}"); + } + if (model.Notifications.Length == 0) + ConsoleHelper.Info("Notifications: ", "[]"); + else + { + ConsoleHelper.Info("Notifications:"); + foreach (var notifyItem in model.Notifications) + { + ConsoleHelper.Info(); + 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()}"); + } + } + if (Settings.Default.Debug) + { + if (model.Logs.Length == 0) + ConsoleHelper.Info("Logs: ", "[]"); + else + { + ConsoleHelper.Info("Logs:"); + foreach (var logItem in model.Logs) + { + ConsoleHelper.Info(); + ConsoleHelper.Info(" ScriptHash: ", $"{logItem.ScriptHash}"); + ConsoleHelper.Info(" Message: ", $"{logItem.Message}"); + } + } + } + } + + private void PrintEventModelToConsole(IReadOnlyCollection<(BlockchainEventModel NotifyLog, UInt256 TxHash)> models) + { + foreach (var (notifyItem, txhash) in models) + { + ConsoleHelper.Info("Transaction Hash: ", $"{txhash}"); + 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()}"); + ConsoleHelper.Info("--------------------------------"); + } + } + + private string GetMethodParameterName(UInt160 scriptHash, string methodName, 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); + return contractEvent.Parameters[parameterIndex].Name; + } + + private JObject EventModelToJObject(BlockchainEventModel model) + { + var root = new JObject(); + root["contract"] = model.ScriptHash.ToString(); + root["eventname"] = model.EventName; + root["state"] = model.State.Select(s => s.ToJson()).ToArray(); + return root; + } + + private JObject TransactionToJObject(UInt256 txHash) + { + var appLog = _neostore.GetTransactionLog(txHash); + if (appLog == null) + return null; + + var raw = new JObject(); + raw["txid"] = txHash.ToString(); + + var trigger = new JObject(); + trigger["trigger"] = appLog.Trigger; + trigger["vmstate"] = appLog.VmState; + trigger["exception"] = string.IsNullOrEmpty(appLog.Exception) ? null : appLog.Exception; + trigger["gasconsumed"] = appLog.GasConsumed.ToString(); + + try + { + trigger["stack"] = appLog.Stack.Select(s => s.ToJson(Settings.Default.MaxStackSize)).ToArray(); + } + catch (Exception ex) + { + trigger["exception"] = ex.Message; + } + + trigger["notifications"] = appLog.Notifications.Select(s => + { + var notification = new JObject(); + notification["contract"] = s.ScriptHash.ToString(); + notification["eventname"] = s.EventName; + + try + { + var state = new JObject(); + state["type"] = "Array"; + state["value"] = s.State.Select(ss => ss.ToJson()).ToArray(); + + notification["state"] = state; + } + catch (InvalidOperationException) + { + notification["state"] = "error: recursive reference"; + } + + return notification; + }).ToArray(); + + if (Settings.Default.Debug) + { + trigger["logs"] = appLog.Logs.Select(s => + { + var log = new JObject(); + log["contract"] = s.ScriptHash.ToString(); + log["message"] = s.Message; + return log; + }).ToArray(); + } + + raw["executions"] = new[] { trigger }; + return raw; + } + + private JObject BlockToJObject(UInt256 blockHash) + { + var blockOnPersist = _neostore.GetBlockLog(blockHash, TriggerType.OnPersist); + var blockPostPersist = _neostore.GetBlockLog(blockHash, TriggerType.PostPersist); + + if (blockOnPersist == null && blockPostPersist == null) + return null; + + var blockJson = new JObject(); + blockJson["blockhash"] = blockHash.ToString(); + var triggerList = new List(); + + if (blockOnPersist != null) + triggerList.Add(BlockItemToJObject(blockOnPersist)); + if (blockPostPersist != null) + triggerList.Add(BlockItemToJObject(blockPostPersist)); + + blockJson["executions"] = triggerList.ToArray(); + return blockJson; + } + + private JObject BlockItemToJObject(BlockchainExecutionModel blockExecutionModel) + { + JObject trigger = new(); + trigger["trigger"] = blockExecutionModel.Trigger; + trigger["vmstate"] = blockExecutionModel.VmState; + trigger["gasconsumed"] = blockExecutionModel.GasConsumed.ToString(); + try + { + trigger["stack"] = blockExecutionModel.Stack.Select(q => q.ToJson(Settings.Default.MaxStackSize)).ToArray(); + } + catch (Exception ex) + { + trigger["exception"] = ex.Message; + } + trigger["notifications"] = blockExecutionModel.Notifications.Select(s => + { + JObject notification = new(); + notification["contract"] = s.ScriptHash.ToString(); + notification["eventname"] = s.EventName; + try + { + var state = new JObject(); + state["type"] = "Array"; + state["value"] = s.State.Select(ss => ss.ToJson()).ToArray(); + + notification["state"] = state; + } + catch (InvalidOperationException) + { + notification["state"] = "error: recursive reference"; + } + return notification; + }).ToArray(); + + if (Settings.Default.Debug) + { + trigger["logs"] = blockExecutionModel.Logs.Select(s => + { + var log = new JObject(); + log["contract"] = s.ScriptHash.ToString(); + log["message"] = s.Message; + return log; + }).ToArray(); + } + + return trigger; + } + + #endregion + } +} diff --git a/src/Plugins/ApplicationLogs/Settings.cs b/src/Plugins/ApplicationLogs/Settings.cs new file mode 100644 index 0000000000..1e425f664b --- /dev/null +++ b/src/Plugins/ApplicationLogs/Settings.cs @@ -0,0 +1,39 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Settings.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; + +namespace Neo.Plugins +{ + internal class Settings + { + public string Path { get; } + public uint Network { get; } + public int MaxStackSize { get; } + + public bool Debug { get; } + + public static Settings Default { get; private set; } + + private Settings(IConfigurationSection section) + { + Path = section.GetValue("Path", "ApplicationLogs_{0}"); + Network = section.GetValue("Network", 5195086u); + MaxStackSize = section.GetValue("MaxStackSize", (int)ushort.MaxValue); + Debug = section.GetValue("Debug", false); + } + + public static void Load(IConfigurationSection section) + { + Default = new Settings(section); + } + } +} diff --git a/src/Plugins/ApplicationLogs/Store/LogStorageStore.cs b/src/Plugins/ApplicationLogs/Store/LogStorageStore.cs new file mode 100644 index 0000000000..aa0357ffb2 --- /dev/null +++ b/src/Plugins/ApplicationLogs/Store/LogStorageStore.cs @@ -0,0 +1,415 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// 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 ApplicationLogs.Store.States; +using Neo; +using Neo.IO; +using Neo.Persistence; +using Neo.Plugins; +using Neo.Plugins.Store.States; +using Neo.SmartContract; +using Neo.VM; +using Neo.VM.Types; + +namespace ApplicationLogs.Store +{ + public sealed class LogStorageStore : IDisposable + { + #region Prefixes + + private static readonly int Prefix_Size = sizeof(int) + sizeof(byte); + private static readonly int Prefix_Block_Trigger_Size = Prefix_Size + UInt256.Length; + private static readonly int Prefix_Execution_Block_Trigger_Size = Prefix_Size + UInt256.Length; + + private static readonly int Prefix_Id = 0x414c4f47; // Magic Code: (ALOG); + private static readonly byte Prefix_Engine = 0x18; // Engine_GUID -> ScriptHash, Message + private static readonly byte Prefix_Engine_Transaction = 0x19; // TxHash -> Engine_GUID_List + private static readonly byte Prefix_Block = 0x20; // BlockHash, Trigger -> NotifyLog_GUID_List + private static readonly byte Prefix_Notify = 0x21; // NotifyLog_GUID -> ScriptHash, EventName, StackItem_GUID_List + private static readonly byte Prefix_Contract = 0x22; // ScriptHash, TimeStamp, EventIterIndex -> txHash, Trigger, NotifyLog_GUID + private static readonly byte Prefix_Execution = 0x23; // Execution_GUID -> Data, StackItem_GUID_List + private static readonly byte Prefix_Execution_Block = 0x24; // BlockHash, Trigger -> Execution_GUID + private static readonly byte Prefix_Execution_Transaction = 0x25; // TxHash -> Execution_GUID + private static readonly byte Prefix_Transaction = 0x26; // TxHash -> NotifyLog_GUID_List + private static readonly byte Prefix_StackItem = 0xed; // StackItem_GUID -> Data + + #endregion + + #region Global Variables + + private readonly ISnapshot _snapshot; + + #endregion + + #region Ctor + + public LogStorageStore(ISnapshot snapshot) + { + ArgumentNullException.ThrowIfNull(snapshot, nameof(snapshot)); + _snapshot = snapshot; + } + + #endregion + + #region IDisposable + + public void Dispose() + { + GC.SuppressFinalize(this); + } + + #endregion + + #region Put + + public Guid PutEngineState(EngineLogState state) + { + var id = Guid.NewGuid(); + var key = new KeyBuilder(Prefix_Id, Prefix_Engine) + .Add(id.ToByteArray()) + .ToArray(); + _snapshot.Put(key, state.ToArray()); + return id; + } + + public void PutTransactionEngineState(UInt256 hash, TransactionEngineLogState state) + { + var key = new KeyBuilder(Prefix_Id, Prefix_Engine_Transaction) + .Add(hash) + .ToArray(); + _snapshot.Put(key, state.ToArray()); + } + + public void PutBlockState(UInt256 hash, TriggerType trigger, BlockLogState state) + { + var key = new KeyBuilder(Prefix_Id, Prefix_Block) + .Add(hash) + .Add((byte)trigger) + .ToArray(); + _snapshot.Put(key, state.ToArray()); + } + + public Guid PutNotifyState(NotifyLogState state) + { + var id = Guid.NewGuid(); + var key = new KeyBuilder(Prefix_Id, Prefix_Notify) + .Add(id.ToByteArray()) + .ToArray(); + _snapshot.Put(key, state.ToArray()); + return id; + } + + public void PutContractState(UInt160 scriptHash, ulong timestamp, uint iterIndex, ContractLogState state) + { + var key = new KeyBuilder(Prefix_Id, Prefix_Contract) + .Add(scriptHash) + .AddBigEndian(timestamp) + .AddBigEndian(iterIndex) + .ToArray(); + _snapshot.Put(key, state.ToArray()); + } + + public Guid PutExecutionState(ExecutionLogState state) + { + var id = Guid.NewGuid(); + var key = new KeyBuilder(Prefix_Id, Prefix_Execution) + .Add(id.ToByteArray()) + .ToArray(); + _snapshot.Put(key, state.ToArray()); + return id; + } + + public void PutExecutionBlockState(UInt256 blockHash, TriggerType trigger, Guid executionStateId) + { + var key = new KeyBuilder(Prefix_Id, Prefix_Execution_Block) + .Add(blockHash) + .Add((byte)trigger) + .ToArray(); + _snapshot.Put(key, executionStateId.ToByteArray()); + } + + public void PutExecutionTransactionState(UInt256 txHash, Guid executionStateId) + { + var key = new KeyBuilder(Prefix_Id, Prefix_Execution_Transaction) + .Add(txHash) + .ToArray(); + _snapshot.Put(key, executionStateId.ToByteArray()); + } + + public void PutTransactionState(UInt256 hash, TransactionLogState state) + { + var key = new KeyBuilder(Prefix_Id, Prefix_Transaction) + .Add(hash) + .ToArray(); + _snapshot.Put(key, state.ToArray()); + } + + public Guid PutStackItemState(StackItem stackItem) + { + var id = Guid.NewGuid(); + var key = new KeyBuilder(Prefix_Id, Prefix_StackItem) + .Add(id.ToByteArray()) + .ToArray(); + try + { + _snapshot.Put(key, BinarySerializer.Serialize(stackItem, ExecutionEngineLimits.Default with { MaxItemSize = (uint)Settings.Default.MaxStackSize })); + } + catch (NotSupportedException) + { + _snapshot.Put(key, BinarySerializer.Serialize(StackItem.Null, ExecutionEngineLimits.Default with { MaxItemSize = (uint)Settings.Default.MaxStackSize })); + } + return id; + } + + #endregion + + #region Find + + public IEnumerable<(BlockLogState State, TriggerType Trigger)> FindBlockState(UInt256 hash) + { + var prefixKey = new KeyBuilder(Prefix_Id, Prefix_Block) + .Add(hash) + .ToArray(); + foreach (var (key, value) in _snapshot.Seek(prefixKey, SeekDirection.Forward)) + { + if (key.AsSpan().StartsWith(prefixKey)) + yield return (value.AsSerializable(), (TriggerType)key.AsSpan(Prefix_Block_Trigger_Size)[0]); + else + yield break; + } + } + + public IEnumerable FindContractState(UInt160 scriptHash, uint page, uint pageSize) + { + var prefix = new KeyBuilder(Prefix_Id, Prefix_Contract) + .Add(scriptHash) + .ToArray(); + var prefixKey = new KeyBuilder(Prefix_Id, Prefix_Contract) + .Add(scriptHash) + .AddBigEndian(ulong.MaxValue) // Get newest to oldest (timestamp) + .ToArray(); + uint index = 1; + foreach (var (key, value) in _snapshot.Seek(prefixKey, SeekDirection.Backward)) // Get newest to oldest + { + if (key.AsSpan().StartsWith(prefix)) + { + if (index >= page && index < (pageSize + page)) + yield return value.AsSerializable(); + index++; + } + else + yield break; + } + } + + public IEnumerable FindContractState(UInt160 scriptHash, TriggerType trigger, uint page, uint pageSize) + { + var prefix = new KeyBuilder(Prefix_Id, Prefix_Contract) + .Add(scriptHash) + .ToArray(); + var prefixKey = new KeyBuilder(Prefix_Id, Prefix_Contract) + .Add(scriptHash) + .AddBigEndian(ulong.MaxValue) // Get newest to oldest (timestamp) + .ToArray(); + uint index = 1; + foreach (var (key, value) in _snapshot.Seek(prefixKey, SeekDirection.Backward)) // Get newest to oldest + { + if (key.AsSpan().StartsWith(prefix)) + { + var state = value.AsSerializable(); + if (state.Trigger == trigger) + { + if (index >= page && index < (pageSize + page)) + yield return state; + index++; + } + } + else + yield break; + } + } + + public IEnumerable FindContractState(UInt160 scriptHash, TriggerType trigger, string eventName, uint page, uint pageSize) + { + var prefix = new KeyBuilder(Prefix_Id, Prefix_Contract) + .Add(scriptHash) + .ToArray(); + var prefixKey = new KeyBuilder(Prefix_Id, Prefix_Contract) + .Add(scriptHash) + .AddBigEndian(ulong.MaxValue) // Get newest to oldest (timestamp) + .ToArray(); + uint index = 1; + foreach (var (key, value) in _snapshot.Seek(prefixKey, SeekDirection.Backward)) // Get newest to oldest + { + if (key.AsSpan().StartsWith(prefix)) + { + var state = value.AsSerializable(); + if (state.Trigger == trigger && state.EventName.Equals(eventName, StringComparison.OrdinalIgnoreCase)) + { + if (index >= page && index < (pageSize + page)) + yield return state; + index++; + } + } + else + yield break; + } + } + + public IEnumerable<(Guid ExecutionStateId, TriggerType Trigger)> FindExecutionBlockState(UInt256 hash) + { + var prefixKey = new KeyBuilder(Prefix_Id, Prefix_Execution_Block) + .Add(hash) + .ToArray(); + foreach (var (key, value) in _snapshot.Seek(prefixKey, SeekDirection.Forward)) + { + if (key.AsSpan().StartsWith(prefixKey)) + yield return (new Guid(value), (TriggerType)key.AsSpan(Prefix_Execution_Block_Trigger_Size)[0]); + else + yield break; + } + } + + #endregion + + #region TryGet + + public bool TryGetEngineState(Guid engineStateId, out EngineLogState state) + { + var key = new KeyBuilder(Prefix_Id, Prefix_Engine) + .Add(engineStateId.ToByteArray()) + .ToArray(); + var data = _snapshot.TryGet(key); + state = data?.AsSerializable()!; + return data != null && data.Length > 0; + } + + public bool TryGetTransactionEngineState(UInt256 hash, out TransactionEngineLogState state) + { + var key = new KeyBuilder(Prefix_Id, Prefix_Engine_Transaction) + .Add(hash) + .ToArray(); + var data = _snapshot.TryGet(key); + state = data?.AsSerializable()!; + return data != null && data.Length > 0; + } + + public bool TryGetBlockState(UInt256 hash, TriggerType trigger, out BlockLogState state) + { + var key = new KeyBuilder(Prefix_Id, Prefix_Block) + .Add(hash) + .Add((byte)trigger) + .ToArray(); + var data = _snapshot.TryGet(key); + state = data?.AsSerializable()!; + return data != null && data.Length > 0; + } + + public bool TryGetNotifyState(Guid notifyStateId, out NotifyLogState state) + { + var key = new KeyBuilder(Prefix_Id, Prefix_Notify) + .Add(notifyStateId.ToByteArray()) + .ToArray(); + var data = _snapshot.TryGet(key); + state = data?.AsSerializable()!; + return data != null && data.Length > 0; + } + + public bool TryGetContractState(UInt160 scriptHash, ulong timestamp, uint iterIndex, out ContractLogState state) + { + var key = new KeyBuilder(Prefix_Id, Prefix_Contract) + .Add(scriptHash) + .AddBigEndian(timestamp) + .AddBigEndian(iterIndex) + .ToArray(); + var data = _snapshot.TryGet(key); + state = data?.AsSerializable()!; + return data != null && data.Length > 0; + } + + public bool TryGetExecutionState(Guid executionStateId, out ExecutionLogState state) + { + var key = new KeyBuilder(Prefix_Id, Prefix_Execution) + .Add(executionStateId.ToByteArray()) + .ToArray(); + var data = _snapshot.TryGet(key); + state = data?.AsSerializable()!; + return data != null && data.Length > 0; + } + + public bool TryGetExecutionBlockState(UInt256 blockHash, TriggerType trigger, out Guid executionStateId) + { + var key = new KeyBuilder(Prefix_Id, Prefix_Execution_Block) + .Add(blockHash) + .Add((byte)trigger) + .ToArray(); + var data = _snapshot.TryGet(key); + if (data == null) + { + executionStateId = Guid.Empty; + return false; + } + else + { + executionStateId = new Guid(data); + return true; + } + } + + public bool TryGetExecutionTransactionState(UInt256 txHash, out Guid executionStateId) + { + var key = new KeyBuilder(Prefix_Id, Prefix_Execution_Transaction) + .Add(txHash) + .ToArray(); + var data = _snapshot.TryGet(key); + if (data == null) + { + executionStateId = Guid.Empty; + return false; + } + else + { + executionStateId = new Guid(data); + return true; + } + } + + public bool TryGetTransactionState(UInt256 hash, out TransactionLogState state) + { + var key = new KeyBuilder(Prefix_Id, Prefix_Transaction) + .Add(hash) + .ToArray(); + var data = _snapshot.TryGet(key); + state = data?.AsSerializable()!; + return data != null && data.Length > 0; + } + + public bool TryGetStackItemState(Guid stackItemId, out StackItem stackItem) + { + var key = new KeyBuilder(Prefix_Id, Prefix_StackItem) + .Add(stackItemId.ToByteArray()) + .ToArray(); + var data = _snapshot.TryGet(key); + if (data == null) + { + stackItem = StackItem.Null; + return false; + } + else + { + stackItem = BinarySerializer.Deserialize(data, ExecutionEngineLimits.Default); + return true; + } + } + + #endregion + } +} diff --git a/src/Plugins/ApplicationLogs/Store/Models/ApplicationEngineLogModel.cs b/src/Plugins/ApplicationLogs/Store/Models/ApplicationEngineLogModel.cs new file mode 100644 index 0000000000..112cc49377 --- /dev/null +++ b/src/Plugins/ApplicationLogs/Store/Models/ApplicationEngineLogModel.cs @@ -0,0 +1,28 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// ApplicationEngineLogModel.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.Plugins.Store.States; + +namespace Neo.Plugins.Store.Models +{ + public class ApplicationEngineLogModel + { + public UInt160 ScriptHash { get; private init; } = new(); + public string Message { get; private init; } = string.Empty; + + public static ApplicationEngineLogModel Create(EngineLogState logEventState) => + new() + { + ScriptHash = logEventState.ScriptHash, + Message = logEventState.Message, + }; + } +} diff --git a/src/Plugins/ApplicationLogs/Store/Models/BlockchainEventModel.cs b/src/Plugins/ApplicationLogs/Store/Models/BlockchainEventModel.cs new file mode 100644 index 0000000000..09245db295 --- /dev/null +++ b/src/Plugins/ApplicationLogs/Store/Models/BlockchainEventModel.cs @@ -0,0 +1,48 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// BlockchainEventModel.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 ApplicationLogs.Store.States; +using Neo; +using Neo.VM.Types; + +namespace ApplicationLogs.Store.Models +{ + public class BlockchainEventModel + { + public UInt160 ScriptHash { get; private init; } = new(); + public string EventName { get; private init; } = string.Empty; + public StackItem[] State { get; private init; } = []; + + public static BlockchainEventModel Create(UInt160 scriptHash, string eventName, StackItem[] state) => + new() + { + ScriptHash = scriptHash, + EventName = eventName ?? string.Empty, + State = state, + }; + + public static BlockchainEventModel Create(NotifyLogState notifyLogState, StackItem[] state) => + new() + { + ScriptHash = notifyLogState.ScriptHash, + EventName = notifyLogState.EventName, + State = state, + }; + + public static BlockchainEventModel Create(ContractLogState contractLogState, StackItem[] state) => + new() + { + ScriptHash = contractLogState.ScriptHash, + EventName = contractLogState.EventName, + State = state, + }; + } +} diff --git a/src/Plugins/ApplicationLogs/Store/Models/BlockchainExecutionModel.cs b/src/Plugins/ApplicationLogs/Store/Models/BlockchainExecutionModel.cs new file mode 100644 index 0000000000..e31ecd0d0c --- /dev/null +++ b/src/Plugins/ApplicationLogs/Store/Models/BlockchainExecutionModel.cs @@ -0,0 +1,40 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// BlockchainExecutionModel.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 ApplicationLogs.Store.States; +using Neo.Plugins.Store.Models; +using Neo.SmartContract; +using Neo.VM; +using Neo.VM.Types; + +namespace ApplicationLogs.Store.Models +{ + public class BlockchainExecutionModel + { + public TriggerType Trigger { get; private init; } = TriggerType.All; + public VMState VmState { get; private init; } = VMState.NONE; + public string Exception { get; private init; } = string.Empty; + public long GasConsumed { get; private init; } = 0L; + public StackItem[] Stack { get; private init; } = []; + public BlockchainEventModel[] Notifications { get; set; } = []; + public ApplicationEngineLogModel[] Logs { get; set; } = []; + + public static BlockchainExecutionModel Create(TriggerType trigger, ExecutionLogState executionLogState, StackItem[] stack) => + new() + { + Trigger = trigger, + VmState = executionLogState.VmState, + Exception = executionLogState.Exception ?? string.Empty, + GasConsumed = executionLogState.GasConsumed, + Stack = stack, + }; + } +} diff --git a/src/Plugins/ApplicationLogs/Store/NeoStore.cs b/src/Plugins/ApplicationLogs/Store/NeoStore.cs new file mode 100644 index 0000000000..496502869b --- /dev/null +++ b/src/Plugins/ApplicationLogs/Store/NeoStore.cs @@ -0,0 +1,308 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// NeoStore.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 ApplicationLogs.Store.Models; +using ApplicationLogs.Store.States; +using Neo; +using Neo.Ledger; +using Neo.Network.P2P.Payloads; +using Neo.Persistence; +using Neo.Plugins.Store.Models; +using Neo.Plugins.Store.States; +using Neo.SmartContract; +using Neo.VM.Types; + +namespace ApplicationLogs.Store +{ + public sealed class NeoStore : IDisposable + { + #region Globals + + private readonly IStore _store; + private ISnapshot _blocklogsnapshot; + + #endregion + + #region ctor + + public NeoStore( + IStore store) + { + _store = store; + } + + #endregion + + #region IDisposable + + public void Dispose() + { + _store?.Dispose(); + GC.SuppressFinalize(this); + } + + #endregion + + #region Batching + + public void StartBlockLogBatch() + { + _blocklogsnapshot?.Dispose(); + _blocklogsnapshot = _store.GetSnapshot(); + } + + public void CommitBlockLog() => + _blocklogsnapshot?.Commit(); + + #endregion + + #region Store + + public IStore GetStore() => _store; + + #endregion + + #region Contract + + public IReadOnlyCollection<(BlockchainEventModel NotifyLog, UInt256 TxHash)> GetContractLog(UInt160 scriptHash, uint page = 1, uint pageSize = 10) + { + using var lss = new LogStorageStore(_store.GetSnapshot()); + var lstModels = new List<(BlockchainEventModel NotifyLog, UInt256 TxHash)>(); + foreach (var contractState in lss.FindContractState(scriptHash, page, pageSize)) + lstModels.Add((BlockchainEventModel.Create(contractState, CreateStackItemArray(lss, contractState.StackItemIds)), contractState.TransactionHash)); + return lstModels; + } + + public IReadOnlyCollection<(BlockchainEventModel NotifyLog, UInt256 TxHash)> GetContractLog(UInt160 scriptHash, TriggerType triggerType, uint page = 1, uint pageSize = 10) + { + using var lss = new LogStorageStore(_store.GetSnapshot()); + var lstModels = new List<(BlockchainEventModel NotifyLog, UInt256 TxHash)>(); + foreach (var contractState in lss.FindContractState(scriptHash, triggerType, page, pageSize)) + lstModels.Add((BlockchainEventModel.Create(contractState, CreateStackItemArray(lss, contractState.StackItemIds)), contractState.TransactionHash)); + return lstModels; + } + + public IReadOnlyCollection<(BlockchainEventModel NotifyLog, UInt256 TxHash)> GetContractLog(UInt160 scriptHash, TriggerType triggerType, string eventName, uint page = 1, uint pageSize = 10) + { + using var lss = new LogStorageStore(_store.GetSnapshot()); + var lstModels = new List<(BlockchainEventModel NotifyLog, UInt256 TxHash)>(); + foreach (var contractState in lss.FindContractState(scriptHash, triggerType, eventName, page, pageSize)) + lstModels.Add((BlockchainEventModel.Create(contractState, CreateStackItemArray(lss, contractState.StackItemIds)), contractState.TransactionHash)); + return lstModels; + } + + #endregion + + #region Engine + + public void PutTransactionEngineLogState(UInt256 hash, IReadOnlyList logs) + { + using var lss = new LogStorageStore(_blocklogsnapshot); + var ids = new List(); + foreach (var log in logs) + ids.Add(lss.PutEngineState(EngineLogState.Create(log.ScriptHash, log.Message))); + lss.PutTransactionEngineState(hash, TransactionEngineLogState.Create(ids.ToArray())); + } + + #endregion + + #region Block + + public BlockchainExecutionModel GetBlockLog(UInt256 hash, TriggerType trigger) + { + using var lss = new LogStorageStore(_store.GetSnapshot()); + if (lss.TryGetExecutionBlockState(hash, trigger, out var executionBlockStateId) && + lss.TryGetExecutionState(executionBlockStateId, out var executionLogState)) + { + var model = BlockchainExecutionModel.Create(trigger, executionLogState, CreateStackItemArray(lss, executionLogState.StackItemIds)); + if (lss.TryGetBlockState(hash, trigger, out var blockLogState)) + { + var lstOfEventModel = new List(); + foreach (var notifyLogItem in blockLogState.NotifyLogIds) + { + if (lss.TryGetNotifyState(notifyLogItem, out var notifyLogState)) + lstOfEventModel.Add(BlockchainEventModel.Create(notifyLogState, CreateStackItemArray(lss, notifyLogState.StackItemIds))); + } + model.Notifications = lstOfEventModel.ToArray(); + } + return model; + } + return null; + } + + public BlockchainExecutionModel GetBlockLog(UInt256 hash, TriggerType trigger, string eventName) + { + using var lss = new LogStorageStore(_store.GetSnapshot()); + if (lss.TryGetExecutionBlockState(hash, trigger, out var executionBlockStateId) && + lss.TryGetExecutionState(executionBlockStateId, out var executionLogState)) + { + var model = BlockchainExecutionModel.Create(trigger, executionLogState, CreateStackItemArray(lss, executionLogState.StackItemIds)); + if (lss.TryGetBlockState(hash, trigger, out var blockLogState)) + { + var lstOfEventModel = new List(); + foreach (var notifyLogItem in blockLogState.NotifyLogIds) + { + if (lss.TryGetNotifyState(notifyLogItem, out var notifyLogState)) + { + if (notifyLogState.EventName.Equals(eventName, StringComparison.OrdinalIgnoreCase)) + lstOfEventModel.Add(BlockchainEventModel.Create(notifyLogState, CreateStackItemArray(lss, notifyLogState.StackItemIds))); + } + } + model.Notifications = lstOfEventModel.ToArray(); + } + return model; + } + return null; + } + + public void PutBlockLog(Block block, IReadOnlyList applicationExecutedList) + { + foreach (var appExecution in applicationExecutedList) + { + using var lss = new LogStorageStore(_blocklogsnapshot); + var exeStateId = PutExecutionLogBlock(lss, block, appExecution); + PutBlockAndTransactionLog(lss, block, appExecution, exeStateId); + } + } + + private static Guid PutExecutionLogBlock(LogStorageStore logStore, Block block, Blockchain.ApplicationExecuted appExecution) + { + var exeStateId = logStore.PutExecutionState(ExecutionLogState.Create(appExecution, CreateStackItemIdList(logStore, appExecution))); + logStore.PutExecutionBlockState(block.Hash, appExecution.Trigger, exeStateId); + return exeStateId; + } + + #endregion + + #region Transaction + + public BlockchainExecutionModel GetTransactionLog(UInt256 hash) + { + using var lss = new LogStorageStore(_store.GetSnapshot()); + if (lss.TryGetExecutionTransactionState(hash, out var executionTransactionStateId) && + lss.TryGetExecutionState(executionTransactionStateId, out var executionLogState)) + { + var model = BlockchainExecutionModel.Create(TriggerType.Application, executionLogState, CreateStackItemArray(lss, executionLogState.StackItemIds)); + if (lss.TryGetTransactionState(hash, out var transactionLogState)) + { + var lstOfEventModel = new List(); + foreach (var notifyLogItem in transactionLogState.NotifyLogIds) + { + if (lss.TryGetNotifyState(notifyLogItem, out var notifyLogState)) + lstOfEventModel.Add(BlockchainEventModel.Create(notifyLogState, CreateStackItemArray(lss, notifyLogState.StackItemIds))); + } + model.Notifications = lstOfEventModel.ToArray(); + + if (lss.TryGetTransactionEngineState(hash, out var transactionEngineLogState)) + { + var lstOfLogs = new List(); + foreach (var logItem in transactionEngineLogState.LogIds) + { + if (lss.TryGetEngineState(logItem, out var engineLogState)) + lstOfLogs.Add(ApplicationEngineLogModel.Create(engineLogState)); + } + model.Logs = lstOfLogs.ToArray(); + } + } + return model; + } + return null; + } + + public BlockchainExecutionModel GetTransactionLog(UInt256 hash, string eventName) + { + using var lss = new LogStorageStore(_store.GetSnapshot()); + if (lss.TryGetExecutionTransactionState(hash, out var executionTransactionStateId) && + lss.TryGetExecutionState(executionTransactionStateId, out var executionLogState)) + { + var model = BlockchainExecutionModel.Create(TriggerType.Application, executionLogState, CreateStackItemArray(lss, executionLogState.StackItemIds)); + if (lss.TryGetTransactionState(hash, out var transactionLogState)) + { + var lstOfEventModel = new List(); + foreach (var notifyLogItem in transactionLogState.NotifyLogIds) + { + if (lss.TryGetNotifyState(notifyLogItem, out var notifyLogState)) + { + if (notifyLogState.EventName.Equals(eventName, StringComparison.OrdinalIgnoreCase)) + lstOfEventModel.Add(BlockchainEventModel.Create(notifyLogState, CreateStackItemArray(lss, notifyLogState.StackItemIds))); + } + } + model.Notifications = lstOfEventModel.ToArray(); + + if (lss.TryGetTransactionEngineState(hash, out var transactionEngineLogState)) + { + var lstOfLogs = new List(); + foreach (var logItem in transactionEngineLogState.LogIds) + { + if (lss.TryGetEngineState(logItem, out var engineLogState)) + lstOfLogs.Add(ApplicationEngineLogModel.Create(engineLogState)); + } + model.Logs = lstOfLogs.ToArray(); + } + } + return model; + } + return null; + } + + private static void PutBlockAndTransactionLog(LogStorageStore logStore, Block block, Blockchain.ApplicationExecuted appExecution, Guid executionStateId) + { + if (appExecution.Transaction != null) + logStore.PutExecutionTransactionState(appExecution.Transaction.Hash, executionStateId); // For looking up execution log by transaction hash + + var lstNotifyLogIds = new List(); + for (uint i = 0; i < appExecution.Notifications.Length; i++) + { + var notifyItem = appExecution.Notifications[i]; + var stackItemStateIds = CreateStackItemIdList(logStore, notifyItem); // Save notify stack items + logStore.PutContractState(notifyItem.ScriptHash, block.Timestamp, i, // save notifylog for the contracts + ContractLogState.Create(appExecution, notifyItem, stackItemStateIds)); + lstNotifyLogIds.Add(logStore.PutNotifyState(NotifyLogState.Create(notifyItem, stackItemStateIds))); + } + + if (appExecution.Transaction != null) + logStore.PutTransactionState(appExecution.Transaction.Hash, TransactionLogState.Create(lstNotifyLogIds.ToArray())); + + logStore.PutBlockState(block.Hash, appExecution.Trigger, BlockLogState.Create(lstNotifyLogIds.ToArray())); + } + + #endregion + + #region StackItem + + private static StackItem[] CreateStackItemArray(LogStorageStore logStore, Guid[] stackItemIds) + { + var lstStackItems = new List(); + foreach (var stackItemId in stackItemIds) + if (logStore.TryGetStackItemState(stackItemId, out var stackItem)) + lstStackItems.Add(stackItem); + return lstStackItems.ToArray(); + } + + private static Guid[] CreateStackItemIdList(LogStorageStore logStore, Blockchain.ApplicationExecuted appExecution) + { + var lstStackItemIds = new List(); + foreach (var stackItem in appExecution.Stack) + lstStackItemIds.Add(logStore.PutStackItemState(stackItem)); + return lstStackItemIds.ToArray(); + } + + private static Guid[] CreateStackItemIdList(LogStorageStore logStore, NotifyEventArgs notifyEventArgs) + { + var lstStackItemIds = new List(); + foreach (var stackItem in notifyEventArgs.State) + lstStackItemIds.Add(logStore.PutStackItemState(stackItem)); + return lstStackItemIds.ToArray(); + } + + #endregion + } +} diff --git a/src/Plugins/ApplicationLogs/Store/States/BlockLogState.cs b/src/Plugins/ApplicationLogs/Store/States/BlockLogState.cs new file mode 100644 index 0000000000..dcbb58b6e6 --- /dev/null +++ b/src/Plugins/ApplicationLogs/Store/States/BlockLogState.cs @@ -0,0 +1,72 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// BlockLogState.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; +using Neo.IO; + +namespace ApplicationLogs.Store.States +{ + public class BlockLogState : ISerializable, IEquatable + { + public Guid[] NotifyLogIds { get; private set; } = []; + + public static BlockLogState Create(Guid[] notifyLogIds) => + new() + { + NotifyLogIds = notifyLogIds, + }; + + #region ISerializable + + public virtual int Size => + sizeof(uint) + + NotifyLogIds.Sum(s => s.ToByteArray().GetVarSize()); + + public virtual void Deserialize(ref MemoryReader reader) + { + // It should be safe because it filled from a block's notifications. + uint aLen = reader.ReadUInt32(); + NotifyLogIds = new Guid[aLen]; + for (int i = 0; i < aLen; i++) + NotifyLogIds[i] = new Guid(reader.ReadVarMemory().Span); + } + + public virtual void Serialize(BinaryWriter writer) + { + writer.Write((uint)NotifyLogIds.Length); + for (int i = 0; i < NotifyLogIds.Length; i++) + writer.WriteVarBytes(NotifyLogIds[i].ToByteArray()); + } + + #endregion + + #region IEquatable + + public bool Equals(BlockLogState other) => + NotifyLogIds.SequenceEqual(other.NotifyLogIds); + + public override bool Equals(object obj) + { + if (ReferenceEquals(this, obj)) return true; + return Equals(obj as BlockLogState); + } + + public override int GetHashCode() + { + var h = new HashCode(); + foreach (var id in NotifyLogIds) + h.Add(id); + return h.ToHashCode(); + } + + #endregion + } +} diff --git a/src/Plugins/ApplicationLogs/Store/States/ContractLogState.cs b/src/Plugins/ApplicationLogs/Store/States/ContractLogState.cs new file mode 100644 index 0000000000..0987e86e67 --- /dev/null +++ b/src/Plugins/ApplicationLogs/Store/States/ContractLogState.cs @@ -0,0 +1,74 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// ContractLogState.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; +using Neo.IO; +using Neo.Ledger; +using Neo.SmartContract; + +namespace ApplicationLogs.Store.States +{ + public class ContractLogState : NotifyLogState, IEquatable + { + public UInt256 TransactionHash { get; private set; } = new(); + public TriggerType Trigger { get; private set; } = TriggerType.All; + + public static ContractLogState Create(Blockchain.ApplicationExecuted applicationExecuted, NotifyEventArgs notifyEventArgs, Guid[] stackItemIds) => + new() + { + TransactionHash = applicationExecuted.Transaction?.Hash ?? new(), + ScriptHash = notifyEventArgs.ScriptHash, + Trigger = applicationExecuted.Trigger, + EventName = notifyEventArgs.EventName, + StackItemIds = stackItemIds, + }; + + #region ISerializable + + public override int Size => + TransactionHash.Size + + sizeof(byte) + + base.Size; + + public override void Deserialize(ref MemoryReader reader) + { + TransactionHash.Deserialize(ref reader); + Trigger = (TriggerType)reader.ReadByte(); + base.Deserialize(ref reader); + } + + public override void Serialize(BinaryWriter writer) + { + TransactionHash.Serialize(writer); + writer.Write((byte)Trigger); + base.Serialize(writer); + } + + #endregion + + #region IEquatable + + public bool Equals(ContractLogState other) => + Trigger == other.Trigger && EventName == other.EventName && + TransactionHash == other.TransactionHash && StackItemIds.SequenceEqual(other.StackItemIds); + + public override bool Equals(object obj) + { + if (ReferenceEquals(this, obj)) return true; + return Equals(obj as ContractLogState); + } + + public override int GetHashCode() => + HashCode.Combine(TransactionHash, Trigger, base.GetHashCode()); + + #endregion + } +} diff --git a/src/Plugins/ApplicationLogs/Store/States/EngineLogState.cs b/src/Plugins/ApplicationLogs/Store/States/EngineLogState.cs new file mode 100644 index 0000000000..8b07855253 --- /dev/null +++ b/src/Plugins/ApplicationLogs/Store/States/EngineLogState.cs @@ -0,0 +1,66 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// EngineLogState.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.IO; + +namespace Neo.Plugins.Store.States +{ + public class EngineLogState : ISerializable, IEquatable + { + public UInt160 ScriptHash { get; private set; } = new(); + public string Message { get; private set; } = string.Empty; + + public static EngineLogState Create(UInt160 scriptHash, string message) => + new() + { + ScriptHash = scriptHash, + Message = message, + }; + + #region ISerializable + + public virtual int Size => + ScriptHash.Size + + Message.GetVarSize(); + + public virtual void Deserialize(ref MemoryReader reader) + { + ScriptHash.Deserialize(ref reader); + // It should be safe because it filled from a transaction's logs. + Message = reader.ReadVarString(); + } + + public virtual void Serialize(BinaryWriter writer) + { + ScriptHash.Serialize(writer); + writer.WriteVarString(Message ?? string.Empty); + } + + #endregion + + #region IEquatable + + public bool Equals(EngineLogState other) => + ScriptHash == other.ScriptHash && + Message == other.Message; + + public override bool Equals(object obj) + { + if (ReferenceEquals(this, obj)) return true; + return Equals(obj as EngineLogState); + } + + public override int GetHashCode() => + HashCode.Combine(ScriptHash, Message); + + #endregion + } +} diff --git a/src/Plugins/ApplicationLogs/Store/States/ExecutionLogState.cs b/src/Plugins/ApplicationLogs/Store/States/ExecutionLogState.cs new file mode 100644 index 0000000000..44f8a74b49 --- /dev/null +++ b/src/Plugins/ApplicationLogs/Store/States/ExecutionLogState.cs @@ -0,0 +1,94 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// ExecutionLogState.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.IO; +using Neo.Ledger; +using Neo.VM; + +namespace ApplicationLogs.Store.States +{ + public class ExecutionLogState : ISerializable, IEquatable + { + public VMState VmState { get; private set; } = VMState.NONE; + public string Exception { get; private set; } = string.Empty; + public long GasConsumed { get; private set; } = 0L; + public Guid[] StackItemIds { get; private set; } = []; + + public static ExecutionLogState Create(Blockchain.ApplicationExecuted appExecution, Guid[] stackItemIds) => + new() + { + VmState = appExecution.VMState, + Exception = appExecution.Exception?.InnerException?.Message ?? appExecution.Exception?.Message!, + GasConsumed = appExecution.GasConsumed, + StackItemIds = stackItemIds, + }; + + #region ISerializable + + public int Size => + sizeof(byte) + + Exception.GetVarSize() + + sizeof(long) + + sizeof(uint) + + StackItemIds.Sum(s => s.ToByteArray().GetVarSize()); + + public void Deserialize(ref MemoryReader reader) + { + VmState = (VMState)reader.ReadByte(); + Exception = reader.ReadVarString(); + GasConsumed = reader.ReadInt64(); + + // It should be safe because it filled from a transaction's stack. + uint aLen = reader.ReadUInt32(); + StackItemIds = new Guid[aLen]; + for (int i = 0; i < aLen; i++) + StackItemIds[i] = new Guid(reader.ReadVarMemory().Span); + } + + public void Serialize(BinaryWriter writer) + { + writer.Write((byte)VmState); + writer.WriteVarString(Exception ?? string.Empty); + writer.Write(GasConsumed); + + writer.Write((uint)StackItemIds.Length); + for (int i = 0; i < StackItemIds.Length; i++) + writer.WriteVarBytes(StackItemIds[i].ToByteArray()); + } + + #endregion + + #region IEquatable + + public bool Equals(ExecutionLogState other) => + VmState == other.VmState && Exception == other.Exception && + GasConsumed == other.GasConsumed && StackItemIds.SequenceEqual(other.StackItemIds); + + public override bool Equals(object obj) + { + if (ReferenceEquals(this, obj)) return true; + return Equals(obj as ExecutionLogState); + } + + public override int GetHashCode() + { + var h = new HashCode(); + h.Add(VmState); + h.Add(Exception); + h.Add(GasConsumed); + foreach (var id in StackItemIds) + h.Add(id); + return h.ToHashCode(); + } + + #endregion + } +} diff --git a/src/Plugins/ApplicationLogs/Store/States/NotifyLogState.cs b/src/Plugins/ApplicationLogs/Store/States/NotifyLogState.cs new file mode 100644 index 0000000000..20fbd9e456 --- /dev/null +++ b/src/Plugins/ApplicationLogs/Store/States/NotifyLogState.cs @@ -0,0 +1,87 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// NotifyLogState.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; +using Neo.IO; +using Neo.SmartContract; + +namespace ApplicationLogs.Store.States +{ + public class NotifyLogState : ISerializable, IEquatable + { + public UInt160 ScriptHash { get; protected set; } = new(); + public string EventName { get; protected set; } = string.Empty; + public Guid[] StackItemIds { get; protected set; } = []; + + public static NotifyLogState Create(NotifyEventArgs notifyItem, Guid[] stackItemsIds) => + new() + { + ScriptHash = notifyItem.ScriptHash, + EventName = notifyItem.EventName, + StackItemIds = stackItemsIds, + }; + + #region ISerializable + + public virtual int Size => + ScriptHash.Size + + EventName.GetVarSize() + + StackItemIds.Sum(s => s.ToByteArray().GetVarSize()); + + public virtual void Deserialize(ref MemoryReader reader) + { + ScriptHash.Deserialize(ref reader); + EventName = reader.ReadVarString(); + + // It should be safe because it filled from a transaction's notifications. + uint aLen = reader.ReadUInt32(); + StackItemIds = new Guid[aLen]; + for (var i = 0; i < aLen; i++) + StackItemIds[i] = new Guid(reader.ReadVarMemory().Span); + } + + public virtual void Serialize(BinaryWriter writer) + { + ScriptHash.Serialize(writer); + writer.WriteVarString(EventName ?? string.Empty); + + writer.Write((uint)StackItemIds.Length); + for (var i = 0; i < StackItemIds.Length; i++) + writer.WriteVarBytes(StackItemIds[i].ToByteArray()); + } + + #endregion + + #region IEquatable + + public bool Equals(NotifyLogState other) => + EventName == other.EventName && ScriptHash == other.ScriptHash && + StackItemIds.SequenceEqual(other.StackItemIds); + + public override bool Equals(object obj) + { + if (ReferenceEquals(this, obj)) return true; + return Equals(obj as NotifyLogState); + } + + public override int GetHashCode() + { + var h = new HashCode(); + h.Add(ScriptHash); + h.Add(EventName); + foreach (var id in StackItemIds) + h.Add(id); + return h.ToHashCode(); + } + + #endregion + } +} diff --git a/src/Plugins/ApplicationLogs/Store/States/TransactionEngineLogState.cs b/src/Plugins/ApplicationLogs/Store/States/TransactionEngineLogState.cs new file mode 100644 index 0000000000..8b32867b66 --- /dev/null +++ b/src/Plugins/ApplicationLogs/Store/States/TransactionEngineLogState.cs @@ -0,0 +1,71 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// TransactionEngineLogState.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.IO; + +namespace Neo.Plugins.Store.States +{ + public class TransactionEngineLogState : ISerializable, IEquatable + { + public Guid[] LogIds { get; private set; } = Array.Empty(); + + public static TransactionEngineLogState Create(Guid[] logIds) => + new() + { + LogIds = logIds, + }; + + #region ISerializable + + public virtual int Size => + sizeof(uint) + + LogIds.Sum(s => s.ToByteArray().GetVarSize()); + + public virtual void Deserialize(ref MemoryReader reader) + { + // It should be safe because it filled from a transaction's logs. + uint aLen = reader.ReadUInt32(); + LogIds = new Guid[aLen]; + for (int i = 0; i < aLen; i++) + LogIds[i] = new Guid(reader.ReadVarMemory().Span); + } + + public virtual void Serialize(BinaryWriter writer) + { + writer.Write((uint)LogIds.Length); + for (int i = 0; i < LogIds.Length; i++) + writer.WriteVarBytes(LogIds[i].ToByteArray()); + } + + #endregion + + #region IEquatable + + public bool Equals(TransactionEngineLogState other) => + LogIds.SequenceEqual(other.LogIds); + + public override bool Equals(object obj) + { + if (ReferenceEquals(this, obj)) return true; + return Equals(obj as TransactionEngineLogState); + } + + public override int GetHashCode() + { + var h = new HashCode(); + foreach (var id in LogIds) + h.Add(id); + return h.ToHashCode(); + } + + #endregion + } +} diff --git a/src/Plugins/ApplicationLogs/Store/States/TransactionLogState.cs b/src/Plugins/ApplicationLogs/Store/States/TransactionLogState.cs new file mode 100644 index 0000000000..b40d3244d0 --- /dev/null +++ b/src/Plugins/ApplicationLogs/Store/States/TransactionLogState.cs @@ -0,0 +1,72 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// TransactionLogState.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; +using Neo.IO; + +namespace ApplicationLogs.Store.States +{ + public class TransactionLogState : ISerializable, IEquatable + { + public Guid[] NotifyLogIds { get; private set; } = Array.Empty(); + + public static TransactionLogState Create(Guid[] notifyLogIds) => + new() + { + NotifyLogIds = notifyLogIds, + }; + + #region ISerializable + + public virtual int Size => + sizeof(uint) + + NotifyLogIds.Sum(s => s.ToByteArray().GetVarSize()); + + public virtual void Deserialize(ref MemoryReader reader) + { + // It should be safe because it filled from a transaction's notifications. + uint aLen = reader.ReadUInt32(); + NotifyLogIds = new Guid[aLen]; + for (int i = 0; i < aLen; i++) + NotifyLogIds[i] = new Guid(reader.ReadVarMemory().Span); + } + + public virtual void Serialize(BinaryWriter writer) + { + writer.Write((uint)NotifyLogIds.Length); + for (int i = 0; i < NotifyLogIds.Length; i++) + writer.WriteVarBytes(NotifyLogIds[i].ToByteArray()); + } + + #endregion + + #region IEquatable + + public bool Equals(TransactionLogState other) => + NotifyLogIds.SequenceEqual(other.NotifyLogIds); + + public override bool Equals(object obj) + { + if (ReferenceEquals(this, obj)) return true; + return Equals(obj as TransactionLogState); + } + + public override int GetHashCode() + { + var h = new HashCode(); + foreach (var id in NotifyLogIds) + h.Add(id); + return h.ToHashCode(); + } + + #endregion + } +} diff --git a/src/Plugins/ApplicationLogs/config.json b/src/Plugins/ApplicationLogs/config.json new file mode 100644 index 0000000000..af601bc81e --- /dev/null +++ b/src/Plugins/ApplicationLogs/config.json @@ -0,0 +1,11 @@ +{ + "PluginConfiguration": { + "Path": "ApplicationLogs_{0}", + "Network": 860833102, + "MaxStackSize": 65535, + "Debug": false + }, + "Dependency": [ + "RpcServer" + ] +} diff --git a/src/Plugins/DBFTPlugin/Consensus/ConsensusContext.Get.cs b/src/Plugins/DBFTPlugin/Consensus/ConsensusContext.Get.cs new file mode 100644 index 0000000000..b54b6eca1e --- /dev/null +++ b/src/Plugins/DBFTPlugin/Consensus/ConsensusContext.Get.cs @@ -0,0 +1,117 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// ConsensusContext.Get.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.Payloads; +using Neo.SmartContract; +using Neo.Wallets; +using System.Linq; +using System.Runtime.CompilerServices; +using static Neo.Consensus.RecoveryMessage; + +namespace Neo.Consensus +{ + partial class ConsensusContext + { + public ConsensusMessage GetMessage(ExtensiblePayload payload) + { + if (payload is null) return null; + if (!cachedMessages.TryGetValue(payload.Hash, out ConsensusMessage message)) + cachedMessages.Add(payload.Hash, message = ConsensusMessage.DeserializeFrom(payload.Data)); + return message; + } + + public T GetMessage(ExtensiblePayload payload) where T : ConsensusMessage + { + return (T)GetMessage(payload); + } + + private ChangeViewPayloadCompact GetChangeViewPayloadCompact(ExtensiblePayload payload) + { + ChangeView message = GetMessage(payload); + return new ChangeViewPayloadCompact + { + ValidatorIndex = message.ValidatorIndex, + OriginalViewNumber = message.ViewNumber, + Timestamp = message.Timestamp, + InvocationScript = payload.Witness.InvocationScript + }; + } + + private CommitPayloadCompact GetCommitPayloadCompact(ExtensiblePayload payload) + { + Commit message = GetMessage(payload); + return new CommitPayloadCompact + { + ViewNumber = message.ViewNumber, + ValidatorIndex = message.ValidatorIndex, + Signature = message.Signature, + InvocationScript = payload.Witness.InvocationScript + }; + } + + private PreparationPayloadCompact GetPreparationPayloadCompact(ExtensiblePayload payload) + { + return new PreparationPayloadCompact + { + ValidatorIndex = GetMessage(payload).ValidatorIndex, + InvocationScript = payload.Witness.InvocationScript + }; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public byte GetPrimaryIndex(byte viewNumber) + { + int p = ((int)Block.Index - viewNumber) % Validators.Length; + return p >= 0 ? (byte)p : (byte)(p + Validators.Length); + } + + public UInt160 GetSender(int index) + { + return Contract.CreateSignatureRedeemScript(Validators[index]).ToScriptHash(); + } + + /// + /// Return the expected block size + /// + public int GetExpectedBlockSize() + { + return GetExpectedBlockSizeWithoutTransactions(Transactions.Count) + // Base size + Transactions.Values.Sum(u => u.Size); // Sum Txs + } + + /// + /// Return the expected block system fee + /// + public long GetExpectedBlockSystemFee() + { + return Transactions.Values.Sum(u => u.SystemFee); // Sum Txs + } + + /// + /// Return the expected block size without txs + /// + /// Expected transactions + internal int GetExpectedBlockSizeWithoutTransactions(int expectedTransactions) + { + return + sizeof(uint) + // Version + UInt256.Length + // PrevHash + UInt256.Length + // MerkleRoot + sizeof(ulong) + // Timestamp + sizeof(ulong) + // Nonce + sizeof(uint) + // Index + sizeof(byte) + // PrimaryIndex + UInt160.Length + // NextConsensus + 1 + _witnessSize + // Witness + IO.Helper.GetVarSize(expectedTransactions); + } + } +} diff --git a/src/Plugins/DBFTPlugin/Consensus/ConsensusContext.MakePayload.cs b/src/Plugins/DBFTPlugin/Consensus/ConsensusContext.MakePayload.cs new file mode 100644 index 0000000000..a761cbafb0 --- /dev/null +++ b/src/Plugins/DBFTPlugin/Consensus/ConsensusContext.MakePayload.cs @@ -0,0 +1,176 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// ConsensusContext.MakePayload.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.SmartContract; +using Neo.Wallets; +using System; +using System.Buffers.Binary; +using System.Collections.Generic; +using System.Linq; +using static Neo.Consensus.RecoveryMessage; + +namespace Neo.Consensus +{ + partial class ConsensusContext + { + public ExtensiblePayload MakeChangeView(ChangeViewReason reason) + { + return ChangeViewPayloads[MyIndex] = MakeSignedPayload(new ChangeView + { + Reason = reason, + Timestamp = TimeProvider.Current.UtcNow.ToTimestampMS() + }); + } + + public ExtensiblePayload MakeCommit() + { + return CommitPayloads[MyIndex] ?? (CommitPayloads[MyIndex] = MakeSignedPayload(new Commit + { + Signature = EnsureHeader().Sign(keyPair, neoSystem.Settings.Network) + })); + } + + private ExtensiblePayload MakeSignedPayload(ConsensusMessage message) + { + message.BlockIndex = Block.Index; + message.ValidatorIndex = (byte)MyIndex; + message.ViewNumber = ViewNumber; + ExtensiblePayload payload = CreatePayload(message, null); + SignPayload(payload); + return payload; + } + + private void SignPayload(ExtensiblePayload payload) + { + ContractParametersContext sc; + try + { + sc = new ContractParametersContext(neoSystem.StoreView, payload, dbftSettings.Network); + wallet.Sign(sc); + } + catch (InvalidOperationException exception) + { + Utility.Log(nameof(ConsensusContext), LogLevel.Debug, exception.ToString()); + return; + } + payload.Witness = sc.GetWitnesses()[0]; + } + + /// + /// Prevent that block exceed the max size + /// + /// Ordered transactions + internal void EnsureMaxBlockLimitation(IEnumerable txs) + { + uint maxTransactionsPerBlock = neoSystem.Settings.MaxTransactionsPerBlock; + + // Limit Speaker proposal to the limit `MaxTransactionsPerBlock` or all available transactions of the mempool + txs = txs.Take((int)maxTransactionsPerBlock); + + List hashes = new List(); + Transactions = new Dictionary(); + VerificationContext = new TransactionVerificationContext(); + + // Expected block size + var blockSize = GetExpectedBlockSizeWithoutTransactions(txs.Count()); + var blockSystemFee = 0L; + + // Iterate transaction until reach the size or maximum system fee + foreach (Transaction tx in txs) + { + // Check if maximum block size has been already exceeded with the current selected set + blockSize += tx.Size; + if (blockSize > dbftSettings.MaxBlockSize) break; + + // Check if maximum block system fee has been already exceeded with the current selected set + blockSystemFee += tx.SystemFee; + if (blockSystemFee > dbftSettings.MaxBlockSystemFee) break; + + hashes.Add(tx.Hash); + Transactions.Add(tx.Hash, tx); + VerificationContext.AddTransaction(tx); + } + + TransactionHashes = hashes.ToArray(); + } + + public ExtensiblePayload MakePrepareRequest() + { + EnsureMaxBlockLimitation(neoSystem.MemPool.GetSortedVerifiedTransactions()); + Block.Header.Timestamp = Math.Max(TimeProvider.Current.UtcNow.ToTimestampMS(), PrevHeader.Timestamp + 1); + Block.Header.Nonce = GetNonce(); + return PreparationPayloads[MyIndex] = MakeSignedPayload(new PrepareRequest + { + Version = Block.Version, + PrevHash = Block.PrevHash, + Timestamp = Block.Timestamp, + Nonce = Block.Nonce, + TransactionHashes = TransactionHashes + }); + } + + public ExtensiblePayload MakeRecoveryRequest() + { + return MakeSignedPayload(new RecoveryRequest + { + Timestamp = TimeProvider.Current.UtcNow.ToTimestampMS() + }); + } + + public ExtensiblePayload MakeRecoveryMessage() + { + PrepareRequest prepareRequestMessage = null; + if (TransactionHashes != null) + { + prepareRequestMessage = new PrepareRequest + { + Version = Block.Version, + PrevHash = Block.PrevHash, + ViewNumber = ViewNumber, + Timestamp = Block.Timestamp, + Nonce = Block.Nonce, + BlockIndex = Block.Index, + ValidatorIndex = Block.PrimaryIndex, + TransactionHashes = TransactionHashes + }; + } + return MakeSignedPayload(new RecoveryMessage + { + ChangeViewMessages = LastChangeViewPayloads.Where(p => p != null).Select(p => GetChangeViewPayloadCompact(p)).Take(M).ToDictionary(p => p.ValidatorIndex), + PrepareRequestMessage = prepareRequestMessage, + // We only need a PreparationHash set if we don't have the PrepareRequest information. + PreparationHash = TransactionHashes == null ? PreparationPayloads.Where(p => p != null).GroupBy(p => GetMessage(p).PreparationHash, (k, g) => new { Hash = k, Count = g.Count() }).OrderByDescending(p => p.Count).Select(p => p.Hash).FirstOrDefault() : null, + PreparationMessages = PreparationPayloads.Where(p => p != null).Select(p => GetPreparationPayloadCompact(p)).ToDictionary(p => p.ValidatorIndex), + CommitMessages = CommitSent + ? CommitPayloads.Where(p => p != null).Select(p => GetCommitPayloadCompact(p)).ToDictionary(p => p.ValidatorIndex) + : new Dictionary() + }); + } + + public ExtensiblePayload MakePrepareResponse() + { + return PreparationPayloads[MyIndex] = MakeSignedPayload(new PrepareResponse + { + PreparationHash = PreparationPayloads[Block.PrimaryIndex].Hash + }); + } + + private static ulong GetNonce() + { + Random _random = new(); + Span buffer = stackalloc byte[8]; + _random.NextBytes(buffer); + return BinaryPrimitives.ReadUInt64LittleEndian(buffer); + } + } +} diff --git a/src/Plugins/DBFTPlugin/Consensus/ConsensusContext.cs b/src/Plugins/DBFTPlugin/Consensus/ConsensusContext.cs new file mode 100644 index 0000000000..35044e4fb8 --- /dev/null +++ b/src/Plugins/DBFTPlugin/Consensus/ConsensusContext.cs @@ -0,0 +1,323 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// ConsensusContext.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; +using Neo.Cryptography.ECC; +using Neo.IO; +using Neo.Ledger; +using Neo.Network.P2P.Payloads; +using Neo.Persistence; +using Neo.SmartContract; +using Neo.SmartContract.Native; +using Neo.VM; +using Neo.Wallets; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace Neo.Consensus +{ + public partial class ConsensusContext : IDisposable, ISerializable + { + /// + /// Key for saving consensus state. + /// + private static readonly byte[] ConsensusStateKey = { 0xf4 }; + + public Block Block; + public byte ViewNumber; + public ECPoint[] Validators; + public int MyIndex; + public UInt256[] TransactionHashes; + public Dictionary Transactions; + public ExtensiblePayload[] PreparationPayloads; + public ExtensiblePayload[] CommitPayloads; + public ExtensiblePayload[] ChangeViewPayloads; + public ExtensiblePayload[] LastChangeViewPayloads; + // LastSeenMessage array stores the height of the last seen message, for each validator. + // if this node never heard from validator i, LastSeenMessage[i] will be -1. + public Dictionary LastSeenMessage { get; private set; } + + /// + /// Store all verified unsorted transactions' senders' fee currently in the consensus context. + /// + public TransactionVerificationContext VerificationContext = new(); + + public SnapshotCache Snapshot { get; private set; } + private KeyPair keyPair; + private int _witnessSize; + private readonly NeoSystem neoSystem; + private readonly Settings dbftSettings; + private readonly Wallet wallet; + private readonly IStore store; + private Dictionary cachedMessages; + + public int F => (Validators.Length - 1) / 3; + public int M => Validators.Length - F; + public bool IsPrimary => MyIndex == Block.PrimaryIndex; + public bool IsBackup => MyIndex >= 0 && MyIndex != Block.PrimaryIndex; + public bool WatchOnly => MyIndex < 0; + public Header PrevHeader => NativeContract.Ledger.GetHeader(Snapshot, Block.PrevHash); + public int CountCommitted => CommitPayloads.Count(p => p != null); + public int CountFailed + { + get + { + if (LastSeenMessage == null) return 0; + return Validators.Count(p => !LastSeenMessage.TryGetValue(p, out var value) || value < (Block.Index - 1)); + } + } + public bool ValidatorsChanged + { + get + { + if (NativeContract.Ledger.CurrentIndex(Snapshot) == 0) return false; + UInt256 hash = NativeContract.Ledger.CurrentHash(Snapshot); + TrimmedBlock currentBlock = NativeContract.Ledger.GetTrimmedBlock(Snapshot, hash); + TrimmedBlock previousBlock = NativeContract.Ledger.GetTrimmedBlock(Snapshot, currentBlock.Header.PrevHash); + return currentBlock.Header.NextConsensus != previousBlock.Header.NextConsensus; + } + } + + #region Consensus States + public bool RequestSentOrReceived => PreparationPayloads[Block.PrimaryIndex] != null; + public bool ResponseSent => !WatchOnly && PreparationPayloads[MyIndex] != null; + public bool CommitSent => !WatchOnly && CommitPayloads[MyIndex] != null; + public bool BlockSent => Block.Transactions != null; + public bool ViewChanging => !WatchOnly && GetMessage(ChangeViewPayloads[MyIndex])?.NewViewNumber > ViewNumber; + // NotAcceptingPayloadsDueToViewChanging imposes nodes to not accept some payloads if View is Changing, + // i.e: OnTransaction function will not process any transaction; OnPrepareRequestReceived will also return; + // as well as OnPrepareResponseReceived and also similar logic for recovering. + // On the other hand, if more than MoreThanFNodesCommittedOrLost is true, we keep accepting those payloads. + // This helps the node to still commit, even while almost changing view. + public bool NotAcceptingPayloadsDueToViewChanging => ViewChanging && !MoreThanFNodesCommittedOrLost; + // A possible attack can happen if the last node to commit is malicious and either sends change view after his + // commit to stall nodes in a higher view, or if he refuses to send recovery messages. In addition, if a node + // asking change views loses network or crashes and comes back when nodes are committed in more than one higher + // numbered view, it is possible for the node accepting recovery to commit in any of the higher views, thus + // potentially splitting nodes among views and stalling the network. + public bool MoreThanFNodesCommittedOrLost => (CountCommitted + CountFailed) > F; + #endregion + + public int Size => throw new NotImplementedException(); + + public ConsensusContext(NeoSystem neoSystem, Settings settings, Wallet wallet) + { + this.wallet = wallet; + this.neoSystem = neoSystem; + dbftSettings = settings; + store = neoSystem.LoadStore(settings.RecoveryLogs); + } + + public Block CreateBlock() + { + EnsureHeader(); + Contract contract = Contract.CreateMultiSigContract(M, Validators); + ContractParametersContext sc = new ContractParametersContext(neoSystem.StoreView, Block.Header, dbftSettings.Network); + for (int i = 0, j = 0; i < Validators.Length && j < M; i++) + { + if (GetMessage(CommitPayloads[i])?.ViewNumber != ViewNumber) continue; + sc.AddSignature(contract, Validators[i], GetMessage(CommitPayloads[i]).Signature.ToArray()); + j++; + } + Block.Header.Witness = sc.GetWitnesses()[0]; + Block.Transactions = TransactionHashes.Select(p => Transactions[p]).ToArray(); + return Block; + } + + public ExtensiblePayload CreatePayload(ConsensusMessage message, ReadOnlyMemory invocationScript = default) + { + ExtensiblePayload payload = new ExtensiblePayload + { + Category = "dBFT", + ValidBlockStart = 0, + ValidBlockEnd = message.BlockIndex, + Sender = GetSender(message.ValidatorIndex), + Data = message.ToArray(), + Witness = invocationScript.IsEmpty ? null : new Witness + { + InvocationScript = invocationScript, + VerificationScript = Contract.CreateSignatureRedeemScript(Validators[message.ValidatorIndex]) + } + }; + cachedMessages.TryAdd(payload.Hash, message); + return payload; + } + + public void Dispose() + { + Snapshot?.Dispose(); + } + + public Block EnsureHeader() + { + if (TransactionHashes == null) return null; + Block.Header.MerkleRoot ??= MerkleTree.ComputeRoot(TransactionHashes); + return Block; + } + + public bool Load() + { + byte[] data = store.TryGet(ConsensusStateKey); + if (data is null || data.Length == 0) return false; + MemoryReader reader = new(data); + try + { + Deserialize(ref reader); + } + catch (InvalidOperationException) + { + return false; + } + catch (Exception exception) + { + Utility.Log(nameof(ConsensusContext), LogLevel.Debug, exception.ToString()); + return false; + } + return true; + } + + public void Reset(byte viewNumber) + { + if (viewNumber == 0) + { + Snapshot?.Dispose(); + Snapshot = neoSystem.GetSnapshot(); + uint height = NativeContract.Ledger.CurrentIndex(Snapshot); + Block = new Block + { + Header = new Header + { + PrevHash = NativeContract.Ledger.CurrentHash(Snapshot), + Index = height + 1, + NextConsensus = Contract.GetBFTAddress( + NeoToken.ShouldRefreshCommittee(height + 1, neoSystem.Settings.CommitteeMembersCount) ? + NativeContract.NEO.ComputeNextBlockValidators(Snapshot, neoSystem.Settings) : + NativeContract.NEO.GetNextBlockValidators(Snapshot, neoSystem.Settings.ValidatorsCount)) + } + }; + var pv = Validators; + Validators = NativeContract.NEO.GetNextBlockValidators(Snapshot, neoSystem.Settings.ValidatorsCount); + if (_witnessSize == 0 || (pv != null && pv.Length != Validators.Length)) + { + // Compute the expected size of the witness + using (ScriptBuilder sb = new()) + { + for (int x = 0; x < M; x++) + { + sb.EmitPush(new byte[64]); + } + _witnessSize = new Witness + { + InvocationScript = sb.ToArray(), + VerificationScript = Contract.CreateMultiSigRedeemScript(M, Validators) + }.Size; + } + } + MyIndex = -1; + ChangeViewPayloads = new ExtensiblePayload[Validators.Length]; + LastChangeViewPayloads = new ExtensiblePayload[Validators.Length]; + CommitPayloads = new ExtensiblePayload[Validators.Length]; + if (ValidatorsChanged || LastSeenMessage is null) + { + var previous_last_seen_message = LastSeenMessage; + LastSeenMessage = new Dictionary(); + foreach (var validator in Validators) + { + if (previous_last_seen_message != null && previous_last_seen_message.TryGetValue(validator, out var value)) + LastSeenMessage[validator] = value; + else + LastSeenMessage[validator] = height; + } + } + keyPair = null; + for (int i = 0; i < Validators.Length; i++) + { + WalletAccount account = wallet?.GetAccount(Validators[i]); + if (account?.HasKey != true) continue; + MyIndex = i; + keyPair = account.GetKey(); + break; + } + cachedMessages = new Dictionary(); + } + else + { + for (int i = 0; i < LastChangeViewPayloads.Length; i++) + if (GetMessage(ChangeViewPayloads[i])?.NewViewNumber >= viewNumber) + LastChangeViewPayloads[i] = ChangeViewPayloads[i]; + else + LastChangeViewPayloads[i] = null; + } + ViewNumber = viewNumber; + Block.Header.PrimaryIndex = GetPrimaryIndex(viewNumber); + Block.Header.MerkleRoot = null; + Block.Header.Timestamp = 0; + Block.Header.Nonce = 0; + Block.Transactions = null; + TransactionHashes = null; + PreparationPayloads = new ExtensiblePayload[Validators.Length]; + if (MyIndex >= 0) LastSeenMessage[Validators[MyIndex]] = Block.Index; + } + + public void Save() + { + store.PutSync(ConsensusStateKey, this.ToArray()); + } + + public void Deserialize(ref MemoryReader reader) + { + Reset(0); + if (reader.ReadUInt32() != Block.Version) throw new FormatException(); + if (reader.ReadUInt32() != Block.Index) throw new InvalidOperationException(); + Block.Header.Timestamp = reader.ReadUInt64(); + Block.Header.Nonce = reader.ReadUInt64(); + Block.Header.PrimaryIndex = reader.ReadByte(); + Block.Header.NextConsensus = reader.ReadSerializable(); + if (Block.NextConsensus.Equals(UInt160.Zero)) + Block.Header.NextConsensus = null; + ViewNumber = reader.ReadByte(); + TransactionHashes = reader.ReadSerializableArray(ushort.MaxValue); + Transaction[] transactions = reader.ReadSerializableArray(ushort.MaxValue); + PreparationPayloads = reader.ReadNullableArray(neoSystem.Settings.ValidatorsCount); + CommitPayloads = reader.ReadNullableArray(neoSystem.Settings.ValidatorsCount); + ChangeViewPayloads = reader.ReadNullableArray(neoSystem.Settings.ValidatorsCount); + LastChangeViewPayloads = reader.ReadNullableArray(neoSystem.Settings.ValidatorsCount); + if (TransactionHashes.Length == 0 && !RequestSentOrReceived) + TransactionHashes = null; + Transactions = transactions.Length == 0 && !RequestSentOrReceived ? null : transactions.ToDictionary(p => p.Hash); + VerificationContext = new TransactionVerificationContext(); + if (Transactions != null) + { + foreach (Transaction tx in Transactions.Values) + VerificationContext.AddTransaction(tx); + } + } + + public void Serialize(BinaryWriter writer) + { + writer.Write(Block.Version); + writer.Write(Block.Index); + writer.Write(Block.Timestamp); + writer.Write(Block.Nonce); + writer.Write(Block.PrimaryIndex); + writer.Write(Block.NextConsensus ?? UInt160.Zero); + writer.Write(ViewNumber); + writer.Write(TransactionHashes ?? Array.Empty()); + writer.Write(Transactions?.Values.ToArray() ?? Array.Empty()); + writer.WriteNullableArray(PreparationPayloads); + writer.WriteNullableArray(CommitPayloads); + writer.WriteNullableArray(ChangeViewPayloads); + writer.WriteNullableArray(LastChangeViewPayloads); + } + } +} diff --git a/src/Plugins/DBFTPlugin/Consensus/ConsensusService.Check.cs b/src/Plugins/DBFTPlugin/Consensus/ConsensusService.Check.cs new file mode 100644 index 0000000000..3b15bcd8fc --- /dev/null +++ b/src/Plugins/DBFTPlugin/Consensus/ConsensusService.Check.cs @@ -0,0 +1,102 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// ConsensusService.Check.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.IO; +using Neo.Network.P2P; +using Neo.Network.P2P.Payloads; +using System; +using System.Linq; + +namespace Neo.Consensus +{ + partial class ConsensusService + { + private bool CheckPrepareResponse() + { + if (context.TransactionHashes.Length == context.Transactions.Count) + { + // if we are the primary for this view, but acting as a backup because we recovered our own + // previously sent prepare request, then we don't want to send a prepare response. + if (context.IsPrimary || context.WatchOnly) return true; + + // Check maximum block size via Native Contract policy + if (context.GetExpectedBlockSize() > dbftSettings.MaxBlockSize) + { + Log($"Rejected block: {context.Block.Index} The size exceed the policy", LogLevel.Warning); + RequestChangeView(ChangeViewReason.BlockRejectedByPolicy); + return false; + } + // Check maximum block system fee via Native Contract policy + if (context.GetExpectedBlockSystemFee() > dbftSettings.MaxBlockSystemFee) + { + Log($"Rejected block: {context.Block.Index} The system fee exceed the policy", LogLevel.Warning); + RequestChangeView(ChangeViewReason.BlockRejectedByPolicy); + return false; + } + + // Timeout extension due to prepare response sent + // around 2*15/M=30.0/5 ~ 40% block time (for M=5) + ExtendTimerByFactor(2); + + Log($"Sending {nameof(PrepareResponse)}"); + localNode.Tell(new LocalNode.SendDirectly { Inventory = context.MakePrepareResponse() }); + CheckPreparations(); + } + return true; + } + + private void CheckCommits() + { + if (context.CommitPayloads.Count(p => context.GetMessage(p)?.ViewNumber == context.ViewNumber) >= context.M && context.TransactionHashes.All(p => context.Transactions.ContainsKey(p))) + { + block_received_index = context.Block.Index; + block_received_time = TimeProvider.Current.UtcNow; + Block block = context.CreateBlock(); + Log($"Sending {nameof(Block)}: height={block.Index} hash={block.Hash} tx={block.Transactions.Length}"); + blockchain.Tell(block); + } + } + + private void CheckExpectedView(byte viewNumber) + { + if (context.ViewNumber >= viewNumber) return; + var messages = context.ChangeViewPayloads.Select(p => context.GetMessage(p)).ToArray(); + // if there are `M` change view payloads with NewViewNumber greater than viewNumber, then, it is safe to move + if (messages.Count(p => p != null && p.NewViewNumber >= viewNumber) >= context.M) + { + if (!context.WatchOnly) + { + ChangeView message = messages[context.MyIndex]; + // Communicate the network about my agreement to move to `viewNumber` + // if my last change view payload, `message`, has NewViewNumber lower than current view to change + if (message is null || message.NewViewNumber < viewNumber) + localNode.Tell(new LocalNode.SendDirectly { Inventory = context.MakeChangeView(ChangeViewReason.ChangeAgreement) }); + } + InitializeConsensus(viewNumber); + } + } + + private void CheckPreparations() + { + if (context.PreparationPayloads.Count(p => p != null) >= context.M && context.TransactionHashes.All(p => context.Transactions.ContainsKey(p))) + { + ExtensiblePayload payload = context.MakeCommit(); + Log($"Sending {nameof(Commit)}"); + context.Save(); + localNode.Tell(new LocalNode.SendDirectly { Inventory = payload }); + // Set timer, so we will resend the commit in case of a networking issue + ChangeTimer(TimeSpan.FromMilliseconds(neoSystem.Settings.MillisecondsPerBlock)); + CheckCommits(); + } + } + } +} diff --git a/src/Plugins/DBFTPlugin/Consensus/ConsensusService.OnMessage.cs b/src/Plugins/DBFTPlugin/Consensus/ConsensusService.OnMessage.cs new file mode 100644 index 0000000000..ecc31f7ba3 --- /dev/null +++ b/src/Plugins/DBFTPlugin/Consensus/ConsensusService.OnMessage.cs @@ -0,0 +1,317 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// ConsensusService.OnMessage.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.Cryptography; +using Neo.IO; +using Neo.Ledger; +using Neo.Network.P2P; +using Neo.Network.P2P.Payloads; +using Neo.SmartContract; +using Neo.SmartContract.Native; +using Neo.Wallets; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Neo.Consensus +{ + partial class ConsensusService + { + private void OnConsensusPayload(ExtensiblePayload payload) + { + if (context.BlockSent) return; + ConsensusMessage message; + try + { + message = context.GetMessage(payload); + } + catch (Exception ex) + { + Utility.Log(nameof(ConsensusService), LogLevel.Debug, ex.ToString()); + return; + } + + if (!message.Verify(neoSystem.Settings)) return; + if (message.BlockIndex != context.Block.Index) + { + if (context.Block.Index < message.BlockIndex) + { + Log($"Chain is behind: expected={message.BlockIndex} current={context.Block.Index - 1}", LogLevel.Warning); + } + return; + } + if (message.ValidatorIndex >= context.Validators.Length) return; + if (payload.Sender != Contract.CreateSignatureRedeemScript(context.Validators[message.ValidatorIndex]).ToScriptHash()) return; + context.LastSeenMessage[context.Validators[message.ValidatorIndex]] = message.BlockIndex; + switch (message) + { + case PrepareRequest request: + OnPrepareRequestReceived(payload, request); + break; + case PrepareResponse response: + OnPrepareResponseReceived(payload, response); + break; + case ChangeView view: + OnChangeViewReceived(payload, view); + break; + case Commit commit: + OnCommitReceived(payload, commit); + break; + case RecoveryRequest request: + OnRecoveryRequestReceived(payload, request); + break; + case RecoveryMessage recovery: + OnRecoveryMessageReceived(recovery); + break; + } + } + + private void OnPrepareRequestReceived(ExtensiblePayload payload, PrepareRequest message) + { + if (context.RequestSentOrReceived || context.NotAcceptingPayloadsDueToViewChanging) return; + if (message.ValidatorIndex != context.Block.PrimaryIndex || message.ViewNumber != context.ViewNumber) return; + if (message.Version != context.Block.Version || message.PrevHash != context.Block.PrevHash) return; + if (message.TransactionHashes.Length > neoSystem.Settings.MaxTransactionsPerBlock) return; + Log($"{nameof(OnPrepareRequestReceived)}: height={message.BlockIndex} view={message.ViewNumber} index={message.ValidatorIndex} tx={message.TransactionHashes.Length}"); + if (message.Timestamp <= context.PrevHeader.Timestamp || message.Timestamp > TimeProvider.Current.UtcNow.AddMilliseconds(8 * neoSystem.Settings.MillisecondsPerBlock).ToTimestampMS()) + { + Log($"Timestamp incorrect: {message.Timestamp}", LogLevel.Warning); + return; + } + + if (message.TransactionHashes.Any(p => NativeContract.Ledger.ContainsTransaction(context.Snapshot, p))) + { + Log($"Invalid request: transaction already exists", LogLevel.Warning); + return; + } + + // Timeout extension: prepare request has been received with success + // around 2*15/M=30.0/5 ~ 40% block time (for M=5) + ExtendTimerByFactor(2); + + context.Block.Header.Timestamp = message.Timestamp; + context.Block.Header.Nonce = message.Nonce; + context.TransactionHashes = message.TransactionHashes; + + context.Transactions = new Dictionary(); + context.VerificationContext = new TransactionVerificationContext(); + for (int i = 0; i < context.PreparationPayloads.Length; i++) + if (context.PreparationPayloads[i] != null) + if (!context.GetMessage(context.PreparationPayloads[i]).PreparationHash.Equals(payload.Hash)) + context.PreparationPayloads[i] = null; + context.PreparationPayloads[message.ValidatorIndex] = payload; + byte[] hashData = context.EnsureHeader().GetSignData(neoSystem.Settings.Network); + for (int i = 0; i < context.CommitPayloads.Length; i++) + if (context.GetMessage(context.CommitPayloads[i])?.ViewNumber == context.ViewNumber) + if (!Crypto.VerifySignature(hashData, context.GetMessage(context.CommitPayloads[i]).Signature.Span, context.Validators[i])) + context.CommitPayloads[i] = null; + + if (context.TransactionHashes.Length == 0) + { + // There are no tx so we should act like if all the transactions were filled + CheckPrepareResponse(); + return; + } + + Dictionary mempoolVerified = neoSystem.MemPool.GetVerifiedTransactions().ToDictionary(p => p.Hash); + List unverified = new List(); + foreach (UInt256 hash in context.TransactionHashes) + { + if (mempoolVerified.TryGetValue(hash, out Transaction tx)) + { + if (NativeContract.Ledger.ContainsConflictHash(context.Snapshot, hash, tx.Signers.Select(s => s.Account), neoSystem.Settings.MaxTraceableBlocks)) + { + Log($"Invalid request: transaction has on-chain conflict", LogLevel.Warning); + return; + } + + if (!AddTransaction(tx, false)) + return; + } + else + { + if (neoSystem.MemPool.TryGetValue(hash, out tx)) + { + if (NativeContract.Ledger.ContainsConflictHash(context.Snapshot, hash, tx.Signers.Select(s => s.Account), neoSystem.Settings.MaxTraceableBlocks)) + { + Log($"Invalid request: transaction has on-chain conflict", LogLevel.Warning); + return; + } + unverified.Add(tx); + } + } + } + foreach (Transaction tx in unverified) + if (!AddTransaction(tx, true)) + return; + if (context.Transactions.Count < context.TransactionHashes.Length) + { + UInt256[] hashes = context.TransactionHashes.Where(i => !context.Transactions.ContainsKey(i)).ToArray(); + taskManager.Tell(new TaskManager.RestartTasks + { + Payload = InvPayload.Create(InventoryType.TX, hashes) + }); + } + } + + private void OnPrepareResponseReceived(ExtensiblePayload payload, PrepareResponse message) + { + if (message.ViewNumber != context.ViewNumber) return; + if (context.PreparationPayloads[message.ValidatorIndex] != null || context.NotAcceptingPayloadsDueToViewChanging) return; + if (context.PreparationPayloads[context.Block.PrimaryIndex] != null && !message.PreparationHash.Equals(context.PreparationPayloads[context.Block.PrimaryIndex].Hash)) + return; + + // Timeout extension: prepare response has been received with success + // around 2*15/M=30.0/5 ~ 40% block time (for M=5) + ExtendTimerByFactor(2); + + Log($"{nameof(OnPrepareResponseReceived)}: height={message.BlockIndex} view={message.ViewNumber} index={message.ValidatorIndex}"); + context.PreparationPayloads[message.ValidatorIndex] = payload; + if (context.WatchOnly || context.CommitSent) return; + if (context.RequestSentOrReceived) + CheckPreparations(); + } + + private void OnChangeViewReceived(ExtensiblePayload payload, ChangeView message) + { + if (message.NewViewNumber <= context.ViewNumber) + OnRecoveryRequestReceived(payload, message); + + if (context.CommitSent) return; + + var expectedView = context.GetMessage(context.ChangeViewPayloads[message.ValidatorIndex])?.NewViewNumber ?? 0; + if (message.NewViewNumber <= expectedView) + return; + + Log($"{nameof(OnChangeViewReceived)}: height={message.BlockIndex} view={message.ViewNumber} index={message.ValidatorIndex} nv={message.NewViewNumber} reason={message.Reason}"); + context.ChangeViewPayloads[message.ValidatorIndex] = payload; + CheckExpectedView(message.NewViewNumber); + } + + private void OnCommitReceived(ExtensiblePayload payload, Commit commit) + { + ref ExtensiblePayload existingCommitPayload = ref context.CommitPayloads[commit.ValidatorIndex]; + if (existingCommitPayload != null) + { + if (existingCommitPayload.Hash != payload.Hash) + Log($"Rejected {nameof(Commit)}: height={commit.BlockIndex} index={commit.ValidatorIndex} view={commit.ViewNumber} existingView={context.GetMessage(existingCommitPayload).ViewNumber}", LogLevel.Warning); + return; + } + + if (commit.ViewNumber == context.ViewNumber) + { + // Timeout extension: commit has been received with success + // around 4*15s/M=60.0s/5=12.0s ~ 80% block time (for M=5) + ExtendTimerByFactor(4); + + Log($"{nameof(OnCommitReceived)}: height={commit.BlockIndex} view={commit.ViewNumber} index={commit.ValidatorIndex} nc={context.CountCommitted} nf={context.CountFailed}"); + + byte[] hashData = context.EnsureHeader()?.GetSignData(neoSystem.Settings.Network); + if (hashData == null) + { + existingCommitPayload = payload; + } + else if (Crypto.VerifySignature(hashData, commit.Signature.Span, context.Validators[commit.ValidatorIndex])) + { + existingCommitPayload = payload; + CheckCommits(); + } + return; + } + else + { + // Receiving commit from another view + existingCommitPayload = payload; + } + } + + private void OnRecoveryMessageReceived(RecoveryMessage message) + { + // isRecovering is always set to false again after OnRecoveryMessageReceived + isRecovering = true; + int validChangeViews = 0, totalChangeViews = 0, validPrepReq = 0, totalPrepReq = 0; + int validPrepResponses = 0, totalPrepResponses = 0, validCommits = 0, totalCommits = 0; + + Log($"{nameof(OnRecoveryMessageReceived)}: height={message.BlockIndex} view={message.ViewNumber} index={message.ValidatorIndex}"); + try + { + if (message.ViewNumber > context.ViewNumber) + { + if (context.CommitSent) return; + ExtensiblePayload[] changeViewPayloads = message.GetChangeViewPayloads(context); + totalChangeViews = changeViewPayloads.Length; + foreach (ExtensiblePayload changeViewPayload in changeViewPayloads) + if (ReverifyAndProcessPayload(changeViewPayload)) validChangeViews++; + } + if (message.ViewNumber == context.ViewNumber && !context.NotAcceptingPayloadsDueToViewChanging && !context.CommitSent) + { + if (!context.RequestSentOrReceived) + { + ExtensiblePayload prepareRequestPayload = message.GetPrepareRequestPayload(context); + if (prepareRequestPayload != null) + { + totalPrepReq = 1; + if (ReverifyAndProcessPayload(prepareRequestPayload)) validPrepReq++; + } + } + ExtensiblePayload[] prepareResponsePayloads = message.GetPrepareResponsePayloads(context); + totalPrepResponses = prepareResponsePayloads.Length; + foreach (ExtensiblePayload prepareResponsePayload in prepareResponsePayloads) + if (ReverifyAndProcessPayload(prepareResponsePayload)) validPrepResponses++; + } + if (message.ViewNumber <= context.ViewNumber) + { + // Ensure we know about all commits from lower view numbers. + ExtensiblePayload[] commitPayloads = message.GetCommitPayloadsFromRecoveryMessage(context); + totalCommits = commitPayloads.Length; + foreach (ExtensiblePayload commitPayload in commitPayloads) + if (ReverifyAndProcessPayload(commitPayload)) validCommits++; + } + } + finally + { + Log($"Recovery finished: (valid/total) ChgView: {validChangeViews}/{totalChangeViews} PrepReq: {validPrepReq}/{totalPrepReq} PrepResp: {validPrepResponses}/{totalPrepResponses} Commits: {validCommits}/{totalCommits}"); + isRecovering = false; + } + } + + private void OnRecoveryRequestReceived(ExtensiblePayload payload, ConsensusMessage message) + { + // We keep track of the payload hashes received in this block, and don't respond with recovery + // in response to the same payload that we already responded to previously. + // ChangeView messages include a Timestamp when the change view is sent, thus if a node restarts + // and issues a change view for the same view, it will have a different hash and will correctly respond + // again; however replay attacks of the ChangeView message from arbitrary nodes will not trigger an + // additional recovery message response. + if (!knownHashes.Add(payload.Hash)) return; + + Log($"{nameof(OnRecoveryRequestReceived)}: height={message.BlockIndex} index={message.ValidatorIndex} view={message.ViewNumber}"); + if (context.WatchOnly) return; + if (!context.CommitSent) + { + bool shouldSendRecovery = false; + int allowedRecoveryNodeCount = context.F + 1; + // Limit recoveries to be sent from an upper limit of `f + 1` nodes + for (int i = 1; i <= allowedRecoveryNodeCount; i++) + { + var chosenIndex = (message.ValidatorIndex + i) % context.Validators.Length; + if (chosenIndex != context.MyIndex) continue; + shouldSendRecovery = true; + break; + } + + if (!shouldSendRecovery) return; + } + localNode.Tell(new LocalNode.SendDirectly { Inventory = context.MakeRecoveryMessage() }); + } + } +} diff --git a/src/Plugins/DBFTPlugin/Consensus/ConsensusService.cs b/src/Plugins/DBFTPlugin/Consensus/ConsensusService.cs new file mode 100644 index 0000000000..8a6d75e8b9 --- /dev/null +++ b/src/Plugins/DBFTPlugin/Consensus/ConsensusService.cs @@ -0,0 +1,344 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// ConsensusService.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.IO; +using Neo.Ledger; +using Neo.Network.P2P; +using Neo.Network.P2P.Payloads; +using Neo.Wallets; +using System; +using System.Collections.Generic; +using System.Linq; +using static Neo.Ledger.Blockchain; + +namespace Neo.Consensus +{ + partial class ConsensusService : UntypedActor + { + public class Start { } + private class Timer { public uint Height; public byte ViewNumber; } + + private readonly ConsensusContext context; + private readonly IActorRef localNode; + private readonly IActorRef taskManager; + private readonly IActorRef blockchain; + private ICancelable timer_token; + private DateTime block_received_time; + private uint block_received_index; + private bool started = false; + + /// + /// This will record the information from last scheduled timer + /// + private DateTime clock_started = TimeProvider.Current.UtcNow; + private TimeSpan expected_delay = TimeSpan.Zero; + + /// + /// This will be cleared every block (so it will not grow out of control, but is used to prevent repeatedly + /// responding to the same message. + /// + private readonly HashSet knownHashes = new(); + /// + /// This variable is only true during OnRecoveryMessageReceived + /// + private bool isRecovering = false; + private readonly Settings dbftSettings; + private readonly NeoSystem neoSystem; + + public ConsensusService(NeoSystem neoSystem, Settings settings, Wallet wallet) + : this(neoSystem, settings, new ConsensusContext(neoSystem, settings, wallet)) { } + + internal ConsensusService(NeoSystem neoSystem, Settings settings, ConsensusContext context) + { + this.neoSystem = neoSystem; + localNode = neoSystem.LocalNode; + taskManager = neoSystem.TaskManager; + blockchain = neoSystem.Blockchain; + dbftSettings = settings; + this.context = context; + Context.System.EventStream.Subscribe(Self, typeof(Blockchain.PersistCompleted)); + Context.System.EventStream.Subscribe(Self, typeof(Blockchain.RelayResult)); + } + + private void OnPersistCompleted(Block block) + { + Log($"Persisted {nameof(Block)}: height={block.Index} hash={block.Hash} tx={block.Transactions.Length} nonce={block.Nonce}"); + knownHashes.Clear(); + InitializeConsensus(0); + } + + private void InitializeConsensus(byte viewNumber) + { + context.Reset(viewNumber); + if (viewNumber > 0) + Log($"View changed: view={viewNumber} primary={context.Validators[context.GetPrimaryIndex((byte)(viewNumber - 1u))]}", LogLevel.Warning); + Log($"Initialize: height={context.Block.Index} view={viewNumber} index={context.MyIndex} role={(context.IsPrimary ? "Primary" : context.WatchOnly ? "WatchOnly" : "Backup")}"); + if (context.WatchOnly) return; + if (context.IsPrimary) + { + if (isRecovering) + { + ChangeTimer(TimeSpan.FromMilliseconds(neoSystem.Settings.MillisecondsPerBlock << (viewNumber + 1))); + } + else + { + TimeSpan span = neoSystem.Settings.TimePerBlock; + if (block_received_index + 1 == context.Block.Index) + { + var diff = TimeProvider.Current.UtcNow - block_received_time; + if (diff >= span) + span = TimeSpan.Zero; + else + span -= diff; + } + ChangeTimer(span); + } + } + else + { + ChangeTimer(TimeSpan.FromMilliseconds(neoSystem.Settings.MillisecondsPerBlock << (viewNumber + 1))); + } + } + + protected override void OnReceive(object message) + { + if (message is Start) + { + if (started) return; + OnStart(); + } + else + { + if (!started) return; + switch (message) + { + case Timer timer: + OnTimer(timer); + break; + case Transaction transaction: + OnTransaction(transaction); + break; + case Blockchain.PersistCompleted completed: + OnPersistCompleted(completed.Block); + break; + case Blockchain.RelayResult rr: + if (rr.Result == VerifyResult.Succeed && rr.Inventory is ExtensiblePayload payload && payload.Category == "dBFT") + OnConsensusPayload(payload); + break; + } + } + } + + private void OnStart() + { + Log("OnStart"); + started = true; + if (!dbftSettings.IgnoreRecoveryLogs && context.Load()) + { + if (context.Transactions != null) + { + blockchain.Ask(new Blockchain.FillMemoryPool + { + Transactions = context.Transactions.Values + }).Wait(); + } + if (context.CommitSent) + { + CheckPreparations(); + return; + } + } + InitializeConsensus(context.ViewNumber); + // Issue a recovery request on start-up in order to possibly catch up with other nodes + if (!context.WatchOnly) + RequestRecovery(); + } + + private void OnTimer(Timer timer) + { + if (context.WatchOnly || context.BlockSent) return; + if (timer.Height != context.Block.Index || timer.ViewNumber != context.ViewNumber) return; + if (context.IsPrimary && !context.RequestSentOrReceived) + { + SendPrepareRequest(); + } + else if ((context.IsPrimary && context.RequestSentOrReceived) || context.IsBackup) + { + if (context.CommitSent) + { + // Re-send commit periodically by sending recover message in case of a network issue. + Log($"Sending {nameof(RecoveryMessage)} to resend {nameof(Commit)}"); + localNode.Tell(new LocalNode.SendDirectly { Inventory = context.MakeRecoveryMessage() }); + ChangeTimer(TimeSpan.FromMilliseconds(neoSystem.Settings.MillisecondsPerBlock << 1)); + } + else + { + var reason = ChangeViewReason.Timeout; + + if (context.Block != null && context.TransactionHashes?.Length > context.Transactions?.Count) + { + reason = ChangeViewReason.TxNotFound; + } + + RequestChangeView(reason); + } + } + } + + private void SendPrepareRequest() + { + Log($"Sending {nameof(PrepareRequest)}: height={context.Block.Index} view={context.ViewNumber}"); + localNode.Tell(new LocalNode.SendDirectly { Inventory = context.MakePrepareRequest() }); + + if (context.Validators.Length == 1) + CheckPreparations(); + + if (context.TransactionHashes.Length > 0) + { + foreach (InvPayload payload in InvPayload.CreateGroup(InventoryType.TX, context.TransactionHashes)) + localNode.Tell(Message.Create(MessageCommand.Inv, payload)); + } + ChangeTimer(TimeSpan.FromMilliseconds((neoSystem.Settings.MillisecondsPerBlock << (context.ViewNumber + 1)) - (context.ViewNumber == 0 ? neoSystem.Settings.MillisecondsPerBlock : 0))); + } + + private void RequestRecovery() + { + Log($"Sending {nameof(RecoveryRequest)}: height={context.Block.Index} view={context.ViewNumber} nc={context.CountCommitted} nf={context.CountFailed}"); + localNode.Tell(new LocalNode.SendDirectly { Inventory = context.MakeRecoveryRequest() }); + } + + private void RequestChangeView(ChangeViewReason reason) + { + if (context.WatchOnly) return; + // Request for next view is always one view more than the current context.ViewNumber + // Nodes will not contribute for changing to a view higher than (context.ViewNumber+1), unless they are recovered + // The latter may happen by nodes in higher views with, at least, `M` proofs + byte expectedView = context.ViewNumber; + expectedView++; + ChangeTimer(TimeSpan.FromMilliseconds(neoSystem.Settings.MillisecondsPerBlock << (expectedView + 1))); + if ((context.CountCommitted + context.CountFailed) > context.F) + { + RequestRecovery(); + } + else + { + Log($"Sending {nameof(ChangeView)}: height={context.Block.Index} view={context.ViewNumber} nv={expectedView} nc={context.CountCommitted} nf={context.CountFailed} reason={reason}"); + localNode.Tell(new LocalNode.SendDirectly { Inventory = context.MakeChangeView(reason) }); + CheckExpectedView(expectedView); + } + } + + private bool ReverifyAndProcessPayload(ExtensiblePayload payload) + { + RelayResult relayResult = blockchain.Ask(new Blockchain.Reverify { Inventories = new IInventory[] { payload } }).Result; + if (relayResult.Result != VerifyResult.Succeed) return false; + OnConsensusPayload(payload); + return true; + } + + private void OnTransaction(Transaction transaction) + { + if (!context.IsBackup || context.NotAcceptingPayloadsDueToViewChanging || !context.RequestSentOrReceived || context.ResponseSent || context.BlockSent) + return; + if (context.Transactions.ContainsKey(transaction.Hash)) return; + if (!context.TransactionHashes.Contains(transaction.Hash)) return; + AddTransaction(transaction, true); + } + + private bool AddTransaction(Transaction tx, bool verify) + { + if (verify) + { + // At this step we're sure that there's no on-chain transaction that conflicts with + // the provided tx because of the previous Blockchain's OnReceive check. Thus, we only + // need to check that current context doesn't contain conflicting transactions. + VerifyResult result; + + // Firstly, check whether tx has Conlicts attribute with the hash of one of the context's transactions. + foreach (var h in tx.GetAttributes().Select(attr => attr.Hash)) + { + if (context.TransactionHashes.Contains(h)) + { + result = VerifyResult.HasConflicts; + Log($"Rejected tx: {tx.Hash}, {result}{Environment.NewLine}{tx.ToArray().ToHexString()}", LogLevel.Warning); + RequestChangeView(ChangeViewReason.TxInvalid); + return false; + } + } + // After that, check whether context's transactions have Conflicts attribute with tx's hash. + foreach (var pooledTx in context.Transactions.Values) + { + if (pooledTx.GetAttributes().Select(attr => attr.Hash).Contains(tx.Hash)) + { + result = VerifyResult.HasConflicts; + Log($"Rejected tx: {tx.Hash}, {result}{Environment.NewLine}{tx.ToArray().ToHexString()}", LogLevel.Warning); + RequestChangeView(ChangeViewReason.TxInvalid); + return false; + } + } + + // We've ensured that there's no conlicting transactions in the context, thus, can safely provide an empty conflicting list + // for futher verification. + var conflictingTxs = new List(); + result = tx.Verify(neoSystem.Settings, context.Snapshot, context.VerificationContext, conflictingTxs); + if (result != VerifyResult.Succeed) + { + Log($"Rejected tx: {tx.Hash}, {result}{Environment.NewLine}{tx.ToArray().ToHexString()}", LogLevel.Warning); + RequestChangeView(result == VerifyResult.PolicyFail ? ChangeViewReason.TxRejectedByPolicy : ChangeViewReason.TxInvalid); + return false; + } + } + context.Transactions[tx.Hash] = tx; + context.VerificationContext.AddTransaction(tx); + return CheckPrepareResponse(); + } + + private void ChangeTimer(TimeSpan delay) + { + clock_started = TimeProvider.Current.UtcNow; + expected_delay = delay; + timer_token.CancelIfNotNull(); + timer_token = Context.System.Scheduler.ScheduleTellOnceCancelable(delay, Self, new Timer + { + Height = context.Block.Index, + ViewNumber = context.ViewNumber + }, ActorRefs.NoSender); + } + + // this function increases existing timer (never decreases) with a value proportional to `maxDelayInBlockTimes`*`Blockchain.MillisecondsPerBlock` + private void ExtendTimerByFactor(int maxDelayInBlockTimes) + { + TimeSpan nextDelay = expected_delay - (TimeProvider.Current.UtcNow - clock_started) + TimeSpan.FromMilliseconds(maxDelayInBlockTimes * neoSystem.Settings.MillisecondsPerBlock / (double)context.M); + if (!context.WatchOnly && !context.ViewChanging && !context.CommitSent && (nextDelay > TimeSpan.Zero)) + ChangeTimer(nextDelay); + } + + protected override void PostStop() + { + Log("OnStop"); + started = false; + Context.System.EventStream.Unsubscribe(Self); + context.Dispose(); + base.PostStop(); + } + + public static Props Props(NeoSystem neoSystem, Settings dbftSettings, Wallet wallet) + { + return Akka.Actor.Props.Create(() => new ConsensusService(neoSystem, dbftSettings, wallet)); + } + + private static void Log(string message, LogLevel level = LogLevel.Info) + { + Utility.Log(nameof(ConsensusService), level, message); + } + } +} diff --git a/src/Plugins/DBFTPlugin/DBFTPlugin.cs b/src/Plugins/DBFTPlugin/DBFTPlugin.cs new file mode 100644 index 0000000000..7fa29ce0dd --- /dev/null +++ b/src/Plugins/DBFTPlugin/DBFTPlugin.cs @@ -0,0 +1,101 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// DBFTPlugin.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.ConsoleService; +using Neo.Network.P2P; +using Neo.Network.P2P.Payloads; +using Neo.Plugins; +using Neo.Wallets; + +namespace Neo.Consensus +{ + public class DBFTPlugin : Plugin + { + private IWalletProvider walletProvider; + private IActorRef consensus; + private bool started = false; + private NeoSystem neoSystem; + private Settings settings; + + public override string Description => "Consensus plugin with dBFT algorithm."; + + public DBFTPlugin() + { + RemoteNode.MessageReceived += RemoteNode_MessageReceived; + } + + public DBFTPlugin(Settings settings) : this() + { + this.settings = settings; + } + + public override void Dispose() + { + RemoteNode.MessageReceived -= RemoteNode_MessageReceived; + } + + protected override void Configure() + { + settings ??= new Settings(GetConfiguration()); + } + + protected override void OnSystemLoaded(NeoSystem system) + { + if (system.Settings.Network != settings.Network) return; + neoSystem = system; + neoSystem.ServiceAdded += NeoSystem_ServiceAdded; + } + + private void NeoSystem_ServiceAdded(object sender, object service) + { + if (service is not IWalletProvider provider) return; + walletProvider = provider; + neoSystem.ServiceAdded -= NeoSystem_ServiceAdded; + if (settings.AutoStart) + { + walletProvider.WalletChanged += WalletProvider_WalletChanged; + } + } + + private void WalletProvider_WalletChanged(object sender, Wallet wallet) + { + walletProvider.WalletChanged -= WalletProvider_WalletChanged; + Start(wallet); + } + + [ConsoleCommand("start consensus", Category = "Consensus", Description = "Start consensus service (dBFT)")] + private void OnStart() + { + Start(walletProvider.GetWallet()); + } + + public void Start(Wallet wallet) + { + if (started) return; + started = true; + consensus = neoSystem.ActorSystem.ActorOf(ConsensusService.Props(neoSystem, settings, wallet)); + consensus.Tell(new ConsensusService.Start()); + } + + private bool RemoteNode_MessageReceived(NeoSystem system, Message message) + { + if (message.Command == MessageCommand.Transaction) + { + Transaction tx = (Transaction)message.Payload; + if (tx.SystemFee > settings.MaxBlockSystemFee) + return false; + consensus?.Tell(tx); + } + return true; + } + } +} diff --git a/src/Plugins/DBFTPlugin/DBFTPlugin.csproj b/src/Plugins/DBFTPlugin/DBFTPlugin.csproj new file mode 100644 index 0000000000..fe681cf2ed --- /dev/null +++ b/src/Plugins/DBFTPlugin/DBFTPlugin.csproj @@ -0,0 +1,13 @@ + + + + net8.0 + Neo.Consensus.DBFT + Neo.Consensus + + + + + + + diff --git a/src/Plugins/DBFTPlugin/Messages/ChangeView.cs b/src/Plugins/DBFTPlugin/Messages/ChangeView.cs new file mode 100644 index 0000000000..e7be40075f --- /dev/null +++ b/src/Plugins/DBFTPlugin/Messages/ChangeView.cs @@ -0,0 +1,56 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// ChangeView.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.IO; +using System.IO; + +namespace Neo.Consensus +{ + public class ChangeView : ConsensusMessage + { + /// + /// NewViewNumber is always set to the current ViewNumber asking changeview + 1 + /// + public byte NewViewNumber => (byte)(ViewNumber + 1); + + /// + /// Timestamp of when the ChangeView message was created. This allows receiving nodes to ensure + /// they only respond once to a specific ChangeView request (it thus prevents replay of the ChangeView + /// message from repeatedly broadcasting RecoveryMessages). + /// + public ulong Timestamp; + + /// + /// Reason + /// + public ChangeViewReason Reason; + + public override int Size => base.Size + + sizeof(ulong) + // Timestamp + sizeof(ChangeViewReason); // Reason + + public ChangeView() : base(ConsensusMessageType.ChangeView) { } + + public override void Deserialize(ref MemoryReader reader) + { + base.Deserialize(ref reader); + Timestamp = reader.ReadUInt64(); + Reason = (ChangeViewReason)reader.ReadByte(); + } + + public override void Serialize(BinaryWriter writer) + { + base.Serialize(writer); + writer.Write(Timestamp); + writer.Write((byte)Reason); + } + } +} diff --git a/src/Plugins/DBFTPlugin/Messages/Commit.cs b/src/Plugins/DBFTPlugin/Messages/Commit.cs new file mode 100644 index 0000000000..6e8fe93d87 --- /dev/null +++ b/src/Plugins/DBFTPlugin/Messages/Commit.cs @@ -0,0 +1,38 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Commit.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.IO; +using System; +using System.IO; + +namespace Neo.Consensus +{ + public class Commit : ConsensusMessage + { + public ReadOnlyMemory Signature; + + public override int Size => base.Size + Signature.Length; + + public Commit() : base(ConsensusMessageType.Commit) { } + + public override void Deserialize(ref MemoryReader reader) + { + base.Deserialize(ref reader); + Signature = reader.ReadMemory(64); + } + + public override void Serialize(BinaryWriter writer) + { + base.Serialize(writer); + writer.Write(Signature.Span); + } + } +} diff --git a/src/Plugins/DBFTPlugin/Messages/ConsensusMessage.cs b/src/Plugins/DBFTPlugin/Messages/ConsensusMessage.cs new file mode 100644 index 0000000000..4e136a99e5 --- /dev/null +++ b/src/Plugins/DBFTPlugin/Messages/ConsensusMessage.cs @@ -0,0 +1,69 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// ConsensusMessage.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.IO; +using System; +using System.IO; + +namespace Neo.Consensus +{ + public abstract class ConsensusMessage : ISerializable + { + public readonly ConsensusMessageType Type; + public uint BlockIndex; + public byte ValidatorIndex; + public byte ViewNumber; + + public virtual int Size => + sizeof(ConsensusMessageType) + //Type + sizeof(uint) + //BlockIndex + sizeof(byte) + //ValidatorIndex + sizeof(byte); //ViewNumber + + protected ConsensusMessage(ConsensusMessageType type) + { + if (!Enum.IsDefined(typeof(ConsensusMessageType), type)) + throw new ArgumentOutOfRangeException(nameof(type)); + Type = type; + } + + public virtual void Deserialize(ref MemoryReader reader) + { + if (Type != (ConsensusMessageType)reader.ReadByte()) + throw new FormatException(); + BlockIndex = reader.ReadUInt32(); + ValidatorIndex = reader.ReadByte(); + ViewNumber = reader.ReadByte(); + } + + public static ConsensusMessage DeserializeFrom(ReadOnlyMemory data) + { + ConsensusMessageType type = (ConsensusMessageType)data.Span[0]; + Type t = typeof(ConsensusMessage); + t = t.Assembly.GetType($"{t.Namespace}.{type}", false); + if (t is null) throw new FormatException(); + return (ConsensusMessage)data.AsSerializable(t); + } + + public virtual bool Verify(ProtocolSettings protocolSettings) + { + return ValidatorIndex < protocolSettings.ValidatorsCount; + } + + public virtual void Serialize(BinaryWriter writer) + { + writer.Write((byte)Type); + writer.Write(BlockIndex); + writer.Write(ValidatorIndex); + writer.Write(ViewNumber); + } + } +} diff --git a/src/Plugins/DBFTPlugin/Messages/PrepareRequest.cs b/src/Plugins/DBFTPlugin/Messages/PrepareRequest.cs new file mode 100644 index 0000000000..2bce609f79 --- /dev/null +++ b/src/Plugins/DBFTPlugin/Messages/PrepareRequest.cs @@ -0,0 +1,64 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// PrepareRequest.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.IO; +using System; +using System.IO; +using System.Linq; + +namespace Neo.Consensus +{ + public class PrepareRequest : ConsensusMessage + { + public uint Version; + public UInt256 PrevHash; + public ulong Timestamp; + public ulong Nonce; + public UInt256[] TransactionHashes; + + public override int Size => base.Size + + sizeof(uint) //Version + + UInt256.Length //PrevHash + + sizeof(ulong) //Timestamp + + sizeof(ulong) // Nonce + + TransactionHashes.GetVarSize(); //TransactionHashes + + public PrepareRequest() : base(ConsensusMessageType.PrepareRequest) { } + + public override void Deserialize(ref MemoryReader reader) + { + base.Deserialize(ref reader); + Version = reader.ReadUInt32(); + PrevHash = reader.ReadSerializable(); + Timestamp = reader.ReadUInt64(); + Nonce = reader.ReadUInt64(); + TransactionHashes = reader.ReadSerializableArray(ushort.MaxValue); + if (TransactionHashes.Distinct().Count() != TransactionHashes.Length) + throw new FormatException(); + } + + public override bool Verify(ProtocolSettings protocolSettings) + { + if (!base.Verify(protocolSettings)) return false; + return TransactionHashes.Length <= protocolSettings.MaxTransactionsPerBlock; + } + + public override void Serialize(BinaryWriter writer) + { + base.Serialize(writer); + writer.Write(Version); + writer.Write(PrevHash); + writer.Write(Timestamp); + writer.Write(Nonce); + writer.Write(TransactionHashes); + } + } +} diff --git a/src/Plugins/DBFTPlugin/Messages/PrepareResponse.cs b/src/Plugins/DBFTPlugin/Messages/PrepareResponse.cs new file mode 100644 index 0000000000..7510ff99bb --- /dev/null +++ b/src/Plugins/DBFTPlugin/Messages/PrepareResponse.cs @@ -0,0 +1,37 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// PrepareResponse.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.IO; +using System.IO; + +namespace Neo.Consensus +{ + public class PrepareResponse : ConsensusMessage + { + public UInt256 PreparationHash; + + public override int Size => base.Size + PreparationHash.Size; + + public PrepareResponse() : base(ConsensusMessageType.PrepareResponse) { } + + public override void Deserialize(ref MemoryReader reader) + { + base.Deserialize(ref reader); + PreparationHash = reader.ReadSerializable(); + } + + public override void Serialize(BinaryWriter writer) + { + base.Serialize(writer); + writer.Write(PreparationHash); + } + } +} diff --git a/src/Plugins/DBFTPlugin/Messages/RecoveryMessage/RecoveryMessage.ChangeViewPayloadCompact.cs b/src/Plugins/DBFTPlugin/Messages/RecoveryMessage/RecoveryMessage.ChangeViewPayloadCompact.cs new file mode 100644 index 0000000000..6a7734e569 --- /dev/null +++ b/src/Plugins/DBFTPlugin/Messages/RecoveryMessage/RecoveryMessage.ChangeViewPayloadCompact.cs @@ -0,0 +1,50 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// RecoveryMessage.ChangeViewPayloadCompact.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.IO; +using System; +using System.IO; + +namespace Neo.Consensus +{ + partial class RecoveryMessage + { + public class ChangeViewPayloadCompact : ISerializable + { + public byte ValidatorIndex; + public byte OriginalViewNumber; + public ulong Timestamp; + public ReadOnlyMemory InvocationScript; + + int ISerializable.Size => + sizeof(byte) + //ValidatorIndex + sizeof(byte) + //OriginalViewNumber + sizeof(ulong) + //Timestamp + InvocationScript.GetVarSize(); //InvocationScript + + void ISerializable.Deserialize(ref MemoryReader reader) + { + ValidatorIndex = reader.ReadByte(); + OriginalViewNumber = reader.ReadByte(); + Timestamp = reader.ReadUInt64(); + InvocationScript = reader.ReadVarMemory(1024); + } + + void ISerializable.Serialize(BinaryWriter writer) + { + writer.Write(ValidatorIndex); + writer.Write(OriginalViewNumber); + writer.Write(Timestamp); + writer.WriteVarBytes(InvocationScript.Span); + } + } + } +} diff --git a/src/Plugins/DBFTPlugin/Messages/RecoveryMessage/RecoveryMessage.CommitPayloadCompact.cs b/src/Plugins/DBFTPlugin/Messages/RecoveryMessage/RecoveryMessage.CommitPayloadCompact.cs new file mode 100644 index 0000000000..2dfa16597a --- /dev/null +++ b/src/Plugins/DBFTPlugin/Messages/RecoveryMessage/RecoveryMessage.CommitPayloadCompact.cs @@ -0,0 +1,50 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// RecoveryMessage.CommitPayloadCompact.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.IO; +using System; +using System.IO; + +namespace Neo.Consensus +{ + partial class RecoveryMessage + { + public class CommitPayloadCompact : ISerializable + { + public byte ViewNumber; + public byte ValidatorIndex; + public ReadOnlyMemory Signature; + public ReadOnlyMemory InvocationScript; + + int ISerializable.Size => + sizeof(byte) + //ViewNumber + sizeof(byte) + //ValidatorIndex + Signature.Length + //Signature + InvocationScript.GetVarSize(); //InvocationScript + + void ISerializable.Deserialize(ref MemoryReader reader) + { + ViewNumber = reader.ReadByte(); + ValidatorIndex = reader.ReadByte(); + Signature = reader.ReadMemory(64); + InvocationScript = reader.ReadVarMemory(1024); + } + + void ISerializable.Serialize(BinaryWriter writer) + { + writer.Write(ViewNumber); + writer.Write(ValidatorIndex); + writer.Write(Signature.Span); + writer.WriteVarBytes(InvocationScript.Span); + } + } + } +} diff --git a/src/Plugins/DBFTPlugin/Messages/RecoveryMessage/RecoveryMessage.PreparationPayloadCompact.cs b/src/Plugins/DBFTPlugin/Messages/RecoveryMessage/RecoveryMessage.PreparationPayloadCompact.cs new file mode 100644 index 0000000000..80b2a48b6f --- /dev/null +++ b/src/Plugins/DBFTPlugin/Messages/RecoveryMessage/RecoveryMessage.PreparationPayloadCompact.cs @@ -0,0 +1,42 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// RecoveryMessage.PreparationPayloadCompact.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.IO; +using System; +using System.IO; + +namespace Neo.Consensus +{ + partial class RecoveryMessage + { + public class PreparationPayloadCompact : ISerializable + { + public byte ValidatorIndex; + public ReadOnlyMemory InvocationScript; + + int ISerializable.Size => + sizeof(byte) + //ValidatorIndex + InvocationScript.GetVarSize(); //InvocationScript + + void ISerializable.Deserialize(ref MemoryReader reader) + { + ValidatorIndex = reader.ReadByte(); + InvocationScript = reader.ReadVarMemory(1024); + } + + void ISerializable.Serialize(BinaryWriter writer) + { + writer.Write(ValidatorIndex); + writer.WriteVarBytes(InvocationScript.Span); + } + } + } +} diff --git a/src/Plugins/DBFTPlugin/Messages/RecoveryMessage/RecoveryMessage.cs b/src/Plugins/DBFTPlugin/Messages/RecoveryMessage/RecoveryMessage.cs new file mode 100644 index 0000000000..fc688d6a1f --- /dev/null +++ b/src/Plugins/DBFTPlugin/Messages/RecoveryMessage/RecoveryMessage.cs @@ -0,0 +1,131 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// RecoveryMessage.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.IO; +using Neo.Network.P2P.Payloads; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace Neo.Consensus +{ + public partial class RecoveryMessage : ConsensusMessage + { + public Dictionary ChangeViewMessages; + public PrepareRequest PrepareRequestMessage; + /// The PreparationHash in case the PrepareRequest hasn't been received yet. + /// This can be null if the PrepareRequest information is present, since it can be derived in that case. + public UInt256 PreparationHash; + public Dictionary PreparationMessages; + public Dictionary CommitMessages; + + public override int Size => base.Size + + /* ChangeViewMessages */ ChangeViewMessages?.Values.GetVarSize() ?? 0 + + /* PrepareRequestMessage */ 1 + PrepareRequestMessage?.Size ?? 0 + + /* PreparationHash */ PreparationHash?.Size ?? 0 + + /* PreparationMessages */ PreparationMessages?.Values.GetVarSize() ?? 0 + + /* CommitMessages */ CommitMessages?.Values.GetVarSize() ?? 0; + + public RecoveryMessage() : base(ConsensusMessageType.RecoveryMessage) { } + + public override void Deserialize(ref MemoryReader reader) + { + base.Deserialize(ref reader); + ChangeViewMessages = reader.ReadSerializableArray(byte.MaxValue).ToDictionary(p => p.ValidatorIndex); + if (reader.ReadBoolean()) + { + PrepareRequestMessage = reader.ReadSerializable(); + } + else + { + int preparationHashSize = UInt256.Zero.Size; + if (preparationHashSize == (int)reader.ReadVarInt((ulong)preparationHashSize)) + PreparationHash = new UInt256(reader.ReadMemory(preparationHashSize).Span); + } + + PreparationMessages = reader.ReadSerializableArray(byte.MaxValue).ToDictionary(p => p.ValidatorIndex); + CommitMessages = reader.ReadSerializableArray(byte.MaxValue).ToDictionary(p => p.ValidatorIndex); + } + + public override bool Verify(ProtocolSettings protocolSettings) + { + if (!base.Verify(protocolSettings)) return false; + return (PrepareRequestMessage is null || PrepareRequestMessage.Verify(protocolSettings)) + && ChangeViewMessages.Values.All(p => p.ValidatorIndex < protocolSettings.ValidatorsCount) + && PreparationMessages.Values.All(p => p.ValidatorIndex < protocolSettings.ValidatorsCount) + && CommitMessages.Values.All(p => p.ValidatorIndex < protocolSettings.ValidatorsCount); + } + + internal ExtensiblePayload[] GetChangeViewPayloads(ConsensusContext context) + { + return ChangeViewMessages.Values.Select(p => context.CreatePayload(new ChangeView + { + BlockIndex = BlockIndex, + ValidatorIndex = p.ValidatorIndex, + ViewNumber = p.OriginalViewNumber, + Timestamp = p.Timestamp + }, p.InvocationScript)).ToArray(); + } + + internal ExtensiblePayload[] GetCommitPayloadsFromRecoveryMessage(ConsensusContext context) + { + return CommitMessages.Values.Select(p => context.CreatePayload(new Commit + { + BlockIndex = BlockIndex, + ValidatorIndex = p.ValidatorIndex, + ViewNumber = p.ViewNumber, + Signature = p.Signature + }, p.InvocationScript)).ToArray(); + } + + internal ExtensiblePayload GetPrepareRequestPayload(ConsensusContext context) + { + if (PrepareRequestMessage == null) return null; + if (!PreparationMessages.TryGetValue(context.Block.PrimaryIndex, out PreparationPayloadCompact compact)) + return null; + return context.CreatePayload(PrepareRequestMessage, compact.InvocationScript); + } + + internal ExtensiblePayload[] GetPrepareResponsePayloads(ConsensusContext context) + { + UInt256 preparationHash = PreparationHash ?? context.PreparationPayloads[context.Block.PrimaryIndex]?.Hash; + if (preparationHash is null) return Array.Empty(); + return PreparationMessages.Values.Where(p => p.ValidatorIndex != context.Block.PrimaryIndex).Select(p => context.CreatePayload(new PrepareResponse + { + BlockIndex = BlockIndex, + ValidatorIndex = p.ValidatorIndex, + ViewNumber = ViewNumber, + PreparationHash = preparationHash + }, p.InvocationScript)).ToArray(); + } + + public override void Serialize(BinaryWriter writer) + { + base.Serialize(writer); + writer.Write(ChangeViewMessages.Values.ToArray()); + bool hasPrepareRequestMessage = PrepareRequestMessage != null; + writer.Write(hasPrepareRequestMessage); + if (hasPrepareRequestMessage) + writer.Write(PrepareRequestMessage); + else + { + if (PreparationHash == null) + writer.WriteVarInt(0); + else + writer.WriteVarBytes(PreparationHash.ToArray()); + } + + writer.Write(PreparationMessages.Values.ToArray()); + writer.Write(CommitMessages.Values.ToArray()); + } + } +} diff --git a/src/Plugins/DBFTPlugin/Messages/RecoveryMessage/RecoveryRequest.cs b/src/Plugins/DBFTPlugin/Messages/RecoveryMessage/RecoveryRequest.cs new file mode 100644 index 0000000000..84cd381add --- /dev/null +++ b/src/Plugins/DBFTPlugin/Messages/RecoveryMessage/RecoveryRequest.cs @@ -0,0 +1,43 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// RecoveryRequest.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.IO; +using System.IO; + +namespace Neo.Consensus +{ + public class RecoveryRequest : ConsensusMessage + { + /// + /// Timestamp of when the ChangeView message was created. This allows receiving nodes to ensure + /// they only respond once to a specific RecoveryRequest request. + /// In this sense, it prevents replay of the RecoveryRequest message from the repeatedly broadcast of Recovery's messages. + /// + public ulong Timestamp; + + public override int Size => base.Size + + sizeof(ulong); //Timestamp + + public RecoveryRequest() : base(ConsensusMessageType.RecoveryRequest) { } + + public override void Deserialize(ref MemoryReader reader) + { + base.Deserialize(ref reader); + Timestamp = reader.ReadUInt64(); + } + + public override void Serialize(BinaryWriter writer) + { + base.Serialize(writer); + writer.Write(Timestamp); + } + } +} diff --git a/src/Plugins/DBFTPlugin/Settings.cs b/src/Plugins/DBFTPlugin/Settings.cs new file mode 100644 index 0000000000..d0ecbb63fd --- /dev/null +++ b/src/Plugins/DBFTPlugin/Settings.cs @@ -0,0 +1,35 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Settings.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; + +namespace Neo.Consensus +{ + public class Settings + { + public string RecoveryLogs { get; } + public bool IgnoreRecoveryLogs { get; } + public bool AutoStart { get; } + public uint Network { get; } + public uint MaxBlockSize { get; } + public long MaxBlockSystemFee { get; } + + public Settings(IConfigurationSection section) + { + RecoveryLogs = section.GetValue("RecoveryLogs", "ConsensusState"); + IgnoreRecoveryLogs = section.GetValue("IgnoreRecoveryLogs", false); + AutoStart = section.GetValue("AutoStart", false); + Network = section.GetValue("Network", 5195086u); + MaxBlockSize = section.GetValue("MaxBlockSize", 262144u); + MaxBlockSystemFee = section.GetValue("MaxBlockSystemFee", 150000000000L); + } + } +} diff --git a/src/Plugins/DBFTPlugin/Types/ChangeViewReason.cs b/src/Plugins/DBFTPlugin/Types/ChangeViewReason.cs new file mode 100644 index 0000000000..4c0a3c1100 --- /dev/null +++ b/src/Plugins/DBFTPlugin/Types/ChangeViewReason.cs @@ -0,0 +1,23 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// ChangeViewReason.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.Consensus +{ + public enum ChangeViewReason : byte + { + Timeout = 0x0, + ChangeAgreement = 0x1, + TxNotFound = 0x2, + TxRejectedByPolicy = 0x3, + TxInvalid = 0x4, + BlockRejectedByPolicy = 0x5 + } +} diff --git a/src/Plugins/DBFTPlugin/Types/ConsensusMessageType.cs b/src/Plugins/DBFTPlugin/Types/ConsensusMessageType.cs new file mode 100644 index 0000000000..f325133f08 --- /dev/null +++ b/src/Plugins/DBFTPlugin/Types/ConsensusMessageType.cs @@ -0,0 +1,25 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// ConsensusMessageType.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.Consensus +{ + public enum ConsensusMessageType : byte + { + ChangeView = 0x00, + + PrepareRequest = 0x20, + PrepareResponse = 0x21, + Commit = 0x30, + + RecoveryRequest = 0x40, + RecoveryMessage = 0x41, + } +} diff --git a/src/Plugins/DBFTPlugin/config.json b/src/Plugins/DBFTPlugin/config.json new file mode 100644 index 0000000000..2e2b710ba3 --- /dev/null +++ b/src/Plugins/DBFTPlugin/config.json @@ -0,0 +1,10 @@ +{ + "PluginConfiguration": { + "RecoveryLogs": "ConsensusState", + "IgnoreRecoveryLogs": false, + "AutoStart": false, + "Network": 860833102, + "MaxBlockSize": 2097152, + "MaxBlockSystemFee": 150000000000 + } +} diff --git a/src/Plugins/Directory.Build.props b/src/Plugins/Directory.Build.props new file mode 100644 index 0000000000..4eb51eef9b --- /dev/null +++ b/src/Plugins/Directory.Build.props @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + PreserveNewest + PreserveNewest + + + diff --git a/src/Plugins/LevelDBStore/IO/Data/LevelDB/DB.cs b/src/Plugins/LevelDBStore/IO/Data/LevelDB/DB.cs new file mode 100644 index 0000000000..60e0e24e5a --- /dev/null +++ b/src/Plugins/LevelDBStore/IO/Data/LevelDB/DB.cs @@ -0,0 +1,114 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// DB.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.IO; + +namespace Neo.IO.Data.LevelDB +{ + public class DB : IDisposable + { + private IntPtr handle; + + /// + /// Return true if haven't got valid handle + /// + public bool IsDisposed => handle == IntPtr.Zero; + + private DB(IntPtr handle) + { + this.handle = handle; + } + + public void Dispose() + { + if (handle != IntPtr.Zero) + { + Native.leveldb_close(handle); + handle = IntPtr.Zero; + } + } + + public void Delete(WriteOptions options, byte[] key) + { + Native.leveldb_delete(handle, options.handle, key, (UIntPtr)key.Length, out IntPtr error); + NativeHelper.CheckError(error); + } + + public byte[] Get(ReadOptions options, byte[] key) + { + IntPtr value = Native.leveldb_get(handle, options.handle, key, (UIntPtr)key.Length, out UIntPtr length, out IntPtr error); + try + { + NativeHelper.CheckError(error); + return value.ToByteArray(length); + } + finally + { + if (value != IntPtr.Zero) Native.leveldb_free(value); + } + } + + public bool Contains(ReadOptions options, byte[] key) + { + IntPtr value = Native.leveldb_get(handle, options.handle, key, (UIntPtr)key.Length, out _, out IntPtr error); + NativeHelper.CheckError(error); + + if (value != IntPtr.Zero) + { + Native.leveldb_free(value); + return true; + } + + return false; + } + + public Snapshot GetSnapshot() + { + return new Snapshot(handle); + } + + public Iterator NewIterator(ReadOptions options) + { + return new Iterator(Native.leveldb_create_iterator(handle, options.handle)); + } + + public static DB Open(string name) + { + return Open(name, Options.Default); + } + + public static DB Open(string name, Options options) + { + IntPtr handle = Native.leveldb_open(options.handle, Path.GetFullPath(name), out IntPtr error); + NativeHelper.CheckError(error); + return new DB(handle); + } + + public void Put(WriteOptions options, byte[] key, byte[] value) + { + Native.leveldb_put(handle, options.handle, key, (UIntPtr)key.Length, value, (UIntPtr)value.Length, out IntPtr error); + NativeHelper.CheckError(error); + } + + public static void Repair(string name, Options options) + { + Native.leveldb_repair_db(options.handle, Path.GetFullPath(name), out IntPtr error); + NativeHelper.CheckError(error); + } + + public void Write(WriteOptions options, WriteBatch write_batch) + { + Native.leveldb_write(handle, options.handle, write_batch.handle, out IntPtr error); + NativeHelper.CheckError(error); + } + } +} diff --git a/src/Plugins/LevelDBStore/IO/Data/LevelDB/Helper.cs b/src/Plugins/LevelDBStore/IO/Data/LevelDB/Helper.cs new file mode 100644 index 0000000000..2ac3a0005f --- /dev/null +++ b/src/Plugins/LevelDBStore/IO/Data/LevelDB/Helper.cs @@ -0,0 +1,63 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Helper.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 System; +using System.Collections.Generic; +using System.Runtime.InteropServices; + +namespace Neo.IO.Data.LevelDB +{ + public static class Helper + { + public static IEnumerable Seek(this DB db, ReadOptions options, byte[] prefix, SeekDirection direction, Func resultSelector) + { + using Iterator it = db.NewIterator(options); + if (direction == SeekDirection.Forward) + { + for (it.Seek(prefix); it.Valid(); it.Next()) + yield return resultSelector(it.Key(), it.Value()); + } + else + { + // SeekForPrev + + it.Seek(prefix); + if (!it.Valid()) + it.SeekToLast(); + else if (it.Key().AsSpan().SequenceCompareTo(prefix) > 0) + it.Prev(); + + for (; it.Valid(); it.Prev()) + yield return resultSelector(it.Key(), it.Value()); + } + } + + public static IEnumerable FindRange(this DB db, ReadOptions options, byte[] startKey, byte[] endKey, Func resultSelector) + { + using Iterator it = db.NewIterator(options); + for (it.Seek(startKey); it.Valid(); it.Next()) + { + byte[] key = it.Key(); + if (key.AsSpan().SequenceCompareTo(endKey) > 0) break; + yield return resultSelector(key, it.Value()); + } + } + + internal static byte[] ToByteArray(this IntPtr data, UIntPtr length) + { + if (data == IntPtr.Zero) return null; + byte[] buffer = new byte[(int)length]; + Marshal.Copy(data, buffer, 0, (int)length); + return buffer; + } + } +} diff --git a/src/Plugins/LevelDBStore/IO/Data/LevelDB/Iterator.cs b/src/Plugins/LevelDBStore/IO/Data/LevelDB/Iterator.cs new file mode 100644 index 0000000000..6c025380fb --- /dev/null +++ b/src/Plugins/LevelDBStore/IO/Data/LevelDB/Iterator.cs @@ -0,0 +1,86 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Iterator.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; + +namespace Neo.IO.Data.LevelDB +{ + public class Iterator : IDisposable + { + private IntPtr handle; + + internal Iterator(IntPtr handle) + { + this.handle = handle; + } + + private void CheckError() + { + Native.leveldb_iter_get_error(handle, out IntPtr error); + NativeHelper.CheckError(error); + } + + public void Dispose() + { + if (handle != IntPtr.Zero) + { + Native.leveldb_iter_destroy(handle); + handle = IntPtr.Zero; + } + } + + public byte[] Key() + { + IntPtr key = Native.leveldb_iter_key(handle, out UIntPtr length); + CheckError(); + return key.ToByteArray(length); + } + + public void Next() + { + Native.leveldb_iter_next(handle); + CheckError(); + } + + public void Prev() + { + Native.leveldb_iter_prev(handle); + CheckError(); + } + + public void Seek(byte[] target) + { + Native.leveldb_iter_seek(handle, target, (UIntPtr)target.Length); + } + + public void SeekToFirst() + { + Native.leveldb_iter_seek_to_first(handle); + } + + public void SeekToLast() + { + Native.leveldb_iter_seek_to_last(handle); + } + + public bool Valid() + { + return Native.leveldb_iter_valid(handle); + } + + public byte[] Value() + { + IntPtr value = Native.leveldb_iter_value(handle, out UIntPtr length); + CheckError(); + return value.ToByteArray(length); + } + } +} diff --git a/src/Plugins/LevelDBStore/IO/Data/LevelDB/LevelDBException.cs b/src/Plugins/LevelDBStore/IO/Data/LevelDB/LevelDBException.cs new file mode 100644 index 0000000000..c9cca42070 --- /dev/null +++ b/src/Plugins/LevelDBStore/IO/Data/LevelDB/LevelDBException.cs @@ -0,0 +1,23 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// LevelDBException.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.Data.Common; + +namespace Neo.IO.Data.LevelDB +{ + public class LevelDBException : DbException + { + internal LevelDBException(string message) + : base(message) + { + } + } +} diff --git a/src/Plugins/LevelDBStore/IO/Data/LevelDB/Native.cs b/src/Plugins/LevelDBStore/IO/Data/LevelDB/Native.cs new file mode 100644 index 0000000000..acf8fa82b9 --- /dev/null +++ b/src/Plugins/LevelDBStore/IO/Data/LevelDB/Native.cs @@ -0,0 +1,264 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Native.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.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace Neo.IO.Data.LevelDB +{ + public enum CompressionType : byte + { + kNoCompression = 0x0, + kSnappyCompression = 0x1 + } + + public static class Native + { + #region Logger + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr leveldb_logger_create(IntPtr /* Action */ logger); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_logger_destroy(IntPtr /* logger*/ option); + #endregion + + #region DB + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr leveldb_open(IntPtr /* Options*/ options, string name, out IntPtr error); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_close(IntPtr /*DB */ db); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_put(IntPtr /* DB */ db, IntPtr /* WriteOptions*/ options, byte[] key, UIntPtr keylen, byte[] val, UIntPtr vallen, out IntPtr errptr); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_delete(IntPtr /* DB */ db, IntPtr /* WriteOptions*/ options, byte[] key, UIntPtr keylen, out IntPtr errptr); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_write(IntPtr /* DB */ db, IntPtr /* WriteOptions*/ options, IntPtr /* WriteBatch */ batch, out IntPtr errptr); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr leveldb_get(IntPtr /* DB */ db, IntPtr /* ReadOptions*/ options, byte[] key, UIntPtr keylen, out UIntPtr vallen, out IntPtr errptr); + + //[DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + //static extern void leveldb_approximate_sizes(IntPtr /* DB */ db, int num_ranges, byte[] range_start_key, long range_start_key_len, byte[] range_limit_key, long range_limit_key_len, out long sizes); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr leveldb_create_iterator(IntPtr /* DB */ db, IntPtr /* ReadOption */ options); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr leveldb_create_snapshot(IntPtr /* DB */ db); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_release_snapshot(IntPtr /* DB */ db, IntPtr /* SnapShot*/ snapshot); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr leveldb_property_value(IntPtr /* DB */ db, string propname); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_repair_db(IntPtr /* Options*/ options, string name, out IntPtr error); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_destroy_db(IntPtr /* Options*/ options, string name, out IntPtr error); + + #region extensions + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_free(IntPtr /* void */ ptr); + + #endregion + + + #endregion + + #region Env + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr leveldb_create_default_env(); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_env_destroy(IntPtr /*Env*/ cache); + #endregion + + #region Iterator + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_iter_destroy(IntPtr /*Iterator*/ iterator); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.U1)] + public static extern bool leveldb_iter_valid(IntPtr /*Iterator*/ iterator); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_iter_seek_to_first(IntPtr /*Iterator*/ iterator); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_iter_seek_to_last(IntPtr /*Iterator*/ iterator); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_iter_seek(IntPtr /*Iterator*/ iterator, byte[] key, UIntPtr length); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_iter_next(IntPtr /*Iterator*/ iterator); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_iter_prev(IntPtr /*Iterator*/ iterator); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr leveldb_iter_key(IntPtr /*Iterator*/ iterator, out UIntPtr length); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr leveldb_iter_value(IntPtr /*Iterator*/ iterator, out UIntPtr length); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_iter_get_error(IntPtr /*Iterator*/ iterator, out IntPtr error); + #endregion + + #region Options + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr leveldb_options_create(); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_options_destroy(IntPtr /*Options*/ options); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_options_set_create_if_missing(IntPtr /*Options*/ options, [MarshalAs(UnmanagedType.U1)] bool o); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_options_set_error_if_exists(IntPtr /*Options*/ options, [MarshalAs(UnmanagedType.U1)] bool o); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_options_set_info_log(IntPtr /*Options*/ options, IntPtr /* Logger */ logger); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_options_set_paranoid_checks(IntPtr /*Options*/ options, [MarshalAs(UnmanagedType.U1)] bool o); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_options_set_env(IntPtr /*Options*/ options, IntPtr /*Env*/ env); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_options_set_write_buffer_size(IntPtr /*Options*/ options, UIntPtr size); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_options_set_max_open_files(IntPtr /*Options*/ options, int max); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_options_set_cache(IntPtr /*Options*/ options, IntPtr /*Cache*/ cache); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_options_set_block_size(IntPtr /*Options*/ options, UIntPtr size); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_options_set_block_restart_interval(IntPtr /*Options*/ options, int interval); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_options_set_compression(IntPtr /*Options*/ options, CompressionType level); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_options_set_comparator(IntPtr /*Options*/ options, IntPtr /*Comparator*/ comparer); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_options_set_filter_policy(IntPtr /*Options*/ options, IntPtr /*FilterPolicy*/ policy); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr leveldb_filterpolicy_create_bloom(int bits_per_key); + #endregion + + #region ReadOptions + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr leveldb_readoptions_create(); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_readoptions_destroy(IntPtr /*ReadOptions*/ options); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_readoptions_set_verify_checksums(IntPtr /*ReadOptions*/ options, [MarshalAs(UnmanagedType.U1)] bool o); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_readoptions_set_fill_cache(IntPtr /*ReadOptions*/ options, [MarshalAs(UnmanagedType.U1)] bool o); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_readoptions_set_snapshot(IntPtr /*ReadOptions*/ options, IntPtr /*SnapShot*/ snapshot); + #endregion + + #region WriteBatch + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr leveldb_writebatch_create(); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_writebatch_destroy(IntPtr /* WriteBatch */ batch); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_writebatch_clear(IntPtr /* WriteBatch */ batch); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_writebatch_put(IntPtr /* WriteBatch */ batch, byte[] key, UIntPtr keylen, byte[] val, UIntPtr vallen); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_writebatch_delete(IntPtr /* WriteBatch */ batch, byte[] key, UIntPtr keylen); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_writebatch_iterate(IntPtr /* WriteBatch */ batch, object state, Action put, Action deleted); + #endregion + + #region WriteOptions + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr leveldb_writeoptions_create(); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_writeoptions_destroy(IntPtr /*WriteOptions*/ options); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_writeoptions_set_sync(IntPtr /*WriteOptions*/ options, [MarshalAs(UnmanagedType.U1)] bool o); + #endregion + + #region Cache + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr leveldb_cache_create_lru(int capacity); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_cache_destroy(IntPtr /*Cache*/ cache); + #endregion + + #region Comparator + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr /* leveldb_comparator_t* */ + leveldb_comparator_create( + IntPtr /* void* */ state, + IntPtr /* void (*)(void*) */ destructor, + IntPtr + /* int (*compare)(void*, + const char* a, size_t alen, + const char* b, size_t blen) */ + compare, + IntPtr /* const char* (*)(void*) */ name); + + [DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)] + public static extern void leveldb_comparator_destroy(IntPtr /* leveldb_comparator_t* */ cmp); + + #endregion + } + + internal static class NativeHelper + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void CheckError(IntPtr error) + { + if (error != IntPtr.Zero) + { + string message = Marshal.PtrToStringAnsi(error); + Native.leveldb_free(error); + throw new LevelDBException(message); + } + } + } +} diff --git a/src/Plugins/LevelDBStore/IO/Data/LevelDB/Options.cs b/src/Plugins/LevelDBStore/IO/Data/LevelDB/Options.cs new file mode 100644 index 0000000000..989987eeed --- /dev/null +++ b/src/Plugins/LevelDBStore/IO/Data/LevelDB/Options.cs @@ -0,0 +1,98 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Options.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; + +namespace Neo.IO.Data.LevelDB +{ + public class Options + { + public static readonly Options Default = new Options(); + internal readonly IntPtr handle = Native.leveldb_options_create(); + + public bool CreateIfMissing + { + set + { + Native.leveldb_options_set_create_if_missing(handle, value); + } + } + + public bool ErrorIfExists + { + set + { + Native.leveldb_options_set_error_if_exists(handle, value); + } + } + + public bool ParanoidChecks + { + set + { + Native.leveldb_options_set_paranoid_checks(handle, value); + } + } + + public int WriteBufferSize + { + set + { + Native.leveldb_options_set_write_buffer_size(handle, (UIntPtr)value); + } + } + + public int MaxOpenFiles + { + set + { + Native.leveldb_options_set_max_open_files(handle, value); + } + } + + public int BlockSize + { + set + { + Native.leveldb_options_set_block_size(handle, (UIntPtr)value); + } + } + + public int BlockRestartInterval + { + set + { + Native.leveldb_options_set_block_restart_interval(handle, value); + } + } + + public CompressionType Compression + { + set + { + Native.leveldb_options_set_compression(handle, value); + } + } + + public IntPtr FilterPolicy + { + set + { + Native.leveldb_options_set_filter_policy(handle, value); + } + } + + ~Options() + { + Native.leveldb_options_destroy(handle); + } + } +} diff --git a/src/Plugins/LevelDBStore/IO/Data/LevelDB/ReadOptions.cs b/src/Plugins/LevelDBStore/IO/Data/LevelDB/ReadOptions.cs new file mode 100644 index 0000000000..727ae9f02a --- /dev/null +++ b/src/Plugins/LevelDBStore/IO/Data/LevelDB/ReadOptions.cs @@ -0,0 +1,50 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// ReadOptions.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; + +namespace Neo.IO.Data.LevelDB +{ + public class ReadOptions + { + public static readonly ReadOptions Default = new ReadOptions(); + internal readonly IntPtr handle = Native.leveldb_readoptions_create(); + + public bool VerifyChecksums + { + set + { + Native.leveldb_readoptions_set_verify_checksums(handle, value); + } + } + + public bool FillCache + { + set + { + Native.leveldb_readoptions_set_fill_cache(handle, value); + } + } + + public Snapshot Snapshot + { + set + { + Native.leveldb_readoptions_set_snapshot(handle, value.handle); + } + } + + ~ReadOptions() + { + Native.leveldb_readoptions_destroy(handle); + } + } +} diff --git a/src/Plugins/LevelDBStore/IO/Data/LevelDB/Snapshot.cs b/src/Plugins/LevelDBStore/IO/Data/LevelDB/Snapshot.cs new file mode 100644 index 0000000000..14280fbc8f --- /dev/null +++ b/src/Plugins/LevelDBStore/IO/Data/LevelDB/Snapshot.cs @@ -0,0 +1,35 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Snapshot.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; + +namespace Neo.IO.Data.LevelDB +{ + public class Snapshot : IDisposable + { + internal IntPtr db, handle; + + internal Snapshot(IntPtr db) + { + this.db = db; + handle = Native.leveldb_create_snapshot(db); + } + + public void Dispose() + { + if (handle != IntPtr.Zero) + { + Native.leveldb_release_snapshot(db, handle); + handle = IntPtr.Zero; + } + } + } +} diff --git a/src/Plugins/LevelDBStore/IO/Data/LevelDB/WriteBatch.cs b/src/Plugins/LevelDBStore/IO/Data/LevelDB/WriteBatch.cs new file mode 100644 index 0000000000..ad82dad450 --- /dev/null +++ b/src/Plugins/LevelDBStore/IO/Data/LevelDB/WriteBatch.cs @@ -0,0 +1,40 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// WriteBatch.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; + +namespace Neo.IO.Data.LevelDB +{ + public class WriteBatch + { + internal readonly IntPtr handle = Native.leveldb_writebatch_create(); + + ~WriteBatch() + { + Native.leveldb_writebatch_destroy(handle); + } + + public void Clear() + { + Native.leveldb_writebatch_clear(handle); + } + + public void Delete(byte[] key) + { + Native.leveldb_writebatch_delete(handle, key, (UIntPtr)key.Length); + } + + public void Put(byte[] key, byte[] value) + { + Native.leveldb_writebatch_put(handle, key, (UIntPtr)key.Length, value, (UIntPtr)value.Length); + } + } +} diff --git a/src/Plugins/LevelDBStore/IO/Data/LevelDB/WriteOptions.cs b/src/Plugins/LevelDBStore/IO/Data/LevelDB/WriteOptions.cs new file mode 100644 index 0000000000..48915ba480 --- /dev/null +++ b/src/Plugins/LevelDBStore/IO/Data/LevelDB/WriteOptions.cs @@ -0,0 +1,36 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// WriteOptions.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; + +namespace Neo.IO.Data.LevelDB +{ + public class WriteOptions + { + public static readonly WriteOptions Default = new WriteOptions(); + public static readonly WriteOptions SyncWrite = new WriteOptions { Sync = true }; + + internal readonly IntPtr handle = Native.leveldb_writeoptions_create(); + + public bool Sync + { + set + { + Native.leveldb_writeoptions_set_sync(handle, value); + } + } + + ~WriteOptions() + { + Native.leveldb_writeoptions_destroy(handle); + } + } +} diff --git a/src/Plugins/LevelDBStore/LevelDBStore.csproj b/src/Plugins/LevelDBStore/LevelDBStore.csproj new file mode 100644 index 0000000000..ba82156b18 --- /dev/null +++ b/src/Plugins/LevelDBStore/LevelDBStore.csproj @@ -0,0 +1,10 @@ + + + + net8.0 + Neo.Plugins.Storage.LevelDBStore + Neo.Plugins.Storage + true + + + diff --git a/src/Plugins/LevelDBStore/Plugins/Storage/LevelDBStore.cs b/src/Plugins/LevelDBStore/Plugins/Storage/LevelDBStore.cs new file mode 100644 index 0000000000..9c676e8a7f --- /dev/null +++ b/src/Plugins/LevelDBStore/Plugins/Storage/LevelDBStore.cs @@ -0,0 +1,35 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// LevelDBStore.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.IO.Data.LevelDB; +using Neo.Persistence; +using System; +using System.Linq; + +namespace Neo.Plugins.Storage +{ + public class LevelDBStore : Plugin, IStoreProvider + { + public override string Description => "Uses LevelDB to store the blockchain data"; + + public LevelDBStore() + { + StoreFactory.RegisterProvider(this); + } + + public IStore GetStore(string path) + { + if (Environment.CommandLine.Split(' ').Any(p => p == "/repair" || p == "--repair")) + DB.Repair(path, Options.Default); + return new Store(path); + } + } +} diff --git a/src/Plugins/LevelDBStore/Plugins/Storage/Snapshot.cs b/src/Plugins/LevelDBStore/Plugins/Storage/Snapshot.cs new file mode 100644 index 0000000000..0b0a63b885 --- /dev/null +++ b/src/Plugins/LevelDBStore/Plugins/Storage/Snapshot.cs @@ -0,0 +1,69 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Snapshot.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.IO.Data.LevelDB; +using Neo.Persistence; +using System.Collections.Generic; +using LSnapshot = Neo.IO.Data.LevelDB.Snapshot; + +namespace Neo.Plugins.Storage +{ + internal class Snapshot : ISnapshot + { + private readonly DB db; + private readonly LSnapshot snapshot; + private readonly ReadOptions options; + private readonly WriteBatch batch; + + public Snapshot(DB db) + { + this.db = db; + snapshot = db.GetSnapshot(); + options = new ReadOptions { FillCache = false, Snapshot = snapshot }; + batch = new WriteBatch(); + } + + public void Commit() + { + db.Write(WriteOptions.Default, batch); + } + + public void Delete(byte[] key) + { + batch.Delete(key); + } + + public void Dispose() + { + snapshot.Dispose(); + } + + public IEnumerable<(byte[] Key, byte[] Value)> Seek(byte[] prefix, SeekDirection direction = SeekDirection.Forward) + { + return db.Seek(options, prefix, direction, (k, v) => (k, v)); + } + + public void Put(byte[] key, byte[] value) + { + batch.Put(key, value); + } + + public bool Contains(byte[] key) + { + return db.Contains(options, key); + } + + public byte[] TryGet(byte[] key) + { + return db.Get(options, key); + } + } +} diff --git a/src/Plugins/LevelDBStore/Plugins/Storage/Store.cs b/src/Plugins/LevelDBStore/Plugins/Storage/Store.cs new file mode 100644 index 0000000000..27b12a8b64 --- /dev/null +++ b/src/Plugins/LevelDBStore/Plugins/Storage/Store.cs @@ -0,0 +1,67 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Store.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.IO.Data.LevelDB; +using Neo.Persistence; +using System.Collections.Generic; + +namespace Neo.Plugins.Storage +{ + internal class Store : IStore + { + private readonly DB db; + + public Store(string path) + { + db = DB.Open(path, new Options { CreateIfMissing = true, FilterPolicy = Native.leveldb_filterpolicy_create_bloom(15) }); + } + + public void Delete(byte[] key) + { + db.Delete(WriteOptions.Default, key); + } + + public void Dispose() + { + db.Dispose(); + } + + public IEnumerable<(byte[], byte[])> Seek(byte[] prefix, SeekDirection direction = SeekDirection.Forward) + { + return db.Seek(ReadOptions.Default, prefix, direction, (k, v) => (k, v)); + } + + public ISnapshot GetSnapshot() + { + return new Snapshot(db); + } + + public void Put(byte[] key, byte[] value) + { + db.Put(WriteOptions.Default, key, value); + } + + public void PutSync(byte[] key, byte[] value) + { + db.Put(WriteOptions.SyncWrite, key, value); + } + + public bool Contains(byte[] key) + { + return db.Contains(ReadOptions.Default, key); + } + + public byte[] TryGet(byte[] key) + { + return db.Get(ReadOptions.Default, key); + } + } +} diff --git a/src/Plugins/MPTTrie/Cryptography/MPTTrie/Cache.cs b/src/Plugins/MPTTrie/Cryptography/MPTTrie/Cache.cs new file mode 100644 index 0000000000..d8baef8529 --- /dev/null +++ b/src/Plugins/MPTTrie/Cryptography/MPTTrie/Cache.cs @@ -0,0 +1,126 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Cache.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.IO; +using Neo.Persistence; +using System.Collections.Generic; +using System.IO; + +namespace Neo.Cryptography.MPTTrie +{ + public class Cache + { + private enum TrackState : byte + { + None, + Added, + Changed, + Deleted + } + + private class Trackable + { + public Node Node; + public TrackState State; + } + + private readonly ISnapshot store; + private readonly byte prefix; + private readonly Dictionary cache = new Dictionary(); + + public Cache(ISnapshot store, byte prefix) + { + this.store = store; + this.prefix = prefix; + } + + private byte[] Key(UInt256 hash) + { + byte[] buffer = new byte[UInt256.Length + 1]; + using (MemoryStream ms = new MemoryStream(buffer, true)) + using (BinaryWriter writer = new BinaryWriter(ms)) + { + writer.Write(prefix); + hash.Serialize(writer); + } + return buffer; + } + + public Node Resolve(UInt256 hash) + { + if (cache.TryGetValue(hash, out Trackable t)) + { + return t.Node?.Clone(); + } + var n = store.TryGet(Key(hash))?.AsSerializable(); + cache.Add(hash, new Trackable + { + Node = n, + State = TrackState.None, + }); + return n?.Clone(); + } + + public void PutNode(Node np) + { + var n = Resolve(np.Hash); + if (n is null) + { + np.Reference = 1; + cache[np.Hash] = new Trackable + { + Node = np.Clone(), + State = TrackState.Added, + }; + return; + } + var entry = cache[np.Hash]; + entry.Node.Reference++; + entry.State = TrackState.Changed; + } + + public void DeleteNode(UInt256 hash) + { + var n = Resolve(hash); + if (n is null) return; + if (1 < n.Reference) + { + var entry = cache[hash]; + entry.Node.Reference--; + entry.State = TrackState.Changed; + return; + } + cache[hash] = new Trackable + { + Node = null, + State = TrackState.Deleted, + }; + } + + public void Commit() + { + foreach (var item in cache) + { + switch (item.Value.State) + { + case TrackState.Added: + case TrackState.Changed: + store.Put(Key(item.Key), item.Value.Node.ToArray()); + break; + case TrackState.Deleted: + store.Delete(Key(item.Key)); + break; + } + } + cache.Clear(); + } + } +} diff --git a/src/Plugins/MPTTrie/Cryptography/MPTTrie/Helper.cs b/src/Plugins/MPTTrie/Cryptography/MPTTrie/Helper.cs new file mode 100644 index 0000000000..5c93afd659 --- /dev/null +++ b/src/Plugins/MPTTrie/Cryptography/MPTTrie/Helper.cs @@ -0,0 +1,28 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Helper.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; + +namespace Neo.Cryptography.MPTTrie +{ + public static class Helper + { + public static int CompareTo(this ReadOnlySpan arr1, ReadOnlySpan arr2) + { + for (int i = 0; i < arr1.Length && i < arr2.Length; i++) + { + var r = arr1[i].CompareTo(arr2[i]); + if (r != 0) return r; + } + return arr2.Length < arr1.Length ? 1 : arr2.Length == arr1.Length ? 0 : -1; + } + } +} diff --git a/src/Plugins/MPTTrie/Cryptography/MPTTrie/Node.Branch.cs b/src/Plugins/MPTTrie/Cryptography/MPTTrie/Node.Branch.cs new file mode 100644 index 0000000000..c8ff04dfc6 --- /dev/null +++ b/src/Plugins/MPTTrie/Cryptography/MPTTrie/Node.Branch.cs @@ -0,0 +1,69 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Node.Branch.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.IO; +using System.IO; + +namespace Neo.Cryptography.MPTTrie +{ + partial class Node + { + public const int BranchChildCount = 17; + public Node[] Children; + + public static Node NewBranch() + { + var n = new Node + { + type = NodeType.BranchNode, + Reference = 1, + Children = new Node[BranchChildCount], + }; + for (int i = 0; i < BranchChildCount; i++) + { + n.Children[i] = new Node(); + } + return n; + } + + protected int BranchSize + { + get + { + int size = 0; + for (int i = 0; i < BranchChildCount; i++) + { + size += Children[i].SizeAsChild; + } + return size; + } + } + + private void SerializeBranch(BinaryWriter writer) + { + for (int i = 0; i < BranchChildCount; i++) + { + Children[i].SerializeAsChild(writer); + } + } + + private void DeserializeBranch(ref MemoryReader reader) + { + Children = new Node[BranchChildCount]; + for (int i = 0; i < BranchChildCount; i++) + { + var n = new Node(); + n.Deserialize(ref reader); + Children[i] = n; + } + } + } +} diff --git a/src/Plugins/MPTTrie/Cryptography/MPTTrie/Node.Extension.cs b/src/Plugins/MPTTrie/Cryptography/MPTTrie/Node.Extension.cs new file mode 100644 index 0000000000..510db49250 --- /dev/null +++ b/src/Plugins/MPTTrie/Cryptography/MPTTrie/Node.Extension.cs @@ -0,0 +1,55 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Node.Extension.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.IO; +using Neo.SmartContract; +using System; +using System.IO; + +namespace Neo.Cryptography.MPTTrie +{ + partial class Node + { + public const int MaxKeyLength = (ApplicationEngine.MaxStorageKeySize + sizeof(int)) * 2; + public ReadOnlyMemory Key; + public Node Next; + + public static Node NewExtension(byte[] key, Node next) + { + if (key is null || next is null) throw new ArgumentNullException(nameof(NewExtension)); + if (key.Length == 0) throw new InvalidOperationException(nameof(NewExtension)); + var n = new Node + { + type = NodeType.ExtensionNode, + Key = key, + Next = next, + Reference = 1, + }; + return n; + } + + protected int ExtensionSize => Key.GetVarSize() + Next.SizeAsChild; + + private void SerializeExtension(BinaryWriter writer) + { + writer.WriteVarBytes(Key.Span); + Next.SerializeAsChild(writer); + } + + private void DeserializeExtension(ref MemoryReader reader) + { + Key = reader.ReadVarMemory(); + var n = new Node(); + n.Deserialize(ref reader); + Next = n; + } + } +} diff --git a/src/Plugins/MPTTrie/Cryptography/MPTTrie/Node.Hash.cs b/src/Plugins/MPTTrie/Cryptography/MPTTrie/Node.Hash.cs new file mode 100644 index 0000000000..e0190dd146 --- /dev/null +++ b/src/Plugins/MPTTrie/Cryptography/MPTTrie/Node.Hash.cs @@ -0,0 +1,43 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Node.Hash.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.IO; +using System; +using System.IO; + +namespace Neo.Cryptography.MPTTrie +{ + partial class Node + { + public static Node NewHash(UInt256 hash) + { + if (hash is null) throw new ArgumentNullException(nameof(NewHash)); + var n = new Node + { + type = NodeType.HashNode, + hash = hash, + }; + return n; + } + + protected int HashSize => hash.Size; + + private void SerializeHash(BinaryWriter writer) + { + writer.Write(hash); + } + + private void DeserializeHash(ref MemoryReader reader) + { + hash = reader.ReadSerializable(); + } + } +} diff --git a/src/Plugins/MPTTrie/Cryptography/MPTTrie/Node.Leaf.cs b/src/Plugins/MPTTrie/Cryptography/MPTTrie/Node.Leaf.cs new file mode 100644 index 0000000000..024a07f8c8 --- /dev/null +++ b/src/Plugins/MPTTrie/Cryptography/MPTTrie/Node.Leaf.cs @@ -0,0 +1,48 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Node.Leaf.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.IO; +using Neo.SmartContract; +using System; +using System.IO; + +namespace Neo.Cryptography.MPTTrie +{ + partial class Node + { + public const int MaxValueLength = 3 + ApplicationEngine.MaxStorageValueSize + sizeof(bool); + public ReadOnlyMemory Value; + + public static Node NewLeaf(byte[] value) + { + if (value is null) throw new ArgumentNullException(nameof(value)); + var n = new Node + { + type = NodeType.LeafNode, + Value = value, + Reference = 1, + }; + return n; + } + + protected int LeafSize => Value.GetVarSize(); + + private void SerializeLeaf(BinaryWriter writer) + { + writer.WriteVarBytes(Value.Span); + } + + private void DeserializeLeaf(ref MemoryReader reader) + { + Value = reader.ReadVarMemory(); + } + } +} diff --git a/src/Plugins/MPTTrie/Cryptography/MPTTrie/Node.cs b/src/Plugins/MPTTrie/Cryptography/MPTTrie/Node.cs new file mode 100644 index 0000000000..ef45548645 --- /dev/null +++ b/src/Plugins/MPTTrie/Cryptography/MPTTrie/Node.cs @@ -0,0 +1,230 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// 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 Neo.IO; +using System; +using System.IO; + +namespace Neo.Cryptography.MPTTrie +{ + public partial class Node : ISerializable + { + private NodeType type; + private UInt256 hash; + public int Reference; + public UInt256 Hash => hash ??= new UInt256(Crypto.Hash256(ToArrayWithoutReference())); + public NodeType Type => type; + public bool IsEmpty => type == NodeType.Empty; + public int Size + { + get + { + int size = sizeof(NodeType); + switch (type) + { + case NodeType.BranchNode: + return size + BranchSize + IO.Helper.GetVarSize(Reference); + case NodeType.ExtensionNode: + return size + ExtensionSize + IO.Helper.GetVarSize(Reference); + case NodeType.LeafNode: + return size + LeafSize + IO.Helper.GetVarSize(Reference); + case NodeType.HashNode: + return size + HashSize; + case NodeType.Empty: + return size; + default: + throw new InvalidOperationException($"{nameof(Node)} Cannt get size, unsupport type"); + }; + } + } + + public Node() + { + type = NodeType.Empty; + } + + public void SetDirty() + { + hash = null; + } + + public int SizeAsChild + { + get + { + switch (type) + { + case NodeType.BranchNode: + case NodeType.ExtensionNode: + case NodeType.LeafNode: + return NewHash(Hash).Size; + case NodeType.HashNode: + case NodeType.Empty: + return Size; + default: + throw new InvalidOperationException(nameof(Node)); + } + } + } + + public void SerializeAsChild(BinaryWriter writer) + { + switch (type) + { + case NodeType.BranchNode: + case NodeType.ExtensionNode: + case NodeType.LeafNode: + var n = NewHash(Hash); + n.Serialize(writer); + break; + case NodeType.HashNode: + case NodeType.Empty: + Serialize(writer); + break; + default: + throw new FormatException(nameof(SerializeAsChild)); + } + } + + private void SerializeWithoutReference(BinaryWriter writer) + { + writer.Write((byte)type); + switch (type) + { + case NodeType.BranchNode: + SerializeBranch(writer); + break; + case NodeType.ExtensionNode: + SerializeExtension(writer); + break; + case NodeType.LeafNode: + SerializeLeaf(writer); + break; + case NodeType.HashNode: + SerializeHash(writer); + break; + case NodeType.Empty: + break; + default: + throw new FormatException(nameof(SerializeWithoutReference)); + } + } + + public void Serialize(BinaryWriter writer) + { + SerializeWithoutReference(writer); + if (type == NodeType.BranchNode || type == NodeType.ExtensionNode || type == NodeType.LeafNode) + writer.WriteVarInt(Reference); + } + + public byte[] ToArrayWithoutReference() + { + using MemoryStream ms = new MemoryStream(); + using BinaryWriter writer = new BinaryWriter(ms, Utility.StrictUTF8, true); + + SerializeWithoutReference(writer); + writer.Flush(); + return ms.ToArray(); + } + + public void Deserialize(ref MemoryReader reader) + { + type = (NodeType)reader.ReadByte(); + switch (type) + { + case NodeType.BranchNode: + DeserializeBranch(ref reader); + Reference = (int)reader.ReadVarInt(); + break; + case NodeType.ExtensionNode: + DeserializeExtension(ref reader); + Reference = (int)reader.ReadVarInt(); + break; + case NodeType.LeafNode: + DeserializeLeaf(ref reader); + Reference = (int)reader.ReadVarInt(); + break; + case NodeType.Empty: + break; + case NodeType.HashNode: + DeserializeHash(ref reader); + break; + default: + throw new FormatException(nameof(Deserialize)); + } + } + + private Node CloneAsChild() + { + switch (type) + { + case NodeType.BranchNode: + case NodeType.ExtensionNode: + case NodeType.LeafNode: + return new Node + { + type = NodeType.HashNode, + hash = Hash, + }; + case NodeType.HashNode: + case NodeType.Empty: + return Clone(); + default: + throw new InvalidOperationException(nameof(Clone)); + } + } + + public Node Clone() + { + switch (type) + { + case NodeType.BranchNode: + var n = new Node + { + type = type, + Reference = Reference, + Children = new Node[BranchChildCount], + }; + for (int i = 0; i < BranchChildCount; i++) + { + n.Children[i] = Children[i].CloneAsChild(); + } + return n; + case NodeType.ExtensionNode: + return new Node + { + type = type, + Key = Key, + Next = Next.CloneAsChild(), + Reference = Reference, + }; + case NodeType.LeafNode: + return new Node + { + type = type, + Value = Value, + Reference = Reference, + }; + case NodeType.HashNode: + case NodeType.Empty: + return this; + default: + throw new InvalidOperationException(nameof(Clone)); + } + } + + public void FromReplica(Node n) + { + MemoryReader reader = new(n.ToArray()); + Deserialize(ref reader); + } + } +} diff --git a/src/Plugins/MPTTrie/Cryptography/MPTTrie/NodeType.cs b/src/Plugins/MPTTrie/Cryptography/MPTTrie/NodeType.cs new file mode 100644 index 0000000000..9c676ff2f7 --- /dev/null +++ b/src/Plugins/MPTTrie/Cryptography/MPTTrie/NodeType.cs @@ -0,0 +1,22 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// NodeType.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.Cryptography.MPTTrie +{ + public enum NodeType : byte + { + BranchNode = 0x00, + ExtensionNode = 0x01, + LeafNode = 0x02, + HashNode = 0x03, + Empty = 0x04 + } +} diff --git a/src/Plugins/MPTTrie/Cryptography/MPTTrie/Trie.Delete.cs b/src/Plugins/MPTTrie/Cryptography/MPTTrie/Trie.Delete.cs new file mode 100644 index 0000000000..2041100a14 --- /dev/null +++ b/src/Plugins/MPTTrie/Cryptography/MPTTrie/Trie.Delete.cs @@ -0,0 +1,136 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Trie.Delete.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 static Neo.Helper; + +namespace Neo.Cryptography.MPTTrie +{ + partial class Trie + { + public bool Delete(byte[] key) + { + var path = ToNibbles(key); + if (path.Length == 0) + throw new ArgumentException("could not be empty", nameof(key)); + if (path.Length > Node.MaxKeyLength) + throw new ArgumentException("exceeds limit", nameof(key)); + return TryDelete(ref root, path); + } + + private bool TryDelete(ref Node node, ReadOnlySpan path) + { + switch (node.Type) + { + case NodeType.LeafNode: + { + if (path.IsEmpty) + { + if (!full) cache.DeleteNode(node.Hash); + node = new Node(); + return true; + } + return false; + } + case NodeType.ExtensionNode: + { + if (path.StartsWith(node.Key.Span)) + { + var oldHash = node.Hash; + var result = TryDelete(ref node.Next, path[node.Key.Length..]); + if (!result) return false; + if (!full) cache.DeleteNode(oldHash); + if (node.Next.IsEmpty) + { + node = node.Next; + return true; + } + if (node.Next.Type == NodeType.ExtensionNode) + { + if (!full) cache.DeleteNode(node.Next.Hash); + node.Key = Concat(node.Key.Span, node.Next.Key.Span); + node.Next = node.Next.Next; + } + node.SetDirty(); + cache.PutNode(node); + return true; + } + return false; + } + case NodeType.BranchNode: + { + bool result; + var oldHash = node.Hash; + if (path.IsEmpty) + { + result = TryDelete(ref node.Children[Node.BranchChildCount - 1], path); + } + else + { + result = TryDelete(ref node.Children[path[0]], path[1..]); + } + if (!result) return false; + if (!full) cache.DeleteNode(oldHash); + List childrenIndexes = new List(Node.BranchChildCount); + for (int i = 0; i < Node.BranchChildCount; i++) + { + if (node.Children[i].IsEmpty) continue; + childrenIndexes.Add((byte)i); + } + if (childrenIndexes.Count > 1) + { + node.SetDirty(); + cache.PutNode(node); + return true; + } + var lastChildIndex = childrenIndexes[0]; + var lastChild = node.Children[lastChildIndex]; + if (lastChildIndex == Node.BranchChildCount - 1) + { + node = lastChild; + return true; + } + if (lastChild.Type == NodeType.HashNode) + { + lastChild = cache.Resolve(lastChild.Hash); + if (lastChild is null) throw new InvalidOperationException("Internal error, can't resolve hash"); + } + if (lastChild.Type == NodeType.ExtensionNode) + { + if (!full) cache.DeleteNode(lastChild.Hash); + lastChild.Key = Concat(childrenIndexes.ToArray(), lastChild.Key.Span); + lastChild.SetDirty(); + cache.PutNode(lastChild); + node = lastChild; + return true; + } + node = Node.NewExtension(childrenIndexes.ToArray(), lastChild); + cache.PutNode(node); + return true; + } + case NodeType.Empty: + { + return false; + } + case NodeType.HashNode: + { + var newNode = cache.Resolve(node.Hash); + if (newNode is null) throw new InvalidOperationException("Internal error, can't resolve hash when mpt delete"); + node = newNode; + return TryDelete(ref node, path); + } + default: + return false; + } + } + } +} diff --git a/src/Plugins/MPTTrie/Cryptography/MPTTrie/Trie.Find.cs b/src/Plugins/MPTTrie/Cryptography/MPTTrie/Trie.Find.cs new file mode 100644 index 0000000000..b3922e8ce8 --- /dev/null +++ b/src/Plugins/MPTTrie/Cryptography/MPTTrie/Trie.Find.cs @@ -0,0 +1,170 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Trie.Find.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.Linq; +using static Neo.Helper; + +namespace Neo.Cryptography.MPTTrie +{ + partial class Trie + { + private ReadOnlySpan Seek(ref Node node, ReadOnlySpan path, out Node start) + { + switch (node.Type) + { + case NodeType.LeafNode: + { + if (path.IsEmpty) + { + start = node; + return ReadOnlySpan.Empty; + } + break; + } + case NodeType.Empty: + break; + case NodeType.HashNode: + { + var newNode = cache.Resolve(node.Hash); + if (newNode is null) throw new InvalidOperationException("Internal error, can't resolve hash when mpt seek"); + node = newNode; + return Seek(ref node, path, out start); + } + case NodeType.BranchNode: + { + if (path.IsEmpty) + { + start = node; + return ReadOnlySpan.Empty; + } + return Concat(path[..1], Seek(ref node.Children[path[0]], path[1..], out start)); + } + case NodeType.ExtensionNode: + { + if (path.IsEmpty) + { + start = node.Next; + return node.Key.Span; + } + if (path.StartsWith(node.Key.Span)) + { + return Concat(node.Key.Span, Seek(ref node.Next, path[node.Key.Length..], out start)); + } + if (node.Key.Span.StartsWith(path)) + { + start = node.Next; + return node.Key.Span; + } + break; + } + } + start = null; + return ReadOnlySpan.Empty; + } + + public IEnumerable<(ReadOnlyMemory Key, ReadOnlyMemory Value)> Find(ReadOnlySpan prefix, byte[] from = null) + { + var path = ToNibbles(prefix); + int offset = 0; + if (from is null) from = Array.Empty(); + if (0 < from.Length) + { + if (!from.AsSpan().StartsWith(prefix)) + throw new InvalidOperationException("invalid from key"); + from = ToNibbles(from.AsSpan()); + } + if (path.Length > Node.MaxKeyLength || from.Length > Node.MaxKeyLength) + throw new ArgumentException("exceeds limit"); + path = Seek(ref root, path, out Node start).ToArray(); + if (from.Length > 0) + { + for (int i = 0; i < from.Length && i < path.Length; i++) + { + if (path[i] < from[i]) return Enumerable.Empty<(ReadOnlyMemory, ReadOnlyMemory)>(); + if (path[i] > from[i]) + { + offset = from.Length; + break; + } + } + if (offset == 0) + { + offset = Math.Min(path.Length, from.Length); + } + } + return Travers(start, path, from, offset).Select(p => (new ReadOnlyMemory(FromNibbles(p.Key.Span)), p.Value)); + } + + private IEnumerable<(ReadOnlyMemory Key, ReadOnlyMemory Value)> Travers(Node node, byte[] path, byte[] from, int offset) + { + if (node is null) yield break; + if (offset < 0) throw new InvalidOperationException("invalid offset"); + switch (node.Type) + { + case NodeType.LeafNode: + { + if (from.Length <= offset && !path.SequenceEqual(from)) + yield return (path, node.Value); + break; + } + case NodeType.Empty: + break; + case NodeType.HashNode: + { + var newNode = cache.Resolve(node.Hash); + if (newNode is null) throw new InvalidOperationException("Internal error, can't resolve hash when mpt find"); + node = newNode; + foreach (var item in Travers(node, path, from, offset)) + yield return item; + break; + } + case NodeType.BranchNode: + { + if (offset < from.Length) + { + 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)) + 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)) + yield return item; + } + } + else + { + foreach (var item in Travers(node.Children[Node.BranchChildCount - 1], path, from, offset)) + 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)) + yield return item; + } + } + break; + } + 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)) + 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)) + yield return item; + break; + } + } + } + } +} diff --git a/src/Plugins/MPTTrie/Cryptography/MPTTrie/Trie.Get.cs b/src/Plugins/MPTTrie/Cryptography/MPTTrie/Trie.Get.cs new file mode 100644 index 0000000000..da69407ac3 --- /dev/null +++ b/src/Plugins/MPTTrie/Cryptography/MPTTrie/Trie.Get.cs @@ -0,0 +1,90 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Trie.Get.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; + +namespace Neo.Cryptography.MPTTrie +{ + partial class Trie + { + public byte[] this[byte[] key] + { + get + { + var path = ToNibbles(key); + if (path.Length == 0) + throw new ArgumentException("could not be empty", nameof(key)); + if (path.Length > Node.MaxKeyLength) + throw new ArgumentException("exceeds limit", nameof(key)); + var result = TryGet(ref root, path, out var value); + return result ? value.ToArray() : throw new KeyNotFoundException(); + } + } + + public bool TryGetValue(byte[] key, out byte[] value) + { + value = default; + var path = ToNibbles(key); + if (path.Length == 0) + throw new ArgumentException("could not be empty", nameof(key)); + if (path.Length > Node.MaxKeyLength) + throw new ArgumentException("exceeds limit", nameof(key)); + var result = TryGet(ref root, path, out var val); + if (result) + value = val.ToArray(); + return result; + } + + private bool TryGet(ref Node node, ReadOnlySpan path, out ReadOnlySpan value) + { + switch (node.Type) + { + case NodeType.LeafNode: + { + if (path.IsEmpty) + { + value = node.Value.Span; + return true; + } + break; + } + case NodeType.Empty: + break; + case NodeType.HashNode: + { + var newNode = cache.Resolve(node.Hash); + if (newNode is null) throw new InvalidOperationException("Internal error, can't resolve hash when mpt get"); + node = newNode; + return TryGet(ref node, path, out value); + } + case NodeType.BranchNode: + { + if (path.IsEmpty) + { + return TryGet(ref node.Children[Node.BranchChildCount - 1], path, out value); + } + return TryGet(ref node.Children[path[0]], path[1..], out value); + } + case NodeType.ExtensionNode: + { + if (path.StartsWith(node.Key.Span)) + { + return TryGet(ref node.Next, path[node.Key.Length..], out value); + } + break; + } + } + value = default; + return false; + } + } +} diff --git a/src/Plugins/MPTTrie/Cryptography/MPTTrie/Trie.Proof.cs b/src/Plugins/MPTTrie/Cryptography/MPTTrie/Trie.Proof.cs new file mode 100644 index 0000000000..e0925452e3 --- /dev/null +++ b/src/Plugins/MPTTrie/Cryptography/MPTTrie/Trie.Proof.cs @@ -0,0 +1,95 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Trie.Proof.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.IO; +using Neo.Persistence; +using System; +using System.Collections.Generic; +using static Neo.Helper; + +namespace Neo.Cryptography.MPTTrie +{ + partial class Trie + { + public bool TryGetProof(byte[] key, out HashSet proof) + { + var path = ToNibbles(key); + if (path.Length == 0) + throw new ArgumentException("could not be empty", nameof(key)); + if (path.Length > Node.MaxKeyLength) + throw new ArgumentException("exceeds limit", nameof(key)); + proof = new HashSet(ByteArrayEqualityComparer.Default); + return GetProof(ref root, path, proof); + } + + private bool GetProof(ref Node node, ReadOnlySpan path, HashSet set) + { + switch (node.Type) + { + case NodeType.LeafNode: + { + if (path.IsEmpty) + { + set.Add(node.ToArrayWithoutReference()); + return true; + } + break; + } + case NodeType.Empty: + break; + case NodeType.HashNode: + { + var newNode = cache.Resolve(node.Hash); + if (newNode is null) throw new InvalidOperationException("Internal error, can't resolve hash when mpt getproof"); + node = newNode; + return GetProof(ref node, path, set); + } + case NodeType.BranchNode: + { + set.Add(node.ToArrayWithoutReference()); + if (path.IsEmpty) + { + return GetProof(ref node.Children[Node.BranchChildCount - 1], path, set); + } + return GetProof(ref node.Children[path[0]], path[1..], set); + } + case NodeType.ExtensionNode: + { + if (path.StartsWith(node.Key.Span)) + { + set.Add(node.ToArrayWithoutReference()); + return GetProof(ref node.Next, path[node.Key.Length..], set); + } + break; + } + } + return false; + } + + private static byte[] Key(byte[] hash) + { + byte[] buffer = new byte[hash.Length + 1]; + buffer[0] = Prefix; + Buffer.BlockCopy(hash, 0, buffer, 1, hash.Length); + return buffer; + } + + 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 })); + using ISnapshot snapshot = memoryStore.GetSnapshot(); + var trie = new Trie(snapshot, root, false); + return trie[key]; + } + } +} diff --git a/src/Plugins/MPTTrie/Cryptography/MPTTrie/Trie.Put.cs b/src/Plugins/MPTTrie/Cryptography/MPTTrie/Trie.Put.cs new file mode 100644 index 0000000000..5de6f3fc85 --- /dev/null +++ b/src/Plugins/MPTTrie/Cryptography/MPTTrie/Trie.Put.cs @@ -0,0 +1,159 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Trie.Put.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; + +namespace Neo.Cryptography.MPTTrie +{ + partial class Trie + { + private static ReadOnlySpan CommonPrefix(ReadOnlySpan a, ReadOnlySpan b) + { + var minLen = a.Length <= b.Length ? a.Length : b.Length; + int i = 0; + if (a.Length != 0 && b.Length != 0) + { + for (i = 0; i < minLen; i++) + { + if (a[i] != b[i]) break; + } + } + return a[..i]; + } + + public void Put(byte[] key, byte[] value) + { + var path = ToNibbles(key); + var val = value; + if (path.Length == 0 || path.Length > Node.MaxKeyLength) + throw new ArgumentException("invalid", nameof(key)); + if (val.Length > Node.MaxValueLength) + throw new ArgumentException("exceed limit", nameof(value)); + var n = Node.NewLeaf(val); + Put(ref root, path, n); + } + + private void Put(ref Node node, ReadOnlySpan path, Node val) + { + switch (node.Type) + { + case NodeType.LeafNode: + { + if (path.IsEmpty) + { + if (!full) cache.DeleteNode(node.Hash); + node = val; + cache.PutNode(node); + return; + } + var branch = Node.NewBranch(); + branch.Children[Node.BranchChildCount - 1] = node; + Put(ref branch.Children[path[0]], path[1..], val); + cache.PutNode(branch); + node = branch; + break; + } + case NodeType.ExtensionNode: + { + if (path.StartsWith(node.Key.Span)) + { + var oldHash = node.Hash; + Put(ref node.Next, path[node.Key.Length..], val); + if (!full) cache.DeleteNode(oldHash); + node.SetDirty(); + cache.PutNode(node); + return; + } + if (!full) cache.DeleteNode(node.Hash); + var prefix = CommonPrefix(node.Key.Span, path); + var pathRemain = path[prefix.Length..]; + var keyRemain = node.Key.Span[prefix.Length..]; + var child = Node.NewBranch(); + Node grandChild = new Node(); + if (keyRemain.Length == 1) + { + child.Children[keyRemain[0]] = node.Next; + } + else + { + var exNode = Node.NewExtension(keyRemain[1..].ToArray(), node.Next); + cache.PutNode(exNode); + child.Children[keyRemain[0]] = exNode; + } + if (pathRemain.IsEmpty) + { + Put(ref grandChild, pathRemain, val); + child.Children[Node.BranchChildCount - 1] = grandChild; + } + else + { + Put(ref grandChild, pathRemain[1..], val); + child.Children[pathRemain[0]] = grandChild; + } + cache.PutNode(child); + if (prefix.Length > 0) + { + var exNode = Node.NewExtension(prefix.ToArray(), child); + cache.PutNode(exNode); + node = exNode; + } + else + { + node = child; + } + break; + } + case NodeType.BranchNode: + { + var oldHash = node.Hash; + if (path.IsEmpty) + { + Put(ref node.Children[Node.BranchChildCount - 1], path, val); + } + else + { + Put(ref node.Children[path[0]], path[1..], val); + } + if (!full) cache.DeleteNode(oldHash); + node.SetDirty(); + cache.PutNode(node); + break; + } + case NodeType.Empty: + { + Node newNode; + if (path.IsEmpty) + { + newNode = val; + } + else + { + newNode = Node.NewExtension(path.ToArray(), val); + cache.PutNode(newNode); + } + node = newNode; + if (val.Type == NodeType.LeafNode) cache.PutNode(val); + break; + } + case NodeType.HashNode: + { + Node newNode = cache.Resolve(node.Hash); + if (newNode is null) throw new InvalidOperationException("Internal error, can't resolve hash when mpt put"); + node = newNode; + Put(ref node, path, val); + break; + } + default: + throw new InvalidOperationException("unsupport node type"); + } + } + } +} diff --git a/src/Plugins/MPTTrie/Cryptography/MPTTrie/Trie.cs b/src/Plugins/MPTTrie/Cryptography/MPTTrie/Trie.cs new file mode 100644 index 0000000000..19ef1c8b4c --- /dev/null +++ b/src/Plugins/MPTTrie/Cryptography/MPTTrie/Trie.cs @@ -0,0 +1,62 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Trie.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 System; + +namespace Neo.Cryptography.MPTTrie +{ + public partial class Trie + { + private const byte Prefix = 0xf0; + private readonly bool full; + private readonly ISnapshot store; + private Node root; + private readonly Cache cache; + public Node Root => root; + + public Trie(ISnapshot store, UInt256 root, bool full_state = false) + { + this.store = store ?? throw new ArgumentNullException(nameof(store)); + cache = new Cache(store, Prefix); + this.root = root is null ? new Node() : Node.NewHash(root); + full = full_state; + } + + private static byte[] ToNibbles(ReadOnlySpan path) + { + var result = new byte[path.Length * 2]; + for (int i = 0; i < path.Length; i++) + { + result[i * 2] = (byte)(path[i] >> 4); + result[i * 2 + 1] = (byte)(path[i] & 0x0F); + } + return result; + } + + private static byte[] FromNibbles(ReadOnlySpan path) + { + if (path.Length % 2 != 0) throw new FormatException($"MPTTrie.FromNibbles invalid path."); + var key = new byte[path.Length / 2]; + for (int i = 0; i < key.Length; i++) + { + key[i] = (byte)(path[i * 2] << 4); + key[i] |= path[i * 2 + 1]; + } + return key; + } + + public void Commit() + { + cache.Commit(); + } + } +} diff --git a/src/Plugins/MPTTrie/IO/ByteArrayEqualityComparer.cs b/src/Plugins/MPTTrie/IO/ByteArrayEqualityComparer.cs new file mode 100644 index 0000000000..590306d560 --- /dev/null +++ b/src/Plugins/MPTTrie/IO/ByteArrayEqualityComparer.cs @@ -0,0 +1,58 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// ByteArrayEqualityComparer.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.Collections.Generic; + +namespace Neo.IO +{ + public class ByteArrayEqualityComparer : IEqualityComparer + { + public static readonly ByteArrayEqualityComparer Default = new ByteArrayEqualityComparer(); + + public unsafe bool Equals(byte[] x, byte[] y) + { + if (ReferenceEquals(x, y)) return true; + if (x is null || y is null) return false; + int len = x.Length; + if (len != y.Length) return false; + if (len == 0) return true; + fixed (byte* xp = x, yp = y) + { + long* xlp = (long*)xp, ylp = (long*)yp; + for (; len >= 8; len -= 8) + { + if (*xlp != *ylp) return false; + xlp++; + ylp++; + } + byte* xbp = (byte*)xlp, ybp = (byte*)ylp; + for (; len > 0; len--) + { + if (*xbp != *ybp) return false; + xbp++; + ybp++; + } + } + return true; + } + + public int GetHashCode(byte[] obj) + { + unchecked + { + int hash = 17; + foreach (byte element in obj) + hash = hash * 31 + element; + return hash; + } + } + } +} diff --git a/src/Plugins/MPTTrie/MPTTrie.csproj b/src/Plugins/MPTTrie/MPTTrie.csproj new file mode 100644 index 0000000000..a2c3377a16 --- /dev/null +++ b/src/Plugins/MPTTrie/MPTTrie.csproj @@ -0,0 +1,10 @@ + + + + net8.0 + Neo.Cryptography.MPT + Neo.Cryptography + true + + + diff --git a/src/Plugins/OracleService/Helper.cs b/src/Plugins/OracleService/Helper.cs new file mode 100644 index 0000000000..35611e8698 --- /dev/null +++ b/src/Plugins/OracleService/Helper.cs @@ -0,0 +1,52 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Helper.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.Linq; +using System.Net; + +namespace Neo.Plugins +{ + static class Helper + { + public static bool IsInternal(this IPHostEntry entry) + { + return entry.AddressList.Any(p => IsInternal(p)); + } + + /// + /// ::1 - IPv6 loopback + /// 10.0.0.0 - 10.255.255.255 (10/8 prefix) + /// 127.0.0.0 - 127.255.255.255 (127/8 prefix) + /// 172.16.0.0 - 172.31.255.255 (172.16/12 prefix) + /// 192.168.0.0 - 192.168.255.255 (192.168/16 prefix) + /// + /// Address + /// True if it was an internal address + public static bool IsInternal(this IPAddress ipAddress) + { + if (IPAddress.IsLoopback(ipAddress)) return true; + if (IPAddress.Broadcast.Equals(ipAddress)) return true; + if (IPAddress.Any.Equals(ipAddress)) return true; + if (IPAddress.IPv6Any.Equals(ipAddress)) return true; + if (IPAddress.IPv6Loopback.Equals(ipAddress)) return true; + + var ip = ipAddress.GetAddressBytes(); + switch (ip[0]) + { + case 10: + case 127: return true; + case 172: return ip[1] >= 16 && ip[1] < 32; + case 192: return ip[1] == 168; + default: return false; + } + } + } +} diff --git a/src/Plugins/OracleService/OracleService.cs b/src/Plugins/OracleService/OracleService.cs new file mode 100644 index 0000000000..bdbbc5869e --- /dev/null +++ b/src/Plugins/OracleService/OracleService.cs @@ -0,0 +1,584 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// OracleService.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 Akka.Util.Internal; +using Neo.ConsoleService; +using Neo.Cryptography; +using Neo.Cryptography.ECC; +using Neo.IO; +using Neo.Json; +using Neo.Ledger; +using Neo.Network.P2P; +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 System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Net.Http; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace Neo.Plugins +{ + public class OracleService : Plugin + { + private const int RefreshIntervalMilliSeconds = 1000 * 60 * 3; + + private static readonly HttpClient httpClient = new() + { + Timeout = TimeSpan.FromSeconds(5), + MaxResponseContentBufferSize = ushort.MaxValue + }; + + private Wallet wallet; + private readonly ConcurrentDictionary pendingQueue = new ConcurrentDictionary(); + private readonly ConcurrentDictionary finishedCache = new ConcurrentDictionary(); + private Timer timer; + private readonly CancellationTokenSource cancelSource = new CancellationTokenSource(); + private OracleStatus status = OracleStatus.Unstarted; + private IWalletProvider walletProvider; + private int counter; + private NeoSystem System; + + private readonly Dictionary protocols = new Dictionary(); + + public override string Description => "Built-in oracle plugin"; + + public OracleService() + { + Blockchain.Committing += OnCommitting; + } + + protected override void Configure() + { + Settings.Load(GetConfiguration()); + foreach (var (_, p) in protocols) + p.Configure(); + } + + protected override void OnSystemLoaded(NeoSystem system) + { + if (system.Settings.Network != Settings.Default.Network) return; + System = system; + System.ServiceAdded += NeoSystem_ServiceAdded; + RpcServerPlugin.RegisterMethods(this, Settings.Default.Network); + } + + private void NeoSystem_ServiceAdded(object sender, object service) + { + if (service is IWalletProvider) + { + walletProvider = service as IWalletProvider; + System.ServiceAdded -= NeoSystem_ServiceAdded; + if (Settings.Default.AutoStart) + { + walletProvider.WalletChanged += WalletProvider_WalletChanged; + } + } + } + + private void WalletProvider_WalletChanged(object sender, Wallet wallet) + { + walletProvider.WalletChanged -= WalletProvider_WalletChanged; + Start(wallet); + } + + public override void Dispose() + { + Blockchain.Committing -= OnCommitting; + OnStop(); + while (status != OracleStatus.Stopped) + Thread.Sleep(100); + foreach (var p in protocols) + p.Value.Dispose(); + } + + [ConsoleCommand("start oracle", Category = "Oracle", Description = "Start oracle service")] + private void OnStart() + { + Start(walletProvider?.GetWallet()); + } + + public void Start(Wallet wallet) + { + if (status == OracleStatus.Running) return; + + if (wallet is null) + { + ConsoleHelper.Warning("Please open wallet first!"); + return; + } + if (!CheckOracleAvaiblable(System.StoreView, out ECPoint[] oracles)) + { + ConsoleHelper.Warning("The oracle service is unavailable"); + return; + } + if (!CheckOracleAccount(wallet, oracles)) + { + ConsoleHelper.Warning("There is no oracle account in wallet"); + return; + } + + this.wallet = wallet; + protocols["https"] = new OracleHttpsProtocol(); + protocols["neofs"] = new OracleNeoFSProtocol(wallet, oracles); + status = OracleStatus.Running; + timer = new Timer(OnTimer, null, RefreshIntervalMilliSeconds, Timeout.Infinite); + ConsoleHelper.Info($"Oracle started"); + ProcessRequestsAsync(); + } + + [ConsoleCommand("stop oracle", Category = "Oracle", Description = "Stop oracle service")] + private void OnStop() + { + cancelSource.Cancel(); + if (timer != null) + { + timer.Dispose(); + timer = null; + } + status = OracleStatus.Stopped; + } + + [ConsoleCommand("oracle status", Category = "Oracle", Description = "Show oracle status")] + private void OnShow() + { + ConsoleHelper.Info($"Oracle status: ", $"{status}"); + } + + private void OnCommitting(NeoSystem system, Block block, DataCache snapshot, IReadOnlyList applicationExecutedList) + { + if (system.Settings.Network != Settings.Default.Network) return; + + if (Settings.Default.AutoStart && status == OracleStatus.Unstarted) + { + OnStart(); + } + if (status != OracleStatus.Running) return; + if (!CheckOracleAvaiblable(snapshot, out ECPoint[] oracles) || !CheckOracleAccount(wallet, oracles)) + OnStop(); + } + + private async void OnTimer(object state) + { + try + { + List outOfDate = new(); + List tasks = new(); + foreach (var (id, task) in pendingQueue) + { + var span = TimeProvider.Current.UtcNow - task.Timestamp; + if (span > Settings.Default.MaxTaskTimeout) + { + outOfDate.Add(id); + continue; + } + + if (span > TimeSpan.FromMilliseconds(RefreshIntervalMilliSeconds)) + { + foreach (var account in wallet.GetAccounts()) + if (task.BackupSigns.TryGetValue(account.GetKey().PublicKey, out byte[] sign)) + tasks.Add(SendResponseSignatureAsync(id, sign, account.GetKey())); + } + } + + await Task.WhenAll(tasks); + + foreach (ulong requestId in outOfDate) + pendingQueue.TryRemove(requestId, out _); + foreach (var (key, value) in finishedCache) + if (TimeProvider.Current.UtcNow - value > TimeSpan.FromDays(3)) + finishedCache.TryRemove(key, out _); + } + catch (Exception e) + { + Log(e, LogLevel.Error); + } + finally + { + if (!cancelSource.IsCancellationRequested) + timer?.Change(RefreshIntervalMilliSeconds, Timeout.Infinite); + } + } + + [RpcMethod] + public JObject SubmitOracleResponse(JArray _params) + { + status.Equals(OracleStatus.Running).True_Or(RpcError.OracleDisabled); + ECPoint oraclePub = ECPoint.DecodePoint(Convert.FromBase64String(_params[0].AsString()), ECCurve.Secp256r1); + ulong requestId = Result.Ok_Or(() => (ulong)_params[1].AsNumber(), RpcError.InvalidParams.WithData($"Invalid requestId: {_params[1]}")); + byte[] txSign = Result.Ok_Or(() => Convert.FromBase64String(_params[2].AsString()), RpcError.InvalidParams.WithData($"Invalid txSign: {_params[2]}")); + byte[] msgSign = Result.Ok_Or(() => Convert.FromBase64String(_params[3].AsString()), RpcError.InvalidParams.WithData($"Invalid msgSign: {_params[3]}")); + + finishedCache.ContainsKey(requestId).False_Or(RpcError.OracleRequestFinished); + + using (var snapshot = System.GetSnapshot()) + { + uint height = NativeContract.Ledger.CurrentIndex(snapshot) + 1; + 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); + Crypto.VerifySignature(data, msgSign, oraclePub).True_Or(RpcErrorFactory.InvalidSignature($"Invalid oracle response transaction signature from '{oraclePub}'.")); + AddResponseTxSign(snapshot, requestId, oraclePub, txSign); + } + return new JObject(); + } + + private static async Task SendContentAsync(Uri url, string content) + { + try + { + using HttpResponseMessage response = await httpClient.PostAsync(url, new StringContent(content, Encoding.UTF8, "application/json")); + response.EnsureSuccessStatusCode(); + } + catch (Exception e) + { + Log($"Failed to send the response signature to {url}, as {e.Message}", LogLevel.Warning); + } + } + + private async Task SendResponseSignatureAsync(ulong requestId, byte[] txSign, KeyPair keyPair) + { + var message = Neo.Helper.Concat(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 + "]}"; + + var tasks = Settings.Default.Nodes.Select(p => SendContentAsync(p, content)); + await Task.WhenAll(tasks); + } + + private async Task ProcessRequestAsync(DataCache snapshot, OracleRequest req) + { + Log($"[{req.OriginalTxid}] Process oracle request start:<{req.Url}>"); + + uint height = NativeContract.Ledger.CurrentIndex(snapshot) + 1; + + (OracleResponseCode code, string data) = await ProcessUrlAsync(req.Url); + + Log($"[{req.OriginalTxid}] Process oracle request end:<{req.Url}>, responseCode:{code}, response:{data}"); + + var oracleNodes = NativeContract.RoleManagement.GetDesignatedByRole(snapshot, Role.Oracle, height); + foreach (var (requestId, request) in NativeContract.Oracle.GetRequestsByUrl(snapshot, req.Url)) + { + var result = Array.Empty(); + if (code == OracleResponseCode.Success) + { + try + { + result = Filter(data, request.Filter); + } + catch (Exception ex) + { + code = OracleResponseCode.Error; + Log($"[{req.OriginalTxid}] Filter '{request.Filter}' error:{ex.Message}"); + } + } + var response = new OracleResponse() { Id = requestId, Code = code, Result = result }; + var responseTx = CreateResponseTx(snapshot, request, response, oracleNodes, System.Settings); + var backupTx = CreateResponseTx(snapshot, request, new OracleResponse() { Code = OracleResponseCode.ConsensusUnreachable, Id = requestId, Result = Array.Empty() }, oracleNodes, System.Settings, true); + + Log($"[{req.OriginalTxid}]-({requestId}) Built response tx[[{responseTx.Hash}]], responseCode:{code}, result:{result.ToHexString()}, validUntilBlock:{responseTx.ValidUntilBlock}, backupTx:{backupTx.Hash}-{backupTx.ValidUntilBlock}"); + + List tasks = new List(); + ECPoint[] oraclePublicKeys = NativeContract.RoleManagement.GetDesignatedByRole(snapshot, Role.Oracle, height); + foreach (var account in wallet.GetAccounts()) + { + var oraclePub = account.GetKey()?.PublicKey; + if (!account.HasKey || account.Lock || !oraclePublicKeys.Contains(oraclePub)) continue; + + var txSign = responseTx.Sign(account.GetKey(), System.Settings.Network); + var backTxSign = backupTx.Sign(account.GetKey(), System.Settings.Network); + AddResponseTxSign(snapshot, requestId, oraclePub, txSign, responseTx, backupTx, backTxSign); + tasks.Add(SendResponseSignatureAsync(requestId, txSign, account.GetKey())); + + Log($"[{request.OriginalTxid}]-[[{responseTx.Hash}]] Send oracle sign data, Oracle node: {oraclePub}, Sign: {txSign.ToHexString()}"); + } + await Task.WhenAll(tasks); + } + } + + private async void ProcessRequestsAsync() + { + while (!cancelSource.IsCancellationRequested) + { + using (var snapshot = System.GetSnapshot()) + { + SyncPendingQueue(snapshot); + foreach (var (id, request) in NativeContract.Oracle.GetRequests(snapshot)) + { + if (cancelSource.IsCancellationRequested) break; + if (!finishedCache.ContainsKey(id) && (!pendingQueue.TryGetValue(id, out OracleTask task) || task.Tx is null)) + await ProcessRequestAsync(snapshot, request); + } + } + if (cancelSource.IsCancellationRequested) break; + await Task.Delay(500); + } + + status = OracleStatus.Stopped; + } + + + private void SyncPendingQueue(DataCache snapshot) + { + var offChainRequests = NativeContract.Oracle.GetRequests(snapshot).ToDictionary(r => r.Item1, r => r.Item2); + var onChainRequests = pendingQueue.Keys.Except(offChainRequests.Keys); + foreach (var onChainRequest in onChainRequests) + { + pendingQueue.TryRemove(onChainRequest, out _); + } + } + + private async Task<(OracleResponseCode, string)> ProcessUrlAsync(string url) + { + if (!Uri.TryCreate(url, UriKind.Absolute, out var uri)) + return (OracleResponseCode.Error, $"Invalid url:<{url}>"); + if (!protocols.TryGetValue(uri.Scheme, out IOracleProtocol protocol)) + return (OracleResponseCode.ProtocolNotSupported, $"Invalid Protocol:<{url}>"); + + using CancellationTokenSource ctsTimeout = new(Settings.Default.MaxOracleTimeout); + using CancellationTokenSource ctsLinked = CancellationTokenSource.CreateLinkedTokenSource(cancelSource.Token, ctsTimeout.Token); + + try + { + return await protocol.ProcessAsync(uri, ctsLinked.Token); + } + catch (Exception ex) + { + return (OracleResponseCode.Error, $"Request <{url}> Error:{ex.Message}"); + } + } + + public static Transaction CreateResponseTx(DataCache snapshot, OracleRequest request, OracleResponse response, ECPoint[] oracleNodes, ProtocolSettings settings, bool useCurrentHeight = false) + { + var requestTx = NativeContract.Ledger.GetTransactionState(snapshot, request.OriginalTxid); + var n = oracleNodes.Length; + var m = n - (n - 1) / 3; + var oracleSignContract = Contract.CreateMultiSigContract(m, oracleNodes); + uint height = NativeContract.Ledger.CurrentIndex(snapshot); + var validUntilBlock = requestTx.BlockIndex + settings.MaxValidUntilBlockIncrement; + while (useCurrentHeight && validUntilBlock <= height) + { + validUntilBlock += settings.MaxValidUntilBlockIncrement; + } + var tx = new Transaction() + { + Version = 0, + Nonce = unchecked((uint)response.Id), + ValidUntilBlock = validUntilBlock, + Signers = new[] + { + new Signer + { + Account = NativeContract.Oracle.Hash, + Scopes = WitnessScope.None + }, + new Signer + { + Account = oracleSignContract.ScriptHash, + Scopes = WitnessScope.None + } + }, + Attributes = new[] { response }, + Script = OracleResponse.FixedScript, + Witnesses = new Witness[2] + }; + Dictionary witnessDict = new Dictionary + { + [oracleSignContract.ScriptHash] = new Witness + { + InvocationScript = Array.Empty(), + VerificationScript = oracleSignContract.Script, + }, + [NativeContract.Oracle.Hash] = new Witness + { + InvocationScript = Array.Empty(), + VerificationScript = Array.Empty(), + } + }; + + UInt160[] hashes = tx.GetScriptHashesForVerifying(snapshot); + tx.Witnesses[0] = witnessDict[hashes[0]]; + tx.Witnesses[1] = witnessDict[hashes[1]]; + + // Calculate network fee + + var oracleContract = NativeContract.ContractManagement.GetContract(snapshot, NativeContract.Oracle.Hash); + var engine = ApplicationEngine.Create(TriggerType.Verification, tx, snapshot.CreateSnapshot(), settings: settings); + ContractMethodDescriptor md = oracleContract.Manifest.Abi.GetMethod("verify", -1); + engine.LoadContract(oracleContract, md, CallFlags.None); + if (engine.Execute() != VMState.HALT) return null; + tx.NetworkFee += engine.GasConsumed; + + var executionFactor = NativeContract.Policy.GetExecFeeFactor(snapshot); + var networkFee = executionFactor * SmartContract.Helper.MultiSignatureContractCost(m, n); + tx.NetworkFee += networkFee; + + // Base size for transaction: includes const_header + signers + script + hashes + witnesses, except attributes + + int size_inv = 66 * m; + int size = Transaction.HeaderSize + tx.Signers.GetVarSize() + tx.Script.GetVarSize() + + IO.Helper.GetVarSize(hashes.Length) + witnessDict[NativeContract.Oracle.Hash].Size + + IO.Helper.GetVarSize(size_inv) + size_inv + oracleSignContract.Script.GetVarSize(); + + var feePerByte = NativeContract.Policy.GetFeePerByte(snapshot); + if (response.Result.Length > OracleResponse.MaxResultSize) + { + response.Code = OracleResponseCode.ResponseTooLarge; + response.Result = Array.Empty(); + } + else if (tx.NetworkFee + (size + tx.Attributes.GetVarSize()) * feePerByte > request.GasForResponse) + { + response.Code = OracleResponseCode.InsufficientFunds; + response.Result = Array.Empty(); + } + size += tx.Attributes.GetVarSize(); + tx.NetworkFee += size * feePerByte; + + // Calcualte system fee + + tx.SystemFee = request.GasForResponse - tx.NetworkFee; + + return tx; + } + + private void AddResponseTxSign(DataCache snapshot, ulong requestId, ECPoint oraclePub, byte[] sign, Transaction responseTx = null, Transaction backupTx = null, byte[] backupSign = null) + { + var task = pendingQueue.GetOrAdd(requestId, _ => new OracleTask + { + Id = requestId, + Request = NativeContract.Oracle.GetRequest(snapshot, requestId), + Signs = new ConcurrentDictionary(), + BackupSigns = new ConcurrentDictionary() + }); + + if (responseTx != null) + { + task.Tx = responseTx; + var data = task.Tx.GetSignData(System.Settings.Network); + task.Signs.Where(p => !Crypto.VerifySignature(data, p.Value, p.Key)).ForEach(p => task.Signs.Remove(p.Key, out _)); + } + if (backupTx != null) + { + task.BackupTx = backupTx; + var data = task.BackupTx.GetSignData(System.Settings.Network); + task.BackupSigns.Where(p => !Crypto.VerifySignature(data, p.Value, p.Key)).ForEach(p => task.BackupSigns.Remove(p.Key, out _)); + task.BackupSigns.TryAdd(oraclePub, backupSign); + } + if (task.Tx == null) + { + task.Signs.TryAdd(oraclePub, sign); + task.BackupSigns.TryAdd(oraclePub, sign); + return; + } + + if (Crypto.VerifySignature(task.Tx.GetSignData(System.Settings.Network), sign, oraclePub)) + task.Signs.TryAdd(oraclePub, sign); + else if (Crypto.VerifySignature(task.BackupTx.GetSignData(System.Settings.Network), sign, oraclePub)) + task.BackupSigns.TryAdd(oraclePub, sign); + else + throw new RpcException(RpcErrorFactory.InvalidSignature($"Invalid oracle response transaction signature from '{oraclePub}'.")); + + if (CheckTxSign(snapshot, task.Tx, task.Signs) || CheckTxSign(snapshot, task.BackupTx, task.BackupSigns)) + { + finishedCache.TryAdd(requestId, new DateTime()); + pendingQueue.TryRemove(requestId, out _); + } + } + + public static byte[] Filter(string input, string filterArgs) + { + if (string.IsNullOrEmpty(filterArgs)) + return Utility.StrictUTF8.GetBytes(input); + + JToken beforeObject = JToken.Parse(input); + JArray afterObjects = beforeObject.JsonPath(filterArgs); + return afterObjects.ToByteArray(false); + } + + private bool CheckTxSign(DataCache snapshot, Transaction tx, ConcurrentDictionary OracleSigns) + { + uint height = NativeContract.Ledger.CurrentIndex(snapshot) + 1; + if (tx.ValidUntilBlock <= height) + { + return false; + } + ECPoint[] oraclesNodes = NativeContract.RoleManagement.GetDesignatedByRole(snapshot, Role.Oracle, height); + int neededThreshold = oraclesNodes.Length - (oraclesNodes.Length - 1) / 3; + if (OracleSigns.Count >= neededThreshold && tx != null) + { + var contract = Contract.CreateMultiSigContract(neededThreshold, oraclesNodes); + ScriptBuilder sb = new ScriptBuilder(); + foreach (var (_, sign) in OracleSigns.OrderBy(p => p.Key)) + { + sb.EmitPush(sign); + if (--neededThreshold == 0) break; + } + var idx = tx.GetScriptHashesForVerifying(snapshot)[0] == contract.ScriptHash ? 0 : 1; + tx.Witnesses[idx].InvocationScript = sb.ToArray(); + + Log($"Send response tx: responseTx={tx.Hash}"); + + System.Blockchain.Tell(tx); + return true; + } + return false; + } + + private static bool CheckOracleAvaiblable(DataCache snapshot, out ECPoint[] oracles) + { + uint height = NativeContract.Ledger.CurrentIndex(snapshot) + 1; + oracles = NativeContract.RoleManagement.GetDesignatedByRole(snapshot, Role.Oracle, height); + return oracles.Length > 0; + } + + private static bool CheckOracleAccount(Wallet wallet, ECPoint[] oracles) + { + if (wallet is null) return false; + return oracles + .Select(p => wallet.GetAccount(p)) + .Any(p => p is not null && p.HasKey && !p.Lock); + } + + private static void Log(string message, LogLevel level = LogLevel.Info) + { + Utility.Log(nameof(OracleService), level, message); + } + + class OracleTask + { + public ulong Id; + public OracleRequest Request; + public Transaction Tx; + public Transaction BackupTx; + public ConcurrentDictionary Signs; + public ConcurrentDictionary BackupSigns; + public readonly DateTime Timestamp = TimeProvider.Current.UtcNow; + } + + enum OracleStatus + { + Unstarted, + Running, + Stopped, + } + } +} diff --git a/src/Plugins/OracleService/OracleService.csproj b/src/Plugins/OracleService/OracleService.csproj new file mode 100644 index 0000000000..a5df44e75c --- /dev/null +++ b/src/Plugins/OracleService/OracleService.csproj @@ -0,0 +1,20 @@ + + + + net8.0 + Neo.Plugins.OracleService + + + + + + + + + + false + runtime + + + + \ No newline at end of file diff --git a/src/Plugins/OracleService/Protocols/IOracleProtocol.cs b/src/Plugins/OracleService/Protocols/IOracleProtocol.cs new file mode 100644 index 0000000000..3532a69454 --- /dev/null +++ b/src/Plugins/OracleService/Protocols/IOracleProtocol.cs @@ -0,0 +1,24 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// IOracleProtocol.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.Payloads; +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace Neo.Plugins +{ + interface IOracleProtocol : IDisposable + { + void Configure(); + Task<(OracleResponseCode, string)> ProcessAsync(Uri uri, CancellationToken cancellation); + } +} diff --git a/src/Plugins/OracleService/Protocols/OracleHttpsProtocol.cs b/src/Plugins/OracleService/Protocols/OracleHttpsProtocol.cs new file mode 100644 index 0000000000..29d3eedc43 --- /dev/null +++ b/src/Plugins/OracleService/Protocols/OracleHttpsProtocol.cs @@ -0,0 +1,115 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// OracleHttpsProtocol.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.Payloads; +using System; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Reflection; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace Neo.Plugins +{ + class OracleHttpsProtocol : IOracleProtocol + { + private readonly HttpClient client = new(new HttpClientHandler() { AllowAutoRedirect = false }); + + public OracleHttpsProtocol() + { + CustomAttributeData attribute = Assembly.GetExecutingAssembly().CustomAttributes.First(p => p.AttributeType == typeof(AssemblyInformationalVersionAttribute)); + string version = (string)attribute.ConstructorArguments[0].Value; + client.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue("NeoOracleService", version)); + } + + public void Configure() + { + client.DefaultRequestHeaders.Accept.Clear(); + foreach (string type in Settings.Default.AllowedContentTypes) + client.DefaultRequestHeaders.Accept.ParseAdd(type); + client.Timeout = Settings.Default.Https.Timeout; + } + + public void Dispose() + { + client.Dispose(); + } + + public async Task<(OracleResponseCode, string)> ProcessAsync(Uri uri, CancellationToken cancellation) + { + Utility.Log(nameof(OracleHttpsProtocol), LogLevel.Debug, $"Request: {uri.AbsoluteUri}"); + + HttpResponseMessage message; + try + { + int redirects = 2; + do + { + if (!Settings.Default.AllowPrivateHost) + { + IPHostEntry entry = await Dns.GetHostEntryAsync(uri.Host, cancellation); + if (entry.IsInternal()) + return (OracleResponseCode.Forbidden, null); + } + message = await client.GetAsync(uri, HttpCompletionOption.ResponseContentRead, cancellation); + if (message.Headers.Location is not null) + { + uri = message.Headers.Location; + message = null; + } + } while (message == null && redirects-- > 0); + } + catch + { + return (OracleResponseCode.Timeout, null); + } + if (message is null) + return (OracleResponseCode.Timeout, null); + if (message.StatusCode == HttpStatusCode.NotFound) + return (OracleResponseCode.NotFound, null); + if (message.StatusCode == HttpStatusCode.Forbidden) + return (OracleResponseCode.Forbidden, null); + if (!message.IsSuccessStatusCode) + return (OracleResponseCode.Error, message.StatusCode.ToString()); + if (!Settings.Default.AllowedContentTypes.Contains(message.Content.Headers.ContentType.MediaType)) + return (OracleResponseCode.ContentTypeNotSupported, null); + if (message.Content.Headers.ContentLength.HasValue && message.Content.Headers.ContentLength > OracleResponse.MaxResultSize) + return (OracleResponseCode.ResponseTooLarge, null); + + byte[] buffer = new byte[OracleResponse.MaxResultSize + 1]; + var stream = message.Content.ReadAsStream(cancellation); + var read = await stream.ReadAsync(buffer, 0, buffer.Length, cancellation); + + if (read > OracleResponse.MaxResultSize) + return (OracleResponseCode.ResponseTooLarge, null); + + var encoding = GetEncoding(message.Content.Headers); + if (!encoding.Equals(Encoding.UTF8)) + return (OracleResponseCode.Error, null); + + return (OracleResponseCode.Success, Utility.StrictUTF8.GetString(buffer, 0, read)); + } + + private static Encoding GetEncoding(HttpContentHeaders headers) + { + Encoding encoding = null; + if ((headers.ContentType != null) && (headers.ContentType.CharSet != null)) + { + encoding = Encoding.GetEncoding(headers.ContentType.CharSet); + } + + return encoding ?? Encoding.UTF8; + } + } +} diff --git a/src/Plugins/OracleService/Protocols/OracleNeoFSProtocol.cs b/src/Plugins/OracleService/Protocols/OracleNeoFSProtocol.cs new file mode 100644 index 0000000000..2bf92fa8f4 --- /dev/null +++ b/src/Plugins/OracleService/Protocols/OracleNeoFSProtocol.cs @@ -0,0 +1,155 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// OracleNeoFSProtocol.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; +using Neo.FileStorage.API.Client; +using Neo.FileStorage.API.Cryptography; +using Neo.FileStorage.API.Refs; +using Neo.Network.P2P.Payloads; +using Neo.Wallets; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using System.Web; +using Object = Neo.FileStorage.API.Object.Object; +using Range = Neo.FileStorage.API.Object.Range; + +namespace Neo.Plugins +{ + class OracleNeoFSProtocol : IOracleProtocol + { + private readonly System.Security.Cryptography.ECDsa privateKey; + + public OracleNeoFSProtocol(Wallet wallet, ECPoint[] oracles) + { + byte[] key = oracles.Select(p => wallet.GetAccount(p)).Where(p => p is not null && p.HasKey && !p.Lock).FirstOrDefault().GetKey().PrivateKey; + privateKey = key.LoadPrivateKey(); + } + + public void Configure() + { + } + + public void Dispose() + { + privateKey.Dispose(); + } + + public async Task<(OracleResponseCode, string)> ProcessAsync(Uri uri, CancellationToken cancellation) + { + Utility.Log(nameof(OracleNeoFSProtocol), LogLevel.Debug, $"Request: {uri.AbsoluteUri}"); + try + { + (OracleResponseCode code, string data) = await GetAsync(uri, Settings.Default.NeoFS.EndPoint, cancellation); + Utility.Log(nameof(OracleNeoFSProtocol), LogLevel.Debug, $"NeoFS result, code: {code}, data: {data}"); + return (code, data); + } + catch (Exception e) + { + Utility.Log(nameof(OracleNeoFSProtocol), LogLevel.Debug, $"NeoFS result: error,{e.Message}"); + return (OracleResponseCode.Error, null); + } + } + + + /// + /// GetAsync returns neofs object from the provided url. + /// If Command is not provided, full object is requested. + /// + /// URI scheme is "neofs:ContainerID/ObjectID/Command/offset|length". + /// Client host. + /// Cancellation token object. + /// Returns neofs object. + private async Task<(OracleResponseCode, string)> GetAsync(Uri uri, string host, CancellationToken cancellation) + { + string[] ps = uri.AbsolutePath.Split("/"); + if (ps.Length < 2) throw new FormatException("Invalid neofs url"); + ContainerID containerID = ContainerID.FromString(ps[0]); + ObjectID objectID = ObjectID.FromString(ps[1]); + Address objectAddr = new() + { + ContainerId = containerID, + ObjectId = objectID + }; + using Client client = new(privateKey, host); + var tokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellation); + tokenSource.CancelAfter(Settings.Default.NeoFS.Timeout); + if (ps.Length == 2) + return GetPayload(client, objectAddr, tokenSource.Token); + return ps[2] switch + { + "range" => await GetRangeAsync(client, objectAddr, ps.Skip(3).ToArray(), tokenSource.Token), + "header" => (OracleResponseCode.Success, await GetHeaderAsync(client, objectAddr, tokenSource.Token)), + "hash" => (OracleResponseCode.Success, await GetHashAsync(client, objectAddr, ps.Skip(3).ToArray(), tokenSource.Token)), + _ => throw new Exception("invalid command") + }; + } + + private static (OracleResponseCode, string) GetPayload(Client client, Address addr, CancellationToken cancellation) + { + var objReader = client.GetObjectInit(addr, options: new CallOptions { Ttl = 2 }, context: cancellation); + var obj = objReader.ReadHeader(); + if (obj.PayloadSize > OracleResponse.MaxResultSize) + return (OracleResponseCode.ResponseTooLarge, ""); + var payload = new byte[obj.PayloadSize]; + int offset = 0; + while (true) + { + if ((ulong)offset > obj.PayloadSize) return (OracleResponseCode.ResponseTooLarge, ""); + (byte[] chunk, bool ok) = objReader.ReadChunk(); + if (!ok) break; + Array.Copy(chunk, 0, payload, offset, chunk.Length); + offset += chunk.Length; + } + return (OracleResponseCode.Success, Utility.StrictUTF8.GetString(payload)); + } + + private static async Task<(OracleResponseCode, string)> GetRangeAsync(Client client, Address addr, string[] ps, CancellationToken cancellation) + { + if (ps.Length == 0) throw new FormatException("missing object range (expected 'Offset|Length')"); + Range range = ParseRange(ps[0]); + if (range.Length > OracleResponse.MaxResultSize) return (OracleResponseCode.ResponseTooLarge, ""); + var res = await client.GetObjectPayloadRangeData(addr, range, options: new CallOptions { Ttl = 2 }, context: cancellation); + return (OracleResponseCode.Success, Utility.StrictUTF8.GetString(res)); + } + + private static async Task GetHeaderAsync(Client client, Address addr, CancellationToken cancellation) + { + var obj = await client.GetObjectHeader(addr, options: new CallOptions { Ttl = 2 }, context: cancellation); + return obj.ToString(); + } + + private static async Task GetHashAsync(Client client, Address addr, string[] ps, CancellationToken cancellation) + { + if (ps.Length == 0 || ps[0] == "") + { + Object obj = await client.GetObjectHeader(addr, options: new CallOptions { Ttl = 2 }, context: cancellation); + return $"\"{new UInt256(obj.PayloadChecksum.Sum.ToByteArray())}\""; + } + Range range = ParseRange(ps[0]); + List hashes = await client.GetObjectPayloadRangeHash(addr, new List() { range }, ChecksumType.Sha256, Array.Empty(), new CallOptions { Ttl = 2 }, cancellation); + if (hashes.Count == 0) throw new Exception("empty response, object range is invalid (expected 'Offset|Length')"); + return $"\"{new UInt256(hashes[0])}\""; + } + + private static Range ParseRange(string s) + { + string url = HttpUtility.UrlDecode(s); + int sepIndex = url.IndexOf("|"); + if (sepIndex < 0) throw new Exception("object range is invalid (expected 'Offset|Length')"); + ulong offset = ulong.Parse(url[..sepIndex]); + ulong length = ulong.Parse(url[(sepIndex + 1)..]); + return new Range() { Offset = offset, Length = length }; + } + } +} diff --git a/src/Plugins/OracleService/Settings.cs b/src/Plugins/OracleService/Settings.cs new file mode 100644 index 0000000000..c66010cb5f --- /dev/null +++ b/src/Plugins/OracleService/Settings.cs @@ -0,0 +1,72 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Settings.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 System; +using System.Linq; + +namespace Neo.Plugins +{ + class HttpsSettings + { + public TimeSpan Timeout { get; } + + public HttpsSettings(IConfigurationSection section) + { + Timeout = TimeSpan.FromMilliseconds(section.GetValue("Timeout", 5000)); + } + } + + class NeoFSSettings + { + public string EndPoint { get; } + public TimeSpan Timeout { get; } + + public NeoFSSettings(IConfigurationSection section) + { + EndPoint = section.GetValue("EndPoint", "127.0.0.1:8080"); + Timeout = TimeSpan.FromMilliseconds(section.GetValue("Timeout", 15000)); + } + } + + class Settings + { + public uint Network { get; } + public Uri[] Nodes { get; } + public TimeSpan MaxTaskTimeout { get; } + public TimeSpan MaxOracleTimeout { get; } + public bool AllowPrivateHost { get; } + public string[] AllowedContentTypes { get; } + public HttpsSettings Https { get; } + public NeoFSSettings NeoFS { get; } + public bool AutoStart { get; } + + public static Settings Default { get; private set; } + + private Settings(IConfigurationSection section) + { + Network = section.GetValue("Network", 5195086u); + Nodes = section.GetSection("Nodes").GetChildren().Select(p => new Uri(p.Get(), UriKind.Absolute)).ToArray(); + MaxTaskTimeout = TimeSpan.FromMilliseconds(section.GetValue("MaxTaskTimeout", 432000000)); + MaxOracleTimeout = TimeSpan.FromMilliseconds(section.GetValue("MaxOracleTimeout", 15000)); + AllowPrivateHost = section.GetValue("AllowPrivateHost", false); + AllowedContentTypes = section.GetSection("AllowedContentTypes").GetChildren().Select(p => p.Get()).ToArray(); + Https = new HttpsSettings(section.GetSection("Https")); + NeoFS = new NeoFSSettings(section.GetSection("NeoFS")); + AutoStart = section.GetValue("AutoStart", false); + } + + public static void Load(IConfigurationSection section) + { + Default = new Settings(section); + } + } +} diff --git a/src/Plugins/OracleService/config.json b/src/Plugins/OracleService/config.json new file mode 100644 index 0000000000..1ab0d93399 --- /dev/null +++ b/src/Plugins/OracleService/config.json @@ -0,0 +1,21 @@ +{ + "PluginConfiguration": { + "Network": 860833102, + "Nodes": [], + "MaxTaskTimeout": 432000000, + "MaxOracleTimeout": 10000, + "AllowPrivateHost": false, + "AllowedContentTypes": [ "application/json" ], + "Https": { + "Timeout": 5000 + }, + "NeoFS": { + "EndPoint": "http://127.0.0.1:8080", + "Timeout": 15000 + }, + "AutoStart": false + }, + "Dependency": [ + "RpcServer" + ] +} diff --git a/src/Plugins/RocksDBStore/Plugins/Storage/Options.cs b/src/Plugins/RocksDBStore/Plugins/Storage/Options.cs new file mode 100644 index 0000000000..26dd6c63aa --- /dev/null +++ b/src/Plugins/RocksDBStore/Plugins/Storage/Options.cs @@ -0,0 +1,36 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Options.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 RocksDbSharp; + +namespace Neo.Plugins.Storage +{ + public static class Options + { + public static readonly DbOptions Default = CreateDbOptions(); + public static readonly ReadOptions ReadDefault = new ReadOptions(); + public static readonly WriteOptions WriteDefault = new WriteOptions(); + public static readonly WriteOptions WriteDefaultSync = new WriteOptions().SetSync(true); + + public static DbOptions CreateDbOptions() + { + DbOptions options = new DbOptions(); + options.SetCreateMissingColumnFamilies(true); + options.SetCreateIfMissing(true); + options.SetErrorIfExists(false); + options.SetMaxOpenFiles(1000); + options.SetParanoidChecks(false); + options.SetWriteBufferSize(4 << 20); + options.SetBlockBasedTableFactory(new BlockBasedTableOptions().SetBlockSize(4096)); + return options; + } + } +} diff --git a/src/Plugins/RocksDBStore/Plugins/Storage/RocksDBStore.cs b/src/Plugins/RocksDBStore/Plugins/Storage/RocksDBStore.cs new file mode 100644 index 0000000000..079a012f67 --- /dev/null +++ b/src/Plugins/RocksDBStore/Plugins/Storage/RocksDBStore.cs @@ -0,0 +1,34 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// RocksDBStore.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.Storage +{ + public class RocksDBStore : Plugin, IStoreProvider + { + public override string Description => "Uses RocksDBStore to store the blockchain data"; + + public RocksDBStore() + { + StoreFactory.RegisterProvider(this); + } + + /// + /// Get store + /// + /// RocksDbStore + public IStore GetStore(string path) + { + return new Store(path); + } + } +} diff --git a/src/Plugins/RocksDBStore/Plugins/Storage/Snapshot.cs b/src/Plugins/RocksDBStore/Plugins/Storage/Snapshot.cs new file mode 100644 index 0000000000..7423f6ae4a --- /dev/null +++ b/src/Plugins/RocksDBStore/Plugins/Storage/Snapshot.cs @@ -0,0 +1,82 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Snapshot.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 RocksDbSharp; +using System; +using System.Collections.Generic; + +namespace Neo.Plugins.Storage +{ + internal class Snapshot : ISnapshot + { + private readonly RocksDb db; + private readonly RocksDbSharp.Snapshot snapshot; + private readonly WriteBatch batch; + private readonly ReadOptions options; + + public Snapshot(RocksDb db) + { + this.db = db; + snapshot = db.CreateSnapshot(); + batch = new WriteBatch(); + + options = new ReadOptions(); + options.SetFillCache(false); + options.SetSnapshot(snapshot); + } + + public void Commit() + { + db.Write(batch, Options.WriteDefault); + } + + public void Delete(byte[] key) + { + batch.Delete(key); + } + + public void Put(byte[] key, byte[] value) + { + batch.Put(key, value); + } + + public IEnumerable<(byte[] Key, byte[] Value)> Seek(byte[] keyOrPrefix, SeekDirection direction) + { + if (keyOrPrefix == null) keyOrPrefix = Array.Empty(); + + using var it = db.NewIterator(readOptions: options); + + if (direction == SeekDirection.Forward) + for (it.Seek(keyOrPrefix); it.Valid(); it.Next()) + yield return (it.Key(), it.Value()); + else + for (it.SeekForPrev(keyOrPrefix); it.Valid(); it.Prev()) + yield return (it.Key(), it.Value()); + } + + public bool Contains(byte[] key) + { + return db.Get(key, Array.Empty(), 0, 0, readOptions: options) >= 0; + } + + public byte[] TryGet(byte[] key) + { + return db.Get(key, readOptions: options); + } + + public void Dispose() + { + snapshot.Dispose(); + batch.Dispose(); + } + } +} diff --git a/src/Plugins/RocksDBStore/Plugins/Storage/Store.cs b/src/Plugins/RocksDBStore/Plugins/Storage/Store.cs new file mode 100644 index 0000000000..ebf160dab0 --- /dev/null +++ b/src/Plugins/RocksDBStore/Plugins/Storage/Store.cs @@ -0,0 +1,77 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Store.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 RocksDbSharp; +using System; +using System.Collections.Generic; +using System.IO; + +namespace Neo.Plugins.Storage +{ + internal class Store : IStore + { + private readonly RocksDb db; + + public Store(string path) + { + db = RocksDb.Open(Options.Default, Path.GetFullPath(path)); + } + + public void Dispose() + { + db.Dispose(); + } + + public ISnapshot GetSnapshot() + { + return new Snapshot(db); + } + + public IEnumerable<(byte[] Key, byte[] Value)> Seek(byte[] keyOrPrefix, SeekDirection direction = SeekDirection.Forward) + { + if (keyOrPrefix == null) keyOrPrefix = Array.Empty(); + + using var it = db.NewIterator(); + if (direction == SeekDirection.Forward) + for (it.Seek(keyOrPrefix); it.Valid(); it.Next()) + yield return (it.Key(), it.Value()); + else + for (it.SeekForPrev(keyOrPrefix); it.Valid(); it.Prev()) + yield return (it.Key(), it.Value()); + } + + public bool Contains(byte[] key) + { + return db.Get(key, Array.Empty(), 0, 0) >= 0; + } + + public byte[] TryGet(byte[] key) + { + return db.Get(key); + } + + public void Delete(byte[] key) + { + db.Remove(key); + } + + public void Put(byte[] key, byte[] value) + { + db.Put(key, value); + } + + public void PutSync(byte[] key, byte[] value) + { + db.Put(key, value, writeOptions: Options.WriteDefaultSync); + } + } +} diff --git a/src/Plugins/RocksDBStore/RocksDBStore.csproj b/src/Plugins/RocksDBStore/RocksDBStore.csproj new file mode 100644 index 0000000000..57037c68cf --- /dev/null +++ b/src/Plugins/RocksDBStore/RocksDBStore.csproj @@ -0,0 +1,13 @@ + + + + net8.0 + Neo.Plugins.Storage.RocksDBStore + Neo.Plugins.Storage + + + + + + + diff --git a/src/Plugins/RpcClient/ContractClient.cs b/src/Plugins/RpcClient/ContractClient.cs new file mode 100644 index 0000000000..f4ec020abc --- /dev/null +++ b/src/Plugins/RpcClient/ContractClient.cs @@ -0,0 +1,77 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// ContractClient.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.Payloads; +using Neo.Network.RPC.Models; +using Neo.SmartContract; +using Neo.SmartContract.Manifest; +using Neo.SmartContract.Native; +using Neo.VM; +using Neo.Wallets; +using System.Threading.Tasks; + +namespace Neo.Network.RPC +{ + /// + /// Contract related operations through RPC API + /// + public class ContractClient + { + protected readonly RpcClient rpcClient; + + /// + /// ContractClient Constructor + /// + /// the RPC client to call NEO RPC methods + public ContractClient(RpcClient rpc) + { + rpcClient = rpc; + } + + /// + /// Use RPC method to test invoke operation. + /// + /// contract script hash + /// contract operation + /// operation arguments + /// + public Task TestInvokeAsync(UInt160 scriptHash, string operation, params object[] args) + { + byte[] script = scriptHash.MakeScript(operation, args); + return rpcClient.InvokeScriptAsync(script); + } + + /// + /// Deploy Contract, return signed transaction + /// + /// neo contract executable file + /// contract manifest + /// sender KeyPair + /// + public async Task CreateDeployContractTxAsync(byte[] nefFile, ContractManifest manifest, KeyPair key) + { + byte[] script; + using (ScriptBuilder sb = new ScriptBuilder()) + { + sb.EmitDynamicCall(NativeContract.ContractManagement.Hash, "deploy", nefFile, manifest.ToJson().ToString()); + script = sb.ToArray(); + } + UInt160 sender = Contract.CreateSignatureRedeemScript(key.PublicKey).ToScriptHash(); + Signer[] signers = new[] { new Signer { Scopes = WitnessScope.CalledByEntry, Account = sender } }; + + TransactionManagerFactory factory = new TransactionManagerFactory(rpcClient); + TransactionManager manager = await factory.MakeTransactionAsync(script, signers).ConfigureAwait(false); + return await manager + .AddSignature(key) + .SignAsync().ConfigureAwait(false); + } + } +} diff --git a/src/Plugins/RpcClient/Models/RpcAccount.cs b/src/Plugins/RpcClient/Models/RpcAccount.cs new file mode 100644 index 0000000000..2afe18b0e9 --- /dev/null +++ b/src/Plugins/RpcClient/Models/RpcAccount.cs @@ -0,0 +1,48 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// RpcAccount.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.Json; + +namespace Neo.Network.RPC.Models +{ + public class RpcAccount + { + public string Address { get; set; } + + public bool HasKey { get; set; } + + public string Label { get; set; } + + public bool WatchOnly { get; set; } + + public JObject ToJson() + { + return new JObject + { + ["address"] = Address, + ["haskey"] = HasKey, + ["label"] = Label, + ["watchonly"] = WatchOnly + }; + } + + public static RpcAccount FromJson(JObject json) + { + return new RpcAccount + { + Address = json["address"].AsString(), + HasKey = json["haskey"].AsBoolean(), + Label = json["label"]?.AsString(), + WatchOnly = json["watchonly"].AsBoolean(), + }; + } + } +} diff --git a/src/Plugins/RpcClient/Models/RpcApplicationLog.cs b/src/Plugins/RpcClient/Models/RpcApplicationLog.cs new file mode 100644 index 0000000000..b641f9df06 --- /dev/null +++ b/src/Plugins/RpcClient/Models/RpcApplicationLog.cs @@ -0,0 +1,118 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// RpcApplicationLog.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.Json; +using Neo.SmartContract; +using Neo.VM; +using Neo.VM.Types; +using System.Collections.Generic; +using System.Linq; + +namespace Neo.Network.RPC.Models +{ + public class RpcApplicationLog + { + public UInt256 TxId { get; set; } + + public UInt256 BlockHash { get; set; } + + public List Executions { get; set; } + + public JObject ToJson() + { + JObject json = new JObject(); + if (TxId != null) + json["txid"] = TxId.ToString(); + if (BlockHash != null) + json["blockhash"] = BlockHash.ToString(); + json["executions"] = Executions.Select(p => p.ToJson()).ToArray(); + return json; + } + + public static RpcApplicationLog FromJson(JObject json, ProtocolSettings protocolSettings) + { + return new RpcApplicationLog + { + TxId = json["txid"] is null ? null : UInt256.Parse(json["txid"].AsString()), + BlockHash = json["blockhash"] is null ? null : UInt256.Parse(json["blockhash"].AsString()), + Executions = ((JArray)json["executions"]).Select(p => Execution.FromJson((JObject)p, protocolSettings)).ToList(), + }; + } + } + + public class Execution + { + public TriggerType Trigger { get; set; } + + public VMState VMState { get; set; } + + public long GasConsumed { get; set; } + + public string ExceptionMessage { get; set; } + + public List Stack { get; set; } + + public List Notifications { get; set; } + + public JObject ToJson() + { + JObject json = new(); + json["trigger"] = Trigger; + json["vmstate"] = VMState; + json["gasconsumed"] = GasConsumed.ToString(); + json["exception"] = ExceptionMessage; + json["stack"] = Stack.Select(q => q.ToJson()).ToArray(); + json["notifications"] = Notifications.Select(q => q.ToJson()).ToArray(); + return json; + } + + public static Execution FromJson(JObject json, ProtocolSettings protocolSettings) + { + return new Execution + { + Trigger = json["trigger"].GetEnum(), + VMState = json["vmstate"].GetEnum(), + GasConsumed = long.Parse(json["gasconsumed"].AsString()), + ExceptionMessage = json["exception"]?.AsString(), + Stack = ((JArray)json["stack"]).Select(p => Utility.StackItemFromJson((JObject)p)).ToList(), + Notifications = ((JArray)json["notifications"]).Select(p => RpcNotifyEventArgs.FromJson((JObject)p, protocolSettings)).ToList() + }; + } + } + + public class RpcNotifyEventArgs + { + public UInt160 Contract { get; set; } + + public string EventName { get; set; } + + public StackItem State { get; set; } + + public JObject ToJson() + { + JObject json = new(); + json["contract"] = Contract.ToString(); + json["eventname"] = EventName; + json["state"] = State.ToJson(); + return json; + } + + public static RpcNotifyEventArgs FromJson(JObject json, ProtocolSettings protocolSettings) + { + return new RpcNotifyEventArgs + { + Contract = json["contract"].ToScriptHash(protocolSettings), + EventName = json["eventname"].AsString(), + State = Utility.StackItemFromJson((JObject)json["state"]) + }; + } + } +} diff --git a/src/Plugins/RpcClient/Models/RpcBlock.cs b/src/Plugins/RpcClient/Models/RpcBlock.cs new file mode 100644 index 0000000000..46f54a7230 --- /dev/null +++ b/src/Plugins/RpcClient/Models/RpcBlock.cs @@ -0,0 +1,43 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// RpcBlock.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.Json; +using Neo.Network.P2P.Payloads; + +namespace Neo.Network.RPC.Models +{ + public class RpcBlock + { + public Block Block { get; set; } + + public uint Confirmations { get; set; } + + public UInt256 NextBlockHash { get; set; } + + public JObject ToJson(ProtocolSettings protocolSettings) + { + JObject json = Utility.BlockToJson(Block, protocolSettings); + json["confirmations"] = Confirmations; + json["nextblockhash"] = NextBlockHash?.ToString(); + return json; + } + + public static RpcBlock FromJson(JObject json, ProtocolSettings protocolSettings) + { + return new RpcBlock + { + Block = Utility.BlockFromJson(json, protocolSettings), + Confirmations = (uint)json["confirmations"].AsNumber(), + NextBlockHash = json["nextblockhash"] is null ? null : UInt256.Parse(json["nextblockhash"].AsString()) + }; + } + } +} diff --git a/src/Plugins/RpcClient/Models/RpcBlockHeader.cs b/src/Plugins/RpcClient/Models/RpcBlockHeader.cs new file mode 100644 index 0000000000..e30a6a64a1 --- /dev/null +++ b/src/Plugins/RpcClient/Models/RpcBlockHeader.cs @@ -0,0 +1,43 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// RpcBlockHeader.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.Json; +using Neo.Network.P2P.Payloads; + +namespace Neo.Network.RPC.Models +{ + public class RpcBlockHeader + { + public Header Header { get; set; } + + public uint Confirmations { get; set; } + + public UInt256 NextBlockHash { get; set; } + + public JObject ToJson(ProtocolSettings protocolSettings) + { + JObject json = Header.ToJson(protocolSettings); + json["confirmations"] = Confirmations; + json["nextblockhash"] = NextBlockHash?.ToString(); + return json; + } + + public static RpcBlockHeader FromJson(JObject json, ProtocolSettings protocolSettings) + { + return new RpcBlockHeader + { + Header = Utility.HeaderFromJson(json, protocolSettings), + Confirmations = (uint)json["confirmations"].AsNumber(), + NextBlockHash = json["nextblockhash"] is null ? null : UInt256.Parse(json["nextblockhash"].AsString()) + }; + } + } +} diff --git a/src/Plugins/RpcClient/Models/RpcContractState.cs b/src/Plugins/RpcClient/Models/RpcContractState.cs new file mode 100644 index 0000000000..b77a2d3a89 --- /dev/null +++ b/src/Plugins/RpcClient/Models/RpcContractState.cs @@ -0,0 +1,42 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// RpcContractState.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.Json; +using Neo.SmartContract; +using Neo.SmartContract.Manifest; + +namespace Neo.Network.RPC.Models +{ + public class RpcContractState + { + public ContractState ContractState { get; set; } + + public JObject ToJson() + { + return ContractState.ToJson(); + } + + public static RpcContractState FromJson(JObject json) + { + return new RpcContractState + { + ContractState = new ContractState + { + Id = (int)json["id"].AsNumber(), + UpdateCounter = (ushort)json["updatecounter"].AsNumber(), + Hash = UInt160.Parse(json["hash"].AsString()), + Nef = RpcNefFile.FromJson((JObject)json["nef"]), + Manifest = ContractManifest.FromJson((JObject)json["manifest"]) + } + }; + } + } +} diff --git a/src/Plugins/RpcClient/Models/RpcFoundStates.cs b/src/Plugins/RpcClient/Models/RpcFoundStates.cs new file mode 100644 index 0000000000..a3a1c1f10a --- /dev/null +++ b/src/Plugins/RpcClient/Models/RpcFoundStates.cs @@ -0,0 +1,44 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// RpcFoundStates.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.Json; +using System; +using System.Linq; + +namespace Neo.Network.RPC.Models +{ + public class RpcFoundStates + { + public bool Truncated; + public (byte[] key, byte[] value)[] Results; + public byte[] FirstProof; + public byte[] LastProof; + + public static RpcFoundStates FromJson(JObject json) + { + return new RpcFoundStates + { + Truncated = json["truncated"].AsBoolean(), + Results = ((JArray)json["results"]) + .Select(j => ( + Convert.FromBase64String(j["key"].AsString()), + Convert.FromBase64String(j["value"].AsString()) + )) + .ToArray(), + FirstProof = ProofFromJson((JString)json["firstProof"]), + LastProof = ProofFromJson((JString)json["lastProof"]), + }; + } + + static byte[] ProofFromJson(JString json) + => json == null ? null : Convert.FromBase64String(json.AsString()); + } +} diff --git a/src/Plugins/RpcClient/Models/RpcInvokeResult.cs b/src/Plugins/RpcClient/Models/RpcInvokeResult.cs new file mode 100644 index 0000000000..6bd661e1ba --- /dev/null +++ b/src/Plugins/RpcClient/Models/RpcInvokeResult.cs @@ -0,0 +1,100 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// RpcInvokeResult.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.Json; +using Neo.VM; +using Neo.VM.Types; +using System; +using System.Linq; + +namespace Neo.Network.RPC.Models +{ + public class RpcInvokeResult + { + public string Script { get; set; } + + public VM.VMState State { get; set; } + + public long GasConsumed { get; set; } + + public StackItem[] Stack { get; set; } + + public string Tx { get; set; } + + public string Exception { get; set; } + + public string Session { get; set; } + + public JObject ToJson() + { + JObject json = new(); + json["script"] = Script; + json["state"] = State; + json["gasconsumed"] = GasConsumed.ToString(); + if (!string.IsNullOrEmpty(Exception)) + json["exception"] = Exception; + try + { + json["stack"] = new JArray(Stack.Select(p => p.ToJson())); + } + catch (InvalidOperationException) + { + // ContractParameter.ToJson() may cause InvalidOperationException + json["stack"] = "error: recursive reference"; + } + if (!string.IsNullOrEmpty(Tx)) json["tx"] = Tx; + return json; + } + + public static RpcInvokeResult FromJson(JObject json) + { + RpcInvokeResult invokeScriptResult = new() + { + Script = json["script"].AsString(), + State = json["state"].GetEnum(), + GasConsumed = long.Parse(json["gasconsumed"].AsString()), + Exception = json["exception"]?.AsString(), + Session = json["session"]?.AsString() + }; + try + { + invokeScriptResult.Stack = ((JArray)json["stack"]).Select(p => Utility.StackItemFromJson((JObject)p)).ToArray(); + } + catch { } + invokeScriptResult.Tx = json["tx"]?.AsString(); + return invokeScriptResult; + } + } + + public class RpcStack + { + public string Type { get; set; } + + public string Value { get; set; } + + public JObject ToJson() + { + JObject json = new(); + json["type"] = Type; + json["value"] = Value; + return json; + } + + public static RpcStack FromJson(JObject json) + { + return new RpcStack + { + Type = json["type"].AsString(), + Value = json["value"].AsString() + }; + } + } +} diff --git a/src/Plugins/RpcClient/Models/RpcMethodToken.cs b/src/Plugins/RpcClient/Models/RpcMethodToken.cs new file mode 100644 index 0000000000..f426950deb --- /dev/null +++ b/src/Plugins/RpcClient/Models/RpcMethodToken.cs @@ -0,0 +1,32 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// RpcMethodToken.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.Json; +using Neo.SmartContract; +using System; + +namespace Neo.Network.RPC.Models +{ + class RpcMethodToken + { + public static MethodToken FromJson(JObject json) + { + return new MethodToken + { + Hash = UInt160.Parse(json["hash"].AsString()), + Method = json["method"].AsString(), + ParametersCount = (ushort)json["paramcount"].AsNumber(), + HasReturnValue = json["hasreturnvalue"].AsBoolean(), + CallFlags = (CallFlags)Enum.Parse(typeof(CallFlags), json["callflags"].AsString()) + }; + } + } +} diff --git a/src/Plugins/RpcClient/Models/RpcNefFile.cs b/src/Plugins/RpcClient/Models/RpcNefFile.cs new file mode 100644 index 0000000000..4b33f2b6ac --- /dev/null +++ b/src/Plugins/RpcClient/Models/RpcNefFile.cs @@ -0,0 +1,33 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// RpcNefFile.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.Json; +using Neo.SmartContract; +using System; +using System.Linq; + +namespace Neo.Network.RPC.Models +{ + class RpcNefFile + { + public static NefFile FromJson(JObject json) + { + return new NefFile + { + Compiler = json["compiler"].AsString(), + Source = json["source"].AsString(), + Tokens = ((JArray)json["tokens"]).Select(p => RpcMethodToken.FromJson((JObject)p)).ToArray(), + Script = Convert.FromBase64String(json["script"].AsString()), + CheckSum = (uint)json["checksum"].AsNumber() + }; + } + } +} diff --git a/src/Plugins/RpcClient/Models/RpcNep17Balances.cs b/src/Plugins/RpcClient/Models/RpcNep17Balances.cs new file mode 100644 index 0000000000..f7f8b00dbe --- /dev/null +++ b/src/Plugins/RpcClient/Models/RpcNep17Balances.cs @@ -0,0 +1,73 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// RpcNep17Balances.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.Json; +using Neo.Wallets; +using System.Collections.Generic; +using System.Linq; +using System.Numerics; + +namespace Neo.Network.RPC.Models +{ + public class RpcNep17Balances + { + public UInt160 UserScriptHash { get; set; } + + public List Balances { get; set; } + + public JObject ToJson(ProtocolSettings protocolSettings) + { + JObject json = new(); + json["balance"] = Balances.Select(p => p.ToJson()).ToArray(); + json["address"] = UserScriptHash.ToAddress(protocolSettings.AddressVersion); + return json; + } + + public static RpcNep17Balances FromJson(JObject json, ProtocolSettings protocolSettings) + { + RpcNep17Balances nep17Balance = new() + { + Balances = ((JArray)json["balance"]).Select(p => RpcNep17Balance.FromJson((JObject)p, protocolSettings)).ToList(), + UserScriptHash = json["address"].ToScriptHash(protocolSettings) + }; + return nep17Balance; + } + } + + public class RpcNep17Balance + { + public UInt160 AssetHash { get; set; } + + public BigInteger Amount { get; set; } + + public uint LastUpdatedBlock { get; set; } + + public JObject ToJson() + { + JObject json = new(); + json["assethash"] = AssetHash.ToString(); + json["amount"] = Amount.ToString(); + json["lastupdatedblock"] = LastUpdatedBlock; + return json; + } + + public static RpcNep17Balance FromJson(JObject json, ProtocolSettings protocolSettings) + { + RpcNep17Balance balance = new() + { + AssetHash = json["assethash"].ToScriptHash(protocolSettings), + Amount = BigInteger.Parse(json["amount"].AsString()), + LastUpdatedBlock = (uint)json["lastupdatedblock"].AsNumber() + }; + return balance; + } + } +} diff --git a/src/Plugins/RpcClient/Models/RpcNep17TokenInfo.cs b/src/Plugins/RpcClient/Models/RpcNep17TokenInfo.cs new file mode 100644 index 0000000000..a7cb6d0ef4 --- /dev/null +++ b/src/Plugins/RpcClient/Models/RpcNep17TokenInfo.cs @@ -0,0 +1,26 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// RpcNep17TokenInfo.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.Numerics; + +namespace Neo.Network.RPC.Models +{ + public class RpcNep17TokenInfo + { + public string Name { get; set; } + + public string Symbol { get; set; } + + public byte Decimals { get; set; } + + public BigInteger TotalSupply { get; set; } + } +} diff --git a/src/Plugins/RpcClient/Models/RpcNep17Transfers.cs b/src/Plugins/RpcClient/Models/RpcNep17Transfers.cs new file mode 100644 index 0000000000..3a3226b9a9 --- /dev/null +++ b/src/Plugins/RpcClient/Models/RpcNep17Transfers.cs @@ -0,0 +1,92 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// RpcNep17Transfers.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.Json; +using Neo.Wallets; +using System.Collections.Generic; +using System.Linq; +using System.Numerics; + +namespace Neo.Network.RPC.Models +{ + public class RpcNep17Transfers + { + public UInt160 UserScriptHash { get; set; } + + public List Sent { get; set; } + + public List Received { get; set; } + + public JObject ToJson(ProtocolSettings protocolSettings) + { + JObject json = new(); + json["sent"] = Sent.Select(p => p.ToJson(protocolSettings)).ToArray(); + json["received"] = Received.Select(p => p.ToJson(protocolSettings)).ToArray(); + json["address"] = UserScriptHash.ToAddress(protocolSettings.AddressVersion); + return json; + } + + public static RpcNep17Transfers FromJson(JObject json, ProtocolSettings protocolSettings) + { + RpcNep17Transfers transfers = new() + { + Sent = ((JArray)json["sent"]).Select(p => RpcNep17Transfer.FromJson((JObject)p, protocolSettings)).ToList(), + Received = ((JArray)json["received"]).Select(p => RpcNep17Transfer.FromJson((JObject)p, protocolSettings)).ToList(), + UserScriptHash = json["address"].ToScriptHash(protocolSettings) + }; + return transfers; + } + } + + public class RpcNep17Transfer + { + public ulong TimestampMS { get; set; } + + public UInt160 AssetHash { get; set; } + + public UInt160 UserScriptHash { get; set; } + + public BigInteger Amount { get; set; } + + public uint BlockIndex { get; set; } + + public ushort TransferNotifyIndex { get; set; } + + public UInt256 TxHash { get; set; } + + public JObject ToJson(ProtocolSettings protocolSettings) + { + JObject json = new(); + json["timestamp"] = TimestampMS; + json["assethash"] = AssetHash.ToString(); + json["transferaddress"] = UserScriptHash?.ToAddress(protocolSettings.AddressVersion); + json["amount"] = Amount.ToString(); + json["blockindex"] = BlockIndex; + json["transfernotifyindex"] = TransferNotifyIndex; + json["txhash"] = TxHash.ToString(); + return json; + } + + public static RpcNep17Transfer FromJson(JObject json, ProtocolSettings protocolSettings) + { + return new RpcNep17Transfer + { + TimestampMS = (ulong)json["timestamp"].AsNumber(), + AssetHash = json["assethash"].ToScriptHash(protocolSettings), + UserScriptHash = json["transferaddress"]?.ToScriptHash(protocolSettings), + Amount = BigInteger.Parse(json["amount"].AsString()), + BlockIndex = (uint)json["blockindex"].AsNumber(), + TransferNotifyIndex = (ushort)json["transfernotifyindex"].AsNumber(), + TxHash = UInt256.Parse(json["txhash"].AsString()) + }; + } + } +} diff --git a/src/Plugins/RpcClient/Models/RpcPeers.cs b/src/Plugins/RpcClient/Models/RpcPeers.cs new file mode 100644 index 0000000000..6659ffe0dd --- /dev/null +++ b/src/Plugins/RpcClient/Models/RpcPeers.cs @@ -0,0 +1,68 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// RpcPeers.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.Json; +using System.Linq; + +namespace Neo.Network.RPC.Models +{ + public class RpcPeers + { + public RpcPeer[] Unconnected { get; set; } + + public RpcPeer[] Bad { get; set; } + + public RpcPeer[] Connected { get; set; } + + public JObject ToJson() + { + JObject json = new(); + json["unconnected"] = new JArray(Unconnected.Select(p => p.ToJson())); + json["bad"] = new JArray(Bad.Select(p => p.ToJson())); + json["connected"] = new JArray(Connected.Select(p => p.ToJson())); + return json; + } + + public static RpcPeers FromJson(JObject json) + { + return new RpcPeers + { + Unconnected = ((JArray)json["unconnected"]).Select(p => RpcPeer.FromJson((JObject)p)).ToArray(), + Bad = ((JArray)json["bad"]).Select(p => RpcPeer.FromJson((JObject)p)).ToArray(), + Connected = ((JArray)json["connected"]).Select(p => RpcPeer.FromJson((JObject)p)).ToArray() + }; + } + } + + public class RpcPeer + { + public string Address { get; set; } + + public int Port { get; set; } + + public JObject ToJson() + { + JObject json = new(); + json["address"] = Address; + json["port"] = Port; + return json; + } + + public static RpcPeer FromJson(JObject json) + { + return new RpcPeer + { + Address = json["address"].AsString(), + Port = int.Parse(json["port"].AsString()) + }; + } + } +} diff --git a/src/Plugins/RpcClient/Models/RpcPlugin.cs b/src/Plugins/RpcClient/Models/RpcPlugin.cs new file mode 100644 index 0000000000..12a8669dea --- /dev/null +++ b/src/Plugins/RpcClient/Models/RpcPlugin.cs @@ -0,0 +1,44 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// RpcPlugin.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.Json; +using System.Linq; + +namespace Neo.Network.RPC.Models +{ + public class RpcPlugin + { + public string Name { get; set; } + + public string Version { get; set; } + + public string[] Interfaces { get; set; } + + public JObject ToJson() + { + JObject json = new(); + json["name"] = Name; + json["version"] = Version; + json["interfaces"] = new JArray(Interfaces.Select(p => (JToken)p)); + return json; + } + + public static RpcPlugin FromJson(JObject json) + { + return new RpcPlugin + { + Name = json["name"].AsString(), + Version = json["version"].AsString(), + Interfaces = ((JArray)json["interfaces"]).Select(p => p.AsString()).ToArray() + }; + } + } +} diff --git a/src/Plugins/RpcClient/Models/RpcRawMemPool.cs b/src/Plugins/RpcClient/Models/RpcRawMemPool.cs new file mode 100644 index 0000000000..4474e0b6be --- /dev/null +++ b/src/Plugins/RpcClient/Models/RpcRawMemPool.cs @@ -0,0 +1,45 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// RpcRawMemPool.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.Json; +using System.Collections.Generic; +using System.Linq; + +namespace Neo.Network.RPC.Models +{ + public class RpcRawMemPool + { + public uint Height { get; set; } + + public List Verified { get; set; } + + public List UnVerified { get; set; } + + public JObject ToJson() + { + JObject json = new(); + json["height"] = Height; + json["verified"] = new JArray(Verified.Select(p => (JToken)p.ToString())); + json["unverified"] = new JArray(UnVerified.Select(p => (JToken)p.ToString())); + return json; + } + + public static RpcRawMemPool FromJson(JObject json) + { + return new RpcRawMemPool + { + Height = uint.Parse(json["height"].AsString()), + Verified = ((JArray)json["verified"]).Select(p => UInt256.Parse(p.AsString())).ToList(), + UnVerified = ((JArray)json["unverified"]).Select(p => UInt256.Parse(p.AsString())).ToList() + }; + } + } +} diff --git a/src/Plugins/RpcClient/Models/RpcRequest.cs b/src/Plugins/RpcClient/Models/RpcRequest.cs new file mode 100644 index 0000000000..1c4b67415a --- /dev/null +++ b/src/Plugins/RpcClient/Models/RpcRequest.cs @@ -0,0 +1,48 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// RpcRequest.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.Json; +using System.Linq; + +namespace Neo.Network.RPC.Models +{ + public class RpcRequest + { + public JToken Id { get; set; } + + public string JsonRpc { get; set; } + + public string Method { get; set; } + + public JToken[] Params { get; set; } + + public static RpcRequest FromJson(JObject json) + { + return new RpcRequest + { + Id = json["id"], + JsonRpc = json["jsonrpc"].AsString(), + Method = json["method"].AsString(), + Params = ((JArray)json["params"]).ToArray() + }; + } + + public JObject ToJson() + { + var json = new JObject(); + json["id"] = Id; + json["jsonrpc"] = JsonRpc; + json["method"] = Method; + json["params"] = new JArray(Params); + return json; + } + } +} diff --git a/src/Plugins/RpcClient/Models/RpcResponse.cs b/src/Plugins/RpcClient/Models/RpcResponse.cs new file mode 100644 index 0000000000..25e3212fc3 --- /dev/null +++ b/src/Plugins/RpcClient/Models/RpcResponse.cs @@ -0,0 +1,83 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// RpcResponse.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.Json; + +namespace Neo.Network.RPC.Models +{ + public class RpcResponse + { + public JToken Id { get; set; } + + public string JsonRpc { get; set; } + + public RpcResponseError Error { get; set; } + + public JToken Result { get; set; } + + public string RawResponse { get; set; } + + public static RpcResponse FromJson(JObject json) + { + RpcResponse response = new() + { + Id = json["id"], + JsonRpc = json["jsonrpc"].AsString(), + Result = json["result"] + }; + + if (json["error"] != null) + { + response.Error = RpcResponseError.FromJson((JObject)json["error"]); + } + + return response; + } + + public JObject ToJson() + { + JObject json = new(); + json["id"] = Id; + json["jsonrpc"] = JsonRpc; + json["error"] = Error?.ToJson(); + json["result"] = Result; + return json; + } + } + + public class RpcResponseError + { + public int Code { get; set; } + + public string Message { get; set; } + + public JToken Data { get; set; } + + public static RpcResponseError FromJson(JObject json) + { + return new RpcResponseError + { + Code = (int)json["code"].AsNumber(), + Message = json["message"].AsString(), + Data = json["data"], + }; + } + + public JObject ToJson() + { + JObject json = new(); + json["code"] = Code; + json["message"] = Message; + json["data"] = Data; + return json; + } + } +} diff --git a/src/Plugins/RpcClient/Models/RpcStateRoot.cs b/src/Plugins/RpcClient/Models/RpcStateRoot.cs new file mode 100644 index 0000000000..095b054a33 --- /dev/null +++ b/src/Plugins/RpcClient/Models/RpcStateRoot.cs @@ -0,0 +1,36 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// RpcStateRoot.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.Json; +using Neo.Network.P2P.Payloads; +using System.Linq; + +namespace Neo.Network.RPC.Models +{ + public class RpcStateRoot + { + public byte Version; + public uint Index; + public UInt256 RootHash; + public Witness Witness; + + public static RpcStateRoot FromJson(JObject json) + { + return new RpcStateRoot + { + Version = (byte)json["version"].AsNumber(), + Index = (uint)json["index"].AsNumber(), + RootHash = UInt256.Parse(json["roothash"].AsString()), + Witness = ((JArray)json["witnesses"]).Select(p => Utility.WitnessFromJson((JObject)p)).FirstOrDefault() + }; + } + } +} diff --git a/src/Plugins/RpcClient/Models/RpcTransaction.cs b/src/Plugins/RpcClient/Models/RpcTransaction.cs new file mode 100644 index 0000000000..cb674316d5 --- /dev/null +++ b/src/Plugins/RpcClient/Models/RpcTransaction.cs @@ -0,0 +1,62 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// RpcTransaction.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.Json; +using Neo.Network.P2P.Payloads; +using Neo.VM; + +namespace Neo.Network.RPC.Models +{ + public class RpcTransaction + { + public Transaction Transaction { get; set; } + + public UInt256 BlockHash { get; set; } + + public uint? Confirmations { get; set; } + + public ulong? BlockTime { get; set; } + + public VMState? VMState { get; set; } + + public JObject ToJson(ProtocolSettings protocolSettings) + { + JObject json = Utility.TransactionToJson(Transaction, protocolSettings); + if (Confirmations != null) + { + json["blockhash"] = BlockHash.ToString(); + json["confirmations"] = Confirmations; + json["blocktime"] = BlockTime; + if (VMState != null) + { + json["vmstate"] = VMState; + } + } + return json; + } + + public static RpcTransaction FromJson(JObject json, ProtocolSettings protocolSettings) + { + RpcTransaction transaction = new RpcTransaction + { + Transaction = Utility.TransactionFromJson(json, protocolSettings) + }; + if (json["confirmations"] != null) + { + transaction.BlockHash = UInt256.Parse(json["blockhash"].AsString()); + transaction.Confirmations = (uint)json["confirmations"].AsNumber(); + transaction.BlockTime = (ulong)json["blocktime"].AsNumber(); + transaction.VMState = json["vmstate"]?.GetEnum(); + } + return transaction; + } + } +} diff --git a/src/Plugins/RpcClient/Models/RpcTransferOut.cs b/src/Plugins/RpcClient/Models/RpcTransferOut.cs new file mode 100644 index 0000000000..d5e82a8468 --- /dev/null +++ b/src/Plugins/RpcClient/Models/RpcTransferOut.cs @@ -0,0 +1,45 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// RpcTransferOut.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.Json; +using Neo.Wallets; + +namespace Neo.Network.RPC.Models +{ + public class RpcTransferOut + { + public UInt160 Asset { get; set; } + + public UInt160 ScriptHash { get; set; } + + public string Value { get; set; } + + public JObject ToJson(ProtocolSettings protocolSettings) + { + return new JObject + { + ["asset"] = Asset.ToString(), + ["value"] = Value, + ["address"] = ScriptHash.ToAddress(protocolSettings.AddressVersion), + }; + } + + public static RpcTransferOut FromJson(JObject json, ProtocolSettings protocolSettings) + { + return new RpcTransferOut + { + Asset = json["asset"].ToScriptHash(protocolSettings), + Value = json["value"].AsString(), + ScriptHash = json["address"].ToScriptHash(protocolSettings), + }; + } + } +} diff --git a/src/Plugins/RpcClient/Models/RpcUnclaimedGas.cs b/src/Plugins/RpcClient/Models/RpcUnclaimedGas.cs new file mode 100644 index 0000000000..c25f527d33 --- /dev/null +++ b/src/Plugins/RpcClient/Models/RpcUnclaimedGas.cs @@ -0,0 +1,39 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// RpcUnclaimedGas.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.Json; + +namespace Neo.Network.RPC.Models +{ + public class RpcUnclaimedGas + { + public long Unclaimed { get; set; } + + public string Address { get; set; } + + public JObject ToJson() + { + JObject json = new(); + json["unclaimed"] = Unclaimed.ToString(); + json["address"] = Address; + return json; + } + + public static RpcUnclaimedGas FromJson(JObject json) + { + return new RpcUnclaimedGas + { + Unclaimed = long.Parse(json["unclaimed"].AsString()), + Address = json["address"].AsString() + }; + } + } +} diff --git a/src/Plugins/RpcClient/Models/RpcValidateAddressResult.cs b/src/Plugins/RpcClient/Models/RpcValidateAddressResult.cs new file mode 100644 index 0000000000..6f49e08f06 --- /dev/null +++ b/src/Plugins/RpcClient/Models/RpcValidateAddressResult.cs @@ -0,0 +1,39 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// RpcValidateAddressResult.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.Json; + +namespace Neo.Network.RPC.Models +{ + public class RpcValidateAddressResult + { + public string Address { get; set; } + + public bool IsValid { get; set; } + + public JObject ToJson() + { + JObject json = new(); + json["address"] = Address; + json["isvalid"] = IsValid; + return json; + } + + public static RpcValidateAddressResult FromJson(JObject json) + { + return new RpcValidateAddressResult + { + Address = json["address"].AsString(), + IsValid = json["isvalid"].AsBoolean() + }; + } + } +} diff --git a/src/Plugins/RpcClient/Models/RpcValidator.cs b/src/Plugins/RpcClient/Models/RpcValidator.cs new file mode 100644 index 0000000000..27031631e9 --- /dev/null +++ b/src/Plugins/RpcClient/Models/RpcValidator.cs @@ -0,0 +1,40 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// RpcValidator.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.Json; +using System.Numerics; + +namespace Neo.Network.RPC.Models +{ + public class RpcValidator + { + public string PublicKey { get; set; } + + public BigInteger Votes { get; set; } + + public JObject ToJson() + { + JObject json = new(); + json["publickey"] = PublicKey; + json["votes"] = Votes.ToString(); + return json; + } + + public static RpcValidator FromJson(JObject json) + { + return new RpcValidator + { + PublicKey = json["publickey"].AsString(), + Votes = BigInteger.Parse(json["votes"].AsString()), + }; + } + } +} diff --git a/src/Plugins/RpcClient/Models/RpcVersion.cs b/src/Plugins/RpcClient/Models/RpcVersion.cs new file mode 100644 index 0000000000..430d659f7c --- /dev/null +++ b/src/Plugins/RpcClient/Models/RpcVersion.cs @@ -0,0 +1,113 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// RpcVersion.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.Json; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Neo.Network.RPC.Models +{ + public class RpcVersion + { + public class RpcProtocol + { + public uint Network { get; set; } + public int ValidatorsCount { get; set; } + public uint MillisecondsPerBlock { get; set; } + public uint MaxValidUntilBlockIncrement { get; set; } + public uint MaxTraceableBlocks { get; set; } + public byte AddressVersion { get; set; } + public uint MaxTransactionsPerBlock { get; set; } + public int MemoryPoolMaxTransactions { get; set; } + public ulong InitialGasDistribution { get; set; } + public IReadOnlyDictionary Hardforks { get; set; } + + public JObject ToJson() + { + JObject json = new(); + json["network"] = Network; + json["validatorscount"] = ValidatorsCount; + json["msperblock"] = MillisecondsPerBlock; + json["maxvaliduntilblockincrement"] = MaxValidUntilBlockIncrement; + json["maxtraceableblocks"] = MaxTraceableBlocks; + json["addressversion"] = AddressVersion; + json["maxtransactionsperblock"] = MaxTransactionsPerBlock; + json["memorypoolmaxtransactions"] = MemoryPoolMaxTransactions; + json["initialgasdistribution"] = InitialGasDistribution; + json["hardforks"] = new JArray(Hardforks.Select(s => new JObject() + { + // Strip HF_ prefix. + ["name"] = StripPrefix(s.Key.ToString(), "HF_"), + ["blockheight"] = s.Value, + })); + return json; + } + + public static RpcProtocol FromJson(JObject json) + { + return new() + { + Network = (uint)json["network"].AsNumber(), + ValidatorsCount = (int)json["validatorscount"].AsNumber(), + MillisecondsPerBlock = (uint)json["msperblock"].AsNumber(), + MaxValidUntilBlockIncrement = (uint)json["maxvaliduntilblockincrement"].AsNumber(), + MaxTraceableBlocks = (uint)json["maxtraceableblocks"].AsNumber(), + AddressVersion = (byte)json["addressversion"].AsNumber(), + MaxTransactionsPerBlock = (uint)json["maxtransactionsperblock"].AsNumber(), + MemoryPoolMaxTransactions = (int)json["memorypoolmaxtransactions"].AsNumber(), + InitialGasDistribution = (ulong)json["initialgasdistribution"].AsNumber(), + Hardforks = new Dictionary(((JArray)json["hardforks"]).Select(s => + { + var name = s["name"].AsString(); + // 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()); + })), + }; + } + + private static string StripPrefix(string s, string prefix) + { + return s.StartsWith(prefix) ? s.Substring(prefix.Length) : s; + } + } + + public int TcpPort { get; set; } + + public uint Nonce { get; set; } + + public string UserAgent { get; set; } + + public RpcProtocol Protocol { get; set; } = new(); + + public JObject ToJson() + { + JObject json = new(); + json["network"] = Protocol.Network; // Obsolete + json["tcpport"] = TcpPort; + json["nonce"] = Nonce; + json["useragent"] = UserAgent; + json["protocol"] = Protocol.ToJson(); + return json; + } + + public static RpcVersion FromJson(JObject json) + { + return new() + { + TcpPort = (int)json["tcpport"].AsNumber(), + Nonce = (uint)json["nonce"].AsNumber(), + UserAgent = json["useragent"].AsString(), + Protocol = RpcProtocol.FromJson((JObject)json["protocol"]) + }; + } + } +} diff --git a/src/Plugins/RpcClient/Nep17API.cs b/src/Plugins/RpcClient/Nep17API.cs new file mode 100644 index 0000000000..518f470924 --- /dev/null +++ b/src/Plugins/RpcClient/Nep17API.cs @@ -0,0 +1,182 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Nep17API.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; +using Neo.Network.P2P.Payloads; +using Neo.Network.RPC.Models; +using Neo.SmartContract; +using Neo.VM; +using Neo.Wallets; +using System; +using System.Linq; +using System.Numerics; +using System.Threading.Tasks; +using static Neo.Helper; + +namespace Neo.Network.RPC +{ + /// + /// Call NEP17 methods with RPC API + /// + public class Nep17API : ContractClient + { + /// + /// Nep17API Constructor + /// + /// the RPC client to call NEO RPC methods + public Nep17API(RpcClient rpcClient) : base(rpcClient) { } + + /// + /// Get balance of NEP17 token + /// + /// contract script hash + /// account script hash + /// + public async Task BalanceOfAsync(UInt160 scriptHash, UInt160 account) + { + var result = await TestInvokeAsync(scriptHash, "balanceOf", account).ConfigureAwait(false); + BigInteger balance = result.Stack.Single().GetInteger(); + return balance; + } + + /// + /// Get symbol of NEP17 token + /// + /// contract script hash + /// + public async Task SymbolAsync(UInt160 scriptHash) + { + var result = await TestInvokeAsync(scriptHash, "symbol").ConfigureAwait(false); + return result.Stack.Single().GetString(); + } + + /// + /// Get decimals of NEP17 token + /// + /// contract script hash + /// + public async Task DecimalsAsync(UInt160 scriptHash) + { + var result = await TestInvokeAsync(scriptHash, "decimals").ConfigureAwait(false); + return (byte)result.Stack.Single().GetInteger(); + } + + /// + /// Get total supply of NEP17 token + /// + /// contract script hash + /// + public async Task TotalSupplyAsync(UInt160 scriptHash) + { + var result = await TestInvokeAsync(scriptHash, "totalSupply").ConfigureAwait(false); + return result.Stack.Single().GetInteger(); + } + + /// + /// Get token information in one rpc call + /// + /// contract script hash + /// + 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")); + var name = contractState.Manifest.Name; + var result = await rpcClient.InvokeScriptAsync(script).ConfigureAwait(false); + var stack = result.Stack; + + return new RpcNep17TokenInfo + { + Name = name, + Symbol = stack[0].GetString(), + Decimals = (byte)stack[1].GetInteger(), + TotalSupply = stack[2].GetInteger() + }; + } + + 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")); + var name = contractState.Manifest.Name; + var result = await rpcClient.InvokeScriptAsync(script).ConfigureAwait(false); + var stack = result.Stack; + + return new RpcNep17TokenInfo + { + Name = name, + Symbol = stack[0].GetString(), + Decimals = (byte)stack[1].GetInteger(), + TotalSupply = stack[2].GetInteger() + }; + } + + /// + /// Create NEP17 token transfer transaction + /// + /// contract script hash + /// from KeyPair + /// to account script hash + /// transfer amount + /// onPayment data + /// Add assert at the end of the script + /// + public async Task CreateTransferTxAsync(UInt160 scriptHash, KeyPair fromKey, UInt160 to, BigInteger amount, object data = null, bool addAssert = true) + { + var sender = Contract.CreateSignatureRedeemScript(fromKey.PublicKey).ToScriptHash(); + Signer[] signers = new[] { new Signer { Scopes = WitnessScope.CalledByEntry, Account = sender } }; + byte[] script = scriptHash.MakeScript("transfer", sender, to, amount, data); + if (addAssert) script = script.Concat(new[] { (byte)OpCode.ASSERT }).ToArray(); + + TransactionManagerFactory factory = new(rpcClient); + TransactionManager manager = await factory.MakeTransactionAsync(script, signers).ConfigureAwait(false); + + return await manager + .AddSignature(fromKey) + .SignAsync().ConfigureAwait(false); + } + + /// + /// Create NEP17 token transfer transaction from multi-sig account + /// + /// contract script hash + /// multi-sig min signature count + /// multi-sig pubKeys + /// sign keys + /// to account + /// transfer amount + /// onPayment data + /// Add assert at the end of the script + /// + public async Task CreateTransferTxAsync(UInt160 scriptHash, int m, ECPoint[] pubKeys, KeyPair[] fromKeys, UInt160 to, BigInteger amount, object data = null, bool addAssert = true) + { + if (m > fromKeys.Length) + throw new ArgumentException($"Need at least {m} KeyPairs for signing!"); + var sender = Contract.CreateMultiSigContract(m, pubKeys).ScriptHash; + Signer[] signers = new[] { new Signer { Scopes = WitnessScope.CalledByEntry, Account = sender } }; + byte[] script = scriptHash.MakeScript("transfer", sender, to, amount, data); + if (addAssert) script = script.Concat(new[] { (byte)OpCode.ASSERT }).ToArray(); + + TransactionManagerFactory factory = new(rpcClient); + TransactionManager manager = await factory.MakeTransactionAsync(script, signers).ConfigureAwait(false); + + return await manager + .AddMultiSig(fromKeys, m, pubKeys) + .SignAsync().ConfigureAwait(false); + } + } +} diff --git a/src/Plugins/RpcClient/PolicyAPI.cs b/src/Plugins/RpcClient/PolicyAPI.cs new file mode 100644 index 0000000000..60e749a79c --- /dev/null +++ b/src/Plugins/RpcClient/PolicyAPI.cs @@ -0,0 +1,71 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// PolicyAPI.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.Native; +using System.Linq; +using System.Threading.Tasks; + +namespace Neo.Network.RPC +{ + /// + /// Get Policy info by RPC API + /// + public class PolicyAPI : ContractClient + { + readonly UInt160 scriptHash = NativeContract.Policy.Hash; + + /// + /// PolicyAPI Constructor + /// + /// the RPC client to call NEO RPC methods + public PolicyAPI(RpcClient rpcClient) : base(rpcClient) { } + + /// + /// Get Fee Factor + /// + /// + public async Task GetExecFeeFactorAsync() + { + var result = await TestInvokeAsync(scriptHash, "getExecFeeFactor").ConfigureAwait(false); + return (uint)result.Stack.Single().GetInteger(); + } + + /// + /// Get Storage Price + /// + /// + public async Task GetStoragePriceAsync() + { + var result = await TestInvokeAsync(scriptHash, "getStoragePrice").ConfigureAwait(false); + return (uint)result.Stack.Single().GetInteger(); + } + + /// + /// Get Network Fee Per Byte + /// + /// + public async Task GetFeePerByteAsync() + { + var result = await TestInvokeAsync(scriptHash, "getFeePerByte").ConfigureAwait(false); + return (long)result.Stack.Single().GetInteger(); + } + + /// + /// Get Ploicy Blocked Accounts + /// + /// + public async Task IsBlockedAsync(UInt160 account) + { + var result = await TestInvokeAsync(scriptHash, "isBlocked", new object[] { account }).ConfigureAwait(false); + return result.Stack.Single().GetBoolean(); + } + } +} diff --git a/src/Plugins/RpcClient/Properties/AssemblyInfo.cs b/src/Plugins/RpcClient/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..d464f67da1 --- /dev/null +++ b/src/Plugins/RpcClient/Properties/AssemblyInfo.cs @@ -0,0 +1,14 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// AssemblyInfo.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.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("Neo.Network.RPC.Tests")] diff --git a/src/Plugins/RpcClient/RpcClient.cs b/src/Plugins/RpcClient/RpcClient.cs new file mode 100644 index 0000000000..27b0023ec0 --- /dev/null +++ b/src/Plugins/RpcClient/RpcClient.cs @@ -0,0 +1,712 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// RpcClient.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.IO; +using Neo.Json; +using Neo.Network.P2P.Payloads; +using Neo.Network.RPC.Models; +using Neo.SmartContract; +using Neo.SmartContract.Manifest; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +namespace Neo.Network.RPC +{ + /// + /// The RPC client to call NEO RPC methods + /// + public class RpcClient : IDisposable + { + private readonly HttpClient httpClient; + private readonly Uri baseAddress; + internal readonly ProtocolSettings protocolSettings; + + public RpcClient(Uri url, string rpcUser = default, string rpcPass = default, ProtocolSettings protocolSettings = null) + { + httpClient = new HttpClient(); + baseAddress = url; + if (!string.IsNullOrEmpty(rpcUser) && !string.IsNullOrEmpty(rpcPass)) + { + string token = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{rpcUser}:{rpcPass}")); + httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", token); + } + this.protocolSettings = protocolSettings ?? ProtocolSettings.Default; + } + + public RpcClient(HttpClient client, Uri url, ProtocolSettings protocolSettings = null) + { + httpClient = client; + baseAddress = url; + this.protocolSettings = protocolSettings ?? ProtocolSettings.Default; + } + + #region IDisposable Support + private bool disposedValue = false; // To detect redundant calls + + protected virtual void Dispose(bool disposing) + { + if (!disposedValue) + { + if (disposing) + { + httpClient.Dispose(); + } + + disposedValue = true; + } + } + + public void Dispose() + { + Dispose(true); + } + #endregion + + static RpcRequest AsRpcRequest(string method, params JToken[] paraArgs) + { + return new RpcRequest + { + Id = 1, + JsonRpc = "2.0", + Method = method, + Params = paraArgs + }; + } + + static RpcResponse AsRpcResponse(string content, bool throwOnError) + { + var response = RpcResponse.FromJson((JObject)JToken.Parse(content)); + response.RawResponse = content; + + if (response.Error != null && throwOnError) + { + throw new RpcException(response.Error.Code, response.Error.Message); + } + + return response; + } + + HttpRequestMessage AsHttpRequest(RpcRequest request) + { + var requestJson = request.ToJson().ToString(); + return new HttpRequestMessage(HttpMethod.Post, baseAddress) + { + Content = new StringContent(requestJson, Neo.Utility.StrictUTF8) + }; + } + + public RpcResponse Send(RpcRequest request, bool throwOnError = true) + { + if (disposedValue) throw new ObjectDisposedException(nameof(RpcClient)); + + using var requestMsg = AsHttpRequest(request); + using var responseMsg = httpClient.Send(requestMsg); + using var contentStream = responseMsg.Content.ReadAsStream(); + using var contentReader = new StreamReader(contentStream); + return AsRpcResponse(contentReader.ReadToEnd(), throwOnError); + } + + public async Task SendAsync(RpcRequest request, bool throwOnError = true) + { + if (disposedValue) throw new ObjectDisposedException(nameof(RpcClient)); + + using var requestMsg = AsHttpRequest(request); + using var responseMsg = await httpClient.SendAsync(requestMsg).ConfigureAwait(false); + var content = await responseMsg.Content.ReadAsStringAsync(); + return AsRpcResponse(content, throwOnError); + } + + public virtual JToken RpcSend(string method, params JToken[] paraArgs) + { + var request = AsRpcRequest(method, paraArgs); + var response = Send(request); + return response.Result; + } + + public virtual async Task RpcSendAsync(string method, params JToken[] paraArgs) + { + var request = AsRpcRequest(method, paraArgs); + var response = await SendAsync(request).ConfigureAwait(false); + return response.Result; + } + + public static string GetRpcName([CallerMemberName] string methodName = null) + { + return new Regex("(.*?)(Hex|Both)?(Async)?").Replace(methodName, "$1").ToLowerInvariant(); + } + + #region Blockchain + + /// + /// Returns the hash of the tallest block in the main chain. + /// + public async Task GetBestBlockHashAsync() + { + var result = await RpcSendAsync(GetRpcName()).ConfigureAwait(false); + return result.AsString(); + } + + /// + /// Returns the hash of the tallest block in the main chain. + /// The serialized information of the block is returned, represented by a hexadecimal string. + /// + public async Task GetBlockHexAsync(string hashOrIndex) + { + var result = int.TryParse(hashOrIndex, out int index) + ? await RpcSendAsync(GetRpcName(), index).ConfigureAwait(false) + : await RpcSendAsync(GetRpcName(), hashOrIndex).ConfigureAwait(false); + return result.AsString(); + } + + /// + /// Returns the hash of the tallest block in the main chain. + /// + public async Task GetBlockAsync(string hashOrIndex) + { + var result = int.TryParse(hashOrIndex, out int index) + ? await RpcSendAsync(GetRpcName(), index, true).ConfigureAwait(false) + : await RpcSendAsync(GetRpcName(), hashOrIndex, true).ConfigureAwait(false); + + return RpcBlock.FromJson((JObject)result, protocolSettings); + } + + /// + /// Gets the number of block header in the main chain. + /// + public async Task GetBlockHeaderCountAsync() + { + var result = await RpcSendAsync(GetRpcName()).ConfigureAwait(false); + return (uint)result.AsNumber(); + } + + /// + /// Gets the number of blocks in the main chain. + /// + public async Task GetBlockCountAsync() + { + var result = await RpcSendAsync(GetRpcName()).ConfigureAwait(false); + return (uint)result.AsNumber(); + } + + /// + /// Returns the hash value of the corresponding block, based on the specified index. + /// + public async Task GetBlockHashAsync(uint index) + { + var result = await RpcSendAsync(GetRpcName(), index).ConfigureAwait(false); + return result.AsString(); + } + + /// + /// Returns the corresponding block header information according to the specified script hash. + /// + public async Task GetBlockHeaderHexAsync(string hashOrIndex) + { + var result = int.TryParse(hashOrIndex, out int index) + ? await RpcSendAsync(GetRpcName(), index).ConfigureAwait(false) + : await RpcSendAsync(GetRpcName(), hashOrIndex).ConfigureAwait(false); + return result.AsString(); + } + + /// + /// Returns the corresponding block header information according to the specified script hash. + /// + public async Task GetBlockHeaderAsync(string hashOrIndex) + { + var result = int.TryParse(hashOrIndex, out int index) + ? await RpcSendAsync(GetRpcName(), index, true).ConfigureAwait(false) + : await RpcSendAsync(GetRpcName(), hashOrIndex, true).ConfigureAwait(false); + + return RpcBlockHeader.FromJson((JObject)result, protocolSettings); + } + + /// + /// Queries contract information, according to the contract script hash. + /// + public async Task GetContractStateAsync(string hash) + { + var result = await RpcSendAsync(GetRpcName(), hash).ConfigureAwait(false); + return ContractStateFromJson((JObject)result); + } + + /// + /// Queries contract information, according to the contract id. + /// + public async Task GetContractStateAsync(int id) + { + var result = await RpcSendAsync(GetRpcName(), id).ConfigureAwait(false); + return ContractStateFromJson((JObject)result); + } + + public static ContractState ContractStateFromJson(JObject json) + { + return new ContractState + { + Id = (int)json["id"].AsNumber(), + UpdateCounter = (ushort)(json["updatecounter"]?.AsNumber() ?? 0), + Hash = UInt160.Parse(json["hash"].AsString()), + Nef = RpcNefFile.FromJson((JObject)json["nef"]), + Manifest = ContractManifest.FromJson((JObject)json["manifest"]) + }; + } + + /// + /// Get all native contracts. + /// + public async Task GetNativeContractsAsync() + { + var result = await RpcSendAsync(GetRpcName()).ConfigureAwait(false); + return ((JArray)result).Select(p => ContractStateFromJson((JObject)p)).ToArray(); + } + + /// + /// Obtains the list of unconfirmed transactions in memory. + /// + public async Task GetRawMempoolAsync() + { + var result = await RpcSendAsync(GetRpcName()).ConfigureAwait(false); + return ((JArray)result).Select(p => p.AsString()).ToArray(); + } + + /// + /// Obtains the list of unconfirmed transactions in memory. + /// shouldGetUnverified = true + /// + public async Task GetRawMempoolBothAsync() + { + var result = await RpcSendAsync(GetRpcName(), true).ConfigureAwait(false); + return RpcRawMemPool.FromJson((JObject)result); + } + + /// + /// Returns the corresponding transaction information, based on the specified hash value. + /// + public async Task GetRawTransactionHexAsync(string txHash) + { + var result = await RpcSendAsync(GetRpcName(), txHash).ConfigureAwait(false); + return result.AsString(); + } + + /// + /// Returns the corresponding transaction information, based on the specified hash value. + /// verbose = true + /// + public async Task GetRawTransactionAsync(string txHash) + { + var result = await RpcSendAsync(GetRpcName(), txHash, true).ConfigureAwait(false); + return RpcTransaction.FromJson((JObject)result, protocolSettings); + } + + /// + /// Calculate network fee + /// + /// Transaction + /// NetworkFee + public async Task CalculateNetworkFeeAsync(Transaction tx) + { + var json = await RpcSendAsync(GetRpcName(), Convert.ToBase64String(tx.ToArray())) + .ConfigureAwait(false); + return (long)json["networkfee"].AsNumber(); + } + + /// + /// Returns the stored value, according to the contract script hash (or Id) and the stored key. + /// + public async Task GetStorageAsync(string scriptHashOrId, string key) + { + var result = int.TryParse(scriptHashOrId, out int id) + ? await RpcSendAsync(GetRpcName(), id, key).ConfigureAwait(false) + : await RpcSendAsync(GetRpcName(), scriptHashOrId, key).ConfigureAwait(false); + return result.AsString(); + } + + /// + /// Returns the block index in which the transaction is found. + /// + public async Task GetTransactionHeightAsync(string txHash) + { + var result = await RpcSendAsync(GetRpcName(), txHash).ConfigureAwait(false); + return uint.Parse(result.AsString()); + } + + /// + /// Returns the next NEO consensus nodes information and voting status. + /// + public async Task GetNextBlockValidatorsAsync() + { + var result = await RpcSendAsync(GetRpcName()).ConfigureAwait(false); + return ((JArray)result).Select(p => RpcValidator.FromJson((JObject)p)).ToArray(); + } + + /// + /// Returns the current NEO committee members. + /// + public async Task GetCommitteeAsync() + { + var result = await RpcSendAsync(GetRpcName()).ConfigureAwait(false); + return ((JArray)result).Select(p => p.AsString()).ToArray(); + } + + #endregion Blockchain + + #region Node + + /// + /// Gets the current number of connections for the node. + /// + public async Task GetConnectionCountAsync() + { + var result = await RpcSendAsync(GetRpcName()).ConfigureAwait(false); + return (int)result.AsNumber(); + } + + /// + /// Gets the list of nodes that the node is currently connected/disconnected from. + /// + public async Task GetPeersAsync() + { + var result = await RpcSendAsync(GetRpcName()).ConfigureAwait(false); + return RpcPeers.FromJson((JObject)result); + } + + /// + /// Returns the version information about the queried node. + /// + public async Task GetVersionAsync() + { + var result = await RpcSendAsync(GetRpcName()).ConfigureAwait(false); + return RpcVersion.FromJson((JObject)result); + } + + /// + /// Broadcasts a serialized transaction over the NEO network. + /// + public async Task SendRawTransactionAsync(byte[] rawTransaction) + { + var result = await RpcSendAsync(GetRpcName(), Convert.ToBase64String(rawTransaction)).ConfigureAwait(false); + return UInt256.Parse(result["hash"].AsString()); + } + + /// + /// Broadcasts a transaction over the NEO network. + /// + public Task SendRawTransactionAsync(Transaction transaction) + { + return SendRawTransactionAsync(transaction.ToArray()); + } + + /// + /// Broadcasts a serialized block over the NEO network. + /// + public async Task SubmitBlockAsync(byte[] block) + { + var result = await RpcSendAsync(GetRpcName(), Convert.ToBase64String(block)).ConfigureAwait(false); + return UInt256.Parse(result["hash"].AsString()); + } + + #endregion Node + + #region SmartContract + + /// + /// Returns the result after calling a smart contract at scripthash with the given operation and parameters. + /// This RPC call does not affect the blockchain in any way. + /// + public async Task InvokeFunctionAsync(string scriptHash, string operation, RpcStack[] stacks, params Signer[] signer) + { + List parameters = new() { scriptHash.AsScriptHash(), operation, stacks.Select(p => p.ToJson()).ToArray() }; + if (signer.Length > 0) + { + parameters.Add(signer.Select(p => p.ToJson()).ToArray()); + } + var result = await RpcSendAsync(GetRpcName(), parameters.ToArray()).ConfigureAwait(false); + return RpcInvokeResult.FromJson((JObject)result); + } + + /// + /// Returns the result after passing a script through the VM. + /// This RPC call does not affect the blockchain in any way. + /// + public async Task InvokeScriptAsync(ReadOnlyMemory script, params Signer[] signers) + { + List parameters = new() { Convert.ToBase64String(script.Span) }; + if (signers.Length > 0) + { + parameters.Add(signers.Select(p => p.ToJson()).ToArray()); + } + var result = await RpcSendAsync(GetRpcName(), parameters.ToArray()).ConfigureAwait(false); + return RpcInvokeResult.FromJson((JObject)result); + } + + public async Task GetUnclaimedGasAsync(string address) + { + var result = await RpcSendAsync(GetRpcName(), address.AsScriptHash()).ConfigureAwait(false); + return RpcUnclaimedGas.FromJson((JObject)result); + } + + + public async IAsyncEnumerable TraverseIteratorAsync(string sessionId, string id) + { + const int count = 100; + while (true) + { + var result = await RpcSendAsync(GetRpcName(), sessionId, id, count).ConfigureAwait(false); + var array = (JArray)result; + foreach (JObject jObject in array) + { + yield return jObject; + } + if (array.Count < count) break; + } + } + + /// + /// Returns limit results from Iterator. + /// This RPC call does not affect the blockchain in any way. + /// + /// + /// + /// + /// + public async IAsyncEnumerable TraverseIteratorAsync(string sessionId, string id, int count) + { + var result = await RpcSendAsync(GetRpcName(), sessionId, id, count).ConfigureAwait(false); + if (result is JArray { Count: > 0 } array) + { + foreach (JObject jObject in array) + { + yield return jObject; + } + } + } + + /// + /// Terminate specified Iterator session. + /// This RPC call does not affect the blockchain in any way. + /// + public async Task TerminateSessionAsync(string sessionId) + { + var result = await RpcSendAsync(GetRpcName(), sessionId).ConfigureAwait(false); + return result.GetBoolean(); + } + + #endregion SmartContract + + #region Utilities + + /// + /// Returns a list of plugins loaded by the node. + /// + public async Task ListPluginsAsync() + { + var result = await RpcSendAsync(GetRpcName()).ConfigureAwait(false); + return ((JArray)result).Select(p => RpcPlugin.FromJson((JObject)p)).ToArray(); + } + + /// + /// Verifies that the address is a correct NEO address. + /// + public async Task ValidateAddressAsync(string address) + { + var result = await RpcSendAsync(GetRpcName(), address).ConfigureAwait(false); + return RpcValidateAddressResult.FromJson((JObject)result); + } + + #endregion Utilities + + #region Wallet + + /// + /// Close the wallet opened by RPC. + /// + public async Task CloseWalletAsync() + { + var result = await RpcSendAsync(GetRpcName()).ConfigureAwait(false); + return result.AsBoolean(); + } + + /// + /// Exports the private key of the specified address. + /// + public async Task DumpPrivKeyAsync(string address) + { + var result = await RpcSendAsync(GetRpcName(), address).ConfigureAwait(false); + return result.AsString(); + } + + /// + /// Creates a new account in the wallet opened by RPC. + /// + public async Task GetNewAddressAsync() + { + var result = await RpcSendAsync(GetRpcName()).ConfigureAwait(false); + return result.AsString(); + } + + /// + /// Returns the balance of the corresponding asset in the wallet, based on the specified asset Id. + /// This method applies to assets that conform to NEP-17 standards. + /// + /// new address as string + public async Task GetWalletBalanceAsync(string assetId) + { + var result = await RpcSendAsync(GetRpcName(), assetId).ConfigureAwait(false); + BigInteger balance = BigInteger.Parse(result["balance"].AsString()); + byte decimals = await new Nep17API(this).DecimalsAsync(UInt160.Parse(assetId.AsScriptHash())).ConfigureAwait(false); + return new BigDecimal(balance, decimals); + } + + /// + /// Gets the amount of unclaimed GAS in the wallet. + /// + public async Task GetWalletUnclaimedGasAsync() + { + var result = await RpcSendAsync(GetRpcName()).ConfigureAwait(false); + return BigDecimal.Parse(result.AsString(), SmartContract.Native.NativeContract.GAS.Decimals); + } + + /// + /// Imports the private key to the wallet. + /// + public async Task ImportPrivKeyAsync(string wif) + { + var result = await RpcSendAsync(GetRpcName(), wif).ConfigureAwait(false); + return RpcAccount.FromJson((JObject)result); + } + + /// + /// Lists all the accounts in the current wallet. + /// + public async Task> ListAddressAsync() + { + var result = await RpcSendAsync(GetRpcName()).ConfigureAwait(false); + return ((JArray)result).Select(p => RpcAccount.FromJson((JObject)p)).ToList(); + } + + /// + /// Open wallet file in the provider's machine. + /// By default, this method is disabled by RpcServer config.json. + /// + public async Task OpenWalletAsync(string path, string password) + { + var result = await RpcSendAsync(GetRpcName(), path, password).ConfigureAwait(false); + return result.AsBoolean(); + } + + /// + /// Transfer from the specified address to the destination address. + /// + /// This function returns Signed Transaction JSON if successful, ContractParametersContext JSON if signing failed. + public async Task SendFromAsync(string assetId, string fromAddress, string toAddress, string amount) + { + return (JObject)await RpcSendAsync(GetRpcName(), assetId.AsScriptHash(), fromAddress.AsScriptHash(), + toAddress.AsScriptHash(), amount).ConfigureAwait(false); + } + + /// + /// Bulk transfer order, and you can specify a sender address. + /// + /// This function returns Signed Transaction JSON if successful, ContractParametersContext JSON if signing failed. + public async Task SendManyAsync(string fromAddress, IEnumerable outputs) + { + var parameters = new List(); + if (!string.IsNullOrEmpty(fromAddress)) + { + parameters.Add(fromAddress.AsScriptHash()); + } + parameters.Add(outputs.Select(p => p.ToJson(protocolSettings)).ToArray()); + + return (JObject)await RpcSendAsync(GetRpcName(), paraArgs: parameters.ToArray()).ConfigureAwait(false); + } + + /// + /// Transfer asset from the wallet to the destination address. + /// + /// This function returns Signed Transaction JSON if successful, ContractParametersContext JSON if signing failed. + public async Task SendToAddressAsync(string assetId, string address, string amount) + { + return (JObject)await RpcSendAsync(GetRpcName(), assetId.AsScriptHash(), address.AsScriptHash(), amount) + .ConfigureAwait(false); + } + + /// + /// Cancel Tx. + /// + /// This function returns Signed Transaction JSON if successful, ContractParametersContext JSON if signing failed. + public async Task CancelTransactionAsync(UInt256 txId, string[] signers, string extraFee) + { + JToken[] parameters = signers.Select(s => (JString)s.AsScriptHash()).ToArray(); + return (JObject)await RpcSendAsync(GetRpcName(), txId.ToString(), new JArray(parameters), extraFee).ConfigureAwait(false); + } + + #endregion Wallet + + #region Plugins + + /// + /// Returns the contract log based on the specified txHash. The complete contract logs are stored under the ApplicationLogs directory. + /// This method is provided by the plugin ApplicationLogs. + /// + public async Task GetApplicationLogAsync(string txHash) + { + var result = await RpcSendAsync(GetRpcName(), txHash).ConfigureAwait(false); + return RpcApplicationLog.FromJson((JObject)result, protocolSettings); + } + + /// + /// Returns the contract log based on the specified txHash. The complete contract logs are stored under the ApplicationLogs directory. + /// This method is provided by the plugin ApplicationLogs. + /// + public async Task GetApplicationLogAsync(string txHash, TriggerType triggerType) + { + var result = await RpcSendAsync(GetRpcName(), txHash, triggerType).ConfigureAwait(false); + return RpcApplicationLog.FromJson((JObject)result, protocolSettings); + } + + /// + /// Returns all the NEP-17 transaction information occurred in the specified address. + /// This method is provided by the plugin RpcNep17Tracker. + /// + /// The address to query the transaction information. + /// The start block Timestamp, default to seven days before UtcNow + /// The end block Timestamp, default to UtcNow + public async Task GetNep17TransfersAsync(string address, ulong? startTimestamp = default, ulong? endTimestamp = default) + { + startTimestamp ??= 0; + endTimestamp ??= DateTime.UtcNow.ToTimestampMS(); + var result = await RpcSendAsync(GetRpcName(), address.AsScriptHash(), startTimestamp, endTimestamp) + .ConfigureAwait(false); + return RpcNep17Transfers.FromJson((JObject)result, protocolSettings); + } + + /// + /// Returns the balance of all NEP-17 assets in the specified address. + /// This method is provided by the plugin RpcNep17Tracker. + /// + public async Task GetNep17BalancesAsync(string address) + { + var result = await RpcSendAsync(GetRpcName(), address.AsScriptHash()) + .ConfigureAwait(false); + return RpcNep17Balances.FromJson((JObject)result, protocolSettings); + } + + #endregion Plugins + } +} diff --git a/src/Plugins/RpcClient/RpcClient.csproj b/src/Plugins/RpcClient/RpcClient.csproj new file mode 100644 index 0000000000..cc634337d5 --- /dev/null +++ b/src/Plugins/RpcClient/RpcClient.csproj @@ -0,0 +1,13 @@ + + + + net8.0 + Neo.Network.RPC.RpcClient + Neo.Network.RPC + + + + + + + diff --git a/src/Plugins/RpcClient/RpcException.cs b/src/Plugins/RpcClient/RpcException.cs new file mode 100644 index 0000000000..d0f2e5e64b --- /dev/null +++ b/src/Plugins/RpcClient/RpcException.cs @@ -0,0 +1,23 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// RpcException.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; + +namespace Neo.Network.RPC +{ + public class RpcException : Exception + { + public RpcException(int code, string message) : base(message) + { + HResult = code; + } + } +} diff --git a/src/Plugins/RpcClient/StateAPI.cs b/src/Plugins/RpcClient/StateAPI.cs new file mode 100644 index 0000000000..de8baa8077 --- /dev/null +++ b/src/Plugins/RpcClient/StateAPI.cs @@ -0,0 +1,88 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// StateAPI.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.Json; +using Neo.Network.RPC.Models; +using System; +using System.Threading.Tasks; + +namespace Neo.Network.RPC +{ + public class StateAPI + { + private readonly RpcClient rpcClient; + + public StateAPI(RpcClient rpc) + { + rpcClient = rpc; + } + + public async Task GetStateRootAsync(uint index) + { + var result = await rpcClient.RpcSendAsync(RpcClient.GetRpcName(), index).ConfigureAwait(false); + return RpcStateRoot.FromJson((JObject)result); + } + + public async Task GetProofAsync(UInt256 rootHash, UInt160 scriptHash, byte[] key) + { + var result = await rpcClient.RpcSendAsync(RpcClient.GetRpcName(), + rootHash.ToString(), scriptHash.ToString(), Convert.ToBase64String(key)).ConfigureAwait(false); + return Convert.FromBase64String(result.AsString()); + } + + public async Task VerifyProofAsync(UInt256 rootHash, byte[] proofBytes) + { + var result = await rpcClient.RpcSendAsync(RpcClient.GetRpcName(), + rootHash.ToString(), Convert.ToBase64String(proofBytes)).ConfigureAwait(false); + + return Convert.FromBase64String(result.AsString()); + } + + public async Task<(uint? localRootIndex, uint? validatedRootIndex)> GetStateHeightAsync() + { + var result = await rpcClient.RpcSendAsync(RpcClient.GetRpcName()).ConfigureAwait(false); + var localRootIndex = ToNullableUint(result["localrootindex"]); + var validatedRootIndex = ToNullableUint(result["validatedrootindex"]); + return (localRootIndex, validatedRootIndex); + } + + static uint? ToNullableUint(JToken json) => (json == null) ? null : (uint?)json.AsNumber(); + + public static JToken[] MakeFindStatesParams(UInt256 rootHash, UInt160 scriptHash, ReadOnlySpan prefix, ReadOnlySpan from = default, int? count = null) + { + var @params = new JToken[count.HasValue ? 5 : 4]; + @params[0] = rootHash.ToString(); + @params[1] = scriptHash.ToString(); + @params[2] = Convert.ToBase64String(prefix); + @params[3] = Convert.ToBase64String(from); + if (count.HasValue) + { + @params[4] = count.Value; + } + return @params; + } + + public async Task FindStatesAsync(UInt256 rootHash, UInt160 scriptHash, ReadOnlyMemory prefix, ReadOnlyMemory from = default, int? count = null) + { + var @params = MakeFindStatesParams(rootHash, scriptHash, prefix.Span, from.Span, count); + var result = await rpcClient.RpcSendAsync(RpcClient.GetRpcName(), @params).ConfigureAwait(false); + + return RpcFoundStates.FromJson((JObject)result); + } + + public async Task GetStateAsync(UInt256 rootHash, UInt160 scriptHash, byte[] key) + { + var result = await rpcClient.RpcSendAsync(RpcClient.GetRpcName(), + rootHash.ToString(), scriptHash.ToString(), Convert.ToBase64String(key)).ConfigureAwait(false); + return Convert.FromBase64String(result.AsString()); + } + } +} diff --git a/src/Plugins/RpcClient/TransactionManager.cs b/src/Plugins/RpcClient/TransactionManager.cs new file mode 100644 index 0000000000..ac20eed450 --- /dev/null +++ b/src/Plugins/RpcClient/TransactionManager.cs @@ -0,0 +1,215 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// TransactionManager.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; +using Neo.IO; +using Neo.Network.P2P.Payloads; +using Neo.SmartContract; +using Neo.SmartContract.Native; +using Neo.Wallets; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Neo.Network.RPC +{ + /// + /// This class helps to create transaction with RPC API. + /// + public class TransactionManager + { + private class SignItem { public Contract Contract; public HashSet KeyPairs; } + + private readonly RpcClient rpcClient; + + /// + /// The Transaction context to manage the witnesses + /// + private readonly ContractParametersContext context; + + /// + /// This container stores the keys for sign the transaction + /// + private readonly List signStore = new List(); + + /// + /// The Transaction managed by this instance + /// + private readonly Transaction tx; + + public Transaction Tx => tx; + + /// + /// TransactionManager Constructor + /// + /// the transaction to manage. Typically buildt + /// the RPC client to call NEO RPC API + public TransactionManager(Transaction tx, RpcClient rpcClient) + { + this.tx = tx; + context = new ContractParametersContext(null, tx, rpcClient.protocolSettings.Network); + this.rpcClient = rpcClient; + } + + /// + /// Helper function for one-off TransactionManager creation + /// + public static Task MakeTransactionAsync(RpcClient rpcClient, ReadOnlyMemory script, Signer[] signers = null, TransactionAttribute[] attributes = null) + { + var factory = new TransactionManagerFactory(rpcClient); + return factory.MakeTransactionAsync(script, signers, attributes); + } + + /// + /// Helper function for one-off TransactionManager creation + /// + public static Task MakeTransactionAsync(RpcClient rpcClient, ReadOnlyMemory script, long systemFee, Signer[] signers = null, TransactionAttribute[] attributes = null) + { + var factory = new TransactionManagerFactory(rpcClient); + return factory.MakeTransactionAsync(script, systemFee, signers, attributes); + } + + /// + /// Add Signature + /// + /// The KeyPair to sign transction + /// + public TransactionManager AddSignature(KeyPair key) + { + var contract = Contract.CreateSignatureContract(key.PublicKey); + AddSignItem(contract, key); + return this; + } + + /// + /// Add Multi-Signature + /// + /// The KeyPair to sign transction + /// The least count of signatures needed for multiple signature contract + /// The Public Keys construct the multiple signature contract + public TransactionManager AddMultiSig(KeyPair key, int m, params ECPoint[] publicKeys) + { + Contract contract = Contract.CreateMultiSigContract(m, publicKeys); + AddSignItem(contract, key); + return this; + } + + /// + /// Add Multi-Signature + /// + /// The KeyPairs to sign transction + /// The least count of signatures needed for multiple signature contract + /// The Public Keys construct the multiple signature contract + public TransactionManager AddMultiSig(KeyPair[] keys, int m, params ECPoint[] publicKeys) + { + Contract contract = Contract.CreateMultiSigContract(m, publicKeys); + for (int i = 0; i < keys.Length; i++) + { + AddSignItem(contract, keys[i]); + } + return this; + } + + private void AddSignItem(Contract contract, KeyPair key) + { + if (!Tx.GetScriptHashesForVerifying(null).Contains(contract.ScriptHash)) + { + throw new Exception($"Add SignItem error: Mismatch ScriptHash ({contract.ScriptHash})"); + } + + SignItem item = signStore.FirstOrDefault(p => p.Contract.ScriptHash == contract.ScriptHash); + if (item is null) + { + signStore.Add(new SignItem { Contract = contract, KeyPairs = new HashSet { key } }); + } + else if (!item.KeyPairs.Contains(key)) + { + item.KeyPairs.Add(key); + } + } + + /// + /// Add Witness with contract + /// + /// The witness verification contract + /// The witness invocation parameters + public TransactionManager AddWitness(Contract contract, params object[] parameters) + { + if (!context.Add(contract, parameters)) + { + throw new Exception("AddWitness failed!"); + }; + return this; + } + + /// + /// Add Witness with scriptHash + /// + /// The witness verification contract hash + /// The witness invocation parameters + public TransactionManager AddWitness(UInt160 scriptHash, params object[] parameters) + { + var contract = Contract.Create(scriptHash); + return AddWitness(contract, parameters); + } + + /// + /// Verify Witness count and add witnesses + /// + public async Task SignAsync() + { + // Calculate NetworkFee + Tx.Witnesses = Tx.GetScriptHashesForVerifying(null).Select(u => new Witness() + { + InvocationScript = Array.Empty(), + VerificationScript = GetVerificationScript(u) + }).ToArray(); + Tx.NetworkFee = await rpcClient.CalculateNetworkFeeAsync(Tx).ConfigureAwait(false); + Tx.Witnesses = null; + + var gasBalance = await new Nep17API(rpcClient).BalanceOfAsync(NativeContract.GAS.Hash, Tx.Sender).ConfigureAwait(false); + if (gasBalance < Tx.SystemFee + Tx.NetworkFee) + throw new InvalidOperationException($"Insufficient GAS in address: {Tx.Sender.ToAddress(rpcClient.protocolSettings.AddressVersion)}"); + + // Sign with signStore + for (int i = 0; i < signStore.Count; i++) + { + foreach (var key in signStore[i].KeyPairs) + { + byte[] signature = Tx.Sign(key, rpcClient.protocolSettings.Network); + if (!context.AddSignature(signStore[i].Contract, key.PublicKey, signature)) + { + throw new Exception("AddSignature failed!"); + } + } + } + + // Verify witness count + if (!context.Completed) + { + throw new Exception($"Please add signature or witness first!"); + } + Tx.Witnesses = context.GetWitnesses(); + return Tx; + } + + private byte[] GetVerificationScript(UInt160 hash) + { + foreach (var item in signStore) + { + if (item.Contract.ScriptHash == hash) return item.Contract.Script; + } + + return Array.Empty(); + } + } +} diff --git a/src/Plugins/RpcClient/TransactionManagerFactory.cs b/src/Plugins/RpcClient/TransactionManagerFactory.cs new file mode 100644 index 0000000000..3fe9e3ded5 --- /dev/null +++ b/src/Plugins/RpcClient/TransactionManagerFactory.cs @@ -0,0 +1,71 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// TransactionManagerFactory.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.Payloads; +using Neo.Network.RPC.Models; +using System; +using System.Threading.Tasks; + +namespace Neo.Network.RPC +{ + public class TransactionManagerFactory + { + private readonly RpcClient rpcClient; + + /// + /// TransactionManagerFactory Constructor + /// + /// the RPC client to call NEO RPC API + public TransactionManagerFactory(RpcClient rpcClient) + { + this.rpcClient = rpcClient; + } + + /// + /// Create an unsigned Transaction object with given parameters. + /// + /// Transaction Script + /// Transaction Signers + /// Transaction Attributes + /// + public async Task MakeTransactionAsync(ReadOnlyMemory script, Signer[] signers = null, TransactionAttribute[] attributes = null) + { + RpcInvokeResult invokeResult = await rpcClient.InvokeScriptAsync(script, signers).ConfigureAwait(false); + return await MakeTransactionAsync(script, invokeResult.GasConsumed, signers, attributes).ConfigureAwait(false); + } + + /// + /// Create an unsigned Transaction object with given parameters. + /// + /// Transaction Script + /// Transaction System Fee + /// Transaction Signers + /// Transaction Attributes + /// + public async Task MakeTransactionAsync(ReadOnlyMemory script, long systemFee, Signer[] signers = null, TransactionAttribute[] attributes = null) + { + uint blockCount = await rpcClient.GetBlockCountAsync().ConfigureAwait(false) - 1; + + var tx = new Transaction + { + Version = 0, + Nonce = (uint)new Random().Next(), + Script = script, + Signers = signers ?? Array.Empty(), + ValidUntilBlock = blockCount - 1 + rpcClient.protocolSettings.MaxValidUntilBlockIncrement, + SystemFee = systemFee, + Attributes = attributes ?? Array.Empty(), + }; + + return new TransactionManager(tx, rpcClient); + } + } +} diff --git a/src/Plugins/RpcClient/Utility.cs b/src/Plugins/RpcClient/Utility.cs new file mode 100644 index 0000000000..659942f8f8 --- /dev/null +++ b/src/Plugins/RpcClient/Utility.cs @@ -0,0 +1,298 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Utility.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; +using Neo.Json; +using Neo.Network.P2P.Payloads; +using Neo.Network.P2P.Payloads.Conditions; +using Neo.SmartContract; +using Neo.SmartContract.Native; +using Neo.VM.Types; +using Neo.Wallets; +using System; +using System.Linq; +using System.Numerics; +using Array = Neo.VM.Types.Array; +using Buffer = Neo.VM.Types.Buffer; + +namespace Neo.Network.RPC +{ + public static class Utility + { + private static (BigInteger numerator, BigInteger denominator) Fraction(decimal d) + { + int[] bits = decimal.GetBits(d); + BigInteger numerator = (1 - ((bits[3] >> 30) & 2)) * + unchecked(((BigInteger)(uint)bits[2] << 64) | + ((BigInteger)(uint)bits[1] << 32) | + (uint)bits[0]); + BigInteger denominator = BigInteger.Pow(10, (bits[3] >> 16) & 0xff); + return (numerator, denominator); + } + + public static UInt160 ToScriptHash(this JToken value, ProtocolSettings protocolSettings) + { + var addressOrScriptHash = value.AsString(); + + return addressOrScriptHash.Length < 40 ? + addressOrScriptHash.ToScriptHash(protocolSettings.AddressVersion) : UInt160.Parse(addressOrScriptHash); + } + + public static string AsScriptHash(this string addressOrScriptHash) + { + foreach (var native in NativeContract.Contracts) + { + if (addressOrScriptHash.Equals(native.Name, StringComparison.InvariantCultureIgnoreCase) || + addressOrScriptHash == native.Id.ToString()) + return native.Hash.ToString(); + } + + return addressOrScriptHash.Length < 40 ? + addressOrScriptHash : UInt160.Parse(addressOrScriptHash).ToString(); + } + + /// + /// Parse WIF or private key hex string to KeyPair + /// + /// WIF or private key hex string + /// Example: WIF ("KyXwTh1hB76RRMquSvnxZrJzQx7h9nQP2PCRL38v6VDb5ip3nf1p"), PrivateKey ("450d6c2a04b5b470339a745427bae6828400cf048400837d73c415063835e005") + /// + public static KeyPair GetKeyPair(string key) + { + if (string.IsNullOrEmpty(key)) { throw new ArgumentNullException(nameof(key)); } + if (key.StartsWith("0x")) { key = key[2..]; } + + return key.Length switch + { + 52 => new KeyPair(Wallet.GetPrivateKeyFromWIF(key)), + 64 => new KeyPair(key.HexToBytes()), + _ => throw new FormatException() + }; + } + + /// + /// Parse address, scripthash or public key string to UInt160 + /// + /// account address, scripthash or public key string + /// Example: address ("Ncm9TEzrp8SSer6Wa3UCSLTRnqzwVhCfuE"), scripthash ("0xb0a31817c80ad5f87b6ed390ecb3f9d312f7ceb8"), public key ("02f9ec1fd0a98796cf75b586772a4ddd41a0af07a1dbdf86a7238f74fb72503575") + /// The protocol settings + /// + public static UInt160 GetScriptHash(string account, ProtocolSettings protocolSettings) + { + if (string.IsNullOrEmpty(account)) { throw new ArgumentNullException(nameof(account)); } + if (account.StartsWith("0x")) { account = account[2..]; } + + return account.Length switch + { + 34 => account.ToScriptHash(protocolSettings.AddressVersion), + 40 => UInt160.Parse(account), + 66 => Contract.CreateSignatureRedeemScript(ECPoint.Parse(account, ECCurve.Secp256r1)).ToScriptHash(), + _ => throw new FormatException(), + }; + } + + /// + /// Convert decimal amount to BigInteger: amount * 10 ^ decimals + /// + /// float value + /// token decimals + /// + public static BigInteger ToBigInteger(this decimal amount, uint decimals) + { + BigInteger factor = BigInteger.Pow(10, (int)decimals); + var (numerator, denominator) = Fraction(amount); + if (factor < denominator) + { + throw new ArgumentException("The decimal places is too long."); + } + + BigInteger res = factor * numerator / denominator; + return res; + } + + public static Block BlockFromJson(JObject json, ProtocolSettings protocolSettings) + { + return new Block() + { + Header = HeaderFromJson(json, protocolSettings), + Transactions = ((JArray)json["tx"]).Select(p => TransactionFromJson((JObject)p, protocolSettings)).ToArray() + }; + } + + public static JObject BlockToJson(Block block, ProtocolSettings protocolSettings) + { + JObject json = block.ToJson(protocolSettings); + json["tx"] = block.Transactions.Select(p => TransactionToJson(p, protocolSettings)).ToArray(); + return json; + } + + public static Header HeaderFromJson(JObject json, ProtocolSettings protocolSettings) + { + return new Header + { + Version = (uint)json["version"].AsNumber(), + PrevHash = UInt256.Parse(json["previousblockhash"].AsString()), + MerkleRoot = UInt256.Parse(json["merkleroot"].AsString()), + Timestamp = (ulong)json["time"].AsNumber(), + Nonce = Convert.ToUInt64(json["nonce"].AsString(), 16), + Index = (uint)json["index"].AsNumber(), + PrimaryIndex = (byte)json["primary"].AsNumber(), + NextConsensus = json["nextconsensus"].ToScriptHash(protocolSettings), + Witness = ((JArray)json["witnesses"]).Select(p => WitnessFromJson((JObject)p)).FirstOrDefault() + }; + } + + public static Transaction TransactionFromJson(JObject json, ProtocolSettings protocolSettings) + { + return new Transaction + { + Version = byte.Parse(json["version"].AsString()), + Nonce = uint.Parse(json["nonce"].AsString()), + Signers = ((JArray)json["signers"]).Select(p => SignerFromJson((JObject)p, protocolSettings)).ToArray(), + SystemFee = long.Parse(json["sysfee"].AsString()), + NetworkFee = long.Parse(json["netfee"].AsString()), + ValidUntilBlock = uint.Parse(json["validuntilblock"].AsString()), + Attributes = ((JArray)json["attributes"]).Select(p => TransactionAttributeFromJson((JObject)p)).ToArray(), + Script = Convert.FromBase64String(json["script"].AsString()), + Witnesses = ((JArray)json["witnesses"]).Select(p => WitnessFromJson((JObject)p)).ToArray() + }; + } + + public static JObject TransactionToJson(Transaction tx, ProtocolSettings protocolSettings) + { + JObject json = tx.ToJson(protocolSettings); + json["sysfee"] = tx.SystemFee.ToString(); + json["netfee"] = tx.NetworkFee.ToString(); + return json; + } + + public static Signer SignerFromJson(JObject json, ProtocolSettings protocolSettings) + { + return new Signer + { + Account = json["account"].ToScriptHash(protocolSettings), + Rules = ((JArray)json["rules"])?.Select(p => RuleFromJson((JObject)p, protocolSettings)).ToArray(), + Scopes = (WitnessScope)Enum.Parse(typeof(WitnessScope), json["scopes"].AsString()), + AllowedContracts = ((JArray)json["allowedcontracts"])?.Select(p => p.ToScriptHash(protocolSettings)).ToArray(), + AllowedGroups = ((JArray)json["allowedgroups"])?.Select(p => ECPoint.Parse(p.AsString(), ECCurve.Secp256r1)).ToArray() + }; + } + + public static TransactionAttribute TransactionAttributeFromJson(JObject json) + { + TransactionAttributeType usage = Enum.Parse(json["type"].AsString()); + return usage switch + { + TransactionAttributeType.HighPriority => new HighPriorityAttribute(), + TransactionAttributeType.OracleResponse => new OracleResponse() + { + Id = (ulong)json["id"].AsNumber(), + Code = Enum.Parse(json["code"].AsString()), + Result = Convert.FromBase64String(json["result"].AsString()), + }, + TransactionAttributeType.NotValidBefore => new NotValidBefore() + { + Height = (uint)json["height"].AsNumber(), + }, + TransactionAttributeType.Conflicts => new Conflicts() + { + Hash = UInt256.Parse(json["hash"].AsString()) + }, + _ => throw new FormatException(), + }; + } + + public static Witness WitnessFromJson(JObject json) + { + return new Witness + { + InvocationScript = Convert.FromBase64String(json["invocation"].AsString()), + VerificationScript = Convert.FromBase64String(json["verification"].AsString()) + }; + } + + public static WitnessRule RuleFromJson(JObject json, ProtocolSettings protocolSettings) + { + return new WitnessRule() + { + Action = Enum.Parse(json["action"].AsString()), + Condition = RuleExpressionFromJson((JObject)json["condition"], protocolSettings) + }; + } + + public static WitnessCondition RuleExpressionFromJson(JObject json, ProtocolSettings protocolSettings) + { + return json["type"].AsString() switch + { + "Or" => new OrCondition { Expressions = ((JArray)json["expressions"])?.Select(p => RuleExpressionFromJson((JObject)p, protocolSettings)).ToArray() }, + "And" => new AndCondition { Expressions = ((JArray)json["expressions"])?.Select(p => RuleExpressionFromJson((JObject)p, protocolSettings)).ToArray() }, + "Boolean" => new BooleanCondition { Expression = json["expression"].AsBoolean() }, + "Not" => new NotCondition { Expression = RuleExpressionFromJson((JObject)json["expression"], protocolSettings) }, + "Group" => new GroupCondition { Group = ECPoint.Parse(json["group"].AsString(), ECCurve.Secp256r1) }, + "CalledByContract" => new CalledByContractCondition { Hash = json["hash"].ToScriptHash(protocolSettings) }, + "ScriptHash" => new ScriptHashCondition { Hash = json["hash"].ToScriptHash(protocolSettings) }, + "CalledByEntry" => new CalledByEntryCondition(), + "CalledByGroup" => new CalledByGroupCondition { Group = ECPoint.Parse(json["group"].AsString(), ECCurve.Secp256r1) }, + _ => throw new FormatException("Wrong rule's condition type"), + }; + } + + public static StackItem StackItemFromJson(JObject json) + { + StackItemType type = json["type"].GetEnum(); + switch (type) + { + case StackItemType.Boolean: + return json["value"].GetBoolean() ? StackItem.True : StackItem.False; + case StackItemType.Buffer: + return new Buffer(Convert.FromBase64String(json["value"].AsString())); + case StackItemType.ByteString: + return new ByteString(Convert.FromBase64String(json["value"].AsString())); + case StackItemType.Integer: + return BigInteger.Parse(json["value"].AsString()); + case StackItemType.Array: + Array array = new(); + foreach (JObject item in (JArray)json["value"]) + array.Add(StackItemFromJson(item)); + return array; + case StackItemType.Struct: + Struct @struct = new(); + foreach (JObject item in (JArray)json["value"]) + @struct.Add(StackItemFromJson(item)); + return @struct; + case StackItemType.Map: + Map map = new(); + foreach (var item in (JArray)json["value"]) + { + PrimitiveType key = (PrimitiveType)StackItemFromJson((JObject)item["key"]); + map[key] = StackItemFromJson((JObject)item["value"]); + } + return map; + case StackItemType.Pointer: + return new Pointer(null, (int)json["value"].AsNumber()); + case StackItemType.InteropInterface: + return new InteropInterface(json); + default: + return json["value"]?.AsString() ?? StackItem.Null; + } + } + + public static string GetIteratorId(this StackItem item) + { + if (item is InteropInterface iop) + { + var json = iop.GetInterface(); + return json["id"]?.GetString(); + } + return null; + } + } +} diff --git a/src/Plugins/RpcClient/WalletAPI.cs b/src/Plugins/RpcClient/WalletAPI.cs new file mode 100644 index 0000000000..bbf684f758 --- /dev/null +++ b/src/Plugins/RpcClient/WalletAPI.cs @@ -0,0 +1,225 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// WalletAPI.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; +using Neo.Network.P2P.Payloads; +using Neo.Network.RPC.Models; +using Neo.SmartContract; +using Neo.SmartContract.Native; +using Neo.Wallets; +using System; +using System.Linq; +using System.Numerics; +using System.Threading.Tasks; + +namespace Neo.Network.RPC +{ + /// + /// Wallet Common APIs + /// + public class WalletAPI + { + private readonly RpcClient rpcClient; + private readonly Nep17API nep17API; + + /// + /// WalletAPI Constructor + /// + /// the RPC client to call NEO RPC methods + public WalletAPI(RpcClient rpc) + { + rpcClient = rpc; + nep17API = new Nep17API(rpc); + } + + /// + /// Get unclaimed gas with address, scripthash or public key string + /// + /// address, scripthash or public key string + /// Example: address ("Ncm9TEzrp8SSer6Wa3UCSLTRnqzwVhCfuE"), scripthash ("0xb0a31817c80ad5f87b6ed390ecb3f9d312f7ceb8"), public key ("02f9ec1fd0a98796cf75b586772a4ddd41a0af07a1dbdf86a7238f74fb72503575") + /// + public Task GetUnclaimedGasAsync(string account) + { + UInt160 accountHash = Utility.GetScriptHash(account, rpcClient.protocolSettings); + return GetUnclaimedGasAsync(accountHash); + } + + /// + /// Get unclaimed gas + /// + /// account scripthash + /// + public async Task GetUnclaimedGasAsync(UInt160 account) + { + UInt160 scriptHash = NativeContract.NEO.Hash; + var blockCount = await rpcClient.GetBlockCountAsync().ConfigureAwait(false); + var result = await nep17API.TestInvokeAsync(scriptHash, "unclaimedGas", account, blockCount - 1).ConfigureAwait(false); + BigInteger balance = result.Stack.Single().GetInteger(); + return ((decimal)balance) / (long)NativeContract.GAS.Factor; + } + + /// + /// Get Neo Balance + /// + /// address, scripthash or public key string + /// Example: address ("Ncm9TEzrp8SSer6Wa3UCSLTRnqzwVhCfuE"), scripthash ("0xb0a31817c80ad5f87b6ed390ecb3f9d312f7ceb8"), public key ("02f9ec1fd0a98796cf75b586772a4ddd41a0af07a1dbdf86a7238f74fb72503575") + /// + public async Task GetNeoBalanceAsync(string account) + { + BigInteger balance = await GetTokenBalanceAsync(NativeContract.NEO.Hash.ToString(), account).ConfigureAwait(false); + return (uint)balance; + } + + /// + /// Get Gas Balance + /// + /// address, scripthash or public key string + /// Example: address ("Ncm9TEzrp8SSer6Wa3UCSLTRnqzwVhCfuE"), scripthash ("0xb0a31817c80ad5f87b6ed390ecb3f9d312f7ceb8"), public key ("02f9ec1fd0a98796cf75b586772a4ddd41a0af07a1dbdf86a7238f74fb72503575") + /// + public async Task GetGasBalanceAsync(string account) + { + BigInteger balance = await GetTokenBalanceAsync(NativeContract.GAS.Hash.ToString(), account).ConfigureAwait(false); + return ((decimal)balance) / (long)NativeContract.GAS.Factor; + } + + /// + /// Get token balance with string parameters + /// + /// token script hash, Example: "0x43cf98eddbe047e198a3e5d57006311442a0ca15"(NEO) + /// address, scripthash or public key string + /// Example: address ("Ncm9TEzrp8SSer6Wa3UCSLTRnqzwVhCfuE"), scripthash ("0xb0a31817c80ad5f87b6ed390ecb3f9d312f7ceb8"), public key ("02f9ec1fd0a98796cf75b586772a4ddd41a0af07a1dbdf86a7238f74fb72503575") + /// + public Task GetTokenBalanceAsync(string tokenHash, string account) + { + UInt160 scriptHash = Utility.GetScriptHash(tokenHash, rpcClient.protocolSettings); + UInt160 accountHash = Utility.GetScriptHash(account, rpcClient.protocolSettings); + return nep17API.BalanceOfAsync(scriptHash, accountHash); + } + + /// + /// The GAS is claimed when doing NEO transfer + /// This function will transfer NEO balance from account to itself + /// + /// wif or private key + /// Example: WIF ("KyXwTh1hB76RRMquSvnxZrJzQx7h9nQP2PCRL38v6VDb5ip3nf1p"), PrivateKey ("450d6c2a04b5b470339a745427bae6828400cf048400837d73c415063835e005") + /// Add assert at the end of the script + /// The transaction sended + public Task ClaimGasAsync(string key, bool addAssert = true) + { + KeyPair keyPair = Utility.GetKeyPair(key); + return ClaimGasAsync(keyPair, addAssert); + } + + /// + /// The GAS is claimed when doing NEO transfer + /// This function will transfer NEO balance from account to itself + /// + /// keyPair + /// Add assert at the end of the script + /// The transaction sended + public async Task ClaimGasAsync(KeyPair keyPair, bool addAssert = true) + { + UInt160 toHash = Contract.CreateSignatureRedeemScript(keyPair.PublicKey).ToScriptHash(); + BigInteger balance = await nep17API.BalanceOfAsync(NativeContract.NEO.Hash, toHash).ConfigureAwait(false); + Transaction transaction = await nep17API.CreateTransferTxAsync(NativeContract.NEO.Hash, keyPair, toHash, balance, null, addAssert).ConfigureAwait(false); + await rpcClient.SendRawTransactionAsync(transaction).ConfigureAwait(false); + return transaction; + } + + /// + /// Transfer NEP17 token balance, with common data types + /// + /// nep17 token script hash, Example: scripthash ("0xb0a31817c80ad5f87b6ed390ecb3f9d312f7ceb8") + /// wif or private key + /// Example: WIF ("KyXwTh1hB76RRMquSvnxZrJzQx7h9nQP2PCRL38v6VDb5ip3nf1p"), PrivateKey ("450d6c2a04b5b470339a745427bae6828400cf048400837d73c415063835e005") + /// address or account script hash + /// token amount + /// onPayment data + /// Add assert at the end of the script + /// + public async Task TransferAsync(string tokenHash, string fromKey, string toAddress, decimal amount, object data = null, bool addAssert = true) + { + UInt160 scriptHash = Utility.GetScriptHash(tokenHash, rpcClient.protocolSettings); + var decimals = await nep17API.DecimalsAsync(scriptHash).ConfigureAwait(false); + + KeyPair from = Utility.GetKeyPair(fromKey); + UInt160 to = Utility.GetScriptHash(toAddress, rpcClient.protocolSettings); + BigInteger amountInteger = amount.ToBigInteger(decimals); + return await TransferAsync(scriptHash, from, to, amountInteger, data, addAssert).ConfigureAwait(false); + } + + /// + /// Transfer NEP17 token from single-sig account + /// + /// contract script hash + /// from KeyPair + /// to account script hash + /// transfer amount + /// onPayment data + /// Add assert at the end of the script + /// + public async Task TransferAsync(UInt160 scriptHash, KeyPair from, UInt160 to, BigInteger amountInteger, object data = null, bool addAssert = true) + { + Transaction transaction = await nep17API.CreateTransferTxAsync(scriptHash, from, to, amountInteger, data, addAssert).ConfigureAwait(false); + await rpcClient.SendRawTransactionAsync(transaction).ConfigureAwait(false); + return transaction; + } + + /// + /// Transfer NEP17 token from multi-sig account + /// + /// contract script hash + /// multi-sig min signature count + /// multi-sig pubKeys + /// sign keys + /// to account + /// transfer amount + /// onPayment data + /// Add assert at the end of the script + /// + public async Task TransferAsync(UInt160 scriptHash, int m, ECPoint[] pubKeys, KeyPair[] keys, UInt160 to, BigInteger amountInteger, object data = null, bool addAssert = true) + { + Transaction transaction = await nep17API.CreateTransferTxAsync(scriptHash, m, pubKeys, keys, to, amountInteger, data, addAssert).ConfigureAwait(false); + await rpcClient.SendRawTransactionAsync(transaction).ConfigureAwait(false); + return transaction; + } + + /// + /// Wait until the transaction is observable block chain + /// + /// the transaction to observe + /// TimeoutException throws after "timeout" seconds + /// the Transaction state, including vmState and blockhash + public async Task WaitTransactionAsync(Transaction transaction, int timeout = 60) + { + DateTime deadline = DateTime.UtcNow.AddSeconds(timeout); + RpcTransaction rpcTx = null; + while (rpcTx == null || rpcTx.Confirmations == null) + { + if (deadline < DateTime.UtcNow) + { + throw new TimeoutException(); + } + + try + { + rpcTx = await rpcClient.GetRawTransactionAsync(transaction.Hash.ToString()).ConfigureAwait(false); + if (rpcTx == null || rpcTx.Confirmations == null) + { + await Task.Delay((int)rpcClient.protocolSettings.MillisecondsPerBlock / 2); + } + } + catch (Exception) { } + } + return rpcTx; + } + } +} diff --git a/src/Plugins/RpcServer/Diagnostic.cs b/src/Plugins/RpcServer/Diagnostic.cs new file mode 100644 index 0000000000..a8cba4af9a --- /dev/null +++ b/src/Plugins/RpcServer/Diagnostic.cs @@ -0,0 +1,53 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Diagnostic.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; + +namespace Neo.Plugins +{ + class Diagnostic : IDiagnostic + { + public Tree InvocationTree { get; } = new(); + + private TreeNode currentNodeOfInvocationTree = null; + + public void Initialized(ApplicationEngine engine) + { + } + + public void Disposed() + { + } + + public void ContextLoaded(ExecutionContext context) + { + var state = context.GetState(); + if (currentNodeOfInvocationTree is null) + currentNodeOfInvocationTree = InvocationTree.AddRoot(state.ScriptHash); + else + currentNodeOfInvocationTree = currentNodeOfInvocationTree.AddChild(state.ScriptHash); + } + + public void ContextUnloaded(ExecutionContext context) + { + currentNodeOfInvocationTree = currentNodeOfInvocationTree.Parent; + } + + public void PreExecuteInstruction(Instruction instruction) + { + } + + public void PostExecuteInstruction(Instruction instruction) + { + } + } +} diff --git a/src/Plugins/RpcServer/Result.cs b/src/Plugins/RpcServer/Result.cs new file mode 100644 index 0000000000..0ead2482cd --- /dev/null +++ b/src/Plugins/RpcServer/Result.cs @@ -0,0 +1,116 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Result.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; +namespace Neo.Plugins +{ + public static class Result + { + /// + /// Checks the execution result of a function and throws an exception if it is null or throw an exception. + /// + /// The function to execute + /// The rpc error + /// Append extra base exception message + /// The return type + /// The execution result + /// The Rpc exception + public static T Ok_Or(this Func function, RpcError err, bool withData = false) + { + try + { + var result = function(); + if (result == null) throw new RpcException(err); + return result; + } + catch (Exception ex) + { + if (withData) + throw new RpcException(err.WithData(ex.GetBaseException().Message)); + throw new RpcException(err); + } + } + + /// + /// Checks the execution result and throws an exception if it is null. + /// + /// The execution result + /// The rpc error + /// The return type + /// The execution result + /// The Rpc exception + public static T NotNull_Or(this T result, RpcError err) + { + if (result == null) throw new RpcException(err); + return result; + } + + /// + /// The execution result is true or throws an exception or null. + /// + /// The function to execute + /// the rpc exception code + /// the execution result + /// The rpc exception + public static bool True_Or(Func function, RpcError err) + { + try + { + var result = function(); + if (!result.Equals(true)) throw new RpcException(err); + return result; + } + catch + { + throw new RpcException(err); + } + } + + /// + /// Checks if the execution result is true or throws an exception. + /// + /// the execution result + /// the rpc exception code + /// the execution result + /// The rpc exception + public static bool True_Or(this bool result, RpcError err) + { + if (!result.Equals(true)) throw new RpcException(err); + return result; + } + + /// + /// Checks if the execution result is false or throws an exception. + /// + /// the execution result + /// the rpc exception code + /// the execution result + /// The rpc exception + public static bool False_Or(this bool result, RpcError err) + { + if (!result.Equals(false)) throw new RpcException(err); + return result; + } + + /// + /// Check if the execution result is null or throws an exception. + /// + /// The execution result + /// the rpc error + /// The execution result type + /// The execution result + /// the rpc exception + public static void Null_Or(this T result, RpcError err) + { + if (result != null) throw new RpcException(err); + } + } +} diff --git a/src/Plugins/RpcServer/RpcError.cs b/src/Plugins/RpcServer/RpcError.cs new file mode 100644 index 0000000000..7130540183 --- /dev/null +++ b/src/Plugins/RpcServer/RpcError.cs @@ -0,0 +1,103 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// RpcError.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.Json; + +namespace Neo.Plugins +{ + public class RpcError + { + #region Default Values + + // https://www.jsonrpc.org/specification + // | code | message | meaning | + // |--------------------|-----------------|-----------------------------------------------------------------------------------| + // | -32700 | Parse error | Invalid JSON was received by the server. An error occurred on the server while parsing the JSON text. | + // | -32600 | Invalid request | The JSON sent is not a valid Request object. | + // | -32601 | Method not found| The method does not exist / is not available. | + // | -32602 | Invalid params | Invalid method parameter(s). | + // | -32603 | Internal error | Internal JSON-RPC error. | + // | -32000 to -32099 | Server error | Reserved for implementation-defined server-errors. | + public static readonly RpcError InvalidRequest = new(-32600, "Invalid request"); + public static readonly RpcError MethodNotFound = new(-32601, "Method not found"); + public static readonly RpcError InvalidParams = new(-32602, "Invalid params"); + public static readonly RpcError InternalServerError = new(-32603, "Internal server RpcError"); + public static readonly RpcError BadRequest = new(-32700, "Bad request"); + + // https://github.com/neo-project/proposals/pull/156/files + public static readonly RpcError UnknownBlock = new(-101, "Unknown block"); + public static readonly RpcError UnknownContract = new(-102, "Unknown contract"); + public static readonly RpcError UnknownTransaction = new(-103, "Unknown transaction"); + public static readonly RpcError UnknownStorageItem = new(-104, "Unknown storage item"); + public static readonly RpcError UnknownScriptContainer = new(-105, "Unknown script container"); + public static readonly RpcError UnknownStateRoot = new(-106, "Unknown state root"); + public static readonly RpcError UnknownSession = new(-107, "Unknown session"); + public static readonly RpcError UnknownIterator = new(-108, "Unknown iterator"); + public static readonly RpcError UnknownHeight = new(-109, "Unknown height"); + + public static readonly RpcError InsufficientFundsWallet = new(-300, "Insufficient funds in wallet"); + public static readonly RpcError WalletFeeLimit = new(-301, "Wallet fee limit exceeded", "The necessary fee is more than the Max_fee, this transaction is failed. Please increase your Max_fee value."); + public static readonly RpcError NoOpenedWallet = new(-302, "No opened wallet"); + public static readonly RpcError WalletNotFound = new(-303, "Wallet not found"); + public static readonly RpcError WalletNotSupported = new(-304, "Wallet not supported"); + + public static readonly RpcError VerificationFailed = new(-500, "Inventory verification failed"); + public static readonly RpcError AlreadyExists = new(-501, "Inventory already exists"); + public static readonly RpcError MempoolCapReached = new(-502, "Memory pool capacity reached"); + public static readonly RpcError AlreadyInPool = new(-503, "Already in pool"); + public static readonly RpcError InsufficientNetworkFee = new(-504, "Insufficient network fee"); + public static readonly RpcError PolicyFailed = new(-505, "Policy check failed"); + public static readonly RpcError InvalidScript = new(-509, "Invalid transaction script"); + public static readonly RpcError InvalidAttribute = new(-507, "Invalid transaction attribute"); + public static readonly RpcError InvalidSignature = new(-508, "Invalid signature"); + public static readonly RpcError InvalidSize = new(-509, "Invalid inventory size"); + public static readonly RpcError ExpiredTransaction = new(-510, "Expired transaction"); + public static readonly RpcError InsufficientFunds = new(-511, "Insufficient funds for fee"); + public static readonly RpcError InvalidContractVerification = new(-512, "Invalid contract verification function"); + + public static readonly RpcError AccessDenied = new(-600, "Access denied"); + public static readonly RpcError SessionsDisabled = new(-601, "State iterator sessions disabled"); + public static readonly RpcError OracleDisabled = new(-602, "Oracle service disabled"); + public static readonly RpcError OracleRequestFinished = new(-603, "Oracle request already finished"); + public static readonly RpcError OracleRequestNotFound = new(-604, "Oracle request not found"); + public static readonly RpcError OracleNotDesignatedNode = new(-605, "Not a designated oracle node"); + public static readonly RpcError UnsupportedState = new(-606, "Old state not supported"); + public static readonly RpcError InvalidProof = new(-607, "Invalid state proof"); + public static readonly RpcError ExecutionFailed = new(-608, "Contract execution failed"); + + #endregion + + public int Code { get; set; } + public string Message { get; set; } + public string Data { get; set; } + + public RpcError(int code, string message, string data = null) + { + Code = code; + Message = message; + Data = data; + } + + public override string ToString() => string.IsNullOrEmpty(Data) ? $"{Message} ({Code})" : $"{Message} ({Code}) - {Data}"; + + public JToken ToJson() + { + JObject json = new(); + json["code"] = Code; + json["message"] = ErrorMessage; + if (!string.IsNullOrEmpty(Data)) + json["data"] = Data; + return json; + } + + public string ErrorMessage => string.IsNullOrEmpty(Data) ? $"{Message}" : $"{Message} - {Data}"; + } +} diff --git a/src/Plugins/RpcServer/RpcErrorFactory.cs b/src/Plugins/RpcServer/RpcErrorFactory.cs new file mode 100644 index 0000000000..328ba02f61 --- /dev/null +++ b/src/Plugins/RpcServer/RpcErrorFactory.cs @@ -0,0 +1,43 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// RpcErrorFactory.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 +{ + public static class RpcErrorFactory + { + public static RpcError WithData(this RpcError error, string data = null) + { + return new RpcError(error.Code, error.Message, data); + } + + public static RpcError NewCustomError(int code, string message, string data = null) + { + return new RpcError(code, message, data); + } + + #region Require data + + public static RpcError MethodNotFound(string method) => RpcError.MethodNotFound.WithData($"The method '{method}' doesn't exists."); + public static RpcError AlreadyExists(string data) => RpcError.AlreadyExists.WithData(data); + public static RpcError InvalidParams(string data) => RpcError.InvalidParams.WithData(data); + public static RpcError BadRequest(string data) => RpcError.BadRequest.WithData(data); + public static RpcError InsufficientFundsWallet(string data) => RpcError.InsufficientFundsWallet.WithData(data); + public static RpcError VerificationFailed(string data) => RpcError.VerificationFailed.WithData(data); + public static RpcError InvalidContractVerification(UInt160 contractHash) => RpcError.InvalidContractVerification.WithData($"The smart contract {contractHash} haven't got verify method."); + public static RpcError InvalidContractVerification(string data) => RpcError.InvalidContractVerification.WithData(data); + public static RpcError InvalidSignature(string data) => RpcError.InvalidSignature.WithData(data); + public static RpcError OracleNotDesignatedNode(ECPoint oraclePub) => RpcError.OracleNotDesignatedNode.WithData($"{oraclePub} isn't an oracle node."); + + #endregion + } +} diff --git a/src/Plugins/RpcServer/RpcException.cs b/src/Plugins/RpcServer/RpcException.cs new file mode 100644 index 0000000000..5c7b5675a1 --- /dev/null +++ b/src/Plugins/RpcServer/RpcException.cs @@ -0,0 +1,23 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// RpcException.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; + +namespace Neo.Plugins +{ + public class RpcException : Exception + { + public RpcException(RpcError error) : base(error.ErrorMessage) + { + HResult = error.Code; + } + } +} diff --git a/src/Plugins/RpcServer/RpcMethodAttribute.cs b/src/Plugins/RpcServer/RpcMethodAttribute.cs new file mode 100644 index 0000000000..89edccdd5a --- /dev/null +++ b/src/Plugins/RpcServer/RpcMethodAttribute.cs @@ -0,0 +1,21 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// RpcMethodAttribute.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; + +namespace Neo.Plugins +{ + [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] + public class RpcMethodAttribute : Attribute + { + public string Name { get; set; } + } +} diff --git a/src/Plugins/RpcServer/RpcServer.Blockchain.cs b/src/Plugins/RpcServer/RpcServer.Blockchain.cs new file mode 100644 index 0000000000..a4fda6e738 --- /dev/null +++ b/src/Plugins/RpcServer/RpcServer.Blockchain.cs @@ -0,0 +1,339 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// 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 Neo.IO; +using Neo.Json; +using Neo.Network.P2P.Payloads; +using Neo.SmartContract; +using Neo.SmartContract.Native; +using Neo.VM; +using Neo.VM.Types; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Neo.Plugins +{ + partial class RpcServer + { + [RpcMethod] + protected virtual JToken GetBestBlockHash(JArray _params) + { + return NativeContract.Ledger.CurrentHash(system.StoreView).ToString(); + } + + [RpcMethod] + protected 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(); + Block block; + if (key is JNumber) + { + uint index = uint.Parse(key.AsString()); + block = NativeContract.Ledger.GetBlock(snapshot, index); + } + else + { + UInt256 hash = UInt256.Parse(key.AsString()); + block = NativeContract.Ledger.GetBlock(snapshot, hash); + } + block.NotNull_Or(RpcError.UnknownBlock); + if (verbose) + { + JObject json = Utility.BlockToJson(block, system.Settings); + json["confirmations"] = NativeContract.Ledger.CurrentIndex(snapshot) - block.Index + 1; + UInt256 hash = NativeContract.Ledger.GetBlockHash(snapshot, block.Index + 1); + if (hash != null) + json["nextblockhash"] = hash.ToString(); + return json; + } + return Convert.ToBase64String(block.ToArray()); + } + + [RpcMethod] + protected virtual JToken GetBlockHeaderCount(JArray _params) + { + return (system.HeaderCache.Last?.Index ?? NativeContract.Ledger.CurrentIndex(system.StoreView)) + 1; + } + + [RpcMethod] + protected virtual JToken GetBlockCount(JArray _params) + { + return NativeContract.Ledger.CurrentIndex(system.StoreView) + 1; + } + + [RpcMethod] + protected 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; + if (height <= NativeContract.Ledger.CurrentIndex(snapshot)) + { + return NativeContract.Ledger.GetBlockHash(snapshot, height).ToString(); + } + throw new RpcException(RpcError.UnknownHeight); + } + + [RpcMethod] + protected virtual JToken GetBlockHeader(JArray _params) + { + JToken key = _params[0]; + bool verbose = _params.Count >= 2 && _params[1].AsBoolean(); + var snapshot = system.StoreView; + Header header; + if (key is JNumber) + { + uint height = uint.Parse(key.AsString()); + header = NativeContract.Ledger.GetHeader(snapshot, height).NotNull_Or(RpcError.UnknownBlock); + } + else + { + UInt256 hash = UInt256.Parse(key.AsString()); + header = NativeContract.Ledger.GetHeader(snapshot, hash).NotNull_Or(RpcError.UnknownBlock); + } + if (verbose) + { + JObject json = header.ToJson(system.Settings); + json["confirmations"] = NativeContract.Ledger.CurrentIndex(snapshot) - header.Index + 1; + UInt256 hash = NativeContract.Ledger.GetBlockHash(snapshot, header.Index + 1); + if (hash != null) + json["nextblockhash"] = hash.ToString(); + return json; + } + + return Convert.ToBase64String(header.ToArray()); + } + + [RpcMethod] + protected virtual JToken GetContractState(JArray _params) + { + if (int.TryParse(_params[0].AsString(), out int contractId)) + { + var contracts = NativeContract.ContractManagement.GetContractById(system.StoreView, contractId); + return contracts?.ToJson().NotNull_Or(RpcError.UnknownContract); + } + else + { + UInt160 script_hash = ToScriptHash(_params[0].AsString()); + ContractState contract = NativeContract.ContractManagement.GetContract(system.StoreView, script_hash); + return contract?.ToJson().NotNull_Or(RpcError.UnknownContract); + } + } + + private static UInt160 ToScriptHash(string keyword) + { + foreach (var native in NativeContract.Contracts) + { + if (keyword.Equals(native.Name, StringComparison.InvariantCultureIgnoreCase) || keyword == native.Id.ToString()) + return native.Hash; + } + + return UInt160.Parse(keyword); + } + + [RpcMethod] + protected virtual JToken GetRawMemPool(JArray _params) + { + bool shouldGetUnverified = _params.Count >= 1 && _params[0].AsBoolean(); + if (!shouldGetUnverified) + return new JArray(system.MemPool.GetVerifiedTransactions().Select(p => (JToken)p.Hash.ToString())); + + JObject json = new(); + json["height"] = NativeContract.Ledger.CurrentIndex(system.StoreView); + system.MemPool.GetVerifiedAndUnverifiedTransactions( + out IEnumerable verifiedTransactions, + out IEnumerable unverifiedTransactions); + json["verified"] = new JArray(verifiedTransactions.Select(p => (JToken)p.Hash.ToString())); + json["unverified"] = new JArray(unverifiedTransactions.Select(p => (JToken)p.Hash.ToString())); + return json; + } + + [RpcMethod] + protected 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(); + if (system.MemPool.TryGetValue(hash, out Transaction tx) && !verbose) + return Convert.ToBase64String(tx.ToArray()); + var snapshot = system.StoreView; + TransactionState state = NativeContract.Ledger.GetTransactionState(snapshot, hash); + tx ??= state?.Transaction; + tx.NotNull_Or(RpcError.UnknownTransaction); + if (!verbose) return Convert.ToBase64String(tx.ToArray()); + JObject json = Utility.TransactionToJson(tx, system.Settings); + if (state is not null) + { + TrimmedBlock block = NativeContract.Ledger.GetTrimmedBlock(snapshot, NativeContract.Ledger.GetBlockHash(snapshot, state.BlockIndex)); + json["blockhash"] = block.Hash.ToString(); + json["confirmations"] = NativeContract.Ledger.CurrentIndex(snapshot) - block.Index + 1; + json["blocktime"] = block.Header.Timestamp; + } + return json; + } + + [RpcMethod] + 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()); + ContractState contract = NativeContract.ContractManagement.GetContract(snapshot, hash).NotNull_Or(RpcError.UnknownContract); + id = contract.Id; + } + byte[] key = Convert.FromBase64String(_params[1].AsString()); + StorageItem item = snapshot.TryGet(new StorageKey + { + Id = id, + Key = key + }).NotNull_Or(RpcError.UnknownStorageItem); + return Convert.ToBase64String(item.Value.Span); + } + + [RpcMethod] + protected virtual JToken FindStorage(JArray _params) + { + using var snapshot = system.GetSnapshot(); + if (!int.TryParse(_params[0].AsString(), out int id)) + { + UInt160 hash = UInt160.Parse(_params[0].AsString()); + ContractState contract = NativeContract.ContractManagement.GetContract(snapshot, hash).NotNull_Or(RpcError.UnknownContract); + id = contract.Id; + } + + byte[] prefix = Convert.FromBase64String(_params[1].AsString()); + byte[] prefix_key = StorageKey.CreateSearchPrefix(id, prefix); + + if (!int.TryParse(_params[2].AsString(), out int start)) + { + start = 0; + } + + JObject json = new(); + JArray jarr = new(); + int pageSize = settings.FindStoragePageSize; + int i = 0; + + using (var iter = snapshot.Find(prefix_key).Skip(count: start).GetEnumerator()) + { + var hasMore = false; + while (iter.MoveNext()) + { + if (i == pageSize) + { + hasMore = true; + break; + } + + JObject j = new(); + j["key"] = Convert.ToBase64String(iter.Current.Key.Key.Span); + j["value"] = Convert.ToBase64String(iter.Current.Value.Value.Span); + jarr.Add(j); + i++; + } + json["truncated"] = hasMore; + } + + json["next"] = start + i; + json["results"] = jarr; + return json; + } + + [RpcMethod] + protected virtual JToken GetTransactionHeight(JArray _params) + { + 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; + if (height.HasValue) return height.Value; + throw new RpcException(RpcError.UnknownTransaction); + } + + [RpcMethod] + protected virtual JToken GetNextBlockValidators(JArray _params) + { + using var snapshot = system.GetSnapshot(); + var validators = NativeContract.NEO.GetNextBlockValidators(snapshot, system.Settings.ValidatorsCount); + return validators.Select(p => + { + JObject validator = new(); + validator["publickey"] = p.ToString(); + validator["votes"] = (int)NativeContract.NEO.GetCandidateVote(snapshot, p); + return validator; + }).ToArray(); + } + + [RpcMethod] + protected virtual JToken GetCandidates(JArray _params) + { + using var snapshot = system.GetSnapshot(); + byte[] script; + using (ScriptBuilder sb = new()) + { + script = sb.EmitDynamicCall(NativeContract.NEO.Hash, "getCandidates", null).ToArray(); + } + StackItem[] resultstack; + try + { + using ApplicationEngine engine = ApplicationEngine.Run(script, snapshot, settings: system.Settings, gas: settings.MaxGasInvoke); + resultstack = engine.ResultStack.ToArray(); + } + catch + { + throw new RpcException(RpcError.InternalServerError.WithData("Can't get candidates.")); + } + + JObject json = new(); + try + { + if (resultstack.Length > 0) + { + JArray jArray = new(); + var validators = NativeContract.NEO.GetNextBlockValidators(snapshot, system.Settings.ValidatorsCount) ?? throw new RpcException(RpcError.InternalServerError.WithData("Can't get next block validators.")); + + foreach (var item in resultstack) + { + var value = (VM.Types.Array)item; + foreach (Struct ele in value) + { + var publickey = ele[0].GetSpan().ToHexString(); + json["publickey"] = publickey; + json["votes"] = ele[1].GetInteger().ToString(); + json["active"] = validators.ToByteArray().ToHexString().Contains(publickey); + jArray.Add(json); + json = new(); + } + return jArray; + } + } + } + catch + { + throw new RpcException(RpcError.InternalServerError.WithData("Can't get next block validators")); + } + + return json; + } + + [RpcMethod] + protected virtual JToken GetCommittee(JArray _params) + { + return new JArray(NativeContract.NEO.GetCommittee(system.StoreView).Select(p => (JToken)p.ToString())); + } + + [RpcMethod] + protected virtual JToken GetNativeContracts(JArray _params) + { + return new JArray(NativeContract.Contracts.Select(p => NativeContract.ContractManagement.GetContract(system.StoreView, p.Hash).ToJson())); + } + } +} diff --git a/src/Plugins/RpcServer/RpcServer.Node.cs b/src/Plugins/RpcServer/RpcServer.Node.cs new file mode 100644 index 0000000000..c455100802 --- /dev/null +++ b/src/Plugins/RpcServer/RpcServer.Node.cs @@ -0,0 +1,168 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// 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 Akka.Actor; +using Neo.IO; +using Neo.Json; +using Neo.Ledger; +using Neo.Network.P2P; +using Neo.Network.P2P.Payloads; +using System; +using System.Linq; +using static Neo.Ledger.Blockchain; + +namespace Neo.Plugins +{ + partial class RpcServer + { + [RpcMethod] + protected virtual JToken GetConnectionCount(JArray _params) + { + return localNode.ConnectedCount; + } + + [RpcMethod] + protected virtual JToken GetPeers(JArray _params) + { + JObject json = new(); + json["unconnected"] = new JArray(localNode.GetUnconnectedPeers().Select(p => + { + JObject peerJson = new(); + peerJson["address"] = p.Address.ToString(); + peerJson["port"] = p.Port; + return peerJson; + })); + json["bad"] = new JArray(); //badpeers has been removed + json["connected"] = new JArray(localNode.GetRemoteNodes().Select(p => + { + JObject peerJson = new(); + peerJson["address"] = p.Remote.Address.ToString(); + peerJson["port"] = p.ListenerTcpPort; + return peerJson; + })); + return json; + } + + private static JObject GetRelayResult(VerifyResult reason, UInt256 hash) + { + + switch (reason) + { + case VerifyResult.Succeed: + { + var ret = new JObject(); + ret["hash"] = hash.ToString(); + return ret; + } + case VerifyResult.AlreadyExists: + { + throw new RpcException(RpcError.AlreadyExists.WithData(reason.ToString())); + } + case VerifyResult.AlreadyInPool: + { + throw new RpcException(RpcError.AlreadyInPool.WithData(reason.ToString())); + } + case VerifyResult.OutOfMemory: + { + throw new RpcException(RpcError.MempoolCapReached.WithData(reason.ToString())); + } + case VerifyResult.InvalidScript: + { + throw new RpcException(RpcError.InvalidScript.WithData(reason.ToString())); + } + case VerifyResult.InvalidAttribute: + { + throw new RpcException(RpcError.InvalidAttribute.WithData(reason.ToString())); + } + case VerifyResult.InvalidSignature: + { + throw new RpcException(RpcError.InvalidSignature.WithData(reason.ToString())); + } + case VerifyResult.OverSize: + { + throw new RpcException(RpcError.InvalidSize.WithData(reason.ToString())); + } + case VerifyResult.Expired: + { + throw new RpcException(RpcError.ExpiredTransaction.WithData(reason.ToString())); + } + case VerifyResult.InsufficientFunds: + { + throw new RpcException(RpcError.InsufficientFunds.WithData(reason.ToString())); + } + case VerifyResult.PolicyFail: + { + throw new RpcException(RpcError.PolicyFailed.WithData(reason.ToString())); + } + default: + { + throw new RpcException(RpcError.VerificationFailed.WithData(reason.ToString())); + } + } + } + + [RpcMethod] + protected virtual JToken GetVersion(JArray _params) + { + JObject json = new(); + json["tcpport"] = localNode.ListenerTcpPort; + json["nonce"] = LocalNode.Nonce; + json["useragent"] = LocalNode.UserAgent; + // rpc settings + JObject rpc = new(); + rpc["maxiteratorresultitems"] = settings.MaxIteratorResultItems; + rpc["sessionenabled"] = settings.SessionEnabled; + // protocol settings + JObject protocol = new(); + protocol["addressversion"] = system.Settings.AddressVersion; + protocol["network"] = system.Settings.Network; + protocol["validatorscount"] = system.Settings.ValidatorsCount; + protocol["msperblock"] = system.Settings.MillisecondsPerBlock; + protocol["maxtraceableblocks"] = system.Settings.MaxTraceableBlocks; + protocol["maxvaliduntilblockincrement"] = system.Settings.MaxValidUntilBlockIncrement; + protocol["maxtransactionsperblock"] = system.Settings.MaxTransactionsPerBlock; + protocol["memorypoolmaxtransactions"] = system.Settings.MemoryPoolMaxTransactions; + protocol["initialgasdistribution"] = system.Settings.InitialGasDistribution; + protocol["hardforks"] = new JArray(system.Settings.Hardforks.Select(hf => + { + JObject forkJson = new(); + // Strip "HF_" prefix. + forkJson["name"] = StripPrefix(hf.Key.ToString(), "HF_"); + forkJson["blockheight"] = hf.Value; + return forkJson; + })); + json["rpc"] = rpc; + json["protocol"] = protocol; + return json; + } + + private static string StripPrefix(string s, string prefix) + { + return s.StartsWith(prefix) ? s.Substring(prefix.Length) : s; + } + + [RpcMethod] + protected 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; + return GetRelayResult(reason.Result, tx.Hash); + } + + [RpcMethod] + protected 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; + return GetRelayResult(reason.Result, block.Hash); + } + } +} diff --git a/src/Plugins/RpcServer/RpcServer.SmartContract.cs b/src/Plugins/RpcServer/RpcServer.SmartContract.cs new file mode 100644 index 0000000000..0fe6fc0c1d --- /dev/null +++ b/src/Plugins/RpcServer/RpcServer.SmartContract.cs @@ -0,0 +1,297 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// RpcServer.SmartContract.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; +using Neo.IO; +using Neo.Json; +using Neo.Network.P2P.Payloads; +using Neo.Persistence; +using Neo.SmartContract; +using Neo.SmartContract.Iterators; +using Neo.SmartContract.Native; +using Neo.VM; +using Neo.VM.Types; +using Neo.Wallets; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using Array = System.Array; + +namespace Neo.Plugins +{ + partial class RpcServer + { + private readonly Dictionary sessions = new(); + private Timer timer; + + private void Initialize_SmartContract() + { + if (settings.SessionEnabled) + timer = new(OnTimer, null, settings.SessionExpirationTime, settings.SessionExpirationTime); + } + + private void Dispose_SmartContract() + { + timer?.Dispose(); + Session[] toBeDestroyed; + lock (sessions) + { + toBeDestroyed = sessions.Values.ToArray(); + sessions.Clear(); + } + foreach (Session session in toBeDestroyed) + session.Dispose(); + } + + private void OnTimer(object state) + { + List<(Guid Id, Session Session)> toBeDestroyed = new(); + lock (sessions) + { + foreach (var (id, session) in sessions) + if (DateTime.UtcNow >= session.StartTime + settings.SessionExpirationTime) + toBeDestroyed.Add((id, session)); + foreach (var (id, _) in toBeDestroyed) + sessions.Remove(id); + } + foreach (var (_, session) in toBeDestroyed) + session.Dispose(); + } + + private JObject GetInvokeResult(byte[] script, Signer[] signers = null, Witness[] witnesses = null, bool useDiagnostic = false) + { + JObject json = new(); + Session session = new(system, script, signers, witnesses, settings.MaxGasInvoke, useDiagnostic ? new Diagnostic() : null); + try + { + json["script"] = Convert.ToBase64String(script); + json["state"] = session.Engine.State; + json["gasconsumed"] = session.Engine.GasConsumed.ToString(); + json["exception"] = GetExceptionMessage(session.Engine.FaultException); + json["notifications"] = new JArray(session.Engine.Notifications.Select(n => + { + var obj = new JObject(); + obj["eventname"] = n.EventName; + obj["contract"] = n.ScriptHash.ToString(); + obj["state"] = ToJson(n.State, session); + return obj; + })); + if (useDiagnostic) + { + Diagnostic diagnostic = (Diagnostic)session.Engine.Diagnostic; + json["diagnostics"] = new JObject() + { + ["invokedcontracts"] = ToJson(diagnostic.InvocationTree.Root), + ["storagechanges"] = ToJson(session.Engine.Snapshot.GetChangeSet()) + }; + } + var stack = new JArray(); + foreach (var item in session.Engine.ResultStack) + { + try + { + stack.Add(ToJson(item, session)); + } + catch (Exception ex) + { + stack.Add("error: " + ex.Message); + } + } + json["stack"] = stack; + if (session.Engine.State != VMState.FAULT) + { + ProcessInvokeWithWallet(json, signers); + } + } + catch + { + session.Dispose(); + throw; + } + if (session.Iterators.Count == 0 || !settings.SessionEnabled) + { + session.Dispose(); + } + else + { + Guid id = Guid.NewGuid(); + json["session"] = id.ToString(); + lock (sessions) + sessions.Add(id, session); + } + return json; + } + + private static JObject ToJson(TreeNode node) + { + JObject json = new(); + json["hash"] = node.Item.ToString(); + if (node.Children.Any()) + { + json["call"] = new JArray(node.Children.Select(ToJson)); + } + return json; + } + + private static JArray ToJson(IEnumerable changes) + { + JArray array = new(); + foreach (var entry in changes) + { + array.Add(new JObject + { + ["state"] = entry.State.ToString(), + ["key"] = Convert.ToBase64String(entry.Key.ToArray()), + ["value"] = Convert.ToBase64String(entry.Item.Value.ToArray()) + }); + } + return array; + } + + private static JObject ToJson(StackItem item, Session session) + { + JObject json = item.ToJson(); + if (item is InteropInterface interopInterface && interopInterface.GetInterface() is IIterator iterator) + { + Guid id = Guid.NewGuid(); + session.Iterators.Add(id, iterator); + json["interface"] = nameof(IIterator); + json["id"] = id.ToString(); + } + return json; + } + + private static Signer[] SignersFromJson(JArray _params, ProtocolSettings settings) + { + if (_params.Count > Transaction.MaxTransactionAttributes) + { + throw new RpcException(RpcError.InvalidParams.WithData("Max allowed witness exceeded.")); + } + + var ret = _params.Select(u => new Signer + { + Account = AddressToScriptHash(u["account"].AsString(), settings.AddressVersion), + Scopes = (WitnessScope)Enum.Parse(typeof(WitnessScope), u["scopes"]?.AsString()), + AllowedContracts = ((JArray)u["allowedcontracts"])?.Select(p => UInt160.Parse(p.AsString())).ToArray() ?? Array.Empty(), + AllowedGroups = ((JArray)u["allowedgroups"])?.Select(p => ECPoint.Parse(p.AsString(), ECCurve.Secp256r1)).ToArray() ?? Array.Empty(), + Rules = ((JArray)u["rules"])?.Select(r => WitnessRule.FromJson((JObject)r)).ToArray() ?? Array.Empty(), + }).ToArray(); + + // Validate format + + _ = IO.Helper.ToByteArray(ret).AsSerializableArray(); + + return ret; + } + + private static Witness[] WitnessesFromJson(JArray _params) + { + if (_params.Count > Transaction.MaxTransactionAttributes) + { + throw new RpcException(RpcError.InvalidParams.WithData("Max allowed witness exceeded.")); + } + + return _params.Select(u => new + { + Invocation = u["invocation"]?.AsString(), + Verification = u["verification"]?.AsString() + }).Where(x => x.Invocation != null || x.Verification != null).Select(x => new Witness() + { + InvocationScript = Convert.FromBase64String(x.Invocation ?? string.Empty), + VerificationScript = Convert.FromBase64String(x.Verification ?? string.Empty) + }).ToArray(); + } + + [RpcMethod] + protected 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); + ContractParameter[] args = _params.Count >= 3 ? ((JArray)_params[2]).Select(p => ContractParameter.FromJson((JObject)p)).ToArray() : System.Array.Empty(); + Signer[] signers = _params.Count >= 4 ? SignersFromJson((JArray)_params[3], system.Settings) : null; + Witness[] witnesses = _params.Count >= 4 ? WitnessesFromJson((JArray)_params[3]) : null; + bool useDiagnostic = _params.Count >= 5 && _params[4].GetBoolean(); + + byte[] script; + using (ScriptBuilder sb = new()) + { + script = sb.EmitDynamicCall(script_hash, operation, args).ToArray(); + } + return GetInvokeResult(script, signers, witnesses, useDiagnostic); + } + + [RpcMethod] + protected 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; + Witness[] witnesses = _params.Count >= 2 ? WitnessesFromJson((JArray)_params[1]) : null; + bool useDiagnostic = _params.Count >= 3 && _params[2].GetBoolean(); + return GetInvokeResult(script, signers, witnesses, useDiagnostic); + } + + [RpcMethod] + protected 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)}")); + Guid iid = Result.Ok_Or(() => Guid.Parse(_params[1].GetString()), RpcError.InvalidParams.WithData($"Invliad iterator id {nameof(iid)}")); + int count = _params[2].GetInt32(); + Result.True_Or(() => count > settings.MaxIteratorResultItems, RpcError.InvalidParams.WithData($"Invalid iterator items count {nameof(count)}")); + Session session; + lock (sessions) + { + session = Result.Ok_Or(() => sessions[sid], RpcError.UnknownSession); + session.ResetExpiration(); + } + IIterator iterator = Result.Ok_Or(() => session.Iterators[iid], RpcError.UnknownIterator); + JArray json = new(); + while (count-- > 0 && iterator.Next()) + json.Add(iterator.Value(null).ToJson()); + return json; + } + + [RpcMethod] + protected 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")); + + Session session = null; + bool result; + lock (sessions) + { + result = Result.Ok_Or(() => sessions.Remove(sid, out session), RpcError.UnknownSession); + } + if (result) session.Dispose(); + return result; + } + + [RpcMethod] + protected virtual JToken GetUnclaimedGas(JArray _params) + { + string address = Result.Ok_Or(() => _params[0].AsString(), RpcError.InvalidParams.WithData($"Invalid address {nameof(address)}")); + JObject json = new(); + UInt160 script_hash = Result.Ok_Or(() => AddressToScriptHash(address, system.Settings.AddressVersion), RpcError.InvalidParams); + + var snapshot = system.StoreView; + json["unclaimed"] = NativeContract.NEO.UnclaimedGas(snapshot, script_hash, NativeContract.Ledger.CurrentIndex(snapshot) + 1).ToString(); + json["address"] = script_hash.ToAddress(system.Settings.AddressVersion); + return json; + } + + static string GetExceptionMessage(Exception exception) + { + return exception?.GetBaseException().Message; + } + } +} diff --git a/src/Plugins/RpcServer/RpcServer.Utilities.cs b/src/Plugins/RpcServer/RpcServer.Utilities.cs new file mode 100644 index 0000000000..f410e01b73 --- /dev/null +++ b/src/Plugins/RpcServer/RpcServer.Utilities.cs @@ -0,0 +1,55 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// RpcServer.Utilities.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.Json; +using Neo.Wallets; +using System.Linq; + +namespace Neo.Plugins +{ + partial class RpcServer + { + [RpcMethod] + protected virtual JToken ListPlugins(JArray _params) + { + return new JArray(Plugin.Plugins + .OrderBy(u => u.Name) + .Select(u => new JObject + { + ["name"] = u.Name, + ["version"] = u.Version.ToString(), + ["interfaces"] = new JArray(u.GetType().GetInterfaces() + .Select(p => p.Name) + .Where(p => p.EndsWith("Plugin")) + .Select(p => (JToken)p)) + })); + } + + [RpcMethod] + protected virtual JToken ValidateAddress(JArray _params) + { + string address = Result.Ok_Or(() => _params[0].AsString(), RpcError.InvalidParams.WithData($"Invlid address format: {_params[0]}")); + JObject json = new(); + UInt160 scriptHash; + try + { + scriptHash = address.ToScriptHash(system.Settings.AddressVersion); + } + catch + { + scriptHash = null; + } + json["address"] = address; + json["isvalid"] = scriptHash != null; + return json; + } + } +} diff --git a/src/Plugins/RpcServer/RpcServer.Wallet.cs b/src/Plugins/RpcServer/RpcServer.Wallet.cs new file mode 100644 index 0000000000..8085c1bd35 --- /dev/null +++ b/src/Plugins/RpcServer/RpcServer.Wallet.cs @@ -0,0 +1,423 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// 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 Akka.Actor; +using Neo.IO; +using Neo.Json; +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.IO; +using System.Linq; +using System.Numerics; + +namespace Neo.Plugins +{ + partial class RpcServer + { + private class DummyWallet : Wallet + { + public DummyWallet(ProtocolSettings settings) : base(null, settings) { } + public override string Name => ""; + public override Version Version => new(); + + public override bool ChangePassword(string oldPassword, string newPassword) => false; + public override bool Contains(UInt160 scriptHash) => false; + public override WalletAccount CreateAccount(byte[] privateKey) => null; + public override WalletAccount CreateAccount(Contract contract, KeyPair key = null) => null; + public override WalletAccount CreateAccount(UInt160 scriptHash) => null; + public override void Delete() { } + public override bool DeleteAccount(UInt160 scriptHash) => false; + public override WalletAccount GetAccount(UInt160 scriptHash) => null; + public override IEnumerable GetAccounts() => Array.Empty(); + public override bool VerifyPassword(string password) => false; + public override void Save() { } + } + + protected Wallet wallet; + + private void CheckWallet() + { + wallet.NotNull_Or(RpcError.NoOpenedWallet); + } + + [RpcMethod] + protected virtual JToken CloseWallet(JArray _params) + { + wallet = null; + return true; + } + + [RpcMethod] + protected virtual JToken DumpPrivKey(JArray _params) + { + CheckWallet(); + UInt160 scriptHash = AddressToScriptHash(_params[0].AsString(), system.Settings.AddressVersion); + WalletAccount account = wallet.GetAccount(scriptHash); + return account.GetKey().Export(); + } + + [RpcMethod] + protected virtual JToken GetNewAddress(JArray _params) + { + CheckWallet(); + WalletAccount account = wallet.CreateAccount(); + if (wallet is NEP6Wallet nep6) + nep6.Save(); + return account.Address; + } + + [RpcMethod] + protected virtual JToken GetWalletBalance(JArray _params) + { + CheckWallet(); + UInt160 asset_id = UInt160.Parse(_params[0].AsString()); + JObject json = new(); + json["balance"] = wallet.GetAvailable(system.StoreView, asset_id).Value.ToString(); + return json; + } + + [RpcMethod] + protected virtual JToken GetWalletUnclaimedGas(JArray _params) + { + CheckWallet(); + BigInteger gas = BigInteger.Zero; + using (var snapshot = system.GetSnapshot()) + { + uint height = NativeContract.Ledger.CurrentIndex(snapshot) + 1; + foreach (UInt160 account in wallet.GetAccounts().Select(p => p.ScriptHash)) + gas += NativeContract.NEO.UnclaimedGas(snapshot, account, height); + } + return gas.ToString(); + } + + [RpcMethod] + protected virtual JToken ImportPrivKey(JArray _params) + { + CheckWallet(); + string privkey = _params[0].AsString(); + WalletAccount account = wallet.Import(privkey); + if (wallet is NEP6Wallet nep6wallet) + nep6wallet.Save(); + return new JObject + { + ["address"] = account.Address, + ["haskey"] = account.HasKey, + ["label"] = account.Label, + ["watchonly"] = account.WatchOnly + }; + } + + [RpcMethod] + protected virtual JToken CalculateNetworkFee(JArray _params) + { + var tx = Convert.FromBase64String(_params[0].AsString()); + + JObject account = new(); + var networkfee = Wallets.Helper.CalculateNetworkFee( + tx.AsSerializable(), system.StoreView, system.Settings, + wallet is not null ? a => wallet.GetAccount(a).Contract.Script : _ => null); + account["networkfee"] = networkfee.ToString(); + return account; + } + + [RpcMethod] + protected virtual JToken ListAddress(JArray _params) + { + CheckWallet(); + return wallet.GetAccounts().Select(p => + { + JObject account = new(); + account["address"] = p.Address; + account["haskey"] = p.HasKey; + account["label"] = p.Label; + account["watchonly"] = p.WatchOnly; + return account; + }).ToArray(); + } + + [RpcMethod] + protected 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); + return true; + } + + private void ProcessInvokeWithWallet(JObject result, Signer[] signers = null) + { + if (wallet == null || signers == null || signers.Length == 0) return; + + UInt160 sender = signers[0].Account; + Transaction tx; + try + { + tx = wallet.MakeTransaction(system.StoreView, Convert.FromBase64String(result["script"].AsString()), sender, signers, maxGas: settings.MaxGasInvoke); + } + catch (Exception e) + { + result["exception"] = GetExceptionMessage(e); + return; + } + ContractParametersContext context = new(system.StoreView, tx, settings.Network); + wallet.Sign(context); + if (context.Completed) + { + tx.Witnesses = context.GetWitnesses(); + result["tx"] = Convert.ToBase64String(tx.ToArray()); + } + else + { + result["pendingsignature"] = context.ToJson(); + } + } + + [RpcMethod] + protected virtual JToken SendFrom(JArray _params) + { + CheckWallet(); + UInt160 assetId = UInt160.Parse(_params[0].AsString()); + UInt160 from = AddressToScriptHash(_params[1].AsString(), system.Settings.AddressVersion); + UInt160 to = AddressToScriptHash(_params[2].AsString(), system.Settings.AddressVersion); + using var snapshot = system.GetSnapshot(); + 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.")); + 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[] + { + new TransferOutput + { + AssetId = assetId, + Value = amount, + ScriptHash = to + } + }, from, signers).NotNull_Or(RpcError.InsufficientFunds); + + ContractParametersContext transContext = new(snapshot, tx, settings.Network); + wallet.Sign(transContext); + if (!transContext.Completed) + return transContext.ToJson(); + tx.Witnesses = transContext.GetWitnesses(); + if (tx.Size > 1024) + { + long calFee = tx.Size * NativeContract.Policy.GetFeePerByte(snapshot) + 100000; + if (tx.NetworkFee < calFee) + tx.NetworkFee = calFee; + } + (tx.NetworkFee <= settings.MaxFee).True_Or(RpcError.WalletFeeLimit); + return SignAndRelay(snapshot, tx); + } + + [RpcMethod] + protected virtual JToken SendMany(JArray _params) + { + CheckWallet(); + int to_start = 0; + UInt160 from = null; + if (_params[0] is JString) + { + from = AddressToScriptHash(_params[0].AsString(), system.Settings.AddressVersion); + to_start = 1; + } + JArray to = Result.Ok_Or(() => (JArray)_params[to_start], RpcError.InvalidParams.WithData($"Invalid 'to' parameter: {_params[to_start]}")); + (to.Count != 0).True_Or(RpcErrorFactory.InvalidParams("Argument 'to' can't be empty.")); + 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(); + for (int i = 0; i < to.Count; i++) + { + UInt160 asset_id = UInt160.Parse(to[i]["asset"].AsString()); + AssetDescriptor descriptor = new(snapshot, system.Settings, asset_id); + outputs[i] = new TransferOutput + { + AssetId = asset_id, + Value = new BigDecimal(BigInteger.Parse(to[i]["value"].AsString()), descriptor.Decimals), + ScriptHash = AddressToScriptHash(to[i]["address"].AsString(), system.Settings.AddressVersion) + }; + (outputs[i].Value.Sign > 0).True_Or(RpcErrorFactory.InvalidParams($"Amount of '{asset_id}' can't be negative.")); + } + Transaction tx = wallet.MakeTransaction(snapshot, outputs, from, signers).NotNull_Or(RpcError.InsufficientFunds); + + ContractParametersContext transContext = new(snapshot, tx, settings.Network); + wallet.Sign(transContext); + if (!transContext.Completed) + return transContext.ToJson(); + tx.Witnesses = transContext.GetWitnesses(); + if (tx.Size > 1024) + { + long calFee = tx.Size * NativeContract.Policy.GetFeePerByte(snapshot) + 100000; + if (tx.NetworkFee < calFee) + tx.NetworkFee = calFee; + } + (tx.NetworkFee <= settings.MaxFee).True_Or(RpcError.WalletFeeLimit); + return SignAndRelay(snapshot, tx); + } + + [RpcMethod] + 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(); + AssetDescriptor descriptor = new(snapshot, system.Settings, assetId); + BigDecimal amount = new(BigInteger.Parse(_params[2].AsString()), descriptor.Decimals); + (amount.Sign > 0).True_Or(RpcError.InvalidParams); + Transaction tx = wallet.MakeTransaction(snapshot, new[] + { + new TransferOutput + { + AssetId = assetId, + Value = amount, + ScriptHash = to + } + }).NotNull_Or(RpcError.InsufficientFunds); + + ContractParametersContext transContext = new(snapshot, tx, settings.Network); + wallet.Sign(transContext); + if (!transContext.Completed) + return transContext.ToJson(); + tx.Witnesses = transContext.GetWitnesses(); + if (tx.Size > 1024) + { + long calFee = tx.Size * NativeContract.Policy.GetFeePerByte(snapshot) + 100000; + if (tx.NetworkFee < calFee) + tx.NetworkFee = calFee; + } + (tx.NetworkFee <= settings.MaxFee).True_Or(RpcError.WalletFeeLimit); + return SignAndRelay(snapshot, tx); + } + + [RpcMethod] + protected virtual JToken CancelTransaction(JArray _params) + { + CheckWallet(); + var txid = Result.Ok_Or(() => UInt256.Parse(_params[0].AsString()), RpcError.InvalidParams.WithData($"Invalid txid: {_params[0]}")); + NativeContract.Ledger.GetTransactionState(system.StoreView, txid).Null_Or(RpcErrorFactory.AlreadyExists("This tx is already confirmed, can't be cancelled.")); + + var conflict = new TransactionAttribute[] { new Conflicts() { Hash = txid } }; + Signer[] signers = _params.Count >= 2 ? ((JArray)_params[1]).Select(j => new Signer() { Account = AddressToScriptHash(j.AsString(), system.Settings.AddressVersion), Scopes = WitnessScope.None }).ToArray() : Array.Empty(); + (!signers.Any()).True_Or(RpcErrorFactory.BadRequest("No signer.")); + Transaction tx = new Transaction + { + Signers = signers, + Attributes = conflict, + Witnesses = Array.Empty(), + }; + + tx = Result.Ok_Or(() => wallet.MakeTransaction(system.StoreView, new[] { (byte)OpCode.RET }, signers[0].Account, signers, conflict), RpcError.InsufficientFunds, true); + + if (system.MemPool.TryGetValue(txid, out Transaction conflictTx)) + { + tx.NetworkFee = Math.Max(tx.NetworkFee, conflictTx.NetworkFee) + 1; + } + else if (_params.Count >= 3) + { + var extraFee = _params[2].AsString(); + AssetDescriptor descriptor = new(system.StoreView, system.Settings, NativeContract.GAS.Hash); + (BigDecimal.TryParse(extraFee, descriptor.Decimals, out BigDecimal decimalExtraFee) && decimalExtraFee.Sign > 0).True_Or(RpcErrorFactory.InvalidParams("Incorrect amount format.")); + + tx.NetworkFee += (long)decimalExtraFee.Value; + }; + return SignAndRelay(system.StoreView, tx); + } + + [RpcMethod] + protected 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(); + Signer[] signers = _params.Count >= 3 ? SignersFromJson((JArray)_params[2], system.Settings) : null; + Witness[] witnesses = _params.Count >= 3 ? WitnessesFromJson((JArray)_params[2]) : null; + return GetVerificationResult(script_hash, args, signers, witnesses); + } + + private JObject GetVerificationResult(UInt160 scriptHash, ContractParameter[] args, Signer[] signers = null, Witness[] witnesses = null) + { + using var snapshot = system.GetSnapshot(); + var contract = NativeContract.ContractManagement.GetContract(snapshot, scriptHash).NotNull_Or(RpcError.UnknownContract); + var md = contract.Manifest.Abi.GetMethod("verify", -1).NotNull_Or(RpcErrorFactory.InvalidContractVerification(contract.Hash)); + (md.ReturnType == ContractParameterType.Boolean).True_Or(RpcErrorFactory.InvalidContractVerification("The verify method doesn't return boolean value.")); + Transaction tx = new() + { + Signers = signers ?? new Signer[] { new() { Account = scriptHash } }, + Attributes = Array.Empty(), + Witnesses = witnesses, + Script = new[] { (byte)OpCode.RET } + }; + using ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Verification, tx, snapshot.CreateSnapshot(), settings: system.Settings); + engine.LoadContract(contract, md, CallFlags.ReadOnly); + + var invocationScript = Array.Empty(); + if (args.Length > 0) + { + using ScriptBuilder sb = new(); + for (int i = args.Length - 1; i >= 0; i--) + sb.EmitPush(args[i]); + + invocationScript = sb.ToArray(); + tx.Witnesses ??= new Witness[] { new() { InvocationScript = invocationScript } }; + engine.LoadScript(new Script(invocationScript), configureState: p => p.CallFlags = CallFlags.None); + } + JObject json = new(); + json["script"] = Convert.ToBase64String(invocationScript); + json["state"] = engine.Execute(); + json["gasconsumed"] = engine.GasConsumed.ToString(); + json["exception"] = GetExceptionMessage(engine.FaultException); + try + { + json["stack"] = new JArray(engine.ResultStack.Select(p => p.ToJson(settings.MaxStackSize))); + } + catch (Exception ex) + { + json["exception"] = ex.Message; + } + return json; + } + + private JObject SignAndRelay(DataCache snapshot, Transaction tx) + { + ContractParametersContext context = new(snapshot, tx, settings.Network); + wallet.Sign(context); + if (context.Completed) + { + tx.Witnesses = context.GetWitnesses(); + system.Blockchain.Tell(tx); + return Utility.TransactionToJson(tx, system.Settings); + } + else + { + return context.ToJson(); + } + } + + internal static UInt160 AddressToScriptHash(string address, byte version) + { + if (UInt160.TryParse(address, out var scriptHash)) + { + return scriptHash; + } + + return address.ToScriptHash(version); + } + } +} diff --git a/src/Plugins/RpcServer/RpcServer.cs b/src/Plugins/RpcServer/RpcServer.cs new file mode 100644 index 0000000000..f77c2d1e33 --- /dev/null +++ b/src/Plugins/RpcServer/RpcServer.cs @@ -0,0 +1,312 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// RpcServer.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 Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.ResponseCompression; +using Microsoft.AspNetCore.Server.Kestrel.Https; +using Microsoft.Extensions.DependencyInjection; +using Neo.Json; +using Neo.Network.P2P; +using System; +using System.Collections.Generic; +using System.IO; +using System.IO.Compression; +using System.Linq; +using System.Net.Security; +using System.Reflection; +using System.Security.Cryptography.X509Certificates; +using System.Text; +using System.Threading.Tasks; + +namespace Neo.Plugins +{ + public partial class RpcServer : IDisposable + { + private const int MaxParamsDepth = 32; + + private readonly Dictionary> methods = new(); + + private IWebHost host; + private RpcServerSettings settings; + private readonly NeoSystem system; + private readonly LocalNode localNode; + + public RpcServer(NeoSystem system, RpcServerSettings settings) + { + this.system = system; + this.settings = settings; + localNode = system.LocalNode.Ask(new LocalNode.GetInstance()).Result; + RegisterMethods(this); + Initialize_SmartContract(); + } + + private bool CheckAuth(HttpContext context) + { + if (string.IsNullOrEmpty(settings.RpcUser)) return true; + + string reqauth = context.Request.Headers["Authorization"]; + if (string.IsNullOrEmpty(reqauth)) + { + context.Response.Headers["WWW-Authenticate"] = "Basic realm=\"Restricted\""; + context.Response.StatusCode = 401; + return false; + } + + string authstring; + try + { + authstring = Encoding.UTF8.GetString(Convert.FromBase64String(reqauth.Replace("Basic ", "").Trim())); + } + catch + { + return false; + } + + string[] authvalues = authstring.Split(new string[] { ":" }, StringSplitOptions.RemoveEmptyEntries); + if (authvalues.Length < 2) + return false; + + return authvalues[0] == settings.RpcUser && authvalues[1] == settings.RpcPass; + } + + private static JObject CreateErrorResponse(JToken id, RpcError rpcError) + { + JObject response = CreateResponse(id); + response["error"] = rpcError.ToJson(); + return response; + } + + private static JObject CreateResponse(JToken id) + { + JObject response = new(); + response["jsonrpc"] = "2.0"; + response["id"] = id; + return response; + } + + public void Dispose() + { + Dispose_SmartContract(); + if (host != null) + { + host.Dispose(); + host = null; + } + } + + public void StartRpcServer() + { + host = new WebHostBuilder().UseKestrel(options => options.Listen(settings.BindAddress, settings.Port, listenOptions => + { + // Default value is 5Mb + options.Limits.MaxRequestBodySize = settings.MaxRequestBodySize; + options.Limits.MaxRequestLineSize = Math.Min(settings.MaxRequestBodySize, options.Limits.MaxRequestLineSize); + // Default value is 40 + options.Limits.MaxConcurrentConnections = settings.MaxConcurrentConnections; + + // Default value is 1 minutes + options.Limits.KeepAliveTimeout = settings.KeepAliveTimeout == -1 ? + TimeSpan.MaxValue : + TimeSpan.FromSeconds(settings.KeepAliveTimeout); + + // Default value is 15 seconds + options.Limits.RequestHeadersTimeout = TimeSpan.FromSeconds(settings.RequestHeadersTimeout); + + if (string.IsNullOrEmpty(settings.SslCert)) return; + listenOptions.UseHttps(settings.SslCert, settings.SslCertPassword, httpsConnectionAdapterOptions => + { + if (settings.TrustedAuthorities is null || settings.TrustedAuthorities.Length == 0) + return; + httpsConnectionAdapterOptions.ClientCertificateMode = ClientCertificateMode.RequireCertificate; + httpsConnectionAdapterOptions.ClientCertificateValidation = (cert, chain, err) => + { + if (err != SslPolicyErrors.None) + return false; + X509Certificate2 authority = chain.ChainElements[^1].Certificate; + return settings.TrustedAuthorities.Contains(authority.Thumbprint); + }; + }); + })) + .Configure(app => + { + if (settings.EnableCors) + app.UseCors("All"); + + app.UseResponseCompression(); + app.Run(ProcessAsync); + }) + .ConfigureServices(services => + { + if (settings.EnableCors) + { + if (settings.AllowOrigins.Length == 0) + services.AddCors(options => + { + options.AddPolicy("All", policy => + { + policy.AllowAnyOrigin() + .WithHeaders("Content-Type") + .WithMethods("GET", "POST"); + // The CORS specification states that setting origins to "*" (all origins) + // is invalid if the Access-Control-Allow-Credentials header is present. + }); + }); + else + services.AddCors(options => + { + options.AddPolicy("All", policy => + { + policy.WithOrigins(settings.AllowOrigins) + .WithHeaders("Content-Type") + .AllowCredentials() + .WithMethods("GET", "POST"); + }); + }); + } + + services.AddResponseCompression(options => + { + // options.EnableForHttps = false; + options.Providers.Add(); + options.MimeTypes = ResponseCompressionDefaults.MimeTypes.Append("application/json"); + }); + + services.Configure(options => + { + options.Level = CompressionLevel.Fastest; + }); + }) + .Build(); + + host.Start(); + } + + internal void UpdateSettings(RpcServerSettings settings) + { + this.settings = settings; + } + + public async Task ProcessAsync(HttpContext context) + { + if (context.Request.Method != "GET" && context.Request.Method != "POST") return; + JToken request = null; + if (context.Request.Method == "GET") + { + string jsonrpc = context.Request.Query["jsonrpc"]; + string id = context.Request.Query["id"]; + string method = context.Request.Query["method"]; + string _params = context.Request.Query["params"]; + if (!string.IsNullOrEmpty(id) && !string.IsNullOrEmpty(method) && !string.IsNullOrEmpty(_params)) + { + try + { + _params = Encoding.UTF8.GetString(Convert.FromBase64String(_params)); + } + catch (FormatException) { } + request = new JObject(); + if (!string.IsNullOrEmpty(jsonrpc)) + request["jsonrpc"] = jsonrpc; + request["id"] = id; + request["method"] = method; + request["params"] = JToken.Parse(_params, MaxParamsDepth); + } + } + else if (context.Request.Method == "POST") + { + using StreamReader reader = new(context.Request.Body); + try + { + request = JToken.Parse(await reader.ReadToEndAsync(), MaxParamsDepth); + } + catch (FormatException) { } + } + JToken response; + if (request == null) + { + response = CreateErrorResponse(null, RpcError.BadRequest); + } + else if (request is JArray array) + { + if (array.Count == 0) + { + response = CreateErrorResponse(request["id"], RpcError.InvalidRequest); + } + else + { + var tasks = array.Select(p => ProcessRequestAsync(context, (JObject)p)); + var results = await Task.WhenAll(tasks); + response = results.Where(p => p != null).ToArray(); + } + } + else + { + response = await ProcessRequestAsync(context, (JObject)request); + } + if (response == null || (response as JArray)?.Count == 0) return; + context.Response.ContentType = "application/json"; + await context.Response.WriteAsync(response.ToString(), Encoding.UTF8); + } + + private async Task ProcessRequestAsync(HttpContext context, JObject request) + { + if (!request.ContainsProperty("id")) return null; + JToken @params = request["params"] ?? new JArray(); + if (!request.ContainsProperty("method") || @params is not JArray) + { + return CreateErrorResponse(request["id"], RpcError.InvalidRequest); + } + JObject response = CreateResponse(request["id"]); + try + { + string method = request["method"].AsString(); + (CheckAuth(context) && !settings.DisabledMethods.Contains(method)).True_Or(RpcError.AccessDenied); + methods.TryGetValue(method, out var func).True_Or(RpcErrorFactory.MethodNotFound(method)); + response["result"] = func((JArray)@params) switch + { + JToken result => result, + Task task => await task, + _ => throw new NotSupportedException() + }; + return response; + } + catch (FormatException ex) + { + return CreateErrorResponse(request["id"], RpcError.InvalidParams.WithData(ex.Message)); + } + catch (IndexOutOfRangeException ex) + { + return CreateErrorResponse(request["id"], RpcError.InvalidParams.WithData(ex.Message)); + } + catch (Exception ex) + { +#if DEBUG + return CreateErrorResponse(request["id"], RpcErrorFactory.NewCustomError(ex.HResult, ex.Message, ex.StackTrace)); +#else + return CreateErrorResponse(request["id"], RpcErrorFactory.NewCustomError(ex.HResult, ex.Message)); +#endif + } + } + + public void RegisterMethods(object handler) + { + foreach (MethodInfo method in handler.GetType().GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) + { + RpcMethodAttribute attribute = method.GetCustomAttribute(); + if (attribute is null) continue; + string name = string.IsNullOrEmpty(attribute.Name) ? method.Name.ToLowerInvariant() : attribute.Name; + methods[name] = method.CreateDelegate>(handler); + } + } + } +} diff --git a/src/Plugins/RpcServer/RpcServer.csproj b/src/Plugins/RpcServer/RpcServer.csproj new file mode 100644 index 0000000000..5629732771 --- /dev/null +++ b/src/Plugins/RpcServer/RpcServer.csproj @@ -0,0 +1,12 @@ + + + + net8.0 + Neo.Plugins.RpcServer + + + + + + + diff --git a/src/Plugins/RpcServer/RpcServerPlugin.cs b/src/Plugins/RpcServer/RpcServerPlugin.cs new file mode 100644 index 0000000000..bc51d63948 --- /dev/null +++ b/src/Plugins/RpcServer/RpcServerPlugin.cs @@ -0,0 +1,85 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// RpcServerPlugin.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.Collections.Generic; +using System.Linq; + +namespace Neo.Plugins +{ + public class RpcServerPlugin : Plugin + { + public override string Name => "RpcServer"; + public override string Description => "Enables RPC for the node"; + + private Settings settings; + private static readonly Dictionary servers = new(); + private static readonly Dictionary> handlers = new(); + + protected override void Configure() + { + settings = new Settings(GetConfiguration()); + foreach (RpcServerSettings s in settings.Servers) + if (servers.TryGetValue(s.Network, out RpcServer server)) + server.UpdateSettings(s); + } + + public override void Dispose() + { + foreach (var (_, server) in servers) + server.Dispose(); + base.Dispose(); + } + + protected override void OnSystemLoaded(NeoSystem system) + { + RpcServerSettings s = settings.Servers.FirstOrDefault(p => p.Network == system.Settings.Network); + if (s is null) return; + + if (s.EnableCors && string.IsNullOrEmpty(s.RpcUser) == false && s.AllowOrigins.Length == 0) + { + Log("RcpServer: CORS is misconfigured!", LogLevel.Warning); + Log($"You have {nameof(s.EnableCors)} and Basic Authentication enabled but " + + $"{nameof(s.AllowOrigins)} is empty in config.json for RcpServer. " + + "You must add url origins to the list to have CORS work from " + + $"browser with basic authentication enabled. " + + $"Example: \"AllowOrigins\": [\"http://{s.BindAddress}:{s.Port}\"]", LogLevel.Info); + } + + RpcServer server = new(system, s); + + if (handlers.Remove(s.Network, out var list)) + { + foreach (var handler in list) + { + server.RegisterMethods(handler); + } + } + + server.StartRpcServer(); + servers.TryAdd(s.Network, server); + } + + public static void RegisterMethods(object handler, uint network) + { + if (servers.TryGetValue(network, out RpcServer server)) + { + server.RegisterMethods(handler); + return; + } + if (!handlers.TryGetValue(network, out var list)) + { + list = new List(); + handlers.Add(network, list); + } + list.Add(handler); + } + } +} diff --git a/src/Plugins/RpcServer/Session.cs b/src/Plugins/RpcServer/Session.cs new file mode 100644 index 0000000000..2b4213c28e --- /dev/null +++ b/src/Plugins/RpcServer/Session.cs @@ -0,0 +1,58 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Session.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.Payloads; +using Neo.Persistence; +using Neo.SmartContract; +using Neo.SmartContract.Iterators; +using Neo.SmartContract.Native; +using System; +using System.Collections.Generic; + +namespace Neo.Plugins +{ + class Session : IDisposable + { + public readonly SnapshotCache Snapshot; + public readonly ApplicationEngine Engine; + public readonly Dictionary Iterators = new(); + public DateTime StartTime; + + public Session(NeoSystem system, byte[] script, Signer[] signers, Witness[] witnesses, long gas, Diagnostic diagnostic) + { + Random random = new(); + Snapshot = system.GetSnapshot(); + Transaction tx = signers == null ? null : new Transaction + { + Version = 0, + Nonce = (uint)random.Next(), + ValidUntilBlock = NativeContract.Ledger.CurrentIndex(Snapshot) + system.Settings.MaxValidUntilBlockIncrement, + Signers = signers, + Attributes = Array.Empty(), + Script = script, + Witnesses = witnesses + }; + Engine = ApplicationEngine.Run(script, Snapshot, container: tx, settings: system.Settings, gas: gas, diagnostic: diagnostic); + ResetExpiration(); + } + + public void ResetExpiration() + { + StartTime = DateTime.UtcNow; + } + + public void Dispose() + { + Engine.Dispose(); + Snapshot.Dispose(); + } + } +} diff --git a/src/Plugins/RpcServer/Settings.cs b/src/Plugins/RpcServer/Settings.cs new file mode 100644 index 0000000000..f4aef116c6 --- /dev/null +++ b/src/Plugins/RpcServer/Settings.cs @@ -0,0 +1,105 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Settings.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 Neo.SmartContract.Native; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; + +namespace Neo.Plugins +{ + class Settings + { + public IReadOnlyList Servers { get; init; } + + public Settings(IConfigurationSection section) + { + Servers = section.GetSection(nameof(Servers)).GetChildren().Select(p => RpcServerSettings.Load(p)).ToArray(); + } + } + + public record RpcServerSettings + { + public uint Network { get; init; } + public IPAddress BindAddress { get; init; } + public ushort Port { get; init; } + public string SslCert { get; init; } + public string SslCertPassword { get; init; } + public string[] TrustedAuthorities { get; init; } + public int MaxConcurrentConnections { get; init; } + public int MaxRequestBodySize { get; init; } + public string RpcUser { get; init; } + public string RpcPass { get; init; } + public bool EnableCors { get; init; } + public string[] AllowOrigins { get; init; } + public int KeepAliveTimeout { get; init; } + public uint RequestHeadersTimeout { get; init; } + public long MaxGasInvoke { get; init; } + public long MaxFee { get; init; } + public int MaxIteratorResultItems { get; init; } + public int MaxStackSize { get; init; } + public string[] DisabledMethods { get; init; } + public bool SessionEnabled { get; init; } + public TimeSpan SessionExpirationTime { get; init; } + public int FindStoragePageSize { get; init; } + + public static RpcServerSettings Default { get; } = new RpcServerSettings + { + Network = 5195086u, + BindAddress = IPAddress.None, + SslCert = string.Empty, + SslCertPassword = string.Empty, + MaxGasInvoke = (long)new BigDecimal(10M, NativeContract.GAS.Decimals).Value, + MaxFee = (long)new BigDecimal(0.1M, NativeContract.GAS.Decimals).Value, + TrustedAuthorities = Array.Empty(), + EnableCors = true, + AllowOrigins = Array.Empty(), + KeepAliveTimeout = 60, + RequestHeadersTimeout = 15, + MaxIteratorResultItems = 100, + MaxStackSize = ushort.MaxValue, + DisabledMethods = Array.Empty(), + MaxConcurrentConnections = 40, + MaxRequestBodySize = 5 * 1024 * 1024, + SessionEnabled = false, + SessionExpirationTime = TimeSpan.FromSeconds(60), + FindStoragePageSize = 50 + }; + + public static RpcServerSettings Load(IConfigurationSection section) => new() + { + Network = section.GetValue("Network", Default.Network), + BindAddress = IPAddress.Parse(section.GetSection("BindAddress").Value), + Port = ushort.Parse(section.GetSection("Port").Value), + SslCert = section.GetSection("SslCert").Value, + SslCertPassword = section.GetSection("SslCertPassword").Value, + TrustedAuthorities = section.GetSection("TrustedAuthorities").GetChildren().Select(p => p.Get()).ToArray(), + RpcUser = section.GetSection("RpcUser").Value, + RpcPass = section.GetSection("RpcPass").Value, + EnableCors = section.GetValue(nameof(EnableCors), Default.EnableCors), + AllowOrigins = section.GetSection(nameof(AllowOrigins)).GetChildren().Select(p => p.Get()).ToArray(), + KeepAliveTimeout = section.GetValue(nameof(KeepAliveTimeout), Default.KeepAliveTimeout), + RequestHeadersTimeout = section.GetValue(nameof(RequestHeadersTimeout), Default.RequestHeadersTimeout), + MaxGasInvoke = (long)new BigDecimal(section.GetValue("MaxGasInvoke", Default.MaxGasInvoke), NativeContract.GAS.Decimals).Value, + MaxFee = (long)new BigDecimal(section.GetValue("MaxFee", Default.MaxFee), NativeContract.GAS.Decimals).Value, + MaxIteratorResultItems = section.GetValue("MaxIteratorResultItems", Default.MaxIteratorResultItems), + MaxStackSize = section.GetValue("MaxStackSize", Default.MaxStackSize), + DisabledMethods = section.GetSection("DisabledMethods").GetChildren().Select(p => p.Get()).ToArray(), + MaxConcurrentConnections = section.GetValue("MaxConcurrentConnections", Default.MaxConcurrentConnections), + MaxRequestBodySize = section.GetValue("MaxRequestBodySize", Default.MaxRequestBodySize), + SessionEnabled = section.GetValue("SessionEnabled", Default.SessionEnabled), + SessionExpirationTime = TimeSpan.FromSeconds(section.GetValue("SessionExpirationTime", (int)Default.SessionExpirationTime.TotalSeconds)), + FindStoragePageSize = section.GetValue("FindStoragePageSize", Default.FindStoragePageSize) + }; + } +} diff --git a/src/Plugins/RpcServer/Tree.cs b/src/Plugins/RpcServer/Tree.cs new file mode 100644 index 0000000000..77ca1fc2a5 --- /dev/null +++ b/src/Plugins/RpcServer/Tree.cs @@ -0,0 +1,36 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Tree.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; + +namespace Neo.Plugins +{ + class Tree + { + public TreeNode Root { get; private set; } + + public TreeNode AddRoot(T item) + { + if (Root is not null) + throw new InvalidOperationException(); + Root = new TreeNode(item, null); + return Root; + } + + public IEnumerable GetItems() + { + if (Root is null) yield break; + foreach (T item in Root.GetItems()) + yield return item; + } + } +} diff --git a/src/Plugins/RpcServer/TreeNode.cs b/src/Plugins/RpcServer/TreeNode.cs new file mode 100644 index 0000000000..82785277b6 --- /dev/null +++ b/src/Plugins/RpcServer/TreeNode.cs @@ -0,0 +1,45 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// TreeNode.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.Collections.Generic; + +namespace Neo.Plugins +{ + class TreeNode + { + private readonly List> children = new(); + + public T Item { get; } + public TreeNode Parent { get; } + public IReadOnlyList> Children => children; + + internal TreeNode(T item, TreeNode parent) + { + Item = item; + Parent = parent; + } + + public TreeNode AddChild(T item) + { + TreeNode child = new(item, this); + children.Add(child); + return child; + } + + internal IEnumerable GetItems() + { + yield return Item; + foreach (var child in children) + foreach (T item in child.GetItems()) + yield return item; + } + } +} diff --git a/src/Plugins/RpcServer/Utility.cs b/src/Plugins/RpcServer/Utility.cs new file mode 100644 index 0000000000..24ccc9248d --- /dev/null +++ b/src/Plugins/RpcServer/Utility.cs @@ -0,0 +1,36 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Utility.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.Json; +using Neo.Network.P2P.Payloads; +using Neo.SmartContract.Native; +using System.Linq; + +namespace Neo.Plugins +{ + static class Utility + { + public static JObject BlockToJson(Block block, ProtocolSettings settings) + { + JObject json = block.ToJson(settings); + json["tx"] = block.Transactions.Select(p => TransactionToJson(p, settings)).ToArray(); + return json; + } + + public static JObject TransactionToJson(Transaction tx, ProtocolSettings settings) + { + JObject json = tx.ToJson(settings); + json["sysfee"] = tx.SystemFee.ToString(); + json["netfee"] = tx.NetworkFee.ToString(); + return json; + } + } +} diff --git a/src/Plugins/RpcServer/config.json b/src/Plugins/RpcServer/config.json new file mode 100644 index 0000000000..8f6905dead --- /dev/null +++ b/src/Plugins/RpcServer/config.json @@ -0,0 +1,29 @@ +{ + "PluginConfiguration": { + "Servers": [ + { + "Network": 860833102, + "BindAddress": "127.0.0.1", + "Port": 10332, + "SslCert": "", + "SslCertPassword": "", + "TrustedAuthorities": [], + "RpcUser": "", + "RpcPass": "", + "EnableCors": true, + "AllowOrigins": [], + "KeepAliveTimeout": 60, + "RequestHeadersTimeout": 15, + "MaxGasInvoke": 20, + "MaxFee": 0.1, + "MaxConcurrentConnections": 40, + "MaxIteratorResultItems": 100, + "MaxStackSize": 65535, + "DisabledMethods": [ "openwallet" ], + "SessionEnabled": false, + "SessionExpirationTime": 60, + "FindStoragePageSize": 50 + } + ] + } +} diff --git a/src/Plugins/SQLiteWallet/Account.cs b/src/Plugins/SQLiteWallet/Account.cs new file mode 100644 index 0000000000..e7ae09af90 --- /dev/null +++ b/src/Plugins/SQLiteWallet/Account.cs @@ -0,0 +1,18 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Account.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.Wallets.SQLite; + +class Account +{ + public byte[] PublicKeyHash { get; set; } + public string Nep2key { get; set; } +} diff --git a/src/Plugins/SQLiteWallet/Address.cs b/src/Plugins/SQLiteWallet/Address.cs new file mode 100644 index 0000000000..6f2b73e427 --- /dev/null +++ b/src/Plugins/SQLiteWallet/Address.cs @@ -0,0 +1,17 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Address.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.Wallets.SQLite; + +class Address +{ + public byte[] ScriptHash { get; set; } +} diff --git a/src/Plugins/SQLiteWallet/Contract.cs b/src/Plugins/SQLiteWallet/Contract.cs new file mode 100644 index 0000000000..2da432a63b --- /dev/null +++ b/src/Plugins/SQLiteWallet/Contract.cs @@ -0,0 +1,21 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// 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. + +namespace Neo.Wallets.SQLite; + +class Contract +{ + public byte[] RawData { get; set; } + public byte[] ScriptHash { get; set; } + public byte[] PublicKeyHash { get; set; } + public Account Account { get; set; } + public Address Address { get; set; } +} diff --git a/src/Plugins/SQLiteWallet/Key.cs b/src/Plugins/SQLiteWallet/Key.cs new file mode 100644 index 0000000000..81a8a6daf4 --- /dev/null +++ b/src/Plugins/SQLiteWallet/Key.cs @@ -0,0 +1,18 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Key.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.Wallets.SQLite; + +class Key +{ + public string Name { get; set; } + public byte[] Value { get; set; } +} diff --git a/src/Plugins/SQLiteWallet/SQLiteWallet.cs b/src/Plugins/SQLiteWallet/SQLiteWallet.cs new file mode 100644 index 0000000000..a4004dcff0 --- /dev/null +++ b/src/Plugins/SQLiteWallet/SQLiteWallet.cs @@ -0,0 +1,416 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// SQLiteWallet.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.EntityFrameworkCore; +using Neo.Cryptography; +using Neo.IO; +using Neo.SmartContract; +using Neo.Wallets.NEP6; +using System.Buffers.Binary; +using System.Reflection; +using System.Security.Cryptography; +using System.Text; +using static System.IO.Path; + +namespace Neo.Wallets.SQLite; + +/// +/// A wallet implementation that uses SQLite as the underlying storage. +/// +class SQLiteWallet : Wallet +{ + private readonly object db_lock = new(); + private readonly byte[] iv; + private readonly byte[] salt; + private readonly byte[] masterKey; + private readonly ScryptParameters scrypt; + private readonly Dictionary accounts; + + public override string Name => GetFileNameWithoutExtension(Path); + + public override Version Version + { + get + { + byte[] buffer = LoadStoredData("Version"); + if (buffer == null || buffer.Length < 16) return new Version(0, 0); + int major = BinaryPrimitives.ReadInt32LittleEndian(buffer); + int minor = BinaryPrimitives.ReadInt32LittleEndian(buffer.AsSpan(4)); + int build = BinaryPrimitives.ReadInt32LittleEndian(buffer.AsSpan(8)); + int revision = BinaryPrimitives.ReadInt32LittleEndian(buffer.AsSpan(12)); + return new Version(major, minor, build, revision); + } + } + + private SQLiteWallet(string path, byte[] passwordKey, ProtocolSettings settings) : base(path, settings) + { + salt = LoadStoredData("Salt"); + byte[] passwordHash = LoadStoredData("PasswordHash"); + if (passwordHash != null && !passwordHash.SequenceEqual(passwordKey.Concat(salt).ToArray().Sha256())) + throw new CryptographicException(); + iv = LoadStoredData("IV"); + masterKey = Decrypt(LoadStoredData("MasterKey"), passwordKey, iv); + scrypt = new ScryptParameters + ( + BinaryPrimitives.ReadInt32LittleEndian(LoadStoredData("ScryptN")), + BinaryPrimitives.ReadInt32LittleEndian(LoadStoredData("ScryptR")), + BinaryPrimitives.ReadInt32LittleEndian(LoadStoredData("ScryptP")) + ); + accounts = LoadAccounts(); + } + + private SQLiteWallet(string path, byte[] passwordKey, ProtocolSettings settings, ScryptParameters scrypt) : base(path, settings) + { + iv = new byte[16]; + salt = new byte[20]; + masterKey = new byte[32]; + this.scrypt = scrypt; + accounts = new Dictionary(); + using (RandomNumberGenerator rng = RandomNumberGenerator.Create()) + { + rng.GetBytes(iv); + rng.GetBytes(salt); + rng.GetBytes(masterKey); + } + Version version = Assembly.GetExecutingAssembly().GetName().Version; + byte[] versionBuffer = new byte[sizeof(int) * 4]; + BinaryPrimitives.WriteInt32LittleEndian(versionBuffer, version.Major); + BinaryPrimitives.WriteInt32LittleEndian(versionBuffer.AsSpan(4), version.Minor); + BinaryPrimitives.WriteInt32LittleEndian(versionBuffer.AsSpan(8), version.Build); + BinaryPrimitives.WriteInt32LittleEndian(versionBuffer.AsSpan(12), version.Revision); + BuildDatabase(); + SaveStoredData("IV", iv); + SaveStoredData("Salt", salt); + SaveStoredData("PasswordHash", passwordKey.Concat(salt).ToArray().Sha256()); + SaveStoredData("MasterKey", Encrypt(masterKey, passwordKey, iv)); + SaveStoredData("Version", versionBuffer); + SaveStoredData("ScryptN", this.scrypt.N); + SaveStoredData("ScryptR", this.scrypt.R); + SaveStoredData("ScryptP", this.scrypt.P); + } + + private void AddAccount(SQLiteWalletAccount account) + { + lock (accounts) + { + if (accounts.TryGetValue(account.ScriptHash, out SQLiteWalletAccount account_old)) + { + if (account.Contract == null) + { + account.Contract = account_old.Contract; + } + } + accounts[account.ScriptHash] = account; + } + lock (db_lock) + { + using WalletDataContext ctx = new(Path); + if (account.HasKey) + { + Account db_account = ctx.Accounts.FirstOrDefault(p => p.PublicKeyHash == account.Key.PublicKeyHash.ToArray()); + if (db_account == null) + { + db_account = ctx.Accounts.Add(new Account + { + Nep2key = account.Key.Export(masterKey, ProtocolSettings.AddressVersion, scrypt.N, scrypt.R, scrypt.P), + PublicKeyHash = account.Key.PublicKeyHash.ToArray() + }).Entity; + } + else + { + db_account.Nep2key = account.Key.Export(masterKey, ProtocolSettings.AddressVersion, scrypt.N, scrypt.R, scrypt.P); + } + } + if (account.Contract != null) + { + Contract db_contract = ctx.Contracts.FirstOrDefault(p => p.ScriptHash == account.Contract.ScriptHash.ToArray()); + if (db_contract != null) + { + db_contract.PublicKeyHash = account.Key.PublicKeyHash.ToArray(); + } + else + { + ctx.Contracts.Add(new Contract + { + RawData = ((VerificationContract)account.Contract).ToArray(), + ScriptHash = account.Contract.ScriptHash.ToArray(), + PublicKeyHash = account.Key.PublicKeyHash.ToArray() + }); + } + } + //add address + { + Address db_address = ctx.Addresses.FirstOrDefault(p => p.ScriptHash == account.ScriptHash.ToArray()); + if (db_address == null) + { + ctx.Addresses.Add(new Address + { + ScriptHash = account.ScriptHash.ToArray() + }); + } + } + ctx.SaveChanges(); + } + } + + private void BuildDatabase() + { + using WalletDataContext ctx = new(Path); + ctx.Database.EnsureDeleted(); + ctx.Database.EnsureCreated(); + } + + public override bool ChangePassword(string oldPassword, string newPassword) + { + if (!VerifyPassword(oldPassword)) return false; + byte[] passwordKey = ToAesKey(newPassword); + try + { + SaveStoredData("PasswordHash", passwordKey.Concat(salt).ToArray().Sha256()); + SaveStoredData("MasterKey", Encrypt(masterKey, passwordKey, iv)); + return true; + } + finally + { + Array.Clear(passwordKey, 0, passwordKey.Length); + } + } + + public override bool Contains(UInt160 scriptHash) + { + lock (accounts) + { + return accounts.ContainsKey(scriptHash); + } + } + + /// + /// Creates a new wallet at the specified path. + /// + /// The path of the wallet. + /// The password of the wallet. + /// The to be used by the wallet. + /// The parameters of the SCrypt algorithm used for encrypting and decrypting the private keys in the wallet. + /// The created wallet. + public static SQLiteWallet Create(string path, string password, ProtocolSettings settings, ScryptParameters scrypt = null) + { + return new SQLiteWallet(path, ToAesKey(password), settings, scrypt ?? ScryptParameters.Default); + } + + public override WalletAccount CreateAccount(byte[] privateKey) + { + KeyPair key = new(privateKey); + VerificationContract contract = new() + { + Script = SmartContract.Contract.CreateSignatureRedeemScript(key.PublicKey), + ParameterList = new[] { ContractParameterType.Signature } + }; + SQLiteWalletAccount account = new(contract.ScriptHash, ProtocolSettings) + { + Key = key, + Contract = contract + }; + AddAccount(account); + return account; + } + + public override WalletAccount CreateAccount(SmartContract.Contract contract, KeyPair key = null) + { + if (contract is not VerificationContract verification_contract) + { + verification_contract = new VerificationContract + { + Script = contract.Script, + ParameterList = contract.ParameterList + }; + } + SQLiteWalletAccount account = new(verification_contract.ScriptHash, ProtocolSettings) + { + Key = key, + Contract = verification_contract + }; + AddAccount(account); + return account; + } + + public override WalletAccount CreateAccount(UInt160 scriptHash) + { + SQLiteWalletAccount account = new(scriptHash, ProtocolSettings); + AddAccount(account); + return account; + } + + public override void Delete() + { + using WalletDataContext ctx = new(Path); + ctx.Database.EnsureDeleted(); + } + + public override bool DeleteAccount(UInt160 scriptHash) + { + SQLiteWalletAccount account; + lock (accounts) + { + if (accounts.TryGetValue(scriptHash, out account)) + accounts.Remove(scriptHash); + } + if (account != null) + { + lock (db_lock) + { + using WalletDataContext ctx = new(Path); + if (account.HasKey) + { + Account db_account = ctx.Accounts.First(p => p.PublicKeyHash == account.Key.PublicKeyHash.ToArray()); + ctx.Accounts.Remove(db_account); + } + if (account.Contract != null) + { + Contract db_contract = ctx.Contracts.First(p => p.ScriptHash == scriptHash.ToArray()); + ctx.Contracts.Remove(db_contract); + } + //delete address + { + Address db_address = ctx.Addresses.First(p => p.ScriptHash == scriptHash.ToArray()); + ctx.Addresses.Remove(db_address); + } + ctx.SaveChanges(); + } + return true; + } + return false; + } + + public override WalletAccount GetAccount(UInt160 scriptHash) + { + lock (accounts) + { + accounts.TryGetValue(scriptHash, out SQLiteWalletAccount account); + return account; + } + } + + public override IEnumerable GetAccounts() + { + lock (accounts) + { + foreach (SQLiteWalletAccount account in accounts.Values) + yield return account; + } + } + + private Dictionary LoadAccounts() + { + using WalletDataContext ctx = new(Path); + Dictionary accounts = ctx.Addresses.Select(p => p.ScriptHash).AsEnumerable().Select(p => new SQLiteWalletAccount(new UInt160(p), ProtocolSettings)).ToDictionary(p => p.ScriptHash); + foreach (Contract db_contract in ctx.Contracts.Include(p => p.Account)) + { + VerificationContract contract = db_contract.RawData.AsSerializable(); + SQLiteWalletAccount account = accounts[contract.ScriptHash]; + account.Contract = contract; + account.Key = new KeyPair(GetPrivateKeyFromNEP2(db_contract.Account.Nep2key, masterKey, ProtocolSettings.AddressVersion, scrypt.N, scrypt.R, scrypt.P)); + } + return accounts; + } + + private byte[] LoadStoredData(string name) + { + using WalletDataContext ctx = new(Path); + return ctx.Keys.FirstOrDefault(p => p.Name == name)?.Value; + } + + /// + /// Opens a wallet at the specified path. + /// + /// The path of the wallet. + /// The password of the wallet. + /// The to be used by the wallet. + /// The opened wallet. + public static new SQLiteWallet Open(string path, string password, ProtocolSettings settings) + { + return new SQLiteWallet(path, ToAesKey(password), settings); + } + + public override void Save() + { + // Do nothing + } + + private void SaveStoredData(string name, int value) + { + byte[] data = new byte[sizeof(int)]; + BinaryPrimitives.WriteInt32LittleEndian(data, value); + SaveStoredData(name, data); + } + + private void SaveStoredData(string name, byte[] value) + { + lock (db_lock) + { + using WalletDataContext ctx = new(Path); + SaveStoredData(ctx, name, value); + ctx.SaveChanges(); + } + } + + private static void SaveStoredData(WalletDataContext ctx, string name, byte[] value) + { + Key key = ctx.Keys.FirstOrDefault(p => p.Name == name); + if (key == null) + { + ctx.Keys.Add(new Key + { + Name = name, + Value = value + }); + } + else + { + key.Value = value; + } + } + + public override bool VerifyPassword(string password) + { + return ToAesKey(password).Concat(salt).ToArray().Sha256().SequenceEqual(LoadStoredData("PasswordHash")); + } + + private static byte[] Encrypt(byte[] data, byte[] key, byte[] iv) + { + if (data == null || key == null || iv == null) throw new ArgumentNullException(); + if (data.Length % 16 != 0 || key.Length != 32 || iv.Length != 16) throw new ArgumentException(); + using Aes aes = Aes.Create(); + aes.Padding = PaddingMode.None; + using ICryptoTransform encryptor = aes.CreateEncryptor(key, iv); + return encryptor.TransformFinalBlock(data, 0, data.Length); + } + + private static byte[] Decrypt(byte[] data, byte[] key, byte[] iv) + { + if (data == null || key == null || iv == null) throw new ArgumentNullException(); + if (data.Length % 16 != 0 || key.Length != 32 || iv.Length != 16) throw new ArgumentException(); + using Aes aes = Aes.Create(); + aes.Padding = PaddingMode.None; + using ICryptoTransform decryptor = aes.CreateDecryptor(key, iv); + return decryptor.TransformFinalBlock(data, 0, data.Length); + } + + private static byte[] ToAesKey(string password) + { + using SHA256 sha256 = SHA256.Create(); + byte[] passwordBytes = Encoding.UTF8.GetBytes(password); + byte[] passwordHash = sha256.ComputeHash(passwordBytes); + byte[] passwordHash2 = sha256.ComputeHash(passwordHash); + Array.Clear(passwordBytes, 0, passwordBytes.Length); + Array.Clear(passwordHash, 0, passwordHash.Length); + return passwordHash2; + } +} diff --git a/src/Plugins/SQLiteWallet/SQLiteWallet.csproj b/src/Plugins/SQLiteWallet/SQLiteWallet.csproj new file mode 100644 index 0000000000..262459b43f --- /dev/null +++ b/src/Plugins/SQLiteWallet/SQLiteWallet.csproj @@ -0,0 +1,14 @@ + + + + net8.0 + Neo.Wallets.SQLite + Neo.Wallets.SQLite + enable + + + + + + + diff --git a/src/Plugins/SQLiteWallet/SQLiteWalletAccount.cs b/src/Plugins/SQLiteWallet/SQLiteWalletAccount.cs new file mode 100644 index 0000000000..88526f7e52 --- /dev/null +++ b/src/Plugins/SQLiteWallet/SQLiteWalletAccount.cs @@ -0,0 +1,29 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// SQLiteWalletAccount.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.Wallets.SQLite; + +sealed class SQLiteWalletAccount : WalletAccount +{ + public KeyPair Key; + + public override bool HasKey => Key != null; + + public SQLiteWalletAccount(UInt160 scriptHash, ProtocolSettings settings) + : base(scriptHash, settings) + { + } + + public override KeyPair GetKey() + { + return Key; + } +} diff --git a/src/Plugins/SQLiteWallet/SQLiteWalletFactory.cs b/src/Plugins/SQLiteWallet/SQLiteWalletFactory.cs new file mode 100644 index 0000000000..d952fd0fc3 --- /dev/null +++ b/src/Plugins/SQLiteWallet/SQLiteWalletFactory.cs @@ -0,0 +1,41 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// SQLiteWalletFactory.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.Plugins; +using static System.IO.Path; + +namespace Neo.Wallets.SQLite; + +public class SQLiteWalletFactory : Plugin, IWalletFactory +{ + public override string Name => "SQLiteWallet"; + public override string Description => "A SQLite-based wallet provider that supports wallet files with .db3 suffix."; + + public SQLiteWalletFactory() + { + Wallet.RegisterFactory(this); + } + + public bool Handle(string path) + { + return GetExtension(path).ToLowerInvariant() == ".db3"; + } + + public Wallet CreateWallet(string name, string path, string password, ProtocolSettings settings) + { + return SQLiteWallet.Create(path, password, settings); + } + + public Wallet OpenWallet(string path, string password, ProtocolSettings settings) + { + return SQLiteWallet.Open(path, password, settings); + } +} diff --git a/src/Plugins/SQLiteWallet/VerificationContract.cs b/src/Plugins/SQLiteWallet/VerificationContract.cs new file mode 100644 index 0000000000..e128045adb --- /dev/null +++ b/src/Plugins/SQLiteWallet/VerificationContract.cs @@ -0,0 +1,56 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// VerificationContract.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.IO; +using Neo.SmartContract; + +namespace Neo.Wallets.SQLite; + +class VerificationContract : SmartContract.Contract, IEquatable, ISerializable +{ + public int Size => ParameterList.GetVarSize() + Script.GetVarSize(); + + public void Deserialize(ref MemoryReader reader) + { + ReadOnlySpan span = reader.ReadVarMemory().Span; + ParameterList = new ContractParameterType[span.Length]; + for (int i = 0; i < span.Length; i++) + { + ParameterList[i] = (ContractParameterType)span[i]; + if (!Enum.IsDefined(typeof(ContractParameterType), ParameterList[i])) + throw new FormatException(); + } + Script = reader.ReadVarMemory().ToArray(); + } + + public bool Equals(VerificationContract other) + { + if (ReferenceEquals(this, other)) return true; + if (other is null) return false; + return ScriptHash.Equals(other.ScriptHash); + } + + public override bool Equals(object obj) + { + return Equals(obj as VerificationContract); + } + + public override int GetHashCode() + { + return ScriptHash.GetHashCode(); + } + + public void Serialize(BinaryWriter writer) + { + writer.WriteVarBytes(ParameterList.Select(p => (byte)p).ToArray()); + writer.WriteVarBytes(Script); + } +} diff --git a/src/Plugins/SQLiteWallet/WalletDataContext.cs b/src/Plugins/SQLiteWallet/WalletDataContext.cs new file mode 100644 index 0000000000..79ca538cd1 --- /dev/null +++ b/src/Plugins/SQLiteWallet/WalletDataContext.cs @@ -0,0 +1,64 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// WalletDataContext.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.Data.Sqlite; +using Microsoft.EntityFrameworkCore; + +namespace Neo.Wallets.SQLite; + +class WalletDataContext : DbContext +{ + public DbSet Accounts { get; set; } + public DbSet
Addresses { get; set; } + public DbSet Contracts { get; set; } + public DbSet Keys { get; set; } + + private readonly string filename; + + public WalletDataContext(string filename) + { + this.filename = filename; + } + + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) + { + base.OnConfiguring(optionsBuilder); + SqliteConnectionStringBuilder sb = new() + { + DataSource = filename + }; + optionsBuilder.UseSqlite(sb.ToString()); + } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + base.OnModelCreating(modelBuilder); + modelBuilder.Entity().ToTable(nameof(Account)); + modelBuilder.Entity().HasKey(p => p.PublicKeyHash); + modelBuilder.Entity().Property(p => p.Nep2key).HasColumnType("VarChar").HasMaxLength(byte.MaxValue).IsRequired(); + modelBuilder.Entity().Property(p => p.PublicKeyHash).HasColumnType("Binary").HasMaxLength(20).IsRequired(); + modelBuilder.Entity
().ToTable(nameof(Address)); + modelBuilder.Entity
().HasKey(p => p.ScriptHash); + modelBuilder.Entity
().Property(p => p.ScriptHash).HasColumnType("Binary").HasMaxLength(20).IsRequired(); + modelBuilder.Entity().ToTable(nameof(Contract)); + modelBuilder.Entity().HasKey(p => p.ScriptHash); + modelBuilder.Entity().HasIndex(p => p.PublicKeyHash); + modelBuilder.Entity().HasOne(p => p.Account).WithMany().HasForeignKey(p => p.PublicKeyHash).OnDelete(DeleteBehavior.Cascade); + modelBuilder.Entity().HasOne(p => p.Address).WithMany().HasForeignKey(p => p.ScriptHash).OnDelete(DeleteBehavior.Cascade); + modelBuilder.Entity().Property(p => p.RawData).HasColumnType("VarBinary").IsRequired(); + modelBuilder.Entity().Property(p => p.ScriptHash).HasColumnType("Binary").HasMaxLength(20).IsRequired(); + modelBuilder.Entity().Property(p => p.PublicKeyHash).HasColumnType("Binary").HasMaxLength(20).IsRequired(); + modelBuilder.Entity().ToTable(nameof(Key)); + modelBuilder.Entity().HasKey(p => p.Name); + modelBuilder.Entity().Property(p => p.Name).HasColumnType("VarChar").HasMaxLength(20).IsRequired(); + modelBuilder.Entity().Property(p => p.Value).HasColumnType("VarBinary").IsRequired(); + } +} diff --git a/src/Plugins/StateService/Network/MessageType.cs b/src/Plugins/StateService/Network/MessageType.cs new file mode 100644 index 0000000000..88ed5b2e9f --- /dev/null +++ b/src/Plugins/StateService/Network/MessageType.cs @@ -0,0 +1,19 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// MessageType.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.StateService.Network +{ + enum MessageType : byte + { + Vote, + StateRoot, + } +} diff --git a/src/Plugins/StateService/Network/StateRoot.cs b/src/Plugins/StateService/Network/StateRoot.cs new file mode 100644 index 0000000000..5b4e8610f2 --- /dev/null +++ b/src/Plugins/StateService/Network/StateRoot.cs @@ -0,0 +1,123 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// StateRoot.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; +using Neo.IO; +using Neo.Json; +using Neo.Network.P2P; +using Neo.Network.P2P.Payloads; +using Neo.Persistence; +using Neo.SmartContract; +using Neo.SmartContract.Native; +using System; +using System.IO; + +namespace Neo.Plugins.StateService.Network +{ + class StateRoot : IVerifiable + { + public const byte CurrentVersion = 0x00; + + public byte Version; + public uint Index; + public UInt256 RootHash; + public Witness Witness; + + private UInt256 _hash = null; + public UInt256 Hash + { + get + { + if (_hash is null) + { + _hash = this.CalculateHash(); + } + return _hash; + } + } + + Witness[] IVerifiable.Witnesses + { + get + { + return new[] { Witness }; + } + set + { + if (value.Length != 1) throw new ArgumentException(null, nameof(value)); + Witness = value[0]; + } + } + + int ISerializable.Size => + sizeof(byte) + //Version + sizeof(uint) + //Index + UInt256.Length + //RootHash + (Witness is null ? 1 : 1 + Witness.Size); //Witness + + void ISerializable.Deserialize(ref MemoryReader reader) + { + DeserializeUnsigned(ref reader); + Witness[] witnesses = reader.ReadSerializableArray(1); + Witness = witnesses.Length switch + { + 0 => null, + 1 => witnesses[0], + _ => throw new FormatException(), + }; + } + + public void DeserializeUnsigned(ref MemoryReader reader) + { + Version = reader.ReadByte(); + Index = reader.ReadUInt32(); + RootHash = reader.ReadSerializable(); + } + + void ISerializable.Serialize(BinaryWriter writer) + { + SerializeUnsigned(writer); + if (Witness is null) + writer.WriteVarInt(0); + else + writer.Write(new[] { Witness }); + } + + public void SerializeUnsigned(BinaryWriter writer) + { + writer.Write(Version); + writer.Write(Index); + writer.Write(RootHash); + } + + public bool Verify(ProtocolSettings settings, DataCache snapshot) + { + return this.VerifyWitnesses(settings, snapshot, 2_00000000L); + } + + public UInt160[] GetScriptHashesForVerifying(DataCache snapshot) + { + ECPoint[] validators = NativeContract.RoleManagement.GetDesignatedByRole(snapshot, Role.StateValidator, Index); + if (validators.Length < 1) throw new InvalidOperationException("No script hash for state root verifying"); + return new UInt160[] { Contract.GetBFTAddress(validators) }; + } + + public JObject ToJson() + { + var json = new JObject(); + json["version"] = Version; + json["index"] = Index; + json["roothash"] = RootHash.ToString(); + json["witnesses"] = Witness is null ? new JArray() : new JArray(Witness.ToJson()); + return json; + } + } +} diff --git a/src/Plugins/StateService/Network/Vote.cs b/src/Plugins/StateService/Network/Vote.cs new file mode 100644 index 0000000000..e6840c7a9f --- /dev/null +++ b/src/Plugins/StateService/Network/Vote.cs @@ -0,0 +1,40 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Vote.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.IO; +using System; +using System.IO; + +namespace Neo.Plugins.StateService.Network +{ + class Vote : ISerializable + { + public int ValidatorIndex; + public uint RootIndex; + public ReadOnlyMemory Signature; + + int ISerializable.Size => sizeof(int) + sizeof(uint) + Signature.GetVarSize(); + + void ISerializable.Serialize(BinaryWriter writer) + { + writer.Write(ValidatorIndex); + writer.Write(RootIndex); + writer.WriteVarBytes(Signature.Span); + } + + void ISerializable.Deserialize(ref MemoryReader reader) + { + ValidatorIndex = reader.ReadInt32(); + RootIndex = reader.ReadUInt32(); + Signature = reader.ReadVarMemory(64); + } + } +} diff --git a/src/Plugins/StateService/README.md b/src/Plugins/StateService/README.md new file mode 100644 index 0000000000..c8e6a2ef0d --- /dev/null +++ b/src/Plugins/StateService/README.md @@ -0,0 +1,70 @@ +# StateService + +## RPC API + +### GetStateRoot +#### Params +|Name|Type|Summary|Required| +|-|-|-|-| +|Index|uint|index|true| +#### Result +StateRoot Object +|Name|Type|Summary| +|-|-|-| +|version|number|version| +|index|number|index| +|roothash|string|version| +|witness|Object|witness from validators| + +### GetProof +#### Params +|Name|Type|Summary|Required| +|-|-|-|-| +|RootHash|UInt256|state root|true| +|ScriptHash|UInt160|contract script hash|true| +|Key|base64 string|key|true| +#### Result +Proof in base64 string + +### VerifyProof +#### Params +|Name|Type|Summary| +|-|-|-| +|RootHash|UInt256|state root|true| +|Proof|base64 string|proof|true| +#### Result +Value in base64 string + +### GetStateheight +#### Result +|Name|Type|Summary| +|-|-|-| +|localrootindex|number|root hash index calculated locally| +|validatedrootindex|number|root hash index verified by validators| + +### GetState +#### Params +|Name|Type|Summary|Required| +|-|-|-|-| +|RootHash|UInt256|specify state|true| +|ScriptHash|UInt160|contract script hash|true| +|Key|base64 string|key|true| +#### Result +Value in base64 string or `null` + +### FindStates +#### Params +|Name|Type|Summary|Required| +|-|-|-|-| +|RootHash|UInt256|specify state|true| +|ScriptHash|UInt160|contract script hash|true| +|Prefix|base64 string|key prefix|true| +|From|base64 string|start key, default `Empty`|optional| +|Count|number|count of results in one request, default `MaxFindResultItems`|optional| +#### Result +|Name|Type|Summary| +|-|-|-| +|firstProof|string|proof of first value in results| +|lastProof|string|proof of last value in results| +|truncated|bool|whether the results is truncated because of limitation| +|results|array|key-values found| diff --git a/src/Plugins/StateService/Settings.cs b/src/Plugins/StateService/Settings.cs new file mode 100644 index 0000000000..8557866bc1 --- /dev/null +++ b/src/Plugins/StateService/Settings.cs @@ -0,0 +1,40 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Settings.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; + +namespace Neo.Plugins.StateService +{ + internal class Settings + { + public string Path { get; } + public bool FullState { get; } + public uint Network { get; } + public bool AutoVerify { get; } + public int MaxFindResultItems { get; } + + public static Settings Default { get; private set; } + + private Settings(IConfigurationSection section) + { + Path = section.GetValue("Path", "Data_MPT_{0}"); + FullState = section.GetValue("FullState", false); + Network = section.GetValue("Network", 5195086u); + AutoVerify = section.GetValue("AutoVerify", false); + MaxFindResultItems = section.GetValue("MaxFindResultItems", 100); + } + + public static void Load(IConfigurationSection section) + { + Default = new Settings(section); + } + } +} diff --git a/src/Plugins/StateService/StatePlugin.cs b/src/Plugins/StateService/StatePlugin.cs new file mode 100644 index 0000000000..dda1e1aff4 --- /dev/null +++ b/src/Plugins/StateService/StatePlugin.cs @@ -0,0 +1,359 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// StatePlugin.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.ConsoleService; +using Neo.Cryptography.MPTTrie; +using Neo.IO; +using Neo.Json; +using Neo.Ledger; +using Neo.Network.P2P.Payloads; +using Neo.Persistence; +using Neo.Plugins.StateService.Network; +using Neo.Plugins.StateService.Storage; +using Neo.Plugins.StateService.Verification; +using Neo.SmartContract; +using Neo.SmartContract.Native; +using Neo.Wallets; +using System; +using System.Buffers.Binary; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using static Neo.Ledger.Blockchain; + +namespace Neo.Plugins.StateService +{ + public class StatePlugin : Plugin + { + public const string StatePayloadCategory = "StateService"; + public override string Name => "StateService"; + public override string Description => "Enables MPT for the node"; + + internal IActorRef Store; + internal IActorRef Verifier; + + internal static NeoSystem System; + private IWalletProvider walletProvider; + + public StatePlugin() + { + Blockchain.Committing += OnCommitting; + Blockchain.Committed += OnCommitted; + } + + protected override void Configure() + { + Settings.Load(GetConfiguration()); + } + + 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; + RpcServerPlugin.RegisterMethods(this, Settings.Default.Network); + } + + private void NeoSystem_ServiceAdded(object sender, object service) + { + if (service is IWalletProvider) + { + walletProvider = service as IWalletProvider; + System.ServiceAdded -= NeoSystem_ServiceAdded; + if (Settings.Default.AutoVerify) + { + walletProvider.WalletChanged += WalletProvider_WalletChanged; + } + } + } + + private void WalletProvider_WalletChanged(object sender, Wallet wallet) + { + walletProvider.WalletChanged -= WalletProvider_WalletChanged; + Start(wallet); + } + + public override void Dispose() + { + base.Dispose(); + Blockchain.Committing -= OnCommitting; + Blockchain.Committed -= OnCommitted; + 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) + { + 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) + { + if (system.Settings.Network != Settings.Default.Network) return; + StateStore.Singleton.UpdateLocalStateRoot(block.Index); + } + + [ConsoleCommand("start states", Category = "StateService", Description = "Start as a state verifier if wallet is open")] + private void OnStartVerifyingState() + { + if (System is null || System.Settings.Network != Settings.Default.Network) throw new InvalidOperationException("Network doesn't match"); + Start(walletProvider.GetWallet()); + } + + public void Start(Wallet wallet) + { + if (Verifier is not null) + { + ConsoleHelper.Warning("Already started!"); + return; + } + if (wallet is null) + { + ConsoleHelper.Warning("Please open wallet first!"); + return; + } + Verifier = System.ActorSystem.ActorOf(VerificationService.Props(wallet)); + } + + [ConsoleCommand("state root", Category = "StateService", Description = "Get state root by index")] + private void OnGetStateRoot(uint index) + { + if (System is null || System.Settings.Network != Settings.Default.Network) throw new InvalidOperationException("Network doesn't match"); + using var snapshot = StateStore.Singleton.GetSnapshot(); + StateRoot state_root = snapshot.GetStateRoot(index); + if (state_root is null) + ConsoleHelper.Warning("Unknown state root"); + else + ConsoleHelper.Info(state_root.ToJson().ToString()); + } + + [ConsoleCommand("state height", Category = "StateService", Description = "Get current state root index")] + private void OnGetStateHeight() + { + if (System is null || System.Settings.Network != Settings.Default.Network) throw new InvalidOperationException("Network doesn't match"); + ConsoleHelper.Info("LocalRootIndex: ", + $"{StateStore.Singleton.LocalRootIndex}", + " ValidatedRootIndex: ", + $"{StateStore.Singleton.ValidatedRootIndex}"); + } + + [ConsoleCommand("get proof", Category = "StateService", Description = "Get proof of key and contract hash")] + private void OnGetProof(UInt256 root_hash, UInt160 script_hash, string key) + { + if (System is null || System.Settings.Network != Settings.Default.Network) throw new InvalidOperationException("Network doesn't match"); + try + { + ConsoleHelper.Info("Proof: ", GetProof(root_hash, script_hash, Convert.FromBase64String(key))); + } + catch (RpcException e) + { + ConsoleHelper.Error(e.Message); + } + } + + [ConsoleCommand("verify proof", Category = "StateService", Description = "Verify proof, return value if successed")] + private void OnVerifyProof(UInt256 root_hash, string proof) + { + try + { + ConsoleHelper.Info("Verify Result: ", + VerifyProof(root_hash, Convert.FromBase64String(proof))); + } + catch (RpcException e) + { + ConsoleHelper.Error(e.Message); + } + } + + [RpcMethod] + public JToken GetStateRoot(JArray _params) + { + uint index = Result.Ok_Or(() => uint.Parse(_params[0].AsString()), RpcError.InvalidParams.WithData($"Invalid state root index: {_params[0]}")); + using var snapshot = StateStore.Singleton.GetSnapshot(); + StateRoot state_root = snapshot.GetStateRoot(index).NotNull_Or(RpcError.UnknownStateRoot); + return state_root.ToJson(); + } + + private string GetProof(Trie trie, int contract_id, byte[] key) + { + StorageKey skey = new() + { + Id = contract_id, + Key = key, + }; + return GetProof(trie, skey); + } + + private string GetProof(Trie trie, StorageKey skey) + { + trie.TryGetProof(skey.ToArray(), out var proof).True_Or(RpcError.UnknownStorageItem); + using MemoryStream ms = new(); + using BinaryWriter writer = new(ms, Utility.StrictUTF8); + + writer.WriteVarBytes(skey.ToArray()); + writer.WriteVarInt(proof.Count); + foreach (var item in proof) + { + writer.WriteVarBytes(item); + } + writer.Flush(); + + return Convert.ToBase64String(ms.ToArray()); + } + + private string GetProof(UInt256 root_hash, UInt160 script_hash, byte[] key) + { + (!Settings.Default.FullState && StateStore.Singleton.CurrentLocalRootHash != root_hash).False_Or(RpcError.UnsupportedState); + using var store = StateStore.Singleton.GetStoreSnapshot(); + var trie = new Trie(store, root_hash); + var contract = GetHistoricalContractState(trie, script_hash).NotNull_Or(RpcError.UnknownContract); + return GetProof(trie, contract.Id, key); + } + + [RpcMethod] + public JToken GetProof(JArray _params) + { + UInt256 root_hash = Result.Ok_Or(() => UInt256.Parse(_params[0].AsString()), RpcError.InvalidParams.WithData($"Invalid root hash: {_params[0]}")); + UInt160 script_hash = Result.Ok_Or(() => UInt160.Parse(_params[1].AsString()), RpcError.InvalidParams.WithData($"Invalid script hash: {_params[1]}")); + byte[] key = Result.Ok_Or(() => Convert.FromBase64String(_params[2].AsString()), RpcError.InvalidParams.WithData($"Invalid key: {_params[2]}")); + return GetProof(root_hash, script_hash, key); + } + + private string VerifyProof(UInt256 root_hash, byte[] proof) + { + var proofs = new HashSet(); + + using MemoryStream ms = new(proof, false); + using BinaryReader reader = new(ms, Utility.StrictUTF8); + + var key = reader.ReadVarBytes(Node.MaxKeyLength); + var count = reader.ReadVarInt(); + for (ulong i = 0; i < count; i++) + { + proofs.Add(reader.ReadVarBytes()); + } + + var value = Trie.VerifyProof(root_hash, key, proofs).NotNull_Or(RpcError.InvalidProof); + return Convert.ToBase64String(value); + } + + [RpcMethod] + public JToken VerifyProof(JArray _params) + { + UInt256 root_hash = Result.Ok_Or(() => UInt256.Parse(_params[0].AsString()), RpcError.InvalidParams.WithData($"Invalid root hash: {_params[0]}")); + byte[] proof_bytes = Result.Ok_Or(() => Convert.FromBase64String(_params[1].AsString()), RpcError.InvalidParams.WithData($"Invalid proof: {_params[1]}")); + return VerifyProof(root_hash, proof_bytes); + } + + [RpcMethod] + public JToken GetStateHeight(JArray _params) + { + var json = new JObject(); + json["localrootindex"] = StateStore.Singleton.LocalRootIndex; + json["validatedrootindex"] = StateStore.Singleton.ValidatedRootIndex; + return json; + } + + private ContractState GetHistoricalContractState(Trie trie, UInt160 script_hash) + { + const byte prefix = 8; + StorageKey skey = new KeyBuilder(NativeContract.ContractManagement.Id, prefix).Add(script_hash); + return trie.TryGetValue(skey.ToArray(), out var value) ? value.AsSerializable().GetInteroperable() : null; + } + + private StorageKey ParseStorageKey(byte[] data) + { + return new() + { + Id = BinaryPrimitives.ReadInt32LittleEndian(data), + Key = data.AsMemory(sizeof(int)), + }; + } + + [RpcMethod] + public JToken FindStates(JArray _params) + { + var root_hash = Result.Ok_Or(() => UInt256.Parse(_params[0].AsString()), RpcError.InvalidParams.WithData($"Invalid root hash: {_params[0]}")); + (!Settings.Default.FullState && StateStore.Singleton.CurrentLocalRootHash != root_hash).False_Or(RpcError.UnsupportedState); + var script_hash = Result.Ok_Or(() => UInt160.Parse(_params[1].AsString()), RpcError.InvalidParams.WithData($"Invalid script hash: {_params[1]}")); + var prefix = Result.Ok_Or(() => Convert.FromBase64String(_params[2].AsString()), RpcError.InvalidParams.WithData($"Invalid prefix: {_params[2]}")); + byte[] key = Array.Empty(); + if (3 < _params.Count) + key = Result.Ok_Or(() => Convert.FromBase64String(_params[3].AsString()), RpcError.InvalidParams.WithData($"Invalid key: {_params[3]}")); + int count = Settings.Default.MaxFindResultItems; + if (4 < _params.Count) + count = Result.Ok_Or(() => int.Parse(_params[4].AsString()), RpcError.InvalidParams.WithData($"Invalid count: {_params[4]}")); + if (Settings.Default.MaxFindResultItems < count) + count = Settings.Default.MaxFindResultItems; + using var store = StateStore.Singleton.GetStoreSnapshot(); + var trie = new Trie(store, root_hash); + var contract = GetHistoricalContractState(trie, script_hash).NotNull_Or(RpcError.UnknownContract); + StorageKey pkey = new() + { + Id = contract.Id, + Key = prefix, + }; + StorageKey fkey = new() + { + Id = pkey.Id, + Key = key, + }; + JObject json = new(); + JArray jarr = new(); + int i = 0; + foreach (var (ikey, ivalue) in trie.Find(pkey.ToArray(), 0 < key.Length ? fkey.ToArray() : null)) + { + if (count < i) break; + if (i < count) + { + JObject j = new(); + j["key"] = Convert.ToBase64String(ParseStorageKey(ikey.ToArray()).Key.Span); + j["value"] = Convert.ToBase64String(ivalue.Span); + jarr.Add(j); + } + i++; + }; + if (0 < jarr.Count) + { + json["firstProof"] = GetProof(trie, contract.Id, Convert.FromBase64String(jarr.First()["key"].AsString())); + } + if (1 < jarr.Count) + { + json["lastProof"] = GetProof(trie, contract.Id, Convert.FromBase64String(jarr.Last()["key"].AsString())); + } + json["truncated"] = count < i; + json["results"] = jarr; + return json; + } + + [RpcMethod] + public JToken GetState(JArray _params) + { + var root_hash = Result.Ok_Or(() => UInt256.Parse(_params[0].AsString()), RpcError.InvalidParams.WithData($"Invalid root hash: {_params[0]}")); + (!Settings.Default.FullState && StateStore.Singleton.CurrentLocalRootHash != root_hash).False_Or(RpcError.UnsupportedState); + var script_hash = Result.Ok_Or(() => UInt160.Parse(_params[1].AsString()), RpcError.InvalidParams.WithData($"Invalid script hash: {_params[1]}")); + var key = Result.Ok_Or(() => Convert.FromBase64String(_params[2].AsString()), RpcError.InvalidParams.WithData($"Invalid key: {_params[2]}")); + using var store = StateStore.Singleton.GetStoreSnapshot(); + var trie = new Trie(store, root_hash); + + var contract = GetHistoricalContractState(trie, script_hash).NotNull_Or(RpcError.UnknownContract); + StorageKey skey = new() + { + Id = contract.Id, + Key = key, + }; + return Convert.ToBase64String(trie[skey.ToArray()]); + } + } +} diff --git a/src/Plugins/StateService/StateService.csproj b/src/Plugins/StateService/StateService.csproj new file mode 100644 index 0000000000..25045d59bc --- /dev/null +++ b/src/Plugins/StateService/StateService.csproj @@ -0,0 +1,15 @@ + + + + net8.0 + Neo.Plugins.StateService + true + + + + + + + + + \ No newline at end of file diff --git a/src/Plugins/StateService/Storage/Keys.cs b/src/Plugins/StateService/Storage/Keys.cs new file mode 100644 index 0000000000..4ffecef48e --- /dev/null +++ b/src/Plugins/StateService/Storage/Keys.cs @@ -0,0 +1,30 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Keys.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.Buffers.Binary; + +namespace Neo.Plugins.StateService.Storage +{ + public static class Keys + { + public static byte[] StateRoot(uint index) + { + byte[] buffer = new byte[sizeof(uint) + 1]; + buffer[0] = 1; + BinaryPrimitives.WriteUInt32BigEndian(buffer.AsSpan(1), index); + return buffer; + } + + public static readonly byte[] CurrentLocalRootIndex = { 0x02 }; + public static readonly byte[] CurrentValidatedRootIndex = { 0x04 }; + } +} diff --git a/src/Plugins/StateService/Storage/StateSnapshot.cs b/src/Plugins/StateService/Storage/StateSnapshot.cs new file mode 100644 index 0000000000..70ec006227 --- /dev/null +++ b/src/Plugins/StateService/Storage/StateSnapshot.cs @@ -0,0 +1,92 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// StateSnapshot.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.MPTTrie; +using Neo.IO; +using Neo.Persistence; +using Neo.Plugins.StateService.Network; +using System; + +namespace Neo.Plugins.StateService.Storage +{ + class StateSnapshot : IDisposable + { + private readonly ISnapshot snapshot; + public Trie Trie; + + public StateSnapshot(IStore store) + { + snapshot = store.GetSnapshot(); + Trie = new Trie(snapshot, CurrentLocalRootHash(), Settings.Default.FullState); + } + + public StateRoot GetStateRoot(uint index) + { + return snapshot.TryGet(Keys.StateRoot(index))?.AsSerializable(); + } + + public void AddLocalStateRoot(StateRoot state_root) + { + snapshot.Put(Keys.StateRoot(state_root.Index), state_root.ToArray()); + snapshot.Put(Keys.CurrentLocalRootIndex, BitConverter.GetBytes(state_root.Index)); + } + + public uint? CurrentLocalRootIndex() + { + var bytes = snapshot.TryGet(Keys.CurrentLocalRootIndex); + if (bytes is null) return null; + return BitConverter.ToUInt32(bytes); + } + + public UInt256 CurrentLocalRootHash() + { + var index = CurrentLocalRootIndex(); + if (index is null) return null; + return GetStateRoot((uint)index)?.RootHash; + } + + public void AddValidatedStateRoot(StateRoot state_root) + { + if (state_root?.Witness is null) + throw new ArgumentException(nameof(state_root) + " missing witness in invalidated state root"); + snapshot.Put(Keys.StateRoot(state_root.Index), state_root.ToArray()); + snapshot.Put(Keys.CurrentValidatedRootIndex, BitConverter.GetBytes(state_root.Index)); + } + + public uint? CurrentValidatedRootIndex() + { + var bytes = snapshot.TryGet(Keys.CurrentValidatedRootIndex); + if (bytes is null) return null; + return BitConverter.ToUInt32(bytes); + } + + public UInt256 CurrentValidatedRootHash() + { + var index = CurrentLocalRootIndex(); + if (index is null) return null; + var state_root = GetStateRoot((uint)index); + if (state_root is null || state_root.Witness is null) + throw new InvalidOperationException(nameof(CurrentValidatedRootHash) + " could not get validated state root"); + return state_root.RootHash; + } + + public void Commit() + { + Trie.Commit(); + snapshot.Commit(); + } + + public void Dispose() + { + snapshot.Dispose(); + } + } +} diff --git a/src/Plugins/StateService/Storage/StateStore.cs b/src/Plugins/StateService/Storage/StateStore.cs new file mode 100644 index 0000000000..1feb8bfacb --- /dev/null +++ b/src/Plugins/StateService/Storage/StateStore.cs @@ -0,0 +1,188 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// StateStore.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.IO; +using Neo.Ledger; +using Neo.Network.P2P.Payloads; +using Neo.Persistence; +using Neo.Plugins.StateService.Network; +using Neo.Plugins.StateService.Verification; +using System; +using System.Collections.Generic; +using System.Threading; + +namespace Neo.Plugins.StateService.Storage +{ + class StateStore : UntypedActor + { + private readonly StatePlugin system; + private readonly IStore store; + private const int MaxCacheCount = 100; + private readonly Dictionary cache = new Dictionary(); + private StateSnapshot currentSnapshot; + private StateSnapshot _state_snapshot; + public UInt256 CurrentLocalRootHash => currentSnapshot.CurrentLocalRootHash(); + public uint? LocalRootIndex => currentSnapshot.CurrentLocalRootIndex(); + public uint? ValidatedRootIndex => currentSnapshot.CurrentValidatedRootIndex(); + + private static StateStore singleton; + public static StateStore Singleton + { + get + { + while (singleton is null) Thread.Sleep(10); + return singleton; + } + } + + public StateStore(StatePlugin system, string path) + { + if (singleton != null) throw new InvalidOperationException(nameof(StateStore)); + this.system = system; + store = StatePlugin.System.LoadStore(path); + singleton = this; + StatePlugin.System.ActorSystem.EventStream.Subscribe(Self, typeof(Blockchain.RelayResult)); + UpdateCurrentSnapshot(); + } + + public void Dispose() + { + store.Dispose(); + } + + public StateSnapshot GetSnapshot() + { + return new StateSnapshot(store); + } + + public ISnapshot GetStoreSnapshot() + { + return store.GetSnapshot(); + } + + protected override void OnReceive(object message) + { + switch (message) + { + case StateRoot state_root: + OnNewStateRoot(state_root); + break; + case Blockchain.RelayResult rr: + if (rr.Result == VerifyResult.Succeed && rr.Inventory is ExtensiblePayload payload && payload.Category == StatePlugin.StatePayloadCategory) + OnStatePayload(payload); + break; + default: + break; + } + } + + private void OnStatePayload(ExtensiblePayload payload) + { + if (payload.Data.Length == 0) return; + if ((MessageType)payload.Data.Span[0] != MessageType.StateRoot) return; + StateRoot message; + try + { + message = payload.Data[1..].AsSerializable(); + } + catch (FormatException) + { + return; + } + OnNewStateRoot(message); + } + + private bool OnNewStateRoot(StateRoot state_root) + { + if (state_root?.Witness is null) return false; + if (ValidatedRootIndex != null && state_root.Index <= ValidatedRootIndex) return false; + if (LocalRootIndex is null) throw new InvalidOperationException(nameof(StateStore) + " could not get local root index"); + if (LocalRootIndex < state_root.Index && state_root.Index < LocalRootIndex + MaxCacheCount) + { + cache.Add(state_root.Index, state_root); + return true; + } + using var state_snapshot = Singleton.GetSnapshot(); + StateRoot local_root = state_snapshot.GetStateRoot(state_root.Index); + if (local_root is null || local_root.Witness != null) return false; + if (!state_root.Verify(StatePlugin.System.Settings, StatePlugin.System.StoreView)) return false; + if (local_root.RootHash != state_root.RootHash) return false; + state_snapshot.AddValidatedStateRoot(state_root); + state_snapshot.Commit(); + UpdateCurrentSnapshot(); + system.Verifier?.Tell(new VerificationService.ValidatedRootPersisted { Index = state_root.Index }); + return true; + } + + public void UpdateLocalStateRootSnapshot(uint height, List change_set) + { + _state_snapshot = Singleton.GetSnapshot(); + foreach (var item in change_set) + { + switch (item.State) + { + case TrackState.Added: + _state_snapshot.Trie.Put(item.Key.ToArray(), item.Item.ToArray()); + break; + case TrackState.Changed: + _state_snapshot.Trie.Put(item.Key.ToArray(), item.Item.ToArray()); + break; + case TrackState.Deleted: + _state_snapshot.Trie.Delete(item.Key.ToArray()); + break; + } + } + UInt256 root_hash = _state_snapshot.Trie.Root.Hash; + StateRoot state_root = new StateRoot + { + Version = StateRoot.CurrentVersion, + Index = height, + RootHash = root_hash, + Witness = null, + }; + _state_snapshot.AddLocalStateRoot(state_root); + } + + public void UpdateLocalStateRoot(uint height) + { + _state_snapshot?.Commit(); + _state_snapshot = null; + UpdateCurrentSnapshot(); + system.Verifier?.Tell(new VerificationService.BlockPersisted { Index = height }); + CheckValidatedStateRoot(height); + } + + private void CheckValidatedStateRoot(uint index) + { + if (cache.TryGetValue(index, out StateRoot state_root)) + { + cache.Remove(index); + Self.Tell(state_root); + } + } + + private void UpdateCurrentSnapshot() + { + Interlocked.Exchange(ref currentSnapshot, GetSnapshot())?.Dispose(); + } + + protected override void PostStop() + { + base.PostStop(); + } + + public static Props Props(StatePlugin system, string path) + { + return Akka.Actor.Props.Create(() => new StateStore(system, path)); + } + } +} diff --git a/src/Plugins/StateService/Verification/VerificationContext.cs b/src/Plugins/StateService/Verification/VerificationContext.cs new file mode 100644 index 0000000000..53743c1345 --- /dev/null +++ b/src/Plugins/StateService/Verification/VerificationContext.cs @@ -0,0 +1,177 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// VerificationContext.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.Cryptography; +using Neo.Cryptography.ECC; +using Neo.IO; +using Neo.Network.P2P; +using Neo.Network.P2P.Payloads; +using Neo.Plugins.StateService.Network; +using Neo.Plugins.StateService.Storage; +using Neo.SmartContract; +using Neo.SmartContract.Native; +using Neo.Wallets; +using System.Collections.Concurrent; +using System.IO; + +namespace Neo.Plugins.StateService.Verification +{ + class VerificationContext + { + private const uint MaxValidUntilBlockIncrement = 100; + private StateRoot root; + private ExtensiblePayload rootPayload; + private ExtensiblePayload votePayload; + private readonly Wallet wallet; + private readonly KeyPair keyPair; + private readonly int myIndex; + private readonly uint rootIndex; + private readonly ECPoint[] verifiers; + private int M => verifiers.Length - (verifiers.Length - 1) / 3; + private readonly ConcurrentDictionary signatures = new ConcurrentDictionary(); + + public int Retries; + public bool IsValidator => myIndex >= 0; + public int MyIndex => myIndex; + public uint RootIndex => rootIndex; + public ECPoint[] Verifiers => verifiers; + public int Sender + { + get + { + int p = ((int)rootIndex - Retries) % verifiers.Length; + return p >= 0 ? p : p + verifiers.Length; + } + } + public bool IsSender => myIndex == Sender; + public ICancelable Timer; + public StateRoot StateRoot + { + get + { + if (root is null) + { + using var snapshot = StateStore.Singleton.GetSnapshot(); + root = snapshot.GetStateRoot(rootIndex); + } + return root; + } + } + public ExtensiblePayload StateRootMessage => rootPayload; + public ExtensiblePayload VoteMessage + { + get + { + if (votePayload is null) + votePayload = CreateVoteMessage(); + return votePayload; + } + } + + public VerificationContext(Wallet wallet, uint index) + { + this.wallet = wallet; + Retries = 0; + myIndex = -1; + rootIndex = index; + verifiers = NativeContract.RoleManagement.GetDesignatedByRole(StatePlugin.System.StoreView, Role.StateValidator, index); + if (wallet is null) return; + for (int i = 0; i < verifiers.Length; i++) + { + WalletAccount account = wallet.GetAccount(verifiers[i]); + if (account?.HasKey != true) continue; + myIndex = i; + keyPair = account.GetKey(); + break; + } + } + + private ExtensiblePayload CreateVoteMessage() + { + if (StateRoot is null) return null; + if (!signatures.TryGetValue(myIndex, out byte[] sig)) + { + sig = StateRoot.Sign(keyPair, StatePlugin.System.Settings.Network); + signatures[myIndex] = sig; + } + return CreatePayload(MessageType.Vote, new Vote + { + RootIndex = rootIndex, + ValidatorIndex = myIndex, + Signature = sig + }, VerificationService.MaxCachedVerificationProcessCount); + } + + public bool AddSignature(int index, byte[] sig) + { + if (M <= signatures.Count) return false; + if (index < 0 || verifiers.Length <= index) return false; + if (signatures.ContainsKey(index)) return false; + Utility.Log(nameof(VerificationContext), LogLevel.Info, $"vote received, height={rootIndex}, index={index}"); + ECPoint validator = verifiers[index]; + byte[] hash_data = StateRoot?.GetSignData(StatePlugin.System.Settings.Network); + if (hash_data is null || !Crypto.VerifySignature(hash_data, sig, validator)) + { + Utility.Log(nameof(VerificationContext), LogLevel.Info, "incorrect vote, invalid signature"); + return false; + } + return signatures.TryAdd(index, sig); + } + + public bool CheckSignatures() + { + if (StateRoot is null) return false; + if (signatures.Count < M) return false; + if (StateRoot.Witness is null) + { + Contract contract = Contract.CreateMultiSigContract(M, verifiers); + ContractParametersContext sc = new(StatePlugin.System.StoreView, StateRoot, StatePlugin.System.Settings.Network); + for (int i = 0, j = 0; i < verifiers.Length && j < M; i++) + { + if (!signatures.TryGetValue(i, out byte[] sig)) continue; + sc.AddSignature(contract, verifiers[i], sig); + j++; + } + if (!sc.Completed) return false; + StateRoot.Witness = sc.GetWitnesses()[0]; + } + if (IsSender) + rootPayload = CreatePayload(MessageType.StateRoot, StateRoot, MaxValidUntilBlockIncrement); + return true; + } + + private ExtensiblePayload CreatePayload(MessageType type, ISerializable payload, uint validBlockEndThreshold) + { + byte[] data; + using (MemoryStream ms = new MemoryStream()) + using (BinaryWriter writer = new BinaryWriter(ms)) + { + writer.Write((byte)type); + payload.Serialize(writer); + writer.Flush(); + data = ms.ToArray(); + } + ExtensiblePayload msg = new ExtensiblePayload + { + Category = StatePlugin.StatePayloadCategory, + ValidBlockStart = StateRoot.Index, + ValidBlockEnd = StateRoot.Index + validBlockEndThreshold, + Sender = Contract.CreateSignatureRedeemScript(verifiers[MyIndex]).ToScriptHash(), + Data = data, + }; + ContractParametersContext sc = new ContractParametersContext(StatePlugin.System.StoreView, msg, StatePlugin.System.Settings.Network); + wallet.Sign(sc); + msg.Witness = sc.GetWitnesses()[0]; + return msg; + } + } +} diff --git a/src/Plugins/StateService/Verification/VerificationService.cs b/src/Plugins/StateService/Verification/VerificationService.cs new file mode 100644 index 0000000000..c6730e7905 --- /dev/null +++ b/src/Plugins/StateService/Verification/VerificationService.cs @@ -0,0 +1,170 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// VerificationService.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 Akka.Util.Internal; +using Neo.IO; +using Neo.Ledger; +using Neo.Network.P2P.Payloads; +using Neo.Plugins.StateService.Network; +using Neo.Wallets; +using System; +using System.Collections.Concurrent; +using System.Linq; + +namespace Neo.Plugins.StateService.Verification +{ + public class VerificationService : UntypedActor + { + public class ValidatedRootPersisted { public uint Index; } + public class BlockPersisted { public uint Index; } + public const int MaxCachedVerificationProcessCount = 10; + private class Timer { public uint Index; } + private static readonly uint TimeoutMilliseconds = StatePlugin.System.Settings.MillisecondsPerBlock; + private static readonly uint DelayMilliseconds = 3000; + private readonly Wallet wallet; + private readonly ConcurrentDictionary contexts = new ConcurrentDictionary(); + + public VerificationService(Wallet wallet) + { + this.wallet = wallet; + StatePlugin.System.ActorSystem.EventStream.Subscribe(Self, typeof(Blockchain.RelayResult)); + } + + private void SendVote(VerificationContext context) + { + if (context.VoteMessage is null) return; + Utility.Log(nameof(VerificationService), LogLevel.Info, $"relay vote, height={context.RootIndex}, retry={context.Retries}"); + StatePlugin.System.Blockchain.Tell(context.VoteMessage); + } + + private void OnStateRootVote(Vote vote) + { + if (contexts.TryGetValue(vote.RootIndex, out VerificationContext context) && context.AddSignature(vote.ValidatorIndex, vote.Signature.ToArray())) + { + CheckVotes(context); + } + } + + private void CheckVotes(VerificationContext context) + { + if (context.IsSender && context.CheckSignatures()) + { + if (context.StateRootMessage is null) return; + Utility.Log(nameof(VerificationService), LogLevel.Info, $"relay state root, height={context.StateRoot.Index}, root={context.StateRoot.RootHash}"); + StatePlugin.System.Blockchain.Tell(context.StateRootMessage); + } + } + + private void OnBlockPersisted(uint index) + { + if (MaxCachedVerificationProcessCount <= contexts.Count) + { + contexts.Keys.OrderBy(p => p).Take(contexts.Count - MaxCachedVerificationProcessCount + 1).ForEach(p => + { + if (contexts.TryRemove(p, out var value)) + { + value.Timer.CancelIfNotNull(); + } + }); + } + var p = new VerificationContext(wallet, index); + if (p.IsValidator && contexts.TryAdd(index, p)) + { + p.Timer = Context.System.Scheduler.ScheduleTellOnceCancelable(TimeSpan.FromMilliseconds(DelayMilliseconds), Self, new Timer + { + Index = index, + }, ActorRefs.NoSender); + Utility.Log(nameof(VerificationContext), LogLevel.Info, $"new validate process, height={index}, index={p.MyIndex}, ongoing={contexts.Count}"); + } + } + + private void OnValidatedRootPersisted(uint index) + { + Utility.Log(nameof(VerificationService), LogLevel.Info, $"persisted state root, height={index}"); + foreach (var i in contexts.Where(i => i.Key <= index)) + { + if (contexts.TryRemove(i.Key, out var value)) + { + value.Timer.CancelIfNotNull(); + } + } + } + + private void OnTimer(uint index) + { + if (contexts.TryGetValue(index, out VerificationContext context)) + { + SendVote(context); + CheckVotes(context); + context.Timer.CancelIfNotNull(); + context.Timer = Context.System.Scheduler.ScheduleTellOnceCancelable(TimeSpan.FromMilliseconds(TimeoutMilliseconds << context.Retries), Self, new Timer + { + Index = index, + }, ActorRefs.NoSender); + context.Retries++; + } + } + + private void OnVoteMessage(ExtensiblePayload payload) + { + if (payload.Data.Length == 0) return; + if ((MessageType)payload.Data.Span[0] != MessageType.Vote) return; + Vote message; + try + { + message = payload.Data[1..].AsSerializable(); + } + catch (FormatException) + { + return; + } + OnStateRootVote(message); + } + + protected override void OnReceive(object message) + { + switch (message) + { + case Vote v: + OnStateRootVote(v); + break; + case BlockPersisted bp: + OnBlockPersisted(bp.Index); + break; + case ValidatedRootPersisted root: + OnValidatedRootPersisted(root.Index); + break; + case Timer timer: + OnTimer(timer.Index); + break; + case Blockchain.RelayResult rr: + if (rr.Result == VerifyResult.Succeed && rr.Inventory is ExtensiblePayload payload && payload.Category == StatePlugin.StatePayloadCategory) + { + OnVoteMessage(payload); + } + break; + default: + break; + } + } + + protected override void PostStop() + { + base.PostStop(); + } + + public static Props Props(Wallet wallet) + { + return Akka.Actor.Props.Create(() => new VerificationService(wallet)); + } + } +} diff --git a/src/Plugins/StateService/config.json b/src/Plugins/StateService/config.json new file mode 100644 index 0000000000..265436fc30 --- /dev/null +++ b/src/Plugins/StateService/config.json @@ -0,0 +1,12 @@ +{ + "PluginConfiguration": { + "Path": "Data_MPT_{0}", + "FullState": false, + "Network": 860833102, + "AutoVerify": false, + "MaxFindResultItems": 100 + }, + "Dependency": [ + "RpcServer" + ] +} diff --git a/src/Plugins/StatesDumper/PersistActions.cs b/src/Plugins/StatesDumper/PersistActions.cs new file mode 100644 index 0000000000..9c1aa2210c --- /dev/null +++ b/src/Plugins/StatesDumper/PersistActions.cs @@ -0,0 +1,21 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// PersistActions.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; + +namespace Neo.Plugins +{ + [Flags] + internal enum PersistActions : byte + { + StorageChanges = 0b00000001 + } +} diff --git a/src/Plugins/StatesDumper/Settings.cs b/src/Plugins/StatesDumper/Settings.cs new file mode 100644 index 0000000000..8fd3b9e163 --- /dev/null +++ b/src/Plugins/StatesDumper/Settings.cs @@ -0,0 +1,58 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Settings.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 Neo.SmartContract.Native; +using System.Collections.Generic; +using System.Linq; + +namespace Neo.Plugins +{ + internal class Settings + { + /// + /// Amount of storages states (heights) to be dump in a given json file + /// + public uint BlockCacheSize { get; } + /// + /// Height to begin storage dump + /// + public uint HeightToBegin { get; } + /// + /// Height to begin real-time syncing and dumping on, consequently, dumping every block into a single files + /// + public int HeightToStartRealTimeSyncing { get; } + /// + /// Persisting actions + /// + public PersistActions PersistAction { get; } + public IReadOnlyList Exclude { get; } + + public static Settings Default { get; private set; } + + private Settings(IConfigurationSection section) + { + /// Geting settings for storage changes state dumper + BlockCacheSize = section.GetValue("BlockCacheSize", 1000u); + HeightToBegin = section.GetValue("HeightToBegin", 0u); + HeightToStartRealTimeSyncing = section.GetValue("HeightToStartRealTimeSyncing", -1); + PersistAction = section.GetValue("PersistAction", PersistActions.StorageChanges); + Exclude = section.GetSection("Exclude").Exists() + ? section.GetSection("Exclude").GetChildren().Select(p => int.Parse(p.Value)).ToArray() + : new[] { NativeContract.Ledger.Id }; + } + + public static void Load(IConfigurationSection section) + { + Default = new Settings(section); + } + } +} diff --git a/src/Plugins/StatesDumper/StatesDumper.cs b/src/Plugins/StatesDumper/StatesDumper.cs new file mode 100644 index 0000000000..a74bda1556 --- /dev/null +++ b/src/Plugins/StatesDumper/StatesDumper.cs @@ -0,0 +1,167 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// StatesDumper.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.ConsoleService; +using Neo.IO; +using Neo.Json; +using Neo.Ledger; +using Neo.Network.P2P.Payloads; +using Neo.Persistence; +using Neo.SmartContract.Native; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace Neo.Plugins +{ + public class StatesDumper : Plugin + { + private readonly Dictionary bs_cache = new Dictionary(); + private readonly Dictionary systems = new Dictionary(); + + public override string Description => "Exports Neo-CLI status data"; + + public StatesDumper() + { + Blockchain.Committing += OnCommitting; + Blockchain.Committed += OnCommitted; + } + + public override void Dispose() + { + Blockchain.Committing -= OnCommitting; + Blockchain.Committed -= OnCommitted; + } + + protected override void Configure() + { + Settings.Load(GetConfiguration()); + } + + protected override void OnSystemLoaded(NeoSystem system) + { + systems.Add(system.Settings.Network, system); + } + + /// + /// Process "dump storage" command + /// + [ConsoleCommand("dump storage", Category = "Storage", Description = "You can specify the contract script hash or use null to get the corresponding information from the storage")] + private void OnDumpStorage(uint network, UInt160 contractHash = null) + { + if (!systems.ContainsKey(network)) throw new InvalidOperationException("invalid network"); + string path = $"dump_{network:x8}.json"; + byte[] prefix = null; + if (contractHash is not null) + { + var contract = NativeContract.ContractManagement.GetContract(systems[network].StoreView, contractHash); + if (contract is null) throw new InvalidOperationException("contract not found"); + prefix = BitConverter.GetBytes(contract.Id); + } + var states = systems[network].StoreView.Find(prefix); + JArray array = new JArray(states.Where(p => !Settings.Default.Exclude.Contains(p.Key.Id)).Select(p => new JObject + { + ["key"] = Convert.ToBase64String(p.Key.ToArray()), + ["value"] = Convert.ToBase64String(p.Value.ToArray()) + })); + File.WriteAllText(path, array.ToString()); + ConsoleHelper.Info("States", + $"({array.Count})", + " have been dumped into file ", + $"{path}"); + } + + private void OnCommitting(NeoSystem system, Block block, DataCache snapshot, IReadOnlyList applicationExecutedList) + { + if (Settings.Default.PersistAction.HasFlag(PersistActions.StorageChanges)) + OnPersistStorage(system.Settings.Network, snapshot); + } + + private void OnPersistStorage(uint network, DataCache snapshot) + { + uint blockIndex = NativeContract.Ledger.CurrentIndex(snapshot); + if (blockIndex >= Settings.Default.HeightToBegin) + { + JArray array = new JArray(); + + foreach (var trackable in snapshot.GetChangeSet()) + { + if (Settings.Default.Exclude.Contains(trackable.Key.Id)) + continue; + JObject state = new JObject(); + switch (trackable.State) + { + case TrackState.Added: + state["state"] = "Added"; + state["key"] = Convert.ToBase64String(trackable.Key.ToArray()); + state["value"] = Convert.ToBase64String(trackable.Item.ToArray()); + // Here we have a new trackable.Key and trackable.Item + break; + case TrackState.Changed: + state["state"] = "Changed"; + state["key"] = Convert.ToBase64String(trackable.Key.ToArray()); + state["value"] = Convert.ToBase64String(trackable.Item.ToArray()); + break; + case TrackState.Deleted: + state["state"] = "Deleted"; + state["key"] = Convert.ToBase64String(trackable.Key.ToArray()); + break; + } + array.Add(state); + } + + JObject bs_item = new JObject(); + bs_item["block"] = blockIndex; + bs_item["size"] = array.Count; + bs_item["storage"] = array; + if (!bs_cache.TryGetValue(network, out JArray cache)) + { + cache = new JArray(); + } + cache.Add(bs_item); + bs_cache[network] = cache; + } + } + + private void OnCommitted(NeoSystem system, Block block) + { + if (Settings.Default.PersistAction.HasFlag(PersistActions.StorageChanges)) + OnCommitStorage(system.Settings.Network, system.StoreView); + } + + void OnCommitStorage(uint network, DataCache snapshot) + { + if (!bs_cache.TryGetValue(network, out JArray cache)) return; + if (cache.Count == 0) return; + uint blockIndex = NativeContract.Ledger.CurrentIndex(snapshot); + if ((blockIndex % Settings.Default.BlockCacheSize == 0) || (Settings.Default.HeightToStartRealTimeSyncing != -1 && blockIndex >= Settings.Default.HeightToStartRealTimeSyncing)) + { + string path = HandlePaths(network, blockIndex); + path = $"{path}/dump-block-{blockIndex}.json"; + File.WriteAllText(path, cache.ToString()); + cache.Clear(); + } + } + + private static string HandlePaths(uint network, uint blockIndex) + { + //Default Parameter + uint storagePerFolder = 100000; + uint folder = (((blockIndex - 1) / storagePerFolder) + 1) * storagePerFolder; + if (blockIndex == 0) + folder = 0; + string dirPathWithBlock = $"./Storage_{network:x8}/BlockStorage_{folder}"; + Directory.CreateDirectory(dirPathWithBlock); + return dirPathWithBlock; + } + } +} diff --git a/src/Plugins/StatesDumper/StatesDumper.csproj b/src/Plugins/StatesDumper/StatesDumper.csproj new file mode 100644 index 0000000000..380f20c89a --- /dev/null +++ b/src/Plugins/StatesDumper/StatesDumper.csproj @@ -0,0 +1,12 @@ + + + + net8.0 + Neo.Plugins.StatesDumper + + + + + + + diff --git a/src/Plugins/StatesDumper/config.json b/src/Plugins/StatesDumper/config.json new file mode 100644 index 0000000000..c3b73767dd --- /dev/null +++ b/src/Plugins/StatesDumper/config.json @@ -0,0 +1,9 @@ +{ + "PluginConfiguration": { + "PersistAction": "StorageChanges", + "BlockCacheSize": 1000, + "HeightToBegin": 0, + "HeightToStartRealTimeSyncing": -1, + "Exclude": [ -4 ] + } +} diff --git a/src/Plugins/StorageDumper/Settings.cs b/src/Plugins/StorageDumper/Settings.cs new file mode 100644 index 0000000000..84fe2b2231 --- /dev/null +++ b/src/Plugins/StorageDumper/Settings.cs @@ -0,0 +1,47 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Settings.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 Neo.SmartContract.Native; + +namespace Neo.Plugins +{ + internal class Settings + { + /// + /// Amount of storages states (heights) to be dump in a given json file + /// + public uint BlockCacheSize { get; } + /// + /// Height to begin storage dump + /// + public uint HeightToBegin { get; } + + public IReadOnlyList Exclude { get; } + + public static Settings? Default { get; private set; } + + private Settings(IConfigurationSection section) + { + /// Geting settings for storage changes state dumper + BlockCacheSize = section.GetValue("BlockCacheSize", 1000u); + HeightToBegin = section.GetValue("HeightToBegin", 0u); + Exclude = section.GetSection("Exclude").Exists() + ? section.GetSection("Exclude").GetChildren().Select(p => int.Parse(p.Value)).ToArray() + : new[] { NativeContract.Ledger.Id }; + } + + public static void Load(IConfigurationSection section) + { + Default = new Settings(section); + } + } +} diff --git a/src/Plugins/StorageDumper/StorageDumper.cs b/src/Plugins/StorageDumper/StorageDumper.cs new file mode 100644 index 0000000000..9f377b8ef7 --- /dev/null +++ b/src/Plugins/StorageDumper/StorageDumper.cs @@ -0,0 +1,182 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// StorageDumper.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.ConsoleService; +using Neo.IO; +using Neo.Json; +using Neo.Ledger; +using Neo.Network.P2P.Payloads; +using Neo.Persistence; +using Neo.SmartContract.Native; + +namespace Neo.Plugins +{ + public class StorageDumper : Plugin + { + private readonly Dictionary systems = new Dictionary(); + + private StreamWriter _writer; + private JObject _currentBlock; + private string _lastCreateDirectory; + + + public override string Description => "Exports Neo-CLI status data"; + + public StorageDumper() + { + Blockchain.Committing += OnCommitting; + Blockchain.Committed += OnCommitted; + } + + public override void Dispose() + { + Blockchain.Committing -= OnCommitting; + Blockchain.Committed -= OnCommitted; + } + + protected override void Configure() + { + Settings.Load(GetConfiguration()); + } + + protected override void OnSystemLoaded(NeoSystem system) + { + systems.Add(system.Settings.Network, system); + } + + /// + /// Process "dump contract-storage" command + /// + [ConsoleCommand("dump contract-storage", Category = "Storage", Description = "You can specify the contract script hash or use null to get the corresponding information from the storage")] + private void OnDumpStorage(uint network, UInt160? contractHash = null) + { + if (!systems.ContainsKey(network)) throw new InvalidOperationException("invalid network"); + string path = $"dump_{network}.json"; + byte[]? prefix = null; + if (contractHash is not null) + { + var contract = NativeContract.ContractManagement.GetContract(systems[network].StoreView, contractHash); + if (contract is null) throw new InvalidOperationException("contract not found"); + prefix = BitConverter.GetBytes(contract.Id); + } + var states = systems[network].StoreView.Find(prefix); + JArray array = new JArray(states.Where(p => !Settings.Default.Exclude.Contains(p.Key.Id)).Select(p => new JObject + { + ["key"] = Convert.ToBase64String(p.Key.ToArray()), + ["value"] = Convert.ToBase64String(p.Value.ToArray()) + })); + File.WriteAllText(path, array.ToString()); + ConsoleHelper.Info("States", + $"({array.Count})", + " have been dumped into file ", + $"{path}"); + } + + private void OnCommitting(NeoSystem system, Block block, DataCache snapshot, IReadOnlyList applicationExecutedList) + { + InitFileWriter(system.Settings.Network, snapshot); + OnPersistStorage(system.Settings.Network, snapshot); + } + + private void OnPersistStorage(uint network, DataCache snapshot) + { + uint blockIndex = NativeContract.Ledger.CurrentIndex(snapshot); + if (blockIndex >= Settings.Default.HeightToBegin) + { + JArray array = new JArray(); + + foreach (var trackable in snapshot.GetChangeSet()) + { + if (Settings.Default.Exclude.Contains(trackable.Key.Id)) + continue; + JObject state = new JObject(); + switch (trackable.State) + { + case TrackState.Added: + state["state"] = "Added"; + state["key"] = Convert.ToBase64String(trackable.Key.ToArray()); + state["value"] = Convert.ToBase64String(trackable.Item.ToArray()); + // Here we have a new trackable.Key and trackable.Item + break; + case TrackState.Changed: + state["state"] = "Changed"; + state["key"] = Convert.ToBase64String(trackable.Key.ToArray()); + state["value"] = Convert.ToBase64String(trackable.Item.ToArray()); + break; + case TrackState.Deleted: + state["state"] = "Deleted"; + state["key"] = Convert.ToBase64String(trackable.Key.ToArray()); + break; + } + array.Add(state); + } + + JObject bs_item = new JObject(); + bs_item["block"] = blockIndex; + bs_item["size"] = array.Count; + bs_item["storage"] = array; + _currentBlock = bs_item; + } + } + + + private void OnCommitted(NeoSystem system, Block block) + { + OnCommitStorage(system.Settings.Network, system.StoreView); + } + + void OnCommitStorage(uint network, DataCache snapshot) + { + if (_currentBlock != null) + { + _writer.WriteLine(_currentBlock.ToString()); + _writer.Flush(); + } + } + + private void InitFileWriter(uint network, DataCache snapshot) + { + uint blockIndex = NativeContract.Ledger.CurrentIndex(snapshot); + if (_writer == null + || blockIndex % Settings.Default.BlockCacheSize == 0) + { + string path = GetOrCreateDirectory(network, blockIndex); + var filepart = (blockIndex / Settings.Default.BlockCacheSize) * Settings.Default.BlockCacheSize; + path = $"{path}/dump-block-{filepart}.dump"; + if (_writer != null) + { + _writer.Dispose(); + } + _writer = new StreamWriter(new FileStream(path, FileMode.Append)); + } + } + + private string GetOrCreateDirectory(uint network, uint blockIndex) + { + string dirPathWithBlock = GetDirectoryPath(network, blockIndex); + if (_lastCreateDirectory != dirPathWithBlock) + { + Directory.CreateDirectory(dirPathWithBlock); + _lastCreateDirectory = dirPathWithBlock; + } + return dirPathWithBlock; + } + + private string GetDirectoryPath(uint network, uint blockIndex) + { + //Default Parameter + uint storagePerFolder = 100000; + uint folder = (blockIndex / storagePerFolder) * storagePerFolder; + return $"./StorageDumper_{network}/BlockStorage_{folder}"; + } + + } +} diff --git a/src/Plugins/StorageDumper/StorageDumper.csproj b/src/Plugins/StorageDumper/StorageDumper.csproj new file mode 100644 index 0000000000..d9276c3581 --- /dev/null +++ b/src/Plugins/StorageDumper/StorageDumper.csproj @@ -0,0 +1,14 @@ + + + + net8.0 + Neo.Plugins.StorageDumper + enable + enable + + + + + + + diff --git a/src/Plugins/StorageDumper/config.json b/src/Plugins/StorageDumper/config.json new file mode 100644 index 0000000000..3f5c0537f0 --- /dev/null +++ b/src/Plugins/StorageDumper/config.json @@ -0,0 +1,7 @@ +{ + "PluginConfiguration": { + "BlockCacheSize": 1000, + "HeightToBegin": 0, + "Exclude": [ -4 ] + } +} diff --git a/src/Plugins/TokensTracker/Extensions.cs b/src/Plugins/TokensTracker/Extensions.cs new file mode 100644 index 0000000000..7805056280 --- /dev/null +++ b/src/Plugins/TokensTracker/Extensions.cs @@ -0,0 +1,67 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Extensions.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.IO; +using Neo.Persistence; +using Neo.VM.Types; +using System; +using System.Collections.Generic; +using System.Numerics; + +namespace Neo.Plugins +{ + public static class Extensions + { + public static bool NotNull(this StackItem item) + { + return !item.IsNull; + } + + public static string ToBase64(this ReadOnlySpan item) + { + return item == null ? String.Empty : Convert.ToBase64String(item); + } + + public static int GetVarSize(this ByteString item) + { + var length = item.GetSpan().Length; + return IO.Helper.GetVarSize(length) + length; + } + + public static int GetVarSize(this BigInteger item) + { + var length = item.GetByteCount(); + return IO.Helper.GetVarSize(length) + length; + } + + public static IEnumerable<(TKey, TValue)> FindPrefix(this IStore db, byte[] prefix) + where TKey : ISerializable, new() + where TValue : class, ISerializable, new() + { + foreach (var (key, value) in db.Seek(prefix, SeekDirection.Forward)) + { + if (!key.AsSpan().StartsWith(prefix)) break; + yield return (key.AsSerializable(1), value.AsSerializable()); + } + } + + public static IEnumerable<(TKey, TValue)> FindRange(this IStore db, byte[] startKey, byte[] endKey) + where TKey : ISerializable, new() + where TValue : class, ISerializable, new() + { + foreach (var (key, value) in db.Seek(startKey, SeekDirection.Forward)) + { + if (key.AsSpan().SequenceCompareTo(endKey) > 0) break; + yield return (key.AsSerializable(1), value.AsSerializable()); + } + } + } +} diff --git a/src/Plugins/TokensTracker/TokensTracker.cs b/src/Plugins/TokensTracker/TokensTracker.cs new file mode 100644 index 0000000000..5567d7d1f5 --- /dev/null +++ b/src/Plugins/TokensTracker/TokensTracker.cs @@ -0,0 +1,102 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// TokensTracker.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 Neo.IO; +using Neo.Ledger; +using Neo.Network.P2P.Payloads; +using Neo.Persistence; +using Neo.Plugins.Trackers; +using System; +using System.Collections.Generic; +using System.Linq; +using static System.IO.Path; + +namespace Neo.Plugins +{ + public class TokensTracker : Plugin + { + private string _dbPath; + private bool _shouldTrackHistory; + private uint _maxResults; + private uint _network; + private string[] _enabledTrackers; + private IStore _db; + private NeoSystem neoSystem; + private readonly List trackers = new(); + + public override string Description => "Enquiries balances and transaction history of accounts through RPC"; + + public TokensTracker() + { + Blockchain.Committing += OnCommitting; + Blockchain.Committed += OnCommitted; + } + + public override void Dispose() + { + Blockchain.Committing -= OnCommitting; + Blockchain.Committed -= OnCommitted; + } + + protected override void Configure() + { + IConfigurationSection config = GetConfiguration(); + _dbPath = config.GetValue("DBPath", "TokensBalanceData"); + _shouldTrackHistory = config.GetValue("TrackHistory", true); + _maxResults = config.GetValue("MaxResults", 1000u); + _network = config.GetValue("Network", 860833102u); + _enabledTrackers = config.GetSection("EnabledTrackers").GetChildren().Select(p => p.Value).ToArray(); + } + + protected override void OnSystemLoaded(NeoSystem system) + { + if (system.Settings.Network != _network) return; + neoSystem = system; + string path = string.Format(_dbPath, neoSystem.Settings.Network.ToString("X8")); + _db = neoSystem.LoadStore(GetFullPath(path)); + if (_enabledTrackers.Contains("NEP-11")) + trackers.Add(new Trackers.NEP_11.Nep11Tracker(_db, _maxResults, _shouldTrackHistory, neoSystem)); + if (_enabledTrackers.Contains("NEP-17")) + trackers.Add(new Trackers.NEP_17.Nep17Tracker(_db, _maxResults, _shouldTrackHistory, neoSystem)); + foreach (TrackerBase tracker in trackers) + RpcServerPlugin.RegisterMethods(tracker, _network); + } + + private void ResetBatch() + { + foreach (var tracker in trackers) + { + tracker.ResetBatch(); + } + } + + private void OnCommitting(NeoSystem system, Block block, DataCache snapshot, IReadOnlyList applicationExecutedList) + { + if (system.Settings.Network != _network) return; + // Start freshly with a new DBCache for each block. + ResetBatch(); + foreach (var tracker in trackers) + { + tracker.OnPersist(system, block, snapshot, applicationExecutedList); + } + } + + private void OnCommitted(NeoSystem system, Block block) + { + if (system.Settings.Network != _network) return; + foreach (var tracker in trackers) + { + tracker.Commit(); + } + } + } +} diff --git a/src/Plugins/TokensTracker/TokensTracker.csproj b/src/Plugins/TokensTracker/TokensTracker.csproj new file mode 100644 index 0000000000..848255fb81 --- /dev/null +++ b/src/Plugins/TokensTracker/TokensTracker.csproj @@ -0,0 +1,12 @@ + + + + net8.0 + Neo.Plugins.TokensTracker + + + + + + + \ No newline at end of file diff --git a/src/Plugins/TokensTracker/Trackers/NEP-11/Nep11BalanceKey.cs b/src/Plugins/TokensTracker/Trackers/NEP-11/Nep11BalanceKey.cs new file mode 100644 index 0000000000..1f375f33d9 --- /dev/null +++ b/src/Plugins/TokensTracker/Trackers/NEP-11/Nep11BalanceKey.cs @@ -0,0 +1,81 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Nep11BalanceKey.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.IO; +using Neo.VM.Types; +using System; +using System.IO; + +namespace Neo.Plugins.Trackers.NEP_11 +{ + public class Nep11BalanceKey : IComparable, IEquatable, ISerializable + { + public readonly UInt160 UserScriptHash; + public readonly UInt160 AssetScriptHash; + public ByteString Token; + public int Size => UInt160.Length + UInt160.Length + Token.GetVarSize(); + + public Nep11BalanceKey() : this(new UInt160(), new UInt160(), ByteString.Empty) + { + } + + public Nep11BalanceKey(UInt160 userScriptHash, UInt160 assetScriptHash, ByteString tokenId) + { + if (userScriptHash == null || assetScriptHash == null || tokenId == null) + throw new ArgumentNullException(); + UserScriptHash = userScriptHash; + AssetScriptHash = assetScriptHash; + Token = tokenId; + } + + public int CompareTo(Nep11BalanceKey other) + { + if (other is null) return 1; + if (ReferenceEquals(this, other)) return 0; + int result = UserScriptHash.CompareTo(other.UserScriptHash); + if (result != 0) return result; + result = AssetScriptHash.CompareTo(other.AssetScriptHash); + if (result != 0) return result; + return (Token.GetInteger() - other.Token.GetInteger()).Sign; + } + + public bool Equals(Nep11BalanceKey other) + { + if (other is null) return false; + if (ReferenceEquals(this, other)) return true; + return UserScriptHash.Equals(other.UserScriptHash) && AssetScriptHash.Equals(AssetScriptHash) && Token.Equals(other.Token); + } + + public override bool Equals(Object other) + { + return other is Nep11BalanceKey otherKey && Equals(otherKey); + } + + public override int GetHashCode() + { + return HashCode.Combine(UserScriptHash.GetHashCode(), AssetScriptHash.GetHashCode(), Token.GetHashCode()); + } + + public void Serialize(BinaryWriter writer) + { + writer.Write(UserScriptHash); + writer.Write(AssetScriptHash); + writer.WriteVarBytes(Token.GetSpan()); + } + + public void Deserialize(ref MemoryReader reader) + { + ((ISerializable)UserScriptHash).Deserialize(ref reader); + ((ISerializable)AssetScriptHash).Deserialize(ref reader); + Token = reader.ReadVarMemory(); + } + } +} diff --git a/src/Plugins/TokensTracker/Trackers/NEP-11/Nep11Tracker.cs b/src/Plugins/TokensTracker/Trackers/NEP-11/Nep11Tracker.cs new file mode 100644 index 0000000000..35a579eb77 --- /dev/null +++ b/src/Plugins/TokensTracker/Trackers/NEP-11/Nep11Tracker.cs @@ -0,0 +1,321 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Nep11Tracker.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.Json; +using Neo.Ledger; +using Neo.Network.P2P.Payloads; +using Neo.Persistence; +using Neo.SmartContract; +using Neo.SmartContract.Native; +using Neo.VM; +using Neo.VM.Types; +using Neo.Wallets; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Numerics; +using Array = Neo.VM.Types.Array; + +namespace Neo.Plugins.Trackers.NEP_11 +{ + class Nep11Tracker : TrackerBase + { + private const byte Nep11BalancePrefix = 0xf8; + private const byte Nep11TransferSentPrefix = 0xf9; + private const byte Nep11TransferReceivedPrefix = 0xfa; + private uint _currentHeight; + private Block _currentBlock; + private readonly HashSet _properties = new() + { + "name", + "description", + "image", + "tokenURI" + }; + + public override string TrackName => nameof(Nep11Tracker); + + public Nep11Tracker(IStore db, uint maxResult, bool shouldRecordHistory, NeoSystem system) : base(db, maxResult, shouldRecordHistory, system) + { + } + + public override void OnPersist(NeoSystem system, Block block, DataCache snapshot, IReadOnlyList applicationExecutedList) + { + _currentBlock = block; + _currentHeight = block.Index; + uint nep11TransferIndex = 0; + List transfers = new(); + foreach (Blockchain.ApplicationExecuted appExecuted in applicationExecutedList) + { + // Executions that fault won't modify storage, so we can skip them. + if (appExecuted.VMState.HasFlag(VMState.FAULT)) continue; + foreach (var notifyEventArgs in appExecuted.Notifications) + { + if (notifyEventArgs.EventName != "Transfer" || notifyEventArgs?.State is not Array stateItems || + stateItems.Count == 0) + continue; + var contract = NativeContract.ContractManagement.GetContract(snapshot, notifyEventArgs.ScriptHash); + if (contract?.Manifest.SupportedStandards.Contains("NEP-11") == true) + { + try + { + HandleNotificationNep11(notifyEventArgs.ScriptContainer, notifyEventArgs.ScriptHash, stateItems, transfers, ref nep11TransferIndex); + } + catch (Exception e) + { + Log(e.ToString(), LogLevel.Error); + throw; + } + } + + } + } + + // update nep11 balance + var contracts = new Dictionary(); + foreach (var transferRecord in transfers) + { + if (!contracts.ContainsKey(transferRecord.asset)) + { + var state = NativeContract.ContractManagement.GetContract(snapshot, transferRecord.asset); + var balanceMethod = state.Manifest.Abi.GetMethod("balanceOf", 1); + var balanceMethod2 = state.Manifest.Abi.GetMethod("balanceOf", 2); + if (balanceMethod == null && balanceMethod2 == null) + { + Log($"{state.Hash} is not nft!", LogLevel.Warning); + continue; + } + + var isDivisible = balanceMethod2 != null; + contracts[transferRecord.asset] = (isDivisible, state); + } + + var asset = contracts[transferRecord.asset]; + if (asset.isDivisible) + { + SaveDivisibleNFTBalance(transferRecord, snapshot); + } + else + { + SaveNFTBalance(transferRecord); + } + } + } + + private void SaveDivisibleNFTBalance(TransferRecord record, DataCache snapshot) + { + using ScriptBuilder sb = new(); + sb.EmitDynamicCall(record.asset, "balanceOf", record.from, record.tokenId); + sb.EmitDynamicCall(record.asset, "balanceOf", record.to, record.tokenId); + using ApplicationEngine engine = ApplicationEngine.Run(sb.ToArray(), snapshot, settings: _neoSystem.Settings, gas: 3400_0000); + if (engine.State.HasFlag(VMState.FAULT) || engine.ResultStack.Count != 2) + { + Log($"Fault: from[{record.from}] to[{record.to}] get {record.asset} token [{record.tokenId.ToHexString()}] balance fault", LogLevel.Warning); + return; + } + var toBalance = engine.ResultStack.Pop(); + var fromBalance = engine.ResultStack.Pop(); + if (toBalance is not Integer || fromBalance is not Integer) + { + Log($"Fault: from[{record.from}] to[{record.to}] get {record.asset} token [{record.tokenId.ToHexString()}] balance not number", LogLevel.Warning); + return; + } + Put(Nep11BalancePrefix, new Nep11BalanceKey(record.to, record.asset, record.tokenId), new TokenBalance { Balance = toBalance.GetInteger(), LastUpdatedBlock = _currentHeight }); + Put(Nep11BalancePrefix, new Nep11BalanceKey(record.from, record.asset, record.tokenId), new TokenBalance { Balance = fromBalance.GetInteger(), LastUpdatedBlock = _currentHeight }); + } + + private void SaveNFTBalance(TransferRecord record) + { + if (record.from != UInt160.Zero) + { + Delete(Nep11BalancePrefix, new Nep11BalanceKey(record.from, record.asset, record.tokenId)); + } + + if (record.to != UInt160.Zero) + { + Put(Nep11BalancePrefix, new Nep11BalanceKey(record.to, record.asset, record.tokenId), new TokenBalance { Balance = 1, LastUpdatedBlock = _currentHeight }); + } + } + + + private void HandleNotificationNep11(IVerifiable scriptContainer, UInt160 asset, Array stateItems, List transfers, ref uint transferIndex) + { + if (stateItems.Count != 4) return; + var transferRecord = GetTransferRecord(asset, stateItems); + if (transferRecord == null) return; + + transfers.Add(transferRecord); + if (scriptContainer is Transaction transaction) + { + RecordTransferHistoryNep11(asset, transferRecord.from, transferRecord.to, transferRecord.tokenId, transferRecord.amount, transaction.Hash, ref transferIndex); + } + } + + + private void RecordTransferHistoryNep11(UInt160 contractHash, UInt160 from, UInt160 to, ByteString tokenId, BigInteger amount, UInt256 txHash, ref uint transferIndex) + { + if (!_shouldTrackHistory) return; + if (from != UInt160.Zero) + { + Put(Nep11TransferSentPrefix, + new Nep11TransferKey(from, _currentBlock.Header.Timestamp, contractHash, tokenId, transferIndex), + new TokenTransfer + { + Amount = amount, + UserScriptHash = to, + BlockIndex = _currentHeight, + TxHash = txHash + }); + } + + if (to != UInt160.Zero) + { + Put(Nep11TransferReceivedPrefix, + new Nep11TransferKey(to, _currentBlock.Header.Timestamp, contractHash, tokenId, transferIndex), + new TokenTransfer + { + Amount = amount, + UserScriptHash = from, + BlockIndex = _currentHeight, + TxHash = txHash + }); + } + transferIndex++; + } + + + [RpcMethod] + public JToken GetNep11Transfers(JArray _params) + { + _shouldTrackHistory.True_Or(RpcError.MethodNotFound); + UInt160 userScriptHash = GetScriptHashFromParam(_params[0].AsString()); + // If start time not present, default to 1 week of history. + ulong startTime = _params.Count > 1 ? (ulong)_params[1].AsNumber() : + (DateTime.UtcNow - TimeSpan.FromDays(7)).ToTimestampMS(); + ulong endTime = _params.Count > 2 ? (ulong)_params[2].AsNumber() : DateTime.UtcNow.ToTimestampMS(); + (endTime >= startTime).True_Or(RpcError.InvalidParams); + + JObject json = new(); + json["address"] = userScriptHash.ToAddress(_neoSystem.Settings.AddressVersion); + JArray transfersSent = new(); + json["sent"] = transfersSent; + JArray transfersReceived = new(); + json["received"] = transfersReceived; + AddNep11Transfers(Nep11TransferSentPrefix, userScriptHash, startTime, endTime, transfersSent); + AddNep11Transfers(Nep11TransferReceivedPrefix, userScriptHash, startTime, endTime, transfersReceived); + return json; + } + + [RpcMethod] + public JToken GetNep11Balances(JArray _params) + { + UInt160 userScriptHash = GetScriptHashFromParam(_params[0].AsString()); + + JObject json = new(); + JArray balances = new(); + json["address"] = userScriptHash.ToAddress(_neoSystem.Settings.AddressVersion); + json["balance"] = balances; + + var map = new Dictionary>(); + int count = 0; + byte[] prefix = Key(Nep11BalancePrefix, userScriptHash); + foreach (var (key, value) in _db.FindPrefix(prefix)) + { + if (NativeContract.ContractManagement.GetContract(_neoSystem.StoreView, key.AssetScriptHash) is null) + continue; + if (!map.TryGetValue(key.AssetScriptHash, out var list)) + { + map[key.AssetScriptHash] = list = new List<(string, BigInteger, uint)>(); + } + list.Add((key.Token.GetSpan().ToHexString(), value.Balance, value.LastUpdatedBlock)); + count++; + if (count >= _maxResults) + { + break; + } + } + foreach (var key in map.Keys) + { + try + { + using var script = new ScriptBuilder(); + script.EmitDynamicCall(key, "decimals"); + script.EmitDynamicCall(key, "symbol"); + + var engine = ApplicationEngine.Run(script.ToArray(), _neoSystem.StoreView, settings: _neoSystem.Settings); + var symbol = engine.ResultStack.Pop().GetString(); + var decimals = engine.ResultStack.Pop().GetInteger(); + var name = NativeContract.ContractManagement.GetContract(_neoSystem.StoreView, key).Manifest.Name; + + balances.Add(new JObject + { + ["assethash"] = key.ToString(), + ["name"] = name, + ["symbol"] = symbol, + ["decimals"] = decimals.ToString(), + ["tokens"] = new JArray(map[key].Select(v => new JObject + { + ["tokenid"] = v.tokenid, + ["amount"] = v.amount.ToString(), + ["lastupdatedblock"] = v.height + })), + }); + } + catch { } + } + return json; + } + + [RpcMethod] + public JToken GetNep11Properties(JArray _params) + { + UInt160 nep11Hash = GetScriptHashFromParam(_params[0].AsString()); + var tokenId = _params[1].AsString().HexToBytes(); + + using ScriptBuilder sb = new(); + sb.EmitDynamicCall(nep11Hash, "properties", CallFlags.ReadOnly, tokenId); + using var snapshot = _neoSystem.GetSnapshot(); + + using var engine = ApplicationEngine.Run(sb.ToArray(), snapshot, settings: _neoSystem.Settings); + JObject json = new(); + + if (engine.State == VMState.HALT) + { + var map = engine.ResultStack.Pop(); + foreach (var keyValue in map) + { + if (keyValue.Value is CompoundType) continue; + var key = keyValue.Key.GetString(); + if (_properties.Contains(key)) + { + json[key] = keyValue.Value.GetString(); + } + else + { + json[key] = keyValue.Value.IsNull ? null : keyValue.Value.GetSpan().ToBase64(); + } + } + } + return json; + } + + private void AddNep11Transfers(byte dbPrefix, UInt160 userScriptHash, ulong startTime, ulong endTime, JArray parentJArray) + { + var transferPairs = QueryTransfers(dbPrefix, userScriptHash, startTime, endTime).Take((int)_maxResults).ToList(); + foreach (var (key, value) in transferPairs.OrderByDescending(l => l.key.TimestampMS)) + { + JObject transfer = ToJson(key, value); + transfer["tokenid"] = key.Token.GetSpan().ToHexString(); + parentJArray.Add(transfer); + } + } + } +} diff --git a/src/Plugins/TokensTracker/Trackers/NEP-11/Nep11TransferKey.cs b/src/Plugins/TokensTracker/Trackers/NEP-11/Nep11TransferKey.cs new file mode 100644 index 0000000000..5c999e8e00 --- /dev/null +++ b/src/Plugins/TokensTracker/Trackers/NEP-11/Nep11TransferKey.cs @@ -0,0 +1,80 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Nep11TransferKey.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.IO; +using Neo.VM.Types; +using System; +using System.IO; + +namespace Neo.Plugins.Trackers.NEP_11 +{ + public class Nep11TransferKey : TokenTransferKey, IComparable, IEquatable + { + public ByteString Token; + public override int Size => base.Size + Token.GetVarSize(); + + public Nep11TransferKey() : this(new UInt160(), 0, new UInt160(), ByteString.Empty, 0) + { + } + + public Nep11TransferKey(UInt160 userScriptHash, ulong timestamp, UInt160 assetScriptHash, ByteString tokenId, uint xferIndex) : base(userScriptHash, timestamp, assetScriptHash, xferIndex) + { + Token = tokenId; + } + + public int CompareTo(Nep11TransferKey other) + { + if (other is null) return 1; + if (ReferenceEquals(this, other)) return 0; + int result = UserScriptHash.CompareTo(other.UserScriptHash); + if (result != 0) return result; + int result2 = TimestampMS.CompareTo(other.TimestampMS); + if (result2 != 0) return result2; + int result3 = AssetScriptHash.CompareTo(other.AssetScriptHash); + if (result3 != 0) return result3; + var result4 = BlockXferNotificationIndex.CompareTo(other.BlockXferNotificationIndex); + if (result4 != 0) return result4; + return (Token.GetInteger() - other.Token.GetInteger()).Sign; + } + + public bool Equals(Nep11TransferKey other) + { + if (other is null) return false; + if (ReferenceEquals(this, other)) return true; + return UserScriptHash.Equals(other.UserScriptHash) + && TimestampMS.Equals(other.TimestampMS) && AssetScriptHash.Equals(other.AssetScriptHash) + && Token.Equals(other.Token) + && BlockXferNotificationIndex.Equals(other.BlockXferNotificationIndex); + } + + public override bool Equals(Object other) + { + return other is Nep11TransferKey otherKey && Equals(otherKey); + } + + public override int GetHashCode() + { + return HashCode.Combine(UserScriptHash.GetHashCode(), TimestampMS.GetHashCode(), AssetScriptHash.GetHashCode(), BlockXferNotificationIndex.GetHashCode(), Token.GetHashCode()); + } + + public override void Serialize(BinaryWriter writer) + { + base.Serialize(writer); + writer.WriteVarBytes(Token.GetSpan()); + } + + public override void Deserialize(ref MemoryReader reader) + { + base.Deserialize(ref reader); + Token = reader.ReadVarMemory(); + } + } +} diff --git a/src/Plugins/TokensTracker/Trackers/NEP-17/Nep17BalanceKey.cs b/src/Plugins/TokensTracker/Trackers/NEP-17/Nep17BalanceKey.cs new file mode 100644 index 0000000000..bbceabec2b --- /dev/null +++ b/src/Plugins/TokensTracker/Trackers/NEP-17/Nep17BalanceKey.cs @@ -0,0 +1,75 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Nep17BalanceKey.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.IO; +using System; +using System.IO; + +namespace Neo.Plugins.Trackers.NEP_17 +{ + public class Nep17BalanceKey : IComparable, IEquatable, ISerializable + { + public readonly UInt160 UserScriptHash; + public readonly UInt160 AssetScriptHash; + + public int Size => UInt160.Length + UInt160.Length; + + public Nep17BalanceKey() : this(new UInt160(), new UInt160()) + { + } + + public Nep17BalanceKey(UInt160 userScriptHash, UInt160 assetScriptHash) + { + if (userScriptHash == null || assetScriptHash == null) + throw new ArgumentNullException(); + UserScriptHash = userScriptHash; + AssetScriptHash = assetScriptHash; + } + + public int CompareTo(Nep17BalanceKey other) + { + if (other is null) return 1; + if (ReferenceEquals(this, other)) return 0; + int result = UserScriptHash.CompareTo(other.UserScriptHash); + if (result != 0) return result; + return AssetScriptHash.CompareTo(other.AssetScriptHash); + } + + public bool Equals(Nep17BalanceKey other) + { + if (other is null) return false; + if (ReferenceEquals(this, other)) return true; + return UserScriptHash.Equals(other.UserScriptHash) && AssetScriptHash.Equals(AssetScriptHash); + } + + public override bool Equals(Object other) + { + return other is Nep17BalanceKey otherKey && Equals(otherKey); + } + + public override int GetHashCode() + { + return HashCode.Combine(UserScriptHash.GetHashCode(), AssetScriptHash.GetHashCode()); + } + + public void Serialize(BinaryWriter writer) + { + writer.Write(UserScriptHash); + writer.Write(AssetScriptHash); + } + + public void Deserialize(ref MemoryReader reader) + { + ((ISerializable)UserScriptHash).Deserialize(ref reader); + ((ISerializable)AssetScriptHash).Deserialize(ref reader); + } + } +} diff --git a/src/Plugins/TokensTracker/Trackers/NEP-17/Nep17Tracker.cs b/src/Plugins/TokensTracker/Trackers/NEP-17/Nep17Tracker.cs new file mode 100644 index 0000000000..8ea2efa6a6 --- /dev/null +++ b/src/Plugins/TokensTracker/Trackers/NEP-17/Nep17Tracker.cs @@ -0,0 +1,256 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Nep17Tracker.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.Json; +using Neo.Ledger; +using Neo.Network.P2P.Payloads; +using Neo.Persistence; +using Neo.SmartContract; +using Neo.SmartContract.Native; +using Neo.VM; +using Neo.VM.Types; +using Neo.Wallets; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Numerics; +using Array = Neo.VM.Types.Array; + +namespace Neo.Plugins.Trackers.NEP_17 +{ + record BalanceChangeRecord(UInt160 User, UInt160 Asset); + + class Nep17Tracker : TrackerBase + { + private const byte Nep17BalancePrefix = 0xe8; + private const byte Nep17TransferSentPrefix = 0xe9; + private const byte Nep17TransferReceivedPrefix = 0xea; + private uint _currentHeight; + private Block _currentBlock; + + public override string TrackName => nameof(Nep17Tracker); + + public Nep17Tracker(IStore db, uint maxResult, bool shouldRecordHistory, NeoSystem system) : base(db, maxResult, shouldRecordHistory, system) + { + } + + public override void OnPersist(NeoSystem system, Block block, DataCache snapshot, IReadOnlyList applicationExecutedList) + { + _currentBlock = block; + _currentHeight = block.Index; + uint nep17TransferIndex = 0; + var balanceChangeRecords = new HashSet(); + + foreach (Blockchain.ApplicationExecuted appExecuted in applicationExecutedList) + { + // Executions that fault won't modify storage, so we can skip them. + if (appExecuted.VMState.HasFlag(VMState.FAULT)) continue; + foreach (var notifyEventArgs in appExecuted.Notifications) + { + if (notifyEventArgs.EventName != "Transfer" || notifyEventArgs?.State is not Array stateItems || stateItems.Count == 0) + continue; + var contract = NativeContract.ContractManagement.GetContract(snapshot, notifyEventArgs.ScriptHash); + if (contract?.Manifest.SupportedStandards.Contains("NEP-17") == true) + { + try + { + HandleNotificationNep17(notifyEventArgs.ScriptContainer, notifyEventArgs.ScriptHash, stateItems, balanceChangeRecords, ref nep17TransferIndex); + } + catch (Exception e) + { + Log(e.ToString(), LogLevel.Error); + throw; + } + } + } + } + + //update nep17 balance + foreach (var balanceChangeRecord in balanceChangeRecords) + { + try + { + SaveNep17Balance(balanceChangeRecord, snapshot); + } + catch (Exception e) + { + Log(e.ToString(), LogLevel.Error); + throw; + } + } + } + + + private void HandleNotificationNep17(IVerifiable scriptContainer, UInt160 asset, Array stateItems, HashSet balanceChangeRecords, ref uint transferIndex) + { + if (stateItems.Count != 3) return; + var transferRecord = GetTransferRecord(asset, stateItems); + if (transferRecord == null) return; + if (transferRecord.from != UInt160.Zero) + { + balanceChangeRecords.Add(new BalanceChangeRecord(transferRecord.from, asset)); + } + if (transferRecord.to != UInt160.Zero) + { + balanceChangeRecords.Add(new BalanceChangeRecord(transferRecord.to, asset)); + } + if (scriptContainer is Transaction transaction) + { + RecordTransferHistoryNep17(asset, transferRecord.from, transferRecord.to, transferRecord.amount, transaction.Hash, ref transferIndex); + } + } + + + private void SaveNep17Balance(BalanceChangeRecord balanceChanged, DataCache snapshot) + { + var key = new Nep17BalanceKey(balanceChanged.User, balanceChanged.Asset); + using ScriptBuilder sb = new(); + sb.EmitDynamicCall(balanceChanged.Asset, "balanceOf", balanceChanged.User); + using ApplicationEngine engine = ApplicationEngine.Run(sb.ToArray(), snapshot, settings: _neoSystem.Settings, gas: 1700_0000); + + if (engine.State.HasFlag(VMState.FAULT) || engine.ResultStack.Count == 0) + { + Log($"Fault:{balanceChanged.User} get {balanceChanged.Asset} balance fault", LogLevel.Warning); + return; + } + + var balanceItem = engine.ResultStack.Pop(); + if (balanceItem is not Integer) + { + Log($"Fault:{balanceChanged.User} get {balanceChanged.Asset} balance not number", LogLevel.Warning); + return; + } + + var balance = balanceItem.GetInteger(); + + if (balance.IsZero) + { + Delete(Nep17BalancePrefix, key); + return; + } + + Put(Nep17BalancePrefix, key, new TokenBalance { Balance = balance, LastUpdatedBlock = _currentHeight }); + } + + + [RpcMethod] + public JToken GetNep17Transfers(JArray _params) + { + _shouldTrackHistory.True_Or(RpcError.MethodNotFound); + UInt160 userScriptHash = GetScriptHashFromParam(_params[0].AsString()); + // If start time not present, default to 1 week of history. + ulong startTime = _params.Count > 1 ? (ulong)_params[1].AsNumber() : + (DateTime.UtcNow - TimeSpan.FromDays(7)).ToTimestampMS(); + ulong endTime = _params.Count > 2 ? (ulong)_params[2].AsNumber() : DateTime.UtcNow.ToTimestampMS(); + + (endTime >= startTime).True_Or(RpcError.InvalidParams); + + JObject json = new(); + json["address"] = userScriptHash.ToAddress(_neoSystem.Settings.AddressVersion); + JArray transfersSent = new(); + json["sent"] = transfersSent; + JArray transfersReceived = new(); + json["received"] = transfersReceived; + AddNep17Transfers(Nep17TransferSentPrefix, userScriptHash, startTime, endTime, transfersSent); + AddNep17Transfers(Nep17TransferReceivedPrefix, userScriptHash, startTime, endTime, transfersReceived); + return json; + } + + [RpcMethod] + public JToken GetNep17Balances(JArray _params) + { + UInt160 userScriptHash = GetScriptHashFromParam(_params[0].AsString()); + + JObject json = new(); + JArray balances = new(); + json["address"] = userScriptHash.ToAddress(_neoSystem.Settings.AddressVersion); + json["balance"] = balances; + + int count = 0; + byte[] prefix = Key(Nep17BalancePrefix, userScriptHash); + foreach (var (key, value) in _db.FindPrefix(prefix)) + { + if (NativeContract.ContractManagement.GetContract(_neoSystem.StoreView, key.AssetScriptHash) is null) + continue; + + try + { + using var script = new ScriptBuilder(); + script.EmitDynamicCall(key.AssetScriptHash, "decimals"); + script.EmitDynamicCall(key.AssetScriptHash, "symbol"); + + var engine = ApplicationEngine.Run(script.ToArray(), _neoSystem.StoreView, settings: _neoSystem.Settings); + var symbol = engine.ResultStack.Pop().GetString(); + var decimals = engine.ResultStack.Pop().GetInteger(); + var name = NativeContract.ContractManagement.GetContract(_neoSystem.StoreView, key.AssetScriptHash).Manifest.Name; + + balances.Add(new JObject + { + ["assethash"] = key.AssetScriptHash.ToString(), + ["name"] = name, + ["symbol"] = symbol, + ["decimals"] = decimals.ToString(), + ["amount"] = value.Balance.ToString(), + ["lastupdatedblock"] = value.LastUpdatedBlock + }); + count++; + if (count >= _maxResults) + { + break; + } + } + catch { } + } + return json; + } + + private void AddNep17Transfers(byte dbPrefix, UInt160 userScriptHash, ulong startTime, ulong endTime, JArray parentJArray) + { + var transferPairs = QueryTransfers(dbPrefix, userScriptHash, startTime, endTime).Take((int)_maxResults).ToList(); + foreach (var (key, value) in transferPairs.OrderByDescending(l => l.key.TimestampMS)) + { + parentJArray.Add(ToJson(key, value)); + } + } + + + private void RecordTransferHistoryNep17(UInt160 scriptHash, UInt160 from, UInt160 to, BigInteger amount, UInt256 txHash, ref uint transferIndex) + { + if (!_shouldTrackHistory) return; + if (from != UInt160.Zero) + { + Put(Nep17TransferSentPrefix, + new Nep17TransferKey(from, _currentBlock.Header.Timestamp, scriptHash, transferIndex), + new TokenTransfer + { + Amount = amount, + UserScriptHash = to, + BlockIndex = _currentHeight, + TxHash = txHash + }); + } + + if (to != UInt160.Zero) + { + Put(Nep17TransferReceivedPrefix, + new Nep17TransferKey(to, _currentBlock.Header.Timestamp, scriptHash, transferIndex), + new TokenTransfer + { + Amount = amount, + UserScriptHash = from, + BlockIndex = _currentHeight, + TxHash = txHash + }); + } + transferIndex++; + } + } +} diff --git a/src/Plugins/TokensTracker/Trackers/NEP-17/Nep17TransferKey.cs b/src/Plugins/TokensTracker/Trackers/NEP-17/Nep17TransferKey.cs new file mode 100644 index 0000000000..8f48195fc9 --- /dev/null +++ b/src/Plugins/TokensTracker/Trackers/NEP-17/Nep17TransferKey.cs @@ -0,0 +1,59 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Nep17TransferKey.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.IO; +using System; + +namespace Neo.Plugins.Trackers.NEP_17 +{ + public class Nep17TransferKey : TokenTransferKey, IComparable, IEquatable, ISerializable + { + public Nep17TransferKey() : base(new UInt160(), 0, new UInt160(), 0) + { + } + + public Nep17TransferKey(UInt160 userScriptHash, ulong timestamp, UInt160 assetScriptHash, uint xferIndex) : base(userScriptHash, timestamp, assetScriptHash, xferIndex) + { + } + + public int CompareTo(Nep17TransferKey other) + { + if (other is null) return 1; + if (ReferenceEquals(this, other)) return 0; + int result = UserScriptHash.CompareTo(other.UserScriptHash); + if (result != 0) return result; + int result2 = TimestampMS.CompareTo(other.TimestampMS); + if (result2 != 0) return result2; + int result3 = AssetScriptHash.CompareTo(other.AssetScriptHash); + if (result3 != 0) return result3; + return BlockXferNotificationIndex.CompareTo(other.BlockXferNotificationIndex); + } + + public bool Equals(Nep17TransferKey other) + { + if (other is null) return false; + if (ReferenceEquals(this, other)) return true; + return UserScriptHash.Equals(other.UserScriptHash) + && TimestampMS.Equals(other.TimestampMS) && AssetScriptHash.Equals(other.AssetScriptHash) + && BlockXferNotificationIndex.Equals(other.BlockXferNotificationIndex); + } + + public override bool Equals(Object other) + { + return other is Nep17TransferKey otherKey && Equals(otherKey); + } + + public override int GetHashCode() + { + return HashCode.Combine(UserScriptHash.GetHashCode(), TimestampMS.GetHashCode(), AssetScriptHash.GetHashCode(), BlockXferNotificationIndex.GetHashCode()); + } + } +} diff --git a/src/Plugins/TokensTracker/Trackers/TokenBalance.cs b/src/Plugins/TokensTracker/Trackers/TokenBalance.cs new file mode 100644 index 0000000000..f54a7c9856 --- /dev/null +++ b/src/Plugins/TokensTracker/Trackers/TokenBalance.cs @@ -0,0 +1,39 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// TokenBalance.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.IO; +using System.IO; +using System.Numerics; + +namespace Neo.Plugins.Trackers +{ + public class TokenBalance : ISerializable + { + public BigInteger Balance; + public uint LastUpdatedBlock; + + int ISerializable.Size => + Balance.GetVarSize() + // Balance + sizeof(uint); // LastUpdatedBlock + + void ISerializable.Serialize(BinaryWriter writer) + { + writer.WriteVarBytes(Balance.ToByteArray()); + writer.Write(LastUpdatedBlock); + } + + void ISerializable.Deserialize(ref MemoryReader reader) + { + Balance = new BigInteger(reader.ReadVarMemory(32).Span); + LastUpdatedBlock = reader.ReadUInt32(); + } + } +} diff --git a/src/Plugins/TokensTracker/Trackers/TokenTransfer.cs b/src/Plugins/TokensTracker/Trackers/TokenTransfer.cs new file mode 100644 index 0000000000..0a221850fc --- /dev/null +++ b/src/Plugins/TokensTracker/Trackers/TokenTransfer.cs @@ -0,0 +1,47 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// TokenTransfer.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.IO; +using System.IO; +using System.Numerics; + +namespace Neo.Plugins.Trackers +{ + public class TokenTransfer : ISerializable + { + public UInt160 UserScriptHash; + public uint BlockIndex; + public UInt256 TxHash; + public BigInteger Amount; + + int ISerializable.Size => + UInt160.Length + // UserScriptHash + sizeof(uint) + // BlockIndex + UInt256.Length + // TxHash + Amount.GetVarSize(); // Amount + + void ISerializable.Serialize(BinaryWriter writer) + { + writer.Write(UserScriptHash); + writer.Write(BlockIndex); + writer.Write(TxHash); + writer.WriteVarBytes(Amount.ToByteArray()); + } + + void ISerializable.Deserialize(ref MemoryReader reader) + { + UserScriptHash = reader.ReadSerializable(); + BlockIndex = reader.ReadUInt32(); + TxHash = reader.ReadSerializable(); + Amount = new BigInteger(reader.ReadVarMemory(32).Span); + } + } +} diff --git a/src/Plugins/TokensTracker/Trackers/TokenTransferKey.cs b/src/Plugins/TokensTracker/Trackers/TokenTransferKey.cs new file mode 100644 index 0000000000..252eb20af0 --- /dev/null +++ b/src/Plugins/TokensTracker/Trackers/TokenTransferKey.cs @@ -0,0 +1,57 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// TokenTransferKey.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.IO; +using System; +using System.Buffers.Binary; +using System.IO; + +namespace Neo.Plugins.Trackers +{ + public class TokenTransferKey : ISerializable + { + public UInt160 UserScriptHash { get; protected set; } + public ulong TimestampMS { get; protected set; } + public UInt160 AssetScriptHash { get; protected set; } + public uint BlockXferNotificationIndex { get; protected set; } + + public TokenTransferKey(UInt160 userScriptHash, ulong timestamp, UInt160 assetScriptHash, uint xferIndex) + { + if (userScriptHash is null || assetScriptHash is null) + throw new ArgumentNullException(); + UserScriptHash = userScriptHash; + TimestampMS = timestamp; + AssetScriptHash = assetScriptHash; + BlockXferNotificationIndex = xferIndex; + } + public virtual void Serialize(BinaryWriter writer) + { + writer.Write(UserScriptHash); + writer.Write(BitConverter.IsLittleEndian ? BinaryPrimitives.ReverseEndianness(TimestampMS) : TimestampMS); + writer.Write(AssetScriptHash); + writer.Write(BlockXferNotificationIndex); + } + + public virtual void Deserialize(ref MemoryReader reader) + { + UserScriptHash.Deserialize(ref reader); + TimestampMS = BitConverter.IsLittleEndian ? BinaryPrimitives.ReverseEndianness(reader.ReadUInt64()) : reader.ReadUInt64(); + AssetScriptHash.Deserialize(ref reader); + BlockXferNotificationIndex = reader.ReadUInt32(); + } + + public virtual int Size => + UInt160.Length + //UserScriptHash + sizeof(ulong) + //TimestampMS + UInt160.Length + //AssetScriptHash + sizeof(uint); //BlockXferNotificationIndex + } +} diff --git a/src/Plugins/TokensTracker/Trackers/TrackerBase.cs b/src/Plugins/TokensTracker/Trackers/TrackerBase.cs new file mode 100644 index 0000000000..471362b019 --- /dev/null +++ b/src/Plugins/TokensTracker/Trackers/TrackerBase.cs @@ -0,0 +1,162 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// TrackerBase.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.IO; +using Neo.Json; +using Neo.Ledger; +using Neo.Network.P2P.Payloads; +using Neo.Persistence; +using Neo.VM.Types; +using Neo.Wallets; +using System; +using System.Buffers.Binary; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Numerics; +using Array = Neo.VM.Types.Array; + +namespace Neo.Plugins.Trackers +{ + record TransferRecord(UInt160 asset, UInt160 from, UInt160 to, byte[] tokenId, BigInteger amount); + + abstract class TrackerBase + { + protected bool _shouldTrackHistory; + protected uint _maxResults; + protected IStore _db; + private ISnapshot _levelDbSnapshot; + protected NeoSystem _neoSystem; + public abstract string TrackName { get; } + + protected TrackerBase(IStore db, uint maxResult, bool shouldTrackHistory, NeoSystem neoSystem) + { + _db = db; + _maxResults = maxResult; + _shouldTrackHistory = shouldTrackHistory; + _neoSystem = neoSystem; + } + + public abstract void OnPersist(NeoSystem system, Block block, DataCache snapshot, IReadOnlyList applicationExecutedList); + + public void ResetBatch() + { + _levelDbSnapshot?.Dispose(); + _levelDbSnapshot = _db.GetSnapshot(); + } + + public void Commit() + { + _levelDbSnapshot?.Commit(); + } + + public IEnumerable<(TKey key, TValue val)> QueryTransfers(byte dbPrefix, UInt160 userScriptHash, ulong startTime, ulong endTime) + where TKey : ISerializable, new() + where TValue : class, ISerializable, new() + { + var prefix = new[] { dbPrefix }.Concat(userScriptHash.ToArray()).ToArray(); + byte[] startTimeBytes, endTimeBytes; + if (BitConverter.IsLittleEndian) + { + startTimeBytes = BitConverter.GetBytes(BinaryPrimitives.ReverseEndianness(startTime)); + endTimeBytes = BitConverter.GetBytes(BinaryPrimitives.ReverseEndianness(endTime)); + } + else + { + startTimeBytes = BitConverter.GetBytes(startTime); + endTimeBytes = BitConverter.GetBytes(endTime); + } + var transferPairs = _db.FindRange(prefix.Concat(startTimeBytes).ToArray(), prefix.Concat(endTimeBytes).ToArray()); + return transferPairs; + } + + protected static byte[] Key(byte prefix, ISerializable key) + { + byte[] buffer = new byte[key.Size + 1]; + using (MemoryStream ms = new(buffer, true)) + using (BinaryWriter writer = new(ms)) + { + writer.Write(prefix); + key.Serialize(writer); + } + return buffer; + } + + protected void Put(byte prefix, ISerializable key, ISerializable value) + { + _levelDbSnapshot.Put(Key(prefix, key), value.ToArray()); + } + + protected void Delete(byte prefix, ISerializable key) + { + _levelDbSnapshot.Delete(Key(prefix, key)); + } + + protected TransferRecord GetTransferRecord(UInt160 asset, Array stateItems) + { + if (stateItems.Count < 3) + { + return null; + } + var fromItem = stateItems[0]; + var toItem = stateItems[1]; + var amountItem = stateItems[2]; + if (fromItem.NotNull() && fromItem is not ByteString) + return null; + if (toItem.NotNull() && toItem is not ByteString) + return null; + if (amountItem is not ByteString && amountItem is not Integer) + return null; + + byte[] fromBytes = fromItem.IsNull ? null : fromItem.GetSpan().ToArray(); + if (fromBytes != null && fromBytes.Length != UInt160.Length) + return null; + byte[] toBytes = toItem.IsNull ? null : toItem.GetSpan().ToArray(); + if (toBytes != null && toBytes.Length != UInt160.Length) + return null; + if (fromBytes == null && toBytes == null) + return null; + + var from = fromBytes == null ? UInt160.Zero : new UInt160(fromBytes); + var to = toBytes == null ? UInt160.Zero : new UInt160(toBytes); + return stateItems.Count switch + { + 3 => new TransferRecord(asset, @from, to, null, amountItem.GetInteger()), + 4 when (stateItems[3] is ByteString tokenId) => new TransferRecord(asset, @from, to, tokenId.Memory.ToArray(), amountItem.GetInteger()), + _ => null + }; + } + + protected JObject ToJson(TokenTransferKey key, TokenTransfer value) + { + JObject transfer = new(); + transfer["timestamp"] = key.TimestampMS; + transfer["assethash"] = key.AssetScriptHash.ToString(); + transfer["transferaddress"] = value.UserScriptHash == UInt160.Zero ? null : value.UserScriptHash.ToAddress(_neoSystem.Settings.AddressVersion); + transfer["amount"] = value.Amount.ToString(); + transfer["blockindex"] = value.BlockIndex; + transfer["transfernotifyindex"] = key.BlockXferNotificationIndex; + transfer["txhash"] = value.TxHash.ToString(); + return transfer; + } + + public UInt160 GetScriptHashFromParam(string addressOrScriptHash) + { + return addressOrScriptHash.Length < 40 ? + addressOrScriptHash.ToScriptHash(_neoSystem.Settings.AddressVersion) : UInt160.Parse(addressOrScriptHash); + } + + public void Log(string message, LogLevel level = LogLevel.Info) + { + Utility.Log(TrackName, level, message); + } + } +} diff --git a/src/Plugins/TokensTracker/config.json b/src/Plugins/TokensTracker/config.json new file mode 100644 index 0000000000..ca63183b68 --- /dev/null +++ b/src/Plugins/TokensTracker/config.json @@ -0,0 +1,12 @@ +{ + "PluginConfiguration": { + "DBPath": "TokenBalanceData", + "TrackHistory": true, + "MaxResults": 1000, + "Network": 860833102, + "EnabledTrackers": [ "NEP-11", "NEP-17" ] + }, + "Dependency": [ + "RpcServer" + ] +} diff --git a/tests/Neo.Cryptography.MPTTrie.Tests/Cryptography/MPTTrie/Helper.cs b/tests/Neo.Cryptography.MPTTrie.Tests/Cryptography/MPTTrie/Helper.cs new file mode 100644 index 0000000000..15f796046b --- /dev/null +++ b/tests/Neo.Cryptography.MPTTrie.Tests/Cryptography/MPTTrie/Helper.cs @@ -0,0 +1,32 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// Helper.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.IO; + +namespace Neo.Cryptography.MPTTrie.Tests +{ + public static class Helper + { + private static readonly byte Prefix = 0xf0; + + public static byte[] ToKey(this UInt256 hash) + { + byte[] buffer = new byte[UInt256.Length + 1]; + using (MemoryStream ms = new MemoryStream(buffer, true)) + using (BinaryWriter writer = new BinaryWriter(ms)) + { + writer.Write(Prefix); + hash.Serialize(writer); + } + return buffer; + } + } +} diff --git a/tests/Neo.Cryptography.MPTTrie.Tests/Cryptography/MPTTrie/UT_Cache.cs b/tests/Neo.Cryptography.MPTTrie.Tests/Cryptography/MPTTrie/UT_Cache.cs new file mode 100644 index 0000000000..3a34962059 --- /dev/null +++ b/tests/Neo.Cryptography.MPTTrie.Tests/Cryptography/MPTTrie/UT_Cache.cs @@ -0,0 +1,235 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_Cache.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.Persistence; +using System.Text; + +namespace Neo.Cryptography.MPTTrie.Tests +{ + + [TestClass] + public class UT_Cache + { + private readonly byte Prefix = 0xf0; + + [TestMethod] + public void TestResolveLeaf() + { + var n = Node.NewLeaf(Encoding.ASCII.GetBytes("leaf")); + var store = new MemoryStore(); + store.Put(n.Hash.ToKey(), n.ToArray()); + var snapshot = store.GetSnapshot(); + var cache = new Cache(snapshot, Prefix); + var resolved = cache.Resolve(n.Hash); + Assert.AreEqual(n.Hash, resolved.Hash); + Assert.AreEqual(n.Value.Span.ToHexString(), resolved.Value.Span.ToHexString()); + } + + [TestMethod] + public void TestResolveBranch() + { + var l = Node.NewLeaf(Encoding.ASCII.GetBytes("leaf")); + var b = Node.NewBranch(); + b.Children[1] = l; + var store = new MemoryStore(); + store.Put(b.Hash.ToKey(), b.ToArray()); + store.Put(l.Hash.ToKey(), l.ToArray()); + var snapshot = store.GetSnapshot(); + var cache = new Cache(snapshot, Prefix); + var resolved_b = cache.Resolve(b.Hash); + Assert.AreEqual(b.Hash, resolved_b.Hash); + Assert.AreEqual(l.Hash, resolved_b.Children[1].Hash); + var resolved_l = cache.Resolve(l.Hash); + Assert.AreEqual(l.Value.Span.ToHexString(), resolved_l.Value.Span.ToHexString()); + } + + [TestMethod] + public void TestResolveExtension() + { + var e = Node.NewExtension(new byte[] { 0x01 }, new Node()); + var store = new MemoryStore(); + store.Put(e.Hash.ToKey(), e.ToArray()); + var snapshot = store.GetSnapshot(); + var cache = new Cache(snapshot, Prefix); + var re = cache.Resolve(e.Hash); + Assert.AreEqual(e.Hash, re.Hash); + Assert.AreEqual(e.Key.Span.ToHexString(), re.Key.Span.ToHexString()); + Assert.IsTrue(re.Next.IsEmpty); + } + + [TestMethod] + public void TestGetAndChangedBranch() + { + var l = Node.NewLeaf(Encoding.ASCII.GetBytes("leaf")); + var b = Node.NewBranch(); + var store = new MemoryStore(); + store.Put(b.Hash.ToKey(), b.ToArray()); + var snapshot = store.GetSnapshot(); + var cache = new Cache(snapshot, Prefix); + var resolved_b = cache.Resolve(b.Hash); + Assert.AreEqual(resolved_b.Hash, b.Hash); + foreach (var n in resolved_b.Children) + { + Assert.IsTrue(n.IsEmpty); + } + resolved_b.Children[1] = l; + resolved_b.SetDirty(); + var resovled_b1 = cache.Resolve(b.Hash); + Assert.AreEqual(resovled_b1.Hash, b.Hash); + foreach (var n in resovled_b1.Children) + { + Assert.IsTrue(n.IsEmpty); + } + } + + [TestMethod] + public void TestGetAndChangedExtension() + { + var e = Node.NewExtension(new byte[] { 0x01 }, new Node()); + var store = new MemoryStore(); + store.Put(e.Hash.ToKey(), e.ToArray()); + var snapshot = store.GetSnapshot(); + var cache = new Cache(snapshot, Prefix); + var re = cache.Resolve(e.Hash); + Assert.AreEqual(e.Hash, re.Hash); + Assert.AreEqual(e.Key.Span.ToHexString(), re.Key.Span.ToHexString()); + Assert.IsTrue(re.Next.IsEmpty); + re.Key = new byte[] { 0x02 }; + re.SetDirty(); + var re1 = cache.Resolve(e.Hash); + Assert.AreEqual(e.Hash, re1.Hash); + Assert.AreEqual(e.Key.Span.ToHexString(), re1.Key.Span.ToHexString()); + Assert.IsTrue(re1.Next.IsEmpty); + } + + [TestMethod] + public void TestGetAndChangedLeaf() + { + var l = Node.NewLeaf(Encoding.ASCII.GetBytes("leaf")); + var store = new MemoryStore(); + store.Put(l.Hash.ToKey(), l.ToArray()); + var snapshot = store.GetSnapshot(); + var cache = new Cache(snapshot, Prefix); + var rl = cache.Resolve(l.Hash); + Assert.AreEqual(l.Hash, rl.Hash); + Assert.AreEqual("leaf", Encoding.ASCII.GetString(rl.Value.Span)); + rl.Value = new byte[] { 0x01 }; + rl.SetDirty(); + var rl1 = cache.Resolve(l.Hash); + Assert.AreEqual(l.Hash, rl1.Hash); + Assert.AreEqual("leaf", Encoding.ASCII.GetString(rl1.Value.Span)); + } + + [TestMethod] + public void TestPutAndChangedBranch() + { + var l = Node.NewLeaf(Encoding.ASCII.GetBytes("leaf")); + var b = Node.NewBranch(); + var h = b.Hash; + var store = new MemoryStore(); + var snapshot = store.GetSnapshot(); + var cache = new Cache(snapshot, Prefix); + cache.PutNode(b); + var rb = cache.Resolve(h); + Assert.AreEqual(h, rb.Hash); + foreach (var n in rb.Children) + { + Assert.IsTrue(n.IsEmpty); + } + rb.Children[1] = l; + rb.SetDirty(); + var rb1 = cache.Resolve(h); + Assert.AreEqual(h, rb1.Hash); + foreach (var n in rb1.Children) + { + Assert.IsTrue(n.IsEmpty); + } + } + + [TestMethod] + public void TestPutAndChangedExtension() + { + var e = Node.NewExtension(new byte[] { 0x01 }, new Node()); + var h = e.Hash; + var store = new MemoryStore(); + var snapshot = store.GetSnapshot(); + var cache = new Cache(snapshot, Prefix); + cache.PutNode(e); + var re = cache.Resolve(e.Hash); + Assert.AreEqual(e.Hash, re.Hash); + Assert.AreEqual(e.Key.Span.ToHexString(), re.Key.Span.ToHexString()); + Assert.IsTrue(re.Next.IsEmpty); + e.Key = new byte[] { 0x02 }; + e.Next = e; + e.SetDirty(); + var re1 = cache.Resolve(h); + Assert.AreEqual(h, re1.Hash); + Assert.AreEqual("01", re1.Key.Span.ToHexString()); + Assert.IsTrue(re1.Next.IsEmpty); + } + + [TestMethod] + public void TestPutAndChangedLeaf() + { + var l = Node.NewLeaf(Encoding.ASCII.GetBytes("leaf")); + var h = l.Hash; + var store = new MemoryStore(); + var snapshot = store.GetSnapshot(); + var cache = new Cache(snapshot, Prefix); + cache.PutNode(l); + var rl = cache.Resolve(l.Hash); + Assert.AreEqual(h, rl.Hash); + Assert.AreEqual("leaf", Encoding.ASCII.GetString(rl.Value.Span)); + l.Value = new byte[] { 0x01 }; + l.SetDirty(); + var rl1 = cache.Resolve(h); + Assert.AreEqual(h, rl1.Hash); + Assert.AreEqual("leaf", Encoding.ASCII.GetString(rl1.Value.Span)); + } + + [TestMethod] + public void TestReference1() + { + var l = Node.NewLeaf(Encoding.ASCII.GetBytes("leaf")); + var store = new MemoryStore(); + var snapshot = store.GetSnapshot(); + var cache = new Cache(snapshot, Prefix); + cache.PutNode(l); + cache.Commit(); + snapshot.Commit(); + var snapshot1 = store.GetSnapshot(); + var cache1 = new Cache(snapshot1, Prefix); + cache1.PutNode(l); + cache1.Commit(); + snapshot1.Commit(); + var snapshot2 = store.GetSnapshot(); + var cache2 = new Cache(snapshot2, Prefix); + var rl = cache2.Resolve(l.Hash); + Assert.AreEqual(2, rl.Reference); + } + + [TestMethod] + public void TestReference2() + { + var l = Node.NewLeaf(Encoding.ASCII.GetBytes("leaf")); + var store = new MemoryStore(); + var snapshot = store.GetSnapshot(); + var cache = new Cache(snapshot, Prefix); + cache.PutNode(l); + cache.PutNode(l); + cache.DeleteNode(l.Hash); + var rl = cache.Resolve(l.Hash); + Assert.AreEqual(1, rl.Reference); + } + } +} diff --git a/tests/Neo.Cryptography.MPTTrie.Tests/Cryptography/MPTTrie/UT_Helper.cs b/tests/Neo.Cryptography.MPTTrie.Tests/Cryptography/MPTTrie/UT_Helper.cs new file mode 100644 index 0000000000..980e7a429e --- /dev/null +++ b/tests/Neo.Cryptography.MPTTrie.Tests/Cryptography/MPTTrie/UT_Helper.cs @@ -0,0 +1,37 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_Helper.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 System; + +namespace Neo.Cryptography.MPTTrie.Tests +{ + [TestClass] + public class UT_Helper + { + [TestMethod] + public void TestCompareTo() + { + ReadOnlySpan arr1 = new byte[] { 0, 1, 2 }; + ReadOnlySpan arr2 = new byte[] { 0, 1, 2 }; + Assert.AreEqual(0, arr1.CompareTo(arr2)); + arr1 = new byte[] { 0, 1 }; + Assert.AreEqual(-1, arr1.CompareTo(arr2)); + arr2 = new byte[] { 0 }; + Assert.AreEqual(1, arr1.CompareTo(arr2)); + arr2 = new byte[] { 0, 2 }; + Assert.AreEqual(-1, arr1.CompareTo(arr2)); + arr1 = new byte[] { 0, 3, 1 }; + Assert.AreEqual(1, arr1.CompareTo(arr2)); + Assert.AreEqual(0, ReadOnlySpan.Empty.CompareTo(ReadOnlySpan.Empty)); + } + } +} diff --git a/tests/Neo.Cryptography.MPTTrie.Tests/Cryptography/MPTTrie/UT_Node.cs b/tests/Neo.Cryptography.MPTTrie.Tests/Cryptography/MPTTrie/UT_Node.cs new file mode 100644 index 0000000000..8f46fbec27 --- /dev/null +++ b/tests/Neo.Cryptography.MPTTrie.Tests/Cryptography/MPTTrie/UT_Node.cs @@ -0,0 +1,216 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_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 System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; + +namespace Neo.Cryptography.MPTTrie.Tests +{ + + [TestClass] + public class UT_Node + { + private byte[] NodeToArrayAsChild(Node n) + { + using var ms = new MemoryStream(); + using var writer = new BinaryWriter(ms, Neo.Utility.StrictUTF8, true); + + n.SerializeAsChild(writer); + writer.Flush(); + return ms.ToArray(); + } + + [TestMethod] + public void TestHashSerialize() + { + var n = Node.NewHash(UInt256.Zero); + var expect = "030000000000000000000000000000000000000000000000000000000000000000"; + Assert.AreEqual(expect, n.ToArray().ToHexString()); + Assert.AreEqual(expect, NodeToArrayAsChild(n).ToHexString()); + } + + [TestMethod] + public void TestEmptySerialize() + { + var n = new Node(); + var expect = "04"; + Assert.AreEqual(expect, n.ToArray().ToHexString()); + Assert.AreEqual(expect, NodeToArrayAsChild(n).ToHexString()); + } + + [TestMethod] + public void TestLeafSerialize() + { + var n = Node.NewLeaf(Encoding.ASCII.GetBytes("leaf")); + var expect = "02" + "04" + Encoding.ASCII.GetBytes("leaf").ToHexString(); + Assert.AreEqual(expect, n.ToArrayWithoutReference().ToHexString()); + expect += "01"; + Assert.AreEqual(expect, n.ToArray().ToHexString()); + Assert.AreEqual(7, n.Size); + } + + [TestMethod] + public void TestLeafSerializeAsChild() + { + var l = Node.NewLeaf(Encoding.ASCII.GetBytes("leaf")); + var expect = "03" + Crypto.Hash256(new byte[] { 0x02, 0x04 }.Concat(Encoding.ASCII.GetBytes("leaf")).ToArray()).ToHexString(); + Assert.AreEqual(expect, NodeToArrayAsChild(l).ToHexString()); + } + + [TestMethod] + public void TestExtensionSerialize() + { + var e = Node.NewExtension("010a".HexToBytes(), new Node()); + var expect = "01" + "02" + "010a" + "04"; + Assert.AreEqual(expect, e.ToArrayWithoutReference().ToHexString()); + expect += "01"; + Assert.AreEqual(expect, e.ToArray().ToHexString()); + Assert.AreEqual(6, e.Size); + } + + [TestMethod] + public void TestExtensionSerializeAsChild() + { + var e = Node.NewExtension("010a".HexToBytes(), new Node()); + var expect = "03" + Crypto.Hash256(new byte[] { 0x01, 0x02, 0x01, 0x0a, 0x04 + }).ToHexString(); + Assert.AreEqual(expect, NodeToArrayAsChild(e).ToHexString()); + } + + [TestMethod] + public void TestBranchSerialize() + { + var n = Node.NewBranch(); + n.Children[1] = Node.NewLeaf(Encoding.ASCII.GetBytes("leaf1")); + n.Children[10] = Node.NewLeaf(Encoding.ASCII.GetBytes("leafa")); + var expect = "00"; + for (int i = 0; i < Node.BranchChildCount; i++) + { + if (i == 1) + expect += "03" + Crypto.Hash256(new byte[] { 0x02, 0x05 }.Concat(Encoding.ASCII.GetBytes("leaf1")).ToArray()).ToHexString(); + else if (i == 10) + expect += "03" + Crypto.Hash256(new byte[] { 0x02, 0x05 }.Concat(Encoding.ASCII.GetBytes("leafa")).ToArray()).ToHexString(); + else + expect += "04"; + } + expect += "01"; + Assert.AreEqual(expect, n.ToArray().ToHexString()); + Assert.AreEqual(83, n.Size); + } + + [TestMethod] + public void TestBranchSerializeAsChild() + { + var n = Node.NewBranch(); + var data = new List(); + data.Add(0x00); + for (int i = 0; i < Node.BranchChildCount; i++) + { + data.Add(0x04); + } + var expect = "03" + Crypto.Hash256(data.ToArray()).ToHexString(); + Assert.AreEqual(expect, NodeToArrayAsChild(n).ToHexString()); + } + + [TestMethod] + public void TestCloneBranch() + { + var l = Node.NewLeaf(Encoding.ASCII.GetBytes("leaf")); + var n = Node.NewBranch(); + var n1 = n.Clone(); + n1.Children[0] = l; + Assert.IsTrue(n.Children[0].IsEmpty); + } + + [TestMethod] + public void TestCloneExtension() + { + var l = Node.NewLeaf(Encoding.ASCII.GetBytes("leaf")); + var n = Node.NewExtension(new byte[] { 0x01 }, new Node()); + var n1 = n.Clone(); + n1.Next = l; + Assert.IsTrue(n.Next.IsEmpty); + } + + [TestMethod] + public void TestCloneLeaf() + { + var l = Node.NewLeaf(Encoding.ASCII.GetBytes("leaf")); + var n = l.Clone(); + n.Value = Encoding.ASCII.GetBytes("value"); + Assert.AreEqual("leaf", Encoding.ASCII.GetString(l.Value.Span)); + } + + [TestMethod] + public void TestNewExtensionException() + { + Assert.ThrowsException(() => Node.NewExtension(null, new Node())); + Assert.ThrowsException(() => Node.NewExtension(new byte[] { 0x01 }, null)); + Assert.ThrowsException(() => Node.NewExtension(Array.Empty(), new Node())); + } + + [TestMethod] + public void TestNewHashException() + { + Assert.ThrowsException(() => Node.NewHash(null)); + } + + [TestMethod] + public void TestNewLeafException() + { + Assert.ThrowsException(() => Node.NewLeaf(null)); + } + + [TestMethod] + public void TestSize() + { + var n = new Node(); + Assert.AreEqual(1, n.Size); + n = Node.NewBranch(); + Assert.AreEqual(19, n.Size); + n = Node.NewExtension(new byte[] { 0x00 }, new Node()); + Assert.AreEqual(5, n.Size); + n = Node.NewLeaf(new byte[] { 0x00 }); + Assert.AreEqual(4, n.Size); + n = Node.NewHash(UInt256.Zero); + Assert.AreEqual(33, n.Size); + } + + [TestMethod] + public void TestFromReplica() + { + var l = Node.NewLeaf(new byte[] { 0x00 }); + var n = Node.NewBranch(); + n.Children[1] = l; + var r = new Node(); + r.FromReplica(n); + Assert.AreEqual(n.Hash, r.Hash); + Assert.AreEqual(NodeType.HashNode, r.Children[1].Type); + Assert.AreEqual(l.Hash, r.Children[1].Hash); + } + + [TestMethod] + public void TestEmptyLeaf() + { + var leaf = Node.NewLeaf(Array.Empty()); + var data = leaf.ToArray(); + Assert.AreEqual(3, data.Length); + var l = data.AsSerializable(); + Assert.AreEqual(NodeType.LeafNode, l.Type); + Assert.AreEqual(0, l.Value.Length); + } + } +} diff --git a/tests/Neo.Cryptography.MPTTrie.Tests/Cryptography/MPTTrie/UT_Trie.cs b/tests/Neo.Cryptography.MPTTrie.Tests/Cryptography/MPTTrie/UT_Trie.cs new file mode 100644 index 0000000000..372de6a738 --- /dev/null +++ b/tests/Neo.Cryptography.MPTTrie.Tests/Cryptography/MPTTrie/UT_Trie.cs @@ -0,0 +1,573 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_Trie.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.Persistence; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using static Neo.Helper; + +namespace Neo.Cryptography.MPTTrie.Tests +{ + class TestSnapshot : ISnapshot + { + public Dictionary store = new Dictionary(ByteArrayEqualityComparer.Default); + + private byte[] StoreKey(byte[] key) + { + return Concat(key); + } + + public void Put(byte[] key, byte[] value) + { + store[key] = value; + } + + public void Delete(byte[] key) + { + store.Remove(StoreKey(key)); + } + + public void Commit() { throw new NotImplementedException(); } + + public bool Contains(byte[] key) { throw new System.NotImplementedException(); } + + public IEnumerable<(byte[] Key, byte[] Value)> Seek(byte[] key, SeekDirection direction) { throw new System.NotImplementedException(); } + + public byte[] TryGet(byte[] key) + { + var result = store.TryGetValue(StoreKey(key), out byte[] value); + if (result) return value; + return null; + } + + public void Dispose() { throw new System.NotImplementedException(); } + + public int Size => store.Count; + } + + [TestClass] + public class UT_Trie + { + private Node root; + private IStore mptdb; + + private void PutToStore(IStore store, Node node) + { + store.Put(Concat(new byte[] { 0xf0 }, node.Hash.ToArray()), node.ToArray()); + } + + [TestInitialize] + public void TestInit() + { + var b = Node.NewBranch(); + var r = Node.NewExtension("0a0c".HexToBytes(), b); + var v1 = Node.NewLeaf("abcd".HexToBytes());//key=ac01 + var v2 = Node.NewLeaf("2222".HexToBytes());//key=ac + var v3 = Node.NewLeaf(Encoding.ASCII.GetBytes("existing"));//key=acae + var v4 = Node.NewLeaf(Encoding.ASCII.GetBytes("missing")); + var h3 = Node.NewHash(v3.Hash); + var e1 = Node.NewExtension(new byte[] { 0x01 }, v1); + var e3 = Node.NewExtension(new byte[] { 0x0e }, h3); + var e4 = Node.NewExtension(new byte[] { 0x01 }, v4); + b.Children[0] = e1; + b.Children[10] = e3; + b.Children[16] = v2; + b.Children[15] = Node.NewHash(e4.Hash); + this.root = r; + this.mptdb = new MemoryStore(); + PutToStore(mptdb, r); + PutToStore(mptdb, b); + PutToStore(mptdb, e1); + PutToStore(mptdb, e3); + PutToStore(mptdb, v1); + PutToStore(mptdb, v2); + PutToStore(mptdb, v3); + } + + [TestMethod] + public void TestTryGet() + { + var mpt = new Trie(mptdb.GetSnapshot(), root.Hash); + Assert.ThrowsException(() => mpt[Array.Empty()]); + Assert.AreEqual("abcd", mpt["ac01".HexToBytes()].ToHexString()); + Assert.AreEqual("2222", mpt["ac".HexToBytes()].ToHexString()); + Assert.ThrowsException(() => mpt["ab99".HexToBytes()]); + Assert.ThrowsException(() => mpt["ac39".HexToBytes()]); + Assert.ThrowsException(() => mpt["ac02".HexToBytes()]); + Assert.ThrowsException(() => mpt["ac0100".HexToBytes()]); + Assert.ThrowsException(() => mpt["ac9910".HexToBytes()]); + Assert.ThrowsException(() => mpt["acf1".HexToBytes()]); + } + + [TestMethod] + public void TestTryGetResolve() + { + var mpt = new Trie(mptdb.GetSnapshot(), root.Hash); + Assert.AreEqual(Encoding.ASCII.GetBytes("existing").ToHexString(), mpt["acae".HexToBytes()].ToHexString()); + } + + [TestMethod] + public void TestTryPut() + { + var store = new MemoryStore(); + var mpt = new Trie(store.GetSnapshot(), null); + mpt.Put("ac01".HexToBytes(), "abcd".HexToBytes()); + mpt.Put("ac".HexToBytes(), "2222".HexToBytes()); + mpt.Put("acae".HexToBytes(), Encoding.ASCII.GetBytes("existing")); + mpt.Put("acf1".HexToBytes(), Encoding.ASCII.GetBytes("missing")); + Assert.AreEqual(root.Hash.ToString(), mpt.Root.Hash.ToString()); + Assert.ThrowsException(() => mpt.Put(Array.Empty(), "01".HexToBytes())); + mpt.Put("01".HexToBytes(), Array.Empty()); + Assert.ThrowsException(() => mpt.Put(new byte[Node.MaxKeyLength / 2 + 1], Array.Empty())); + Assert.ThrowsException(() => mpt.Put("01".HexToBytes(), new byte[Node.MaxValueLength + 1])); + mpt.Put("ac01".HexToBytes(), "ab".HexToBytes()); + } + + [TestMethod] + public void TestPutCantResolve() + { + var mpt = new Trie(mptdb.GetSnapshot(), root.Hash); + Assert.ThrowsException(() => mpt.Put("acf111".HexToBytes(), new byte[] { 1 })); + } + + [TestMethod] + public void TestTryDelete() + { + var mpt = new Trie(mptdb.GetSnapshot(), root.Hash); + Assert.IsNotNull(mpt["ac".HexToBytes()]); + Assert.IsFalse(mpt.Delete("0c99".HexToBytes())); + Assert.ThrowsException(() => mpt.Delete(Array.Empty())); + Assert.IsFalse(mpt.Delete("ac20".HexToBytes())); + Assert.ThrowsException(() => mpt.Delete("acf1".HexToBytes())); + Assert.IsTrue(mpt.Delete("ac".HexToBytes())); + Assert.IsFalse(mpt.Delete("acae01".HexToBytes())); + Assert.IsTrue(mpt.Delete("acae".HexToBytes())); + Assert.AreEqual("0xcb06925428b7c727375c7fdd943a302fe2c818cf2e2eaf63a7932e3fd6cb3408", mpt.Root.Hash.ToString()); + } + + [TestMethod] + public void TestDeleteRemainCanResolve() + { + var store = new MemoryStore(); + var snapshot = store.GetSnapshot(); + var mpt1 = new Trie(snapshot, null); + mpt1.Put("ac00".HexToBytes(), "abcd".HexToBytes()); + mpt1.Put("ac10".HexToBytes(), "abcd".HexToBytes()); + mpt1.Commit(); + snapshot.Commit(); + var snapshot2 = store.GetSnapshot(); + var mpt2 = new Trie(snapshot2, mpt1.Root.Hash); + Assert.IsTrue(mpt2.Delete("ac00".HexToBytes())); + mpt2.Commit(); + snapshot2.Commit(); + Assert.IsTrue(mpt2.Delete("ac10".HexToBytes())); + } + + [TestMethod] + public void TestDeleteRemainCantResolve() + { + var b = Node.NewBranch(); + var r = Node.NewExtension("0a0c".HexToBytes(), b); + var v1 = Node.NewLeaf("abcd".HexToBytes());//key=ac01 + var v4 = Node.NewLeaf(Encoding.ASCII.GetBytes("missing")); + var e1 = Node.NewExtension(new byte[] { 0x01 }, v1); + var e4 = Node.NewExtension(new byte[] { 0x01 }, v4); + b.Children[0] = e1; + b.Children[15] = Node.NewHash(e4.Hash); + var store = new MemoryStore(); + PutToStore(store, r); + PutToStore(store, b); + PutToStore(store, e1); + PutToStore(store, v1); + + var snapshot = store.GetSnapshot(); + var mpt = new Trie(snapshot, r.Hash); + Assert.ThrowsException(() => mpt.Delete("ac01".HexToBytes())); + } + + + [TestMethod] + public void TestDeleteSameValue() + { + var store = new MemoryStore(); + var snapshot = store.GetSnapshot(); + var mpt = new Trie(snapshot, null); + mpt.Put("ac01".HexToBytes(), "abcd".HexToBytes()); + mpt.Put("ac02".HexToBytes(), "abcd".HexToBytes()); + Assert.IsNotNull(mpt["ac01".HexToBytes()]); + Assert.IsNotNull(mpt["ac02".HexToBytes()]); + mpt.Delete("ac01".HexToBytes()); + Assert.IsNotNull(mpt["ac02".HexToBytes()]); + mpt.Commit(); + snapshot.Commit(); + var mpt0 = new Trie(store.GetSnapshot(), mpt.Root.Hash); + Assert.IsNotNull(mpt0["ac02".HexToBytes()]); + } + + [TestMethod] + public void TestBranchNodeRemainValue() + { + var snapshot = new TestSnapshot(); + var mpt = new Trie(snapshot, null); + mpt.Put("ac11".HexToBytes(), "ac11".HexToBytes()); + mpt.Put("ac22".HexToBytes(), "ac22".HexToBytes()); + mpt.Put("ac".HexToBytes(), "ac".HexToBytes()); + mpt.Commit(); + Assert.AreEqual(7, snapshot.Size); + Assert.IsTrue(mpt.Delete("ac11".HexToBytes())); + mpt.Commit(); + Assert.AreEqual(5, snapshot.Size); + Assert.IsTrue(mpt.Delete("ac22".HexToBytes())); + Assert.IsNotNull(mpt["ac".HexToBytes()]); + mpt.Commit(); + Assert.AreEqual(2, snapshot.Size); + } + + [TestMethod] + public void TestGetProof() + { + var b = Node.NewBranch(); + var r = Node.NewExtension("0a0c".HexToBytes(), b); + var v1 = Node.NewLeaf("abcd".HexToBytes());//key=ac01 + var v2 = Node.NewLeaf("2222".HexToBytes());//key=ac + var v3 = Node.NewLeaf(Encoding.ASCII.GetBytes("existing"));//key=acae + var v4 = Node.NewLeaf(Encoding.ASCII.GetBytes("missing")); + var h3 = Node.NewHash(v3.Hash); + var e1 = Node.NewExtension(new byte[] { 0x01 }, v1); + var e3 = Node.NewExtension(new byte[] { 0x0e }, h3); + var e4 = Node.NewExtension(new byte[] { 0x01 }, v4); + b.Children[0] = e1; + b.Children[10] = e3; + b.Children[16] = v2; + b.Children[15] = Node.NewHash(e4.Hash); + + var mpt = new Trie(mptdb.GetSnapshot(), r.Hash); + Assert.AreEqual(r.Hash.ToString(), mpt.Root.Hash.ToString()); + var result = mpt.TryGetProof("ac01".HexToBytes(), out var proof); + Assert.IsTrue(result); + Assert.AreEqual(4, proof.Count); + Assert.IsTrue(proof.Contains(b.ToArrayWithoutReference())); + Assert.IsTrue(proof.Contains(r.ToArrayWithoutReference())); + Assert.IsTrue(proof.Contains(e1.ToArrayWithoutReference())); + Assert.IsTrue(proof.Contains(v1.ToArrayWithoutReference())); + + result = mpt.TryGetProof("ac".HexToBytes(), out proof); + Assert.AreEqual(3, proof.Count); + + result = mpt.TryGetProof("ac10".HexToBytes(), out proof); + Assert.IsFalse(result); + + result = mpt.TryGetProof("acae".HexToBytes(), out proof); + Assert.AreEqual(4, proof.Count); + + Assert.ThrowsException(() => mpt.TryGetProof(Array.Empty(), out proof)); + + result = mpt.TryGetProof("ac0100".HexToBytes(), out proof); + Assert.IsFalse(result); + + Assert.ThrowsException(() => mpt.TryGetProof("acf1".HexToBytes(), out var proof)); + } + + [TestMethod] + public void TestVerifyProof() + { + var mpt = new Trie(mptdb.GetSnapshot(), root.Hash); + var result = mpt.TryGetProof("ac01".HexToBytes(), out var proof); + Assert.IsTrue(result); + var value = Trie.VerifyProof(root.Hash, "ac01".HexToBytes(), proof); + Assert.IsNotNull(value); + Assert.AreEqual(value.ToHexString(), "abcd"); + } + + [TestMethod] + public void TestAddLongerKey() + { + var store = new MemoryStore(); + var snapshot = store.GetSnapshot(); + var mpt = new Trie(snapshot, null); + mpt.Put(new byte[] { 0xab }, new byte[] { 0x01 }); + mpt.Put(new byte[] { 0xab, 0xcd }, new byte[] { 0x02 }); + Assert.AreEqual("01", mpt[new byte[] { 0xab }].ToHexString()); + } + + [TestMethod] + public void TestSplitKey() + { + var store = new MemoryStore(); + var snapshot = store.GetSnapshot(); + var mpt1 = new Trie(snapshot, null); + mpt1.Put(new byte[] { 0xab, 0xcd }, new byte[] { 0x01 }); + mpt1.Put(new byte[] { 0xab }, new byte[] { 0x02 }); + var r = mpt1.TryGetProof(new byte[] { 0xab, 0xcd }, out var set1); + Assert.IsTrue(r); + Assert.AreEqual(4, set1.Count); + var mpt2 = new Trie(snapshot, null); + mpt2.Put(new byte[] { 0xab }, new byte[] { 0x02 }); + mpt2.Put(new byte[] { 0xab, 0xcd }, new byte[] { 0x01 }); + r = mpt2.TryGetProof(new byte[] { 0xab, 0xcd }, out var set2); + Assert.IsTrue(r); + Assert.AreEqual(4, set2.Count); + Assert.AreEqual(mpt1.Root.Hash, mpt2.Root.Hash); + } + + [TestMethod] + public void TestFind() + { + var store = new MemoryStore(); + var snapshot = store.GetSnapshot(); + var mpt1 = new Trie(snapshot, null); + var results = mpt1.Find(ReadOnlySpan.Empty).ToArray(); + Assert.AreEqual(0, results.Length); + var mpt2 = new Trie(snapshot, null); + mpt2.Put(new byte[] { 0xab, 0xcd, 0xef }, new byte[] { 0x01 }); + mpt2.Put(new byte[] { 0xab, 0xcd, 0xe1 }, new byte[] { 0x02 }); + mpt2.Put(new byte[] { 0xab }, new byte[] { 0x03 }); + results = mpt2.Find(ReadOnlySpan.Empty).ToArray(); + Assert.AreEqual(3, results.Length); + results = mpt2.Find(new byte[] { 0xab }).ToArray(); + Assert.AreEqual(3, results.Length); + results = mpt2.Find(new byte[] { 0xab, 0xcd }).ToArray(); + Assert.AreEqual(2, results.Length); + results = mpt2.Find(new byte[] { 0xac }).ToArray(); + Assert.AreEqual(0, results.Length); + results = mpt2.Find(new byte[] { 0xab, 0xcd, 0xef, 0x00 }).ToArray(); + Assert.AreEqual(0, results.Length); + } + + [TestMethod] + public void TestFindCantResolve() + { + var b = Node.NewBranch(); + var r = Node.NewExtension("0a0c".HexToBytes(), b); + var v1 = Node.NewLeaf("abcd".HexToBytes());//key=ac01 + var v4 = Node.NewLeaf(Encoding.ASCII.GetBytes("missing")); + var e1 = Node.NewExtension(new byte[] { 0x01 }, v1); + var e4 = Node.NewExtension(new byte[] { 0x01 }, v4); + b.Children[0] = e1; + b.Children[15] = Node.NewHash(e4.Hash); + var store = new MemoryStore(); + PutToStore(store, r); + PutToStore(store, b); + PutToStore(store, e1); + PutToStore(store, v1); + + var snapshot = store.GetSnapshot(); + var mpt = new Trie(snapshot, r.Hash); + Assert.ThrowsException(() => mpt.Find("ac".HexToBytes()).Count()); + } + + [TestMethod] + public void TestFindLeadNode() + { + // r.Key = 0x0a0c + // b.Key = 0x00 + // l1.Key = 0x01 + var mpt = new Trie(mptdb.GetSnapshot(), root.Hash); + var prefix = new byte[] { 0xac, 0x01 }; // = FromNibbles(path = { 0x0a, 0x0c, 0x00, 0x01 }); + var results = mpt.Find(prefix).ToArray(); + Assert.AreEqual(1, results.Count()); + + prefix = new byte[] { 0xac }; // = FromNibbles(path = { 0x0a, 0x0c }); + Assert.ThrowsException(() => mpt.Find(prefix).ToArray()); + } + + [TestMethod] + public void TestFromNibblesException() + { + var b = Node.NewBranch(); + var r = Node.NewExtension("0c".HexToBytes(), b); + var v1 = Node.NewLeaf("abcd".HexToBytes());//key=ac01 + var v2 = Node.NewLeaf("2222".HexToBytes());//key=ac + var e1 = Node.NewExtension(new byte[] { 0x01 }, v1); + b.Children[0] = e1; + b.Children[16] = v2; + var store = new MemoryStore(); + PutToStore(store, r); + PutToStore(store, b); + PutToStore(store, e1); + PutToStore(store, v1); + PutToStore(store, v2); + + var snapshot = store.GetSnapshot(); + var mpt = new Trie(snapshot, r.Hash); + Assert.ThrowsException(() => mpt.Find(Array.Empty()).Count()); + } + + [TestMethod] + public void TestReference1() + { + var store = new MemoryStore(); + var snapshot = store.GetSnapshot(); + var mpt = new Trie(snapshot, null); + mpt.Put("a101".HexToBytes(), "01".HexToBytes()); + mpt.Put("a201".HexToBytes(), "01".HexToBytes()); + mpt.Put("a301".HexToBytes(), "01".HexToBytes()); + mpt.Commit(); + snapshot.Commit(); + var snapshot1 = store.GetSnapshot(); + var mpt1 = new Trie(snapshot1, mpt.Root.Hash); + mpt1.Delete("a301".HexToBytes()); + mpt1.Commit(); + snapshot1.Commit(); + var snapshot2 = store.GetSnapshot(); + var mpt2 = new Trie(snapshot2, mpt1.Root.Hash); + mpt2.Delete("a201".HexToBytes()); + Assert.AreEqual("01", mpt2["a101".HexToBytes()].ToHexString()); + } + + [TestMethod] + public void TestReference2() + { + var snapshot = new TestSnapshot(); + var mpt = new Trie(snapshot, null); + mpt.Put("a101".HexToBytes(), "01".HexToBytes()); + mpt.Put("a201".HexToBytes(), "01".HexToBytes()); + mpt.Put("a301".HexToBytes(), "01".HexToBytes()); + mpt.Commit(); + Assert.AreEqual(4, snapshot.Size); + mpt.Delete("a301".HexToBytes()); + mpt.Commit(); + Assert.AreEqual(4, snapshot.Size); + mpt.Delete("a201".HexToBytes()); + mpt.Commit(); + Assert.AreEqual(2, snapshot.Size); + Assert.AreEqual("01", mpt["a101".HexToBytes()].ToHexString()); + } + + + [TestMethod] + public void TestExtensionDeleteDirty() + { + var snapshot = new TestSnapshot(); + var mpt = new Trie(snapshot, null); + mpt.Put("a1".HexToBytes(), "01".HexToBytes()); + mpt.Put("a2".HexToBytes(), "02".HexToBytes()); + mpt.Commit(); + Assert.AreEqual(4, snapshot.Size); + var mpt1 = new Trie(snapshot, mpt.Root.Hash); + mpt1.Delete("a1".HexToBytes()); + mpt1.Commit(); + Assert.AreEqual(2, snapshot.Size); + var mpt2 = new Trie(snapshot, mpt1.Root.Hash); + mpt2.Delete("a2".HexToBytes()); + mpt2.Commit(); + Assert.AreEqual(0, snapshot.Size); + } + + [TestMethod] + public void TestBranchDeleteDirty() + { + var snapshot = new TestSnapshot(); + var mpt = new Trie(snapshot, null); + mpt.Put("10".HexToBytes(), "01".HexToBytes()); + mpt.Put("20".HexToBytes(), "02".HexToBytes()); + mpt.Put("30".HexToBytes(), "03".HexToBytes()); + mpt.Commit(); + Assert.AreEqual(7, snapshot.Size); + var mpt1 = new Trie(snapshot, mpt.Root.Hash); + mpt1.Delete("10".HexToBytes()); + mpt1.Commit(); + Assert.AreEqual(5, snapshot.Size); + var mpt2 = new Trie(snapshot, mpt1.Root.Hash); + mpt2.Delete("20".HexToBytes()); + mpt2.Commit(); + Assert.AreEqual(2, snapshot.Size); + var mpt3 = new Trie(snapshot, mpt2.Root.Hash); + mpt3.Delete("30".HexToBytes()); + mpt3.Commit(); + Assert.AreEqual(0, snapshot.Size); + } + + [TestMethod] + public void TestExtensionPutDirty() + { + var snapshot = new TestSnapshot(); + var mpt = new Trie(snapshot, null); + mpt.Put("a1".HexToBytes(), "01".HexToBytes()); + mpt.Put("a2".HexToBytes(), "02".HexToBytes()); + mpt.Commit(); + Assert.AreEqual(4, snapshot.Size); + var mpt1 = new Trie(snapshot, mpt.Root.Hash); + mpt1.Put("a3".HexToBytes(), "03".HexToBytes()); + mpt1.Commit(); + Assert.AreEqual(5, snapshot.Size); + } + + [TestMethod] + public void TestBranchPutDirty() + { + var snapshot = new TestSnapshot(); + var mpt = new Trie(snapshot, null); + mpt.Put("10".HexToBytes(), "01".HexToBytes()); + mpt.Put("20".HexToBytes(), "02".HexToBytes()); + mpt.Commit(); + Assert.AreEqual(5, snapshot.Size); + var mpt1 = new Trie(snapshot, mpt.Root.Hash); + mpt1.Put("30".HexToBytes(), "03".HexToBytes()); + mpt1.Commit(); + Assert.AreEqual(7, snapshot.Size); + } + + [TestMethod] + public void TestEmptyValueIssue633() + { + var key = "01".HexToBytes(); + var snapshot = new TestSnapshot(); + var mpt = new Trie(snapshot, null); + mpt.Put(key, Array.Empty()); + var val = mpt[key]; + Assert.IsNotNull(val); + Assert.AreEqual(0, val.Length); + var r = mpt.TryGetProof(key, out var proof); + Assert.IsTrue(r); + val = Trie.VerifyProof(mpt.Root.Hash, key, proof); + Assert.IsNotNull(val); + Assert.AreEqual(0, val.Length); + } + + [TestMethod] + public void TestFindWithFrom() + { + var snapshot = new TestSnapshot(); + var mpt = new Trie(snapshot, null); + mpt.Put("aa".HexToBytes(), "02".HexToBytes()); + mpt.Put("aa10".HexToBytes(), "03".HexToBytes()); + mpt.Put("aa50".HexToBytes(), "04".HexToBytes()); + var r = mpt.Find("aa".HexToBytes()).ToList(); + Assert.AreEqual(3, r.Count); + r = mpt.Find("aa".HexToBytes(), "aa30".HexToBytes()).ToList(); + Assert.AreEqual(1, r.Count); + r = mpt.Find("aa".HexToBytes(), "aa60".HexToBytes()).ToList(); + Assert.AreEqual(0, r.Count); + r = mpt.Find("aa".HexToBytes(), "aa10".HexToBytes()).ToList(); + Assert.AreEqual(1, r.Count); + } + + [TestMethod] + public void TestFindStatesIssue652() + { + var snapshot = new TestSnapshot(); + var mpt = new Trie(snapshot, null); + mpt.Put("abc1".HexToBytes(), "01".HexToBytes()); + mpt.Put("abc3".HexToBytes(), "02".HexToBytes()); + var r = mpt.Find("ab".HexToBytes(), "abd2".HexToBytes()).ToList(); + Assert.AreEqual(0, r.Count); + r = mpt.Find("ab".HexToBytes(), "abb2".HexToBytes()).ToList(); + Assert.AreEqual(2, r.Count); + r = mpt.Find("ab".HexToBytes(), "abc2".HexToBytes()).ToList(); + Assert.AreEqual(1, r.Count); + } + } +} diff --git a/tests/Neo.Cryptography.MPTTrie.Tests/Neo.Cryptography.MPTTrie.Tests.csproj b/tests/Neo.Cryptography.MPTTrie.Tests/Neo.Cryptography.MPTTrie.Tests.csproj new file mode 100644 index 0000000000..41bad3d63b --- /dev/null +++ b/tests/Neo.Cryptography.MPTTrie.Tests/Neo.Cryptography.MPTTrie.Tests.csproj @@ -0,0 +1,18 @@ + + + + net8.0 + Neo.Cryptography.MPT.Tests + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/Neo.Network.RPC.Tests/Neo.Network.RPC.Tests.csproj b/tests/Neo.Network.RPC.Tests/Neo.Network.RPC.Tests.csproj new file mode 100644 index 0000000000..8875785e77 --- /dev/null +++ b/tests/Neo.Network.RPC.Tests/Neo.Network.RPC.Tests.csproj @@ -0,0 +1,26 @@ + + + + net8.0 + Neo.Network.RPC.Tests + + + + + + + + + + + + + + + + + PreserveNewest + + + + diff --git a/tests/Neo.Network.RPC.Tests/RpcTestCases.json b/tests/Neo.Network.RPC.Tests/RpcTestCases.json new file mode 100644 index 0000000000..cfbffb3ede --- /dev/null +++ b/tests/Neo.Network.RPC.Tests/RpcTestCases.json @@ -0,0 +1,3340 @@ +[ + { + "Name": "sendrawtransactionasyncerror", + "Request": { + "jsonrpc": "2.0", + "method": "sendrawtransaction", + "params": [ "ANIHn05ujtUAAAAAACYcEwAAAAAAQkEAAAEKo4e1Ppa3mJpjFDGgVt0fQKBC9gEAXQMAyBeoBAAAAAwUzViuz9M1vh6z0xHh3IAJY9/XLZ8MFAqjh7U+lreYmmMUMaBW3R9AoEL2E8AMCHRyYW5zZmVyDBSlB7dGdv/td+dUuG7NmQnwus08ukFifVtSOAFCDEDh8zgTrGUXyzVX60wBCMyajNRfzFRiEPAe8CgGQ10bA2C3fnVz68Gw+Amgn5gmvuNfYKgWQ/W68Km1bYUPlnEYKQwhA86j4vgfGvk1ItKe3k8kofC+3q1ykzkdM4gPVHXZeHjJC0GVRA14" ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "error": { + "code": -500, + "message": "InsufficientFunds", + "data": " at Neo.Plugins.RpcServer.GetRelayResult(RelayResultReason reason, UInt256 hash)\r\n at Neo.Network.RPC.Models.RpcServer.SendRawTransaction(JArray _params)\r\n at Neo.Network.RPC.Models.RpcServer.ProcessRequest(HttpContext context, JObject request)" + } + } + }, + { + "Name": "getbestblockhashasync", + "Request": { + "jsonrpc": "2.0", + "method": "getbestblockhash", + "params": [], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": "0x530de76326a8662d1b730ba4fbdf011051eabd142015587e846da42376adf35f" + } + }, + { + "Name": "getblockhexasync", + "Request": { + "jsonrpc": "2.0", + "method": "getblock", + "params": [ 0 ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": "0000000000000000000000000000000000000000000000000000000000000000000000002bbb6298fc7039330cdfd2e4dfbe976ee72c4cba6c16d68f0b49ab1bca685b7388ea19ef55010000000000009903b0c3d292988febe5f306a02f654ea2eb16290100011102001dac2b7c000000000000000000ca61e52e881d41374e640f819cd118cc153b21a7000000000000000000000000000000000000000000000541123e7fe801000111" + } + }, + { + "Name": "getblockhexasync", + "Request": { + "jsonrpc": "2.0", + "method": "getblock", + "params": [ "0xe191fe1aea732c3e23f20af8a95e09f95891176f8064a2fce8571d51f80619a8" ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": "0000000000000000000000000000000000000000000000000000000000000000000000002bbb6298fc7039330cdfd2e4dfbe976ee72c4cba6c16d68f0b49ab1bca685b7388ea19ef55010000000000009903b0c3d292988febe5f306a02f654ea2eb16290100011102001dac2b7c000000000000000000ca61e52e881d41374e640f819cd118cc153b21a7000000000000000000000000000000000000000000000541123e7fe801000111" + } + }, + { + "Name": "getblockasync", + "Request": { + "jsonrpc": "2.0", + "method": "getblock", + "params": [ 7, true ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": { + "hash": "0x6d1556889c92249da88d2fb7729ae82fb2cc1b45dcd9030a40208b72a1d3cb83", + "size": 470, + "version": 0, + "previousblockhash": "0xaae8867e9086afaf06fd02cc538e88a69b801abd6f9d3ae39ae630e29d5b39e2", + "merkleroot": "0xe95761f21c733ad53066786af24ee5d613b32bd5aae538df2d611492ec0cae82", + "time": 1594867377561, + "nonce": "FFFFFFFFFFFFFFFF", + "index": 7, + "primary": 1, + "nextconsensus": "NikvsLcNP1jWhrFPrfS3n4spEASgdNYTG2", + "witnesses": [ + { + "invocation": "DEBs6hZDHUtL7KOJuF1m8/vITM8VeduwegKhBdbqcLKdBzXA1uZZiBl8jM/rhjXBaIGQSFIQuq8Er1Nb5y5/DWUx", + "verification": "EQwhAqnqaELMDLOw8jF7B8hQ3j0eKyQ6mO0tVqP/TKZqrzMLEQtBE43vrw==" + } + ], + "tx": [ + { + "hash": "0x83d44d71d59f854bc29f4e3932bf68703545807d05fb5429504d70cfc8d05071", + "size": 248, + "version": 0, + "nonce": 631973574, + "sender": "NikvsLcNP1jWhrFPrfS3n4spEASgdNYTG2", + "sysfee": "9007990", + "netfee": "1248450", + "validuntilblock": 2102405, + "signers": [ + { + "account": "0xe19de267a37a71734478f512b3e92c79fc3695fa", + "scopes": "CalledByEntry" + } + ], + "attributes": [], + "script": "AccyDBQcA1dGS3d\u002Bz2tfOsOJOs4fixYh9gwU\u002BpU2/Hks6bMS9XhEc3F6o2fineETwAwIdHJhbnNmZXIMFCUFnstIeNOodfkcUc7e0zDUV1/eQWJ9W1I4", + "witnesses": [ + { + "invocation": "DEDZxkskUb1aH1I4EX5ja02xrYX4fCubAmQzBuPpfY7pDEb1n4Dzx\u002BUB\u002BqSdC/CGskGf5BuzJ0MWJJipsHuivKmU", + "verification": "EQwhAqnqaELMDLOw8jF7B8hQ3j0eKyQ6mO0tVqP/TKZqrzMLEQtBE43vrw==" + } + ] + } + ], + "confirmations": 695, + "nextblockhash": "0xc4b986813396932a47d6823a9987ccee0148c6fca0150102f4b24ce05cfc9c6f" + } + } + }, + { + "Name": "getblockasync", + "Request": { + "jsonrpc": "2.0", + "method": "getblock", + "params": [ "0xb9579b028e4cf31a0c3bd9582f9f7fbd40b0e0495604406b8f530c7ebce5bcc8", true ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": { + "hash": "0x6d1556889c92249da88d2fb7729ae82fb2cc1b45dcd9030a40208b72a1d3cb83", + "size": 470, + "version": 0, + "previousblockhash": "0xaae8867e9086afaf06fd02cc538e88a69b801abd6f9d3ae39ae630e29d5b39e2", + "merkleroot": "0xe95761f21c733ad53066786af24ee5d613b32bd5aae538df2d611492ec0cae82", + "time": 1594867377561, + "nonce": "FFFFFFFFFFFFFFFF", + "index": 7, + "primary": 1, + "nextconsensus": "NikvsLcNP1jWhrFPrfS3n4spEASgdNYTG2", + "witnesses": [ + { + "invocation": "DEBs6hZDHUtL7KOJuF1m8/vITM8VeduwegKhBdbqcLKdBzXA1uZZiBl8jM/rhjXBaIGQSFIQuq8Er1Nb5y5/DWUx", + "verification": "EQwhAqnqaELMDLOw8jF7B8hQ3j0eKyQ6mO0tVqP/TKZqrzMLEQtBE43vrw==" + } + ], + "tx": [ + { + "hash": "0x83d44d71d59f854bc29f4e3932bf68703545807d05fb5429504d70cfc8d05071", + "size": 248, + "version": 0, + "nonce": 631973574, + "sender": "NikvsLcNP1jWhrFPrfS3n4spEASgdNYTG2", + "sysfee": "9007990", + "netfee": "1248450", + "validuntilblock": 2102405, + "signers": [ + { + "account": "0xe19de267a37a71734478f512b3e92c79fc3695fa", + "scopes": "CalledByEntry" + } + ], + "attributes": [], + "script": "AccyDBQcA1dGS3d\u002Bz2tfOsOJOs4fixYh9gwU\u002BpU2/Hks6bMS9XhEc3F6o2fineETwAwIdHJhbnNmZXIMFCUFnstIeNOodfkcUc7e0zDUV1/eQWJ9W1I4", + "witnesses": [ + { + "invocation": "DEDZxkskUb1aH1I4EX5ja02xrYX4fCubAmQzBuPpfY7pDEb1n4Dzx\u002BUB\u002BqSdC/CGskGf5BuzJ0MWJJipsHuivKmU", + "verification": "EQwhAqnqaELMDLOw8jF7B8hQ3j0eKyQ6mO0tVqP/TKZqrzMLEQtBE43vrw==" + } + ] + } + ], + "confirmations": 695, + "nextblockhash": "0xc4b986813396932a47d6823a9987ccee0148c6fca0150102f4b24ce05cfc9c6f" + } + } + }, + { + "Name": "getblockheadercountasync", + "Request": { + "jsonrpc": "2.0", + "method": "getblockheadercount", + "params": [], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": 3825 + } + }, + { + "Name": "getblockcountasync", + "Request": { + "jsonrpc": "2.0", + "method": "getblockcount", + "params": [], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": 2691 + } + }, + { + "Name": "getblockhashasync", + "Request": { + "jsonrpc": "2.0", + "method": "getblockhash", + "params": [ 0 ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": "0xe191fe1aea732c3e23f20af8a95e09f95891176f8064a2fce8571d51f80619a8" + } + }, + { + "Name": "getblockheaderhexasync", + "Request": { + "jsonrpc": "2.0", + "method": "getblockheader", + "params": [ 0 ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": "0000000000000000000000000000000000000000000000000000000000000000000000002bbb6298fc7039330cdfd2e4dfbe976ee72c4cba6c16d68f0b49ab1bca685b7388ea19ef55010000000000009903b0c3d292988febe5f306a02f654ea2eb16290100011100" + } + }, + { + "Name": "getblockheaderhexasync", + "Request": { + "jsonrpc": "2.0", + "method": "getblockheader", + "params": [ "0xe191fe1aea732c3e23f20af8a95e09f95891176f8064a2fce8571d51f80619a8" ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": "0000000000000000000000000000000000000000000000000000000000000000000000002bbb6298fc7039330cdfd2e4dfbe976ee72c4cba6c16d68f0b49ab1bca685b7388ea19ef55010000000000009903b0c3d292988febe5f306a02f654ea2eb16290100011100" + } + }, + { + "Name": "getblockheaderasync", + "Request": { + "jsonrpc": "2.0", + "method": "getblockheader", + "params": [ 0, true ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": { + "hash": "0xbbf7e191d4947f8a4dc33477902dacd0b047e371a81c18a6df62fe0d541725f5", + "size": 113, + "version": 0, + "previousblockhash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "merkleroot": "0x735b68ca1bab490b8fd6166cba4c2ce76e97bedfe4d2df0c333970fc9862bb2b", + "time": 1468595301000, + "nonce": "FFFFFFFFFFFFFFFF", + "index": 0, + "primary": 1, + "nextconsensus": "NZs2zXSPuuv9ZF6TDGSWT1RBmE8rfGj7UW", + "witnesses": [ + { + "invocation": "", + "verification": "EQ==" + } + ], + "confirmations": 2700, + "nextblockhash": "0x423173109798b038019b35129417b55cc4b5976ac79978dfab8ea2512d155f69" + } + } + }, + { + "Name": "getblockheaderasync", + "Request": { + "jsonrpc": "2.0", + "method": "getblockheader", + "params": [ "0x656bcb02e4fe8a19dbb15149073a5ae0bd8adc2da8504b67b112b44f68b4c9d7", true ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": { + "hash": "0xbbf7e191d4947f8a4dc33477902dacd0b047e371a81c18a6df62fe0d541725f5", + "size": 113, + "version": 0, + "previousblockhash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "merkleroot": "0x735b68ca1bab490b8fd6166cba4c2ce76e97bedfe4d2df0c333970fc9862bb2b", + "time": 1468595301000, + "nonce": "FFFFFFFFFFFFFFFF", + "index": 0, + "primary": 1, + "nextconsensus": "NZs2zXSPuuv9ZF6TDGSWT1RBmE8rfGj7UW", + "witnesses": [ + { + "invocation": "", + "verification": "EQ==" + } + ], + "confirmations": 2700, + "nextblockhash": "0x423173109798b038019b35129417b55cc4b5976ac79978dfab8ea2512d155f69" + } + } + }, + { + "Name": "getblocksysfeeasync", + "Request": { + "jsonrpc": "2.0", + "method": "getblocksysfee", + "params": [ 100 ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": "300000000" + } + }, + { + "Name": "getcommitteeasync", + "Request": { + "jsonrpc": "2.0", + "method": "getcommittee", + "params": [], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": [ + "02ced432397ddc44edba031c0bc3b933f28fdd9677792d7b20e6c036ddaaacf1e2" + ] + } + }, + { + "Name": "getcontractstateasync", + "Request": { + "jsonrpc": "2.0", + "method": "getcontractstate", + "params": [ "gastoken" ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": { + "id": -4, + "updatecounter": 0, + "hash": "0xd2a4cff31913016155e38e474a2c06d08be276cf", + "nef": { + "magic": 860243278, + "compiler": "neo-core-v3.0", + "source": "", + "tokens": [], + "script": "APxBGvd7Zw==", + "checksum": 3155977747 + }, + "manifest": { + "name": "GasToken", + "groups": [], + "features": {}, + "supportedstandards": [ + "NEP-17" + ], + "abi": { + "methods": [ + { + "name": "balanceOf", + "parameters": [ + { + "name": "account", + "type": "Hash160" + } + ], + "returntype": "Integer", + "offset": 0, + "safe": true + }, + { + "name": "decimals", + "parameters": [], + "returntype": "Integer", + "offset": 0, + "safe": true + }, + { + "name": "symbol", + "parameters": [], + "returntype": "String", + "offset": 0, + "safe": true + }, + { + "name": "totalSupply", + "parameters": [], + "returntype": "Integer", + "offset": 0, + "safe": true + }, + { + "name": "transfer", + "parameters": [ + { + "name": "from", + "type": "Hash160" + }, + { + "name": "to", + "type": "Hash160" + }, + { + "name": "amount", + "type": "Integer" + }, + { + "name": "data", + "type": "Any" + } + ], + "returntype": "Boolean", + "offset": 0, + "safe": false + } + ], + "events": [ + { + "name": "Transfer", + "parameters": [ + { + "name": "from", + "type": "Hash160" + }, + { + "name": "to", + "type": "Hash160" + }, + { + "name": "amount", + "type": "Integer" + } + ] + } + ] + }, + "permissions": [ + { + "contract": "*", + "methods": "*" + } + ], + "trusts": [], + "extra": null + } + } + } + }, + { + "Name": "getcontractstateasync", + "Request": { + "jsonrpc": "2.0", + "method": "getcontractstate", + "params": [ "0xd2a4cff31913016155e38e474a2c06d08be276cf" ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": { + "id": -4, + "updatecounter": 0, + "hash": "0xd2a4cff31913016155e38e474a2c06d08be276cf", + "nef": { + "magic": 860243278, + "compiler": "neo-core-v3.0", + "source": "", + "tokens": [], + "script": "APxBGvd7Zw==", + "checksum": 3155977747 + }, + "manifest": { + "name": "GasToken", + "groups": [], + "features": {}, + "supportedstandards": [ + "NEP-17" + ], + "abi": { + "methods": [ + { + "name": "balanceOf", + "parameters": [ + { + "name": "account", + "type": "Hash160" + } + ], + "returntype": "Integer", + "offset": 0, + "safe": true + }, + { + "name": "decimals", + "parameters": [], + "returntype": "Integer", + "offset": 0, + "safe": true + }, + { + "name": "symbol", + "parameters": [], + "returntype": "String", + "offset": 0, + "safe": true + }, + { + "name": "totalSupply", + "parameters": [], + "returntype": "Integer", + "offset": 0, + "safe": true + }, + { + "name": "transfer", + "parameters": [ + { + "name": "from", + "type": "Hash160" + }, + { + "name": "to", + "type": "Hash160" + }, + { + "name": "amount", + "type": "Integer" + }, + { + "name": "data", + "type": "Any" + } + ], + "returntype": "Boolean", + "offset": 0, + "safe": false + } + ], + "events": [ + { + "name": "Transfer", + "parameters": [ + { + "name": "from", + "type": "Hash160" + }, + { + "name": "to", + "type": "Hash160" + }, + { + "name": "amount", + "type": "Integer" + } + ] + } + ] + }, + "permissions": [ + { + "contract": "*", + "methods": "*" + } + ], + "trusts": [], + "extra": null + } + } + } + }, + { + "Name": "getcontractstateasync", + "Request": { + "jsonrpc": "2.0", + "id": 1, + "method": "getcontractstate", + "params": [ "neotoken" ] + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": { + "id": -3, + "updatecounter": 0, + "hash": "0xef4073a0f2b305a38ec4050e4d3d28bc40ea63f5", + "nef": { + "magic": 860243278, + "compiler": "neo-core-v3.0", + "source": "", + "tokens": [], + "script": "AP1BGvd7Zw==", + "checksum": 3921333105 + }, + "manifest": { + "name": "NeoToken", + "groups": [], + "features": {}, + "supportedstandards": [ + "NEP-17" + ], + "abi": { + "methods": [ + { + "name": "balanceOf", + "parameters": [ + { + "name": "account", + "type": "Hash160" + } + ], + "returntype": "Integer", + "offset": 0, + "safe": true + }, + { + "name": "decimals", + "parameters": [], + "returntype": "Integer", + "offset": 0, + "safe": true + }, + { + "name": "getCandidates", + "parameters": [], + "returntype": "Array", + "offset": 0, + "safe": true + }, + { + "name": "getCommittee", + "parameters": [], + "returntype": "Array", + "offset": 0, + "safe": true + }, + { + "name": "getGasPerBlock", + "parameters": [], + "returntype": "Integer", + "offset": 0, + "safe": true + }, + { + "name": "getNextBlockValidators", + "parameters": [], + "returntype": "Array", + "offset": 0, + "safe": true + }, + { + "name": "registerCandidate", + "parameters": [ + { + "name": "pubkey", + "type": "ByteArray" + } + ], + "returntype": "Boolean", + "offset": 0, + "safe": false + }, + { + "name": "setGasPerBlock", + "parameters": [ + { + "name": "gasPerBlock", + "type": "Integer" + } + ], + "returntype": "Boolean", + "offset": 0, + "safe": false + }, + { + "name": "symbol", + "parameters": [], + "returntype": "String", + "offset": 0, + "safe": true + }, + { + "name": "totalSupply", + "parameters": [], + "returntype": "Integer", + "offset": 0, + "safe": true + }, + { + "name": "transfer", + "parameters": [ + { + "name": "from", + "type": "Hash160" + }, + { + "name": "to", + "type": "Hash160" + }, + { + "name": "amount", + "type": "Integer" + }, + { + "name": "data", + "type": "Any" + } + ], + "returntype": "Boolean", + "offset": 0, + "safe": false + }, + { + "name": "unclaimedGas", + "parameters": [ + { + "name": "account", + "type": "Hash160" + }, + { + "name": "end", + "type": "Integer" + } + ], + "returntype": "Integer", + "offset": 0, + "safe": true + }, + { + "name": "unregisterCandidate", + "parameters": [ + { + "name": "pubkey", + "type": "ByteArray" + } + ], + "returntype": "Boolean", + "offset": 0, + "safe": false + }, + { + "name": "vote", + "parameters": [ + { + "name": "account", + "type": "Hash160" + }, + { + "name": "voteTo", + "type": "ByteArray" + } + ], + "returntype": "Boolean", + "offset": 0, + "safe": false + } + ], + "events": [ + { + "name": "Transfer", + "parameters": [ + { + "name": "from", + "type": "Hash160" + }, + { + "name": "to", + "type": "Hash160" + }, + { + "name": "amount", + "type": "Integer" + } + ] + } + ] + }, + "permissions": [ + { + "contract": "*", + "methods": "*" + } + ], + "trusts": [], + "extra": null + } + } + } + }, + { + "Name": "getcontractstateasync", + "Request": { + "jsonrpc": "2.0", + "id": 1, + "method": "getcontractstate", + "params": [ "0xef4073a0f2b305a38ec4050e4d3d28bc40ea63f5" ] + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": { + "id": -3, + "updatecounter": 0, + "hash": "0xef4073a0f2b305a38ec4050e4d3d28bc40ea63f5", + "nef": { + "magic": 860243278, + "compiler": "neo-core-v3.0", + "source": "", + "tokens": [], + "script": "AP1BGvd7Zw==", + "checksum": 3921333105 + }, + "manifest": { + "name": "NeoToken", + "groups": [], + "features": {}, + "supportedstandards": [ + "NEP-17" + ], + "abi": { + "methods": [ + { + "name": "balanceOf", + "parameters": [ + { + "name": "account", + "type": "Hash160" + } + ], + "returntype": "Integer", + "offset": 0, + "safe": true + }, + { + "name": "decimals", + "parameters": [], + "returntype": "Integer", + "offset": 0, + "safe": true + }, + { + "name": "getCandidates", + "parameters": [], + "returntype": "Array", + "offset": 0, + "safe": true + }, + { + "name": "getCommittee", + "parameters": [], + "returntype": "Array", + "offset": 0, + "safe": true + }, + { + "name": "getGasPerBlock", + "parameters": [], + "returntype": "Integer", + "offset": 0, + "safe": true + }, + { + "name": "getNextBlockValidators", + "parameters": [], + "returntype": "Array", + "offset": 0, + "safe": true + }, + { + "name": "registerCandidate", + "parameters": [ + { + "name": "pubkey", + "type": "ByteArray" + } + ], + "returntype": "Boolean", + "offset": 0, + "safe": false + }, + { + "name": "setGasPerBlock", + "parameters": [ + { + "name": "gasPerBlock", + "type": "Integer" + } + ], + "returntype": "Boolean", + "offset": 0, + "safe": false + }, + { + "name": "symbol", + "parameters": [], + "returntype": "String", + "offset": 0, + "safe": true + }, + { + "name": "totalSupply", + "parameters": [], + "returntype": "Integer", + "offset": 0, + "safe": true + }, + { + "name": "transfer", + "parameters": [ + { + "name": "from", + "type": "Hash160" + }, + { + "name": "to", + "type": "Hash160" + }, + { + "name": "amount", + "type": "Integer" + }, + { + "name": "data", + "type": "Any" + } + ], + "returntype": "Boolean", + "offset": 0, + "safe": false + }, + { + "name": "unclaimedGas", + "parameters": [ + { + "name": "account", + "type": "Hash160" + }, + { + "name": "end", + "type": "Integer" + } + ], + "returntype": "Integer", + "offset": 0, + "safe": true + }, + { + "name": "unregisterCandidate", + "parameters": [ + { + "name": "pubkey", + "type": "ByteArray" + } + ], + "returntype": "Boolean", + "offset": 0, + "safe": false + }, + { + "name": "vote", + "parameters": [ + { + "name": "account", + "type": "Hash160" + }, + { + "name": "voteTo", + "type": "ByteArray" + } + ], + "returntype": "Boolean", + "offset": 0, + "safe": false + } + ], + "events": [ + { + "name": "Transfer", + "parameters": [ + { + "name": "from", + "type": "Hash160" + }, + { + "name": "to", + "type": "Hash160" + }, + { + "name": "amount", + "type": "Integer" + } + ] + } + ] + }, + "permissions": [ + { + "contract": "*", + "methods": "*" + } + ], + "trusts": [], + "extra": null + } + } + } + }, + { + "Name": "getnativecontractsasync", + "Request": { + "jsonrpc": "2.0", + "id": 1, + "method": "getnativecontracts", + "params": [] + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": [ + { + "id": -1, + "updatecounter": 0, + "hash": "0xa501d7d7d10983673b61b7a2d3a813b36f9f0e43", + "nef": { + "magic": 860243278, + "compiler": "neo-core-v3.0", + "source": "", + "tokens": [], + "script": "D0Ea93tn", + "checksum": 3516775561 + }, + "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": 0, + "safe": false + }, + { + "name": "destroy", + "parameters": [], + "returntype": "Void", + "offset": 0, + "safe": false + }, + { + "name": "getContract", + "parameters": [ + { + "name": "hash", + "type": "Hash160" + } + ], + "returntype": "Array", + "offset": 0, + "safe": true + }, + { + "name": "getMinimumDeploymentFee", + "parameters": [], + "returntype": "Integer", + "offset": 0, + "safe": true + }, + { + "name": "setMinimumDeploymentFee", + "parameters": [ + { + "name": "value", + "type": "Integer" + } + ], + "returntype": "Void", + "offset": 0, + "safe": false + }, + { + "name": "update", + "parameters": [ + { + "name": "nefFile", + "type": "ByteArray" + }, + { + "name": "manifest", + "type": "ByteArray" + } + ], + "returntype": "Void", + "offset": 0, + "safe": false + }, + { + "name": "update", + "parameters": [ + { + "name": "nefFile", + "type": "ByteArray" + }, + { + "name": "manifest", + "type": "ByteArray" + }, + { + "name": "data", + "type": "Any" + } + ], + "returntype": "Void", + "offset": 0, + "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 + } + }, + { + "id": -2, + "updatecounter": 1, + "hash": "0x971d69c6dd10ce88e7dfffec1dc603c6125a8764", + "nef": { + "magic": 860243278, + "compiler": "neo-core-v3.0", + "source": "", + "tokens": [], + "script": "AP5BGvd7Zw==", + "checksum": 3395482975 + }, + "manifest": { + "name": "LedgerContract", + "groups": [], + "features": {}, + "supportedstandards": [], + "abi": { + "methods": [ + { + "name": "currentHash", + "parameters": [], + "returntype": "Hash256", + "offset": 0, + "safe": true + }, + { + "name": "currentIndex", + "parameters": [], + "returntype": "Integer", + "offset": 0, + "safe": true + }, + { + "name": "getBlock", + "parameters": [ + { + "name": "indexOrHash", + "type": "ByteArray" + } + ], + "returntype": "Array", + "offset": 0, + "safe": true + }, + { + "name": "getTransaction", + "parameters": [ + { + "name": "hash", + "type": "Hash256" + } + ], + "returntype": "Array", + "offset": 0, + "safe": true + }, + { + "name": "getTransactionFromBlock", + "parameters": [ + { + "name": "blockIndexOrHash", + "type": "ByteArray" + }, + { + "name": "txIndex", + "type": "Integer" + } + ], + "returntype": "Array", + "offset": 0, + "safe": true + }, + { + "name": "getTransactionHeight", + "parameters": [ + { + "name": "hash", + "type": "Hash256" + } + ], + "returntype": "Integer", + "offset": 0, + "safe": true + } + ], + "events": [] + }, + "permissions": [ + { + "contract": "*", + "methods": "*" + } + ], + "trusts": [], + "extra": null + } + }, + { + "id": -3, + "updatecounter": 0, + "hash": "0xef4073a0f2b305a38ec4050e4d3d28bc40ea63f5", + "nef": { + "magic": 860243278, + "compiler": "neo-core-v3.0", + "source": "", + "tokens": [], + "script": "AP1BGvd7Zw==", + "checksum": 3921333105 + }, + "manifest": { + "name": "NeoToken", + "groups": [], + "features": {}, + "supportedstandards": [ + "NEP-17" + ], + "abi": { + "methods": [ + { + "name": "balanceOf", + "parameters": [ + { + "name": "account", + "type": "Hash160" + } + ], + "returntype": "Integer", + "offset": 0, + "safe": true + }, + { + "name": "decimals", + "parameters": [], + "returntype": "Integer", + "offset": 0, + "safe": true + }, + { + "name": "getCandidates", + "parameters": [], + "returntype": "Array", + "offset": 0, + "safe": true + }, + { + "name": "getCommittee", + "parameters": [], + "returntype": "Array", + "offset": 0, + "safe": true + }, + { + "name": "getGasPerBlock", + "parameters": [], + "returntype": "Integer", + "offset": 0, + "safe": true + }, + { + "name": "getNextBlockValidators", + "parameters": [], + "returntype": "Array", + "offset": 0, + "safe": true + }, + { + "name": "registerCandidate", + "parameters": [ + { + "name": "pubkey", + "type": "ByteArray" + } + ], + "returntype": "Boolean", + "offset": 0, + "safe": false + }, + { + "name": "setGasPerBlock", + "parameters": [ + { + "name": "gasPerBlock", + "type": "Integer" + } + ], + "returntype": "Boolean", + "offset": 0, + "safe": false + }, + { + "name": "symbol", + "parameters": [], + "returntype": "String", + "offset": 0, + "safe": true + }, + { + "name": "totalSupply", + "parameters": [], + "returntype": "Integer", + "offset": 0, + "safe": true + }, + { + "name": "transfer", + "parameters": [ + { + "name": "from", + "type": "Hash160" + }, + { + "name": "to", + "type": "Hash160" + }, + { + "name": "amount", + "type": "Integer" + }, + { + "name": "data", + "type": "Any" + } + ], + "returntype": "Boolean", + "offset": 0, + "safe": false + }, + { + "name": "unclaimedGas", + "parameters": [ + { + "name": "account", + "type": "Hash160" + }, + { + "name": "end", + "type": "Integer" + } + ], + "returntype": "Integer", + "offset": 0, + "safe": true + }, + { + "name": "unregisterCandidate", + "parameters": [ + { + "name": "pubkey", + "type": "ByteArray" + } + ], + "returntype": "Boolean", + "offset": 0, + "safe": false + }, + { + "name": "vote", + "parameters": [ + { + "name": "account", + "type": "Hash160" + }, + { + "name": "voteTo", + "type": "ByteArray" + } + ], + "returntype": "Boolean", + "offset": 0, + "safe": false + } + ], + "events": [ + { + "name": "Transfer", + "parameters": [ + { + "name": "from", + "type": "Hash160" + }, + { + "name": "to", + "type": "Hash160" + }, + { + "name": "amount", + "type": "Integer" + } + ] + } + ] + }, + "permissions": [ + { + "contract": "*", + "methods": "*" + } + ], + "trusts": [], + "extra": null + } + }, + { + "id": -4, + "updatecounter": 0, + "hash": "0xd2a4cff31913016155e38e474a2c06d08be276cf", + "nef": { + "magic": 860243278, + "compiler": "neo-core-v3.0", + "source": "", + "tokens": [], + "script": "APxBGvd7Zw==", + "checksum": 3155977747 + }, + "manifest": { + "name": "GasToken", + "groups": [], + "features": {}, + "supportedstandards": [ + "NEP-17" + ], + "abi": { + "methods": [ + { + "name": "balanceOf", + "parameters": [ + { + "name": "account", + "type": "Hash160" + } + ], + "returntype": "Integer", + "offset": 0, + "safe": true + }, + { + "name": "decimals", + "parameters": [], + "returntype": "Integer", + "offset": 0, + "safe": true + }, + { + "name": "symbol", + "parameters": [], + "returntype": "String", + "offset": 0, + "safe": true + }, + { + "name": "totalSupply", + "parameters": [], + "returntype": "Integer", + "offset": 0, + "safe": true + }, + { + "name": "transfer", + "parameters": [ + { + "name": "from", + "type": "Hash160" + }, + { + "name": "to", + "type": "Hash160" + }, + { + "name": "amount", + "type": "Integer" + }, + { + "name": "data", + "type": "Any" + } + ], + "returntype": "Boolean", + "offset": 0, + "safe": false + } + ], + "events": [ + { + "name": "Transfer", + "parameters": [ + { + "name": "from", + "type": "Hash160" + }, + { + "name": "to", + "type": "Hash160" + }, + { + "name": "amount", + "type": "Integer" + } + ] + } + ] + }, + "permissions": [ + { + "contract": "*", + "methods": "*" + } + ], + "trusts": [], + "extra": null + } + }, + { + "id": -5, + "updatecounter": 0, + "hash": "0x79bcd398505eb779df6e67e4be6c14cded08e2f2", + "nef": { + "magic": 860243278, + "compiler": "neo-core-v3.0", + "source": "", + "tokens": [], + "script": "APtBGvd7Zw==", + "checksum": 1136340263 + }, + "manifest": { + "name": "PolicyContract", + "groups": [], + "features": {}, + "supportedstandards": [], + "abi": { + "methods": [ + { + "name": "blockAccount", + "parameters": [ + { + "name": "account", + "type": "Hash160" + } + ], + "returntype": "Boolean", + "offset": 0, + "safe": false + }, + { + "name": "getExecFeeFactor", + "parameters": [], + "returntype": "Integer", + "offset": 0, + "safe": true + }, + { + "name": "getFeePerByte", + "parameters": [], + "returntype": "Integer", + "offset": 0, + "safe": true + }, + { + "name": "getMaxBlockSize", + "parameters": [], + "returntype": "Integer", + "offset": 0, + "safe": true + }, + { + "name": "getMaxBlockSystemFee", + "parameters": [], + "returntype": "Integer", + "offset": 0, + "safe": true + }, + { + "name": "getMaxTransactionsPerBlock", + "parameters": [], + "returntype": "Integer", + "offset": 0, + "safe": true + }, + { + "name": "getStoragePrice", + "parameters": [], + "returntype": "Integer", + "offset": 0, + "safe": true + }, + { + "name": "isBlocked", + "parameters": [ + { + "name": "account", + "type": "Hash160" + } + ], + "returntype": "Boolean", + "offset": 0, + "safe": true + }, + { + "name": "setExecFeeFactor", + "parameters": [ + { + "name": "value", + "type": "Integer" + } + ], + "returntype": "Boolean", + "offset": 0, + "safe": false + }, + { + "name": "setFeePerByte", + "parameters": [ + { + "name": "value", + "type": "Integer" + } + ], + "returntype": "Boolean", + "offset": 0, + "safe": false + }, + { + "name": "setMaxBlockSize", + "parameters": [ + { + "name": "value", + "type": "Integer" + } + ], + "returntype": "Boolean", + "offset": 0, + "safe": false + }, + { + "name": "setMaxBlockSystemFee", + "parameters": [ + { + "name": "value", + "type": "Integer" + } + ], + "returntype": "Boolean", + "offset": 0, + "safe": false + }, + { + "name": "setMaxTransactionsPerBlock", + "parameters": [ + { + "name": "value", + "type": "Integer" + } + ], + "returntype": "Boolean", + "offset": 0, + "safe": false + }, + { + "name": "setStoragePrice", + "parameters": [ + { + "name": "value", + "type": "Integer" + } + ], + "returntype": "Boolean", + "offset": 0, + "safe": false + }, + { + "name": "unblockAccount", + "parameters": [ + { + "name": "account", + "type": "Hash160" + } + ], + "returntype": "Boolean", + "offset": 0, + "safe": false + } + ], + "events": [] + }, + "permissions": [ + { + "contract": "*", + "methods": "*" + } + ], + "trusts": [], + "extra": null + } + }, + { + "id": -6, + "updatecounter": 0, + "hash": "0x597b1471bbce497b7809e2c8f10db67050008b02", + "nef": { + "magic": 860243278, + "compiler": "neo-core-v3.0", + "source": "", + "tokens": [], + "script": "APpBGvd7Zw==", + "checksum": 3289425910 + }, + "manifest": { + "name": "RoleManagement", + "groups": [], + "features": {}, + "supportedstandards": [], + "abi": { + "methods": [ + { + "name": "designateAsRole", + "parameters": [ + { + "name": "role", + "type": "Integer" + }, + { + "name": "nodes", + "type": "Array" + } + ], + "returntype": "Void", + "offset": 0, + "safe": false + }, + { + "name": "getDesignatedByRole", + "parameters": [ + { + "name": "role", + "type": "Integer" + }, + { + "name": "index", + "type": "Integer" + } + ], + "returntype": "Array", + "offset": 0, + "safe": true + } + ], + "events": [] + }, + "permissions": [ + { + "contract": "*", + "methods": "*" + } + ], + "trusts": [], + "extra": null + } + }, + { + "id": -7, + "updatecounter": 0, + "hash": "0x8dc0e742cbdfdeda51ff8a8b78d46829144c80ee", + "nef": { + "magic": 860243278, + "compiler": "neo-core-v3.0", + "source": "", + "tokens": [], + "script": "APlBGvd7Zw==", + "checksum": 3902663397 + }, + "manifest": { + "name": "OracleContract", + "groups": [], + "features": {}, + "supportedstandards": [], + "abi": { + "methods": [ + { + "name": "finish", + "parameters": [], + "returntype": "Void", + "offset": 0, + "safe": false + }, + { + "name": "request", + "parameters": [ + { + "name": "url", + "type": "String" + }, + { + "name": "filter", + "type": "String" + }, + { + "name": "callback", + "type": "String" + }, + { + "name": "userData", + "type": "Any" + }, + { + "name": "gasForResponse", + "type": "Integer" + } + ], + "returntype": "Void", + "offset": 0, + "safe": false + }, + { + "name": "verify", + "parameters": [], + "returntype": "Boolean", + "offset": 0, + "safe": true + } + ], + "events": [ + { + "name": "OracleRequest", + "parameters": [ + { + "name": "Id", + "type": "Integer" + }, + { + "name": "RequestContract", + "type": "Hash160" + }, + { + "name": "Url", + "type": "String" + }, + { + "name": "Filter", + "type": "String" + } + ] + }, + { + "name": "OracleResponse", + "parameters": [ + { + "name": "Id", + "type": "Integer" + }, + { + "name": "OriginalTx", + "type": "Hash256" + } + ] + } + ] + }, + "permissions": [ + { + "contract": "*", + "methods": "*" + } + ], + "trusts": [], + "extra": null + } + }, + { + "id": -8, + "updatecounter": 0, + "hash": "0xa2b524b68dfe43a9d56af84f443c6b9843b8028c", + "nef": { + "magic": 860243278, + "compiler": "neo-core-v3.0", + "source": "", + "tokens": [], + "script": "APhBGvd7Zw==", + "checksum": 3740064217 + }, + "manifest": { + "name": "NameService", + "groups": [], + "features": {}, + "supportedstandards": [], + "abi": { + "methods": [ + { + "name": "addRoot", + "parameters": [ + { + "name": "root", + "type": "String" + } + ], + "returntype": "Void", + "offset": 0, + "safe": false + }, + { + "name": "balanceOf", + "parameters": [ + { + "name": "owner", + "type": "Hash160" + } + ], + "returntype": "Integer", + "offset": 0, + "safe": true + }, + { + "name": "decimals", + "parameters": [], + "returntype": "Integer", + "offset": 0, + "safe": true + }, + { + "name": "deleteRecord", + "parameters": [ + { + "name": "name", + "type": "String" + }, + { + "name": "type", + "type": "Integer" + } + ], + "returntype": "Void", + "offset": 0, + "safe": false + }, + { + "name": "getPrice", + "parameters": [], + "returntype": "Integer", + "offset": 0, + "safe": true + }, + { + "name": "getRecord", + "parameters": [ + { + "name": "name", + "type": "String" + }, + { + "name": "type", + "type": "Integer" + } + ], + "returntype": "String", + "offset": 0, + "safe": true + }, + { + "name": "isAvailable", + "parameters": [ + { + "name": "name", + "type": "String" + } + ], + "returntype": "Boolean", + "offset": 0, + "safe": true + }, + { + "name": "ownerOf", + "parameters": [ + { + "name": "tokenId", + "type": "ByteArray" + } + ], + "returntype": "Hash160", + "offset": 0, + "safe": true + }, + { + "name": "properties", + "parameters": [ + { + "name": "tokenId", + "type": "ByteArray" + } + ], + "returntype": "Map", + "offset": 0, + "safe": true + }, + { + "name": "register", + "parameters": [ + { + "name": "name", + "type": "String" + }, + { + "name": "owner", + "type": "Hash160" + } + ], + "returntype": "Boolean", + "offset": 0, + "safe": false + }, + { + "name": "renew", + "parameters": [ + { + "name": "name", + "type": "String" + } + ], + "returntype": "Integer", + "offset": 0, + "safe": false + }, + { + "name": "resolve", + "parameters": [ + { + "name": "name", + "type": "String" + }, + { + "name": "type", + "type": "Integer" + } + ], + "returntype": "String", + "offset": 0, + "safe": true + }, + { + "name": "setAdmin", + "parameters": [ + { + "name": "name", + "type": "String" + }, + { + "name": "admin", + "type": "Hash160" + } + ], + "returntype": "Void", + "offset": 0, + "safe": false + }, + { + "name": "setPrice", + "parameters": [ + { + "name": "price", + "type": "Integer" + } + ], + "returntype": "Void", + "offset": 0, + "safe": false + }, + { + "name": "setRecord", + "parameters": [ + { + "name": "name", + "type": "String" + }, + { + "name": "type", + "type": "Integer" + }, + { + "name": "data", + "type": "String" + } + ], + "returntype": "Void", + "offset": 0, + "safe": false + }, + { + "name": "symbol", + "parameters": [], + "returntype": "String", + "offset": 0, + "safe": true + }, + { + "name": "tokensOf", + "parameters": [ + { + "name": "owner", + "type": "Hash160" + } + ], + "returntype": "Any", + "offset": 0, + "safe": true + }, + { + "name": "totalSupply", + "parameters": [], + "returntype": "Integer", + "offset": 0, + "safe": true + }, + { + "name": "transfer", + "parameters": [ + { + "name": "to", + "type": "Hash160" + }, + { + "name": "tokenId", + "type": "ByteArray" + } + ], + "returntype": "Boolean", + "offset": 0, + "safe": false + } + ], + "events": [ + { + "name": "Transfer", + "parameters": [ + { + "name": "from", + "type": "Hash160" + }, + { + "name": "to", + "type": "Hash160" + }, + { + "name": "amount", + "type": "Integer" + }, + { + "name": "tokenId", + "type": "ByteArray" + } + ] + } + ] + }, + "permissions": [ + { + "contract": "*", + "methods": "*" + } + ], + "trusts": [], + "extra": null + } + } + ] + } + }, + { + "Name": "getrawmempoolasync", + "Request": { + "jsonrpc": "2.0", + "method": "getrawmempool", + "params": [], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": [ "0x9786cce0dddb524c40ddbdd5e31a41ed1f6b5c8a683c122f627ca4a007a7cf4e", "0xb488ad25eb474f89d5ca3f985cc047ca96bc7373a6d3da8c0f192722896c1cd7" ] + } + }, + { + "Name": "getrawmempoolbothasync", + "Request": { + "jsonrpc": "2.0", + "method": "getrawmempool", + "params": [ true ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": { + "height": 2846, + "verified": [ "0x9786cce0dddb524c40ddbdd5e31a41ed1f6b5c8a683c122f627ca4a007a7cf4e" ], + "unverified": [ "0xb488ad25eb474f89d5ca3f985cc047ca96bc7373a6d3da8c0f192722896c1cd7" ] + } + } + }, + { + "Name": "getrawtransactionhexasync", + "Request": { + "jsonrpc": "2.0", + "method": "getrawtransaction", + "params": [ "0x0cfd49c48306f9027dc71585589b6456bcc53567c359fb7858eabca482186b78" ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": "004cdec1396925aa554712439a9c613ba114efa3fac23ddbca00e1f50500000000466a130000000000311d2000005d030010a5d4e80000000c149903b0c3d292988febe5f306a02f654ea2eb16290c146925aa554712439a9c613ba114efa3fac23ddbca13c00c087472616e736665720c143b7d3711c6f0ccf9b1dca903d1bfa1d896f1238c41627d5b523901420c401f85b40d7fa12164aa1d4d18b06ca470f2c89572dc5b901ab1667faebb587cf536454b98a09018adac72376c5e7c5d164535155b763564347aa47b69aa01b3cc290c2103aa052fbcb8e5b33a4eefd662536f8684641f04109f1d5e69cdda6f084890286a0b410a906ad4" + } + }, + { + "Name": "getrawtransactionasync", + "Request": { + "jsonrpc": "2.0", + "method": "getrawtransaction", + "params": [ "0xc97cc05c790a844f05f582d80952c4ced3894cbe6d96a74f3e5589d741372dd4", true ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": { + "hash": "0x99eaba3e230702d428ce6bfb4a2dceba6d4cd441f9ca1b7bfe2a418926ae40ab", + "size": 252, + "version": 0, + "nonce": 969006668, + "sender": "NikvsLcNP1jWhrFPrfS3n4spEASgdNYTG2", + "sysfee": "100000000", + "netfee": "1272390", + "validuntilblock": 2104625, + "signers": [ + { + "account": "0xe19de267a37a71734478f512b3e92c79fc3695fa", + "scopes": "CalledByEntry" + } + ], + "attributes": [], + "script": "AwAQpdToAAAADBSZA7DD0pKYj\u002Bvl8wagL2VOousWKQwUaSWqVUcSQ5qcYTuhFO\u002Bj\u002BsI928oTwAwIdHJhbnNmZXIMFDt9NxHG8Mz5sdypA9G/odiW8SOMQWJ9W1I5", + "witnesses": [ + { + "invocation": "DEAfhbQNf6EhZKodTRiwbKRw8siVctxbkBqxZn\u002Buu1h89TZFS5igkBitrHI3bF58XRZFNRVbdjVkNHqke2mqAbPM", + "verification": "DCEDqgUvvLjlszpO79ZiU2\u002BGhGQfBBCfHV5pzdpvCEiQKGoLQQqQatQ=" + } + ], + "blockhash": "0xc1ed259e394c9cd93c1e0eb1e0f144c0d10da64861a24c0084f0d98270b698f1", + "confirmations": 643, + "blocktime": 1579417249620, + "vmstate": "HALT" + } + } + }, + { + "Name": "getstorageasync", + "Request": { + "jsonrpc": "2.0", + "method": "getstorage", + "params": [ "0x8c23f196d8a1bfd103a9dcb1f9ccf0c611377d3b", "146925aa554712439a9c613ba114efa3fac23ddbca" ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": "410121064c5d11a2a700" + } + }, + { + "Name": "getstorageasync", + "Request": { + "jsonrpc": "2.0", + "method": "getstorage", + "params": [ -2, "146925aa554712439a9c613ba114efa3fac23ddbca" ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": "410121064c5d11a2a700" + } + }, + { + "Name": "gettransactionheightasync", + "Request": { + "jsonrpc": "2.0", + "method": "gettransactionheight", + "params": [ "0x0cfd49c48306f9027dc71585589b6456bcc53567c359fb7858eabca482186b78" ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": 2226 + } + }, + { + "Name": "getnextblockvalidatorsasync", + "Request": { + "jsonrpc": "2.0", + "method": "getnextblockvalidators", + "params": [], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": [ + { + "publickey": "03aa052fbcb8e5b33a4eefd662536f8684641f04109f1d5e69cdda6f084890286a", + "votes": "0" + } + ] + } + }, + + + { + "Name": "getconnectioncountasync", + "Request": { + "jsonrpc": "2.0", + "method": "getconnectioncount", + "params": [], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": 0 + } + }, + { + "Name": "getpeersasync", + "Request": { + "jsonrpc": "2.0", + "method": "getpeers", + "params": [], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": { + "unconnected": [ + { + "address": "::ffff:70.73.16.236", + "port": 10333 + } + ], + "bad": [], + "connected": [ + { + "address": "::ffff:139.219.106.33", + "port": 10333 + }, + { + "address": "::ffff:47.88.53.224", + "port": 10333 + } + ] + } + } + }, + { + "Name": "getversionasync", + "Request": { + "jsonrpc": "2.0", + "method": "getversion", + "params": [], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": { + "network": 0, + "tcpport": 20333, + "nonce": 592651621, + "useragent": "/Neo:3.0.0-rc1/", + "protocol": { + "network": 0, + "validatorscount": 0, + "msperblock": 15000, + "maxvaliduntilblockincrement": 1, + "maxtraceableblocks": 1, + "addressversion": 0, + "maxtransactionsperblock": 0, + "memorypoolmaxtransactions": 0, + "initialgasdistribution": 0, + "hardforks": [ + { + "name": "Aspidochelone", + "blockheight": 0 + } + ] + } + } + } + }, + { + "Name": "sendrawtransactionasync", + "Request": { + "jsonrpc": "2.0", + "method": "sendrawtransaction", + "params": [ "ANIHn05ujtUAAAAAACYcEwAAAAAAQkEAAAEKo4e1Ppa3mJpjFDGgVt0fQKBC9gEAXQMAyBeoBAAAAAwUzViuz9M1vh6z0xHh3IAJY9/XLZ8MFAqjh7U+lreYmmMUMaBW3R9AoEL2E8AMCHRyYW5zZmVyDBSlB7dGdv/td+dUuG7NmQnwus08ukFifVtSOAFCDEDh8zgTrGUXyzVX60wBCMyajNRfzFRiEPAe8CgGQ10bA2C3fnVz68Gw+Amgn5gmvuNfYKgWQ/W68Km1bYUPlnEYKQwhA86j4vgfGvk1ItKe3k8kofC+3q1ykzkdM4gPVHXZeHjJC0GVRA14" ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": { + "hash": "0x4d47255ff5564aaa73855068c3574f8f28e2bb18c7fb7256e58ae51fab44c9bc" + } + } + }, + { + "Name": "submitblockasync", + "Request": { + "jsonrpc": "2.0", + "method": "submitblock", + "params": [ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAI+JfEVZZd6cjX2qJADFSuzRR40IzeV3K1zS9Q2wqetqI6hnvVQEAAAAAAAD6lrDvowCyjK9dBALCmE1fvMuahQEAARECAB2sK3wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHKYeUuiB1BN05kD4Gc0RjMFTshpwAABUESPn/oAQABEQ==" ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": { + "hash": "0xa11c9d14748f967178fe22fdcfb829354ae6ccb86824675e147cb128f16d8171" + } + } + }, + + + { + "Name": "invokefunctionasync", + "Request": { + "jsonrpc": "2.0", + "method": "invokefunction", + "params": [ + "0x8c23f196d8a1bfd103a9dcb1f9ccf0c611377d3b", + "balanceOf", + [ + { + "type": "Hash160", + "value": "91b83e96f2a7c4fdf0c1688441ec61986c7cae26" + } + ] + ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": { + "script": "0c1426ae7c6c9861ec418468c1f0fdc4a7f2963eb89111c00c0962616c616e63654f660c143b7d3711c6f0ccf9b1dca903d1bfa1d896f1238c41627d5b52", + "state": "HALT", + "gasconsumed": "2007570", + "stack": [ + { + "type": "Integer", + "value": "0" + } + ], + "tx": "00d1eb88136925aa554712439a9c613ba114efa3fac23ddbca00e1f50500000000269f1200000000004520200000003e0c1426ae7c6c9861ec418468c1f0fdc4a7f2963eb89111c00c0962616c616e63654f660c143b7d3711c6f0ccf9b1dca903d1bfa1d896f1238c41627d5b5201420c40794c91299bba340ea2505c777d15ca898f75bcce686461066a2b8018cc1de114a122dcdbc77b447ac7db5fb1584f1533b164fbc8f30ddf5bd6acf016a125e983290c2103aa052fbcb8e5b33a4eefd662536f8684641f04109f1d5e69cdda6f084890286a0b410a906ad4" + } + } + }, + { + "Name": "invokescriptasync", + "Request": { + "jsonrpc": "2.0", + "method": "invokescript", + "params": [ "EMMMBG5hbWUMFDt9NxHG8Mz5sdypA9G/odiW8SOMQWJ9W1IQwwwGc3ltYm9sDBQ7fTcRxvDM+bHcqQPRv6HYlvEjjEFifVtSEMMMCGRlY2ltYWxzDBQ7fTcRxvDM+bHcqQPRv6HYlvEjjEFifVtSEMMMC3RvdGFsU3VwcGx5DBQ7fTcRxvDM+bHcqQPRv6HYlvEjjEFifVtS" ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": { + "script": "EMMMBG5hbWUMFDt9NxHG8Mz5sdypA9G/odiW8SOMQWJ9W1IQwwwGc3ltYm9sDBQ7fTcRxvDM+bHcqQPRv6HYlvEjjEFifVtSEMMMCGRlY2ltYWxzDBQ7fTcRxvDM+bHcqQPRv6HYlvEjjEFifVtSEMMMC3RvdGFsU3VwcGx5DBQ7fTcRxvDM+bHcqQPRv6HYlvEjjEFifVtS", + "state": "HALT", + "gasconsumed": "5061560", + "stack": [ + { + "type": "Array", + "value": [ + { + "type": "ByteString", + "value": "dGVzdA==" + }, + { + "type": "InteropInterface" + }, + { + "type": "Integer", + "value": "1" + }, + { + "type": "Buffer", + "value": "CAwiNQw=" + }, + { + "type": "Array", + "value": [ + { + "type": "ByteString", + "value": "YmI=" + }, + { + "type": "ByteString", + "value": "Y2Mw" + } + ] + }, + { + "type": "Map", + "value": [ + { + "key": { + "type": "Integer", + "value": "2" + }, + "value": { + "type": "Integer", + "value": "12" + } + }, + { + "key": { + "type": "Integer", + "value": "0" + }, + "value": { + "type": "Integer", + "value": "24" + } + } + ] + } + ] + } + ], + "tx": "00769d16556925aa554712439a9c613ba114efa3fac23ddbca00e1f505000000009e021400000000005620200000009910c30c046e616d650c143b7d3711c6f0ccf9b1dca903d1bfa1d896f1238c41627d5b5210c30c0673796d626f6c0c143b7d3711c6f0ccf9b1dca903d1bfa1d896f1238c41627d5b5210c30c08646563696d616c730c143b7d3711c6f0ccf9b1dca903d1bfa1d896f1238c41627d5b5210c30c0b746f74616c537570706c790c143b7d3711c6f0ccf9b1dca903d1bfa1d896f1238c41627d5b5201420c40c848d0fcbf5e6a820508242ea8b7ccbeed3caefeed5db570537279c2154f7cfd8b0d8f477f37f4e6ca912935b732684d57c455dff7aa525ad4ab000931f22208290c2103aa052fbcb8e5b33a4eefd662536f8684641f04109f1d5e69cdda6f084890286a0b410a906ad4" + } + } + }, + + { + "Name": "getunclaimedgasasync", + "Request": { + "jsonrpc": "2.0", + "method": "getunclaimedgas", + "params": [ "NPvKVTGZapmFWABLsyvfreuqn73jCjJtN1" ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": { + "unclaimed": "735870007400", + "address": "NPvKVTGZapmFWABLsyvfreuqn73jCjJtN1" + } + } + }, + + { + "Name": "listpluginsasync", + "Request": { + "jsonrpc": "2.0", + "method": "listplugins", + "params": [], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": [ + { + "name": "ApplicationLogs", + "version": "3.0.0.0", + "interfaces": [ + "IPersistencePlugin" + ] + }, + { + "name": "LevelDBStore", + "version": "3.0.0.0", + "interfaces": [ + "IStoragePlugin" + ] + }, + { + "name": "RpcNep17Tracker", + "version": "3.0.0.0", + "interfaces": [ + "IPersistencePlugin" + ] + }, + { + "name": "RpcServer", + "version": "3.0.0.0", + "interfaces": [] + } + ] + } + }, + { + "Name": "validateaddressasync", + "Request": { + "jsonrpc": "2.0", + "method": "validateaddress", + "params": [ "NZs2zXSPuuv9ZF6TDGSWT1RBmE8rfGj7UW" ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": { + "address": "NZs2zXSPuuv9ZF6TDGSWT1RBmE8rfGj7UW", + "isvalid": true + } + } + }, + + + { + "Name": "closewalletasync", + "Request": { + "jsonrpc": "2.0", + "method": "closewallet", + "params": [], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": true + } + }, + { + "Name": "dumpprivkeyasync", + "Request": { + "jsonrpc": "2.0", + "method": "dumpprivkey", + "params": [ "NVVwFw6XyhtRCFQ8SpUTMdPyYt4Vd9A1XQ" ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": "KyoYyZpoccbR6KZ25eLzhMTUxREwCpJzDsnuodGTKXSG8fDW9t7x" + } + }, + { + "Name": "invokescriptasync", + "Request": { + "jsonrpc": "2.0", + "id": 1, + "method": "invokescript", + "params": [ + "EMAfDAhkZWNpbWFscwwU++3+LtIiZZK2SMTal7nJzV3BpqZBYn1bUg==" + ] + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": { + "script": "HxDDDAhkZWNpbWFscwwU++3+LtIiZZK2SMTal7nJzV3BpqZB7vQM2w==", + "state": "HALT", + "gasconsumed": "999180", + "exception": null, + "stack": [ + { + "type": "Integer", + "value": "8" + } + ] + } + } + }, + { + "Name": "invokescriptasync", + "Request": { + "jsonrpc": "2.0", + "id": 1, + "method": "invokescript", + "params": [ + "wh8MCGRlY2ltYWxzDBTPduKL0AYsSkeO41VhARMZ88+k0kFifVtS" + ] + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": { + "script": "EBEfDAhkZWNpbWFscwwU++3+LtIiZZK2SMTal7nJzV3BpqZBYn1bUg==", + "state": "HALT", + "gasconsumed": "999180", + "exception": null, + "stack": [ + { + "type": "Integer", + "value": "8" + } + ] + } + } + }, + { + "Name": "getnewaddressasync", + "Request": { + "jsonrpc": "2.0", + "method": "getnewaddress", + "params": [], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": "NXpCs9kcDkPvfyAobNYmFg8yfRZaDopDbf" + } + }, + { + "Name": "getwalletbalanceasync", + "Request": { + "jsonrpc": "2.0", + "method": "getwalletbalance", + "params": [ "0xd2a4cff31913016155e38e474a2c06d08be276cf" ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": { + "balance": "3001101329992600" + } + } + }, + { + "Name": "getwalletunclaimedgasasync", + "Request": { + "jsonrpc": "2.0", + "method": "getwalletunclaimedgas", + "params": [], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": "735870007400" + } + }, + { + "Name": "importprivkeyasync", + "Request": { + "jsonrpc": "2.0", + "method": "importprivkey", + "params": [ "KyoYyZpoccbR6KZ25eLzhMTUxREwCpJzDsnuodGTKXSG8fDW9t7x" ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": { + "address": "NVVwFw6XyhtRCFQ8SpUTMdPyYt4Vd9A1XQ", + "haskey": true, + "label": null, + "watchonly": false + } + } + }, + { + "Name": "listaddressasync", + "Request": { + "jsonrpc": "2.0", + "method": "listaddress", + "params": [], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": [ + { + "address": "NVVwFw6XyhtRCFQ8SpUTMdPyYt4Vd9A1XQ", + "haskey": true, + "label": null, + "watchonly": false + }, + { + "address": "NZs2zXSPuuv9ZF6TDGSWT1RBmE8rfGj7UW", + "haskey": true, + "label": null, + "watchonly": false + } + ] + } + }, + { + "Name": "openwalletasync", + "Request": { + "jsonrpc": "2.0", + "method": "openwallet", + "params": [ "D:\\temp\\3.json", "1111" ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": true + } + }, + { + "Name": "sendfromasync", + "Request": { + "jsonrpc": "2.0", + "method": "sendfrom", + "params": [ "0x8c23f196d8a1bfd103a9dcb1f9ccf0c611377d3b", "NVVwFw6XyhtRCFQ8SpUTMdPyYt4Vd9A1XQ", "NZs2zXSPuuv9ZF6TDGSWT1RBmE8rfGj7UW", "100.123" ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": { + "hash": "0x035facc3be1fc57da1690e3d2f8214f449d368437d8557ffabb2d408caf9ad76", + "size": 272, + "version": 0, + "nonce": 1553700339, + "sender": "NVVwFw6XyhtRCFQ8SpUTMdPyYt4Vd9A1XQ", + "sysfee": "100000000", + "netfee": "1272390", + "validuntilblock": 2105487, + "attributes": [], + "cosigners": [ + { + "account": "0xcadb3dc2faa3ef14a13b619c9a43124755aa2569", + "scopes": "CalledByEntry" + } + ], + "script": "A+CSx1QCAAAADBSZA7DD0pKYj+vl8wagL2VOousWKQwUaSWqVUcSQ5qcYTuhFO+j+sI928oTwAwIdHJhbnNmZXIMFDt9NxHG8Mz5sdypA9G/odiW8SOMQWJ9W1I5", + "witnesses": [ + { + "invocation": "DEDOA/QF5jYT2TCl9T94fFwAncuBhVhciISaq4fZ3WqGarEoT/0iDo3RIwGjfRW0mm/SV3nAVGEQeZInLqKQ98HX", + "verification": "DCEDqgUvvLjlszpO79ZiU2+GhGQfBBCfHV5pzdpvCEiQKGoLQQqQatQ=" + } + ] + } + } + }, + { + "Name": "sendmanyasync", + "Request": { + "jsonrpc": "2.0", + "method": "sendmany", + "params": [ + "NVVwFw6XyhtRCFQ8SpUTMdPyYt4Vd9A1XQ", + [ + { + "asset": "0x9bde8f209c88dd0e7ca3bf0af0f476cdd8207789", + "value": "10", + "address": "NVVwFw6XyhtRCFQ8SpUTMdPyYt4Vd9A1XQ" + }, + { + "asset": "0x8c23f196d8a1bfd103a9dcb1f9ccf0c611377d3b", + "value": "1.2345", + "address": "NZs2zXSPuuv9ZF6TDGSWT1RBmE8rfGj7UW" + } + ] + ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": { + "hash": "0x542e64a9048bbe1ee565b840c41ccf9b5a1ef11f52e5a6858a523938a20c53ec", + "size": 483, + "version": 0, + "nonce": 34429660, + "sender": "NUMK37TV9yYKbJr1Gufh74nZiM623eBLqX", + "sysfee": "100000000", + "netfee": "2483780", + "validuntilblock": 2105494, + "attributes": [], + "cosigners": [ + { + "account": "0x36d6200fb4c9737c7b552d2b5530ab43605c5869", + "scopes": "CalledByEntry" + }, + { + "account": "0x9a55ca1006e2c359bbc8b9b0de6458abdff98b5c", + "scopes": "CalledByEntry" + } + ], + "script": "GgwUaSWqVUcSQ5qcYTuhFO+j+sI928oMFGlYXGBDqzBVKy1Ve3xzybQPINY2E8AMCHRyYW5zZmVyDBSJdyDYzXb08Aq/o3wO3YicII/em0FifVtSOQKQslsHDBSZA7DD0pKYj+vl8wagL2VOousWKQwUXIv536tYZN6wuci7WcPiBhDKVZoTwAwIdHJhbnNmZXIMFDt9NxHG8Mz5sdypA9G/odiW8SOMQWJ9W1I5", + "witnesses": [ + { + "invocation": "DECOdTEWg1WkuHN0GNV67kwxeuKADyC6TO59vTaU5dK6K1BGt8+EM6L3TdMga4qB2J+Meez8eYwZkSSRubkuvfr9", + "verification": "DCECeiS9CyBqFJwNKzonOs/yzajOraFep4IqFJVxBe6TesULQQqQatQ=" + }, + { + "invocation": "DEB1Laj6lvjoBJLTgE/RdvbJiXOmaKp6eNWDJt+p8kxnW6jbeKoaBRZWfUflqrKV7mZEE2JHA5MxrL5TkRIvsL5K", + "verification": "DCECkXL4gxd936eGEDt3KWfIuAsBsQcfyyBUcS8ggF6lZnwLQQqQatQ=" + } + ] + } + } + }, + { + "Name": "sendtoaddressasync", + "Request": { + "jsonrpc": "2.0", + "method": "sendtoaddress", + "params": [ "0x8c23f196d8a1bfd103a9dcb1f9ccf0c611377d3b", "NVVwFw6XyhtRCFQ8SpUTMdPyYt4Vd9A1XQ", "100.123" ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": { + "hash": "0xee5fc3f57d9f9bc9695c88ecc504444aab622b1680b1cb0848d5b6e39e7fd118", + "size": 381, + "version": 0, + "nonce": 330056065, + "sender": "NUMK37TV9yYKbJr1Gufh74nZiM623eBLqX", + "sysfee": "100000000", + "netfee": "2381780", + "validuntilblock": 2105500, + "attributes": [], + "cosigners": [ + { + "account": "0xcadb3dc2faa3ef14a13b619c9a43124755aa2569", + "scopes": "CalledByEntry" + } + ], + "script": "A+CSx1QCAAAADBRpJapVRxJDmpxhO6EU76P6wj3bygwUaSWqVUcSQ5qcYTuhFO+j+sI928oTwAwIdHJhbnNmZXIMFDt9NxHG8Mz5sdypA9G/odiW8SOMQWJ9W1I5", + "witnesses": [ + { + "invocation": "DECruSKmQKs0Y2cxplKROjPx8HKiyiYrrPn7zaV9zwHPumLzFc8DvgIo2JxmTnJsORyygN/su8mTmSLLb3PesBvY", + "verification": "DCECkXL4gxd936eGEDt3KWfIuAsBsQcfyyBUcS8ggF6lZnwLQQqQatQ=" + }, + { + "invocation": "DECS5npCs5PwsPUAQ01KyHyCev27dt3kDdT1Vi0K8PwnEoSlxYTOGGQCAwaiNEXSyBdBmT6unhZydmFnkezD7qzW", + "verification": "DCEDqgUvvLjlszpO79ZiU2+GhGQfBBCfHV5pzdpvCEiQKGoLQQqQatQ=" + } + ] + } + } + }, + + + { + "Name": "getapplicationlogasync", + "Request": { + "jsonrpc": "2.0", + "method": "getapplicationlog", + "params": [ "0x6ea186fe714b8168ede3b78461db8945c06d867da649852352dbe7cbf1ba3724" ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": { + "blockhash": "0x6ea186fe714b8168ede3b78461db8945c06d867da649852352dbe7cbf1ba3724", + "executions": [ + { + "trigger": "OnPersist", + "vmstate": "HALT", + "gasconsumed": "2031260", + "exception": null, + "stack": [], + "notifications": [ + { + "contract": "0x668e0c1f9d7b70a99dd9e06eadd4c784d641afbc", + "eventname": "Transfer", + "state": { + "type": "Array", + "value": [ + { + "type": "ByteString", + "value": "CqOHtT6Wt5iaYxQxoFbdH0CgQvY=" + }, + { + "type": "Any" + }, + { + "type": "Integer", + "value": "18083410" + } + ] + } + }, + { + "contract": "0x668e0c1f9d7b70a99dd9e06eadd4c784d641afbc", + "eventname": "Transfer", + "state": { + "type": "Array", + "value": [ + { + "type": "Any" + }, + { + "type": "ByteString", + "value": "z6LDQN4w1uEMToIZiPSxToNRPog=" + }, + { + "type": "Integer", + "value": "1252390" + } + ] + } + } + ] + }, + { + "trigger": "PostPersist", + "vmstate": "HALT", + "gasconsumed": "2031260", + "exception": null, + "stack": [], + "notifications": [ + { + "contract": "0x668e0c1f9d7b70a99dd9e06eadd4c784d641afbc", + "eventname": "Transfer", + "state": { + "type": "Array", + "value": [ + { + "type": "Any" + }, + { + "type": "ByteString", + "value": "z6LDQN4w1uEMToIZiPSxToNRPog=" + }, + { + "type": "Integer", + "value": "50000000" + } + ] + } + } + ] + } + ] + } + } + }, + { + "Name": "getapplicationlogasync_triggertype", + "Request": { + "jsonrpc": "2.0", + "method": "getapplicationlog", + "params": [ "0x6ea186fe714b8168ede3b78461db8945c06d867da649852352dbe7cbf1ba3724", "OnPersist" ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": { + "blockhash": "0x6ea186fe714b8168ede3b78461db8945c06d867da649852352dbe7cbf1ba3724", + "executions": [ + { + "trigger": "OnPersist", + "vmstate": "HALT", + "gasconsumed": "2031260", + "exception": null, + "stack": [], + "notifications": [ + { + "contract": "0x668e0c1f9d7b70a99dd9e06eadd4c784d641afbc", + "eventname": "Transfer", + "state": { + "type": "Array", + "value": [ + { + "type": "ByteString", + "value": "CqOHtT6Wt5iaYxQxoFbdH0CgQvY=" + }, + { + "type": "Any" + }, + { + "type": "Integer", + "value": "18083410" + } + ] + } + }, + { + "contract": "0x668e0c1f9d7b70a99dd9e06eadd4c784d641afbc", + "eventname": "Transfer", + "state": { + "type": "Array", + "value": [ + { + "type": "Any" + }, + { + "type": "ByteString", + "value": "z6LDQN4w1uEMToIZiPSxToNRPog=" + }, + { + "type": "Integer", + "value": "1252390" + } + ] + } + } + ] + } + ] + } + } + }, + { + "Name": "getnep17transfersasync", + "Request": { + "jsonrpc": "2.0", + "method": "getnep17transfers", + "params": [ "NVVwFw6XyhtRCFQ8SpUTMdPyYt4Vd9A1XQ", 0, 1868595301000 ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": { + "sent": [ + { + "timestamp": 1579250114541, + "assethash": "0x8c23f196d8a1bfd103a9dcb1f9ccf0c611377d3b", + "transferaddress": "NVVwFw6XyhtRCFQ8SpUTMdPyYt4Vd9A1XQ", + "amount": "1000000000", + "blockindex": 603, + "transfernotifyindex": 0, + "txhash": "0x5e177b8d1dc33e9103c0cfd42f6dbf4efbe43029e2d6a18ea5ba0cb8437056b3" + }, + { + "timestamp": 1579406581635, + "assethash": "0x8c23f196d8a1bfd103a9dcb1f9ccf0c611377d3b", + "transferaddress": "NUMK37TV9yYKbJr1Gufh74nZiM623eBLqX", + "amount": "1000000000", + "blockindex": 1525, + "transfernotifyindex": 0, + "txhash": "0xc9c618b48972b240e0058d97b8d79b807ad51015418c84012765298526aeb77d" + } + ], + "received": [ + { + "timestamp": 1579250114541, + "assethash": "0x8c23f196d8a1bfd103a9dcb1f9ccf0c611377d3b", + "transferaddress": "NVVwFw6XyhtRCFQ8SpUTMdPyYt4Vd9A1XQ", + "amount": "1000000000", + "blockindex": 603, + "transfernotifyindex": 0, + "txhash": "0x5e177b8d1dc33e9103c0cfd42f6dbf4efbe43029e2d6a18ea5ba0cb8437056b3" + } + ], + "address": "NVVwFw6XyhtRCFQ8SpUTMdPyYt4Vd9A1XQ" + } + } + }, + { + "Name": "getnep17transfersasync_with_null_transferaddress", + "Request": { + "jsonrpc": "2.0", + "method": "getnep17transfers", + "params": [ "Ncb7jVsYWBt1q5T5k3ZTP8bn5eK4DuanLd", 0, 1868595301000 ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": { + "sent": [ + { + "timestamp": 1579250114541, + "assethash": "0x8c23f196d8a1bfd103a9dcb1f9ccf0c611377d3b", + "transferaddress": null, + "amount": "1000000000", + "blockindex": 603, + "transfernotifyindex": 0, + "txhash": "0x5e177b8d1dc33e9103c0cfd42f6dbf4efbe43029e2d6a18ea5ba0cb8437056b3" + }, + { + "timestamp": 1579406581635, + "assethash": "0x8c23f196d8a1bfd103a9dcb1f9ccf0c611377d3b", + "transferaddress": "Ncb7jVsYWBt1q5T5k3ZTP8bn5eK4DuanLd", + "amount": "1000000000", + "blockindex": 1525, + "transfernotifyindex": 0, + "txhash": "0xc9c618b48972b240e0058d97b8d79b807ad51015418c84012765298526aeb77d" + } + ], + "received": [ + { + "timestamp": 1579250114541, + "assethash": "0x8c23f196d8a1bfd103a9dcb1f9ccf0c611377d3b", + "transferaddress": null, + "amount": "1000000000", + "blockindex": 603, + "transfernotifyindex": 0, + "txhash": "0x5e177b8d1dc33e9103c0cfd42f6dbf4efbe43029e2d6a18ea5ba0cb8437056b3" + } + ], + "address": "Ncb7jVsYWBt1q5T5k3ZTP8bn5eK4DuanLd" + } + } + }, + { + "Name": "getnep17balancesasync", + "Request": { + "jsonrpc": "2.0", + "method": "getnep17balances", + "params": [ "NVVwFw6XyhtRCFQ8SpUTMdPyYt4Vd9A1XQ" ], + "id": 1 + }, + "Response": { + "jsonrpc": "2.0", + "id": 1, + "result": { + "balance": [ + { + "assethash": "0x8c23f196d8a1bfd103a9dcb1f9ccf0c611377d3b", + "amount": "719978585420", + "lastupdatedblock": 3101 + }, + { + "assethash": "0x9bde8f209c88dd0e7ca3bf0af0f476cdd8207789", + "amount": "89999810", + "lastupdatedblock": 3096 + } + ], + "address": "NVVwFw6XyhtRCFQ8SpUTMdPyYt4Vd9A1XQ" + } + } + } +] diff --git a/tests/Neo.Network.RPC.Tests/TestUtils.cs b/tests/Neo.Network.RPC.Tests/TestUtils.cs new file mode 100644 index 0000000000..068de3388b --- /dev/null +++ b/tests/Neo.Network.RPC.Tests/TestUtils.cs @@ -0,0 +1,95 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// TestUtils.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.Json; +using Neo.Network.P2P.Payloads; +using Neo.Network.RPC.Models; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace Neo.Network.RPC.Tests +{ + internal static class TestUtils + { + public readonly static List RpcTestCases = ((JArray)JToken.Parse(File.ReadAllText("RpcTestCases.json"))).Select(p => RpcTestCase.FromJson((JObject)p)).ToList(); + + public static Block GetBlock(int txCount) + { + return new Block + { + Header = new Header + { + PrevHash = UInt256.Zero, + MerkleRoot = UInt256.Zero, + NextConsensus = UInt160.Zero, + Witness = new Witness + { + InvocationScript = new byte[0], + VerificationScript = new byte[0] + } + }, + Transactions = Enumerable.Range(0, txCount).Select(p => GetTransaction()).ToArray() + }; + } + + public static Header GetHeader() + { + return GetBlock(0).Header; + } + + public static Transaction GetTransaction() + { + return new Transaction + { + Script = new byte[1], + Signers = new Signer[] { new Signer { Account = UInt160.Zero } }, + Attributes = new TransactionAttribute[0], + Witnesses = new Witness[] + { + new Witness + { + InvocationScript = new byte[0], + VerificationScript = new byte[0] + } + } + }; + } + } + + internal class RpcTestCase + { + public string Name { get; set; } + public RpcRequest Request { get; set; } + public RpcResponse Response { get; set; } + + public JObject ToJson() + { + return new JObject + { + ["Name"] = Name, + ["Request"] = Request.ToJson(), + ["Response"] = Response.ToJson(), + }; + } + + public static RpcTestCase FromJson(JObject json) + { + return new RpcTestCase + { + Name = json["Name"].AsString(), + Request = RpcRequest.FromJson((JObject)json["Request"]), + Response = RpcResponse.FromJson((JObject)json["Response"]), + }; + } + + } +} diff --git a/tests/Neo.Network.RPC.Tests/UT_ContractClient.cs b/tests/Neo.Network.RPC.Tests/UT_ContractClient.cs new file mode 100644 index 0000000000..c3cf226a3e --- /dev/null +++ b/tests/Neo.Network.RPC.Tests/UT_ContractClient.cs @@ -0,0 +1,81 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_ContractClient.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 Moq; +using Neo.SmartContract; +using Neo.SmartContract.Manifest; +using Neo.SmartContract.Native; +using Neo.VM; +using Neo.Wallets; +using System.Threading.Tasks; + +namespace Neo.Network.RPC.Tests +{ + [TestClass] + public class UT_ContractClient + { + Mock rpcClientMock; + KeyPair keyPair1; + UInt160 sender; + + [TestInitialize] + public void TestSetup() + { + keyPair1 = new KeyPair(Wallet.GetPrivateKeyFromWIF("KyXwTh1hB76RRMquSvnxZrJzQx7h9nQP2PCRL38v6VDb5ip3nf1p")); + sender = Contract.CreateSignatureRedeemScript(keyPair1.PublicKey).ToScriptHash(); + rpcClientMock = UT_TransactionManager.MockRpcClient(sender, new byte[0]); + } + + [TestMethod] + public async Task TestInvoke() + { + byte[] testScript = NativeContract.GAS.Hash.MakeScript("balanceOf", UInt160.Zero); + UT_TransactionManager.MockInvokeScript(rpcClientMock, testScript, new ContractParameter { Type = ContractParameterType.ByteArray, Value = "00e057eb481b".HexToBytes() }); + + ContractClient contractClient = new ContractClient(rpcClientMock.Object); + var result = await contractClient.TestInvokeAsync(NativeContract.GAS.Hash, "balanceOf", UInt160.Zero); + + Assert.AreEqual(30000000000000L, (long)result.Stack[0].GetInteger()); + } + + [TestMethod] + public async Task TestDeployContract() + { + byte[] script; + var manifest = new ContractManifest() + { + Permissions = new[] { ContractPermission.DefaultPermission }, + Abi = new ContractAbi() + { + Events = new ContractEventDescriptor[0], + Methods = new ContractMethodDescriptor[0] + }, + Groups = new ContractGroup[0], + Trusts = WildcardContainer.Create(), + SupportedStandards = new string[] { "NEP-10" }, + Extra = null, + }; + using (ScriptBuilder sb = new ScriptBuilder()) + { + sb.EmitDynamicCall(NativeContract.ContractManagement.Hash, "deploy", new byte[1], manifest.ToJson().ToString()); + script = sb.ToArray(); + } + + UT_TransactionManager.MockInvokeScript(rpcClientMock, script, new ContractParameter()); + + ContractClient contractClient = new ContractClient(rpcClientMock.Object); + var result = await contractClient.CreateDeployContractTxAsync(new byte[1], manifest, keyPair1); + + Assert.IsNotNull(result); + } + } +} diff --git a/tests/Neo.Network.RPC.Tests/UT_Nep17API.cs b/tests/Neo.Network.RPC.Tests/UT_Nep17API.cs new file mode 100644 index 0000000000..3bfb4e87ff --- /dev/null +++ b/tests/Neo.Network.RPC.Tests/UT_Nep17API.cs @@ -0,0 +1,168 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_Nep17API.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 Moq; +using Neo.Json; +using Neo.SmartContract; +using Neo.SmartContract.Native; +using Neo.VM; +using Neo.Wallets; +using System.Linq; +using System.Numerics; +using System.Threading.Tasks; +using static Neo.Helper; + +namespace Neo.Network.RPC.Tests +{ + [TestClass] + public class UT_Nep17API + { + Mock rpcClientMock; + KeyPair keyPair1; + UInt160 sender; + Nep17API nep17API; + + [TestInitialize] + public void TestSetup() + { + keyPair1 = new KeyPair(Wallet.GetPrivateKeyFromWIF("KyXwTh1hB76RRMquSvnxZrJzQx7h9nQP2PCRL38v6VDb5ip3nf1p")); + sender = Contract.CreateSignatureRedeemScript(keyPair1.PublicKey).ToScriptHash(); + rpcClientMock = UT_TransactionManager.MockRpcClient(sender, new byte[0]); + nep17API = new Nep17API(rpcClientMock.Object); + } + + [TestMethod] + public async Task TestBalanceOf() + { + byte[] testScript = NativeContract.GAS.Hash.MakeScript("balanceOf", UInt160.Zero); + UT_TransactionManager.MockInvokeScript(rpcClientMock, testScript, new ContractParameter { Type = ContractParameterType.Integer, Value = new BigInteger(10000) }); + + var balance = await nep17API.BalanceOfAsync(NativeContract.GAS.Hash, UInt160.Zero); + Assert.AreEqual(10000, (int)balance); + } + + [TestMethod] + public async Task TestGetSymbol() + { + byte[] testScript = NativeContract.GAS.Hash.MakeScript("symbol"); + UT_TransactionManager.MockInvokeScript(rpcClientMock, testScript, new ContractParameter { Type = ContractParameterType.String, Value = NativeContract.GAS.Symbol }); + + var result = await nep17API.SymbolAsync(NativeContract.GAS.Hash); + Assert.AreEqual(NativeContract.GAS.Symbol, result); + } + + [TestMethod] + public async Task TestGetDecimals() + { + byte[] testScript = NativeContract.GAS.Hash.MakeScript("decimals"); + UT_TransactionManager.MockInvokeScript(rpcClientMock, testScript, new ContractParameter { Type = ContractParameterType.Integer, Value = new BigInteger(NativeContract.GAS.Decimals) }); + + var result = await nep17API.DecimalsAsync(NativeContract.GAS.Hash); + Assert.AreEqual(NativeContract.GAS.Decimals, result); + } + + [TestMethod] + public async Task TestGetTotalSupply() + { + byte[] testScript = NativeContract.GAS.Hash.MakeScript("totalSupply"); + UT_TransactionManager.MockInvokeScript(rpcClientMock, testScript, new ContractParameter { Type = ContractParameterType.Integer, Value = new BigInteger(1_00000000) }); + + var result = await nep17API.TotalSupplyAsync(NativeContract.GAS.Hash); + Assert.AreEqual(1_00000000, (int)result); + } + + [TestMethod] + public async Task TestGetTokenInfo() + { + UInt160 scriptHash = NativeContract.GAS.Hash; + byte[] testScript = Concat( + 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")); + 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) }, + new ContractParameter { Type = ContractParameterType.Integer, Value = new BigInteger(1_00000000) }); + + var tests = TestUtils.RpcTestCases.Where(p => p.Name == "getcontractstateasync"); + var haveGasTokenUT = false; + var haveNeoTokenUT = false; + foreach (var test in tests) + { + rpcClientMock.Setup(p => p.RpcSendAsync("getcontractstate", It.Is(u => true))) + .ReturnsAsync(test.Response.Result) + .Verifiable(); + if (test.Request.Params[0].AsString() == NativeContract.GAS.Hash.ToString() || test.Request.Params[0].AsString().Equals(NativeContract.GAS.Name, System.StringComparison.OrdinalIgnoreCase)) + { + var result = await nep17API.GetTokenInfoAsync(NativeContract.GAS.Name.ToLower()); + Assert.AreEqual(NativeContract.GAS.Symbol, result.Symbol); + Assert.AreEqual(8, result.Decimals); + Assert.AreEqual(1_00000000, (int)result.TotalSupply); + Assert.AreEqual("GasToken", result.Name); + + result = await nep17API.GetTokenInfoAsync(NativeContract.GAS.Hash); + Assert.AreEqual(NativeContract.GAS.Symbol, result.Symbol); + Assert.AreEqual(8, result.Decimals); + Assert.AreEqual(1_00000000, (int)result.TotalSupply); + Assert.AreEqual("GasToken", result.Name); + haveGasTokenUT = true; + } + else if (test.Request.Params[0].AsString() == NativeContract.NEO.Hash.ToString() || test.Request.Params[0].AsString().Equals(NativeContract.NEO.Name, System.StringComparison.OrdinalIgnoreCase)) + { + var result = await nep17API.GetTokenInfoAsync(NativeContract.NEO.Name.ToLower()); + Assert.AreEqual(NativeContract.NEO.Symbol, result.Symbol); + Assert.AreEqual(0, result.Decimals); + Assert.AreEqual(1_00000000, (int)result.TotalSupply); + Assert.AreEqual("NeoToken", result.Name); + + result = await nep17API.GetTokenInfoAsync(NativeContract.NEO.Hash); + Assert.AreEqual(NativeContract.NEO.Symbol, result.Symbol); + Assert.AreEqual(0, result.Decimals); + Assert.AreEqual(1_00000000, (int)result.TotalSupply); + Assert.AreEqual("NeoToken", result.Name); + haveNeoTokenUT = true; + } + } + Assert.IsTrue(haveGasTokenUT && haveNeoTokenUT); //Update RpcTestCases.json + } + + [TestMethod] + public async Task TestTransfer() + { + byte[] testScript = NativeContract.GAS.Hash.MakeScript("transfer", sender, UInt160.Zero, new BigInteger(1_00000000), null) + .Concat(new[] { (byte)OpCode.ASSERT }) + .ToArray(); + UT_TransactionManager.MockInvokeScript(rpcClientMock, testScript, new ContractParameter()); + + var client = rpcClientMock.Object; + var result = await nep17API.CreateTransferTxAsync(NativeContract.GAS.Hash, keyPair1, UInt160.Zero, new BigInteger(1_00000000), null, true); + + testScript = NativeContract.GAS.Hash.MakeScript("transfer", sender, UInt160.Zero, new BigInteger(1_00000000), string.Empty) + .Concat(new[] { (byte)OpCode.ASSERT }) + .ToArray(); + UT_TransactionManager.MockInvokeScript(rpcClientMock, testScript, new ContractParameter()); + + result = await nep17API.CreateTransferTxAsync(NativeContract.GAS.Hash, keyPair1, UInt160.Zero, new BigInteger(1_00000000), string.Empty, true); + Assert.IsNotNull(result); + } + } +} diff --git a/tests/Neo.Network.RPC.Tests/UT_PolicyAPI.cs b/tests/Neo.Network.RPC.Tests/UT_PolicyAPI.cs new file mode 100644 index 0000000000..7defa163ad --- /dev/null +++ b/tests/Neo.Network.RPC.Tests/UT_PolicyAPI.cs @@ -0,0 +1,79 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_PolicyAPI.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 Moq; +using Neo.SmartContract; +using Neo.SmartContract.Native; +using Neo.VM; +using Neo.Wallets; +using System.Numerics; +using System.Threading.Tasks; + +namespace Neo.Network.RPC.Tests +{ + [TestClass] + public class UT_PolicyAPI + { + Mock rpcClientMock; + KeyPair keyPair1; + UInt160 sender; + PolicyAPI policyAPI; + + [TestInitialize] + public void TestSetup() + { + keyPair1 = new KeyPair(Wallet.GetPrivateKeyFromWIF("KyXwTh1hB76RRMquSvnxZrJzQx7h9nQP2PCRL38v6VDb5ip3nf1p")); + sender = Contract.CreateSignatureRedeemScript(keyPair1.PublicKey).ToScriptHash(); + rpcClientMock = UT_TransactionManager.MockRpcClient(sender, new byte[0]); + policyAPI = new PolicyAPI(rpcClientMock.Object); + } + + [TestMethod] + public async Task TestGetExecFeeFactor() + { + byte[] testScript = NativeContract.Policy.Hash.MakeScript("getExecFeeFactor"); + UT_TransactionManager.MockInvokeScript(rpcClientMock, testScript, new ContractParameter { Type = ContractParameterType.Integer, Value = new BigInteger(30) }); + + var result = await policyAPI.GetExecFeeFactorAsync(); + Assert.AreEqual(30u, result); + } + + [TestMethod] + public async Task TestGetStoragePrice() + { + byte[] testScript = NativeContract.Policy.Hash.MakeScript("getStoragePrice"); + UT_TransactionManager.MockInvokeScript(rpcClientMock, testScript, new ContractParameter { Type = ContractParameterType.Integer, Value = new BigInteger(100000) }); + + var result = await policyAPI.GetStoragePriceAsync(); + Assert.AreEqual(100000u, result); + } + + [TestMethod] + public async Task TestGetFeePerByte() + { + byte[] testScript = NativeContract.Policy.Hash.MakeScript("getFeePerByte"); + UT_TransactionManager.MockInvokeScript(rpcClientMock, testScript, new ContractParameter { Type = ContractParameterType.Integer, Value = new BigInteger(1000) }); + + var result = await policyAPI.GetFeePerByteAsync(); + Assert.AreEqual(1000L, result); + } + + [TestMethod] + public async Task TestIsBlocked() + { + byte[] testScript = NativeContract.Policy.Hash.MakeScript("isBlocked", UInt160.Zero); + UT_TransactionManager.MockInvokeScript(rpcClientMock, testScript, new ContractParameter { Type = ContractParameterType.Boolean, Value = true }); + var result = await policyAPI.IsBlockedAsync(UInt160.Zero); + Assert.AreEqual(true, result); + } + } +} diff --git a/tests/Neo.Network.RPC.Tests/UT_RpcClient.cs b/tests/Neo.Network.RPC.Tests/UT_RpcClient.cs new file mode 100644 index 0000000000..4af0f557e3 --- /dev/null +++ b/tests/Neo.Network.RPC.Tests/UT_RpcClient.cs @@ -0,0 +1,525 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_RpcClient.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 Moq; +using Moq.Protected; +using Neo.IO; +using Neo.Json; +using Neo.Network.P2P.Payloads; +using Neo.Network.RPC.Models; +using Neo.SmartContract; +using System; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; + +namespace Neo.Network.RPC.Tests +{ + [TestClass] + public class UT_RpcClient + { + RpcClient rpc; + Mock handlerMock; + + [TestInitialize] + public void TestSetup() + { + handlerMock = new Mock(MockBehavior.Strict); + + // use real http client with mocked handler here + var httpClient = new HttpClient(handlerMock.Object); + rpc = new RpcClient(httpClient, new Uri("http://seed1.neo.org:10331"), null); + foreach (var test in TestUtils.RpcTestCases) + { + MockResponse(test.Request, test.Response); + } + } + + private void MockResponse(RpcRequest request, RpcResponse response) + { + handlerMock.Protected() + // Setup the PROTECTED method to mock + .Setup>( + "SendAsync", + ItExpr.Is(p => p.Content.ReadAsStringAsync().Result == request.ToJson().ToString()), + ItExpr.IsAny() + ) + // prepare the expected response of the mocked http call + .ReturnsAsync(new HttpResponseMessage() + { + StatusCode = HttpStatusCode.OK, + Content = new StringContent(response.ToJson().ToString()), + }) + .Verifiable(); + } + + [TestMethod] + public async Task TestErrorResponse() + { + var test = TestUtils.RpcTestCases.Find(p => p.Name == (nameof(rpc.SendRawTransactionAsync) + "error").ToLower()); + try + { + var result = await rpc.SendRawTransactionAsync(Convert.FromBase64String(test.Request.Params[0].AsString()).AsSerializable()); + } + catch (RpcException ex) + { + Assert.AreEqual(-500, ex.HResult); + Assert.AreEqual("InsufficientFunds", ex.Message); + } + } + + [TestMethod] + public async Task TestNoThrowErrorResponse() + { + var test = TestUtils.RpcTestCases.Find(p => p.Name == (nameof(rpc.SendRawTransactionAsync) + "error").ToLower()); + handlerMock = new Mock(MockBehavior.Strict); + handlerMock.Protected() + // Setup the PROTECTED method to mock + .Setup>( + "SendAsync", + ItExpr.IsAny(), + ItExpr.IsAny()) + // prepare the expected response of the mocked http call + .ReturnsAsync(new HttpResponseMessage() + { + StatusCode = HttpStatusCode.OK, + Content = new StringContent(test.Response.ToJson().ToString()), + }) + .Verifiable(); + + var httpClient = new HttpClient(handlerMock.Object); + var client = new RpcClient(httpClient, new Uri("http://seed1.neo.org:10331"), null); + var response = await client.SendAsync(test.Request, false); + + Assert.IsNull(response.Result); + Assert.IsNotNull(response.Error); + Assert.AreEqual(-500, response.Error.Code); + Assert.AreEqual("InsufficientFunds", response.Error.Message); + } + + [TestMethod] + public void TestConstructorByUrlAndDispose() + { + //dummy url for test + var client = new RpcClient(new Uri("http://www.xxx.yyy")); + Action action = () => client.Dispose(); + action.Should().NotThrow(); + } + + [TestMethod] + public void TestConstructorWithBasicAuth() + { + var client = new RpcClient(new Uri("http://www.xxx.yyy"), "krain", "123456"); + client.Dispose(); + } + + #region Blockchain + + [TestMethod] + public async Task TestGetBestBlockHash() + { + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetBestBlockHashAsync).ToLower()); + var result = await rpc.GetBestBlockHashAsync(); + Assert.AreEqual(test.Response.Result.AsString(), result); + } + + [TestMethod] + public async Task TestGetBlockHex() + { + var tests = TestUtils.RpcTestCases.Where(p => p.Name == nameof(rpc.GetBlockHexAsync).ToLower()); + foreach (var test in tests) + { + var result = await rpc.GetBlockHexAsync(test.Request.Params[0].AsString()); + Assert.AreEqual(test.Response.Result.AsString(), result); + } + } + + [TestMethod] + public async Task TestGetBlock() + { + var tests = TestUtils.RpcTestCases.Where(p => p.Name == nameof(rpc.GetBlockAsync).ToLower()); + foreach (var test in tests) + { + var result = await rpc.GetBlockAsync(test.Request.Params[0].AsString()); + Assert.AreEqual(test.Response.Result.AsString(), result.ToJson(rpc.protocolSettings).ToString()); + } + } + + [TestMethod] + public async Task TestGetBlockHeaderCount() + { + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetBlockHeaderCountAsync).ToLower()); + var result = await rpc.GetBlockHeaderCountAsync(); + Assert.AreEqual(test.Response.Result.AsString(), result.ToString()); + } + + [TestMethod] + public async Task TestGetBlockCount() + { + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetBlockCountAsync).ToLower()); + var result = await rpc.GetBlockCountAsync(); + Assert.AreEqual(test.Response.Result.AsString(), result.ToString()); + } + + [TestMethod] + public async Task TestGetBlockHash() + { + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetBlockHashAsync).ToLower()); + var result = await rpc.GetBlockHashAsync((uint)test.Request.Params[0].AsNumber()); + Assert.AreEqual(test.Response.Result.AsString(), result.ToString()); + } + + [TestMethod] + public async Task TestGetBlockHeaderHex() + { + var tests = TestUtils.RpcTestCases.Where(p => p.Name == nameof(rpc.GetBlockHeaderHexAsync).ToLower()); + foreach (var test in tests) + { + var result = await rpc.GetBlockHeaderHexAsync(test.Request.Params[0].AsString()); + Assert.AreEqual(test.Response.Result.AsString(), result); + } + } + + [TestMethod] + public async Task TestGetBlockHeader() + { + var tests = TestUtils.RpcTestCases.Where(p => p.Name == nameof(rpc.GetBlockHeaderAsync).ToLower()); + foreach (var test in tests) + { + var result = await rpc.GetBlockHeaderAsync(test.Request.Params[0].AsString()); + Assert.AreEqual(test.Response.Result.ToString(), result.ToJson(rpc.protocolSettings).ToString()); + } + } + + [TestMethod] + public async Task TestGetCommittee() + { + var tests = TestUtils.RpcTestCases.Where(p => p.Name == nameof(rpc.GetCommitteeAsync).ToLower()); + foreach (var test in tests) + { + var result = await rpc.GetCommitteeAsync(); + Assert.AreEqual(test.Response.Result.ToString(), ((JArray)result.Select(p => (JToken)p).ToArray()).ToString()); + } + } + + [TestMethod] + public async Task TestGetContractState() + { + var tests = TestUtils.RpcTestCases.Where(p => p.Name == nameof(rpc.GetContractStateAsync).ToLower()); + foreach (var test in tests) + { + var result = await rpc.GetContractStateAsync(test.Request.Params[0].AsString()); + Assert.AreEqual(test.Response.Result.ToString(), result.ToJson().ToString()); + } + } + + [TestMethod] + public async Task TestGetNativeContracts() + { + var tests = TestUtils.RpcTestCases.Where(p => p.Name == nameof(rpc.GetNativeContractsAsync).ToLower()); + foreach (var test in tests) + { + var result = await rpc.GetNativeContractsAsync(); + Assert.AreEqual(test.Response.Result.ToString(), ((JArray)result.Select(p => p.ToJson()).ToArray()).ToString()); + } + } + + [TestMethod] + public async Task TestGetRawMempool() + { + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetRawMempoolAsync).ToLower()); + var result = await rpc.GetRawMempoolAsync(); + Assert.AreEqual(test.Response.Result.ToString(), ((JArray)result.Select(p => (JToken)p).ToArray()).ToString()); + } + + [TestMethod] + public async Task TestGetRawMempoolBoth() + { + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetRawMempoolBothAsync).ToLower()); + var result = await rpc.GetRawMempoolBothAsync(); + Assert.AreEqual(test.Response.Result.ToString(), result.ToJson().ToString()); + } + + [TestMethod] + public async Task TestGetRawTransactionHex() + { + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetRawTransactionHexAsync).ToLower()); + var result = await rpc.GetRawTransactionHexAsync(test.Request.Params[0].AsString()); + Assert.AreEqual(test.Response.Result.AsString(), result); + } + + [TestMethod] + public async Task TestGetRawTransaction() + { + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetRawTransactionAsync).ToLower()); + var result = await rpc.GetRawTransactionAsync(test.Request.Params[0].AsString()); + Assert.AreEqual(test.Response.Result.ToString(), result.ToJson(rpc.protocolSettings).ToString()); + } + + [TestMethod] + public async Task TestGetStorage() + { + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetStorageAsync).ToLower()); + var result = await rpc.GetStorageAsync(test.Request.Params[0].AsString(), test.Request.Params[1].AsString()); + Assert.AreEqual(test.Response.Result.AsString(), result); + } + + [TestMethod] + public async Task TestGetTransactionHeight() + { + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetTransactionHeightAsync).ToLower()); + var result = await rpc.GetTransactionHeightAsync(test.Request.Params[0].AsString()); + Assert.AreEqual(test.Response.Result.ToString(), result.ToString()); + } + + [TestMethod] + public async Task TestGetNextBlockValidators() + { + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetNextBlockValidatorsAsync).ToLower()); + var result = await rpc.GetNextBlockValidatorsAsync(); + Assert.AreEqual(test.Response.Result.ToString(), ((JArray)result.Select(p => p.ToJson()).ToArray()).ToString()); + } + + #endregion Blockchain + + #region Node + + [TestMethod] + public async Task TestGetConnectionCount() + { + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetConnectionCountAsync).ToLower()); + var result = await rpc.GetConnectionCountAsync(); + Assert.AreEqual(test.Response.Result.ToString(), result.ToString()); + } + + [TestMethod] + public async Task TestGetPeers() + { + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetPeersAsync).ToLower()); + var result = await rpc.GetPeersAsync(); + Assert.AreEqual(test.Response.Result.ToString(), result.ToJson().ToString()); + } + + [TestMethod] + public async Task TestGetVersion() + { + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetVersionAsync).ToLower()); + var result = await rpc.GetVersionAsync(); + Assert.AreEqual(test.Response.Result.ToString(), result.ToJson().ToString()); + } + + [TestMethod] + public async Task TestSendRawTransaction() + { + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.SendRawTransactionAsync).ToLower()); + var result = await rpc.SendRawTransactionAsync(Convert.FromBase64String(test.Request.Params[0].AsString()).AsSerializable()); + Assert.AreEqual(test.Response.Result["hash"].AsString(), result.ToString()); + } + + [TestMethod] + public async Task TestSubmitBlock() + { + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.SubmitBlockAsync).ToLower()); + var result = await rpc.SubmitBlockAsync(Convert.FromBase64String(test.Request.Params[0].AsString())); + Assert.AreEqual(test.Response.Result["hash"].AsString(), result.ToString()); + } + + #endregion Node + + #region SmartContract + + [TestMethod] + public async Task TestInvokeFunction() + { + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.InvokeFunctionAsync).ToLower()); + var result = await rpc.InvokeFunctionAsync(test.Request.Params[0].AsString(), test.Request.Params[1].AsString(), + ((JArray)test.Request.Params[2]).Select(p => RpcStack.FromJson((JObject)p)).ToArray()); + Assert.AreEqual(test.Response.Result.ToString(), result.ToJson().ToString()); + + // TODO test verify method + } + + [TestMethod] + public async Task TestInvokeScript() + { + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.InvokeScriptAsync).ToLower()); + var result = await rpc.InvokeScriptAsync(Convert.FromBase64String(test.Request.Params[0].AsString())); + Assert.AreEqual(test.Response.Result.ToString(), result.ToJson().ToString()); + } + + [TestMethod] + public async Task TestGetUnclaimedGas() + { + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetUnclaimedGasAsync).ToLower()); + var result = await rpc.GetUnclaimedGasAsync(test.Request.Params[0].AsString()); + Assert.AreEqual(result.ToJson().AsString(), RpcUnclaimedGas.FromJson(result.ToJson()).ToJson().AsString()); + Assert.AreEqual(test.Response.Result["unclaimed"].AsString(), result.Unclaimed.ToString()); + } + + #endregion SmartContract + + #region Utilities + + [TestMethod] + public async Task TestListPlugins() + { + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.ListPluginsAsync).ToLower()); + var result = await rpc.ListPluginsAsync(); + Assert.AreEqual(test.Response.Result.ToString(), ((JArray)result.Select(p => p.ToJson()).ToArray()).ToString()); + } + + [TestMethod] + public async Task TestValidateAddress() + { + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.ValidateAddressAsync).ToLower()); + var result = await rpc.ValidateAddressAsync(test.Request.Params[0].AsString()); + Assert.AreEqual(test.Response.Result.ToString(), result.ToJson().ToString()); + } + + #endregion Utilities + + #region Wallet + + [TestMethod] + public async Task TestCloseWallet() + { + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.CloseWalletAsync).ToLower()); + var result = await rpc.CloseWalletAsync(); + Assert.AreEqual(test.Response.Result.AsBoolean(), result); + } + + [TestMethod] + public async Task TestDumpPrivKey() + { + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.DumpPrivKeyAsync).ToLower()); + var result = await rpc.DumpPrivKeyAsync(test.Request.Params[0].AsString()); + Assert.AreEqual(test.Response.Result.AsString(), result); + } + + [TestMethod] + public async Task TestGetNewAddress() + { + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetNewAddressAsync).ToLower()); + var result = await rpc.GetNewAddressAsync(); + Assert.AreEqual(test.Response.Result.AsString(), result); + } + + [TestMethod] + public async Task TestGetWalletBalance() + { + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetWalletBalanceAsync).ToLower()); + var result = await rpc.GetWalletBalanceAsync(test.Request.Params[0].AsString()); + Assert.AreEqual(test.Response.Result["balance"].AsString(), result.Value.ToString()); + } + + [TestMethod] + public async Task TestGetWalletUnclaimedGas() + { + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetWalletUnclaimedGasAsync).ToLower()); + var result = await rpc.GetWalletUnclaimedGasAsync(); + Assert.AreEqual(test.Response.Result.AsString(), result.ToString()); + } + + [TestMethod] + public async Task TestImportPrivKey() + { + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.ImportPrivKeyAsync).ToLower()); + var result = await rpc.ImportPrivKeyAsync(test.Request.Params[0].AsString()); + Assert.AreEqual(test.Response.Result.ToString(), result.ToJson().ToString()); + } + + [TestMethod] + public async Task TestListAddress() + { + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.ListAddressAsync).ToLower()); + var result = await rpc.ListAddressAsync(); + Assert.AreEqual(test.Response.Result.ToString(), ((JArray)result.Select(p => p.ToJson()).ToArray()).ToString()); + } + + [TestMethod] + public async Task TestOpenWallet() + { + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.OpenWalletAsync).ToLower()); + var result = await rpc.OpenWalletAsync(test.Request.Params[0].AsString(), test.Request.Params[1].AsString()); + Assert.AreEqual(test.Response.Result.AsBoolean(), result); + } + + [TestMethod] + public async Task TestSendFrom() + { + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.SendFromAsync).ToLower()); + var result = await rpc.SendFromAsync(test.Request.Params[0].AsString(), test.Request.Params[1].AsString(), + test.Request.Params[2].AsString(), test.Request.Params[3].AsString()); + Assert.AreEqual(test.Response.Result.ToString(), result.ToString()); + } + + [TestMethod] + public async Task TestSendMany() + { + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.SendManyAsync).ToLower()); + var result = await rpc.SendManyAsync(test.Request.Params[0].AsString(), ((JArray)test.Request.Params[1]).Select(p => RpcTransferOut.FromJson((JObject)p, rpc.protocolSettings))); + Assert.AreEqual(test.Response.Result.ToString(), result.ToString()); + } + + [TestMethod] + public async Task TestSendToAddress() + { + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.SendToAddressAsync).ToLower()); + var result = await rpc.SendToAddressAsync(test.Request.Params[0].AsString(), test.Request.Params[1].AsString(), test.Request.Params[2].AsString()); + Assert.AreEqual(test.Response.Result.ToString(), result.ToString()); + } + + #endregion Wallet + + #region Plugins + + [TestMethod()] + public async Task GetApplicationLogTest() + { + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetApplicationLogAsync).ToLower()); + var result = await rpc.GetApplicationLogAsync(test.Request.Params[0].AsString()); + Assert.AreEqual(test.Response.Result.ToString(), result.ToJson().ToString()); + } + + [TestMethod()] + public async Task GetApplicationLogTest_TriggerType() + { + var test = TestUtils.RpcTestCases.Find(p => p.Name == (nameof(rpc.GetApplicationLogAsync) + "_triggertype").ToLower()); + var result = await rpc.GetApplicationLogAsync(test.Request.Params[0].AsString(), TriggerType.OnPersist); + Assert.AreEqual(test.Response.Result.ToString(), result.ToJson().ToString()); + } + + [TestMethod()] + public async Task GetNep17TransfersTest() + { + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetNep17TransfersAsync).ToLower()); + var result = await rpc.GetNep17TransfersAsync(test.Request.Params[0].AsString(), (ulong)test.Request.Params[1].AsNumber(), (ulong)test.Request.Params[2].AsNumber()); + Assert.AreEqual(test.Response.Result.ToString(), result.ToJson(rpc.protocolSettings).ToString()); + test = TestUtils.RpcTestCases.Find(p => p.Name == (nameof(rpc.GetNep17TransfersAsync).ToLower() + "_with_null_transferaddress")); + result = await rpc.GetNep17TransfersAsync(test.Request.Params[0].AsString(), (ulong)test.Request.Params[1].AsNumber(), (ulong)test.Request.Params[2].AsNumber()); + Assert.AreEqual(test.Response.Result.ToString(), result.ToJson(rpc.protocolSettings).ToString()); + } + + [TestMethod()] + public async Task GetNep17BalancesTest() + { + var test = TestUtils.RpcTestCases.Find(p => p.Name == nameof(rpc.GetNep17BalancesAsync).ToLower()); + var result = await rpc.GetNep17BalancesAsync(test.Request.Params[0].AsString()); + Assert.AreEqual(test.Response.Result.ToString(), result.ToJson(rpc.protocolSettings).ToString()); + } + + #endregion Plugins + } +} diff --git a/tests/Neo.Network.RPC.Tests/UT_RpcModels.cs b/tests/Neo.Network.RPC.Tests/UT_RpcModels.cs new file mode 100644 index 0000000000..43eb7cfe7b --- /dev/null +++ b/tests/Neo.Network.RPC.Tests/UT_RpcModels.cs @@ -0,0 +1,175 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_RpcModels.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 Moq; +using Neo.Json; +using Neo.Network.RPC.Models; +using System; +using System.Linq; +using System.Net.Http; + +namespace Neo.Network.RPC.Tests +{ + [TestClass()] + public class UT_RpcModels + { + RpcClient rpc; + Mock handlerMock; + + [TestInitialize] + public void TestSetup() + { + handlerMock = new Mock(MockBehavior.Strict); + + // use real http client with mocked handler here + var httpClient = new HttpClient(handlerMock.Object); + rpc = new RpcClient(httpClient, new Uri("http://seed1.neo.org:10331"), null); + } + + [TestMethod()] + public void TestRpcAccount() + { + JToken json = TestUtils.RpcTestCases.Find(p => p.Name == nameof(RpcClient.ImportPrivKeyAsync).ToLower()).Response.Result; + var item = RpcAccount.FromJson((JObject)json); + Assert.AreEqual(json.ToString(), item.ToJson().ToString()); + } + + [TestMethod()] + public void TestRpcApplicationLog() + { + JToken json = TestUtils.RpcTestCases.Find(p => p.Name == nameof(RpcClient.GetApplicationLogAsync).ToLower()).Response.Result; + var item = RpcApplicationLog.FromJson((JObject)json, rpc.protocolSettings); + Assert.AreEqual(json.ToString(), item.ToJson().ToString()); + } + + [TestMethod()] + public void TestRpcBlock() + { + JToken json = TestUtils.RpcTestCases.Find(p => p.Name == nameof(RpcClient.GetBlockAsync).ToLower()).Response.Result; + var item = RpcBlock.FromJson((JObject)json, rpc.protocolSettings); + Assert.AreEqual(json.ToString(), item.ToJson(rpc.protocolSettings).ToString()); + } + + [TestMethod()] + public void TestRpcBlockHeader() + { + JToken json = TestUtils.RpcTestCases.Find(p => p.Name == nameof(RpcClient.GetBlockHeaderAsync).ToLower()).Response.Result; + var item = RpcBlockHeader.FromJson((JObject)json, rpc.protocolSettings); + Assert.AreEqual(json.ToString(), item.ToJson(rpc.protocolSettings).ToString()); + } + + [TestMethod()] + public void TestGetContractState() + { + JToken json = TestUtils.RpcTestCases.Find(p => p.Name == nameof(RpcClient.GetContractStateAsync).ToLower()).Response.Result; + var item = RpcContractState.FromJson((JObject)json); + Assert.AreEqual(json.ToString(), item.ToJson().ToString()); + + var nef = RpcNefFile.FromJson((JObject)json["nef"]); + Assert.AreEqual(json["nef"].ToString(), nef.ToJson().ToString()); + } + + [TestMethod()] + public void TestRpcInvokeResult() + { + JToken json = TestUtils.RpcTestCases.Find(p => p.Name == nameof(RpcClient.InvokeFunctionAsync).ToLower()).Response.Result; + var item = RpcInvokeResult.FromJson((JObject)json); + Assert.AreEqual(json.ToString(), item.ToJson().ToString()); + } + + [TestMethod()] + public void TestRpcMethodToken() + { + RpcMethodToken.FromJson((JObject)JToken.Parse("{\"hash\": \"0x0e1b9bfaa44e60311f6f3c96cfcd6d12c2fc3add\", \"method\":\"test\",\"paramcount\":\"1\",\"hasreturnvalue\":\"true\",\"callflags\":\"All\"}")); + } + + [TestMethod()] + public void TestRpcNep17Balances() + { + JToken json = TestUtils.RpcTestCases.Find(p => p.Name == nameof(RpcClient.GetNep17BalancesAsync).ToLower()).Response.Result; + var item = RpcNep17Balances.FromJson((JObject)json, rpc.protocolSettings); + Assert.AreEqual(json.ToString(), item.ToJson(rpc.protocolSettings).ToString()); + } + + [TestMethod()] + public void TestRpcNep17Transfers() + { + JToken json = TestUtils.RpcTestCases.Find(p => p.Name == nameof(RpcClient.GetNep17TransfersAsync).ToLower()).Response.Result; + var item = RpcNep17Transfers.FromJson((JObject)json, rpc.protocolSettings); + Assert.AreEqual(json.ToString(), item.ToJson(rpc.protocolSettings).ToString()); + } + + [TestMethod()] + public void TestRpcPeers() + { + JToken json = TestUtils.RpcTestCases.Find(p => p.Name == nameof(RpcClient.GetPeersAsync).ToLower()).Response.Result; + var item = RpcPeers.FromJson((JObject)json); + Assert.AreEqual(json.ToString(), item.ToJson().ToString()); + } + + [TestMethod()] + public void TestRpcPlugin() + { + JToken json = TestUtils.RpcTestCases.Find(p => p.Name == nameof(RpcClient.ListPluginsAsync).ToLower()).Response.Result; + var item = ((JArray)json).Select(p => RpcPlugin.FromJson((JObject)p)); + Assert.AreEqual(json.ToString(), ((JArray)item.Select(p => p.ToJson()).ToArray()).ToString()); + } + + [TestMethod()] + public void TestRpcRawMemPool() + { + JToken json = TestUtils.RpcTestCases.Find(p => p.Name == nameof(RpcClient.GetRawMempoolBothAsync).ToLower()).Response.Result; + var item = RpcRawMemPool.FromJson((JObject)json); + Assert.AreEqual(json.ToString(), item.ToJson().ToString()); + } + + [TestMethod()] + public void TestRpcTransaction() + { + JToken json = TestUtils.RpcTestCases.Find(p => p.Name == nameof(RpcClient.GetRawTransactionAsync).ToLower()).Response.Result; + var item = RpcTransaction.FromJson((JObject)json, rpc.protocolSettings); + Assert.AreEqual(json.ToString(), item.ToJson(rpc.protocolSettings).ToString()); + } + + [TestMethod()] + public void TestRpcTransferOut() + { + JToken json = TestUtils.RpcTestCases.Find(p => p.Name == nameof(RpcClient.SendManyAsync).ToLower()).Request.Params[1]; + var item = ((JArray)json).Select(p => RpcTransferOut.FromJson((JObject)p, rpc.protocolSettings)); + Assert.AreEqual(json.ToString(), ((JArray)item.Select(p => p.ToJson(rpc.protocolSettings)).ToArray()).ToString()); + } + + [TestMethod()] + public void TestRpcValidateAddressResult() + { + JToken json = TestUtils.RpcTestCases.Find(p => p.Name == nameof(RpcClient.ValidateAddressAsync).ToLower()).Response.Result; + var item = RpcValidateAddressResult.FromJson((JObject)json); + Assert.AreEqual(json.ToString(), item.ToJson().ToString()); + } + + [TestMethod()] + public void TestRpcValidator() + { + JToken json = TestUtils.RpcTestCases.Find(p => p.Name == nameof(RpcClient.GetNextBlockValidatorsAsync).ToLower()).Response.Result; + var item = ((JArray)json).Select(p => RpcValidator.FromJson((JObject)p)); + Assert.AreEqual(json.ToString(), ((JArray)item.Select(p => p.ToJson()).ToArray()).ToString()); + } + + [TestMethod()] + public void TestRpcVersion() + { + JToken json = TestUtils.RpcTestCases.Find(p => p.Name == nameof(RpcClient.GetVersionAsync).ToLower()).Response.Result; + var item = RpcVersion.FromJson((JObject)json); + Assert.AreEqual(json.ToString(), item.ToJson().ToString()); + } + } +} diff --git a/tests/Neo.Network.RPC.Tests/UT_TransactionManager.cs b/tests/Neo.Network.RPC.Tests/UT_TransactionManager.cs new file mode 100644 index 0000000000..ae025cf65a --- /dev/null +++ b/tests/Neo.Network.RPC.Tests/UT_TransactionManager.cs @@ -0,0 +1,267 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_TransactionManager.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 Moq; +using Neo.Cryptography; +using Neo.Cryptography.ECC; +using Neo.IO; +using Neo.Json; +using Neo.Network.P2P; +using Neo.Network.P2P.Payloads; +using Neo.Network.RPC.Models; +using Neo.SmartContract; +using Neo.SmartContract.Native; +using Neo.VM; +using Neo.Wallets; +using System; +using System.Linq; +using System.Numerics; +using System.Threading.Tasks; + +namespace Neo.Network.RPC.Tests +{ + [TestClass] + public class UT_TransactionManager + { + TransactionManager txManager; + Mock rpcClientMock; + Mock multiSigMock; + KeyPair keyPair1; + KeyPair keyPair2; + UInt160 sender; + UInt160 multiHash; + RpcClient client; + + [TestInitialize] + public void TestSetup() + { + keyPair1 = new KeyPair(Wallet.GetPrivateKeyFromWIF("KyXwTh1hB76RRMquSvnxZrJzQx7h9nQP2PCRL38v6VDb5ip3nf1p")); + keyPair2 = new KeyPair(Wallet.GetPrivateKeyFromWIF("L2LGkrwiNmUAnWYb1XGd5mv7v2eDf6P4F3gHyXSrNJJR4ArmBp7Q")); + sender = Contract.CreateSignatureRedeemScript(keyPair1.PublicKey).ToScriptHash(); + multiHash = Contract.CreateMultiSigContract(2, new ECPoint[] { keyPair1.PublicKey, keyPair2.PublicKey }).ScriptHash; + rpcClientMock = MockRpcClient(sender, new byte[1]); + client = rpcClientMock.Object; + multiSigMock = MockMultiSig(multiHash, new byte[1]); + } + + public static Mock MockRpcClient(UInt160 sender, byte[] script) + { + var mockRpc = new Mock(MockBehavior.Strict, new Uri("http://seed1.neo.org:10331"), null, null, null); + + // MockHeight + mockRpc.Setup(p => p.RpcSendAsync("getblockcount")).ReturnsAsync(100).Verifiable(); + + // calculatenetworkfee + var networkfee = new JObject(); + networkfee["networkfee"] = 100000000; + mockRpc.Setup(p => p.RpcSendAsync("calculatenetworkfee", It.Is(u => true))) + .ReturnsAsync(networkfee) + .Verifiable(); + + // MockGasBalance + byte[] balanceScript = NativeContract.GAS.Hash.MakeScript("balanceOf", sender); + var balanceResult = new ContractParameter() { Type = ContractParameterType.Integer, Value = BigInteger.Parse("10000000000000000") }; + + MockInvokeScript(mockRpc, balanceScript, balanceResult); + + // MockFeePerByte + byte[] policyScript = NativeContract.Policy.Hash.MakeScript("getFeePerByte"); + var policyResult = new ContractParameter() { Type = ContractParameterType.Integer, Value = BigInteger.Parse("1000") }; + + MockInvokeScript(mockRpc, policyScript, policyResult); + + // MockGasConsumed + var result = new ContractParameter(); + MockInvokeScript(mockRpc, script, result); + + return mockRpc; + } + + public static Mock MockMultiSig(UInt160 multiHash, byte[] script) + { + var mockRpc = new Mock(MockBehavior.Strict, new Uri("http://seed1.neo.org:10331"), null, null, null); + + // MockHeight + mockRpc.Setup(p => p.RpcSendAsync("getblockcount")).ReturnsAsync(100).Verifiable(); + + // calculatenetworkfee + var networkfee = new JObject(); + networkfee["networkfee"] = 100000000; + mockRpc.Setup(p => p.RpcSendAsync("calculatenetworkfee", It.Is(u => true))) + .ReturnsAsync(networkfee) + .Verifiable(); + + // MockGasBalance + byte[] balanceScript = NativeContract.GAS.Hash.MakeScript("balanceOf", multiHash); + var balanceResult = new ContractParameter() { Type = ContractParameterType.Integer, Value = BigInteger.Parse("10000000000000000") }; + + MockInvokeScript(mockRpc, balanceScript, balanceResult); + + // MockFeePerByte + byte[] policyScript = NativeContract.Policy.Hash.MakeScript("getFeePerByte"); + var policyResult = new ContractParameter() { Type = ContractParameterType.Integer, Value = BigInteger.Parse("1000") }; + + MockInvokeScript(mockRpc, policyScript, policyResult); + + // MockGasConsumed + var result = new ContractParameter(); + MockInvokeScript(mockRpc, script, result); + + return mockRpc; + } + + public static void MockInvokeScript(Mock mockClient, byte[] script, params ContractParameter[] parameters) + { + var result = new RpcInvokeResult() + { + Stack = parameters.Select(p => p.ToStackItem()).ToArray(), + GasConsumed = 100, + Script = Convert.ToBase64String(script), + State = VMState.HALT + }; + + mockClient.Setup(p => p.RpcSendAsync("invokescript", It.Is(j => + Convert.FromBase64String(j[0].AsString()).SequenceEqual(script)))) + .ReturnsAsync(result.ToJson()) + .Verifiable(); + } + + [TestMethod] + public async Task TestMakeTransaction() + { + Signer[] signers = new Signer[1] + { + new Signer + { + Account = sender, + Scopes= WitnessScope.Global + } + }; + + byte[] script = new byte[1]; + txManager = await TransactionManager.MakeTransactionAsync(rpcClientMock.Object, script, signers); + + var tx = txManager.Tx; + Assert.AreEqual(WitnessScope.Global, tx.Signers[0].Scopes); + } + + [TestMethod] + public async Task TestSign() + { + Signer[] signers = new Signer[1] + { + new Signer + { + Account = sender, + Scopes = WitnessScope.Global + } + }; + + byte[] script = new byte[1]; + txManager = await TransactionManager.MakeTransactionAsync(client, script, signers); + await txManager + .AddSignature(keyPair1) + .SignAsync(); + + // get signature from Witnesses + var tx = txManager.Tx; + ReadOnlyMemory signature = tx.Witnesses[0].InvocationScript[2..]; + + Assert.IsTrue(Crypto.VerifySignature(tx.GetSignData(client.protocolSettings.Network), signature.Span, keyPair1.PublicKey)); + // verify network fee and system fee + Assert.AreEqual(100000000/*Mock*/, tx.NetworkFee); + Assert.AreEqual(100, tx.SystemFee); + + // duplicate sign should not add new witness + await ThrowsAsync(async () => await txManager.AddSignature(keyPair1).SignAsync()); + Assert.AreEqual(null, txManager.Tx.Witnesses); + + // throw exception when the KeyPair is wrong + await ThrowsAsync(async () => await txManager.AddSignature(keyPair2).SignAsync()); + } + + // https://docs.microsoft.com/en-us/archive/msdn-magazine/2014/november/async-programming-unit-testing-asynchronous-code#testing-exceptions + static async Task ThrowsAsync(Func action, bool allowDerivedTypes = true) + where TException : Exception + { + try + { + await action(); + } + catch (Exception ex) + { + if (allowDerivedTypes && !(ex is TException)) + throw new Exception("Delegate threw exception of type " + + ex.GetType().Name + ", but " + typeof(TException).Name + + " or a derived type was expected.", ex); + if (!allowDerivedTypes && ex.GetType() != typeof(TException)) + throw new Exception("Delegate threw exception of type " + + ex.GetType().Name + ", but " + typeof(TException).Name + + " was expected.", ex); + return (TException)ex; + } + throw new Exception("Delegate did not throw expected exception " + + typeof(TException).Name + "."); + } + + [TestMethod] + public async Task TestSignMulti() + { + // Cosigner needs multi signature + Signer[] signers = new Signer[1] + { + new Signer + { + Account = multiHash, + Scopes = WitnessScope.Global + } + }; + + byte[] script = new byte[1]; + txManager = await TransactionManager.MakeTransactionAsync(multiSigMock.Object, script, signers); + await txManager + .AddMultiSig(keyPair1, 2, keyPair1.PublicKey, keyPair2.PublicKey) + .AddMultiSig(keyPair2, 2, keyPair1.PublicKey, keyPair2.PublicKey) + .SignAsync(); + } + + [TestMethod] + public async Task TestAddWitness() + { + // Cosigner as contract scripthash + Signer[] signers = new Signer[2] + { + new Signer + { + Account = sender, + Scopes = WitnessScope.Global + }, + new Signer + { + Account = UInt160.Zero, + Scopes = WitnessScope.Global + } + }; + + byte[] script = new byte[1]; + txManager = await TransactionManager.MakeTransactionAsync(rpcClientMock.Object, script, signers); + txManager.AddWitness(UInt160.Zero); + txManager.AddSignature(keyPair1); + await txManager.SignAsync(); + + var tx = txManager.Tx; + Assert.AreEqual(2, tx.Witnesses.Length); + Assert.AreEqual(40, tx.Witnesses[0].VerificationScript.Length); + Assert.AreEqual(66, tx.Witnesses[0].InvocationScript.Length); + } + } +} diff --git a/tests/Neo.Network.RPC.Tests/UT_Utility.cs b/tests/Neo.Network.RPC.Tests/UT_Utility.cs new file mode 100644 index 0000000000..fa410c5437 --- /dev/null +++ b/tests/Neo.Network.RPC.Tests/UT_Utility.cs @@ -0,0 +1,87 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_Utility.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.Wallets; +using System; +using System.Numerics; + +namespace Neo.Network.RPC.Tests +{ + [TestClass] + public class UT_Utility + { + private KeyPair keyPair; + private UInt160 scriptHash; + private ProtocolSettings protocolSettings; + + [TestInitialize] + public void TestSetup() + { + keyPair = new KeyPair(Wallet.GetPrivateKeyFromWIF("KyXwTh1hB76RRMquSvnxZrJzQx7h9nQP2PCRL38v6VDb5ip3nf1p")); + scriptHash = Contract.CreateSignatureRedeemScript(keyPair.PublicKey).ToScriptHash(); + protocolSettings = ProtocolSettings.Load("protocol.json"); + } + + [TestMethod] + public void TestGetKeyPair() + { + string nul = null; + Assert.ThrowsException(() => Utility.GetKeyPair(nul)); + + string wif = "KyXwTh1hB76RRMquSvnxZrJzQx7h9nQP2PCRL38v6VDb5ip3nf1p"; + var result = Utility.GetKeyPair(wif); + Assert.AreEqual(keyPair, result); + + string privateKey = keyPair.PrivateKey.ToHexString(); + result = Utility.GetKeyPair(privateKey); + Assert.AreEqual(keyPair, result); + } + + [TestMethod] + public void TestGetScriptHash() + { + string nul = null; + Assert.ThrowsException(() => Utility.GetScriptHash(nul, protocolSettings)); + + string addr = scriptHash.ToAddress(protocolSettings.AddressVersion); + var result = Utility.GetScriptHash(addr, protocolSettings); + Assert.AreEqual(scriptHash, result); + + string hash = scriptHash.ToString(); + result = Utility.GetScriptHash(hash, protocolSettings); + Assert.AreEqual(scriptHash, result); + + string publicKey = keyPair.PublicKey.ToString(); + result = Utility.GetScriptHash(publicKey, protocolSettings); + Assert.AreEqual(scriptHash, result); + } + + [TestMethod] + public void TestToBigInteger() + { + decimal amount = 1.23456789m; + uint decimals = 9; + var result = amount.ToBigInteger(decimals); + Assert.AreEqual(1234567890, result); + + amount = 1.23456789m; + decimals = 18; + result = amount.ToBigInteger(decimals); + Assert.AreEqual(BigInteger.Parse("1234567890000000000"), result); + + amount = 1.23456789m; + decimals = 4; + Assert.ThrowsException(() => result = amount.ToBigInteger(decimals)); + } + } +} diff --git a/tests/Neo.Network.RPC.Tests/UT_WalletAPI.cs b/tests/Neo.Network.RPC.Tests/UT_WalletAPI.cs new file mode 100644 index 0000000000..10a35fd064 --- /dev/null +++ b/tests/Neo.Network.RPC.Tests/UT_WalletAPI.cs @@ -0,0 +1,181 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_WalletAPI.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 Moq; +using Neo.Cryptography.ECC; +using Neo.Json; +using Neo.Network.P2P.Payloads; +using Neo.Network.RPC.Models; +using Neo.SmartContract; +using Neo.SmartContract.Native; +using Neo.VM; +using Neo.Wallets; +using System.Linq; +using System.Numerics; +using System.Threading.Tasks; + +namespace Neo.Network.RPC.Tests +{ + [TestClass] + public class UT_WalletAPI + { + Mock rpcClientMock; + KeyPair keyPair1; + string address1; + UInt160 sender; + WalletAPI walletAPI; + UInt160 multiSender; + RpcClient client; + + [TestInitialize] + public void TestSetup() + { + keyPair1 = new KeyPair(Wallet.GetPrivateKeyFromWIF("KyXwTh1hB76RRMquSvnxZrJzQx7h9nQP2PCRL38v6VDb5ip3nf1p")); + sender = Contract.CreateSignatureRedeemScript(keyPair1.PublicKey).ToScriptHash(); + multiSender = Contract.CreateMultiSigContract(1, new ECPoint[] { keyPair1.PublicKey }).ScriptHash; + rpcClientMock = UT_TransactionManager.MockRpcClient(sender, new byte[0]); + client = rpcClientMock.Object; + address1 = Wallets.Helper.ToAddress(sender, client.protocolSettings.AddressVersion); + walletAPI = new WalletAPI(rpcClientMock.Object); + } + + [TestMethod] + public async Task TestGetUnclaimedGas() + { + byte[] testScript = NativeContract.NEO.Hash.MakeScript("unclaimedGas", sender, 99); + UT_TransactionManager.MockInvokeScript(rpcClientMock, testScript, new ContractParameter { Type = ContractParameterType.Integer, Value = new BigInteger(1_10000000) }); + + var balance = await walletAPI.GetUnclaimedGasAsync(address1); + Assert.AreEqual(1.1m, balance); + } + + [TestMethod] + public async Task TestGetNeoBalance() + { + byte[] testScript = NativeContract.NEO.Hash.MakeScript("balanceOf", sender); + UT_TransactionManager.MockInvokeScript(rpcClientMock, testScript, new ContractParameter { Type = ContractParameterType.Integer, Value = new BigInteger(1_00000000) }); + + var balance = await walletAPI.GetNeoBalanceAsync(address1); + Assert.AreEqual(1_00000000u, balance); + } + + [TestMethod] + public async Task TestGetGasBalance() + { + byte[] testScript = NativeContract.GAS.Hash.MakeScript("balanceOf", sender); + UT_TransactionManager.MockInvokeScript(rpcClientMock, testScript, new ContractParameter { Type = ContractParameterType.Integer, Value = new BigInteger(1_10000000) }); + + var balance = await walletAPI.GetGasBalanceAsync(address1); + Assert.AreEqual(1.1m, balance); + } + + [TestMethod] + public async Task TestGetTokenBalance() + { + byte[] testScript = UInt160.Zero.MakeScript("balanceOf", sender); + UT_TransactionManager.MockInvokeScript(rpcClientMock, testScript, new ContractParameter { Type = ContractParameterType.Integer, Value = new BigInteger(1_10000000) }); + + var balance = await walletAPI.GetTokenBalanceAsync(UInt160.Zero.ToString(), address1); + Assert.AreEqual(1_10000000, balance); + } + + [TestMethod] + public async Task TestClaimGas() + { + byte[] balanceScript = NativeContract.NEO.Hash.MakeScript("balanceOf", sender); + UT_TransactionManager.MockInvokeScript(rpcClientMock, balanceScript, new ContractParameter { Type = ContractParameterType.Integer, Value = new BigInteger(1_00000000) }); + + byte[] testScript = NativeContract.NEO.Hash.MakeScript("transfer", sender, sender, new BigInteger(1_00000000), null); + UT_TransactionManager.MockInvokeScript(rpcClientMock, testScript, new ContractParameter { Type = ContractParameterType.Integer, Value = new BigInteger(1_10000000) }); + + var json = new JObject(); + json["hash"] = UInt256.Zero.ToString(); + rpcClientMock.Setup(p => p.RpcSendAsync("sendrawtransaction", It.IsAny())).ReturnsAsync(json); + + var tranaction = await walletAPI.ClaimGasAsync(keyPair1.Export(), false); + Assert.AreEqual(testScript.ToHexString(), tranaction.Script.Span.ToHexString()); + } + + [TestMethod] + public async Task TestTransfer() + { + byte[] decimalsScript = NativeContract.GAS.Hash.MakeScript("decimals"); + UT_TransactionManager.MockInvokeScript(rpcClientMock, decimalsScript, new ContractParameter { Type = ContractParameterType.Integer, Value = new BigInteger(8) }); + + byte[] testScript = NativeContract.GAS.Hash.MakeScript("transfer", sender, UInt160.Zero, NativeContract.GAS.Factor * 100, null) + .Concat(new[] { (byte)OpCode.ASSERT }) + .ToArray(); + UT_TransactionManager.MockInvokeScript(rpcClientMock, testScript, new ContractParameter { Type = ContractParameterType.Integer, Value = new BigInteger(1_10000000) }); + + var json = new JObject(); + json["hash"] = UInt256.Zero.ToString(); + rpcClientMock.Setup(p => p.RpcSendAsync("sendrawtransaction", It.IsAny())).ReturnsAsync(json); + + var tranaction = await walletAPI.TransferAsync(NativeContract.GAS.Hash.ToString(), keyPair1.Export(), UInt160.Zero.ToAddress(client.protocolSettings.AddressVersion), 100, null, true); + Assert.AreEqual(testScript.ToHexString(), tranaction.Script.Span.ToHexString()); + } + + [TestMethod] + public async Task TestTransferfromMultiSigAccount() + { + byte[] balanceScript = NativeContract.GAS.Hash.MakeScript("balanceOf", multiSender); + var balanceResult = new ContractParameter() { Type = ContractParameterType.Integer, Value = BigInteger.Parse("10000000000000000") }; + + UT_TransactionManager.MockInvokeScript(rpcClientMock, balanceScript, balanceResult); + + byte[] decimalsScript = NativeContract.GAS.Hash.MakeScript("decimals"); + UT_TransactionManager.MockInvokeScript(rpcClientMock, decimalsScript, new ContractParameter { Type = ContractParameterType.Integer, Value = new BigInteger(8) }); + + byte[] testScript = NativeContract.GAS.Hash.MakeScript("transfer", multiSender, UInt160.Zero, NativeContract.GAS.Factor * 100, null) + .Concat(new[] { (byte)OpCode.ASSERT }) + .ToArray(); + UT_TransactionManager.MockInvokeScript(rpcClientMock, testScript, new ContractParameter { Type = ContractParameterType.Integer, Value = new BigInteger(1_10000000) }); + + var json = new JObject(); + json["hash"] = UInt256.Zero.ToString(); + rpcClientMock.Setup(p => p.RpcSendAsync("sendrawtransaction", It.IsAny())).ReturnsAsync(json); + + var tranaction = await walletAPI.TransferAsync(NativeContract.GAS.Hash, 1, new[] { keyPair1.PublicKey }, new[] { keyPair1 }, UInt160.Zero, NativeContract.GAS.Factor * 100, null, true); + Assert.AreEqual(testScript.ToHexString(), tranaction.Script.Span.ToHexString()); + + try + { + tranaction = await walletAPI.TransferAsync(NativeContract.GAS.Hash, 2, new[] { keyPair1.PublicKey }, new[] { keyPair1 }, UInt160.Zero, NativeContract.GAS.Factor * 100, null, true); + Assert.Fail(); + } + catch (System.Exception e) + { + Assert.AreEqual(e.Message, $"Need at least 2 KeyPairs for signing!"); + } + + testScript = NativeContract.GAS.Hash.MakeScript("transfer", multiSender, UInt160.Zero, NativeContract.GAS.Factor * 100, string.Empty) + .Concat(new[] { (byte)OpCode.ASSERT }) + .ToArray(); + UT_TransactionManager.MockInvokeScript(rpcClientMock, testScript, new ContractParameter { Type = ContractParameterType.Integer, Value = new BigInteger(1_10000000) }); + + tranaction = await walletAPI.TransferAsync(NativeContract.GAS.Hash, 1, new[] { keyPair1.PublicKey }, new[] { keyPair1 }, UInt160.Zero, NativeContract.GAS.Factor * 100, string.Empty, true); + Assert.AreEqual(testScript.ToHexString(), tranaction.Script.Span.ToHexString()); + } + + [TestMethod] + public async Task TestWaitTransaction() + { + Transaction transaction = TestUtils.GetTransaction(); + rpcClientMock.Setup(p => p.RpcSendAsync("getrawtransaction", It.Is(j => j[0].AsString() == transaction.Hash.ToString()))) + .ReturnsAsync(new RpcTransaction { Transaction = transaction, VMState = VMState.HALT, BlockHash = UInt256.Zero, BlockTime = 100, Confirmations = 1 }.ToJson(client.protocolSettings)); + + var tx = await walletAPI.WaitTransactionAsync(transaction); + Assert.AreEqual(VMState.HALT, tx.VMState); + Assert.AreEqual(UInt256.Zero, tx.BlockHash); + } + } +} diff --git a/tests/Neo.Plugins.OracleService.Tests/Neo.Plugins.OracleService.Tests.csproj b/tests/Neo.Plugins.OracleService.Tests/Neo.Plugins.OracleService.Tests.csproj new file mode 100644 index 0000000000..388def4624 --- /dev/null +++ b/tests/Neo.Plugins.OracleService.Tests/Neo.Plugins.OracleService.Tests.csproj @@ -0,0 +1,28 @@ + + + + net8.0 + OracleService.Tests + Neo.Plugins + + + + + + + + + + + + + + + + + PreserveNewest + PreserveNewest + + + + diff --git a/tests/Neo.Plugins.OracleService.Tests/TestBlockchain.cs b/tests/Neo.Plugins.OracleService.Tests/TestBlockchain.cs new file mode 100644 index 0000000000..88c08575fa --- /dev/null +++ b/tests/Neo.Plugins.OracleService.Tests/TestBlockchain.cs @@ -0,0 +1,36 @@ +// 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 Neo.Persistence; +using System; + +namespace Neo.Plugins +{ + public static class TestBlockchain + { + public static readonly NeoSystem TheNeoSystem; + + static TestBlockchain() + { + Console.WriteLine("initialize NeoSystem"); + TheNeoSystem = new NeoSystem(ProtocolSettings.Load("config.json"), new MemoryStoreProvider()); + } + + public static void InitializeMockNeoSystem() + { + } + + internal static DataCache GetTestSnapshot() + { + return TheNeoSystem.GetSnapshot().CreateSnapshot(); + } + } +} diff --git a/tests/Neo.Plugins.OracleService.Tests/TestUtils.cs b/tests/Neo.Plugins.OracleService.Tests/TestUtils.cs new file mode 100644 index 0000000000..5700b83769 --- /dev/null +++ b/tests/Neo.Plugins.OracleService.Tests/TestUtils.cs @@ -0,0 +1,32 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// TestUtils.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.IO; +using Neo.SmartContract; +using Neo.SmartContract.Native; + +namespace Neo.Plugins +{ + public static class TestUtils + { + public static StorageKey CreateStorageKey(this NativeContract contract, byte prefix, ISerializable key) + { + var k = new KeyBuilder(contract.Id, prefix); + if (key != null) k = k.Add(key); + return k; + } + + public static StorageKey CreateStorageKey(this NativeContract contract, byte prefix, uint value) + { + return new KeyBuilder(contract.Id, prefix).AddBigEndian(value); + } + } +} diff --git a/tests/Neo.Plugins.OracleService.Tests/UT_OracleService.cs b/tests/Neo.Plugins.OracleService.Tests/UT_OracleService.cs new file mode 100644 index 0000000000..08f96c95d7 --- /dev/null +++ b/tests/Neo.Plugins.OracleService.Tests/UT_OracleService.cs @@ -0,0 +1,118 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_OracleService.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.TestKit.Xunit2; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Cryptography.ECC; +using Neo.Network.P2P.Payloads; +using Neo.SmartContract; +using Neo.SmartContract.Native; + +namespace Neo.Plugins.Tests +{ + [TestClass] + public class UT_OracleService : TestKit + { + [TestInitialize] + public void TestSetup() + { + TestBlockchain.InitializeMockNeoSystem(); + } + + [TestMethod] + public void TestFilter() + { + var json = @"{ + ""Stores"": [ + ""Lambton Quay"", + ""Willis Street"" + ], + ""Manufacturers"": [ + { + ""Name"": ""Acme Co"", + ""Products"": [ + { + ""Name"": ""Anvil"", + ""Price"": 50 + } + ] + }, + { + ""Name"": ""Contoso"", + ""Products"": [ + { + ""Name"": ""Elbow Grease"", + ""Price"": 99.95 + }, + { + ""Name"": ""Headlight Fluid"", + ""Price"": 4 + } + ] + } + ] +}"; + + Assert.AreEqual(@"[""Acme Co""]", Utility.StrictUTF8.GetString(OracleService.Filter(json, "$.Manufacturers[0].Name"))); + Assert.AreEqual("[50]", Utility.StrictUTF8.GetString(OracleService.Filter(json, "$.Manufacturers[0].Products[0].Price"))); + Assert.AreEqual(@"[""Elbow Grease""]", Utility.StrictUTF8.GetString(OracleService.Filter(json, "$.Manufacturers[1].Products[0].Name"))); + Assert.AreEqual(@"[{""Name"":""Elbow Grease"",""Price"":99.95}]", Utility.StrictUTF8.GetString(OracleService.Filter(json, "$.Manufacturers[1].Products[0]"))); + } + + [TestMethod] + public void TestCreateOracleResponseTx() + { + var snapshot = TestBlockchain.GetTestSnapshot(); + + var executionFactor = NativeContract.Policy.GetExecFeeFactor(snapshot); + Assert.AreEqual(executionFactor, (uint)30); + var feePerByte = NativeContract.Policy.GetFeePerByte(snapshot); + Assert.AreEqual(feePerByte, 1000); + + OracleRequest request = new OracleRequest + { + OriginalTxid = UInt256.Zero, + GasForResponse = 100000000 * 1, + Url = "https://127.0.0.1/test", + Filter = "", + CallbackContract = UInt160.Zero, + CallbackMethod = "callback", + UserData = System.Array.Empty() + }; + byte Prefix_Transaction = 11; + snapshot.Add(NativeContract.Ledger.CreateStorageKey(Prefix_Transaction, request.OriginalTxid), new StorageItem(new TransactionState() + { + BlockIndex = 1, + Transaction = new Transaction() + { + ValidUntilBlock = 1 + } + })); + 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); + + Assert.AreEqual(166, tx.Size); + Assert.AreEqual(2198650, tx.NetworkFee); + Assert.AreEqual(97801350, tx.SystemFee); + + // case (2) The size of attribute exceed the maximum limit + + request.GasForResponse = 0_10000000; + response.Result = new byte[10250]; + tx = OracleService.CreateResponseTx(snapshot, request, response, oracleNodes, ProtocolSettings.Default); + Assert.AreEqual(165, tx.Size); + Assert.AreEqual(OracleResponseCode.InsufficientFunds, response.Code); + Assert.AreEqual(2197650, tx.NetworkFee); + Assert.AreEqual(7802350, tx.SystemFee); + } + } +} diff --git a/tests/Neo.Plugins.OracleService.Tests/config.json b/tests/Neo.Plugins.OracleService.Tests/config.json new file mode 100644 index 0000000000..b4800b80ea --- /dev/null +++ b/tests/Neo.Plugins.OracleService.Tests/config.json @@ -0,0 +1,74 @@ +{ + "ApplicationConfiguration": { + "Logger": { + "Path": "Logs", + "ConsoleOutput": false, + "Active": false + }, + "Storage": { + "Engine": "LevelDBStore", // Candidates [MemoryStore, LevelDBStore, RocksDBStore] + "Path": "Data_LevelDB_{0}" // {0} is a placeholder for the network id + }, + "P2P": { + "Port": 10333, + "MinDesiredConnections": 10, + "MaxConnections": 40, + "MaxConnectionsPerAddress": 3 + }, + "UnlockWallet": { + "Path": "", + "Password": "", + "IsActive": false + }, + "Contracts": { + "NeoNameService": "0x50ac1c37690cc2cfc594472833cf57505d5f46de" + }, + "Plugins": { + "DownloadUrl": "https://api.github.com/repos/neo-project/neo-modules/releases" + } + }, + "ProtocolConfiguration": { + "Network": 860833102, + "AddressVersion": 53, + "MillisecondsPerBlock": 15000, + "MaxTransactionsPerBlock": 512, + "MemoryPoolMaxTransactions": 50000, + "MaxTraceableBlocks": 2102400, + "Hardforks": { + "HF_Aspidochelone": 1730000, + "HF_Basilisk": 4120000 + }, + "InitialGasDistribution": 5200000000000000, + "ValidatorsCount": 7, + "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/Neo.Plugins.RpcServer.Tests.csproj b/tests/Neo.Plugins.RpcServer.Tests/Neo.Plugins.RpcServer.Tests.csproj new file mode 100644 index 0000000000..4b5f60b96a --- /dev/null +++ b/tests/Neo.Plugins.RpcServer.Tests/Neo.Plugins.RpcServer.Tests.csproj @@ -0,0 +1,19 @@ + + + + net8.0 + Neo.Plugins.RpcServer.Tests + Neo.Plugins.RpcServer.Tests + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/Neo.Plugins.RpcServer.Tests/UT_RpcError.cs b/tests/Neo.Plugins.RpcServer.Tests/UT_RpcError.cs new file mode 100644 index 0000000000..d3c43a5458 --- /dev/null +++ b/tests/Neo.Plugins.RpcServer.Tests/UT_RpcError.cs @@ -0,0 +1,48 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_RpcError.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 System.Collections.Generic; +using System.Linq; +using System.Reflection; + +namespace Neo.Plugins.RpcServer.Tests +{ + [TestClass] + public class UT_RpcError + { + [TestMethod] + public void AllDifferent() + { + HashSet codes = new(); + + foreach (RpcError error in typeof(RpcError) + .GetFields(BindingFlags.Static | BindingFlags.Public) + .Where(u => u.DeclaringType == typeof(RpcError)) + .Select(u => u.GetValue(null)) + .Cast()) + { + Assert.IsTrue(codes.Add(error.ToString())); + + if (error.Code == RpcError.WalletFeeLimit.Code) + Assert.IsNotNull(error.Data); + else + Assert.IsNull(error.Data); + } + } + + [TestMethod] + public void TestJson() + { + Assert.AreEqual("{\"code\":-600,\"message\":\"Access denied\"}", RpcError.AccessDenied.ToJson().ToString(false)); + } + } +} diff --git a/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.cs b/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.cs new file mode 100644 index 0000000000..803980eb8f --- /dev/null +++ b/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.cs @@ -0,0 +1,20 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_RpcServer.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; + +namespace Neo.Plugins.RpcServer.Tests +{ + [TestClass] + public class UT_RpcServer + { + } +} diff --git a/tests/Neo.Plugins.Storage.Tests/Neo.Plugins.Storage.Tests.csproj b/tests/Neo.Plugins.Storage.Tests/Neo.Plugins.Storage.Tests.csproj new file mode 100644 index 0000000000..9ecf8ef16b --- /dev/null +++ b/tests/Neo.Plugins.Storage.Tests/Neo.Plugins.Storage.Tests.csproj @@ -0,0 +1,19 @@ + + + + net8.0 + Neo.Plugins.Storage.Tests + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/Neo.Plugins.Storage.Tests/StoreTest.cs b/tests/Neo.Plugins.Storage.Tests/StoreTest.cs new file mode 100644 index 0000000000..2773f92e80 --- /dev/null +++ b/tests/Neo.Plugins.Storage.Tests/StoreTest.cs @@ -0,0 +1,200 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// StoreTest.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.IO; +using System.Linq; + +namespace Neo.Plugins.Storage.Tests +{ + [TestClass] + public class StoreTest + { + private const string path_leveldb = "Data_LevelDB_UT"; + private const string path_rocksdb = "Data_RocksDB_UT"; + + [TestInitialize] + public void OnStart() + { + if (Directory.Exists(path_leveldb)) Directory.Delete(path_leveldb, true); + if (Directory.Exists(path_rocksdb)) Directory.Delete(path_rocksdb, true); + } + + [TestMethod] + public void TestMemory() + { + using var store = new MemoryStore(); + TestPersistenceDelete(store); + // Test all with the same store + + TestStorage(store); + + // Test with different storages + + TestPersistenceWrite(store); + TestPersistenceRead(store, true); + TestPersistenceDelete(store); + TestPersistenceRead(store, false); + } + + [TestMethod] + public void TestLevelDb() + { + using var plugin = new LevelDBStore(); + TestPersistenceDelete(plugin.GetStore(path_leveldb)); + // Test all with the same store + + TestStorage(plugin.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); + } + + [TestMethod] + public void TestRocksDb() + { + using var plugin = new RocksDBStore(); + TestPersistenceDelete(plugin.GetStore(path_rocksdb)); + // Test all with the same store + + TestStorage(plugin.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); + } + + /// + /// Test Put/Delete/TryGet/Seek + /// + /// Store + private void TestStorage(IStore store) + { + using (store) + { + var key1 = new byte[] { 0x01, 0x02 }; + var value1 = new byte[] { 0x03, 0x04 }; + + store.Delete(key1); + var ret = store.TryGet(key1); + Assert.IsNull(ret); + + store.Put(key1, value1); + ret = store.TryGet(key1); + CollectionAssert.AreEqual(value1, ret); + Assert.IsTrue(store.Contains(key1)); + + ret = store.TryGet(value1); + Assert.IsNull(ret); + Assert.IsTrue(store.Contains(key1)); + + store.Delete(key1); + + ret = store.TryGet(key1); + Assert.IsNull(ret); + Assert.IsFalse(store.Contains(key1)); + + // Test seek in order + + store.Put(new byte[] { 0x00, 0x00, 0x04 }, new byte[] { 0x04 }); + store.Put(new byte[] { 0x00, 0x00, 0x00 }, new byte[] { 0x00 }); + store.Put(new byte[] { 0x00, 0x00, 0x01 }, new byte[] { 0x01 }); + store.Put(new byte[] { 0x00, 0x00, 0x02 }, new byte[] { 0x02 }); + store.Put(new byte[] { 0x00, 0x00, 0x03 }, new byte[] { 0x03 }); + + // Seek Forward + + var entries = store.Seek(new byte[] { 0x00, 0x00, 0x02 }, SeekDirection.Forward).ToArray(); + Assert.AreEqual(3, entries.Length); + CollectionAssert.AreEqual(new byte[] { 0x00, 0x00, 0x02 }, entries[0].Key); + CollectionAssert.AreEqual(new byte[] { 0x02 }, entries[0].Value); + CollectionAssert.AreEqual(new byte[] { 0x00, 0x00, 0x03 }, entries[1].Key); + CollectionAssert.AreEqual(new byte[] { 0x03 }, entries[1].Value); + CollectionAssert.AreEqual(new byte[] { 0x00, 0x00, 0x04 }, entries[2].Key); + CollectionAssert.AreEqual(new byte[] { 0x04 }, entries[2].Value); + + // Seek Backward + + entries = store.Seek(new byte[] { 0x00, 0x00, 0x02 }, SeekDirection.Backward).ToArray(); + Assert.AreEqual(3, entries.Length); + CollectionAssert.AreEqual(new byte[] { 0x00, 0x00, 0x02 }, entries[0].Key); + CollectionAssert.AreEqual(new byte[] { 0x02 }, entries[0].Value); + CollectionAssert.AreEqual(new byte[] { 0x00, 0x00, 0x01 }, entries[1].Key); + CollectionAssert.AreEqual(new byte[] { 0x01 }, entries[1].Value); + + // Seek Backward + store.Delete(new byte[] { 0x00, 0x00, 0x00 }); + store.Delete(new byte[] { 0x00, 0x00, 0x01 }); + store.Delete(new byte[] { 0x00, 0x00, 0x02 }); + store.Delete(new byte[] { 0x00, 0x00, 0x03 }); + store.Delete(new byte[] { 0x00, 0x00, 0x04 }); + store.Put(new byte[] { 0x00, 0x00, 0x00 }, new byte[] { 0x00 }); + store.Put(new byte[] { 0x00, 0x00, 0x01 }, new byte[] { 0x01 }); + store.Put(new byte[] { 0x00, 0x01, 0x02 }, new byte[] { 0x02 }); + + entries = store.Seek(new byte[] { 0x00, 0x00, 0x03 }, SeekDirection.Backward).ToArray(); + Assert.AreEqual(2, entries.Length); + CollectionAssert.AreEqual(new byte[] { 0x00, 0x00, 0x01 }, entries[0].Key); + CollectionAssert.AreEqual(new byte[] { 0x01 }, entries[0].Value); + CollectionAssert.AreEqual(new byte[] { 0x00, 0x00, 0x00 }, entries[1].Key); + CollectionAssert.AreEqual(new byte[] { 0x00 }, entries[1].Value); + } + } + + /// + /// Test Put + /// + /// Store + private void TestPersistenceWrite(IStore store) + { + using (store) + { + store.Put(new byte[] { 0x01, 0x02, 0x03 }, new byte[] { 0x04, 0x05, 0x06 }); + } + } + + /// + /// Test Put + /// + /// Store + private void TestPersistenceDelete(IStore store) + { + using (store) + { + store.Delete(new byte[] { 0x01, 0x02, 0x03 }); + } + } + + /// + /// Test Read + /// + /// Store + /// Should exist + private void TestPersistenceRead(IStore store, bool shouldExist) + { + using (store) + { + var ret = store.TryGet(new byte[] { 0x01, 0x02, 0x03 }); + + if (shouldExist) CollectionAssert.AreEqual(new byte[] { 0x04, 0x05, 0x06 }, ret); + else Assert.IsNull(ret); + } + } + } +} From f8c43cf24ad5116f2f0f9e7cc5fa2285581ff2e3 Mon Sep 17 00:00:00 2001 From: Anna Shaleva Date: Tue, 21 May 2024 11:14:01 +0300 Subject: [PATCH 136/168] Native: include DeprecatedIn hardfork into usedHardforks (#3245) DeprecatedIn hardfork of every native method (if not null) should be included into the set of used hardforks, otherwise no contract update will be performed on this hardfork activation: https://github.com/neo-project/neo/blob/08f2dfc56762bb43be33e873bc3659bad368d4d6/src/Neo/SmartContract/Native/NativeContract.cs#L279-L284 https://github.com/neo-project/neo/blob/08f2dfc56762bb43be33e873bc3659bad368d4d6/src/Neo/SmartContract/Native/ContractManagement.cs#L69-L73 This commit should be a part of #3234 and a part of 3.7.4. Luckily, this new DeprecatedIn functionality is used only for the old native CryptoLib's verifyWithECDsa method with Cockatrice hardfork. And luckily, there are other CryptoLib's methods with ActiveIn set to Cockatrice hardfork. Due to these two facts this bug does not affect mainnet/testnet, and thus we don't need 3.7.5 with this fix included. So this fix may safely be postponed to 3.8.0. Signed-off-by: Anna Shaleva Co-authored-by: Shargon --- src/Neo/SmartContract/Native/NativeContract.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Neo/SmartContract/Native/NativeContract.cs b/src/Neo/SmartContract/Native/NativeContract.cs index 55e88b2ec6..03815b3fae 100644 --- a/src/Neo/SmartContract/Native/NativeContract.cs +++ b/src/Neo/SmartContract/Native/NativeContract.cs @@ -160,6 +160,7 @@ protected NativeContract() // Calculate the initializations forks usedHardforks = methodDescriptors.Select(u => u.ActiveIn) + .Concat(methodDescriptors.Select(u => u.DeprecatedIn)) .Concat(eventsDescriptors.Select(u => u.ActiveIn)) .Concat(new Hardfork?[] { ActiveIn }) .Where(u => u is not null) From 2db4a17dd33db980db9a6860b66fb1f7ac248094 Mon Sep 17 00:00:00 2001 From: Hecate2 <2474101468@qq.com> Date: Wed, 22 May 2024 18:04:55 +0800 Subject: [PATCH 137/168] fix TraverseIterator count (#3261) --- src/Plugins/RpcServer/RpcServer.SmartContract.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Plugins/RpcServer/RpcServer.SmartContract.cs b/src/Plugins/RpcServer/RpcServer.SmartContract.cs index 0fe6fc0c1d..92ea7ff62c 100644 --- a/src/Plugins/RpcServer/RpcServer.SmartContract.cs +++ b/src/Plugins/RpcServer/RpcServer.SmartContract.cs @@ -246,7 +246,7 @@ protected virtual JToken TraverseIterator(JArray _params) Guid sid = Result.Ok_Or(() => Guid.Parse(_params[0].GetString()), RpcError.InvalidParams.WithData($"Invalid session id {nameof(sid)}")); Guid iid = Result.Ok_Or(() => Guid.Parse(_params[1].GetString()), RpcError.InvalidParams.WithData($"Invliad iterator id {nameof(iid)}")); int count = _params[2].GetInt32(); - Result.True_Or(() => count > settings.MaxIteratorResultItems, RpcError.InvalidParams.WithData($"Invalid iterator items count {nameof(count)}")); + Result.True_Or(() => count <= settings.MaxIteratorResultItems, RpcError.InvalidParams.WithData($"Invalid iterator items count {nameof(count)}")); Session session; lock (sessions) { From d3cde6d8c07969cdf8fd49fb9c9993aaeb668649 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vitor=20Naz=C3=A1rio=20Coelho?= Date: Wed, 22 May 2024 07:58:28 -0300 Subject: [PATCH 138/168] COVERALL: fix broken by changing report from lcov to cobertura (#3252) * Update main.yml * Update main.yml * Update main.yml * Update main.yml * try with * * Update main.yml * Update main.yml * Apply suggestions from code review --------- Co-authored-by: Shargon --- .github/workflows/main.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 6f7f9867c8..5d34cb9740 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -51,15 +51,15 @@ jobs: dotnet test ./tests/Neo.Network.RPC.Tests /p:CollectCoverage=true /p:CoverletOutput='${{ github.workspace }}/TestResults/coverage/' /p:MergeWith='${{ github.workspace }}/TestResults/coverage/coverage.json' dotnet test ./tests/Neo.Plugins.OracleService.Tests /p:CollectCoverage=true /p:CoverletOutput='${{ github.workspace }}/TestResults/coverage/' /p:MergeWith='${{ github.workspace }}/TestResults/coverage/coverage.json' dotnet test ./tests/Neo.Plugins.RpcServer.Tests /p:CollectCoverage=true /p:CoverletOutput='${{ github.workspace }}/TestResults/coverage/' /p:MergeWith='${{ github.workspace }}/TestResults/coverage/coverage.json' - dotnet test ./tests/Neo.Plugins.Storage.Tests /p:CollectCoverage=true /p:CoverletOutput='${{ github.workspace }}/TestResults/coverage/' /p:MergeWith='${{ github.workspace }}/TestResults/coverage/coverage.json' /p:CoverletOutputFormat='lcov' - + dotnet test ./tests/Neo.Plugins.Storage.Tests /p:CollectCoverage=true /p:CoverletOutput='${{ github.workspace }}/TestResults/coverage/' /p:MergeWith='${{ github.workspace }}/TestResults/coverage/coverage.json' /p:CoverletOutputFormat='cobertura' + - name: Coveralls if: matrix.os == 'ubuntu-latest' - uses: coverallsapp/github-action@v2.2.3 + uses: coverallsapp/github-action@v2.3.0 with: github-token: ${{ secrets.GITHUB_TOKEN }} - format: lcov - file: ${{ github.workspace }}/TestResults/coverage/coverage.info + format: cobertura + file: ${{ github.workspace }}/TestResults/coverage/coverage.cobertura.xml PublishPackage: if: github.ref == 'refs/heads/master' && startsWith(github.repository, 'neo-project/') From 8119830edfee598d90b024014b86db4cf65072df Mon Sep 17 00:00:00 2001 From: Hecate2 <2474101468@qq.com> Date: Wed, 22 May 2024 19:10:04 +0800 Subject: [PATCH 139/168] fix CancelTransaction !signers.Any() (#3263) Co-authored-by: Shargon --- src/Plugins/RpcServer/RpcServer.Wallet.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Plugins/RpcServer/RpcServer.Wallet.cs b/src/Plugins/RpcServer/RpcServer.Wallet.cs index 8085c1bd35..36825b3f82 100644 --- a/src/Plugins/RpcServer/RpcServer.Wallet.cs +++ b/src/Plugins/RpcServer/RpcServer.Wallet.cs @@ -316,7 +316,7 @@ protected virtual JToken CancelTransaction(JArray _params) var conflict = new TransactionAttribute[] { new Conflicts() { Hash = txid } }; Signer[] signers = _params.Count >= 2 ? ((JArray)_params[1]).Select(j => new Signer() { Account = AddressToScriptHash(j.AsString(), system.Settings.AddressVersion), Scopes = WitnessScope.None }).ToArray() : Array.Empty(); - (!signers.Any()).True_Or(RpcErrorFactory.BadRequest("No signer.")); + signers.Any().True_Or(RpcErrorFactory.BadRequest("No signer.")); Transaction tx = new Transaction { Signers = signers, From 955c0771b43e8f2f181b92360db4bc5e2e9fb2b5 Mon Sep 17 00:00:00 2001 From: Shargon Date: Wed, 22 May 2024 04:14:48 -0700 Subject: [PATCH 140/168] Optimize plugin's models (#3246) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jimmy Co-authored-by: Vitor Nazário Coelho --- .../Store/Models/ApplicationEngineLogModel.cs | 4 ++-- .../Store/Models/BlockchainEventModel.cs | 12 ++++++------ .../Store/Models/BlockchainExecutionModel.cs | 18 ++++++++++-------- 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/Plugins/ApplicationLogs/Store/Models/ApplicationEngineLogModel.cs b/src/Plugins/ApplicationLogs/Store/Models/ApplicationEngineLogModel.cs index 112cc49377..9836db7146 100644 --- a/src/Plugins/ApplicationLogs/Store/Models/ApplicationEngineLogModel.cs +++ b/src/Plugins/ApplicationLogs/Store/Models/ApplicationEngineLogModel.cs @@ -15,8 +15,8 @@ namespace Neo.Plugins.Store.Models { public class ApplicationEngineLogModel { - public UInt160 ScriptHash { get; private init; } = new(); - public string Message { get; private init; } = string.Empty; + public required UInt160 ScriptHash { get; init; } + public required string Message { get; init; } public static ApplicationEngineLogModel Create(EngineLogState logEventState) => new() diff --git a/src/Plugins/ApplicationLogs/Store/Models/BlockchainEventModel.cs b/src/Plugins/ApplicationLogs/Store/Models/BlockchainEventModel.cs index 09245db295..a882ff1a8c 100644 --- a/src/Plugins/ApplicationLogs/Store/Models/BlockchainEventModel.cs +++ b/src/Plugins/ApplicationLogs/Store/Models/BlockchainEventModel.cs @@ -17,11 +17,11 @@ namespace ApplicationLogs.Store.Models { public class BlockchainEventModel { - public UInt160 ScriptHash { get; private init; } = new(); - public string EventName { get; private init; } = string.Empty; - public StackItem[] State { get; private init; } = []; + public required UInt160 ScriptHash { get; init; } + public required string EventName { get; init; } + public required StackItem[] State { get; init; } - public static BlockchainEventModel Create(UInt160 scriptHash, string eventName, StackItem[] state) => + public static BlockchainEventModel Create(UInt160 scriptHash, string eventName, params StackItem[] state) => new() { ScriptHash = scriptHash, @@ -29,7 +29,7 @@ public static BlockchainEventModel Create(UInt160 scriptHash, string eventName, State = state, }; - public static BlockchainEventModel Create(NotifyLogState notifyLogState, StackItem[] state) => + public static BlockchainEventModel Create(NotifyLogState notifyLogState, params StackItem[] state) => new() { ScriptHash = notifyLogState.ScriptHash, @@ -37,7 +37,7 @@ public static BlockchainEventModel Create(NotifyLogState notifyLogState, StackIt State = state, }; - public static BlockchainEventModel Create(ContractLogState contractLogState, StackItem[] state) => + public static BlockchainEventModel Create(ContractLogState contractLogState, params StackItem[] state) => new() { ScriptHash = contractLogState.ScriptHash, diff --git a/src/Plugins/ApplicationLogs/Store/Models/BlockchainExecutionModel.cs b/src/Plugins/ApplicationLogs/Store/Models/BlockchainExecutionModel.cs index e31ecd0d0c..19a3de5749 100644 --- a/src/Plugins/ApplicationLogs/Store/Models/BlockchainExecutionModel.cs +++ b/src/Plugins/ApplicationLogs/Store/Models/BlockchainExecutionModel.cs @@ -19,15 +19,15 @@ namespace ApplicationLogs.Store.Models { public class BlockchainExecutionModel { - public TriggerType Trigger { get; private init; } = TriggerType.All; - public VMState VmState { get; private init; } = VMState.NONE; - public string Exception { get; private init; } = string.Empty; - public long GasConsumed { get; private init; } = 0L; - public StackItem[] Stack { get; private init; } = []; - public BlockchainEventModel[] Notifications { get; set; } = []; - public ApplicationEngineLogModel[] Logs { get; set; } = []; + public required TriggerType Trigger { get; init; } + public required VMState VmState { get; init; } + public required string Exception { get; init; } + public required long GasConsumed { get; init; } + public required StackItem[] Stack { get; init; } + public required BlockchainEventModel[] Notifications { get; set; } + public required ApplicationEngineLogModel[] Logs { get; set; } - public static BlockchainExecutionModel Create(TriggerType trigger, ExecutionLogState executionLogState, StackItem[] stack) => + public static BlockchainExecutionModel Create(TriggerType trigger, ExecutionLogState executionLogState, params StackItem[] stack) => new() { Trigger = trigger, @@ -35,6 +35,8 @@ public static BlockchainExecutionModel Create(TriggerType trigger, ExecutionLogS Exception = executionLogState.Exception ?? string.Empty, GasConsumed = executionLogState.GasConsumed, Stack = stack, + Notifications = [], + Logs = [] }; } } From c05e50ace25c31acd28039957cce95bba11d992c Mon Sep 17 00:00:00 2001 From: Shargon Date: Wed, 22 May 2024 09:10:17 -0700 Subject: [PATCH 141/168] Add optimization to template (#3247) * Add optimization to template * Update .github/PULL_REQUEST_TEMPLATE.md * Update .github/PULL_REQUEST_TEMPLATE.md * Update .github/PULL_REQUEST_TEMPLATE.md Co-authored-by: Jimmy --------- Co-authored-by: Jimmy --- .github/PULL_REQUEST_TEMPLATE.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 7b043f14a7..4ebc00ed19 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -8,6 +8,8 @@ Fixes # (issue) +- [ ] Optimization (the change is only an optimization) +- [ ] Style (the change is only a code style for better maintenance or standard purpose) - [ ] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) From cf70a69c4de613cdc1b9e8a0eec753f8ef26925c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vitor=20Naz=C3=A1rio=20Coelho?= Date: Wed, 22 May 2024 14:03:16 -0300 Subject: [PATCH 142/168] Fix and Update devcontainer.json to use Dockerfile (#3259) * Update devcontainer.json * Create Dockerfile * Update devcontainer.json * Rename Dockerfile to devcontainer.dockerfile * Update .devcontainer/devcontainer.json --------- Co-authored-by: Shargon --- .devcontainer/devcontainer.dockerfile | 3 +++ .devcontainer/devcontainer.json | 5 ++++- 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 .devcontainer/devcontainer.dockerfile diff --git a/.devcontainer/devcontainer.dockerfile b/.devcontainer/devcontainer.dockerfile new file mode 100644 index 0000000000..3b16107e9e --- /dev/null +++ b/.devcontainer/devcontainer.dockerfile @@ -0,0 +1,3 @@ +FROM mcr.microsoft.com/devcontainers/dotnet:8.0-jammy +# Install the libleveldb-dev package +RUN apt-get update && apt-get install -y libleveldb-dev diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 00807d9b64..5e9bdf6374 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -2,7 +2,10 @@ // README at: https://github.com/devcontainers/templates/tree/main/src/dotnet { "name": "C# (.NET)", - "image": "mcr.microsoft.com/devcontainers/dotnet:1-8.0-jammy", + "build": { + // Path is relative to the devcontainer.json file. + "dockerfile": "devcontainer.dockerfile" + }, "postCreateCommand": "dotnet build", "customizations": { "vscode": { From 793b04824d7ade5628f621497e7a5965a53c58a9 Mon Sep 17 00:00:00 2001 From: Shargon Date: Wed, 22 May 2024 11:31:14 -0700 Subject: [PATCH 143/168] Fix `dotnet pack` error (#3266) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update nugets * use same path --------- Co-authored-by: Vitor Nazário Coelho --- src/Directory.Build.props | 4 ++-- src/Plugins/Directory.Build.props | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Directory.Build.props b/src/Directory.Build.props index d3de66b478..c211ee34aa 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 4eb51eef9b..b921258ed3 100644 --- a/src/Plugins/Directory.Build.props +++ b/src/Plugins/Directory.Build.props @@ -4,8 +4,8 @@ - - + + From 6c267fb5d6f3b02ca37befac5b036979821654cc Mon Sep 17 00:00:00 2001 From: Christopher Schuchardt Date: Wed, 22 May 2024 16:36:17 -0400 Subject: [PATCH 144/168] [**Part-2**] Neo module/master fixes (#3244) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Moved `neo-modules` to `neo` * Configured module projects * Configured Test Projects * Dotnet format * Update github workflow for tests * removed dupes in `.editorconfig` * remove dupe file * Fixed waarning * fixed `macOS` workflow for leveldb * Added `EXCLUDED_TESTS` for `Neo.Plugins.Storage` on `macOS` and `Windows` * Fixed workflow tests for `windows` * Fixed `char` ecsape for tests on `windows` * Fixed tests * Fixed tests * Apply suggestions from code review Not related to the PR * Apply suggestions from code review * Update .editorconfig * Update .editorconfig * Changed for @vncoelho request * Added @vncoelho changes * Moved `RpcClient` to `src\plugins` * fixed rpc tests * Update .github/workflows/main.yml Co-authored-by: Shargon * Update .github/workflows/main.yml * Update .github/workflows/main.yml * Plugin fixes for `configuration` files * Renamed file extensions from `config` to `json` * removed dev files * dotnet format * Deleted old `config.json` files * Renamed `system` to `_system` * PreserveNewest instead of always --------- Co-authored-by: Shargon Co-authored-by: Vitor Nazário Coelho --- .../ApplicationLogs/ApplicationLogs.csproj | 5 +++ .../{config.json => ApplicationLogs.json} | 0 src/Plugins/ApplicationLogs/LogReader.cs | 4 ++- src/Plugins/DBFTPlugin/DBFTPlugin.cs | 2 ++ src/Plugins/DBFTPlugin/DBFTPlugin.csproj | 6 ++++ .../{config.json => DBFTPlugin.json} | 0 src/Plugins/Directory.Build.props | 6 ---- src/Plugins/OracleService/OracleService.cs | 36 ++++++++++--------- .../OracleService/OracleService.csproj | 6 ++++ .../{config.json => OracleService.json} | 0 src/Plugins/RpcServer/RpcServer.csproj | 8 ++++- .../RpcServer/{config.json => RpcServer.json} | 0 src/Plugins/RpcServer/RpcServerPlugin.cs | 2 ++ src/Plugins/StateService/StatePlugin.cs | 25 ++++++------- src/Plugins/StateService/StateService.csproj | 6 ++++ .../{config.json => StateService.json} | 0 .../StateService/Storage/StateStore.cs | 6 ++-- .../Verification/VerificationContext.cs | 10 +++--- .../Verification/VerificationService.cs | 8 ++--- src/Plugins/StatesDumper/StatesDumper.cs | 2 ++ src/Plugins/StatesDumper/StatesDumper.csproj | 6 ++++ .../{config.json => StatesDumper.json} | 0 src/Plugins/StorageDumper/StorageDumper.cs | 2 ++ .../StorageDumper/StorageDumper.csproj | 6 ++++ .../{config.json => StorageDumper.json} | 0 src/Plugins/TokensTracker/TokensTracker.cs | 2 ++ .../TokensTracker/TokensTracker.csproj | 8 ++++- .../{config.json => TokensTracker.json} | 0 28 files changed, 107 insertions(+), 49 deletions(-) rename src/Plugins/ApplicationLogs/{config.json => ApplicationLogs.json} (100%) rename src/Plugins/DBFTPlugin/{config.json => DBFTPlugin.json} (100%) rename src/Plugins/OracleService/{config.json => OracleService.json} (100%) rename src/Plugins/RpcServer/{config.json => RpcServer.json} (100%) rename src/Plugins/StateService/{config.json => StateService.json} (100%) rename src/Plugins/StatesDumper/{config.json => StatesDumper.json} (100%) rename src/Plugins/StorageDumper/{config.json => StorageDumper.json} (100%) rename src/Plugins/TokensTracker/{config.json => TokensTracker.json} (100%) diff --git a/src/Plugins/ApplicationLogs/ApplicationLogs.csproj b/src/Plugins/ApplicationLogs/ApplicationLogs.csproj index 2079abfcff..89eea3b1bb 100644 --- a/src/Plugins/ApplicationLogs/ApplicationLogs.csproj +++ b/src/Plugins/ApplicationLogs/ApplicationLogs.csproj @@ -13,4 +13,9 @@ runtime + + + PreserveNewest + + \ No newline at end of file diff --git a/src/Plugins/ApplicationLogs/config.json b/src/Plugins/ApplicationLogs/ApplicationLogs.json similarity index 100% rename from src/Plugins/ApplicationLogs/config.json rename to src/Plugins/ApplicationLogs/ApplicationLogs.json diff --git a/src/Plugins/ApplicationLogs/LogReader.cs b/src/Plugins/ApplicationLogs/LogReader.cs index 56163ef4f1..4de4237acb 100644 --- a/src/Plugins/ApplicationLogs/LogReader.cs +++ b/src/Plugins/ApplicationLogs/LogReader.cs @@ -36,7 +36,7 @@ public class LogReader : Plugin #endregion public override string Name => "ApplicationLogs"; - public override string Description => "Synchronizes smart contract VM executions and notificatons (NotifyLog) on blockchain."; + public override string Description => "Synchronizes smart contract VM executions and notifications (NotifyLog) on blockchain."; #region Ctor @@ -51,6 +51,8 @@ public LogReader() #region Override Methods + public override string ConfigFile => Combine(RootPath, "ApplicationLogs.json"); + public override void Dispose() { Blockchain.Committing -= OnCommitting; diff --git a/src/Plugins/DBFTPlugin/DBFTPlugin.cs b/src/Plugins/DBFTPlugin/DBFTPlugin.cs index 7fa29ce0dd..59191d2881 100644 --- a/src/Plugins/DBFTPlugin/DBFTPlugin.cs +++ b/src/Plugins/DBFTPlugin/DBFTPlugin.cs @@ -28,6 +28,8 @@ public class DBFTPlugin : Plugin public override string Description => "Consensus plugin with dBFT algorithm."; + public override string ConfigFile => System.IO.Path.Combine(RootPath, "DBFTPlugin.json"); + public DBFTPlugin() { RemoteNode.MessageReceived += RemoteNode_MessageReceived; diff --git a/src/Plugins/DBFTPlugin/DBFTPlugin.csproj b/src/Plugins/DBFTPlugin/DBFTPlugin.csproj index fe681cf2ed..b04e2e5c4f 100644 --- a/src/Plugins/DBFTPlugin/DBFTPlugin.csproj +++ b/src/Plugins/DBFTPlugin/DBFTPlugin.csproj @@ -10,4 +10,10 @@ + + + PreserveNewest + + + diff --git a/src/Plugins/DBFTPlugin/config.json b/src/Plugins/DBFTPlugin/DBFTPlugin.json similarity index 100% rename from src/Plugins/DBFTPlugin/config.json rename to src/Plugins/DBFTPlugin/DBFTPlugin.json diff --git a/src/Plugins/Directory.Build.props b/src/Plugins/Directory.Build.props index b921258ed3..f7bcef093b 100644 --- a/src/Plugins/Directory.Build.props +++ b/src/Plugins/Directory.Build.props @@ -12,10 +12,4 @@ - - - PreserveNewest - PreserveNewest - - diff --git a/src/Plugins/OracleService/OracleService.cs b/src/Plugins/OracleService/OracleService.cs index bdbbc5869e..637c06712f 100644 --- a/src/Plugins/OracleService/OracleService.cs +++ b/src/Plugins/OracleService/OracleService.cs @@ -54,12 +54,14 @@ public class OracleService : Plugin private OracleStatus status = OracleStatus.Unstarted; private IWalletProvider walletProvider; private int counter; - private NeoSystem System; + private NeoSystem _system; private readonly Dictionary protocols = new Dictionary(); public override string Description => "Built-in oracle plugin"; + public override string ConfigFile => System.IO.Path.Combine(RootPath, "OracleService.json"); + public OracleService() { Blockchain.Committing += OnCommitting; @@ -75,8 +77,8 @@ protected override void Configure() protected override void OnSystemLoaded(NeoSystem system) { if (system.Settings.Network != Settings.Default.Network) return; - System = system; - System.ServiceAdded += NeoSystem_ServiceAdded; + _system = system; + _system.ServiceAdded += NeoSystem_ServiceAdded; RpcServerPlugin.RegisterMethods(this, Settings.Default.Network); } @@ -85,7 +87,7 @@ private void NeoSystem_ServiceAdded(object sender, object service) if (service is IWalletProvider) { walletProvider = service as IWalletProvider; - System.ServiceAdded -= NeoSystem_ServiceAdded; + _system.ServiceAdded -= NeoSystem_ServiceAdded; if (Settings.Default.AutoStart) { walletProvider.WalletChanged += WalletProvider_WalletChanged; @@ -124,7 +126,8 @@ public void Start(Wallet wallet) ConsoleHelper.Warning("Please open wallet first!"); return; } - if (!CheckOracleAvaiblable(System.StoreView, out ECPoint[] oracles)) + + if (!CheckOracleAvaiblable(_system.StoreView, out ECPoint[] oracles)) { ConsoleHelper.Warning("The oracle service is unavailable"); return; @@ -228,7 +231,7 @@ public JObject SubmitOracleResponse(JArray _params) finishedCache.ContainsKey(requestId).False_Or(RpcError.OracleRequestFinished); - using (var snapshot = System.GetSnapshot()) + using (var snapshot = _system.GetSnapshot()) { uint height = NativeContract.Ledger.CurrentIndex(snapshot) + 1; var oracles = NativeContract.RoleManagement.GetDesignatedByRole(snapshot, Role.Oracle, height); @@ -292,8 +295,8 @@ private async Task ProcessRequestAsync(DataCache snapshot, OracleRequest req) } } var response = new OracleResponse() { Id = requestId, Code = code, Result = result }; - var responseTx = CreateResponseTx(snapshot, request, response, oracleNodes, System.Settings); - var backupTx = CreateResponseTx(snapshot, request, new OracleResponse() { Code = OracleResponseCode.ConsensusUnreachable, Id = requestId, Result = Array.Empty() }, oracleNodes, System.Settings, true); + var responseTx = CreateResponseTx(snapshot, request, response, oracleNodes, _system.Settings); + var backupTx = CreateResponseTx(snapshot, request, new OracleResponse() { Code = OracleResponseCode.ConsensusUnreachable, Id = requestId, Result = Array.Empty() }, oracleNodes, _system.Settings, true); Log($"[{req.OriginalTxid}]-({requestId}) Built response tx[[{responseTx.Hash}]], responseCode:{code}, result:{result.ToHexString()}, validUntilBlock:{responseTx.ValidUntilBlock}, backupTx:{backupTx.Hash}-{backupTx.ValidUntilBlock}"); @@ -304,8 +307,9 @@ private async Task ProcessRequestAsync(DataCache snapshot, OracleRequest req) var oraclePub = account.GetKey()?.PublicKey; if (!account.HasKey || account.Lock || !oraclePublicKeys.Contains(oraclePub)) continue; - var txSign = responseTx.Sign(account.GetKey(), System.Settings.Network); - var backTxSign = backupTx.Sign(account.GetKey(), System.Settings.Network); + var txSign = responseTx.Sign(account.GetKey(), _system.Settings.Network); + var backTxSign = backupTx.Sign(account.GetKey(), _system.Settings.Network); + AddResponseTxSign(snapshot, requestId, oraclePub, txSign, responseTx, backupTx, backTxSign); tasks.Add(SendResponseSignatureAsync(requestId, txSign, account.GetKey())); @@ -319,7 +323,7 @@ private async void ProcessRequestsAsync() { while (!cancelSource.IsCancellationRequested) { - using (var snapshot = System.GetSnapshot()) + using (var snapshot = _system.GetSnapshot()) { SyncPendingQueue(snapshot); foreach (var (id, request) in NativeContract.Oracle.GetRequests(snapshot)) @@ -473,13 +477,13 @@ private void AddResponseTxSign(DataCache snapshot, ulong requestId, ECPoint orac if (responseTx != null) { task.Tx = responseTx; - var data = task.Tx.GetSignData(System.Settings.Network); + var data = task.Tx.GetSignData(_system.Settings.Network); task.Signs.Where(p => !Crypto.VerifySignature(data, p.Value, p.Key)).ForEach(p => task.Signs.Remove(p.Key, out _)); } if (backupTx != null) { task.BackupTx = backupTx; - var data = task.BackupTx.GetSignData(System.Settings.Network); + var data = task.BackupTx.GetSignData(_system.Settings.Network); task.BackupSigns.Where(p => !Crypto.VerifySignature(data, p.Value, p.Key)).ForEach(p => task.BackupSigns.Remove(p.Key, out _)); task.BackupSigns.TryAdd(oraclePub, backupSign); } @@ -490,9 +494,9 @@ private void AddResponseTxSign(DataCache snapshot, ulong requestId, ECPoint orac return; } - if (Crypto.VerifySignature(task.Tx.GetSignData(System.Settings.Network), sign, oraclePub)) + if (Crypto.VerifySignature(task.Tx.GetSignData(_system.Settings.Network), sign, oraclePub)) task.Signs.TryAdd(oraclePub, sign); - else if (Crypto.VerifySignature(task.BackupTx.GetSignData(System.Settings.Network), sign, oraclePub)) + else if (Crypto.VerifySignature(task.BackupTx.GetSignData(_system.Settings.Network), sign, oraclePub)) task.BackupSigns.TryAdd(oraclePub, sign); else throw new RpcException(RpcErrorFactory.InvalidSignature($"Invalid oracle response transaction signature from '{oraclePub}'.")); @@ -537,7 +541,7 @@ private bool CheckTxSign(DataCache snapshot, Transaction tx, ConcurrentDictionar Log($"Send response tx: responseTx={tx.Hash}"); - System.Blockchain.Tell(tx); + _system.Blockchain.Tell(tx); return true; } return false; diff --git a/src/Plugins/OracleService/OracleService.csproj b/src/Plugins/OracleService/OracleService.csproj index a5df44e75c..48ca5f3808 100644 --- a/src/Plugins/OracleService/OracleService.csproj +++ b/src/Plugins/OracleService/OracleService.csproj @@ -17,4 +17,10 @@ + + + PreserveNewest + + + \ No newline at end of file diff --git a/src/Plugins/OracleService/config.json b/src/Plugins/OracleService/OracleService.json similarity index 100% rename from src/Plugins/OracleService/config.json rename to src/Plugins/OracleService/OracleService.json diff --git a/src/Plugins/RpcServer/RpcServer.csproj b/src/Plugins/RpcServer/RpcServer.csproj index 5629732771..ab2d7e6783 100644 --- a/src/Plugins/RpcServer/RpcServer.csproj +++ b/src/Plugins/RpcServer/RpcServer.csproj @@ -1,4 +1,4 @@ - + net8.0 @@ -9,4 +9,10 @@ + + + PreserveNewest + + + diff --git a/src/Plugins/RpcServer/config.json b/src/Plugins/RpcServer/RpcServer.json similarity index 100% rename from src/Plugins/RpcServer/config.json rename to src/Plugins/RpcServer/RpcServer.json diff --git a/src/Plugins/RpcServer/RpcServerPlugin.cs b/src/Plugins/RpcServer/RpcServerPlugin.cs index bc51d63948..61d9da4397 100644 --- a/src/Plugins/RpcServer/RpcServerPlugin.cs +++ b/src/Plugins/RpcServer/RpcServerPlugin.cs @@ -23,6 +23,8 @@ public class RpcServerPlugin : Plugin private static readonly Dictionary servers = new(); private static readonly Dictionary> handlers = new(); + public override string ConfigFile => System.IO.Path.Combine(RootPath, "RpcServer.json"); + protected override void Configure() { settings = new Settings(GetConfiguration()); diff --git a/src/Plugins/StateService/StatePlugin.cs b/src/Plugins/StateService/StatePlugin.cs index dda1e1aff4..36d2c01050 100644 --- a/src/Plugins/StateService/StatePlugin.cs +++ b/src/Plugins/StateService/StatePlugin.cs @@ -37,11 +37,12 @@ public class StatePlugin : Plugin public const string StatePayloadCategory = "StateService"; public override string Name => "StateService"; public override string Description => "Enables MPT for the node"; + public override string ConfigFile => System.IO.Path.Combine(RootPath, "StateService.json"); internal IActorRef Store; internal IActorRef Verifier; - internal static NeoSystem System; + internal static NeoSystem _system; private IWalletProvider walletProvider; public StatePlugin() @@ -58,9 +59,9 @@ protected override void Configure() 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 = system; + Store = _system.ActorSystem.ActorOf(StateStore.Props(this, string.Format(Settings.Default.Path, system.Settings.Network.ToString("X8")))); + _system.ServiceAdded += NeoSystem_ServiceAdded; RpcServerPlugin.RegisterMethods(this, Settings.Default.Network); } @@ -69,7 +70,7 @@ private void NeoSystem_ServiceAdded(object sender, object service) if (service is IWalletProvider) { walletProvider = service as IWalletProvider; - System.ServiceAdded -= NeoSystem_ServiceAdded; + _system.ServiceAdded -= NeoSystem_ServiceAdded; if (Settings.Default.AutoVerify) { walletProvider.WalletChanged += WalletProvider_WalletChanged; @@ -88,8 +89,8 @@ public override void Dispose() base.Dispose(); Blockchain.Committing -= OnCommitting; Blockchain.Committed -= OnCommitted; - if (Store is not null) System.EnsureStopped(Store); - if (Verifier is not null) System.EnsureStopped(Verifier); + 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) @@ -107,7 +108,7 @@ private void OnCommitted(NeoSystem system, Block block) [ConsoleCommand("start states", Category = "StateService", Description = "Start as a state verifier if wallet is open")] private void OnStartVerifyingState() { - if (System is null || System.Settings.Network != Settings.Default.Network) throw new InvalidOperationException("Network doesn't match"); + if (_system is null || _system.Settings.Network != Settings.Default.Network) throw new InvalidOperationException("Network doesn't match"); Start(walletProvider.GetWallet()); } @@ -123,13 +124,13 @@ public void Start(Wallet wallet) ConsoleHelper.Warning("Please open wallet first!"); return; } - Verifier = System.ActorSystem.ActorOf(VerificationService.Props(wallet)); + Verifier = _system.ActorSystem.ActorOf(VerificationService.Props(wallet)); } [ConsoleCommand("state root", Category = "StateService", Description = "Get state root by index")] private void OnGetStateRoot(uint index) { - if (System is null || System.Settings.Network != Settings.Default.Network) throw new InvalidOperationException("Network doesn't match"); + if (_system is null || _system.Settings.Network != Settings.Default.Network) throw new InvalidOperationException("Network doesn't match"); using var snapshot = StateStore.Singleton.GetSnapshot(); StateRoot state_root = snapshot.GetStateRoot(index); if (state_root is null) @@ -141,7 +142,7 @@ private void OnGetStateRoot(uint index) [ConsoleCommand("state height", Category = "StateService", Description = "Get current state root index")] private void OnGetStateHeight() { - if (System is null || System.Settings.Network != Settings.Default.Network) throw new InvalidOperationException("Network doesn't match"); + if (_system is null || _system.Settings.Network != Settings.Default.Network) throw new InvalidOperationException("Network doesn't match"); ConsoleHelper.Info("LocalRootIndex: ", $"{StateStore.Singleton.LocalRootIndex}", " ValidatedRootIndex: ", @@ -151,7 +152,7 @@ private void OnGetStateHeight() [ConsoleCommand("get proof", Category = "StateService", Description = "Get proof of key and contract hash")] private void OnGetProof(UInt256 root_hash, UInt160 script_hash, string key) { - if (System is null || System.Settings.Network != Settings.Default.Network) throw new InvalidOperationException("Network doesn't match"); + if (_system is null || _system.Settings.Network != Settings.Default.Network) throw new InvalidOperationException("Network doesn't match"); try { ConsoleHelper.Info("Proof: ", GetProof(root_hash, script_hash, Convert.FromBase64String(key))); diff --git a/src/Plugins/StateService/StateService.csproj b/src/Plugins/StateService/StateService.csproj index 25045d59bc..b8e395c990 100644 --- a/src/Plugins/StateService/StateService.csproj +++ b/src/Plugins/StateService/StateService.csproj @@ -12,4 +12,10 @@ + + + PreserveNewest + + + \ No newline at end of file diff --git a/src/Plugins/StateService/config.json b/src/Plugins/StateService/StateService.json similarity index 100% rename from src/Plugins/StateService/config.json rename to src/Plugins/StateService/StateService.json diff --git a/src/Plugins/StateService/Storage/StateStore.cs b/src/Plugins/StateService/Storage/StateStore.cs index 1feb8bfacb..f2ca6d7d05 100644 --- a/src/Plugins/StateService/Storage/StateStore.cs +++ b/src/Plugins/StateService/Storage/StateStore.cs @@ -48,9 +48,9 @@ public StateStore(StatePlugin system, string path) { if (singleton != null) throw new InvalidOperationException(nameof(StateStore)); this.system = system; - store = StatePlugin.System.LoadStore(path); + store = StatePlugin._system.LoadStore(path); singleton = this; - StatePlugin.System.ActorSystem.EventStream.Subscribe(Self, typeof(Blockchain.RelayResult)); + StatePlugin._system.ActorSystem.EventStream.Subscribe(Self, typeof(Blockchain.RelayResult)); UpdateCurrentSnapshot(); } @@ -114,7 +114,7 @@ private bool OnNewStateRoot(StateRoot state_root) using var state_snapshot = Singleton.GetSnapshot(); StateRoot local_root = state_snapshot.GetStateRoot(state_root.Index); if (local_root is null || local_root.Witness != null) return false; - if (!state_root.Verify(StatePlugin.System.Settings, StatePlugin.System.StoreView)) return false; + if (!state_root.Verify(StatePlugin._system.Settings, StatePlugin._system.StoreView)) return false; if (local_root.RootHash != state_root.RootHash) return false; state_snapshot.AddValidatedStateRoot(state_root); state_snapshot.Commit(); diff --git a/src/Plugins/StateService/Verification/VerificationContext.cs b/src/Plugins/StateService/Verification/VerificationContext.cs index 53743c1345..feaf591795 100644 --- a/src/Plugins/StateService/Verification/VerificationContext.cs +++ b/src/Plugins/StateService/Verification/VerificationContext.cs @@ -83,7 +83,7 @@ public VerificationContext(Wallet wallet, uint index) Retries = 0; myIndex = -1; rootIndex = index; - verifiers = NativeContract.RoleManagement.GetDesignatedByRole(StatePlugin.System.StoreView, Role.StateValidator, index); + verifiers = NativeContract.RoleManagement.GetDesignatedByRole(StatePlugin._system.StoreView, Role.StateValidator, index); if (wallet is null) return; for (int i = 0; i < verifiers.Length; i++) { @@ -100,7 +100,7 @@ private ExtensiblePayload CreateVoteMessage() if (StateRoot is null) return null; if (!signatures.TryGetValue(myIndex, out byte[] sig)) { - sig = StateRoot.Sign(keyPair, StatePlugin.System.Settings.Network); + sig = StateRoot.Sign(keyPair, StatePlugin._system.Settings.Network); signatures[myIndex] = sig; } return CreatePayload(MessageType.Vote, new Vote @@ -118,7 +118,7 @@ public bool AddSignature(int index, byte[] sig) if (signatures.ContainsKey(index)) return false; Utility.Log(nameof(VerificationContext), LogLevel.Info, $"vote received, height={rootIndex}, index={index}"); ECPoint validator = verifiers[index]; - byte[] hash_data = StateRoot?.GetSignData(StatePlugin.System.Settings.Network); + byte[] hash_data = StateRoot?.GetSignData(StatePlugin._system.Settings.Network); if (hash_data is null || !Crypto.VerifySignature(hash_data, sig, validator)) { Utility.Log(nameof(VerificationContext), LogLevel.Info, "incorrect vote, invalid signature"); @@ -134,7 +134,7 @@ public bool CheckSignatures() if (StateRoot.Witness is null) { Contract contract = Contract.CreateMultiSigContract(M, verifiers); - ContractParametersContext sc = new(StatePlugin.System.StoreView, StateRoot, StatePlugin.System.Settings.Network); + ContractParametersContext sc = new(StatePlugin._system.StoreView, StateRoot, StatePlugin._system.Settings.Network); for (int i = 0, j = 0; i < verifiers.Length && j < M; i++) { if (!signatures.TryGetValue(i, out byte[] sig)) continue; @@ -168,7 +168,7 @@ private ExtensiblePayload CreatePayload(MessageType type, ISerializable payload, Sender = Contract.CreateSignatureRedeemScript(verifiers[MyIndex]).ToScriptHash(), Data = data, }; - ContractParametersContext sc = new ContractParametersContext(StatePlugin.System.StoreView, msg, StatePlugin.System.Settings.Network); + ContractParametersContext sc = new ContractParametersContext(StatePlugin._system.StoreView, msg, StatePlugin._system.Settings.Network); wallet.Sign(sc); msg.Witness = sc.GetWitnesses()[0]; return msg; diff --git a/src/Plugins/StateService/Verification/VerificationService.cs b/src/Plugins/StateService/Verification/VerificationService.cs index c6730e7905..a8eb9fd030 100644 --- a/src/Plugins/StateService/Verification/VerificationService.cs +++ b/src/Plugins/StateService/Verification/VerificationService.cs @@ -28,7 +28,7 @@ public class ValidatedRootPersisted { public uint Index; } public class BlockPersisted { public uint Index; } public const int MaxCachedVerificationProcessCount = 10; private class Timer { public uint Index; } - private static readonly uint TimeoutMilliseconds = StatePlugin.System.Settings.MillisecondsPerBlock; + private static readonly uint TimeoutMilliseconds = StatePlugin._system.Settings.MillisecondsPerBlock; private static readonly uint DelayMilliseconds = 3000; private readonly Wallet wallet; private readonly ConcurrentDictionary contexts = new ConcurrentDictionary(); @@ -36,14 +36,14 @@ private class Timer { public uint Index; } public VerificationService(Wallet wallet) { this.wallet = wallet; - StatePlugin.System.ActorSystem.EventStream.Subscribe(Self, typeof(Blockchain.RelayResult)); + StatePlugin._system.ActorSystem.EventStream.Subscribe(Self, typeof(Blockchain.RelayResult)); } private void SendVote(VerificationContext context) { if (context.VoteMessage is null) return; Utility.Log(nameof(VerificationService), LogLevel.Info, $"relay vote, height={context.RootIndex}, retry={context.Retries}"); - StatePlugin.System.Blockchain.Tell(context.VoteMessage); + StatePlugin._system.Blockchain.Tell(context.VoteMessage); } private void OnStateRootVote(Vote vote) @@ -60,7 +60,7 @@ private void CheckVotes(VerificationContext context) { if (context.StateRootMessage is null) return; Utility.Log(nameof(VerificationService), LogLevel.Info, $"relay state root, height={context.StateRoot.Index}, root={context.StateRoot.RootHash}"); - StatePlugin.System.Blockchain.Tell(context.StateRootMessage); + StatePlugin._system.Blockchain.Tell(context.StateRootMessage); } } diff --git a/src/Plugins/StatesDumper/StatesDumper.cs b/src/Plugins/StatesDumper/StatesDumper.cs index a74bda1556..da1bbd3f69 100644 --- a/src/Plugins/StatesDumper/StatesDumper.cs +++ b/src/Plugins/StatesDumper/StatesDumper.cs @@ -30,6 +30,8 @@ public class StatesDumper : Plugin public override string Description => "Exports Neo-CLI status data"; + public override string ConfigFile => System.IO.Path.Combine(RootPath, "StatesDumper.json"); + public StatesDumper() { Blockchain.Committing += OnCommitting; diff --git a/src/Plugins/StatesDumper/StatesDumper.csproj b/src/Plugins/StatesDumper/StatesDumper.csproj index 380f20c89a..4ebf25f2c1 100644 --- a/src/Plugins/StatesDumper/StatesDumper.csproj +++ b/src/Plugins/StatesDumper/StatesDumper.csproj @@ -9,4 +9,10 @@ + + + PreserveNewest + + + diff --git a/src/Plugins/StatesDumper/config.json b/src/Plugins/StatesDumper/StatesDumper.json similarity index 100% rename from src/Plugins/StatesDumper/config.json rename to src/Plugins/StatesDumper/StatesDumper.json diff --git a/src/Plugins/StorageDumper/StorageDumper.cs b/src/Plugins/StorageDumper/StorageDumper.cs index 9f377b8ef7..696f5014ac 100644 --- a/src/Plugins/StorageDumper/StorageDumper.cs +++ b/src/Plugins/StorageDumper/StorageDumper.cs @@ -30,6 +30,8 @@ public class StorageDumper : Plugin public override string Description => "Exports Neo-CLI status data"; + public override string ConfigFile => System.IO.Path.Combine(RootPath, "StorageDumper.json"); + public StorageDumper() { Blockchain.Committing += OnCommitting; diff --git a/src/Plugins/StorageDumper/StorageDumper.csproj b/src/Plugins/StorageDumper/StorageDumper.csproj index d9276c3581..49d5362538 100644 --- a/src/Plugins/StorageDumper/StorageDumper.csproj +++ b/src/Plugins/StorageDumper/StorageDumper.csproj @@ -10,5 +10,11 @@ + + + + PreserveNewest + + diff --git a/src/Plugins/StorageDumper/config.json b/src/Plugins/StorageDumper/StorageDumper.json similarity index 100% rename from src/Plugins/StorageDumper/config.json rename to src/Plugins/StorageDumper/StorageDumper.json diff --git a/src/Plugins/TokensTracker/TokensTracker.cs b/src/Plugins/TokensTracker/TokensTracker.cs index 5567d7d1f5..0d8863a767 100644 --- a/src/Plugins/TokensTracker/TokensTracker.cs +++ b/src/Plugins/TokensTracker/TokensTracker.cs @@ -35,6 +35,8 @@ public class TokensTracker : Plugin public override string Description => "Enquiries balances and transaction history of accounts through RPC"; + public override string ConfigFile => System.IO.Path.Combine(RootPath, "TokensTracker.json"); + public TokensTracker() { Blockchain.Committing += OnCommitting; diff --git a/src/Plugins/TokensTracker/TokensTracker.csproj b/src/Plugins/TokensTracker/TokensTracker.csproj index 848255fb81..7c3df5c0c6 100644 --- a/src/Plugins/TokensTracker/TokensTracker.csproj +++ b/src/Plugins/TokensTracker/TokensTracker.csproj @@ -1,4 +1,4 @@ - + net8.0 @@ -9,4 +9,10 @@ + + + PreserveNewest + + + \ No newline at end of file diff --git a/src/Plugins/TokensTracker/config.json b/src/Plugins/TokensTracker/TokensTracker.json similarity index 100% rename from src/Plugins/TokensTracker/config.json rename to src/Plugins/TokensTracker/TokensTracker.json From 12565ccf8546398b291f156538056b735b6a0ea3 Mon Sep 17 00:00:00 2001 From: Shargon Date: Wed, 22 May 2024 14:24:11 -0700 Subject: [PATCH 145/168] Update nuget (#3262) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Vitor Nazário Coelho --- src/Neo.Extensions/Neo.Extensions.csproj | 2 +- src/Neo/Neo.csproj | 2 +- src/Plugins/SQLiteWallet/SQLiteWallet.csproj | 2 +- .../Neo.ConsoleService.Tests.csproj | 4 ++-- .../Neo.Cryptography.BLS12_381.Tests.csproj | 4 ++-- .../Neo.Cryptography.MPTTrie.Tests.csproj | 4 ++-- tests/Neo.Json.UnitTests/Neo.Json.UnitTests.csproj | 4 ++-- tests/Neo.Network.RPC.Tests/Neo.Network.RPC.Tests.csproj | 4 ++-- .../Neo.Plugins.OracleService.Tests.csproj | 8 ++++---- .../Neo.Plugins.RpcServer.Tests.csproj | 4 ++-- .../Neo.Plugins.Storage.Tests.csproj | 4 ++-- tests/Neo.UnitTests/Neo.UnitTests.csproj | 8 ++++---- tests/Neo.VM.Tests/Neo.VM.Tests.csproj | 4 ++-- 13 files changed, 27 insertions(+), 27 deletions(-) diff --git a/src/Neo.Extensions/Neo.Extensions.csproj b/src/Neo.Extensions/Neo.Extensions.csproj index d0d899cec3..71330a05a3 100644 --- a/src/Neo.Extensions/Neo.Extensions.csproj +++ b/src/Neo.Extensions/Neo.Extensions.csproj @@ -7,7 +7,7 @@ - + diff --git a/src/Neo/Neo.csproj b/src/Neo/Neo.csproj index 02668fda95..6a1ba44504 100644 --- a/src/Neo/Neo.csproj +++ b/src/Neo/Neo.csproj @@ -7,7 +7,7 @@ - + diff --git a/src/Plugins/SQLiteWallet/SQLiteWallet.csproj b/src/Plugins/SQLiteWallet/SQLiteWallet.csproj index 262459b43f..fb2d3e71b8 100644 --- a/src/Plugins/SQLiteWallet/SQLiteWallet.csproj +++ b/src/Plugins/SQLiteWallet/SQLiteWallet.csproj @@ -8,7 +8,7 @@ - + diff --git a/tests/Neo.ConsoleService.Tests/Neo.ConsoleService.Tests.csproj b/tests/Neo.ConsoleService.Tests/Neo.ConsoleService.Tests.csproj index 03e67d6f78..6562480859 100644 --- a/tests/Neo.ConsoleService.Tests/Neo.ConsoleService.Tests.csproj +++ b/tests/Neo.ConsoleService.Tests/Neo.ConsoleService.Tests.csproj @@ -11,8 +11,8 @@ - - + + 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 5c4a8f5951..999bc1c5f4 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 @@ -12,8 +12,8 @@ - - + + 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 41bad3d63b..3691fba90a 100644 --- a/tests/Neo.Cryptography.MPTTrie.Tests/Neo.Cryptography.MPTTrie.Tests.csproj +++ b/tests/Neo.Cryptography.MPTTrie.Tests/Neo.Cryptography.MPTTrie.Tests.csproj @@ -7,8 +7,8 @@ - - + + diff --git a/tests/Neo.Json.UnitTests/Neo.Json.UnitTests.csproj b/tests/Neo.Json.UnitTests/Neo.Json.UnitTests.csproj index 1e66e0ce65..81e70ebbe1 100644 --- a/tests/Neo.Json.UnitTests/Neo.Json.UnitTests.csproj +++ b/tests/Neo.Json.UnitTests/Neo.Json.UnitTests.csproj @@ -11,8 +11,8 @@ - - + + 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 8875785e77..13a13f5c98 100644 --- a/tests/Neo.Network.RPC.Tests/Neo.Network.RPC.Tests.csproj +++ b/tests/Neo.Network.RPC.Tests/Neo.Network.RPC.Tests.csproj @@ -8,8 +8,8 @@ - - + + 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 388def4624..4dd4abbfa4 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 4b5f60b96a..2459b1cb5f 100644 --- a/tests/Neo.Plugins.RpcServer.Tests/Neo.Plugins.RpcServer.Tests.csproj +++ b/tests/Neo.Plugins.RpcServer.Tests/Neo.Plugins.RpcServer.Tests.csproj @@ -8,8 +8,8 @@ - - + + 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 9ecf8ef16b..3e06cf32ca 100644 --- a/tests/Neo.Plugins.Storage.Tests/Neo.Plugins.Storage.Tests.csproj +++ b/tests/Neo.Plugins.Storage.Tests/Neo.Plugins.Storage.Tests.csproj @@ -7,8 +7,8 @@ - - + + diff --git a/tests/Neo.UnitTests/Neo.UnitTests.csproj b/tests/Neo.UnitTests/Neo.UnitTests.csproj index 6ac259db7b..fb246cbdc3 100644 --- a/tests/Neo.UnitTests/Neo.UnitTests.csproj +++ b/tests/Neo.UnitTests/Neo.UnitTests.csproj @@ -6,8 +6,8 @@ - - + + @@ -24,8 +24,8 @@ - - + + diff --git a/tests/Neo.VM.Tests/Neo.VM.Tests.csproj b/tests/Neo.VM.Tests/Neo.VM.Tests.csproj index 6b3dab4177..53c16ed4af 100644 --- a/tests/Neo.VM.Tests/Neo.VM.Tests.csproj +++ b/tests/Neo.VM.Tests/Neo.VM.Tests.csproj @@ -18,8 +18,8 @@ - - + + From c8f933810d1f11fc2db4e90b7761c750a73ec22a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vitor=20Naz=C3=A1rio=20Coelho?= Date: Thu, 23 May 2024 05:31:58 -0300 Subject: [PATCH 146/168] COVERALL: Improve maintenance and readbility of some variables (#3248) * Update main.yml * Update main.yml * Update main.yml --------- Co-authored-by: Shargon --- .github/workflows/main.yml | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 5d34cb9740..3dae25a1df 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -7,6 +7,8 @@ on: env: DOTNET_VERSION: 8.0.x + COVERALL_COLLECT_OUTPUT: "/p:CollectCoverage=true /p:CoverletOutput='${{ github.workspace }}/TestResults/coverage/'" + COVERALL_MERGE_PATH: "/p:MergeWith='${{ github.workspace }}/TestResults/coverage/coverage.json'" jobs: @@ -40,19 +42,20 @@ jobs: if: matrix.os == 'ubuntu-latest' run: | sudo apt-get --assume-yes install libleveldb-dev librocksdb-dev - dotnet test ./tests/Neo.Cryptography.BLS12_381.Tests /p:CollectCoverage=true /p:CoverletOutput='${{ github.workspace }}/TestResults/coverage/' - dotnet test ./tests/Neo.ConsoleService.Tests /p:CollectCoverage=true /p:CoverletOutput='${{ github.workspace }}/TestResults/coverage/' /p:MergeWith='${{ github.workspace }}/TestResults/coverage/coverage.json' - dotnet test ./tests/Neo.UnitTests /p:CollectCoverage=true /p:CoverletOutput='${{ github.workspace }}/TestResults/coverage/' /p:MergeWith='${{ github.workspace }}/TestResults/coverage/coverage.json' - dotnet test ./tests/Neo.VM.Tests /p:CollectCoverage=true /p:CoverletOutput='${{ github.workspace }}/TestResults/coverage/' /p:MergeWith='${{ github.workspace }}/TestResults/coverage/coverage.json' - dotnet test ./tests/Neo.Json.UnitTests /p:CollectCoverage=true /p:CoverletOutput='${{ github.workspace }}/TestResults/coverage/' /p:MergeWith='${{ github.workspace }}/TestResults/coverage/coverage.json' + + dotnet test ./tests/Neo.Cryptography.BLS12_381.Tests ${{ env.COVERALL_COLLECT_OUTPUT }} + dotnet test ./tests/Neo.ConsoleService.Tests ${{ env.COVERALL_COLLECT_OUTPUT }} ${{ env.COVERALL_MERGE_PATH }} + dotnet test ./tests/Neo.UnitTests ${{ env.COVERALL_COLLECT_OUTPUT }} ${{ env.COVERALL_MERGE_PATH }} + dotnet test ./tests/Neo.VM.Tests ${{ env.COVERALL_COLLECT_OUTPUT }} ${{ env.COVERALL_MERGE_PATH }} + dotnet test ./tests/Neo.Json.UnitTests ${{ env.COVERALL_COLLECT_OUTPUT }} ${{ env.COVERALL_MERGE_PATH }} # Plugins - dotnet test ./tests/Neo.Cryptography.MPTTrie.Tests /p:CollectCoverage=true /p:CoverletOutput='${{ github.workspace }}/TestResults/coverage/' /p:MergeWith='${{ github.workspace }}/TestResults/coverage/coverage.json' - dotnet test ./tests/Neo.Network.RPC.Tests /p:CollectCoverage=true /p:CoverletOutput='${{ github.workspace }}/TestResults/coverage/' /p:MergeWith='${{ github.workspace }}/TestResults/coverage/coverage.json' - dotnet test ./tests/Neo.Plugins.OracleService.Tests /p:CollectCoverage=true /p:CoverletOutput='${{ github.workspace }}/TestResults/coverage/' /p:MergeWith='${{ github.workspace }}/TestResults/coverage/coverage.json' - dotnet test ./tests/Neo.Plugins.RpcServer.Tests /p:CollectCoverage=true /p:CoverletOutput='${{ github.workspace }}/TestResults/coverage/' /p:MergeWith='${{ github.workspace }}/TestResults/coverage/coverage.json' - dotnet test ./tests/Neo.Plugins.Storage.Tests /p:CollectCoverage=true /p:CoverletOutput='${{ github.workspace }}/TestResults/coverage/' /p:MergeWith='${{ github.workspace }}/TestResults/coverage/coverage.json' /p:CoverletOutputFormat='cobertura' - + dotnet test ./tests/Neo.Cryptography.MPTTrie.Tests ${{ env.COVERALL_COLLECT_OUTPUT }} ${{ env.COVERALL_MERGE_PATH }} + dotnet test ./tests/Neo.Network.RPC.Tests ${{ env.COVERALL_COLLECT_OUTPUT }} ${{ env.COVERALL_MERGE_PATH }} + dotnet test ./tests/Neo.Plugins.OracleService.Tests ${{ env.COVERALL_COLLECT_OUTPUT }} ${{ env.COVERALL_MERGE_PATH }} + dotnet test ./tests/Neo.Plugins.RpcServer.Tests ${{ env.COVERALL_COLLECT_OUTPUT }} ${{ env.COVERALL_MERGE_PATH }} + dotnet test ./tests/Neo.Plugins.Storage.Tests ${{ env.COVERALL_COLLECT_OUTPUT }} ${{ env.COVERALL_MERGE_PATH }} /p:CoverletOutputFormat='cobertura' + - name: Coveralls if: matrix.os == 'ubuntu-latest' uses: coverallsapp/github-action@v2.3.0 From 44c8cd9669beffd8460a56aedf81a53b47ff5b5f Mon Sep 17 00:00:00 2001 From: Shargon Date: Fri, 24 May 2024 01:05:17 -0700 Subject: [PATCH 147/168] fix: custom plugins won't shown by command `plugins` (#3269) * fix: iterate non listed * fix: Remove null warning * style: use names * fix: bug when no plugins * Update src/Neo.CLI/CLI/MainService.Plugins.cs --- src/Neo.CLI/CLI/MainService.Plugins.cs | 36 ++++++++++++++------------ 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/src/Neo.CLI/CLI/MainService.Plugins.cs b/src/Neo.CLI/CLI/MainService.Plugins.cs index 5b346fc33c..a73cdcb31e 100644 --- a/src/Neo.CLI/CLI/MainService.Plugins.cs +++ b/src/Neo.CLI/CLI/MainService.Plugins.cs @@ -228,24 +228,28 @@ private void OnPluginsCommand() { try { - var plugins = GetPluginListAsync().GetAwaiter().GetResult(); - if (plugins == null) return; - plugins - .Order() - .ForEach(f => + var plugins = GetPluginListAsync().GetAwaiter().GetResult()?.ToArray() ?? []; + var installedPlugins = Plugin.Plugins.ToList(); + + var maxLength = installedPlugins.Count == 0 ? 0 : installedPlugins.Max(s => s.Name.Length); + if (plugins.Length > 0) { - var installedPlugin = Plugin.Plugins.SingleOrDefault(pp => string.Equals(pp.Name, f, StringComparison.CurrentCultureIgnoreCase)); - if (installedPlugin != null) + maxLength = Math.Max(maxLength, plugins.Max(s => s.Length)); + } + + plugins.Select(s => (name: s, installedPlugin: Plugin.Plugins.SingleOrDefault(pp => string.Equals(pp.Name, s, StringComparison.InvariantCultureIgnoreCase)))) + .Concat(installedPlugins.Select(u => (name: u.Name, installedPlugin: (Plugin?)u)).Where(u => !plugins.Contains(u.name, StringComparer.InvariantCultureIgnoreCase))) + .OrderBy(u => u.name) + .ForEach((f) => { - var maxLength = plugins.Select(s => s.Length).OrderDescending().First(); - string tabs = string.Empty; - if (f.Length < maxLength) - tabs = "\t"; - ConsoleHelper.Info("", $"[Installed]\t {f,6}{tabs}", " @", $"{installedPlugin.Version.ToString(3)} {installedPlugin.Description}"); - } - else - ConsoleHelper.Info($"[Not Installed]\t {f}"); - }); + if (f.installedPlugin != null) + { + var tabs = f.name.Length < maxLength ? "\t" : string.Empty; + ConsoleHelper.Info("", $"[Installed]\t {f.name,6}{tabs}", " @", $"{f.installedPlugin.Version.ToString(3)} {f.installedPlugin.Description}"); + } + else + ConsoleHelper.Info($"[Not Installed]\t {f.name}"); + }); } catch (Exception ex) { From 59bd092b286cb19288862cde339b5d2a7179fb84 Mon Sep 17 00:00:00 2001 From: Anna Shaleva Date: Mon, 27 May 2024 06:58:19 +0300 Subject: [PATCH 148/168] Native: remove deprecated NamedCurve enum (#3273) 3.7.0 (and a batch of 3.7.*) is out, which means that users can see the "Obsolete" warning for NamedCurve enum and migrate to NamedCurveHash. Close #3236. Signed-off-by: Anna Shaleva Co-authored-by: Shargon --- src/Neo/SmartContract/Native/CryptoLib.cs | 15 +++----- src/Neo/SmartContract/Native/NamedCurve.cs | 38 ------------------- .../SmartContract/Native/NamedCurveHash.cs | 1 - 3 files changed, 6 insertions(+), 48 deletions(-) delete mode 100644 src/Neo/SmartContract/Native/NamedCurve.cs diff --git a/src/Neo/SmartContract/Native/CryptoLib.cs b/src/Neo/SmartContract/Native/CryptoLib.cs index 452dd31faa..9027298752 100644 --- a/src/Neo/SmartContract/Native/CryptoLib.cs +++ b/src/Neo/SmartContract/Native/CryptoLib.cs @@ -21,12 +21,6 @@ namespace Neo.SmartContract.Native /// public sealed partial class CryptoLib : NativeContract { - private static readonly Dictionary curves = new() - { - [NamedCurve.secp256k1] = ECCurve.Secp256k1, - [NamedCurve.secp256r1] = ECCurve.Secp256r1, - }; - private static readonly Dictionary s_curves = new() { [NamedCurveHash.secp256k1SHA256] = (ECCurve.Secp256k1, Hasher.SHA256), @@ -106,12 +100,15 @@ public static bool VerifyWithECDsa(byte[] message, byte[] pubkey, byte[] signatu } // This is for solving the hardfork issue in https://github.com/neo-project/neo/pull/3209 - [ContractMethod(true, Hardfork.HF_Cockatrice, CpuFee = 1 << 15)] - public static bool VerifyWithECDsa(byte[] message, byte[] pubkey, byte[] signature, NamedCurve curve) + [ContractMethod(true, Hardfork.HF_Cockatrice, CpuFee = 1 << 15, Name = "verifyWithECDsa")] + public static bool VerifyWithECDsaV0(byte[] message, byte[] pubkey, byte[] signature, NamedCurveHash curve) { + if (curve != NamedCurveHash.secp256k1SHA256 && curve != NamedCurveHash.secp256r1SHA256) + throw new ArgumentOutOfRangeException(nameof(curve)); + try { - return Crypto.VerifySignature(message, signature, pubkey, curves[curve]); + return Crypto.VerifySignature(message, signature, pubkey, s_curves[curve].Curve); } catch (ArgumentException) { diff --git a/src/Neo/SmartContract/Native/NamedCurve.cs b/src/Neo/SmartContract/Native/NamedCurve.cs deleted file mode 100644 index 8c7a9107e9..0000000000 --- a/src/Neo/SmartContract/Native/NamedCurve.cs +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (C) 2015-2024 The Neo Project. -// -// NamedCurve.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; - -namespace Neo.SmartContract.Native -{ - /// - /// Represents the named curve used in ECDSA. This enum is obsolete - /// and will be removed in future versions. Please, use an extended instead. - /// - /// - /// https://tools.ietf.org/html/rfc4492#section-5.1.1 - /// - [Obsolete("NamedCurve enum is obsolete and will be removed in future versions. Please, use an extended NamedCurveHash instead.")] - public enum NamedCurve : byte - { - /// - /// The secp256k1 curve. - /// - [Obsolete("secp256k1 value is obsolete and will be removed in future versions. Please, use NamedCurveHash.secp256k1SHA256 for compatible behaviour.")] - secp256k1 = 22, - - /// - /// The secp256r1 curve, which known as prime256v1 or nistP-256. - /// - [Obsolete("secp256r1 value is obsolete and will be removed in future versions. Please, use NamedCurveHash.secp256r1SHA256 for compatible behaviour.")] - secp256r1 = 23 - } -} diff --git a/src/Neo/SmartContract/Native/NamedCurveHash.cs b/src/Neo/SmartContract/Native/NamedCurveHash.cs index 8bd63bf874..653ed3aa88 100644 --- a/src/Neo/SmartContract/Native/NamedCurveHash.cs +++ b/src/Neo/SmartContract/Native/NamedCurveHash.cs @@ -13,7 +13,6 @@ namespace Neo.SmartContract.Native { /// /// Represents a pair of the named curve used in ECDSA and a hash algorithm used to hash message. - /// This is a compatible extension of an obsolete enum. /// public enum NamedCurveHash : byte { From 6aab01173d5acf8bbe4af3b8d7ae9d0f2a812664 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Mon, 27 May 2024 12:39:39 +0800 Subject: [PATCH 149/168] use datoshi as the name of the smallest unit of GAS (#3241) * use datoshi * two changes * fix more datoshi, and add comments to plugins --------- Co-authored-by: Fernando Diaz Toledano Co-authored-by: NGD Admin <154295625+NGDAdmin@users.noreply.github.com> --- src/Neo.CLI/CLI/MainService.Blockchain.cs | 6 +-- src/Neo.CLI/CLI/MainService.Contracts.cs | 19 ++++----- src/Neo.CLI/CLI/MainService.Wallet.cs | 4 +- src/Neo.CLI/CLI/MainService.cs | 16 ++++---- src/Neo.GUI/GUI/InvokeContractDialog.cs | 4 +- .../Ledger/Blockchain.ApplicationExecuted.cs | 2 +- src/Neo/Network/P2P/Payloads/Transaction.cs | 18 +++++---- src/Neo/ProtocolSettings.cs | 1 + .../ApplicationEngine.Contract.cs | 6 ++- .../SmartContract/ApplicationEngine.Crypto.cs | 3 +- .../ApplicationEngine.OpCodePrices.cs | 4 ++ .../ApplicationEngine.Runtime.cs | 11 +++--- .../ApplicationEngine.Storage.cs | 2 +- src/Neo/SmartContract/ApplicationEngine.cs | 39 ++++++++++++------- src/Neo/SmartContract/Helper.cs | 21 +++++----- .../Native/ContractManagement.cs | 7 ++-- .../SmartContract/Native/NativeContract.cs | 3 +- src/Neo/SmartContract/Native/NeoToken.cs | 13 +++++-- .../SmartContract/Native/OracleContract.cs | 8 ++-- .../SmartContract/Native/PolicyContract.cs | 1 + src/Neo/Wallets/Helper.cs | 5 ++- src/Neo/Wallets/Wallet.cs | 4 +- .../RpcServer/RpcServer.SmartContract.cs | 1 + src/Plugins/RpcServer/RpcServer.Wallet.cs | 8 ++-- src/Plugins/RpcServer/Session.cs | 4 +- src/Plugins/RpcServer/Settings.cs | 2 + .../Extensions/NativeContractExtensions.cs | 14 ++++++- tests/Neo.UnitTests/Ledger/UT_PoolItem.cs | 22 +++++------ .../Network/P2P/Payloads/UT_Transaction.cs | 16 ++++---- .../SmartContract/UT_Contract.cs | 4 +- .../Neo.UnitTests/SmartContract/UT_Helper.cs | 4 +- .../SmartContract/UT_InteropPrices.cs | 16 ++++---- 32 files changed, 170 insertions(+), 118 deletions(-) diff --git a/src/Neo.CLI/CLI/MainService.Blockchain.cs b/src/Neo.CLI/CLI/MainService.Blockchain.cs index 4f896d63e3..090939de49 100644 --- a/src/Neo.CLI/CLI/MainService.Blockchain.cs +++ b/src/Neo.CLI/CLI/MainService.Blockchain.cs @@ -137,9 +137,9 @@ public void OnShowTransactionCommand(UInt256 hash) ConsoleHelper.Info("", " Nonce: ", $"{tx.Transaction.Nonce}"); ConsoleHelper.Info("", " Sender: ", $"{tx.Transaction.Sender}"); ConsoleHelper.Info("", " ValidUntilBlock: ", $"{tx.Transaction.ValidUntilBlock}"); - ConsoleHelper.Info("", " FeePerByte: ", $"{tx.Transaction.FeePerByte}"); - ConsoleHelper.Info("", " NetworkFee: ", $"{tx.Transaction.NetworkFee}"); - ConsoleHelper.Info("", " SystemFee: ", $"{tx.Transaction.SystemFee}"); + ConsoleHelper.Info("", " FeePerByte: ", $"{tx.Transaction.FeePerByte} datoshi"); + ConsoleHelper.Info("", " NetworkFee: ", $"{tx.Transaction.NetworkFee} datoshi"); + ConsoleHelper.Info("", " SystemFee: ", $"{tx.Transaction.SystemFee} datoshi"); ConsoleHelper.Info("", " Script: ", $"{Convert.ToBase64String(tx.Transaction.Script.Span)}"); ConsoleHelper.Info("", " Version: ", $"{tx.Transaction.Version}"); ConsoleHelper.Info("", " BlockIndex: ", $"{block.Index}"); diff --git a/src/Neo.CLI/CLI/MainService.Contracts.cs b/src/Neo.CLI/CLI/MainService.Contracts.cs index 94fbe32f89..684b3330bc 100644 --- a/src/Neo.CLI/CLI/MainService.Contracts.cs +++ b/src/Neo.CLI/CLI/MainService.Contracts.cs @@ -46,8 +46,8 @@ private void OnDeployCommand(string filePath, string? manifestPath = null, JObje UInt160 hash = SmartContract.Helper.GetContractHash(tx.Sender, nef.CheckSum, manifest.Name); ConsoleHelper.Info("Contract hash: ", $"{hash}"); - ConsoleHelper.Info("Gas consumed: ", $"{new BigDecimal((BigInteger)tx.SystemFee, NativeContract.GAS.Decimals)}"); - ConsoleHelper.Info("Network fee: ", $"{new BigDecimal((BigInteger)tx.NetworkFee, NativeContract.GAS.Decimals)}"); + ConsoleHelper.Info("Gas consumed: ", $"{new BigDecimal((BigInteger)tx.SystemFee, NativeContract.GAS.Decimals)} GAS"); + ConsoleHelper.Info("Network fee: ", $"{new BigDecimal((BigInteger)tx.NetworkFee, NativeContract.GAS.Decimals)} GAS"); ConsoleHelper.Info("Total fee: ", $"{new BigDecimal((BigInteger)(tx.SystemFee + tx.NetworkFee), NativeContract.GAS.Decimals)} GAS"); if (!ConsoleHelper.ReadUserInput("Relay tx? (no|yes)").IsYes()) // Add this in case just want to get hash but not relay { @@ -108,8 +108,8 @@ private void OnUpdateCommand(UInt160 scriptHash, string filePath, string manifes { ConsoleHelper.Info("Contract hash: ", $"{scriptHash}"); ConsoleHelper.Info("Updated times: ", $"{contract.UpdateCounter}"); - ConsoleHelper.Info("Gas consumed: ", $"{new BigDecimal((BigInteger)tx.SystemFee, NativeContract.GAS.Decimals)}"); - ConsoleHelper.Info("Network fee: ", $"{new BigDecimal((BigInteger)tx.NetworkFee, NativeContract.GAS.Decimals)}"); + ConsoleHelper.Info("Gas consumed: ", $"{new BigDecimal((BigInteger)tx.SystemFee, NativeContract.GAS.Decimals)} GAS"); + ConsoleHelper.Info("Network fee: ", $"{new BigDecimal((BigInteger)tx.NetworkFee, NativeContract.GAS.Decimals)} GAS"); ConsoleHelper.Info("Total fee: ", $"{new BigDecimal((BigInteger)(tx.SystemFee + tx.NetworkFee), NativeContract.GAS.Decimals)} GAS"); if (!ConsoleHelper.ReadUserInput("Relay tx? (no|yes)").IsYes()) // Add this in case just want to get hash but not relay { @@ -127,11 +127,12 @@ private void OnUpdateCommand(UInt160 scriptHash, string filePath, string manifes /// Contract parameters /// Transaction's sender /// Signer's accounts - /// Max fee for running the script + /// Max fee for running the script, in the unit of GAS [ConsoleCommand("invoke", Category = "Contract Commands")] private void OnInvokeCommand(UInt160 scriptHash, string operation, JArray? contractParameters = null, UInt160? sender = null, UInt160[]? signerAccounts = null, decimal maxGas = 20) { - var gas = new BigDecimal(maxGas, NativeContract.GAS.Decimals); + // In the unit of datoshi, 1 datoshi = 1e-8 GAS + var datoshi = new BigDecimal(maxGas, NativeContract.GAS.Decimals); Signer[] signers = Array.Empty(); if (!NoWallet()) { @@ -163,12 +164,12 @@ private void OnInvokeCommand(UInt160 scriptHash, string operation, JArray? contr Witnesses = Array.Empty(), }; - if (!OnInvokeWithResult(scriptHash, operation, out _, tx, contractParameters, gas: (long)gas.Value)) return; + if (!OnInvokeWithResult(scriptHash, operation, out _, tx, contractParameters, datoshi: (long)datoshi.Value)) return; if (NoWallet()) return; try { - tx = CurrentWallet!.MakeTransaction(NeoSystem.StoreView, tx.Script, sender, signers, maxGas: (long)gas.Value); + tx = CurrentWallet!.MakeTransaction(NeoSystem.StoreView, tx.Script, sender, signers, maxGas: (long)datoshi.Value); } catch (InvalidOperationException e) { @@ -176,7 +177,7 @@ private void OnInvokeCommand(UInt160 scriptHash, string operation, JArray? contr return; } ConsoleHelper.Info("Network fee: ", - $"{new BigDecimal((BigInteger)tx.NetworkFee, NativeContract.GAS.Decimals)}\t", + $"{new BigDecimal((BigInteger)tx.NetworkFee, NativeContract.GAS.Decimals)} GAS\t", "Total fee: ", $"{new BigDecimal((BigInteger)(tx.SystemFee + tx.NetworkFee), NativeContract.GAS.Decimals)} GAS"); if (!ConsoleHelper.ReadUserInput("Relay tx? (no|yes)").IsYes()) diff --git a/src/Neo.CLI/CLI/MainService.Wallet.cs b/src/Neo.CLI/CLI/MainService.Wallet.cs index 4f65390f85..db33e89564 100644 --- a/src/Neo.CLI/CLI/MainService.Wallet.cs +++ b/src/Neo.CLI/CLI/MainService.Wallet.cs @@ -626,7 +626,7 @@ private void OnCancelCommand(UInt256 txid, UInt160? sender = null, UInt160[]? si { var snapshot = NeoSystem.StoreView; AssetDescriptor descriptor = new(snapshot, NeoSystem.Settings, NativeContract.GAS.Hash); - string extracFee = ConsoleHelper.ReadUserInput("This tx is not in mempool, please input extra fee manually"); + string extracFee = ConsoleHelper.ReadUserInput("This tx is not in mempool, please input extra fee (datoshi) manually"); if (!BigDecimal.TryParse(extracFee, descriptor.Decimals, out BigDecimal decimalExtraFee) || decimalExtraFee.Sign <= 0) { ConsoleHelper.Error("Incorrect Amount Format"); @@ -636,7 +636,7 @@ private void OnCancelCommand(UInt256 txid, UInt160? sender = null, UInt160[]? si }; ConsoleHelper.Info("Network fee: ", - $"{new BigDecimal((BigInteger)tx.NetworkFee, NativeContract.GAS.Decimals)}\t", + $"{new BigDecimal((BigInteger)tx.NetworkFee, NativeContract.GAS.Decimals)} GAS\t", "Total fee: ", $"{new BigDecimal((BigInteger)(tx.SystemFee + tx.NetworkFee), NativeContract.GAS.Decimals)} GAS"); if (!ConsoleHelper.ReadUserInput("Relay tx? (no|yes)").IsYes()) diff --git a/src/Neo.CLI/CLI/MainService.cs b/src/Neo.CLI/CLI/MainService.cs index efe48b0165..1d349df320 100644 --- a/src/Neo.CLI/CLI/MainService.cs +++ b/src/Neo.CLI/CLI/MainService.cs @@ -515,8 +515,8 @@ private static void WriteLineWithoutFlicker(string message = "", int maxWidth = /// /// script /// sender - /// Max fee for running the script - private void SendTransaction(byte[] script, UInt160? account = null, long gas = TestModeGas) + /// Max fee for running the script, in the unit of datoshi, 1 datoshi = 1e-8 GAS + private void SendTransaction(byte[] script, UInt160? account = null, long datoshi = TestModeGas) { if (NoWallet()) return; @@ -533,10 +533,10 @@ private void SendTransaction(byte[] script, UInt160? account = null, long gas = try { - Transaction tx = CurrentWallet!.MakeTransaction(snapshot, script, account, signers, maxGas: gas); + Transaction tx = CurrentWallet!.MakeTransaction(snapshot, script, account, signers, maxGas: datoshi); ConsoleHelper.Info("Invoking script with: ", $"'{Convert.ToBase64String(tx.Script.Span)}'"); - using (ApplicationEngine engine = ApplicationEngine.Run(tx.Script, snapshot, container: tx, settings: NeoSystem.Settings, gas: gas)) + using (ApplicationEngine engine = ApplicationEngine.Run(tx.Script, snapshot, container: tx, settings: NeoSystem.Settings, gas: datoshi)) { PrintExecutionOutput(engine, true); if (engine.State == VMState.FAULT) return; @@ -564,9 +564,9 @@ private void SendTransaction(byte[] script, UInt160? account = null, long gas = /// Transaction /// Contract parameters /// Show result stack if it is true - /// Max fee for running the script + /// Max fee for running the script, in the unit of datoshi, 1 datoshi = 1e-8 GAS /// Return true if it was successful - private bool OnInvokeWithResult(UInt160 scriptHash, string operation, out StackItem result, IVerifiable? verifiable = null, JArray? contractParameters = null, bool showStack = true, long gas = TestModeGas) + private bool OnInvokeWithResult(UInt160 scriptHash, string operation, out StackItem result, IVerifiable? verifiable = null, JArray? contractParameters = null, bool showStack = true, long datoshi = TestModeGas) { List parameters = new(); @@ -612,7 +612,7 @@ private bool OnInvokeWithResult(UInt160 scriptHash, string operation, out StackI tx.Script = script; } - using ApplicationEngine engine = ApplicationEngine.Run(script, NeoSystem.StoreView, container: verifiable, settings: NeoSystem.Settings, gas: gas); + using ApplicationEngine engine = ApplicationEngine.Run(script, NeoSystem.StoreView, container: verifiable, settings: NeoSystem.Settings, gas: datoshi); PrintExecutionOutput(engine, showStack); result = engine.State == VMState.FAULT ? StackItem.Null : engine.ResultStack.Peek(); return engine.State != VMState.FAULT; @@ -621,7 +621,7 @@ private bool OnInvokeWithResult(UInt160 scriptHash, string operation, out StackI private void PrintExecutionOutput(ApplicationEngine engine, bool showStack = true) { ConsoleHelper.Info("VM State: ", engine.State.ToString()); - ConsoleHelper.Info("Gas Consumed: ", new BigDecimal((BigInteger)engine.GasConsumed, NativeContract.GAS.Decimals).ToString()); + ConsoleHelper.Info("Gas Consumed: ", new BigDecimal((BigInteger)engine.FeeConsumed, NativeContract.GAS.Decimals).ToString()); if (showStack) ConsoleHelper.Info("Result Stack: ", new JArray(engine.ResultStack.Select(p => p.ToJson())).ToString()); diff --git a/src/Neo.GUI/GUI/InvokeContractDialog.cs b/src/Neo.GUI/GUI/InvokeContractDialog.cs index 4e46799f5c..d8a8a6b66f 100644 --- a/src/Neo.GUI/GUI/InvokeContractDialog.cs +++ b/src/Neo.GUI/GUI/InvokeContractDialog.cs @@ -90,12 +90,12 @@ private void button5_Click(object sender, EventArgs e) using ApplicationEngine engine = ApplicationEngine.Run(tx_test.Script, Service.NeoSystem.StoreView, container: tx_test); StringBuilder sb = new StringBuilder(); sb.AppendLine($"VM State: {engine.State}"); - sb.AppendLine($"Gas Consumed: {engine.GasConsumed}"); + sb.AppendLine($"Gas Consumed: {engine.FeeConsumed}"); sb.AppendLine($"Evaluation Stack: {new JArray(engine.ResultStack.Select(p => p.ToParameter().ToJson()))}"); textBox7.Text = sb.ToString(); if (engine.State != VMState.FAULT) { - label7.Text = engine.GasConsumed + " gas"; + label7.Text = engine.FeeConsumed + " gas"; button3.Enabled = true; } else diff --git a/src/Neo/Ledger/Blockchain.ApplicationExecuted.cs b/src/Neo/Ledger/Blockchain.ApplicationExecuted.cs index 211ac14117..e1fa5fae62 100644 --- a/src/Neo/Ledger/Blockchain.ApplicationExecuted.cs +++ b/src/Neo/Ledger/Blockchain.ApplicationExecuted.cs @@ -62,7 +62,7 @@ internal ApplicationExecuted(ApplicationEngine engine) Transaction = engine.ScriptContainer as Transaction; Trigger = engine.Trigger; VMState = engine.State; - GasConsumed = engine.GasConsumed; + GasConsumed = engine.FeeConsumed; Exception = engine.FaultException; Stack = engine.ResultStack.ToArray(); Notifications = engine.Notifications.ToArray(); diff --git a/src/Neo/Network/P2P/Payloads/Transaction.cs b/src/Neo/Network/P2P/Payloads/Transaction.cs index 16417beb43..b922674d91 100644 --- a/src/Neo/Network/P2P/Payloads/Transaction.cs +++ b/src/Neo/Network/P2P/Payloads/Transaction.cs @@ -46,7 +46,9 @@ public class Transaction : IEquatable, IInventory, IInteroperable private byte version; private uint nonce; + // In the unit of datoshi, 1 datoshi = 1e-8 GAS private long sysfee; + // In the unit of datoshi, 1 datoshi = 1e-8 GAS private long netfee; private uint validUntilBlock; private Signer[] _signers; @@ -372,26 +374,26 @@ public virtual VerifyResult VerifyStateDependent(ProtocolSettings settings, Data return VerifyResult.InvalidAttribute; else attributesFee += attribute.CalculateNetworkFee(snapshot, this); - long net_fee = NetworkFee - (Size * NativeContract.Policy.GetFeePerByte(snapshot)) - attributesFee; - if (net_fee < 0) return VerifyResult.InsufficientFunds; + long netFeeDatoshi = NetworkFee - (Size * NativeContract.Policy.GetFeePerByte(snapshot)) - attributesFee; + if (netFeeDatoshi < 0) return VerifyResult.InsufficientFunds; - if (net_fee > MaxVerificationGas) net_fee = MaxVerificationGas; + if (netFeeDatoshi > MaxVerificationGas) netFeeDatoshi = MaxVerificationGas; uint execFeeFactor = NativeContract.Policy.GetExecFeeFactor(snapshot); for (int i = 0; i < hashes.Length; i++) { if (IsSignatureContract(witnesses[i].VerificationScript.Span)) - net_fee -= execFeeFactor * SignatureContractCost(); + netFeeDatoshi -= execFeeFactor * SignatureContractCost(); else if (IsMultiSigContract(witnesses[i].VerificationScript.Span, out int m, out int n)) { - net_fee -= execFeeFactor * MultiSignatureContractCost(m, n); + netFeeDatoshi -= execFeeFactor * MultiSignatureContractCost(m, n); } else { - if (!this.VerifyWitness(settings, snapshot, hashes[i], witnesses[i], net_fee, out long fee)) + if (!this.VerifyWitness(settings, snapshot, hashes[i], witnesses[i], netFeeDatoshi, out long fee)) return VerifyResult.Invalid; - net_fee -= fee; + netFeeDatoshi -= fee; } - if (net_fee < 0) return VerifyResult.InsufficientFunds; + if (netFeeDatoshi < 0) return VerifyResult.InsufficientFunds; } return VerifyResult.Succeed; } diff --git a/src/Neo/ProtocolSettings.cs b/src/Neo/ProtocolSettings.cs index f03e5ffaf9..19011dc24c 100644 --- a/src/Neo/ProtocolSettings.cs +++ b/src/Neo/ProtocolSettings.cs @@ -93,6 +93,7 @@ public record ProtocolSettings /// /// Indicates the amount of gas to distribute during initialization. + /// In the unit of datoshi, 1 GAS = 1e8 datoshi /// public ulong InitialGasDistribution { get; init; } diff --git a/src/Neo/SmartContract/ApplicationEngine.Contract.cs b/src/Neo/SmartContract/ApplicationEngine.Contract.cs index 6f4b257016..e5c1c762a7 100644 --- a/src/Neo/SmartContract/ApplicationEngine.Contract.cs +++ b/src/Neo/SmartContract/ApplicationEngine.Contract.cs @@ -120,10 +120,11 @@ protected internal CallFlags GetCallFlags() /// The hash of the account. internal protected UInt160 CreateStandardAccount(ECPoint pubKey) { + // In the unit of datoshi, 1 datoshi = 1e-8 GAS long fee = IsHardforkEnabled(Hardfork.HF_Aspidochelone) ? CheckSigPrice : 1 << 8; - AddGas(fee * ExecFeeFactor); + AddFee(fee * ExecFeeFactor); return Contract.CreateSignatureRedeemScript(pubKey).ToScriptHash(); } @@ -136,10 +137,11 @@ internal protected UInt160 CreateStandardAccount(ECPoint pubKey) /// The hash of the account. internal protected UInt160 CreateMultisigAccount(int m, ECPoint[] pubKeys) { + // In the unit of datoshi, 1 datoshi = 1e-8 GAS long fee = IsHardforkEnabled(Hardfork.HF_Aspidochelone) ? CheckSigPrice * pubKeys.Length : 1 << 8; - AddGas(fee * ExecFeeFactor); + AddFee(fee * ExecFeeFactor); return Contract.CreateMultiSigRedeemScript(m, pubKeys).ToScriptHash(); } diff --git a/src/Neo/SmartContract/ApplicationEngine.Crypto.cs b/src/Neo/SmartContract/ApplicationEngine.Crypto.cs index 1a8b2c7d6d..b63f1287f0 100644 --- a/src/Neo/SmartContract/ApplicationEngine.Crypto.cs +++ b/src/Neo/SmartContract/ApplicationEngine.Crypto.cs @@ -20,6 +20,7 @@ partial class ApplicationEngine { /// /// The price of System.Crypto.CheckSig. + /// In the unit of datoshi, 1 datoshi = 1e-8 GAS /// public const long CheckSigPrice = 1 << 15; @@ -66,7 +67,7 @@ protected internal bool CheckMultisig(byte[][] pubkeys, byte[][] signatures) byte[] message = ScriptContainer.GetSignData(ProtocolSettings.Network); int m = signatures.Length, n = pubkeys.Length; if (n == 0 || m == 0 || m > n) throw new ArgumentException(); - AddGas(CheckSigPrice * n * ExecFeeFactor); + AddFee(CheckSigPrice * n * ExecFeeFactor); try { for (int i = 0, j = 0; i < m && j < n;) diff --git a/src/Neo/SmartContract/ApplicationEngine.OpCodePrices.cs b/src/Neo/SmartContract/ApplicationEngine.OpCodePrices.cs index 16a0a95944..17e4bd6bfb 100644 --- a/src/Neo/SmartContract/ApplicationEngine.OpCodePrices.cs +++ b/src/Neo/SmartContract/ApplicationEngine.OpCodePrices.cs @@ -221,6 +221,10 @@ partial class ApplicationEngine [OpCode.CONVERT] = 1 << 13, }; + /// + /// The prices of all the opcodes. + /// In the unit of datoshi, 1 datoshi = 1e-8 GAS + /// public static readonly long[] OpCodePriceTable = new long[byte.MaxValue]; /// diff --git a/src/Neo/SmartContract/ApplicationEngine.Runtime.cs b/src/Neo/SmartContract/ApplicationEngine.Runtime.cs index 293b245bd7..b39fd55a01 100644 --- a/src/Neo/SmartContract/ApplicationEngine.Runtime.cs +++ b/src/Neo/SmartContract/ApplicationEngine.Runtime.cs @@ -305,6 +305,7 @@ protected internal int GetInvocationCounter() protected internal BigInteger GetRandom() { byte[] buffer; + // In the unit of datoshi, 1 datoshi = 1e-8 GAS long price; if (IsHardforkEnabled(Hardfork.HF_Aspidochelone)) { @@ -316,7 +317,7 @@ protected internal BigInteger GetRandom() buffer = nonceData = Cryptography.Helper.Murmur128(nonceData, ProtocolSettings.Network); price = 1 << 4; } - AddGas(price * ExecFeeFactor); + AddFee(price * ExecFeeFactor); return new BigInteger(buffer, isUnsigned: true); } @@ -420,12 +421,12 @@ protected internal NotifyEventArgs[] GetNotifications(UInt160 hash) /// The implementation of System.Runtime.BurnGas. /// Burning GAS to benefit the NEO ecosystem. /// - /// The amount of GAS to burn. - protected internal void BurnGas(long gas) + /// The amount of GAS to burn, in the unit of datoshi, 1 datoshi = 1e-8 GAS + protected internal void BurnGas(long datoshi) { - if (gas <= 0) + if (datoshi <= 0) throw new InvalidOperationException("GAS must be positive."); - AddGas(gas); + AddFee(datoshi); } /// diff --git a/src/Neo/SmartContract/ApplicationEngine.Storage.cs b/src/Neo/SmartContract/ApplicationEngine.Storage.cs index 3a8bb9d122..fbd452d6cc 100644 --- a/src/Neo/SmartContract/ApplicationEngine.Storage.cs +++ b/src/Neo/SmartContract/ApplicationEngine.Storage.cs @@ -194,7 +194,7 @@ protected internal void Put(StorageContext context, byte[] key, byte[] value) else newDataSize = (item.Value.Length - 1) / 4 + 1 + value.Length - item.Value.Length; } - AddGas(newDataSize * StoragePrice); + AddFee(newDataSize * StoragePrice); item.Value = value; } diff --git a/src/Neo/SmartContract/ApplicationEngine.cs b/src/Neo/SmartContract/ApplicationEngine.cs index 14dedf8e7c..5df47349fb 100644 --- a/src/Neo/SmartContract/ApplicationEngine.cs +++ b/src/Neo/SmartContract/ApplicationEngine.cs @@ -36,6 +36,7 @@ public partial class ApplicationEngine : ExecutionEngine /// /// The maximum cost that can be spent when a contract is executed in test mode. + /// In the unit of datoshi, 1 datoshi = 1e-8 GAS /// public const long TestModeGas = 20_00000000; @@ -50,7 +51,9 @@ public partial class ApplicationEngine : ExecutionEngine public static event EventHandler Log; private static Dictionary services; - private readonly long gas_amount; + // Total amount of GAS spent to execute. + // 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 List notifications; @@ -58,6 +61,7 @@ public partial class ApplicationEngine : ExecutionEngine private readonly Dictionary invocationCounter = new(); private readonly Dictionary contractTasks = new(); internal readonly uint ExecFeeFactor; + // In the unit of datoshi, 1 datoshi = 1e-8 GAS internal readonly uint StoragePrice; private byte[] nonceData; @@ -105,13 +109,22 @@ public partial class ApplicationEngine : ExecutionEngine /// /// GAS spent to execute. + /// In the unit of datoshi, 1 datoshi = 1e-8 GAS, 1 GAS = 1e8 datoshi /// + [Obsolete("This property is deprecated. Use FeeConsumed instead.")] public long GasConsumed { get; private set; } = 0; + /// + /// GAS spent to execute. + /// In the unit of datoshi, 1 datoshi = 1e-8 GAS, 1 GAS = 1e8 datoshi + /// + public long FeeConsumed { get; private set; } = 0; + /// /// The remaining GAS that can be spent in order to complete the execution. + /// In the unit of datoshi, 1 datoshi = 1e-8 GAS, 1 GAS = 1e8 datoshi /// - public long GasLeft => gas_amount - GasConsumed; + public long GasLeft => _feeAmount - FeeConsumed; /// /// The exception that caused the execution to terminate abnormally. This field could be if no exception is thrown. @@ -154,7 +167,7 @@ public virtual UInt160 CallingScriptHash /// 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 used in this execution. The execution will fail when the gas is exhausted. + /// 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( @@ -167,7 +180,7 @@ protected unsafe ApplicationEngine( originalSnapshot = snapshot; PersistingBlock = persistingBlock; ProtocolSettings = settings; - gas_amount = gas; + _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); @@ -235,13 +248,13 @@ protected static void OnSysCall(ExecutionEngine engine, Instruction instruction) #endregion /// - /// Adds GAS to and checks if it has exceeded the maximum limit. + /// Adds GAS to and checks if it has exceeded the maximum limit. /// - /// The amount of GAS to be added. - protected internal void AddGas(long gas) + /// The amount of GAS, in the unit of datoshi, 1 datoshi = 1e-8 GAS, to be added. + protected internal void AddFee(long datoshi) { - GasConsumed = checked(GasConsumed + gas); - if (GasConsumed > gas_amount) + FeeConsumed = GasConsumed = checked(FeeConsumed + datoshi); + if (FeeConsumed > _feeAmount) throw new InvalidOperationException("Insufficient GAS."); } @@ -372,7 +385,7 @@ internal override void UnloadContext(ExecutionContext context) /// 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 used in this execution. The execution will fail when the gas is exhausted. + /// The maximum gas used in this execution, in the unit of datoshi. The execution will fail when the gas is exhausted. /// The diagnostic to be used by the . /// The engine instance created. public static ApplicationEngine Create(TriggerType trigger, IVerifiable container, DataCache snapshot, Block persistingBlock = null, ProtocolSettings settings = null, long gas = TestModeGas, IDiagnostic diagnostic = null) @@ -555,7 +568,7 @@ internal protected void ValidateCallFlags(CallFlags requiredCallFlags) protected virtual void OnSysCall(InteropDescriptor descriptor) { ValidateCallFlags(descriptor.RequiredCallFlags); - AddGas(descriptor.FixedPrice * ExecFeeFactor); + AddFee(descriptor.FixedPrice * ExecFeeFactor); object[] parameters = new object[descriptor.Parameters.Count]; for (int i = 0; i < parameters.Length; i++) @@ -569,7 +582,7 @@ protected virtual void OnSysCall(InteropDescriptor descriptor) protected override void PreExecuteInstruction(Instruction instruction) { Diagnostic?.PreExecuteInstruction(instruction); - AddGas(ExecFeeFactor * OpCodePriceTable[(byte)instruction.OpCode]); + AddFee(ExecFeeFactor * OpCodePriceTable[(byte)instruction.OpCode]); } protected override void PostExecuteInstruction(Instruction instruction) @@ -627,7 +640,7 @@ private static InteropDescriptor Register(string name, string handler, long fixe /// The block being persisted. /// The used by the engine. /// The initial position of the instruction pointer. - /// The maximum gas used in this execution. The execution will fail when the gas is exhausted. + /// 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 engine instance created. public static ApplicationEngine Run(ReadOnlyMemory script, DataCache snapshot, IVerifiable container = null, Block persistingBlock = null, ProtocolSettings settings = null, int offset = 0, long gas = TestModeGas, IDiagnostic diagnostic = null) diff --git a/src/Neo/SmartContract/Helper.cs b/src/Neo/SmartContract/Helper.cs index c0c694fc4e..744fe7e908 100644 --- a/src/Neo/SmartContract/Helper.cs +++ b/src/Neo/SmartContract/Helper.cs @@ -31,11 +31,13 @@ public static class Helper { /// /// The maximum GAS that can be consumed when is called. + /// The unit is datoshi, 1 datoshi = 1e-8 GAS /// public const long MaxVerificationGas = 1_50000000; /// /// Calculates the verification fee for a signature address. + /// In the unit of datoshi, 1 datoshi = 1e-8 GAS /// /// The calculated cost. public static long SignatureContractCost() => @@ -45,6 +47,7 @@ public static long SignatureContractCost() => /// /// Calculates the verification fee for a multi-signature address. + /// In the unit of datoshi, 1 datoshi = 1e-8 GAS /// /// The minimum number of correct signatures that need to be provided in order for the verification to pass. /// The number of public keys in the account. @@ -285,12 +288,12 @@ public static UInt160 ToScriptHash(this ReadOnlySpan script) /// The to be verified. /// The to be used for the verification. /// The snapshot used to read data. - /// The maximum GAS that can be used. + /// The maximum GAS that can be used, in the unit of datoshi, 1 datoshi = 1e-8 GAS. /// if the is verified as valid; otherwise, . - public static bool VerifyWitnesses(this IVerifiable verifiable, ProtocolSettings settings, DataCache snapshot, long gas) + public static bool VerifyWitnesses(this IVerifiable verifiable, ProtocolSettings settings, DataCache snapshot, long datoshi) { - if (gas < 0) return false; - if (gas > MaxVerificationGas) gas = MaxVerificationGas; + if (datoshi < 0) return false; + if (datoshi > MaxVerificationGas) datoshi = MaxVerificationGas; UInt160[] hashes; try @@ -304,14 +307,14 @@ public static bool VerifyWitnesses(this IVerifiable verifiable, ProtocolSettings if (hashes.Length != verifiable.Witnesses.Length) return false; for (int i = 0; i < hashes.Length; i++) { - if (!verifiable.VerifyWitness(settings, snapshot, hashes[i], verifiable.Witnesses[i], gas, out long fee)) + if (!verifiable.VerifyWitness(settings, snapshot, hashes[i], verifiable.Witnesses[i], datoshi, out long fee)) return false; - gas -= fee; + datoshi -= fee; } return true; } - internal static bool VerifyWitness(this IVerifiable verifiable, ProtocolSettings settings, DataCache snapshot, UInt160 hash, Witness witness, long gas, out long fee) + internal static bool VerifyWitness(this IVerifiable verifiable, ProtocolSettings settings, DataCache snapshot, UInt160 hash, Witness witness, long datoshi, out long fee) { fee = 0; Script invocationScript; @@ -323,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, gas)) + using (ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Verification, verifiable, snapshot?.CreateSnapshot(), null, settings, datoshi)) { if (witness.VerificationScript.Length == 0) { @@ -357,7 +360,7 @@ internal static bool VerifyWitness(this IVerifiable verifiable, ProtocolSettings if (engine.Execute() == VMState.FAULT) return false; if (!engine.ResultStack.Peek().GetBoolean()) return false; - fee = engine.GasConsumed; + fee = engine.FeeConsumed; } return true; } diff --git a/src/Neo/SmartContract/Native/ContractManagement.cs b/src/Neo/SmartContract/Native/ContractManagement.cs index e7a7e122f2..8356e09393 100644 --- a/src/Neo/SmartContract/Native/ContractManagement.cs +++ b/src/Neo/SmartContract/Native/ContractManagement.cs @@ -118,11 +118,12 @@ internal override async ContractTask OnPersistAsync(ApplicationEngine engine) [ContractMethod(CpuFee = 1 << 15, RequiredCallFlags = CallFlags.ReadStates)] private long GetMinimumDeploymentFee(DataCache snapshot) { + // In the unit of datoshi, 1 datoshi = 1e-8 GAS return (long)(BigInteger)snapshot[CreateStorageKey(Prefix_MinimumDeploymentFee)]; } [ContractMethod(CpuFee = 1 << 15, RequiredCallFlags = CallFlags.States)] - private void SetMinimumDeploymentFee(ApplicationEngine engine, BigInteger value) + private void SetMinimumDeploymentFee(ApplicationEngine engine, BigInteger value/* In the unit of datoshi, 1 datoshi = 1e-8 GAS*/) { if (value < 0) throw new ArgumentOutOfRangeException(nameof(value)); if (!CheckCommittee(engine)) throw new InvalidOperationException(); @@ -218,7 +219,7 @@ private async ContractTask Deploy(ApplicationEngine engine, byte[ if (manifest.Length == 0) throw new ArgumentException($"Invalid Manifest Length: {manifest.Length}"); - engine.AddGas(Math.Max( + engine.AddFee(Math.Max( engine.StoragePrice * (nefFile.Length + manifest.Length), GetMinimumDeploymentFee(engine.Snapshot) )); @@ -264,7 +265,7 @@ private ContractTask Update(ApplicationEngine engine, byte[] nefFile, byte[] man { if (nefFile is null && manifest is null) throw new ArgumentException(); - engine.AddGas(engine.StoragePrice * ((nefFile?.Length ?? 0) + (manifest?.Length ?? 0))); + engine.AddFee(engine.StoragePrice * ((nefFile?.Length ?? 0) + (manifest?.Length ?? 0))); var contract = engine.Snapshot.GetAndChange(CreateStorageKey(Prefix_Contract).Add(engine.CallingScriptHash))?.GetInteroperable(false); if (contract is null) throw new InvalidOperationException($"Updating Contract Does Not Exist: {engine.CallingScriptHash}"); diff --git a/src/Neo/SmartContract/Native/NativeContract.cs b/src/Neo/SmartContract/Native/NativeContract.cs index 03815b3fae..be43df68fd 100644 --- a/src/Neo/SmartContract/Native/NativeContract.cs +++ b/src/Neo/SmartContract/Native/NativeContract.cs @@ -380,7 +380,8 @@ internal async void Invoke(ApplicationEngine engine, byte version) ExecutionContextState state = context.GetState(); if (!state.CallFlags.HasFlag(method.RequiredCallFlags)) throw new InvalidOperationException($"Cannot call this method with the flag {state.CallFlags}."); - engine.AddGas(method.CpuFee * engine.ExecFeeFactor + method.StorageFee * engine.StoragePrice); + // In the unit of datoshi, 1 datoshi = 1e-8 GAS + 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); diff --git a/src/Neo/SmartContract/Native/NeoToken.cs b/src/Neo/SmartContract/Native/NeoToken.cs index 1fbf07204e..99ecd41e29 100644 --- a/src/Neo/SmartContract/Native/NeoToken.cs +++ b/src/Neo/SmartContract/Native/NeoToken.cs @@ -106,7 +106,8 @@ private GasDistribution DistributeGas(ApplicationEngine engine, UInt160 account, // PersistingBlock is null when running under the debugger if (engine.PersistingBlock is null) return null; - BigInteger gas = CalculateBonus(engine.Snapshot, state, engine.PersistingBlock.Index); + // In the unit of datoshi, 1 datoshi = 1e-8 GAS + BigInteger datoshi = CalculateBonus(engine.Snapshot, state, engine.PersistingBlock.Index); state.BalanceHeight = engine.PersistingBlock.Index; if (state.VoteTo is not null) { @@ -114,11 +115,11 @@ private GasDistribution DistributeGas(ApplicationEngine engine, UInt160 account, var latestGasPerVote = engine.Snapshot.TryGet(keyLastest) ?? BigInteger.Zero; state.LastGasPerVote = latestGasPerVote; } - if (gas == 0) return null; + if (datoshi == 0) return null; return new GasDistribution { Account = account, - Amount = gas + Amount = datoshi }; } @@ -130,6 +131,7 @@ private BigInteger CalculateBonus(DataCache snapshot, NeoAccountState state, uin var expectEnd = Ledger.CurrentIndex(snapshot) + 1; if (expectEnd != end) throw new ArgumentOutOfRangeException(nameof(end)); if (state.BalanceHeight >= end) return BigInteger.Zero; + // In the unit of datoshi, 1 datoshi = 1e-8 GAS BigInteger neoHolderReward = CalculateNeoHolderReward(snapshot, state.Balance, state.BalanceHeight, end); if (state.VoteTo is null) return neoHolderReward; @@ -142,6 +144,7 @@ private BigInteger CalculateBonus(DataCache snapshot, NeoAccountState state, uin private BigInteger CalculateNeoHolderReward(DataCache snapshot, BigInteger value, uint start, uint end) { + // In the unit of datoshi, 1 GAS = 10^8 datoshi BigInteger sum = 0; foreach (var (index, gasPerBlock) in GetSortedGasRecords(snapshot, end - 1)) { @@ -295,6 +298,7 @@ private void SetRegisterPrice(ApplicationEngine engine, long registerPrice) [ContractMethod(CpuFee = 1 << 15, RequiredCallFlags = CallFlags.ReadStates)] public long GetRegisterPrice(DataCache snapshot) { + // In the unit of datoshi, 1 datoshi = 1e-8 GAS return (long)(BigInteger)snapshot[CreateStorageKey(Prefix_RegisterPrice)]; } @@ -327,7 +331,8 @@ private bool RegisterCandidate(ApplicationEngine engine, ECPoint pubkey) { if (!engine.CheckWitnessInternal(Contract.CreateSignatureRedeemScript(pubkey).ToScriptHash())) return false; - engine.AddGas(GetRegisterPrice(engine.Snapshot)); + // In the unit of datoshi, 1 datoshi = 1e-8 GAS + engine.AddFee(GetRegisterPrice(engine.Snapshot)); StorageKey key = CreateStorageKey(Prefix_Candidate).Add(pubkey); StorageItem item = engine.Snapshot.GetAndChange(key, () => new StorageItem(new CandidateState())); CandidateState state = item.GetInteroperable(); diff --git a/src/Neo/SmartContract/Native/OracleContract.cs b/src/Neo/SmartContract/Native/OracleContract.cs index b391518733..13a7264660 100644 --- a/src/Neo/SmartContract/Native/OracleContract.cs +++ b/src/Neo/SmartContract/Native/OracleContract.cs @@ -63,7 +63,7 @@ private void SetPrice(ApplicationEngine engine, long price) /// Gets the price for an Oracle request. /// /// The snapshot used to read data. - /// The price for an Oracle request. + /// The price for an Oracle request, in the unit of datoshi, 1 datoshi = 1e-8 GAS. [ContractMethod(CpuFee = 1 << 15, RequiredCallFlags = CallFlags.ReadStates)] public long GetPrice(DataCache snapshot) { @@ -184,7 +184,7 @@ internal override async ContractTask PostPersistAsync(ApplicationEngine engine) } [ContractMethod(RequiredCallFlags = CallFlags.States | CallFlags.AllowNotify)] - private async ContractTask Request(ApplicationEngine engine, string url, string filter, string callback, StackItem userData, long gasForResponse) + private async ContractTask Request(ApplicationEngine engine, string url, string filter, string callback, StackItem userData, long gasForResponse /* In the unit of datoshi, 1 datoshi = 1e-8 GAS */) { //Check the arguments if (Utility.StrictUTF8.GetByteCount(url) > MaxUrlLength @@ -193,10 +193,10 @@ private async ContractTask Request(ApplicationEngine engine, string url, string || gasForResponse < 0_10000000) throw new ArgumentException(); - engine.AddGas(GetPrice(engine.Snapshot)); + engine.AddFee(GetPrice(engine.Snapshot)); //Mint gas for the response - engine.AddGas(gasForResponse); + engine.AddFee(gasForResponse); await GAS.Mint(engine, Hash, gasForResponse, false); //Increase the request id diff --git a/src/Neo/SmartContract/Native/PolicyContract.cs b/src/Neo/SmartContract/Native/PolicyContract.cs index 7b921d191f..2da6255094 100644 --- a/src/Neo/SmartContract/Native/PolicyContract.cs +++ b/src/Neo/SmartContract/Native/PolicyContract.cs @@ -35,6 +35,7 @@ public sealed class PolicyContract : NativeContract /// /// The default network fee per byte of transactions. + /// In the unit of datoshi, 1 datoshi = 1e-8 GAS /// public const uint DefaultFeePerByte = 1000; diff --git a/src/Neo/Wallets/Helper.cs b/src/Neo/Wallets/Helper.cs index 7589ae949a..dcc9eba896 100644 --- a/src/Neo/Wallets/Helper.cs +++ b/src/Neo/Wallets/Helper.cs @@ -80,6 +80,7 @@ internal static byte[] XOR(byte[] x, byte[] y) /// /// Calculates the network fee for the specified transaction. + /// In the unit of datoshi, 1 datoshi = 1e-8 GAS /// /// The transaction to calculate. /// The snapshot used to read data. @@ -138,9 +139,9 @@ public static long CalculateNetworkFee(this Transaction tx, DataCache snapshot, if (engine.Execute() == VMState.FAULT) throw new ArgumentException($"Smart contract {contract.Hash} verification fault."); if (!engine.ResultStack.Pop().GetBoolean()) throw new ArgumentException($"Smart contract {contract.Hash} returns false."); - maxExecutionCost -= engine.GasConsumed; + maxExecutionCost -= engine.FeeConsumed; if (maxExecutionCost <= 0) throw new InvalidOperationException("Insufficient GAS."); - networkFee += engine.GasConsumed; + networkFee += engine.FeeConsumed; } else if (IsSignatureContract(witnessScript)) { diff --git a/src/Neo/Wallets/Wallet.cs b/src/Neo/Wallets/Wallet.cs index 761b0b1999..e50c98ea48 100644 --- a/src/Neo/Wallets/Wallet.cs +++ b/src/Neo/Wallets/Wallet.cs @@ -535,7 +535,7 @@ public Transaction MakeTransaction(DataCache snapshot, TransferOutput[] outputs, /// The sender of the transaction. /// The cosigners to be added to the transaction. /// The attributes to be added to the transaction. - /// The maximum gas that can be spent to execute the script. + /// The maximum gas that can be spent to execute the script, in the unit of datoshi, 1 datoshi = 1e-8 GAS. /// The block environment to execute the transaction. If null, will be used. /// The created transaction. public Transaction MakeTransaction(DataCache snapshot, ReadOnlyMemory script, UInt160 sender = null, Signer[] cosigners = null, TransactionAttribute[] attributes = null, long maxGas = ApplicationEngine.TestModeGas, Block persistingBlock = null) @@ -575,7 +575,7 @@ private Transaction MakeTransaction(DataCache snapshot, ReadOnlyMemory scr { throw new InvalidOperationException($"Failed execution for '{Convert.ToBase64String(script.Span)}'", engine.FaultException); } - tx.SystemFee = engine.GasConsumed; + tx.SystemFee = engine.FeeConsumed; } tx.NetworkFee = tx.CalculateNetworkFee(snapshot, ProtocolSettings, (a) => GetAccount(a)?.Contract?.Script, maxGas); diff --git a/src/Plugins/RpcServer/RpcServer.SmartContract.cs b/src/Plugins/RpcServer/RpcServer.SmartContract.cs index 92ea7ff62c..dc35ba49f6 100644 --- a/src/Plugins/RpcServer/RpcServer.SmartContract.cs +++ b/src/Plugins/RpcServer/RpcServer.SmartContract.cs @@ -75,6 +75,7 @@ private JObject GetInvokeResult(byte[] script, Signer[] signers = null, Witness[ { json["script"] = Convert.ToBase64String(script); json["state"] = session.Engine.State; + // Gas consumed in the unit of datoshi, 1 GAS = 10^8 datoshi json["gasconsumed"] = session.Engine.GasConsumed.ToString(); json["exception"] = GetExceptionMessage(session.Engine.FaultException); json["notifications"] = new JArray(session.Engine.Notifications.Select(n => diff --git a/src/Plugins/RpcServer/RpcServer.Wallet.cs b/src/Plugins/RpcServer/RpcServer.Wallet.cs index 36825b3f82..b45b048e14 100644 --- a/src/Plugins/RpcServer/RpcServer.Wallet.cs +++ b/src/Plugins/RpcServer/RpcServer.Wallet.cs @@ -95,14 +95,15 @@ protected virtual JToken GetWalletBalance(JArray _params) protected virtual JToken GetWalletUnclaimedGas(JArray _params) { CheckWallet(); - BigInteger gas = BigInteger.Zero; + // Datoshi is the smallest unit of GAS, 1 GAS = 10^8 Datoshi + BigInteger datoshi = BigInteger.Zero; using (var snapshot = system.GetSnapshot()) { uint height = NativeContract.Ledger.CurrentIndex(snapshot) + 1; foreach (UInt160 account in wallet.GetAccounts().Select(p => p.ScriptHash)) - gas += NativeContract.NEO.UnclaimedGas(snapshot, account, height); + datoshi += NativeContract.NEO.UnclaimedGas(snapshot, account, height); } - return gas.ToString(); + return datoshi.ToString(); } [RpcMethod] @@ -381,6 +382,7 @@ private JObject GetVerificationResult(UInt160 scriptHash, ContractParameter[] ar JObject json = new(); json["script"] = Convert.ToBase64String(invocationScript); json["state"] = engine.Execute(); + // Gas consumed in the unit of datoshi, 1 GAS = 1e8 datoshi json["gasconsumed"] = engine.GasConsumed.ToString(); json["exception"] = GetExceptionMessage(engine.FaultException); try diff --git a/src/Plugins/RpcServer/Session.cs b/src/Plugins/RpcServer/Session.cs index 2b4213c28e..6cfef61099 100644 --- a/src/Plugins/RpcServer/Session.cs +++ b/src/Plugins/RpcServer/Session.cs @@ -26,7 +26,7 @@ class Session : IDisposable public readonly Dictionary Iterators = new(); public DateTime StartTime; - public Session(NeoSystem system, byte[] script, Signer[] signers, Witness[] witnesses, long gas, Diagnostic diagnostic) + public Session(NeoSystem system, byte[] script, Signer[] signers, Witness[] witnesses, long datoshi, Diagnostic diagnostic) { Random random = new(); Snapshot = system.GetSnapshot(); @@ -40,7 +40,7 @@ public Session(NeoSystem system, byte[] script, Signer[] signers, Witness[] witn Script = script, Witnesses = witnesses }; - Engine = ApplicationEngine.Run(script, Snapshot, container: tx, settings: system.Settings, gas: gas, diagnostic: diagnostic); + Engine = ApplicationEngine.Run(script, Snapshot, container: tx, settings: system.Settings, gas: datoshi, diagnostic: diagnostic); ResetExpiration(); } diff --git a/src/Plugins/RpcServer/Settings.cs b/src/Plugins/RpcServer/Settings.cs index f4aef116c6..6ed11b956b 100644 --- a/src/Plugins/RpcServer/Settings.cs +++ b/src/Plugins/RpcServer/Settings.cs @@ -44,7 +44,9 @@ public record RpcServerSettings public string[] AllowOrigins { get; init; } public int KeepAliveTimeout { get; init; } public uint RequestHeadersTimeout { get; init; } + // In the unit of datoshi, 1 GAS = 10^8 datoshi public long MaxGasInvoke { get; init; } + // In the unit of datoshi, 1 GAS = 10^8 datoshi public long MaxFee { get; init; } public int MaxIteratorResultItems { get; init; } public int MaxStackSize { get; init; } diff --git a/tests/Neo.UnitTests/Extensions/NativeContractExtensions.cs b/tests/Neo.UnitTests/Extensions/NativeContractExtensions.cs index 9e72fc7ec3..9a282759a9 100644 --- a/tests/Neo.UnitTests/Extensions/NativeContractExtensions.cs +++ b/tests/Neo.UnitTests/Extensions/NativeContractExtensions.cs @@ -21,13 +21,23 @@ namespace Neo.UnitTests.Extensions { public static class NativeContractExtensions { - public static ContractState DeployContract(this DataCache snapshot, UInt160 sender, byte[] nefFile, byte[] manifest, long gas = 200_00000000) + /// + /// Deploy a contract to the blockchain. + /// + /// The snapshot used for deploying the contract. + /// The address of the contract deployer. + /// The file of the contract to be deployed. + /// The manifest of the contract to be deployed. + /// The gas fee to spend for deploying the contract in the unit of datoshi, 1 datoshi = 1e-8 GAS. + /// + /// + public static ContractState DeployContract(this DataCache snapshot, UInt160 sender, byte[] nefFile, byte[] manifest, long datoshi = 200_00000000) { var script = new ScriptBuilder(); script.EmitDynamicCall(NativeContract.ContractManagement.Hash, "deploy", nefFile, manifest, null); var engine = ApplicationEngine.Create(TriggerType.Application, - sender != null ? new Transaction() { Signers = new Signer[] { new Signer() { Account = sender } }, Attributes = System.Array.Empty() } : null, snapshot, settings: TestBlockchain.TheNeoSystem.Settings, gas: gas); + sender != null ? new Transaction() { Signers = new Signer[] { new Signer() { Account = sender } }, Attributes = System.Array.Empty() } : null, snapshot, settings: TestBlockchain.TheNeoSystem.Settings, gas: datoshi); engine.LoadScript(script.ToArray()); if (engine.Execute() != VMState.HALT) diff --git a/tests/Neo.UnitTests/Ledger/UT_PoolItem.cs b/tests/Neo.UnitTests/Ledger/UT_PoolItem.cs index 683291eda9..2b8e54b919 100644 --- a/tests/Neo.UnitTests/Ledger/UT_PoolItem.cs +++ b/tests/Neo.UnitTests/Ledger/UT_PoolItem.cs @@ -47,11 +47,11 @@ public void TestCleanup() public void PoolItem_CompareTo_Fee() { int size1 = 51; - int netFeeSatoshi1 = 1; - var tx1 = GenerateTx(netFeeSatoshi1, size1); + int netFeeDatoshi1 = 1; + var tx1 = GenerateTx(netFeeDatoshi1, size1); int size2 = 51; - int netFeeSatoshi2 = 2; - var tx2 = GenerateTx(netFeeSatoshi2, size2); + int netFeeDatoshi2 = 2; + var tx2 = GenerateTx(netFeeDatoshi2, size2); PoolItem pitem1 = new PoolItem(tx1); PoolItem pitem2 = new PoolItem(tx2); @@ -67,10 +67,10 @@ public void PoolItem_CompareTo_Fee() public void PoolItem_CompareTo_Hash() { int sizeFixed = 51; - int netFeeSatoshiFixed = 1; + int netFeeDatoshiFixed = 1; - var tx1 = GenerateTxWithFirstByteOfHashGreaterThanOrEqualTo(0x80, netFeeSatoshiFixed, sizeFixed); - var tx2 = GenerateTxWithFirstByteOfHashLessThanOrEqualTo(0x79, netFeeSatoshiFixed, sizeFixed); + var tx1 = GenerateTxWithFirstByteOfHashGreaterThanOrEqualTo(0x80, netFeeDatoshiFixed, sizeFixed); + var tx2 = GenerateTxWithFirstByteOfHashLessThanOrEqualTo(0x79, netFeeDatoshiFixed, sizeFixed); tx1.Attributes = new TransactionAttribute[] { new HighPriorityAttribute() }; @@ -83,8 +83,8 @@ public void PoolItem_CompareTo_Hash() // Bulk test for (int testRuns = 0; testRuns < 30; testRuns++) { - tx1 = GenerateTxWithFirstByteOfHashGreaterThanOrEqualTo(0x80, netFeeSatoshiFixed, sizeFixed); - tx2 = GenerateTxWithFirstByteOfHashLessThanOrEqualTo(0x79, netFeeSatoshiFixed, sizeFixed); + tx1 = GenerateTxWithFirstByteOfHashGreaterThanOrEqualTo(0x80, netFeeDatoshiFixed, sizeFixed); + tx2 = GenerateTxWithFirstByteOfHashLessThanOrEqualTo(0x79, netFeeDatoshiFixed, sizeFixed); pitem1 = new PoolItem(tx1); pitem2 = new PoolItem(tx2); @@ -103,8 +103,8 @@ public void PoolItem_CompareTo_Hash() public void PoolItem_CompareTo_Equals() { int sizeFixed = 500; - int netFeeSatoshiFixed = 10; - var tx = GenerateTx(netFeeSatoshiFixed, sizeFixed, new byte[] { 0x13, 0x37 }); + int netFeeDatoshiFixed = 10; + var tx = GenerateTx(netFeeDatoshiFixed, sizeFixed, new byte[] { 0x13, 0x37 }); PoolItem pitem1 = new PoolItem(tx); PoolItem pitem2 = new PoolItem(tx); diff --git a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs index 43755374d3..56d9a66bec 100644 --- a/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs +++ b/tests/Neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs @@ -187,7 +187,7 @@ public void FeeIsMultiSigContract() Assert.AreEqual(VMState.HALT, engine.Execute()); Assert.AreEqual(1, engine.ResultStack.Count); Assert.IsTrue(engine.ResultStack.Pop().GetBoolean()); - verificationGas += engine.GasConsumed; + verificationGas += engine.FeeConsumed; } var sizeGas = tx.Size * NativeContract.Policy.GetFeePerByte(snapshot); @@ -263,7 +263,7 @@ public void FeeIsSignatureContractDetailed() Assert.AreEqual(VMState.HALT, engine.Execute()); Assert.AreEqual(1, engine.ResultStack.Count); Assert.IsTrue(engine.ResultStack.Pop().GetBoolean()); - verificationGas += engine.GasConsumed; + verificationGas += engine.FeeConsumed; } // ------------------ @@ -368,7 +368,7 @@ public void FeeIsSignatureContract_TestScope_Global() Assert.AreEqual(VMState.HALT, engine.Execute()); Assert.AreEqual(1, engine.ResultStack.Count); Assert.IsTrue(engine.ResultStack.Pop().GetBoolean()); - verificationGas += engine.GasConsumed; + verificationGas += engine.FeeConsumed; } // get sizeGas var sizeGas = tx.Size * NativeContract.Policy.GetFeePerByte(snapshot); @@ -448,7 +448,7 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_GAS() Assert.AreEqual(VMState.HALT, engine.Execute()); Assert.AreEqual(1, engine.ResultStack.Count); Assert.IsTrue(engine.ResultStack.Pop().GetBoolean()); - verificationGas += engine.GasConsumed; + verificationGas += engine.FeeConsumed; } // get sizeGas var sizeGas = tx.Size * NativeContract.Policy.GetFeePerByte(snapshot); @@ -531,7 +531,7 @@ public void FeeIsSignatureContract_TestScope_CalledByEntry_Plus_GAS() Assert.AreEqual(VMState.HALT, engine.Execute()); Assert.AreEqual(1, engine.ResultStack.Count); Assert.IsTrue(engine.ResultStack.Pop().GetBoolean()); - verificationGas += engine.GasConsumed; + verificationGas += engine.FeeConsumed; } // get sizeGas var sizeGas = tx.Size * NativeContract.Policy.GetFeePerByte(snapshot); @@ -661,7 +661,7 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_NEO_GAS() Assert.AreEqual(VMState.HALT, engine.Execute()); Assert.AreEqual(1, engine.ResultStack.Count); Assert.IsTrue(engine.ResultStack.Pop().GetBoolean()); - verificationGas += engine.GasConsumed; + verificationGas += engine.FeeConsumed; } // get sizeGas var sizeGas = tx.Size * NativeContract.Policy.GetFeePerByte(snapshot); @@ -818,7 +818,7 @@ public void Transaction_Serialize_Deserialize_Simple() "00" + // version "04030201" + // nonce "00e1f50500000000" + // system fee (1 GAS) - "0100000000000000" + // network fee (1 satoshi) + "0100000000000000" + // network fee (1 datoshi) "04030201" + // timelimit "01000000000000000000000000000000000000000000" + // empty signer "00" + // no attributes @@ -1050,7 +1050,7 @@ public void FeeIsSignatureContract_TestScope_FeeOnly_Default() Assert.AreEqual(VMState.HALT, engine.Execute()); Assert.AreEqual(1, engine.ResultStack.Count); Assert.IsTrue(engine.ResultStack.Pop().GetBoolean()); - verificationGas += engine.GasConsumed; + verificationGas += engine.FeeConsumed; } // get sizeGas var sizeGas = tx.Size * NativeContract.Policy.GetFeePerByte(snapshot); diff --git a/tests/Neo.UnitTests/SmartContract/UT_Contract.cs b/tests/Neo.UnitTests/SmartContract/UT_Contract.cs index a263779282..07ae320a0f 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_Contract.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_Contract.cs @@ -170,7 +170,7 @@ public void TestSignatureRedeemScriptFee() { engine.LoadScript(invocation.Concat(verification).ToArray(), configureState: p => p.CallFlags = CallFlags.None); engine.Execute(); - engine.GasConsumed.Should().Be(fee); + engine.FeeConsumed.Should().Be(fee); } } @@ -198,7 +198,7 @@ public void TestCreateMultiSigRedeemScriptFee() { engine.LoadScript(invocation.Concat(verification).ToArray(), configureState: p => p.CallFlags = CallFlags.None); engine.Execute(); - engine.GasConsumed.Should().Be(fee); + engine.FeeConsumed.Should().Be(fee); } } } diff --git a/tests/Neo.UnitTests/SmartContract/UT_Helper.cs b/tests/Neo.UnitTests/SmartContract/UT_Helper.cs index ffffc70728..e629a5908f 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_Helper.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_Helper.cs @@ -133,7 +133,7 @@ public void TestSignatureContractCost() Assert.AreEqual(VMState.HALT, engine.Execute()); Assert.IsTrue(engine.ResultStack.Pop().GetBoolean()); - Assert.AreEqual(Neo.SmartContract.Helper.SignatureContractCost() * PolicyContract.DefaultExecFeeFactor, engine.GasConsumed); + Assert.AreEqual(Neo.SmartContract.Helper.SignatureContractCost() * PolicyContract.DefaultExecFeeFactor, engine.FeeConsumed); } [TestMethod] @@ -153,7 +153,7 @@ public void TestMultiSignatureContractCost() Assert.AreEqual(VMState.HALT, engine.Execute()); Assert.IsTrue(engine.ResultStack.Pop().GetBoolean()); - Assert.AreEqual(Neo.SmartContract.Helper.MultiSignatureContractCost(1, 1) * PolicyContract.DefaultExecFeeFactor, engine.GasConsumed); + Assert.AreEqual(Neo.SmartContract.Helper.MultiSignatureContractCost(1, 1) * PolicyContract.DefaultExecFeeFactor, engine.FeeConsumed); } } } diff --git a/tests/Neo.UnitTests/SmartContract/UT_InteropPrices.cs b/tests/Neo.UnitTests/SmartContract/UT_InteropPrices.cs index a55db382df..581bf42751 100644 --- a/tests/Neo.UnitTests/SmartContract/UT_InteropPrices.cs +++ b/tests/Neo.UnitTests/SmartContract/UT_InteropPrices.cs @@ -74,9 +74,9 @@ public void ApplicationEngineRegularPut() debugger.StepInto(); debugger.StepInto(); debugger.StepInto(); - var setupPrice = ae.GasConsumed; + var setupPrice = ae.FeeConsumed; debugger.Execute(); - (ae.GasConsumed - setupPrice).Should().Be(ae.StoragePrice * value.Length + (1 << 15) * 30); + (ae.FeeConsumed - setupPrice).Should().Be(ae.StoragePrice * value.Length + (1 << 15) * 30); } /// @@ -105,9 +105,9 @@ public void ApplicationEngineReusedStorage_FullReuse() debugger.StepInto(); debugger.StepInto(); debugger.StepInto(); - var setupPrice = applicationEngine.GasConsumed; + var setupPrice = applicationEngine.FeeConsumed; debugger.Execute(); - (applicationEngine.GasConsumed - setupPrice).Should().Be(1 * applicationEngine.StoragePrice + (1 << 15) * 30); + (applicationEngine.FeeConsumed - setupPrice).Should().Be(1 * applicationEngine.StoragePrice + (1 << 15) * 30); } /// @@ -138,10 +138,10 @@ public void ApplicationEngineReusedStorage_PartialReuse() debugger.StepInto(); debugger.StepInto(); debugger.StepInto(); - var setupPrice = ae.GasConsumed; + var setupPrice = ae.FeeConsumed; debugger.StepInto(); debugger.StepInto(); - (ae.GasConsumed - setupPrice).Should().Be((1 + (oldValue.Length / 4) + value.Length - oldValue.Length) * ae.StoragePrice + (1 << 15) * 30); + (ae.FeeConsumed - setupPrice).Should().Be((1 + (oldValue.Length / 4) + value.Length - oldValue.Length) * ae.StoragePrice + (1 << 15) * 30); } /// @@ -176,9 +176,9 @@ public void ApplicationEngineReusedStorage_PartialReuseTwice() debugger.StepInto(); //push value debugger.StepInto(); //push key debugger.StepInto(); //syscall Storage.GetContext - var setupPrice = ae.GasConsumed; + var setupPrice = ae.FeeConsumed; debugger.StepInto(); //syscall Storage.Put - (ae.GasConsumed - setupPrice).Should().Be((sItem.Value.Length / 4 + 1) * ae.StoragePrice + (1 << 15) * 30); // = PUT basic fee + (ae.FeeConsumed - setupPrice).Should().Be((sItem.Value.Length / 4 + 1) * ae.StoragePrice + (1 << 15) * 30); // = PUT basic fee } private static byte[] CreateMultiplePutScript(byte[] key, byte[] value, int times = 2) From 68005ba7adbc357246295ef106f98c9a8d986140 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Tue, 28 May 2024 06:09:27 +0800 Subject: [PATCH 150/168] [NEO CLI] Remove comments in Json file (#3278) * json readme * update port --------- Co-authored-by: Shargon --- src/Neo.CLI/config.fs.mainnet.json | 4 +- src/Neo.CLI/config.fs.testnet.json | 4 +- src/Neo.CLI/config.json.md | 85 ++++++++++++++++++++++++++++++ src/Neo.CLI/config.mainnet.json | 4 +- src/Neo.CLI/config.testnet.json | 4 +- 5 files changed, 93 insertions(+), 8 deletions(-) create mode 100644 src/Neo.CLI/config.json.md diff --git a/src/Neo.CLI/config.fs.mainnet.json b/src/Neo.CLI/config.fs.mainnet.json index e79a31c312..6adb47eb03 100644 --- a/src/Neo.CLI/config.fs.mainnet.json +++ b/src/Neo.CLI/config.fs.mainnet.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": 40333, diff --git a/src/Neo.CLI/config.fs.testnet.json b/src/Neo.CLI/config.fs.testnet.json index b167f35b81..ca0f0225e6 100644 --- a/src/Neo.CLI/config.fs.testnet.json +++ b/src/Neo.CLI/config.fs.testnet.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": 50333, diff --git a/src/Neo.CLI/config.json.md b/src/Neo.CLI/config.json.md new file mode 100644 index 0000000000..da3bbaec6e --- /dev/null +++ b/src/Neo.CLI/config.json.md @@ -0,0 +1,85 @@ +# 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. + +## ApplicationConfiguration + +### Logger +- **Path**: Directory where log files are stored. Default is "Logs". +- **ConsoleOutput**: Boolean flag to enable or disable console output for logging. Default is `false`. +- **Active**: Boolean flag to activate or deactivate the logger. Default is `false`. + +### Storage +- **Engine**: Specifies the storage engine used by the node. Possible values are: + - `MemoryStore` + - `LevelDBStore` + - `RocksDBStore` +- **Path**: Path to the data storage directory. `{0}` is a placeholder for the network ID. + +### P2P +- **Port**: Port number for the P2P network. MainNet is `10333`, TestNet is `20333`. +- **MinDesiredConnections**: Minimum number of desired P2P connections. Default is `10`. +- **MaxConnections**: Maximum number of P2P connections. Default is `40`. +- **MaxConnectionsPerAddress**: Maximum number of connections allowed per address. Default is `3`. + +### UnlockWallet +- **Path**: Path to the wallet file. +- **Password**: Password for the wallet. +- **IsActive**: Boolean flag to activate or deactivate the wallet. Default is `false`. + +### Contracts +- **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`. + +## ProtocolConfiguration + +### Network +- **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`. + +### MillisecondsPerBlock +- **MillisecondsPerBlock**: Time interval between blocks in milliseconds. Default is `15000` (15 seconds). + +### MaxTransactionsPerBlock +- **MaxTransactionsPerBlock**: Maximum number of transactions allowed per block. Default is `512`. + +### MemoryPoolMaxTransactions +- **MemoryPoolMaxTransactions**: Maximum number of transactions that can be held in the memory pool. Default is `50000`. + +### MaxTraceableBlocks +- **MaxTraceableBlocks**: Maximum number of blocks that can be traced back. Default is `2102400`. + +### Hardforks +- **HF_Aspidochelone**: Block height for the Aspidochelone hard fork. MainNet is `1730000`, TestNet is `210000`. +- **HF_Basilisk**: Block height for the Basilisk hard fork. MainNet is `4120000`, TestNet is `2680000`. +- **HF_Cockatrice**: Block height for the Cockatrice hard fork. MainNet is `5450000`, TestNet is `3967000`. + +### InitialGasDistribution +- **InitialGasDistribution**: Total amount of GAS distributed initially. Default is `5,200,000,000,000,000 Datoshi` (`52,000,000 GAS`). + +### ValidatorsCount +- **ValidatorsCount**: Number of consensus validators. Default is `7`. + +### StandbyCommittee +- **StandbyCommittee**: List of public keys for the standby committee members. + +### SeedList +- **SeedList**: List of seed nodes with their addresses and ports. + - MainNet addresses are: + - `seed1.neo.org:10333` + - `seed2.neo.org:10333` + - `seed3.neo.org:10333` + - `seed4.neo.org:10333` + - `seed5.neo.org:10333` + - TestNet addresses are: + - `seed1t5.neo.org:20333` + - `seed2t5.neo.org:20333` + - `seed3t5.neo.org:20333` + - `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. diff --git a/src/Neo.CLI/config.mainnet.json b/src/Neo.CLI/config.mainnet.json index c9544a337f..a32cad5ad5 100644 --- a/src/Neo.CLI/config.mainnet.json +++ b/src/Neo.CLI/config.mainnet.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.testnet.json b/src/Neo.CLI/config.testnet.json index 6e566c7ce1..4350fc62f2 100644 --- a/src/Neo.CLI/config.testnet.json +++ b/src/Neo.CLI/config.testnet.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": 20333, From 7bb4900de8f5b4d9008e4ec2f2d76f11903cfb77 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Tue, 28 May 2024 15:38:48 +0800 Subject: [PATCH 151/168] fix getcontractstate (#3282) --- src/Plugins/RpcServer/RpcServer.Blockchain.cs | 14 +++++----- .../Neo.Plugins.RpcServer.Tests/UT_Result.cs | 26 +++++++++++++++++++ 2 files changed, 32 insertions(+), 8 deletions(-) create mode 100644 tests/Neo.Plugins.RpcServer.Tests/UT_Result.cs diff --git a/src/Plugins/RpcServer/RpcServer.Blockchain.cs b/src/Plugins/RpcServer/RpcServer.Blockchain.cs index a4fda6e738..cf3c16b59d 100644 --- a/src/Plugins/RpcServer/RpcServer.Blockchain.cs +++ b/src/Plugins/RpcServer/RpcServer.Blockchain.cs @@ -119,15 +119,13 @@ protected virtual JToken GetContractState(JArray _params) { if (int.TryParse(_params[0].AsString(), out int contractId)) { - var contracts = NativeContract.ContractManagement.GetContractById(system.StoreView, contractId); - return contracts?.ToJson().NotNull_Or(RpcError.UnknownContract); - } - else - { - UInt160 script_hash = ToScriptHash(_params[0].AsString()); - ContractState contract = NativeContract.ContractManagement.GetContract(system.StoreView, script_hash); - return contract?.ToJson().NotNull_Or(RpcError.UnknownContract); + var contractState = NativeContract.ContractManagement.GetContractById(system.StoreView, contractId); + return contractState.NotNull_Or(RpcError.UnknownContract).ToJson(); } + + var scriptHash = ToScriptHash(_params[0].AsString()); + var contract = NativeContract.ContractManagement.GetContract(system.StoreView, scriptHash); + return contract.NotNull_Or(RpcError.UnknownContract).ToJson(); } private static UInt160 ToScriptHash(string keyword) diff --git a/tests/Neo.Plugins.RpcServer.Tests/UT_Result.cs b/tests/Neo.Plugins.RpcServer.Tests/UT_Result.cs new file mode 100644 index 0000000000..aa6a8fe308 --- /dev/null +++ b/tests/Neo.Plugins.RpcServer.Tests/UT_Result.cs @@ -0,0 +1,26 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// UT_Result.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; + +namespace Neo.Plugins.RpcServer.Tests; + +[TestClass] +public class UT_Result +{ + [TestMethod] + public void TestNotNull_Or() + { + ContractState? contracts = null; + Assert.ThrowsException(() => contracts.NotNull_Or(RpcError.UnknownContract).ToJson()); + } +} From df067915f25f0632dcaf6ddc4325bb7ccef3034f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vitor=20Naz=C3=A1rio=20Coelho?= Date: Tue, 28 May 2024 05:06:44 -0300 Subject: [PATCH 152/168] Remove StatesDumper - Minor Refactor on StorageDumper (#3281) * Remove StatesDumper - Minor Refactor on StorageDumper * remove extra line --------- Co-authored-by: Jimmy --- neo.sln | 7 - src/Plugins/StatesDumper/PersistActions.cs | 21 --- src/Plugins/StatesDumper/Settings.cs | 58 ------- src/Plugins/StatesDumper/StatesDumper.cs | 169 ------------------- src/Plugins/StatesDumper/StatesDumper.csproj | 18 -- src/Plugins/StatesDumper/StatesDumper.json | 9 - src/Plugins/StorageDumper/Settings.cs | 6 +- src/Plugins/StorageDumper/StorageDumper.cs | 16 +- src/Plugins/StorageDumper/StorageDumper.json | 1 + 9 files changed, 14 insertions(+), 291 deletions(-) delete mode 100644 src/Plugins/StatesDumper/PersistActions.cs delete mode 100644 src/Plugins/StatesDumper/Settings.cs delete mode 100644 src/Plugins/StatesDumper/StatesDumper.cs delete mode 100644 src/Plugins/StatesDumper/StatesDumper.csproj delete mode 100644 src/Plugins/StatesDumper/StatesDumper.json diff --git a/neo.sln b/neo.sln index 46ff7c64e8..b0de1c27b1 100644 --- a/neo.sln +++ b/neo.sln @@ -70,8 +70,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RpcServer", "src\Plugins\Rp EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SQLiteWallet", "src\Plugins\SQLiteWallet\SQLiteWallet.csproj", "{F53D5FF0-5D3D-4E8B-A44F-C4C5D9B563B1}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StatesDumper", "src\Plugins\StatesDumper\StatesDumper.csproj", "{90CCA7D4-C277-4112-A036-BBB90C3FE3BE}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StateService", "src\Plugins\StateService\StateService.csproj", "{88975A8D-4797-45A4-BC3E-15962A425A54}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StorageDumper", "src\Plugins\StorageDumper\StorageDumper.csproj", "{FF76D8A4-356B-461A-8471-BC1B83E57BBC}" @@ -202,10 +200,6 @@ Global {F53D5FF0-5D3D-4E8B-A44F-C4C5D9B563B1}.Debug|Any CPU.Build.0 = Debug|Any CPU {F53D5FF0-5D3D-4E8B-A44F-C4C5D9B563B1}.Release|Any CPU.ActiveCfg = Release|Any CPU {F53D5FF0-5D3D-4E8B-A44F-C4C5D9B563B1}.Release|Any CPU.Build.0 = Release|Any CPU - {90CCA7D4-C277-4112-A036-BBB90C3FE3BE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {90CCA7D4-C277-4112-A036-BBB90C3FE3BE}.Debug|Any CPU.Build.0 = Debug|Any CPU - {90CCA7D4-C277-4112-A036-BBB90C3FE3BE}.Release|Any CPU.ActiveCfg = Release|Any CPU - {90CCA7D4-C277-4112-A036-BBB90C3FE3BE}.Release|Any CPU.Build.0 = Release|Any CPU {88975A8D-4797-45A4-BC3E-15962A425A54}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {88975A8D-4797-45A4-BC3E-15962A425A54}.Debug|Any CPU.Build.0 = Debug|Any CPU {88975A8D-4797-45A4-BC3E-15962A425A54}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -257,7 +251,6 @@ Global {3DE59148-59D6-4CD3-8086-0BC74E3D4E0B} = {C2DC830A-327A-42A7-807D-295216D30DBB} {A3941551-E72C-42D7-8C4D-5122CB60D73D} = {C2DC830A-327A-42A7-807D-295216D30DBB} {F53D5FF0-5D3D-4E8B-A44F-C4C5D9B563B1} = {C2DC830A-327A-42A7-807D-295216D30DBB} - {90CCA7D4-C277-4112-A036-BBB90C3FE3BE} = {C2DC830A-327A-42A7-807D-295216D30DBB} {88975A8D-4797-45A4-BC3E-15962A425A54} = {C2DC830A-327A-42A7-807D-295216D30DBB} {FF76D8A4-356B-461A-8471-BC1B83E57BBC} = {C2DC830A-327A-42A7-807D-295216D30DBB} {5E4947F3-05D3-4806-B0F3-30DAC71B5986} = {C2DC830A-327A-42A7-807D-295216D30DBB} diff --git a/src/Plugins/StatesDumper/PersistActions.cs b/src/Plugins/StatesDumper/PersistActions.cs deleted file mode 100644 index 9c1aa2210c..0000000000 --- a/src/Plugins/StatesDumper/PersistActions.cs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (C) 2015-2024 The Neo Project. -// -// PersistActions.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; - -namespace Neo.Plugins -{ - [Flags] - internal enum PersistActions : byte - { - StorageChanges = 0b00000001 - } -} diff --git a/src/Plugins/StatesDumper/Settings.cs b/src/Plugins/StatesDumper/Settings.cs deleted file mode 100644 index 8fd3b9e163..0000000000 --- a/src/Plugins/StatesDumper/Settings.cs +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (C) 2015-2024 The Neo Project. -// -// Settings.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 Neo.SmartContract.Native; -using System.Collections.Generic; -using System.Linq; - -namespace Neo.Plugins -{ - internal class Settings - { - /// - /// Amount of storages states (heights) to be dump in a given json file - /// - public uint BlockCacheSize { get; } - /// - /// Height to begin storage dump - /// - public uint HeightToBegin { get; } - /// - /// Height to begin real-time syncing and dumping on, consequently, dumping every block into a single files - /// - public int HeightToStartRealTimeSyncing { get; } - /// - /// Persisting actions - /// - public PersistActions PersistAction { get; } - public IReadOnlyList Exclude { get; } - - public static Settings Default { get; private set; } - - private Settings(IConfigurationSection section) - { - /// Geting settings for storage changes state dumper - BlockCacheSize = section.GetValue("BlockCacheSize", 1000u); - HeightToBegin = section.GetValue("HeightToBegin", 0u); - HeightToStartRealTimeSyncing = section.GetValue("HeightToStartRealTimeSyncing", -1); - PersistAction = section.GetValue("PersistAction", PersistActions.StorageChanges); - Exclude = section.GetSection("Exclude").Exists() - ? section.GetSection("Exclude").GetChildren().Select(p => int.Parse(p.Value)).ToArray() - : new[] { NativeContract.Ledger.Id }; - } - - public static void Load(IConfigurationSection section) - { - Default = new Settings(section); - } - } -} diff --git a/src/Plugins/StatesDumper/StatesDumper.cs b/src/Plugins/StatesDumper/StatesDumper.cs deleted file mode 100644 index da1bbd3f69..0000000000 --- a/src/Plugins/StatesDumper/StatesDumper.cs +++ /dev/null @@ -1,169 +0,0 @@ -// Copyright (C) 2015-2024 The Neo Project. -// -// StatesDumper.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.ConsoleService; -using Neo.IO; -using Neo.Json; -using Neo.Ledger; -using Neo.Network.P2P.Payloads; -using Neo.Persistence; -using Neo.SmartContract.Native; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; - -namespace Neo.Plugins -{ - public class StatesDumper : Plugin - { - private readonly Dictionary bs_cache = new Dictionary(); - private readonly Dictionary systems = new Dictionary(); - - public override string Description => "Exports Neo-CLI status data"; - - public override string ConfigFile => System.IO.Path.Combine(RootPath, "StatesDumper.json"); - - public StatesDumper() - { - Blockchain.Committing += OnCommitting; - Blockchain.Committed += OnCommitted; - } - - public override void Dispose() - { - Blockchain.Committing -= OnCommitting; - Blockchain.Committed -= OnCommitted; - } - - protected override void Configure() - { - Settings.Load(GetConfiguration()); - } - - protected override void OnSystemLoaded(NeoSystem system) - { - systems.Add(system.Settings.Network, system); - } - - /// - /// Process "dump storage" command - /// - [ConsoleCommand("dump storage", Category = "Storage", Description = "You can specify the contract script hash or use null to get the corresponding information from the storage")] - private void OnDumpStorage(uint network, UInt160 contractHash = null) - { - if (!systems.ContainsKey(network)) throw new InvalidOperationException("invalid network"); - string path = $"dump_{network:x8}.json"; - byte[] prefix = null; - if (contractHash is not null) - { - var contract = NativeContract.ContractManagement.GetContract(systems[network].StoreView, contractHash); - if (contract is null) throw new InvalidOperationException("contract not found"); - prefix = BitConverter.GetBytes(contract.Id); - } - var states = systems[network].StoreView.Find(prefix); - JArray array = new JArray(states.Where(p => !Settings.Default.Exclude.Contains(p.Key.Id)).Select(p => new JObject - { - ["key"] = Convert.ToBase64String(p.Key.ToArray()), - ["value"] = Convert.ToBase64String(p.Value.ToArray()) - })); - File.WriteAllText(path, array.ToString()); - ConsoleHelper.Info("States", - $"({array.Count})", - " have been dumped into file ", - $"{path}"); - } - - private void OnCommitting(NeoSystem system, Block block, DataCache snapshot, IReadOnlyList applicationExecutedList) - { - if (Settings.Default.PersistAction.HasFlag(PersistActions.StorageChanges)) - OnPersistStorage(system.Settings.Network, snapshot); - } - - private void OnPersistStorage(uint network, DataCache snapshot) - { - uint blockIndex = NativeContract.Ledger.CurrentIndex(snapshot); - if (blockIndex >= Settings.Default.HeightToBegin) - { - JArray array = new JArray(); - - foreach (var trackable in snapshot.GetChangeSet()) - { - if (Settings.Default.Exclude.Contains(trackable.Key.Id)) - continue; - JObject state = new JObject(); - switch (trackable.State) - { - case TrackState.Added: - state["state"] = "Added"; - state["key"] = Convert.ToBase64String(trackable.Key.ToArray()); - state["value"] = Convert.ToBase64String(trackable.Item.ToArray()); - // Here we have a new trackable.Key and trackable.Item - break; - case TrackState.Changed: - state["state"] = "Changed"; - state["key"] = Convert.ToBase64String(trackable.Key.ToArray()); - state["value"] = Convert.ToBase64String(trackable.Item.ToArray()); - break; - case TrackState.Deleted: - state["state"] = "Deleted"; - state["key"] = Convert.ToBase64String(trackable.Key.ToArray()); - break; - } - array.Add(state); - } - - JObject bs_item = new JObject(); - bs_item["block"] = blockIndex; - bs_item["size"] = array.Count; - bs_item["storage"] = array; - if (!bs_cache.TryGetValue(network, out JArray cache)) - { - cache = new JArray(); - } - cache.Add(bs_item); - bs_cache[network] = cache; - } - } - - private void OnCommitted(NeoSystem system, Block block) - { - if (Settings.Default.PersistAction.HasFlag(PersistActions.StorageChanges)) - OnCommitStorage(system.Settings.Network, system.StoreView); - } - - void OnCommitStorage(uint network, DataCache snapshot) - { - if (!bs_cache.TryGetValue(network, out JArray cache)) return; - if (cache.Count == 0) return; - uint blockIndex = NativeContract.Ledger.CurrentIndex(snapshot); - if ((blockIndex % Settings.Default.BlockCacheSize == 0) || (Settings.Default.HeightToStartRealTimeSyncing != -1 && blockIndex >= Settings.Default.HeightToStartRealTimeSyncing)) - { - string path = HandlePaths(network, blockIndex); - path = $"{path}/dump-block-{blockIndex}.json"; - File.WriteAllText(path, cache.ToString()); - cache.Clear(); - } - } - - private static string HandlePaths(uint network, uint blockIndex) - { - //Default Parameter - uint storagePerFolder = 100000; - uint folder = (((blockIndex - 1) / storagePerFolder) + 1) * storagePerFolder; - if (blockIndex == 0) - folder = 0; - string dirPathWithBlock = $"./Storage_{network:x8}/BlockStorage_{folder}"; - Directory.CreateDirectory(dirPathWithBlock); - return dirPathWithBlock; - } - } -} diff --git a/src/Plugins/StatesDumper/StatesDumper.csproj b/src/Plugins/StatesDumper/StatesDumper.csproj deleted file mode 100644 index 4ebf25f2c1..0000000000 --- a/src/Plugins/StatesDumper/StatesDumper.csproj +++ /dev/null @@ -1,18 +0,0 @@ - - - - net8.0 - Neo.Plugins.StatesDumper - - - - - - - - - PreserveNewest - - - - diff --git a/src/Plugins/StatesDumper/StatesDumper.json b/src/Plugins/StatesDumper/StatesDumper.json deleted file mode 100644 index c3b73767dd..0000000000 --- a/src/Plugins/StatesDumper/StatesDumper.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "PluginConfiguration": { - "PersistAction": "StorageChanges", - "BlockCacheSize": 1000, - "HeightToBegin": 0, - "HeightToStartRealTimeSyncing": -1, - "Exclude": [ -4 ] - } -} diff --git a/src/Plugins/StorageDumper/Settings.cs b/src/Plugins/StorageDumper/Settings.cs index 84fe2b2231..aac37ea6d8 100644 --- a/src/Plugins/StorageDumper/Settings.cs +++ b/src/Plugins/StorageDumper/Settings.cs @@ -24,7 +24,10 @@ internal class Settings /// Height to begin storage dump /// public uint HeightToBegin { get; } - + /// + /// Default number of items per folder + /// + public uint StoragePerFolder { get; } public IReadOnlyList Exclude { get; } public static Settings? Default { get; private set; } @@ -34,6 +37,7 @@ private Settings(IConfigurationSection section) /// Geting settings for storage changes state dumper BlockCacheSize = section.GetValue("BlockCacheSize", 1000u); HeightToBegin = section.GetValue("HeightToBegin", 0u); + StoragePerFolder = section.GetValue("StoragePerFolder", 100000u); Exclude = section.GetSection("Exclude").Exists() ? section.GetSection("Exclude").GetChildren().Select(p => int.Parse(p.Value)).ToArray() : new[] { NativeContract.Ledger.Id }; diff --git a/src/Plugins/StorageDumper/StorageDumper.cs b/src/Plugins/StorageDumper/StorageDumper.cs index 696f5014ac..eb9a56c72b 100644 --- a/src/Plugins/StorageDumper/StorageDumper.cs +++ b/src/Plugins/StorageDumper/StorageDumper.cs @@ -24,6 +24,9 @@ public class StorageDumper : Plugin private readonly Dictionary systems = new Dictionary(); private StreamWriter _writer; + /// + /// _currentBlock stores the last cached item + /// private JObject _currentBlock; private string _lastCreateDirectory; @@ -93,7 +96,7 @@ private void OnPersistStorage(uint network, DataCache snapshot) uint blockIndex = NativeContract.Ledger.CurrentIndex(snapshot); if (blockIndex >= Settings.Default.HeightToBegin) { - JArray array = new JArray(); + JArray stateChangeArray = new JArray(); foreach (var trackable in snapshot.GetChangeSet()) { @@ -106,7 +109,6 @@ private void OnPersistStorage(uint network, DataCache snapshot) state["state"] = "Added"; state["key"] = Convert.ToBase64String(trackable.Key.ToArray()); state["value"] = Convert.ToBase64String(trackable.Item.ToArray()); - // Here we have a new trackable.Key and trackable.Item break; case TrackState.Changed: state["state"] = "Changed"; @@ -118,13 +120,13 @@ private void OnPersistStorage(uint network, DataCache snapshot) state["key"] = Convert.ToBase64String(trackable.Key.ToArray()); break; } - array.Add(state); + stateChangeArray.Add(state); } JObject bs_item = new JObject(); bs_item["block"] = blockIndex; - bs_item["size"] = array.Count; - bs_item["storage"] = array; + bs_item["size"] = stateChangeArray.Count; + bs_item["storage"] = stateChangeArray; _currentBlock = bs_item; } } @@ -174,9 +176,7 @@ private string GetOrCreateDirectory(uint network, uint blockIndex) private string GetDirectoryPath(uint network, uint blockIndex) { - //Default Parameter - uint storagePerFolder = 100000; - uint folder = (blockIndex / storagePerFolder) * storagePerFolder; + uint folder = (blockIndex / Settings.Default.StoragePerFolder) * Settings.Default.StoragePerFolder; return $"./StorageDumper_{network}/BlockStorage_{folder}"; } diff --git a/src/Plugins/StorageDumper/StorageDumper.json b/src/Plugins/StorageDumper/StorageDumper.json index 3f5c0537f0..b327c37e0c 100644 --- a/src/Plugins/StorageDumper/StorageDumper.json +++ b/src/Plugins/StorageDumper/StorageDumper.json @@ -2,6 +2,7 @@ "PluginConfiguration": { "BlockCacheSize": 1000, "HeightToBegin": 0, + "StoragePerFolder": 100000, "Exclude": [ -4 ] } } From 5bcfc45bc520df747db2c66659f062e3480112a0 Mon Sep 17 00:00:00 2001 From: Christopher Schuchardt Date: Thu, 30 May 2024 03:51:55 -0400 Subject: [PATCH 153/168] Remove Wanring (#3283) --- src/Neo.GUI/Neo.GUI.csproj | 1 + src/Neo/SmartContract/ApplicationEngine.cs | 2 ++ src/Plugins/OracleService/OracleService.cs | 2 +- .../RpcServer/RpcServer.SmartContract.cs | 2 +- src/Plugins/RpcServer/RpcServer.Wallet.cs | 2 +- src/Plugins/StorageDumper/Settings.cs | 4 ++-- src/Plugins/StorageDumper/StorageDumper.cs | 18 +++++++++--------- 7 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/Neo.GUI/Neo.GUI.csproj b/src/Neo.GUI/Neo.GUI.csproj index 34e515b159..6c7c20912e 100644 --- a/src/Neo.GUI/Neo.GUI.csproj +++ b/src/Neo.GUI/Neo.GUI.csproj @@ -10,6 +10,7 @@ true Neo.GUI neo.ico + false diff --git a/src/Neo/SmartContract/ApplicationEngine.cs b/src/Neo/SmartContract/ApplicationEngine.cs index 5df47349fb..ead04aaba8 100644 --- a/src/Neo/SmartContract/ApplicationEngine.cs +++ b/src/Neo/SmartContract/ApplicationEngine.cs @@ -253,7 +253,9 @@ protected static void OnSysCall(ExecutionEngine engine, Instruction instruction) /// The amount of GAS, in the unit of datoshi, 1 datoshi = 1e-8 GAS, to be added. protected internal void AddFee(long datoshi) { +#pragma warning disable CS0618 // Type or member is obsolete FeeConsumed = GasConsumed = checked(FeeConsumed + datoshi); +#pragma warning restore CS0618 // Type or member is obsolete if (FeeConsumed > _feeAmount) throw new InvalidOperationException("Insufficient GAS."); } diff --git a/src/Plugins/OracleService/OracleService.cs b/src/Plugins/OracleService/OracleService.cs index 637c06712f..703ca7fd65 100644 --- a/src/Plugins/OracleService/OracleService.cs +++ b/src/Plugins/OracleService/OracleService.cs @@ -430,7 +430,7 @@ public static Transaction CreateResponseTx(DataCache snapshot, OracleRequest req ContractMethodDescriptor md = oracleContract.Manifest.Abi.GetMethod("verify", -1); engine.LoadContract(oracleContract, md, CallFlags.None); if (engine.Execute() != VMState.HALT) return null; - tx.NetworkFee += engine.GasConsumed; + tx.NetworkFee += engine.FeeConsumed; var executionFactor = NativeContract.Policy.GetExecFeeFactor(snapshot); var networkFee = executionFactor * SmartContract.Helper.MultiSignatureContractCost(m, n); diff --git a/src/Plugins/RpcServer/RpcServer.SmartContract.cs b/src/Plugins/RpcServer/RpcServer.SmartContract.cs index dc35ba49f6..e1b70df0b0 100644 --- a/src/Plugins/RpcServer/RpcServer.SmartContract.cs +++ b/src/Plugins/RpcServer/RpcServer.SmartContract.cs @@ -76,7 +76,7 @@ private JObject GetInvokeResult(byte[] script, Signer[] signers = null, Witness[ json["script"] = Convert.ToBase64String(script); json["state"] = session.Engine.State; // Gas consumed in the unit of datoshi, 1 GAS = 10^8 datoshi - json["gasconsumed"] = session.Engine.GasConsumed.ToString(); + json["gasconsumed"] = session.Engine.FeeConsumed.ToString(); json["exception"] = GetExceptionMessage(session.Engine.FaultException); json["notifications"] = new JArray(session.Engine.Notifications.Select(n => { diff --git a/src/Plugins/RpcServer/RpcServer.Wallet.cs b/src/Plugins/RpcServer/RpcServer.Wallet.cs index b45b048e14..a907308f17 100644 --- a/src/Plugins/RpcServer/RpcServer.Wallet.cs +++ b/src/Plugins/RpcServer/RpcServer.Wallet.cs @@ -383,7 +383,7 @@ private JObject GetVerificationResult(UInt160 scriptHash, ContractParameter[] ar json["script"] = Convert.ToBase64String(invocationScript); json["state"] = engine.Execute(); // Gas consumed in the unit of datoshi, 1 GAS = 1e8 datoshi - json["gasconsumed"] = engine.GasConsumed.ToString(); + json["gasconsumed"] = engine.FeeConsumed.ToString(); json["exception"] = GetExceptionMessage(engine.FaultException); try { diff --git a/src/Plugins/StorageDumper/Settings.cs b/src/Plugins/StorageDumper/Settings.cs index aac37ea6d8..98b5bc68eb 100644 --- a/src/Plugins/StorageDumper/Settings.cs +++ b/src/Plugins/StorageDumper/Settings.cs @@ -34,12 +34,12 @@ internal class Settings private Settings(IConfigurationSection section) { - /// Geting settings for storage changes state dumper + // Geting settings for storage changes state dumper BlockCacheSize = section.GetValue("BlockCacheSize", 1000u); HeightToBegin = section.GetValue("HeightToBegin", 0u); StoragePerFolder = section.GetValue("StoragePerFolder", 100000u); Exclude = section.GetSection("Exclude").Exists() - ? section.GetSection("Exclude").GetChildren().Select(p => int.Parse(p.Value)).ToArray() + ? section.GetSection("Exclude").GetChildren().Select(p => int.Parse(p.Value!)).ToArray() : new[] { NativeContract.Ledger.Id }; } diff --git a/src/Plugins/StorageDumper/StorageDumper.cs b/src/Plugins/StorageDumper/StorageDumper.cs index eb9a56c72b..2c442886e7 100644 --- a/src/Plugins/StorageDumper/StorageDumper.cs +++ b/src/Plugins/StorageDumper/StorageDumper.cs @@ -23,12 +23,12 @@ public class StorageDumper : Plugin { private readonly Dictionary systems = new Dictionary(); - private StreamWriter _writer; + private StreamWriter? _writer; /// /// _currentBlock stores the last cached item /// - private JObject _currentBlock; - private string _lastCreateDirectory; + private JObject? _currentBlock; + private string? _lastCreateDirectory; public override string Description => "Exports Neo-CLI status data"; @@ -73,7 +73,7 @@ private void OnDumpStorage(uint network, UInt160? contractHash = null) prefix = BitConverter.GetBytes(contract.Id); } var states = systems[network].StoreView.Find(prefix); - JArray array = new JArray(states.Where(p => !Settings.Default.Exclude.Contains(p.Key.Id)).Select(p => new JObject + JArray array = new JArray(states.Where(p => !Settings.Default!.Exclude.Contains(p.Key.Id)).Select(p => new JObject { ["key"] = Convert.ToBase64String(p.Key.ToArray()), ["value"] = Convert.ToBase64String(p.Value.ToArray()) @@ -94,7 +94,7 @@ private void OnCommitting(NeoSystem system, Block block, DataCache snapshot, IRe private void OnPersistStorage(uint network, DataCache snapshot) { uint blockIndex = NativeContract.Ledger.CurrentIndex(snapshot); - if (blockIndex >= Settings.Default.HeightToBegin) + if (blockIndex >= Settings.Default!.HeightToBegin) { JArray stateChangeArray = new JArray(); @@ -139,7 +139,7 @@ private void OnCommitted(NeoSystem system, Block block) void OnCommitStorage(uint network, DataCache snapshot) { - if (_currentBlock != null) + if (_currentBlock != null && _writer != null) { _writer.WriteLine(_currentBlock.ToString()); _writer.Flush(); @@ -150,10 +150,10 @@ private void InitFileWriter(uint network, DataCache snapshot) { uint blockIndex = NativeContract.Ledger.CurrentIndex(snapshot); if (_writer == null - || blockIndex % Settings.Default.BlockCacheSize == 0) + || blockIndex % Settings.Default!.BlockCacheSize == 0) { string path = GetOrCreateDirectory(network, blockIndex); - var filepart = (blockIndex / Settings.Default.BlockCacheSize) * Settings.Default.BlockCacheSize; + var filepart = (blockIndex / Settings.Default!.BlockCacheSize) * Settings.Default.BlockCacheSize; path = $"{path}/dump-block-{filepart}.dump"; if (_writer != null) { @@ -176,7 +176,7 @@ private string GetOrCreateDirectory(uint network, uint blockIndex) private string GetDirectoryPath(uint network, uint blockIndex) { - uint folder = (blockIndex / Settings.Default.StoragePerFolder) * Settings.Default.StoragePerFolder; + uint folder = (blockIndex / Settings.Default!.StoragePerFolder) * Settings.Default.StoragePerFolder; return $"./StorageDumper_{network}/BlockStorage_{folder}"; } From 2c0ce81c244ddd5518e81b39beaf06c14e4332b9 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Fri, 31 May 2024 16:08:02 +0800 Subject: [PATCH 154/168] [Neo Wallet Fix] Add cert import exception (#3279) * add exception * Use using Org.BouncyCastle.Crypto; * clean using * clean further using * update wallet as well * ban the use of import on macos --------- Co-authored-by: Shargon --- src/Neo/Wallets/NEP6/NEP6Wallet.cs | 5 +++++ src/Neo/Wallets/Wallet.cs | 5 +++++ tests/Neo.UnitTests/Wallets/NEP6/UT_NEP6Wallet.cs | 6 ++++++ 3 files changed, 16 insertions(+) diff --git a/src/Neo/Wallets/NEP6/NEP6Wallet.cs b/src/Neo/Wallets/NEP6/NEP6Wallet.cs index cede8e0efa..17a59fc830 100644 --- a/src/Neo/Wallets/NEP6/NEP6Wallet.cs +++ b/src/Neo/Wallets/NEP6/NEP6Wallet.cs @@ -15,6 +15,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using System.Runtime.InteropServices; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using System.Threading.Tasks; @@ -223,6 +224,10 @@ public override IEnumerable GetAccounts() public override WalletAccount Import(X509Certificate2 cert) { + if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + throw new PlatformNotSupportedException("Importing certificates is not supported on macOS."); + } KeyPair key; using (ECDsa ecdsa = cert.GetECDsaPrivateKey()) { diff --git a/src/Neo/Wallets/Wallet.cs b/src/Neo/Wallets/Wallet.cs index e50c98ea48..aca30b008f 100644 --- a/src/Neo/Wallets/Wallet.cs +++ b/src/Neo/Wallets/Wallet.cs @@ -22,6 +22,7 @@ using System.Collections.Generic; using System.Linq; using System.Numerics; +using System.Runtime.InteropServices; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using System.Text; @@ -412,6 +413,10 @@ private static Signer[] GetSigners(UInt160 sender, Signer[] cosigners) /// The imported account. public virtual WalletAccount Import(X509Certificate2 cert) { + if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + throw new PlatformNotSupportedException("Importing certificates is not supported on macOS."); + } byte[] privateKey; using (ECDsa ecdsa = cert.GetECDsaPrivateKey()) { diff --git a/tests/Neo.UnitTests/Wallets/NEP6/UT_NEP6Wallet.cs b/tests/Neo.UnitTests/Wallets/NEP6/UT_NEP6Wallet.cs index aff3561a75..71914c86f0 100644 --- a/tests/Neo.UnitTests/Wallets/NEP6/UT_NEP6Wallet.cs +++ b/tests/Neo.UnitTests/Wallets/NEP6/UT_NEP6Wallet.cs @@ -19,6 +19,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Runtime.InteropServices; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using Contract = Neo.SmartContract.Contract; @@ -302,6 +303,11 @@ public void TestImportCert() X509Certificate2 cert = NewCertificate(); Assert.IsNotNull(cert); Assert.AreEqual(true, cert.HasPrivateKey); + if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + Assert.ThrowsException(() => uut.Import(cert)); + return; + } WalletAccount account = uut.Import(cert); Assert.IsNotNull(account); } From 68d40058861c184c08c478e9a533b179c8948609 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Sat, 1 Jun 2024 16:58:01 +0800 Subject: [PATCH 155/168] [Neo Plugins UT] Fix namespace for adding plugin ut tests (#3286) * update namespaces * fix the moc * avoid change to neo core * Remove empty file --------- Co-authored-by: Shargon --- src/Neo/Neo.csproj | 1 + src/Plugins/ApplicationLogs/LogReader.cs | 8 +-- src/Plugins/ApplicationLogs/Settings.cs | 2 +- .../ApplicationLogs/Store/LogStorageStore.cs | 7 +- .../Store/Models/ApplicationEngineLogModel.cs | 4 +- .../Store/Models/BlockchainEventModel.cs | 5 +- .../Store/Models/BlockchainExecutionModel.cs | 5 +- src/Plugins/ApplicationLogs/Store/NeoStore.cs | 9 +-- .../Store/States/BlockLogState.cs | 2 +- .../Store/States/ContractLogState.cs | 2 +- .../Store/States/EngineLogState.cs | 2 +- .../Store/States/ExecutionLogState.cs | 2 +- .../Store/States/NotifyLogState.cs | 2 +- .../Store/States/TransactionEngineLogState.cs | 2 +- .../Store/States/TransactionLogState.cs | 3 +- .../Consensus/ConsensusContext.Get.cs | 17 +++-- .../Consensus/ConsensusContext.MakePayload.cs | 7 +- .../DBFTPlugin/Consensus/ConsensusContext.cs | 3 +- .../Consensus/ConsensusService.Check.cs | 4 +- .../Consensus/ConsensusService.OnMessage.cs | 5 +- .../DBFTPlugin/Consensus/ConsensusService.cs | 4 +- src/Plugins/DBFTPlugin/DBFTPlugin.cs | 3 +- src/Plugins/DBFTPlugin/Messages/ChangeView.cs | 3 +- src/Plugins/DBFTPlugin/Messages/Commit.cs | 3 +- .../DBFTPlugin/Messages/ConsensusMessage.cs | 3 +- .../DBFTPlugin/Messages/PrepareRequest.cs | 3 +- .../DBFTPlugin/Messages/PrepareResponse.cs | 3 +- ...ecoveryMessage.ChangeViewPayloadCompact.cs | 2 +- .../RecoveryMessage.CommitPayloadCompact.cs | 2 +- ...coveryMessage.PreparationPayloadCompact.cs | 2 +- .../RecoveryMessage/RecoveryMessage.cs | 4 +- .../RecoveryMessage/RecoveryRequest.cs | 3 +- src/Plugins/DBFTPlugin/Settings.cs | 2 +- .../DBFTPlugin/Types/ChangeViewReason.cs | 2 +- .../DBFTPlugin/Types/ConsensusMessageType.cs | 2 +- src/Plugins/OracleService/Helper.cs | 2 +- src/Plugins/OracleService/OracleService.cs | 3 +- .../Protocols/IOracleProtocol.cs | 2 +- .../Protocols/OracleHttpsProtocol.cs | 2 +- .../Protocols/OracleNeoFSProtocol.cs | 2 +- src/Plugins/OracleService/Settings.cs | 2 +- src/Plugins/RpcServer/Diagnostic.cs | 2 +- src/Plugins/RpcServer/Result.cs | 2 +- src/Plugins/RpcServer/RpcError.cs | 2 +- src/Plugins/RpcServer/RpcErrorFactory.cs | 2 +- src/Plugins/RpcServer/RpcException.cs | 2 +- src/Plugins/RpcServer/RpcMethodAttribute.cs | 2 +- src/Plugins/RpcServer/RpcServer.Blockchain.cs | 4 +- src/Plugins/RpcServer/RpcServer.Node.cs | 2 +- .../RpcServer/RpcServer.SmartContract.cs | 2 +- src/Plugins/RpcServer/RpcServer.Utilities.cs | 2 +- src/Plugins/RpcServer/RpcServer.Wallet.cs | 2 +- src/Plugins/RpcServer/RpcServer.cs | 4 +- src/Plugins/RpcServer/RpcServer.csproj | 6 +- src/Plugins/RpcServer/RpcServerPlugin.cs | 10 +-- src/Plugins/RpcServer/Session.cs | 2 +- src/Plugins/RpcServer/Settings.cs | 2 +- src/Plugins/RpcServer/Tree.cs | 2 +- src/Plugins/RpcServer/TreeNode.cs | 2 +- src/Plugins/RpcServer/Utility.cs | 2 +- src/Plugins/StateService/StatePlugin.cs | 1 + src/Plugins/StorageDumper/Settings.cs | 2 +- src/Plugins/StorageDumper/StorageDumper.cs | 2 +- src/Plugins/TokensTracker/TokensTracker.cs | 3 +- .../Trackers/NEP-11/Nep11Tracker.cs | 1 + .../Trackers/NEP-17/Nep17Tracker.cs | 1 + .../TestBlockchain.cs | 2 +- .../TestUtils.cs | 2 +- .../UT_OracleService.cs | 2 +- .../MockNeoSystem.cs | 34 ++++++++++ .../Neo.Plugins.RpcServer.Tests.csproj | 2 + .../TestBlockchain.cs | 49 ++++++++++++++ .../TestProtocolSettings.cs | 65 +++++++++++++++++++ .../UT_RpcServer.cs | 43 +++++++++++- 74 files changed, 306 insertions(+), 103 deletions(-) create mode 100644 tests/Neo.Plugins.RpcServer.Tests/MockNeoSystem.cs create mode 100644 tests/Neo.Plugins.RpcServer.Tests/TestBlockchain.cs create mode 100644 tests/Neo.Plugins.RpcServer.Tests/TestProtocolSettings.cs diff --git a/src/Neo/Neo.csproj b/src/Neo/Neo.csproj index 6a1ba44504..a10444df17 100644 --- a/src/Neo/Neo.csproj +++ b/src/Neo/Neo.csproj @@ -27,6 +27,7 @@ + diff --git a/src/Plugins/ApplicationLogs/LogReader.cs b/src/Plugins/ApplicationLogs/LogReader.cs index 4de4237acb..6a8682ab5e 100644 --- a/src/Plugins/ApplicationLogs/LogReader.cs +++ b/src/Plugins/ApplicationLogs/LogReader.cs @@ -9,21 +9,21 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. -using ApplicationLogs.Store; -using ApplicationLogs.Store.Models; using Neo.ConsoleService; -using Neo.IO; using Neo.Json; using Neo.Ledger; using Neo.Network.P2P.Payloads; using Neo.Persistence; +using Neo.Plugins.ApplicationLogs.Store; +using Neo.Plugins.ApplicationLogs.Store.Models; +using Neo.Plugins.RpcServer; using Neo.SmartContract; using Neo.SmartContract.Native; using Neo.VM; using System.Numerics; using static System.IO.Path; -namespace Neo.Plugins +namespace Neo.Plugins.ApplicationLogs { public class LogReader : Plugin { diff --git a/src/Plugins/ApplicationLogs/Settings.cs b/src/Plugins/ApplicationLogs/Settings.cs index 1e425f664b..8f2a0da1e1 100644 --- a/src/Plugins/ApplicationLogs/Settings.cs +++ b/src/Plugins/ApplicationLogs/Settings.cs @@ -11,7 +11,7 @@ using Microsoft.Extensions.Configuration; -namespace Neo.Plugins +namespace Neo.Plugins.ApplicationLogs { internal class Settings { diff --git a/src/Plugins/ApplicationLogs/Store/LogStorageStore.cs b/src/Plugins/ApplicationLogs/Store/LogStorageStore.cs index aa0357ffb2..249c5d3bd1 100644 --- a/src/Plugins/ApplicationLogs/Store/LogStorageStore.cs +++ b/src/Plugins/ApplicationLogs/Store/LogStorageStore.cs @@ -9,17 +9,14 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. -using ApplicationLogs.Store.States; -using Neo; using Neo.IO; using Neo.Persistence; -using Neo.Plugins; -using Neo.Plugins.Store.States; +using Neo.Plugins.ApplicationLogs.Store.States; using Neo.SmartContract; using Neo.VM; using Neo.VM.Types; -namespace ApplicationLogs.Store +namespace Neo.Plugins.ApplicationLogs.Store { public sealed class LogStorageStore : IDisposable { diff --git a/src/Plugins/ApplicationLogs/Store/Models/ApplicationEngineLogModel.cs b/src/Plugins/ApplicationLogs/Store/Models/ApplicationEngineLogModel.cs index 9836db7146..edc85b1da6 100644 --- a/src/Plugins/ApplicationLogs/Store/Models/ApplicationEngineLogModel.cs +++ b/src/Plugins/ApplicationLogs/Store/Models/ApplicationEngineLogModel.cs @@ -9,9 +9,9 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. -using Neo.Plugins.Store.States; +using Neo.Plugins.ApplicationLogs.Store.States; -namespace Neo.Plugins.Store.Models +namespace Neo.Plugins.ApplicationLogs.Store.Models { public class ApplicationEngineLogModel { diff --git a/src/Plugins/ApplicationLogs/Store/Models/BlockchainEventModel.cs b/src/Plugins/ApplicationLogs/Store/Models/BlockchainEventModel.cs index a882ff1a8c..b067d02f9d 100644 --- a/src/Plugins/ApplicationLogs/Store/Models/BlockchainEventModel.cs +++ b/src/Plugins/ApplicationLogs/Store/Models/BlockchainEventModel.cs @@ -9,11 +9,10 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. -using ApplicationLogs.Store.States; -using Neo; +using Neo.Plugins.ApplicationLogs.Store.States; using Neo.VM.Types; -namespace ApplicationLogs.Store.Models +namespace Neo.Plugins.ApplicationLogs.Store.Models { public class BlockchainEventModel { diff --git a/src/Plugins/ApplicationLogs/Store/Models/BlockchainExecutionModel.cs b/src/Plugins/ApplicationLogs/Store/Models/BlockchainExecutionModel.cs index 19a3de5749..e8ee0fc180 100644 --- a/src/Plugins/ApplicationLogs/Store/Models/BlockchainExecutionModel.cs +++ b/src/Plugins/ApplicationLogs/Store/Models/BlockchainExecutionModel.cs @@ -9,13 +9,12 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. -using ApplicationLogs.Store.States; -using Neo.Plugins.Store.Models; +using Neo.Plugins.ApplicationLogs.Store.States; using Neo.SmartContract; using Neo.VM; using Neo.VM.Types; -namespace ApplicationLogs.Store.Models +namespace Neo.Plugins.ApplicationLogs.Store.Models { public class BlockchainExecutionModel { diff --git a/src/Plugins/ApplicationLogs/Store/NeoStore.cs b/src/Plugins/ApplicationLogs/Store/NeoStore.cs index 496502869b..bc61a9b03c 100644 --- a/src/Plugins/ApplicationLogs/Store/NeoStore.cs +++ b/src/Plugins/ApplicationLogs/Store/NeoStore.cs @@ -9,18 +9,15 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. -using ApplicationLogs.Store.Models; -using ApplicationLogs.Store.States; -using Neo; using Neo.Ledger; using Neo.Network.P2P.Payloads; using Neo.Persistence; -using Neo.Plugins.Store.Models; -using Neo.Plugins.Store.States; +using Neo.Plugins.ApplicationLogs.Store.Models; +using Neo.Plugins.ApplicationLogs.Store.States; using Neo.SmartContract; using Neo.VM.Types; -namespace ApplicationLogs.Store +namespace Neo.Plugins.ApplicationLogs.Store { public sealed class NeoStore : IDisposable { diff --git a/src/Plugins/ApplicationLogs/Store/States/BlockLogState.cs b/src/Plugins/ApplicationLogs/Store/States/BlockLogState.cs index dcbb58b6e6..54369a672a 100644 --- a/src/Plugins/ApplicationLogs/Store/States/BlockLogState.cs +++ b/src/Plugins/ApplicationLogs/Store/States/BlockLogState.cs @@ -12,7 +12,7 @@ using Neo; using Neo.IO; -namespace ApplicationLogs.Store.States +namespace Neo.Plugins.ApplicationLogs.Store.States { public class BlockLogState : ISerializable, IEquatable { diff --git a/src/Plugins/ApplicationLogs/Store/States/ContractLogState.cs b/src/Plugins/ApplicationLogs/Store/States/ContractLogState.cs index 0987e86e67..011886f67c 100644 --- a/src/Plugins/ApplicationLogs/Store/States/ContractLogState.cs +++ b/src/Plugins/ApplicationLogs/Store/States/ContractLogState.cs @@ -14,7 +14,7 @@ using Neo.Ledger; using Neo.SmartContract; -namespace ApplicationLogs.Store.States +namespace Neo.Plugins.ApplicationLogs.Store.States { public class ContractLogState : NotifyLogState, IEquatable { diff --git a/src/Plugins/ApplicationLogs/Store/States/EngineLogState.cs b/src/Plugins/ApplicationLogs/Store/States/EngineLogState.cs index 8b07855253..96f9041aaf 100644 --- a/src/Plugins/ApplicationLogs/Store/States/EngineLogState.cs +++ b/src/Plugins/ApplicationLogs/Store/States/EngineLogState.cs @@ -11,7 +11,7 @@ using Neo.IO; -namespace Neo.Plugins.Store.States +namespace Neo.Plugins.ApplicationLogs.Store.States { public class EngineLogState : ISerializable, IEquatable { diff --git a/src/Plugins/ApplicationLogs/Store/States/ExecutionLogState.cs b/src/Plugins/ApplicationLogs/Store/States/ExecutionLogState.cs index 44f8a74b49..210ac36283 100644 --- a/src/Plugins/ApplicationLogs/Store/States/ExecutionLogState.cs +++ b/src/Plugins/ApplicationLogs/Store/States/ExecutionLogState.cs @@ -13,7 +13,7 @@ using Neo.Ledger; using Neo.VM; -namespace ApplicationLogs.Store.States +namespace Neo.Plugins.ApplicationLogs.Store.States { public class ExecutionLogState : ISerializable, IEquatable { diff --git a/src/Plugins/ApplicationLogs/Store/States/NotifyLogState.cs b/src/Plugins/ApplicationLogs/Store/States/NotifyLogState.cs index 20fbd9e456..70b53268e5 100644 --- a/src/Plugins/ApplicationLogs/Store/States/NotifyLogState.cs +++ b/src/Plugins/ApplicationLogs/Store/States/NotifyLogState.cs @@ -13,7 +13,7 @@ using Neo.IO; using Neo.SmartContract; -namespace ApplicationLogs.Store.States +namespace Neo.Plugins.ApplicationLogs.Store.States { public class NotifyLogState : ISerializable, IEquatable { diff --git a/src/Plugins/ApplicationLogs/Store/States/TransactionEngineLogState.cs b/src/Plugins/ApplicationLogs/Store/States/TransactionEngineLogState.cs index 8b32867b66..9417f984e2 100644 --- a/src/Plugins/ApplicationLogs/Store/States/TransactionEngineLogState.cs +++ b/src/Plugins/ApplicationLogs/Store/States/TransactionEngineLogState.cs @@ -11,7 +11,7 @@ using Neo.IO; -namespace Neo.Plugins.Store.States +namespace Neo.Plugins.ApplicationLogs.Store.States { public class TransactionEngineLogState : ISerializable, IEquatable { diff --git a/src/Plugins/ApplicationLogs/Store/States/TransactionLogState.cs b/src/Plugins/ApplicationLogs/Store/States/TransactionLogState.cs index b40d3244d0..1667478509 100644 --- a/src/Plugins/ApplicationLogs/Store/States/TransactionLogState.cs +++ b/src/Plugins/ApplicationLogs/Store/States/TransactionLogState.cs @@ -9,10 +9,9 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. -using Neo; using Neo.IO; -namespace ApplicationLogs.Store.States +namespace Neo.Plugins.ApplicationLogs.Store.States { public class TransactionLogState : ISerializable, IEquatable { diff --git a/src/Plugins/DBFTPlugin/Consensus/ConsensusContext.Get.cs b/src/Plugins/DBFTPlugin/Consensus/ConsensusContext.Get.cs index b54b6eca1e..edffc1cb09 100644 --- a/src/Plugins/DBFTPlugin/Consensus/ConsensusContext.Get.cs +++ b/src/Plugins/DBFTPlugin/Consensus/ConsensusContext.Get.cs @@ -10,13 +10,12 @@ // modifications are permitted. using Neo.Network.P2P.Payloads; +using Neo.Plugins.DBFTPlugin.Messages; using Neo.SmartContract; -using Neo.Wallets; using System.Linq; using System.Runtime.CompilerServices; -using static Neo.Consensus.RecoveryMessage; -namespace Neo.Consensus +namespace Neo.Plugins.DBFTPlugin.Consensus { partial class ConsensusContext { @@ -33,10 +32,10 @@ public T GetMessage(ExtensiblePayload payload) where T : ConsensusMessage return (T)GetMessage(payload); } - private ChangeViewPayloadCompact GetChangeViewPayloadCompact(ExtensiblePayload payload) + private RecoveryMessage.ChangeViewPayloadCompact GetChangeViewPayloadCompact(ExtensiblePayload payload) { ChangeView message = GetMessage(payload); - return new ChangeViewPayloadCompact + return new RecoveryMessage.ChangeViewPayloadCompact { ValidatorIndex = message.ValidatorIndex, OriginalViewNumber = message.ViewNumber, @@ -45,10 +44,10 @@ private ChangeViewPayloadCompact GetChangeViewPayloadCompact(ExtensiblePayload p }; } - private CommitPayloadCompact GetCommitPayloadCompact(ExtensiblePayload payload) + private RecoveryMessage.CommitPayloadCompact GetCommitPayloadCompact(ExtensiblePayload payload) { Commit message = GetMessage(payload); - return new CommitPayloadCompact + return new RecoveryMessage.CommitPayloadCompact { ViewNumber = message.ViewNumber, ValidatorIndex = message.ValidatorIndex, @@ -57,9 +56,9 @@ private CommitPayloadCompact GetCommitPayloadCompact(ExtensiblePayload payload) }; } - private PreparationPayloadCompact GetPreparationPayloadCompact(ExtensiblePayload payload) + private RecoveryMessage.PreparationPayloadCompact GetPreparationPayloadCompact(ExtensiblePayload payload) { - return new PreparationPayloadCompact + return new RecoveryMessage.PreparationPayloadCompact { ValidatorIndex = GetMessage(payload).ValidatorIndex, InvocationScript = payload.Witness.InvocationScript diff --git a/src/Plugins/DBFTPlugin/Consensus/ConsensusContext.MakePayload.cs b/src/Plugins/DBFTPlugin/Consensus/ConsensusContext.MakePayload.cs index a761cbafb0..ee3b8a7747 100644 --- a/src/Plugins/DBFTPlugin/Consensus/ConsensusContext.MakePayload.cs +++ b/src/Plugins/DBFTPlugin/Consensus/ConsensusContext.MakePayload.cs @@ -11,15 +11,16 @@ using Neo.Ledger; using Neo.Network.P2P.Payloads; +using Neo.Plugins.DBFTPlugin.Messages; +using Neo.Plugins.DBFTPlugin.Types; using Neo.SmartContract; using Neo.Wallets; using System; using System.Buffers.Binary; using System.Collections.Generic; using System.Linq; -using static Neo.Consensus.RecoveryMessage; -namespace Neo.Consensus +namespace Neo.Plugins.DBFTPlugin.Consensus { partial class ConsensusContext { @@ -153,7 +154,7 @@ public ExtensiblePayload MakeRecoveryMessage() PreparationMessages = PreparationPayloads.Where(p => p != null).Select(p => GetPreparationPayloadCompact(p)).ToDictionary(p => p.ValidatorIndex), CommitMessages = CommitSent ? CommitPayloads.Where(p => p != null).Select(p => GetCommitPayloadCompact(p)).ToDictionary(p => p.ValidatorIndex) - : new Dictionary() + : new Dictionary() }); } diff --git a/src/Plugins/DBFTPlugin/Consensus/ConsensusContext.cs b/src/Plugins/DBFTPlugin/Consensus/ConsensusContext.cs index 35044e4fb8..abd0309783 100644 --- a/src/Plugins/DBFTPlugin/Consensus/ConsensusContext.cs +++ b/src/Plugins/DBFTPlugin/Consensus/ConsensusContext.cs @@ -15,6 +15,7 @@ using Neo.Ledger; using Neo.Network.P2P.Payloads; using Neo.Persistence; +using Neo.Plugins.DBFTPlugin.Messages; using Neo.SmartContract; using Neo.SmartContract.Native; using Neo.VM; @@ -24,7 +25,7 @@ using System.IO; using System.Linq; -namespace Neo.Consensus +namespace Neo.Plugins.DBFTPlugin.Consensus { public partial class ConsensusContext : IDisposable, ISerializable { diff --git a/src/Plugins/DBFTPlugin/Consensus/ConsensusService.Check.cs b/src/Plugins/DBFTPlugin/Consensus/ConsensusService.Check.cs index 3b15bcd8fc..c6ba86ee86 100644 --- a/src/Plugins/DBFTPlugin/Consensus/ConsensusService.Check.cs +++ b/src/Plugins/DBFTPlugin/Consensus/ConsensusService.Check.cs @@ -13,10 +13,12 @@ using Neo.IO; using Neo.Network.P2P; using Neo.Network.P2P.Payloads; +using Neo.Plugins.DBFTPlugin.Messages; +using Neo.Plugins.DBFTPlugin.Types; using System; using System.Linq; -namespace Neo.Consensus +namespace Neo.Plugins.DBFTPlugin.Consensus { partial class ConsensusService { diff --git a/src/Plugins/DBFTPlugin/Consensus/ConsensusService.OnMessage.cs b/src/Plugins/DBFTPlugin/Consensus/ConsensusService.OnMessage.cs index ecc31f7ba3..3c6ab8e243 100644 --- a/src/Plugins/DBFTPlugin/Consensus/ConsensusService.OnMessage.cs +++ b/src/Plugins/DBFTPlugin/Consensus/ConsensusService.OnMessage.cs @@ -11,18 +11,17 @@ using Akka.Actor; using Neo.Cryptography; -using Neo.IO; using Neo.Ledger; using Neo.Network.P2P; using Neo.Network.P2P.Payloads; +using Neo.Plugins.DBFTPlugin.Messages; using Neo.SmartContract; using Neo.SmartContract.Native; -using Neo.Wallets; using System; using System.Collections.Generic; using System.Linq; -namespace Neo.Consensus +namespace Neo.Plugins.DBFTPlugin.Consensus { partial class ConsensusService { diff --git a/src/Plugins/DBFTPlugin/Consensus/ConsensusService.cs b/src/Plugins/DBFTPlugin/Consensus/ConsensusService.cs index 8a6d75e8b9..eb97e7024b 100644 --- a/src/Plugins/DBFTPlugin/Consensus/ConsensusService.cs +++ b/src/Plugins/DBFTPlugin/Consensus/ConsensusService.cs @@ -14,13 +14,15 @@ using Neo.Ledger; using Neo.Network.P2P; using Neo.Network.P2P.Payloads; +using Neo.Plugins.DBFTPlugin.Messages; +using Neo.Plugins.DBFTPlugin.Types; using Neo.Wallets; using System; using System.Collections.Generic; using System.Linq; using static Neo.Ledger.Blockchain; -namespace Neo.Consensus +namespace Neo.Plugins.DBFTPlugin.Consensus { partial class ConsensusService : UntypedActor { diff --git a/src/Plugins/DBFTPlugin/DBFTPlugin.cs b/src/Plugins/DBFTPlugin/DBFTPlugin.cs index 59191d2881..9ca44adc74 100644 --- a/src/Plugins/DBFTPlugin/DBFTPlugin.cs +++ b/src/Plugins/DBFTPlugin/DBFTPlugin.cs @@ -14,9 +14,10 @@ using Neo.Network.P2P; using Neo.Network.P2P.Payloads; using Neo.Plugins; +using Neo.Plugins.DBFTPlugin.Consensus; using Neo.Wallets; -namespace Neo.Consensus +namespace Neo.Plugins.DBFTPlugin { public class DBFTPlugin : Plugin { diff --git a/src/Plugins/DBFTPlugin/Messages/ChangeView.cs b/src/Plugins/DBFTPlugin/Messages/ChangeView.cs index e7be40075f..84f681f499 100644 --- a/src/Plugins/DBFTPlugin/Messages/ChangeView.cs +++ b/src/Plugins/DBFTPlugin/Messages/ChangeView.cs @@ -10,9 +10,10 @@ // modifications are permitted. using Neo.IO; +using Neo.Plugins.DBFTPlugin.Types; using System.IO; -namespace Neo.Consensus +namespace Neo.Plugins.DBFTPlugin.Messages { public class ChangeView : ConsensusMessage { diff --git a/src/Plugins/DBFTPlugin/Messages/Commit.cs b/src/Plugins/DBFTPlugin/Messages/Commit.cs index 6e8fe93d87..8f276bb6fe 100644 --- a/src/Plugins/DBFTPlugin/Messages/Commit.cs +++ b/src/Plugins/DBFTPlugin/Messages/Commit.cs @@ -10,10 +10,11 @@ // modifications are permitted. using Neo.IO; +using Neo.Plugins.DBFTPlugin.Types; using System; using System.IO; -namespace Neo.Consensus +namespace Neo.Plugins.DBFTPlugin.Messages { public class Commit : ConsensusMessage { diff --git a/src/Plugins/DBFTPlugin/Messages/ConsensusMessage.cs b/src/Plugins/DBFTPlugin/Messages/ConsensusMessage.cs index 4e136a99e5..de030d166d 100644 --- a/src/Plugins/DBFTPlugin/Messages/ConsensusMessage.cs +++ b/src/Plugins/DBFTPlugin/Messages/ConsensusMessage.cs @@ -10,10 +10,11 @@ // modifications are permitted. using Neo.IO; +using Neo.Plugins.DBFTPlugin.Types; using System; using System.IO; -namespace Neo.Consensus +namespace Neo.Plugins.DBFTPlugin.Messages { public abstract class ConsensusMessage : ISerializable { diff --git a/src/Plugins/DBFTPlugin/Messages/PrepareRequest.cs b/src/Plugins/DBFTPlugin/Messages/PrepareRequest.cs index 2bce609f79..495ccbd726 100644 --- a/src/Plugins/DBFTPlugin/Messages/PrepareRequest.cs +++ b/src/Plugins/DBFTPlugin/Messages/PrepareRequest.cs @@ -10,11 +10,12 @@ // modifications are permitted. using Neo.IO; +using Neo.Plugins.DBFTPlugin.Types; using System; using System.IO; using System.Linq; -namespace Neo.Consensus +namespace Neo.Plugins.DBFTPlugin.Messages { public class PrepareRequest : ConsensusMessage { diff --git a/src/Plugins/DBFTPlugin/Messages/PrepareResponse.cs b/src/Plugins/DBFTPlugin/Messages/PrepareResponse.cs index 7510ff99bb..b4608ff9af 100644 --- a/src/Plugins/DBFTPlugin/Messages/PrepareResponse.cs +++ b/src/Plugins/DBFTPlugin/Messages/PrepareResponse.cs @@ -10,9 +10,10 @@ // modifications are permitted. using Neo.IO; +using Neo.Plugins.DBFTPlugin.Types; using System.IO; -namespace Neo.Consensus +namespace Neo.Plugins.DBFTPlugin.Messages { public class PrepareResponse : ConsensusMessage { diff --git a/src/Plugins/DBFTPlugin/Messages/RecoveryMessage/RecoveryMessage.ChangeViewPayloadCompact.cs b/src/Plugins/DBFTPlugin/Messages/RecoveryMessage/RecoveryMessage.ChangeViewPayloadCompact.cs index 6a7734e569..2d7283cd22 100644 --- a/src/Plugins/DBFTPlugin/Messages/RecoveryMessage/RecoveryMessage.ChangeViewPayloadCompact.cs +++ b/src/Plugins/DBFTPlugin/Messages/RecoveryMessage/RecoveryMessage.ChangeViewPayloadCompact.cs @@ -13,7 +13,7 @@ using System; using System.IO; -namespace Neo.Consensus +namespace Neo.Plugins.DBFTPlugin.Messages { partial class RecoveryMessage { diff --git a/src/Plugins/DBFTPlugin/Messages/RecoveryMessage/RecoveryMessage.CommitPayloadCompact.cs b/src/Plugins/DBFTPlugin/Messages/RecoveryMessage/RecoveryMessage.CommitPayloadCompact.cs index 2dfa16597a..6d3880f3c0 100644 --- a/src/Plugins/DBFTPlugin/Messages/RecoveryMessage/RecoveryMessage.CommitPayloadCompact.cs +++ b/src/Plugins/DBFTPlugin/Messages/RecoveryMessage/RecoveryMessage.CommitPayloadCompact.cs @@ -13,7 +13,7 @@ using System; using System.IO; -namespace Neo.Consensus +namespace Neo.Plugins.DBFTPlugin.Messages { partial class RecoveryMessage { diff --git a/src/Plugins/DBFTPlugin/Messages/RecoveryMessage/RecoveryMessage.PreparationPayloadCompact.cs b/src/Plugins/DBFTPlugin/Messages/RecoveryMessage/RecoveryMessage.PreparationPayloadCompact.cs index 80b2a48b6f..8fae1596ef 100644 --- a/src/Plugins/DBFTPlugin/Messages/RecoveryMessage/RecoveryMessage.PreparationPayloadCompact.cs +++ b/src/Plugins/DBFTPlugin/Messages/RecoveryMessage/RecoveryMessage.PreparationPayloadCompact.cs @@ -13,7 +13,7 @@ using System; using System.IO; -namespace Neo.Consensus +namespace Neo.Plugins.DBFTPlugin.Messages { partial class RecoveryMessage { diff --git a/src/Plugins/DBFTPlugin/Messages/RecoveryMessage/RecoveryMessage.cs b/src/Plugins/DBFTPlugin/Messages/RecoveryMessage/RecoveryMessage.cs index fc688d6a1f..2de33470ea 100644 --- a/src/Plugins/DBFTPlugin/Messages/RecoveryMessage/RecoveryMessage.cs +++ b/src/Plugins/DBFTPlugin/Messages/RecoveryMessage/RecoveryMessage.cs @@ -11,12 +11,14 @@ using Neo.IO; using Neo.Network.P2P.Payloads; +using Neo.Plugins.DBFTPlugin.Consensus; +using Neo.Plugins.DBFTPlugin.Types; using System; using System.Collections.Generic; using System.IO; using System.Linq; -namespace Neo.Consensus +namespace Neo.Plugins.DBFTPlugin.Messages { public partial class RecoveryMessage : ConsensusMessage { diff --git a/src/Plugins/DBFTPlugin/Messages/RecoveryMessage/RecoveryRequest.cs b/src/Plugins/DBFTPlugin/Messages/RecoveryMessage/RecoveryRequest.cs index 84cd381add..2872d28e26 100644 --- a/src/Plugins/DBFTPlugin/Messages/RecoveryMessage/RecoveryRequest.cs +++ b/src/Plugins/DBFTPlugin/Messages/RecoveryMessage/RecoveryRequest.cs @@ -10,9 +10,10 @@ // modifications are permitted. using Neo.IO; +using Neo.Plugins.DBFTPlugin.Types; using System.IO; -namespace Neo.Consensus +namespace Neo.Plugins.DBFTPlugin.Messages { public class RecoveryRequest : ConsensusMessage { diff --git a/src/Plugins/DBFTPlugin/Settings.cs b/src/Plugins/DBFTPlugin/Settings.cs index d0ecbb63fd..28ad21f37a 100644 --- a/src/Plugins/DBFTPlugin/Settings.cs +++ b/src/Plugins/DBFTPlugin/Settings.cs @@ -11,7 +11,7 @@ using Microsoft.Extensions.Configuration; -namespace Neo.Consensus +namespace Neo.Plugins.DBFTPlugin { public class Settings { diff --git a/src/Plugins/DBFTPlugin/Types/ChangeViewReason.cs b/src/Plugins/DBFTPlugin/Types/ChangeViewReason.cs index 4c0a3c1100..5d9e55ffeb 100644 --- a/src/Plugins/DBFTPlugin/Types/ChangeViewReason.cs +++ b/src/Plugins/DBFTPlugin/Types/ChangeViewReason.cs @@ -9,7 +9,7 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. -namespace Neo.Consensus +namespace Neo.Plugins.DBFTPlugin.Types { public enum ChangeViewReason : byte { diff --git a/src/Plugins/DBFTPlugin/Types/ConsensusMessageType.cs b/src/Plugins/DBFTPlugin/Types/ConsensusMessageType.cs index f325133f08..81636e94c1 100644 --- a/src/Plugins/DBFTPlugin/Types/ConsensusMessageType.cs +++ b/src/Plugins/DBFTPlugin/Types/ConsensusMessageType.cs @@ -9,7 +9,7 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. -namespace Neo.Consensus +namespace Neo.Plugins.DBFTPlugin.Types { public enum ConsensusMessageType : byte { diff --git a/src/Plugins/OracleService/Helper.cs b/src/Plugins/OracleService/Helper.cs index 35611e8698..a4711b848e 100644 --- a/src/Plugins/OracleService/Helper.cs +++ b/src/Plugins/OracleService/Helper.cs @@ -12,7 +12,7 @@ using System.Linq; using System.Net; -namespace Neo.Plugins +namespace Neo.Plugins.OracleService { static class Helper { diff --git a/src/Plugins/OracleService/OracleService.cs b/src/Plugins/OracleService/OracleService.cs index 703ca7fd65..11415091d7 100644 --- a/src/Plugins/OracleService/OracleService.cs +++ b/src/Plugins/OracleService/OracleService.cs @@ -20,6 +20,7 @@ using Neo.Network.P2P; using Neo.Network.P2P.Payloads; using Neo.Persistence; +using Neo.Plugins.RpcServer; using Neo.SmartContract; using Neo.SmartContract.Manifest; using Neo.SmartContract.Native; @@ -34,7 +35,7 @@ using System.Threading; using System.Threading.Tasks; -namespace Neo.Plugins +namespace Neo.Plugins.OracleService { public class OracleService : Plugin { diff --git a/src/Plugins/OracleService/Protocols/IOracleProtocol.cs b/src/Plugins/OracleService/Protocols/IOracleProtocol.cs index 3532a69454..d8b84660ee 100644 --- a/src/Plugins/OracleService/Protocols/IOracleProtocol.cs +++ b/src/Plugins/OracleService/Protocols/IOracleProtocol.cs @@ -14,7 +14,7 @@ using System.Threading; using System.Threading.Tasks; -namespace Neo.Plugins +namespace Neo.Plugins.OracleService { interface IOracleProtocol : IDisposable { diff --git a/src/Plugins/OracleService/Protocols/OracleHttpsProtocol.cs b/src/Plugins/OracleService/Protocols/OracleHttpsProtocol.cs index 29d3eedc43..a825f5e60f 100644 --- a/src/Plugins/OracleService/Protocols/OracleHttpsProtocol.cs +++ b/src/Plugins/OracleService/Protocols/OracleHttpsProtocol.cs @@ -20,7 +20,7 @@ using System.Threading; using System.Threading.Tasks; -namespace Neo.Plugins +namespace Neo.Plugins.OracleService { class OracleHttpsProtocol : IOracleProtocol { diff --git a/src/Plugins/OracleService/Protocols/OracleNeoFSProtocol.cs b/src/Plugins/OracleService/Protocols/OracleNeoFSProtocol.cs index 2bf92fa8f4..de0cbd8044 100644 --- a/src/Plugins/OracleService/Protocols/OracleNeoFSProtocol.cs +++ b/src/Plugins/OracleService/Protocols/OracleNeoFSProtocol.cs @@ -24,7 +24,7 @@ using Object = Neo.FileStorage.API.Object.Object; using Range = Neo.FileStorage.API.Object.Range; -namespace Neo.Plugins +namespace Neo.Plugins.OracleService { class OracleNeoFSProtocol : IOracleProtocol { diff --git a/src/Plugins/OracleService/Settings.cs b/src/Plugins/OracleService/Settings.cs index c66010cb5f..952ea0c27b 100644 --- a/src/Plugins/OracleService/Settings.cs +++ b/src/Plugins/OracleService/Settings.cs @@ -13,7 +13,7 @@ using System; using System.Linq; -namespace Neo.Plugins +namespace Neo.Plugins.OracleService { class HttpsSettings { diff --git a/src/Plugins/RpcServer/Diagnostic.cs b/src/Plugins/RpcServer/Diagnostic.cs index a8cba4af9a..7363bc852c 100644 --- a/src/Plugins/RpcServer/Diagnostic.cs +++ b/src/Plugins/RpcServer/Diagnostic.cs @@ -12,7 +12,7 @@ using Neo.SmartContract; using Neo.VM; -namespace Neo.Plugins +namespace Neo.Plugins.RpcServer { class Diagnostic : IDiagnostic { diff --git a/src/Plugins/RpcServer/Result.cs b/src/Plugins/RpcServer/Result.cs index 0ead2482cd..9c7ace227c 100644 --- a/src/Plugins/RpcServer/Result.cs +++ b/src/Plugins/RpcServer/Result.cs @@ -10,7 +10,7 @@ // modifications are permitted. using System; -namespace Neo.Plugins +namespace Neo.Plugins.RpcServer { public static class Result { diff --git a/src/Plugins/RpcServer/RpcError.cs b/src/Plugins/RpcServer/RpcError.cs index 7130540183..667a3906d4 100644 --- a/src/Plugins/RpcServer/RpcError.cs +++ b/src/Plugins/RpcServer/RpcError.cs @@ -11,7 +11,7 @@ using Neo.Json; -namespace Neo.Plugins +namespace Neo.Plugins.RpcServer { public class RpcError { diff --git a/src/Plugins/RpcServer/RpcErrorFactory.cs b/src/Plugins/RpcServer/RpcErrorFactory.cs index 328ba02f61..3d2ac7c9a5 100644 --- a/src/Plugins/RpcServer/RpcErrorFactory.cs +++ b/src/Plugins/RpcServer/RpcErrorFactory.cs @@ -11,7 +11,7 @@ using Neo.Cryptography.ECC; -namespace Neo.Plugins +namespace Neo.Plugins.RpcServer { public static class RpcErrorFactory { diff --git a/src/Plugins/RpcServer/RpcException.cs b/src/Plugins/RpcServer/RpcException.cs index 5c7b5675a1..ab47901b6d 100644 --- a/src/Plugins/RpcServer/RpcException.cs +++ b/src/Plugins/RpcServer/RpcException.cs @@ -11,7 +11,7 @@ using System; -namespace Neo.Plugins +namespace Neo.Plugins.RpcServer { public class RpcException : Exception { diff --git a/src/Plugins/RpcServer/RpcMethodAttribute.cs b/src/Plugins/RpcServer/RpcMethodAttribute.cs index 89edccdd5a..743530ca83 100644 --- a/src/Plugins/RpcServer/RpcMethodAttribute.cs +++ b/src/Plugins/RpcServer/RpcMethodAttribute.cs @@ -11,7 +11,7 @@ using System; -namespace Neo.Plugins +namespace Neo.Plugins.RpcServer { [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] public class RpcMethodAttribute : Attribute diff --git a/src/Plugins/RpcServer/RpcServer.Blockchain.cs b/src/Plugins/RpcServer/RpcServer.Blockchain.cs index cf3c16b59d..1c8eecb99f 100644 --- a/src/Plugins/RpcServer/RpcServer.Blockchain.cs +++ b/src/Plugins/RpcServer/RpcServer.Blockchain.cs @@ -20,7 +20,7 @@ using System.Collections.Generic; using System.Linq; -namespace Neo.Plugins +namespace Neo.Plugins.RpcServer { partial class RpcServer { @@ -61,7 +61,7 @@ protected virtual JToken GetBlock(JArray _params) } [RpcMethod] - protected virtual JToken GetBlockHeaderCount(JArray _params) + internal virtual JToken GetBlockHeaderCount(JArray _params) { return (system.HeaderCache.Last?.Index ?? NativeContract.Ledger.CurrentIndex(system.StoreView)) + 1; } diff --git a/src/Plugins/RpcServer/RpcServer.Node.cs b/src/Plugins/RpcServer/RpcServer.Node.cs index c455100802..79a8884a0f 100644 --- a/src/Plugins/RpcServer/RpcServer.Node.cs +++ b/src/Plugins/RpcServer/RpcServer.Node.cs @@ -19,7 +19,7 @@ using System.Linq; using static Neo.Ledger.Blockchain; -namespace Neo.Plugins +namespace Neo.Plugins.RpcServer { partial class RpcServer { diff --git a/src/Plugins/RpcServer/RpcServer.SmartContract.cs b/src/Plugins/RpcServer/RpcServer.SmartContract.cs index e1b70df0b0..2fe49d4965 100644 --- a/src/Plugins/RpcServer/RpcServer.SmartContract.cs +++ b/src/Plugins/RpcServer/RpcServer.SmartContract.cs @@ -26,7 +26,7 @@ using System.Threading; using Array = System.Array; -namespace Neo.Plugins +namespace Neo.Plugins.RpcServer { partial class RpcServer { diff --git a/src/Plugins/RpcServer/RpcServer.Utilities.cs b/src/Plugins/RpcServer/RpcServer.Utilities.cs index f410e01b73..f9b874c824 100644 --- a/src/Plugins/RpcServer/RpcServer.Utilities.cs +++ b/src/Plugins/RpcServer/RpcServer.Utilities.cs @@ -13,7 +13,7 @@ using Neo.Wallets; using System.Linq; -namespace Neo.Plugins +namespace Neo.Plugins.RpcServer { partial class RpcServer { diff --git a/src/Plugins/RpcServer/RpcServer.Wallet.cs b/src/Plugins/RpcServer/RpcServer.Wallet.cs index a907308f17..30e501263e 100644 --- a/src/Plugins/RpcServer/RpcServer.Wallet.cs +++ b/src/Plugins/RpcServer/RpcServer.Wallet.cs @@ -25,7 +25,7 @@ using System.Linq; using System.Numerics; -namespace Neo.Plugins +namespace Neo.Plugins.RpcServer { partial class RpcServer { diff --git a/src/Plugins/RpcServer/RpcServer.cs b/src/Plugins/RpcServer/RpcServer.cs index f77c2d1e33..c53f17b860 100644 --- a/src/Plugins/RpcServer/RpcServer.cs +++ b/src/Plugins/RpcServer/RpcServer.cs @@ -29,7 +29,7 @@ using System.Text; using System.Threading.Tasks; -namespace Neo.Plugins +namespace Neo.Plugins.RpcServer { public partial class RpcServer : IDisposable { @@ -51,7 +51,7 @@ public RpcServer(NeoSystem system, RpcServerSettings settings) Initialize_SmartContract(); } - private bool CheckAuth(HttpContext context) + internal bool CheckAuth(HttpContext context) { if (string.IsNullOrEmpty(settings.RpcUser)) return true; diff --git a/src/Plugins/RpcServer/RpcServer.csproj b/src/Plugins/RpcServer/RpcServer.csproj index ab2d7e6783..1721c6bccb 100644 --- a/src/Plugins/RpcServer/RpcServer.csproj +++ b/src/Plugins/RpcServer/RpcServer.csproj @@ -1,7 +1,7 @@  - net8.0 + net8.0 Neo.Plugins.RpcServer @@ -15,4 +15,8 @@ + + + + diff --git a/src/Plugins/RpcServer/RpcServerPlugin.cs b/src/Plugins/RpcServer/RpcServerPlugin.cs index 61d9da4397..c22462d139 100644 --- a/src/Plugins/RpcServer/RpcServerPlugin.cs +++ b/src/Plugins/RpcServer/RpcServerPlugin.cs @@ -12,7 +12,7 @@ using System.Collections.Generic; using System.Linq; -namespace Neo.Plugins +namespace Neo.Plugins.RpcServer { public class RpcServerPlugin : Plugin { @@ -55,18 +55,18 @@ protected override void OnSystemLoaded(NeoSystem system) $"Example: \"AllowOrigins\": [\"http://{s.BindAddress}:{s.Port}\"]", LogLevel.Info); } - RpcServer server = new(system, s); + RpcServer rpcRpcServer = new(system, s); if (handlers.Remove(s.Network, out var list)) { foreach (var handler in list) { - server.RegisterMethods(handler); + rpcRpcServer.RegisterMethods(handler); } } - server.StartRpcServer(); - servers.TryAdd(s.Network, server); + rpcRpcServer.StartRpcServer(); + servers.TryAdd(s.Network, rpcRpcServer); } public static void RegisterMethods(object handler, uint network) diff --git a/src/Plugins/RpcServer/Session.cs b/src/Plugins/RpcServer/Session.cs index 6cfef61099..1dd8808dde 100644 --- a/src/Plugins/RpcServer/Session.cs +++ b/src/Plugins/RpcServer/Session.cs @@ -17,7 +17,7 @@ using System; using System.Collections.Generic; -namespace Neo.Plugins +namespace Neo.Plugins.RpcServer { class Session : IDisposable { diff --git a/src/Plugins/RpcServer/Settings.cs b/src/Plugins/RpcServer/Settings.cs index 6ed11b956b..ad624d9082 100644 --- a/src/Plugins/RpcServer/Settings.cs +++ b/src/Plugins/RpcServer/Settings.cs @@ -16,7 +16,7 @@ using System.Linq; using System.Net; -namespace Neo.Plugins +namespace Neo.Plugins.RpcServer { class Settings { diff --git a/src/Plugins/RpcServer/Tree.cs b/src/Plugins/RpcServer/Tree.cs index 77ca1fc2a5..b2d1afc11a 100644 --- a/src/Plugins/RpcServer/Tree.cs +++ b/src/Plugins/RpcServer/Tree.cs @@ -12,7 +12,7 @@ using System; using System.Collections.Generic; -namespace Neo.Plugins +namespace Neo.Plugins.RpcServer { class Tree { diff --git a/src/Plugins/RpcServer/TreeNode.cs b/src/Plugins/RpcServer/TreeNode.cs index 82785277b6..0ba06a689f 100644 --- a/src/Plugins/RpcServer/TreeNode.cs +++ b/src/Plugins/RpcServer/TreeNode.cs @@ -11,7 +11,7 @@ using System.Collections.Generic; -namespace Neo.Plugins +namespace Neo.Plugins.RpcServer { class TreeNode { diff --git a/src/Plugins/RpcServer/Utility.cs b/src/Plugins/RpcServer/Utility.cs index 24ccc9248d..1dda8c131c 100644 --- a/src/Plugins/RpcServer/Utility.cs +++ b/src/Plugins/RpcServer/Utility.cs @@ -14,7 +14,7 @@ using Neo.SmartContract.Native; using System.Linq; -namespace Neo.Plugins +namespace Neo.Plugins.RpcServer { static class Utility { diff --git a/src/Plugins/StateService/StatePlugin.cs b/src/Plugins/StateService/StatePlugin.cs index 36d2c01050..1c28e92193 100644 --- a/src/Plugins/StateService/StatePlugin.cs +++ b/src/Plugins/StateService/StatePlugin.cs @@ -17,6 +17,7 @@ using Neo.Ledger; using Neo.Network.P2P.Payloads; using Neo.Persistence; +using Neo.Plugins.RpcServer; using Neo.Plugins.StateService.Network; using Neo.Plugins.StateService.Storage; using Neo.Plugins.StateService.Verification; diff --git a/src/Plugins/StorageDumper/Settings.cs b/src/Plugins/StorageDumper/Settings.cs index 98b5bc68eb..c2761ce6b9 100644 --- a/src/Plugins/StorageDumper/Settings.cs +++ b/src/Plugins/StorageDumper/Settings.cs @@ -12,7 +12,7 @@ using Microsoft.Extensions.Configuration; using Neo.SmartContract.Native; -namespace Neo.Plugins +namespace Neo.Plugins.StorageDumper { internal class Settings { diff --git a/src/Plugins/StorageDumper/StorageDumper.cs b/src/Plugins/StorageDumper/StorageDumper.cs index 2c442886e7..d8987cdcaa 100644 --- a/src/Plugins/StorageDumper/StorageDumper.cs +++ b/src/Plugins/StorageDumper/StorageDumper.cs @@ -17,7 +17,7 @@ using Neo.Persistence; using Neo.SmartContract.Native; -namespace Neo.Plugins +namespace Neo.Plugins.StorageDumper { public class StorageDumper : Plugin { diff --git a/src/Plugins/TokensTracker/TokensTracker.cs b/src/Plugins/TokensTracker/TokensTracker.cs index 0d8863a767..eacd0de6e4 100644 --- a/src/Plugins/TokensTracker/TokensTracker.cs +++ b/src/Plugins/TokensTracker/TokensTracker.cs @@ -10,12 +10,11 @@ // modifications are permitted. using Microsoft.Extensions.Configuration; -using Neo.IO; using Neo.Ledger; using Neo.Network.P2P.Payloads; 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; diff --git a/src/Plugins/TokensTracker/Trackers/NEP-11/Nep11Tracker.cs b/src/Plugins/TokensTracker/Trackers/NEP-11/Nep11Tracker.cs index 35a579eb77..12d3c208bc 100644 --- a/src/Plugins/TokensTracker/Trackers/NEP-11/Nep11Tracker.cs +++ b/src/Plugins/TokensTracker/Trackers/NEP-11/Nep11Tracker.cs @@ -13,6 +13,7 @@ using Neo.Ledger; using Neo.Network.P2P.Payloads; using Neo.Persistence; +using Neo.Plugins.RpcServer; using Neo.SmartContract; using Neo.SmartContract.Native; using Neo.VM; diff --git a/src/Plugins/TokensTracker/Trackers/NEP-17/Nep17Tracker.cs b/src/Plugins/TokensTracker/Trackers/NEP-17/Nep17Tracker.cs index 8ea2efa6a6..d4698cba1e 100644 --- a/src/Plugins/TokensTracker/Trackers/NEP-17/Nep17Tracker.cs +++ b/src/Plugins/TokensTracker/Trackers/NEP-17/Nep17Tracker.cs @@ -13,6 +13,7 @@ using Neo.Ledger; using Neo.Network.P2P.Payloads; using Neo.Persistence; +using Neo.Plugins.RpcServer; using Neo.SmartContract; using Neo.SmartContract.Native; using Neo.VM; diff --git a/tests/Neo.Plugins.OracleService.Tests/TestBlockchain.cs b/tests/Neo.Plugins.OracleService.Tests/TestBlockchain.cs index 88c08575fa..d689578e22 100644 --- a/tests/Neo.Plugins.OracleService.Tests/TestBlockchain.cs +++ b/tests/Neo.Plugins.OracleService.Tests/TestBlockchain.cs @@ -12,7 +12,7 @@ using Neo.Persistence; using System; -namespace Neo.Plugins +namespace Neo.Plugins.OracleService.Tests { public static class TestBlockchain { diff --git a/tests/Neo.Plugins.OracleService.Tests/TestUtils.cs b/tests/Neo.Plugins.OracleService.Tests/TestUtils.cs index 5700b83769..7f1c3a58d5 100644 --- a/tests/Neo.Plugins.OracleService.Tests/TestUtils.cs +++ b/tests/Neo.Plugins.OracleService.Tests/TestUtils.cs @@ -13,7 +13,7 @@ using Neo.SmartContract; using Neo.SmartContract.Native; -namespace Neo.Plugins +namespace Neo.Plugins.OracleService.Tests { public static class TestUtils { diff --git a/tests/Neo.Plugins.OracleService.Tests/UT_OracleService.cs b/tests/Neo.Plugins.OracleService.Tests/UT_OracleService.cs index 08f96c95d7..9622ceb9e2 100644 --- a/tests/Neo.Plugins.OracleService.Tests/UT_OracleService.cs +++ b/tests/Neo.Plugins.OracleService.Tests/UT_OracleService.cs @@ -16,7 +16,7 @@ using Neo.SmartContract; using Neo.SmartContract.Native; -namespace Neo.Plugins.Tests +namespace Neo.Plugins.OracleService.Tests { [TestClass] public class UT_OracleService : TestKit diff --git a/tests/Neo.Plugins.RpcServer.Tests/MockNeoSystem.cs b/tests/Neo.Plugins.RpcServer.Tests/MockNeoSystem.cs new file mode 100644 index 0000000000..0f45a63d98 --- /dev/null +++ b/tests/Neo.Plugins.RpcServer.Tests/MockNeoSystem.cs @@ -0,0 +1,34 @@ +// 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 2459b1cb5f..5b693c96b8 100644 --- a/tests/Neo.Plugins.RpcServer.Tests/Neo.Plugins.RpcServer.Tests.csproj +++ b/tests/Neo.Plugins.RpcServer.Tests/Neo.Plugins.RpcServer.Tests.csproj @@ -8,11 +8,13 @@ + + diff --git a/tests/Neo.Plugins.RpcServer.Tests/TestBlockchain.cs b/tests/Neo.Plugins.RpcServer.Tests/TestBlockchain.cs new file mode 100644 index 0000000000..f6e35cf695 --- /dev/null +++ b/tests/Neo.Plugins.RpcServer.Tests/TestBlockchain.cs @@ -0,0 +1,49 @@ +// 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 new file mode 100644 index 0000000000..edf2df39fb --- /dev/null +++ b/tests/Neo.Plugins.RpcServer.Tests/TestProtocolSettings.cs @@ -0,0 +1,65 @@ +// 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.cs b/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.cs index 803980eb8f..7bca550b83 100644 --- a/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.cs +++ b/tests/Neo.Plugins.RpcServer.Tests/UT_RpcServer.cs @@ -9,12 +9,53 @@ // Redistribution and use in source and binary forms with or without // modifications are permitted. +using Microsoft.AspNetCore.Http; using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +using Neo.Ledger; +using Neo.Persistence; +using System; +using System.Text; namespace Neo.Plugins.RpcServer.Tests { [TestClass] - public class UT_RpcServer + public partial class UT_RpcServer { + private Mock _systemMock; + private SnapshotCache _snapshotCache; + private MemoryPool _memoryPool; + private RpcServerSettings _settings; + private RpcServer _rpcServer; + + [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); + + _rpcServer = new RpcServer(_systemMock.Object, RpcServerSettings.Default); + } + + [TestMethod] + public void TestCheckAuth_ValidCredentials_ReturnsTrue() + { + var context = new DefaultHttpContext(); + context.Request.Headers["Authorization"] = "Basic " + Convert.ToBase64String(Encoding.UTF8.GetBytes("testuser:testpass")); + var result = _rpcServer.CheckAuth(context); + Assert.IsTrue(result); + } } } From fd1edf0ef20e80f2e22f2746d10b404920ca6461 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Mon, 3 Jun 2024 15:38:02 +0800 Subject: [PATCH 156/168] [Neo MemStore] fix memstore commit bug (#3288) * fix memstore commit issue * update name and format --- src/Neo/Persistence/SnapshotCache.cs | 2 +- .../Persistence/UT_MemoryStore.cs | 49 +++++++++++++------ 2 files changed, 34 insertions(+), 17 deletions(-) diff --git a/src/Neo/Persistence/SnapshotCache.cs b/src/Neo/Persistence/SnapshotCache.cs index 24036b41dc..6731e5342f 100644 --- a/src/Neo/Persistence/SnapshotCache.cs +++ b/src/Neo/Persistence/SnapshotCache.cs @@ -48,7 +48,7 @@ protected override void DeleteInternal(StorageKey key) public override void Commit() { base.Commit(); - snapshot.Commit(); + snapshot?.Commit(); } protected override bool ContainsInternal(StorageKey key) diff --git a/tests/Neo.UnitTests/Persistence/UT_MemoryStore.cs b/tests/Neo.UnitTests/Persistence/UT_MemoryStore.cs index 88d48ba548..b0f61791f6 100644 --- a/tests/Neo.UnitTests/Persistence/UT_MemoryStore.cs +++ b/tests/Neo.UnitTests/Persistence/UT_MemoryStore.cs @@ -11,8 +11,10 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.Persistence; +using Neo.SmartContract; using System; using System.Linq; +using System.Text; namespace Neo.UnitTests.Persistence { @@ -30,27 +32,42 @@ public void StoreTest() { using var store = new MemoryStore(); - store.Delete(new byte[] { 1 }); - Assert.AreEqual(null, store.TryGet(new byte[] { 1 })); - store.Put(new byte[] { 1 }, new byte[] { 1, 2, 3 }); - CollectionAssert.AreEqual(new byte[] { 1, 2, 3 }, store.TryGet(new byte[] { 1 })); + store.Delete([1]); + Assert.AreEqual(null, store.TryGet([1])); + store.Put([1], [1, 2, 3]); + CollectionAssert.AreEqual(new byte[] { 1, 2, 3 }, store.TryGet([1])); - store.Put(new byte[] { 2 }, new byte[] { 4, 5, 6 }); - CollectionAssert.AreEqual(new byte[] { 1 }, store.Seek(Array.Empty(), SeekDirection.Forward).Select(u => u.Key).First()); - CollectionAssert.AreEqual(new byte[] { 2 }, store.Seek(new byte[] { 2 }, SeekDirection.Backward).Select(u => u.Key).First()); - CollectionAssert.AreEqual(new byte[] { 1 }, store.Seek(new byte[] { 1 }, SeekDirection.Backward).Select(u => u.Key).First()); + store.Put([2], [4, 5, 6]); + CollectionAssert.AreEqual(new byte[] { 1 }, store.Seek(Array.Empty()).Select(u => u.Key).First()); + CollectionAssert.AreEqual(new byte[] { 2 }, store.Seek([2], SeekDirection.Backward).Select(u => u.Key).First()); + CollectionAssert.AreEqual(new byte[] { 1 }, store.Seek([1], SeekDirection.Backward).Select(u => u.Key).First()); - store.Delete(new byte[] { 1 }); - store.Delete(new byte[] { 2 }); + store.Delete([1]); + store.Delete([2]); - store.Put(new byte[] { 0x00, 0x00, 0x00 }, new byte[] { 0x00 }); - store.Put(new byte[] { 0x00, 0x00, 0x01 }, new byte[] { 0x01 }); - store.Put(new byte[] { 0x00, 0x00, 0x02 }, new byte[] { 0x02 }); - store.Put(new byte[] { 0x00, 0x00, 0x03 }, new byte[] { 0x03 }); - store.Put(new byte[] { 0x00, 0x00, 0x04 }, new byte[] { 0x04 }); + store.Put([0x00, 0x00, 0x00], [0x00]); + store.Put([0x00, 0x00, 0x01], [0x01]); + store.Put([0x00, 0x00, 0x02], [0x02]); + store.Put([0x00, 0x00, 0x03], [0x03]); + store.Put([0x00, 0x00, 0x04], [0x04]); var entries = store.Seek(Array.Empty(), SeekDirection.Backward).ToArray(); - Assert.AreEqual(entries.Count(), 0); + Assert.AreEqual(entries.Length, 0); } + + [TestMethod] + public void NeoSystemStoreViewTest() + { + var neoSystem = new NeoSystem(TestProtocolSettings.Default, new MemoryStoreProvider()); + 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); + Assert.AreEqual("testValue", Encoding.UTF8.GetString(result.Value.ToArray())); + } + } } From 2fa8f0c91f3814c4a3ac72e6107e8857d22a73e9 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Wed, 5 Jun 2024 21:24:47 +0800 Subject: [PATCH 157/168] [Neo Core Style] define a class for the contractbasemethod (#3291) * define a class for the contractbasemethod, avoid directly using method name string and int pcount everywhere. * add mising file --- src/Neo/SmartContract/ApplicationEngine.cs | 2 +- src/Neo/SmartContract/ContractBasicMethod.cs | 122 ++++++++++++++++++ src/Neo/SmartContract/DeployedContract.cs | 2 +- src/Neo/SmartContract/Helper.cs | 2 +- .../Native/ContractManagement.cs | 2 +- src/Neo/Wallets/Helper.cs | 2 +- src/Plugins/OracleService/OracleService.cs | 2 +- src/Plugins/RpcServer/RpcServer.Wallet.cs | 2 +- 8 files changed, 129 insertions(+), 7 deletions(-) create mode 100644 src/Neo/SmartContract/ContractBasicMethod.cs diff --git a/src/Neo/SmartContract/ApplicationEngine.cs b/src/Neo/SmartContract/ApplicationEngine.cs index ead04aaba8..8602eb054d 100644 --- a/src/Neo/SmartContract/ApplicationEngine.cs +++ b/src/Neo/SmartContract/ApplicationEngine.cs @@ -436,7 +436,7 @@ public ExecutionContext LoadContract(ContractState contract, ContractMethodDescr }); // Call initialization - var init = contract.Manifest.Abi.GetMethod("_initialize", 0); + var init = contract.Manifest.Abi.GetMethod(ContractBasicMethod.Initialize, ContractBasicMethod.InitializePCount); if (init != null) { LoadContext(context.Clone(init.Offset)); diff --git a/src/Neo/SmartContract/ContractBasicMethod.cs b/src/Neo/SmartContract/ContractBasicMethod.cs new file mode 100644 index 0000000000..7897f50c0a --- /dev/null +++ b/src/Neo/SmartContract/ContractBasicMethod.cs @@ -0,0 +1,122 @@ +// Copyright (C) 2015-2024 The Neo Project. +// +// ContractBasicMethod.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 +{ + /// + /// This class provides a guideline for basic methods used in the Neo blockchain, offering + /// a generalized interaction mechanism for smart contract deployment, verification, updates, and destruction. + /// + public record ContractBasicMethod + { + /// + /// The verification method. This must be called when withdrawing tokens from the contract. + /// If the contract address is included in the transaction signature, this method verifies the signature. + /// Example: + /// + /// public static bool Verify() => Runtime.CheckWitness(Owner); + /// + /// + /// { + /// "name": "verify", + /// "safe": false, + /// "parameters": [], + /// "returntype": "bool" + /// } + /// + /// + public static string Verify { get; } = "verify"; + + /// + /// The initialization method. Compiled into the file if any function uses the initialize statement. + /// These functions are executed first when loading the contract. + /// Example: + /// + /// private static readonly UInt160 owner = "NdUL5oDPD159KeFpD5A9zw5xNF1xLX6nLT"; + /// + /// + public static string Initialize { get; } = "_initialize"; + + /// + /// The deployment method. Automatically executed by the ContractManagement contract when a contract is first deployed or updated. + /// + /// { + /// "name": "_deploy", + /// "safe": false, + /// "parameters": [ + /// { + /// "name": "data", + /// "type": "Any" + /// }, + /// { + /// "name": "update", + /// "type": "Boolean" + /// } + /// ], + /// "returntype": "Void" + /// } + /// + /// + public static string Deploy { get; } = "_deploy"; + + /// + /// The update method. Requires or , or both, and is passed to _deploy. + /// Should verify the signer's address using SYSCALL Neo.Runtime.CheckWitness. + /// + /// { + /// "name": "update", + /// "safe": false, + /// "parameters": [ + /// { + /// "name": "nefFile", + /// "type": "ByteArray" + /// }, + /// { + /// "name": "manifest", + /// "type": "ByteArray" + /// }, + /// { + /// "name": "data", + /// "type": "Any" + /// } + /// ], + /// "returntype": "Void" + /// } + /// + /// + public static string Update { get; } = "update"; + + /// + /// The destruction method. Deletes all the storage of the contract. + /// Should verify the signer's address using SYSCALL Neo.Runtime.CheckWitness. + /// Any tokens in the contract must be transferred before destruction. + /// + /// { + /// "name": "destroy", + /// "safe": false, + /// "parameters": [], + /// "returntype": "Void" + /// } + /// + /// + public static string Destroy { get; } = "destroy"; + + /// + /// Parameter counts for the methods. + /// -1 represents the method can take arbitrary parameters. + /// + public static int VerifyPCount { get; } = -1; + public static int InitializePCount { get; } = 0; + public static int DeployPCount { get; } = 2; + public static int UpdatePCount { get; } = 3; + public static int DestroyPCount { get; } = 0; + } +} diff --git a/src/Neo/SmartContract/DeployedContract.cs b/src/Neo/SmartContract/DeployedContract.cs index 0587a029e5..a3f9cfd9fb 100644 --- a/src/Neo/SmartContract/DeployedContract.cs +++ b/src/Neo/SmartContract/DeployedContract.cs @@ -32,7 +32,7 @@ public DeployedContract(ContractState contract) Script = null; ScriptHash = contract.Hash; - ContractMethodDescriptor descriptor = contract.Manifest.Abi.GetMethod("verify", -1); + ContractMethodDescriptor descriptor = contract.Manifest.Abi.GetMethod(ContractBasicMethod.Verify, ContractBasicMethod.VerifyPCount); if (descriptor is null) throw new NotSupportedException("The smart contract haven't got verify method."); ParameterList = descriptor.Parameters.Select(u => u.Type).ToArray(); diff --git a/src/Neo/SmartContract/Helper.cs b/src/Neo/SmartContract/Helper.cs index 744fe7e908..ae31d66a50 100644 --- a/src/Neo/SmartContract/Helper.cs +++ b/src/Neo/SmartContract/Helper.cs @@ -332,7 +332,7 @@ internal static bool VerifyWitness(this IVerifiable verifiable, ProtocolSettings { ContractState cs = NativeContract.ContractManagement.GetContract(snapshot, hash); if (cs is null) return false; - ContractMethodDescriptor md = cs.Manifest.Abi.GetMethod("verify", -1); + ContractMethodDescriptor md = cs.Manifest.Abi.GetMethod(ContractBasicMethod.Verify, ContractBasicMethod.VerifyPCount); if (md?.ReturnType != ContractParameterType.Boolean) return false; engine.LoadContract(cs, md, CallFlags.ReadOnly); } diff --git a/src/Neo/SmartContract/Native/ContractManagement.cs b/src/Neo/SmartContract/Native/ContractManagement.cs index 8356e09393..c533f029a6 100644 --- a/src/Neo/SmartContract/Native/ContractManagement.cs +++ b/src/Neo/SmartContract/Native/ContractManagement.cs @@ -60,7 +60,7 @@ internal override ContractTask InitializeAsync(ApplicationEngine engine, Hardfor private async ContractTask OnDeployAsync(ApplicationEngine engine, ContractState contract, StackItem data, bool update) { - ContractMethodDescriptor md = contract.Manifest.Abi.GetMethod("_deploy", 2); + ContractMethodDescriptor md = contract.Manifest.Abi.GetMethod(ContractBasicMethod.Deploy, ContractBasicMethod.DeployPCount); if (md is not null) await engine.CallFromNativeContractAsync(Hash, contract.Hash, md.Name, data, update); engine.SendNotification(Hash, update ? "Update" : "Deploy", new VM.Types.Array(engine.ReferenceCounter) { contract.Hash.ToArray() }); diff --git a/src/Neo/Wallets/Helper.cs b/src/Neo/Wallets/Helper.cs index dcc9eba896..1273bafc50 100644 --- a/src/Neo/Wallets/Helper.cs +++ b/src/Neo/Wallets/Helper.cs @@ -120,7 +120,7 @@ public static long CalculateNetworkFee(this Transaction tx, DataCache snapshot, var contract = NativeContract.ContractManagement.GetContract(snapshot, hash); if (contract is null) throw new ArgumentException($"The smart contract or address {hash} is not found"); - var md = contract.Manifest.Abi.GetMethod("verify", -1); + var md = contract.Manifest.Abi.GetMethod(ContractBasicMethod.Verify, ContractBasicMethod.VerifyPCount); if (md is null) throw new ArgumentException($"The smart contract {contract.Hash} haven't got verify method"); if (md.ReturnType != ContractParameterType.Boolean) diff --git a/src/Plugins/OracleService/OracleService.cs b/src/Plugins/OracleService/OracleService.cs index 11415091d7..e9787b3d4c 100644 --- a/src/Plugins/OracleService/OracleService.cs +++ b/src/Plugins/OracleService/OracleService.cs @@ -428,7 +428,7 @@ public static Transaction CreateResponseTx(DataCache snapshot, OracleRequest req var oracleContract = NativeContract.ContractManagement.GetContract(snapshot, NativeContract.Oracle.Hash); var engine = ApplicationEngine.Create(TriggerType.Verification, tx, snapshot.CreateSnapshot(), settings: settings); - ContractMethodDescriptor md = oracleContract.Manifest.Abi.GetMethod("verify", -1); + ContractMethodDescriptor md = oracleContract.Manifest.Abi.GetMethod(ContractBasicMethod.Verify, ContractBasicMethod.VerifyPCount); engine.LoadContract(oracleContract, md, CallFlags.None); if (engine.Execute() != VMState.HALT) return null; tx.NetworkFee += engine.FeeConsumed; diff --git a/src/Plugins/RpcServer/RpcServer.Wallet.cs b/src/Plugins/RpcServer/RpcServer.Wallet.cs index 30e501263e..f1adb277ce 100644 --- a/src/Plugins/RpcServer/RpcServer.Wallet.cs +++ b/src/Plugins/RpcServer/RpcServer.Wallet.cs @@ -356,7 +356,7 @@ private JObject GetVerificationResult(UInt160 scriptHash, ContractParameter[] ar { using var snapshot = system.GetSnapshot(); var contract = NativeContract.ContractManagement.GetContract(snapshot, scriptHash).NotNull_Or(RpcError.UnknownContract); - var md = contract.Manifest.Abi.GetMethod("verify", -1).NotNull_Or(RpcErrorFactory.InvalidContractVerification(contract.Hash)); + 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.")); Transaction tx = new() { From 766ad0854b2933a1cb8367162fbf2c5f5011d4a0 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Fri, 7 Jun 2024 17:28:09 +0800 Subject: [PATCH 158/168] [Neo Core Style] Rename parameters, update comments, fix code style (#3294) * fix code style * Clean code --------- Co-authored-by: Fernando Diaz Toledano --- .../SmartContract/Native/NativeContract.cs | 91 +++++++++---------- 1 file changed, 45 insertions(+), 46 deletions(-) diff --git a/src/Neo/SmartContract/Native/NativeContract.cs b/src/Neo/SmartContract/Native/NativeContract.cs index be43df68fd..1cc244408d 100644 --- a/src/Neo/SmartContract/Native/NativeContract.cs +++ b/src/Neo/SmartContract/Native/NativeContract.cs @@ -35,7 +35,7 @@ public class CacheEntry public byte[] Script { get; set; } } - internal Dictionary NativeContracts { get; set; } = new Dictionary(); + internal Dictionary NativeContracts { get; set; } = new(); public CacheEntry GetAllowedMethods(NativeContract native, ApplicationEngine engine) { @@ -48,12 +48,12 @@ public CacheEntry GetAllowedMethods(NativeContract native, ApplicationEngine eng } } - public delegate bool IsHardforkEnabledDelegate(Hardfork hf, uint index); - private static readonly List contractsList = new(); - private static readonly Dictionary contractsDictionary = new(); - private readonly ImmutableHashSet usedHardforks; - private readonly ReadOnlyCollection methodDescriptors; - private readonly ReadOnlyCollection eventsDescriptors; + public delegate bool IsHardforkEnabledDelegate(Hardfork hf, uint blockHeight); + private static readonly List s_contractsList = []; + private static readonly Dictionary s_contractsDictionary = new(); + private readonly ImmutableHashSet _usedHardforks; + private readonly ReadOnlyCollection _methodDescriptors; + private readonly ReadOnlyCollection _eventsDescriptors; private static int id_counter = 0; #region Named Native Contracts @@ -108,7 +108,7 @@ public CacheEntry GetAllowedMethods(NativeContract native, ApplicationEngine eng /// /// Gets all native contracts. /// - public static IReadOnlyCollection Contracts { get; } = contractsList; + public static IReadOnlyCollection Contracts { get; } = s_contractsList; /// /// The name of the native contract. @@ -139,17 +139,17 @@ protected NativeContract() // Reflection to get the methods - List listMethods = new(); + List listMethods = []; foreach (MemberInfo member in GetType().GetMembers(BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public)) { ContractMethodAttribute attribute = member.GetCustomAttribute(); if (attribute is null) continue; listMethods.Add(new ContractMethodMetadata(member, attribute)); } - methodDescriptors = listMethods.OrderBy(p => p.Name, StringComparer.Ordinal).ThenBy(p => p.Parameters.Length).ToList().AsReadOnly(); + _methodDescriptors = listMethods.OrderBy(p => p.Name, StringComparer.Ordinal).ThenBy(p => p.Parameters.Length).ToList().AsReadOnly(); // Reflection to get the events - eventsDescriptors = + _eventsDescriptors = GetType().GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public, null, Array.Empty(), null)?. GetCustomAttributes(). // Take into account not only the contract constructor, but also the base type constructor for proper FungibleToken events handling. @@ -158,26 +158,25 @@ protected NativeContract() OrderBy(p => p.Order).ToList().AsReadOnly(); // Calculate the initializations forks - usedHardforks = - methodDescriptors.Select(u => u.ActiveIn) - .Concat(methodDescriptors.Select(u => u.DeprecatedIn)) - .Concat(eventsDescriptors.Select(u => u.ActiveIn)) - .Concat(new Hardfork?[] { ActiveIn }) - .Where(u => u is not null) - .OrderBy(u => (byte)u) - .Cast().ToImmutableHashSet(); - - contractsList.Add(this); - contractsDictionary.Add(Hash, this); + _usedHardforks = + _methodDescriptors.Select(u => u.ActiveIn) + .Concat(_methodDescriptors.Select(u => u.DeprecatedIn)) + .Concat(_eventsDescriptors.Select(u => u.ActiveIn)) + .Concat([ActiveIn]) + .Where(u => u is not null) + .OrderBy(u => (byte)u) + .Cast().ToImmutableHashSet(); + s_contractsList.Add(this); + s_contractsDictionary.Add(Hash, this); } /// /// The allowed methods and his offsets. /// /// Hardfork checker - /// Block index + /// Block height. Used to check the hardforks and active methods. /// The . - private NativeContractsCache.CacheEntry GetAllowedMethods(IsHardforkEnabledDelegate hfChecker, uint index) + private NativeContractsCache.CacheEntry GetAllowedMethods(IsHardforkEnabledDelegate hfChecker, uint blockHeight) { Dictionary methods = new(); @@ -185,14 +184,14 @@ private NativeContractsCache.CacheEntry GetAllowedMethods(IsHardforkEnabledDeleg byte[] script; using (ScriptBuilder sb = new()) { - foreach (ContractMethodMetadata method in methodDescriptors.Where(u + 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, index) == false || + 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, index)) + u.ActiveIn is not null && hfChecker(u.ActiveIn.Value, blockHeight)) ) { method.Descriptor.Offset = sb.Length; @@ -204,35 +203,35 @@ u.ActiveIn is null && u.DeprecatedIn is null || script = sb.ToArray(); } - return new NativeContractsCache.CacheEntry() { Methods = methods, Script = script }; + return new NativeContractsCache.CacheEntry { Methods = methods, Script = script }; } /// /// The of the native contract. /// /// The where the HardForks are configured. - /// Block index + /// Block index /// The . [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ContractState GetContractState(ProtocolSettings settings, uint index) => GetContractState(settings.IsHardforkEnabled, index); + public ContractState GetContractState(ProtocolSettings settings, uint blockHeight) => GetContractState(settings.IsHardforkEnabled, blockHeight); /// /// The of the native contract. /// /// Hardfork checker - /// Block index + /// Block height. Used to check hardforks and active methods. /// The . - public ContractState GetContractState(IsHardforkEnabledDelegate hfChecker, uint index) + public ContractState GetContractState(IsHardforkEnabledDelegate hfChecker, uint blockHeight) { // Get allowed methods and nef script - var allowedMethods = GetAllowedMethods(hfChecker, index); + var allowedMethods = GetAllowedMethods(hfChecker, blockHeight); // Compose nef file var nef = new NefFile() { Compiler = "neo-core-v3.0", Source = string.Empty, - Tokens = Array.Empty(), + Tokens = [], Script = allowedMethods.Script }; nef.CheckSum = NefFile.ComputeChecksum(nef); @@ -241,17 +240,17 @@ public ContractState GetContractState(IsHardforkEnabledDelegate hfChecker, uint var manifest = new ContractManifest() { Name = Name, - Groups = Array.Empty(), - SupportedStandards = Array.Empty(), - Abi = new ContractAbi() + Groups = [], + SupportedStandards = [], + Abi = new ContractAbi { - Events = eventsDescriptors - .Where(u => u.ActiveIn is null || hfChecker(u.ActiveIn.Value, index)) + Events = _eventsDescriptors + .Where(u => u.ActiveIn is null || hfChecker(u.ActiveIn.Value, blockHeight)) .Select(p => p.Descriptor).ToArray(), Methods = allowedMethods.Methods.Values .Select(p => p.Descriptor).ToArray() }, - Permissions = new[] { ContractPermission.DefaultPermission }, + Permissions = [ContractPermission.DefaultPermission], Trusts = WildcardContainer.Create(), Extra = null }; @@ -282,7 +281,7 @@ internal bool IsInitializeBlock(ProtocolSettings settings, uint index, out Hardf var hfs = new List(); // If is in the hardfork height, add them to return array - foreach (var hf in usedHardforks) + foreach (var hf in _usedHardforks) { if (!settings.Hardforks.TryGetValue(hf, out var activeIn)) { @@ -319,9 +318,9 @@ internal bool IsInitializeBlock(ProtocolSettings settings, uint index, out Hardf /// Is the native contract active /// /// The where the HardForks are configured. - /// Block index + /// Block height /// True if the native contract is active - internal bool IsActive(ProtocolSettings settings, uint index) + internal bool IsActive(ProtocolSettings settings, uint blockHeight) { if (ActiveIn is null) return true; @@ -331,7 +330,7 @@ internal bool IsActive(ProtocolSettings settings, uint index) activeIn = 0; } - return activeIn <= index; + return activeIn <= blockHeight; } /// @@ -357,7 +356,7 @@ private protected KeyBuilder CreateStorageKey(byte prefix) /// The native contract with the specified hash. public static NativeContract GetContract(UInt160 hash) { - contractsDictionary.TryGetValue(hash, out var contract); + s_contractsDictionary.TryGetValue(hash, out var contract); return contract; } @@ -415,7 +414,7 @@ internal async void Invoke(ApplicationEngine engine, byte version) /// if the contract is native; otherwise, . public static bool IsNative(UInt160 hash) { - return contractsDictionary.ContainsKey(hash); + return s_contractsDictionary.ContainsKey(hash); } internal virtual ContractTask InitializeAsync(ApplicationEngine engine, Hardfork? hardFork) From 6e8c7308267b046fd24fa232f5d0ea35f6a07b5d Mon Sep 17 00:00:00 2001 From: Christopher Schuchardt Date: Fri, 7 Jun 2024 05:46:56 -0400 Subject: [PATCH 159/168] Fixed up `main.yml` (#3292) * Added `BaseOutputPath` * Remove binaries * Fixed Build * Changed output directory `github` actions * Fixed tests * Fixed bug with `output` * Added `test` soltion file * Remove output for mac and windows * Fixed Coveralls * Fixed Coveralls `path` * Revert "Fixed Coveralls `path`" This reverts commit 5ba38b14df04ebf98f684770baf515d2203c9775. * Fixed up coverall * Fixed `mergewith` * Fixed pathing * fixed `ls` command * Fixed all paths for tests * Added new steps and jobs * Move a command * Added new path for `coverage.cobertura.xml` report * Changed `Coveralls` report path * Fixed pathing for `TestResults` * Fixed Report location * Fixed Report location * Fixed file extensions * Fixed `MergeWith` path * Added list directory * Changed format coverage.lcov * Added all files * Fixed location * Fixed path for lcov * Fixed file extension * Added `${{ github.workspace }}/` * Fixed path * sfs * Fixed files argument * Fixed files * Fixed `Neo.Json.UnitTests` path * Fixed `Neo.Json.UnitTests` test output path * Update .github/workflows/main.yml Co-authored-by: Shargon --------- Co-authored-by: Jimmy Co-authored-by: Shargon --- .github/workflows/main.yml | 69 ++++++++++++------- src/Neo.CLI/Neo.CLI.csproj | 1 + .../Neo.ConsoleService.csproj | 1 + .../Neo.Cryptography.BLS12_381.csproj | 2 + src/Neo.Extensions/Neo.Extensions.csproj | 2 + src/Neo.GUI/Neo.GUI.csproj | 3 +- 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 + .../ApplicationLogs/ApplicationLogs.csproj | 3 +- src/Plugins/DBFTPlugin/DBFTPlugin.csproj | 1 + src/Plugins/Directory.Build.props | 2 +- src/Plugins/LevelDBStore/LevelDBStore.csproj | 1 + src/Plugins/MPTTrie/MPTTrie.csproj | 1 + .../OracleService/OracleService.csproj | 3 +- src/Plugins/RocksDBStore/RocksDBStore.csproj | 1 + src/Plugins/RpcClient/RpcClient.csproj | 1 + src/Plugins/RpcServer/RpcServer.csproj | 3 +- src/Plugins/SQLiteWallet/SQLiteWallet.csproj | 1 + src/Plugins/StateService/StateService.csproj | 3 +- .../StorageDumper/StorageDumper.csproj | 1 + .../TokensTracker/TokensTracker.csproj | 5 +- tests/Directory.Build.props | 3 + 24 files changed, 82 insertions(+), 33 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 3dae25a1df..dca46dbbd6 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -7,12 +7,30 @@ on: env: DOTNET_VERSION: 8.0.x - COVERALL_COLLECT_OUTPUT: "/p:CollectCoverage=true /p:CoverletOutput='${{ github.workspace }}/TestResults/coverage/'" - COVERALL_MERGE_PATH: "/p:MergeWith='${{ github.workspace }}/TestResults/coverage/coverage.json'" jobs: + Format: + 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: Check Format (*.cs) + run: dotnet format --verify-no-changes --verbosity diagnostic + + - name: Build (Neo.CLI) + run: | + dotnet build ./src/Neo.CLI \ + --output ./out/Neo.CLI + Test: + needs: [Format] timeout-minutes: 15 strategy: matrix: @@ -25,14 +43,6 @@ jobs: uses: actions/setup-dotnet@v4 with: dotnet-version: ${{ env.DOTNET_VERSION }} - - name: Check format - if: matrix.os == 'ubuntu-latest' - run: | - dotnet format --verify-no-changes --verbosity diagnostic - - name: Build CLI - if: matrix.os == 'ubuntu-latest' - run: | - dotnet publish ./src/Neo.CLI - name: Test if: matrix.os != 'ubuntu-latest' run: | @@ -42,31 +52,40 @@ jobs: if: matrix.os == 'ubuntu-latest' run: | sudo apt-get --assume-yes install libleveldb-dev librocksdb-dev - - dotnet test ./tests/Neo.Cryptography.BLS12_381.Tests ${{ env.COVERALL_COLLECT_OUTPUT }} - dotnet test ./tests/Neo.ConsoleService.Tests ${{ env.COVERALL_COLLECT_OUTPUT }} ${{ env.COVERALL_MERGE_PATH }} - dotnet test ./tests/Neo.UnitTests ${{ env.COVERALL_COLLECT_OUTPUT }} ${{ env.COVERALL_MERGE_PATH }} - dotnet test ./tests/Neo.VM.Tests ${{ env.COVERALL_COLLECT_OUTPUT }} ${{ env.COVERALL_MERGE_PATH }} - dotnet test ./tests/Neo.Json.UnitTests ${{ env.COVERALL_COLLECT_OUTPUT }} ${{ env.COVERALL_MERGE_PATH }} + + dotnet test ./tests/Neo.Cryptography.BLS12_381.Tests --output ./bin/tests/Neo.Cryptography.BLS12_381.Tests + dotnet test ./tests/Neo.ConsoleService.Tests --output ./bin/tests/Neo.ConsoleService.Tests + 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 # Plugins - dotnet test ./tests/Neo.Cryptography.MPTTrie.Tests ${{ env.COVERALL_COLLECT_OUTPUT }} ${{ env.COVERALL_MERGE_PATH }} - dotnet test ./tests/Neo.Network.RPC.Tests ${{ env.COVERALL_COLLECT_OUTPUT }} ${{ env.COVERALL_MERGE_PATH }} - dotnet test ./tests/Neo.Plugins.OracleService.Tests ${{ env.COVERALL_COLLECT_OUTPUT }} ${{ env.COVERALL_MERGE_PATH }} - dotnet test ./tests/Neo.Plugins.RpcServer.Tests ${{ env.COVERALL_COLLECT_OUTPUT }} ${{ env.COVERALL_MERGE_PATH }} - dotnet test ./tests/Neo.Plugins.Storage.Tests ${{ env.COVERALL_COLLECT_OUTPUT }} ${{ env.COVERALL_MERGE_PATH }} /p:CoverletOutputFormat='cobertura' + dotnet test ./tests/Neo.Cryptography.MPTTrie.Tests --output ./bin/tests/Neo.Cryptography.MPTTrie.Tests + dotnet test ./tests/Neo.Network.RPC.Tests --output ./bin/tests/Neo.Network.RPC.Tests + 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 - name: Coveralls if: matrix.os == 'ubuntu-latest' uses: coverallsapp/github-action@v2.3.0 with: github-token: ${{ secrets.GITHUB_TOKEN }} - format: cobertura - file: ${{ github.workspace }}/TestResults/coverage/coverage.cobertura.xml + files: + ${{ github.workspace }}/tests/Neo.Cryptography.BLS12_381.Tests/TestResults/coverage.info + ${{ github.workspace }}/tests/Neo.ConsoleService.Tests/TestResults/coverage.info + ${{ github.workspace }}/tests/Neo.UnitTests/TestResults/coverage.info + ${{ github.workspace }}/tests/Neo.VM.Tests/TestResults/coverage.info + ${{ github.workspace }}/tests/Neo.Json.UnitTests/TestResults/coverage.info + ${{ github.workspace }}/tests/Neo.Cryptography.MPTTrie.Tests/TestResults/coverage.info + ${{ github.workspace }}/tests/Neo.Network.RPC.Tests/TestResults/coverage.info + ${{ 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 PublishPackage: if: github.ref == 'refs/heads/master' && startsWith(github.repository, 'neo-project/') - needs: Test + needs: [Test] runs-on: ubuntu-latest steps: - name: Checkout @@ -115,7 +134,7 @@ jobs: Release: if: github.ref == 'refs/heads/master' && startsWith(github.repository, 'neo-project/') - needs: Test + needs: [Test] runs-on: ubuntu-latest steps: - name: Checkout diff --git a/src/Neo.CLI/Neo.CLI.csproj b/src/Neo.CLI/Neo.CLI.csproj index bb52675ec4..a9d4c9919e 100644 --- a/src/Neo.CLI/Neo.CLI.csproj +++ b/src/Neo.CLI/Neo.CLI.csproj @@ -10,6 +10,7 @@ Neo.CLI neo.ico enable + $(SolutionDir)/bin/$(AssemblyTitle) diff --git a/src/Neo.ConsoleService/Neo.ConsoleService.csproj b/src/Neo.ConsoleService/Neo.ConsoleService.csproj index 206e18235e..9b3ad32dfe 100644 --- a/src/Neo.ConsoleService/Neo.ConsoleService.csproj +++ b/src/Neo.ConsoleService/Neo.ConsoleService.csproj @@ -4,6 +4,7 @@ netstandard2.1;net8.0 Neo.ConsoleService enable + $(SolutionDir)/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 800699719f..d5313d9eab 100644 --- a/src/Neo.Cryptography.BLS12_381/Neo.Cryptography.BLS12_381.csproj +++ b/src/Neo.Cryptography.BLS12_381/Neo.Cryptography.BLS12_381.csproj @@ -5,6 +5,8 @@ netstandard2.1;net8.0 enable enable + Neo.Cryptography.BLS12_381 + $(SolutionDir)/bin/$(PackageId) diff --git a/src/Neo.Extensions/Neo.Extensions.csproj b/src/Neo.Extensions/Neo.Extensions.csproj index 71330a05a3..c6d549be6a 100644 --- a/src/Neo.Extensions/Neo.Extensions.csproj +++ b/src/Neo.Extensions/Neo.Extensions.csproj @@ -3,7 +3,9 @@ netstandard2.1;net8.0 enable + Neo.Extensions NEO;Blockchain;Extensions + $(SolutionDir)/bin/$(PackageId) diff --git a/src/Neo.GUI/Neo.GUI.csproj b/src/Neo.GUI/Neo.GUI.csproj index 6c7c20912e..014459be4c 100644 --- a/src/Neo.GUI/Neo.GUI.csproj +++ b/src/Neo.GUI/Neo.GUI.csproj @@ -11,6 +11,7 @@ Neo.GUI neo.ico false + $(SolutionDir)/bin/$(AssemblyTitle) @@ -62,4 +63,4 @@ - \ No newline at end of file + diff --git a/src/Neo.IO/Neo.IO.csproj b/src/Neo.IO/Neo.IO.csproj index f920a40fd5..a1a0a9ea2e 100644 --- a/src/Neo.IO/Neo.IO.csproj +++ b/src/Neo.IO/Neo.IO.csproj @@ -4,7 +4,9 @@ netstandard2.1;net8.0 true enable + Neo.IO NEO;Blockchain;IO + $(SolutionDir)/bin/$(PackageId) diff --git a/src/Neo.Json/Neo.Json.csproj b/src/Neo.Json/Neo.Json.csproj index cc3ea45278..3d75276dec 100644 --- a/src/Neo.Json/Neo.Json.csproj +++ b/src/Neo.Json/Neo.Json.csproj @@ -4,7 +4,9 @@ netstandard2.1;net8.0 enable enable + Neo.Json NEO;JSON + $(SolutionDir)/bin/$(PackageId) diff --git a/src/Neo.VM/Neo.VM.csproj b/src/Neo.VM/Neo.VM.csproj index a9157f5bcf..9315a850df 100644 --- a/src/Neo.VM/Neo.VM.csproj +++ b/src/Neo.VM/Neo.VM.csproj @@ -4,6 +4,8 @@ netstandard2.1;net8.0 true enable + Neo.VM + $(SolutionDir)/bin/$(PackageId) diff --git a/src/Neo/Neo.csproj b/src/Neo/Neo.csproj index a10444df17..707b94fa4c 100644 --- a/src/Neo/Neo.csproj +++ b/src/Neo/Neo.csproj @@ -3,7 +3,9 @@ netstandard2.1;net8.0 true + Neo NEO;AntShares;Blockchain;Smart Contract + $(SolutionDir)/bin/$(PackageId) diff --git a/src/Plugins/ApplicationLogs/ApplicationLogs.csproj b/src/Plugins/ApplicationLogs/ApplicationLogs.csproj index 89eea3b1bb..4529b946af 100644 --- a/src/Plugins/ApplicationLogs/ApplicationLogs.csproj +++ b/src/Plugins/ApplicationLogs/ApplicationLogs.csproj @@ -4,6 +4,7 @@ Neo.Plugins.ApplicationLogs Neo.Plugins enable + $(SolutionDir)/bin/$(PackageId) @@ -18,4 +19,4 @@ PreserveNewest - \ No newline at end of file + diff --git a/src/Plugins/DBFTPlugin/DBFTPlugin.csproj b/src/Plugins/DBFTPlugin/DBFTPlugin.csproj index b04e2e5c4f..68595be53a 100644 --- a/src/Plugins/DBFTPlugin/DBFTPlugin.csproj +++ b/src/Plugins/DBFTPlugin/DBFTPlugin.csproj @@ -4,6 +4,7 @@ net8.0 Neo.Consensus.DBFT Neo.Consensus + $(SolutionDir)/bin/$(PackageId) diff --git a/src/Plugins/Directory.Build.props b/src/Plugins/Directory.Build.props index f7bcef093b..72e96f0300 100644 --- a/src/Plugins/Directory.Build.props +++ b/src/Plugins/Directory.Build.props @@ -9,7 +9,7 @@ - + diff --git a/src/Plugins/LevelDBStore/LevelDBStore.csproj b/src/Plugins/LevelDBStore/LevelDBStore.csproj index ba82156b18..ef605a7afe 100644 --- a/src/Plugins/LevelDBStore/LevelDBStore.csproj +++ b/src/Plugins/LevelDBStore/LevelDBStore.csproj @@ -5,6 +5,7 @@ Neo.Plugins.Storage.LevelDBStore Neo.Plugins.Storage true + $(SolutionDir)/bin/$(PackageId) diff --git a/src/Plugins/MPTTrie/MPTTrie.csproj b/src/Plugins/MPTTrie/MPTTrie.csproj index a2c3377a16..ef9e45cc51 100644 --- a/src/Plugins/MPTTrie/MPTTrie.csproj +++ b/src/Plugins/MPTTrie/MPTTrie.csproj @@ -5,6 +5,7 @@ Neo.Cryptography.MPT Neo.Cryptography true + $(SolutionDir)/bin/$(PackageId) diff --git a/src/Plugins/OracleService/OracleService.csproj b/src/Plugins/OracleService/OracleService.csproj index 48ca5f3808..1fa5c5602f 100644 --- a/src/Plugins/OracleService/OracleService.csproj +++ b/src/Plugins/OracleService/OracleService.csproj @@ -3,6 +3,7 @@ net8.0 Neo.Plugins.OracleService + $(SolutionDir)/bin/$(PackageId) @@ -23,4 +24,4 @@ - \ No newline at end of file + diff --git a/src/Plugins/RocksDBStore/RocksDBStore.csproj b/src/Plugins/RocksDBStore/RocksDBStore.csproj index 57037c68cf..441b17306e 100644 --- a/src/Plugins/RocksDBStore/RocksDBStore.csproj +++ b/src/Plugins/RocksDBStore/RocksDBStore.csproj @@ -4,6 +4,7 @@ net8.0 Neo.Plugins.Storage.RocksDBStore Neo.Plugins.Storage + $(SolutionDir)/bin/$(PackageId) diff --git a/src/Plugins/RpcClient/RpcClient.csproj b/src/Plugins/RpcClient/RpcClient.csproj index cc634337d5..c43c71ef8a 100644 --- a/src/Plugins/RpcClient/RpcClient.csproj +++ b/src/Plugins/RpcClient/RpcClient.csproj @@ -4,6 +4,7 @@ net8.0 Neo.Network.RPC.RpcClient Neo.Network.RPC + $(SolutionDir)/bin/$(PackageId) diff --git a/src/Plugins/RpcServer/RpcServer.csproj b/src/Plugins/RpcServer/RpcServer.csproj index 1721c6bccb..3fb7a7bb9a 100644 --- a/src/Plugins/RpcServer/RpcServer.csproj +++ b/src/Plugins/RpcServer/RpcServer.csproj @@ -1,8 +1,9 @@ - + net8.0 Neo.Plugins.RpcServer + $(SolutionDir)/bin/$(PackageId) diff --git a/src/Plugins/SQLiteWallet/SQLiteWallet.csproj b/src/Plugins/SQLiteWallet/SQLiteWallet.csproj index fb2d3e71b8..4c9029040f 100644 --- a/src/Plugins/SQLiteWallet/SQLiteWallet.csproj +++ b/src/Plugins/SQLiteWallet/SQLiteWallet.csproj @@ -5,6 +5,7 @@ Neo.Wallets.SQLite Neo.Wallets.SQLite enable + $(SolutionDir)/bin/$(PackageId) diff --git a/src/Plugins/StateService/StateService.csproj b/src/Plugins/StateService/StateService.csproj index b8e395c990..2bf85f1465 100644 --- a/src/Plugins/StateService/StateService.csproj +++ b/src/Plugins/StateService/StateService.csproj @@ -4,6 +4,7 @@ net8.0 Neo.Plugins.StateService true + $(SolutionDir)/bin/$(PackageId) @@ -18,4 +19,4 @@ - \ No newline at end of file + diff --git a/src/Plugins/StorageDumper/StorageDumper.csproj b/src/Plugins/StorageDumper/StorageDumper.csproj index 49d5362538..7805140f3e 100644 --- a/src/Plugins/StorageDumper/StorageDumper.csproj +++ b/src/Plugins/StorageDumper/StorageDumper.csproj @@ -5,6 +5,7 @@ Neo.Plugins.StorageDumper enable enable + $(SolutionDir)/bin/$(PackageId) diff --git a/src/Plugins/TokensTracker/TokensTracker.csproj b/src/Plugins/TokensTracker/TokensTracker.csproj index 7c3df5c0c6..bdacd3839c 100644 --- a/src/Plugins/TokensTracker/TokensTracker.csproj +++ b/src/Plugins/TokensTracker/TokensTracker.csproj @@ -1,8 +1,9 @@ - + net8.0 Neo.Plugins.TokensTracker + $(SolutionDir)/bin/$(PackageId) @@ -15,4 +16,4 @@ - \ No newline at end of file + diff --git a/tests/Directory.Build.props b/tests/Directory.Build.props index 7ba3905160..a2fc251365 100644 --- a/tests/Directory.Build.props +++ b/tests/Directory.Build.props @@ -7,6 +7,9 @@ false true 0 + true + TestResults/ + lcov 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 160/168] 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 161/168] [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 162/168] 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 163/168] [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 164/168] 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 165/168] [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 166/168] 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 167/168] [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 168/168] 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)