private uint GetP2SHSigOpCount(Transaction tx, UnspentOutputSet 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); }
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); }
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(); } }