Пример #1
0
        private UnspentOutputSet GetMockOutputSet()
        {
            Transaction transaction = this.network.Consensus.ConsensusFactory.CreateTransaction();

            var fakeTxOut = new TxOut
            {
                Value = 100_000_000
            };

            var coins = new UnspentOutputs(new uint(), transaction)
            {
                Outputs = new TxOut[] { fakeTxOut }
            };

            var unspentOutputs = new UnspentOutputSet();

            unspentOutputs.SetCoins(new[] { coins });

            return(unspentOutputs);
        }
Пример #2
0
        /// <summary>
        /// Calculates pay-to-script-hash (BIP16) transaction signature operation cost.
        /// </summary>
        /// <param name="transaction">Transaction for which we are computing the cost.</param>
        /// <param name="inputs">Map of previous transactions that have outputs we're spending.</param>
        /// <returns>Signature operation cost for transaction.</returns>
        private uint GetP2SHSignatureOperationsCount(Transaction transaction, UnspentOutputSet inputs)
        {
            if (transaction.IsCoinBase)
            {
                return(0);
            }

            uint sigOps = 0;

            for (int i = 0; i < transaction.Inputs.Count; i++)
            {
                TxOut prevout = inputs.GetOutputFor(transaction.Inputs[i]);
                if (prevout.ScriptPubKey.IsPayToScriptHash(this.Parent.Network))
                {
                    sigOps += prevout.ScriptPubKey.GetSigOpCount(this.Parent.Network, transaction.Inputs[i].ScriptSig);
                }
            }

            return(sigOps);
        }
        /// <summary>
        /// Calculates total signature operation cost of a transaction.
        /// </summary>
        /// <param name="transaction">Transaction for which we are computing the cost.</param>
        /// <param name="inputs">Map of previous transactions that have outputs we're spending.</param>
        /// <param name="flags">Script verification flags.</param>
        /// <returns>Signature operation cost for all transaction's inputs.</returns>
        public long GetTransactionSignatureOperationCost(Transaction transaction, UnspentOutputSet inputs, DeploymentFlags flags)
        {
            long signatureOperationCost = this.GetLegacySignatureOperationsCount(transaction) * this.ConsensusOptions.WitnessScaleFactor;

            if (transaction.IsCoinBase)
            {
                return(signatureOperationCost);
            }

            if (flags.ScriptFlags.HasFlag(ScriptVerify.P2SH))
            {
                signatureOperationCost += this.GetP2SHSignatureOperationsCount(transaction, inputs) * this.ConsensusOptions.WitnessScaleFactor;
            }

            for (int i = 0; i < transaction.Inputs.Count; i++)
            {
                TxOut prevout = inputs.GetOutputFor(transaction.Inputs[i]);
                signatureOperationCost += this.CountWitnessSignatureOperation(prevout.ScriptPubKey, transaction.Inputs[i].WitScript, flags);
            }

            return(signatureOperationCost);
        }
