From 0e9cb9ff354aaf8c608b6e5e4637466ce225e881 Mon Sep 17 00:00:00 2001 From: belane Date: Fri, 29 Sep 2023 19:03:03 +0200 Subject: [PATCH 01/30] 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 02/30] 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 03/30] 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 04/30] 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 05/30] 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 06/30] 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 07/30] 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 08/30] 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 09/30] 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 10/30] 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 11/30] 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 12/30] 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 13/30] 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 14/30] 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 15/30] 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 16/30] 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 17/30] 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 18/30] 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 19/30] 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 20/30] 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 21/30] 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 22/30] 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 23/30] 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 24/30] 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 25/30] 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 26/30] 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 27/30] 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 28/30] 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 29/30] 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 30/30] 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