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 @@ -471,7 +475,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 @@ -688,11 +688,14 @@ auto nSigOpsCount = GetTransactionSigOpCount(tx, view, nextBlockScriptVerifyFlags); + const bool fLimitSigOpCount = + !IsPhononEnabled(consensusParams, chainActive.Tip()); + // Check that the transaction doesn't have an excessive number of // sigops. static_assert(MAX_STANDARD_TX_SIGOPS <= MAX_TX_SIGOPS_COUNT, "we don't want transactions we can't even mine"); - 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)); @@ -1809,6 +1812,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); @@ -1847,18 +1852,20 @@ REJECT_INVALID, "bad-txns-accumulated-fee-outofrange"); } - // 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"); + } } // The following checks do not apply to the coinbase. @@ -3731,6 +3738,7 @@ // Keep track of the sigops count. uint64_t nSigOps = 0; + const bool fLimitSigOpCount = !IsPhononEnabled(params, pindexPrev); const auto currentBlockSize = ::GetSerializeSize(block, PROTOCOL_VERSION); auto nMaxSigOpsCount = GetMaxBlockSigOpsCount(currentBlockSize); // Note that pindexPrev may be null if reindexing genesis block. @@ -3769,17 +3777,19 @@ } } - // Count the sigops for the current transaction. If the tx or total - // sigops counts are too high, then the block is invalid. - const auto txSigOps = GetSigOpCountWithoutP2SH(tx, scriptFlags); - if (txSigOps > MAX_TX_SIGOPS_COUNT) { - return state.DoS(100, false, REJECT_INVALID, "bad-txn-sigops", - false, "out-of-bounds SigOpCount"); - } - nSigOps += txSigOps; - 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 tx or total + // sigops counts are too high, then the block is invalid. + const auto txSigOps = GetSigOpCountWithoutP2SH(tx, scriptFlags); + if (txSigOps > MAX_TX_SIGOPS_COUNT) { + return state.DoS(100, false, REJECT_INVALID, "bad-txn-sigops", + false, "out-of-bounds SigOpCount"); + } + nSigOps += txSigOps; + 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 @@ -54,6 +54,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(): @@ -73,7 +76,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