private async ContractTask OnDeploy(ApplicationEngine engine, ContractState contract, StackItem data, bool update) { ContractMethodDescriptor md = contract.Manifest.Abi.GetMethod("_deploy", 2); if (md is not null) await engine.CallFromNativeContract(Hash, contract.Hash, md.Name, data, update); engine.SendNotification(Hash, update ? "Update" : "Deploy", new VM.Types.Array { contract.Hash.ToArray() }); }
private ContractState Deploy(ApplicationEngine engine, byte[] nefFile, byte[] manifest, StackItem data) { if (engine.ScriptContainer is not Transaction tx) { throw new InvalidOperationException(); } if (nefFile.Length == 0) { throw new ArgumentException($"Invalid NefFile Length: {nefFile.Length}"); } if (manifest.Length == 0 || manifest.Length > ContractManifest.MaxLength) { throw new ArgumentException($"Invalid Manifest Length: {manifest.Length}"); } engine.AddGas(Math.Max( engine.StoragePrice * (nefFile.Length + manifest.Length), GetMinimumDeploymentFee(engine.Snapshot) )); NefFile nef = nefFile.AsSerializable <NefFile>(); ContractManifest parsedManifest = ContractManifest.Parse(manifest); UInt160 hash = Helper.GetContractHash(tx.Sender, nef.CheckSum, parsedManifest.Name); StorageKey key = CreateStorageKey(Prefix_Contract).Add(hash); if (engine.Snapshot.Contains(key)) { throw new InvalidOperationException($"Contract Already Exists: {hash}"); } ContractState contract = new ContractState { Id = GetNextAvailableId(engine.Snapshot), UpdateCounter = 0, Nef = nef, Hash = hash, Manifest = parsedManifest }; if (!contract.Manifest.IsValid(hash)) { throw new InvalidOperationException($"Invalid Manifest Hash: {hash}"); } engine.Snapshot.Add(key, new StorageItem(contract)); // Execute _deploy ContractMethodDescriptor md = contract.Manifest.Abi.GetMethod("_deploy", 2); if (md != null) { engine.CallFromNativeContract(Hash, hash, md.Name, data, false); } engine.SendNotification(Hash, "Deploy", new VM.Types.Array { contract.Hash.ToArray() }); return(contract); }
private void CallContractInternal(ContractState contract, ContractMethodDescriptor method, CallFlags flags, bool hasReturnValue, StackItem[] args) { if (invocationCounter.TryGetValue(contract.Hash, out var counter)) { invocationCounter[contract.Hash] = counter + 1; } else { invocationCounter[contract.Hash] = 1; } ExecutionContextState state = CurrentContext.GetState <ExecutionContextState>(); UInt160 callingScriptHash = state.ScriptHash; CallFlags callingFlags = state.CallFlags; if (args.Length != method.Parameters.Length) { throw new InvalidOperationException($"Method {method.Name} Expects {method.Parameters.Length} Arguments But Receives {args.Length} Arguments"); } ExecutionContext context_new = LoadContract(contract, method.Name, flags & callingFlags, hasReturnValue, (ushort)args.Length); state = context_new.GetState <ExecutionContextState>(); state.CallingScriptHash = callingScriptHash; for (int i = args.Length - 1; i >= 0; i--) { context_new.EvaluationStack.Push(args[i]); } if (NativeContract.IsNative(contract.Hash)) { context_new.EvaluationStack.Push(method.Name); } }
public ContractMethodModel(ContractMethodDescriptor method) : base(method) { if (method != null) { ReturnType = method.ReturnType; } }
public ExecutionContext LoadContract(ContractState contract, string method, CallFlags callFlags, bool packParameters = false) { ContractMethodDescriptor md = contract.Manifest.Abi.GetMethod(method); if (md is null) { return(null); } ExecutionContext context = LoadScript(contract.Script, callFlags, contract.Hash, md.Offset); if (NativeContract.IsNative(contract.Hash)) { if (packParameters) { using ScriptBuilder sb = new ScriptBuilder(); sb.Emit(OpCode.DEPTH, OpCode.PACK); sb.EmitPush(md.Name); LoadScript(sb.ToArray(), CallFlags.None); } } else { // Call initialization var init = contract.Manifest.Abi.GetMethod("_initialize"); if (init != null) { LoadContext(context.Clone(init.Offset), false); } } return(context); }
private void CallContractInternal(UInt160 contractHash, string method, CallFlags flags, bool hasReturnValue, StackItem[] 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}"); } if (md.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}"); } } CallContractInternal(contract, md, flags, hasReturnValue, args); }
private void CallContractInternal(UInt160 contractHash, string method, Array args, CallFlags flags, ReturnTypeConvention convention) { if (method.StartsWith('_')) { throw new ArgumentException($"Invalid Method Name: {method}"); } ContractState contract = NativeContract.Management.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}"); } if (md.Safe) { flags &= ~CallFlags.WriteStates; } else { ContractState currentContract = NativeContract.Management.GetContract(Snapshot, CurrentScriptHash); if (currentContract?.CanCall(contract, method) == false) { throw new InvalidOperationException($"Cannot Call Method {method} Of Contract {contractHash} From Contract {CurrentScriptHash}"); } } CallContractInternal(contract, md, args, flags, convention); }
public ExecutionContext LoadContract(ContractState contract, string method, CallFlags callFlags, bool hasReturnValue, ushort pcount) { ContractMethodDescriptor md = contract.Manifest.Abi.GetMethod(method); if (md is null) { return(null); } ExecutionContext context = LoadScript(contract.Script, pcount: pcount, rvcount: hasReturnValue ? 1 : 0, initialPosition: md.Offset, configureState: p => { p.CallFlags = callFlags; p.ScriptHash = contract.Hash; }); // Call initialization var init = contract.Manifest.Abi.GetMethod("_initialize"); if (init != null) { LoadContext(context.Clone(init.Offset)); } return(context); }
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) { throw new ArgumentOutOfRangeException(nameof(callFlags)); } 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, args.Count); if (md is null) { throw new InvalidOperationException($"Method \"{method}\" with {args.Count} parameter(s) doesn't exist in the contract {contractHash}."); } bool hasReturnValue = md.ReturnType != ContractParameterType.Void; if (!hasReturnValue) { CurrentContext.EvaluationStack.Push(StackItem.Null); } CallContractInternal(contract, md, callFlags, hasReturnValue, args); }
private void Update(ApplicationEngine engine, byte[] nefFile, byte[] manifest, StackItem data) { if (nefFile is null && manifest is null) { throw new ArgumentException(); } engine.AddGas(engine.StoragePrice * ((nefFile?.Length ?? 0) + (manifest?.Length ?? 0))); var contract = engine.Snapshot.GetAndChange(CreateStorageKey(Prefix_Contract).Add(engine.CallingScriptHash))?.GetInteroperable <ContractState>(); if (contract is null) { throw new InvalidOperationException($"Updating Contract Does Not Exist: {engine.CallingScriptHash}"); } if (nefFile != null) { if (nefFile.Length == 0) { throw new ArgumentException($"Invalid NefFile Length: {nefFile.Length}"); } // Update nef contract.Nef = nefFile.AsSerializable <NefFile>(); } if (manifest != null) { if (manifest.Length == 0) { throw new ArgumentException($"Invalid Manifest Length: {manifest.Length}"); } ContractManifest manifest_new = ContractManifest.Parse(manifest); if (manifest_new.Name != contract.Manifest.Name) { throw new InvalidOperationException("The name of the contract can't be changed."); } if (!manifest_new.IsValid(contract.Hash)) { throw new InvalidOperationException($"Invalid Manifest Hash: {contract.Hash}"); } contract.Manifest = manifest_new; } Check(contract.Nef.Script, contract.Manifest.Abi); contract.UpdateCounter++; // Increase update counter if (nefFile != null) { ContractMethodDescriptor md = contract.Manifest.Abi.GetMethod("_deploy", 2); if (md != null) { engine.CallFromNativeContract(Hash, contract.Hash, md.Name, data, true); } } engine.SendNotification(Hash, "Update", new VM.Types.Array { contract.Hash.ToArray() }); }
public ContractMethodModel(ContractMethodDescriptor method) : base(method) { if (method != null) { Offset = method.Offset; Safe = method.Safe; ReturnType = method.ReturnType; } }
private ExecutionContext CallContractInternal(ContractState contract, ContractMethodDescriptor method, CallFlags flags, bool hasReturnValue, IReadOnlyList <StackItem> args) { if (method.Safe) { flags &= ~CallFlags.WriteStates; } else { ContractState currentContract = NativeContract.ContractManagement.GetContract(Snapshot, 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)) { invocationCounter[contract.Hash] = counter + 1; } else { invocationCounter[contract.Hash] = 1; } ExecutionContextState state = CurrentContext.GetState <ExecutionContextState>(); UInt160 callingScriptHash = state.ScriptHash; CallFlags callingFlags = state.CallFlags; 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, flags & callingFlags); state = context_new.GetState <ExecutionContextState>(); state.CallingScriptHash = callingScriptHash; 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.Name); } return(context_new); }
private ContractState Deploy(ApplicationEngine engine, byte[] nefFile, byte[] manifest) { if (!(engine.ScriptContainer is Transaction tx)) { throw new InvalidOperationException(); } if (nefFile.Length == 0) { throw new ArgumentException($"Invalid NefFile Length: {nefFile.Length}"); } if (manifest.Length == 0 || manifest.Length > ContractManifest.MaxLength) { throw new ArgumentException($"Invalid Manifest Length: {manifest.Length}"); } engine.AddGas(engine.StoragePrice * (nefFile.Length + manifest.Length)); NefFile nef = nefFile.AsSerializable <NefFile>(); UInt160 hash = Helper.GetContractHash(tx.Sender, nef.Script); StorageKey key = CreateStorageKey(Prefix_Contract).Add(hash); if (engine.Snapshot.Storages.Contains(key)) { throw new InvalidOperationException($"Contract Already Exists: {hash}"); } ContractState contract = new ContractState { Id = GetNextAvailableId(engine.Snapshot), UpdateCounter = 0, Script = nef.Script, Hash = hash, Manifest = ContractManifest.Parse(manifest) }; if (!contract.Manifest.IsValid(hash)) { throw new InvalidOperationException($"Invalid Manifest Hash: {hash}"); } engine.Snapshot.Storages.Add(key, new StorageItem(contract)); // Execute _deploy ContractMethodDescriptor md = contract.Manifest.Abi.GetMethod("_deploy"); if (md != null) { engine.CallFromNativeContract(Hash, hash, md.Name, false); } return(contract); }
private void Update(ApplicationEngine engine, byte[] nefFile, byte[] manifest) { if (nefFile is null && manifest is null) { throw new ArgumentException(); } engine.AddGas(engine.StoragePrice * ((nefFile?.Length ?? 0) + (manifest?.Length ?? 0))); var contract = engine.Snapshot.Storages.GetAndChange(CreateStorageKey(Prefix_Contract).Add(engine.CallingScriptHash))?.GetInteroperable <ContractState>(); if (contract is null) { throw new InvalidOperationException($"Updating Contract Does Not Exist: {engine.CallingScriptHash}"); } if (nefFile != null) { if (nefFile.Length == 0) { throw new ArgumentException($"Invalid NefFile Length: {nefFile.Length}"); } NefFile nef = nefFile.AsSerializable <NefFile>(); // Update script contract.Script = nef.Script; } if (manifest != null) { if (manifest.Length == 0 || manifest.Length > ContractManifest.MaxLength) { throw new ArgumentException($"Invalid Manifest Length: {manifest.Length}"); } contract.Manifest = ContractManifest.Parse(manifest); if (!contract.Manifest.IsValid(contract.Hash)) { throw new InvalidOperationException($"Invalid Manifest Hash: {contract.Hash}"); } } contract.UpdateCounter++; // Increase update counter if (nefFile != null) { ContractMethodDescriptor md = contract.Manifest.Abi.GetMethod("_deploy"); if (md != null) { engine.CallFromNativeContract(Hash, contract.Hash, md.Name, true); } } }
private bool _loadContract(UInt160 hash, string method, int pcount, CallFlags flags) { this.isEngineInitialized(); ContractState cs = NativeContract.ContractManagement.GetContract(this.snapshot, hash); if (cs is null) { return(false); } ContractMethodDescriptor md = cs.Manifest.Abi.GetMethod(method, pcount); this.engine.LoadContract(cs, md, flags); return(true); }
public MethodCallback(ApplicationEngine engine, UInt160 hash, string method) : base(ApplicationEngine.System_Contract_Call, false) { if (method.StartsWith('_')) { throw new ArgumentException(); } this.contract = NativeContract.Management.GetContract(engine.Snapshot, hash); ContractState currentContract = NativeContract.Management.GetContract(engine.Snapshot, engine.CurrentScriptHash); if (currentContract?.CanCall(this.contract, method) == false) { throw new InvalidOperationException(); } this.method = this.contract.Manifest.Abi.Methods.First(p => p.Name == method); }
private ExecutionContext CallContractInternal(UInt160 contractHash, string method, CallFlags flags, bool hasReturnValue, StackItem[] 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, args.Length); if (md is null) { throw new InvalidOperationException($"Method \"{method}\" with {args.Length} parameter(s) doesn't exist in the contract {contractHash}."); } return(CallContractInternal(contract, md, flags, hasReturnValue, args)); }
public MethodCallback(ApplicationEngine engine, UInt160 hash, string method) : base(ApplicationEngine.System_Contract_Call, false) { if (method.StartsWith('_')) { throw new ArgumentException(); } this.contract = engine.Snapshot.Contracts[hash]; ContractManifest currentManifest = engine.Snapshot.Contracts.TryGet(engine.CurrentScriptHash)?.Manifest; if (currentManifest != null && !currentManifest.CanCall(this.contract.Manifest, method)) { throw new InvalidOperationException(); } this.method = this.contract.Manifest.Abi.Methods.First(p => p.Name == method); }
/// <summary> /// Initializes a new instance of the <see cref="DeployedContract"/> class with the specified <see cref="ContractState"/>. /// </summary> /// <param name="contract">The <see cref="ContractState"/> corresponding to the contract.</param> public DeployedContract(ContractState contract) { if (contract is null) { throw new ArgumentNullException(nameof(contract)); } Script = null; ScriptHash = contract.Hash; ContractMethodDescriptor descriptor = contract.Manifest.Abi.GetMethod("verify", -1); if (descriptor is null) { throw new NotSupportedException("The smart contract haven't got verify method."); } ParameterList = descriptor.Parameters.Select(u => u.Type).ToArray(); }
public ExecutionContext LoadContract(ContractState contract, ContractMethodDescriptor method, CallFlags callFlags) { ExecutionContext context = LoadScript(contract.Script, rvcount: method.ReturnType == ContractParameterType.Void ? 0 : 1, initialPosition: method.Offset, configureState: p => { p.CallFlags = callFlags; p.ScriptHash = contract.Hash; p.Contract = contract; }); // Call initialization var init = contract.Manifest.Abi.GetMethod("_initialize", 0); if (init != null) { LoadContext(context.Clone(init.Offset)); } return(context); }
// Copied from OracleService.CreateResponseTx to avoid taking dependency on OracleService package and it's 110mb GRPC runtime public static Transaction?CreateResponseTx(DataCache snapshot, OracleRequest request, OracleResponse response, IReadOnlyList <ECPoint> oracleNodes, ProtocolSettings settings) { if (oracleNodes.Count == 0) { throw new Exception("No oracle nodes available. Have you enabled oracles via the `oracle enable` command?"); } var requestTx = NativeContract.Ledger.GetTransactionState(snapshot, request.OriginalTxid); var n = oracleNodes.Count; var m = n - (n - 1) / 3; var oracleSignContract = Contract.CreateMultiSigContract(m, oracleNodes); var tx = new Transaction() { Version = 0, Nonce = unchecked ((uint)response.Id), ValidUntilBlock = requestTx.BlockIndex + settings.MaxValidUntilBlockIncrement, Signers = new[] { new Signer { Account = NativeContract.Oracle.Hash, Scopes = WitnessScope.None }, new Signer { Account = oracleSignContract.ScriptHash, Scopes = WitnessScope.None } }, Attributes = new[] { response }, Script = OracleResponse.FixedScript, Witnesses = new Witness[2] }; Dictionary <UInt160, Witness> witnessDict = new Dictionary <UInt160, Witness> { [oracleSignContract.ScriptHash] = new Witness { InvocationScript = Array.Empty <byte>(), VerificationScript = oracleSignContract.Script, }, [NativeContract.Oracle.Hash] = new Witness { InvocationScript = Array.Empty <byte>(), VerificationScript = Array.Empty <byte>(), } }; UInt160[] hashes = tx.GetScriptHashesForVerifying(snapshot); tx.Witnesses[0] = witnessDict[hashes[0]]; tx.Witnesses[1] = witnessDict[hashes[1]]; // Calculate network fee var oracleContract = NativeContract.ContractManagement.GetContract(snapshot, NativeContract.Oracle.Hash); var engine = ApplicationEngine.Create(TriggerType.Verification, tx, snapshot.CreateSnapshot(), settings: settings); ContractMethodDescriptor md = oracleContract.Manifest.Abi.GetMethod("verify", -1); engine.LoadContract(oracleContract, md, CallFlags.None); if (engine.Execute() != Neo.VM.VMState.HALT) { return(null); } tx.NetworkFee += engine.GasConsumed; var executionFactor = NativeContract.Policy.GetExecFeeFactor(snapshot); var networkFee = executionFactor * Neo.SmartContract.Helper.MultiSignatureContractCost(m, n); tx.NetworkFee += networkFee; // Base size for transaction: includes const_header + signers + script + hashes + witnesses, except attributes int size_inv = 66 * m; int size = Transaction.HeaderSize + tx.Signers.GetVarSize() + tx.Script.GetVarSize() + Neo.IO.Helper.GetVarSize(hashes.Length) + witnessDict[NativeContract.Oracle.Hash].Size + Neo.IO.Helper.GetVarSize(size_inv) + size_inv + oracleSignContract.Script.GetVarSize(); var feePerByte = NativeContract.Policy.GetFeePerByte(snapshot); if (response.Result.Length > OracleResponse.MaxResultSize) { response.Code = OracleResponseCode.ResponseTooLarge; response.Result = Array.Empty <byte>(); } else if (tx.NetworkFee + (size + tx.Attributes.GetVarSize()) * feePerByte > request.GasForResponse) { response.Code = OracleResponseCode.InsufficientFunds; response.Result = Array.Empty <byte>(); } size += tx.Attributes.GetVarSize(); tx.NetworkFee += size * feePerByte; // Calculate system fee tx.SystemFee = request.GasForResponse - tx.NetworkFee; return(tx); }
internal static bool VerifyWitness(this IVerifiable verifiable, DataCache snapshot, UInt160 hash, Witness witness, long gas, out long fee) { fee = 0; using (ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Verification, verifiable, snapshot?.CreateSnapshot(), null, gas)) { CallFlags callFlags = !witness.VerificationScript.IsStandardContract() ? CallFlags.ReadStates : CallFlags.None; byte[] verification = witness.VerificationScript; if (verification.Length == 0) { ContractState cs = NativeContract.ContractManagement.GetContract(snapshot, hash); if (cs is null) { return(false); } ContractMethodDescriptor md = cs.Manifest.Abi.GetMethod("verify", -1); if (md?.ReturnType != ContractParameterType.Boolean) { return(false); } engine.LoadContract(cs, md, callFlags); } else { if (NativeContract.IsNative(hash)) { return(false); } if (hash != witness.ScriptHash) { return(false); } engine.LoadScript(verification, initialPosition: 0, configureState: p => { p.CallFlags = callFlags; p.ScriptHash = hash; }); } engine.LoadScript(witness.InvocationScript, configureState: p => p.CallFlags = CallFlags.None); if (NativeContract.IsNative(hash)) { try { engine.StepOut(); engine.Push("verify"); } catch { } } if (engine.Execute() == VMState.FAULT) { return(false); } if (!engine.ResultStack.Peek().GetBoolean()) { return(false); } fee = engine.GasConsumed; } return(true); }
internal static bool VerifyWitnesses(this IVerifiable verifiable, StoreView snapshot, long gas) { if (gas < 0) { return(false); } UInt160[] hashes; try { hashes = verifiable.GetScriptHashesForVerifying(snapshot); } catch (InvalidOperationException) { return(false); } if (hashes.Length != verifiable.Witnesses.Length) { return(false); } for (int i = 0; i < hashes.Length; i++) { int offset; byte[] verification = verifiable.Witnesses[i].VerificationScript; if (verification.Length == 0) { ContractState cs = snapshot.Contracts.TryGet(hashes[i]); 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; } else { if (hashes[i] != verifiable.Witnesses[i].ScriptHash) { return(false); } offset = 0; } using (ApplicationEngine engine = new ApplicationEngine(TriggerType.Verification, verifiable, snapshot, gas)) { engine.LoadScript(verification, CallFlags.ReadOnly).InstructionPointer = offset; engine.LoadScript(verifiable.Witnesses[i].InvocationScript, CallFlags.None); if (engine.Execute() == VMState.FAULT) { return(false); } if (!engine.ResultStack.TryPop(out StackItem result) || !result.ToBoolean()) { return(false); } gas -= engine.GasConsumed; } } return(true); }
internal static bool VerifyWitnesses(this IVerifiable verifiable, StoreView snapshot, long gas, WitnessFlag filter = WitnessFlag.All) { if (gas < 0) { return(false); } if (gas > MaxVerificationGas) { gas = MaxVerificationGas; } UInt160[] hashes; try { hashes = verifiable.GetScriptHashesForVerifying(snapshot); } catch (InvalidOperationException) { return(false); } if (hashes.Length != verifiable.Witnesses.Length) { return(false); } for (int i = 0; i < hashes.Length; i++) { WitnessFlag flag = verifiable.Witnesses[i].StateDependent ? WitnessFlag.StateDependent : WitnessFlag.StateIndependent; if (!filter.HasFlag(flag)) { gas -= verifiable.Witnesses[i].GasConsumed; if (gas < 0) { return(false); } continue; } int offset; ContractMethodDescriptor init = null; byte[] verification = verifiable.Witnesses[i].VerificationScript; if (verification.Length == 0) { ContractState cs = snapshot.Contracts.TryGet(hashes[i]); 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"); } else { if (NativeContract.IsNative(hashes[i])) { return(false); } if (hashes[i] != verifiable.Witnesses[i].ScriptHash) { return(false); } offset = 0; } using (ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Verification, verifiable, snapshot?.Clone(), gas)) { CallFlags callFlags = verifiable.Witnesses[i].StateDependent ? CallFlags.AllowStates : CallFlags.None; ExecutionContext context = engine.LoadScript(verification, callFlags, offset); if (NativeContract.IsNative(hashes[i])) { using ScriptBuilder sb = new ScriptBuilder(); sb.Emit(OpCode.DEPTH, OpCode.PACK); sb.EmitPush("verify"); engine.LoadScript(sb.ToArray(), CallFlags.None); } else if (init != null) { engine.LoadContext(context.Clone(init.Offset), false); } 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); } gas -= engine.GasConsumed; verifiable.Witnesses[i].GasConsumed = engine.GasConsumed; } } return(true); }
internal static bool VerifyWitness(this IVerifiable verifiable, ProtocolSettings settings, DataCache snapshot, UInt160 hash, Witness witness, long gas, out long fee) { fee = 0; Script invocationScript; try { invocationScript = new Script(witness.InvocationScript, true); } catch (BadScriptException) { return(false); } using (ApplicationEngine engine = ApplicationEngine.Create(TriggerType.Verification, verifiable, snapshot?.CreateSnapshot(), null, settings, gas)) { if (witness.VerificationScript.Length == 0) { ContractState cs = NativeContract.ContractManagement.GetContract(snapshot, hash); if (cs is null) { return(false); } ContractMethodDescriptor md = cs.Manifest.Abi.GetMethod("verify", -1); if (md?.ReturnType != ContractParameterType.Boolean) { return(false); } engine.LoadContract(cs, md, CallFlags.ReadOnly); } else { if (NativeContract.IsNative(hash)) { return(false); } if (hash != witness.ScriptHash) { return(false); } Script verificationScript; try { verificationScript = new Script(witness.VerificationScript, true); } catch (BadScriptException) { return(false); } engine.LoadScript(verificationScript, initialPosition: 0, configureState: p => { p.CallFlags = CallFlags.ReadOnly; p.ScriptHash = hash; }); } engine.LoadScript(invocationScript, configureState: p => p.CallFlags = CallFlags.None); if (engine.Execute() == VMState.FAULT) { return(false); } if (!engine.ResultStack.Peek().GetBoolean()) { return(false); } fee = engine.GasConsumed; } return(true); }