From 7a59f1347415364f1b8acee562690fb32e17e2e8 Mon Sep 17 00:00:00 2001 From: erikzhang Date: Thu, 28 Mar 2019 18:03:45 +0800 Subject: [PATCH 1/5] Change version to v2.10.1 --- neo/Ledger/Blockchain.cs | 3 +- neo/SmartContract/ApplicationEngine.cs | 63 +++++++------------------- neo/SmartContract/Helper.cs | 3 +- neo/neo.csproj | 11 ++--- 4 files changed, 23 insertions(+), 57 deletions(-) diff --git a/neo/Ledger/Blockchain.cs b/neo/Ledger/Blockchain.cs index f2b1626239..9aed274872 100644 --- a/neo/Ledger/Blockchain.cs +++ b/neo/Ledger/Blockchain.cs @@ -583,7 +583,8 @@ private void Persist(Block block) using (ApplicationEngine engine = new ApplicationEngine(TriggerType.Application, tx_invocation, snapshot.Clone(), tx_invocation.Gas)) { engine.LoadScript(tx_invocation.Script); - if (engine.Execute()) + engine.Execute(); + if (!engine.State.HasFlag(VMState.FAULT)) { engine.Service.Commit(); } diff --git a/neo/SmartContract/ApplicationEngine.cs b/neo/SmartContract/ApplicationEngine.cs index b7e5d6685e..7694db2441 100644 --- a/neo/SmartContract/ApplicationEngine.cs +++ b/neo/SmartContract/ApplicationEngine.cs @@ -3,6 +3,7 @@ using Neo.Persistence; using Neo.VM; using Neo.VM.Types; +using System.Linq; using System.Text; namespace Neo.SmartContract @@ -27,16 +28,14 @@ public ApplicationEngine(TriggerType trigger, IScriptContainer container, Snapsh this.snapshot = snapshot; } - private bool CheckDynamicInvoke(OpCode nextInstruction) + private bool CheckDynamicInvoke() { - switch (nextInstruction) + Instruction instruction = CurrentContext.CurrentInstruction; + switch (instruction.OpCode) { case OpCode.APPCALL: case OpCode.TAILCALL: - for (int i = CurrentContext.InstructionPointer + 1; i < CurrentContext.InstructionPointer + 21; i++) - { - if (CurrentContext.Script[i] != 0) return true; - } + if (instruction.Operand.Any(p => p != 0)) return true; // if we get this far it is a dynamic call // now look at the current executing script // to determine if it can do dynamic calls @@ -55,35 +54,11 @@ public override void Dispose() Service.Dispose(); } - public new bool Execute() - { - try - { - while (true) - { - OpCode nextOpcode = CurrentContext.InstructionPointer >= CurrentContext.Script.Length ? OpCode.RET : CurrentContext.NextInstruction; - if (!PreStepInto(nextOpcode)) - { - State |= VMState.FAULT; - return false; - } - StepInto(); - if (State.HasFlag(VMState.HALT) || State.HasFlag(VMState.FAULT)) - break; - } - } - catch - { - State |= VMState.FAULT; - return false; - } - return !State.HasFlag(VMState.FAULT); - } - - protected virtual long GetPrice(OpCode nextInstruction) + protected virtual long GetPrice() { - if (nextInstruction <= OpCode.NOP) return 0; - switch (nextInstruction) + Instruction instruction = CurrentContext.CurrentInstruction; + if (instruction.OpCode <= OpCode.NOP) return 0; + switch (instruction.OpCode) { case OpCode.APPCALL: case OpCode.TAILCALL: @@ -118,14 +93,10 @@ protected virtual long GetPrice(OpCode nextInstruction) protected virtual long GetPriceForSysCall() { - if (CurrentContext.InstructionPointer >= CurrentContext.Script.Length - 3) - return 1; - byte length = (byte)CurrentContext.Script[CurrentContext.InstructionPointer + 1]; - if (CurrentContext.InstructionPointer > CurrentContext.Script.Length - length - 2) - return 1; - uint api_hash = length == 4 - ? System.BitConverter.ToUInt32(CurrentContext.Script, CurrentContext.InstructionPointer + 2) - : Encoding.ASCII.GetString(CurrentContext.Script, CurrentContext.InstructionPointer + 2, length).ToInteropMethodHash(); + Instruction instruction = CurrentContext.CurrentInstruction; + uint api_hash = instruction.Operand.Length == 4 + ? System.BitConverter.ToUInt32(instruction.Operand, 0) + : Encoding.ASCII.GetString(instruction.Operand).ToInteropMethodHash(); long price = Service.GetPrice(api_hash); if (price > 0) return price; if (api_hash == "Neo.Asset.Create".ToInteropMethodHash() || @@ -161,13 +132,11 @@ protected virtual long GetPriceForSysCall() return 1; } - private bool PreStepInto(OpCode nextOpcode) + protected override bool PreExecuteInstruction() { - if (CurrentContext.InstructionPointer >= CurrentContext.Script.Length) - return true; - gas_consumed = checked(gas_consumed + GetPrice(nextOpcode) * ratio); + gas_consumed = checked(gas_consumed + GetPrice() * ratio); if (!testMode && gas_consumed > gas_amount) return false; - if (!CheckDynamicInvoke(nextOpcode)) return false; + if (!CheckDynamicInvoke()) return false; return true; } diff --git a/neo/SmartContract/Helper.cs b/neo/SmartContract/Helper.cs index 436755d4db..ce49cf21bb 100644 --- a/neo/SmartContract/Helper.cs +++ b/neo/SmartContract/Helper.cs @@ -115,7 +115,8 @@ internal static bool VerifyWitnesses(this IVerifiable verifiable, Snapshot snaps { engine.LoadScript(verification); engine.LoadScript(verifiable.Witnesses[i].InvocationScript); - if (!engine.Execute()) return false; + engine.Execute(); + if (engine.State.HasFlag(VMState.FAULT)) return false; if (engine.ResultStack.Count != 1 || !engine.ResultStack.Pop().GetBoolean()) return false; } } diff --git a/neo/neo.csproj b/neo/neo.csproj index e8e9ebadbf..284c31e71f 100644 --- a/neo/neo.csproj +++ b/neo/neo.csproj @@ -1,9 +1,9 @@  - 2015-2018 The Neo Project + 2015-2019 The Neo Project Neo - 2.10.0 + 2.10.1 The Neo Project netstandard2.0;net47 true @@ -19,11 +19,6 @@ latest - - none - False - - @@ -32,7 +27,7 @@ - + From d7e20a4989131685934444d117c9f57482bb1a36 Mon Sep 17 00:00:00 2001 From: erikzhang Date: Mon, 1 Apr 2019 23:16:32 +0800 Subject: [PATCH 2/5] Upgrade dependency --- neo.UnitTests/UT_InteropPrices.cs | 64 +++++++++++++++----------- neo/Helper.cs | 25 ++++++++++ neo/SmartContract/ApplicationEngine.cs | 8 ++-- neo/neo.csproj | 2 +- 4 files changed, 65 insertions(+), 34 deletions(-) diff --git a/neo.UnitTests/UT_InteropPrices.cs b/neo.UnitTests/UT_InteropPrices.cs index 0a74659d84..818b95c8c4 100644 --- a/neo.UnitTests/UT_InteropPrices.cs +++ b/neo.UnitTests/UT_InteropPrices.cs @@ -259,9 +259,10 @@ public void ApplicationEngineVariablePrices() byte[] SyscallAssetRenewHash = new byte[]{0x59, 0x59, 0x68, 0x04, 0x78, 0x84, 0x90, 0x71}; using ( ApplicationEngine ae = new ApplicationEngine(TriggerType.Application, null, null, Fixed8.Zero) ) { + Debugger debugger = new Debugger(ae); ae.LoadScript(SyscallAssetRenewHash); - ae.StepInto(); // push 9 - ae.StepInto(); // push 9 + debugger.StepInto(); // push 9 + debugger.StepInto(); // push 9 GetPriceForSysCall.Invoke(ae, new object[]{}).Should().Be(9L * 5000L * 100000000L / 100000); // assuming private ae.ratio = 100000 } @@ -269,11 +270,12 @@ public void ApplicationEngineVariablePrices() byte[] SyscallContractCreateHash00 = new byte[]{(byte)ContractPropertyState.NoProperty, 0x00, 0x00, 0x00, 0x68, 0x04, 0xf6, 0x6c, 0xa5, 0x6e}; using ( ApplicationEngine ae = new ApplicationEngine(TriggerType.Application, null, null, Fixed8.Zero) ) { + Debugger debugger = new Debugger(ae); ae.LoadScript(SyscallContractCreateHash00); - ae.StepInto(); // push 0 - ContractPropertyState.NoProperty - ae.StepInto(); // push 0 - ae.StepInto(); // push 0 - ae.StepInto(); // push 0 + debugger.StepInto(); // push 0 - ContractPropertyState.NoProperty + debugger.StepInto(); // push 0 + debugger.StepInto(); // push 0 + debugger.StepInto(); // push 0 GetPriceForSysCall.Invoke(ae, new object[]{}).Should().Be(100L * 100000000L / 100000); // assuming private ae.ratio = 100000 } @@ -281,11 +283,12 @@ public void ApplicationEngineVariablePrices() byte[] SyscallContractCreateHash01 = new byte[]{0x51, 0x00, 0x00, 0x00, 0x68, 0x04, 0xf6, 0x6c, 0xa5, 0x6e}; using ( ApplicationEngine ae = new ApplicationEngine(TriggerType.Application, null, null, Fixed8.Zero) ) { + Debugger debugger = new Debugger(ae); ae.LoadScript(SyscallContractCreateHash01); - ae.StepInto(); // push 01 - ContractPropertyState.HasStorage - ae.StepInto(); // push 0 - ae.StepInto(); // push 0 - ae.StepInto(); // push 0 + debugger.StepInto(); // push 01 - ContractPropertyState.HasStorage + debugger.StepInto(); // push 0 + debugger.StepInto(); // push 0 + debugger.StepInto(); // push 0 GetPriceForSysCall.Invoke(ae, new object[]{}).Should().Be(500L * 100000000L / 100000); // assuming private ae.ratio = 100000 } @@ -293,11 +296,12 @@ public void ApplicationEngineVariablePrices() byte[] SyscallContractCreateHash02 = new byte[]{0x52, 0x00, 0x00, 0x00, 0x68, 0x04, 0xf6, 0x6c, 0xa5, 0x6e}; using ( ApplicationEngine ae = new ApplicationEngine(TriggerType.Application, null, null, Fixed8.Zero) ) { + Debugger debugger = new Debugger(ae); ae.LoadScript(SyscallContractCreateHash02); - ae.StepInto(); // push 02 - ContractPropertyState.HasDynamicInvoke - ae.StepInto(); // push 0 - ae.StepInto(); // push 0 - ae.StepInto(); // push 0 + debugger.StepInto(); // push 02 - ContractPropertyState.HasDynamicInvoke + debugger.StepInto(); // push 0 + debugger.StepInto(); // push 0 + debugger.StepInto(); // push 0 GetPriceForSysCall.Invoke(ae, new object[]{}).Should().Be(600L * 100000000L / 100000); // assuming private ae.ratio = 100000 } @@ -305,11 +309,12 @@ public void ApplicationEngineVariablePrices() byte[] SyscallContractCreateHash03 = new byte[]{0x53, 0x00, 0x00, 0x00, 0x68, 0x04, 0xf6, 0x6c, 0xa5, 0x6e}; using ( ApplicationEngine ae = new ApplicationEngine(TriggerType.Application, null, null, Fixed8.Zero) ) { + Debugger debugger = new Debugger(ae); ae.LoadScript(SyscallContractCreateHash03); - ae.StepInto(); // push 03 - HasStorage and HasDynamicInvoke - ae.StepInto(); // push 0 - ae.StepInto(); // push 0 - ae.StepInto(); // push 0 + debugger.StepInto(); // push 03 - HasStorage and HasDynamicInvoke + debugger.StepInto(); // push 0 + debugger.StepInto(); // push 0 + debugger.StepInto(); // push 0 GetPriceForSysCall.Invoke(ae, new object[]{}).Should().Be(1000L * 100000000L / 100000); // assuming private ae.ratio = 100000 } @@ -317,11 +322,12 @@ public void ApplicationEngineVariablePrices() byte[] SyscallContractMigrateHash00 = new byte[]{(byte)ContractPropertyState.NoProperty, 0x00, 0x00, 0x00, 0x68, 0x04, 0x47, 0x1b, 0x62, 0x90}; using ( ApplicationEngine ae = new ApplicationEngine(TriggerType.Application, null, null, Fixed8.Zero) ) { + Debugger debugger = new Debugger(ae); ae.LoadScript(SyscallContractMigrateHash00); - ae.StepInto(); // push 0 - ContractPropertyState.NoProperty - ae.StepInto(); // push 0 - ae.StepInto(); // push 0 - ae.StepInto(); // push 0 + debugger.StepInto(); // push 0 - ContractPropertyState.NoProperty + debugger.StepInto(); // push 0 + debugger.StepInto(); // push 0 + debugger.StepInto(); // push 0 GetPriceForSysCall.Invoke(ae, new object[]{}).Should().Be(100L * 100000000L / 100000); // assuming private ae.ratio = 100000 } @@ -329,10 +335,11 @@ public void ApplicationEngineVariablePrices() byte[] SyscallStoragePutHash = new byte[]{0x53, 0x53, 0x00, 0x68, 0x04, 0xe6, 0x3f, 0x18, 0x84}; using ( ApplicationEngine ae = new ApplicationEngine(TriggerType.Application, null, null, Fixed8.Zero) ) { + Debugger debugger = new Debugger(ae); ae.LoadScript(SyscallStoragePutHash); - ae.StepInto(); // push 03 (length 1) - ae.StepInto(); // push 03 (length 1) - ae.StepInto(); // push 00 + debugger.StepInto(); // push 03 (length 1) + debugger.StepInto(); // push 03 (length 1) + debugger.StepInto(); // push 00 GetPriceForSysCall.Invoke(ae, new object[]{}).Should().Be(1000L); //((1+1-1) / 1024 + 1) * 1000); } @@ -340,10 +347,11 @@ public void ApplicationEngineVariablePrices() byte[] SyscallStoragePutExHash = new byte[]{0x53, 0x53, 0x00, 0x68, 0x04, 0x73, 0xe1, 0x9b, 0x3a}; using ( ApplicationEngine ae = new ApplicationEngine(TriggerType.Application, null, null, Fixed8.Zero) ) { + Debugger debugger = new Debugger(ae); ae.LoadScript(SyscallStoragePutExHash); - ae.StepInto(); // push 03 (length 1) - ae.StepInto(); // push 03 (length 1) - ae.StepInto(); // push 00 + debugger.StepInto(); // push 03 (length 1) + debugger.StepInto(); // push 03 (length 1) + debugger.StepInto(); // push 00 GetPriceForSysCall.Invoke(ae, new object[]{}).Should().Be(1000L); //((1+1-1) / 1024 + 1) * 1000); } } diff --git a/neo/Helper.cs b/neo/Helper.cs index 7672d078b3..7387280e2b 100644 --- a/neo/Helper.cs +++ b/neo/Helper.cs @@ -126,6 +126,31 @@ internal static BigInteger NextBigInteger(this RandomNumberGenerator rng, int si return new BigInteger(b); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + unsafe internal static bool NotZero(this byte[] x) + { + if (x is null) + throw new ArgumentNullException(nameof(x)); + int len = x.Length; + if (len == 0) return false; + fixed (byte* xp = x) + { + long* xlp = (long*)xp; + for (; len >= 8; len -= 8) + { + if (*xlp != 0) return true; + xlp++; + } + byte* xbp = (byte*)xlp; + for (; len > 0; len--) + { + if (*xbp != 0) return true; + xbp++; + } + } + return false; + } + public static Fixed8 Sum(this IEnumerable source) { long sum = 0; diff --git a/neo/SmartContract/ApplicationEngine.cs b/neo/SmartContract/ApplicationEngine.cs index 7694db2441..81606438ed 100644 --- a/neo/SmartContract/ApplicationEngine.cs +++ b/neo/SmartContract/ApplicationEngine.cs @@ -3,8 +3,6 @@ using Neo.Persistence; using Neo.VM; using Neo.VM.Types; -using System.Linq; -using System.Text; namespace Neo.SmartContract { @@ -35,7 +33,7 @@ private bool CheckDynamicInvoke() { case OpCode.APPCALL: case OpCode.TAILCALL: - if (instruction.Operand.Any(p => p != 0)) return true; + if (instruction.Operand.NotZero()) return true; // if we get this far it is a dynamic call // now look at the current executing script // to determine if it can do dynamic calls @@ -95,8 +93,8 @@ protected virtual long GetPriceForSysCall() { Instruction instruction = CurrentContext.CurrentInstruction; uint api_hash = instruction.Operand.Length == 4 - ? System.BitConverter.ToUInt32(instruction.Operand, 0) - : Encoding.ASCII.GetString(instruction.Operand).ToInteropMethodHash(); + ? instruction.TokenU32 + : instruction.TokenString.ToInteropMethodHash(); long price = Service.GetPrice(api_hash); if (price > 0) return price; if (api_hash == "Neo.Asset.Create".ToInteropMethodHash() || diff --git a/neo/neo.csproj b/neo/neo.csproj index 284c31e71f..70def65b22 100644 --- a/neo/neo.csproj +++ b/neo/neo.csproj @@ -27,7 +27,7 @@ - + From c1cebf18d5a5f901542c509fceb0e245867f8029 Mon Sep 17 00:00:00 2001 From: erikzhang Date: Tue, 2 Apr 2019 18:02:12 +0800 Subject: [PATCH 3/5] fixes `gas_consumed` --- neo/SmartContract/ApplicationEngine.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/neo/SmartContract/ApplicationEngine.cs b/neo/SmartContract/ApplicationEngine.cs index 81606438ed..8eedc84c87 100644 --- a/neo/SmartContract/ApplicationEngine.cs +++ b/neo/SmartContract/ApplicationEngine.cs @@ -132,6 +132,8 @@ protected virtual long GetPriceForSysCall() protected override bool PreExecuteInstruction() { + if (CurrentContext.InstructionPointer >= CurrentContext.Script.Length) + return true; gas_consumed = checked(gas_consumed + GetPrice() * ratio); if (!testMode && gas_consumed > gas_amount) return false; if (!CheckDynamicInvoke()) return false; From d12dba1a1f7ca0073db3ab7222841e53a9b8566c Mon Sep 17 00:00:00 2001 From: erikzhang Date: Tue, 2 Apr 2019 21:54:03 +0800 Subject: [PATCH 4/5] Upgrade dependency --- neo/neo.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/neo/neo.csproj b/neo/neo.csproj index 70def65b22..1fdb547fb2 100644 --- a/neo/neo.csproj +++ b/neo/neo.csproj @@ -27,7 +27,7 @@ - + From 01409d4775bbc2d6ada7fc9f501ec43d9a91219d Mon Sep 17 00:00:00 2001 From: erikzhang Date: Thu, 4 Apr 2019 21:43:35 +0800 Subject: [PATCH 5/5] Upgrade dependency --- neo/neo.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/neo/neo.csproj b/neo/neo.csproj index 1fdb547fb2..db7ed335f1 100644 --- a/neo/neo.csproj +++ b/neo/neo.csproj @@ -27,7 +27,7 @@ - +