/// <summary> /// Determines whether the specified account has witnessed the current transaction. /// </summary> /// <param name="hash">The hash of the account.</param> /// <returns><see langword="true"/> if the account has witnessed the current transaction; otherwise, <see langword="false"/>.</returns> protected internal bool CheckWitnessInternal(UInt160 hash) { if (hash.Equals(CallingScriptHash)) return true; if (ScriptContainer is Transaction tx) { Signer[] signers; OracleResponse response = tx.GetAttribute<OracleResponse>(); if (response is null) { signers = tx.Signers; } else { OracleRequest request = NativeContract.Oracle.GetRequest(Snapshot, response.Id); signers = NativeContract.Ledger.GetTransaction(Snapshot, request.OriginalTxid).Signers; } Signer signer = signers.FirstOrDefault(p => p.Account.Equals(hash)); if (signer is null) return false; if (signer.Scopes == WitnessScope.Global) return true; if (signer.Scopes.HasFlag(WitnessScope.CalledByEntry)) { if (CallingScriptHash == null || CallingScriptHash == EntryScriptHash) return true; } if (signer.Scopes.HasFlag(WitnessScope.CustomContracts)) { if (signer.AllowedContracts.Contains(CurrentScriptHash)) return true; } if (signer.Scopes.HasFlag(WitnessScope.CustomGroups)) { // Check allow state callflag ValidateCallFlags(CallFlags.ReadStates); var contract = NativeContract.ContractManagement.GetContract(Snapshot, CallingScriptHash); // check if current group is the required one if (contract.Manifest.Groups.Select(p => p.PubKey).Intersect(signer.AllowedGroups).Any()) return true; } return false; } // Check allow state callflag ValidateCallFlags(CallFlags.ReadStates); // only for non-Transaction types (Block, etc) var hashes_for_verifying = ScriptContainer.GetScriptHashesForVerifying(Snapshot); return hashes_for_verifying.Contains(hash); }
public void TestCreateOracleResponseTx() { var snapshot = Blockchain.Singleton.GetSnapshot(); var executionFactor = NativeContract.Policy.GetExecFeeFactor(snapshot); Assert.AreEqual(executionFactor, (uint)30); var feePerByte = NativeContract.Policy.GetFeePerByte(snapshot); Assert.AreEqual(feePerByte, (uint)1000); OracleRequest request = new OracleRequest { OriginalTxid = UInt256.Zero, GasForResponse = 100000000 * 1, Url = "https://127.0.0.1/test", Filter = "", CallbackContract = UInt160.Zero, CallbackMethod = "callback", UserData = System.Array.Empty <byte>() }; byte Prefix_Transaction = 11; snapshot.Add(NativeContract.Ledger.CreateStorageKey(Prefix_Transaction, request.OriginalTxid), new StorageItem(new TransactionState() { BlockIndex = 1, Transaction = new Transaction() { ValidUntilBlock = 1 } })); OracleResponse response = new OracleResponse() { Id = 1, Code = OracleResponseCode.Success, Result = new byte[] { 0x00 } }; ECPoint[] oracleNodes = new ECPoint[] { ECCurve.Secp256r1.G }; var tx = OracleService.CreateResponseTx(snapshot, request, response, oracleNodes); Assert.AreEqual(167, tx.Size); Assert.AreEqual(2216640, tx.NetworkFee); Assert.AreEqual(97783360, tx.SystemFee); // case (2) The size of attribute exceed the maximum limit request.GasForResponse = 0_10000000; response.Result = new byte[10250]; tx = OracleService.CreateResponseTx(snapshot, request, response, oracleNodes); Assert.AreEqual(166, tx.Size); Assert.AreEqual(OracleResponseCode.InsufficientFunds, response.Code); Assert.AreEqual(2215640, tx.NetworkFee); Assert.AreEqual(7784360, tx.SystemFee); }
/// <summary> /// Determines whether the specified account has witnessed the current transaction. /// </summary> /// <param name="hash">The hash of the account.</param> /// <returns><see langword="true"/> if the account has witnessed the current transaction; otherwise, <see langword="false"/>.</returns> protected internal bool CheckWitnessInternal(UInt160 hash) { if (hash.Equals(CallingScriptHash)) { return(true); } if (ScriptContainer is Transaction tx) { Signer[] signers; OracleResponse response = tx.GetAttribute <OracleResponse>(); if (response is null) { signers = tx.Signers; } else { OracleRequest request = NativeContract.Oracle.GetRequest(Snapshot, response.Id); signers = NativeContract.Ledger.GetTransaction(Snapshot, request.OriginalTxid).Signers; } Signer signer = signers.FirstOrDefault(p => p.Account.Equals(hash)); if (signer is null) { return(false); } foreach (WitnessRule rule in signer.GetAllRules()) { if (rule.Condition.Match(this)) { return(rule.Action == WitnessRuleAction.Allow); } } return(false); } // Check allow state callflag ValidateCallFlags(CallFlags.ReadStates); // only for non-Transaction types (Block, etc) var hashes_for_verifying = ScriptContainer.GetScriptHashesForVerifying(Snapshot); return(hashes_for_verifying.Contains(hash)); }
public override bool Verify(DataCache snapshot, Transaction tx) { if (tx.Signers.Any(p => p.Scopes != WitnessScope.None)) { return(false); } if (!tx.Script.Span.SequenceEqual(FixedScript)) { return(false); } OracleRequest request = NativeContract.Oracle.GetRequest(snapshot, Id); if (request is null) { return(false); } if (tx.NetworkFee + tx.SystemFee != request.GasForResponse) { return(false); } UInt160 oracleAccount = Contract.GetBFTAddress(NativeContract.RoleManagement.GetDesignatedByRole(snapshot, Role.Oracle, NativeContract.Ledger.CurrentIndex(snapshot) + 1)); return(tx.Signers.Any(p => p.Account.Equals(oracleAccount))); }
public override bool Verify(StoreView snapshot, Transaction tx) { if (tx.Signers.Any(p => p.Scopes != WitnessScope.None)) { return(false); } if (!tx.Script.AsSpan().SequenceEqual(FixedScript)) { return(false); } OracleRequest request = NativeContract.Oracle.GetRequest(snapshot, Id); if (request is null) { return(false); } if (tx.NetworkFee + tx.SystemFee != request.GasForResponse) { return(false); } UInt160 oracleAccount = Blockchain.GetConsensusAddress(NativeContract.Designate.GetDesignatedByRole(snapshot, Role.Oracle)); return(tx.Signers.Any(p => p.Account.Equals(oracleAccount))); }
protected internal bool CheckWitnessInternal(UInt160 hash) { if (hash.Equals(CallingScriptHash)) { return(true); } if (ScriptContainer is Transaction tx) { Signer[] signers; OracleResponse response = tx.GetAttribute <OracleResponse>(); if (response is null) { signers = tx.Signers; } else { OracleRequest request = NativeContract.Oracle.GetRequest(Snapshot, response.Id); signers = Snapshot.GetTransaction(request.OriginalTxid).Signers; } Signer signer = signers.FirstOrDefault(p => p.Account.Equals(hash)); if (signer is null) { return(false); } if (signer.Scopes == WitnessScope.Global) { return(true); } if (signer.Scopes.HasFlag(WitnessScope.CalledByEntry)) { if (CallingScriptHash == null || CallingScriptHash == EntryScriptHash) { return(true); } } if (signer.Scopes.HasFlag(WitnessScope.CustomContracts)) { if (signer.AllowedContracts.Contains(CurrentScriptHash)) { return(true); } } if (signer.Scopes.HasFlag(WitnessScope.CustomGroups)) { // Check allow state callflag if (!CurrentContext.GetState <ExecutionContextState>().CallFlags.HasFlag(CallFlags.ReadStates)) { throw new InvalidOperationException($"Cannot call this SYSCALL without the flag AllowStates."); } var contract = NativeContract.Management.GetContract(Snapshot, CallingScriptHash); // check if current group is the required one if (contract.Manifest.Groups.Select(p => p.PubKey).Intersect(signer.AllowedGroups).Any()) { return(true); } } return(false); } // Check allow state callflag if (!CurrentContext.GetState <ExecutionContextState>().CallFlags.HasFlag(CallFlags.ReadStates)) { throw new InvalidOperationException($"Cannot call this SYSCALL without the flag AllowStates."); } // only for non-Transaction types (Block, etc) var hashes_for_verifying = ScriptContainer.GetScriptHashesForVerifying(Snapshot); return(hashes_for_verifying.Contains(hash)); }
// 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); }