From 791355c58bdc1fc5d7c1b42a6ab247cbf69cf6d5 Mon Sep 17 00:00:00 2001 From: Shargon Date: Thu, 9 Jul 2020 16:58:59 +0200 Subject: [PATCH 01/12] Move NEP10 to manifest (#1729) * NEP10 abi * To lower case * Move to Manifest * Clean code * Update ContractManifest.cs * Update ContractManifest.cs * Fix native contracts Co-authored-by: Erik Zhang --- src/neo/Ledger/ContractState.cs | 4 +- .../Manifest/ContractManifest.cs | 53 ++++++++++++------- .../SmartContract/Native/NativeContract.cs | 13 +++-- .../SmartContract/Native/Tokens/Nep5Token.cs | 2 +- .../Nep5NativeContractExtensions.cs | 23 -------- .../neo.UnitTests/Ledger/UT_ContractState.cs | 2 +- .../Manifest/UT_ContractManifest.cs | 16 +++--- .../Native/Tokens/UT_GasToken.cs | 3 -- .../Native/Tokens/UT_NeoToken.cs | 3 -- .../SmartContract/Native/UT_PolicyContract.cs | 3 -- tests/neo.UnitTests/TestUtils.cs | 11 ++-- 11 files changed, 58 insertions(+), 75 deletions(-) diff --git a/src/neo/Ledger/ContractState.cs b/src/neo/Ledger/ContractState.cs index 504175ee4b..882abb4e2e 100644 --- a/src/neo/Ledger/ContractState.cs +++ b/src/neo/Ledger/ContractState.cs @@ -32,7 +32,7 @@ public UInt160 ScriptHash } } - int ISerializable.Size => sizeof(int) + Script.GetVarSize() + Manifest.ToJson().ToString().GetVarSize(); + int ISerializable.Size => sizeof(int) + Script.GetVarSize() + Manifest.Size; ContractState ICloneable.Clone() { @@ -82,7 +82,7 @@ public JObject ToJson() public StackItem ToStackItem(ReferenceCounter referenceCounter) { - return new Array(referenceCounter, new StackItem[] { Script, HasStorage, Payable }); + return new Array(referenceCounter, new StackItem[] { Script, Manifest.ToString(), HasStorage, Payable }); } } } diff --git a/src/neo/SmartContract/Manifest/ContractManifest.cs b/src/neo/SmartContract/Manifest/ContractManifest.cs index b68eefbe89..990a400929 100644 --- a/src/neo/SmartContract/Manifest/ContractManifest.cs +++ b/src/neo/SmartContract/Manifest/ContractManifest.cs @@ -20,7 +20,14 @@ public class ContractManifest : ISerializable /// /// Serialized size /// - public int Size => ToJson().ToString().GetVarSize(); + public int Size + { + get + { + int size = Utility.StrictUTF8.GetByteCount(ToString()); + return IO.Helper.GetVarSize(size) + size; + } + } /// /// Contract hash @@ -37,6 +44,11 @@ public class ContractManifest : ISerializable /// public ContractFeatures Features { get; set; } + /// + /// NEP10 - SupportedStandards + /// + public string[] SupportedStandards { get; set; } + /// /// For technical details of ABI, please refer to NEP-3: NeoContract ABI. (https://github.com/neo-project/proposals/blob/master/nep-3.mediawiki) /// @@ -101,20 +113,21 @@ public static ContractManifest FromJson(JObject json) /// public JObject ToJson() { - var feature = new JObject(); - feature["storage"] = Features.HasFlag(ContractFeatures.HasStorage); - feature["payable"] = Features.HasFlag(ContractFeatures.Payable); - - var json = new JObject(); - json["groups"] = new JArray(Groups.Select(u => u.ToJson()).ToArray()); - json["features"] = feature; - json["abi"] = Abi.ToJson(); - json["permissions"] = Permissions.Select(p => p.ToJson()).ToArray(); - json["trusts"] = Trusts.ToJson(); - json["safemethods"] = SafeMethods.ToJson(); - json["extra"] = Extra; - - return json; + return new JObject + { + ["groups"] = Groups.Select(u => u.ToJson()).ToArray(), + ["features"] = new JObject + { + ["storage"] = Features.HasFlag(ContractFeatures.HasStorage), + ["payable"] = Features.HasFlag(ContractFeatures.Payable) + }, + ["supportedstandards"] = SupportedStandards.Select(u => new JString(u)).ToArray(), + ["abi"] = Abi.ToJson(), + ["permissions"] = Permissions.Select(p => p.ToJson()).ToArray(), + ["trusts"] = Trusts.ToJson(), + ["safemethods"] = SafeMethods.ToJson(), + ["extra"] = Extra + }; } /// @@ -127,6 +140,7 @@ public ContractManifest Clone() { Groups = Groups.Select(p => p.Clone()).ToArray(), Features = Features, + SupportedStandards = SupportedStandards[..], Abi = Abi.Clone(), Permissions = Permissions.Select(p => p.Clone()).ToArray(), Trusts = Trusts, @@ -143,7 +157,7 @@ public ContractManifest Clone() public void Serialize(BinaryWriter writer) { - writer.WriteVarString(ToJson().ToString()); + writer.WriteVarString(ToString()); } public void Deserialize(BinaryReader reader) @@ -153,15 +167,16 @@ public void Deserialize(BinaryReader reader) private void DeserializeFromJson(JObject json) { - Abi = ContractAbi.FromJson(json["abi"]); Groups = ((JArray)json["groups"]).Select(u => ContractGroup.FromJson(u)).ToArray(); Features = ContractFeatures.NoProperty; + if (json["features"]["storage"].AsBoolean()) Features |= ContractFeatures.HasStorage; + if (json["features"]["payable"].AsBoolean()) Features |= ContractFeatures.Payable; + SupportedStandards = ((JArray)json["supportedstandards"]).Select(u => u.AsString()).ToArray(); + Abi = ContractAbi.FromJson(json["abi"]); Permissions = ((JArray)json["permissions"]).Select(u => ContractPermission.FromJson(u)).ToArray(); Trusts = WildcardContainer.FromJson(json["trusts"], u => UInt160.Parse(u.AsString())); SafeMethods = WildcardContainer.FromJson(json["safemethods"], u => u.AsString()); Extra = json["extra"]; - if (json["features"]["storage"].AsBoolean()) Features |= ContractFeatures.HasStorage; - if (json["features"]["payable"].AsBoolean()) Features |= ContractFeatures.Payable; } /// diff --git a/src/neo/SmartContract/Native/NativeContract.cs b/src/neo/SmartContract/Native/NativeContract.cs index 0f86ce91ba..217c4c9091 100644 --- a/src/neo/SmartContract/Native/NativeContract.cs +++ b/src/neo/SmartContract/Native/NativeContract.cs @@ -30,8 +30,6 @@ public abstract class NativeContract public UInt160 Hash { get; } public abstract int Id { get; } public ContractManifest Manifest { get; } - [ContractMethod(0, CallFlags.None)] - public virtual string[] SupportedStandards { get; } = { "NEP-10" }; protected NativeContract() { @@ -60,18 +58,19 @@ protected NativeContract() } this.Manifest = new ContractManifest { - Permissions = new[] { ContractPermission.DefaultPermission }, + Groups = System.Array.Empty(), + Features = ContractFeatures.NoProperty, + SupportedStandards = new string[0], Abi = new ContractAbi() { Hash = Hash, Events = System.Array.Empty(), Methods = descriptors.ToArray() }, - Features = ContractFeatures.NoProperty, - Groups = System.Array.Empty(), - SafeMethods = WildcardContainer.Create(safeMethods.ToArray()), + Permissions = new[] { ContractPermission.DefaultPermission }, Trusts = WildcardContainer.Create(), - Extra = null, + SafeMethods = WildcardContainer.Create(safeMethods.ToArray()), + Extra = null }; contractsList.Add(this); contractsNameDictionary.Add(Name, this); diff --git a/src/neo/SmartContract/Native/Tokens/Nep5Token.cs b/src/neo/SmartContract/Native/Tokens/Nep5Token.cs index 6e7598ab70..111b69d4ce 100644 --- a/src/neo/SmartContract/Native/Tokens/Nep5Token.cs +++ b/src/neo/SmartContract/Native/Tokens/Nep5Token.cs @@ -13,7 +13,6 @@ namespace Neo.SmartContract.Native.Tokens public abstract class Nep5Token : NativeContract where TState : AccountState, new() { - public override string[] SupportedStandards { get; } = { "NEP-5", "NEP-10" }; [ContractMethod(0, CallFlags.None)] public abstract string Symbol { get; } [ContractMethod(0, CallFlags.None)] @@ -28,6 +27,7 @@ protected Nep5Token() this.Factor = BigInteger.Pow(10, Decimals); Manifest.Features = ContractFeatures.HasStorage; + Manifest.SupportedStandards = new[] { "NEP-5" }; var events = new List(Manifest.Abi.Events) { diff --git a/tests/neo.UnitTests/Extensions/Nep5NativeContractExtensions.cs b/tests/neo.UnitTests/Extensions/Nep5NativeContractExtensions.cs index e3a5fc9adf..0053b4e929 100644 --- a/tests/neo.UnitTests/Extensions/Nep5NativeContractExtensions.cs +++ b/tests/neo.UnitTests/Extensions/Nep5NativeContractExtensions.cs @@ -6,7 +6,6 @@ using Neo.VM; using System; using System.IO; -using System.Linq; using System.Numerics; namespace Neo.UnitTests.Extensions @@ -68,28 +67,6 @@ public static bool Transfer(this NativeContract contract, StoreView snapshot, by return result.GetBoolean(); } - public static string[] SupportedStandards(this NativeContract contract) - { - var engine = new ApplicationEngine(TriggerType.Application, null, null, 0, testMode: true); - - engine.LoadScript(contract.Script); - - var script = new ScriptBuilder(); - script.EmitPush(0); - script.Emit(OpCode.PACK); - script.EmitPush("supportedStandards"); - engine.LoadScript(script.ToArray()); - - engine.Execute().Should().Be(VMState.HALT); - - var result = engine.ResultStack.Pop(); - result.Should().BeOfType(typeof(VM.Types.Array)); - - return (result as VM.Types.Array).ToArray() - .Select(u => u.GetString()) - .ToArray(); - } - public static BigInteger TotalSupply(this NativeContract contract, StoreView snapshot) { var engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); diff --git a/tests/neo.UnitTests/Ledger/UT_ContractState.cs b/tests/neo.UnitTests/Ledger/UT_ContractState.cs index 40e4a6a23d..76c48c4c3e 100644 --- a/tests/neo.UnitTests/Ledger/UT_ContractState.cs +++ b/tests/neo.UnitTests/Ledger/UT_ContractState.cs @@ -84,7 +84,7 @@ public void TestDeserialize() public void TestGetSize() { ISerializable newContract = contract; - newContract.Size.Should().Be(239); + newContract.Size.Should().Be(265); } [TestMethod] diff --git a/tests/neo.UnitTests/SmartContract/Manifest/UT_ContractManifest.cs b/tests/neo.UnitTests/SmartContract/Manifest/UT_ContractManifest.cs index ef2df0acff..fbd8e10f4e 100644 --- a/tests/neo.UnitTests/SmartContract/Manifest/UT_ContractManifest.cs +++ b/tests/neo.UnitTests/SmartContract/Manifest/UT_ContractManifest.cs @@ -11,7 +11,7 @@ public class UT_ContractManifest [TestMethod] public void ParseFromJson_Default() { - var json = @"{""groups"":[],""features"":{""storage"":false,""payable"":false},""abi"":{""hash"":""0x0000000000000000000000000000000000000000"",""methods"":[],""events"":[]},""permissions"":[{""contract"":""*"",""methods"":""*""}],""trusts"":[],""safemethods"":[],""extra"":null}"; + var json = @"{""groups"":[],""features"":{""storage"":false,""payable"":false},""supportedstandards"":[],""abi"":{""hash"":""0x0000000000000000000000000000000000000000"",""methods"":[],""events"":[]},""permissions"":[{""contract"":""*"",""methods"":""*""}],""trusts"":[],""safemethods"":[],""extra"":null}"; var manifest = ContractManifest.Parse(json); Assert.AreEqual(manifest.ToString(), json); @@ -22,7 +22,7 @@ public void ParseFromJson_Default() [TestMethod] public void ParseFromJson_Features() { - var json = @"{""groups"":[],""features"":{""storage"":true,""payable"":true},""abi"":{""hash"":""0x0000000000000000000000000000000000000000"",""methods"":[],""events"":[]},""permissions"":[{""contract"":""*"",""methods"":""*""}],""trusts"":[],""safemethods"":[],""extra"":null}"; + var json = @"{""groups"":[],""features"":{""storage"":true,""payable"":true},""supportedstandards"":[],""abi"":{""hash"":""0x0000000000000000000000000000000000000000"",""methods"":[],""events"":[]},""permissions"":[{""contract"":""*"",""methods"":""*""}],""trusts"":[],""safemethods"":[],""extra"":null}"; var manifest = ContractManifest.Parse(json); Assert.AreEqual(manifest.ToJson().ToString(), json); @@ -34,7 +34,7 @@ public void ParseFromJson_Features() [TestMethod] public void ParseFromJson_Permissions() { - var json = @"{""groups"":[],""features"":{""storage"":false,""payable"":false},""abi"":{""hash"":""0x0000000000000000000000000000000000000000"",""methods"":[],""events"":[]},""permissions"":[{""contract"":""0x0000000000000000000000000000000000000000"",""methods"":[""method1"",""method2""]}],""trusts"":[],""safemethods"":[],""extra"":null}"; + var json = @"{""groups"":[],""features"":{""storage"":false,""payable"":false},""supportedstandards"":[],""abi"":{""hash"":""0x0000000000000000000000000000000000000000"",""methods"":[],""events"":[]},""permissions"":[{""contract"":""0x0000000000000000000000000000000000000000"",""methods"":[""method1"",""method2""]}],""trusts"":[],""safemethods"":[],""extra"":null}"; var manifest = ContractManifest.Parse(json); Assert.AreEqual(manifest.ToString(), json); @@ -53,7 +53,7 @@ public void ParseFromJson_Permissions() [TestMethod] public void ParseFromJson_SafeMethods() { - var json = @"{""groups"":[],""features"":{""storage"":false,""payable"":false},""abi"":{""hash"":""0x0000000000000000000000000000000000000000"",""methods"":[],""events"":[]},""permissions"":[{""contract"":""*"",""methods"":""*""}],""trusts"":[],""safemethods"":[""balanceOf""],""extra"":null}"; + var json = @"{""groups"":[],""features"":{""storage"":false,""payable"":false},""supportedstandards"":[],""abi"":{""hash"":""0x0000000000000000000000000000000000000000"",""methods"":[],""events"":[]},""permissions"":[{""contract"":""*"",""methods"":""*""}],""trusts"":[],""safemethods"":[""balanceOf""],""extra"":null}"; var manifest = ContractManifest.Parse(json); Assert.AreEqual(manifest.ToString(), json); @@ -65,7 +65,7 @@ public void ParseFromJson_SafeMethods() [TestMethod] public void ParseFromJson_Trust() { - var json = @"{""groups"":[],""features"":{""storage"":false,""payable"":false},""abi"":{""hash"":""0x0000000000000000000000000000000000000000"",""methods"":[],""events"":[]},""permissions"":[{""contract"":""*"",""methods"":""*""}],""trusts"":[""0x0000000000000000000000000000000000000001""],""safemethods"":[],""extra"":null}"; + var json = @"{""groups"":[],""features"":{""storage"":false,""payable"":false},""supportedstandards"":[],""abi"":{""hash"":""0x0000000000000000000000000000000000000000"",""methods"":[],""events"":[]},""permissions"":[{""contract"":""*"",""methods"":""*""}],""trusts"":[""0x0000000000000000000000000000000000000001""],""safemethods"":[],""extra"":null}"; var manifest = ContractManifest.Parse(json); Assert.AreEqual(manifest.ToString(), json); @@ -77,7 +77,7 @@ public void ParseFromJson_Trust() [TestMethod] public void ParseFromJson_Groups() { - var json = @"{""groups"":[{""pubkey"":""03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c"",""signature"":""QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQQ==""}],""features"":{""storage"":false,""payable"":false},""abi"":{""hash"":""0x0000000000000000000000000000000000000000"",""methods"":[],""events"":[]},""permissions"":[{""contract"":""*"",""methods"":""*""}],""trusts"":[],""safemethods"":[],""extra"":null}"; + var json = @"{""groups"":[{""pubkey"":""03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c"",""signature"":""QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQQ==""}],""features"":{""storage"":false,""payable"":false},""supportedstandards"":[],""abi"":{""hash"":""0x0000000000000000000000000000000000000000"",""methods"":[],""events"":[]},""permissions"":[{""contract"":""*"",""methods"":""*""}],""trusts"":[],""safemethods"":[],""extra"":null}"; var manifest = ContractManifest.Parse(json); Assert.AreEqual(manifest.ToString(), json); @@ -89,7 +89,7 @@ public void ParseFromJson_Groups() [TestMethod] public void ParseFromJson_Extra() { - var json = @"{""groups"":[],""features"":{""storage"":false,""payable"":false},""abi"":{""hash"":""0x0000000000000000000000000000000000000000"",""methods"":[],""events"":[]},""permissions"":[{""contract"":""*"",""methods"":""*""}],""trusts"":[],""safemethods"":[],""extra"":{""key"":""value""}}"; + var json = @"{""groups"":[],""features"":{""storage"":false,""payable"":false},""supportedstandards"":[],""abi"":{""hash"":""0x0000000000000000000000000000000000000000"",""methods"":[],""events"":[]},""permissions"":[{""contract"":""*"",""methods"":""*""}],""trusts"":[],""safemethods"":[],""extra"":{""key"":""value""}}"; var manifest = ContractManifest.Parse(json); Assert.AreEqual(json, json); Assert.AreEqual("value", manifest.Extra["key"].AsString(), false); @@ -122,7 +122,7 @@ public void TestGetHash() public void TestGetSize() { var temp = TestUtils.CreateDefaultManifest(UInt160.Zero); - Assert.AreEqual(233, temp.Size); + Assert.AreEqual(259, temp.Size); } [TestMethod] diff --git a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_GasToken.cs b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_GasToken.cs index e2910ae1e5..f1d10853b0 100644 --- a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_GasToken.cs +++ b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_GasToken.cs @@ -31,9 +31,6 @@ public void TestSetup() [TestMethod] public void Check_Decimals() => NativeContract.GAS.Decimals().Should().Be(8); - [TestMethod] - public void Check_SupportedStandards() => NativeContract.GAS.SupportedStandards().Should().BeEquivalentTo(new string[] { "NEP-5", "NEP-10" }); - [TestMethod] public void Check_BalanceOfTransferAndBurn() { diff --git a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs index dafb1f9a72..02e9cba21a 100644 --- a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs +++ b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs @@ -36,9 +36,6 @@ public void TestSetup() [TestMethod] public void Check_Decimals() => NativeContract.NEO.Decimals().Should().Be(0); - [TestMethod] - public void Check_SupportedStandards() => NativeContract.NEO.SupportedStandards().Should().BeEquivalentTo(new string[] { "NEP-5", "NEP-10" }); - [TestMethod] public void Check_Vote() { diff --git a/tests/neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs b/tests/neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs index a33b209a12..ac3b1dd2e9 100644 --- a/tests/neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs +++ b/tests/neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs @@ -19,9 +19,6 @@ public void TestSetup() TestBlockchain.InitializeMockNeoSystem(); } - [TestMethod] - public void Check_SupportedStandards() => NativeContract.Policy.SupportedStandards().Should().BeEquivalentTo(new string[] { "NEP-10" }); - [TestMethod] public void Check_Initialize() { diff --git a/tests/neo.UnitTests/TestUtils.cs b/tests/neo.UnitTests/TestUtils.cs index adaf205ea1..3edc590dae 100644 --- a/tests/neo.UnitTests/TestUtils.cs +++ b/tests/neo.UnitTests/TestUtils.cs @@ -22,18 +22,19 @@ public static ContractManifest CreateDefaultManifest(UInt160 hash) { return new ContractManifest() { - Permissions = new[] { ContractPermission.DefaultPermission }, + Groups = new ContractGroup[0], + Features = ContractFeatures.NoProperty, + SupportedStandards = Array.Empty(), Abi = new ContractAbi() { Hash = hash, Events = new ContractEventDescriptor[0], Methods = new ContractMethodDescriptor[0] }, - Features = ContractFeatures.NoProperty, - Groups = new ContractGroup[0], - SafeMethods = WildcardContainer.Create(), + Permissions = new[] { ContractPermission.DefaultPermission }, Trusts = WildcardContainer.Create(), - Extra = null, + SafeMethods = WildcardContainer.Create(), + Extra = null }; } From 39f750611f6c4a78c88e2925ca65528f2d7cd6b3 Mon Sep 17 00:00:00 2001 From: Shargon Date: Fri, 10 Jul 2020 13:57:40 +0200 Subject: [PATCH 02/12] Capture fault Exception (#1761) * Capture faultException * Update Wallet error * Remove flag check * Clean code --- src/neo/SmartContract/ApplicationEngine.cs | 7 +++++++ src/neo/Wallets/Wallet.cs | 6 ++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/neo/SmartContract/ApplicationEngine.cs b/src/neo/SmartContract/ApplicationEngine.cs index 05f963ddb2..97646236bb 100644 --- a/src/neo/SmartContract/ApplicationEngine.cs +++ b/src/neo/SmartContract/ApplicationEngine.cs @@ -40,6 +40,7 @@ private class InvocationState public StoreView Snapshot { get; } public long GasConsumed { get; private set; } = 0; public long GasLeft => testMode ? -1 : gas_amount - GasConsumed; + public Exception FaultException { get; private set; } public UInt160 CurrentScriptHash => CurrentContext?.GetState().ScriptHash; public UInt160 CallingScriptHash => CurrentContext?.GetState().CallingScriptHash; public UInt160 EntryScriptHash => EntryContext?.GetState().ScriptHash; @@ -61,6 +62,12 @@ internal void AddGas(long gas) throw new InvalidOperationException("Insufficient GAS."); } + protected override void OnFault(Exception e) + { + FaultException = e; + base.OnFault(e); + } + internal void CallFromNativeContract(Action onComplete, UInt160 hash, string method, params StackItem[] args) { InvocationState state = GetInvocationState(CurrentContext); diff --git a/src/neo/Wallets/Wallet.cs b/src/neo/Wallets/Wallet.cs index d70fa23f8b..d18abbc9f1 100644 --- a/src/neo/Wallets/Wallet.cs +++ b/src/neo/Wallets/Wallet.cs @@ -327,8 +327,10 @@ private Transaction MakeTransaction(StoreView snapshot, byte[] script, Transacti // will try to execute 'transfer' script to check if it works using (ApplicationEngine engine = ApplicationEngine.Run(script, snapshot.Clone(), tx, testMode: true)) { - if (engine.State.HasFlag(VMState.FAULT)) - throw new InvalidOperationException($"Failed execution for '{script.ToHexString()}'"); + if (engine.State == VMState.FAULT) + { + throw new InvalidOperationException($"Failed execution for '{script.ToHexString()}'", engine.FaultException); + } tx.SystemFee = engine.GasConsumed; } From c4799e9f65830fe4f7cde2784b8435487395d0a5 Mon Sep 17 00:00:00 2001 From: Shargon Date: Sat, 11 Jul 2020 11:24:24 +0200 Subject: [PATCH 03/12] Sender from signers (#1752) * Sender from signers * Remove co- * Move signers outside attributes * Fix UT and remove Signers class * Fix UT * Add FeeOnly scope * Remove orderBy * Remove _signersCache * Fix Signers * Fix WitnessScope * Fix Sender * Update TransactionAttributeType.cs * Update Wallet.cs * Fix Wallet * Rename * Update Wallet.cs * Update Wallet.cs * Partial UT fix * More UT fixes * Fix Sender's WitnessScope * Fix Wallet * Fix UT * Explicit FeeOnly for DeployNativeContracts * Same order as serialization * Test FeeOnly * dotnet format * format Co-authored-by: Erik Zhang --- src/neo/Ledger/Blockchain.cs | 9 +- .../P2P/Payloads/{Cosigner.cs => Signer.cs} | 20 +- src/neo/Network/P2P/Payloads/Transaction.cs | 58 +++--- .../P2P/Payloads/TransactionAttributeType.cs | 4 - src/neo/Network/P2P/Payloads/WitnessScope.cs | 13 +- .../ApplicationEngine.Runtime.cs | 15 +- src/neo/Wallets/Wallet.cs | 49 +++-- .../Consensus/UT_ConsensusContext.cs | 4 +- .../Cryptography/UT_Cryptography_Helper.cs | 2 +- .../neo.UnitTests/IO/Caching/UT_RelayCache.cs | 5 +- tests/neo.UnitTests/Ledger/UT_Blockchain.cs | 51 +++-- tests/neo.UnitTests/Ledger/UT_MemoryPool.cs | 8 +- tests/neo.UnitTests/Ledger/UT_PoolItem.cs | 4 +- .../Ledger/UT_SendersFeeMonitor.cs | 2 +- .../Ledger/UT_TransactionState.cs | 2 +- tests/neo.UnitTests/Ledger/UT_TrimmedBlock.cs | 14 +- .../Network/P2P/Payloads/UT_Block.cs | 26 +-- .../{UT_Cosigner.cs => UT_Signers.cs} | 42 ++-- .../Network/P2P/Payloads/UT_Transaction.cs | 179 ++++++++++-------- .../Network/P2P/Payloads/UT_Witness.cs | 6 +- .../UT_ContractParameterContext.cs | 29 ++- .../SmartContract/UT_InteropService.cs | 4 +- .../SmartContract/UT_Syscalls.cs | 4 +- tests/neo.UnitTests/TestUtils.cs | 14 +- tests/neo.UnitTests/Wallets/UT_Wallet.cs | 13 +- 25 files changed, 319 insertions(+), 258 deletions(-) rename src/neo/Network/P2P/Payloads/{Cosigner.cs => Signer.cs} (77%) rename tests/neo.UnitTests/Network/P2P/Payloads/{UT_Cosigner.cs => UT_Signers.cs} (66%) diff --git a/src/neo/Ledger/Blockchain.cs b/src/neo/Ledger/Blockchain.cs index 50cee9509d..092309a5a7 100644 --- a/src/neo/Ledger/Blockchain.cs +++ b/src/neo/Ledger/Blockchain.cs @@ -166,8 +166,15 @@ private static Transaction DeployNativeContracts() { Version = 0, Script = script, - Sender = (new[] { (byte)OpCode.PUSH1 }).ToScriptHash(), SystemFee = 0, + Signers = new[] + { + new Signer + { + Account = (new[] { (byte)OpCode.PUSH1 }).ToScriptHash(), + Scopes = WitnessScope.FeeOnly + } + }, Attributes = Array.Empty(), Witnesses = new[] { diff --git a/src/neo/Network/P2P/Payloads/Cosigner.cs b/src/neo/Network/P2P/Payloads/Signer.cs similarity index 77% rename from src/neo/Network/P2P/Payloads/Cosigner.cs rename to src/neo/Network/P2P/Payloads/Signer.cs index ba8a6fa3dd..4be59a349f 100644 --- a/src/neo/Network/P2P/Payloads/Cosigner.cs +++ b/src/neo/Network/P2P/Payloads/Signer.cs @@ -1,12 +1,13 @@ using Neo.Cryptography.ECC; using Neo.IO; using Neo.IO.Json; +using System; using System.IO; using System.Linq; namespace Neo.Network.P2P.Payloads { - public class Cosigner : TransactionAttribute + public class Signer : ISerializable { // This limits maximum number of AllowedContracts or AllowedGroups here private const int MaxSubitems = 16; @@ -16,19 +17,20 @@ public class Cosigner : TransactionAttribute public UInt160[] AllowedContracts; public ECPoint[] AllowedGroups; - public override TransactionAttributeType Type => TransactionAttributeType.Cosigner; - public override bool AllowMultiple => true; - - public override int Size => base.Size + + public int Size => /*Account*/ UInt160.Length + /*Scopes*/ sizeof(WitnessScope) + /*AllowedContracts*/ (Scopes.HasFlag(WitnessScope.CustomContracts) ? AllowedContracts.GetVarSize() : 0) + /*AllowedGroups*/ (Scopes.HasFlag(WitnessScope.CustomGroups) ? AllowedGroups.GetVarSize() : 0); - protected override void DeserializeWithoutType(BinaryReader reader) + public void Deserialize(BinaryReader reader) { Account = reader.ReadSerializable(); Scopes = (WitnessScope)reader.ReadByte(); + if ((Scopes & ~(WitnessScope.CalledByEntry | WitnessScope.CustomContracts | WitnessScope.CustomGroups | WitnessScope.Global)) != 0) + throw new FormatException(); + if (Scopes.HasFlag(WitnessScope.Global) && Scopes != WitnessScope.Global) + throw new FormatException(); AllowedContracts = Scopes.HasFlag(WitnessScope.CustomContracts) ? reader.ReadSerializableArray(MaxSubitems) : new UInt160[0]; @@ -37,7 +39,7 @@ protected override void DeserializeWithoutType(BinaryReader reader) : new ECPoint[0]; } - protected override void SerializeWithoutType(BinaryWriter writer) + public void Serialize(BinaryWriter writer) { writer.Write(Account); writer.Write((byte)Scopes); @@ -47,9 +49,9 @@ protected override void SerializeWithoutType(BinaryWriter writer) writer.Write(AllowedGroups); } - public override JObject ToJson() + public JObject ToJson() { - JObject json = base.ToJson(); + var json = new JObject(); json["account"] = Account.ToString(); json["scopes"] = Scopes; if (Scopes.HasFlag(WitnessScope.CustomContracts)) diff --git a/src/neo/Network/P2P/Payloads/Transaction.cs b/src/neo/Network/P2P/Payloads/Transaction.cs index 127f56cb17..5aab07af65 100644 --- a/src/neo/Network/P2P/Payloads/Transaction.cs +++ b/src/neo/Network/P2P/Payloads/Transaction.cs @@ -28,10 +28,10 @@ public class Transaction : IEquatable, IInventory, IInteroperable private byte version; private uint nonce; - private UInt160 sender; private long sysfee; private long netfee; private uint validUntilBlock; + private Signer[] _signers; private TransactionAttribute[] attributes; private byte[] script; private Witness[] witnesses; @@ -39,7 +39,6 @@ public class Transaction : IEquatable, IInventory, IInteroperable public const int HeaderSize = sizeof(byte) + //Version sizeof(uint) + //Nonce - 20 + //Sender sizeof(long) + //SystemFee sizeof(long) + //NetworkFee sizeof(uint); //ValidUntilBlock @@ -47,12 +46,9 @@ public class Transaction : IEquatable, IInventory, IInteroperable public TransactionAttribute[] Attributes { get => attributes; - set { attributes = value; _cosigners = null; _hash = null; _size = 0; } + set { attributes = value; _hash = null; _size = 0; } } - private Dictionary _cosigners; - public IReadOnlyDictionary Cosigners => _cosigners ??= attributes.OfType().ToDictionary(p => p.Account); - /// /// The NetworkFee for the transaction divided by its Size. /// Note that this property must be used with care. Getting the value of this property multiple times will return the same result. The value of this property can only be obtained after the transaction has been completely built (no longer modified). @@ -95,10 +91,15 @@ public byte[] Script set { script = value; _hash = null; _size = 0; } } - public UInt160 Sender + /// + /// Correspond with the first entry of Signers + /// + public UInt160 Sender => _signers[0].Account; + + public Signer[] Signers { - get => sender; - set { sender = value; _hash = null; } + get => _signers; + set { _signers = value; _hash = null; _size = 0; } } private int _size; @@ -109,6 +110,7 @@ public int Size if (_size == 0) { _size = HeaderSize + + Signers.GetVarSize() + // Signers Attributes.GetVarSize() + // Attributes Script.GetVarSize() + // Script Witnesses.GetVarSize(); // Witnesses @@ -155,9 +157,9 @@ void ISerializable.Deserialize(BinaryReader reader) _size = (int)reader.BaseStream.Position - startPosition; } - private static IEnumerable DeserializeAttributes(BinaryReader reader) + private static IEnumerable DeserializeAttributes(BinaryReader reader, int maxCount) { - int count = (int)reader.ReadVarInt(MaxTransactionAttributes); + int count = (int)reader.ReadVarInt((ulong)maxCount); HashSet hashset = new HashSet(); while (count-- > 0) { @@ -168,27 +170,35 @@ private static IEnumerable DeserializeAttributes(BinaryRea } } + private static IEnumerable DeserializeSigners(BinaryReader reader, int maxCount) + { + int count = (int)reader.ReadVarInt((ulong)maxCount); + if (count == 0) throw new FormatException(); + HashSet hashset = new HashSet(); + for (int i = 0; i < count; i++) + { + Signer signer = reader.ReadSerializable(); + if (i > 0 && signer.Scopes == WitnessScope.FeeOnly) + throw new FormatException(); + if (!hashset.Add(signer.Account)) + throw new FormatException(); + yield return signer; + } + } + public void DeserializeUnsigned(BinaryReader reader) { Version = reader.ReadByte(); if (Version > 0) throw new FormatException(); Nonce = reader.ReadUInt32(); - Sender = reader.ReadSerializable(); SystemFee = reader.ReadInt64(); if (SystemFee < 0) throw new FormatException(); NetworkFee = reader.ReadInt64(); if (NetworkFee < 0) throw new FormatException(); if (SystemFee + NetworkFee < SystemFee) throw new FormatException(); ValidUntilBlock = reader.ReadUInt32(); - Attributes = DeserializeAttributes(reader).ToArray(); - try - { - _ = Cosigners; - } - catch (ArgumentException) - { - throw new FormatException(); - } + Signers = DeserializeSigners(reader, MaxTransactionAttributes).ToArray(); + Attributes = DeserializeAttributes(reader, MaxTransactionAttributes - Signers.Length).ToArray(); Script = reader.ReadVarBytes(ushort.MaxValue); if (Script.Length == 0) throw new FormatException(); } @@ -217,8 +227,7 @@ public override int GetHashCode() public UInt160[] GetScriptHashesForVerifying(StoreView snapshot) { - var hashes = new HashSet(Cosigners.Keys) { Sender }; - return hashes.OrderBy(p => p).ToArray(); + return Signers.Select(p => p.Account).ToArray(); } void ISerializable.Serialize(BinaryWriter writer) @@ -231,10 +240,10 @@ void IVerifiable.SerializeUnsigned(BinaryWriter writer) { writer.Write(Version); writer.Write(Nonce); - writer.Write(Sender); writer.Write(SystemFee); writer.Write(NetworkFee); writer.Write(ValidUntilBlock); + writer.Write(Signers); writer.Write(Attributes); writer.WriteVarBytes(Script); } @@ -250,6 +259,7 @@ public JObject ToJson() json["sysfee"] = SystemFee.ToString(); json["netfee"] = NetworkFee.ToString(); json["validuntilblock"] = ValidUntilBlock; + json["signers"] = Signers.Select(p => p.ToJson()).ToArray(); json["attributes"] = Attributes.Select(p => p.ToJson()).ToArray(); json["script"] = Convert.ToBase64String(Script); json["witnesses"] = Witnesses.Select(p => p.ToJson()).ToArray(); diff --git a/src/neo/Network/P2P/Payloads/TransactionAttributeType.cs b/src/neo/Network/P2P/Payloads/TransactionAttributeType.cs index f1e2d704da..c3f32ddecf 100644 --- a/src/neo/Network/P2P/Payloads/TransactionAttributeType.cs +++ b/src/neo/Network/P2P/Payloads/TransactionAttributeType.cs @@ -1,10 +1,6 @@ -using Neo.IO.Caching; - namespace Neo.Network.P2P.Payloads { public enum TransactionAttributeType : byte { - [ReflectionCache(typeof(Cosigner))] - Cosigner = 0x01 } } diff --git a/src/neo/Network/P2P/Payloads/WitnessScope.cs b/src/neo/Network/P2P/Payloads/WitnessScope.cs index f35e550a34..9cc3cd99fd 100644 --- a/src/neo/Network/P2P/Payloads/WitnessScope.cs +++ b/src/neo/Network/P2P/Payloads/WitnessScope.cs @@ -6,10 +6,9 @@ namespace Neo.Network.P2P.Payloads public enum WitnessScope : byte { /// - /// Global allows this witness in all contexts (default Neo2 behavior) - /// This cannot be combined with other flags + /// It's only valid for be a sender, it can't be used during the execution /// - Global = 0x00, + FeeOnly = 0, /// /// CalledByEntry means that this condition must hold: EntryScriptHash == CallingScriptHash @@ -26,6 +25,12 @@ public enum WitnessScope : byte /// /// Custom pubkey for group members /// - CustomGroups = 0x20 + CustomGroups = 0x20, + + /// + /// Global allows this witness in all contexts (default Neo2 behavior) + /// This cannot be combined with other flags + /// + Global = 0x80 } } diff --git a/src/neo/SmartContract/ApplicationEngine.Runtime.cs b/src/neo/SmartContract/ApplicationEngine.Runtime.cs index a000f06e34..c670971937 100644 --- a/src/neo/SmartContract/ApplicationEngine.Runtime.cs +++ b/src/neo/SmartContract/ApplicationEngine.Runtime.cs @@ -104,23 +104,24 @@ internal bool CheckWitnessInternal(UInt160 hash) { if (ScriptContainer is Transaction tx) { - if (!tx.Cosigners.TryGetValue(hash, out Cosigner cosigner)) return false; - if (cosigner.Scopes == WitnessScope.Global) return true; - if (cosigner.Scopes.HasFlag(WitnessScope.CalledByEntry)) + Signer signer = tx.Signers.FirstOrDefault(p => p.Account.Equals(hash)); + if (signer is null) return false; + if (signer.Scopes == WitnessScope.Global) return true; + if (signer.Scopes.HasFlag(WitnessScope.CalledByEntry)) { if (CallingScriptHash == EntryScriptHash) return true; } - if (cosigner.Scopes.HasFlag(WitnessScope.CustomContracts)) + if (signer.Scopes.HasFlag(WitnessScope.CustomContracts)) { - if (cosigner.AllowedContracts.Contains(CurrentScriptHash)) + if (signer.AllowedContracts.Contains(CurrentScriptHash)) return true; } - if (cosigner.Scopes.HasFlag(WitnessScope.CustomGroups)) + if (signer.Scopes.HasFlag(WitnessScope.CustomGroups)) { var contract = Snapshot.Contracts[CallingScriptHash]; // check if current group is the required one - if (contract.Manifest.Groups.Select(p => p.PubKey).Intersect(cosigner.AllowedGroups).Any()) + if (contract.Manifest.Groups.Select(p => p.PubKey).Intersect(signer.AllowedGroups).Any()) return true; } return false; diff --git a/src/neo/Wallets/Wallet.cs b/src/neo/Wallets/Wallet.cs index d18abbc9f1..d77532abb9 100644 --- a/src/neo/Wallets/Wallet.cs +++ b/src/neo/Wallets/Wallet.cs @@ -192,6 +192,26 @@ public static byte[] GetPrivateKeyFromWIF(string wif) return privateKey; } + private static Signer[] GetSigners(UInt160 sender, Signer[] cosigners) + { + for (int i = 0; i < cosigners.Length; i++) + { + if (cosigners[i].Account.Equals(sender)) + { + if (i == 0) return cosigners; + List list = new List(cosigners); + list.RemoveAt(i); + list.Insert(0, cosigners[i]); + return list.ToArray(); + } + } + return cosigners.Prepend(new Signer + { + Account = sender, + Scopes = WitnessScope.FeeOnly + }).ToArray(); + } + public virtual WalletAccount Import(X509Certificate2 cert) { byte[] privateKey; @@ -277,19 +297,18 @@ public Transaction MakeTransaction(TransferOutput[] outputs, UInt160 from = null if (balances_gas is null) balances_gas = accounts.Select(p => (Account: p, Value: NativeContract.GAS.BalanceOf(snapshot, p))).Where(p => p.Value.Sign > 0).ToList(); - var cosigners = cosignerList.Select(p => - new Cosigner() - { - // default access for transfers should be valid only for first invocation - Scopes = WitnessScope.CalledByEntry, - Account = new UInt160(p.ToArray()) - }).ToArray(); + var cosigners = cosignerList.Select(p => new Signer() + { + // default access for transfers should be valid only for first invocation + Scopes = WitnessScope.CalledByEntry, + Account = p + }).ToArray(); - return MakeTransaction(snapshot, script, cosigners, balances_gas); + return MakeTransaction(snapshot, script, cosigners, Array.Empty(), balances_gas); } } - public Transaction MakeTransaction(byte[] script, UInt160 sender = null, TransactionAttribute[] attributes = null) + public Transaction MakeTransaction(byte[] script, UInt160 sender = null, Signer[] cosigners = null, TransactionAttribute[] attributes = null) { UInt160[] accounts; if (sender is null) @@ -299,17 +318,17 @@ public Transaction MakeTransaction(byte[] script, UInt160 sender = null, Transac else { if (!Contains(sender)) - throw new ArgumentException($"The address {sender.ToString()} was not found in the wallet"); + throw new ArgumentException($"The address {sender} was not found in the wallet"); accounts = new[] { sender }; } using (SnapshotView snapshot = Blockchain.Singleton.GetSnapshot()) { var balances_gas = accounts.Select(p => (Account: p, Value: NativeContract.GAS.BalanceOf(snapshot, p))).Where(p => p.Value.Sign > 0).ToList(); - return MakeTransaction(snapshot, script, attributes ?? new TransactionAttribute[0], balances_gas); + return MakeTransaction(snapshot, script, cosigners ?? Array.Empty(), attributes ?? Array.Empty(), balances_gas); } } - private Transaction MakeTransaction(StoreView snapshot, byte[] script, TransactionAttribute[] attributes, List<(UInt160 Account, BigInteger Value)> balances_gas) + private Transaction MakeTransaction(StoreView snapshot, byte[] script, Signer[] cosigners, TransactionAttribute[] attributes, List<(UInt160 Account, BigInteger Value)> balances_gas) { Random rand = new Random(); foreach (var (account, value) in balances_gas) @@ -319,8 +338,8 @@ private Transaction MakeTransaction(StoreView snapshot, byte[] script, Transacti Version = 0, Nonce = (uint)rand.Next(), Script = script, - Sender = account, ValidUntilBlock = snapshot.Height + Transaction.MaxValidUntilBlockIncrement, + Signers = GetSigners(account, cosigners), Attributes = attributes, }; @@ -336,8 +355,8 @@ private Transaction MakeTransaction(StoreView snapshot, byte[] script, Transacti UInt160[] hashes = tx.GetScriptHashesForVerifying(snapshot); - // base size for transaction: includes const_header + attributes + script + hashes - int size = Transaction.HeaderSize + tx.Attributes.GetVarSize() + script.GetVarSize() + IO.Helper.GetVarSize(hashes.Length); + // base size for transaction: includes const_header + signers + attributes + script + hashes + int size = Transaction.HeaderSize + tx.Signers.GetVarSize() + tx.Attributes.GetVarSize() + script.GetVarSize() + IO.Helper.GetVarSize(hashes.Length); foreach (UInt160 hash in hashes) { diff --git a/tests/neo.UnitTests/Consensus/UT_ConsensusContext.cs b/tests/neo.UnitTests/Consensus/UT_ConsensusContext.cs index 2f32b4b7ff..ca12f676a0 100644 --- a/tests/neo.UnitTests/Consensus/UT_ConsensusContext.cs +++ b/tests/neo.UnitTests/Consensus/UT_ConsensusContext.cs @@ -125,10 +125,10 @@ private Transaction CreateTransactionWithSize(int v) var tx = new Transaction() { Attributes = System.Array.Empty(), + Signers = new Signer[] { new Signer() { Account = UInt160.Zero } }, NetworkFee = 0, Nonce = (uint)Environment.TickCount, Script = new byte[0], - Sender = UInt160.Zero, SystemFee = 0, ValidUntilBlock = (uint)r.Next(), Version = 0, @@ -145,10 +145,10 @@ private Transaction CreateTransactionWithSytemFee(long fee) var tx = new Transaction() { Attributes = System.Array.Empty(), + Signers = new Signer[] { new Signer() { Account = UInt160.Zero } }, NetworkFee = 0, Nonce = (uint)Environment.TickCount, Script = new byte[0], - Sender = UInt160.Zero, SystemFee = fee, ValidUntilBlock = int.MaxValue, Version = 0, diff --git a/tests/neo.UnitTests/Cryptography/UT_Cryptography_Helper.cs b/tests/neo.UnitTests/Cryptography/UT_Cryptography_Helper.cs index b2c5775903..65aa81e0c0 100644 --- a/tests/neo.UnitTests/Cryptography/UT_Cryptography_Helper.cs +++ b/tests/neo.UnitTests/Cryptography/UT_Cryptography_Helper.cs @@ -152,8 +152,8 @@ public void TestTest() Transaction tx = new Transaction { Script = TestUtils.GetByteArray(32, 0x42), - Sender = UInt160.Zero, SystemFee = 4200000000, + Signers = Array.Empty(), Attributes = Array.Empty(), Witnesses = new[] { diff --git a/tests/neo.UnitTests/IO/Caching/UT_RelayCache.cs b/tests/neo.UnitTests/IO/Caching/UT_RelayCache.cs index d442a018e9..659b7f5797 100644 --- a/tests/neo.UnitTests/IO/Caching/UT_RelayCache.cs +++ b/tests/neo.UnitTests/IO/Caching/UT_RelayCache.cs @@ -24,16 +24,15 @@ public void TestGetKeyForItem() { Version = 0, Nonce = 1, - Sender = UInt160.Parse("0xa400ff00ff00ff00ff00ff00ff00ff00ff00ff01"), SystemFee = 0, NetworkFee = 0, ValidUntilBlock = 100, Attributes = Array.Empty(), + Signers = Array.Empty(), Script = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04 }, - Witnesses = new Witness[0] + Witnesses = Array.Empty() }; relayCache.Add(tx); - relayCache.Contains(tx).Should().BeTrue(); relayCache.TryGet(tx.Hash, out IInventory tmp).Should().BeTrue(); (tmp is Transaction).Should().BeTrue(); diff --git a/tests/neo.UnitTests/Ledger/UT_Blockchain.cs b/tests/neo.UnitTests/Ledger/UT_Blockchain.cs index 7e04dfe229..a94bd98984 100644 --- a/tests/neo.UnitTests/Ledger/UT_Blockchain.cs +++ b/tests/neo.UnitTests/Ledger/UT_Blockchain.cs @@ -73,13 +73,13 @@ public void TestContainsTransaction() [TestMethod] public void TestGetCurrentBlockHash() { - Blockchain.Singleton.CurrentBlockHash.Should().Be(UInt256.Parse("0x3843c6d0dd2082a801cf3da0fe0e847ba8d5571e0606c5018f9a35ce49c55e18")); + Blockchain.Singleton.CurrentBlockHash.Should().Be(UInt256.Parse("0xecaee33262f1bc7c7c28f2b25b54a5d61d50670871f45c0c6fe755a40cbde4a8")); } [TestMethod] public void TestGetCurrentHeaderHash() { - Blockchain.Singleton.CurrentHeaderHash.Should().Be(UInt256.Parse("0x3843c6d0dd2082a801cf3da0fe0e847ba8d5571e0606c5018f9a35ce49c55e18")); + Blockchain.Singleton.CurrentHeaderHash.Should().Be(UInt256.Parse("0xecaee33262f1bc7c7c28f2b25b54a5d61d50670871f45c0c6fe755a40cbde4a8")); } [TestMethod] @@ -91,7 +91,7 @@ public void TestGetBlock() [TestMethod] public void TestGetBlockHash() { - Blockchain.Singleton.GetBlockHash(0).Should().Be(UInt256.Parse("0x3843c6d0dd2082a801cf3da0fe0e847ba8d5571e0606c5018f9a35ce49c55e18")); + Blockchain.Singleton.GetBlockHash(0).Should().Be(UInt256.Parse("0xecaee33262f1bc7c7c28f2b25b54a5d61d50670871f45c0c6fe755a40cbde4a8")); Blockchain.Singleton.GetBlockHash(10).Should().BeNull(); } @@ -109,33 +109,29 @@ public void TestValidTransaction() var snapshot = Blockchain.Singleton.GetSnapshot(); var walletA = TestUtils.GenerateTestWallet(); - using (var unlockA = walletA.Unlock("123")) - { - var acc = walletA.CreateAccount(); - - // Fake balance + using var unlockA = walletA.Unlock("123"); + var acc = walletA.CreateAccount(); - var key = NativeContract.GAS.CreateStorageKey(20, acc.ScriptHash); - var entry = snapshot.Storages.GetAndChange(key, () => new StorageItem(new AccountState())); + // Fake balance - entry.GetInteroperable().Balance = 100_000_000 * NativeContract.GAS.Factor; + var key = new KeyBuilder(NativeContract.GAS.Id, 20).Add(acc.ScriptHash); + var entry = snapshot.Storages.GetAndChange(key, () => new StorageItem(new AccountState())); + entry.GetInteroperable().Balance = 100_000_000 * NativeContract.GAS.Factor; + snapshot.Commit(); - snapshot.Commit(); + typeof(Blockchain) + .GetMethod("UpdateCurrentSnapshot", BindingFlags.Instance | BindingFlags.NonPublic) + .Invoke(Blockchain.Singleton, null); - typeof(Blockchain) - .GetMethod("UpdateCurrentSnapshot", BindingFlags.Instance | BindingFlags.NonPublic) - .Invoke(Blockchain.Singleton, null); + // Make transaction - // Make transaction + var tx = CreateValidTx(walletA, acc.ScriptHash, 0); - var tx = CreateValidTx(walletA, acc.ScriptHash, 0); + senderProbe.Send(system.Blockchain, tx); + senderProbe.ExpectMsg(p => p.Result == VerifyResult.Succeed); - senderProbe.Send(system.Blockchain, tx); - senderProbe.ExpectMsg(p => p.Result == VerifyResult.Succeed); - - senderProbe.Send(system.Blockchain, tx); - senderProbe.ExpectMsg(p => p.Result == VerifyResult.AlreadyExists); - } + senderProbe.Send(system.Blockchain, tx); + senderProbe.ExpectMsg(p => p.Result == VerifyResult.AlreadyExists); } [TestMethod] @@ -145,10 +141,10 @@ public void TestInvalidTransactionInPersist() var tx = new Transaction() { Attributes = Array.Empty(), + Signers = Array.Empty(), NetworkFee = 0, Nonce = (uint)Environment.TickCount, Script = new byte[] { 1 }, - Sender = UInt160.Zero, SystemFee = 0, ValidUntilBlock = Blockchain.GenesisBlock.Index + 1, Version = 0, @@ -184,9 +180,9 @@ private Transaction CreateValidTx(NEP6Wallet wallet, UInt160 account, uint nonce { new TransferOutput() { - AssetId = NativeContract.GAS.Hash, - ScriptHash = account, - Value = new BigDecimal(1,8) + AssetId = NativeContract.GAS.Hash, + ScriptHash = account, + Value = new BigDecimal(1,8) } }, account); @@ -198,7 +194,6 @@ private Transaction CreateValidTx(NEP6Wallet wallet, UInt160 account, uint nonce Assert.IsTrue(data.Completed); tx.Witnesses = data.GetWitnesses(); - return tx; } } diff --git a/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs b/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs index 4e96605b7b..4fd9617e63 100644 --- a/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs +++ b/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs @@ -77,9 +77,9 @@ private Transaction CreateTransactionWithFee(long fee) mock.Setup(p => p.VerifyForEachBlock(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); mock.Setup(p => p.Verify(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); mock.Object.Script = randomBytes; - mock.Object.Sender = UInt160.Zero; mock.Object.NetworkFee = fee; mock.Object.Attributes = Array.Empty(); + mock.Object.Signers = new Signer[] { new Signer() { Account = UInt160.Zero, Scopes = WitnessScope.FeeOnly } }; mock.Object.Witnesses = new[] { new Witness @@ -97,13 +97,13 @@ private Transaction CreateTransactionWithFeeAndBalanceVerify(long fee) var randomBytes = new byte[16]; random.NextBytes(randomBytes); Mock mock = new Mock(); - UInt160 sender = UInt160.Zero; - mock.Setup(p => p.VerifyForEachBlock(It.IsAny(), It.IsAny())).Returns((StoreView snapshot, BigInteger amount) => NativeContract.GAS.BalanceOf(snapshot, sender) >= amount + fee ? VerifyResult.Succeed : VerifyResult.InsufficientFunds); + mock.Setup(p => p.VerifyForEachBlock(It.IsAny(), It.IsAny())).Returns((StoreView snapshot, BigInteger amount) => + NativeContract.GAS.BalanceOf(snapshot, UInt160.Zero) >= amount + fee ? VerifyResult.Succeed : VerifyResult.InsufficientFunds); mock.Setup(p => p.Verify(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); mock.Object.Script = randomBytes; - mock.Object.Sender = sender; mock.Object.NetworkFee = fee; mock.Object.Attributes = Array.Empty(); + mock.Object.Signers = new Signer[] { new Signer() { Account = UInt160.Zero, Scopes = WitnessScope.FeeOnly } }; mock.Object.Witnesses = new[] { new Witness diff --git a/tests/neo.UnitTests/Ledger/UT_PoolItem.cs b/tests/neo.UnitTests/Ledger/UT_PoolItem.cs index 09b6e71fba..4c4c406c62 100644 --- a/tests/neo.UnitTests/Ledger/UT_PoolItem.cs +++ b/tests/neo.UnitTests/Ledger/UT_PoolItem.cs @@ -118,9 +118,9 @@ public static Transaction GenerateTx(long networkFee, int size, byte[] overrideS { Nonce = (uint)TestRandom.Next(), Script = overrideScriptBytes ?? new byte[0], - Sender = UInt160.Zero, NetworkFee = networkFee, Attributes = Array.Empty(), + Signers = Array.Empty(), Witnesses = new[] { new Witness @@ -132,7 +132,7 @@ public static Transaction GenerateTx(long networkFee, int size, byte[] overrideS }; tx.Attributes.Length.Should().Be(0); - tx.Cosigners.Count.Should().Be(0); + tx.Signers.Length.Should().Be(0); int diff = size - tx.Size; if (diff < 0) throw new ArgumentException(); diff --git a/tests/neo.UnitTests/Ledger/UT_SendersFeeMonitor.cs b/tests/neo.UnitTests/Ledger/UT_SendersFeeMonitor.cs index cd8a5af463..4c9e2fa333 100644 --- a/tests/neo.UnitTests/Ledger/UT_SendersFeeMonitor.cs +++ b/tests/neo.UnitTests/Ledger/UT_SendersFeeMonitor.cs @@ -21,10 +21,10 @@ private Transaction CreateTransactionWithFee(long networkFee, long systemFee) mock.Setup(p => p.VerifyForEachBlock(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); mock.Setup(p => p.Verify(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); mock.Object.Script = randomBytes; - mock.Object.Sender = UInt160.Zero; mock.Object.NetworkFee = networkFee; mock.Object.SystemFee = systemFee; mock.Object.Attributes = Array.Empty(); + mock.Object.Signers = new Signer[] { new Signer() { Account = UInt160.Zero, Scopes = WitnessScope.FeeOnly } }; mock.Object.Witnesses = new[] { new Witness diff --git a/tests/neo.UnitTests/Ledger/UT_TransactionState.cs b/tests/neo.UnitTests/Ledger/UT_TransactionState.cs index 9446b954d2..e30416a136 100644 --- a/tests/neo.UnitTests/Ledger/UT_TransactionState.cs +++ b/tests/neo.UnitTests/Ledger/UT_TransactionState.cs @@ -61,7 +61,7 @@ public void TestDeserialize() [TestMethod] public void TestGetSize() { - ((ISerializable)origin).Size.Should().Be(61); + ((ISerializable)origin).Size.Should().Be(63); } } } diff --git a/tests/neo.UnitTests/Ledger/UT_TrimmedBlock.cs b/tests/neo.UnitTests/Ledger/UT_TrimmedBlock.cs index b74a0b2a9e..c8b0e30fb8 100644 --- a/tests/neo.UnitTests/Ledger/UT_TrimmedBlock.cs +++ b/tests/neo.UnitTests/Ledger/UT_TrimmedBlock.cs @@ -35,7 +35,7 @@ public static TrimmedBlock GetTrimmedBlockWithNoTransaction() public void TestGetIsBlock() { TrimmedBlock block = GetTrimmedBlockWithNoTransaction(); - block.Hashes = new UInt256[] { TestUtils.GetTransaction().Hash }; + block.Hashes = new UInt256[] { TestUtils.GetTransaction(UInt160.Zero).Hash }; block.IsBlock.Should().BeTrue(); } @@ -43,7 +43,7 @@ public void TestGetIsBlock() public void TestGetBlock() { var snapshot = Blockchain.Singleton.GetSnapshot(); - var tx1 = TestUtils.GetTransaction(); + var tx1 = TestUtils.GetTransaction(UInt160.Zero); tx1.Script = new byte[] { 0x01,0x01,0x01,0x01, 0x01,0x01,0x01,0x01, 0x01,0x01,0x01,0x01, @@ -53,7 +53,7 @@ public void TestGetBlock() Transaction = tx1, BlockIndex = 1 }; - var tx2 = TestUtils.GetTransaction(); + var tx2 = TestUtils.GetTransaction(UInt160.Zero); tx2.Script = new byte[] { 0x01,0x01,0x01,0x01, 0x01,0x01,0x01,0x01, 0x01,0x01,0x01,0x01, @@ -89,7 +89,7 @@ public void TestGetHeader() public void TestGetSize() { TrimmedBlock tblock = GetTrimmedBlockWithNoTransaction(); - tblock.Hashes = new UInt256[] { TestUtils.GetTransaction().Hash }; + tblock.Hashes = new UInt256[] { TestUtils.GetTransaction(UInt160.Zero).Hash }; tblock.Size.Should().Be(146); } @@ -97,7 +97,7 @@ public void TestGetSize() public void TestDeserialize() { TrimmedBlock tblock = GetTrimmedBlockWithNoTransaction(); - tblock.Hashes = new UInt256[] { TestUtils.GetTransaction().Hash }; + tblock.Hashes = new UInt256[] { TestUtils.GetTransaction(UInt160.Zero).Hash }; var newBlock = new TrimmedBlock(); using (MemoryStream ms = new MemoryStream(1024)) using (BinaryWriter writer = new BinaryWriter(ms)) @@ -119,7 +119,7 @@ public void TestDeserialize() public void TestClone() { TrimmedBlock tblock = GetTrimmedBlockWithNoTransaction(); - tblock.Hashes = new UInt256[] { TestUtils.GetTransaction().Hash }; + tblock.Hashes = new UInt256[] { TestUtils.GetTransaction(UInt160.Zero).Hash }; ICloneable cloneable = tblock; var clonedBlock = cloneable.Clone(); clonedBlock.ToJson().ToString().Should().Be(tblock.ToJson().ToString()); @@ -129,7 +129,7 @@ public void TestClone() public void TestFromReplica() { TrimmedBlock tblock = GetTrimmedBlockWithNoTransaction(); - tblock.Hashes = new UInt256[] { TestUtils.GetTransaction().Hash }; + tblock.Hashes = new UInt256[] { TestUtils.GetTransaction(UInt160.Zero).Hash }; ICloneable cloneable = new TrimmedBlock(); cloneable.FromReplica(tblock); ((TrimmedBlock)cloneable).ToJson().ToString().Should().Be(tblock.ToJson().ToString()); diff --git a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Block.cs b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Block.cs index 1efd90a3a8..0d5208de5a 100644 --- a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Block.cs +++ b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Block.cs @@ -56,10 +56,10 @@ public void Size_Get_1_Transaction() uut.Transactions = new[] { - TestUtils.GetTransaction() + TestUtils.GetTransaction(UInt160.Zero) }; - uut.Size.Should().Be(165); + uut.Size.Should().Be(167); } [TestMethod] @@ -70,12 +70,12 @@ public void Size_Get_3_Transaction() uut.Transactions = new[] { - TestUtils.GetTransaction(), - TestUtils.GetTransaction(), - TestUtils.GetTransaction() + TestUtils.GetTransaction(UInt160.Zero), + TestUtils.GetTransaction(UInt160.Zero), + TestUtils.GetTransaction(UInt160.Zero) }; - uut.Size.Should().Be(267); + uut.Size.Should().Be(273); } [TestMethod] @@ -84,7 +84,7 @@ public void Serialize() UInt256 val256 = UInt256.Zero; TestUtils.SetupBlockWithValues(uut, val256, out var _, out var _, out var _, out var _, out var _, out var _, 1); - var hex = "000000000000000000000000000000000000000000000000000000000000000000000000bc72014eb4f1fcdd27831b79c42ffa71e1b949086a97c87654a644585dd616f6e913ff854c0000000000000000000000000000000000000000000000000000000100011102000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100010000"; + var hex = "000000000000000000000000000000000000000000000000000000000000000000000000add6632f6f3d29cdf94555bb191fb5296683e5446f9937c56bb94c8608023044e913ff854c00000000000000000000000000000000000000000000000000000001000111020000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000001000100010000"; uut.ToArray().ToHexString().Should().Be(hex); } @@ -94,7 +94,7 @@ public void Deserialize() UInt256 val256 = UInt256.Zero; TestUtils.SetupBlockWithValues(new Block(), val256, out var merkRoot, out var val160, out var timestampVal, out var indexVal, out var scriptVal, out var transactionsVal, 1); - var hex = "000000000000000000000000000000000000000000000000000000000000000000000000bc72014eb4f1fcdd27831b79c42ffa71e1b949086a97c87654a644585dd616f6e913ff854c0000000000000000000000000000000000000000000000000000000100011102000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100010000"; + var hex = "000000000000000000000000000000000000000000000000000000000000000000000000add6632f6f3d29cdf94555bb191fb5296683e5446f9937c56bb94c8608023044e913ff854c00000000000000000000000000000000000000000000000000000001000111020000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000001000100010000"; using (MemoryStream ms = new MemoryStream(hex.HexToBytes(), false)) using (BinaryReader reader = new BinaryReader(ms)) @@ -199,11 +199,11 @@ public void ToJson() JObject jObj = uut.ToJson(); jObj.Should().NotBeNull(); - jObj["hash"].AsString().Should().Be("0xac84cebc5825cbe78941b301789bc43e8906bb9d86edd80cc94591088a26d9cc"); - jObj["size"].AsNumber().Should().Be(165); + jObj["hash"].AsString().Should().Be("0x9a164d5b9a1ab8745c97dbaaaef8eb30b0d80a00205acdc82daf502bee69bc20"); + jObj["size"].AsNumber().Should().Be(167); jObj["version"].AsNumber().Should().Be(0); jObj["previousblockhash"].AsString().Should().Be("0x0000000000000000000000000000000000000000000000000000000000000000"); - jObj["merkleroot"].AsString().Should().Be("0xf616d65d5844a65476c8976a0849b9e171fa2fc4791b8327ddfcf1b44e0172bc"); + jObj["merkleroot"].AsString().Should().Be("0x44300208864cb96bc537996f44e5836629b51f19bb5545f9cd293d6f2f63d6ad"); jObj["time"].AsNumber().Should().Be(328665601001); jObj["index"].AsNumber().Should().Be(0); jObj["nextconsensus"].AsString().Should().Be("NKuyBkoGdZZSLyPbJEetheRhMjeznFZszf"); @@ -214,8 +214,8 @@ public void ToJson() jObj["tx"].Should().NotBeNull(); JArray txObj = (JArray)jObj["tx"]; - txObj[0]["hash"].AsString().Should().Be("0x5f9b7409b6cf21fb0bf63c3890f62cccfe5fb9c3277ea33935e0a09f4255407c"); - txObj[0]["size"].AsNumber().Should().Be(51); + txObj[0]["hash"].AsString().Should().Be("0x995ce8ff19c30f6b0d6b03e5ed8bd30b08027c92177923782d3a64f573421931"); + txObj[0]["size"].AsNumber().Should().Be(53); txObj[0]["version"].AsNumber().Should().Be(0); ((JArray)txObj[0]["attributes"]).Count.Should().Be(0); txObj[0]["netfee"].AsString().Should().Be("0"); diff --git a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Cosigner.cs b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Signers.cs similarity index 66% rename from tests/neo.UnitTests/Network/P2P/Payloads/UT_Cosigner.cs rename to tests/neo.UnitTests/Network/P2P/Payloads/UT_Signers.cs index 22ca14cb82..82799f233f 100644 --- a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Cosigner.cs +++ b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Signers.cs @@ -7,21 +7,21 @@ namespace Neo.UnitTests.Network.P2P.Payloads { [TestClass] - public class UT_Cosigner + public class UT_Signers { [TestMethod] public void Serialize_Deserialize_Global() { - var attr = new Cosigner() + var attr = new Signer() { Scopes = WitnessScope.Global, Account = UInt160.Zero }; - var hex = "01000000000000000000000000000000000000000000"; + var hex = "000000000000000000000000000000000000000080"; attr.ToArray().ToHexString().Should().Be(hex); - var copy = hex.HexToBytes().AsSerializable(); + var copy = hex.HexToBytes().AsSerializable(); Assert.AreEqual(attr.Scopes, copy.Scopes); Assert.AreEqual(attr.Account, copy.Account); @@ -30,16 +30,16 @@ public void Serialize_Deserialize_Global() [TestMethod] public void Serialize_Deserialize_CalledByEntry() { - var attr = new Cosigner() + var attr = new Signer() { Scopes = WitnessScope.CalledByEntry, Account = UInt160.Zero }; - var hex = "01000000000000000000000000000000000000000001"; + var hex = "000000000000000000000000000000000000000001"; attr.ToArray().ToHexString().Should().Be(hex); - var copy = hex.HexToBytes().AsSerializable(); + var copy = hex.HexToBytes().AsSerializable(); Assert.AreEqual(attr.Scopes, copy.Scopes); Assert.AreEqual(attr.Account, copy.Account); @@ -48,17 +48,17 @@ public void Serialize_Deserialize_CalledByEntry() [TestMethod] public void Serialize_Deserialize_CustomContracts() { - var attr = new Cosigner() + var attr = new Signer() { Scopes = WitnessScope.CustomContracts, AllowedContracts = new[] { UInt160.Zero }, Account = UInt160.Zero }; - var hex = "01000000000000000000000000000000000000000010010000000000000000000000000000000000000000"; + var hex = "000000000000000000000000000000000000000010010000000000000000000000000000000000000000"; attr.ToArray().ToHexString().Should().Be(hex); - var copy = hex.HexToBytes().AsSerializable(); + var copy = hex.HexToBytes().AsSerializable(); Assert.AreEqual(attr.Scopes, copy.Scopes); CollectionAssert.AreEqual(attr.AllowedContracts, copy.AllowedContracts); @@ -68,17 +68,17 @@ public void Serialize_Deserialize_CustomContracts() [TestMethod] public void Serialize_Deserialize_CustomGroups() { - var attr = new Cosigner() + var attr = new Signer() { Scopes = WitnessScope.CustomGroups, AllowedGroups = new[] { ECPoint.Parse("03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c", ECCurve.Secp256r1) }, Account = UInt160.Zero }; - var hex = "010000000000000000000000000000000000000000200103b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c"; + var hex = "0000000000000000000000000000000000000000200103b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c"; attr.ToArray().ToHexString().Should().Be(hex); - var copy = hex.HexToBytes().AsSerializable(); + var copy = hex.HexToBytes().AsSerializable(); Assert.AreEqual(attr.Scopes, copy.Scopes); CollectionAssert.AreEqual(attr.AllowedGroups, copy.AllowedGroups); @@ -88,54 +88,54 @@ public void Serialize_Deserialize_CustomGroups() [TestMethod] public void Json_Global() { - var attr = new Cosigner() + var attr = new Signer() { Scopes = WitnessScope.Global, Account = UInt160.Zero }; - var json = "{\"type\":\"Cosigner\",\"account\":\"0x0000000000000000000000000000000000000000\",\"scopes\":\"Global\"}"; + var json = "{\"account\":\"0x0000000000000000000000000000000000000000\",\"scopes\":\"Global\"}"; attr.ToJson().ToString().Should().Be(json); } [TestMethod] public void Json_CalledByEntry() { - var attr = new Cosigner() + var attr = new Signer() { Scopes = WitnessScope.CalledByEntry, Account = UInt160.Zero }; - var json = "{\"type\":\"Cosigner\",\"account\":\"0x0000000000000000000000000000000000000000\",\"scopes\":\"CalledByEntry\"}"; + var json = "{\"account\":\"0x0000000000000000000000000000000000000000\",\"scopes\":\"CalledByEntry\"}"; attr.ToJson().ToString().Should().Be(json); } [TestMethod] public void Json_CustomContracts() { - var attr = new Cosigner() + var attr = new Signer() { Scopes = WitnessScope.CustomContracts, AllowedContracts = new[] { UInt160.Zero }, Account = UInt160.Zero }; - var json = "{\"type\":\"Cosigner\",\"account\":\"0x0000000000000000000000000000000000000000\",\"scopes\":\"CustomContracts\",\"allowedcontracts\":[\"0x0000000000000000000000000000000000000000\"]}"; + var json = "{\"account\":\"0x0000000000000000000000000000000000000000\",\"scopes\":\"CustomContracts\",\"allowedcontracts\":[\"0x0000000000000000000000000000000000000000\"]}"; attr.ToJson().ToString().Should().Be(json); } [TestMethod] public void Json_CustomGroups() { - var attr = new Cosigner() + var attr = new Signer() { Scopes = WitnessScope.CustomGroups, AllowedGroups = new[] { ECPoint.Parse("03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c", ECCurve.Secp256r1) }, Account = UInt160.Zero }; - var json = "{\"type\":\"Cosigner\",\"account\":\"0x0000000000000000000000000000000000000000\",\"scopes\":\"CustomGroups\",\"allowedgroups\":[\"03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c\"]}"; + var json = "{\"account\":\"0x0000000000000000000000000000000000000000\",\"scopes\":\"CustomGroups\",\"allowedgroups\":[\"03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c\"]}"; attr.ToJson().ToString().Should().Be(json); } } diff --git a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs index 61ea913867..bf11da269f 100644 --- a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs +++ b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs @@ -64,7 +64,7 @@ public void Gas_Set() public void Size_Get() { uut.Script = TestUtils.GetByteArray(32, 0x42); - uut.Sender = UInt160.Zero; + uut.Signers = Array.Empty(); uut.Attributes = Array.Empty(); uut.Witnesses = new[] { @@ -78,7 +78,7 @@ public void Size_Get() uut.Version.Should().Be(0); uut.Script.Length.Should().Be(32); uut.Script.GetVarSize().Should().Be(33); - uut.Size.Should().Be(82); + uut.Size.Should().Be(63); } [TestMethod] @@ -158,8 +158,8 @@ public void FeeIsMultiSigContract() var sizeGas = tx.Size * NativeContract.Policy.GetFeePerByte(snapshot); Assert.AreEqual(2000810, verificationGas); - Assert.AreEqual(367000, sizeGas); - Assert.AreEqual(2367810, tx.NetworkFee); + Assert.AreEqual(347000, sizeGas); + Assert.AreEqual(2347810, tx.NetworkFee); } } @@ -200,7 +200,7 @@ public void FeeIsSignatureContractDetailed() Assert.IsNull(tx.Witnesses); // check pre-computed network fee (already guessing signature sizes) - tx.NetworkFee.Should().Be(1264390); + tx.NetworkFee.Should().Be(1244390L); // ---- // Sign @@ -242,32 +242,32 @@ public void FeeIsSignatureContractDetailed() // ------------------ // check tx_size cost // ------------------ - Assert.AreEqual(264, tx.Size); + Assert.AreEqual(244, tx.Size); // will verify tx size, step by step // Part I - Assert.AreEqual(45, Transaction.HeaderSize); + Assert.AreEqual(25, Transaction.HeaderSize); // Part II - Assert.AreEqual(23, tx.Attributes.GetVarSize()); - Assert.AreEqual(1, tx.Attributes.Length); - Assert.AreEqual(1, tx.Cosigners.Count); - Assert.AreEqual(23, tx.Cosigners.Values.ToArray().GetVarSize()); + Assert.AreEqual(1, tx.Attributes.GetVarSize()); + Assert.AreEqual(0, tx.Attributes.Length); + Assert.AreEqual(1, tx.Signers.Length); // Note that Data size and Usage size are different (because of first byte on GetVarSize()) - Assert.AreEqual(22, tx.Cosigners.Values.First().Size); + Assert.AreEqual(22, tx.Signers.GetVarSize()); // Part III Assert.AreEqual(86, tx.Script.GetVarSize()); // Part IV Assert.AreEqual(110, tx.Witnesses.GetVarSize()); // I + II + III + IV - Assert.AreEqual(45 + 23 + 86 + 110, tx.Size); + Assert.AreEqual(25 + 22 + 1 + 86 + 110, tx.Size); Assert.AreEqual(1000, NativeContract.Policy.GetFeePerByte(snapshot)); var sizeGas = tx.Size * NativeContract.Policy.GetFeePerByte(snapshot); - Assert.AreEqual(264000, sizeGas); - // final check on sum: verification_cost + tx_size - Assert.AreEqual(1264390, verificationGas + sizeGas); + // final check: verification_cost and tx_size + Assert.AreEqual(244000, sizeGas); + Assert.AreEqual(1000390, verificationGas); + // final assert Assert.AreEqual(tx.NetworkFee, verificationGas + sizeGas); } @@ -301,14 +301,14 @@ public void FeeIsSignatureContract_TestScope_Global() using (ScriptBuilder sb = new ScriptBuilder()) { // self-transfer of 1e-8 GAS - System.Numerics.BigInteger value = (new BigDecimal(1, 8)).Value; + BigInteger value = (new BigDecimal(1, 8)).Value; sb.EmitAppCall(NativeContract.GAS.Hash, "transfer", acc.ScriptHash, acc.ScriptHash, value); sb.Emit(OpCode.ASSERT); script = sb.ToArray(); } // trying global scope - var cosigners = new Cosigner[]{ new Cosigner + var signers = new Signer[]{ new Signer { Account = acc.ScriptHash, Scopes = WitnessScope.Global @@ -316,7 +316,7 @@ public void FeeIsSignatureContract_TestScope_Global() // using this... - var tx = wallet.MakeTransaction(script, acc.ScriptHash, cosigners); + var tx = wallet.MakeTransaction(script, acc.ScriptHash, signers); Assert.IsNotNull(tx); Assert.IsNull(tx.Witnesses); @@ -353,7 +353,7 @@ public void FeeIsSignatureContract_TestScope_Global() // get sizeGas var sizeGas = tx.Size * NativeContract.Policy.GetFeePerByte(snapshot); // final check on sum: verification_cost + tx_size - Assert.AreEqual(1264390, verificationGas + sizeGas); + Assert.AreEqual(1244390, verificationGas + sizeGas); // final assert Assert.AreEqual(tx.NetworkFee, verificationGas + sizeGas); } @@ -387,14 +387,14 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_GAS() using (ScriptBuilder sb = new ScriptBuilder()) { // self-transfer of 1e-8 GAS - System.Numerics.BigInteger value = (new BigDecimal(1, 8)).Value; + BigInteger value = (new BigDecimal(1, 8)).Value; sb.EmitAppCall(NativeContract.GAS.Hash, "transfer", acc.ScriptHash, acc.ScriptHash, value); sb.Emit(OpCode.ASSERT); script = sb.ToArray(); } // trying global scope - var cosigners = new Cosigner[]{ new Cosigner + var signers = new Signer[]{ new Signer { Account = acc.ScriptHash, Scopes = WitnessScope.CustomContracts, @@ -403,7 +403,7 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_GAS() // using this... - var tx = wallet.MakeTransaction(script, acc.ScriptHash, cosigners); + var tx = wallet.MakeTransaction(script, acc.ScriptHash, signers); Assert.IsNotNull(tx); Assert.IsNull(tx.Witnesses); @@ -440,7 +440,7 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_GAS() // get sizeGas var sizeGas = tx.Size * NativeContract.Policy.GetFeePerByte(snapshot); // final check on sum: verification_cost + tx_size - Assert.AreEqual(1285390, verificationGas + sizeGas); + Assert.AreEqual(1265390, verificationGas + sizeGas); // final assert Assert.AreEqual(tx.NetworkFee, verificationGas + sizeGas); } @@ -481,7 +481,7 @@ public void FeeIsSignatureContract_TestScope_CalledByEntry_Plus_GAS() } // trying CalledByEntry together with GAS - var cosigners = new Cosigner[]{ new Cosigner + var signers = new Signer[]{ new Signer { Account = acc.ScriptHash, // This combination is supposed to actually be an OR, @@ -493,7 +493,7 @@ public void FeeIsSignatureContract_TestScope_CalledByEntry_Plus_GAS() // using this... - var tx = wallet.MakeTransaction(script, acc.ScriptHash, cosigners); + var tx = wallet.MakeTransaction(script, acc.ScriptHash, signers); Assert.IsNotNull(tx); Assert.IsNull(tx.Witnesses); @@ -530,7 +530,7 @@ public void FeeIsSignatureContract_TestScope_CalledByEntry_Plus_GAS() // get sizeGas var sizeGas = tx.Size * NativeContract.Policy.GetFeePerByte(snapshot); // final check on sum: verification_cost + tx_size - Assert.AreEqual(1285390, verificationGas + sizeGas); + Assert.AreEqual(1265390, verificationGas + sizeGas); // final assert Assert.AreEqual(tx.NetworkFee, verificationGas + sizeGas); } @@ -569,7 +569,7 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_NEO_FAULT() } // trying global scope - var cosigners = new Cosigner[]{ new Cosigner + var signers = new Signer[]{ new Signer { Account = acc.ScriptHash, Scopes = WitnessScope.CustomContracts, @@ -581,7 +581,7 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_NEO_FAULT() // expects FAULT on execution of 'transfer' Application script // due to lack of a valid witness validation Transaction tx = null; - Assert.ThrowsException(() => tx = wallet.MakeTransaction(script, acc.ScriptHash, cosigners)); + Assert.ThrowsException(() => tx = wallet.MakeTransaction(script, acc.ScriptHash, signers)); Assert.IsNull(tx); } } @@ -614,14 +614,14 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_NEO_GAS() using (ScriptBuilder sb = new ScriptBuilder()) { // self-transfer of 1e-8 GAS - System.Numerics.BigInteger value = (new BigDecimal(1, 8)).Value; + BigInteger value = (new BigDecimal(1, 8)).Value; sb.EmitAppCall(NativeContract.GAS.Hash, "transfer", acc.ScriptHash, acc.ScriptHash, value); sb.Emit(OpCode.ASSERT); script = sb.ToArray(); } // trying two custom hashes, for same target account - var cosigners = new Cosigner[]{ new Cosigner + var signers = new Signer[]{ new Signer { Account = acc.ScriptHash, Scopes = WitnessScope.CustomContracts, @@ -630,7 +630,7 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_NEO_GAS() // using this... - var tx = wallet.MakeTransaction(script, acc.ScriptHash, cosigners); + var tx = wallet.MakeTransaction(script, acc.ScriptHash, signers); Assert.IsNotNull(tx); Assert.IsNull(tx.Witnesses); @@ -648,9 +648,9 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_NEO_GAS() // only a single witness should exist tx.Witnesses.Length.Should().Be(1); // no attributes must exist - tx.Attributes.Length.Should().Be(1); + tx.Attributes.Length.Should().Be(0); // one cosigner must exist - tx.Cosigners.Count.Should().Be(1); + tx.Signers.Length.Should().Be(1); // Fast check Assert.IsTrue(tx.VerifyWitnesses(snapshot, tx.NetworkFee)); @@ -672,7 +672,7 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_NEO_GAS() // get sizeGas var sizeGas = tx.Size * NativeContract.Policy.GetFeePerByte(snapshot); // final check on sum: verification_cost + tx_size - Assert.AreEqual(1305390, verificationGas + sizeGas); + Assert.AreEqual(1285390, verificationGas + sizeGas); // final assert Assert.AreEqual(tx.NetworkFee, verificationGas + sizeGas); } @@ -704,7 +704,7 @@ public void FeeIsSignatureContract_TestScope_NoScopeFAULT() using (ScriptBuilder sb = new ScriptBuilder()) { // self-transfer of 1e-8 GAS - System.Numerics.BigInteger value = (new BigDecimal(1, 8)).Value; + BigInteger value = (new BigDecimal(1, 8)).Value; sb.EmitAppCall(NativeContract.GAS.Hash, "transfer", acc.ScriptHash, acc.ScriptHash, value); sb.Emit(OpCode.ASSERT); script = sb.ToArray(); @@ -713,12 +713,19 @@ public void FeeIsSignatureContract_TestScope_NoScopeFAULT() // trying with no scope var attributes = new TransactionAttribute[] { }; + var signers = new Signer[]{ new Signer + { + Account = acc.ScriptHash, + Scopes = (WitnessScope) 0xFF, + AllowedContracts = new[] { NativeContract.NEO.Hash, NativeContract.GAS.Hash } + } }; + // using this... // expects FAULT on execution of 'transfer' Application script // due to lack of a valid witness validation Transaction tx = null; - Assert.ThrowsException(() => tx = wallet.MakeTransaction(script, acc.ScriptHash, attributes)); + Assert.ThrowsException(() => tx = wallet.MakeTransaction(script, acc.ScriptHash, signers, attributes)); Assert.IsNull(tx); } } @@ -731,13 +738,12 @@ public void Transaction_Reverify_Hashes_Length_Unequal_To_Witnesses_Length() { Version = 0x00, Nonce = 0x01020304, - Sender = UInt160.Zero, SystemFee = (long)BigInteger.Pow(10, 8), // 1 GAS NetworkFee = 0x0000000000000001, ValidUntilBlock = 0x01020304, - Attributes = new[] - { - new Cosigner + Attributes = Array.Empty(), + Signers = new[]{ + new Signer { Account = UInt160.Parse("0x0001020304050607080900010203040506070809"), Scopes = WitnessScope.Global @@ -747,7 +753,7 @@ public void Transaction_Reverify_Hashes_Length_Unequal_To_Witnesses_Length() Witnesses = new Witness[0] { } }; UInt160[] hashes = txSimple.GetScriptHashesForVerifying(snapshot); - Assert.AreEqual(2, hashes.Length); + Assert.AreEqual(1, hashes.Length); Assert.AreNotEqual(VerifyResult.Succeed, txSimple.VerifyForEachBlock(snapshot, BigInteger.Zero)); } @@ -759,10 +765,10 @@ public void Transaction_Serialize_Deserialize_Simple() { Version = 0x00, Nonce = 0x01020304, - Sender = UInt160.Zero, SystemFee = (long)BigInteger.Pow(10, 8), // 1 GAS NetworkFee = 0x0000000000000001, ValidUntilBlock = 0x01020304, + Signers = new Signer[] { new Signer() { Account = UInt160.Zero } }, Attributes = Array.Empty(), Script = new byte[] { (byte)OpCode.PUSH1 }, Witnesses = new Witness[0] { } @@ -771,15 +777,16 @@ public void Transaction_Serialize_Deserialize_Simple() byte[] sTx = txSimple.ToArray(); // detailed hexstring info (basic checking) - sTx.ToHexString().Should().Be("00" + // version - "04030201" + // nonce - "0000000000000000000000000000000000000000" + // sender - "00e1f50500000000" + // system fee (1 GAS) - "0100000000000000" + // network fee (1 satoshi) - "04030201" + // timelimit - "00" + // no attributes - "0111" + // push1 script - "00"); // no witnesses + sTx.ToHexString().Should().Be( + "00" + // version + "04030201" + // nonce + "00e1f50500000000" + // system fee (1 GAS) + "0100000000000000" + // network fee (1 satoshi) + "04030201" + // timelimit + "01000000000000000000000000000000000000000000" + // empty signer + "00" + // no attributes + "0111" + // push1 script + "00"); // no witnesses // try to deserialize Transaction tx2 = Neo.IO.Helper.AsSerializable(sTx); @@ -791,7 +798,14 @@ public void Transaction_Serialize_Deserialize_Simple() tx2.NetworkFee.Should().Be(0x0000000000000001); tx2.ValidUntilBlock.Should().Be(0x01020304); tx2.Attributes.Should().BeEquivalentTo(new TransactionAttribute[0] { }); - tx2.Cosigners.Should().BeEquivalentTo(new Cosigner[0] { }); + tx2.Signers.Should().BeEquivalentTo(new Signer[] { + new Signer() + { + Account = UInt160.Zero, + AllowedContracts = Array.Empty(), + AllowedGroups = Array.Empty() } + } + ); tx2.Script.Should().BeEquivalentTo(new byte[] { (byte)OpCode.PUSH1 }); tx2.Witnesses.Should().BeEquivalentTo(new Witness[0] { }); } @@ -805,18 +819,18 @@ public void Transaction_Serialize_Deserialize_DistinctCosigners() { Version = 0x00, Nonce = 0x01020304, - Sender = UInt160.Zero, SystemFee = (long)BigInteger.Pow(10, 8), // 1 GAS NetworkFee = 0x0000000000000001, ValidUntilBlock = 0x01020304, - Attributes = new[] + Attributes = Array.Empty(), + Signers = new Signer[] { - new Cosigner + new Signer() { Account = UInt160.Parse("0x0001020304050607080900010203040506070809"), Scopes = WitnessScope.Global }, - new Cosigner + new Signer() { Account = UInt160.Parse("0x0001020304050607080900010203040506070809"), // same account as above Scopes = WitnessScope.CalledByEntry // different scope, but still, same account (cannot do that) @@ -829,7 +843,7 @@ public void Transaction_Serialize_Deserialize_DistinctCosigners() byte[] sTx = txDoubleCosigners.ToArray(); // no need for detailed hexstring here (see basic tests for it) - sTx.ToHexString().Should().Be("0004030201000000000000000000000000000000000000000000e1f50500000000010000000000000004030201020109080706050403020100090807060504030201000001090807060504030201000908070605040302010001011100"); + sTx.ToHexString().Should().Be("000403020100e1f505000000000100000000000000040302010209080706050403020100090807060504030201008009080706050403020100090807060504030201000100011100"); // back to transaction (should fail, due to non-distinct cosigners) Transaction tx2 = null; @@ -850,15 +864,16 @@ public void Transaction_Serialize_Deserialize_MaxSizeCosigners() // -------------------------------------- // this should pass (respecting max size) - var cosigners1 = new Cosigner[maxCosigners]; + var cosigners1 = new Signer[maxCosigners]; for (int i = 0; i < cosigners1.Length; i++) { string hex = i.ToString("X4"); while (hex.Length < 40) hex = hex.Insert(0, "0"); - cosigners1[i] = new Cosigner + cosigners1[i] = new Signer { - Account = UInt160.Parse(hex) + Account = UInt160.Parse(hex), + Scopes = WitnessScope.CalledByEntry }; } @@ -866,11 +881,11 @@ public void Transaction_Serialize_Deserialize_MaxSizeCosigners() { Version = 0x00, Nonce = 0x01020304, - Sender = UInt160.Zero, SystemFee = (long)BigInteger.Pow(10, 8), // 1 GAS NetworkFee = 0x0000000000000001, ValidUntilBlock = 0x01020304, - Attributes = cosigners1, // max + 1 (should fail) + Attributes = Array.Empty(), + Signers = cosigners1, // max + 1 (should fail) Script = new byte[] { (byte)OpCode.PUSH1 }, Witnesses = new Witness[0] { } }; @@ -884,13 +899,13 @@ public void Transaction_Serialize_Deserialize_MaxSizeCosigners() // ---------------------------- // this should fail (max + 1) - var cosigners = new Cosigner[maxCosigners + 1]; + var cosigners = new Signer[maxCosigners + 1]; for (var i = 0; i < maxCosigners + 1; i++) { string hex = i.ToString("X4"); while (hex.Length < 40) hex = hex.Insert(0, "0"); - cosigners[i] = new Cosigner + cosigners[i] = new Signer { Account = UInt160.Parse(hex) }; @@ -900,11 +915,11 @@ public void Transaction_Serialize_Deserialize_MaxSizeCosigners() { Version = 0x00, Nonce = 0x01020304, - Sender = UInt160.Zero, SystemFee = (long)BigInteger.Pow(10, 8), // 1 GAS NetworkFee = 0x0000000000000001, ValidUntilBlock = 0x01020304, - Attributes = cosigners, // max + 1 (should fail) + Attributes = Array.Empty(), + Signers = cosigners, // max + 1 (should fail) Script = new byte[] { (byte)OpCode.PUSH1 }, Witnesses = new Witness[0] { } }; @@ -920,12 +935,12 @@ public void Transaction_Serialize_Deserialize_MaxSizeCosigners() } [TestMethod] - public void FeeIsSignatureContract_TestScope_Global_Default() + public void FeeIsSignatureContract_TestScope_FeeOnly_Default() { // Global is supposed to be default - Cosigner cosigner = new Cosigner(); - cosigner.Scopes.Should().Be(WitnessScope.Global); + Signer cosigner = new Signer(); + cosigner.Scopes.Should().Be(WitnessScope.FeeOnly); var wallet = TestUtils.GenerateTestWallet(); var snapshot = Blockchain.Singleton.GetSnapshot(); @@ -952,21 +967,25 @@ public void FeeIsSignatureContract_TestScope_Global_Default() using (ScriptBuilder sb = new ScriptBuilder()) { // self-transfer of 1e-8 GAS - System.Numerics.BigInteger value = (new BigDecimal(1, 8)).Value; + BigInteger value = (new BigDecimal(1, 8)).Value; sb.EmitAppCall(NativeContract.GAS.Hash, "transfer", acc.ScriptHash, acc.ScriptHash, value); sb.Emit(OpCode.ASSERT); script = sb.ToArray(); } - // default to global scope - var cosigners = new Cosigner[]{ new Cosigner + // try to use fee only inside the smart contract + var signers = new Signer[]{ new Signer { - Account = acc.ScriptHash + Account = acc.ScriptHash, + Scopes = WitnessScope.FeeOnly } }; - // using this... + Assert.ThrowsException(() => wallet.MakeTransaction(script, acc.ScriptHash, signers)); + + // change to global scope + signers[0].Scopes = WitnessScope.Global; - var tx = wallet.MakeTransaction(script, acc.ScriptHash, cosigners); + var tx = wallet.MakeTransaction(script, acc.ScriptHash, signers); Assert.IsNotNull(tx); Assert.IsNull(tx.Witnesses); @@ -1003,7 +1022,7 @@ public void FeeIsSignatureContract_TestScope_Global_Default() // get sizeGas var sizeGas = tx.Size * NativeContract.Policy.GetFeePerByte(snapshot); // final check on sum: verification_cost + tx_size - Assert.AreEqual(1264390, verificationGas + sizeGas); + Assert.AreEqual(1244390, verificationGas + sizeGas); // final assert Assert.AreEqual(tx.NetworkFee, verificationGas + sizeGas); } @@ -1013,8 +1032,8 @@ public void FeeIsSignatureContract_TestScope_Global_Default() public void ToJson() { uut.Script = TestUtils.GetByteArray(32, 0x42); - uut.Sender = UInt160.Zero; uut.SystemFee = 4200000000; + uut.Signers = new Signer[] { new Signer() { Account = UInt160.Zero } }; uut.Attributes = Array.Empty(); uut.Witnesses = new[] { @@ -1027,8 +1046,8 @@ public void ToJson() JObject jObj = uut.ToJson(); jObj.Should().NotBeNull(); - jObj["hash"].AsString().Should().Be("0xfe08a23db645733a95914622ead5e738b03918680e927e00928116395e571758"); - jObj["size"].AsNumber().Should().Be(82); + jObj["hash"].AsString().Should().Be("0xe17382d26702bde77b00a9f23ea156b77c418764cbc45b2692088b5fde0336e3"); + jObj["size"].AsNumber().Should().Be(84); jObj["version"].AsNumber().Should().Be(0); ((JArray)jObj["attributes"]).Count.Should().Be(0); jObj["netfee"].AsString().Should().Be("0"); diff --git a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Witness.cs b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Witness.cs index a6cc76682f..ff47beef29 100644 --- a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Witness.cs +++ b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Witness.cs @@ -54,8 +54,12 @@ private Witness PrepareDummyWitness(int maxAccounts) var data = new ContractParametersContext(new Transaction() { - Sender = multiSignContract.ScriptHash, Attributes = Array.Empty(), + Signers = new[] {new Signer() + { + Account = multiSignContract.ScriptHash, + Scopes = WitnessScope.CalledByEntry + }}, NetworkFee = 0, Nonce = 0, Script = new byte[0], diff --git a/tests/neo.UnitTests/SmartContract/UT_ContractParameterContext.cs b/tests/neo.UnitTests/SmartContract/UT_ContractParameterContext.cs index 23e474e4b8..b96c06ae3c 100644 --- a/tests/neo.UnitTests/SmartContract/UT_ContractParameterContext.cs +++ b/tests/neo.UnitTests/SmartContract/UT_ContractParameterContext.cs @@ -33,8 +33,7 @@ public static void ClassSetUp(TestContext context) [TestMethod] public void TestGetComplete() { - Transaction tx = TestUtils.GetTransaction(); - tx.Sender = UInt160.Parse("0x1bd5c777ec35768892bd3daab60fb7a1cb905066"); + Transaction tx = TestUtils.GetTransaction(UInt160.Parse("0x1bd5c777ec35768892bd3daab60fb7a1cb905066")); var context = new ContractParametersContext(tx); context.Completed.Should().BeFalse(); } @@ -42,18 +41,17 @@ public void TestGetComplete() [TestMethod] public void TestToString() { - Transaction tx = TestUtils.GetTransaction(); - tx.Sender = UInt160.Parse("0x1bd5c777ec35768892bd3daab60fb7a1cb905066"); + Transaction tx = TestUtils.GetTransaction(UInt160.Parse("0x1bd5c777ec35768892bd3daab60fb7a1cb905066")); var context = new ContractParametersContext(tx); context.Add(contract, 0, new byte[] { 0x01 }); string str = context.ToString(); - str.Should().Be(@"{""type"":""Neo.Network.P2P.Payloads.Transaction"",""hex"":""AAAAAABmUJDLobcPtqo9vZKIdjXsd8fVGwAAAAAAAAAAAAAAAAAAAAAAAAAAAAEA"",""items"":{}}"); + str.Should().Be(@"{""type"":""Neo.Network.P2P.Payloads.Transaction"",""hex"":""AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFmUJDLobcPtqo9vZKIdjXsd8fVGwEAAQA="",""items"":{}}"); } [TestMethod] public void TestParse() { - var ret = ContractParametersContext.Parse("{\"type\":\"Neo.Network.P2P.Payloads.Transaction\",\"hex\":\"AAAAAABmUJDLobcPtqo9vZKIdjXsd8fVGwAAAAAAAAAAAAAAAAAAAAAAAAAAAAEA\",\"items\":{\"0xbecaad15c0ea585211faf99738a4354014f177f2\":{\"script\":\"IQJv8DuUkkHOHa3UNRnmlg4KhbQaaaBcMoEDqivOFZTKFmh0dHaq\",\"parameters\":[{\"type\":\"Signature\",\"value\":\"AQ==\"}]}}}"); + var ret = ContractParametersContext.Parse("{\"type\":\"Neo.Network.P2P.Payloads.Transaction\",\"hex\":\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFmUJDLobcPtqo9vZKIdjXsd8fVGwEAAQA=\",\"items\":{\"0xbecaad15c0ea585211faf99738a4354014f177f2\":{\"script\":\"IQJv8DuUkkHOHa3UNRnmlg4KhbQaaaBcMoEDqivOFZTKFmh0dHaq\",\"parameters\":[{\"type\":\"Signature\",\"value\":\"AQ==\"}]}}}"); ret.ScriptHashes[0].ToString().Should().Be("0x1bd5c777ec35768892bd3daab60fb7a1cb905066"); ((Transaction)ret.Verifiable).Script.ToHexString().Should().Be(new byte[1].ToHexString()); } @@ -68,11 +66,11 @@ public void TestFromJson() [TestMethod] public void TestAdd() { - Transaction tx = TestUtils.GetTransaction(); + Transaction tx = TestUtils.GetTransaction(UInt160.Zero); var context1 = new ContractParametersContext(tx); context1.Add(contract, 0, new byte[] { 0x01 }).Should().BeFalse(); - tx.Sender = UInt160.Parse("0x282646ee0afa5508bb999318f35074b84a17c9f0"); + tx = TestUtils.GetTransaction(UInt160.Parse("0x282646ee0afa5508bb999318f35074b84a17c9f0")); var context2 = new ContractParametersContext(tx); context2.Add(contract, 0, new byte[] { 0x01 }).Should().BeTrue(); //test repeatlly createItem @@ -82,8 +80,7 @@ public void TestAdd() [TestMethod] public void TestGetParameter() { - Transaction tx = TestUtils.GetTransaction(); - tx.Sender = UInt160.Parse("0x282646ee0afa5508bb999318f35074b84a17c9f0"); + Transaction tx = TestUtils.GetTransaction(UInt160.Parse("0x282646ee0afa5508bb999318f35074b84a17c9f0")); var context = new ContractParametersContext(tx); context.GetParameter(tx.Sender, 0).Should().BeNull(); @@ -95,8 +92,7 @@ public void TestGetParameter() [TestMethod] public void TestGetWitnesses() { - Transaction tx = TestUtils.GetTransaction(); - tx.Sender = UInt160.Parse("0x282646ee0afa5508bb999318f35074b84a17c9f0"); + Transaction tx = TestUtils.GetTransaction(UInt160.Parse("0x282646ee0afa5508bb999318f35074b84a17c9f0")); var context = new ContractParametersContext(tx); context.Add(contract, 0, new byte[] { 0x01 }); Witness[] witnesses = context.GetWitnesses(); @@ -108,9 +104,8 @@ public void TestGetWitnesses() [TestMethod] public void TestAddSignature() { - Transaction tx = TestUtils.GetTransaction(); var singleSender = UInt160.Parse("0x282646ee0afa5508bb999318f35074b84a17c9f0"); - tx.Sender = singleSender; + Transaction tx = TestUtils.GetTransaction(singleSender); //singleSign @@ -140,16 +135,16 @@ public void TestAddSignature() key2.PublicKey }); var multiSender = UInt160.Parse("0x3593816cc1085a6328fea2b899c24d78cd0ba372"); - tx.Sender = multiSender; + tx = TestUtils.GetTransaction(multiSender); context = new ContractParametersContext(tx); context.AddSignature(multiSignContract, key.PublicKey, new byte[] { 0x01 }).Should().BeTrue(); context.AddSignature(multiSignContract, key2.PublicKey, new byte[] { 0x01 }).Should().BeTrue(); - tx.Sender = singleSender; + tx = TestUtils.GetTransaction(singleSender); context = new ContractParametersContext(tx); context.AddSignature(multiSignContract, key.PublicKey, new byte[] { 0x01 }).Should().BeFalse(); - tx.Sender = multiSender; + tx = TestUtils.GetTransaction(multiSender); context = new ContractParametersContext(tx); byte[] privateKey3 = new byte[] { 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 670c2530a5..174aace8f1 100644 --- a/tests/neo.UnitTests/SmartContract/UT_InteropService.cs +++ b/tests/neo.UnitTests/SmartContract/UT_InteropService.cs @@ -250,7 +250,7 @@ public void TestRuntime_CheckWitness() ECPoint pubkey = keyPair.PublicKey; var engine = GetEngine(true); - ((Transaction)engine.ScriptContainer).Sender = Contract.CreateSignatureRedeemScript(pubkey).ToScriptHash(); + ((Transaction)engine.ScriptContainer).Signers[0].Account = Contract.CreateSignatureRedeemScript(pubkey).ToScriptHash(); engine.CheckWitness(pubkey.EncodePoint(true)).Should().BeFalse(); engine.CheckWitness(((Transaction)engine.ScriptContainer).Sender.ToArray()).Should().BeFalse(); @@ -698,7 +698,7 @@ public static void LogEvent(object sender, LogEventArgs args) private static ApplicationEngine GetEngine(bool hasContainer = false, bool hasSnapshot = false, bool addScript = true) { - var tx = TestUtils.GetTransaction(); + var tx = TestUtils.GetTransaction(UInt160.Zero); var snapshot = Blockchain.Singleton.GetSnapshot(); ApplicationEngine engine; if (hasContainer && hasSnapshot) diff --git a/tests/neo.UnitTests/SmartContract/UT_Syscalls.cs b/tests/neo.UnitTests/SmartContract/UT_Syscalls.cs index 192e7292ff..b32e808f4d 100644 --- a/tests/neo.UnitTests/SmartContract/UT_Syscalls.cs +++ b/tests/neo.UnitTests/SmartContract/UT_Syscalls.cs @@ -26,13 +26,13 @@ public void System_Blockchain_GetBlock() { Script = new byte[] { 0x01 }, Attributes = Array.Empty(), + Signers = Array.Empty(), NetworkFee = 0x02, SystemFee = 0x03, Nonce = 0x04, ValidUntilBlock = 0x05, Version = 0x06, Witnesses = new Witness[] { new Witness() { VerificationScript = new byte[] { 0x07 } } }, - Sender = UInt160.Parse("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"), }; var block = new Block() @@ -239,6 +239,7 @@ public void System_ExecutionEngine_GetScriptContainer() var tx = new Transaction() { Script = new byte[] { 0x01 }, + Signers = new Signer[] { new Signer() { Account = UInt160.Zero, Scopes = WitnessScope.FeeOnly } }, Attributes = Array.Empty(), NetworkFee = 0x02, SystemFee = 0x03, @@ -246,7 +247,6 @@ public void System_ExecutionEngine_GetScriptContainer() ValidUntilBlock = 0x05, Version = 0x06, Witnesses = new Witness[] { new Witness() { VerificationScript = new byte[] { 0x07 } } }, - Sender = UInt160.Parse("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"), }; engine = new ApplicationEngine(TriggerType.Application, tx, snapshot, 0, true); diff --git a/tests/neo.UnitTests/TestUtils.cs b/tests/neo.UnitTests/TestUtils.cs index 3edc590dae..a97869c8b5 100644 --- a/tests/neo.UnitTests/TestUtils.cs +++ b/tests/neo.UnitTests/TestUtils.cs @@ -81,7 +81,7 @@ public static NEP6Wallet GenerateTestWallet() { JObject wallet = new JObject(); wallet["name"] = "noname"; - wallet["version"] = new System.Version("3.0").ToString(); + wallet["version"] = new Version("3.0").ToString(); wallet["scrypt"] = new ScryptParameters(0, 0, 0).ToJson(); wallet["accounts"] = new JArray(); wallet["extra"] = null; @@ -89,13 +89,17 @@ public static NEP6Wallet GenerateTestWallet() return new NEP6Wallet(wallet); } - public static Transaction GetTransaction() + public static Transaction GetTransaction(UInt160 sender) { return new Transaction { Script = new byte[1], - Sender = UInt160.Zero, Attributes = Array.Empty(), + Signers = new[]{ new Signer() + { + Account = sender, + Scopes = WitnessScope.CalledByEntry + } }, Witnesses = new Witness[]{ new Witness { InvocationScript = new byte[0], @@ -155,7 +159,7 @@ public static void SetupBlockWithValues(Block block, UInt256 val256, out UInt256 { for (int i = 0; i < numberOfTransactions; i++) { - transactionsVal[i] = TestUtils.GetTransaction(); + transactionsVal[i] = TestUtils.GetTransaction(UInt160.Zero); } } @@ -190,8 +194,8 @@ public static Transaction CreateRandomHashTransaction() return new Transaction { Script = randomBytes, - Sender = UInt160.Zero, Attributes = Array.Empty(), + Signers = new Signer[] { new Signer() { Account = UInt160.Zero } }, Witnesses = new[] { new Witness diff --git a/tests/neo.UnitTests/Wallets/UT_Wallet.cs b/tests/neo.UnitTests/Wallets/UT_Wallet.cs index e63145ff5d..7f4ad69332 100644 --- a/tests/neo.UnitTests/Wallets/UT_Wallet.cs +++ b/tests/neo.UnitTests/Wallets/UT_Wallet.cs @@ -367,8 +367,8 @@ public void TestMakeTransaction1() public void TestMakeTransaction2() { MyWallet wallet = new MyWallet(); - Action action = () => wallet.MakeTransaction(new byte[] { }, UInt160.Zero, new TransactionAttribute[] { }); - action.Should().Throw(); + Action action = () => wallet.MakeTransaction(new byte[] { }, null, null, Array.Empty()); + action.Should().Throw(); Contract contract = Contract.Create(new ContractParameterType[] { ContractParameterType.Boolean }, new byte[] { 1 }); WalletAccount account = wallet.CreateAccount(contract, glkey.PrivateKey); @@ -381,10 +381,15 @@ public void TestMakeTransaction2() entry.GetInteroperable().Balance = 1000000 * NativeContract.GAS.Factor; snapshot.Commit(); - var tx = wallet.MakeTransaction(new byte[] { }, account.ScriptHash, new TransactionAttribute[] { }); + var tx = wallet.MakeTransaction(new byte[] { }, account.ScriptHash, new[]{ new Signer() + { + Account = account.ScriptHash, + Scopes = WitnessScope.CalledByEntry + }}, new TransactionAttribute[] { }); + tx.Should().NotBeNull(); - tx = wallet.MakeTransaction(new byte[] { }, null, new TransactionAttribute[] { }); + tx = wallet.MakeTransaction(new byte[] { }, null, null, Array.Empty()); tx.Should().NotBeNull(); entry = snapshot.Storages.GetAndChange(key, () => new StorageItem(new AccountState())); From 9d996e064ebb27e9ae64b4983c3b1f730fa4c915 Mon Sep 17 00:00:00 2001 From: Harry Pierson Date: Sat, 11 Jul 2020 09:25:03 -0700 Subject: [PATCH 04/12] IApplicationEngineProvider (#1758) --- src/neo/Ledger/Blockchain.cs | 4 +- src/neo/Plugins/IApplicationEngineProvider.cs | 11 +++ ...{IStoragePlugin.cs => IStorageProvider.cs} | 2 +- src/neo/Plugins/Plugin.cs | 6 +- src/neo/SmartContract/ApplicationEngine.cs | 21 ++++- src/neo/SmartContract/Helper.cs | 2 +- .../Extensions/NativeContractExtensions.cs | 2 +- .../Nep5NativeContractExtensions.cs | 12 +-- tests/neo.UnitTests/Ledger/UT_MemoryPool.cs | 2 +- .../Network/P2P/Payloads/UT_Transaction.cs | 14 ++-- .../Native/Tokens/UT_GasToken.cs | 4 +- .../Native/Tokens/UT_NeoToken.cs | 12 +-- .../SmartContract/Native/UT_NativeContract.cs | 8 +- .../SmartContract/Native/UT_PolicyContract.cs | 12 +-- .../SmartContract/UT_ApplicationEngine.cs | 2 +- .../UT_ApplicationEngineProvider.cs | 80 +++++++++++++++++++ .../SmartContract/UT_InteropPrices.cs | 14 ++-- .../SmartContract/UT_InteropService.NEO.cs | 10 +-- .../SmartContract/UT_InteropService.cs | 32 ++++---- .../SmartContract/UT_Syscalls.Callback.cs | 6 +- .../SmartContract/UT_Syscalls.cs | 26 +++--- 21 files changed, 196 insertions(+), 86 deletions(-) create mode 100644 src/neo/Plugins/IApplicationEngineProvider.cs rename src/neo/Plugins/{IStoragePlugin.cs => IStorageProvider.cs} (70%) create mode 100644 tests/neo.UnitTests/SmartContract/UT_ApplicationEngineProvider.cs diff --git a/src/neo/Ledger/Blockchain.cs b/src/neo/Ledger/Blockchain.cs index 092309a5a7..142180932a 100644 --- a/src/neo/Ledger/Blockchain.cs +++ b/src/neo/Ledger/Blockchain.cs @@ -411,7 +411,7 @@ private void Persist(Block block) snapshot.PersistingBlock = block; if (block.Index > 0) { - using (ApplicationEngine engine = new ApplicationEngine(TriggerType.System, null, snapshot, 0, true)) + using (ApplicationEngine engine = ApplicationEngine.Create(TriggerType.System, null, snapshot, 0, true)) { engine.LoadScript(onPersistNativeContractScript); if (engine.Execute() != VMState.HALT) throw new InvalidOperationException(); @@ -434,7 +434,7 @@ private void Persist(Block block) clonedSnapshot.Transactions.Add(tx.Hash, state); clonedSnapshot.Transactions.Commit(); - using (ApplicationEngine engine = new ApplicationEngine(TriggerType.Application, tx, clonedSnapshot, tx.SystemFee)) + using (ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Application, tx, clonedSnapshot, tx.SystemFee)) { engine.LoadScript(tx.Script); state.VMState = engine.Execute(); diff --git a/src/neo/Plugins/IApplicationEngineProvider.cs b/src/neo/Plugins/IApplicationEngineProvider.cs new file mode 100644 index 0000000000..ed74147fa0 --- /dev/null +++ b/src/neo/Plugins/IApplicationEngineProvider.cs @@ -0,0 +1,11 @@ +using Neo.Network.P2P.Payloads; +using Neo.Persistence; +using Neo.SmartContract; + +namespace Neo.Plugins +{ + public interface IApplicationEngineProvider + { + ApplicationEngine Create(TriggerType trigger, IVerifiable container, StoreView snapshot, long gas, bool testMode = false); + } +} diff --git a/src/neo/Plugins/IStoragePlugin.cs b/src/neo/Plugins/IStorageProvider.cs similarity index 70% rename from src/neo/Plugins/IStoragePlugin.cs rename to src/neo/Plugins/IStorageProvider.cs index 68f75dd2bb..5ef2d9f098 100644 --- a/src/neo/Plugins/IStoragePlugin.cs +++ b/src/neo/Plugins/IStorageProvider.cs @@ -2,7 +2,7 @@ namespace Neo.Plugins { - public interface IStoragePlugin + public interface IStorageProvider { IStore GetStore(); } diff --git a/src/neo/Plugins/Plugin.cs b/src/neo/Plugins/Plugin.cs index d98d1703a6..690c202d53 100644 --- a/src/neo/Plugins/Plugin.cs +++ b/src/neo/Plugins/Plugin.cs @@ -1,4 +1,5 @@ using Microsoft.Extensions.Configuration; +using Neo.SmartContract; using System; using System.Collections.Generic; using System.IO; @@ -13,7 +14,7 @@ public abstract class Plugin : IDisposable { public static readonly List Plugins = new List(); internal static readonly List Loggers = new List(); - internal static readonly Dictionary Storages = new Dictionary(); + internal static readonly Dictionary Storages = new Dictionary(); internal static readonly List PersistencePlugins = new List(); internal static readonly List P2PPlugins = new List(); internal static readonly List TxObserverPlugins = new List(); @@ -50,10 +51,11 @@ protected Plugin() Plugins.Add(this); if (this is ILogPlugin logger) Loggers.Add(logger); - if (this is IStoragePlugin storage) Storages.Add(Name, storage); + if (this is IStorageProvider storage) Storages.Add(Name, storage); if (this is IP2PPlugin p2p) P2PPlugins.Add(p2p); if (this is IPersistencePlugin persistence) PersistencePlugins.Add(persistence); if (this is IMemoryPoolTxObserverPlugin txObserver) TxObserverPlugins.Add(txObserver); + if (this is IApplicationEngineProvider provider) ApplicationEngine.SetApplicationEngineProvider(provider); Configure(); } diff --git a/src/neo/SmartContract/ApplicationEngine.cs b/src/neo/SmartContract/ApplicationEngine.cs index 97646236bb..a3a1078a37 100644 --- a/src/neo/SmartContract/ApplicationEngine.cs +++ b/src/neo/SmartContract/ApplicationEngine.cs @@ -2,6 +2,7 @@ using Neo.Ledger; using Neo.Network.P2P.Payloads; using Neo.Persistence; +using Neo.Plugins; using Neo.VM; using Neo.VM.Types; using System; @@ -9,6 +10,7 @@ using System.Linq; using System.Numerics; using System.Reflection; +using static System.Threading.Interlocked; using Array = System.Array; using VMArray = Neo.VM.Types.Array; @@ -26,6 +28,7 @@ private class InvocationState public static event EventHandler Notify; public static event EventHandler Log; + private static IApplicationEngineProvider applicationEngineProvider; private static Dictionary services; private readonly long gas_amount; private readonly bool testMode; @@ -46,7 +49,7 @@ private class InvocationState public UInt160 EntryScriptHash => EntryContext?.GetState().ScriptHash; public IReadOnlyList Notifications => notifications ?? (IReadOnlyList)Array.Empty(); - public ApplicationEngine(TriggerType trigger, IVerifiable container, StoreView snapshot, long gas, bool testMode = false) + protected ApplicationEngine(TriggerType trigger, IVerifiable container, StoreView snapshot, long gas, bool testMode = false) { this.Trigger = trigger; this.ScriptContainer = container; @@ -108,6 +111,10 @@ protected override void ContextUnloaded(ExecutionContext context) } } + public static ApplicationEngine Create(TriggerType trigger, IVerifiable container, StoreView snapshot, long gas, bool testMode = false) + => applicationEngineProvider?.Create(trigger, container, snapshot, gas, testMode) + ?? new ApplicationEngine(trigger, container, snapshot, gas, testMode); + private InvocationState GetInvocationState(ExecutionContext context) { if (!invocationStates.TryGetValue(context, out InvocationState state)) @@ -266,11 +273,16 @@ private static InteropDescriptor Register(string name, string handler, long fixe return descriptor; } + internal static void ResetApplicationEngineProvider() + { + Exchange(ref applicationEngineProvider, null); + } + public static ApplicationEngine Run(byte[] script, StoreView snapshot, IVerifiable container = null, Block persistingBlock = null, int offset = 0, bool testMode = false, long gas = default) { snapshot.PersistingBlock = persistingBlock ?? snapshot.PersistingBlock ?? CreateDummyBlock(snapshot); - ApplicationEngine engine = new ApplicationEngine(TriggerType.Application, container, snapshot, gas, testMode); + ApplicationEngine engine = Create(TriggerType.Application, container, snapshot, gas, testMode); engine.LoadScript(script).InstructionPointer = offset; engine.Execute(); return engine; @@ -283,5 +295,10 @@ public static ApplicationEngine Run(byte[] script, IVerifiable container = null, return Run(script, snapshot, container, persistingBlock, offset, testMode, gas); } } + + internal static bool SetApplicationEngineProvider(IApplicationEngineProvider provider) + { + return CompareExchange(ref applicationEngineProvider, provider, null) is null; + } } } diff --git a/src/neo/SmartContract/Helper.cs b/src/neo/SmartContract/Helper.cs index 6fedd8b9f9..54f3c9eb2e 100644 --- a/src/neo/SmartContract/Helper.cs +++ b/src/neo/SmartContract/Helper.cs @@ -162,7 +162,7 @@ internal static bool VerifyWitnesses(this IVerifiable verifiable, StoreView snap if (hashes[i] != verifiable.Witnesses[i].ScriptHash) return false; offset = 0; } - using (ApplicationEngine engine = new ApplicationEngine(TriggerType.Verification, verifiable, snapshot, gas)) + using (ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Verification, verifiable, snapshot, gas)) { engine.LoadScript(verification, CallFlags.ReadOnly).InstructionPointer = offset; engine.LoadScript(verifiable.Witnesses[i].InvocationScript, CallFlags.None); diff --git a/tests/neo.UnitTests/Extensions/NativeContractExtensions.cs b/tests/neo.UnitTests/Extensions/NativeContractExtensions.cs index cbf4a109d9..dfd2cb7005 100644 --- a/tests/neo.UnitTests/Extensions/NativeContractExtensions.cs +++ b/tests/neo.UnitTests/Extensions/NativeContractExtensions.cs @@ -17,7 +17,7 @@ public static StackItem Call(this NativeContract contract, StoreView snapshot, s public static StackItem Call(this NativeContract contract, StoreView snapshot, IVerifiable container, string method, params ContractParameter[] args) { - var engine = new ApplicationEngine(TriggerType.Application, container, snapshot, 0, true); + var engine = ApplicationEngine.Create(TriggerType.Application, container, snapshot, 0, true); engine.LoadScript(contract.Script); diff --git a/tests/neo.UnitTests/Extensions/Nep5NativeContractExtensions.cs b/tests/neo.UnitTests/Extensions/Nep5NativeContractExtensions.cs index 0053b4e929..b0cd686022 100644 --- a/tests/neo.UnitTests/Extensions/Nep5NativeContractExtensions.cs +++ b/tests/neo.UnitTests/Extensions/Nep5NativeContractExtensions.cs @@ -42,7 +42,7 @@ public void SerializeUnsigned(BinaryWriter writer) { } public static bool Transfer(this NativeContract contract, StoreView snapshot, byte[] from, byte[] to, BigInteger amount, bool signFrom) { - var engine = new ApplicationEngine(TriggerType.Application, + var engine = ApplicationEngine.Create(TriggerType.Application, new ManualWitness(signFrom ? new UInt160(from) : null), snapshot, 0, true); engine.LoadScript(contract.Script); @@ -69,7 +69,7 @@ public static bool Transfer(this NativeContract contract, StoreView snapshot, by public static BigInteger TotalSupply(this NativeContract contract, StoreView snapshot) { - var engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); + var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, 0, true); engine.LoadScript(contract.Script); @@ -89,7 +89,7 @@ public static BigInteger TotalSupply(this NativeContract contract, StoreView sna public static BigInteger BalanceOf(this NativeContract contract, StoreView snapshot, byte[] account) { - var engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); + var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, 0, true); engine.LoadScript(contract.Script); @@ -110,7 +110,7 @@ public static BigInteger BalanceOf(this NativeContract contract, StoreView snaps public static BigInteger Decimals(this NativeContract contract) { - var engine = new ApplicationEngine(TriggerType.Application, null, null, 0, testMode: true); + var engine = ApplicationEngine.Create(TriggerType.Application, null, null, 0, testMode: true); engine.LoadScript(contract.Script); @@ -130,7 +130,7 @@ public static BigInteger Decimals(this NativeContract contract) public static string Symbol(this NativeContract contract) { - var engine = new ApplicationEngine(TriggerType.Application, null, null, 0, testMode: true); + var engine = ApplicationEngine.Create(TriggerType.Application, null, null, 0, testMode: true); engine.LoadScript(contract.Script); @@ -150,7 +150,7 @@ public static string Symbol(this NativeContract contract) public static string Name(this NativeContract contract) { - var engine = new ApplicationEngine(TriggerType.Application, null, null, 0, testMode: true); + var engine = ApplicationEngine.Create(TriggerType.Application, null, null, 0, testMode: true); engine.LoadScript(contract.Script); diff --git a/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs b/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs index 4fd9617e63..e2bb92836e 100644 --- a/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs +++ b/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs @@ -223,7 +223,7 @@ public void BlockPersistAndReverificationWillAbandonTxAsBalanceTransfered() SnapshotView snapshot = Blockchain.Singleton.GetSnapshot(); BigInteger balance = NativeContract.GAS.BalanceOf(snapshot, sender); - ApplicationEngine applicationEngine = new ApplicationEngine(TriggerType.All, block, snapshot, (long)balance); + ApplicationEngine applicationEngine = ApplicationEngine.Create(TriggerType.All, block, snapshot, (long)balance); NativeContract.GAS.Burn(applicationEngine, sender, balance); NativeContract.GAS.Mint(applicationEngine, sender, txFee * 30); // Set the balance to meet 30 txs only diff --git a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs index bf11da269f..de5079a46d 100644 --- a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs +++ b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs @@ -145,7 +145,7 @@ public void FeeIsMultiSigContract() long verificationGas = 0; foreach (var witness in tx.Witnesses) { - using (ApplicationEngine engine = new ApplicationEngine(TriggerType.Verification, tx, snapshot, tx.NetworkFee, false)) + using (ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Verification, tx, snapshot, tx.NetworkFee, false)) { engine.LoadScript(witness.VerificationScript); engine.LoadScript(witness.InvocationScript); @@ -227,7 +227,7 @@ public void FeeIsSignatureContractDetailed() long verificationGas = 0; foreach (var witness in tx.Witnesses) { - using (ApplicationEngine engine = new ApplicationEngine(TriggerType.Verification, tx, snapshot, tx.NetworkFee, false)) + using (ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Verification, tx, snapshot, tx.NetworkFee, false)) { engine.LoadScript(witness.VerificationScript); engine.LoadScript(witness.InvocationScript); @@ -340,7 +340,7 @@ public void FeeIsSignatureContract_TestScope_Global() long verificationGas = 0; foreach (var witness in tx.Witnesses) { - using (ApplicationEngine engine = new ApplicationEngine(TriggerType.Verification, tx, snapshot, tx.NetworkFee, false)) + using (ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Verification, tx, snapshot, tx.NetworkFee, false)) { engine.LoadScript(witness.VerificationScript); engine.LoadScript(witness.InvocationScript); @@ -427,7 +427,7 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_GAS() long verificationGas = 0; foreach (var witness in tx.Witnesses) { - using (ApplicationEngine engine = new ApplicationEngine(TriggerType.Verification, tx, snapshot, tx.NetworkFee, false)) + using (ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Verification, tx, snapshot, tx.NetworkFee, false)) { engine.LoadScript(witness.VerificationScript); engine.LoadScript(witness.InvocationScript); @@ -517,7 +517,7 @@ public void FeeIsSignatureContract_TestScope_CalledByEntry_Plus_GAS() long verificationGas = 0; foreach (var witness in tx.Witnesses) { - using (ApplicationEngine engine = new ApplicationEngine(TriggerType.Verification, tx, snapshot, tx.NetworkFee, false)) + using (ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Verification, tx, snapshot, tx.NetworkFee, false)) { engine.LoadScript(witness.VerificationScript); engine.LoadScript(witness.InvocationScript); @@ -659,7 +659,7 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_NEO_GAS() long verificationGas = 0; foreach (var witness in tx.Witnesses) { - using (ApplicationEngine engine = new ApplicationEngine(TriggerType.Verification, tx, snapshot, tx.NetworkFee, false)) + using (ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Verification, tx, snapshot, tx.NetworkFee, false)) { engine.LoadScript(witness.VerificationScript); engine.LoadScript(witness.InvocationScript); @@ -1009,7 +1009,7 @@ public void FeeIsSignatureContract_TestScope_FeeOnly_Default() long verificationGas = 0; foreach (var witness in tx.Witnesses) { - using (ApplicationEngine engine = new ApplicationEngine(TriggerType.Verification, tx, snapshot, tx.NetworkFee, false)) + using (ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Verification, tx, snapshot, tx.NetworkFee, false)) { engine.LoadScript(witness.VerificationScript); engine.LoadScript(witness.InvocationScript); diff --git a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_GasToken.cs b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_GasToken.cs index f1d10853b0..17e45ed08c 100644 --- a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_GasToken.cs +++ b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_GasToken.cs @@ -89,7 +89,7 @@ public void Check_BalanceOfTransferAndBurn() // Burn - var engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0); + var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, 0); keyCount = snapshot.Storages.GetChangeSet().Count(); Assert.ThrowsException(() => @@ -124,7 +124,7 @@ public void Check_BalanceOfTransferAndBurn() [TestMethod] public void Check_BadScript() { - var engine = new ApplicationEngine(TriggerType.Application, null, Blockchain.Singleton.GetSnapshot(), 0); + var engine = ApplicationEngine.Create(TriggerType.Application, null, Blockchain.Singleton.GetSnapshot(), 0); var script = new ScriptBuilder(); script.Emit(OpCode.NOP); diff --git a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs index 02e9cba21a..1cce77536e 100644 --- a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs +++ b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs @@ -206,7 +206,7 @@ public void Check_Initialize() [TestMethod] public void Check_BadScript() { - var engine = new ApplicationEngine(TriggerType.Application, null, Blockchain.Singleton.GetSnapshot(), 0); + var engine = ApplicationEngine.Create(TriggerType.Application, null, Blockchain.Singleton.GetSnapshot(), 0); var script = new ScriptBuilder(); script.Emit(OpCode.NOP); @@ -424,7 +424,7 @@ public void TestVote() { var snapshot = Blockchain.Singleton.GetSnapshot(); snapshot.PersistingBlock = Blockchain.GenesisBlock; - var engine = new ApplicationEngine(TriggerType.Application, Blockchain.GenesisBlock, snapshot, 0, true); + var engine = ApplicationEngine.Create(TriggerType.Application, Blockchain.GenesisBlock, snapshot, 0, true); ScriptBuilder sb = new ScriptBuilder(); var tmp = engine.ScriptContainer.GetScriptHashesForVerifying(engine.Snapshot); UInt160 from = engine.ScriptContainer.GetScriptHashesForVerifying(engine.Snapshot)[0]; @@ -455,7 +455,7 @@ public void TestVote() internal static (bool State, bool Result) Check_Vote(StoreView snapshot, byte[] account, byte[] pubkey, bool signAccount) { - var engine = new ApplicationEngine(TriggerType.Application, + var engine = ApplicationEngine.Create(TriggerType.Application, new Nep5NativeContractExtensions.ManualWitness(signAccount ? new UInt160(account) : UInt160.Zero), snapshot, 0, true); engine.LoadScript(NativeContract.NEO.Script); @@ -485,7 +485,7 @@ internal static (bool State, bool Result) Check_Vote(StoreView snapshot, byte[] internal static (bool State, bool Result) Check_RegisterValidator(StoreView snapshot, byte[] pubkey) { - var engine = new ApplicationEngine(TriggerType.Application, + var engine = ApplicationEngine.Create(TriggerType.Application, new Nep5NativeContractExtensions.ManualWitness(Contract.CreateSignatureRedeemScript(ECPoint.DecodePoint(pubkey, ECCurve.Secp256r1)).ToScriptHash()), snapshot, 0, true); engine.LoadScript(NativeContract.NEO.Script); @@ -510,7 +510,7 @@ internal static (bool State, bool Result) Check_RegisterValidator(StoreView snap internal static ECPoint[] Check_GetValidators(StoreView snapshot) { - var engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); + var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, 0, true); engine.LoadScript(NativeContract.NEO.Script); @@ -530,7 +530,7 @@ internal static ECPoint[] Check_GetValidators(StoreView snapshot) internal static (BigInteger Value, bool State) Check_UnclaimedGas(StoreView snapshot, byte[] address) { - var engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); + var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, 0, true); engine.LoadScript(NativeContract.NEO.Script); diff --git a/tests/neo.UnitTests/SmartContract/Native/UT_NativeContract.cs b/tests/neo.UnitTests/SmartContract/Native/UT_NativeContract.cs index 90970a506b..3188bddb4c 100644 --- a/tests/neo.UnitTests/SmartContract/Native/UT_NativeContract.cs +++ b/tests/neo.UnitTests/SmartContract/Native/UT_NativeContract.cs @@ -24,7 +24,7 @@ public void TestSetup() [TestMethod] public void TestInitialize() { - ApplicationEngine ae = new ApplicationEngine(TriggerType.Application, null, null, 0); + ApplicationEngine ae = ApplicationEngine.Create(TriggerType.Application, null, null, 0); testNativeContract.Initialize(ae); } @@ -32,7 +32,7 @@ public void TestInitialize() public void TestInvoke() { var snapshot = Blockchain.Singleton.GetSnapshot(); - ApplicationEngine engine = new ApplicationEngine(TriggerType.System, null, snapshot, 0); + ApplicationEngine engine = ApplicationEngine.Create(TriggerType.System, null, snapshot, 0); engine.LoadScript(testNativeContract.Script); ByteString method1 = new ByteString(System.Text.Encoding.Default.GetBytes("wrongMethod")); @@ -53,10 +53,10 @@ public void TestOnPersistWithArgs() { var snapshot = Blockchain.Singleton.GetSnapshot(); - ApplicationEngine engine1 = new ApplicationEngine(TriggerType.Application, null, snapshot, 0); + ApplicationEngine engine1 = ApplicationEngine.Create(TriggerType.Application, null, snapshot, 0); Assert.ThrowsException(() => testNativeContract.TestOnPersist(engine1)); - ApplicationEngine engine2 = new ApplicationEngine(TriggerType.System, null, snapshot, 0); + ApplicationEngine engine2 = ApplicationEngine.Create(TriggerType.System, null, snapshot, 0); testNativeContract.TestOnPersist(engine2); } diff --git a/tests/neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs b/tests/neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs index ac3b1dd2e9..d464f45ea8 100644 --- a/tests/neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs +++ b/tests/neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs @@ -25,7 +25,7 @@ public void Check_Initialize() var snapshot = Blockchain.Singleton.GetSnapshot(); var keyCount = snapshot.Storages.GetChangeSet().Count(); - NativeContract.Policy.Initialize(new ApplicationEngine(TriggerType.Application, null, snapshot, 0)); + NativeContract.Policy.Initialize(ApplicationEngine.Create(TriggerType.Application, null, snapshot, 0)); (keyCount + 5).Should().Be(snapshot.Storages.GetChangeSet().Count()); @@ -62,7 +62,7 @@ public void Check_SetMaxBlockSize() UInt160 committeeMultiSigAddr = NativeContract.NEO.GetCommitteeAddress(snapshot); - NativeContract.Policy.Initialize(new ApplicationEngine(TriggerType.Application, null, snapshot, 0)); + NativeContract.Policy.Initialize(ApplicationEngine.Create(TriggerType.Application, null, snapshot, 0)); // Without signature @@ -110,7 +110,7 @@ public void Check_SetMaxBlockSystemFee() UInt160 committeeMultiSigAddr = NativeContract.NEO.GetCommitteeAddress(snapshot); - NativeContract.Policy.Initialize(new ApplicationEngine(TriggerType.Application, null, snapshot, 0)); + NativeContract.Policy.Initialize(ApplicationEngine.Create(TriggerType.Application, null, snapshot, 0)); // Without signature @@ -156,7 +156,7 @@ public void Check_SetMaxTransactionsPerBlock() snapshot.PersistingBlock = new Block() { Index = 1000, PrevHash = UInt256.Zero }; snapshot.Blocks.Add(UInt256.Zero, new Neo.Ledger.TrimmedBlock() { NextConsensus = UInt160.Zero }); - NativeContract.Policy.Initialize(new ApplicationEngine(TriggerType.Application, null, snapshot, 0)); + NativeContract.Policy.Initialize(ApplicationEngine.Create(TriggerType.Application, null, snapshot, 0)); // Without signature @@ -191,7 +191,7 @@ public void Check_SetFeePerByte() snapshot.PersistingBlock = new Block() { Index = 1000, PrevHash = UInt256.Zero }; snapshot.Blocks.Add(UInt256.Zero, new Neo.Ledger.TrimmedBlock() { NextConsensus = UInt160.Zero }); - NativeContract.Policy.Initialize(new ApplicationEngine(TriggerType.Application, null, snapshot, 0)); + NativeContract.Policy.Initialize(ApplicationEngine.Create(TriggerType.Application, null, snapshot, 0)); // Without signature @@ -228,7 +228,7 @@ public void Check_Block_UnblockAccount() UInt160 committeeMultiSigAddr = NativeContract.NEO.GetCommitteeAddress(snapshot); - NativeContract.Policy.Initialize(new ApplicationEngine(TriggerType.Application, null, snapshot, 0)); + NativeContract.Policy.Initialize(ApplicationEngine.Create(TriggerType.Application, null, snapshot, 0)); // Block without signature diff --git a/tests/neo.UnitTests/SmartContract/UT_ApplicationEngine.cs b/tests/neo.UnitTests/SmartContract/UT_ApplicationEngine.cs index 6bccb8f179..3d8c435a06 100644 --- a/tests/neo.UnitTests/SmartContract/UT_ApplicationEngine.cs +++ b/tests/neo.UnitTests/SmartContract/UT_ApplicationEngine.cs @@ -21,7 +21,7 @@ public void TestSetup() public void TestNotify() { var snapshot = Blockchain.Singleton.GetSnapshot(); - var engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); + var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, 0, true); ApplicationEngine.Notify += Test_Notify1; const string notifyEvent = "TestEvent"; diff --git a/tests/neo.UnitTests/SmartContract/UT_ApplicationEngineProvider.cs b/tests/neo.UnitTests/SmartContract/UT_ApplicationEngineProvider.cs new file mode 100644 index 0000000000..81c32cd8b5 --- /dev/null +++ b/tests/neo.UnitTests/SmartContract/UT_ApplicationEngineProvider.cs @@ -0,0 +1,80 @@ +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Neo.Network.P2P.Payloads; +using Neo.Persistence; +using Neo.Plugins; +using Neo.SmartContract; + +namespace Neo.UnitTests.SmartContract +{ + [TestClass] + public class UT_ApplicationEngineProvider + { + [TestInitialize] + public void TestInitialize() + { + ApplicationEngine.ResetApplicationEngineProvider(); + } + + [TestCleanup] + public void TestCleanup() + { + ApplicationEngine.ResetApplicationEngineProvider(); + } + + [TestMethod] + public void TestSetAppEngineProvider() + { + var provider = new TestProvider(); + ApplicationEngine.SetApplicationEngineProvider(provider).Should().BeTrue(); + + using var appEngine = ApplicationEngine.Create(TriggerType.Application, null, null, 0); + (appEngine is TestEngine).Should().BeTrue(); + } + + [TestMethod] + public void TestDefaultAppEngineProvider() + { + using var appEngine = ApplicationEngine.Create(TriggerType.Application, null, null, 0); + (appEngine is ApplicationEngine).Should().BeTrue(); + } + + [TestMethod] + public void TestCantSetAppEngineProviderTwice() + { + var provider = new TestProvider(); + ApplicationEngine.SetApplicationEngineProvider(provider).Should().BeTrue(); + + var provider2 = new TestProvider(); + ApplicationEngine.SetApplicationEngineProvider(provider2).Should().BeFalse(); + } + + [TestMethod] + public void TestCanResetAppEngineProviderTwice() + { + var provider = new TestProvider(); + ApplicationEngine.SetApplicationEngineProvider(provider).Should().BeTrue(); + + ApplicationEngine.ResetApplicationEngineProvider(); + + var provider2 = new TestProvider(); + ApplicationEngine.SetApplicationEngineProvider(provider2).Should().BeTrue(); + } + + class TestProvider : IApplicationEngineProvider + { + public ApplicationEngine Create(TriggerType trigger, IVerifiable container, StoreView snapshot, long gas, bool testMode = false) + { + return new TestEngine(trigger, container, snapshot, gas, testMode); + } + } + + class TestEngine : ApplicationEngine + { + public TestEngine(TriggerType trigger, IVerifiable container, StoreView snapshot, long gas, bool testMode = false) + : base(trigger, container, snapshot, gas, testMode) + { + } + } + } +} diff --git a/tests/neo.UnitTests/SmartContract/UT_InteropPrices.cs b/tests/neo.UnitTests/SmartContract/UT_InteropPrices.cs index cf93e5abb3..1635e431e8 100644 --- a/tests/neo.UnitTests/SmartContract/UT_InteropPrices.cs +++ b/tests/neo.UnitTests/SmartContract/UT_InteropPrices.cs @@ -21,7 +21,7 @@ public void ApplicationEngineFixedPrices() { // System.Runtime.CheckWitness: f827ec8c (price is 200) byte[] SyscallSystemRuntimeCheckWitnessHash = new byte[] { 0x68, 0xf8, 0x27, 0xec, 0x8c }; - using (ApplicationEngine ae = new ApplicationEngine(TriggerType.Application, null, null, 0)) + using (ApplicationEngine ae = ApplicationEngine.Create(TriggerType.Application, null, null, 0)) { ae.LoadScript(SyscallSystemRuntimeCheckWitnessHash); ApplicationEngine.System_Runtime_CheckWitness.FixedPrice.Should().Be(0_00030000L); @@ -29,7 +29,7 @@ public void ApplicationEngineFixedPrices() // System.Storage.GetContext: 9bf667ce (price is 1) byte[] SyscallSystemStorageGetContextHash = new byte[] { 0x68, 0x9b, 0xf6, 0x67, 0xce }; - using (ApplicationEngine ae = new ApplicationEngine(TriggerType.Application, null, null, 0)) + using (ApplicationEngine ae = ApplicationEngine.Create(TriggerType.Application, null, null, 0)) { ae.LoadScript(SyscallSystemStorageGetContextHash); ApplicationEngine.System_Storage_GetContext.FixedPrice.Should().Be(0_00000400L); @@ -37,7 +37,7 @@ public void ApplicationEngineFixedPrices() // System.Storage.Get: 925de831 (price is 100) byte[] SyscallSystemStorageGetHash = new byte[] { 0x68, 0x92, 0x5d, 0xe8, 0x31 }; - using (ApplicationEngine ae = new ApplicationEngine(TriggerType.Application, null, null, 0)) + using (ApplicationEngine ae = ApplicationEngine.Create(TriggerType.Application, null, null, 0)) { ae.LoadScript(SyscallSystemStorageGetHash); ApplicationEngine.System_Storage_Get.FixedPrice.Should().Be(0_01000000L); @@ -65,7 +65,7 @@ public void ApplicationEngineRegularPut() snapshot.Storages.Add(skey, sItem); snapshot.Contracts.Add(script.ToScriptHash(), contractState); - using (ApplicationEngine ae = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, testMode: true)) + using (ApplicationEngine ae = ApplicationEngine.Create(TriggerType.Application, null, snapshot, 0, testMode: true)) { Debugger debugger = new Debugger(ae); ae.LoadScript(script); @@ -99,7 +99,7 @@ public void ApplicationEngineReusedStorage_FullReuse() snapshot.Storages.Add(skey, sItem); snapshot.Contracts.Add(script.ToScriptHash(), contractState); - using (ApplicationEngine applicationEngine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, testMode: true)) + using (ApplicationEngine applicationEngine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, 0, testMode: true)) { Debugger debugger = new Debugger(applicationEngine); applicationEngine.LoadScript(script); @@ -135,7 +135,7 @@ public void ApplicationEngineReusedStorage_PartialReuse() snapshot.Storages.Add(skey, sItem); snapshot.Contracts.Add(script.ToScriptHash(), contractState); - using (ApplicationEngine ae = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, testMode: true)) + using (ApplicationEngine ae = ApplicationEngine.Create(TriggerType.Application, null, snapshot, 0, testMode: true)) { Debugger debugger = new Debugger(ae); ae.LoadScript(script); @@ -172,7 +172,7 @@ public void ApplicationEngineReusedStorage_PartialReuseTwice() snapshot.Storages.Add(skey, sItem); snapshot.Contracts.Add(script.ToScriptHash(), contractState); - using (ApplicationEngine ae = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, testMode: true)) + using (ApplicationEngine ae = ApplicationEngine.Create(TriggerType.Application, null, snapshot, 0, testMode: true)) { Debugger debugger = new Debugger(ae); ae.LoadScript(script); diff --git a/tests/neo.UnitTests/SmartContract/UT_InteropService.NEO.cs b/tests/neo.UnitTests/SmartContract/UT_InteropService.NEO.cs index 5d78c4ebd5..4d4eaf4b07 100644 --- a/tests/neo.UnitTests/SmartContract/UT_InteropService.NEO.cs +++ b/tests/neo.UnitTests/SmartContract/UT_InteropService.NEO.cs @@ -115,12 +115,12 @@ public void TestAccount_IsStandard() var snapshot = Blockchain.Singleton.GetSnapshot(); var state = TestUtils.GetContract(); snapshot.Contracts.Add(state.ScriptHash, state); - engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); + engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, 0, true); engine.LoadScript(new byte[] { 0x01 }); engine.IsStandardContract(state.ScriptHash).Should().BeFalse(); state.Script = Contract.CreateSignatureRedeemScript(Blockchain.StandbyValidators[0]); - engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); + engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, 0, true); engine.LoadScript(new byte[] { 0x01 }); engine.IsStandardContract(state.ScriptHash).Should().BeTrue(); } @@ -141,7 +141,7 @@ public void TestContract_Create() var snapshot = Blockchain.Singleton.GetSnapshot(); var state = TestUtils.GetContract(); snapshot.Contracts.Add(state.ScriptHash, state); - engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0); + engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, 0); engine.LoadScript(new byte[] { 0x01 }); Assert.ThrowsException(() => engine.CreateContract(state.Script, manifest.ToJson().ToByteArray(false))); } @@ -184,7 +184,7 @@ public void TestContract_Update() }; snapshot.Contracts.Add(state.ScriptHash, state); snapshot.Storages.Add(storageKey, storageItem); - engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); + engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, 0, true); engine.LoadScript(state.Script); engine.UpdateContract(script, manifest.ToJson().ToByteArray(false)); engine.Snapshot.Storages.Find(BitConverter.GetBytes(state.Id)).ToList().Count().Should().Be(1); @@ -209,7 +209,7 @@ public void TestStorage_Find() }; snapshot.Contracts.Add(state.ScriptHash, state); snapshot.Storages.Add(storageKey, storageItem); - var engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); + var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, 0, true); engine.LoadScript(new byte[] { 0x01 }); var iterator = engine.Find(new StorageContext diff --git a/tests/neo.UnitTests/SmartContract/UT_InteropService.cs b/tests/neo.UnitTests/SmartContract/UT_InteropService.cs index 174aace8f1..3a0062275f 100644 --- a/tests/neo.UnitTests/SmartContract/UT_InteropService.cs +++ b/tests/neo.UnitTests/SmartContract/UT_InteropService.cs @@ -58,7 +58,7 @@ public void Runtime_GetNotifications_Test() // Wrong length - using (var engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true)) + using (var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, 0, true)) using (var script = new ScriptBuilder()) { // Retrive @@ -75,7 +75,7 @@ public void Runtime_GetNotifications_Test() // All test - using (var engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true)) + using (var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, 0, true)) using (var script = new ScriptBuilder()) { // Notification @@ -127,7 +127,7 @@ public void Runtime_GetNotifications_Test() // Script notifications - using (var engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true)) + using (var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, 0, true)) using (var script = new ScriptBuilder()) { // Notification @@ -386,7 +386,7 @@ public void TestBlockchain_GetContract() var snapshot = Blockchain.Singleton.GetSnapshot(); var state = TestUtils.GetContract(); snapshot.Contracts.Add(state.ScriptHash, state); - engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); + engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, 0, true); engine.LoadScript(new byte[] { 0x01 }); engine.GetContract(state.ScriptHash).Should().BeSameAs(state); } @@ -433,7 +433,7 @@ public void TestStorage_Get() }; snapshot.Contracts.Add(state.ScriptHash, state); snapshot.Storages.Add(storageKey, storageItem); - var engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); + var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, 0, true); engine.LoadScript(new byte[] { 0x01 }); engine.Get(new StorageContext @@ -491,7 +491,7 @@ public void TestStorage_Put() }; snapshot.Contracts.Add(state.ScriptHash, state); snapshot.Storages.Add(storageKey, storageItem); - engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); + engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, 0, true); engine.LoadScript(new byte[] { 0x01 }); key = new byte[] { 0x01 }; value = new byte[] { 0x02 }; @@ -527,7 +527,7 @@ public void TestStorage_PutEx() }; snapshot.Contracts.Add(state.ScriptHash, state); snapshot.Storages.Add(storageKey, storageItem); - engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); + engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, 0, true); engine.LoadScript(new byte[] { 0x01 }); var key = new byte[] { 0x01 }; var value = new byte[] { 0x02 }; @@ -558,7 +558,7 @@ public void TestStorage_Delete() }; snapshot.Contracts.Add(state.ScriptHash, state); snapshot.Storages.Add(storageKey, storageItem); - engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); + engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, 0, true); engine.LoadScript(new byte[] { 0x01 }); state.Manifest.Features = ContractFeatures.HasStorage; var key = new byte[] { 0x01 }; @@ -597,7 +597,7 @@ public void TestContract_Call() state.Manifest.Features = ContractFeatures.HasStorage; snapshot.Contracts.Add(state.ScriptHash, state); - var engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); + var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, 0, true); engine.LoadScript(new byte[] { 0x01 }); engine.CallContract(state.ScriptHash, method, args); @@ -627,7 +627,7 @@ public void TestContract_CallEx() foreach (var flags in new CallFlags[] { CallFlags.None, CallFlags.AllowCall, CallFlags.AllowModifyStates, CallFlags.All }) { - var engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); + var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, 0, true); engine.LoadScript(new byte[] { 0x01 }); engine.CallContractEx(state.ScriptHash, method, args, CallFlags.All); @@ -667,7 +667,7 @@ public void TestContract_Destroy() }; snapshot.Contracts.Add(scriptHash, state); snapshot.Storages.Add(storageKey, storageItem); - engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); + engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, 0, true); engine.LoadScript(new byte[0]); engine.DestroyContract(); engine.Snapshot.Storages.Find(BitConverter.GetBytes(0x43000000)).Any().Should().BeFalse(); @@ -676,7 +676,7 @@ public void TestContract_Destroy() snapshot = Blockchain.Singleton.GetSnapshot(); state = TestUtils.GetContract(); snapshot.Contracts.Add(scriptHash, state); - engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); + engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, 0, true); engine.LoadScript(new byte[0]); engine.DestroyContract(); engine.Snapshot.Storages.Find(BitConverter.GetBytes(0x43000000)).Any().Should().BeFalse(); @@ -703,19 +703,19 @@ private static ApplicationEngine GetEngine(bool hasContainer = false, bool hasSn ApplicationEngine engine; if (hasContainer && hasSnapshot) { - engine = new ApplicationEngine(TriggerType.Application, tx, snapshot, 0, true); + engine = ApplicationEngine.Create(TriggerType.Application, tx, snapshot, 0, true); } else if (hasContainer && !hasSnapshot) { - engine = new ApplicationEngine(TriggerType.Application, tx, null, 0, true); + engine = ApplicationEngine.Create(TriggerType.Application, tx, null, 0, true); } else if (!hasContainer && hasSnapshot) { - engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); + engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, 0, true); } else { - engine = new ApplicationEngine(TriggerType.Application, null, null, 0, true); + engine = ApplicationEngine.Create(TriggerType.Application, null, null, 0, true); } if (addScript) { diff --git a/tests/neo.UnitTests/SmartContract/UT_Syscalls.Callback.cs b/tests/neo.UnitTests/SmartContract/UT_Syscalls.Callback.cs index e97e144637..92444fa92c 100644 --- a/tests/neo.UnitTests/SmartContract/UT_Syscalls.Callback.cs +++ b/tests/neo.UnitTests/SmartContract/UT_Syscalls.Callback.cs @@ -21,7 +21,7 @@ public void CreateCallbackTest() // Execute - var engine = new ApplicationEngine(TriggerType.Application, null, null, 100_000_000, false); + var engine = ApplicationEngine.Create(TriggerType.Application, null, null, 100_000_000, false); engine.LoadScript(script.ToArray()); Assert.AreEqual(engine.Execute(), VMState.HALT); @@ -54,7 +54,7 @@ public void InvokeCallbackTest() // Execute - var engine = new ApplicationEngine(TriggerType.Application, null, null, 100_000_000, false); + var engine = ApplicationEngine.Create(TriggerType.Application, null, null, 100_000_000, false); engine.LoadScript(script.ToArray()); Assert.AreEqual(engine.Execute(), VMState.HALT); @@ -79,7 +79,7 @@ public void CreateSyscallCallbackTest() // Execute - var engine = new ApplicationEngine(TriggerType.Application, null, null, 100_000_000, false); + var engine = ApplicationEngine.Create(TriggerType.Application, null, null, 100_000_000, false); engine.LoadScript(script.ToArray()); Assert.AreEqual(engine.Execute(), VMState.HALT); diff --git a/tests/neo.UnitTests/SmartContract/UT_Syscalls.cs b/tests/neo.UnitTests/SmartContract/UT_Syscalls.cs index b32e808f4d..72b33f41b5 100644 --- a/tests/neo.UnitTests/SmartContract/UT_Syscalls.cs +++ b/tests/neo.UnitTests/SmartContract/UT_Syscalls.cs @@ -61,7 +61,7 @@ public void System_Blockchain_GetBlock() // Without block - var engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); + var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, 0, true); engine.LoadScript(script.ToArray()); Assert.AreEqual(engine.Execute(), VMState.HALT); @@ -78,7 +78,7 @@ public void System_Blockchain_GetBlock() blocks.Add(block.Hash, block.Trim()); txs.Add(tx.Hash, new TransactionState() { Transaction = tx, BlockIndex = block.Index, VMState = VMState.HALT }); - engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); + engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, 0, true); engine.LoadScript(script.ToArray()); Assert.AreEqual(engine.Execute(), VMState.HALT); @@ -89,7 +89,7 @@ public void System_Blockchain_GetBlock() height.Index = block.Index; - engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); + engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, 0, true); engine.LoadScript(script.ToArray()); Assert.AreEqual(engine.Execute(), VMState.HALT); @@ -117,7 +117,7 @@ public void Json_Deserialize() script.EmitPush("null"); script.EmitSysCall(ApplicationEngine.System_Json_Deserialize); - using (var engine = new ApplicationEngine(TriggerType.Application, null, null, 0, true)) + using (var engine = ApplicationEngine.Create(TriggerType.Application, null, null, 0, true)) { engine.LoadScript(script.ToArray()); @@ -136,7 +136,7 @@ public void Json_Deserialize() script.EmitPush("***"); script.EmitSysCall(ApplicationEngine.System_Json_Deserialize); - using (var engine = new ApplicationEngine(TriggerType.Application, null, null, 0, true)) + using (var engine = ApplicationEngine.Create(TriggerType.Application, null, null, 0, true)) { engine.LoadScript(script.ToArray()); @@ -152,7 +152,7 @@ public void Json_Deserialize() script.EmitPush("123.45"); script.EmitSysCall(ApplicationEngine.System_Json_Deserialize); - using (var engine = new ApplicationEngine(TriggerType.Application, null, null, 0, true)) + using (var engine = ApplicationEngine.Create(TriggerType.Application, null, null, 0, true)) { engine.LoadScript(script.ToArray()); @@ -185,7 +185,7 @@ public void Json_Serialize() script.Emit(OpCode.SETITEM); script.EmitSysCall(ApplicationEngine.System_Json_Serialize); - using (var engine = new ApplicationEngine(TriggerType.Application, null, null, 0, true)) + using (var engine = ApplicationEngine.Create(TriggerType.Application, null, null, 0, true)) { engine.LoadScript(script.ToArray()); @@ -207,7 +207,7 @@ public void Json_Serialize() script.EmitSysCall(ApplicationEngine.System_Storage_GetContext); script.EmitSysCall(ApplicationEngine.System_Json_Serialize); - using (var engine = new ApplicationEngine(TriggerType.Application, null, null, 0, true)) + using (var engine = ApplicationEngine.Create(TriggerType.Application, null, null, 0, true)) { engine.LoadScript(script.ToArray()); @@ -227,7 +227,7 @@ public void System_ExecutionEngine_GetScriptContainer() // Without tx - var engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); + var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, 0, true); engine.LoadScript(script.ToArray()); Assert.AreEqual(engine.Execute(), VMState.HALT); @@ -249,7 +249,7 @@ public void System_ExecutionEngine_GetScriptContainer() Witnesses = new Witness[] { new Witness() { VerificationScript = new byte[] { 0x07 } } }, }; - engine = new ApplicationEngine(TriggerType.Application, tx, snapshot, 0, true); + engine = ApplicationEngine.Create(TriggerType.Application, tx, snapshot, 0, true); engine.LoadScript(script.ToArray()); Assert.AreEqual(engine.Execute(), VMState.HALT); @@ -278,7 +278,7 @@ public void System_Runtime_GasLeft() // Execute - var engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 100_000_000, false); + var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, 100_000_000, false); engine.LoadScript(script.ToArray()); Assert.AreEqual(engine.Execute(), VMState.HALT); @@ -299,7 +299,7 @@ public void System_Runtime_GasLeft() // Execute - var engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); + var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, 0, true); engine.LoadScript(script.ToArray()); // Check the results @@ -353,7 +353,7 @@ public void System_Runtime_GetInvocationCounter() // Execute - var engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); + var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, 0, true); engine.LoadScript(script.ToArray()); Assert.AreEqual(VMState.HALT, engine.Execute()); From 54784e03091aa217e133fbe3e70288d36c985e58 Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Mon, 13 Jul 2020 19:21:14 +0800 Subject: [PATCH 05/12] Remove the lock from SendersFeeMonitor and rename it to TransactionVerificationContext (#1756) --- src/neo/Consensus/ConsensusContext.cs | 10 +-- src/neo/Consensus/ConsensusService.cs | 28 ++++---- src/neo/Ledger/Blockchain.cs | 13 +--- src/neo/Ledger/MemoryPool.cs | 50 +++++++------ src/neo/Ledger/SendersFeeMonitor.cs | 43 ----------- .../Ledger/TransactionVerificationContext.cs | 37 ++++++++++ src/neo/Network/P2P/Payloads/Transaction.cs | 13 ++-- .../SmartContract/Native/PolicyContract.cs | 10 --- tests/neo.UnitTests/Ledger/UT_Blockchain.cs | 2 +- tests/neo.UnitTests/Ledger/UT_MemoryPool.cs | 46 +++++++----- .../Ledger/UT_SendersFeeMonitor.cs | 55 -------------- .../UT_TransactionVerificationContext.cs | 71 +++++++++++++++++++ .../Network/P2P/Payloads/UT_Transaction.cs | 2 +- .../SmartContract/Native/UT_PolicyContract.cs | 23 ------ 14 files changed, 196 insertions(+), 207 deletions(-) delete mode 100644 src/neo/Ledger/SendersFeeMonitor.cs create mode 100644 src/neo/Ledger/TransactionVerificationContext.cs delete mode 100644 tests/neo.UnitTests/Ledger/UT_SendersFeeMonitor.cs create mode 100644 tests/neo.UnitTests/Ledger/UT_TransactionVerificationContext.cs diff --git a/src/neo/Consensus/ConsensusContext.cs b/src/neo/Consensus/ConsensusContext.cs index 3d3a4fcb5d..7b1cc8b3d0 100644 --- a/src/neo/Consensus/ConsensusContext.cs +++ b/src/neo/Consensus/ConsensusContext.cs @@ -40,7 +40,7 @@ internal class ConsensusContext : IDisposable, ISerializable /// /// Store all verified unsorted transactions' senders' fee currently in the consensus context. /// - public SendersFeeMonitor SendersFeeMonitor = new SendersFeeMonitor(); + public TransactionVerificationContext VerificationContext = new TransactionVerificationContext(); public SnapshotView Snapshot { get; private set; } private KeyPair keyPair; @@ -116,11 +116,11 @@ public void Deserialize(BinaryReader reader) if (TransactionHashes.Length == 0 && !RequestSentOrReceived) TransactionHashes = null; Transactions = transactions.Length == 0 && !RequestSentOrReceived ? null : transactions.ToDictionary(p => p.Hash); - SendersFeeMonitor = new SendersFeeMonitor(); + VerificationContext = new TransactionVerificationContext(); if (Transactions != null) { foreach (Transaction tx in Transactions.Values) - SendersFeeMonitor.AddSenderFee(tx); + VerificationContext.AddTransaction(tx); } } @@ -266,7 +266,7 @@ internal void EnsureMaxBlockLimitation(IEnumerable txs) txs = txs.Take((int)maxTransactionsPerBlock); List hashes = new List(); Transactions = new Dictionary(); - SendersFeeMonitor = new SendersFeeMonitor(); + VerificationContext = new TransactionVerificationContext(); // Expected block size var blockSize = GetExpectedBlockSizeWithoutTransactions(txs.Count()); @@ -285,7 +285,7 @@ internal void EnsureMaxBlockLimitation(IEnumerable txs) hashes.Add(tx.Hash); Transactions.Add(tx.Hash, tx); - SendersFeeMonitor.AddSenderFee(tx); + VerificationContext.AddTransaction(tx); } TransactionHashes = hashes.ToArray(); diff --git a/src/neo/Consensus/ConsensusService.cs b/src/neo/Consensus/ConsensusService.cs index 26648c4429..9caca4b651 100644 --- a/src/neo/Consensus/ConsensusService.cs +++ b/src/neo/Consensus/ConsensusService.cs @@ -64,20 +64,24 @@ internal ConsensusService(IActorRef localNode, IActorRef taskManager, IActorRef private bool AddTransaction(Transaction tx, bool verify) { - if (verify && tx.Verify(context.Snapshot, context.SendersFeeMonitor.GetSenderFee(tx.Sender)) != VerifyResult.Succeed) + if (verify) { - Log($"Invalid transaction: {tx.Hash}{Environment.NewLine}{tx.ToArray().ToHexString()}", LogLevel.Warning); - RequestChangeView(ChangeViewReason.TxInvalid); - return false; - } - if (!NativeContract.Policy.CheckPolicy(tx, context.Snapshot)) - { - Log($"reject tx: {tx.Hash}{Environment.NewLine}{tx.ToArray().ToHexString()}", LogLevel.Warning); - RequestChangeView(ChangeViewReason.TxRejectedByPolicy); - return false; + VerifyResult result = tx.Verify(context.Snapshot, context.VerificationContext); + if (result == VerifyResult.PolicyFail) + { + Log($"reject tx: {tx.Hash}{Environment.NewLine}{tx.ToArray().ToHexString()}", LogLevel.Warning); + RequestChangeView(ChangeViewReason.TxRejectedByPolicy); + return false; + } + else if (result != VerifyResult.Succeed) + { + Log($"Invalid transaction: {tx.Hash}{Environment.NewLine}{tx.ToArray().ToHexString()}", LogLevel.Warning); + RequestChangeView(ChangeViewReason.TxInvalid); + return false; + } } context.Transactions[tx.Hash] = tx; - context.SendersFeeMonitor.AddSenderFee(tx); + context.VerificationContext.AddTransaction(tx); return CheckPrepareResponse(); } @@ -433,7 +437,7 @@ private void OnPrepareRequestReceived(ConsensusPayload payload, PrepareRequest m context.Block.ConsensusData.Nonce = message.Nonce; context.TransactionHashes = message.TransactionHashes; context.Transactions = new Dictionary(); - context.SendersFeeMonitor = new SendersFeeMonitor(); + context.VerificationContext = new TransactionVerificationContext(); for (int i = 0; i < context.PreparationPayloads.Length; i++) if (context.PreparationPayloads[i] != null) if (!context.PreparationPayloads[i].GetDeserializedMessage().PreparationHash.Equals(payload.Hash)) diff --git a/src/neo/Ledger/Blockchain.cs b/src/neo/Ledger/Blockchain.cs index 142180932a..f4f0c6879e 100644 --- a/src/neo/Ledger/Blockchain.cs +++ b/src/neo/Ledger/Blockchain.cs @@ -290,15 +290,10 @@ private void OnFillMemoryPool(IEnumerable transactions) { if (View.ContainsTransaction(tx.Hash)) continue; - if (!NativeContract.Policy.CheckPolicy(tx, currentSnapshot)) - continue; // First remove the tx if it is unverified in the pool. MemPool.TryRemoveUnVerified(tx.Hash, out _); - // Verify the the transaction - if (tx.Verify(currentSnapshot, MemPool.SendersFeeMonitor.GetSenderFee(tx.Sender)) != VerifyResult.Succeed) - continue; // Add to the memory pool - MemPool.TryAdd(tx.Hash, tx); + MemPool.TryAdd(tx, currentSnapshot); } // Transactions originally in the pool will automatically be reverified based on their priority. @@ -362,11 +357,7 @@ private VerifyResult OnNewInventory(IInventory inventory) private VerifyResult OnNewTransaction(Transaction transaction) { if (ContainsTransaction(transaction.Hash)) return VerifyResult.AlreadyExists; - if (!MemPool.CanTransactionFitInPool(transaction)) return VerifyResult.OutOfMemory; - VerifyResult reason = transaction.Verify(currentSnapshot, MemPool.SendersFeeMonitor.GetSenderFee(transaction.Sender)); - if (reason != VerifyResult.Succeed) return reason; - if (!MemPool.TryAdd(transaction.Hash, transaction)) return VerifyResult.OutOfMemory; - return VerifyResult.Succeed; + return MemPool.TryAdd(transaction, currentSnapshot); } protected override void OnReceive(object message) diff --git a/src/neo/Ledger/MemoryPool.cs b/src/neo/Ledger/MemoryPool.cs index 62466d65e8..9a8b42b6e6 100644 --- a/src/neo/Ledger/MemoryPool.cs +++ b/src/neo/Ledger/MemoryPool.cs @@ -71,7 +71,7 @@ public class MemoryPool : IReadOnlyCollection /// /// Store all verified unsorted transactions' senders' fee currently in the memory pool. /// - public SendersFeeMonitor SendersFeeMonitor = new SendersFeeMonitor(); + private TransactionVerificationContext VerificationContext = new TransactionVerificationContext(); /// /// Total count of transactions in the pool. @@ -261,18 +261,21 @@ internal bool CanTransactionFitInPool(Transaction tx) /// /// /// - internal bool TryAdd(UInt256 hash, Transaction tx) + internal VerifyResult TryAdd(Transaction tx, StoreView snapshot) { var poolItem = new PoolItem(tx); - if (_unsortedTransactions.ContainsKey(hash)) return false; + if (_unsortedTransactions.ContainsKey(tx.Hash)) return VerifyResult.AlreadyExists; List removedTransactions = null; _txRwLock.EnterWriteLock(); try { - _unsortedTransactions.Add(hash, poolItem); - SendersFeeMonitor.AddSenderFee(tx); + VerifyResult result = tx.Verify(snapshot, VerificationContext); + if (result != VerifyResult.Succeed) return result; + + _unsortedTransactions.Add(tx.Hash, poolItem); + VerificationContext.AddTransaction(tx); _sortedTransactions.Add(poolItem); if (Count > Capacity) @@ -290,7 +293,8 @@ internal bool TryAdd(UInt256 hash, Transaction tx) plugin.TransactionsRemoved(MemoryPoolTxRemovalReason.CapacityExceeded, removedTransactions); } - return _unsortedTransactions.ContainsKey(hash); + if (!_unsortedTransactions.ContainsKey(tx.Hash)) return VerifyResult.OutOfMemory; + return VerifyResult.Succeed; } private List RemoveOverCapacity() @@ -303,6 +307,9 @@ private List RemoveOverCapacity() unsortedPool.Remove(minItem.Tx.Hash); sortedPool.Remove(minItem); removedTransactions.Add(minItem.Tx); + + if (ReferenceEquals(sortedPool, _sortedTransactions)) + VerificationContext.RemoveTransaction(minItem.Tx); } while (Count > Capacity); return removedTransactions; @@ -315,7 +322,6 @@ private bool TryRemoveVerified(UInt256 hash, out PoolItem item) return false; _unsortedTransactions.Remove(hash); - SendersFeeMonitor.RemoveSenderFee(item.Tx); _sortedTransactions.Remove(item); return true; @@ -343,7 +349,7 @@ internal void InvalidateVerifiedTransactions() // Clear the verified transactions now, since they all must be reverified. _unsortedTransactions.Clear(); - SendersFeeMonitor = new SendersFeeMonitor(); + VerificationContext = new TransactionVerificationContext(); _sortedTransactions.Clear(); } @@ -413,23 +419,23 @@ private int ReverifyTransactions(SortedSet verifiedSortedTxPool, List reverifiedItems = new List(count); List invalidItems = new List(); - // Since unverifiedSortedTxPool is ordered in an ascending manner, we take from the end. - foreach (PoolItem item in unverifiedSortedTxPool.Reverse().Take(count)) + _txRwLock.EnterWriteLock(); + try { - if (item.Tx.VerifyForEachBlock(snapshot, SendersFeeMonitor.GetSenderFee(item.Tx.Sender)) == VerifyResult.Succeed) + // Since unverifiedSortedTxPool is ordered in an ascending manner, we take from the end. + foreach (PoolItem item in unverifiedSortedTxPool.Reverse().Take(count)) { - reverifiedItems.Add(item); - SendersFeeMonitor.AddSenderFee(item.Tx); - } - else // Transaction no longer valid -- it will be removed from unverifiedTxPool. - invalidItems.Add(item); + if (item.Tx.VerifyForEachBlock(snapshot, VerificationContext) == VerifyResult.Succeed) + { + reverifiedItems.Add(item); + VerificationContext.AddTransaction(item.Tx); + } + else // Transaction no longer valid -- it will be removed from unverifiedTxPool. + invalidItems.Add(item); - if (DateTime.UtcNow > reverifyCutOffTimeStamp) break; - } + if (DateTime.UtcNow > reverifyCutOffTimeStamp) break; + } - _txRwLock.EnterWriteLock(); - try - { int blocksTillRebroadcast = BlocksTillRebroadcast; // Increases, proportionally, blocksTillRebroadcast if mempool has more items than threshold bigger RebroadcastMultiplierThreshold if (Count > RebroadcastMultiplierThreshold) @@ -450,7 +456,7 @@ private int ReverifyTransactions(SortedSet verifiedSortedTxPool, } } else - SendersFeeMonitor.RemoveSenderFee(item.Tx); + VerificationContext.RemoveTransaction(item.Tx); _unverifiedTransactions.Remove(item.Tx.Hash); unverifiedSortedTxPool.Remove(item); diff --git a/src/neo/Ledger/SendersFeeMonitor.cs b/src/neo/Ledger/SendersFeeMonitor.cs deleted file mode 100644 index efe3ac6ebe..0000000000 --- a/src/neo/Ledger/SendersFeeMonitor.cs +++ /dev/null @@ -1,43 +0,0 @@ -using Neo.Network.P2P.Payloads; -using System.Collections.Generic; -using System.Numerics; -using System.Threading; - -namespace Neo.Ledger -{ - public class SendersFeeMonitor - { - private readonly ReaderWriterLockSlim _senderFeeRwLock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion); - - /// - /// Store all verified unsorted transactions' senders' fee currently in the memory pool. - /// - private readonly Dictionary _senderFee = new Dictionary(); - - public BigInteger GetSenderFee(UInt160 sender) - { - _senderFeeRwLock.EnterReadLock(); - if (!_senderFee.TryGetValue(sender, out var value)) - value = BigInteger.Zero; - _senderFeeRwLock.ExitReadLock(); - return value; - } - - public void AddSenderFee(Transaction tx) - { - _senderFeeRwLock.EnterWriteLock(); - if (_senderFee.TryGetValue(tx.Sender, out var value)) - _senderFee[tx.Sender] = value + tx.SystemFee + tx.NetworkFee; - else - _senderFee.Add(tx.Sender, tx.SystemFee + tx.NetworkFee); - _senderFeeRwLock.ExitWriteLock(); - } - - public void RemoveSenderFee(Transaction tx) - { - _senderFeeRwLock.EnterWriteLock(); - if ((_senderFee[tx.Sender] -= tx.SystemFee + tx.NetworkFee) == 0) _senderFee.Remove(tx.Sender); - _senderFeeRwLock.ExitWriteLock(); - } - } -} diff --git a/src/neo/Ledger/TransactionVerificationContext.cs b/src/neo/Ledger/TransactionVerificationContext.cs new file mode 100644 index 0000000000..a2bae45b0b --- /dev/null +++ b/src/neo/Ledger/TransactionVerificationContext.cs @@ -0,0 +1,37 @@ +using Neo.Network.P2P.Payloads; +using Neo.Persistence; +using Neo.SmartContract.Native; +using System.Collections.Generic; +using System.Numerics; + +namespace Neo.Ledger +{ + public class TransactionVerificationContext + { + /// + /// Store all verified unsorted transactions' senders' fee currently in the memory pool. + /// + private readonly Dictionary senderFee = new Dictionary(); + + public void AddTransaction(Transaction tx) + { + if (senderFee.TryGetValue(tx.Sender, out var value)) + senderFee[tx.Sender] = value + tx.SystemFee + tx.NetworkFee; + else + senderFee.Add(tx.Sender, tx.SystemFee + tx.NetworkFee); + } + + public bool CheckTransaction(Transaction tx, StoreView snapshot) + { + BigInteger balance = NativeContract.GAS.BalanceOf(snapshot, tx.Sender); + senderFee.TryGetValue(tx.Sender, out var totalSenderFeeFromPool); + BigInteger fee = tx.SystemFee + tx.NetworkFee + totalSenderFeeFromPool; + return balance >= fee; + } + + public void RemoveTransaction(Transaction tx) + { + if ((senderFee[tx.Sender] -= tx.SystemFee + tx.NetworkFee) == 0) senderFee.Remove(tx.Sender); + } + } +} diff --git a/src/neo/Network/P2P/Payloads/Transaction.cs b/src/neo/Network/P2P/Payloads/Transaction.cs index 5aab07af65..8c4071379c 100644 --- a/src/neo/Network/P2P/Payloads/Transaction.cs +++ b/src/neo/Network/P2P/Payloads/Transaction.cs @@ -12,7 +12,6 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using System.Numerics; using Array = Neo.VM.Types.Array; namespace Neo.Network.P2P.Payloads @@ -268,10 +267,10 @@ public JObject ToJson() bool IInventory.Verify(StoreView snapshot) { - return Verify(snapshot, BigInteger.Zero) == VerifyResult.Succeed; + return Verify(snapshot, null) == VerifyResult.Succeed; } - public virtual VerifyResult VerifyForEachBlock(StoreView snapshot, BigInteger totalSenderFeeFromPool) + public virtual VerifyResult VerifyForEachBlock(StoreView snapshot, TransactionVerificationContext context) { if (ValidUntilBlock <= snapshot.Height || ValidUntilBlock > snapshot.Height + MaxValidUntilBlockIncrement) return VerifyResult.Expired; @@ -280,9 +279,7 @@ public virtual VerifyResult VerifyForEachBlock(StoreView snapshot, BigInteger to return VerifyResult.PolicyFail; if (NativeContract.Policy.GetMaxBlockSystemFee(snapshot) < SystemFee) return VerifyResult.PolicyFail; - BigInteger balance = NativeContract.GAS.BalanceOf(snapshot, Sender); - BigInteger fee = SystemFee + NetworkFee + totalSenderFeeFromPool; - if (balance < fee) return VerifyResult.InsufficientFunds; + if (!(context?.CheckTransaction(this, snapshot) ?? true)) return VerifyResult.InsufficientFunds; if (hashes.Length != Witnesses.Length) return VerifyResult.Invalid; for (int i = 0; i < hashes.Length; i++) { @@ -292,9 +289,9 @@ public virtual VerifyResult VerifyForEachBlock(StoreView snapshot, BigInteger to return VerifyResult.Succeed; } - public virtual VerifyResult Verify(StoreView snapshot, BigInteger totalSenderFeeFromPool) + public virtual VerifyResult Verify(StoreView snapshot, TransactionVerificationContext context) { - VerifyResult result = VerifyForEachBlock(snapshot, totalSenderFeeFromPool); + VerifyResult result = VerifyForEachBlock(snapshot, context); if (result != VerifyResult.Succeed) return result; int size = Size; if (size > MaxTransactionSize) return VerifyResult.Invalid; diff --git a/src/neo/SmartContract/Native/PolicyContract.cs b/src/neo/SmartContract/Native/PolicyContract.cs index 6fd173b409..65c690424e 100644 --- a/src/neo/SmartContract/Native/PolicyContract.cs +++ b/src/neo/SmartContract/Native/PolicyContract.cs @@ -2,12 +2,10 @@ using Neo.IO; using Neo.Ledger; -using Neo.Network.P2P.Payloads; using Neo.Persistence; using Neo.SmartContract.Manifest; using System; using System.Collections.Generic; -using System.Linq; namespace Neo.SmartContract.Native { @@ -27,14 +25,6 @@ public PolicyContract() Manifest.Features = ContractFeatures.HasStorage; } - internal bool CheckPolicy(Transaction tx, StoreView snapshot) - { - UInt160[] blockedAccounts = GetBlockedAccounts(snapshot); - if (blockedAccounts.Intersect(tx.GetScriptHashesForVerifying(snapshot)).Any()) - return false; - return true; - } - private bool CheckCommittees(ApplicationEngine engine) { UInt160 committeeMultiSigAddr = NEO.GetCommitteeAddress(engine.Snapshot); diff --git a/tests/neo.UnitTests/Ledger/UT_Blockchain.cs b/tests/neo.UnitTests/Ledger/UT_Blockchain.cs index a94bd98984..e4bf204d47 100644 --- a/tests/neo.UnitTests/Ledger/UT_Blockchain.cs +++ b/tests/neo.UnitTests/Ledger/UT_Blockchain.cs @@ -54,7 +54,7 @@ public class UT_Blockchain : TestKit public void Initialize() { system = TestBlockchain.TheNeoSystem; - Blockchain.Singleton.MemPool.TryAdd(txSample.Hash, txSample); + Blockchain.Singleton.MemPool.TryAdd(txSample, Blockchain.Singleton.GetSnapshot()); } [TestMethod] diff --git a/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs b/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs index e2bb92836e..106e60adc5 100644 --- a/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs +++ b/tests/neo.UnitTests/Ledger/UT_MemoryPool.cs @@ -27,12 +27,20 @@ public void TransactionsRemoved(MemoryPoolTxRemovalReason reason, IEnumerable mock = new Mock(); - mock.Setup(p => p.VerifyForEachBlock(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); - mock.Setup(p => p.Verify(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); + mock.Setup(p => p.VerifyForEachBlock(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); + mock.Setup(p => p.Verify(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); mock.Object.Script = randomBytes; mock.Object.NetworkFee = fee; mock.Object.Attributes = Array.Empty(); @@ -97,9 +105,8 @@ private Transaction CreateTransactionWithFeeAndBalanceVerify(long fee) var randomBytes = new byte[16]; random.NextBytes(randomBytes); Mock mock = new Mock(); - mock.Setup(p => p.VerifyForEachBlock(It.IsAny(), It.IsAny())).Returns((StoreView snapshot, BigInteger amount) => - NativeContract.GAS.BalanceOf(snapshot, UInt160.Zero) >= amount + fee ? VerifyResult.Succeed : VerifyResult.InsufficientFunds); - mock.Setup(p => p.Verify(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); + mock.Setup(p => p.VerifyForEachBlock(It.IsAny(), It.IsAny())).Returns((StoreView snapshot, TransactionVerificationContext context) => context.CheckTransaction(mock.Object, snapshot) ? VerifyResult.Succeed : VerifyResult.InsufficientFunds); + mock.Setup(p => p.Verify(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); mock.Object.Script = randomBytes; mock.Object.NetworkFee = fee; mock.Object.Attributes = Array.Empty(); @@ -124,10 +131,11 @@ private Transaction CreateTransaction(long fee = -1) private void AddTransactions(int count) { + var snapshot = Blockchain.Singleton.GetSnapshot(); for (int i = 0; i < count; i++) { var txToAdd = CreateTransaction(); - _unit.TryAdd(txToAdd.Hash, txToAdd); + _unit.TryAdd(txToAdd, snapshot); } Console.WriteLine($"created {count} tx"); @@ -135,15 +143,17 @@ private void AddTransactions(int count) private void AddTransaction(Transaction txToAdd) { - _unit.TryAdd(txToAdd.Hash, txToAdd); + var snapshot = Blockchain.Singleton.GetSnapshot(); + _unit.TryAdd(txToAdd, snapshot); } private void AddTransactionsWithBalanceVerify(int count, long fee) { + var snapshot = Blockchain.Singleton.GetSnapshot(); for (int i = 0; i < count; i++) { var txToAdd = CreateTransactionWithFeeAndBalanceVerify(fee); - _unit.TryAdd(txToAdd.Hash, txToAdd); + _unit.TryAdd(txToAdd, snapshot); } Console.WriteLine($"created {count} tx"); @@ -355,10 +365,11 @@ public void TestInvalidateAll() [TestMethod] public void TestContainsKey() { + var snapshot = Blockchain.Singleton.GetSnapshot(); AddTransactions(10); var txToAdd = CreateTransaction(); - _unit.TryAdd(txToAdd.Hash, txToAdd); + _unit.TryAdd(txToAdd, snapshot); _unit.ContainsKey(txToAdd.Hash).Should().BeTrue(); _unit.InvalidateVerifiedTransactions(); _unit.ContainsKey(txToAdd.Hash).Should().BeTrue(); @@ -394,11 +405,12 @@ public void TestIEnumerableGetEnumerator() [TestMethod] public void TestGetVerifiedTransactions() { + var snapshot = Blockchain.Singleton.GetSnapshot(); var tx1 = CreateTransaction(); var tx2 = CreateTransaction(); - _unit.TryAdd(tx1.Hash, tx1); + _unit.TryAdd(tx1, snapshot); _unit.InvalidateVerifiedTransactions(); - _unit.TryAdd(tx2.Hash, tx2); + _unit.TryAdd(tx2, snapshot); IEnumerable enumerable = _unit.GetVerifiedTransactions(); enumerable.Count().Should().Be(1); var enumerator = enumerable.GetEnumerator(); @@ -445,17 +457,19 @@ public void TestReVerifyTopUnverifiedTransactionsIfNeeded() [TestMethod] public void TestTryAdd() { + var snapshot = Blockchain.Singleton.GetSnapshot(); var tx1 = CreateTransaction(); - _unit.TryAdd(tx1.Hash, tx1).Should().BeTrue(); - _unit.TryAdd(tx1.Hash, tx1).Should().BeFalse(); - _unit2.TryAdd(tx1.Hash, tx1).Should().BeFalse(); + _unit.TryAdd(tx1, snapshot).Should().Be(VerifyResult.Succeed); + _unit.TryAdd(tx1, snapshot).Should().NotBe(VerifyResult.Succeed); + _unit2.TryAdd(tx1, snapshot).Should().NotBe(VerifyResult.Succeed); } [TestMethod] public void TestTryGetValue() { + var snapshot = Blockchain.Singleton.GetSnapshot(); var tx1 = CreateTransaction(); - _unit.TryAdd(tx1.Hash, tx1); + _unit.TryAdd(tx1, snapshot); _unit.TryGetValue(tx1.Hash, out Transaction tx).Should().BeTrue(); tx.Should().BeEquivalentTo(tx1); @@ -491,7 +505,7 @@ public void TestUpdatePoolForBlockPersisted() var tx1 = CreateTransaction(); var tx2 = CreateTransaction(); Transaction[] transactions = { tx1, tx2 }; - _unit.TryAdd(tx1.Hash, tx1); + _unit.TryAdd(tx1, snapshot); var block = new Block { Transactions = transactions }; diff --git a/tests/neo.UnitTests/Ledger/UT_SendersFeeMonitor.cs b/tests/neo.UnitTests/Ledger/UT_SendersFeeMonitor.cs deleted file mode 100644 index 4c9e2fa333..0000000000 --- a/tests/neo.UnitTests/Ledger/UT_SendersFeeMonitor.cs +++ /dev/null @@ -1,55 +0,0 @@ -using FluentAssertions; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Moq; -using Neo.Ledger; -using Neo.Network.P2P.Payloads; -using Neo.Persistence; -using System; -using System.Numerics; - -namespace Neo.UnitTests.Ledger -{ - [TestClass] - public class UT_SendersFeeMonitor - { - private Transaction CreateTransactionWithFee(long networkFee, long systemFee) - { - Random random = new Random(); - var randomBytes = new byte[16]; - random.NextBytes(randomBytes); - Mock mock = new Mock(); - mock.Setup(p => p.VerifyForEachBlock(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); - mock.Setup(p => p.Verify(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); - mock.Object.Script = randomBytes; - mock.Object.NetworkFee = networkFee; - mock.Object.SystemFee = systemFee; - mock.Object.Attributes = Array.Empty(); - mock.Object.Signers = new Signer[] { new Signer() { Account = UInt160.Zero, Scopes = WitnessScope.FeeOnly } }; - mock.Object.Witnesses = new[] - { - new Witness - { - InvocationScript = new byte[0], - VerificationScript = new byte[0] - } - }; - return mock.Object; - } - - [TestMethod] - public void TestMemPoolSenderFee() - { - Transaction transaction = CreateTransactionWithFee(1, 2); - SendersFeeMonitor sendersFeeMonitor = new SendersFeeMonitor(); - sendersFeeMonitor.GetSenderFee(transaction.Sender).Should().Be(0); - sendersFeeMonitor.AddSenderFee(transaction); - sendersFeeMonitor.GetSenderFee(transaction.Sender).Should().Be(3); - sendersFeeMonitor.AddSenderFee(transaction); - sendersFeeMonitor.GetSenderFee(transaction.Sender).Should().Be(6); - sendersFeeMonitor.RemoveSenderFee(transaction); - sendersFeeMonitor.GetSenderFee(transaction.Sender).Should().Be(3); - sendersFeeMonitor.RemoveSenderFee(transaction); - sendersFeeMonitor.GetSenderFee(transaction.Sender).Should().Be(0); - } - } -} diff --git a/tests/neo.UnitTests/Ledger/UT_TransactionVerificationContext.cs b/tests/neo.UnitTests/Ledger/UT_TransactionVerificationContext.cs new file mode 100644 index 0000000000..a3636a4c91 --- /dev/null +++ b/tests/neo.UnitTests/Ledger/UT_TransactionVerificationContext.cs @@ -0,0 +1,71 @@ +using FluentAssertions; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +using Neo.Ledger; +using Neo.Network.P2P.Payloads; +using Neo.Persistence; +using Neo.SmartContract; +using Neo.SmartContract.Native; +using System; +using System.Numerics; + +namespace Neo.UnitTests.Ledger +{ + [TestClass] + public class UT_TransactionVerificationContext + { + private static NeoSystem testBlockchain; + + [ClassInitialize] + public static void TestSetup(TestContext ctx) + { + testBlockchain = TestBlockchain.TheNeoSystem; + } + + private Transaction CreateTransactionWithFee(long networkFee, long systemFee) + { + Random random = new Random(); + var randomBytes = new byte[16]; + random.NextBytes(randomBytes); + Mock mock = new Mock(); + mock.Setup(p => p.VerifyForEachBlock(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); + mock.Setup(p => p.Verify(It.IsAny(), It.IsAny())).Returns(VerifyResult.Succeed); + mock.Object.Script = randomBytes; + mock.Object.NetworkFee = networkFee; + mock.Object.SystemFee = systemFee; + mock.Object.Signers = new[] { new Signer { Account = UInt160.Zero } }; + mock.Object.Attributes = Array.Empty(); + mock.Object.Witnesses = new[] + { + new Witness + { + InvocationScript = new byte[0], + VerificationScript = new byte[0] + } + }; + return mock.Object; + } + + [TestMethod] + public void TestTransactionSenderFee() + { + var snapshot = Blockchain.Singleton.GetSnapshot(); + ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot, long.MaxValue); + BigInteger balance = NativeContract.GAS.BalanceOf(snapshot, UInt160.Zero); + NativeContract.GAS.Burn(engine, UInt160.Zero, balance); + NativeContract.GAS.Mint(engine, UInt160.Zero, 8); + + TransactionVerificationContext verificationContext = new TransactionVerificationContext(); + var tx = CreateTransactionWithFee(1, 2); + verificationContext.CheckTransaction(tx, snapshot).Should().BeTrue(); + verificationContext.AddTransaction(tx); + verificationContext.CheckTransaction(tx, snapshot).Should().BeTrue(); + verificationContext.AddTransaction(tx); + verificationContext.CheckTransaction(tx, snapshot).Should().BeFalse(); + verificationContext.RemoveTransaction(tx); + verificationContext.CheckTransaction(tx, snapshot).Should().BeTrue(); + verificationContext.AddTransaction(tx); + verificationContext.CheckTransaction(tx, snapshot).Should().BeFalse(); + } + } +} diff --git a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs index de5079a46d..e6f7c3414a 100644 --- a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs +++ b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs @@ -754,7 +754,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.VerifyForEachBlock(snapshot, BigInteger.Zero)); + Assert.AreNotEqual(VerifyResult.Succeed, txSimple.VerifyForEachBlock(snapshot, new TransactionVerificationContext())); } [TestMethod] diff --git a/tests/neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs b/tests/neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs index d464f45ea8..8eba15bf5c 100644 --- a/tests/neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs +++ b/tests/neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs @@ -276,28 +276,5 @@ public void Check_Block_UnblockAccount() ret.Should().BeOfType(); ((VM.Types.Array)ret).Count.Should().Be(0); } - - [TestMethod] - public void TestCheckPolicy() - { - Transaction tx = Blockchain.GenesisBlock.Transactions[0]; - var snapshot = Blockchain.Singleton.GetSnapshot(); - - StorageKey storageKey = new StorageKey - { - Id = NativeContract.Policy.Id, - Key = new byte[sizeof(byte)] - }; - storageKey.Key[0] = 15; - snapshot.Storages.Add(storageKey, new StorageItem - { - Value = new UInt160[] { tx.Sender }.ToByteArray(), - }); - - NativeContract.Policy.CheckPolicy(tx, snapshot).Should().BeFalse(); - - snapshot = Blockchain.Singleton.GetSnapshot(); - NativeContract.Policy.CheckPolicy(tx, snapshot).Should().BeTrue(); - } } } From d5b962caf925110acb3e0c393219bd99598d1dbf Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Tue, 14 Jul 2020 20:29:11 +0800 Subject: [PATCH 06/12] Add EffectiveVoterTurnout (#1762) --- src/neo/Consensus/ConsensusContext.cs | 8 +- src/neo/Consensus/RecoveryMessage.cs | 6 +- src/neo/Ledger/Blockchain.cs | 4 +- src/neo/Network/P2P/Payloads/ConsensusData.cs | 2 +- src/neo/ProtocolSettings.cs | 8 +- src/neo/SmartContract/Native/KeyBuilder.cs | 8 ++ .../SmartContract/Native/Tokens/NeoToken.cs | 85 +++++++++---------- .../Native/Tokens/UT_GasToken.cs | 22 ++--- .../Native/Tokens/UT_NeoToken.cs | 66 +++----------- 9 files changed, 87 insertions(+), 122 deletions(-) diff --git a/src/neo/Consensus/ConsensusContext.cs b/src/neo/Consensus/ConsensusContext.cs index 7b1cc8b3d0..763fa2e77f 100644 --- a/src/neo/Consensus/ConsensusContext.cs +++ b/src/neo/Consensus/ConsensusContext.cs @@ -109,10 +109,10 @@ public void Deserialize(BinaryReader reader) ViewNumber = reader.ReadByte(); TransactionHashes = reader.ReadSerializableArray(); Transaction[] transactions = reader.ReadSerializableArray(Block.MaxTransactionsPerBlock); - PreparationPayloads = reader.ReadNullableArray(ProtocolSettings.Default.MaxValidatorsCount); - CommitPayloads = reader.ReadNullableArray(ProtocolSettings.Default.MaxValidatorsCount); - ChangeViewPayloads = reader.ReadNullableArray(ProtocolSettings.Default.MaxValidatorsCount); - LastChangeViewPayloads = reader.ReadNullableArray(ProtocolSettings.Default.MaxValidatorsCount); + PreparationPayloads = reader.ReadNullableArray(ProtocolSettings.Default.ValidatorsCount); + CommitPayloads = reader.ReadNullableArray(ProtocolSettings.Default.ValidatorsCount); + ChangeViewPayloads = reader.ReadNullableArray(ProtocolSettings.Default.ValidatorsCount); + LastChangeViewPayloads = reader.ReadNullableArray(ProtocolSettings.Default.ValidatorsCount); if (TransactionHashes.Length == 0 && !RequestSentOrReceived) TransactionHashes = null; Transactions = transactions.Length == 0 && !RequestSentOrReceived ? null : transactions.ToDictionary(p => p.Hash); diff --git a/src/neo/Consensus/RecoveryMessage.cs b/src/neo/Consensus/RecoveryMessage.cs index cadb137b80..b082f2aeb2 100644 --- a/src/neo/Consensus/RecoveryMessage.cs +++ b/src/neo/Consensus/RecoveryMessage.cs @@ -31,7 +31,7 @@ public RecoveryMessage() : base(ConsensusMessageType.RecoveryMessage) public override void Deserialize(BinaryReader reader) { base.Deserialize(reader); - ChangeViewMessages = reader.ReadSerializableArray(ProtocolSettings.Default.MaxValidatorsCount).ToDictionary(p => (int)p.ValidatorIndex); + ChangeViewMessages = reader.ReadSerializableArray(ProtocolSettings.Default.ValidatorsCount).ToDictionary(p => (int)p.ValidatorIndex); if (reader.ReadBoolean()) PrepareRequestMessage = reader.ReadSerializable(); else @@ -41,8 +41,8 @@ public override void Deserialize(BinaryReader reader) PreparationHash = new UInt256(reader.ReadFixedBytes(preparationHashSize)); } - PreparationMessages = reader.ReadSerializableArray(ProtocolSettings.Default.MaxValidatorsCount).ToDictionary(p => (int)p.ValidatorIndex); - CommitMessages = reader.ReadSerializableArray(ProtocolSettings.Default.MaxValidatorsCount).ToDictionary(p => (int)p.ValidatorIndex); + PreparationMessages = reader.ReadSerializableArray(ProtocolSettings.Default.ValidatorsCount).ToDictionary(p => (int)p.ValidatorIndex); + CommitMessages = reader.ReadSerializableArray(ProtocolSettings.Default.ValidatorsCount).ToDictionary(p => (int)p.ValidatorIndex); } internal ConsensusPayload[] GetChangeViewPayloads(ConsensusContext context, ConsensusPayload payload) diff --git a/src/neo/Ledger/Blockchain.cs b/src/neo/Ledger/Blockchain.cs index f4f0c6879e..0ac37aa5ab 100644 --- a/src/neo/Ledger/Blockchain.cs +++ b/src/neo/Ledger/Blockchain.cs @@ -32,8 +32,8 @@ public class RelayResult { public IInventory Inventory; public VerifyResult Resu public const uint DecrementInterval = 2000000; public static readonly uint[] GenerationAmount = { 6, 5, 4, 3, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; public static readonly TimeSpan TimePerBlock = TimeSpan.FromMilliseconds(MillisecondsPerBlock); - public static readonly ECPoint[] StandbyCommittee = ProtocolSettings.Default.StandbyCommittee.Take(ProtocolSettings.Default.MaxCommitteeMembersCount).Select(p => ECPoint.DecodePoint(p.HexToBytes(), ECCurve.Secp256r1)).ToArray(); - public static readonly ECPoint[] StandbyValidators = StandbyCommittee.Take(ProtocolSettings.Default.MaxValidatorsCount).ToArray(); + public static readonly ECPoint[] StandbyCommittee = ProtocolSettings.Default.StandbyCommittee.Select(p => ECPoint.DecodePoint(p.HexToBytes(), ECCurve.Secp256r1)).ToArray(); + public static readonly ECPoint[] StandbyValidators = StandbyCommittee[0..ProtocolSettings.Default.ValidatorsCount]; public static readonly Block GenesisBlock = new Block { diff --git a/src/neo/Network/P2P/Payloads/ConsensusData.cs b/src/neo/Network/P2P/Payloads/ConsensusData.cs index 7bbee151fb..8a63f2350f 100644 --- a/src/neo/Network/P2P/Payloads/ConsensusData.cs +++ b/src/neo/Network/P2P/Payloads/ConsensusData.cs @@ -27,7 +27,7 @@ public UInt256 Hash void ISerializable.Deserialize(BinaryReader reader) { - PrimaryIndex = (uint)reader.ReadVarInt((ulong)ProtocolSettings.Default.MaxValidatorsCount - 1); + PrimaryIndex = (uint)reader.ReadVarInt((ulong)ProtocolSettings.Default.ValidatorsCount - 1); Nonce = reader.ReadUInt64(); } diff --git a/src/neo/ProtocolSettings.cs b/src/neo/ProtocolSettings.cs index e004b637a8..79a422f060 100644 --- a/src/neo/ProtocolSettings.cs +++ b/src/neo/ProtocolSettings.cs @@ -10,8 +10,8 @@ public class ProtocolSettings public uint Magic { get; } public byte AddressVersion { get; } public string[] StandbyCommittee { get; } - public byte MaxCommitteeMembersCount { get; } - public byte MaxValidatorsCount { get; } + public int CommitteeMembersCount { get; } + public int ValidatorsCount { get; } public string[] SeedList { get; } public uint MillisecondsPerBlock { get; } public int MemoryPoolMaxTransactions { get; } @@ -78,8 +78,8 @@ private ProtocolSettings(IConfigurationSection section) "03cdcea66032b82f5c30450e381e5295cae85c5e6943af716cc6b646352a6067dc", "02cd5a5547119e24feaa7c2a0f37b8c9366216bab7054de0065c9be42084003c8a" }; - this.MaxCommitteeMembersCount = section.GetValue("MaxCommitteeMembersCount", (byte)21); - this.MaxValidatorsCount = section.GetValue("MaxValidatorsCount", (byte)7); + this.CommitteeMembersCount = StandbyCommittee.Length; + this.ValidatorsCount = section.GetValue("ValidatorsCount", (byte)7); IConfigurationSection section_sl = section.GetSection("SeedList"); if (section_sl.Exists()) this.SeedList = section_sl.GetChildren().Select(p => p.Get()).ToArray(); diff --git a/src/neo/SmartContract/Native/KeyBuilder.cs b/src/neo/SmartContract/Native/KeyBuilder.cs index a5cafedfd9..79ae513df8 100644 --- a/src/neo/SmartContract/Native/KeyBuilder.cs +++ b/src/neo/SmartContract/Native/KeyBuilder.cs @@ -37,6 +37,14 @@ unsafe public KeyBuilder Add(T key) where T : unmanaged return Add(new ReadOnlySpan(&key, sizeof(T))); } + public byte[] ToArray() + { + using (stream) + { + return StorageKey.CreateSearchPrefix(id, stream.ToArray()); + } + } + public static implicit operator StorageKey(KeyBuilder builder) { using (builder.stream) diff --git a/src/neo/SmartContract/Native/Tokens/NeoToken.cs b/src/neo/SmartContract/Native/Tokens/NeoToken.cs index aef7abd14d..fa86ca70d5 100644 --- a/src/neo/SmartContract/Native/Tokens/NeoToken.cs +++ b/src/neo/SmartContract/Native/Tokens/NeoToken.cs @@ -21,6 +21,9 @@ public sealed class NeoToken : Nep5Token public override byte Decimals => 0; public BigInteger TotalAmount { get; } + public const decimal EffectiveVoterTurnout = 0.2M; + + private const byte Prefix_VotersCount = 1; private const byte Prefix_Candidate = 33; private const byte Prefix_NextValidators = 14; @@ -40,9 +43,10 @@ protected override void OnBalanceChanging(ApplicationEngine engine, UInt160 acco if (amount.IsZero) return; if (state.VoteTo != null) { - StorageItem storage_validator = engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_Candidate).Add(state.VoteTo)); - CandidateState state_validator = storage_validator.GetInteroperable(); - state_validator.Votes += amount; + engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_Candidate).Add(state.VoteTo)).GetInteroperable().Votes += amount; + StorageItem item = engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_VotersCount)); + BigInteger votersCount = new BigInteger(item.Value) + amount; + item.Value = votersCount.ToByteArray(); } } @@ -87,19 +91,8 @@ private BigInteger CalculateBonus(BigInteger value, uint start, uint end) internal override void Initialize(ApplicationEngine engine) { - BigInteger amount = TotalAmount; - for (int i = 0; i < Blockchain.StandbyCommittee.Length; i++) - { - ECPoint pubkey = Blockchain.StandbyCommittee[i]; - RegisterCandidateInternal(engine.Snapshot, pubkey); - BigInteger balance = TotalAmount / 2 / (Blockchain.StandbyValidators.Length * 2 + (Blockchain.StandbyCommittee.Length - Blockchain.StandbyValidators.Length)); - if (i < Blockchain.StandbyValidators.Length) balance *= 2; - UInt160 account = Contract.CreateSignatureRedeemScript(pubkey).ToScriptHash(); - Mint(engine, account, balance); - VoteInternal(engine.Snapshot, account, pubkey); - amount -= balance; - } - Mint(engine, Blockchain.GetConsensusAddress(Blockchain.StandbyValidators), amount); + engine.Snapshot.Storages.Add(CreateStorageKey(Prefix_VotersCount), new StorageItem(new byte[0])); + Mint(engine, Blockchain.GetConsensusAddress(Blockchain.StandbyValidators), TotalAmount); } protected override void OnPersist(ApplicationEngine engine) @@ -123,16 +116,11 @@ private bool RegisterCandidate(ApplicationEngine engine, ECPoint pubkey) { if (!engine.CheckWitnessInternal(Contract.CreateSignatureRedeemScript(pubkey).ToScriptHash())) return false; - RegisterCandidateInternal(engine.Snapshot, pubkey); - return true; - } - - private void RegisterCandidateInternal(StoreView snapshot, ECPoint pubkey) - { StorageKey key = CreateStorageKey(Prefix_Candidate).Add(pubkey); - StorageItem item = snapshot.Storages.GetAndChange(key, () => new StorageItem(new CandidateState())); + StorageItem item = engine.Snapshot.Storages.GetAndChange(key, () => new StorageItem(new CandidateState())); CandidateState state = item.GetInteroperable(); state.Registered = true; + return true; } [ContractMethod(0_05000000, CallFlags.AllowModifyStates)] @@ -155,30 +143,35 @@ private bool UnregisterCandidate(ApplicationEngine engine, ECPoint pubkey) private bool Vote(ApplicationEngine engine, UInt160 account, ECPoint voteTo) { if (!engine.CheckWitnessInternal(account)) return false; - return VoteInternal(engine.Snapshot, account, voteTo); - } - - private bool VoteInternal(StoreView snapshot, UInt160 account, ECPoint voteTo) - { StorageKey key_account = CreateStorageKey(Prefix_Account).Add(account); - if (snapshot.Storages.TryGet(key_account) is null) return false; - StorageItem storage_account = snapshot.Storages.GetAndChange(key_account); + if (engine.Snapshot.Storages.TryGet(key_account) is null) return false; + StorageItem storage_account = engine.Snapshot.Storages.GetAndChange(key_account); NeoAccountState state_account = storage_account.GetInteroperable(); + if (state_account.VoteTo is null ^ voteTo is null) + { + StorageItem item = engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_VotersCount)); + BigInteger votersCount = new BigInteger(item.Value); + if (state_account.VoteTo is null) + votersCount += state_account.Balance; + else + votersCount -= state_account.Balance; + item.Value = votersCount.ToByteArray(); + } if (state_account.VoteTo != null) { StorageKey key = CreateStorageKey(Prefix_Candidate).Add(state_account.VoteTo); - StorageItem storage_validator = snapshot.Storages.GetAndChange(key); + StorageItem storage_validator = engine.Snapshot.Storages.GetAndChange(key); CandidateState state_validator = storage_validator.GetInteroperable(); state_validator.Votes -= state_account.Balance; if (!state_validator.Registered && state_validator.Votes.IsZero) - snapshot.Storages.Delete(key); + engine.Snapshot.Storages.Delete(key); } state_account.VoteTo = voteTo; if (voteTo != null) { StorageKey key = CreateStorageKey(Prefix_Candidate).Add(voteTo); - if (snapshot.Storages.TryGet(key) is null) return false; - StorageItem storage_validator = snapshot.Storages.GetAndChange(key); + if (engine.Snapshot.Storages.TryGet(key) is null) return false; + StorageItem storage_validator = engine.Snapshot.Storages.GetAndChange(key); CandidateState state_validator = storage_validator.GetInteroperable(); if (!state_validator.Registered) return false; state_validator.Votes += state_account.Balance; @@ -189,29 +182,24 @@ private bool VoteInternal(StoreView snapshot, UInt160 account, ECPoint voteTo) [ContractMethod(1_00000000, CallFlags.AllowStates)] public (ECPoint PublicKey, BigInteger Votes)[] GetCandidates(StoreView snapshot) { - return GetCandidatesInternal(snapshot).ToArray(); - } - - private IEnumerable<(ECPoint PublicKey, BigInteger Votes)> GetCandidatesInternal(StoreView snapshot) - { - byte[] prefix_key = StorageKey.CreateSearchPrefix(Id, new[] { Prefix_Candidate }); + byte[] prefix_key = CreateStorageKey(Prefix_Candidate).ToArray(); return snapshot.Storages.Find(prefix_key).Select(p => ( p.Key.Key.AsSerializable(1), p.Value.GetInteroperable() - )).Where(p => p.Item2.Registered).Select(p => (p.Item1, p.Item2.Votes)); + )).Where(p => p.Item2.Registered).Select(p => (p.Item1, p.Item2.Votes)).ToArray(); } [ContractMethod(1_00000000, CallFlags.AllowStates)] public ECPoint[] GetValidators(StoreView snapshot) { - return GetCommitteeMembers(snapshot, ProtocolSettings.Default.MaxValidatorsCount).OrderBy(p => p).ToArray(); + return GetCommitteeMembers(snapshot).Take(ProtocolSettings.Default.ValidatorsCount).OrderBy(p => p).ToArray(); } [ContractMethod(1_00000000, CallFlags.AllowStates)] public ECPoint[] GetCommittee(StoreView snapshot) { - return GetCommitteeMembers(snapshot, ProtocolSettings.Default.MaxCommitteeMembersCount).OrderBy(p => p).ToArray(); + return GetCommitteeMembers(snapshot).OrderBy(p => p).ToArray(); } public UInt160 GetCommitteeAddress(StoreView snapshot) @@ -220,9 +208,16 @@ public UInt160 GetCommitteeAddress(StoreView snapshot) return Contract.CreateMultiSigRedeemScript(committees.Length - (committees.Length - 1) / 2, committees).ToScriptHash(); } - private IEnumerable GetCommitteeMembers(StoreView snapshot, int count) + private IEnumerable GetCommitteeMembers(StoreView snapshot) { - return GetCandidatesInternal(snapshot).OrderByDescending(p => p.Votes).ThenBy(p => p.PublicKey).Select(p => p.PublicKey).Take(count); + decimal votersCount = (decimal)new BigInteger(snapshot.Storages[CreateStorageKey(Prefix_VotersCount)].Value); + decimal VoterTurnout = votersCount / (decimal)TotalAmount; + if (VoterTurnout < EffectiveVoterTurnout) + return Blockchain.StandbyCommittee; + var candidates = GetCandidates(snapshot); + if (candidates.Length < ProtocolSettings.Default.CommitteeMembersCount) + return Blockchain.StandbyCommittee; + return candidates.OrderByDescending(p => p.Votes).ThenBy(p => p.PublicKey).Select(p => p.PublicKey).Take(ProtocolSettings.Default.CommitteeMembersCount); } [ContractMethod(1_00000000, CallFlags.AllowStates)] diff --git a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_GasToken.cs b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_GasToken.cs index 17e45ed08c..380bdb65a6 100644 --- a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_GasToken.cs +++ b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_GasToken.cs @@ -49,16 +49,16 @@ public void Check_BalanceOfTransferAndBurn() // Check unclaim var unclaim = UT_NeoToken.Check_UnclaimedGas(snapshot, from); - unclaim.Value.Should().Be(new BigInteger(300000048000)); + unclaim.Value.Should().Be(new BigInteger(600000000000)); unclaim.State.Should().BeTrue(); // Transfer NativeContract.NEO.Transfer(snapshot, from, to, BigInteger.Zero, true).Should().BeTrue(); - NativeContract.NEO.BalanceOf(snapshot, from).Should().Be(50000008); + NativeContract.NEO.BalanceOf(snapshot, from).Should().Be(100000000); NativeContract.NEO.BalanceOf(snapshot, to).Should().Be(0); - NativeContract.GAS.BalanceOf(snapshot, from).Should().Be(3000300000048000); + NativeContract.GAS.BalanceOf(snapshot, from).Should().Be(30006000_00000000); NativeContract.GAS.BalanceOf(snapshot, to).Should().Be(0); // Check unclaim @@ -68,7 +68,7 @@ public void Check_BalanceOfTransferAndBurn() unclaim.State.Should().BeTrue(); supply = NativeContract.GAS.TotalSupply(snapshot); - supply.Should().Be(3000300000048000); + supply.Should().Be(30006000_00000000); snapshot.Storages.GetChangeSet().Count().Should().Be(keyCount + 3); // Gas @@ -76,13 +76,13 @@ public void Check_BalanceOfTransferAndBurn() keyCount = snapshot.Storages.GetChangeSet().Count(); - NativeContract.GAS.Transfer(snapshot, from, to, 3000300000048000, false).Should().BeFalse(); // Not signed - NativeContract.GAS.Transfer(snapshot, from, to, 3000300000048001, true).Should().BeFalse(); // More than balance - NativeContract.GAS.Transfer(snapshot, from, to, 3000300000048000, true).Should().BeTrue(); // All balance + NativeContract.GAS.Transfer(snapshot, from, to, 30006000_00000000, false).Should().BeFalse(); // Not signed + NativeContract.GAS.Transfer(snapshot, from, to, 30006000_00000001, true).Should().BeFalse(); // More than balance + NativeContract.GAS.Transfer(snapshot, from, to, 30006000_00000000, true).Should().BeTrue(); // All balance // Balance of - NativeContract.GAS.BalanceOf(snapshot, to).Should().Be(3000300000048000); + NativeContract.GAS.BalanceOf(snapshot, to).Should().Be(30006000_00000000); NativeContract.GAS.BalanceOf(snapshot, from).Should().Be(0); snapshot.Storages.GetChangeSet().Count().Should().Be(keyCount + 1); // All @@ -98,19 +98,19 @@ public void Check_BalanceOfTransferAndBurn() // Burn more than expected Assert.ThrowsException(() => - NativeContract.GAS.Burn(engine, new UInt160(to), new BigInteger(3000300000048001))); + NativeContract.GAS.Burn(engine, new UInt160(to), new BigInteger(30006000_00000001))); // Real burn NativeContract.GAS.Burn(engine, new UInt160(to), new BigInteger(1)); - NativeContract.GAS.BalanceOf(snapshot, to).Should().Be(3000300000047999); + NativeContract.GAS.BalanceOf(snapshot, to).Should().Be(30005999_99999999); keyCount.Should().Be(snapshot.Storages.GetChangeSet().Count()); // Burn all - NativeContract.GAS.Burn(engine, new UInt160(to), new BigInteger(3000300000047999)); + NativeContract.GAS.Burn(engine, new UInt160(to), new BigInteger(30005999_99999999)); (keyCount - 1).Should().Be(snapshot.Storages.GetChangeSet().Count()); diff --git a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs index 1cce77536e..846f03d5cc 100644 --- a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs +++ b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs @@ -84,7 +84,7 @@ public void Check_UnclaimedGas() byte[] from = Blockchain.GetConsensusAddress(Blockchain.StandbyValidators).ToArray(); var unclaim = Check_UnclaimedGas(snapshot, from); - unclaim.Value.Should().Be(new BigInteger(300000048000)); + unclaim.Value.Should().Be(new BigInteger(600000000000)); unclaim.State.Should().BeTrue(); unclaim = Check_UnclaimedGas(snapshot, new byte[19]); @@ -116,16 +116,8 @@ public void Check_RegisterValidator() // Check GetRegisteredValidators - var members = NativeContract.NEO.GetCandidates(snapshot).OrderBy(u => u.PublicKey).ToArray(); - var check = Blockchain.StandbyCommittee.Select(u => u.EncodePoint(true)).ToList(); - check.Add(point); // Add the new member - - for (int x = 0; x < members.Length; x++) - { - Assert.AreEqual(1, check.RemoveAll(u => u.SequenceEqual(members[x].PublicKey.EncodePoint(true)))); - } - - Assert.AreEqual(0, check.Count); + var members = NativeContract.NEO.GetCandidates(snapshot); + Assert.AreEqual(2, members.Length); } [TestMethod] @@ -143,14 +135,14 @@ public void Check_Transfer() // Check unclaim var unclaim = Check_UnclaimedGas(snapshot, from); - unclaim.Value.Should().Be(new BigInteger(300000048000)); + unclaim.Value.Should().Be(new BigInteger(600000000000)); unclaim.State.Should().BeTrue(); // Transfer NativeContract.NEO.Transfer(snapshot, from, to, BigInteger.One, false).Should().BeFalse(); // Not signed NativeContract.NEO.Transfer(snapshot, from, to, BigInteger.One, true).Should().BeTrue(); - NativeContract.NEO.BalanceOf(snapshot, from).Should().Be(50000007); + NativeContract.NEO.BalanceOf(snapshot, from).Should().Be(99999999); NativeContract.NEO.BalanceOf(snapshot, to).Should().Be(1); // Check unclaim @@ -186,7 +178,7 @@ public void Check_BalanceOf() var snapshot = Blockchain.Singleton.GetSnapshot(); byte[] account = Blockchain.GetConsensusAddress(Blockchain.StandbyValidators).ToArray(); - NativeContract.NEO.BalanceOf(snapshot, account).Should().Be(50_000_008); + NativeContract.NEO.BalanceOf(snapshot, account).Should().Be(100_000_000); account[5]++; // Without existing balance @@ -276,53 +268,23 @@ public void TestGetNextBlockValidators2() } [TestMethod] - public void TestGetRegisteredValidators1() + public void TestGetCandidates1() { - using (ApplicationEngine engine = NativeContract.NEO.TestCall("getCandidates")) - { - var array = engine.ResultStack.Pop(); - array.Count.Should().Be(21); - ((VM.Types.Struct)array[0])[0].GetSpan().ToHexString().Should().Be("020f2887f41474cfeb11fd262e982051c1541418137c02a0f4961af911045de639"); - ((VM.Types.Struct)array[0])[1].GetInteger().Should().Be(new BigInteger(1785714)); - ((VM.Types.Struct)array[1])[0].GetSpan().ToHexString().Should().Be("0222038884bbd1d8ff109ed3bdef3542e768eef76c1247aea8bc8171f532928c30"); - ((VM.Types.Struct)array[1])[1].GetInteger().Should().Be(new BigInteger(1785714)); - ((VM.Types.Struct)array[2])[0].GetSpan().ToHexString().Should().Be("0226933336f1b75baa42d42b71d9091508b638046d19abd67f4e119bf64a7cfb4d"); - ((VM.Types.Struct)array[2])[1].GetInteger().Should().Be(new BigInteger(1785714)); - ((VM.Types.Struct)array[3])[0].GetSpan().ToHexString().Should().Be("023a36c72844610b4d34d1968662424011bf783ca9d984efa19a20babf5582f3fe"); - ((VM.Types.Struct)array[3])[1].GetInteger().Should().Be(new BigInteger(1785714)); - ((VM.Types.Struct)array[4])[0].GetSpan().ToHexString().Should().Be("02486fd15702c4490a26703112a5cc1d0923fd697a33406bd5a1c00e0013b09a70"); - ((VM.Types.Struct)array[4])[1].GetInteger().Should().Be(new BigInteger(3571428)); - ((VM.Types.Struct)array[5])[0].GetSpan().ToHexString().Should().Be("024c7b7fb6c310fccf1ba33b082519d82964ea93868d676662d4a59ad548df0e7d"); - ((VM.Types.Struct)array[5])[1].GetInteger().Should().Be(new BigInteger(3571428)); - ((VM.Types.Struct)array[6])[0].GetSpan().ToHexString().Should().Be("02504acbc1f4b3bdad1d86d6e1a08603771db135a73e61c9d565ae06a1938cd2ad"); - ((VM.Types.Struct)array[6])[1].GetInteger().Should().Be(new BigInteger(1785714)); - } + using ApplicationEngine engine = NativeContract.NEO.TestCall("getCandidates"); + var array = engine.ResultStack.Pop(); + array.Count.Should().Be(0); } [TestMethod] - public void TestGetRegisteredValidators2() + public void TestGetCandidates2() { var snapshot = Blockchain.Singleton.GetSnapshot(); - var result = NativeContract.NEO.GetCandidates(snapshot).ToArray(); - result.Length.Should().Be(21); - result[0].PublicKey.ToArray().ToHexString().Should().Be("020f2887f41474cfeb11fd262e982051c1541418137c02a0f4961af911045de639"); - result[0].Votes.Should().Be(new BigInteger(1785714)); - result[1].PublicKey.ToArray().ToHexString().Should().Be("0222038884bbd1d8ff109ed3bdef3542e768eef76c1247aea8bc8171f532928c30"); - result[1].Votes.Should().Be(new BigInteger(1785714)); - result[2].PublicKey.ToArray().ToHexString().Should().Be("0226933336f1b75baa42d42b71d9091508b638046d19abd67f4e119bf64a7cfb4d"); - result[2].Votes.Should().Be(new BigInteger(1785714)); - result[3].PublicKey.ToArray().ToHexString().Should().Be("023a36c72844610b4d34d1968662424011bf783ca9d984efa19a20babf5582f3fe"); - result[3].Votes.Should().Be(new BigInteger(1785714)); - result[4].PublicKey.ToArray().ToHexString().Should().Be("02486fd15702c4490a26703112a5cc1d0923fd697a33406bd5a1c00e0013b09a70"); - result[4].Votes.Should().Be(new BigInteger(3571428)); - result[5].PublicKey.ToArray().ToHexString().Should().Be("024c7b7fb6c310fccf1ba33b082519d82964ea93868d676662d4a59ad548df0e7d"); - result[5].Votes.Should().Be(new BigInteger(3571428)); - result[6].PublicKey.ToArray().ToHexString().Should().Be("02504acbc1f4b3bdad1d86d6e1a08603771db135a73e61c9d565ae06a1938cd2ad"); - result[6].Votes.Should().Be(new BigInteger(1785714)); + var result = NativeContract.NEO.GetCandidates(snapshot); + result.Length.Should().Be(0); StorageKey key = NativeContract.NEO.CreateStorageKey(33, ECCurve.Secp256r1.G); snapshot.Storages.Add(key, new StorageItem(new CandidateState())); - NativeContract.NEO.GetCandidates(snapshot).ToArray().Length.Should().Be(22); + NativeContract.NEO.GetCandidates(snapshot).Length.Should().Be(1); } [TestMethod] From 2c20df6d8451c3289240b6769308eda5b79837e6 Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Wed, 15 Jul 2020 22:56:33 +0800 Subject: [PATCH 07/12] Remove AllowedTriggers from SYSCALLs (#1755) --- .../SmartContract/ApplicationEngine.Binary.cs | 8 +++--- .../ApplicationEngine.Blockchain.cs | 12 ++++----- .../ApplicationEngine.Callback.cs | 8 +++--- .../ApplicationEngine.Contract.cs | 16 ++++++------ .../SmartContract/ApplicationEngine.Crypto.cs | 13 +++++----- .../ApplicationEngine.Enumerator.cs | 8 +++--- .../ApplicationEngine.Iterator.cs | 10 +++---- .../SmartContract/ApplicationEngine.Json.cs | 4 +-- .../SmartContract/ApplicationEngine.Native.cs | 4 +-- .../ApplicationEngine.Runtime.cs | 26 +++++++++---------- .../ApplicationEngine.Storage.cs | 16 ++++++------ src/neo/SmartContract/ApplicationEngine.cs | 6 ++--- src/neo/SmartContract/Helper.cs | 2 +- src/neo/SmartContract/InteropDescriptor.cs | 4 +-- 14 files changed, 66 insertions(+), 71 deletions(-) diff --git a/src/neo/SmartContract/ApplicationEngine.Binary.cs b/src/neo/SmartContract/ApplicationEngine.Binary.cs index 1dd240efdb..d004dd633e 100644 --- a/src/neo/SmartContract/ApplicationEngine.Binary.cs +++ b/src/neo/SmartContract/ApplicationEngine.Binary.cs @@ -5,10 +5,10 @@ namespace Neo.SmartContract { partial class ApplicationEngine { - public static readonly InteropDescriptor System_Binary_Serialize = Register("System.Binary.Serialize", nameof(BinarySerialize), 0_00100000, TriggerType.All, CallFlags.None, true); - public static readonly InteropDescriptor System_Binary_Deserialize = Register("System.Binary.Deserialize", nameof(BinaryDeserialize), 0_00500000, TriggerType.All, CallFlags.None, true); - public static readonly InteropDescriptor System_Binary_Base64Encode = Register("System.Binary.Base64Encode", nameof(Base64Encode), 0_00100000, TriggerType.All, CallFlags.None, true); - public static readonly InteropDescriptor System_Binary_Base64Decode = Register("System.Binary.Base64Decode", nameof(Base64Decode), 0_00100000, TriggerType.All, CallFlags.None, true); + public static readonly InteropDescriptor System_Binary_Serialize = Register("System.Binary.Serialize", nameof(BinarySerialize), 0_00100000, CallFlags.None, true); + public static readonly InteropDescriptor System_Binary_Deserialize = Register("System.Binary.Deserialize", nameof(BinaryDeserialize), 0_00500000, CallFlags.None, true); + public static readonly InteropDescriptor System_Binary_Base64Encode = Register("System.Binary.Base64Encode", nameof(Base64Encode), 0_00100000, CallFlags.None, true); + public static readonly InteropDescriptor System_Binary_Base64Decode = Register("System.Binary.Base64Decode", nameof(Base64Decode), 0_00100000, CallFlags.None, true); internal byte[] BinarySerialize(StackItem item) { diff --git a/src/neo/SmartContract/ApplicationEngine.Blockchain.cs b/src/neo/SmartContract/ApplicationEngine.Blockchain.cs index a4d5cd8bd3..628a746a3a 100644 --- a/src/neo/SmartContract/ApplicationEngine.Blockchain.cs +++ b/src/neo/SmartContract/ApplicationEngine.Blockchain.cs @@ -10,12 +10,12 @@ partial class ApplicationEngine { public const uint MaxTraceableBlocks = Transaction.MaxValidUntilBlockIncrement; - public static readonly InteropDescriptor System_Blockchain_GetHeight = Register("System.Blockchain.GetHeight", nameof(GetBlockchainHeight), 0_00000400, TriggerType.Application, CallFlags.AllowStates, true); - public static readonly InteropDescriptor System_Blockchain_GetBlock = Register("System.Blockchain.GetBlock", nameof(GetBlock), 0_02500000, TriggerType.Application, CallFlags.AllowStates, true); - public static readonly InteropDescriptor System_Blockchain_GetTransaction = Register("System.Blockchain.GetTransaction", nameof(GetTransaction), 0_01000000, TriggerType.Application, CallFlags.AllowStates, true); - public static readonly InteropDescriptor System_Blockchain_GetTransactionHeight = Register("System.Blockchain.GetTransactionHeight", nameof(GetTransactionHeight), 0_01000000, TriggerType.Application, CallFlags.AllowStates, true); - public static readonly InteropDescriptor System_Blockchain_GetTransactionFromBlock = Register("System.Blockchain.GetTransactionFromBlock", nameof(GetTransactionFromBlock), 0_01000000, TriggerType.Application, CallFlags.AllowStates, true); - public static readonly InteropDescriptor System_Blockchain_GetContract = Register("System.Blockchain.GetContract", nameof(GetContract), 0_01000000, TriggerType.Application, CallFlags.AllowStates, true); + public static readonly InteropDescriptor System_Blockchain_GetHeight = Register("System.Blockchain.GetHeight", nameof(GetBlockchainHeight), 0_00000400, CallFlags.AllowStates, true); + public static readonly InteropDescriptor System_Blockchain_GetBlock = Register("System.Blockchain.GetBlock", nameof(GetBlock), 0_02500000, CallFlags.AllowStates, true); + public static readonly InteropDescriptor System_Blockchain_GetTransaction = Register("System.Blockchain.GetTransaction", nameof(GetTransaction), 0_01000000, CallFlags.AllowStates, true); + public static readonly InteropDescriptor System_Blockchain_GetTransactionHeight = Register("System.Blockchain.GetTransactionHeight", nameof(GetTransactionHeight), 0_01000000, CallFlags.AllowStates, true); + public static readonly InteropDescriptor System_Blockchain_GetTransactionFromBlock = Register("System.Blockchain.GetTransactionFromBlock", nameof(GetTransactionFromBlock), 0_01000000, CallFlags.AllowStates, true); + public static readonly InteropDescriptor System_Blockchain_GetContract = Register("System.Blockchain.GetContract", nameof(GetContract), 0_01000000, CallFlags.AllowStates, true); internal uint GetBlockchainHeight() { diff --git a/src/neo/SmartContract/ApplicationEngine.Callback.cs b/src/neo/SmartContract/ApplicationEngine.Callback.cs index 633a6c6fe2..673de39039 100644 --- a/src/neo/SmartContract/ApplicationEngine.Callback.cs +++ b/src/neo/SmartContract/ApplicationEngine.Callback.cs @@ -7,10 +7,10 @@ namespace Neo.SmartContract { partial class ApplicationEngine { - public static readonly InteropDescriptor System_Callback_Create = Register("System.Callback.Create", nameof(CreateCallback), 0_00000400, TriggerType.All, CallFlags.None, false); - public static readonly InteropDescriptor System_Callback_CreateFromMethod = Register("System.Callback.CreateFromMethod", nameof(CreateCallbackFromMethod), 0_01000000, TriggerType.All, CallFlags.None, false); - public static readonly InteropDescriptor System_Callback_CreateFromSyscall = Register("System.Callback.CreateFromSyscall", nameof(CreateCallbackFromSyscall), 0_00000400, TriggerType.All, CallFlags.None, false); - public static readonly InteropDescriptor System_Callback_Invoke = Register("System.Callback.Invoke", nameof(InvokeCallback), 0_01000000, TriggerType.All, CallFlags.None, false); + public static readonly InteropDescriptor System_Callback_Create = Register("System.Callback.Create", nameof(CreateCallback), 0_00000400, CallFlags.None, false); + public static readonly InteropDescriptor System_Callback_CreateFromMethod = Register("System.Callback.CreateFromMethod", nameof(CreateCallbackFromMethod), 0_01000000, CallFlags.None, false); + public static readonly InteropDescriptor System_Callback_CreateFromSyscall = Register("System.Callback.CreateFromSyscall", nameof(CreateCallbackFromSyscall), 0_00000400, CallFlags.None, false); + public static readonly InteropDescriptor System_Callback_Invoke = Register("System.Callback.Invoke", nameof(InvokeCallback), 0_01000000, CallFlags.None, false); internal void InvokeCallback(CallbackBase callback, Array args) { diff --git a/src/neo/SmartContract/ApplicationEngine.Contract.cs b/src/neo/SmartContract/ApplicationEngine.Contract.cs index 5b84938289..4ecfdde31e 100644 --- a/src/neo/SmartContract/ApplicationEngine.Contract.cs +++ b/src/neo/SmartContract/ApplicationEngine.Contract.cs @@ -15,18 +15,18 @@ partial class ApplicationEngine { public const int MaxContractLength = 1024 * 1024; - public static readonly InteropDescriptor System_Contract_Create = Register("System.Contract.Create", nameof(CreateContract), 0, TriggerType.Application, CallFlags.AllowModifyStates, false); - public static readonly InteropDescriptor System_Contract_Update = Register("System.Contract.Update", nameof(UpdateContract), 0, TriggerType.Application, CallFlags.AllowModifyStates, false); - public static readonly InteropDescriptor System_Contract_Destroy = Register("System.Contract.Destroy", nameof(DestroyContract), 0_01000000, TriggerType.Application, CallFlags.AllowModifyStates, false); - public static readonly InteropDescriptor System_Contract_Call = Register("System.Contract.Call", nameof(CallContract), 0_01000000, TriggerType.System | TriggerType.Application, CallFlags.AllowCall, false); - public static readonly InteropDescriptor System_Contract_CallEx = Register("System.Contract.CallEx", nameof(CallContractEx), 0_01000000, TriggerType.System | TriggerType.Application, CallFlags.AllowCall, false); - public static readonly InteropDescriptor System_Contract_IsStandard = Register("System.Contract.IsStandard", nameof(IsStandardContract), 0_00030000, TriggerType.All, CallFlags.None, true); - public static readonly InteropDescriptor System_Contract_GetCallFlags = Register("System.Contract.GetCallFlags", nameof(GetCallFlags), 0_00030000, TriggerType.All, CallFlags.None, false); + public static readonly InteropDescriptor System_Contract_Create = Register("System.Contract.Create", nameof(CreateContract), 0, CallFlags.AllowModifyStates, false); + public static readonly InteropDescriptor System_Contract_Update = Register("System.Contract.Update", nameof(UpdateContract), 0, CallFlags.AllowModifyStates, false); + public static readonly InteropDescriptor System_Contract_Destroy = Register("System.Contract.Destroy", nameof(DestroyContract), 0_01000000, CallFlags.AllowModifyStates, false); + public static readonly InteropDescriptor System_Contract_Call = Register("System.Contract.Call", nameof(CallContract), 0_01000000, CallFlags.AllowCall, false); + public static readonly InteropDescriptor System_Contract_CallEx = Register("System.Contract.CallEx", nameof(CallContractEx), 0_01000000, CallFlags.AllowCall, false); + public static readonly InteropDescriptor System_Contract_IsStandard = Register("System.Contract.IsStandard", nameof(IsStandardContract), 0_00030000, CallFlags.None, true); + public static readonly InteropDescriptor System_Contract_GetCallFlags = Register("System.Contract.GetCallFlags", nameof(GetCallFlags), 0_00030000, CallFlags.None, false); /// /// Calculate corresponding account scripthash for given public key /// Warning: check first that input public key is valid, before creating the script. /// - public static readonly InteropDescriptor System_Contract_CreateStandardAccount = Register("System.Contract.CreateStandardAccount", nameof(CreateStandardAccount), 0_00010000, TriggerType.All, CallFlags.None, true); + public static readonly InteropDescriptor System_Contract_CreateStandardAccount = Register("System.Contract.CreateStandardAccount", nameof(CreateStandardAccount), 0_00010000, CallFlags.None, true); internal ContractState CreateContract(byte[] script, byte[] manifest) { diff --git a/src/neo/SmartContract/ApplicationEngine.Crypto.cs b/src/neo/SmartContract/ApplicationEngine.Crypto.cs index 13a8edab9e..e448e60374 100644 --- a/src/neo/SmartContract/ApplicationEngine.Crypto.cs +++ b/src/neo/SmartContract/ApplicationEngine.Crypto.cs @@ -2,7 +2,6 @@ using Neo.Cryptography.ECC; using Neo.Network.P2P; using Neo.Network.P2P.Payloads; -using Neo.VM; using Neo.VM.Types; using System; @@ -12,12 +11,12 @@ partial class ApplicationEngine { public const long ECDsaVerifyPrice = 0_01000000; - public static readonly InteropDescriptor Neo_Crypto_RIPEMD160 = Register("Neo.Crypto.RIPEMD160", nameof(RIPEMD160), 0_01000000, TriggerType.All, CallFlags.None, true); - public static readonly InteropDescriptor Neo_Crypto_SHA256 = Register("Neo.Crypto.SHA256", nameof(Sha256), 0_01000000, TriggerType.All, CallFlags.None, true); - public static readonly InteropDescriptor Neo_Crypto_VerifyWithECDsaSecp256r1 = Register("Neo.Crypto.VerifyWithECDsaSecp256r1", nameof(VerifyWithECDsaSecp256r1), ECDsaVerifyPrice, TriggerType.All, CallFlags.None, true); - public static readonly InteropDescriptor Neo_Crypto_VerifyWithECDsaSecp256k1 = Register("Neo.Crypto.VerifyWithECDsaSecp256k1", nameof(VerifyWithECDsaSecp256k1), ECDsaVerifyPrice, TriggerType.All, CallFlags.None, true); - public static readonly InteropDescriptor Neo_Crypto_CheckMultisigWithECDsaSecp256r1 = Register("Neo.Crypto.CheckMultisigWithECDsaSecp256r1", nameof(CheckMultisigWithECDsaSecp256r1), 0, TriggerType.All, CallFlags.None, true); - public static readonly InteropDescriptor Neo_Crypto_CheckMultisigWithECDsaSecp256k1 = Register("Neo.Crypto.CheckMultisigWithECDsaSecp256k1", nameof(CheckMultisigWithECDsaSecp256k1), 0, TriggerType.All, CallFlags.None, true); + public static readonly InteropDescriptor Neo_Crypto_RIPEMD160 = Register("Neo.Crypto.RIPEMD160", nameof(RIPEMD160), 0_01000000, CallFlags.None, true); + public static readonly InteropDescriptor Neo_Crypto_SHA256 = Register("Neo.Crypto.SHA256", nameof(Sha256), 0_01000000, CallFlags.None, true); + public static readonly InteropDescriptor Neo_Crypto_VerifyWithECDsaSecp256r1 = Register("Neo.Crypto.VerifyWithECDsaSecp256r1", nameof(VerifyWithECDsaSecp256r1), ECDsaVerifyPrice, CallFlags.None, true); + public static readonly InteropDescriptor Neo_Crypto_VerifyWithECDsaSecp256k1 = Register("Neo.Crypto.VerifyWithECDsaSecp256k1", nameof(VerifyWithECDsaSecp256k1), ECDsaVerifyPrice, CallFlags.None, true); + public static readonly InteropDescriptor Neo_Crypto_CheckMultisigWithECDsaSecp256r1 = Register("Neo.Crypto.CheckMultisigWithECDsaSecp256r1", nameof(CheckMultisigWithECDsaSecp256r1), 0, CallFlags.None, true); + public static readonly InteropDescriptor Neo_Crypto_CheckMultisigWithECDsaSecp256k1 = Register("Neo.Crypto.CheckMultisigWithECDsaSecp256k1", nameof(CheckMultisigWithECDsaSecp256k1), 0, CallFlags.None, true); internal byte[] RIPEMD160(StackItem item) { diff --git a/src/neo/SmartContract/ApplicationEngine.Enumerator.cs b/src/neo/SmartContract/ApplicationEngine.Enumerator.cs index 02f1409310..765bdaa901 100644 --- a/src/neo/SmartContract/ApplicationEngine.Enumerator.cs +++ b/src/neo/SmartContract/ApplicationEngine.Enumerator.cs @@ -8,10 +8,10 @@ namespace Neo.SmartContract { partial class ApplicationEngine { - public static readonly InteropDescriptor System_Enumerator_Create = Register("System.Enumerator.Create", nameof(CreateEnumerator), 0_00000400, TriggerType.All, CallFlags.None, false); - public static readonly InteropDescriptor System_Enumerator_Next = Register("System.Enumerator.Next", nameof(EnumeratorNext), 0_01000000, TriggerType.All, CallFlags.None, false); - public static readonly InteropDescriptor System_Enumerator_Value = Register("System.Enumerator.Value", nameof(EnumeratorValue), 0_00000400, TriggerType.All, CallFlags.None, false); - public static readonly InteropDescriptor System_Enumerator_Concat = Register("System.Enumerator.Concat", nameof(ConcatEnumerators), 0_00000400, TriggerType.All, CallFlags.None, false); + public static readonly InteropDescriptor System_Enumerator_Create = Register("System.Enumerator.Create", nameof(CreateEnumerator), 0_00000400, CallFlags.None, false); + public static readonly InteropDescriptor System_Enumerator_Next = Register("System.Enumerator.Next", nameof(EnumeratorNext), 0_01000000, CallFlags.None, false); + public static readonly InteropDescriptor System_Enumerator_Value = Register("System.Enumerator.Value", nameof(EnumeratorValue), 0_00000400, CallFlags.None, false); + public static readonly InteropDescriptor System_Enumerator_Concat = Register("System.Enumerator.Concat", nameof(ConcatEnumerators), 0_00000400, CallFlags.None, false); internal IEnumerator CreateEnumerator(StackItem item) { diff --git a/src/neo/SmartContract/ApplicationEngine.Iterator.cs b/src/neo/SmartContract/ApplicationEngine.Iterator.cs index c902c50979..cfe5509e0a 100644 --- a/src/neo/SmartContract/ApplicationEngine.Iterator.cs +++ b/src/neo/SmartContract/ApplicationEngine.Iterator.cs @@ -8,11 +8,11 @@ namespace Neo.SmartContract { partial class ApplicationEngine { - public static readonly InteropDescriptor System_Iterator_Create = Register("System.Iterator.Create", nameof(CreateIterator), 0_00000400, TriggerType.All, CallFlags.None, false); - public static readonly InteropDescriptor System_Iterator_Key = Register("System.Iterator.Key", nameof(IteratorKey), 0_00000400, TriggerType.All, CallFlags.None, false); - public static readonly InteropDescriptor System_Iterator_Keys = Register("System.Iterator.Keys", nameof(IteratorKeys), 0_00000400, TriggerType.All, CallFlags.None, false); - public static readonly InteropDescriptor System_Iterator_Values = Register("System.Iterator.Values", nameof(IteratorValues), 0_00000400, TriggerType.All, CallFlags.None, false); - public static readonly InteropDescriptor System_Iterator_Concat = Register("System.Iterator.Concat", nameof(ConcatIterators), 0_00000400, TriggerType.All, CallFlags.None, false); + public static readonly InteropDescriptor System_Iterator_Create = Register("System.Iterator.Create", nameof(CreateIterator), 0_00000400, CallFlags.None, false); + public static readonly InteropDescriptor System_Iterator_Key = Register("System.Iterator.Key", nameof(IteratorKey), 0_00000400, CallFlags.None, false); + public static readonly InteropDescriptor System_Iterator_Keys = Register("System.Iterator.Keys", nameof(IteratorKeys), 0_00000400, CallFlags.None, false); + public static readonly InteropDescriptor System_Iterator_Values = Register("System.Iterator.Values", nameof(IteratorValues), 0_00000400, CallFlags.None, false); + public static readonly InteropDescriptor System_Iterator_Concat = Register("System.Iterator.Concat", nameof(ConcatIterators), 0_00000400, CallFlags.None, false); internal IIterator CreateIterator(StackItem item) { diff --git a/src/neo/SmartContract/ApplicationEngine.Json.cs b/src/neo/SmartContract/ApplicationEngine.Json.cs index 047ff2920f..491e1365b2 100644 --- a/src/neo/SmartContract/ApplicationEngine.Json.cs +++ b/src/neo/SmartContract/ApplicationEngine.Json.cs @@ -5,8 +5,8 @@ namespace Neo.SmartContract { partial class ApplicationEngine { - public static readonly InteropDescriptor System_Json_Serialize = Register("System.Json.Serialize", nameof(JsonSerialize), 0_00100000, TriggerType.All, CallFlags.None, true); - public static readonly InteropDescriptor System_Json_Deserialize = Register("System.Json.Deserialize", nameof(JsonDeserialize), 0_00500000, TriggerType.All, CallFlags.None, true); + public static readonly InteropDescriptor System_Json_Serialize = Register("System.Json.Serialize", nameof(JsonSerialize), 0_00100000, CallFlags.None, true); + public static readonly InteropDescriptor System_Json_Deserialize = Register("System.Json.Deserialize", nameof(JsonDeserialize), 0_00500000, CallFlags.None, true); internal byte[] JsonSerialize(StackItem item) { diff --git a/src/neo/SmartContract/ApplicationEngine.Native.cs b/src/neo/SmartContract/ApplicationEngine.Native.cs index 7ea7736745..9cc38c369b 100644 --- a/src/neo/SmartContract/ApplicationEngine.Native.cs +++ b/src/neo/SmartContract/ApplicationEngine.Native.cs @@ -6,8 +6,8 @@ namespace Neo.SmartContract { partial class ApplicationEngine { - public static readonly InteropDescriptor Neo_Native_Deploy = Register("Neo.Native.Deploy", nameof(DeployNativeContracts), 0, TriggerType.Application, CallFlags.AllowModifyStates, false); - public static readonly InteropDescriptor Neo_Native_Call = Register("Neo.Native.Call", nameof(CallNativeContract), 0, TriggerType.System | TriggerType.Application, CallFlags.None, false); + public static readonly InteropDescriptor Neo_Native_Deploy = Register("Neo.Native.Deploy", nameof(DeployNativeContracts), 0, CallFlags.AllowModifyStates, false); + public static readonly InteropDescriptor Neo_Native_Call = Register("Neo.Native.Call", nameof(CallNativeContract), 0, CallFlags.None, false); internal void DeployNativeContracts() { diff --git a/src/neo/SmartContract/ApplicationEngine.Runtime.cs b/src/neo/SmartContract/ApplicationEngine.Runtime.cs index c670971937..9713d03893 100644 --- a/src/neo/SmartContract/ApplicationEngine.Runtime.cs +++ b/src/neo/SmartContract/ApplicationEngine.Runtime.cs @@ -14,19 +14,19 @@ partial class ApplicationEngine public const int MaxEventName = 32; public const int MaxNotificationSize = 1024; - public static readonly InteropDescriptor System_Runtime_Platform = Register("System.Runtime.Platform", nameof(GetPlatform), 0_00000250, TriggerType.All, CallFlags.None, true); - public static readonly InteropDescriptor System_Runtime_GetTrigger = Register("System.Runtime.GetTrigger", nameof(Trigger), 0_00000250, TriggerType.All, CallFlags.None, true); - public static readonly InteropDescriptor System_Runtime_GetTime = Register("System.Runtime.GetTime", nameof(GetTime), 0_00000250, TriggerType.Application, CallFlags.AllowStates, true); - public static readonly InteropDescriptor System_Runtime_GetScriptContainer = Register("System.Runtime.GetScriptContainer", nameof(GetScriptContainer), 0_00000250, TriggerType.All, CallFlags.None, true); - public static readonly InteropDescriptor System_Runtime_GetExecutingScriptHash = Register("System.Runtime.GetExecutingScriptHash", nameof(CurrentScriptHash), 0_00000400, TriggerType.All, CallFlags.None, true); - public static readonly InteropDescriptor System_Runtime_GetCallingScriptHash = Register("System.Runtime.GetCallingScriptHash", nameof(CallingScriptHash), 0_00000400, TriggerType.All, CallFlags.None, true); - public static readonly InteropDescriptor System_Runtime_GetEntryScriptHash = Register("System.Runtime.GetEntryScriptHash", nameof(EntryScriptHash), 0_00000400, TriggerType.All, CallFlags.None, true); - public static readonly InteropDescriptor System_Runtime_CheckWitness = Register("System.Runtime.CheckWitness", nameof(CheckWitness), 0_00030000, TriggerType.All, CallFlags.AllowStates, true); - public static readonly InteropDescriptor System_Runtime_GetInvocationCounter = Register("System.Runtime.GetInvocationCounter", nameof(GetInvocationCounter), 0_00000400, TriggerType.All, CallFlags.None, true); - public static readonly InteropDescriptor System_Runtime_Log = Register("System.Runtime.Log", nameof(RuntimeLog), 0_01000000, TriggerType.All, CallFlags.AllowNotify, false); - public static readonly InteropDescriptor System_Runtime_Notify = Register("System.Runtime.Notify", nameof(RuntimeNotify), 0_01000000, TriggerType.All, CallFlags.AllowNotify, false); - public static readonly InteropDescriptor System_Runtime_GetNotifications = Register("System.Runtime.GetNotifications", nameof(GetNotifications), 0_00010000, TriggerType.All, CallFlags.None, true); - public static readonly InteropDescriptor System_Runtime_GasLeft = Register("System.Runtime.GasLeft", nameof(GasLeft), 0_00000400, TriggerType.All, CallFlags.None, true); + public static readonly InteropDescriptor System_Runtime_Platform = Register("System.Runtime.Platform", nameof(GetPlatform), 0_00000250, CallFlags.None, true); + public static readonly InteropDescriptor System_Runtime_GetTrigger = Register("System.Runtime.GetTrigger", nameof(Trigger), 0_00000250, CallFlags.None, true); + public static readonly InteropDescriptor System_Runtime_GetTime = Register("System.Runtime.GetTime", nameof(GetTime), 0_00000250, CallFlags.AllowStates, true); + public static readonly InteropDescriptor System_Runtime_GetScriptContainer = Register("System.Runtime.GetScriptContainer", nameof(GetScriptContainer), 0_00000250, CallFlags.None, true); + public static readonly InteropDescriptor System_Runtime_GetExecutingScriptHash = Register("System.Runtime.GetExecutingScriptHash", nameof(CurrentScriptHash), 0_00000400, CallFlags.None, true); + public static readonly InteropDescriptor System_Runtime_GetCallingScriptHash = Register("System.Runtime.GetCallingScriptHash", nameof(CallingScriptHash), 0_00000400, CallFlags.None, true); + public static readonly InteropDescriptor System_Runtime_GetEntryScriptHash = Register("System.Runtime.GetEntryScriptHash", nameof(EntryScriptHash), 0_00000400, CallFlags.None, true); + public static readonly InteropDescriptor System_Runtime_CheckWitness = Register("System.Runtime.CheckWitness", nameof(CheckWitness), 0_00030000, CallFlags.AllowStates, true); + public static readonly InteropDescriptor System_Runtime_GetInvocationCounter = Register("System.Runtime.GetInvocationCounter", nameof(GetInvocationCounter), 0_00000400, CallFlags.None, true); + public static readonly InteropDescriptor System_Runtime_Log = Register("System.Runtime.Log", nameof(RuntimeLog), 0_01000000, CallFlags.AllowNotify, false); + public static readonly InteropDescriptor System_Runtime_Notify = Register("System.Runtime.Notify", nameof(RuntimeNotify), 0_01000000, CallFlags.AllowNotify, false); + public static readonly InteropDescriptor System_Runtime_GetNotifications = Register("System.Runtime.GetNotifications", nameof(GetNotifications), 0_00010000, CallFlags.None, true); + public static readonly InteropDescriptor System_Runtime_GasLeft = Register("System.Runtime.GasLeft", nameof(GasLeft), 0_00000400, CallFlags.None, true); private static bool CheckItemForNotification(StackItem state) { diff --git a/src/neo/SmartContract/ApplicationEngine.Storage.cs b/src/neo/SmartContract/ApplicationEngine.Storage.cs index 97ccb5494c..f790b6f7e7 100644 --- a/src/neo/SmartContract/ApplicationEngine.Storage.cs +++ b/src/neo/SmartContract/ApplicationEngine.Storage.cs @@ -12,14 +12,14 @@ partial class ApplicationEngine public const int MaxStorageKeySize = 64; public const int MaxStorageValueSize = ushort.MaxValue; - public static readonly InteropDescriptor System_Storage_GetContext = Register("System.Storage.GetContext", nameof(GetStorageContext), 0_00000400, TriggerType.Application, CallFlags.AllowStates, false); - public static readonly InteropDescriptor System_Storage_GetReadOnlyContext = Register("System.Storage.GetReadOnlyContext", nameof(GetReadOnlyContext), 0_00000400, TriggerType.Application, CallFlags.AllowStates, false); - public static readonly InteropDescriptor System_Storage_AsReadOnly = Register("System.Storage.AsReadOnly", nameof(AsReadOnly), 0_00000400, TriggerType.Application, CallFlags.AllowStates, false); - public static readonly InteropDescriptor System_Storage_Get = Register("System.Storage.Get", nameof(Get), 0_01000000, TriggerType.Application, CallFlags.AllowStates, false); - public static readonly InteropDescriptor System_Storage_Find = Register("System.Storage.Find", nameof(Find), 0_01000000, TriggerType.Application, CallFlags.AllowStates, false); - public static readonly InteropDescriptor System_Storage_Put = Register("System.Storage.Put", nameof(Put), 0, TriggerType.Application, CallFlags.AllowModifyStates, false); - public static readonly InteropDescriptor System_Storage_PutEx = Register("System.Storage.PutEx", nameof(PutEx), 0, TriggerType.Application, CallFlags.AllowModifyStates, false); - public static readonly InteropDescriptor System_Storage_Delete = Register("System.Storage.Delete", nameof(Delete), 1 * StoragePrice, TriggerType.Application, CallFlags.AllowModifyStates, false); + public static readonly InteropDescriptor System_Storage_GetContext = Register("System.Storage.GetContext", nameof(GetStorageContext), 0_00000400, CallFlags.AllowStates, false); + public static readonly InteropDescriptor System_Storage_GetReadOnlyContext = Register("System.Storage.GetReadOnlyContext", nameof(GetReadOnlyContext), 0_00000400, CallFlags.AllowStates, false); + public static readonly InteropDescriptor System_Storage_AsReadOnly = Register("System.Storage.AsReadOnly", nameof(AsReadOnly), 0_00000400, CallFlags.AllowStates, false); + public static readonly InteropDescriptor System_Storage_Get = Register("System.Storage.Get", nameof(Get), 0_01000000, CallFlags.AllowStates, false); + public static readonly InteropDescriptor System_Storage_Find = Register("System.Storage.Find", nameof(Find), 0_01000000, CallFlags.AllowStates, false); + public static readonly InteropDescriptor System_Storage_Put = Register("System.Storage.Put", nameof(Put), 0, CallFlags.AllowModifyStates, false); + public static readonly InteropDescriptor System_Storage_PutEx = Register("System.Storage.PutEx", nameof(PutEx), 0, CallFlags.AllowModifyStates, false); + public static readonly InteropDescriptor System_Storage_Delete = Register("System.Storage.Delete", nameof(Delete), 1 * StoragePrice, CallFlags.AllowModifyStates, false); internal StorageContext GetStorageContext() { diff --git a/src/neo/SmartContract/ApplicationEngine.cs b/src/neo/SmartContract/ApplicationEngine.cs index a3a1078a37..81c462f9de 100644 --- a/src/neo/SmartContract/ApplicationEngine.cs +++ b/src/neo/SmartContract/ApplicationEngine.cs @@ -220,8 +220,6 @@ public override void Dispose() protected override void OnSysCall(uint method) { InteropDescriptor descriptor = services[method]; - if (!descriptor.AllowedTriggers.HasFlag(Trigger)) - throw new InvalidOperationException($"Cannot call this SYSCALL with the trigger {Trigger}."); ExecutionContextState state = CurrentContext.GetState(); if (!state.CallFlags.HasFlag(descriptor.RequiredCallFlags)) throw new InvalidOperationException($"Cannot call this SYSCALL with the flag {state.CallFlags}."); @@ -263,11 +261,11 @@ private static Block CreateDummyBlock(StoreView snapshot) }; } - private static InteropDescriptor Register(string name, string handler, long fixedPrice, TriggerType allowedTriggers, CallFlags requiredCallFlags, bool allowCallback) + private static InteropDescriptor Register(string name, string handler, long fixedPrice, CallFlags requiredCallFlags, bool allowCallback) { MethodInfo method = typeof(ApplicationEngine).GetMethod(handler, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) ?? typeof(ApplicationEngine).GetProperty(handler, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).GetMethod; - InteropDescriptor descriptor = new InteropDescriptor(name, method, fixedPrice, allowedTriggers, requiredCallFlags, allowCallback); + InteropDescriptor descriptor = new InteropDescriptor(name, method, fixedPrice, requiredCallFlags, allowCallback); services ??= new Dictionary(); services.Add(descriptor.Hash, descriptor); return descriptor; diff --git a/src/neo/SmartContract/Helper.cs b/src/neo/SmartContract/Helper.cs index 54f3c9eb2e..b2cdb416a2 100644 --- a/src/neo/SmartContract/Helper.cs +++ b/src/neo/SmartContract/Helper.cs @@ -162,7 +162,7 @@ internal static bool VerifyWitnesses(this IVerifiable verifiable, StoreView snap if (hashes[i] != verifiable.Witnesses[i].ScriptHash) return false; offset = 0; } - using (ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Verification, verifiable, snapshot, gas)) + using (ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Verification, verifiable, snapshot.Clone(), gas)) { engine.LoadScript(verification, CallFlags.ReadOnly).InstructionPointer = offset; engine.LoadScript(verifiable.Witnesses[i].InvocationScript, CallFlags.None); diff --git a/src/neo/SmartContract/InteropDescriptor.cs b/src/neo/SmartContract/InteropDescriptor.cs index b41d2ec57a..5a3b833f18 100644 --- a/src/neo/SmartContract/InteropDescriptor.cs +++ b/src/neo/SmartContract/InteropDescriptor.cs @@ -13,18 +13,16 @@ public class InteropDescriptor internal MethodInfo Handler { get; } internal InteropParameterDescriptor[] Parameters { get; } public long FixedPrice { get; } - public TriggerType AllowedTriggers { get; } public CallFlags RequiredCallFlags { get; } public bool AllowCallback { get; } - internal InteropDescriptor(string name, MethodInfo handler, long fixedPrice, TriggerType allowedTriggers, CallFlags requiredCallFlags, bool allowCallback) + internal InteropDescriptor(string name, MethodInfo handler, long fixedPrice, CallFlags requiredCallFlags, bool allowCallback) { this.Name = name; this.Hash = BitConverter.ToUInt32(Encoding.ASCII.GetBytes(name).Sha256(), 0); this.Handler = handler; this.Parameters = handler.GetParameters().Select(p => new InteropParameterDescriptor(p)).ToArray(); this.FixedPrice = fixedPrice; - this.AllowedTriggers = allowedTriggers; this.RequiredCallFlags = requiredCallFlags; this.AllowCallback = allowCallback; } From b47157669cabc9c4f0f4ff56cf4fe2a82905bcfe Mon Sep 17 00:00:00 2001 From: Luchuan Date: Thu, 16 Jul 2020 20:33:35 +0800 Subject: [PATCH 08/12] fix validatorscount (#1770) Co-authored-by: Tommo-L --- src/neo/ProtocolSettings.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/neo/ProtocolSettings.cs b/src/neo/ProtocolSettings.cs index 79a422f060..7ac2f16273 100644 --- a/src/neo/ProtocolSettings.cs +++ b/src/neo/ProtocolSettings.cs @@ -47,9 +47,9 @@ private ProtocolSettings(IConfigurationSection section) { this.Magic = section.GetValue("Magic", 0x4F454Eu); this.AddressVersion = section.GetValue("AddressVersion", (byte)0x35); - IConfigurationSection section_sv = section.GetSection("StandbyValidators"); - if (section_sv.Exists()) - this.StandbyCommittee = section_sv.GetChildren().Select(p => p.Get()).ToArray(); + IConfigurationSection section_sc = section.GetSection("StandbyCommittee"); + if (section_sc.Exists()) + this.StandbyCommittee = section_sc.GetChildren().Select(p => p.Get()).ToArray(); else this.StandbyCommittee = new[] { From 6c01017f6c905b9a7b5bdc4dd1a1985f3b34276e Mon Sep 17 00:00:00 2001 From: Shargon Date: Fri, 17 Jul 2020 16:29:11 +0200 Subject: [PATCH 09/12] workflows: use checkout action v2 (#1775) * Update git workflow * Update .github/workflows/main.yml Co-authored-by: Erik Zhang Co-authored-by: Erik Zhang --- .github/workflows/main.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index a4b5d0a845..bef6f53e43 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v1 + uses: actions/checkout@v2 - name: Setup .NET Core uses: actions/setup-dotnet@v1 with: @@ -39,7 +39,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v1 + uses: actions/checkout@v2 - name: Setup .NET Core uses: actions/setup-dotnet@v1 with: @@ -61,7 +61,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v1 + uses: actions/checkout@v2 - name: Setup .NET Core uses: actions/setup-dotnet@v1 with: @@ -79,7 +79,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v1 + uses: actions/checkout@v2 - name: Get version id: get_version run: | From da6be43f82e680956835d6b1d4203a5e0d95e7f1 Mon Sep 17 00:00:00 2001 From: Shargon Date: Fri, 17 Jul 2020 16:36:43 +0200 Subject: [PATCH 10/12] Add cache to native contract executions V2 (#1766) * cache v2 * More optimizations * Policy contract optimization * Remove interporable variable * Two more * Add Set * Optimizations * Optimize Co-authored-by: erikzhang --- src/neo/Ledger/StorageItem.cs | 61 +++++++++++++++---- .../SmartContract/Native/PolicyContract.cs | 36 +++++------ .../SmartContract/Native/Tokens/NeoToken.cs | 14 ++--- .../SmartContract/Native/Tokens/Nep5Token.cs | 15 ++--- 4 files changed, 77 insertions(+), 49 deletions(-) diff --git a/src/neo/Ledger/StorageItem.cs b/src/neo/Ledger/StorageItem.cs index 801f0c72a0..5304d926df 100644 --- a/src/neo/Ledger/StorageItem.cs +++ b/src/neo/Ledger/StorageItem.cs @@ -1,13 +1,16 @@ using Neo.IO; using Neo.SmartContract; +using System; +using System.Collections.Generic; using System.IO; +using System.Numerics; namespace Neo.Ledger { public class StorageItem : ICloneable, ISerializable { private byte[] value; - private IInteroperable interoperable; + private object cache; public bool IsConstant; public int Size => Value.GetVarSize() + sizeof(bool); @@ -16,20 +19,23 @@ public byte[] Value { get { - if (value is null && interoperable != null) - value = BinarySerializer.Serialize(interoperable.ToStackItem(null), 4096); - return value; + return value ??= cache switch + { + BigInteger bi => bi.ToByteArrayStandard(), + IInteroperable interoperable => BinarySerializer.Serialize(interoperable.ToStackItem(null), 4096), + IReadOnlyCollection list => list.ToByteArray(), + null => null, + _ => throw new InvalidCastException() + }; } set { - interoperable = null; this.value = value; + cache = null; } } - public StorageItem() - { - } + public StorageItem() { } public StorageItem(byte[] value, bool isConstant = false) { @@ -37,12 +43,23 @@ public StorageItem(byte[] value, bool isConstant = false) this.IsConstant = isConstant; } + public StorageItem(BigInteger value, bool isConstant = false) + { + this.cache = value; + this.IsConstant = isConstant; + } + public StorageItem(IInteroperable interoperable, bool isConstant = false) { - this.interoperable = interoperable; + this.cache = interoperable; this.IsConstant = isConstant; } + public void Add(BigInteger integer) + { + Set(this + integer); + } + StorageItem ICloneable.Clone() { return new StorageItem @@ -66,13 +83,21 @@ void ICloneable.FromReplica(StorageItem replica) public T GetInteroperable() where T : IInteroperable, new() { - if (interoperable is null) + if (cache is null) { - interoperable = new T(); + var interoperable = new T(); interoperable.FromStackItem(BinarySerializer.Deserialize(value, 16, 34)); + cache = interoperable; } value = null; - return (T)interoperable; + return (T)cache; + } + + public List GetSerializableList() where T : ISerializable, new() + { + cache ??= new List(value.AsSerializableArray()); + value = null; + return (List)cache; } public void Serialize(BinaryWriter writer) @@ -80,5 +105,17 @@ public void Serialize(BinaryWriter writer) writer.WriteVarBytes(Value); writer.Write(IsConstant); } + + public void Set(BigInteger integer) + { + cache = integer; + value = null; + } + + public static implicit operator BigInteger(StorageItem item) + { + item.cache ??= new BigInteger(item.value); + return (BigInteger)item.cache; + } } } diff --git a/src/neo/SmartContract/Native/PolicyContract.cs b/src/neo/SmartContract/Native/PolicyContract.cs index 65c690424e..872e9ec666 100644 --- a/src/neo/SmartContract/Native/PolicyContract.cs +++ b/src/neo/SmartContract/Native/PolicyContract.cs @@ -6,6 +6,7 @@ using Neo.SmartContract.Manifest; using System; using System.Collections.Generic; +using System.Numerics; namespace Neo.SmartContract.Native { @@ -58,31 +59,31 @@ internal override void Initialize(ApplicationEngine engine) [ContractMethod(0_01000000, CallFlags.AllowStates)] public uint GetMaxTransactionsPerBlock(StoreView snapshot) { - return BitConverter.ToUInt32(snapshot.Storages[CreateStorageKey(Prefix_MaxTransactionsPerBlock)].Value, 0); + return (uint)(BigInteger)snapshot.Storages[CreateStorageKey(Prefix_MaxTransactionsPerBlock)]; } [ContractMethod(0_01000000, CallFlags.AllowStates)] public uint GetMaxBlockSize(StoreView snapshot) { - return BitConverter.ToUInt32(snapshot.Storages[CreateStorageKey(Prefix_MaxBlockSize)].Value, 0); + return (uint)(BigInteger)snapshot.Storages[CreateStorageKey(Prefix_MaxBlockSize)]; } [ContractMethod(0_01000000, CallFlags.AllowStates)] public long GetMaxBlockSystemFee(StoreView snapshot) { - return BitConverter.ToInt64(snapshot.Storages[CreateStorageKey(Prefix_MaxBlockSystemFee)].Value, 0); + return (long)(BigInteger)snapshot.Storages[CreateStorageKey(Prefix_MaxBlockSystemFee)]; } [ContractMethod(0_01000000, CallFlags.AllowStates)] public long GetFeePerByte(StoreView snapshot) { - return BitConverter.ToInt64(snapshot.Storages[CreateStorageKey(Prefix_FeePerByte)].Value, 0); + return (long)(BigInteger)snapshot.Storages[CreateStorageKey(Prefix_FeePerByte)]; } [ContractMethod(0_01000000, CallFlags.AllowStates)] public UInt160[] GetBlockedAccounts(StoreView snapshot) { - return snapshot.Storages[CreateStorageKey(Prefix_BlockedAccounts)].Value.AsSerializableArray(); + return snapshot.Storages[CreateStorageKey(Prefix_BlockedAccounts)].GetSerializableList().ToArray(); } [ContractMethod(0_03000000, CallFlags.AllowModifyStates)] @@ -91,7 +92,7 @@ private bool SetMaxBlockSize(ApplicationEngine engine, uint value) if (!CheckCommittees(engine)) return false; if (Network.P2P.Message.PayloadMaxSize <= value) return false; StorageItem storage = engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_MaxBlockSize)); - storage.Value = BitConverter.GetBytes(value); + storage.Set(value); return true; } @@ -100,7 +101,7 @@ private bool SetMaxTransactionsPerBlock(ApplicationEngine engine, uint value) { if (!CheckCommittees(engine)) return false; StorageItem storage = engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_MaxTransactionsPerBlock)); - storage.Value = BitConverter.GetBytes(value); + storage.Set(value); return true; } @@ -110,7 +111,7 @@ private bool SetMaxBlockSystemFee(ApplicationEngine engine, long value) if (!CheckCommittees(engine)) return false; if (value <= 4007600) return false; StorageItem storage = engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_MaxBlockSystemFee)); - storage.Value = BitConverter.GetBytes(value); + storage.Set(value); return true; } @@ -119,7 +120,7 @@ private bool SetFeePerByte(ApplicationEngine engine, long value) { if (!CheckCommittees(engine)) return false; StorageItem storage = engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_FeePerByte)); - storage.Value = BitConverter.GetBytes(value); + storage.Set(value); return true; } @@ -129,10 +130,10 @@ private bool BlockAccount(ApplicationEngine engine, UInt160 account) if (!CheckCommittees(engine)) return false; StorageKey key = CreateStorageKey(Prefix_BlockedAccounts); StorageItem storage = engine.Snapshot.Storages[key]; - SortedSet accounts = new SortedSet(storage.Value.AsSerializableArray()); - if (!accounts.Add(account)) return false; - storage = engine.Snapshot.Storages.GetAndChange(key); - storage.Value = accounts.ToByteArray(); + List accounts = storage.GetSerializableList(); + if (accounts.Contains(account)) return false; + engine.Snapshot.Storages.GetAndChange(key); + accounts.Add(account); return true; } @@ -142,10 +143,11 @@ private bool UnblockAccount(ApplicationEngine engine, UInt160 account) if (!CheckCommittees(engine)) return false; StorageKey key = CreateStorageKey(Prefix_BlockedAccounts); StorageItem storage = engine.Snapshot.Storages[key]; - SortedSet accounts = new SortedSet(storage.Value.AsSerializableArray()); - if (!accounts.Remove(account)) return false; - storage = engine.Snapshot.Storages.GetAndChange(key); - storage.Value = accounts.ToByteArray(); + List accounts = storage.GetSerializableList(); + int index = accounts.IndexOf(account); + if (index < 0) return false; + engine.Snapshot.Storages.GetAndChange(key); + accounts.RemoveAt(index); return true; } } diff --git a/src/neo/SmartContract/Native/Tokens/NeoToken.cs b/src/neo/SmartContract/Native/Tokens/NeoToken.cs index fa86ca70d5..4024de5690 100644 --- a/src/neo/SmartContract/Native/Tokens/NeoToken.cs +++ b/src/neo/SmartContract/Native/Tokens/NeoToken.cs @@ -44,9 +44,7 @@ protected override void OnBalanceChanging(ApplicationEngine engine, UInt160 acco if (state.VoteTo != null) { engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_Candidate).Add(state.VoteTo)).GetInteroperable().Votes += amount; - StorageItem item = engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_VotersCount)); - BigInteger votersCount = new BigInteger(item.Value) + amount; - item.Value = votersCount.ToByteArray(); + engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_VotersCount)).Add(amount); } } @@ -150,12 +148,10 @@ private bool Vote(ApplicationEngine engine, UInt160 account, ECPoint voteTo) if (state_account.VoteTo is null ^ voteTo is null) { StorageItem item = engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_VotersCount)); - BigInteger votersCount = new BigInteger(item.Value); if (state_account.VoteTo is null) - votersCount += state_account.Balance; + item.Add(state_account.Balance); else - votersCount -= state_account.Balance; - item.Value = votersCount.ToByteArray(); + item.Add(-state_account.Balance); } if (state_account.VoteTo != null) { @@ -210,7 +206,7 @@ public UInt160 GetCommitteeAddress(StoreView snapshot) private IEnumerable GetCommitteeMembers(StoreView snapshot) { - decimal votersCount = (decimal)new BigInteger(snapshot.Storages[CreateStorageKey(Prefix_VotersCount)].Value); + decimal votersCount = (decimal)(BigInteger)snapshot.Storages[CreateStorageKey(Prefix_VotersCount)]; decimal VoterTurnout = votersCount / (decimal)TotalAmount; if (VoterTurnout < EffectiveVoterTurnout) return Blockchain.StandbyCommittee; @@ -225,7 +221,7 @@ public ECPoint[] GetNextBlockValidators(StoreView snapshot) { StorageItem storage = snapshot.Storages.TryGet(CreateStorageKey(Prefix_NextValidators)); if (storage is null) return Blockchain.StandbyValidators; - return storage.Value.AsSerializableArray(); + return storage.GetSerializableList().ToArray(); } public class NeoAccountState : AccountState diff --git a/src/neo/SmartContract/Native/Tokens/Nep5Token.cs b/src/neo/SmartContract/Native/Tokens/Nep5Token.cs index 111b69d4ce..ed4308b73c 100644 --- a/src/neo/SmartContract/Native/Tokens/Nep5Token.cs +++ b/src/neo/SmartContract/Native/Tokens/Nep5Token.cs @@ -66,13 +66,8 @@ internal protected virtual void Mint(ApplicationEngine engine, UInt160 account, TState state = storage.GetInteroperable(); OnBalanceChanging(engine, account, state, amount); state.Balance += amount; - storage = engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_TotalSupply), () => new StorageItem - { - Value = BigInteger.Zero.ToByteArrayStandard() - }); - BigInteger totalSupply = new BigInteger(storage.Value); - totalSupply += amount; - storage.Value = totalSupply.ToByteArrayStandard(); + storage = engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_TotalSupply), () => new StorageItem(BigInteger.Zero)); + storage.Add(amount); engine.SendNotification(Hash, "Transfer", new Array { StackItem.Null, account.ToArray(), amount }); } @@ -90,9 +85,7 @@ internal protected virtual void Burn(ApplicationEngine engine, UInt160 account, else state.Balance -= amount; storage = engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_TotalSupply)); - BigInteger totalSupply = new BigInteger(storage.Value); - totalSupply -= amount; - storage.Value = totalSupply.ToByteArrayStandard(); + storage.Add(-amount); engine.SendNotification(Hash, "Transfer", new Array { account.ToArray(), StackItem.Null, amount }); } @@ -101,7 +94,7 @@ public virtual BigInteger TotalSupply(StoreView snapshot) { StorageItem storage = snapshot.Storages.TryGet(CreateStorageKey(Prefix_TotalSupply)); if (storage is null) return BigInteger.Zero; - return new BigInteger(storage.Value); + return storage; } [ContractMethod(0_01000000, CallFlags.AllowStates)] From 85543c701d6eacd9d88969a17c45ca440fe8e262 Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Sat, 18 Jul 2020 17:24:39 +0800 Subject: [PATCH 11/12] Optimize attributes (#1774) --- src/neo/Network/P2P/Payloads/Transaction.cs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/neo/Network/P2P/Payloads/Transaction.cs b/src/neo/Network/P2P/Payloads/Transaction.cs index 8c4071379c..1671b70085 100644 --- a/src/neo/Network/P2P/Payloads/Transaction.cs +++ b/src/neo/Network/P2P/Payloads/Transaction.cs @@ -42,10 +42,11 @@ public class Transaction : IEquatable, IInventory, IInteroperable sizeof(long) + //NetworkFee sizeof(uint); //ValidUntilBlock + private Dictionary _attributesCache; public TransactionAttribute[] Attributes { get => attributes; - set { attributes = value; _hash = null; _size = 0; } + set { attributes = value; _attributesCache = null; _hash = null; _size = 0; } } /// @@ -219,6 +220,18 @@ void IInteroperable.FromStackItem(StackItem stackItem) throw new NotSupportedException(); } + public T GetAttribute() where T : TransactionAttribute + { + return GetAttributes()?.First(); + } + + public T[] GetAttributes() where T : TransactionAttribute + { + _attributesCache ??= attributes.GroupBy(p => p.GetType()).ToDictionary(p => p.Key, p => (TransactionAttribute[])p.OfType().ToArray()); + _attributesCache.TryGetValue(typeof(T), out var result); + return (T[])result; + } + public override int GetHashCode() { return Hash.GetHashCode(); From 9d83a64ee5f0c2a5efe4295b4ba03c1fe26a2087 Mon Sep 17 00:00:00 2001 From: Shargon Date: Sat, 18 Jul 2020 11:57:03 +0200 Subject: [PATCH 12/12] Add length before compression data (#1768) * Add length before compression * Optimize * Fix UT * Add UT * Add UT Co-authored-by: erikzhang --- src/neo/IO/Helper.cs | 14 ++++++------ tests/neo.UnitTests/IO/UT_IOHelper.cs | 31 +++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 7 deletions(-) diff --git a/src/neo/IO/Helper.cs b/src/neo/IO/Helper.cs index e165016139..e871bbaedf 100644 --- a/src/neo/IO/Helper.cs +++ b/src/neo/IO/Helper.cs @@ -1,6 +1,7 @@ using K4os.Compression.LZ4; using System; using System.Buffers; +using System.Buffers.Binary; using System.Collections.Generic; using System.IO; using System.Linq; @@ -69,20 +70,19 @@ public static byte[] CompressLz4(this byte[] data) int maxLength = LZ4Codec.MaximumOutputSize(data.Length); using var buffer = MemoryPool.Shared.Rent(maxLength); int length = LZ4Codec.Encode(data, buffer.Memory.Span); - byte[] result = new byte[length]; - buffer.Memory[..length].CopyTo(result); + byte[] result = new byte[sizeof(uint) + length]; + BinaryPrimitives.WriteInt32LittleEndian(result, data.Length); + buffer.Memory[..length].CopyTo(result.AsMemory(4)); return result; } public static byte[] DecompressLz4(this byte[] data, int maxOutput) { - var maxDecompressDataLength = data.Length * 255; - if (maxDecompressDataLength > 0) maxOutput = Math.Min(maxOutput, maxDecompressDataLength); - using var buffer = MemoryPool.Shared.Rent(maxOutput); - int length = LZ4Codec.Decode(data, buffer.Memory.Span); + int length = BinaryPrimitives.ReadInt32LittleEndian(data); if (length < 0 || length > maxOutput) throw new FormatException(); byte[] result = new byte[length]; - buffer.Memory[..length].CopyTo(result); + if (LZ4Codec.Decode(data.AsSpan(4), result) != length) + throw new FormatException(); return result; } diff --git a/tests/neo.UnitTests/IO/UT_IOHelper.cs b/tests/neo.UnitTests/IO/UT_IOHelper.cs index 1128270716..b126b7f485 100644 --- a/tests/neo.UnitTests/IO/UT_IOHelper.cs +++ b/tests/neo.UnitTests/IO/UT_IOHelper.cs @@ -119,6 +119,37 @@ public void TestAsSerializable() } } + [TestMethod] + public void TestCompression() + { + var data = new byte[] { 1, 2, 3, 4 }; + var byteArray = Neo.IO.Helper.CompressLz4(data); + var result = Neo.IO.Helper.DecompressLz4(byteArray, byte.MaxValue); + + CollectionAssert.AreEqual(result, data); + + // Compress + + data = new byte[255]; + for (int x = 0; x < data.Length; x++) data[x] = 1; + + byteArray = Neo.IO.Helper.CompressLz4(data); + result = Neo.IO.Helper.DecompressLz4(byteArray, byte.MaxValue); + + Assert.IsTrue(byteArray.Length < result.Length); + CollectionAssert.AreEqual(result, data); + + // Error max length + + Assert.ThrowsException(() => Neo.IO.Helper.DecompressLz4(byteArray, byte.MaxValue - 1)); + Assert.ThrowsException(() => Neo.IO.Helper.DecompressLz4(byteArray, -1)); + + // Error length + + byteArray[0]++; + Assert.ThrowsException(() => Neo.IO.Helper.DecompressLz4(byteArray, byte.MaxValue)); + } + [TestMethod] public void TestAsSerializableArray() {