From d0a68c60baa737385d260cb02d27eac5ab52f601 Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Sun, 10 Jan 2021 14:33:48 +0800 Subject: [PATCH 1/4] Optimize dynamic call --- .../Network/P2P/Payloads/OracleResponse.cs | 2 +- .../ApplicationEngine.Contract.cs | 19 ++++--- src/neo/SmartContract/ApplicationEngine.cs | 20 +++++--- .../SmartContract/Native/NativeContract.cs | 4 +- src/neo/VM/Helper.cs | 21 ++++---- src/neo/Wallets/AssetDescriptor.cs | 4 +- src/neo/Wallets/Wallet.cs | 8 +-- .../Extensions/NativeContractExtensions.cs | 6 +-- .../Network/P2P/Payloads/UT_Transaction.cs | 14 +++--- .../SmartContract/Native/UT_NativeContract.cs | 2 +- .../SmartContract/Native/UT_NeoToken.cs | 8 +-- .../SmartContract/UT_InteropService.cs | 18 +++---- .../SmartContract/UT_Syscalls.cs | 8 +-- tests/neo.UnitTests/VM/UT_Helper.cs | 49 +++++++++---------- 14 files changed, 93 insertions(+), 90 deletions(-) diff --git a/src/neo/Network/P2P/Payloads/OracleResponse.cs b/src/neo/Network/P2P/Payloads/OracleResponse.cs index 25f7797dbf..77ed8cf7ec 100644 --- a/src/neo/Network/P2P/Payloads/OracleResponse.cs +++ b/src/neo/Network/P2P/Payloads/OracleResponse.cs @@ -31,7 +31,7 @@ public class OracleResponse : TransactionAttribute static OracleResponse() { using ScriptBuilder sb = new ScriptBuilder(); - sb.EmitDynamicCall(NativeContract.Oracle.Hash, "finish", false); + sb.EmitDynamicCall(NativeContract.Oracle.Hash, "finish"); FixedScript = sb.ToArray(); } diff --git a/src/neo/SmartContract/ApplicationEngine.Contract.cs b/src/neo/SmartContract/ApplicationEngine.Contract.cs index 17dd21fc4f..6101c0bad0 100644 --- a/src/neo/SmartContract/ApplicationEngine.Contract.cs +++ b/src/neo/SmartContract/ApplicationEngine.Contract.cs @@ -1,8 +1,10 @@ using Neo.Cryptography.ECC; using Neo.Network.P2P.Payloads; +using Neo.SmartContract.Manifest; using Neo.SmartContract.Native; using Neo.VM.Types; using System; +using Array = Neo.VM.Types.Array; namespace Neo.SmartContract { @@ -20,17 +22,20 @@ partial class ApplicationEngine public static readonly InteropDescriptor System_Contract_NativeOnPersist = Register("System.Contract.NativeOnPersist", nameof(NativeOnPersist), 0, CallFlags.WriteStates); public static readonly InteropDescriptor System_Contract_NativePostPersist = Register("System.Contract.NativePostPersist", nameof(NativePostPersist), 0, CallFlags.WriteStates); - protected internal void CallContract(UInt160 contractHash, string method, CallFlags callFlags, bool hasReturnValue, ushort pcount) + protected internal void CallContract(UInt160 contractHash, string method, Array args, CallFlags callFlags) { if (method.StartsWith('_')) throw new ArgumentException($"Invalid Method Name: {method}"); if ((callFlags & ~CallFlags.All) != 0) throw new ArgumentOutOfRangeException(nameof(callFlags)); - if (pcount > CurrentContext.EvaluationStack.Count) - throw new InvalidOperationException(); - StackItem[] args = new StackItem[pcount]; - for (int i = 0; i < pcount; i++) - args[i] = Pop(); - CallContractInternal(contractHash, method, callFlags, hasReturnValue, args); + + ContractState contract = NativeContract.ContractManagement.GetContract(Snapshot, contractHash); + if (contract is null) throw new InvalidOperationException($"Called Contract Does Not Exist: {contractHash}"); + ContractMethodDescriptor md = contract.Manifest.Abi.GetMethod(method); + if (md is null) throw new InvalidOperationException($"Method {method} Does Not Exist In Contract {contractHash}"); + bool hasReturnValue = md.ReturnType != ContractParameterType.Void; + + if (!hasReturnValue) CurrentContext.EvaluationStack.Push(StackItem.Null); + CallContractInternal(contract, md, callFlags, hasReturnValue, args); } protected internal void CallNativeContract(string name) diff --git a/src/neo/SmartContract/ApplicationEngine.cs b/src/neo/SmartContract/ApplicationEngine.cs index 883ea6ef7e..f481e27726 100644 --- a/src/neo/SmartContract/ApplicationEngine.cs +++ b/src/neo/SmartContract/ApplicationEngine.cs @@ -82,16 +82,20 @@ private ExecutionContext CallContractInternal(UInt160 contractHash, string metho if (contract is null) throw new InvalidOperationException($"Called Contract Does Not Exist: {contractHash}"); ContractMethodDescriptor md = contract.Manifest.Abi.GetMethod(method); if (md is null) throw new InvalidOperationException($"Method {method} Does Not Exist In Contract {contractHash}"); + return CallContractInternal(contract, md, flags, hasReturnValue, args); + } - if (md.Safe) + private ExecutionContext CallContractInternal(ContractState contract, ContractMethodDescriptor method, CallFlags flags, bool hasReturnValue, IReadOnlyList args) + { + if (method.Safe) { flags &= ~CallFlags.WriteStates; } else { ContractState currentContract = NativeContract.ContractManagement.GetContract(Snapshot, CurrentScriptHash); - if (currentContract?.CanCall(contract, method) == false) - throw new InvalidOperationException($"Cannot Call Method {method} Of Contract {contractHash} From Contract {CurrentScriptHash}"); + if (currentContract?.CanCall(contract, method.Name) == false) + throw new InvalidOperationException($"Cannot Call Method {method} Of Contract {contract.Hash} From Contract {CurrentScriptHash}"); } if (invocationCounter.TryGetValue(contract.Hash, out var counter)) @@ -107,16 +111,16 @@ private ExecutionContext CallContractInternal(UInt160 contractHash, string metho UInt160 callingScriptHash = state.ScriptHash; CallFlags callingFlags = state.CallFlags; - if (args.Length != md.Parameters.Length) throw new InvalidOperationException($"Method {method} Expects {md.Parameters.Length} Arguments But Receives {args.Length} Arguments"); - if (hasReturnValue ^ (md.ReturnType != ContractParameterType.Void)) throw new InvalidOperationException("The return value type does not match."); - ExecutionContext context_new = LoadContract(contract, method, flags & callingFlags, hasReturnValue, (ushort)args.Length); + if (args.Count != method.Parameters.Length) throw new InvalidOperationException($"Method {method} Expects {method.Parameters.Length} Arguments But Receives {args.Count} Arguments"); + if (hasReturnValue ^ (method.ReturnType != ContractParameterType.Void)) throw new InvalidOperationException("The return value type does not match."); + ExecutionContext context_new = LoadContract(contract, method.Name, flags & callingFlags, hasReturnValue, (ushort)args.Count); state = context_new.GetState(); state.CallingScriptHash = callingScriptHash; - for (int i = args.Length - 1; i >= 0; i--) + for (int i = args.Count - 1; i >= 0; i--) context_new.EvaluationStack.Push(args[i]); if (NativeContract.IsNative(contract.Hash)) - context_new.EvaluationStack.Push(method); + context_new.EvaluationStack.Push(method.Name); return context_new; } diff --git a/src/neo/SmartContract/Native/NativeContract.cs b/src/neo/SmartContract/Native/NativeContract.cs index 115a48a956..1eafb3977b 100644 --- a/src/neo/SmartContract/Native/NativeContract.cs +++ b/src/neo/SmartContract/Native/NativeContract.cs @@ -149,11 +149,11 @@ internal virtual void PostPersist(ApplicationEngine engine) { } - public ApplicationEngine TestCall(string operation, bool hasReturnValue, params object[] args) + public ApplicationEngine TestCall(string operation, params object[] args) { using (ScriptBuilder sb = new ScriptBuilder()) { - sb.EmitDynamicCall(Hash, operation, hasReturnValue, args); + sb.EmitDynamicCall(Hash, operation, args); return ApplicationEngine.Run(sb.ToArray()); } } diff --git a/src/neo/VM/Helper.cs b/src/neo/VM/Helper.cs index 764f7fd9ab..f7f6d02e67 100644 --- a/src/neo/VM/Helper.cs +++ b/src/neo/VM/Helper.cs @@ -46,37 +46,36 @@ public static ScriptBuilder Emit(this ScriptBuilder sb, params OpCode[] ops) return sb; } - public static ScriptBuilder EmitDynamicCall(this ScriptBuilder sb, UInt160 scriptHash, string operation, bool hasReturnValue) + public static ScriptBuilder EmitDynamicCall(this ScriptBuilder sb, UInt160 scriptHash, string operation) { - sb.EmitPush(0); - sb.EmitPush(hasReturnValue ? 1 : 0); sb.EmitPush(CallFlags.All); + sb.Emit(OpCode.NEWARRAY0); sb.EmitPush(operation); sb.EmitPush(scriptHash); sb.EmitSysCall(ApplicationEngine.System_Contract_Call); return sb; } - public static ScriptBuilder EmitDynamicCall(this ScriptBuilder sb, UInt160 scriptHash, string operation, bool hasReturnValue, params ContractParameter[] args) + public static ScriptBuilder EmitDynamicCall(this ScriptBuilder sb, UInt160 scriptHash, string operation, params ContractParameter[] args) { + sb.EmitPush(CallFlags.All); for (int i = args.Length - 1; i >= 0; i--) sb.EmitPush(args[i]); sb.EmitPush(args.Length); - sb.EmitPush(hasReturnValue ? 1 : 0); - sb.EmitPush(CallFlags.All); + sb.Emit(OpCode.PACK); sb.EmitPush(operation); sb.EmitPush(scriptHash); sb.EmitSysCall(ApplicationEngine.System_Contract_Call); return sb; } - public static ScriptBuilder EmitDynamicCall(this ScriptBuilder sb, UInt160 scriptHash, string operation, bool hasReturnValue, params object[] args) + public static ScriptBuilder EmitDynamicCall(this ScriptBuilder sb, UInt160 scriptHash, string operation, params object[] args) { + sb.EmitPush(CallFlags.All); for (int i = args.Length - 1; i >= 0; i--) sb.EmitPush(args[i]); sb.EmitPush(args.Length); - sb.EmitPush(hasReturnValue ? 1 : 0); - sb.EmitPush(CallFlags.All); + sb.Emit(OpCode.PACK); sb.EmitPush(operation); sb.EmitPush(scriptHash); sb.EmitSysCall(ApplicationEngine.System_Contract_Call); @@ -213,10 +212,10 @@ public static ScriptBuilder EmitSysCall(this ScriptBuilder sb, uint method, para /// contract operation /// operation arguments /// - public static byte[] MakeScript(this UInt160 scriptHash, string operation, bool hasReturnValue, params object[] args) + public static byte[] MakeScript(this UInt160 scriptHash, string operation, params object[] args) { using ScriptBuilder sb = new ScriptBuilder(); - sb.EmitDynamicCall(scriptHash, operation, hasReturnValue, args); + sb.EmitDynamicCall(scriptHash, operation, args); return sb.ToArray(); } diff --git a/src/neo/Wallets/AssetDescriptor.cs b/src/neo/Wallets/AssetDescriptor.cs index e13fb02589..3be315f86d 100644 --- a/src/neo/Wallets/AssetDescriptor.cs +++ b/src/neo/Wallets/AssetDescriptor.cs @@ -23,8 +23,8 @@ public AssetDescriptor(UInt160 asset_id) byte[] script; using (ScriptBuilder sb = new ScriptBuilder()) { - sb.EmitDynamicCall(asset_id, "decimals", true); - sb.EmitDynamicCall(asset_id, "symbol", true); + sb.EmitDynamicCall(asset_id, "decimals"); + sb.EmitDynamicCall(asset_id, "symbol"); script = sb.ToArray(); } using ApplicationEngine engine = ApplicationEngine.Run(script, snapshot, gas: 0_10000000); diff --git a/src/neo/Wallets/Wallet.cs b/src/neo/Wallets/Wallet.cs index 44cb5990f3..77015abf60 100644 --- a/src/neo/Wallets/Wallet.cs +++ b/src/neo/Wallets/Wallet.cs @@ -138,10 +138,10 @@ public BigDecimal GetBalance(UInt160 asset_id, params UInt160[] accounts) sb.EmitPush(0); foreach (UInt160 account in accounts) { - sb.EmitDynamicCall(asset_id, "balanceOf", true, account); + sb.EmitDynamicCall(asset_id, "balanceOf", account); sb.Emit(OpCode.ADD); } - sb.EmitDynamicCall(asset_id, "decimals", true); + sb.EmitDynamicCall(asset_id, "decimals"); script = sb.ToArray(); } using ApplicationEngine engine = ApplicationEngine.Run(script, gas: 20000000L * accounts.Length); @@ -265,7 +265,7 @@ public Transaction MakeTransaction(TransferOutput[] outputs, UInt160 from = null foreach (UInt160 account in accounts) using (ScriptBuilder sb2 = new ScriptBuilder()) { - sb2.EmitDynamicCall(assetId, "balanceOf", true, account); + sb2.EmitDynamicCall(assetId, "balanceOf", account); using (ApplicationEngine engine = ApplicationEngine.Run(sb2.ToArray(), snapshot)) { if (engine.State.HasFlag(VMState.FAULT)) @@ -296,7 +296,7 @@ public Transaction MakeTransaction(TransferOutput[] outputs, UInt160 from = null Scopes = WitnessScope.CalledByEntry }); } - sb.EmitDynamicCall(output.AssetId, "transfer", true, account, output.ScriptHash, value, output.Data); + sb.EmitDynamicCall(output.AssetId, "transfer", account, output.ScriptHash, value, output.Data); sb.Emit(OpCode.ASSERT); } } diff --git a/tests/neo.UnitTests/Extensions/NativeContractExtensions.cs b/tests/neo.UnitTests/Extensions/NativeContractExtensions.cs index 5a2d01fa30..a98b08b3b8 100644 --- a/tests/neo.UnitTests/Extensions/NativeContractExtensions.cs +++ b/tests/neo.UnitTests/Extensions/NativeContractExtensions.cs @@ -13,7 +13,7 @@ public static class NativeContractExtensions public static ContractState DeployContract(this StoreView snapshot, UInt160 sender, byte[] nefFile, byte[] manifest, long gas = 200_00000000) { var script = new ScriptBuilder(); - script.EmitDynamicCall(NativeContract.ContractManagement.Hash, "deploy", true, nefFile, manifest); + script.EmitDynamicCall(NativeContract.ContractManagement.Hash, "deploy", nefFile, manifest); var engine = ApplicationEngine.Create(TriggerType.Application, sender != null ? new Transaction() { Signers = new Signer[] { new Signer() { Account = sender } } } : null, snapshot, null, gas); @@ -34,7 +34,7 @@ public static ContractState DeployContract(this StoreView snapshot, UInt160 send public static void UpdateContract(this StoreView snapshot, UInt160 callingScriptHash, byte[] nefFile, byte[] manifest) { var script = new ScriptBuilder(); - script.EmitDynamicCall(NativeContract.ContractManagement.Hash, "update", false, nefFile, manifest); + script.EmitDynamicCall(NativeContract.ContractManagement.Hash, "update", nefFile, manifest); var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot); engine.LoadScript(script.ToArray()); @@ -57,7 +57,7 @@ public static void UpdateContract(this StoreView snapshot, UInt160 callingScript public static void DestroyContract(this StoreView snapshot, UInt160 callingScriptHash) { var script = new ScriptBuilder(); - script.EmitDynamicCall(NativeContract.ContractManagement.Hash, "destroy", false); + script.EmitDynamicCall(NativeContract.ContractManagement.Hash, "destroy"); var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot); engine.LoadScript(script.ToArray()); diff --git a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs index 16aac9d21d..b4f0934307 100644 --- a/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs +++ b/tests/neo.UnitTests/Network/P2P/Payloads/UT_Transaction.cs @@ -319,7 +319,7 @@ public void FeeIsSignatureContract_TestScope_Global() { // self-transfer of 1e-8 GAS BigInteger value = (new BigDecimal(1, 8)).Value; - sb.EmitDynamicCall(NativeContract.GAS.Hash, "transfer", true, acc.ScriptHash, acc.ScriptHash, value, null); + sb.EmitDynamicCall(NativeContract.GAS.Hash, "transfer", acc.ScriptHash, acc.ScriptHash, value, null); sb.Emit(OpCode.ASSERT); script = sb.ToArray(); } @@ -405,7 +405,7 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_GAS() { // self-transfer of 1e-8 GAS BigInteger value = (new BigDecimal(1, 8)).Value; - sb.EmitDynamicCall(NativeContract.GAS.Hash, "transfer", true, acc.ScriptHash, acc.ScriptHash, value, null); + sb.EmitDynamicCall(NativeContract.GAS.Hash, "transfer", acc.ScriptHash, acc.ScriptHash, value, null); sb.Emit(OpCode.ASSERT); script = sb.ToArray(); } @@ -492,7 +492,7 @@ public void FeeIsSignatureContract_TestScope_CalledByEntry_Plus_GAS() { // self-transfer of 1e-8 GAS System.Numerics.BigInteger value = (new BigDecimal(1, 8)).Value; - sb.EmitDynamicCall(NativeContract.GAS.Hash, "transfer", true, acc.ScriptHash, acc.ScriptHash, value, null); + sb.EmitDynamicCall(NativeContract.GAS.Hash, "transfer", acc.ScriptHash, acc.ScriptHash, value, null); sb.Emit(OpCode.ASSERT); script = sb.ToArray(); } @@ -580,7 +580,7 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_NEO_FAULT() { // self-transfer of 1e-8 GAS System.Numerics.BigInteger value = (new BigDecimal(1, 8)).Value; - sb.EmitDynamicCall(NativeContract.GAS.Hash, "transfer", true, acc.ScriptHash, acc.ScriptHash, value); + sb.EmitDynamicCall(NativeContract.GAS.Hash, "transfer", acc.ScriptHash, acc.ScriptHash, value); sb.Emit(OpCode.ASSERT); script = sb.ToArray(); } @@ -632,7 +632,7 @@ public void FeeIsSignatureContract_TestScope_CurrentHash_NEO_GAS() { // self-transfer of 1e-8 GAS BigInteger value = (new BigDecimal(1, 8)).Value; - sb.EmitDynamicCall(NativeContract.GAS.Hash, "transfer", true, acc.ScriptHash, acc.ScriptHash, value, null); + sb.EmitDynamicCall(NativeContract.GAS.Hash, "transfer", acc.ScriptHash, acc.ScriptHash, value, null); sb.Emit(OpCode.ASSERT); script = sb.ToArray(); } @@ -722,7 +722,7 @@ public void FeeIsSignatureContract_TestScope_NoScopeFAULT() { // self-transfer of 1e-8 GAS BigInteger value = (new BigDecimal(1, 8)).Value; - sb.EmitDynamicCall(NativeContract.GAS.Hash, "transfer", true, acc.ScriptHash, acc.ScriptHash, value); + sb.EmitDynamicCall(NativeContract.GAS.Hash, "transfer", acc.ScriptHash, acc.ScriptHash, value); sb.Emit(OpCode.ASSERT); script = sb.ToArray(); } @@ -985,7 +985,7 @@ public void FeeIsSignatureContract_TestScope_FeeOnly_Default() { // self-transfer of 1e-8 GAS BigInteger value = (new BigDecimal(1, 8)).Value; - sb.EmitDynamicCall(NativeContract.GAS.Hash, "transfer", true, acc.ScriptHash, acc.ScriptHash, value, null); + sb.EmitDynamicCall(NativeContract.GAS.Hash, "transfer", acc.ScriptHash, acc.ScriptHash, value, null); sb.Emit(OpCode.ASSERT); script = sb.ToArray(); } diff --git a/tests/neo.UnitTests/SmartContract/Native/UT_NativeContract.cs b/tests/neo.UnitTests/SmartContract/Native/UT_NativeContract.cs index eed8e77026..9cd24fc66d 100644 --- a/tests/neo.UnitTests/SmartContract/Native/UT_NativeContract.cs +++ b/tests/neo.UnitTests/SmartContract/Native/UT_NativeContract.cs @@ -129,7 +129,7 @@ public void TestTrigger() [TestMethod] public void TestTestCall() { - ApplicationEngine engine = testNativeContract.TestCall("System.Blockchain.GetHeight", false, 0); + ApplicationEngine engine = testNativeContract.TestCall("System.Blockchain.GetHeight", 0); engine.ResultStack.Should().BeEmpty(); } } diff --git a/tests/neo.UnitTests/SmartContract/Native/UT_NeoToken.cs b/tests/neo.UnitTests/SmartContract/Native/UT_NeoToken.cs index 024641eff3..e580e6f465 100644 --- a/tests/neo.UnitTests/SmartContract/Native/UT_NeoToken.cs +++ b/tests/neo.UnitTests/SmartContract/Native/UT_NeoToken.cs @@ -511,7 +511,7 @@ public void TestCalculateBonus() [TestMethod] public void TestGetNextBlockValidators1() { - using (ApplicationEngine engine = NativeContract.NEO.TestCall("getNextBlockValidators", true)) + using (ApplicationEngine engine = NativeContract.NEO.TestCall("getNextBlockValidators")) { var result = engine.ResultStack.Peek(); result.GetType().Should().Be(typeof(VM.Types.Array)); @@ -544,7 +544,7 @@ public void TestGetNextBlockValidators2() [TestMethod] public void TestGetCandidates1() { - using ApplicationEngine engine = NativeContract.NEO.TestCall("getCandidates", true); + using ApplicationEngine engine = NativeContract.NEO.TestCall("getCandidates"); var array = engine.ResultStack.Pop(); array.Count.Should().Be(0); } @@ -605,7 +605,7 @@ public void TestCheckCandidate() [TestMethod] public void TestGetCommittee() { - using (ApplicationEngine engine = NativeContract.NEO.TestCall("getCommittee", true)) + using (ApplicationEngine engine = NativeContract.NEO.TestCall("getCommittee")) { var result = engine.ResultStack.Peek(); result.GetType().Should().Be(typeof(VM.Types.Array)); @@ -837,7 +837,7 @@ public void TestVote() })); } - sb.EmitDynamicCall(NativeContract.NEO.Hash, "transfer", true, from, UInt160.Zero, amount, null); + sb.EmitDynamicCall(NativeContract.NEO.Hash, "transfer", from, UInt160.Zero, amount, null); engine.LoadScript(sb.ToArray()); engine.Execute(); var result = engine.ResultStack.Peek(); diff --git a/tests/neo.UnitTests/SmartContract/UT_InteropService.cs b/tests/neo.UnitTests/SmartContract/UT_InteropService.cs index 2c99d9b7a8..7c5dc594fc 100644 --- a/tests/neo.UnitTests/SmartContract/UT_InteropService.cs +++ b/tests/neo.UnitTests/SmartContract/UT_InteropService.cs @@ -89,7 +89,7 @@ public void Runtime_GetNotifications_Test() // Call script - script.EmitDynamicCall(scriptHash2, "test", true, "testEvent2", 1); + script.EmitDynamicCall(scriptHash2, "test", "testEvent2", 1); // Drop return @@ -141,7 +141,7 @@ public void Runtime_GetNotifications_Test() // Call script - script.EmitDynamicCall(scriptHash2, "test", true, "testEvent2", 1); + script.EmitDynamicCall(scriptHash2, "test", "testEvent2", 1); // Drop return @@ -224,7 +224,7 @@ public void TestExecutionEngine_GetCallingScriptHash() engine.Snapshot.AddContract(contract.Hash, contract); using ScriptBuilder scriptB = new ScriptBuilder(); - scriptB.EmitDynamicCall(contract.Hash, "test", true, 0, 1); + scriptB.EmitDynamicCall(contract.Hash, "test", 0, 1); engine.LoadScript(scriptB.ToArray()); Assert.AreEqual(VMState.HALT, engine.Execute()); @@ -596,21 +596,17 @@ public void TestContract_Call() var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot); engine.LoadScript(new byte[] { 0x01 }); - engine.Push(args[1]); engine.Push(args[0]); - engine.CallContract(state.Hash, method, CallFlags.All, true, (ushort)args.Count); + engine.CallContract(state.Hash, method, args, CallFlags.All); engine.CurrentContext.EvaluationStack.Pop().Should().Be(args[0]); engine.CurrentContext.EvaluationStack.Pop().Should().Be(args[1]); state.Manifest.Permissions[0].Methods = WildcardContainer.Create("a"); - engine.Push(args[1]); engine.Push(args[0]); - Assert.ThrowsException(() => engine.CallContract(state.Hash, method, CallFlags.All, true, (ushort)args.Count)); + Assert.ThrowsException(() => engine.CallContract(state.Hash, method, args, CallFlags.All)); state.Manifest.Permissions[0].Methods = WildcardContainer.CreateWildcard(); - engine.Push(args[1]); engine.Push(args[0]); - engine.CallContract(state.Hash, method, CallFlags.All, true, (ushort)args.Count); + engine.CallContract(state.Hash, method, args, CallFlags.All); - engine.Push(args[1]); engine.Push(args[0]); - Assert.ThrowsException(() => engine.CallContract(UInt160.Zero, method, CallFlags.All, true, (ushort)args.Count)); + Assert.ThrowsException(() => engine.CallContract(UInt160.Zero, method, args, CallFlags.All)); } [TestMethod] diff --git a/tests/neo.UnitTests/SmartContract/UT_Syscalls.cs b/tests/neo.UnitTests/SmartContract/UT_Syscalls.cs index 029c04c623..ed7abb463e 100644 --- a/tests/neo.UnitTests/SmartContract/UT_Syscalls.cs +++ b/tests/neo.UnitTests/SmartContract/UT_Syscalls.cs @@ -349,10 +349,10 @@ public void System_Runtime_GetInvocationCounter() using (var script = new ScriptBuilder()) { - script.EmitDynamicCall(contractA.Hash, "dummyMain", true, 0, 1); - script.EmitDynamicCall(contractB.Hash, "dummyMain", true, 0, 1); - script.EmitDynamicCall(contractB.Hash, "dummyMain", true, 0, 1); - script.EmitDynamicCall(contractC.Hash, "dummyMain", true, 0, 1); + script.EmitDynamicCall(contractA.Hash, "dummyMain", 0, 1); + script.EmitDynamicCall(contractB.Hash, "dummyMain", 0, 1); + script.EmitDynamicCall(contractB.Hash, "dummyMain", 0, 1); + script.EmitDynamicCall(contractC.Hash, "dummyMain", 0, 1); // Execute diff --git a/tests/neo.UnitTests/VM/UT_Helper.cs b/tests/neo.UnitTests/VM/UT_Helper.cs index 3b8333e531..429d2c10a0 100644 --- a/tests/neo.UnitTests/VM/UT_Helper.cs +++ b/tests/neo.UnitTests/VM/UT_Helper.cs @@ -51,20 +51,19 @@ public void TestToJson() public void TestEmitAppCall1() { ScriptBuilder sb = new ScriptBuilder(); - sb.EmitDynamicCall(UInt160.Zero, "AAAAA", false); - byte[] tempArray = new byte[37]; - tempArray[0] = (byte)OpCode.PUSH0; - tempArray[1] = (byte)OpCode.PUSH0; - tempArray[2] = (byte)OpCode.PUSH15;//(byte)CallFlags.All; - tempArray[3] = (byte)OpCode.PUSHDATA1; - tempArray[4] = 5;//operation.Length - Array.Copy(Encoding.UTF8.GetBytes("AAAAA"), 0, tempArray, 5, 5);//operation.data - tempArray[10] = (byte)OpCode.PUSHDATA1; - tempArray[11] = 0x14;//scriptHash.Length - Array.Copy(UInt160.Zero.ToArray(), 0, tempArray, 12, 20);//operation.data + sb.EmitDynamicCall(UInt160.Zero, "AAAAA"); + byte[] tempArray = new byte[36]; + tempArray[0] = (byte)OpCode.PUSH15;//(byte)CallFlags.All; + tempArray[1] = (byte)OpCode.NEWARRAY0; + tempArray[2] = (byte)OpCode.PUSHDATA1; + tempArray[3] = 5;//operation.Length + Array.Copy(Encoding.UTF8.GetBytes("AAAAA"), 0, tempArray, 4, 5);//operation.data + tempArray[9] = (byte)OpCode.PUSHDATA1; + tempArray[10] = 0x14;//scriptHash.Length + Array.Copy(UInt160.Zero.ToArray(), 0, tempArray, 11, 20);//operation.data uint api = ApplicationEngine.System_Contract_Call; - tempArray[32] = (byte)OpCode.SYSCALL; - Array.Copy(BitConverter.GetBytes(api), 0, tempArray, 33, 4);//api.data + tempArray[31] = (byte)OpCode.SYSCALL; + Array.Copy(BitConverter.GetBytes(api), 0, tempArray, 32, 4);//api.data Assert.AreEqual(tempArray.ToHexString(), sb.ToArray().ToHexString()); } @@ -114,12 +113,12 @@ public void TestEmitMap() public void TestEmitAppCall2() { ScriptBuilder sb = new ScriptBuilder(); - sb.EmitDynamicCall(UInt160.Zero, "AAAAA", false, new ContractParameter[] { new ContractParameter(ContractParameterType.Integer) }); + sb.EmitDynamicCall(UInt160.Zero, "AAAAA", new ContractParameter[] { new ContractParameter(ContractParameterType.Integer) }); byte[] tempArray = new byte[38]; - tempArray[0] = (byte)OpCode.PUSH0; - tempArray[1] = (byte)OpCode.PUSH1; - tempArray[2] = (byte)OpCode.PUSH0; - tempArray[3] = (byte)OpCode.PUSH15;//(byte)CallFlags.All; + tempArray[0] = (byte)OpCode.PUSH15;//(byte)CallFlags.All; + tempArray[1] = (byte)OpCode.PUSH0; + tempArray[2] = (byte)OpCode.PUSH1; + tempArray[3] = (byte)OpCode.PACK; tempArray[4] = (byte)OpCode.PUSHDATA1; tempArray[5] = 0x05;//operation.Length Array.Copy(Encoding.UTF8.GetBytes("AAAAA"), 0, tempArray, 6, 5);//operation.data @@ -136,12 +135,12 @@ public void TestEmitAppCall2() public void TestEmitAppCall3() { ScriptBuilder sb = new ScriptBuilder(); - sb.EmitDynamicCall(UInt160.Zero, "AAAAA", false, true); + sb.EmitDynamicCall(UInt160.Zero, "AAAAA", true); byte[] tempArray = new byte[38]; - tempArray[0] = (byte)OpCode.PUSH1; - tempArray[1] = (byte)OpCode.PUSH1;//arg.Length - tempArray[2] = (byte)OpCode.PUSH0;//return - tempArray[3] = (byte)OpCode.PUSH15;//(byte)CallFlags.All; + tempArray[0] = (byte)OpCode.PUSH15;//(byte)CallFlags.All; + tempArray[1] = (byte)OpCode.PUSH1; + tempArray[2] = (byte)OpCode.PUSH1;//arg.Length + tempArray[3] = (byte)OpCode.PACK; tempArray[4] = (byte)OpCode.PUSHDATA1; tempArray[5] = 0x05;//operation.Length Array.Copy(Encoding.UTF8.GetBytes("AAAAA"), 0, tempArray, 6, 5);//operation.data @@ -157,9 +156,9 @@ public void TestEmitAppCall3() [TestMethod] public void TestMakeScript() { - byte[] testScript = NativeContract.GAS.Hash.MakeScript("balanceOf", true, UInt160.Zero); + byte[] testScript = NativeContract.GAS.Hash.MakeScript("balanceOf", UInt160.Zero); - Assert.AreEqual("0c14000000000000000000000000000000000000000011111f0c0962616c616e63654f660c141717ddafdd757eec365865b963473beb617f9a1441627d5b52", + Assert.AreEqual("1f0c14000000000000000000000000000000000000000011c00c0962616c616e63654f660c141717ddafdd757eec365865b963473beb617f9a1441627d5b52", testScript.ToHexString()); } From 5bfaaa0bf8004de51c078e3e53b9955b9fc8f139 Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Sun, 10 Jan 2021 19:15:40 +0800 Subject: [PATCH 2/4] Fix merge --- .../SmartContract/Native/UT_NameService.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/neo.UnitTests/SmartContract/Native/UT_NameService.cs b/tests/neo.UnitTests/SmartContract/Native/UT_NameService.cs index 919d8edce9..85a5daa48c 100644 --- a/tests/neo.UnitTests/SmartContract/Native/UT_NameService.cs +++ b/tests/neo.UnitTests/SmartContract/Native/UT_NameService.cs @@ -159,7 +159,7 @@ internal static bool Check_DeleteRecord(StoreView snapshot, string name, RecordT { var engine = ApplicationEngine.Create(TriggerType.Application, new Nep17NativeContractExtensions.ManualWitness(signedBy), snapshot, persistingBlock); var script = new ScriptBuilder(); - script.EmitDynamicCall(NativeContract.NameService.Hash, "deleteRecord", false, new ContractParameter[] { + script.EmitDynamicCall(NativeContract.NameService.Hash, "deleteRecord", new ContractParameter[] { new ContractParameter(ContractParameterType.String) { Value = name }, new ContractParameter(ContractParameterType.Integer) { Value = (int)type } }); @@ -177,7 +177,7 @@ internal static bool Check_SetRecord(StoreView snapshot, string name, RecordType { var engine = ApplicationEngine.Create(TriggerType.Application, new Nep17NativeContractExtensions.ManualWitness(signedBy), snapshot, persistingBlock); var script = new ScriptBuilder(); - script.EmitDynamicCall(NativeContract.NameService.Hash, "setRecord", false, new ContractParameter[] { + script.EmitDynamicCall(NativeContract.NameService.Hash, "setRecord", new ContractParameter[] { new ContractParameter(ContractParameterType.String) { Value = name }, new ContractParameter(ContractParameterType.Integer) { Value = (int)type }, new ContractParameter(ContractParameterType.String) { Value = data } @@ -196,7 +196,7 @@ internal static BigInteger Check_Renew(StoreView snapshot, string name, UInt160 { var engine = ApplicationEngine.Create(TriggerType.Application, new Nep17NativeContractExtensions.ManualWitness(signedBy), snapshot, persistingBlock); var script = new ScriptBuilder(); - script.EmitDynamicCall(NativeContract.NameService.Hash, "renew", true, new ContractParameter[] { + script.EmitDynamicCall(NativeContract.NameService.Hash, "renew", new ContractParameter[] { new ContractParameter(ContractParameterType.String) { Value = name } }); engine.LoadScript(script.ToArray(), 0, -1, 0); @@ -216,7 +216,7 @@ internal static bool Check_SetAdmin(StoreView snapshot, string name, UInt160 adm { var engine = ApplicationEngine.Create(TriggerType.Application, new Nep17NativeContractExtensions.ManualWitness(admin, signedBy), snapshot, persistingBlock); var script = new ScriptBuilder(); - script.EmitDynamicCall(NativeContract.NameService.Hash, "setAdmin", false, new ContractParameter[] { + script.EmitDynamicCall(NativeContract.NameService.Hash, "setAdmin", new ContractParameter[] { new ContractParameter(ContractParameterType.String) { Value = name }, new ContractParameter(ContractParameterType.Hash160) { Value = admin } }); @@ -234,7 +234,7 @@ internal static bool Check_Register(StoreView snapshot, string name, UInt160 own { var engine = ApplicationEngine.Create(TriggerType.Application, new Nep17NativeContractExtensions.ManualWitness(owner), snapshot, persistingBlock); var script = new ScriptBuilder(); - script.EmitDynamicCall(NativeContract.NameService.Hash, "register", true, new ContractParameter[] { + script.EmitDynamicCall(NativeContract.NameService.Hash, "register", new ContractParameter[] { new ContractParameter(ContractParameterType.String) { Value = name }, new ContractParameter(ContractParameterType.Hash160) { Value = owner } }); @@ -255,7 +255,7 @@ internal static bool Check_SetPrice(StoreView snapshot, UInt160 signedBy, long p { var engine = ApplicationEngine.Create(TriggerType.Application, new Nep17NativeContractExtensions.ManualWitness(signedBy), snapshot, persistingBlock); var script = new ScriptBuilder(); - script.EmitDynamicCall(NativeContract.NameService.Hash, "setPrice", false, new ContractParameter[] { new ContractParameter(ContractParameterType.Integer) { Value = price } }); + script.EmitDynamicCall(NativeContract.NameService.Hash, "setPrice", new ContractParameter[] { new ContractParameter(ContractParameterType.Integer) { Value = price } }); engine.LoadScript(script.ToArray(), 0, -1, 0); if (engine.Execute() == VMState.FAULT) @@ -270,7 +270,7 @@ internal static bool Check_AddRoot(StoreView snapshot, UInt160 signedBy, string { var engine = ApplicationEngine.Create(TriggerType.Application, new Nep17NativeContractExtensions.ManualWitness(signedBy), snapshot, persistingBlock); var script = new ScriptBuilder(); - script.EmitDynamicCall(NativeContract.NameService.Hash, "addRoot", false, new ContractParameter[] { new ContractParameter(ContractParameterType.String) { Value = root } }); + script.EmitDynamicCall(NativeContract.NameService.Hash, "addRoot", new ContractParameter[] { new ContractParameter(ContractParameterType.String) { Value = root } }); engine.LoadScript(script.ToArray(), 0, -1, 0); if (engine.Execute() == VMState.FAULT) From 8bc29430cbb142abb0f05269e9b33461cdc25bae Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Sun, 10 Jan 2021 19:20:47 +0800 Subject: [PATCH 3/4] Change the parameters order --- src/neo/SmartContract/ApplicationEngine.Contract.cs | 2 +- src/neo/VM/Helper.cs | 6 +++--- tests/neo.UnitTests/SmartContract/UT_InteropService.cs | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/neo/SmartContract/ApplicationEngine.Contract.cs b/src/neo/SmartContract/ApplicationEngine.Contract.cs index 6101c0bad0..f40ada522c 100644 --- a/src/neo/SmartContract/ApplicationEngine.Contract.cs +++ b/src/neo/SmartContract/ApplicationEngine.Contract.cs @@ -22,7 +22,7 @@ partial class ApplicationEngine public static readonly InteropDescriptor System_Contract_NativeOnPersist = Register("System.Contract.NativeOnPersist", nameof(NativeOnPersist), 0, CallFlags.WriteStates); public static readonly InteropDescriptor System_Contract_NativePostPersist = Register("System.Contract.NativePostPersist", nameof(NativePostPersist), 0, CallFlags.WriteStates); - protected internal void CallContract(UInt160 contractHash, string method, Array args, CallFlags callFlags) + protected internal void CallContract(UInt160 contractHash, string method, CallFlags callFlags, Array args) { if (method.StartsWith('_')) throw new ArgumentException($"Invalid Method Name: {method}"); if ((callFlags & ~CallFlags.All) != 0) diff --git a/src/neo/VM/Helper.cs b/src/neo/VM/Helper.cs index f7f6d02e67..4eed45e1d2 100644 --- a/src/neo/VM/Helper.cs +++ b/src/neo/VM/Helper.cs @@ -48,8 +48,8 @@ public static ScriptBuilder Emit(this ScriptBuilder sb, params OpCode[] ops) public static ScriptBuilder EmitDynamicCall(this ScriptBuilder sb, UInt160 scriptHash, string operation) { - sb.EmitPush(CallFlags.All); sb.Emit(OpCode.NEWARRAY0); + sb.EmitPush(CallFlags.All); sb.EmitPush(operation); sb.EmitPush(scriptHash); sb.EmitSysCall(ApplicationEngine.System_Contract_Call); @@ -58,11 +58,11 @@ public static ScriptBuilder EmitDynamicCall(this ScriptBuilder sb, UInt160 scrip public static ScriptBuilder EmitDynamicCall(this ScriptBuilder sb, UInt160 scriptHash, string operation, params ContractParameter[] args) { - sb.EmitPush(CallFlags.All); for (int i = args.Length - 1; i >= 0; i--) sb.EmitPush(args[i]); sb.EmitPush(args.Length); sb.Emit(OpCode.PACK); + sb.EmitPush(CallFlags.All); sb.EmitPush(operation); sb.EmitPush(scriptHash); sb.EmitSysCall(ApplicationEngine.System_Contract_Call); @@ -71,11 +71,11 @@ public static ScriptBuilder EmitDynamicCall(this ScriptBuilder sb, UInt160 scrip public static ScriptBuilder EmitDynamicCall(this ScriptBuilder sb, UInt160 scriptHash, string operation, params object[] args) { - sb.EmitPush(CallFlags.All); for (int i = args.Length - 1; i >= 0; i--) sb.EmitPush(args[i]); sb.EmitPush(args.Length); sb.Emit(OpCode.PACK); + sb.EmitPush(CallFlags.All); sb.EmitPush(operation); sb.EmitPush(scriptHash); sb.EmitSysCall(ApplicationEngine.System_Contract_Call); diff --git a/tests/neo.UnitTests/SmartContract/UT_InteropService.cs b/tests/neo.UnitTests/SmartContract/UT_InteropService.cs index 7c5dc594fc..d5e70f1a23 100644 --- a/tests/neo.UnitTests/SmartContract/UT_InteropService.cs +++ b/tests/neo.UnitTests/SmartContract/UT_InteropService.cs @@ -596,17 +596,17 @@ public void TestContract_Call() var engine = ApplicationEngine.Create(TriggerType.Application, null, snapshot); engine.LoadScript(new byte[] { 0x01 }); - engine.CallContract(state.Hash, method, args, CallFlags.All); + engine.CallContract(state.Hash, method, CallFlags.All, args); engine.CurrentContext.EvaluationStack.Pop().Should().Be(args[0]); engine.CurrentContext.EvaluationStack.Pop().Should().Be(args[1]); state.Manifest.Permissions[0].Methods = WildcardContainer.Create("a"); - Assert.ThrowsException(() => engine.CallContract(state.Hash, method, args, CallFlags.All)); + Assert.ThrowsException(() => engine.CallContract(state.Hash, method, CallFlags.All, args)); state.Manifest.Permissions[0].Methods = WildcardContainer.CreateWildcard(); - engine.CallContract(state.Hash, method, args, CallFlags.All); + engine.CallContract(state.Hash, method, CallFlags.All, args); - Assert.ThrowsException(() => engine.CallContract(UInt160.Zero, method, args, CallFlags.All)); + Assert.ThrowsException(() => engine.CallContract(UInt160.Zero, method, CallFlags.All, args)); } [TestMethod] From 486bc16d87899b5afa3411b29c6b1f4616d2b5c0 Mon Sep 17 00:00:00 2001 From: Erik Zhang Date: Sun, 10 Jan 2021 19:23:04 +0800 Subject: [PATCH 4/4] Fix UT --- tests/neo.UnitTests/VM/UT_Helper.cs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/tests/neo.UnitTests/VM/UT_Helper.cs b/tests/neo.UnitTests/VM/UT_Helper.cs index 429d2c10a0..896fa6f67d 100644 --- a/tests/neo.UnitTests/VM/UT_Helper.cs +++ b/tests/neo.UnitTests/VM/UT_Helper.cs @@ -53,8 +53,8 @@ public void TestEmitAppCall1() ScriptBuilder sb = new ScriptBuilder(); sb.EmitDynamicCall(UInt160.Zero, "AAAAA"); byte[] tempArray = new byte[36]; - tempArray[0] = (byte)OpCode.PUSH15;//(byte)CallFlags.All; - tempArray[1] = (byte)OpCode.NEWARRAY0; + tempArray[0] = (byte)OpCode.NEWARRAY0; + tempArray[1] = (byte)OpCode.PUSH15;//(byte)CallFlags.All; tempArray[2] = (byte)OpCode.PUSHDATA1; tempArray[3] = 5;//operation.Length Array.Copy(Encoding.UTF8.GetBytes("AAAAA"), 0, tempArray, 4, 5);//operation.data @@ -115,10 +115,10 @@ public void TestEmitAppCall2() ScriptBuilder sb = new ScriptBuilder(); sb.EmitDynamicCall(UInt160.Zero, "AAAAA", new ContractParameter[] { new ContractParameter(ContractParameterType.Integer) }); byte[] tempArray = new byte[38]; - tempArray[0] = (byte)OpCode.PUSH15;//(byte)CallFlags.All; - tempArray[1] = (byte)OpCode.PUSH0; - tempArray[2] = (byte)OpCode.PUSH1; - tempArray[3] = (byte)OpCode.PACK; + tempArray[0] = (byte)OpCode.PUSH0; + tempArray[1] = (byte)OpCode.PUSH1; + tempArray[2] = (byte)OpCode.PACK; + tempArray[3] = (byte)OpCode.PUSH15;//(byte)CallFlags.All; tempArray[4] = (byte)OpCode.PUSHDATA1; tempArray[5] = 0x05;//operation.Length Array.Copy(Encoding.UTF8.GetBytes("AAAAA"), 0, tempArray, 6, 5);//operation.data @@ -137,10 +137,10 @@ public void TestEmitAppCall3() ScriptBuilder sb = new ScriptBuilder(); sb.EmitDynamicCall(UInt160.Zero, "AAAAA", true); byte[] tempArray = new byte[38]; - tempArray[0] = (byte)OpCode.PUSH15;//(byte)CallFlags.All; - tempArray[1] = (byte)OpCode.PUSH1; - tempArray[2] = (byte)OpCode.PUSH1;//arg.Length - tempArray[3] = (byte)OpCode.PACK; + tempArray[0] = (byte)OpCode.PUSH1; + tempArray[1] = (byte)OpCode.PUSH1;//arg.Length + tempArray[2] = (byte)OpCode.PACK; + tempArray[3] = (byte)OpCode.PUSH15;//(byte)CallFlags.All; tempArray[4] = (byte)OpCode.PUSHDATA1; tempArray[5] = 0x05;//operation.Length Array.Copy(Encoding.UTF8.GetBytes("AAAAA"), 0, tempArray, 6, 5);//operation.data @@ -158,7 +158,7 @@ public void TestMakeScript() { byte[] testScript = NativeContract.GAS.Hash.MakeScript("balanceOf", UInt160.Zero); - Assert.AreEqual("1f0c14000000000000000000000000000000000000000011c00c0962616c616e63654f660c141717ddafdd757eec365865b963473beb617f9a1441627d5b52", + Assert.AreEqual("0c14000000000000000000000000000000000000000011c01f0c0962616c616e63654f660c141717ddafdd757eec365865b963473beb617f9a1441627d5b52", testScript.ToHexString()); }