public BackgroundCommiterCoinView(CoinView inner)
 {
     if (inner == null)
     {
         throw new ArgumentNullException("inner");
     }
     _Inner           = inner;
     _InnerCommitable = new CommitableCoinView(Inner);
     _Commitable      = new CommitableCoinView(_InnerCommitable);
     FlushPeriod      = TimeSpan.FromSeconds(5);
 }
        private void CheckIntputs(Transaction tx, CommitableCoinView inputs, int nSpendHeight)
        {
            if (!inputs.HaveInputs(tx))
            {
                ConsensusErrors.BadTransactionMissingInput.Throw();
            }
            Money nValueIn = Money.Zero;
            Money nFees    = Money.Zero;

            for (int i = 0; i < tx.Inputs.Count; i++)
            {
                var prevout = tx.Inputs[i].PrevOut;
                var coins   = inputs.AccessCoins(prevout.Hash);

                // If prev is coinbase, check that it's matured
                if (coins.IsCoinbase)
                {
                    if (nSpendHeight - coins.Height < COINBASE_MATURITY)
                    {
                        ConsensusErrors.BadTransactionPrematureCoinbaseSpending.Throw();
                    }
                }

                // Check for negative or overflow input values
                nValueIn += coins.TryGetOutput(prevout.N).Value;
                if (!MoneyRange(coins.TryGetOutput(prevout.N).Value) || !MoneyRange(nValueIn))
                {
                    ConsensusErrors.BadTransactionInputValueOutOfRange.Throw();
                }
            }

            if (nValueIn < tx.TotalOut)
            {
                ConsensusErrors.BadTransactionInBelowOut.Throw();
            }

            // Tally transaction fees
            Money nTxFee = nValueIn - tx.TotalOut;

            if (nTxFee < 0)
            {
                ConsensusErrors.BadTransactionNegativeFee.Throw();
            }
            nFees += nTxFee;
            if (!MoneyRange(nFees))
            {
                ConsensusErrors.BadTransactionFeeOutOfRange.Throw();
            }
        }
        private uint GetP2SHSigOpCount(Transaction tx, CommitableCoinView inputs)
        {
            if (tx.IsCoinBase)
            {
                return(0);
            }

            uint nSigOps = 0;

            for (uint i = 0; i < tx.Inputs.Count; i++)
            {
                var prevout = inputs.GetOutputFor(tx.Inputs[i]);
                if (prevout.ScriptPubKey.IsPayToScriptHash)
                {
                    nSigOps += prevout.ScriptPubKey.GetSigOpCount(tx.Inputs[i].ScriptSig);
                }
            }
            return(nSigOps);
        }
        private long GetTransactionSigOpCost(Transaction tx, CommitableCoinView inputs, ConsensusFlags flags)
        {
            long nSigOps = GetLegacySigOpCount(tx) * WITNESS_SCALE_FACTOR;

            if (tx.IsCoinBase)
            {
                return(nSigOps);
            }

            if (flags.ScriptFlags.HasFlag(ScriptVerify.P2SH))
            {
                nSigOps += GetP2SHSigOpCount(tx, inputs) * WITNESS_SCALE_FACTOR;
            }

            for (var i = 0; i < tx.Inputs.Count; i++)
            {
                var prevout = inputs.GetOutputFor(tx.Inputs[i]);
                nSigOps += CountWitnessSigOps(tx.Inputs[i].ScriptSig, prevout.ScriptPubKey, tx.Inputs[i].WitScript, flags);
            }
            return(nSigOps);
        }
        /// <summary>
        /// Pull blocks, validate them and update the UTXO Set
        /// </summary>
        /// <param name="utxo">UTXO Set</param>
        /// <param name="puller">Block source</param>
        /// <returns>Stream of validated blocks</returns>
        public IEnumerable <Block> Run(CoinViewStack utxoStack, BlockPuller puller)
        {
            var utxo            = utxoStack.Top;
            var cache           = utxoStack.Find <CacheCoinView>();
            var lookaheadPuller = puller as ILookaheadBlockPuller;

            puller.SetLocation(utxo.Tip);
            ThresholdConditionCache bip9 = new ThresholdConditionCache(_ConsensusParams);
            StopWatch watch    = new StopWatch();
            bool      rejected = false;

            while (true)
            {
                Block block = null;
                while (true)
                {
                    rejected = false;
                    try
                    {
                        using (watch.Start(o => PerformanceCounter.AddBlockFetchingTime(o)))
                        {
                            block = puller.NextBlock();
                        }
                        ChainedBlock       next;
                        ContextInformation context;
                        ConsensusFlags     flags;
                        using (watch.Start(o => PerformanceCounter.AddBlockProcessingTime(o)))
                        {
                            CheckBlockHeader(block.Header);
                            next    = new ChainedBlock(block.Header, block.Header.GetHash(), utxo.Tip);
                            context = new ContextInformation(next, this._ConsensusParams);
                            ContextualCheckBlockHeader(block.Header, context);
                            var states = bip9.GetStates(utxo.Tip);
                            flags = new ConsensusFlags(next, states, _ConsensusParams);
                            ContextualCheckBlock(block, flags, context);
                            CheckBlock(block);
                        }

                        var commitable = new CommitableCoinView(next, utxo);
                        using (watch.Start(o => PerformanceCounter.AddUTXOFetchingTime(o)))
                        {
                            commitable.FetchCoins(GetIdsToFetch(block, flags.EnforceBIP30));
                        }
                        commitable.SetInner(NullCoinView.Instance);

                        Task prefetching = GetPrefetchingTask(cache, lookaheadPuller, flags);
                        using (watch.Start(o => PerformanceCounter.AddBlockProcessingTime(o)))
                        {
                            ExecuteBlock(block, next, flags, commitable, null);
                        }
                        using (watch.Start(o => PerformanceCounter.AddUTXOFetchingTime(o)))
                        {
                            prefetching.Wait();
                            commitable.Commit(utxo);
                        }
                    }
                    catch (ConsensusErrorException ex)
                    {
                        rejected = true;
                        if (ex.ConsensusError == ConsensusErrors.TimeTooNew)
                        {
                            puller.Reject(block, RejectionMode.Temporary);
                        }
                        else
                        {
                            puller.Reject(block, RejectionMode.Permanent);
                        }
                    }
                    if (!rejected)
                    {
                        yield return(block);
                    }
                }
            }
        }
        public void ExecuteBlock(Block block, ChainedBlock index, ConsensusFlags flags, CommitableCoinView view, TaskScheduler taskScheduler)
        {
            PerformanceCounter.AddProcessedBlocks(1);
            taskScheduler = taskScheduler ?? TaskScheduler.Default;
            if (flags.EnforceBIP30)
            {
                foreach (var tx in block.Transactions)
                {
                    var coins = view.AccessCoins(tx.GetHash());
                    if (coins != null && !coins.IsPrunable)
                    {
                        ConsensusErrors.BadTransactionBIP30.Throw();
                    }
                }
            }
            long  nSigOpsCost = 0;
            Money nFees       = Money.Zero;
            List <Task <bool> > checkInputs = new List <Task <bool> >();

            for (int i = 0; i < block.Transactions.Count; i++)
            {
                PerformanceCounter.AddProcessedTransactions(1);
                var tx = block.Transactions[i];
                if (!tx.IsCoinBase)
                {
                    int[] prevheights;

                    if (!view.HaveInputs(tx))
                    {
                        ConsensusErrors.BadTransactionMissingInput.Throw();
                    }

                    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 (var 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))
                    {
                        ConsensusErrors.BadTransactionNonFinal.Throw();
                    }
                }
                // GetTransactionSigOpCost 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)
                nSigOpsCost += GetTransactionSigOpCost(tx, view, flags);
                if (nSigOpsCost > MAX_BLOCK_SIGOPS_COST)
                {
                    ConsensusErrors.BadBlockSigOps.Throw();
                }

                if (!tx.IsCoinBase)
                {
                    CheckIntputs(tx, view, index.Height);
                    nFees += view.GetValueIn(tx) - tx.TotalOut;
                    int ii      = i;
                    var localTx = tx;
                    PrecomputedTransactionData txData = new PrecomputedTransactionData(tx);
                    for (int iInput = 0; iInput < tx.Inputs.Count; iInput++)
                    {
                        PerformanceCounter.AddProcessedInputs(1);
                        var input      = tx.Inputs[iInput];
                        int iiIntput   = iInput;
                        var txout      = view.GetOutputFor(input);
                        var checkInput = new Task <bool>(() =>
                        {
                            if (UseConsensusLib)
                            {
                                Script.BitcoinConsensusError error;
                                return(Script.VerifyScriptConsensus(txout.ScriptPubKey, tx, (uint)iiIntput, flags.ScriptFlags, out error));
                            }
                            else
                            {
                                var checker      = new TransactionChecker(tx, iiIntput, txout.Value, txData);
                                var ctx          = new ScriptEvaluationContext();
                                ctx.ScriptVerify = flags.ScriptFlags;
                                return(ctx.VerifyScript(input.ScriptSig, txout.ScriptPubKey, checker));
                            }
                        });
                        checkInput.Start(taskScheduler);
                        checkInputs.Add(checkInput);
                    }
                }
                view.Update(tx, index.Height);
            }
            Money blockReward = nFees + GetBlockSubsidy(index.Height);

            if (block.Transactions[0].TotalOut > blockReward)
            {
                ConsensusErrors.BadCoinbaseAmount.Throw();
            }
            var passed = checkInputs.All(c => c.GetAwaiter().GetResult());

            if (!passed)
            {
                ConsensusErrors.BadTransactionScriptError.Throw();
            }
        }