From d2759168c2695b7211dd9fec921d3ea601c8effb Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Mon, 22 Jun 2020 19:15:18 +0800 Subject: [PATCH 01/32] Allow call from native contract (#1700) --- src/neo/SmartContract/ApplicationEngine.cs | 41 +++++++++++++++++++ .../InteropParameterDescriptor.cs | 16 +++++--- 2 files changed, 52 insertions(+), 5 deletions(-) diff --git a/src/neo/SmartContract/ApplicationEngine.cs b/src/neo/SmartContract/ApplicationEngine.cs index c1dedd9178..2602397ebc 100644 --- a/src/neo/SmartContract/ApplicationEngine.cs +++ b/src/neo/SmartContract/ApplicationEngine.cs @@ -16,6 +16,12 @@ namespace Neo.SmartContract { public partial class ApplicationEngine : ExecutionEngine { + private class InvocationState + { + public Type ReturnType; + public Delegate Callback; + } + public static event EventHandler Notify; public static event EventHandler Log; @@ -27,6 +33,7 @@ public partial class ApplicationEngine : ExecutionEngine private readonly List notifications = new List(); private readonly List disposables = new List(); private readonly Dictionary invocationCounter = new Dictionary(); + private readonly Dictionary invocationStates = new Dictionary(); public static IReadOnlyDictionary Services => services; public TriggerType Trigger { get; } @@ -55,12 +62,46 @@ internal void AddGas(long gas) throw new InvalidOperationException("Insufficient GAS."); } + internal void CallFromNativeContract(Action onComplete, UInt160 hash, string method, params StackItem[] args) + { + invocationStates.Add(CurrentContext, new InvocationState + { + ReturnType = typeof(void), + Callback = onComplete + }); + CallContract(hash, method, new VMArray(args)); + } + + internal void CallFromNativeContract(Action onComplete, UInt160 hash, string method, params StackItem[] args) + { + invocationStates.Add(CurrentContext, new InvocationState + { + ReturnType = typeof(T), + Callback = onComplete + }); + CallContract(hash, method, new VMArray(args)); + } + protected override void ContextUnloaded(ExecutionContext context) { base.ContextUnloaded(context); if (CurrentContext != null && context.EvaluationStack != CurrentContext.EvaluationStack) if (context.EvaluationStack.Count == 0) Push(StackItem.Null); + if (!(UncaughtException is null)) return; + if (invocationStates.Count == 0) return; + if (!invocationStates.Remove(CurrentContext, out InvocationState state)) return; + switch (state.Callback) + { + case null: + break; + case Action action: + action(); + break; + default: + state.Callback.DynamicInvoke(Convert(Pop(), new InteropParameterDescriptor(state.ReturnType))); + break; + } } protected override void LoadContext(ExecutionContext context) diff --git a/src/neo/SmartContract/InteropParameterDescriptor.cs b/src/neo/SmartContract/InteropParameterDescriptor.cs index f97d7e6c4e..440e4588af 100644 --- a/src/neo/SmartContract/InteropParameterDescriptor.cs +++ b/src/neo/SmartContract/InteropParameterDescriptor.cs @@ -23,6 +23,7 @@ internal class InteropParameterDescriptor [typeof(VM.Types.Pointer)] = p => p, [typeof(VM.Types.Array)] = p => p, [typeof(InteropInterface)] = p => p, + [typeof(bool)] = p => p.ToBoolean(), [typeof(sbyte)] = p => (sbyte)p.GetBigInteger(), [typeof(byte)] = p => (byte)p.GetBigInteger(), [typeof(short)] = p => (short)p.GetBigInteger(), @@ -40,20 +41,25 @@ internal class InteropParameterDescriptor }; public InteropParameterDescriptor(ParameterInfo parameterInfo) + : this(parameterInfo.ParameterType) { - Name = parameterInfo.Name; - Type = parameterInfo.ParameterType; + this.Name = parameterInfo.Name; + } + + public InteropParameterDescriptor(Type type) + { + this.Type = type; if (IsEnum) { - Converter = converters[Type.GetEnumUnderlyingType()]; + Converter = converters[type.GetEnumUnderlyingType()]; } else if (IsArray) { - Converter = converters[Type.GetElementType()]; + Converter = converters[type.GetElementType()]; } else { - IsInterface = !converters.TryGetValue(Type, out var converter); + IsInterface = !converters.TryGetValue(type, out var converter); if (IsInterface) Converter = converters[typeof(InteropInterface)]; else From 8f509db2fac4e30ab9a904ffd9595be4593ad276 Mon Sep 17 00:00:00 2001 From: Shargon Date: Mon, 22 Jun 2020 13:42:55 +0200 Subject: [PATCH 02/32] Fix MethodCallback (#1723) --- src/neo/SmartContract/Callbacks/MethodCallback.cs | 8 ++++---- src/neo/SmartContract/Callbacks/SyscallCallback.cs | 4 ++-- src/neo/SmartContract/Manifest/ContractManifest.cs | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/neo/SmartContract/Callbacks/MethodCallback.cs b/src/neo/SmartContract/Callbacks/MethodCallback.cs index 37c5809196..5cb26c4fff 100644 --- a/src/neo/SmartContract/Callbacks/MethodCallback.cs +++ b/src/neo/SmartContract/Callbacks/MethodCallback.cs @@ -15,14 +15,14 @@ internal class MethodCallback : SyscallCallback public override int ParametersCount => method.Parameters.Length; public MethodCallback(ApplicationEngine engine, UInt160 hash, string method) - : base(ApplicationEngine.System_Contract_Call) + : base(ApplicationEngine.System_Contract_Call, false) { if (method.StartsWith('_')) throw new ArgumentException(); + this.contract = engine.Snapshot.Contracts[hash]; ContractManifest currentManifest = engine.Snapshot.Contracts.TryGet(engine.CurrentScriptHash)?.Manifest; - if (currentManifest != null && !currentManifest.CanCall(contract.Manifest, method)) + if (currentManifest != null && !currentManifest.CanCall(this.contract.Manifest, method)) throw new InvalidOperationException(); - this.contract = engine.Snapshot.Contracts[hash]; - this.method = contract.Manifest.Abi.Methods.First(p => p.Name == method); + this.method = this.contract.Manifest.Abi.Methods.First(p => p.Name == method); } public override void LoadContext(ApplicationEngine engine, Array args) diff --git a/src/neo/SmartContract/Callbacks/SyscallCallback.cs b/src/neo/SmartContract/Callbacks/SyscallCallback.cs index 8ffe0abb32..2c514814da 100644 --- a/src/neo/SmartContract/Callbacks/SyscallCallback.cs +++ b/src/neo/SmartContract/Callbacks/SyscallCallback.cs @@ -8,10 +8,10 @@ internal class SyscallCallback : CallbackBase public InteropDescriptor Method { get; } public override int ParametersCount => Method.Parameters.Length; - public SyscallCallback(uint method) + public SyscallCallback(uint method, bool check = true) { this.Method = ApplicationEngine.Services[method]; - if (!Method.AllowCallback) + if (check && !Method.AllowCallback) throw new InvalidOperationException("This SYSCALL is not allowed for creating callback."); } diff --git a/src/neo/SmartContract/Manifest/ContractManifest.cs b/src/neo/SmartContract/Manifest/ContractManifest.cs index da56c1cb0f..1d6124c334 100644 --- a/src/neo/SmartContract/Manifest/ContractManifest.cs +++ b/src/neo/SmartContract/Manifest/ContractManifest.cs @@ -94,7 +94,7 @@ public static ContractManifest FromJson(JObject json) /// Return ContractManifest public static ContractManifest Parse(ReadOnlySpan json) => FromJson(JObject.Parse(json)); - internal static ContractManifest Parse(string json) => FromJson(JObject.Parse(json)); + public static ContractManifest Parse(string json) => FromJson(JObject.Parse(json)); /// Date: Tue, 23 Jun 2020 15:11:42 +0800 Subject: [PATCH 03/32] Fix #1714 (#1715) --- src/neo/SmartContract/JsonSerializer.cs | 12 ++++++----- .../SmartContract/UT_JsonSerializer.cs | 4 ++-- .../SmartContract/UT_Syscalls.cs | 21 +++++++------------ 3 files changed, 17 insertions(+), 20 deletions(-) diff --git a/src/neo/SmartContract/JsonSerializer.cs b/src/neo/SmartContract/JsonSerializer.cs index e9db3ed18d..ff79e0a4ae 100644 --- a/src/neo/SmartContract/JsonSerializer.cs +++ b/src/neo/SmartContract/JsonSerializer.cs @@ -9,6 +9,7 @@ using System.Text.Json; using Array = Neo.VM.Types.Array; using Boolean = Neo.VM.Types.Boolean; +using Buffer = Neo.VM.Types.Buffer; namespace Neo.SmartContract { @@ -27,9 +28,10 @@ public static JObject Serialize(StackItem item) { return array.Select(p => Serialize(p)).ToArray(); } - case ByteString buffer: + case ByteString _: + case Buffer _: { - return Convert.ToBase64String(buffer.GetSpan()); + return item.GetString(); } case Integer num: { @@ -89,8 +91,8 @@ public static byte[] SerializeToByteArray(StackItem item, uint maxSize) case JsonTokenType.EndArray: writer.WriteEndArray(); break; - case ByteString buffer: - writer.WriteStringValue(Convert.ToBase64String(buffer.GetSpan())); + case StackItem buffer when buffer is ByteString || buffer is Buffer: + writer.WriteStringValue(buffer.GetString()); break; case Integer num: { @@ -118,7 +120,7 @@ public static byte[] SerializeToByteArray(StackItem item, uint maxSize) writer.WriteEndObject(); break; case JsonTokenType.PropertyName: - writer.WritePropertyName(((ByteString)stack.Pop()).GetString()); + writer.WritePropertyName(((StackItem)stack.Pop()).GetString()); break; case Null _: writer.WriteNullValue(); diff --git a/tests/neo.UnitTests/SmartContract/UT_JsonSerializer.cs b/tests/neo.UnitTests/SmartContract/UT_JsonSerializer.cs index c16b6d6a27..93100368a4 100644 --- a/tests/neo.UnitTests/SmartContract/UT_JsonSerializer.cs +++ b/tests/neo.UnitTests/SmartContract/UT_JsonSerializer.cs @@ -277,7 +277,7 @@ public void Serialize_Array_Bool_Str_Num() var json = JsonSerializer.Serialize(entry).ToString(); - Assert.AreEqual(json, "[true,\"dGVzdA==\",123]"); + Assert.AreEqual(json, "[true,\"test\",123]"); } [TestMethod] @@ -306,7 +306,7 @@ public void Serialize_Array_OfArray() var json = JsonSerializer.Serialize(entry).ToString(); - Assert.AreEqual(json, "[[true,\"dGVzdDE=\",123],[true,\"dGVzdDI=\",321]]"); + Assert.AreEqual(json, "[[true,\"test1\",123],[true,\"test2\",321]]"); } [TestMethod] diff --git a/tests/neo.UnitTests/SmartContract/UT_Syscalls.cs b/tests/neo.UnitTests/SmartContract/UT_Syscalls.cs index 8990620fb5..12f576a092 100644 --- a/tests/neo.UnitTests/SmartContract/UT_Syscalls.cs +++ b/tests/neo.UnitTests/SmartContract/UT_Syscalls.cs @@ -89,16 +89,14 @@ public void System_Blockchain_GetBlock() height.Index = block.Index; - script.EmitSysCall(ApplicationEngine.System_Json_Serialize); engine = new ApplicationEngine(TriggerType.Application, null, snapshot, 0, true); engine.LoadScript(script.ToArray()); Assert.AreEqual(engine.Execute(), VMState.HALT); Assert.AreEqual(1, engine.ResultStack.Count); - Assert.IsInstanceOfType(engine.ResultStack.Peek(), typeof(ByteString)); - Assert.AreEqual(engine.ResultStack.Pop().GetSpan().ToHexString(), - "5b2261564e62466b35384f51717547373870747154766561762f48677941566a72634e41434d4e59705c7530303242366f6f3d222c332c22414141414141414141414141414141414141414141414141414141414141414141414141414141414141413d222c22414141414141414141414141414141414141414141414141414141414141414141414141414141414141413d222c322c302c224141414141414141414141414141414141414141414141414141413d222c315d"); - Assert.AreEqual(0, engine.ResultStack.Count); + + var array = engine.ResultStack.Pop(); + Assert.AreEqual(block.Hash, new UInt256(array[0].GetSpan())); // Clean @@ -194,9 +192,9 @@ public void Json_Serialize() Assert.AreEqual(engine.Execute(), VMState.HALT); Assert.AreEqual(5, engine.ResultStack.Count); - Assert.IsTrue(engine.ResultStack.Pop().GetString() == "{\"key\":\"dmFsdWU=\"}"); + Assert.IsTrue(engine.ResultStack.Pop().GetString() == "{\"key\":\"value\"}"); Assert.IsTrue(engine.ResultStack.Pop().GetString() == "null"); - Assert.IsTrue(engine.ResultStack.Pop().GetString() == "\"dGVzdA==\""); + Assert.IsTrue(engine.ResultStack.Pop().GetString() == "\"test\""); Assert.IsTrue(engine.ResultStack.Pop().GetString() == "true"); Assert.IsTrue(engine.ResultStack.Pop().GetString() == "5"); } @@ -238,8 +236,6 @@ public void System_ExecutionEngine_GetScriptContainer() // With tx - script.EmitSysCall(ApplicationEngine.System_Json_Serialize); - var tx = new Transaction() { Script = new byte[] { 0x01 }, @@ -258,10 +254,9 @@ public void System_ExecutionEngine_GetScriptContainer() Assert.AreEqual(engine.Execute(), VMState.HALT); Assert.AreEqual(1, engine.ResultStack.Count); - Assert.IsInstanceOfType(engine.ResultStack.Peek(), typeof(ByteString)); - Assert.AreEqual(engine.ResultStack.Pop().GetSpan().ToHexString(), - @"5b224435724a376f755c753030324256574845456c5c75303032426e74486b414a424f614c4a6737496776303356337a4953646d6750413d222c362c342c222f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f2f383d222c332c322c352c2241513d3d225d"); - Assert.AreEqual(0, engine.ResultStack.Count); + + var array = engine.ResultStack.Pop(); + Assert.AreEqual(tx.Hash, new UInt256(array[0].GetSpan())); } } From 815180c7653a342214bfa644c6ad03bc8b1da8b4 Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Tue, 23 Jun 2020 16:35:34 +0800 Subject: [PATCH 04/32] Add base64 SYSCALLs (#1717) --- src/neo/SmartContract/ApplicationEngine.Binary.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/neo/SmartContract/ApplicationEngine.Binary.cs b/src/neo/SmartContract/ApplicationEngine.Binary.cs index 17a41f1072..1dd240efdb 100644 --- a/src/neo/SmartContract/ApplicationEngine.Binary.cs +++ b/src/neo/SmartContract/ApplicationEngine.Binary.cs @@ -1,4 +1,5 @@ using Neo.VM.Types; +using static System.Convert; namespace Neo.SmartContract { @@ -6,6 +7,8 @@ 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); internal byte[] BinarySerialize(StackItem item) { @@ -16,5 +19,15 @@ internal StackItem BinaryDeserialize(byte[] data) { return BinarySerializer.Deserialize(data, MaxStackSize, MaxItemSize, ReferenceCounter); } + + internal string Base64Encode(byte[] data) + { + return ToBase64String(data); + } + + internal byte[] Base64Decode(string s) + { + return FromBase64String(s); + } } } From cd988e85222f4d9df614f969668d2a915094b2e2 Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Tue, 23 Jun 2020 20:04:57 +0800 Subject: [PATCH 05/32] Neo.VM.3.0.0-CI00230 (#1725) --- src/neo/SmartContract/ApplicationEngine.cs | 2 +- src/neo/SmartContract/BinarySerializer.cs | 32 +++++++--- src/neo/SmartContract/ContainerPlaceholder.cs | 23 -------- src/neo/SmartContract/Helper.cs | 2 +- .../InteropParameterDescriptor.cs | 21 ++++--- .../Iterators/ByteArrayWrapper.cs | 2 +- src/neo/SmartContract/JsonSerializer.cs | 14 ++--- .../SmartContract/Native/NativeContract.cs | 2 +- .../Native/Tokens/AccountState.cs | 2 +- .../SmartContract/Native/Tokens/NeoToken.cs | 6 +- src/neo/VM/Helper.cs | 52 +++-------------- src/neo/Wallets/AssetDescriptor.cs | 2 +- src/neo/Wallets/Wallet.cs | 6 +- src/neo/neo.csproj | 2 +- .../Nep5NativeContractExtensions.cs | 8 +-- .../Network/P2P/Payloads/UT_Transaction.cs | 14 ++--- .../Iterators/UT_PrimitiveWrapper.cs | 5 +- .../Native/Tokens/UT_NeoToken.cs | 26 ++++----- .../SmartContract/Native/UT_PolicyContract.cs | 58 +++++++++---------- .../SmartContract/UT_ContainerPlaceholder.cs | 35 ----------- .../SmartContract/UT_InteropService.NEO.cs | 11 ++-- .../SmartContract/UT_InteropService.cs | 2 +- .../SmartContract/UT_JsonSerializer.cs | 23 ++++---- .../SmartContract/UT_Syscalls.Callback.cs | 2 +- .../SmartContract/UT_Syscalls.cs | 8 +-- tests/neo.UnitTests/VM/UT_Helper.cs | 14 ++--- 26 files changed, 143 insertions(+), 231 deletions(-) delete mode 100644 src/neo/SmartContract/ContainerPlaceholder.cs delete mode 100644 tests/neo.UnitTests/SmartContract/UT_ContainerPlaceholder.cs diff --git a/src/neo/SmartContract/ApplicationEngine.cs b/src/neo/SmartContract/ApplicationEngine.cs index 2602397ebc..ca994e836f 100644 --- a/src/neo/SmartContract/ApplicationEngine.cs +++ b/src/neo/SmartContract/ApplicationEngine.cs @@ -165,7 +165,7 @@ internal object Convert(StackItem item, InteropParameterDescriptor descriptor) } else { - int count = (int)item.GetBigInteger(); + int count = (int)item.GetInteger(); if (count > MaxStackSize) throw new InvalidOperationException(); av = Array.CreateInstance(descriptor.Type.GetElementType(), count); for (int i = 0; i < av.Length; i++) diff --git a/src/neo/SmartContract/BinarySerializer.cs b/src/neo/SmartContract/BinarySerializer.cs index 5083be59a7..89bf477e3a 100644 --- a/src/neo/SmartContract/BinarySerializer.cs +++ b/src/neo/SmartContract/BinarySerializer.cs @@ -14,6 +14,24 @@ namespace Neo.SmartContract { internal static class BinarySerializer { + private class ContainerPlaceholder : StackItem + { + public override StackItemType Type { get; } + public int ElementCount { get; } + + public ContainerPlaceholder(StackItemType type, int count) + { + Type = type; + ElementCount = count; + } + + public override bool Equals(StackItem other) => throw new NotSupportedException(); + + public override int GetHashCode() => throw new NotSupportedException(); + + public override bool GetBoolean() => throw new NotSupportedException(); + } + public static StackItem Deserialize(byte[] data, uint maxArraySize, uint maxItemSize, ReferenceCounter referenceCounter = null) { using MemoryStream ms = new MemoryStream(data, false); @@ -137,16 +155,12 @@ private static void Serialize(StackItem item, BinaryWriter writer, uint maxSize) case Null _: break; case Boolean _: - writer.Write(item.ToBoolean()); - break; - case Integer integer: - writer.WriteVarBytes(integer.Span); - break; - case ByteString bytes: - writer.WriteVarBytes(bytes.Span); + writer.Write(item.GetBoolean()); break; - case Buffer buffer: - writer.WriteVarBytes(buffer.InnerBuffer); + case Integer _: + case ByteString _: + case Buffer _: + writer.WriteVarBytes(item.GetSpan()); break; case Array array: if (serialized.Any(p => ReferenceEquals(p, array))) diff --git a/src/neo/SmartContract/ContainerPlaceholder.cs b/src/neo/SmartContract/ContainerPlaceholder.cs deleted file mode 100644 index 757d77ccbc..0000000000 --- a/src/neo/SmartContract/ContainerPlaceholder.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Neo.VM.Types; -using System; - -namespace Neo.SmartContract -{ - internal class ContainerPlaceholder : StackItem - { - public override StackItemType Type { get; } - public int ElementCount { get; } - - public ContainerPlaceholder(StackItemType type, int count) - { - Type = type; - ElementCount = count; - } - - public override bool Equals(StackItem other) => throw new NotSupportedException(); - - public override int GetHashCode() => throw new NotSupportedException(); - - public override bool ToBoolean() => throw new NotSupportedException(); - } -} diff --git a/src/neo/SmartContract/Helper.cs b/src/neo/SmartContract/Helper.cs index d9299e30f3..a365806b87 100644 --- a/src/neo/SmartContract/Helper.cs +++ b/src/neo/SmartContract/Helper.cs @@ -164,7 +164,7 @@ internal static bool VerifyWitnesses(this IVerifiable verifiable, StoreView snap engine.LoadScript(verification, CallFlags.ReadOnly).InstructionPointer = offset; engine.LoadScript(verifiable.Witnesses[i].InvocationScript, CallFlags.None); if (engine.Execute() == VMState.FAULT) return false; - if (engine.ResultStack.Count != 1 || !engine.ResultStack.Pop().ToBoolean()) return false; + if (engine.ResultStack.Count != 1 || !engine.ResultStack.Pop().GetBoolean()) return false; gas -= engine.GasConsumed; } } diff --git a/src/neo/SmartContract/InteropParameterDescriptor.cs b/src/neo/SmartContract/InteropParameterDescriptor.cs index 440e4588af..fd380ffb68 100644 --- a/src/neo/SmartContract/InteropParameterDescriptor.cs +++ b/src/neo/SmartContract/InteropParameterDescriptor.cs @@ -1,5 +1,4 @@ using Neo.Cryptography.ECC; -using Neo.VM; using Neo.VM.Types; using System; using System.Collections.Generic; @@ -23,16 +22,16 @@ internal class InteropParameterDescriptor [typeof(VM.Types.Pointer)] = p => p, [typeof(VM.Types.Array)] = p => p, [typeof(InteropInterface)] = p => p, - [typeof(bool)] = p => p.ToBoolean(), - [typeof(sbyte)] = p => (sbyte)p.GetBigInteger(), - [typeof(byte)] = p => (byte)p.GetBigInteger(), - [typeof(short)] = p => (short)p.GetBigInteger(), - [typeof(ushort)] = p => (ushort)p.GetBigInteger(), - [typeof(int)] = p => (int)p.GetBigInteger(), - [typeof(uint)] = p => (uint)p.GetBigInteger(), - [typeof(long)] = p => (long)p.GetBigInteger(), - [typeof(ulong)] = p => (ulong)p.GetBigInteger(), - [typeof(BigInteger)] = p => p.GetBigInteger(), + [typeof(bool)] = p => p.GetBoolean(), + [typeof(sbyte)] = p => (sbyte)p.GetInteger(), + [typeof(byte)] = p => (byte)p.GetInteger(), + [typeof(short)] = p => (short)p.GetInteger(), + [typeof(ushort)] = p => (ushort)p.GetInteger(), + [typeof(int)] = p => (int)p.GetInteger(), + [typeof(uint)] = p => (uint)p.GetInteger(), + [typeof(long)] = p => (long)p.GetInteger(), + [typeof(ulong)] = p => (ulong)p.GetInteger(), + [typeof(BigInteger)] = p => p.GetInteger(), [typeof(byte[])] = p => p.IsNull ? null : p.GetSpan().ToArray(), [typeof(string)] = p => p.IsNull ? null : p.GetString(), [typeof(UInt160)] = p => p.IsNull ? null : new UInt160(p.GetSpan()), diff --git a/src/neo/SmartContract/Iterators/ByteArrayWrapper.cs b/src/neo/SmartContract/Iterators/ByteArrayWrapper.cs index c60c839543..f409b3beed 100644 --- a/src/neo/SmartContract/Iterators/ByteArrayWrapper.cs +++ b/src/neo/SmartContract/Iterators/ByteArrayWrapper.cs @@ -10,7 +10,7 @@ internal class ByteArrayWrapper : IIterator public ByteArrayWrapper(PrimitiveType value) { - this.array = value.Span.ToArray(); + this.array = value.GetSpan().ToArray(); } public void Dispose() { } diff --git a/src/neo/SmartContract/JsonSerializer.cs b/src/neo/SmartContract/JsonSerializer.cs index ff79e0a4ae..ef772183c9 100644 --- a/src/neo/SmartContract/JsonSerializer.cs +++ b/src/neo/SmartContract/JsonSerializer.cs @@ -35,14 +35,14 @@ public static JObject Serialize(StackItem item) } case Integer num: { - var integer = num.GetBigInteger(); + var integer = num.GetInteger(); if (integer > JNumber.MAX_SAFE_INTEGER || integer < JNumber.MIN_SAFE_INTEGER) - return integer.ToString(); - return (double)num.GetBigInteger(); + throw new InvalidOperationException(); + return (double)integer; } case Boolean boolean: { - return boolean.ToBoolean(); + return boolean.GetBoolean(); } case Map map: { @@ -96,14 +96,14 @@ public static byte[] SerializeToByteArray(StackItem item, uint maxSize) break; case Integer num: { - var integer = num.GetBigInteger(); + var integer = num.GetInteger(); if (integer > JNumber.MAX_SAFE_INTEGER || integer < JNumber.MIN_SAFE_INTEGER) throw new InvalidOperationException(); - writer.WriteNumberValue((double)num.GetBigInteger()); + writer.WriteNumberValue((double)integer); break; } case Boolean boolean: - writer.WriteBooleanValue(boolean.ToBoolean()); + writer.WriteBooleanValue(boolean.GetBoolean()); break; case Map map: writer.WriteStartObject(); diff --git a/src/neo/SmartContract/Native/NativeContract.cs b/src/neo/SmartContract/Native/NativeContract.cs index 21c9b429a1..4d649ac627 100644 --- a/src/neo/SmartContract/Native/NativeContract.cs +++ b/src/neo/SmartContract/Native/NativeContract.cs @@ -112,7 +112,7 @@ internal void Invoke(ApplicationEngine engine) { if (!engine.CurrentScriptHash.Equals(Hash)) throw new InvalidOperationException("It is not allowed to use Neo.Native.Call directly to call native contracts. System.Contract.Call should be used."); - string operation = engine.PopString(); + string operation = engine.Pop().GetString(); Array args = engine.Pop(); ContractMethodMetadata method = methods[operation]; ExecutionContextState state = engine.CurrentContext.GetState(); diff --git a/src/neo/SmartContract/Native/Tokens/AccountState.cs b/src/neo/SmartContract/Native/Tokens/AccountState.cs index 4cffcc406c..30d3d02e49 100644 --- a/src/neo/SmartContract/Native/Tokens/AccountState.cs +++ b/src/neo/SmartContract/Native/Tokens/AccountState.cs @@ -10,7 +10,7 @@ public class AccountState : IInteroperable public virtual void FromStackItem(StackItem stackItem) { - Balance = ((Struct)stackItem)[0].GetBigInteger(); + Balance = ((Struct)stackItem)[0].GetInteger(); } public virtual StackItem ToStackItem(ReferenceCounter referenceCounter) diff --git a/src/neo/SmartContract/Native/Tokens/NeoToken.cs b/src/neo/SmartContract/Native/Tokens/NeoToken.cs index 494bf4afc6..3d814cbe2f 100644 --- a/src/neo/SmartContract/Native/Tokens/NeoToken.cs +++ b/src/neo/SmartContract/Native/Tokens/NeoToken.cs @@ -242,7 +242,7 @@ public override void FromStackItem(StackItem stackItem) { base.FromStackItem(stackItem); Struct @struct = (Struct)stackItem; - BalanceHeight = (uint)@struct[1].GetBigInteger(); + BalanceHeight = (uint)@struct[1].GetInteger(); VoteTo = @struct[2].IsNull ? null : @struct[2].GetSpan().AsSerializable(); } @@ -263,8 +263,8 @@ internal class CandidateState : IInteroperable public void FromStackItem(StackItem stackItem) { Struct @struct = (Struct)stackItem; - Registered = @struct[0].ToBoolean(); - Votes = @struct[1].GetBigInteger(); + Registered = @struct[0].GetBoolean(); + Votes = @struct[1].GetInteger(); } public StackItem ToStackItem(ReferenceCounter referenceCounter) diff --git a/src/neo/VM/Helper.cs b/src/neo/VM/Helper.cs index c31c12d512..6437b75118 100644 --- a/src/neo/VM/Helper.cs +++ b/src/neo/VM/Helper.cs @@ -7,7 +7,6 @@ using System.Collections.Generic; using System.Linq; using System.Numerics; -using System.Text; using Array = Neo.VM.Types.Array; using Boolean = Neo.VM.Types.Boolean; using Buffer = Neo.VM.Types.Buffer; @@ -168,39 +167,6 @@ public static ScriptBuilder EmitSysCall(this ScriptBuilder sb, uint method, para return sb.EmitSysCall(method); } - public static BigInteger GetBigInteger(this StackItem item) - { - if (!(item is PrimitiveType primitive)) - throw new ArgumentException(); - return primitive.ToBigInteger(); - } - - public static int GetByteLength(this StackItem item) - { - return item switch - { - PrimitiveType p => p.Size, - Buffer b => b.Size, - Null _ => 0, - _ => throw new ArgumentException(), - }; - } - - public static ReadOnlySpan GetSpan(this StackItem item) - { - return item switch - { - PrimitiveType p => p.Span, - Buffer b => b.InnerBuffer, - _ => throw new ArgumentException(), - }; - } - - public static string GetString(this StackItem item) - { - return Utility.StrictUTF8.GetString(item.GetSpan()); - } - /// /// Generate scripts to call a specific method from a specific contract. /// @@ -237,16 +203,14 @@ private static JObject ToJson(StackItem item, HashSet context) json["value"] = new JArray(array.Select(p => ToJson(p, context))); break; case Boolean boolean: - json["value"] = boolean.ToBoolean(); - break; - case Buffer buffer: - json["value"] = Convert.ToBase64String(buffer.InnerBuffer); + json["value"] = boolean.GetBoolean(); break; - case ByteString byteString: - json["value"] = Convert.ToBase64String(byteString.Span); + case Buffer _: + case ByteString _: + json["value"] = Convert.ToBase64String(item.GetSpan()); break; case Integer integer: - json["value"] = integer.ToBigInteger().ToString(); + json["value"] = integer.GetInteger().ToString(); break; case Map map: context ??= new HashSet(ReferenceEqualityComparer.Default); @@ -305,21 +269,21 @@ private static ContractParameter ToParameter(StackItem item, List<(StackItem, Co parameter = new ContractParameter { Type = ContractParameterType.Boolean, - Value = item.ToBoolean() + Value = item.GetBoolean() }; break; case ByteString array: parameter = new ContractParameter { Type = ContractParameterType.ByteArray, - Value = array.Span.ToArray() + Value = array.GetSpan().ToArray() }; break; case Integer i: parameter = new ContractParameter { Type = ContractParameterType.Integer, - Value = i.ToBigInteger() + Value = i.GetInteger() }; break; case InteropInterface _: diff --git a/src/neo/Wallets/AssetDescriptor.cs b/src/neo/Wallets/AssetDescriptor.cs index 46a80a0f5c..c49712f7ec 100644 --- a/src/neo/Wallets/AssetDescriptor.cs +++ b/src/neo/Wallets/AssetDescriptor.cs @@ -23,7 +23,7 @@ public AssetDescriptor(UInt160 asset_id) if (engine.State.HasFlag(VMState.FAULT)) throw new ArgumentException(); this.AssetId = asset_id; this.AssetName = engine.ResultStack.Pop().GetString(); - this.Decimals = (byte)engine.ResultStack.Pop().GetBigInteger(); + this.Decimals = (byte)engine.ResultStack.Pop().GetInteger(); } public override string ToString() diff --git a/src/neo/Wallets/Wallet.cs b/src/neo/Wallets/Wallet.cs index def6977959..69708cca42 100644 --- a/src/neo/Wallets/Wallet.cs +++ b/src/neo/Wallets/Wallet.cs @@ -146,8 +146,8 @@ public BigDecimal GetBalance(UInt160 asset_id, params UInt160[] accounts) using ApplicationEngine engine = ApplicationEngine.Run(script, extraGAS: 20000000L * accounts.Length); if (engine.State.HasFlag(VMState.FAULT)) return new BigDecimal(0, 0); - byte decimals = (byte)engine.ResultStack.Pop().GetBigInteger(); - BigInteger amount = engine.ResultStack.Pop().GetBigInteger(); + byte decimals = (byte)engine.ResultStack.Pop().GetInteger(); + BigInteger amount = engine.ResultStack.Pop().GetInteger(); return new BigDecimal(amount, decimals); } @@ -251,7 +251,7 @@ public Transaction MakeTransaction(TransferOutput[] outputs, UInt160 from = null { if (engine.State.HasFlag(VMState.FAULT)) throw new InvalidOperationException($"Execution for {assetId.ToString()}.balanceOf('{account.ToString()}' fault"); - BigInteger value = engine.ResultStack.Pop().GetBigInteger(); + BigInteger value = engine.ResultStack.Pop().GetInteger(); if (value.Sign > 0) balances.Add((account, value)); } } diff --git a/src/neo/neo.csproj b/src/neo/neo.csproj index 3cd431d612..e3ee5b5259 100644 --- a/src/neo/neo.csproj +++ b/src/neo/neo.csproj @@ -27,7 +27,7 @@ - + diff --git a/tests/neo.UnitTests/Extensions/Nep5NativeContractExtensions.cs b/tests/neo.UnitTests/Extensions/Nep5NativeContractExtensions.cs index 70098c9c04..e3a5fc9adf 100644 --- a/tests/neo.UnitTests/Extensions/Nep5NativeContractExtensions.cs +++ b/tests/neo.UnitTests/Extensions/Nep5NativeContractExtensions.cs @@ -65,7 +65,7 @@ public static bool Transfer(this NativeContract contract, StoreView snapshot, by var result = engine.ResultStack.Pop(); result.Should().BeOfType(typeof(VM.Types.Boolean)); - return result.ToBoolean(); + return result.GetBoolean(); } public static string[] SupportedStandards(this NativeContract contract) @@ -107,7 +107,7 @@ public static BigInteger TotalSupply(this NativeContract contract, StoreView sna var result = engine.ResultStack.Pop(); result.Should().BeOfType(typeof(VM.Types.Integer)); - return (result as VM.Types.Integer).GetBigInteger(); + return result.GetInteger(); } public static BigInteger BalanceOf(this NativeContract contract, StoreView snapshot, byte[] account) @@ -128,7 +128,7 @@ public static BigInteger BalanceOf(this NativeContract contract, StoreView snaps var result = engine.ResultStack.Pop(); result.Should().BeOfType(typeof(VM.Types.Integer)); - return (result as VM.Types.Integer).GetBigInteger(); + return result.GetInteger(); } public static BigInteger Decimals(this NativeContract contract) @@ -148,7 +148,7 @@ public static BigInteger Decimals(this NativeContract contract) var result = engine.ResultStack.Pop(); result.Should().BeOfType(typeof(VM.Types.Integer)); - return (result as VM.Types.Integer).GetBigInteger(); + return result.GetInteger(); } public static string Symbol(this NativeContract contract) diff --git a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs index 7e025ad4cd..5425b71974 100644 --- a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs +++ b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs @@ -151,7 +151,7 @@ public void FeeIsMultiSigContract() engine.LoadScript(witness.InvocationScript); Assert.AreEqual(VMState.HALT, engine.Execute()); Assert.AreEqual(1, engine.ResultStack.Count); - Assert.IsTrue(engine.ResultStack.Pop().ToBoolean()); + Assert.IsTrue(engine.ResultStack.Pop().GetBoolean()); verificationGas += engine.GasConsumed; } } @@ -233,7 +233,7 @@ public void FeeIsSignatureContractDetailed() engine.LoadScript(witness.InvocationScript); Assert.AreEqual(VMState.HALT, engine.Execute()); Assert.AreEqual(1, engine.ResultStack.Count); - Assert.IsTrue(engine.ResultStack.Pop().ToBoolean()); + Assert.IsTrue(engine.ResultStack.Pop().GetBoolean()); verificationGas += engine.GasConsumed; } } @@ -346,7 +346,7 @@ public void FeeIsSignatureContract_TestScope_Global() engine.LoadScript(witness.InvocationScript); Assert.AreEqual(VMState.HALT, engine.Execute()); Assert.AreEqual(1, engine.ResultStack.Count); - Assert.IsTrue(engine.ResultStack.Pop().ToBoolean()); + Assert.IsTrue(engine.ResultStack.Pop().GetBoolean()); verificationGas += engine.GasConsumed; } } @@ -433,7 +433,7 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_GAS() engine.LoadScript(witness.InvocationScript); Assert.AreEqual(VMState.HALT, engine.Execute()); Assert.AreEqual(1, engine.ResultStack.Count); - Assert.IsTrue(engine.ResultStack.Pop().ToBoolean()); + Assert.IsTrue(engine.ResultStack.Pop().GetBoolean()); verificationGas += engine.GasConsumed; } } @@ -523,7 +523,7 @@ public void FeeIsSignatureContract_TestScope_CalledByEntry_Plus_GAS() engine.LoadScript(witness.InvocationScript); Assert.AreEqual(VMState.HALT, engine.Execute()); Assert.AreEqual(1, engine.ResultStack.Count); - Assert.IsTrue(engine.ResultStack.Pop().ToBoolean()); + Assert.IsTrue(engine.ResultStack.Pop().GetBoolean()); verificationGas += engine.GasConsumed; } } @@ -665,7 +665,7 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_NEO_GAS() engine.LoadScript(witness.InvocationScript); Assert.AreEqual(VMState.HALT, engine.Execute()); Assert.AreEqual(1, engine.ResultStack.Count); - Assert.IsTrue(engine.ResultStack.Pop().ToBoolean()); + Assert.IsTrue(engine.ResultStack.Pop().GetBoolean()); verificationGas += engine.GasConsumed; } } @@ -996,7 +996,7 @@ public void FeeIsSignatureContract_TestScope_Global_Default() engine.LoadScript(witness.InvocationScript); Assert.AreEqual(VMState.HALT, engine.Execute()); Assert.AreEqual(1, engine.ResultStack.Count); - Assert.IsTrue(engine.ResultStack.Pop().ToBoolean()); + Assert.IsTrue(engine.ResultStack.Pop().GetBoolean()); verificationGas += engine.GasConsumed; } } diff --git a/tests/neo.UnitTests/SmartContract/Iterators/UT_PrimitiveWrapper.cs b/tests/neo.UnitTests/SmartContract/Iterators/UT_PrimitiveWrapper.cs index 72c4750225..c097986de3 100644 --- a/tests/neo.UnitTests/SmartContract/Iterators/UT_PrimitiveWrapper.cs +++ b/tests/neo.UnitTests/SmartContract/Iterators/UT_PrimitiveWrapper.cs @@ -1,7 +1,6 @@ using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.SmartContract.Iterators; -using Neo.VM; using Neo.VM.Types; using System; @@ -28,10 +27,10 @@ public void TestKeyAndValue() Action action2 = () => arrayWrapper.Value(); action2.Should().Throw(); arrayWrapper.Next(); - Assert.AreEqual(0x00, arrayWrapper.Key().GetBigInteger()); + Assert.AreEqual(0x00, arrayWrapper.Key().GetInteger()); Assert.AreEqual(0x01, arrayWrapper.Value()); arrayWrapper.Next(); - Assert.AreEqual(0x01, arrayWrapper.Key().GetBigInteger()); + Assert.AreEqual(0x01, arrayWrapper.Key().GetInteger()); Assert.AreEqual(0x02, arrayWrapper.Value()); } diff --git a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs index 14b6536ccc..dafb1f9a72 100644 --- a/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs +++ b/tests/neo.UnitTests/SmartContract/Native/Tokens/UT_NeoToken.cs @@ -286,19 +286,19 @@ public void TestGetRegisteredValidators1() 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].GetBigInteger().Should().Be(new BigInteger(1785714)); + ((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].GetBigInteger().Should().Be(new BigInteger(1785714)); + ((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].GetBigInteger().Should().Be(new BigInteger(1785714)); + ((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].GetBigInteger().Should().Be(new BigInteger(1785714)); + ((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].GetBigInteger().Should().Be(new BigInteger(3571428)); + ((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].GetBigInteger().Should().Be(new BigInteger(3571428)); + ((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].GetBigInteger().Should().Be(new BigInteger(1785714)); + ((VM.Types.Struct)array[6])[1].GetInteger().Should().Be(new BigInteger(1785714)); } } @@ -453,7 +453,7 @@ public void TestVote() engine.Execute(); var result = engine.ResultStack.Peek(); result.GetType().Should().Be(typeof(VM.Types.Boolean)); - return (true, result.ToBoolean()); + return (true, result.GetBoolean()); } internal static (bool State, bool Result) Check_Vote(StoreView snapshot, byte[] account, byte[] pubkey, bool signAccount) @@ -483,7 +483,7 @@ internal static (bool State, bool Result) Check_Vote(StoreView snapshot, byte[] var result = engine.ResultStack.Pop(); result.Should().BeOfType(typeof(VM.Types.Boolean)); - return (true, result.ToBoolean()); + return (true, result.GetBoolean()); } internal static (bool State, bool Result) Check_RegisterValidator(StoreView snapshot, byte[] pubkey) @@ -508,7 +508,7 @@ internal static (bool State, bool Result) Check_RegisterValidator(StoreView snap var result = engine.ResultStack.Pop(); result.Should().BeOfType(typeof(VM.Types.Boolean)); - return (true, result.ToBoolean()); + return (true, result.GetBoolean()); } internal static ECPoint[] Check_GetValidators(StoreView snapshot) @@ -553,7 +553,7 @@ internal static (BigInteger Value, bool State) Check_UnclaimedGas(StoreView snap var result = engine.ResultStack.Pop(); result.Should().BeOfType(typeof(VM.Types.Integer)); - return ((result as VM.Types.Integer).GetBigInteger(), true); + return (result.GetInteger(), true); } internal static void CheckValidator(ECPoint eCPoint, DataCache.Trackable trackable) @@ -572,8 +572,8 @@ internal static void CheckBalance(byte[] account, DataCache u.GetType()).ToArray().Should().BeEquivalentTo(new Type[] { typeof(VM.Types.Integer), typeof(VM.Types.Integer), typeof(VM.Types.ByteString) }); // Balance - st[0].GetBigInteger().Should().Be(balance); // Balance - st[1].GetBigInteger().Should().Be(height); // BalanceHeight + st[0].GetInteger().Should().Be(balance); // Balance + st[1].GetInteger().Should().Be(height); // BalanceHeight st[2].GetSpan().AsSerializable().Should().BeEquivalentTo(voteTo); // Votes trackable.Key.Key.Should().BeEquivalentTo(new byte[] { 20 }.Concat(account)); diff --git a/tests/neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs b/tests/neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs index 5695f3d105..a33b209a12 100644 --- a/tests/neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs +++ b/tests/neo.UnitTests/SmartContract/Native/UT_PolicyContract.cs @@ -5,9 +5,7 @@ using Neo.Network.P2P.Payloads; using Neo.SmartContract; using Neo.SmartContract.Native; -using Neo.SmartContract.Native.Tokens; using Neo.UnitTests.Extensions; -using Neo.VM; using System.Linq; namespace Neo.UnitTests.SmartContract.Native @@ -36,19 +34,19 @@ public void Check_Initialize() var ret = NativeContract.Policy.Call(snapshot, "getMaxTransactionsPerBlock"); ret.Should().BeOfType(); - ret.GetBigInteger().Should().Be(512); + ret.GetInteger().Should().Be(512); ret = NativeContract.Policy.Call(snapshot, "getMaxBlockSize"); ret.Should().BeOfType(); - ret.GetBigInteger().Should().Be(1024 * 256); + ret.GetInteger().Should().Be(1024 * 256); ret = NativeContract.Policy.Call(snapshot, "getMaxBlockSystemFee"); ret.Should().BeOfType(); - ret.GetBigInteger().Should().Be(9000 * 100000000L); + ret.GetInteger().Should().Be(9000 * 100000000L); ret = NativeContract.Policy.Call(snapshot, "getFeePerByte"); ret.Should().BeOfType(); - ret.GetBigInteger().Should().Be(1000); + ret.GetInteger().Should().Be(1000); ret = NativeContract.Policy.Call(snapshot, "getBlockedAccounts"); ret.Should().BeOfType(); @@ -74,33 +72,33 @@ public void Check_SetMaxBlockSize() var ret = NativeContract.Policy.Call(snapshot, new Nep5NativeContractExtensions.ManualWitness(null), "setMaxBlockSize", new ContractParameter(ContractParameterType.Integer) { Value = 1024 }); ret.Should().BeOfType(); - ret.ToBoolean().Should().BeFalse(); + ret.GetBoolean().Should().BeFalse(); ret = NativeContract.Policy.Call(snapshot, "getMaxBlockSize"); ret.Should().BeOfType(); - ret.GetBigInteger().Should().Be(1024 * 256); + ret.GetInteger().Should().Be(1024 * 256); // More than expected ret = NativeContract.Policy.Call(snapshot, new Nep5NativeContractExtensions.ManualWitness(committeeMultiSigAddr), "setMaxBlockSize", new ContractParameter(ContractParameterType.Integer) { Value = Neo.Network.P2P.Message.PayloadMaxSize }); ret.Should().BeOfType(); - ret.ToBoolean().Should().BeFalse(); + ret.GetBoolean().Should().BeFalse(); ret = NativeContract.Policy.Call(snapshot, "getMaxBlockSize"); ret.Should().BeOfType(); - ret.GetBigInteger().Should().Be(1024 * 256); + ret.GetInteger().Should().Be(1024 * 256); // With signature ret = NativeContract.Policy.Call(snapshot, new Nep5NativeContractExtensions.ManualWitness(committeeMultiSigAddr), "setMaxBlockSize", new ContractParameter(ContractParameterType.Integer) { Value = 1024 }); ret.Should().BeOfType(); - ret.ToBoolean().Should().BeTrue(); + ret.GetBoolean().Should().BeTrue(); ret = NativeContract.Policy.Call(snapshot, "getMaxBlockSize"); ret.Should().BeOfType(); - ret.GetBigInteger().Should().Be(1024); + ret.GetInteger().Should().Be(1024); } [TestMethod] @@ -122,33 +120,33 @@ public void Check_SetMaxBlockSystemFee() var ret = NativeContract.Policy.Call(snapshot, new Nep5NativeContractExtensions.ManualWitness(null), "setMaxBlockSystemFee", new ContractParameter(ContractParameterType.Integer) { Value = 1024 * (long)NativeContract.GAS.Factor }); ret.Should().BeOfType(); - ret.ToBoolean().Should().BeFalse(); + ret.GetBoolean().Should().BeFalse(); ret = NativeContract.Policy.Call(snapshot, "getMaxBlockSystemFee"); ret.Should().BeOfType(); - ret.GetBigInteger().Should().Be(9000 * (long)NativeContract.GAS.Factor); + ret.GetInteger().Should().Be(9000 * (long)NativeContract.GAS.Factor); // Less than expected ret = NativeContract.Policy.Call(snapshot, new Nep5NativeContractExtensions.ManualWitness(committeeMultiSigAddr), "setMaxBlockSystemFee", new ContractParameter(ContractParameterType.Integer) { Value = -1000 }); ret.Should().BeOfType(); - ret.ToBoolean().Should().BeFalse(); + ret.GetBoolean().Should().BeFalse(); ret = NativeContract.Policy.Call(snapshot, "getMaxBlockSystemFee"); ret.Should().BeOfType(); - ret.GetBigInteger().Should().Be(9000 * (long)NativeContract.GAS.Factor); + ret.GetInteger().Should().Be(9000 * (long)NativeContract.GAS.Factor); // With signature ret = NativeContract.Policy.Call(snapshot, new Nep5NativeContractExtensions.ManualWitness(committeeMultiSigAddr), "setMaxBlockSystemFee", new ContractParameter(ContractParameterType.Integer) { Value = 1024 * (long)NativeContract.GAS.Factor }); ret.Should().BeOfType(); - ret.ToBoolean().Should().BeTrue(); + ret.GetBoolean().Should().BeTrue(); ret = NativeContract.Policy.Call(snapshot, "getMaxBlockSystemFee"); ret.Should().BeOfType(); - ret.GetBigInteger().Should().Be(1024 * (long)NativeContract.GAS.Factor); + ret.GetInteger().Should().Be(1024 * (long)NativeContract.GAS.Factor); } [TestMethod] @@ -168,22 +166,22 @@ public void Check_SetMaxTransactionsPerBlock() var ret = NativeContract.Policy.Call(snapshot, new Nep5NativeContractExtensions.ManualWitness(), "setMaxTransactionsPerBlock", new ContractParameter(ContractParameterType.Integer) { Value = 1 }); ret.Should().BeOfType(); - ret.ToBoolean().Should().BeFalse(); + ret.GetBoolean().Should().BeFalse(); ret = NativeContract.Policy.Call(snapshot, "getMaxTransactionsPerBlock"); ret.Should().BeOfType(); - ret.GetBigInteger().Should().Be(512); + ret.GetInteger().Should().Be(512); // With signature ret = NativeContract.Policy.Call(snapshot, new Nep5NativeContractExtensions.ManualWitness(NativeContract.NEO.GetCommitteeAddress(snapshot)), "setMaxTransactionsPerBlock", new ContractParameter(ContractParameterType.Integer) { Value = 1 }); ret.Should().BeOfType(); - ret.ToBoolean().Should().BeTrue(); + ret.GetBoolean().Should().BeTrue(); ret = NativeContract.Policy.Call(snapshot, "getMaxTransactionsPerBlock"); ret.Should().BeOfType(); - ret.GetBigInteger().Should().Be(1); + ret.GetInteger().Should().Be(1); } [TestMethod] @@ -203,22 +201,22 @@ public void Check_SetFeePerByte() var ret = NativeContract.Policy.Call(snapshot, new Nep5NativeContractExtensions.ManualWitness(), "setFeePerByte", new ContractParameter(ContractParameterType.Integer) { Value = 1 }); ret.Should().BeOfType(); - ret.ToBoolean().Should().BeFalse(); + ret.GetBoolean().Should().BeFalse(); ret = NativeContract.Policy.Call(snapshot, "getFeePerByte"); ret.Should().BeOfType(); - ret.GetBigInteger().Should().Be(1000); + ret.GetInteger().Should().Be(1000); // With signature UInt160 committeeMultiSigAddr = NativeContract.NEO.GetCommitteeAddress(snapshot); ret = NativeContract.Policy.Call(snapshot, new Nep5NativeContractExtensions.ManualWitness(committeeMultiSigAddr), "setFeePerByte", new ContractParameter(ContractParameterType.Integer) { Value = 1 }); ret.Should().BeOfType(); - ret.ToBoolean().Should().BeTrue(); + ret.GetBoolean().Should().BeTrue(); ret = NativeContract.Policy.Call(snapshot, "getFeePerByte"); ret.Should().BeOfType(); - ret.GetBigInteger().Should().Be(1); + ret.GetInteger().Should().Be(1); } [TestMethod] @@ -240,7 +238,7 @@ public void Check_Block_UnblockAccount() var ret = NativeContract.Policy.Call(snapshot, new Nep5NativeContractExtensions.ManualWitness(), "blockAccount", new ContractParameter(ContractParameterType.Hash160) { Value = UInt160.Zero }); ret.Should().BeOfType(); - ret.ToBoolean().Should().BeFalse(); + ret.GetBoolean().Should().BeFalse(); ret = NativeContract.Policy.Call(snapshot, "getBlockedAccounts"); ret.Should().BeOfType(); @@ -251,7 +249,7 @@ public void Check_Block_UnblockAccount() ret = NativeContract.Policy.Call(snapshot, new Nep5NativeContractExtensions.ManualWitness(committeeMultiSigAddr), "blockAccount", new ContractParameter(ContractParameterType.Hash160) { Value = UInt160.Zero }); ret.Should().BeOfType(); - ret.ToBoolean().Should().BeTrue(); + ret.GetBoolean().Should().BeTrue(); ret = NativeContract.Policy.Call(snapshot, "getBlockedAccounts"); ret.Should().BeOfType(); @@ -263,7 +261,7 @@ public void Check_Block_UnblockAccount() ret = NativeContract.Policy.Call(snapshot, new Nep5NativeContractExtensions.ManualWitness(), "unblockAccount", new ContractParameter(ContractParameterType.Hash160) { Value = UInt160.Zero }); ret.Should().BeOfType(); - ret.ToBoolean().Should().BeFalse(); + ret.GetBoolean().Should().BeFalse(); ret = NativeContract.Policy.Call(snapshot, "getBlockedAccounts"); ret.Should().BeOfType(); @@ -275,7 +273,7 @@ public void Check_Block_UnblockAccount() ret = NativeContract.Policy.Call(snapshot, new Nep5NativeContractExtensions.ManualWitness(committeeMultiSigAddr), "unblockAccount", new ContractParameter(ContractParameterType.Hash160) { Value = UInt160.Zero }); ret.Should().BeOfType(); - ret.ToBoolean().Should().BeTrue(); + ret.GetBoolean().Should().BeTrue(); ret = NativeContract.Policy.Call(snapshot, "getBlockedAccounts"); ret.Should().BeOfType(); diff --git a/tests/neo.UnitTests/SmartContract/UT_ContainerPlaceholder.cs b/tests/neo.UnitTests/SmartContract/UT_ContainerPlaceholder.cs deleted file mode 100644 index 73023d6db8..0000000000 --- a/tests/neo.UnitTests/SmartContract/UT_ContainerPlaceholder.cs +++ /dev/null @@ -1,35 +0,0 @@ -using FluentAssertions; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Neo.SmartContract; -using Neo.VM.Types; -using System; - -namespace Neo.UnitTests.SmartContract -{ - [TestClass] - public class UT_ContainerPlaceholder - { - [TestMethod] - public void TestGenerator() - { - ContainerPlaceholder containerPlaceholder = new ContainerPlaceholder(StackItemType.Any, 0); - Assert.IsNotNull(containerPlaceholder); - } - - [TestMethod] - public void TestEquals() - { - ContainerPlaceholder containerPlaceholder = new ContainerPlaceholder(StackItemType.Any, 0); - Action action = () => containerPlaceholder.Equals(new Integer(0)); - action.Should().Throw(); - } - - [TestMethod] - public void TestGetBoolean() - { - ContainerPlaceholder containerPlaceholder = new ContainerPlaceholder(StackItemType.Any, 0); - Action action = () => containerPlaceholder.ToBoolean(); - action.Should().Throw(); - } - } -} diff --git a/tests/neo.UnitTests/SmartContract/UT_InteropService.NEO.cs b/tests/neo.UnitTests/SmartContract/UT_InteropService.NEO.cs index b0a2547107..283fdc1d3f 100644 --- a/tests/neo.UnitTests/SmartContract/UT_InteropService.NEO.cs +++ b/tests/neo.UnitTests/SmartContract/UT_InteropService.NEO.cs @@ -9,7 +9,6 @@ using Neo.SmartContract; using Neo.SmartContract.Iterators; using Neo.SmartContract.Manifest; -using Neo.VM; using Neo.VM.Types; using Neo.Wallets; using System; @@ -296,8 +295,8 @@ public void TestIterator_Create() }; ret = engine.CreateIterator(map); ret.Next(); - ret.Key().GetBigInteger().Should().Be(1); - ret.Value().GetBigInteger().Should().Be(2); + ret.Key().GetInteger().Should().Be(1); + ret.Value().GetInteger().Should().Be(2); } [TestMethod] @@ -310,7 +309,7 @@ public void TestIterator_Key() }; var wrapper = new ArrayWrapper(arr); wrapper.Next(); - engine.IteratorKey(wrapper).GetBigInteger().Should().Be(0); + engine.IteratorKey(wrapper).GetInteger().Should().Be(0); } [TestMethod] @@ -324,7 +323,7 @@ public void TestIterator_Keys() var wrapper = new ArrayWrapper(arr); var ret = engine.IteratorKeys(wrapper); ret.Next(); - ret.Value().GetBigInteger().Should().Be(0); + ret.Value().GetInteger().Should().Be(0); } [TestMethod] @@ -363,7 +362,7 @@ public void TestIterator_Concat() [TestMethod] public void TestJson_Deserialize() { - GetEngine().JsonDeserialize(new byte[] { (byte)'1' }).GetBigInteger().Should().Be(1); + GetEngine().JsonDeserialize(new byte[] { (byte)'1' }).GetInteger().Should().Be(1); } [TestMethod] diff --git a/tests/neo.UnitTests/SmartContract/UT_InteropService.cs b/tests/neo.UnitTests/SmartContract/UT_InteropService.cs index a72fb896c3..670c2530a5 100644 --- a/tests/neo.UnitTests/SmartContract/UT_InteropService.cs +++ b/tests/neo.UnitTests/SmartContract/UT_InteropService.cs @@ -297,7 +297,7 @@ public void TestRuntime_Serialize() public void TestRuntime_Deserialize() { var engine = GetEngine(); - engine.BinaryDeserialize(engine.BinarySerialize(100)).GetBigInteger().Should().Be(100); + engine.BinaryDeserialize(engine.BinarySerialize(100)).GetInteger().Should().Be(100); //FormatException Assert.ThrowsException(() => engine.BinaryDeserialize(new byte[] { 0xfa, 0x01 })); diff --git a/tests/neo.UnitTests/SmartContract/UT_JsonSerializer.cs b/tests/neo.UnitTests/SmartContract/UT_JsonSerializer.cs index 93100368a4..220627d5d0 100644 --- a/tests/neo.UnitTests/SmartContract/UT_JsonSerializer.cs +++ b/tests/neo.UnitTests/SmartContract/UT_JsonSerializer.cs @@ -1,7 +1,6 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Neo.IO.Json; using Neo.SmartContract; -using Neo.VM; using Neo.VM.Types; using System; using System.Linq; @@ -204,9 +203,7 @@ public void Serialize_EmptyObject() public void Serialize_Number() { var entry = new VM.Types.Array { 1, 9007199254740992 }; - var json = JsonSerializer.Serialize(entry).ToString(); - - Assert.AreEqual(json, "[1,\"9007199254740992\"]"); + Assert.ThrowsException(() => JsonSerializer.Serialize(entry)); } [TestMethod] @@ -262,12 +259,12 @@ public void Deserialize_Map_Test() var map = (Map)items; Assert.IsTrue(map.TryGetValue("test1", out var value)); - Assert.AreEqual(value.GetBigInteger(), 123); + Assert.AreEqual(value.GetInteger(), 123); Assert.IsTrue(map.TryGetValue("test2", out value)); - Assert.AreEqual(value.GetBigInteger(), 321); + Assert.AreEqual(value.GetInteger(), 321); - CollectionAssert.AreEqual(map.Values.Select(u => u.GetBigInteger()).ToArray(), new BigInteger[] { 123, 321 }); + CollectionAssert.AreEqual(map.Values.Select(u => u.GetInteger()).ToArray(), new BigInteger[] { 123, 321 }); } [TestMethod] @@ -290,9 +287,9 @@ public void Deserialize_Array_Bool_Str_Num() var array = (VM.Types.Array)items; - Assert.IsTrue(array[0].ToBoolean()); + Assert.IsTrue(array[0].GetBoolean()); Assert.AreEqual(array[1].GetString(), "test"); - Assert.AreEqual(array[2].GetBigInteger(), 123); + Assert.AreEqual(array[2].GetInteger(), 123); } [TestMethod] @@ -325,17 +322,17 @@ public void Deserialize_Array_OfArray() array = (VM.Types.Array)array[0]; Assert.AreEqual(array.Count, 3); - Assert.IsTrue(array[0].ToBoolean()); + Assert.IsTrue(array[0].GetBoolean()); Assert.AreEqual(array[1].GetString(), "test1"); - Assert.AreEqual(array[2].GetBigInteger(), 123); + Assert.AreEqual(array[2].GetInteger(), 123); array = (VM.Types.Array)items; array = (VM.Types.Array)array[1]; Assert.AreEqual(array.Count, 3); - Assert.IsTrue(array[0].ToBoolean()); + Assert.IsTrue(array[0].GetBoolean()); Assert.AreEqual(array[1].GetString(), "test2"); - Assert.AreEqual(array[2].GetBigInteger(), 321); + Assert.AreEqual(array[2].GetInteger(), 321); } } } diff --git a/tests/neo.UnitTests/SmartContract/UT_Syscalls.Callback.cs b/tests/neo.UnitTests/SmartContract/UT_Syscalls.Callback.cs index 633df8e7d7..e97e144637 100644 --- a/tests/neo.UnitTests/SmartContract/UT_Syscalls.Callback.cs +++ b/tests/neo.UnitTests/SmartContract/UT_Syscalls.Callback.cs @@ -62,7 +62,7 @@ public void InvokeCallbackTest() Assert.AreEqual(1, engine.ResultStack.Count); var item = engine.ResultStack.Pop(); - Assert.AreEqual(4, item.GetBigInteger()); + Assert.AreEqual(4, item.GetInteger()); } [TestMethod] diff --git a/tests/neo.UnitTests/SmartContract/UT_Syscalls.cs b/tests/neo.UnitTests/SmartContract/UT_Syscalls.cs index 12f576a092..192e7292ff 100644 --- a/tests/neo.UnitTests/SmartContract/UT_Syscalls.cs +++ b/tests/neo.UnitTests/SmartContract/UT_Syscalls.cs @@ -125,7 +125,7 @@ public void Json_Deserialize() Assert.AreEqual(2, engine.ResultStack.Count); engine.ResultStack.Pop(); - Assert.IsTrue(engine.ResultStack.Pop().GetBigInteger() == 123); + Assert.IsTrue(engine.ResultStack.Pop().GetInteger() == 123); } } @@ -286,7 +286,7 @@ public void System_Runtime_GasLeft() CollectionAssert.AreEqual ( - engine.ResultStack.Select(u => (int)((VM.Types.Integer)u).GetBigInteger()).ToArray(), + engine.ResultStack.Select(u => (int)u.GetInteger()).ToArray(), new int[] { 99_999_570, 99_999_140, 99_998_650 } ); } @@ -307,7 +307,7 @@ public void System_Runtime_GasLeft() Assert.AreEqual(engine.Execute(), VMState.HALT); Assert.AreEqual(1, engine.ResultStack.Count); Assert.IsInstanceOfType(engine.ResultStack.Peek(), typeof(Integer)); - Assert.AreEqual(-1, engine.ResultStack.Pop().GetBigInteger()); + Assert.AreEqual(-1, engine.ResultStack.Pop().GetInteger()); } } @@ -361,7 +361,7 @@ public void System_Runtime_GetInvocationCounter() CollectionAssert.AreEqual ( - engine.ResultStack.Select(u => (int)((VM.Types.Integer)u).GetBigInteger()).ToArray(), + engine.ResultStack.Select(u => (int)u.GetInteger()).ToArray(), new int[] { 1, /* A */ diff --git a/tests/neo.UnitTests/VM/UT_Helper.cs b/tests/neo.UnitTests/VM/UT_Helper.cs index 4c89fe09a5..9c22266069 100644 --- a/tests/neo.UnitTests/VM/UT_Helper.cs +++ b/tests/neo.UnitTests/VM/UT_Helper.cs @@ -150,19 +150,19 @@ public void TestToStackItem() Assert.ThrowsException(() => parameter.ToStackItem()); ContractParameter byteParameter = new ContractParameter { Type = ContractParameterType.ByteArray, Value = "00e057eb481b".HexToBytes() }; - Assert.AreEqual(30000000000000L, (long)byteParameter.ToStackItem().GetBigInteger()); + Assert.AreEqual(30000000000000L, (long)byteParameter.ToStackItem().GetInteger()); ContractParameter boolParameter = new ContractParameter { Type = ContractParameterType.Boolean, Value = false }; - Assert.AreEqual(false, boolParameter.ToStackItem().ToBoolean()); + Assert.AreEqual(false, boolParameter.ToStackItem().GetBoolean()); ContractParameter intParameter = new ContractParameter { Type = ContractParameterType.Integer, Value = new BigInteger(1000) }; - Assert.AreEqual(1000, intParameter.ToStackItem().GetBigInteger()); + Assert.AreEqual(1000, intParameter.ToStackItem().GetInteger()); ContractParameter h160Parameter = new ContractParameter { Type = ContractParameterType.Hash160, Value = UInt160.Zero }; - Assert.AreEqual(0, h160Parameter.ToStackItem().GetBigInteger()); + Assert.AreEqual(0, h160Parameter.ToStackItem().GetInteger()); ContractParameter h256Parameter = new ContractParameter { Type = ContractParameterType.Hash256, Value = UInt256.Zero }; - Assert.AreEqual(0, h256Parameter.ToStackItem().GetBigInteger()); + Assert.AreEqual(0, h256Parameter.ToStackItem().GetInteger()); ContractParameter pkParameter = new ContractParameter { Type = ContractParameterType.PublicKey, Value = ECPoint.Parse("02f9ec1fd0a98796cf75b586772a4ddd41a0af07a1dbdf86a7238f74fb72503575", ECCurve.Secp256r1) }; Assert.AreEqual("02f9ec1fd0a98796cf75b586772a4ddd41a0af07a1dbdf86a7238f74fb72503575", pkParameter.ToStackItem().GetSpan().ToHexString()); @@ -177,10 +177,10 @@ public void TestToStackItem() Assert.AreEqual(StackItem.Null, interopParameter2.ToStackItem()); ContractParameter arrayParameter = new ContractParameter { Type = ContractParameterType.Array, Value = new[] { byteParameter, boolParameter, intParameter, h160Parameter, h256Parameter, pkParameter, strParameter }.ToList() }; - Assert.AreEqual(1000, ((VM.Types.Array)arrayParameter.ToStackItem())[2].GetBigInteger()); + Assert.AreEqual(1000, ((VM.Types.Array)arrayParameter.ToStackItem())[2].GetInteger()); ContractParameter mapParameter = new ContractParameter { Type = ContractParameterType.Map, Value = new[] { new KeyValuePair(byteParameter, pkParameter) } }; - Assert.AreEqual(30000000000000L, (long)((VM.Types.Map)mapParameter.ToStackItem()).Keys.First().GetBigInteger()); + Assert.AreEqual(30000000000000L, (long)((VM.Types.Map)mapParameter.ToStackItem()).Keys.First().GetInteger()); } [TestMethod] From 801ac7f82331adf7d0f1b9a6d421d13eb12bb504 Mon Sep 17 00:00:00 2001 From: Shargon Date: Wed, 24 Jun 2020 08:50:00 +0200 Subject: [PATCH 06/32] Allow to iterate buffer (#1726) * Buffer iterator * Rename * Remove using Co-authored-by: Erik Zhang --- src/neo/SmartContract/ApplicationEngine.Iterator.cs | 1 + src/neo/SmartContract/Iterators/ByteArrayWrapper.cs | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/src/neo/SmartContract/ApplicationEngine.Iterator.cs b/src/neo/SmartContract/ApplicationEngine.Iterator.cs index 26ea78d695..c902c50979 100644 --- a/src/neo/SmartContract/ApplicationEngine.Iterator.cs +++ b/src/neo/SmartContract/ApplicationEngine.Iterator.cs @@ -20,6 +20,7 @@ internal IIterator CreateIterator(StackItem item) { Array array => new ArrayWrapper(array), Map map => new MapWrapper(map), + VM.Types.Buffer buffer => new ByteArrayWrapper(buffer), PrimitiveType primitive => new ByteArrayWrapper(primitive), _ => throw new ArgumentException() }; diff --git a/src/neo/SmartContract/Iterators/ByteArrayWrapper.cs b/src/neo/SmartContract/Iterators/ByteArrayWrapper.cs index f409b3beed..c26ca2b0e1 100644 --- a/src/neo/SmartContract/Iterators/ByteArrayWrapper.cs +++ b/src/neo/SmartContract/Iterators/ByteArrayWrapper.cs @@ -13,6 +13,11 @@ public ByteArrayWrapper(PrimitiveType value) this.array = value.GetSpan().ToArray(); } + public ByteArrayWrapper(VM.Types.Buffer value) + { + this.array = value.GetSpan().ToArray(); + } + public void Dispose() { } public PrimitiveType Key() From 66cfaf5ce16f14f0c7c2af914c083a08b0dc34c0 Mon Sep 17 00:00:00 2001 From: Harry Pierson Date: Wed, 24 Jun 2020 04:34:17 -0700 Subject: [PATCH 07/32] Update StorageContext.cs (#1728) StorageContext needs to be public so it can be accessed by Neo Debugger Co-authored-by: Erik Zhang --- src/neo/SmartContract/StorageContext.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/neo/SmartContract/StorageContext.cs b/src/neo/SmartContract/StorageContext.cs index 2944583f38..f9272269c8 100644 --- a/src/neo/SmartContract/StorageContext.cs +++ b/src/neo/SmartContract/StorageContext.cs @@ -1,6 +1,6 @@ namespace Neo.SmartContract { - internal class StorageContext + public class StorageContext { public int Id; public bool IsReadOnly; From ae0669639cd806fc8342ae2f75124d58213cdec8 Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Fri, 26 Jun 2020 15:30:47 +0800 Subject: [PATCH 08/32] Fix return value check (#1730) Co-authored-by: Shargon --- .../ApplicationEngine.Contract.cs | 2 ++ src/neo/SmartContract/ApplicationEngine.cs | 36 ++++++++++++------- 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/src/neo/SmartContract/ApplicationEngine.Contract.cs b/src/neo/SmartContract/ApplicationEngine.Contract.cs index 7ba4f0a33e..c537469da6 100644 --- a/src/neo/SmartContract/ApplicationEngine.Contract.cs +++ b/src/neo/SmartContract/ApplicationEngine.Contract.cs @@ -131,6 +131,8 @@ private void CallContractInternal(UInt160 contractHash, string method, Array arg invocationCounter[contract.ScriptHash] = 1; } + GetInvocationState(CurrentContext).NeedCheckReturnValue = true; + ExecutionContextState state = CurrentContext.GetState(); UInt160 callingScriptHash = state.ScriptHash; CallFlags callingFlags = state.CallFlags; diff --git a/src/neo/SmartContract/ApplicationEngine.cs b/src/neo/SmartContract/ApplicationEngine.cs index ca994e836f..30fc027be0 100644 --- a/src/neo/SmartContract/ApplicationEngine.cs +++ b/src/neo/SmartContract/ApplicationEngine.cs @@ -20,6 +20,7 @@ private class InvocationState { public Type ReturnType; public Delegate Callback; + public bool NeedCheckReturnValue; } public static event EventHandler Notify; @@ -64,33 +65,31 @@ internal void AddGas(long gas) internal void CallFromNativeContract(Action onComplete, UInt160 hash, string method, params StackItem[] args) { - invocationStates.Add(CurrentContext, new InvocationState - { - ReturnType = typeof(void), - Callback = onComplete - }); + InvocationState state = GetInvocationState(CurrentContext); + state.ReturnType = typeof(void); + state.Callback = onComplete; CallContract(hash, method, new VMArray(args)); } internal void CallFromNativeContract(Action onComplete, UInt160 hash, string method, params StackItem[] args) { - invocationStates.Add(CurrentContext, new InvocationState - { - ReturnType = typeof(T), - Callback = onComplete - }); + InvocationState state = GetInvocationState(CurrentContext); + state.ReturnType = typeof(T); + state.Callback = onComplete; CallContract(hash, method, new VMArray(args)); } protected override void ContextUnloaded(ExecutionContext context) { base.ContextUnloaded(context); - if (CurrentContext != null && context.EvaluationStack != CurrentContext.EvaluationStack) - if (context.EvaluationStack.Count == 0) - Push(StackItem.Null); if (!(UncaughtException is null)) return; if (invocationStates.Count == 0) return; if (!invocationStates.Remove(CurrentContext, out InvocationState state)) return; + if (state.NeedCheckReturnValue) + if (context.EvaluationStack.Count == 0) + Push(StackItem.Null); + else if (context.EvaluationStack.Count > 1) + throw new InvalidOperationException(); switch (state.Callback) { case null: @@ -104,6 +103,16 @@ protected override void ContextUnloaded(ExecutionContext context) } } + private InvocationState GetInvocationState(ExecutionContext context) + { + if (!invocationStates.TryGetValue(context, out InvocationState state)) + { + state = new InvocationState(); + invocationStates.Add(context, state); + } + return state; + } + protected override void LoadContext(ExecutionContext context) { // Set default execution context state @@ -114,6 +123,7 @@ protected override void LoadContext(ExecutionContext context) internal void LoadContext(ExecutionContext context, int initialPosition) { + GetInvocationState(CurrentContext).NeedCheckReturnValue = true; context.InstructionPointer = initialPosition; LoadContext(context); } From 087453742af12bf26b99cdfa034ee6b58e7aa110 Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Mon, 29 Jun 2020 15:36:35 +0800 Subject: [PATCH 09/32] Fix ContractEventDescriptor (#1733) --- src/neo/SmartContract/Manifest/ContractEventDescriptor.cs | 8 ++++---- src/neo/SmartContract/Native/Tokens/Nep5Token.cs | 5 ++--- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/neo/SmartContract/Manifest/ContractEventDescriptor.cs b/src/neo/SmartContract/Manifest/ContractEventDescriptor.cs index 0aa11a3eea..8be3806b03 100644 --- a/src/neo/SmartContract/Manifest/ContractEventDescriptor.cs +++ b/src/neo/SmartContract/Manifest/ContractEventDescriptor.cs @@ -25,13 +25,13 @@ public ContractEventDescriptor Clone() } /// - /// Parse ContractMethodDescription from json + /// Parse ContractEventDescriptor from json /// /// Json - /// Return ContractMethodDescription - public static ContractMethodDescriptor FromJson(JObject json) + /// Return ContractEventDescriptor + public static ContractEventDescriptor FromJson(JObject json) { - return new ContractMethodDescriptor + return new ContractEventDescriptor { Name = json["name"].AsString(), Parameters = ((JArray)json["parameters"]).Select(u => ContractParameterDefinition.FromJson(u)).ToArray(), diff --git a/src/neo/SmartContract/Native/Tokens/Nep5Token.cs b/src/neo/SmartContract/Native/Tokens/Nep5Token.cs index 852f1f00da..bc417cf931 100644 --- a/src/neo/SmartContract/Native/Tokens/Nep5Token.cs +++ b/src/neo/SmartContract/Native/Tokens/Nep5Token.cs @@ -31,7 +31,7 @@ protected Nep5Token() var events = new List(Manifest.Abi.Events) { - new ContractMethodDescriptor() + new ContractEventDescriptor { Name = "Transfer", Parameters = new ContractParameterDefinition[] @@ -51,8 +51,7 @@ protected Nep5Token() Name = "amount", Type = ContractParameterType.Integer } - }, - ReturnType = ContractParameterType.Boolean + } } }; From 5ddf54bb533dc353e17be3101b32493ffb056d6c Mon Sep 17 00:00:00 2001 From: Luchuan Date: Wed, 1 Jul 2020 18:36:26 +0800 Subject: [PATCH 10/32] fix enumerator (#1744) Co-authored-by: Tommo-L --- src/neo/SmartContract/ApplicationEngine.Enumerator.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/neo/SmartContract/ApplicationEngine.Enumerator.cs b/src/neo/SmartContract/ApplicationEngine.Enumerator.cs index 5bfc2ae48b..02f1409310 100644 --- a/src/neo/SmartContract/ApplicationEngine.Enumerator.cs +++ b/src/neo/SmartContract/ApplicationEngine.Enumerator.cs @@ -18,6 +18,7 @@ internal IEnumerator CreateEnumerator(StackItem item) return item switch { Array array => new ArrayWrapper(array), + VM.Types.Buffer buffer => new ByteArrayWrapper(buffer), PrimitiveType primitive => new ByteArrayWrapper(primitive), _ => throw new ArgumentException() }; From 76448e1fa771754e3ca6c44dc48a224e14481142 Mon Sep 17 00:00:00 2001 From: joeqian Date: Thu, 2 Jul 2020 11:52:09 +0800 Subject: [PATCH 11/32] Change json fields to all lower case for consistency (#1736) --- src/neo/Ledger/TrimmedBlock.cs | 2 +- src/neo/Network/P2P/Payloads/Block.cs | 2 +- src/neo/Network/P2P/Payloads/Cosigner.cs | 4 ++-- src/neo/Network/P2P/Payloads/Transaction.cs | 6 +++--- src/neo/SmartContract/Manifest/ContractGroup.cs | 4 ++-- src/neo/SmartContract/Manifest/ContractManifest.cs | 4 ++-- .../Manifest/ContractMethodDescriptor.cs | 4 ++-- src/neo/Wallets/NEP6/NEP6Account.cs | 4 ++-- .../neo.UnitTests/Network/P2P/Payloads/UT_Block.cs | 2 +- .../Network/P2P/Payloads/UT_Cosigner.cs | 4 ++-- .../Network/P2P/Payloads/UT_Transaction.cs | 4 ++-- .../SmartContract/Manifest/UT_ContractManifest.cs | 14 +++++++------- tests/neo.UnitTests/Wallets/NEP6/UT_NEP6Account.cs | 4 ++-- 13 files changed, 29 insertions(+), 29 deletions(-) diff --git a/src/neo/Ledger/TrimmedBlock.cs b/src/neo/Ledger/TrimmedBlock.cs index 2a6f84672b..5b58e40246 100644 --- a/src/neo/Ledger/TrimmedBlock.cs +++ b/src/neo/Ledger/TrimmedBlock.cs @@ -106,7 +106,7 @@ public override void Serialize(BinaryWriter writer) public override JObject ToJson() { JObject json = base.ToJson(); - json["consensus_data"] = ConsensusData?.ToJson(); + json["consensusdata"] = ConsensusData?.ToJson(); json["hashes"] = Hashes.Select(p => (JObject)p.ToString()).ToArray(); return json; } diff --git a/src/neo/Network/P2P/Payloads/Block.cs b/src/neo/Network/P2P/Payloads/Block.cs index 82b25252d3..bbea8db9cc 100644 --- a/src/neo/Network/P2P/Payloads/Block.cs +++ b/src/neo/Network/P2P/Payloads/Block.cs @@ -108,7 +108,7 @@ public override void Serialize(BinaryWriter writer) public override JObject ToJson() { JObject json = base.ToJson(); - json["consensus_data"] = ConsensusData.ToJson(); + json["consensusdata"] = ConsensusData.ToJson(); json["tx"] = Transactions.Select(p => p.ToJson()).ToArray(); return json; } diff --git a/src/neo/Network/P2P/Payloads/Cosigner.cs b/src/neo/Network/P2P/Payloads/Cosigner.cs index 6677c688ea..ba8a6fa3dd 100644 --- a/src/neo/Network/P2P/Payloads/Cosigner.cs +++ b/src/neo/Network/P2P/Payloads/Cosigner.cs @@ -53,9 +53,9 @@ public override JObject ToJson() json["account"] = Account.ToString(); json["scopes"] = Scopes; if (Scopes.HasFlag(WitnessScope.CustomContracts)) - json["allowedContracts"] = AllowedContracts.Select(p => (JObject)p.ToString()).ToArray(); + json["allowedcontracts"] = AllowedContracts.Select(p => (JObject)p.ToString()).ToArray(); if (Scopes.HasFlag(WitnessScope.CustomGroups)) - json["allowedGroups"] = AllowedGroups.Select(p => (JObject)p.ToString()).ToArray(); + json["allowedgroups"] = AllowedGroups.Select(p => (JObject)p.ToString()).ToArray(); return json; } } diff --git a/src/neo/Network/P2P/Payloads/Transaction.cs b/src/neo/Network/P2P/Payloads/Transaction.cs index 10591659ca..127f56cb17 100644 --- a/src/neo/Network/P2P/Payloads/Transaction.cs +++ b/src/neo/Network/P2P/Payloads/Transaction.cs @@ -247,9 +247,9 @@ public JObject ToJson() json["version"] = Version; json["nonce"] = Nonce; json["sender"] = Sender.ToAddress(); - json["sys_fee"] = SystemFee.ToString(); - json["net_fee"] = NetworkFee.ToString(); - json["valid_until_block"] = ValidUntilBlock; + json["sysfee"] = SystemFee.ToString(); + json["netfee"] = NetworkFee.ToString(); + json["validuntilblock"] = ValidUntilBlock; 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/SmartContract/Manifest/ContractGroup.cs b/src/neo/SmartContract/Manifest/ContractGroup.cs index 8cb6ced3b8..95b3d7e82b 100644 --- a/src/neo/SmartContract/Manifest/ContractGroup.cs +++ b/src/neo/SmartContract/Manifest/ContractGroup.cs @@ -40,7 +40,7 @@ public static ContractGroup FromJson(JObject json) { return new ContractGroup { - PubKey = ECPoint.Parse(json["pubKey"].AsString(), ECCurve.Secp256r1), + PubKey = ECPoint.Parse(json["pubkey"].AsString(), ECCurve.Secp256r1), Signature = Convert.FromBase64String(json["signature"].AsString()), }; } @@ -58,7 +58,7 @@ public bool IsValid(UInt160 hash) public virtual JObject ToJson() { var json = new JObject(); - json["pubKey"] = PubKey.ToString(); + json["pubkey"] = PubKey.ToString(); json["signature"] = Convert.ToBase64String(Signature); return json; } diff --git a/src/neo/SmartContract/Manifest/ContractManifest.cs b/src/neo/SmartContract/Manifest/ContractManifest.cs index 1d6124c334..b68eefbe89 100644 --- a/src/neo/SmartContract/Manifest/ContractManifest.cs +++ b/src/neo/SmartContract/Manifest/ContractManifest.cs @@ -111,7 +111,7 @@ public JObject ToJson() json["abi"] = Abi.ToJson(); json["permissions"] = Permissions.Select(p => p.ToJson()).ToArray(); json["trusts"] = Trusts.ToJson(); - json["safeMethods"] = SafeMethods.ToJson(); + json["safemethods"] = SafeMethods.ToJson(); json["extra"] = Extra; return json; @@ -158,7 +158,7 @@ private void DeserializeFromJson(JObject json) Features = ContractFeatures.NoProperty; 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()); + 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/Manifest/ContractMethodDescriptor.cs b/src/neo/SmartContract/Manifest/ContractMethodDescriptor.cs index 873999096a..ecae987758 100644 --- a/src/neo/SmartContract/Manifest/ContractMethodDescriptor.cs +++ b/src/neo/SmartContract/Manifest/ContractMethodDescriptor.cs @@ -43,7 +43,7 @@ public int Offset Name = json["name"].AsString(), Parameters = ((JArray)json["parameters"]).Select(u => ContractParameterDefinition.FromJson(u)).ToArray(), Offset = (int)json["offset"].AsNumber(), - ReturnType = (ContractParameterType)Enum.Parse(typeof(ContractParameterType), json["returnType"].AsString()), + ReturnType = (ContractParameterType)Enum.Parse(typeof(ContractParameterType), json["returntype"].AsString()), }; } @@ -51,7 +51,7 @@ public override JObject ToJson() { var json = base.ToJson(); json["offset"] = Offset; - json["returnType"] = ReturnType.ToString(); + json["returntype"] = ReturnType.ToString(); return json; } } diff --git a/src/neo/Wallets/NEP6/NEP6Account.cs b/src/neo/Wallets/NEP6/NEP6Account.cs index 58ed806fb1..870b449400 100644 --- a/src/neo/Wallets/NEP6/NEP6Account.cs +++ b/src/neo/Wallets/NEP6/NEP6Account.cs @@ -33,7 +33,7 @@ public static NEP6Account FromJson(JObject json, NEP6Wallet wallet) return new NEP6Account(wallet, json["address"].AsString().ToScriptHash(), json["key"]?.AsString()) { Label = json["label"]?.AsString(), - IsDefault = json["isDefault"].AsBoolean(), + IsDefault = json["isdefault"].AsBoolean(), Lock = json["lock"].AsBoolean(), Contract = NEP6Contract.FromJson(json["contract"]), Extra = json["extra"] @@ -65,7 +65,7 @@ public JObject ToJson() JObject account = new JObject(); account["address"] = ScriptHash.ToAddress(); account["label"] = Label; - account["isDefault"] = IsDefault; + account["isdefault"] = IsDefault; account["lock"] = Lock; account["key"] = nep2key; account["contract"] = ((NEP6Contract)Contract)?.ToJson(); diff --git a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Block.cs b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Block.cs index 0e36930f0b..1efd90a3a8 100644 --- a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Block.cs +++ b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Block.cs @@ -218,7 +218,7 @@ public void ToJson() txObj[0]["size"].AsNumber().Should().Be(51); txObj[0]["version"].AsNumber().Should().Be(0); ((JArray)txObj[0]["attributes"]).Count.Should().Be(0); - txObj[0]["net_fee"].AsString().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_Cosigner.cs index 87ea4c8c26..22ca14cb82 100644 --- a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Cosigner.cs +++ b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Cosigner.cs @@ -121,7 +121,7 @@ public void Json_CustomContracts() Account = UInt160.Zero }; - var json = "{\"type\":\"Cosigner\",\"account\":\"0x0000000000000000000000000000000000000000\",\"scopes\":\"CustomContracts\",\"allowedContracts\":[\"0x0000000000000000000000000000000000000000\"]}"; + var json = "{\"type\":\"Cosigner\",\"account\":\"0x0000000000000000000000000000000000000000\",\"scopes\":\"CustomContracts\",\"allowedcontracts\":[\"0x0000000000000000000000000000000000000000\"]}"; attr.ToJson().ToString().Should().Be(json); } @@ -135,7 +135,7 @@ public void Json_CustomGroups() Account = UInt160.Zero }; - var json = "{\"type\":\"Cosigner\",\"account\":\"0x0000000000000000000000000000000000000000\",\"scopes\":\"CustomGroups\",\"allowedGroups\":[\"03b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c\"]}"; + var json = "{\"type\":\"Cosigner\",\"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 5425b71974..61ea913867 100644 --- a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs +++ b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs @@ -1031,9 +1031,9 @@ public void ToJson() jObj["size"].AsNumber().Should().Be(82); jObj["version"].AsNumber().Should().Be(0); ((JArray)jObj["attributes"]).Count.Should().Be(0); - jObj["net_fee"].AsString().Should().Be("0"); + jObj["netfee"].AsString().Should().Be("0"); jObj["script"].AsString().Should().Be("QiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA="); - jObj["sys_fee"].AsString().Should().Be("4200000000"); + jObj["sysfee"].AsString().Should().Be("4200000000"); } } } diff --git a/tests/neo.UnitTests/SmartContract/Manifest/UT_ContractManifest.cs b/tests/neo.UnitTests/SmartContract/Manifest/UT_ContractManifest.cs index 1df0b7ec07..ef2df0acff 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},""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},""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},""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},""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},""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},""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},""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); diff --git a/tests/neo.UnitTests/Wallets/NEP6/UT_NEP6Account.cs b/tests/neo.UnitTests/Wallets/NEP6/UT_NEP6Account.cs index addfc5b54e..e2cb70b11a 100644 --- a/tests/neo.UnitTests/Wallets/NEP6/UT_NEP6Account.cs +++ b/tests/neo.UnitTests/Wallets/NEP6/UT_NEP6Account.cs @@ -83,7 +83,7 @@ public void TestFromJson() json["address"] = "NdtB8RXRmJ7Nhw1FPTm7E6HoDZGnDw37nf"; json["key"] = null; json["label"] = null; - json["isDefault"] = true; + json["isdefault"] = true; json["lock"] = false; json["contract"] = null; json["extra"] = null; @@ -138,7 +138,7 @@ public void TestToJson() JObject json = _account.ToJson(); json["address"].Should().Equals("AZk5bAanTtD6AvpeesmYgL8CLRYUt5JQsX"); json["label"].Should().BeNull(); - json["isDefault"].ToString().Should().Be("false"); + json["isdefault"].ToString().Should().Be("false"); json["lock"].ToString().Should().Be("false"); json["key"].Should().BeNull(); json["contract"]["script"].ToString().Should().Be(@"""IQNgPziA63rqCtRQCJOSXkpC/qSKRO5viYoQs8fOBdKiZ6w="""); From 9001938c9e73fb045a4ce2105e331336b3427e7d Mon Sep 17 00:00:00 2001 From: Luchuan Date: Fri, 3 Jul 2020 02:39:36 +0800 Subject: [PATCH 12/32] Replace DataCache.Find by DataCache.Seek (#1740) * replace DataCache.Find by DataCache.Seek * fix order * optimize * Update ByteArrayComparer.cs * Update ByteArrayComparer.cs * Update DataCache.cs * fix comments * fix comments * fix comments * Update DataCache.cs * Update DataCache.cs * Reorder methods Co-authored-by: Tommo-L Co-authored-by: erikzhang Co-authored-by: Shargon --- src/neo/IO/ByteArrayComparer.cs | 19 ++- src/neo/IO/Caching/CloneCache.cs | 10 +- src/neo/IO/Caching/DataCache.cs | 120 +++++++++++------- src/neo/IO/Caching/SeekDirection.cs | 8 ++ src/neo/Persistence/IReadOnlyStore.cs | 3 +- src/neo/Persistence/MemorySnapshot.cs | 18 +-- src/neo/Persistence/MemoryStore.cs | 22 ++-- src/neo/Persistence/StoreDataCache.cs | 8 +- .../neo.UnitTests/IO/Caching/UT_DataCache.cs | 42 +++++- .../neo.UnitTests/IO/UT_ByteArrayComparer.cs | 12 +- 10 files changed, 181 insertions(+), 81 deletions(-) create mode 100644 src/neo/IO/Caching/SeekDirection.cs diff --git a/src/neo/IO/ByteArrayComparer.cs b/src/neo/IO/ByteArrayComparer.cs index 478c6e3c7d..8e9b2573c0 100644 --- a/src/neo/IO/ByteArrayComparer.cs +++ b/src/neo/IO/ByteArrayComparer.cs @@ -1,13 +1,30 @@ using System; using System.Collections.Generic; +using System.Runtime.CompilerServices; namespace Neo.IO { internal class ByteArrayComparer : IComparer { - public static readonly ByteArrayComparer Default = new ByteArrayComparer(); + public static readonly ByteArrayComparer Default = new ByteArrayComparer(1); + public static readonly ByteArrayComparer Reverse = new ByteArrayComparer(-1); + + private readonly int direction; + + private ByteArrayComparer(int direction) + { + this.direction = direction; + } public int Compare(byte[] x, byte[] y) + { + return direction > 0 + ? CompareInternal(x, y) + : -CompareInternal(x, y); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static int CompareInternal(byte[] x, byte[] y) { int length = Math.Min(x.Length, y.Length); for (int i = 0; i < length; i++) diff --git a/src/neo/IO/Caching/CloneCache.cs b/src/neo/IO/Caching/CloneCache.cs index 559ee3d279..93e01e115a 100644 --- a/src/neo/IO/Caching/CloneCache.cs +++ b/src/neo/IO/Caching/CloneCache.cs @@ -24,15 +24,15 @@ protected override void DeleteInternal(TKey key) innerCache.Delete(key); } - protected override IEnumerable<(TKey, TValue)> FindInternal(byte[] key_prefix) + protected override TValue GetInternal(TKey key) { - foreach (var (key, value) in innerCache.Find(key_prefix)) - yield return (key, value.Clone()); + return innerCache[key].Clone(); } - protected override TValue GetInternal(TKey key) + protected override IEnumerable<(TKey, TValue)> SeekInternal(byte[] keyOrPreifx, SeekDirection direction) { - return innerCache[key].Clone(); + foreach (var (key, value) in innerCache.Seek(keyOrPreifx, direction)) + yield return (key, value.Clone()); } protected override TValue TryGetInternal(TKey key) diff --git a/src/neo/IO/Caching/DataCache.cs b/src/neo/IO/Caching/DataCache.cs index 4b39b5b7cc..21e4f95bb4 100644 --- a/src/neo/IO/Caching/DataCache.cs +++ b/src/neo/IO/Caching/DataCache.cs @@ -151,57 +151,18 @@ public void Delete(TKey key) /// Entries found with the desired prefix public IEnumerable<(TKey Key, TValue Value)> Find(byte[] key_prefix = null) { - IEnumerable<(byte[], TKey, TValue)> cached; - HashSet cachedKeySet; - lock (dictionary) - { - cached = dictionary - .Where(p => p.Value.State != TrackState.Deleted && (key_prefix == null || p.Key.ToArray().AsSpan().StartsWith(key_prefix))) - .Select(p => - ( - KeyBytes: p.Key.ToArray(), - p.Key, - p.Value.Item - )) - .OrderBy(p => p.KeyBytes, ByteArrayComparer.Default) - .ToArray(); - cachedKeySet = new HashSet(dictionary.Keys); - } - var uncached = FindInternal(key_prefix ?? Array.Empty()) - .Where(p => !cachedKeySet.Contains(p.Key)) - .Select(p => - ( - KeyBytes: p.Key.ToArray(), - p.Key, - p.Value - )); - using (var e1 = cached.GetEnumerator()) - using (var e2 = uncached.GetEnumerator()) - { - (byte[] KeyBytes, TKey Key, TValue Item) i1, i2; - bool c1 = e1.MoveNext(); - bool c2 = e2.MoveNext(); - i1 = c1 ? e1.Current : default; - i2 = c2 ? e2.Current : default; - while (c1 || c2) - { - if (!c2 || (c1 && ByteArrayComparer.Default.Compare(i1.KeyBytes, i2.KeyBytes) < 0)) - { - yield return (i1.Key, i1.Item); - c1 = e1.MoveNext(); - i1 = c1 ? e1.Current : default; - } - else - { - yield return (i2.Key, i2.Item); - c2 = e2.MoveNext(); - i2 = c2 ? e2.Current : default; - } - } - } + foreach (var (key, value) in Seek(key_prefix, SeekDirection.Forward)) + if (key.ToArray().AsSpan().StartsWith(key_prefix)) + yield return (key, value); } - protected abstract IEnumerable<(TKey Key, TValue Value)> FindInternal(byte[] key_prefix); + public IEnumerable<(TKey Key, TValue Value)> FindRange(TKey start, TKey end) + { + var endKey = end.ToArray(); + foreach (var (key, value) in Seek(start.ToArray(), SeekDirection.Forward)) + if (ByteArrayComparer.Default.Compare(key.ToArray(), endKey) < 0) + yield return (key, value); + } public IEnumerable GetChangeSet() { @@ -299,6 +260,67 @@ public TValue GetOrAdd(TKey key, Func factory) } } + /// + /// Seek to the entry with specific key + /// + /// The key to be sought + /// The direction of seek + /// An enumerator containing all the entries after seeking. + public IEnumerable<(TKey Key, TValue Value)> Seek(byte[] keyOrPrefix = null, SeekDirection direction = SeekDirection.Forward) + { + IEnumerable<(byte[], TKey, TValue)> cached; + HashSet cachedKeySet; + ByteArrayComparer comparer = direction == SeekDirection.Forward ? ByteArrayComparer.Default : ByteArrayComparer.Reverse; + lock (dictionary) + { + cached = dictionary + .Where(p => p.Value.State != TrackState.Deleted && (keyOrPrefix == null || comparer.Compare(p.Key.ToArray(), keyOrPrefix) >= 0)) + .Select(p => + ( + KeyBytes: p.Key.ToArray(), + p.Key, + p.Value.Item + )) + .OrderBy(p => p.KeyBytes, comparer) + .ToArray(); + cachedKeySet = new HashSet(dictionary.Keys); + } + var uncached = SeekInternal(keyOrPrefix ?? Array.Empty(), direction) + .Where(p => !cachedKeySet.Contains(p.Key)) + .Select(p => + ( + KeyBytes: p.Key.ToArray(), + p.Key, + p.Value + )); + using (var e1 = cached.GetEnumerator()) + using (var e2 = uncached.GetEnumerator()) + { + (byte[] KeyBytes, TKey Key, TValue Item) i1, i2; + bool c1 = e1.MoveNext(); + bool c2 = e2.MoveNext(); + i1 = c1 ? e1.Current : default; + i2 = c2 ? e2.Current : default; + while (c1 || c2) + { + if (!c2 || (c1 && comparer.Compare(i1.KeyBytes, i2.KeyBytes) < 0)) + { + yield return (i1.Key, i1.Item); + c1 = e1.MoveNext(); + i1 = c1 ? e1.Current : default; + } + else + { + yield return (i2.Key, i2.Item); + c2 = e2.MoveNext(); + i2 = c2 ? e2.Current : default; + } + } + } + } + + protected abstract IEnumerable<(TKey Key, TValue Value)> SeekInternal(byte[] keyOrPrefix, SeekDirection direction); + public TValue TryGet(TKey key) { lock (dictionary) diff --git a/src/neo/IO/Caching/SeekDirection.cs b/src/neo/IO/Caching/SeekDirection.cs new file mode 100644 index 0000000000..5387fd8311 --- /dev/null +++ b/src/neo/IO/Caching/SeekDirection.cs @@ -0,0 +1,8 @@ +namespace Neo.IO.Caching +{ + public enum SeekDirection : sbyte + { + Forward = 1, + Backward = -1 + } +} diff --git a/src/neo/Persistence/IReadOnlyStore.cs b/src/neo/Persistence/IReadOnlyStore.cs index 7a23bd4c80..234a36f534 100644 --- a/src/neo/Persistence/IReadOnlyStore.cs +++ b/src/neo/Persistence/IReadOnlyStore.cs @@ -1,3 +1,4 @@ +using Neo.IO.Caching; using System.Collections.Generic; namespace Neo.Persistence @@ -7,7 +8,7 @@ namespace Neo.Persistence /// public interface IReadOnlyStore { - IEnumerable<(byte[] Key, byte[] Value)> Find(byte table, byte[] prefix); + IEnumerable<(byte[] Key, byte[] Value)> Seek(byte table, byte[] key, SeekDirection direction); byte[] TryGet(byte table, byte[] key); } } diff --git a/src/neo/Persistence/MemorySnapshot.cs b/src/neo/Persistence/MemorySnapshot.cs index 5b1dc35742..1474b26df7 100644 --- a/src/neo/Persistence/MemorySnapshot.cs +++ b/src/neo/Persistence/MemorySnapshot.cs @@ -1,4 +1,5 @@ using Neo.IO; +using Neo.IO.Caching; using System; using System.Collections.Concurrent; using System.Collections.Generic; @@ -41,18 +42,19 @@ public void Dispose() { } - public IEnumerable<(byte[] Key, byte[] Value)> Find(byte table, byte[] prefix) + public void Put(byte table, byte[] key, byte[] value) { - IEnumerable> records = immutableData[table]; - if (prefix?.Length > 0) - records = records.Where(p => p.Key.AsSpan().StartsWith(prefix)); - records = records.OrderBy(p => p.Key, ByteArrayComparer.Default); - return records.Select(p => (p.Key, p.Value)); + writeBatch[table][key.EnsureNotNull()] = value; } - public void Put(byte table, byte[] key, byte[] value) + public IEnumerable<(byte[] Key, byte[] Value)> Seek(byte table, byte[] keyOrPrefix, SeekDirection direction = SeekDirection.Forward) { - writeBatch[table][key.EnsureNotNull()] = value; + ByteArrayComparer comparer = direction == SeekDirection.Forward ? ByteArrayComparer.Default : ByteArrayComparer.Reverse; + IEnumerable> records = immutableData[table]; + if (keyOrPrefix?.Length > 0) + records = records.Where(p => comparer.Compare(p.Key, keyOrPrefix) >= 0); + records = records.OrderBy(p => p.Key, comparer); + return records.Select(p => (p.Key, p.Value)); } public byte[] TryGet(byte table, byte[] key) diff --git a/src/neo/Persistence/MemoryStore.cs b/src/neo/Persistence/MemoryStore.cs index 5b6c09c58f..67bdd04152 100644 --- a/src/neo/Persistence/MemoryStore.cs +++ b/src/neo/Persistence/MemoryStore.cs @@ -1,4 +1,5 @@ using Neo.IO; +using Neo.IO.Caching; using System; using System.Collections.Concurrent; using System.Collections.Generic; @@ -26,16 +27,6 @@ public void Dispose() { } - public IEnumerable<(byte[] Key, byte[] Value)> Find(byte table, byte[] prefix) - { - IEnumerable> records = innerData[table]; - if (prefix?.Length > 0) - records = records.Where(p => p.Key.AsSpan().StartsWith(prefix)); - records = records.OrderBy(p => p.Key, ByteArrayComparer.Default); - foreach (var pair in records) - yield return (pair.Key, pair.Value); - } - public ISnapshot GetSnapshot() { return new MemorySnapshot(innerData); @@ -46,6 +37,17 @@ public void Put(byte table, byte[] key, byte[] value) innerData[table][key.EnsureNotNull()] = value; } + public IEnumerable<(byte[] Key, byte[] Value)> Seek(byte table, byte[] keyOrPrefix, SeekDirection direction = SeekDirection.Forward) + { + ByteArrayComparer comparer = direction == SeekDirection.Forward ? ByteArrayComparer.Default : ByteArrayComparer.Reverse; + IEnumerable> records = innerData[table]; + if (keyOrPrefix?.Length > 0) + records = records.Where(p => comparer.Compare(p.Key, keyOrPrefix) >= 0); + records = records.OrderBy(p => p.Key, comparer); + foreach (var pair in records) + yield return (pair.Key, pair.Value); + } + public byte[] TryGet(byte table, byte[] key) { innerData[table].TryGetValue(key.EnsureNotNull(), out byte[] value); diff --git a/src/neo/Persistence/StoreDataCache.cs b/src/neo/Persistence/StoreDataCache.cs index 995a34290f..831c88dce1 100644 --- a/src/neo/Persistence/StoreDataCache.cs +++ b/src/neo/Persistence/StoreDataCache.cs @@ -31,14 +31,14 @@ protected override void DeleteInternal(TKey key) snapshot?.Delete(prefix, key.ToArray()); } - protected override IEnumerable<(TKey, TValue)> FindInternal(byte[] key_prefix) + protected override TValue GetInternal(TKey key) { - return store.Find(prefix, key_prefix).Select(p => (p.Key.AsSerializable(), p.Value.AsSerializable())); + return store.TryGet(prefix, key.ToArray()).AsSerializable(); } - protected override TValue GetInternal(TKey key) + protected override IEnumerable<(TKey, TValue)> SeekInternal(byte[] keyOrPrefix, SeekDirection direction) { - return store.TryGet(prefix, key.ToArray()).AsSerializable(); + return store.Seek(prefix, keyOrPrefix, direction).Select(p => (p.Key.AsSerializable(), p.Value.AsSerializable())); } protected override TValue TryGetInternal(TKey key) diff --git a/tests/neo.UnitTests/IO/Caching/UT_DataCache.cs b/tests/neo.UnitTests/IO/Caching/UT_DataCache.cs index 2b07c8fa0c..74f3213f82 100644 --- a/tests/neo.UnitTests/IO/Caching/UT_DataCache.cs +++ b/tests/neo.UnitTests/IO/Caching/UT_DataCache.cs @@ -115,9 +115,10 @@ protected override void AddInternal(TKey key, TValue value) InnerDict.Add(key, value); } - protected override IEnumerable<(TKey, TValue)> FindInternal(byte[] key_prefix) + protected override IEnumerable<(TKey, TValue)> SeekInternal(byte[] keyOrPrefix, SeekDirection direction = SeekDirection.Forward) { - return InnerDict.Where(kvp => kvp.Key.ToArray().Take(key_prefix.Length).SequenceEqual(key_prefix)).Select(p => (p.Key, p.Value)); + ByteArrayComparer comparer = direction == SeekDirection.Forward ? ByteArrayComparer.Default : ByteArrayComparer.Reverse; + return InnerDict.Where(kvp => comparer.Compare(kvp.Key.ToArray(), keyOrPrefix) >= 0).Select(p => (p.Key, p.Value)); } protected override TValue GetInternal(TKey key) @@ -264,6 +265,43 @@ public void TestFind() items.Count().Should().Be(0); } + [TestMethod] + public void TestSeek() + { + myDataCache.Add(new MyKey("key1"), new MyValue("value1")); + myDataCache.Add(new MyKey("key2"), new MyValue("value2")); + + myDataCache.InnerDict.Add(new MyKey("key3"), new MyValue("value3")); + myDataCache.InnerDict.Add(new MyKey("key4"), new MyValue("value4")); + + var items = myDataCache.Seek(new MyKey("key3").ToArray(), SeekDirection.Backward).ToArray(); + items[0].Key.Should().Be(new MyKey("key3")); + items[0].Value.Should().Be(new MyValue("value3")); + items[1].Key.Should().Be(new MyKey("key2")); + items[1].Value.Should().Be(new MyValue("value2")); + items.Count().Should().Be(3); + + items = myDataCache.Seek(new MyKey("key5").ToArray(), SeekDirection.Forward).ToArray(); + items.Count().Should().Be(0); + } + + [TestMethod] + public void TestFindRange() + { + myDataCache.Add(new MyKey("key1"), new MyValue("value1")); + myDataCache.Add(new MyKey("key2"), new MyValue("value2")); + + myDataCache.InnerDict.Add(new MyKey("key3"), new MyValue("value3")); + myDataCache.InnerDict.Add(new MyKey("key4"), new MyValue("value4")); + + var items = myDataCache.FindRange(new MyKey("key3"), new MyKey("key5")).ToArray(); + items[0].Key.Should().Be(new MyKey("key3")); + items[0].Value.Should().Be(new MyValue("value3")); + items[1].Key.Should().Be(new MyKey("key4")); + items[1].Value.Should().Be(new MyValue("value4")); + items.Count().Should().Be(2); + } + [TestMethod] public void TestGetChangeSet() { diff --git a/tests/neo.UnitTests/IO/UT_ByteArrayComparer.cs b/tests/neo.UnitTests/IO/UT_ByteArrayComparer.cs index 562e2b6f6e..89c0c621d7 100644 --- a/tests/neo.UnitTests/IO/UT_ByteArrayComparer.cs +++ b/tests/neo.UnitTests/IO/UT_ByteArrayComparer.cs @@ -10,7 +10,7 @@ public class UT_ByteArrayComparer [TestMethod] public void TestCompare() { - ByteArrayComparer comparer = new ByteArrayComparer(); + ByteArrayComparer comparer = ByteArrayComparer.Default; byte[] x = new byte[0], y = new byte[0]; comparer.Compare(x, y).Should().Be(0); @@ -22,6 +22,16 @@ public void TestCompare() x = new byte[] { 1 }; y = new byte[] { 2 }; comparer.Compare(x, y).Should().Be(-1); + + comparer = ByteArrayComparer.Reverse; + x = new byte[] { 3 }; + comparer.Compare(x, y).Should().Be(-1); + y = x; + comparer.Compare(x, y).Should().Be(0); + + x = new byte[] { 1 }; + y = new byte[] { 2 }; + comparer.Compare(x, y).Should().Be(1); } } } From ad5816ac0e3eff4de3c2722161f42e9607211daf Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Fri, 3 Jul 2020 14:10:22 +0800 Subject: [PATCH 13/32] Add MaxVerificationGas (#1745) Co-authored-by: Shargon --- src/neo/SmartContract/Helper.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/neo/SmartContract/Helper.cs b/src/neo/SmartContract/Helper.cs index a365806b87..6fedd8b9f9 100644 --- a/src/neo/SmartContract/Helper.cs +++ b/src/neo/SmartContract/Helper.cs @@ -13,6 +13,8 @@ namespace Neo.SmartContract { public static class Helper { + private const long MaxVerificationGas = 0_50000000; + public static UInt160 GetScriptHash(this ExecutionContext context) { return context.GetState().ScriptHash; @@ -130,6 +132,7 @@ public static UInt160 ToScriptHash(this ReadOnlySpan script) internal static bool VerifyWitnesses(this IVerifiable verifiable, StoreView snapshot, long gas) { if (gas < 0) return false; + if (gas > MaxVerificationGas) gas = MaxVerificationGas; UInt160[] hashes; try From 54095fc93991e90bfaf0adb8b807d3f403774f5c Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Sat, 4 Jul 2020 16:37:39 +0800 Subject: [PATCH 14/32] Create KeyBuilder (#1748) --- src/neo/SmartContract/Native/KeyBuilder.cs | 52 +++++++++++++++++++ .../SmartContract/Native/NativeContract.cs | 17 +----- .../SmartContract/Native/Tokens/NeoToken.cs | 14 ++--- .../SmartContract/Native/Tokens/Nep5Token.cs | 15 ++---- tests/neo.UnitTests/TestUtils.cs | 10 ++++ 5 files changed, 76 insertions(+), 32 deletions(-) create mode 100644 src/neo/SmartContract/Native/KeyBuilder.cs diff --git a/src/neo/SmartContract/Native/KeyBuilder.cs b/src/neo/SmartContract/Native/KeyBuilder.cs new file mode 100644 index 0000000000..a5cafedfd9 --- /dev/null +++ b/src/neo/SmartContract/Native/KeyBuilder.cs @@ -0,0 +1,52 @@ +using Neo.IO; +using Neo.Ledger; +using System; +using System.IO; + +namespace Neo.SmartContract.Native +{ + internal class KeyBuilder + { + private readonly int id; + private readonly MemoryStream stream = new MemoryStream(); + + public KeyBuilder(int id, byte prefix) + { + this.id = id; + this.stream.WriteByte(prefix); + } + + public KeyBuilder Add(ReadOnlySpan key) + { + stream.Write(key); + return this; + } + + public KeyBuilder Add(ISerializable key) + { + using (BinaryWriter writer = new BinaryWriter(stream, Utility.StrictUTF8, true)) + { + key.Serialize(writer); + writer.Flush(); + } + return this; + } + + unsafe public KeyBuilder Add(T key) where T : unmanaged + { + return Add(new ReadOnlySpan(&key, sizeof(T))); + } + + public static implicit operator StorageKey(KeyBuilder builder) + { + using (builder.stream) + { + return new StorageKey + { + Id = builder.id, + Key = builder.stream.ToArray() + }; + } + } + } +} diff --git a/src/neo/SmartContract/Native/NativeContract.cs b/src/neo/SmartContract/Native/NativeContract.cs index 4d649ac627..0f86ce91ba 100644 --- a/src/neo/SmartContract/Native/NativeContract.cs +++ b/src/neo/SmartContract/Native/NativeContract.cs @@ -1,5 +1,4 @@ using Neo.IO; -using Neo.Ledger; using Neo.SmartContract.Manifest; using Neo.SmartContract.Native.Tokens; using Neo.VM; @@ -79,21 +78,9 @@ protected NativeContract() contractsHashDictionary.Add(Hash, this); } - protected StorageKey CreateStorageKey(byte prefix, byte[] key = null) + private protected KeyBuilder CreateStorageKey(byte prefix) { - StorageKey storageKey = new StorageKey - { - Id = Id, - Key = new byte[sizeof(byte) + (key?.Length ?? 0)] - }; - storageKey.Key[0] = prefix; - key?.CopyTo(storageKey.Key.AsSpan(1)); - return storageKey; - } - - internal protected StorageKey CreateStorageKey(byte prefix, ISerializable key) - { - return CreateStorageKey(prefix, key.ToArray()); + return new KeyBuilder(Id, prefix); } public static NativeContract GetContract(UInt160 hash) diff --git a/src/neo/SmartContract/Native/Tokens/NeoToken.cs b/src/neo/SmartContract/Native/Tokens/NeoToken.cs index 3d814cbe2f..aef7abd14d 100644 --- a/src/neo/SmartContract/Native/Tokens/NeoToken.cs +++ b/src/neo/SmartContract/Native/Tokens/NeoToken.cs @@ -40,7 +40,7 @@ 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, state.VoteTo.ToArray())); + StorageItem storage_validator = engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_Candidate).Add(state.VoteTo)); CandidateState state_validator = storage_validator.GetInteroperable(); state_validator.Votes += amount; } @@ -112,7 +112,7 @@ protected override void OnPersist(ApplicationEngine engine) [ContractMethod(0_03000000, CallFlags.AllowStates)] public BigInteger UnclaimedGas(StoreView snapshot, UInt160 account, uint end) { - StorageItem storage = snapshot.Storages.TryGet(CreateAccountKey(account)); + StorageItem storage = snapshot.Storages.TryGet(CreateStorageKey(Prefix_Account).Add(account)); if (storage is null) return BigInteger.Zero; NeoAccountState state = storage.GetInteroperable(); return CalculateBonus(state.Balance, state.BalanceHeight, end); @@ -129,7 +129,7 @@ private bool RegisterCandidate(ApplicationEngine engine, ECPoint pubkey) private void RegisterCandidateInternal(StoreView snapshot, ECPoint pubkey) { - StorageKey key = CreateStorageKey(Prefix_Candidate, pubkey); + StorageKey key = CreateStorageKey(Prefix_Candidate).Add(pubkey); StorageItem item = snapshot.Storages.GetAndChange(key, () => new StorageItem(new CandidateState())); CandidateState state = item.GetInteroperable(); state.Registered = true; @@ -140,7 +140,7 @@ private bool UnregisterCandidate(ApplicationEngine engine, ECPoint pubkey) { if (!engine.CheckWitnessInternal(Contract.CreateSignatureRedeemScript(pubkey).ToScriptHash())) return false; - StorageKey key = CreateStorageKey(Prefix_Candidate, pubkey); + StorageKey key = CreateStorageKey(Prefix_Candidate).Add(pubkey); if (engine.Snapshot.Storages.TryGet(key) is null) return true; StorageItem item = engine.Snapshot.Storages.GetAndChange(key); CandidateState state = item.GetInteroperable(); @@ -160,13 +160,13 @@ private bool Vote(ApplicationEngine engine, UInt160 account, ECPoint voteTo) private bool VoteInternal(StoreView snapshot, UInt160 account, ECPoint voteTo) { - StorageKey key_account = CreateAccountKey(account); + 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); NeoAccountState state_account = storage_account.GetInteroperable(); if (state_account.VoteTo != null) { - StorageKey key = CreateStorageKey(Prefix_Candidate, state_account.VoteTo.ToArray()); + StorageKey key = CreateStorageKey(Prefix_Candidate).Add(state_account.VoteTo); StorageItem storage_validator = snapshot.Storages.GetAndChange(key); CandidateState state_validator = storage_validator.GetInteroperable(); state_validator.Votes -= state_account.Balance; @@ -176,7 +176,7 @@ private bool VoteInternal(StoreView snapshot, UInt160 account, ECPoint voteTo) state_account.VoteTo = voteTo; if (voteTo != null) { - StorageKey key = CreateStorageKey(Prefix_Candidate, voteTo.ToArray()); + StorageKey key = CreateStorageKey(Prefix_Candidate).Add(voteTo); if (snapshot.Storages.TryGet(key) is null) return false; StorageItem storage_validator = snapshot.Storages.GetAndChange(key); CandidateState state_validator = storage_validator.GetInteroperable(); diff --git a/src/neo/SmartContract/Native/Tokens/Nep5Token.cs b/src/neo/SmartContract/Native/Tokens/Nep5Token.cs index bc417cf931..6e7598ab70 100644 --- a/src/neo/SmartContract/Native/Tokens/Nep5Token.cs +++ b/src/neo/SmartContract/Native/Tokens/Nep5Token.cs @@ -58,16 +58,11 @@ protected Nep5Token() Manifest.Abi.Events = events.ToArray(); } - protected StorageKey CreateAccountKey(UInt160 account) - { - return CreateStorageKey(Prefix_Account, account); - } - internal protected virtual void Mint(ApplicationEngine engine, UInt160 account, BigInteger amount) { if (amount.Sign < 0) throw new ArgumentOutOfRangeException(nameof(amount)); if (amount.IsZero) return; - StorageItem storage = engine.Snapshot.Storages.GetAndChange(CreateAccountKey(account), () => new StorageItem(new TState())); + StorageItem storage = engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_Account).Add(account), () => new StorageItem(new TState())); TState state = storage.GetInteroperable(); OnBalanceChanging(engine, account, state, amount); state.Balance += amount; @@ -85,7 +80,7 @@ internal protected virtual void Burn(ApplicationEngine engine, UInt160 account, { if (amount.Sign < 0) throw new ArgumentOutOfRangeException(nameof(amount)); if (amount.IsZero) return; - StorageKey key = CreateAccountKey(account); + StorageKey key = CreateStorageKey(Prefix_Account).Add(account); StorageItem storage = engine.Snapshot.Storages.GetAndChange(key); TState state = storage.GetInteroperable(); if (state.Balance < amount) throw new InvalidOperationException(); @@ -112,7 +107,7 @@ public virtual BigInteger TotalSupply(StoreView snapshot) [ContractMethod(0_01000000, CallFlags.AllowStates)] public virtual BigInteger BalanceOf(StoreView snapshot, UInt160 account) { - StorageItem storage = snapshot.Storages.TryGet(CreateAccountKey(account)); + StorageItem storage = snapshot.Storages.TryGet(CreateStorageKey(Prefix_Account).Add(account)); if (storage is null) return BigInteger.Zero; return storage.GetInteroperable().Balance; } @@ -125,7 +120,7 @@ protected virtual bool Transfer(ApplicationEngine engine, UInt160 from, UInt160 return false; ContractState contract_to = engine.Snapshot.Contracts.TryGet(to); if (contract_to?.Payable == false) return false; - StorageKey key_from = CreateAccountKey(from); + StorageKey key_from = CreateStorageKey(Prefix_Account).Add(from); StorageItem storage_from = engine.Snapshot.Storages.GetAndChange(key_from); if (amount.IsZero) { @@ -151,7 +146,7 @@ protected virtual bool Transfer(ApplicationEngine engine, UInt160 from, UInt160 engine.Snapshot.Storages.Delete(key_from); else state_from.Balance -= amount; - StorageKey key_to = CreateAccountKey(to); + StorageKey key_to = CreateStorageKey(Prefix_Account).Add(to); StorageItem storage_to = engine.Snapshot.Storages.GetAndChange(key_to, () => new StorageItem(new TState())); TState state_to = storage_to.GetInteroperable(); OnBalanceChanging(engine, to, state_to, amount); diff --git a/tests/neo.UnitTests/TestUtils.cs b/tests/neo.UnitTests/TestUtils.cs index ef380908dd..adaf205ea1 100644 --- a/tests/neo.UnitTests/TestUtils.cs +++ b/tests/neo.UnitTests/TestUtils.cs @@ -5,6 +5,7 @@ using Neo.Network.P2P.Payloads; using Neo.SmartContract; using Neo.SmartContract.Manifest; +using Neo.SmartContract.Native; using Neo.VM; using Neo.Wallets.NEP6; using System; @@ -55,6 +56,15 @@ public static ContractManifest CreateManifest(UInt160 hash, string method, Contr return manifest; } + public static StorageKey CreateStorageKey(this NativeContract contract, byte prefix, ISerializable key) + { + return new StorageKey + { + Id = contract.Id, + Key = key.ToArray().Prepend(prefix).ToArray() + }; + } + public static byte[] GetByteArray(int length, byte firstByte) { byte[] array = new byte[length]; From e91abdcd476a6cf112d87a6998d9177679011ea0 Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Mon, 6 Jul 2020 18:48:51 +0800 Subject: [PATCH 15/32] Speed up the initialization of ApplicationEngine. (#1749) --- .../ApplicationEngine.Runtime.cs | 1 + .../ApplicationEngine.Storage.cs | 2 ++ src/neo/SmartContract/ApplicationEngine.cs | 29 ++++++++++--------- src/neo/Wallets/AssetDescriptor.cs | 2 +- src/neo/Wallets/Wallet.cs | 4 +-- src/neo/neo.csproj | 2 +- 6 files changed, 22 insertions(+), 18 deletions(-) diff --git a/src/neo/SmartContract/ApplicationEngine.Runtime.cs b/src/neo/SmartContract/ApplicationEngine.Runtime.cs index a7dd969582..a000f06e34 100644 --- a/src/neo/SmartContract/ApplicationEngine.Runtime.cs +++ b/src/neo/SmartContract/ApplicationEngine.Runtime.cs @@ -157,6 +157,7 @@ internal void SendNotification(UInt160 hash, string eventName, Array state) { NotifyEventArgs notification = new NotifyEventArgs(ScriptContainer, hash, eventName, (Array)state.DeepCopy()); Notify?.Invoke(this, notification); + notifications ??= new List(); notifications.Add(notification); } diff --git a/src/neo/SmartContract/ApplicationEngine.Storage.cs b/src/neo/SmartContract/ApplicationEngine.Storage.cs index 73aace9c37..97ccb5494c 100644 --- a/src/neo/SmartContract/ApplicationEngine.Storage.cs +++ b/src/neo/SmartContract/ApplicationEngine.Storage.cs @@ -1,6 +1,7 @@ using Neo.Ledger; using Neo.SmartContract.Iterators; using System; +using System.Collections.Generic; using System.Linq; namespace Neo.SmartContract @@ -66,6 +67,7 @@ internal IIterator Find(StorageContext context, byte[] prefix) { byte[] prefix_key = StorageKey.CreateSearchPrefix(context.Id, prefix); StorageIterator iterator = new StorageIterator(Snapshot.Storages.Find(prefix_key).Where(p => p.Key.Key.AsSpan().StartsWith(prefix)).GetEnumerator()); + disposables ??= new List(); disposables.Add(iterator); return iterator; } diff --git a/src/neo/SmartContract/ApplicationEngine.cs b/src/neo/SmartContract/ApplicationEngine.cs index 30fc027be0..05f963ddb2 100644 --- a/src/neo/SmartContract/ApplicationEngine.cs +++ b/src/neo/SmartContract/ApplicationEngine.cs @@ -26,13 +26,11 @@ private class InvocationState public static event EventHandler Notify; public static event EventHandler Log; - public const long GasFree = 0; - private static Dictionary services; private readonly long gas_amount; private readonly bool testMode; - private readonly List notifications = new List(); - private readonly List disposables = new List(); + private List notifications; + private List disposables; private readonly Dictionary invocationCounter = new Dictionary(); private readonly Dictionary invocationStates = new Dictionary(); @@ -45,15 +43,15 @@ private class InvocationState public UInt160 CurrentScriptHash => CurrentContext?.GetState().ScriptHash; public UInt160 CallingScriptHash => CurrentContext?.GetState().CallingScriptHash; public UInt160 EntryScriptHash => EntryContext?.GetState().ScriptHash; - public IReadOnlyList Notifications => notifications; + public IReadOnlyList Notifications => notifications ?? (IReadOnlyList)Array.Empty(); public ApplicationEngine(TriggerType trigger, IVerifiable container, StoreView snapshot, long gas, bool testMode = false) { - this.gas_amount = GasFree + gas; - this.testMode = testMode; this.Trigger = trigger; this.ScriptContainer = container; this.Snapshot = snapshot; + this.gas_amount = gas; + this.testMode = testMode; } internal void AddGas(long gas) @@ -196,9 +194,12 @@ internal object Convert(StackItem item, InteropParameterDescriptor descriptor) public override void Dispose() { - foreach (IDisposable disposable in disposables) - disposable.Dispose(); - disposables.Clear(); + if (disposables != null) + { + foreach (IDisposable disposable in disposables) + disposable.Dispose(); + disposables = null; + } base.Dispose(); } @@ -259,20 +260,20 @@ private static InteropDescriptor Register(string name, string handler, long fixe } public static ApplicationEngine Run(byte[] script, StoreView snapshot, - IVerifiable container = null, Block persistingBlock = null, int offset = 0, bool testMode = false, long extraGAS = default) + 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, extraGAS, testMode); + ApplicationEngine engine = new ApplicationEngine(TriggerType.Application, container, snapshot, gas, testMode); engine.LoadScript(script).InstructionPointer = offset; engine.Execute(); return engine; } - public static ApplicationEngine Run(byte[] script, IVerifiable container = null, Block persistingBlock = null, int offset = 0, bool testMode = false, long extraGAS = default) + public static ApplicationEngine Run(byte[] script, IVerifiable container = null, Block persistingBlock = null, int offset = 0, bool testMode = false, long gas = default) { using (SnapshotView snapshot = Blockchain.Singleton.GetSnapshot()) { - return Run(script, snapshot, container, persistingBlock, offset, testMode, extraGAS); + return Run(script, snapshot, container, persistingBlock, offset, testMode, gas); } } } diff --git a/src/neo/Wallets/AssetDescriptor.cs b/src/neo/Wallets/AssetDescriptor.cs index c49712f7ec..9f6a4d4c18 100644 --- a/src/neo/Wallets/AssetDescriptor.cs +++ b/src/neo/Wallets/AssetDescriptor.cs @@ -19,7 +19,7 @@ public AssetDescriptor(UInt160 asset_id) sb.EmitAppCall(asset_id, "name"); script = sb.ToArray(); } - using ApplicationEngine engine = ApplicationEngine.Run(script, extraGAS: 3_000_000); + using ApplicationEngine engine = ApplicationEngine.Run(script, gas: 3_000_000); if (engine.State.HasFlag(VMState.FAULT)) throw new ArgumentException(); this.AssetId = asset_id; this.AssetName = engine.ResultStack.Pop().GetString(); diff --git a/src/neo/Wallets/Wallet.cs b/src/neo/Wallets/Wallet.cs index 69708cca42..d70fa23f8b 100644 --- a/src/neo/Wallets/Wallet.cs +++ b/src/neo/Wallets/Wallet.cs @@ -143,7 +143,7 @@ public BigDecimal GetBalance(UInt160 asset_id, params UInt160[] accounts) sb.EmitAppCall(asset_id, "decimals"); script = sb.ToArray(); } - using ApplicationEngine engine = ApplicationEngine.Run(script, extraGAS: 20000000L * accounts.Length); + using ApplicationEngine engine = ApplicationEngine.Run(script, gas: 20000000L * accounts.Length); if (engine.State.HasFlag(VMState.FAULT)) return new BigDecimal(0, 0); byte decimals = (byte)engine.ResultStack.Pop().GetInteger(); @@ -329,7 +329,7 @@ private Transaction MakeTransaction(StoreView snapshot, byte[] script, Transacti { if (engine.State.HasFlag(VMState.FAULT)) throw new InvalidOperationException($"Failed execution for '{script.ToHexString()}'"); - tx.SystemFee = Math.Max(engine.GasConsumed - ApplicationEngine.GasFree, 0); + tx.SystemFee = engine.GasConsumed; } UInt160[] hashes = tx.GetScriptHashesForVerifying(snapshot); diff --git a/src/neo/neo.csproj b/src/neo/neo.csproj index e3ee5b5259..d1694c67c2 100644 --- a/src/neo/neo.csproj +++ b/src/neo/neo.csproj @@ -27,7 +27,7 @@ - + From 699a28c9d72228f31de830acef9ffb9750d6fe8d Mon Sep 17 00:00:00 2001 From: Shargon Date: Wed, 8 Jul 2020 09:44:17 +0200 Subject: [PATCH 16/32] Change nef checksum to double SHA256 (#1751) * Change to double SHA256 * Clean code * Revert change * Clean code * Fix checksum * Update NefFile.cs * Fix compile * Clean code Clean code Fix checksum Update NefFile.cs Fix compile * Optimize * Optimize * Fix Co-authored-by: erikzhang --- src/neo/SmartContract/NefFile.cs | 50 ++++++++++++++++---------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/src/neo/SmartContract/NefFile.cs b/src/neo/SmartContract/NefFile.cs index 815f2252fb..daa5d3b7f8 100644 --- a/src/neo/SmartContract/NefFile.cs +++ b/src/neo/SmartContract/NefFile.cs @@ -14,7 +14,7 @@ namespace Neo.SmartContract /// | Version | 16 bytes | Compiler version (Mayor, Minor, Build, Version) | /// | ScriptHash | 20 bytes | ScriptHash for the script | /// +------------+-----------+------------------------------------------------------------+ - /// | Checksum | 4 bytes | Sha256 of the header (CRC) | + /// | Checksum | 4 bytes | First four bytes of double SHA256 hash | /// +------------+-----------+------------------------------------------------------------+ /// | Script | Var bytes | Var bytes for the payload | /// +------------+-----------+------------------------------------------------------------+ @@ -52,17 +52,24 @@ public class NefFile : ISerializable public byte[] Script { get; set; } private const int HeaderSize = - sizeof(uint) + // Magic - 32 + // Compiler - (sizeof(int) * 4) + // Version - UInt160.Length + // ScriptHash - sizeof(uint); // Checksum + sizeof(uint) + // Magic + 32 + // Compiler + (sizeof(int) * 4) + // Version + UInt160.Length; // ScriptHash public int Size => - HeaderSize + // Header - Script.GetVarSize(); // Script + HeaderSize + // Header + sizeof(uint) + // Checksum + Script.GetVarSize();// Script public void Serialize(BinaryWriter writer) + { + SerializeHeader(writer); + writer.Write(CheckSum); + writer.WriteVarBytes(Script ?? Array.Empty()); + } + + private void SerializeHeader(BinaryWriter writer) { writer.Write(Magic); writer.WriteFixedString(Compiler, 32); @@ -74,8 +81,6 @@ public void Serialize(BinaryWriter writer) writer.Write(Version.Revision); writer.Write(ScriptHash); - writer.Write(CheckSum); - writer.WriteVarBytes(Script ?? Array.Empty()); } public void Deserialize(BinaryReader reader) @@ -108,22 +113,17 @@ public void Deserialize(BinaryReader reader) /// /// File /// Return checksum - public static uint ComputeChecksum(NefFile file) + unsafe public static uint ComputeChecksum(NefFile file) { - using (var ms = new MemoryStream()) - using (var wr = new BinaryWriter(ms)) - { - file.Serialize(wr); - wr.Flush(); - - // Read header without CRC - - Span buffer = stackalloc byte[HeaderSize - sizeof(uint)]; - ms.Seek(0, SeekOrigin.Begin); - ms.Read(buffer); - - return BitConverter.ToUInt32(buffer.Sha256(), 0); - } + Span header = stackalloc byte[HeaderSize]; + fixed (byte* p = header) + using (UnmanagedMemoryStream ms = new UnmanagedMemoryStream(p, HeaderSize, HeaderSize, FileAccess.Write)) + using (BinaryWriter wr = new BinaryWriter(ms, Utility.StrictUTF8, false)) + { + file.SerializeHeader(wr); + wr.Flush(); + } + return BitConverter.ToUInt32(Crypto.Hash256(header), 0); } } } From 5952ad22e3d405bed14d51669a2b1e04151724ec Mon Sep 17 00:00:00 2001 From: Shargon Date: Wed, 8 Jul 2020 12:44:09 +0200 Subject: [PATCH 17/32] Check witnesses on isStandard (#1754) * Check witness on isStandard * Add IsDeployed * Add IsPayable * Fix UT * format * Add coverage * Remove IsPayable, IsDeployed --- .../ApplicationEngine.Contract.cs | 23 ++++++++++++++++++- .../SmartContract/UT_InteropService.NEO.cs | 7 +++++- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/src/neo/SmartContract/ApplicationEngine.Contract.cs b/src/neo/SmartContract/ApplicationEngine.Contract.cs index c537469da6..5b84938289 100644 --- a/src/neo/SmartContract/ApplicationEngine.Contract.cs +++ b/src/neo/SmartContract/ApplicationEngine.Contract.cs @@ -1,6 +1,7 @@ using Neo.Cryptography.ECC; using Neo.IO; using Neo.Ledger; +using Neo.Network.P2P.Payloads; using Neo.SmartContract.Manifest; using Neo.SmartContract.Native; using Neo.VM; @@ -164,7 +165,27 @@ private void CallContractInternal(UInt160 contractHash, string method, Array arg internal bool IsStandardContract(UInt160 hash) { ContractState contract = Snapshot.Contracts.TryGet(hash); - return contract is null || contract.Script.IsStandardContract(); + + // It's a stored contract + + if (contract != null) return contract.Script.IsStandardContract(); + + // Try to find it in the transaction + + if (ScriptContainer is Transaction tx) + { + foreach (var witness in tx.Witnesses) + { + if (witness.ScriptHash == hash) + { + return witness.VerificationScript.IsStandardContract(); + } + } + } + + // It's not possible to determine if it's standard + + return false; } internal CallFlags GetCallFlags() diff --git a/tests/neo.UnitTests/SmartContract/UT_InteropService.NEO.cs b/tests/neo.UnitTests/SmartContract/UT_InteropService.NEO.cs index 283fdc1d3f..5d78c4ebd5 100644 --- a/tests/neo.UnitTests/SmartContract/UT_InteropService.NEO.cs +++ b/tests/neo.UnitTests/SmartContract/UT_InteropService.NEO.cs @@ -110,7 +110,7 @@ public void TestAccount_IsStandard() 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }; - engine.IsStandardContract(new UInt160(hash)).Should().BeTrue(); + engine.IsStandardContract(new UInt160(hash)).Should().BeFalse(); var snapshot = Blockchain.Singleton.GetSnapshot(); var state = TestUtils.GetContract(); @@ -118,6 +118,11 @@ public void TestAccount_IsStandard() engine = new ApplicationEngine(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.LoadScript(new byte[] { 0x01 }); + engine.IsStandardContract(state.ScriptHash).Should().BeTrue(); } [TestMethod] From 791355c58bdc1fc5d7c1b42a6ab247cbf69cf6d5 Mon Sep 17 00:00:00 2001 From: Shargon Date: Thu, 9 Jul 2020 16:58:59 +0200 Subject: [PATCH 18/32] 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 19/32] 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 20/32] 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 21/32] 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 22/32] 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 23/32] 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 24/32] 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 25/32] 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 26/32] 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 27/32] 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 28/32] 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 29/32] 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() { From d542ac3eb822da41743d0a0c5dd9872768f1dc81 Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Mon, 20 Jul 2020 16:32:46 +0800 Subject: [PATCH 30/32] Fix VerifyWitnesses (#1776) --- src/neo/SmartContract/Helper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/neo/SmartContract/Helper.cs b/src/neo/SmartContract/Helper.cs index b2cdb416a2..4448ff83b6 100644 --- a/src/neo/SmartContract/Helper.cs +++ b/src/neo/SmartContract/Helper.cs @@ -164,7 +164,7 @@ internal static bool VerifyWitnesses(this IVerifiable verifiable, StoreView snap } using (ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Verification, verifiable, snapshot.Clone(), gas)) { - engine.LoadScript(verification, CallFlags.ReadOnly).InstructionPointer = offset; + engine.LoadScript(verification, CallFlags.None).InstructionPointer = offset; engine.LoadScript(verifiable.Witnesses[i].InvocationScript, CallFlags.None); if (engine.Execute() == VMState.FAULT) return false; if (engine.ResultStack.Count != 1 || !engine.ResultStack.Pop().GetBoolean()) return false; From ae383669a6d4e324f71265d83060d5d90b808892 Mon Sep 17 00:00:00 2001 From: Shargon Date: Mon, 20 Jul 2020 15:00:59 +0200 Subject: [PATCH 31/32] Ensure non predictable peers (#1739) * Plugins from List to array * Move false to init * Fix UT * Refactor --- src/neo/Network/P2P/Peer.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/neo/Network/P2P/Peer.cs b/src/neo/Network/P2P/Peer.cs index dc921b9526..106f530b71 100644 --- a/src/neo/Network/P2P/Peer.cs +++ b/src/neo/Network/P2P/Peer.cs @@ -270,7 +270,9 @@ private void OnTimer() // If there aren't available UnconnectedPeers, it triggers an abstract implementation of NeedMorePeers if (UnconnectedPeers.Count == 0) NeedMorePeers(MinDesiredConnections - ConnectedPeers.Count); - IPEndPoint[] endpoints = UnconnectedPeers.Take(MinDesiredConnections - ConnectedPeers.Count).ToArray(); + + Random rand = new Random(); + IPEndPoint[] endpoints = UnconnectedPeers.OrderBy(u => rand.Next()).Take(MinDesiredConnections - ConnectedPeers.Count).ToArray(); ImmutableInterlocked.Update(ref UnconnectedPeers, p => p.Except(endpoints)); foreach (IPEndPoint endpoint in endpoints) { From 5406085af441bdf916a735b676bfbc67cf10cdc9 Mon Sep 17 00:00:00 2001 From: cloud8little <34291844+cloud8little@users.noreply.github.com> Date: Wed, 22 Jul 2020 15:16:25 +0800 Subject: [PATCH 32/32] Add Exception Message For CreateContract (#1787) * Add Exception Message When Create Contract * Add Exception Message * Code optimization * add UT Co-authored-by: Shargon Co-authored-by: Qiao Jin <43407364+Qiao-Jin@users.noreply.github.com> --- .../ApplicationEngine.Contract.cs | 32 ++++++++++--------- .../SmartContract/UT_InteropService.NEO.cs | 10 ++++++ 2 files changed, 27 insertions(+), 15 deletions(-) diff --git a/src/neo/SmartContract/ApplicationEngine.Contract.cs b/src/neo/SmartContract/ApplicationEngine.Contract.cs index 4ecfdde31e..19e20b071f 100644 --- a/src/neo/SmartContract/ApplicationEngine.Contract.cs +++ b/src/neo/SmartContract/ApplicationEngine.Contract.cs @@ -30,14 +30,16 @@ partial class ApplicationEngine internal ContractState CreateContract(byte[] script, byte[] manifest) { - if (script.Length == 0 || script.Length > MaxContractLength || manifest.Length == 0 || manifest.Length > ContractManifest.MaxLength) - throw new ArgumentException(); + if (script.Length == 0 || script.Length > MaxContractLength) + throw new ArgumentException($"Invalid Script Length: {script.Length}"); + if (manifest.Length == 0 || manifest.Length > ContractManifest.MaxLength) + throw new ArgumentException($"Invalid Manifest Length: {manifest.Length}"); AddGas(StoragePrice * (script.Length + manifest.Length)); UInt160 hash = script.ToScriptHash(); ContractState contract = Snapshot.Contracts.TryGet(hash); - if (contract != null) throw new InvalidOperationException(); + if (contract != null) throw new InvalidOperationException($"Contract Already Exists: {hash}"); contract = new ContractState { Id = Snapshot.ContractId.GetAndChange().NextId++, @@ -45,7 +47,7 @@ internal ContractState CreateContract(byte[] script, byte[] manifest) Manifest = ContractManifest.Parse(manifest) }; - if (!contract.Manifest.IsValid(hash)) throw new InvalidOperationException(); + if (!contract.Manifest.IsValid(hash)) throw new InvalidOperationException($"Invalid Manifest Hash: {hash}"); Snapshot.Contracts.Add(hash, contract); return contract; @@ -56,15 +58,15 @@ internal void UpdateContract(byte[] script, byte[] manifest) AddGas(StoragePrice * (script?.Length ?? 0 + manifest?.Length ?? 0)); var contract = Snapshot.Contracts.TryGet(CurrentScriptHash); - if (contract is null) throw new InvalidOperationException(); + if (contract is null) throw new InvalidOperationException($"Updating Contract Does Not Exist: {CurrentScriptHash}"); if (script != null) { if (script.Length == 0 || script.Length > MaxContractLength) - throw new ArgumentException(); + throw new ArgumentException($"Invalid Script Length: {script.Length}"); UInt160 hash_new = script.ToScriptHash(); if (hash_new.Equals(CurrentScriptHash) || Snapshot.Contracts.TryGet(hash_new) != null) - throw new InvalidOperationException(); + throw new InvalidOperationException($"Adding Contract Hash Already Exist: {hash_new}"); contract = new ContractState { Id = contract.Id, @@ -78,13 +80,13 @@ internal void UpdateContract(byte[] script, byte[] manifest) if (manifest != null) { if (manifest.Length == 0 || manifest.Length > ContractManifest.MaxLength) - throw new ArgumentException(); + throw new ArgumentException($"Invalid Manifest Length: {manifest.Length}"); contract = Snapshot.Contracts.GetAndChange(contract.ScriptHash); contract.Manifest = ContractManifest.Parse(manifest); if (!contract.Manifest.IsValid(contract.ScriptHash)) - throw new InvalidOperationException(); + throw new InvalidOperationException($"Invalid Manifest Hash: {contract.ScriptHash}"); if (!contract.HasStorage && Snapshot.Storages.Find(BitConverter.GetBytes(contract.Id)).Any()) - throw new InvalidOperationException(); + throw new InvalidOperationException($"Contract Does Not Support Storage But Uses Storage"); } } @@ -113,15 +115,15 @@ internal void CallContractEx(UInt160 contractHash, string method, Array args, Ca private void CallContractInternal(UInt160 contractHash, string method, Array args, CallFlags flags) { - if (method.StartsWith('_')) throw new ArgumentException(); + if (method.StartsWith('_')) throw new ArgumentException($"Invalid Method Name: {method}"); ContractState contract = Snapshot.Contracts.TryGet(contractHash); - if (contract is null) throw new InvalidOperationException(); + if (contract is null) throw new InvalidOperationException($"Called Contract Does Not Exist: {contractHash}"); ContractManifest currentManifest = Snapshot.Contracts.TryGet(CurrentScriptHash)?.Manifest; if (currentManifest != null && !currentManifest.CanCall(contract.Manifest, method)) - throw new InvalidOperationException(); + throw new InvalidOperationException($"Cannot Call Method {method} Of Contract {contractHash} From Contract {CurrentScriptHash}"); if (invocationCounter.TryGetValue(contract.ScriptHash, out var counter)) { @@ -139,8 +141,8 @@ private void CallContractInternal(UInt160 contractHash, string method, Array arg CallFlags callingFlags = state.CallFlags; ContractMethodDescriptor md = contract.Manifest.Abi.GetMethod(method); - if (md is null) throw new InvalidOperationException(); - if (args.Count != md.Parameters.Length) throw new InvalidOperationException(); + if (md is null) throw new InvalidOperationException($"Method {method} Does Not Exist In Contract {contractHash}"); + if (args.Count != md.Parameters.Length) throw new InvalidOperationException($"Method {method} Expects {md.Parameters.Length} Arguments But Receives {args.Count} Arguments"); ExecutionContext context_new = LoadScript(contract.Script); state = context_new.GetState(); state.CallingScriptHash = callingScriptHash; diff --git a/tests/neo.UnitTests/SmartContract/UT_InteropService.NEO.cs b/tests/neo.UnitTests/SmartContract/UT_InteropService.NEO.cs index 4d4eaf4b07..95a7ad7b66 100644 --- a/tests/neo.UnitTests/SmartContract/UT_InteropService.NEO.cs +++ b/tests/neo.UnitTests/SmartContract/UT_InteropService.NEO.cs @@ -9,6 +9,7 @@ using Neo.SmartContract; using Neo.SmartContract.Iterators; using Neo.SmartContract.Manifest; +using Neo.SmartContract.Native; using Neo.VM.Types; using Neo.Wallets; using System; @@ -135,6 +136,15 @@ public void TestContract_Create() var manifest = TestUtils.CreateDefaultManifest(UInt160.Parse("0xa400ff00ff00ff00ff00ff00ff00ff00ff00ff01")); Assert.ThrowsException(() => engine.CreateContract(script, manifest.ToJson().ToByteArray(false))); + var script_exceedMaxLength = new byte[ApplicationEngine.MaxContractLength + 1]; + Assert.ThrowsException(() => engine.CreateContract(script_exceedMaxLength, manifest.ToJson().ToByteArray(true))); + + var script_zeroLength = new byte[] { }; + Assert.ThrowsException(() => engine.CreateContract(script_zeroLength, manifest.ToJson().ToByteArray(true))); + + var manifest_zeroLength = new byte[] { }; + Assert.ThrowsException(() => engine.CreateContract(script, manifest_zeroLength)); + manifest.Abi.Hash = script.ToScriptHash(); engine.CreateContract(script, manifest.ToJson().ToByteArray(false));