/// <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));
        }
Beispiel #4
0
        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)));
        }
Beispiel #5
0
        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)));
        }
Beispiel #6
0
        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));
        }
Beispiel #7
0
        // 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);
        }