Ejemplo n.º 1
0
 public ConsensusFlags GetFlags(ChainedBlock block = null)
 {
     block = block ?? Tip;
     lock (bip9)
     {
         var states = bip9.GetStates(block.Previous);
         var flags  = new ConsensusFlags(block, states, Validator.ConsensusParams);
         return(flags);
     }
 }
Ejemplo n.º 2
0
        private Task TryPrefetchAsync(ConsensusFlags flags)
        {
            Task prefetching = Task.FromResult <bool>(true);

            if (UTXOSet is CachedCoinView)
            {
                var nextBlock = this.Puller.TryGetLookahead(0);
                if (nextBlock != null)
                {
                    prefetching = UTXOSet.FetchCoinsAsync(GetIdsToFetch(nextBlock, flags.EnforceBIP30));
                }
            }
            return(prefetching);
        }
Ejemplo n.º 3
0
        public long GetTransactionSigOpCost(Transaction tx, UnspentOutputSet inputs, ConsensusFlags flags)
        {
            long nSigOps = GetLegacySigOpCount(tx) * this.consensusOptions.WITNESS_SCALE_FACTOR;

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

            if (flags.ScriptFlags.HasFlag(ScriptVerify.P2SH))
            {
                nSigOps += GetP2SHSigOpCount(tx, inputs) * this.consensusOptions.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);
        }
Ejemplo n.º 4
0
        private long WitnessSigOps(WitProgramParameters witParams, WitScript witScript, ConsensusFlags flags)
        {
            if (witParams.Version == 0)
            {
                if (witParams.Program.Length == 20)
                {
                    return(1);
                }

                if (witParams.Program.Length == 32 && witScript.PushCount > 0)
                {
                    Script subscript = Script.FromBytesUnsafe(witScript.GetUnsafePush(witScript.PushCount - 1));
                    return(subscript.GetSigOpCount(true));
                }
            }

            // Future flags may be implemented here.
            return(0);
        }
Ejemplo n.º 5
0
        private long CountWitnessSigOps(Script scriptSig, Script scriptPubKey, WitScript witness, ConsensusFlags flags)
        {
            witness = witness ?? WitScript.Empty;
            if (!flags.ScriptFlags.HasFlag(ScriptVerify.Witness))
            {
                return(0);
            }
            var witParams = PayToWitTemplate.Instance.ExtractScriptPubKeyParameters2(scriptPubKey);

            if (witParams != null)
            {
                return(WitnessSigOps(witParams, witness, flags));
            }

            if (scriptPubKey.IsPayToScriptHash && scriptSig.IsPushOnly)
            {
                var data      = scriptSig.ToOps().Select(o => o.PushData).LastOrDefault() ?? new byte[0];
                var subScript = Script.FromBytesUnsafe(data);

                witParams = PayToWitTemplate.Instance.ExtractScriptPubKeyParameters2(scriptPubKey);
                if (witParams != null)
                {
                    return(WitnessSigOps(witParams, witness, flags));
                }
            }
            return(0);
        }
Ejemplo n.º 6
0
        public virtual void ExecuteBlock(ContextInformation context, TaskScheduler taskScheduler)
        {
            Block            block = context.BlockResult.Block;
            ChainedBlock     index = context.BlockResult.ChainedBlock;
            ConsensusFlags   flags = context.Flags;
            UnspentOutputSet view  = context.Set;

            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 && !tx.IsCoinStake)
                {
                    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 > this.consensusOptions.MAX_BLOCK_SIGOPS_COST)
                {
                    ConsensusErrors.BadBlockSigOps.Throw();
                }

                if (!tx.IsCoinBase && !tx.IsCoinStake)
                {
                    CheckInputs(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);
                    }
                }

                if (tx.IsCoinStake)
                {
                    context.Stake.TotalCoinStakeValueIn = view.GetValueIn(tx);
                }

                view.Update(tx, index.Height);
            }

            this.CheckBlockReward(context, nFees, index, block);

            var passed = checkInputs.All(c => c.GetAwaiter().GetResult());

            if (!passed)
            {
                ConsensusErrors.BadTransactionScriptError.Throw();
            }
        }
        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();
            }
        }