public void ContextualCheckBlockHeader(BlockHeader header, ContextInformation context)
        {
            if (context.BestBlock == null)
            {
                throw new ArgumentException("context.BestBlock should not be null");
            }
            int nHeight = context.BestBlock.Height + 1;

            // Check proof of work
            if (header.Bits != context.NextWorkRequired)
            {
                ConsensusErrors.BadDiffBits.Throw();
            }

            // Check timestamp against prev
            if (header.BlockTime <= context.BestBlock.MedianTimePast)
            {
                ConsensusErrors.TimeTooOld.Throw();
            }

            // Check timestamp
            if (header.BlockTime > context.Time + TimeSpan.FromHours(2))
            {
                ConsensusErrors.TimeTooNew.Throw();
            }

            // Reject outdated version blocks when 95% (75% on testnet) of the network has upgraded:
            // check for version 2, 3 and 4 upgrades
            if ((header.Version < 2 && nHeight >= _ConsensusParams.BuriedDeployments[BuriedDeployments.BIP34]) ||
                (header.Version < 3 && nHeight >= _ConsensusParams.BuriedDeployments[BuriedDeployments.BIP66]) ||
                (header.Version < 4 && nHeight >= _ConsensusParams.BuriedDeployments[BuriedDeployments.BIP65]))
            {
                ConsensusErrors.BadVersion.Throw();
            }
        }
        /// <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 ContextualCheckBlock(Block block, ConsensusFlags consensusFlags, ContextInformation context)
        {
            int nHeight = context.BestBlock == null ? 0 : context.BestBlock.Height + 1;

            // Start enforcing BIP113 (Median Time Past) using versionbits logic.
            var nLockTimeCutoff = consensusFlags.LockTimeFlags.HasFlag(LockTimeFlags.MedianTimePast) ?
                                  context.BestBlock.MedianTimePast :
                                  block.Header.BlockTime;

            // Check that all transactions are finalized
            foreach (var transaction in block.Transactions)
            {
                if (!transaction.IsFinal(nLockTimeCutoff, nHeight))
                {
                    ConsensusErrors.BadTransactionNonFinal.Throw();
                }
            }

            // Enforce rule that the coinbase starts with serialized block height
            if (consensusFlags.EnforceBIP34)
            {
                Script expect = new Script(Op.GetPushOp(nHeight));
                Script actual = block.Transactions[0].Inputs[0].ScriptSig;
                if (!StartWith(actual.ToBytes(true), expect.ToBytes(true)))
                {
                    ConsensusErrors.BadCoinbaseHeight.Throw();
                }
            }

            // Validation for witness commitments.
            // * We compute the witness hash (which is the hash including witnesses) of all the block's transactions, except the
            //   coinbase (where 0x0000....0000 is used instead).
            // * The coinbase scriptWitness is a stack of a single 32-byte vector, containing a witness nonce (unconstrained).
            // * We build a merkle tree with all those witness hashes as leaves (similar to the hashMerkleRoot in the block header).
            // * There must be at least one output whose scriptPubKey is a single 36-byte push, the first 4 bytes of which are
            //   {0xaa, 0x21, 0xa9, 0xed}, and the following 32 bytes are SHA256^2(witness root, witness nonce). In case there are
            //   multiple, the last one is used.
            bool fHaveWitness = false;

            if (consensusFlags.ScriptFlags.HasFlag(ScriptVerify.Witness))
            {
                int commitpos = GetWitnessCommitmentIndex(block);
                if (commitpos != -1)
                {
                    bool    malleated   = false;
                    uint256 hashWitness = BlockWitnessMerkleRoot(block, ref malleated);
                    // The malleation check is ignored; as the transaction tree itself
                    // already does not permit it, it is impossible to trigger in the
                    // witness tree.
                    var witness = block.Transactions[0].Inputs[0].WitScript;
                    if (witness.PushCount != 1 || witness.Pushes.First().Length != 32)
                    {
                        ConsensusErrors.BadWitnessNonceSize.Throw();
                    }

                    byte[] hashed = new byte[64];
                    Buffer.BlockCopy(hashWitness.ToBytes(), 0, hashed, 0, 32);
                    Buffer.BlockCopy(witness.Pushes.First(), 0, hashed, 32, 32);
                    hashWitness = Hashes.Hash256(hashed);
                    if (!EqualsArray(hashWitness.ToBytes(), block.Transactions[0].Outputs[commitpos].ScriptPubKey.ToBytes(true).Skip(6).ToArray(), 32))
                    {
                        ConsensusErrors.BadWitnessMerkleMatch.Throw();
                    }
                    fHaveWitness = true;
                }
            }

            if (!fHaveWitness)
            {
                for (var i = 0; i < block.Transactions.Count; i++)
                {
                    if (block.Transactions[i].HasWitness)
                    {
                        ConsensusErrors.UnexpectedWitness.Throw();
                    }
                }
            }

            // After the coinbase witness nonce and commitment are verified,
            // we can check if the block weight passes (before we've checked the
            // coinbase witness, it would be possible for the weight to be too
            // large by filling up the coinbase witness, which doesn't change
            // the block hash, so we couldn't mark the block as permanently
            // failed).
            if (GetBlockWeight(block) > MAX_BLOCK_WEIGHT)
            {
                ConsensusErrors.BadCoinbaseHeight.Throw();
            }
        }