Пример #4
0
        /// <inheritdoc />
        public override void UpdateCoinView(RuleContext context, Transaction transaction)
        {
            this.Logger.LogTrace("()");

            if (this.generatedTransaction != null)
            {
                base.ValidateGeneratedTransaction(transaction);
                base.UpdateUTXOSet(context, transaction);
                return;
            }

            // If we are here, was definitely submitted by someone
            base.ValidateSubmittedTransaction(transaction);

            TxOut smartContractTxOut = transaction.Outputs.FirstOrDefault(txOut => txOut.ScriptPubKey.IsSmartContractExec());

            if (smartContractTxOut == null)
            {
                // Someone submitted a standard transaction - no smart contract opcodes.
                var posRuleContext    = context as PosRuleContext;
                UnspentOutputSet view = posRuleContext.UnspentOutputSet;
                if (transaction.IsCoinStake)
                {
                    posRuleContext.TotalCoinStakeValueIn = view.GetValueIn(transaction);
                }

                base.UpdateUTXOSet(context, transaction);

                return;
            }

            // Someone submitted a smart contract transaction.
            base.ExecuteContractTransaction(context, transaction);

            base.UpdateUTXOSet(context, transaction);

            this.Logger.LogTrace("(-)");
        }
        /// <inheritdoc />
        protected override bool IsTxFinal(Transaction transaction, RuleContext context)
        {
            if (transaction.IsCoinBase)
            {
                return(true);
            }

            ChainedHeader index = context.ValidationContext.ChainedHeaderToValidate;

            UnspentOutputSet view = (context as UtxoRuleContext).UnspentOutputSet;

            var prevheights = new int[transaction.Inputs.Count];

            // Check that transaction is BIP68 final.
            // BIP68 lock checks (as opposed to nLockTime checks) must
            // be in ConnectBlock because they require the UTXO set.
            for (int i = 0; i < transaction.Inputs.Count; i++)
            {
                prevheights[i] = (int)view.AccessCoins(transaction.Inputs[i].PrevOut.Hash).Height;
            }

            return(transaction.CheckSequenceLocks(prevheights, index, context.Flags.LockTimeFlags));
        }
        /// <inheritdoc />
        public override async Task RunAsync(RuleContext context)
        {
            Block            block = context.ValidationContext.BlockToValidate;
            ChainedHeader    index = context.ValidationContext.ChainedHeaderToValidate;
            DeploymentFlags  flags = context.Flags;
            UnspentOutputSet view  = (context as UtxoRuleContext).UnspentOutputSet;

            long  sigOpsCost    = 0;
            Money fees          = Money.Zero;
            var   inputsToCheck = new List <(Transaction tx, int inputIndexCopy, TxOut txOut, PrecomputedTransactionData txData, TxIn input, DeploymentFlags flags)>();

            for (int txIndex = 0; txIndex < block.Transactions.Count; txIndex++)
            {
                Transaction tx = block.Transactions[txIndex];

                if (!context.SkipValidation)
                {
                    if (!tx.IsCoinBase && !view.HaveInputs(tx))
                    {
                        this.Logger.LogTrace("Transaction '{0}' has not inputs", tx.GetHash());
                        this.Logger.LogTrace("(-)[BAD_TX_NO_INPUT]");
                        ConsensusErrors.BadTransactionMissingInput.Throw();
                    }

                    if (!this.IsTxFinal(tx, context))
                    {
                        this.Logger.LogTrace("Transaction '{0}' is not final", tx.GetHash());
                        this.Logger.LogTrace("(-)[BAD_TX_NON_FINAL]");
                        ConsensusErrors.BadTransactionNonFinal.Throw();
                    }

                    // GetTransactionSignatureOperationCost counts 3 types of sigops:
                    // * legacy (always),
                    // * p2sh (when P2SH enabled in flags and excludes coinbase),
                    // * witness (when witness enabled in flags and excludes coinbase).
                    sigOpsCost += this.GetTransactionSignatureOperationCost(tx, view, flags);
                    if (sigOpsCost > this.ConsensusOptions.MaxBlockSigopsCost)
                    {
                        this.Logger.LogTrace("(-)[BAD_BLOCK_SIG_OPS]");
                        ConsensusErrors.BadBlockSigOps.Throw();
                    }

                    if (!tx.IsCoinBase)
                    {
                        this.CheckInputs(tx, view, index.Height);

                        if (!tx.IsCoinStake)
                        {
                            fees += view.GetValueIn(tx) - tx.TotalOut;
                        }

                        var txData = new PrecomputedTransactionData(tx);
                        for (int inputIndex = 0; inputIndex < tx.Inputs.Count; inputIndex++)
                        {
                            TxIn input = tx.Inputs[inputIndex];

                            inputsToCheck.Add((
                                                  tx: tx,
                                                  inputIndexCopy: inputIndex,
                                                  txOut: view.GetOutputFor(input),
                                                  txData,
                                                  input: input,
                                                  flags
                                                  ));
                        }
                    }
                }

                this.UpdateCoinView(context, tx);
            }

            if (!context.SkipValidation)
            {
                this.CheckBlockReward(context, fees, index.Height, block);

                // Start the Parallel loop on a thread so its result can be awaited rather than blocking
                Task <ParallelLoopResult> checkInputsInParallel = Task.Run(() =>
                {
                    return(Parallel.ForEach(inputsToCheck, (input, state) =>
                    {
                        if (state.ShouldExitCurrentIteration)
                        {
                            return;
                        }

                        if (!this.CheckInput(input.tx, input.inputIndexCopy, input.txOut, input.txData, input.input, input.flags))
                        {
                            state.Stop();
                        }
                    }));
                });

                ParallelLoopResult loopResult = await checkInputsInParallel.ConfigureAwait(false);

                if (!loopResult.IsCompleted)
                {
                    this.Logger.LogTrace("(-)[BAD_TX_SCRIPT]");

                    ConsensusErrors.BadTransactionScriptError.Throw();
                }
            }
            else
            {
                this.Logger.LogTrace("BIP68, SigOp cost, and block reward validation skipped for block at height {0}.", index.Height);
            }
        }
