diff --git a/src/miner.h b/src/miner.h --- a/src/miner.h +++ b/src/miner.h @@ -186,14 +186,16 @@ * Increments nPackagesSelected / nDescendantsUpdated with corresponding * statistics from the package selection (for logging statistics). */ - void addPackageTxs(int &nPackagesSelected, int &nDescendantsUpdated) + void addPackageTxs(int &nPackagesSelected, int &nDescendantsUpdated, + bool fLimitSigOpCount) EXCLUSIVE_LOCKS_REQUIRED(mempool->cs); // helper functions for addPackageTxs() /** Remove confirmed (inBlock) entries from given set */ void onlyUnconfirmed(CTxMemPool::setEntries &testSet); /** Test if a new package would "fit" in the block */ - bool TestPackage(uint64_t packageSize, int64_t packageSigOpCount) const; + bool TestPackage(uint64_t packageSize, int64_t packageSigOpCount, + bool fLimitSigOpCount) const; /** * Perform checks on each transaction in a package: * locktime, serialized size (if necessary). These checks should always diff --git a/src/miner.cpp b/src/miner.cpp --- a/src/miner.cpp +++ b/src/miner.cpp @@ -155,9 +155,12 @@ ? nMedianTimePast : pblock->GetBlockTime(); + const bool fLimitSigOpCount = + !IsPhononEnabled(chainparams.GetConsensus(), pindexPrev); + int nPackagesSelected = 0; int nDescendantsUpdated = 0; - addPackageTxs(nPackagesSelected, nDescendantsUpdated); + addPackageTxs(nPackagesSelected, nDescendantsUpdated, fLimitSigOpCount); if (IsMagneticAnomalyEnabled(chainparams.GetConsensus(), pindexPrev)) { // If magnetic anomaly is enabled, we make sure transaction are @@ -247,15 +250,15 @@ } } -bool BlockAssembler::TestPackage(uint64_t packageSize, - int64_t packageSigOps) const { +bool BlockAssembler::TestPackage(uint64_t packageSize, int64_t packageSigOps, + bool fLimitSigOpCount) const { auto blockSizeWithPackage = nBlockSize + packageSize; if (blockSizeWithPackage >= nMaxGeneratedBlockSize) { return false; } - if (nBlockSigOps + packageSigOps >= - GetMaxBlockSigOpsCount(blockSizeWithPackage)) { + if (fLimitSigOpCount && nBlockSigOps + packageSigOps >= + GetMaxBlockSigOpsCount(blockSizeWithPackage)) { return false; } @@ -373,7 +376,8 @@ * @param[out] nDescendantsUpdated Number of descendant transactions updated */ void BlockAssembler::addPackageTxs(int &nPackagesSelected, - int &nDescendantsUpdated) { + int &nDescendantsUpdated, + bool fLimitSigOpCount) { // selection algorithm orders the mempool based on feerate of a // transaction including all unconfirmed ancestors. Since we don't remove // transactions from the mempool as we select them for block inclusion, we @@ -462,7 +466,7 @@ // The following must not use virtual size since TestPackage relies on // having an accurate call to // GetMaxBlockSigOpsCount(blockSizeWithPackage). - if (!TestPackage(packageSize, packageSigOps)) { + if (!TestPackage(packageSize, packageSigOps, fLimitSigOpCount)) { if (fUsingModified) { // Since we always look at the best entry in mapModifiedTx, we // must erase failed entries so that we can consider the next diff --git a/src/validation.cpp b/src/validation.cpp --- a/src/validation.cpp +++ b/src/validation.cpp @@ -663,6 +663,8 @@ "bad-txns-nonstandard-inputs"); } + const bool fLimitSigOpCount = + !IsPhononEnabled(consensusParams, chainActive.Tip()); int64_t nSigOpsCount = GetTransactionSigOpCount(tx, view, STANDARD_SCRIPT_VERIFY_FLAGS); @@ -690,7 +692,7 @@ // itself can contain sigops MAX_STANDARD_TX_SIGOPS is less than // MAX_BLOCK_SIGOPS_PER_MB; we still consider this an invalid rather // than merely non-standard transaction. - if (nSigOpsCount > MAX_STANDARD_TX_SIGOPS) { + if (fLimitSigOpCount && nSigOpsCount > MAX_STANDARD_TX_SIGOPS) { return state.DoS(0, false, REJECT_NONSTANDARD, "bad-txns-too-many-sigops", false, strprintf("%d", nSigOpsCount)); @@ -1805,6 +1807,8 @@ int nInputs = 0; // Sigops counting. We need to do it again because of P2SH. + const bool fLimitSigOpCount = + !IsPhononEnabled(consensusParams, pindex->pprev); uint64_t nSigOpsCount = 0; const uint64_t currentBlockSize = ::GetSerializeSize(block, PROTOCOL_VERSION); @@ -1817,7 +1821,7 @@ nInputs += tx.vin.size(); - if (tx.IsCoinBase()) { + if (fLimitSigOpCount && tx.IsCoinBase()) { // We've already checked for sigops count before P2SH in CheckBlock. nSigOpsCount += GetSigOpCountWithoutP2SH(tx, flags); } @@ -1865,18 +1869,20 @@ REJECT_INVALID, "bad-txns-nonfinal"); } - // GetTransactionSigOpCount counts 2 types of sigops: - // * legacy (always) - // * p2sh (when P2SH enabled in flags and excludes coinbase) - auto txSigOpsCount = GetTransactionSigOpCount(tx, view, flags); - if (txSigOpsCount > MAX_TX_SIGOPS_COUNT) { - return state.DoS(100, false, REJECT_INVALID, "bad-txn-sigops"); - } + if (fLimitSigOpCount) { + // GetTransactionSigOpCount counts 2 types of sigops: + // * legacy (always) + // * p2sh (when P2SH enabled in flags and excludes coinbase) + auto txSigOpsCount = GetTransactionSigOpCount(tx, view, flags); + if (txSigOpsCount > MAX_TX_SIGOPS_COUNT) { + return state.DoS(100, false, REJECT_INVALID, "bad-txn-sigops"); + } - nSigOpsCount += txSigOpsCount; - if (nSigOpsCount > nMaxSigOpsCount) { - return state.DoS(100, error("ConnectBlock(): too many sigops"), - REJECT_INVALID, "bad-blk-sigops"); + nSigOpsCount += txSigOpsCount; + if (nSigOpsCount > nMaxSigOpsCount) { + return state.DoS(100, error("ConnectBlock(): too many sigops"), + REJECT_INVALID, "bad-blk-sigops"); + } } // Don't cache results if we're actually connecting blocks (still @@ -3721,6 +3727,7 @@ // Keep track of the sigops count. uint64_t nSigOps = 0; + const bool fLimitSigOpCount = !IsPhononEnabled(params, pindexPrev); auto currentBlockSize = ::GetSerializeSize(block, PROTOCOL_VERSION); auto nMaxSigOpsCount = GetMaxBlockSigOpsCount(currentBlockSize); @@ -3753,12 +3760,15 @@ } } - // Count the sigops for the current transaction. If the total sigops - // count is too high, the the block is invalid. - nSigOps += GetSigOpCountWithoutP2SH(tx, STANDARD_SCRIPT_VERIFY_FLAGS); - if (nSigOps > nMaxSigOpsCount) { - return state.DoS(100, false, REJECT_INVALID, "bad-blk-sigops", - false, "out-of-bounds SigOpCount"); + if (fLimitSigOpCount) { + // Count the sigops for the current transaction. If the total sigops + // count is too high, the the block is invalid. + nSigOps += + GetSigOpCountWithoutP2SH(tx, STANDARD_SCRIPT_VERIFY_FLAGS); + if (nSigOps > nMaxSigOpsCount) { + return state.DoS(100, false, REJECT_INVALID, "bad-blk-sigops", + false, "out-of-bounds SigOpCount"); + } } if (!ContextualCheckTransaction(params, tx, state, nHeight, diff --git a/test/functional/abc-mempool-accept-txn.py b/test/functional/abc-mempool-accept-txn.py --- a/test/functional/abc-mempool-accept-txn.py +++ b/test/functional/abc-mempool-accept-txn.py @@ -47,6 +47,9 @@ # Error for too many sigops in one TX RPC_TXNS_TOO_MANY_SIGOPS_ERROR = "bad-txns-too-many-sigops" +# Set test to run with sigops deactivation far in the future. +SIGOPS_DEACTIVATION_TIME = 2000000000 + class PreviousSpendableOutput(): @@ -67,6 +70,8 @@ self.coinbase_pubkey = self.coinbase_key.get_pubkey() self.tip = None self.blocks = {} + self.extra_args = [ + ['-phononactivationtime={}'.format(SIGOPS_DEACTIVATION_TIME)]] def add_options(self, parser): super().add_options(parser) diff --git a/test/functional/abc-p2p-fullblocktest-sigops.py b/test/functional/abc-p2p-fullblocktest-sigops.py --- a/test/functional/abc-p2p-fullblocktest-sigops.py +++ b/test/functional/abc-p2p-fullblocktest-sigops.py @@ -52,6 +52,9 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import assert_equal +# Set test to run with sigops deactivation far in the future. +SIGOPS_DEACTIVATION_TIME = 2000000000 + class PreviousSpendableOutput(): @@ -71,7 +74,7 @@ self.blocks = {} self.excessive_block_size = 100 * ONE_MEGABYTE self.extra_args = [['-whitelist=127.0.0.1', - "-excessiveblocksize={}".format(self.excessive_block_size)]] + "-excessiveblocksize={}".format(self.excessive_block_size), '-phononactivationtime={}'.format(SIGOPS_DEACTIVATION_TIME)]] def add_options(self, parser): super().add_options(parser) diff --git a/test/functional/feature_block_sigops.py b/test/functional/feature_block_sigops.py --- a/test/functional/feature_block_sigops.py +++ b/test/functional/feature_block_sigops.py @@ -46,12 +46,16 @@ from test_framework.txtools import pad_tx from test_framework.util import assert_equal +# Set test to run with sigops deactivation far in the future. +SIGOPS_DEACTIVATION_TIME = 2000000000 + class FullBlockSigOpsTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 1 self.setup_clean_chain = True - self.extra_args = [['-noparkdeepreorg', '-maxreorgdepth=-1']] + self.extra_args = [['-noparkdeepreorg', '-maxreorgdepth=-1', + '-phononactivationtime={}'.format(SIGOPS_DEACTIVATION_TIME)]] def run_test(self): self.bootstrap_p2p() # Add one p2p connection to the node