From 0ce0b58ca6bbc884223420f331fd6356c445bf17 Mon Sep 17 00:00:00 2001 From: Shargon Date: Tue, 28 Jul 2020 10:20:35 +0200 Subject: [PATCH 01/33] Allow sc verify --- .../ContractParametersContext.cs | 12 ++++----- src/neo/Wallets/Wallet.cs | 25 +++++++++++++++++++ 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/src/neo/SmartContract/ContractParametersContext.cs b/src/neo/SmartContract/ContractParametersContext.cs index c494fcf994..02f291e29e 100644 --- a/src/neo/SmartContract/ContractParametersContext.cs +++ b/src/neo/SmartContract/ContractParametersContext.cs @@ -9,7 +9,6 @@ using System.IO; using System.Linq; using System.Reflection; -using System.Text; namespace Neo.SmartContract { @@ -109,17 +108,17 @@ public ContractParametersContext(IVerifiable verifiable) this.ContextItems = new Dictionary(); } - public bool Add(Contract contract, int index, object parameter) + public bool Add(Contract contract, int index, object parameter, bool copyScript = true) { - ContextItem item = CreateItem(contract); + ContextItem item = CreateItem(contract, copyScript); if (item == null) return false; item.Parameters[index].Value = parameter; return true; } - public bool Add(Contract contract, params object[] parameters) + public bool Add(Contract contract, bool copyScript = true, params object[] parameters) { - ContextItem item = CreateItem(contract); + ContextItem item = CreateItem(contract, copyScript); if (item == null) return false; for (int index = 0; index < parameters.Length; index++) { @@ -180,7 +179,7 @@ public bool AddSignature(Contract contract, ECPoint pubkey, byte[] signature) } } - private ContextItem CreateItem(Contract contract) + private ContextItem CreateItem(Contract contract, bool copyScript = true) { if (ContextItems.TryGetValue(contract.ScriptHash, out ContextItem item)) return item; @@ -188,6 +187,7 @@ private ContextItem CreateItem(Contract contract) return null; item = new ContextItem(contract); ContextItems.Add(contract.ScriptHash, item); + if (!copyScript) item.Script = null; return item; } diff --git a/src/neo/Wallets/Wallet.cs b/src/neo/Wallets/Wallet.cs index d77532abb9..694168d0c5 100644 --- a/src/neo/Wallets/Wallet.cs +++ b/src/neo/Wallets/Wallet.cs @@ -435,8 +435,33 @@ public bool Sign(ContractParametersContext context) byte[] signature = context.Verifiable.Sign(key); fSuccess |= context.AddSignature(account.Contract, key.PublicKey, signature); } + else + { + // Smart contract verification + + using var snapshot = Blockchain.Singleton.GetSnapshot(); + var contract = snapshot.Contracts.TryGet(account.ScriptHash); + + if (contract != null) + { + // Only works with verify without parameters + + var verify = contract.Manifest.Abi.GetMethod("verify"); + + if (verify != null && verify.Parameters.Length == 0) + { + fSuccess |= context.Add(new Contract() + { + Script = contract.Script, + ParameterList = verify.Parameters.Select(u => u.Type).ToArray() + }, + false, new object[0]); + } + } + } } } + return fSuccess; } From 83e28508772a39e4e8592ef0d305b7104b181e80 Mon Sep 17 00:00:00 2001 From: Shargon Date: Wed, 29 Jul 2020 09:18:51 +0200 Subject: [PATCH 02/33] Create DeployedContract --- .../ContractParametersContext.cs | 11 ++++---- src/neo/SmartContract/DeployedContract.cs | 25 +++++++++++++++++++ src/neo/Wallets/Wallet.cs | 13 +++------- 3 files changed, 34 insertions(+), 15 deletions(-) create mode 100644 src/neo/SmartContract/DeployedContract.cs diff --git a/src/neo/SmartContract/ContractParametersContext.cs b/src/neo/SmartContract/ContractParametersContext.cs index 02f291e29e..0b2a3a5447 100644 --- a/src/neo/SmartContract/ContractParametersContext.cs +++ b/src/neo/SmartContract/ContractParametersContext.cs @@ -108,17 +108,17 @@ public ContractParametersContext(IVerifiable verifiable) this.ContextItems = new Dictionary(); } - public bool Add(Contract contract, int index, object parameter, bool copyScript = true) + public bool Add(Contract contract, int index, object parameter) { - ContextItem item = CreateItem(contract, copyScript); + ContextItem item = CreateItem(contract); if (item == null) return false; item.Parameters[index].Value = parameter; return true; } - public bool Add(Contract contract, bool copyScript = true, params object[] parameters) + public bool Add(Contract contract, params object[] parameters) { - ContextItem item = CreateItem(contract, copyScript); + ContextItem item = CreateItem(contract); if (item == null) return false; for (int index = 0; index < parameters.Length; index++) { @@ -179,7 +179,7 @@ public bool AddSignature(Contract contract, ECPoint pubkey, byte[] signature) } } - private ContextItem CreateItem(Contract contract, bool copyScript = true) + private ContextItem CreateItem(Contract contract) { if (ContextItems.TryGetValue(contract.ScriptHash, out ContextItem item)) return item; @@ -187,7 +187,6 @@ private ContextItem CreateItem(Contract contract, bool copyScript = true) return null; item = new ContextItem(contract); ContextItems.Add(contract.ScriptHash, item); - if (!copyScript) item.Script = null; return item; } diff --git a/src/neo/SmartContract/DeployedContract.cs b/src/neo/SmartContract/DeployedContract.cs new file mode 100644 index 0000000000..0325fdf1e8 --- /dev/null +++ b/src/neo/SmartContract/DeployedContract.cs @@ -0,0 +1,25 @@ +using Neo.Ledger; +using Neo.SmartContract.Manifest; +using System; +using System.Linq; + +namespace Neo.SmartContract +{ + public class DeployedContract : Contract + { + private readonly UInt160 _scriptHash; + public readonly ContractMethodDescriptor Verify; + + public override UInt160 ScriptHash => _scriptHash; + + public DeployedContract(ContractState contract) + { + if (contract == null) throw new ArgumentNullException(nameof(contract)); + + Script = null; + _scriptHash = contract.ScriptHash; + Verify = contract.Manifest.Abi.GetMethod("verify"); + ParameterList = Verify.Parameters.Select(u => u.Type).ToArray(); + } + } +} diff --git a/src/neo/Wallets/Wallet.cs b/src/neo/Wallets/Wallet.cs index 694168d0c5..a0b69b6bff 100644 --- a/src/neo/Wallets/Wallet.cs +++ b/src/neo/Wallets/Wallet.cs @@ -444,18 +444,13 @@ public bool Sign(ContractParametersContext context) if (contract != null) { - // Only works with verify without parameters + var deployed = new DeployedContract(contract); - var verify = contract.Manifest.Abi.GetMethod("verify"); + // Only works with verify without parameters - if (verify != null && verify.Parameters.Length == 0) + if (deployed.Verify != null && deployed.ParameterList.Length == 0) { - fSuccess |= context.Add(new Contract() - { - Script = contract.Script, - ParameterList = verify.Parameters.Select(u => u.Type).ToArray() - }, - false, new object[0]); + fSuccess |= context.Add(new DeployedContract(contract), new object[0]); } } } From 466895594ea0bd329f107441d8f06fc217b90fdb Mon Sep 17 00:00:00 2001 From: Shargon Date: Wed, 29 Jul 2020 11:13:11 +0200 Subject: [PATCH 03/33] Fix fee --- src/neo/Wallets/Wallet.cs | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/src/neo/Wallets/Wallet.cs b/src/neo/Wallets/Wallet.cs index a0b69b6bff..f333bc5eff 100644 --- a/src/neo/Wallets/Wallet.cs +++ b/src/neo/Wallets/Wallet.cs @@ -4,6 +4,7 @@ using Neo.Network.P2P.Payloads; using Neo.Persistence; using Neo.SmartContract; +using Neo.SmartContract.Manifest; using Neo.SmartContract.Native; using Neo.VM; using System; @@ -361,7 +362,15 @@ private Transaction MakeTransaction(StoreView snapshot, byte[] script, Signer[] foreach (UInt160 hash in hashes) { byte[] witness_script = GetAccount(hash)?.Contract?.Script ?? snapshot.Contracts.TryGet(hash)?.Script; - if (witness_script is null) continue; + if (witness_script is null) + { + var contract = snapshot.Contracts.TryGet(hash); + if (contract != null) + { + tx.NetworkFee += CalculateNetworkFee(snapshot, tx, contract, ref size); + } + continue; + } tx.NetworkFee += CalculateNetworkFee(witness_script, ref size); } tx.NetworkFee += size * NativeContract.Policy.GetFeePerByte(snapshot); @@ -370,6 +379,28 @@ private Transaction MakeTransaction(StoreView snapshot, byte[] script, Signer[] throw new InvalidOperationException("Insufficient GAS"); } + public static long CalculateNetworkFee(StoreView snapshot, Transaction tx, ContractState contract, ref int size) + { + long networkFee = 0; + + // Empty invocation and verification scripts + size += Array.Empty().GetVarSize() * 2; + + // Check verify cost + ContractMethodDescriptor md = contract.Manifest.Abi.GetMethod("verify"); + if (md is null) return 0; + + using (ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Verification, tx, snapshot.Clone(), 0, testMode: true)) + { + engine.LoadScript(contract.Script, CallFlags.None).InstructionPointer = md.Offset; + engine.LoadScript(Array.Empty(), CallFlags.None); + if (engine.Execute() == VMState.FAULT) return 0; + if (engine.ResultStack.Count != 1 || !engine.ResultStack.Pop().GetBoolean()) return 0; + } + + return networkFee; + } + public static long CalculateNetworkFee(byte[] witness_script, ref int size) { long networkFee = 0; From 21536a435e31aee9bd4a657328aa78b4586a5b40 Mon Sep 17 00:00:00 2001 From: Shargon Date: Wed, 29 Jul 2020 11:15:03 +0200 Subject: [PATCH 04/33] Fix --- src/neo/Wallets/Wallet.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/neo/Wallets/Wallet.cs b/src/neo/Wallets/Wallet.cs index f333bc5eff..6cf8c4c74f 100644 --- a/src/neo/Wallets/Wallet.cs +++ b/src/neo/Wallets/Wallet.cs @@ -361,7 +361,7 @@ private Transaction MakeTransaction(StoreView snapshot, byte[] script, Signer[] foreach (UInt160 hash in hashes) { - byte[] witness_script = GetAccount(hash)?.Contract?.Script ?? snapshot.Contracts.TryGet(hash)?.Script; + byte[] witness_script = GetAccount(hash)?.Contract?.Script ?? null; if (witness_script is null) { var contract = snapshot.Contracts.TryGet(hash); @@ -381,8 +381,6 @@ private Transaction MakeTransaction(StoreView snapshot, byte[] script, Signer[] public static long CalculateNetworkFee(StoreView snapshot, Transaction tx, ContractState contract, ref int size) { - long networkFee = 0; - // Empty invocation and verification scripts size += Array.Empty().GetVarSize() * 2; @@ -396,9 +394,9 @@ public static long CalculateNetworkFee(StoreView snapshot, Transaction tx, Contr engine.LoadScript(Array.Empty(), CallFlags.None); if (engine.Execute() == VMState.FAULT) return 0; if (engine.ResultStack.Count != 1 || !engine.ResultStack.Pop().GetBoolean()) return 0; - } - return networkFee; + return engine.GasConsumed; + } } public static long CalculateNetworkFee(byte[] witness_script, ref int size) From 26905d4d0d118b3e2cc45333b8e5a52b8763f90e Mon Sep 17 00:00:00 2001 From: Shargon Date: Wed, 29 Jul 2020 11:18:28 +0200 Subject: [PATCH 05/33] Change to exceptions --- src/neo/Wallets/Wallet.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/neo/Wallets/Wallet.cs b/src/neo/Wallets/Wallet.cs index 6cf8c4c74f..a88fa53ed8 100644 --- a/src/neo/Wallets/Wallet.cs +++ b/src/neo/Wallets/Wallet.cs @@ -386,14 +386,14 @@ public static long CalculateNetworkFee(StoreView snapshot, Transaction tx, Contr // Check verify cost ContractMethodDescriptor md = contract.Manifest.Abi.GetMethod("verify"); - if (md is null) return 0; + if (md is null) throw new ArgumentException($"The smart contract {contract.ScriptHash} haven't got verify method"); using (ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Verification, tx, snapshot.Clone(), 0, testMode: true)) { engine.LoadScript(contract.Script, CallFlags.None).InstructionPointer = md.Offset; engine.LoadScript(Array.Empty(), CallFlags.None); - if (engine.Execute() == VMState.FAULT) return 0; - if (engine.ResultStack.Count != 1 || !engine.ResultStack.Pop().GetBoolean()) return 0; + if (engine.Execute() == VMState.FAULT) throw new ArgumentException($"Smart contract {contract.ScriptHash} verification fault."); + if (engine.ResultStack.Count != 1 || !engine.ResultStack.Pop().GetBoolean()) throw new ArgumentException($"Smart contract {contract.ScriptHash} returns false."); return engine.GasConsumed; } From 4ce99fbf3f84eda7dafdf0b125d61d39384f93af Mon Sep 17 00:00:00 2001 From: Shargon Date: Wed, 29 Jul 2020 13:05:56 +0200 Subject: [PATCH 06/33] Allow static variables during verification --- src/neo/SmartContract/Helper.cs | 3 +++ src/neo/Wallets/Wallet.cs | 9 +++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/neo/SmartContract/Helper.cs b/src/neo/SmartContract/Helper.cs index 4448ff83b6..e89b34d158 100644 --- a/src/neo/SmartContract/Helper.cs +++ b/src/neo/SmartContract/Helper.cs @@ -147,6 +147,7 @@ internal static bool VerifyWitnesses(this IVerifiable verifiable, StoreView snap for (int i = 0; i < hashes.Length; i++) { int offset; + ContractMethodDescriptor init = null; byte[] verification = verifiable.Witnesses[i].VerificationScript; if (verification.Length == 0) { @@ -156,6 +157,7 @@ internal static bool VerifyWitnesses(this IVerifiable verifiable, StoreView snap if (md is null) return false; verification = cs.Script; offset = md.Offset; + init = cs.Manifest.Abi.GetMethod("_initialize"); } else { @@ -165,6 +167,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.None).InstructionPointer = offset; + if (init != null) engine.LoadClonedContext(init.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; diff --git a/src/neo/Wallets/Wallet.cs b/src/neo/Wallets/Wallet.cs index a88fa53ed8..18dec2aa1e 100644 --- a/src/neo/Wallets/Wallet.cs +++ b/src/neo/Wallets/Wallet.cs @@ -385,12 +385,13 @@ public static long CalculateNetworkFee(StoreView snapshot, Transaction tx, Contr size += Array.Empty().GetVarSize() * 2; // Check verify cost - ContractMethodDescriptor md = contract.Manifest.Abi.GetMethod("verify"); - if (md is null) throw new ArgumentException($"The smart contract {contract.ScriptHash} haven't got verify method"); - + ContractMethodDescriptor verify = contract.Manifest.Abi.GetMethod("verify"); + if (verify is null) throw new ArgumentException($"The smart contract {contract.ScriptHash} haven't got verify method"); + ContractMethodDescriptor init = contract.Manifest.Abi.GetMethod("_initialize"); using (ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Verification, tx, snapshot.Clone(), 0, testMode: true)) { - engine.LoadScript(contract.Script, CallFlags.None).InstructionPointer = md.Offset; + engine.LoadScript(contract.Script, CallFlags.None).InstructionPointer = verify.Offset; + if (init != null) engine.LoadClonedContext(init.Offset); engine.LoadScript(Array.Empty(), CallFlags.None); if (engine.Execute() == VMState.FAULT) throw new ArgumentException($"Smart contract {contract.ScriptHash} verification fault."); if (engine.ResultStack.Count != 1 || !engine.ResultStack.Pop().GetBoolean()) throw new ArgumentException($"Smart contract {contract.ScriptHash} returns false."); From 37f6670f959feb71e98a0bdb570c8c77471b93dc Mon Sep 17 00:00:00 2001 From: erikzhang Date: Wed, 29 Jul 2020 21:08:45 +0800 Subject: [PATCH 07/33] Simplify DeployedContract --- src/neo/SmartContract/DeployedContract.cs | 11 ++++------- src/neo/Wallets/Wallet.cs | 2 +- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/neo/SmartContract/DeployedContract.cs b/src/neo/SmartContract/DeployedContract.cs index 0325fdf1e8..1dbf237d1b 100644 --- a/src/neo/SmartContract/DeployedContract.cs +++ b/src/neo/SmartContract/DeployedContract.cs @@ -7,19 +7,16 @@ namespace Neo.SmartContract { public class DeployedContract : Contract { - private readonly UInt160 _scriptHash; - public readonly ContractMethodDescriptor Verify; - - public override UInt160 ScriptHash => _scriptHash; + public override UInt160 ScriptHash { get; } public DeployedContract(ContractState contract) { if (contract == null) throw new ArgumentNullException(nameof(contract)); Script = null; - _scriptHash = contract.ScriptHash; - Verify = contract.Manifest.Abi.GetMethod("verify"); - ParameterList = Verify.Parameters.Select(u => u.Type).ToArray(); + ScriptHash = contract.ScriptHash; + ContractMethodDescriptor descriptor = contract.Manifest.Abi.GetMethod("verify"); + ParameterList = descriptor.Parameters.Select(u => u.Type).ToArray(); } } } diff --git a/src/neo/Wallets/Wallet.cs b/src/neo/Wallets/Wallet.cs index 18dec2aa1e..6c88ee41dc 100644 --- a/src/neo/Wallets/Wallet.cs +++ b/src/neo/Wallets/Wallet.cs @@ -478,7 +478,7 @@ public bool Sign(ContractParametersContext context) // Only works with verify without parameters - if (deployed.Verify != null && deployed.ParameterList.Length == 0) + if (deployed.ParameterList.Length == 0) { fSuccess |= context.Add(new DeployedContract(contract), new object[0]); } From 898f1c61cfd3f9bfae401095703eaa9f204d0465 Mon Sep 17 00:00:00 2001 From: Shargon Date: Wed, 29 Jul 2020 18:32:34 +0200 Subject: [PATCH 08/33] Change verify call flags --- src/neo/SmartContract/Helper.cs | 2 +- src/neo/Wallets/Wallet.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/neo/SmartContract/Helper.cs b/src/neo/SmartContract/Helper.cs index e89b34d158..3615bdad37 100644 --- a/src/neo/SmartContract/Helper.cs +++ b/src/neo/SmartContract/Helper.cs @@ -166,7 +166,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.None).InstructionPointer = offset; + engine.LoadScript(verification, CallFlags.All).InstructionPointer = offset; if (init != null) engine.LoadClonedContext(init.Offset); engine.LoadScript(verifiable.Witnesses[i].InvocationScript, CallFlags.None); if (engine.Execute() == VMState.FAULT) return false; diff --git a/src/neo/Wallets/Wallet.cs b/src/neo/Wallets/Wallet.cs index 18dec2aa1e..af19e962f9 100644 --- a/src/neo/Wallets/Wallet.cs +++ b/src/neo/Wallets/Wallet.cs @@ -390,7 +390,7 @@ public static long CalculateNetworkFee(StoreView snapshot, Transaction tx, Contr ContractMethodDescriptor init = contract.Manifest.Abi.GetMethod("_initialize"); using (ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Verification, tx, snapshot.Clone(), 0, testMode: true)) { - engine.LoadScript(contract.Script, CallFlags.None).InstructionPointer = verify.Offset; + engine.LoadScript(contract.Script, CallFlags.All).InstructionPointer = verify.Offset; if (init != null) engine.LoadClonedContext(init.Offset); engine.LoadScript(Array.Empty(), CallFlags.None); if (engine.Execute() == VMState.FAULT) throw new ArgumentException($"Smart contract {contract.ScriptHash} verification fault."); From d541f8046628fa3c7b7f71a6c555ceb16d22443f Mon Sep 17 00:00:00 2001 From: Shargon Date: Wed, 29 Jul 2020 18:37:37 +0200 Subject: [PATCH 09/33] Change to ReadOnly --- src/neo/SmartContract/Helper.cs | 2 +- src/neo/Wallets/Wallet.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/neo/SmartContract/Helper.cs b/src/neo/SmartContract/Helper.cs index 3615bdad37..89f646eaeb 100644 --- a/src/neo/SmartContract/Helper.cs +++ b/src/neo/SmartContract/Helper.cs @@ -166,7 +166,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.All).InstructionPointer = offset; + engine.LoadScript(verification, CallFlags.ReadOnly).InstructionPointer = offset; if (init != null) engine.LoadClonedContext(init.Offset); engine.LoadScript(verifiable.Witnesses[i].InvocationScript, CallFlags.None); if (engine.Execute() == VMState.FAULT) return false; diff --git a/src/neo/Wallets/Wallet.cs b/src/neo/Wallets/Wallet.cs index af19e962f9..67fcad8e57 100644 --- a/src/neo/Wallets/Wallet.cs +++ b/src/neo/Wallets/Wallet.cs @@ -390,7 +390,7 @@ public static long CalculateNetworkFee(StoreView snapshot, Transaction tx, Contr ContractMethodDescriptor init = contract.Manifest.Abi.GetMethod("_initialize"); using (ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Verification, tx, snapshot.Clone(), 0, testMode: true)) { - engine.LoadScript(contract.Script, CallFlags.All).InstructionPointer = verify.Offset; + engine.LoadScript(contract.Script, CallFlags.ReadOnly).InstructionPointer = verify.Offset; if (init != null) engine.LoadClonedContext(init.Offset); engine.LoadScript(Array.Empty(), CallFlags.None); if (engine.Execute() == VMState.FAULT) throw new ArgumentException($"Smart contract {contract.ScriptHash} verification fault."); From 467c47bb35fa2b2f49d67aaf051298bcb3d3036e Mon Sep 17 00:00:00 2001 From: Shargon Date: Wed, 29 Jul 2020 18:46:43 +0200 Subject: [PATCH 10/33] Add error description --- src/neo/SmartContract/DeployedContract.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/neo/SmartContract/DeployedContract.cs b/src/neo/SmartContract/DeployedContract.cs index 1dbf237d1b..187ce552e8 100644 --- a/src/neo/SmartContract/DeployedContract.cs +++ b/src/neo/SmartContract/DeployedContract.cs @@ -16,6 +16,8 @@ public DeployedContract(ContractState contract) Script = null; ScriptHash = contract.ScriptHash; ContractMethodDescriptor descriptor = contract.Manifest.Abi.GetMethod("verify"); + if (descriptor == null) throw new ArgumentNullException("The smart contract haven't got verify method."); + ParameterList = descriptor.Parameters.Select(u => u.Type).ToArray(); } } From 51b8352db3066251857df9790ddeb339ccf6066f Mon Sep 17 00:00:00 2001 From: Shargon Date: Thu, 30 Jul 2020 09:47:55 +0200 Subject: [PATCH 11/33] Allow cosigners in makeTransaction --- src/neo/Wallets/Wallet.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/neo/Wallets/Wallet.cs b/src/neo/Wallets/Wallet.cs index 96bbb5ffa5..75d06e1e17 100644 --- a/src/neo/Wallets/Wallet.cs +++ b/src/neo/Wallets/Wallet.cs @@ -241,7 +241,7 @@ public virtual WalletAccount Import(string nep2, string passphrase, int N = 1638 return account; } - public Transaction MakeTransaction(TransferOutput[] outputs, UInt160 from = null) + public Transaction MakeTransaction(TransferOutput[] outputs, UInt160 from = null, Signer[] cosigners = null) { UInt160[] accounts; if (from is null) @@ -251,7 +251,7 @@ public Transaction MakeTransaction(TransferOutput[] outputs, UInt160 from = null else { if (!Contains(from)) - throw new ArgumentException($"The address {from.ToString()} was not found in the wallet"); + throw new ArgumentException($"The address {from} was not found in the wallet"); accounts = new[] { from }; } using (SnapshotView snapshot = Blockchain.Singleton.GetSnapshot()) @@ -298,12 +298,12 @@ 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 Signer() + cosigners = cosignerList.Select(p => new Signer() { // default access for transfers should be valid only for first invocation Scopes = WitnessScope.CalledByEntry, Account = p - }).ToArray(); + }).Concat(cosigners?.Where(u => !cosignerList.Contains(u.Account)) ?? Array.Empty()).ToArray(); return MakeTransaction(snapshot, script, cosigners, Array.Empty(), balances_gas); } From d8bf588ee71293d7ec4a3a530842be66f3ec1f5e Mon Sep 17 00:00:00 2001 From: Shargon Date: Thu, 30 Jul 2020 11:06:30 +0200 Subject: [PATCH 12/33] Verify as APPCALL --- src/neo/SmartContract/DeployedContract.cs | 6 ++++-- src/neo/SmartContract/Helper.cs | 15 +++++++------- src/neo/Wallets/Wallet.cs | 24 +++++++++++++++-------- 3 files changed, 27 insertions(+), 18 deletions(-) diff --git a/src/neo/SmartContract/DeployedContract.cs b/src/neo/SmartContract/DeployedContract.cs index 187ce552e8..d64433d666 100644 --- a/src/neo/SmartContract/DeployedContract.cs +++ b/src/neo/SmartContract/DeployedContract.cs @@ -1,7 +1,6 @@ using Neo.Ledger; using Neo.SmartContract.Manifest; using System; -using System.Linq; namespace Neo.SmartContract { @@ -9,6 +8,8 @@ public class DeployedContract : Contract { public override UInt160 ScriptHash { get; } + public ContractParameterDefinition[] VerifyArguments { get; } + public DeployedContract(ContractState contract) { if (contract == null) throw new ArgumentNullException(nameof(contract)); @@ -18,7 +19,8 @@ public DeployedContract(ContractState contract) ContractMethodDescriptor descriptor = contract.Manifest.Abi.GetMethod("verify"); if (descriptor == null) throw new ArgumentNullException("The smart contract haven't got verify method."); - ParameterList = descriptor.Parameters.Select(u => u.Type).ToArray(); + VerifyArguments = descriptor.Parameters; + ParameterList = new ContractParameterType[] { ContractParameterType.Array }; } } } diff --git a/src/neo/SmartContract/Helper.cs b/src/neo/SmartContract/Helper.cs index 89f646eaeb..c4ecdaf4d4 100644 --- a/src/neo/SmartContract/Helper.cs +++ b/src/neo/SmartContract/Helper.cs @@ -146,8 +146,6 @@ internal static bool VerifyWitnesses(this IVerifiable verifiable, StoreView snap if (hashes.Length != verifiable.Witnesses.Length) return false; for (int i = 0; i < hashes.Length; i++) { - int offset; - ContractMethodDescriptor init = null; byte[] verification = verifiable.Witnesses[i].VerificationScript; if (verification.Length == 0) { @@ -155,19 +153,20 @@ internal static bool VerifyWitnesses(this IVerifiable verifiable, StoreView snap if (cs is null) return false; ContractMethodDescriptor md = cs.Manifest.Abi.GetMethod("verify"); if (md is null) return false; - verification = cs.Script; - offset = md.Offset; - init = cs.Manifest.Abi.GetMethod("_initialize"); + + using var sb = new ScriptBuilder(); + sb.EmitPush("verify"); + sb.EmitPush(cs.ScriptHash); + sb.EmitSysCall(ApplicationEngine.System_Contract_Call); + verification = sb.ToArray(); } else { if (hashes[i] != verifiable.Witnesses[i].ScriptHash) return false; - offset = 0; } using (ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Verification, verifiable, snapshot.Clone(), gas)) { - engine.LoadScript(verification, CallFlags.ReadOnly).InstructionPointer = offset; - if (init != null) engine.LoadClonedContext(init.Offset); + engine.LoadScript(verification, CallFlags.ReadOnly); 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; diff --git a/src/neo/Wallets/Wallet.cs b/src/neo/Wallets/Wallet.cs index 75d06e1e17..93f6fd6e92 100644 --- a/src/neo/Wallets/Wallet.cs +++ b/src/neo/Wallets/Wallet.cs @@ -381,18 +381,26 @@ private Transaction MakeTransaction(StoreView snapshot, byte[] script, Signer[] public static long CalculateNetworkFee(StoreView snapshot, Transaction tx, ContractState contract, ref int size) { - // Empty invocation and verification scripts - size += Array.Empty().GetVarSize() * 2; + // Empty verification scripts and PACK 0 as invocation + size += Array.Empty().GetVarSize() + IO.Helper.GetVarSize(2); // Check verify cost ContractMethodDescriptor verify = contract.Manifest.Abi.GetMethod("verify"); if (verify is null) throw new ArgumentException($"The smart contract {contract.ScriptHash} haven't got verify method"); - ContractMethodDescriptor init = contract.Manifest.Abi.GetMethod("_initialize"); + + using var invocation = new ScriptBuilder(); + invocation.EmitPush(0); + invocation.Emit(OpCode.PACK); + + using var verification = new ScriptBuilder(); + verification.EmitPush("verify"); + verification.EmitPush(contract.ScriptHash); + verification.EmitSysCall(ApplicationEngine.System_Contract_Call); + using (ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Verification, tx, snapshot.Clone(), 0, testMode: true)) { - engine.LoadScript(contract.Script, CallFlags.ReadOnly).InstructionPointer = verify.Offset; - if (init != null) engine.LoadClonedContext(init.Offset); - engine.LoadScript(Array.Empty(), CallFlags.None); + engine.LoadScript(verification.ToArray(), CallFlags.ReadOnly); + engine.LoadScript(invocation.ToArray(), CallFlags.None); if (engine.Execute() == VMState.FAULT) throw new ArgumentException($"Smart contract {contract.ScriptHash} verification fault."); if (engine.ResultStack.Count != 1 || !engine.ResultStack.Pop().GetBoolean()) throw new ArgumentException($"Smart contract {contract.ScriptHash} returns false."); @@ -478,9 +486,9 @@ public bool Sign(ContractParametersContext context) // Only works with verify without parameters - if (deployed.ParameterList.Length == 0) + if (deployed.VerifyArguments.Length == 0) { - fSuccess |= context.Add(new DeployedContract(contract), new object[0]); + fSuccess |= context.Add(new DeployedContract(contract), new object[] { new ContractParameter[0] { } }); } } } From e8d59a9dfbb326ced7c09f713d01af7c6f88629d Mon Sep 17 00:00:00 2001 From: Shargon Date: Thu, 30 Jul 2020 11:10:43 +0200 Subject: [PATCH 13/33] Fix fee --- src/neo/Wallets/Wallet.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/neo/Wallets/Wallet.cs b/src/neo/Wallets/Wallet.cs index 93f6fd6e92..6f685433d4 100644 --- a/src/neo/Wallets/Wallet.cs +++ b/src/neo/Wallets/Wallet.cs @@ -382,7 +382,7 @@ private Transaction MakeTransaction(StoreView snapshot, byte[] script, Signer[] public static long CalculateNetworkFee(StoreView snapshot, Transaction tx, ContractState contract, ref int size) { // Empty verification scripts and PACK 0 as invocation - size += Array.Empty().GetVarSize() + IO.Helper.GetVarSize(2); + size += Array.Empty().GetVarSize() + (IO.Helper.GetVarSize(2) + 2); // Check verify cost ContractMethodDescriptor verify = contract.Manifest.Abi.GetMethod("verify"); From 817b5520f118bfb90632f528e3683cd5df016427 Mon Sep 17 00:00:00 2001 From: Shargon Date: Thu, 30 Jul 2020 11:10:43 +0200 Subject: [PATCH 14/33] Revert "Fix fee" This reverts commit e8d59a9dfbb326ced7c09f713d01af7c6f88629d. --- src/neo/Wallets/Wallet.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/neo/Wallets/Wallet.cs b/src/neo/Wallets/Wallet.cs index 6f685433d4..93f6fd6e92 100644 --- a/src/neo/Wallets/Wallet.cs +++ b/src/neo/Wallets/Wallet.cs @@ -382,7 +382,7 @@ private Transaction MakeTransaction(StoreView snapshot, byte[] script, Signer[] public static long CalculateNetworkFee(StoreView snapshot, Transaction tx, ContractState contract, ref int size) { // Empty verification scripts and PACK 0 as invocation - size += Array.Empty().GetVarSize() + (IO.Helper.GetVarSize(2) + 2); + size += Array.Empty().GetVarSize() + IO.Helper.GetVarSize(2); // Check verify cost ContractMethodDescriptor verify = contract.Manifest.Abi.GetMethod("verify"); From 29f1ad210e457141fed0fda503c74134744ac6f6 Mon Sep 17 00:00:00 2001 From: Shargon Date: Thu, 30 Jul 2020 11:06:30 +0200 Subject: [PATCH 15/33] Revert "Verify as APPCALL" This reverts commit d8bf588ee71293d7ec4a3a530842be66f3ec1f5e. --- src/neo/SmartContract/DeployedContract.cs | 6 ++---- src/neo/SmartContract/Helper.cs | 15 +++++++------- src/neo/Wallets/Wallet.cs | 24 ++++++++--------------- 3 files changed, 18 insertions(+), 27 deletions(-) diff --git a/src/neo/SmartContract/DeployedContract.cs b/src/neo/SmartContract/DeployedContract.cs index d64433d666..187ce552e8 100644 --- a/src/neo/SmartContract/DeployedContract.cs +++ b/src/neo/SmartContract/DeployedContract.cs @@ -1,6 +1,7 @@ using Neo.Ledger; using Neo.SmartContract.Manifest; using System; +using System.Linq; namespace Neo.SmartContract { @@ -8,8 +9,6 @@ public class DeployedContract : Contract { public override UInt160 ScriptHash { get; } - public ContractParameterDefinition[] VerifyArguments { get; } - public DeployedContract(ContractState contract) { if (contract == null) throw new ArgumentNullException(nameof(contract)); @@ -19,8 +18,7 @@ public DeployedContract(ContractState contract) ContractMethodDescriptor descriptor = contract.Manifest.Abi.GetMethod("verify"); if (descriptor == null) throw new ArgumentNullException("The smart contract haven't got verify method."); - VerifyArguments = descriptor.Parameters; - ParameterList = new ContractParameterType[] { ContractParameterType.Array }; + ParameterList = descriptor.Parameters.Select(u => u.Type).ToArray(); } } } diff --git a/src/neo/SmartContract/Helper.cs b/src/neo/SmartContract/Helper.cs index c4ecdaf4d4..89f646eaeb 100644 --- a/src/neo/SmartContract/Helper.cs +++ b/src/neo/SmartContract/Helper.cs @@ -146,6 +146,8 @@ internal static bool VerifyWitnesses(this IVerifiable verifiable, StoreView snap if (hashes.Length != verifiable.Witnesses.Length) return false; for (int i = 0; i < hashes.Length; i++) { + int offset; + ContractMethodDescriptor init = null; byte[] verification = verifiable.Witnesses[i].VerificationScript; if (verification.Length == 0) { @@ -153,20 +155,19 @@ internal static bool VerifyWitnesses(this IVerifiable verifiable, StoreView snap if (cs is null) return false; ContractMethodDescriptor md = cs.Manifest.Abi.GetMethod("verify"); if (md is null) return false; - - using var sb = new ScriptBuilder(); - sb.EmitPush("verify"); - sb.EmitPush(cs.ScriptHash); - sb.EmitSysCall(ApplicationEngine.System_Contract_Call); - verification = sb.ToArray(); + verification = cs.Script; + offset = md.Offset; + init = cs.Manifest.Abi.GetMethod("_initialize"); } else { if (hashes[i] != verifiable.Witnesses[i].ScriptHash) return false; + offset = 0; } using (ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Verification, verifiable, snapshot.Clone(), gas)) { - engine.LoadScript(verification, CallFlags.ReadOnly); + engine.LoadScript(verification, CallFlags.ReadOnly).InstructionPointer = offset; + if (init != null) engine.LoadClonedContext(init.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; diff --git a/src/neo/Wallets/Wallet.cs b/src/neo/Wallets/Wallet.cs index 93f6fd6e92..75d06e1e17 100644 --- a/src/neo/Wallets/Wallet.cs +++ b/src/neo/Wallets/Wallet.cs @@ -381,26 +381,18 @@ private Transaction MakeTransaction(StoreView snapshot, byte[] script, Signer[] public static long CalculateNetworkFee(StoreView snapshot, Transaction tx, ContractState contract, ref int size) { - // Empty verification scripts and PACK 0 as invocation - size += Array.Empty().GetVarSize() + IO.Helper.GetVarSize(2); + // Empty invocation and verification scripts + size += Array.Empty().GetVarSize() * 2; // Check verify cost ContractMethodDescriptor verify = contract.Manifest.Abi.GetMethod("verify"); if (verify is null) throw new ArgumentException($"The smart contract {contract.ScriptHash} haven't got verify method"); - - using var invocation = new ScriptBuilder(); - invocation.EmitPush(0); - invocation.Emit(OpCode.PACK); - - using var verification = new ScriptBuilder(); - verification.EmitPush("verify"); - verification.EmitPush(contract.ScriptHash); - verification.EmitSysCall(ApplicationEngine.System_Contract_Call); - + ContractMethodDescriptor init = contract.Manifest.Abi.GetMethod("_initialize"); using (ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Verification, tx, snapshot.Clone(), 0, testMode: true)) { - engine.LoadScript(verification.ToArray(), CallFlags.ReadOnly); - engine.LoadScript(invocation.ToArray(), CallFlags.None); + engine.LoadScript(contract.Script, CallFlags.ReadOnly).InstructionPointer = verify.Offset; + if (init != null) engine.LoadClonedContext(init.Offset); + engine.LoadScript(Array.Empty(), CallFlags.None); if (engine.Execute() == VMState.FAULT) throw new ArgumentException($"Smart contract {contract.ScriptHash} verification fault."); if (engine.ResultStack.Count != 1 || !engine.ResultStack.Pop().GetBoolean()) throw new ArgumentException($"Smart contract {contract.ScriptHash} returns false."); @@ -486,9 +478,9 @@ public bool Sign(ContractParametersContext context) // Only works with verify without parameters - if (deployed.VerifyArguments.Length == 0) + if (deployed.ParameterList.Length == 0) { - fSuccess |= context.Add(new DeployedContract(contract), new object[] { new ContractParameter[0] { } }); + fSuccess |= context.Add(new DeployedContract(contract), new object[0]); } } } From aa83e12054e0763dae226d29c3228b1758267384 Mon Sep 17 00:00:00 2001 From: Shargon Date: Thu, 30 Jul 2020 11:20:11 +0200 Subject: [PATCH 16/33] Auto stash before revert of "Allow cosigners in makeTransaction" --- src/neo/SmartContract/ApplicationEngine.Runtime.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/neo/SmartContract/ApplicationEngine.Runtime.cs b/src/neo/SmartContract/ApplicationEngine.Runtime.cs index 9713d03893..acd47ef797 100644 --- a/src/neo/SmartContract/ApplicationEngine.Runtime.cs +++ b/src/neo/SmartContract/ApplicationEngine.Runtime.cs @@ -21,7 +21,7 @@ partial class ApplicationEngine 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_CheckWitness = Register("System.Runtime.CheckWitness", nameof(CheckWitness), 0_00030000, CallFlags.None, 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); @@ -109,7 +109,7 @@ internal bool CheckWitnessInternal(UInt160 hash) if (signer.Scopes == WitnessScope.Global) return true; if (signer.Scopes.HasFlag(WitnessScope.CalledByEntry)) { - if (CallingScriptHash == EntryScriptHash) + if (CallingScriptHash == null || CallingScriptHash == EntryScriptHash) return true; } if (signer.Scopes.HasFlag(WitnessScope.CustomContracts)) @@ -127,6 +127,10 @@ internal bool CheckWitnessInternal(UInt160 hash) return false; } + ExecutionContextState state = CurrentContext.GetState(); + if (!state.CallFlags.HasFlag(CallFlags.AllowStates)) + throw new InvalidOperationException($"Cannot call this SYSCALL with the flag {state.CallFlags}."); + // only for non-Transaction types (Block, etc) var hashes_for_verifying = ScriptContainer.GetScriptHashesForVerifying(Snapshot); From 71cc3f6bd60af68f0f0ee2a38dab0a6d894ef2dd Mon Sep 17 00:00:00 2001 From: Shargon Date: Thu, 30 Jul 2020 11:22:52 +0200 Subject: [PATCH 17/33] None --- src/neo/SmartContract/Helper.cs | 2 +- src/neo/Wallets/Wallet.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/neo/SmartContract/Helper.cs b/src/neo/SmartContract/Helper.cs index 89f646eaeb..e89b34d158 100644 --- a/src/neo/SmartContract/Helper.cs +++ b/src/neo/SmartContract/Helper.cs @@ -166,7 +166,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; if (init != null) engine.LoadClonedContext(init.Offset); engine.LoadScript(verifiable.Witnesses[i].InvocationScript, CallFlags.None); if (engine.Execute() == VMState.FAULT) return false; diff --git a/src/neo/Wallets/Wallet.cs b/src/neo/Wallets/Wallet.cs index 75d06e1e17..2128339dd2 100644 --- a/src/neo/Wallets/Wallet.cs +++ b/src/neo/Wallets/Wallet.cs @@ -390,7 +390,7 @@ public static long CalculateNetworkFee(StoreView snapshot, Transaction tx, Contr ContractMethodDescriptor init = contract.Manifest.Abi.GetMethod("_initialize"); using (ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Verification, tx, snapshot.Clone(), 0, testMode: true)) { - engine.LoadScript(contract.Script, CallFlags.ReadOnly).InstructionPointer = verify.Offset; + engine.LoadScript(contract.Script, CallFlags.None).InstructionPointer = verify.Offset; if (init != null) engine.LoadClonedContext(init.Offset); engine.LoadScript(Array.Empty(), CallFlags.None); if (engine.Execute() == VMState.FAULT) throw new ArgumentException($"Smart contract {contract.ScriptHash} verification fault."); From 6b7ce695ee3d8bdcea19aac4c9e8baecd3045f61 Mon Sep 17 00:00:00 2001 From: Shargon Date: Thu, 30 Jul 2020 11:32:09 +0200 Subject: [PATCH 18/33] Add comment --- src/neo/SmartContract/ApplicationEngine.Runtime.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/neo/SmartContract/ApplicationEngine.Runtime.cs b/src/neo/SmartContract/ApplicationEngine.Runtime.cs index acd47ef797..31922f88cc 100644 --- a/src/neo/SmartContract/ApplicationEngine.Runtime.cs +++ b/src/neo/SmartContract/ApplicationEngine.Runtime.cs @@ -127,6 +127,8 @@ internal bool CheckWitnessInternal(UInt160 hash) return false; } + // Check allow state callflag + ExecutionContextState state = CurrentContext.GetState(); if (!state.CallFlags.HasFlag(CallFlags.AllowStates)) throw new InvalidOperationException($"Cannot call this SYSCALL with the flag {state.CallFlags}."); From d2b94bcea9a04de73482cac6dc37a4ada30840f1 Mon Sep 17 00:00:00 2001 From: Shargon Date: Fri, 31 Jul 2020 09:58:41 +0200 Subject: [PATCH 19/33] Fix CustomGroups --- src/neo/SmartContract/ApplicationEngine.Runtime.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/neo/SmartContract/ApplicationEngine.Runtime.cs b/src/neo/SmartContract/ApplicationEngine.Runtime.cs index 31922f88cc..ffa551b00f 100644 --- a/src/neo/SmartContract/ApplicationEngine.Runtime.cs +++ b/src/neo/SmartContract/ApplicationEngine.Runtime.cs @@ -119,6 +119,11 @@ internal bool CheckWitnessInternal(UInt160 hash) } if (signer.Scopes.HasFlag(WitnessScope.CustomGroups)) { + // Check allow state callflag + + if (!CurrentContext.GetState().CallFlags.HasFlag(CallFlags.AllowStates)) + throw new InvalidOperationException($"Cannot call this SYSCALL without the flag AllowStates."); + var contract = Snapshot.Contracts[CallingScriptHash]; // check if current group is the required one if (contract.Manifest.Groups.Select(p => p.PubKey).Intersect(signer.AllowedGroups).Any()) @@ -129,9 +134,8 @@ internal bool CheckWitnessInternal(UInt160 hash) // Check allow state callflag - ExecutionContextState state = CurrentContext.GetState(); - if (!state.CallFlags.HasFlag(CallFlags.AllowStates)) - throw new InvalidOperationException($"Cannot call this SYSCALL with the flag {state.CallFlags}."); + if (!CurrentContext.GetState().CallFlags.HasFlag(CallFlags.AllowStates)) + throw new InvalidOperationException($"Cannot call this SYSCALL without the flag AllowStates."); // only for non-Transaction types (Block, etc) From b26bf2e3dd012de8429d253e5d17366d5afa833c Mon Sep 17 00:00:00 2001 From: Shargon Date: Fri, 31 Jul 2020 10:12:52 +0200 Subject: [PATCH 20/33] Fix UT --- tests/neo.UnitTests/SmartContract/UT_InteropService.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/neo.UnitTests/SmartContract/UT_InteropService.cs b/tests/neo.UnitTests/SmartContract/UT_InteropService.cs index 3a0062275f..c3764cc0fa 100644 --- a/tests/neo.UnitTests/SmartContract/UT_InteropService.cs +++ b/tests/neo.UnitTests/SmartContract/UT_InteropService.cs @@ -251,9 +251,13 @@ public void TestRuntime_CheckWitness() var engine = GetEngine(true); ((Transaction)engine.ScriptContainer).Signers[0].Account = Contract.CreateSignatureRedeemScript(pubkey).ToScriptHash(); + ((Transaction)engine.ScriptContainer).Signers[0].Scopes = WitnessScope.CalledByEntry; + engine.CheckWitness(pubkey.EncodePoint(true)).Should().BeTrue(); + engine.CheckWitness(((Transaction)engine.ScriptContainer).Sender.ToArray()).Should().BeTrue(); + + ((Transaction)engine.ScriptContainer).Signers = new Signer[0]; engine.CheckWitness(pubkey.EncodePoint(true)).Should().BeFalse(); - engine.CheckWitness(((Transaction)engine.ScriptContainer).Sender.ToArray()).Should().BeFalse(); Action action = () => engine.CheckWitness(new byte[0]); action.Should().Throw(); From 0f93d89e02973cdf186b9fccb6259f1af9f53478 Mon Sep 17 00:00:00 2001 From: erikzhang Date: Fri, 31 Jul 2020 17:10:40 +0800 Subject: [PATCH 21/33] Update DeployedContract.cs --- src/neo/SmartContract/DeployedContract.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/neo/SmartContract/DeployedContract.cs b/src/neo/SmartContract/DeployedContract.cs index 187ce552e8..e9b1c42d62 100644 --- a/src/neo/SmartContract/DeployedContract.cs +++ b/src/neo/SmartContract/DeployedContract.cs @@ -11,12 +11,12 @@ public class DeployedContract : Contract public DeployedContract(ContractState contract) { - if (contract == null) throw new ArgumentNullException(nameof(contract)); + if (contract is null) throw new ArgumentNullException(nameof(contract)); Script = null; ScriptHash = contract.ScriptHash; ContractMethodDescriptor descriptor = contract.Manifest.Abi.GetMethod("verify"); - if (descriptor == null) throw new ArgumentNullException("The smart contract haven't got verify method."); + if (descriptor is null) throw new NotSupportedException("The smart contract haven't got verify method."); ParameterList = descriptor.Parameters.Select(u => u.Type).ToArray(); } From 94bd4c26e7b59c5b2fe7df07fe0b383662b6f42b Mon Sep 17 00:00:00 2001 From: erikzhang Date: Fri, 31 Jul 2020 17:32:05 +0800 Subject: [PATCH 22/33] Optimize MakeTransaction() --- src/neo/Wallets/Wallet.cs | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/neo/Wallets/Wallet.cs b/src/neo/Wallets/Wallet.cs index 2128339dd2..d1f2c8f4ee 100644 --- a/src/neo/Wallets/Wallet.cs +++ b/src/neo/Wallets/Wallet.cs @@ -256,7 +256,7 @@ public Transaction MakeTransaction(TransferOutput[] outputs, UInt160 from = null } using (SnapshotView snapshot = Blockchain.Singleton.GetSnapshot()) { - HashSet cosignerList = new HashSet(); + Dictionary cosignerList = cosigners.ToDictionary(p => p.Account) ?? new Dictionary(); byte[] script; List<(UInt160 Account, BigInteger Value)> balances_gas = null; using (ScriptBuilder sb = new ScriptBuilder()) @@ -283,9 +283,21 @@ public Transaction MakeTransaction(TransferOutput[] outputs, UInt160 from = null { balances = balances.OrderBy(p => p.Value).ToList(); var balances_used = FindPayingAccounts(balances, output.Value.Value); - cosignerList.UnionWith(balances_used.Select(p => p.Account)); foreach (var (account, value) in balances_used) { + if (cosignerList.TryGetValue(account, out Signer signer)) + { + if (signer.Scopes != WitnessScope.Global) + signer.Scopes |= WitnessScope.CalledByEntry; + } + else + { + cosignerList.Add(account, new Signer + { + Account = account, + Scopes = WitnessScope.CalledByEntry + }); + } sb.EmitAppCall(output.AssetId, "transfer", account, output.ScriptHash, value); sb.Emit(OpCode.ASSERT); } @@ -298,14 +310,7 @@ 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(); - cosigners = cosignerList.Select(p => new Signer() - { - // default access for transfers should be valid only for first invocation - Scopes = WitnessScope.CalledByEntry, - Account = p - }).Concat(cosigners?.Where(u => !cosignerList.Contains(u.Account)) ?? Array.Empty()).ToArray(); - - return MakeTransaction(snapshot, script, cosigners, Array.Empty(), balances_gas); + return MakeTransaction(snapshot, script, cosignerList.Values.ToArray(), Array.Empty(), balances_gas); } } From 2d6d7cd171c0f60ebe6034e371e0b37360a7ad3c Mon Sep 17 00:00:00 2001 From: erikzhang Date: Fri, 31 Jul 2020 17:37:57 +0800 Subject: [PATCH 23/33] Update Wallet.cs --- src/neo/Wallets/Wallet.cs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/neo/Wallets/Wallet.cs b/src/neo/Wallets/Wallet.cs index d1f2c8f4ee..1692e0400a 100644 --- a/src/neo/Wallets/Wallet.cs +++ b/src/neo/Wallets/Wallet.cs @@ -366,15 +366,12 @@ private Transaction MakeTransaction(StoreView snapshot, byte[] script, Signer[] foreach (UInt160 hash in hashes) { - byte[] witness_script = GetAccount(hash)?.Contract?.Script ?? null; + byte[] witness_script = GetAccount(hash)?.Contract?.Script; if (witness_script is null) { var contract = snapshot.Contracts.TryGet(hash); - if (contract != null) - { - tx.NetworkFee += CalculateNetworkFee(snapshot, tx, contract, ref size); - } - continue; + if (contract is null) continue; + tx.NetworkFee += CalculateNetworkFee(snapshot, tx, contract, ref size); } tx.NetworkFee += CalculateNetworkFee(witness_script, ref size); } From 62bbfad61f09de88d975f5b9e9ba5e179834709c Mon Sep 17 00:00:00 2001 From: erikzhang Date: Fri, 31 Jul 2020 17:45:20 +0800 Subject: [PATCH 24/33] Fix --- src/neo/Wallets/Wallet.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/neo/Wallets/Wallet.cs b/src/neo/Wallets/Wallet.cs index 1692e0400a..13c149cb71 100644 --- a/src/neo/Wallets/Wallet.cs +++ b/src/neo/Wallets/Wallet.cs @@ -256,7 +256,7 @@ public Transaction MakeTransaction(TransferOutput[] outputs, UInt160 from = null } using (SnapshotView snapshot = Blockchain.Singleton.GetSnapshot()) { - Dictionary cosignerList = cosigners.ToDictionary(p => p.Account) ?? new Dictionary(); + Dictionary cosignerList = cosigners?.ToDictionary(p => p.Account) ?? new Dictionary(); byte[] script; List<(UInt160 Account, BigInteger Value)> balances_gas = null; using (ScriptBuilder sb = new ScriptBuilder()) From 55426f4f3cc57140bb5c9729a4c289c29c3d7223 Mon Sep 17 00:00:00 2001 From: Shargon Date: Fri, 31 Jul 2020 15:38:04 +0200 Subject: [PATCH 25/33] Fix fee calculation --- src/neo/Wallets/Wallet.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/neo/Wallets/Wallet.cs b/src/neo/Wallets/Wallet.cs index 13c149cb71..f165e8bab8 100644 --- a/src/neo/Wallets/Wallet.cs +++ b/src/neo/Wallets/Wallet.cs @@ -373,7 +373,10 @@ private Transaction MakeTransaction(StoreView snapshot, byte[] script, Signer[] if (contract is null) continue; tx.NetworkFee += CalculateNetworkFee(snapshot, tx, contract, ref size); } - tx.NetworkFee += CalculateNetworkFee(witness_script, ref size); + else + { + tx.NetworkFee += CalculateNetworkFee(witness_script, ref size); + } } tx.NetworkFee += size * NativeContract.Policy.GetFeePerByte(snapshot); if (value >= tx.SystemFee + tx.NetworkFee) return tx; From 06e8fd69578a13d99359415bf78ad3fa584c07a5 Mon Sep 17 00:00:00 2001 From: erikzhang Date: Sat, 1 Aug 2020 15:36:57 +0800 Subject: [PATCH 26/33] Optimize CalculateNetworkFee() --- src/neo/Wallets/Wallet.cs | 112 +++++++++++++++++--------------------- 1 file changed, 50 insertions(+), 62 deletions(-) diff --git a/src/neo/Wallets/Wallet.cs b/src/neo/Wallets/Wallet.cs index f165e8bab8..baea9e46df 100644 --- a/src/neo/Wallets/Wallet.cs +++ b/src/neo/Wallets/Wallet.cs @@ -359,78 +359,66 @@ private Transaction MakeTransaction(StoreView snapshot, byte[] script, Signer[] tx.SystemFee = engine.GasConsumed; } - UInt160[] hashes = tx.GetScriptHashesForVerifying(snapshot); - - // 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) - { - byte[] witness_script = GetAccount(hash)?.Contract?.Script; - if (witness_script is null) - { - var contract = snapshot.Contracts.TryGet(hash); - if (contract is null) continue; - tx.NetworkFee += CalculateNetworkFee(snapshot, tx, contract, ref size); - } - else - { - tx.NetworkFee += CalculateNetworkFee(witness_script, ref size); - } - } - tx.NetworkFee += size * NativeContract.Policy.GetFeePerByte(snapshot); + tx.NetworkFee = CalculateNetworkFee(snapshot, tx); if (value >= tx.SystemFee + tx.NetworkFee) return tx; } throw new InvalidOperationException("Insufficient GAS"); } - public static long CalculateNetworkFee(StoreView snapshot, Transaction tx, ContractState contract, ref int size) + public long CalculateNetworkFee(StoreView snapshot, Transaction tx) { - // Empty invocation and verification scripts - size += Array.Empty().GetVarSize() * 2; - - // Check verify cost - ContractMethodDescriptor verify = contract.Manifest.Abi.GetMethod("verify"); - if (verify is null) throw new ArgumentException($"The smart contract {contract.ScriptHash} haven't got verify method"); - ContractMethodDescriptor init = contract.Manifest.Abi.GetMethod("_initialize"); - using (ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Verification, tx, snapshot.Clone(), 0, testMode: true)) - { - engine.LoadScript(contract.Script, CallFlags.None).InstructionPointer = verify.Offset; - if (init != null) engine.LoadClonedContext(init.Offset); - engine.LoadScript(Array.Empty(), CallFlags.None); - if (engine.Execute() == VMState.FAULT) throw new ArgumentException($"Smart contract {contract.ScriptHash} verification fault."); - if (engine.ResultStack.Count != 1 || !engine.ResultStack.Pop().GetBoolean()) throw new ArgumentException($"Smart contract {contract.ScriptHash} returns false."); - - return engine.GasConsumed; - } - } + UInt160[] hashes = tx.GetScriptHashesForVerifying(snapshot); - public static long CalculateNetworkFee(byte[] witness_script, ref int size) - { + // base size for transaction: includes const_header + signers + attributes + script + hashes + int size = Transaction.HeaderSize + tx.Signers.GetVarSize() + tx.Attributes.GetVarSize() + tx.Script.GetVarSize() + IO.Helper.GetVarSize(hashes.Length); long networkFee = 0; - - if (witness_script.IsSignatureContract()) - { - size += 67 + witness_script.GetVarSize(); - networkFee += ApplicationEngine.OpCodePrices[OpCode.PUSHDATA1] + ApplicationEngine.OpCodePrices[OpCode.PUSHDATA1] + ApplicationEngine.OpCodePrices[OpCode.PUSHNULL] + ApplicationEngine.ECDsaVerifyPrice; - } - else if (witness_script.IsMultiSigContract(out int m, out int n)) - { - int size_inv = 66 * m; - size += IO.Helper.GetVarSize(size_inv) + size_inv + witness_script.GetVarSize(); - networkFee += ApplicationEngine.OpCodePrices[OpCode.PUSHDATA1] * m; - using (ScriptBuilder sb = new ScriptBuilder()) - networkFee += ApplicationEngine.OpCodePrices[(OpCode)sb.EmitPush(m).ToArray()[0]]; - networkFee += ApplicationEngine.OpCodePrices[OpCode.PUSHDATA1] * n; - using (ScriptBuilder sb = new ScriptBuilder()) - networkFee += ApplicationEngine.OpCodePrices[(OpCode)sb.EmitPush(n).ToArray()[0]]; - networkFee += ApplicationEngine.OpCodePrices[OpCode.PUSHNULL] + ApplicationEngine.ECDsaVerifyPrice * n; - } - else + foreach (UInt160 hash in hashes) { - //We can support more contract types in the future. + byte[] witness_script = GetAccount(hash)?.Contract?.Script; + if (witness_script is null) + { + var contract = snapshot.Contracts.TryGet(hash); + if (contract is null) continue; + + // Empty invocation and verification scripts + size += Array.Empty().GetVarSize() * 2; + + // Check verify cost + ContractMethodDescriptor verify = contract.Manifest.Abi.GetMethod("verify"); + if (verify is null) throw new ArgumentException($"The smart contract {contract.ScriptHash} haven't got verify method"); + ContractMethodDescriptor init = contract.Manifest.Abi.GetMethod("_initialize"); + using ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Verification, tx, snapshot.Clone(), 0, testMode: true); + engine.LoadScript(contract.Script, CallFlags.None).InstructionPointer = verify.Offset; + if (init != null) engine.LoadClonedContext(init.Offset); + engine.LoadScript(Array.Empty(), CallFlags.None); + if (engine.Execute() == VMState.FAULT) throw new ArgumentException($"Smart contract {contract.ScriptHash} verification fault."); + if (engine.ResultStack.Count != 1 || !engine.ResultStack.Pop().GetBoolean()) throw new ArgumentException($"Smart contract {contract.ScriptHash} returns false."); + + networkFee += engine.GasConsumed; + } + else if (witness_script.IsSignatureContract()) + { + size += 67 + witness_script.GetVarSize(); + networkFee += ApplicationEngine.OpCodePrices[OpCode.PUSHDATA1] + ApplicationEngine.OpCodePrices[OpCode.PUSHDATA1] + ApplicationEngine.OpCodePrices[OpCode.PUSHNULL] + ApplicationEngine.ECDsaVerifyPrice; + } + else if (witness_script.IsMultiSigContract(out int m, out int n)) + { + int size_inv = 66 * m; + size += IO.Helper.GetVarSize(size_inv) + size_inv + witness_script.GetVarSize(); + networkFee += ApplicationEngine.OpCodePrices[OpCode.PUSHDATA1] * m; + using (ScriptBuilder sb = new ScriptBuilder()) + networkFee += ApplicationEngine.OpCodePrices[(OpCode)sb.EmitPush(m).ToArray()[0]]; + networkFee += ApplicationEngine.OpCodePrices[OpCode.PUSHDATA1] * n; + using (ScriptBuilder sb = new ScriptBuilder()) + networkFee += ApplicationEngine.OpCodePrices[(OpCode)sb.EmitPush(n).ToArray()[0]]; + networkFee += ApplicationEngine.OpCodePrices[OpCode.PUSHNULL] + ApplicationEngine.ECDsaVerifyPrice * n; + } + else + { + //We can support more contract types in the future. + } } - + networkFee += size * NativeContract.Policy.GetFeePerByte(snapshot); return networkFee; } From ab971cede24d08dca66986ecc201ca7c0208023d Mon Sep 17 00:00:00 2001 From: Shargon Date: Sat, 1 Aug 2020 12:44:37 +0200 Subject: [PATCH 27/33] Try sc verification when the account it's null --- src/neo/Wallets/Wallet.cs | 76 ++++++++++++++++++++------------------- 1 file changed, 39 insertions(+), 37 deletions(-) diff --git a/src/neo/Wallets/Wallet.cs b/src/neo/Wallets/Wallet.cs index baea9e46df..e0d3bbd357 100644 --- a/src/neo/Wallets/Wallet.cs +++ b/src/neo/Wallets/Wallet.cs @@ -428,54 +428,56 @@ public bool Sign(ContractParametersContext context) foreach (UInt160 scriptHash in context.ScriptHashes) { WalletAccount account = GetAccount(scriptHash); - if (account is null) continue; - // Try to sign self-contained multiSig - - Contract multiSigContract = account.Contract; - - if (multiSigContract != null && - multiSigContract.Script.IsMultiSigContract(out int m, out ECPoint[] points)) - { - foreach (var point in points) - { - account = GetAccount(point); - if (account?.HasKey != true) continue; - KeyPair key = account.GetKey(); - byte[] signature = context.Verifiable.Sign(key); - fSuccess |= context.AddSignature(multiSigContract, key.PublicKey, signature); - if (fSuccess) m--; - if (context.Completed || m <= 0) break; - } - } - else + if (account != null) { - // Try to sign with regular accounts + // Try to sign self-contained multiSig + + Contract multiSigContract = account.Contract; - if (account.HasKey) + if (multiSigContract != null && + multiSigContract.Script.IsMultiSigContract(out int m, out ECPoint[] points)) { - KeyPair key = account.GetKey(); - byte[] signature = context.Verifiable.Sign(key); - fSuccess |= context.AddSignature(account.Contract, key.PublicKey, signature); + foreach (var point in points) + { + account = GetAccount(point); + if (account?.HasKey != true) continue; + KeyPair key = account.GetKey(); + byte[] signature = context.Verifiable.Sign(key); + fSuccess |= context.AddSignature(multiSigContract, key.PublicKey, signature); + if (fSuccess) m--; + if (context.Completed || m <= 0) break; + } + continue; } else { - // Smart contract verification - - using var snapshot = Blockchain.Singleton.GetSnapshot(); - var contract = snapshot.Contracts.TryGet(account.ScriptHash); + // Try to sign with regular accounts - if (contract != null) + if (account.HasKey) { - var deployed = new DeployedContract(contract); + KeyPair key = account.GetKey(); + byte[] signature = context.Verifiable.Sign(key); + fSuccess |= context.AddSignature(account.Contract, key.PublicKey, signature); + continue; + } + } + } - // Only works with verify without parameters + // Try Smart contract verification - if (deployed.ParameterList.Length == 0) - { - fSuccess |= context.Add(new DeployedContract(contract), new object[0]); - } - } + using var snapshot = Blockchain.Singleton.GetSnapshot(); + var contract = snapshot.Contracts.TryGet(scriptHash); + + if (contract != null) + { + var deployed = new DeployedContract(contract); + + // Only works with verify without parameters + + if (deployed.ParameterList.Length == 0) + { + fSuccess |= context.Add(new DeployedContract(contract), new object[0]); } } } From c98d61d76212fef80bf709587e4afa7d1610e376 Mon Sep 17 00:00:00 2001 From: erikzhang Date: Sun, 2 Aug 2020 15:23:11 +0800 Subject: [PATCH 28/33] Update Wallet.cs --- src/neo/Wallets/Wallet.cs | 38 +++++++++++++++++--------------------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/src/neo/Wallets/Wallet.cs b/src/neo/Wallets/Wallet.cs index e0d3bbd357..36b5abc111 100644 --- a/src/neo/Wallets/Wallet.cs +++ b/src/neo/Wallets/Wallet.cs @@ -448,36 +448,32 @@ public bool Sign(ContractParametersContext context) if (fSuccess) m--; if (context.Completed || m <= 0) break; } - continue; } - else + else if (account.HasKey) { // Try to sign with regular accounts - - if (account.HasKey) - { - KeyPair key = account.GetKey(); - byte[] signature = context.Verifiable.Sign(key); - fSuccess |= context.AddSignature(account.Contract, key.PublicKey, signature); - continue; - } + KeyPair key = account.GetKey(); + byte[] signature = context.Verifiable.Sign(key); + fSuccess |= context.AddSignature(account.Contract, key.PublicKey, signature); } } - - // Try Smart contract verification - - using var snapshot = Blockchain.Singleton.GetSnapshot(); - var contract = snapshot.Contracts.TryGet(scriptHash); - - if (contract != null) + else { - var deployed = new DeployedContract(contract); + // Try Smart contract verification - // Only works with verify without parameters + using var snapshot = Blockchain.Singleton.GetSnapshot(); + var contract = snapshot.Contracts.TryGet(scriptHash); - if (deployed.ParameterList.Length == 0) + if (contract != null) { - fSuccess |= context.Add(new DeployedContract(contract), new object[0]); + var deployed = new DeployedContract(contract); + + // Only works with verify without parameters + + if (deployed.ParameterList.Length == 0) + { + fSuccess |= context.Add(new DeployedContract(contract)); + } } } } From ce30cd73dad1fd9c703b706a3636c13f3bdc69db Mon Sep 17 00:00:00 2001 From: Shargon Date: Sun, 2 Aug 2020 15:29:37 +0200 Subject: [PATCH 29/33] Update Wallet.cs --- src/neo/Wallets/Wallet.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/neo/Wallets/Wallet.cs b/src/neo/Wallets/Wallet.cs index 36b5abc111..e353ef85da 100644 --- a/src/neo/Wallets/Wallet.cs +++ b/src/neo/Wallets/Wallet.cs @@ -472,7 +472,7 @@ public bool Sign(ContractParametersContext context) if (deployed.ParameterList.Length == 0) { - fSuccess |= context.Add(new DeployedContract(contract)); + fSuccess |= context.Add(deployed); } } } From df0d29ce61f05ac0d7c6c9225fb42056328e67db Mon Sep 17 00:00:00 2001 From: Shargon Date: Sun, 2 Aug 2020 16:03:58 +0200 Subject: [PATCH 30/33] Add true verify test --- .../Extensions/Nep5NativeContractExtensions.cs | 9 ++------- .../SmartContract/UT_SmartContractHelper.cs | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/tests/neo.UnitTests/Extensions/Nep5NativeContractExtensions.cs b/tests/neo.UnitTests/Extensions/Nep5NativeContractExtensions.cs index b0cd686022..e6be60e661 100644 --- a/tests/neo.UnitTests/Extensions/Nep5NativeContractExtensions.cs +++ b/tests/neo.UnitTests/Extensions/Nep5NativeContractExtensions.cs @@ -4,7 +4,6 @@ using Neo.SmartContract; using Neo.SmartContract.Native; using Neo.VM; -using System; using System.IO; using System.Numerics; @@ -16,14 +15,10 @@ internal class ManualWitness : IVerifiable { private readonly UInt160[] _hashForVerify; - public Witness[] Witnesses - { - get => throw new NotImplementedException(); - set => throw new NotImplementedException(); - } - public int Size => 0; + public Witness[] Witnesses { get; set; } + public ManualWitness(params UInt160[] hashForVerify) { _hashForVerify = hashForVerify ?? new UInt160[0]; diff --git a/tests/neo.UnitTests/SmartContract/UT_SmartContractHelper.cs b/tests/neo.UnitTests/SmartContract/UT_SmartContractHelper.cs index 0f4e9f5f74..da6cf22d42 100644 --- a/tests/neo.UnitTests/SmartContract/UT_SmartContractHelper.cs +++ b/tests/neo.UnitTests/SmartContract/UT_SmartContractHelper.cs @@ -142,6 +142,21 @@ public void TestVerifyWitnesses() Manifest = TestUtils.CreateManifest(UInt160.Zero, "verify", ContractParameterType.Boolean, ContractParameterType.Signature), }); Assert.AreEqual(false, Neo.SmartContract.Helper.VerifyWitnesses(header3, snapshot3, 100)); + + // Smart contract verification + + var contract = new ContractState() + { + Script = "11".HexToBytes(), // 17 PUSH1 + Manifest = TestUtils.CreateManifest(UInt160.Zero, "verify", ContractParameterType.Boolean, ContractParameterType.Signature), // Offset = 0 + }; + snapshot3.Contracts.Add(contract.ScriptHash, contract); + var tx = new Extensions.Nep5NativeContractExtensions.ManualWitness(contract.ScriptHash) + { + Witnesses = new Witness[] { new Witness() { InvocationScript = new byte[0], VerificationScript = new byte[0] } } + }; + + Assert.AreEqual(true, Neo.SmartContract.Helper.VerifyWitnesses(tx, snapshot3, 1000)); } } } From 47e8b52e34123d0f74fa994ce8d615b66e96f79e Mon Sep 17 00:00:00 2001 From: erikzhang Date: Mon, 3 Aug 2020 17:14:11 +0800 Subject: [PATCH 31/33] Update Wallet.cs --- src/neo/Wallets/Wallet.cs | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/neo/Wallets/Wallet.cs b/src/neo/Wallets/Wallet.cs index e353ef85da..b465f396f7 100644 --- a/src/neo/Wallets/Wallet.cs +++ b/src/neo/Wallets/Wallet.cs @@ -448,6 +448,7 @@ public bool Sign(ContractParametersContext context) if (fSuccess) m--; if (context.Completed || m <= 0) break; } + continue; } else if (account.HasKey) { @@ -455,25 +456,24 @@ public bool Sign(ContractParametersContext context) KeyPair key = account.GetKey(); byte[] signature = context.Verifiable.Sign(key); fSuccess |= context.AddSignature(account.Contract, key.PublicKey, signature); + continue; } } - else - { - // Try Smart contract verification - using var snapshot = Blockchain.Singleton.GetSnapshot(); - var contract = snapshot.Contracts.TryGet(scriptHash); + // Try Smart contract verification - if (contract != null) - { - var deployed = new DeployedContract(contract); + using var snapshot = Blockchain.Singleton.GetSnapshot(); + var contract = snapshot.Contracts.TryGet(scriptHash); - // Only works with verify without parameters + if (contract != null) + { + var deployed = new DeployedContract(contract); - if (deployed.ParameterList.Length == 0) - { - fSuccess |= context.Add(deployed); - } + // Only works with verify without parameters + + if (deployed.ParameterList.Length == 0) + { + fSuccess |= context.Add(deployed); } } } From b495fc40b2d82f62d8e2a7519b5312a8aa2180ba Mon Sep 17 00:00:00 2001 From: Shargon Date: Tue, 4 Aug 2020 09:50:03 +0200 Subject: [PATCH 32/33] Remove check account in wallet --- src/neo/Wallets/Wallet.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/neo/Wallets/Wallet.cs b/src/neo/Wallets/Wallet.cs index 2d81206b69..65c5505a6c 100644 --- a/src/neo/Wallets/Wallet.cs +++ b/src/neo/Wallets/Wallet.cs @@ -250,8 +250,6 @@ public Transaction MakeTransaction(TransferOutput[] outputs, UInt160 from = null } else { - if (!Contains(from)) - throw new ArgumentException($"The address {from} was not found in the wallet"); accounts = new[] { from }; } using (SnapshotView snapshot = Blockchain.Singleton.GetSnapshot()) @@ -323,8 +321,6 @@ public Transaction MakeTransaction(byte[] script, UInt160 sender = null, Signer[ } else { - if (!Contains(sender)) - throw new ArgumentException($"The address {sender} was not found in the wallet"); accounts = new[] { sender }; } using (SnapshotView snapshot = Blockchain.Singleton.GetSnapshot()) From c1c2fa42420eaa039a1cbb6f1d540a521c8f7cc0 Mon Sep 17 00:00:00 2001 From: Shargon Date: Tue, 4 Aug 2020 09:58:53 +0200 Subject: [PATCH 33/33] Fix UT --- tests/neo.UnitTests/Wallets/UT_Wallet.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/neo.UnitTests/Wallets/UT_Wallet.cs b/tests/neo.UnitTests/Wallets/UT_Wallet.cs index 7f4ad69332..82b1031fbc 100644 --- a/tests/neo.UnitTests/Wallets/UT_Wallet.cs +++ b/tests/neo.UnitTests/Wallets/UT_Wallet.cs @@ -298,7 +298,7 @@ public void TestMakeTransaction1() Value = new BigDecimal(1,8) } }, UInt160.Zero); - action.Should().Throw(); + action.Should().Throw(); action = () => wallet.MakeTransaction(new TransferOutput[] {