Пример #7
0
 protected abstract Money GetTransactionFee(UnspentOutputSet view, Transaction tx);
 protected override Money GetTransactionFee(UnspentOutputSet view, Transaction tx)
 {
     return(view.GetValueIn(tx) - tx.TotalOut);
 }
        /// <inheritdoc />
        public async override Task RunAsync(RuleContext context)
        {
            this.Logger.LogTrace("()");

            this.blockTxsProcessed = new List <Transaction>();
            NBitcoin.Block   block = context.ValidationContext.Block;
            ChainedHeader    index = context.ValidationContext.ChainedHeader;
            DeploymentFlags  flags = context.Flags;
            UnspentOutputSet view  = ((UtxoRuleContext)context).UnspentOutputSet;

            this.Parent.PerformanceCounter.AddProcessedBlocks(1);

            // Start state from previous block's root
            this.ContractCoinviewRule.OriginalStateRoot.SyncToRoot(((SmartContractBlockHeader)context.ConsensusTip.Header).HashStateRoot.ToBytes());
            IContractState trackedState = this.ContractCoinviewRule.OriginalStateRoot.StartTracking();

            this.receipts = new List <Receipt>();

            this.refundCounter = 1;
            long  sigOpsCost  = 0;
            Money fees        = Money.Zero;
            var   checkInputs = new List <Task <bool> >();

            for (int txIndex = 0; txIndex < block.Transactions.Count; txIndex++)
            {
                this.Parent.PerformanceCounter.AddProcessedTransactions(1);
                Transaction tx = block.Transactions[txIndex];
                if (!context.SkipValidation)
                {
                    if (!this.IsProtocolTransaction(tx))
                    {
                        if (!view.HaveInputs(tx))
                        {
                            this.Logger.LogTrace("(-)[BAD_TX_NO_INPUT]");
                            ConsensusErrors.BadTransactionMissingInput.Throw();
                        }

                        var prevheights = new int[tx.Inputs.Count];
                        // Check that transaction is BIP68 final.
                        // BIP68 lock checks (as opposed to nLockTime checks) must
                        // be in ConnectBlock because they require the UTXO set.
                        for (int j = 0; j < tx.Inputs.Count; j++)
                        {
                            prevheights[j] = (int)view.AccessCoins(tx.Inputs[j].PrevOut.Hash).Height;
                        }

                        if (!tx.CheckSequenceLocks(prevheights, index, flags.LockTimeFlags))
                        {
                            this.Logger.LogTrace("(-)[BAD_TX_NON_FINAL]");
                            ConsensusErrors.BadTransactionNonFinal.Throw();
                        }
                    }

                    // GetTransactionSignatureOperationCost counts 3 types of sigops:
                    // * legacy (always),
                    // * p2sh (when P2SH enabled in flags and excludes coinbase),
                    // * witness (when witness enabled in flags and excludes coinbase).
                    sigOpsCost += this.GetTransactionSignatureOperationCost(tx, view, flags);
                    if (sigOpsCost > this.ConsensusOptions.MaxBlockSigopsCost)
                    {
                        ConsensusErrors.BadBlockSigOps.Throw();
                    }

                    if (!this.IsProtocolTransaction(tx))
                    {
                        this.CheckInputs(tx, view, index.Height);
                        fees += view.GetValueIn(tx) - tx.TotalOut;
                        var txData = new PrecomputedTransactionData(tx);
                        for (int inputIndex = 0; inputIndex < tx.Inputs.Count; inputIndex++)
                        {
                            this.Parent.PerformanceCounter.AddProcessedInputs(1);
                            TxIn  input          = tx.Inputs[inputIndex];
                            int   inputIndexCopy = inputIndex;
                            TxOut txout          = view.GetOutputFor(input);
                            var   checkInput     = new Task <bool>(() =>
                            {
                                if (txout.ScriptPubKey.IsSmartContractExec() || txout.ScriptPubKey.IsSmartContractInternalCall())
                                {
                                    return(input.ScriptSig.IsSmartContractSpend());
                                }

                                var checker      = new TransactionChecker(tx, inputIndexCopy, txout.Value, txData);
                                var ctx          = new ScriptEvaluationContext(this.Parent.Network);
                                ctx.ScriptVerify = flags.ScriptFlags;
                                return(ctx.VerifyScript(input.ScriptSig, txout.ScriptPubKey, checker));
                            });

                            checkInput.Start();
                            checkInputs.Add(checkInput);
                        }
                    }
                }

                this.UpdateCoinView(context, tx);

                this.blockTxsProcessed.Add(tx);
            }

            if (!context.SkipValidation)
            {
                this.CheckBlockReward(context, fees, index.Height, block);

                foreach (Task <bool> checkInput in checkInputs)
                {
                    if (await checkInput.ConfigureAwait(false))
                    {
                        continue;
                    }

                    this.Logger.LogTrace("(-)[BAD_TX_SCRIPT]");
                    ConsensusErrors.BadTransactionScriptError.Throw();
                }
            }
            else
            {
                this.Logger.LogTrace("BIP68, SigOp cost, and block reward validation skipped for block at height {0}.", index.Height);
            }

            if (new uint256(this.ContractCoinviewRule.OriginalStateRoot.Root) != ((SmartContractBlockHeader)block.Header).HashStateRoot)
            {
                SmartContractConsensusErrors.UnequalStateRoots.Throw();
            }

            ValidateAndStoreReceipts(((SmartContractBlockHeader)block.Header).ReceiptRoot);

            this.ContractCoinviewRule.OriginalStateRoot.Commit();

            this.Logger.LogTrace("(-)");
        }
        /// <inheritdoc />
        public override async Task RunAsync(RuleContext context)
        {
            Block            block = context.ValidationContext.BlockToValidate;
            ChainedHeader    index = context.ValidationContext.ChainedHeaderToValidate;
            DeploymentFlags  flags = context.Flags;
            UnspentOutputSet view  = (context as UtxoRuleContext).UnspentOutputSet;

            long  sigOpsCost  = 0;
            Money fees        = Money.Zero;
            var   checkInputs = new List <Task <bool> >();

            for (int txIndex = 0; txIndex < block.Transactions.Count; txIndex++)
            {
                Transaction tx = block.Transactions[txIndex];

                if (!context.SkipValidation)
                {
                    if (!this.IsProtocolTransaction(tx))
                    {
                        if (!view.HaveInputs(tx))
                        {
                            this.Logger.LogTrace("(-)[BAD_TX_NO_INPUT]");
                            ConsensusErrors.BadTransactionMissingInput.Throw();
                        }

                        var prevheights = new int[tx.Inputs.Count];
                        // Check that transaction is BIP68 final.
                        // BIP68 lock checks (as opposed to nLockTime checks) must
                        // be in ConnectBlock because they require the UTXO set.
                        for (int j = 0; j < tx.Inputs.Count; j++)
                        {
                            prevheights[j] = (int)view.AccessCoins(tx.Inputs[j].PrevOut.Hash).Height;
                        }

                        if (!tx.CheckSequenceLocks(prevheights, index, flags.LockTimeFlags))
                        {
                            this.Logger.LogTrace("(-)[BAD_TX_NON_FINAL]");
                            ConsensusErrors.BadTransactionNonFinal.Throw();
                        }
                    }

                    // GetTransactionSignatureOperationCost counts 3 types of sigops:
                    // * legacy (always),
                    // * p2sh (when P2SH enabled in flags and excludes coinbase),
                    // * witness (when witness enabled in flags and excludes coinbase).
                    sigOpsCost += this.GetTransactionSignatureOperationCost(tx, view, flags);
                    if (sigOpsCost > this.ConsensusOptions.MaxBlockSigopsCost)
                    {
                        this.Logger.LogTrace("(-)[BAD_BLOCK_SIG_OPS]");
                        ConsensusErrors.BadBlockSigOps.Throw();
                    }

                    if (!this.IsProtocolTransaction(tx))
                    {
                        this.CheckInputs(tx, view, index.Height);
                        fees += view.GetValueIn(tx) - tx.TotalOut;
                        var txData = new PrecomputedTransactionData(tx);
                        for (int inputIndex = 0; inputIndex < tx.Inputs.Count; inputIndex++)
                        {
                            TxIn  input          = tx.Inputs[inputIndex];
                            int   inputIndexCopy = inputIndex;
                            TxOut txout          = view.GetOutputFor(input);
                            var   checkInput     = new Task <bool>(() => this.CheckInput(tx, inputIndexCopy, txout, txData, input, flags));
                            checkInput.Start();
                            checkInputs.Add(checkInput);
                        }
                    }
                }

                this.UpdateCoinView(context, tx);
            }

            if (!context.SkipValidation)
            {
                this.CheckBlockReward(context, fees, index.Height, block);

                foreach (Task <bool> checkInput in checkInputs)
                {
                    if (await checkInput.ConfigureAwait(false))
                    {
                        continue;
                    }

                    this.Logger.LogTrace("(-)[BAD_TX_SCRIPT]");
                    ConsensusErrors.BadTransactionScriptError.Throw();
                }
            }
            else
            {
                this.Logger.LogTrace("BIP68, SigOp cost, and block reward validation skipped for block at height {0}.", index.Height);
            }
        }
Пример #11
0
        protected override uint GetP2SHSignatureOperationsCount(Transaction transaction, UnspentOutputSet inputs)
        {
            if (transaction.IsCoinBase)
            {
                return(0);
            }

            uint sigOps = 0;

            for (int i = 0; i < transaction.Inputs.Count; i++)
            {
                TxOut prevout = inputs.GetOutputFor(transaction.Inputs[i]);
                if (prevout.ScriptPubKey.IsScriptType(ScriptType.P2SH))
                {
                    sigOps += this.GetSigOpCount(prevout.ScriptPubKey, this.Parent.Network, transaction.Inputs[i].ScriptSig);
                }
            }

            return(sigOps);
        }
        /// <inheritdoc />
        public override async Task RunAsync(RuleContext context)
        {
            this.Logger.LogTrace("()");

            Block            block = context.BlockValidationContext.Block;
            ChainedHeader    index = context.BlockValidationContext.ChainedHeader;
            DeploymentFlags  flags = context.Flags;
            UnspentOutputSet view  = context.Set;

            this.Parent.PerformanceCounter.AddProcessedBlocks(1);

            long  sigOpsCost  = 0;
            Money fees        = Money.Zero;
            var   checkInputs = new List <Task <bool> >();

            for (int txIndex = 0; txIndex < block.Transactions.Count; txIndex++)
            {
                this.Parent.PerformanceCounter.AddProcessedTransactions(1);
                Transaction tx = block.Transactions[txIndex];
                if (!context.SkipValidation)
                {
                    // TODO: Simplify this condition.
                    if (!tx.IsCoinBase && (!context.IsPoS || (context.IsPoS && !tx.IsCoinStake)))
                    {
                        if (!view.HaveInputs(tx))
                        {
                            this.Logger.LogTrace("(-)[BAD_TX_NO_INPUT]");
                            ConsensusErrors.BadTransactionMissingInput.Throw();
                        }

                        var prevheights = new int[tx.Inputs.Count];
                        // Check that transaction is BIP68 final.
                        // BIP68 lock checks (as opposed to nLockTime checks) must
                        // be in ConnectBlock because they require the UTXO set.
                        for (int j = 0; j < tx.Inputs.Count; j++)
                        {
                            prevheights[j] = (int)view.AccessCoins(tx.Inputs[j].PrevOut.Hash).Height;
                        }

                        if (!tx.CheckSequenceLocks(prevheights, index, flags.LockTimeFlags))
                        {
                            this.Logger.LogTrace("(-)[BAD_TX_NON_FINAL]");
                            ConsensusErrors.BadTransactionNonFinal.Throw();
                        }
                    }

                    // GetTransactionSignatureOperationCost counts 3 types of sigops:
                    // * legacy (always),
                    // * p2sh (when P2SH enabled in flags and excludes coinbase),
                    // * witness (when witness enabled in flags and excludes coinbase).
                    sigOpsCost += this.GetTransactionSignatureOperationCost(tx, view, flags);
                    if (sigOpsCost > this.PowConsensusOptions.MaxBlockSigopsCost)
                    {
                        this.Logger.LogTrace("(-)[BAD_BLOCK_SIG_OPS]");
                        ConsensusErrors.BadBlockSigOps.Throw();
                    }

                    // TODO: Simplify this condition.
                    if (!tx.IsCoinBase && (!context.IsPoS || (context.IsPoS && !tx.IsCoinStake)))
                    {
                        this.CheckInputs(tx, view, index.Height);
                        fees += view.GetValueIn(tx) - tx.TotalOut;
                        var txData = new PrecomputedTransactionData(tx);
                        for (int inputIndex = 0; inputIndex < tx.Inputs.Count; inputIndex++)
                        {
                            this.Parent.PerformanceCounter.AddProcessedInputs(1);
                            TxIn  input          = tx.Inputs[inputIndex];
                            int   inputIndexCopy = inputIndex;
                            TxOut txout          = view.GetOutputFor(input);
                            var   checkInput     = new Task <bool>(() =>
                            {
                                var checker             = new TransactionChecker(tx, inputIndexCopy, txout.Value, txData);
                                var ctx                 = new ScriptEvaluationContext(this.Parent.Network);
                                ctx.ScriptVerify        = flags.ScriptFlags;
                                bool verifyScriptResult = ctx.VerifyScript(input.ScriptSig, txout.ScriptPubKey, checker);

                                if (verifyScriptResult == false)
                                {
                                    this.Logger.LogTrace("Verify script for transaction '{0}' failed, ScriptSig = '{1}', ScriptPubKey = '{2}', script evaluation error = '{3}'", tx.GetHash(), input.ScriptSig, txout.ScriptPubKey, ctx.Error);
                                }

                                return(verifyScriptResult);
                            });
                            checkInput.Start();
                            checkInputs.Add(checkInput);
                        }
                    }
                }

                this.UpdateCoinView(context, tx);
            }

            if (!context.SkipValidation)
            {
                this.CheckBlockReward(context, fees, index.Height, block);

                foreach (Task <bool> checkInput in checkInputs)
                {
                    if (await checkInput.ConfigureAwait(false))
                    {
                        continue;
                    }

                    this.Logger.LogTrace("(-)[BAD_TX_SCRIPT]");
                    ConsensusErrors.BadTransactionScriptError.Throw();
                }
            }
            else
            {
                this.Logger.LogTrace("BIP68, SigOp cost, and block reward validation skipped for block at height {0}.", index.Height);
            }

            this.Logger.LogTrace("(-)");
        }
        /// <inheritdoc />
        public override async Task RunAsync(RuleContext context)
        {
            Block            block = context.ValidationContext.BlockToValidate;
            ChainedHeader    index = context.ValidationContext.ChainedHeaderToValidate;
            DeploymentFlags  flags = context.Flags;
            UnspentOutputSet view  = (context as UtxoRuleContext).UnspentOutputSet;

            long  sigOpsCost  = 0;
            Money fees        = Money.Zero;
            var   checkInputs = new List <Task <bool> >();

            for (int txIndex = 0; txIndex < block.Transactions.Count; txIndex++)
            {
                Transaction tx = block.Transactions[txIndex];

                if (!context.SkipValidation)
                {
                    if (!tx.IsCoinBase && !view.HaveInputs(tx))
                    {
                        this.Logger.LogTrace("Transaction '{0}' has not inputs", tx.GetHash());
                        this.Logger.LogTrace("(-)[BAD_TX_NO_INPUT]");
                        ConsensusErrors.BadTransactionMissingInput.Throw();
                    }

                    if (!this.IsTxFinal(tx, context))
                    {
                        this.Logger.LogTrace("Transaction '{0}' is not final", tx.GetHash());
                        this.Logger.LogTrace("(-)[BAD_TX_NON_FINAL]");
                        ConsensusErrors.BadTransactionNonFinal.Throw();
                    }

                    // GetTransactionSignatureOperationCost counts 3 types of sigops:
                    // * legacy (always),
                    // * p2sh (when P2SH enabled in flags and excludes coinbase),
                    // * witness (when witness enabled in flags and excludes coinbase).
                    sigOpsCost += this.GetTransactionSignatureOperationCost(tx, view, flags);
                    if (sigOpsCost > this.ConsensusOptions.MaxBlockSigopsCost)
                    {
                        this.Logger.LogTrace("(-)[BAD_BLOCK_SIG_OPS]");
                        ConsensusErrors.BadBlockSigOps.Throw();
                    }

                    if (!tx.IsCoinBase)
                    {
                        this.CheckInputs(tx, view, index.Height);

                        if (!tx.IsCoinStake)
                        {
                            fees += view.GetValueIn(tx) - tx.TotalOut;
                        }

                        var txData = new PrecomputedTransactionData(tx);
                        for (int inputIndex = 0; inputIndex < tx.Inputs.Count; inputIndex++)
                        {
                            TxIn  input          = tx.Inputs[inputIndex];
                            int   inputIndexCopy = inputIndex;
                            TxOut txout          = view.GetOutputFor(input);
                            var   checkInput     = new Task <bool>(() => this.CheckInput(tx, inputIndexCopy, txout, txData, input, flags));
                            checkInput.Start();
                            checkInputs.Add(checkInput);
                        }
                    }
                }

                this.UpdateCoinView(context, tx);
            }

            if (!context.SkipValidation)
            {
                this.CheckBlockReward(context, fees, index.Height, block);

                foreach (Task <bool> checkInput in checkInputs)
                {
                    if (await checkInput.ConfigureAwait(false))
                    {
                        continue;
                    }

                    this.Logger.LogTrace("(-)[BAD_TX_SCRIPT]");
                    ConsensusErrors.BadTransactionScriptError.Throw();
                }
            }
            else
            {
                this.Logger.LogTrace("BIP68, SigOp cost, and block reward validation skipped for block at height {0}.", index.Height);
            }
        }