From c74fb4a6061fb06f037e009967cd5fdc60c3a978 Mon Sep 17 00:00:00 2001 From: Sjors Provoost Date: Tue, 20 Aug 2024 17:43:17 +0200 Subject: [PATCH] mining: add -coinbaselocktime To prepare for a potential soft fork that would mandate nLockTime of the coinbase to be set to the block height, allow miners to opt-in to doing this sooner. By using this setting, miners can check if there is any ancillary software they're relying on that is incompatible with such a proposed change. --- src/init.cpp | 1 + src/node/miner.cpp | 4 ++++ src/node/miner.h | 2 ++ src/policy/policy.h | 2 ++ test/functional/mining_basic.py | 14 ++++++++++++-- 5 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index faaf3353d070d4..6a9b32dbee3bd4 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -659,6 +659,7 @@ void SetupServerArgs(ArgsManager& argsman) argsman.AddArg("-blockmaxweight=", strprintf("Set maximum BIP141 block weight (default: %d)", DEFAULT_BLOCK_MAX_WEIGHT), ArgsManager::ALLOW_ANY, OptionsCategory::BLOCK_CREATION); argsman.AddArg("-blockmintxfee=", strprintf("Set lowest fee rate (in %s/kvB) for transactions to be included in block creation. (default: %s)", CURRENCY_UNIT, FormatMoney(DEFAULT_BLOCK_MIN_TX_FEE)), ArgsManager::ALLOW_ANY, OptionsCategory::BLOCK_CREATION); argsman.AddArg("-blockversion=", "Override block version to test forking scenarios", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::BLOCK_CREATION); + argsman.AddArg("-coinbaselocktime", strprintf("Set maximum BIP141 block weight (default: %d)", DEFAULT_COINBASE_LOCKTIME), ArgsManager::ALLOW_ANY, OptionsCategory::BLOCK_CREATION); argsman.AddArg("-rest", strprintf("Accept public REST requests (default: %u)", DEFAULT_REST_ENABLE), ArgsManager::ALLOW_ANY, OptionsCategory::RPC); argsman.AddArg("-rpcallowip=", "Allow JSON-RPC connections from specified source. Valid values for are a single IP (e.g. 1.2.3.4), a network/netmask (e.g. 1.2.3.4/255.255.255.0), a network/CIDR (e.g. 1.2.3.4/24), all ipv4 (0.0.0.0/0), or all ipv6 (::/0). This option can be specified multiple times", ArgsManager::ALLOW_ANY, OptionsCategory::RPC); diff --git a/src/node/miner.cpp b/src/node/miner.cpp index fa2d979b86a637..dcc5baaca86edc 100644 --- a/src/node/miner.cpp +++ b/src/node/miner.cpp @@ -83,6 +83,7 @@ void ApplyArgsManOptions(const ArgsManager& args, BlockAssembler::Options& optio if (const auto parsed{ParseMoney(*blockmintxfee)}) options.blockMinFeeRate = CFeeRate{*parsed}; } options.print_modified_fee = args.GetBoolArg("-printpriority", options.print_modified_fee); + options.coinbase_locktime = args.GetBoolArg("-coinbaselocktime", DEFAULT_COINBASE_LOCKTIME); } void BlockAssembler::resetBlock() @@ -151,6 +152,9 @@ std::unique_ptr BlockAssembler::CreateNewBlock(const CScript& sc coinbaseTx.vout[0].scriptPubKey = scriptPubKeyIn; coinbaseTx.vout[0].nValue = nFees + GetBlockSubsidy(nHeight, chainparams.GetConsensus()); coinbaseTx.vin[0].scriptSig = CScript() << nHeight << OP_0; + if (m_options.coinbase_locktime) { + coinbaseTx.nLockTime = nHeight; + } pblock->vtx[0] = MakeTransactionRef(std::move(coinbaseTx)); pblocktemplate->vchCoinbaseCommitment = m_chainstate.m_chainman.GenerateCoinbaseCommitment(*pblock, pindexPrev); pblocktemplate->vTxFees[0] = -nFees; diff --git a/src/node/miner.h b/src/node/miner.h index 1b8294376692e4..a5b77bdbb6238e 100644 --- a/src/node/miner.h +++ b/src/node/miner.h @@ -162,6 +162,8 @@ class BlockAssembler // Configuration parameters for the block size size_t nBlockMaxWeight{DEFAULT_BLOCK_MAX_WEIGHT}; CFeeRate blockMinFeeRate{DEFAULT_BLOCK_MIN_TX_FEE}; + // Whether to set nLockTime to the current height + bool coinbase_locktime{DEFAULT_COINBASE_LOCKTIME}; // Whether to call TestBlockValidity() at the end of CreateNewBlock(). bool test_block_validity{true}; bool print_modified_fee{DEFAULT_PRINT_MODIFIED_FEE}; diff --git a/src/policy/policy.h b/src/policy/policy.h index a82488a28c9589..06113279dcb072 100644 --- a/src/policy/policy.h +++ b/src/policy/policy.h @@ -23,6 +23,8 @@ class CScript; static constexpr unsigned int DEFAULT_BLOCK_MAX_WEIGHT{MAX_BLOCK_WEIGHT - 4000}; /** Default for -blockmintxfee, which sets the minimum feerate for a transaction in blocks created by mining code **/ static constexpr unsigned int DEFAULT_BLOCK_MIN_TX_FEE{1000}; +/** Default for -coinbaselocktime, which sets the coinbase nLockTime in blocks created by mining code **/ +static constexpr bool DEFAULT_COINBASE_LOCKTIME{false}; /** The maximum weight for transactions we're willing to relay/mine */ static constexpr int32_t MAX_STANDARD_TX_WEIGHT{400000}; /** The minimum non-witness size for transactions we're willing to relay/mine: one larger than 64 */ diff --git a/test/functional/mining_basic.py b/test/functional/mining_basic.py index 6a364a481599e9..c7b147e7b8bebf 100755 --- a/test/functional/mining_basic.py +++ b/test/functional/mining_basic.py @@ -75,6 +75,7 @@ def mine_chain(self): assert_equal(VERSIONBITS_TOP_BITS + (1 << VERSIONBITS_DEPLOYMENT_TESTDUMMY_BIT), self.nodes[0].getblocktemplate(NORMAL_GBT_REQUEST_PARAMS)['version']) self.restart_node(0) self.connect_nodes(0, 1) + return t def test_blockmintxfee_parameter(self): self.log.info("Test -blockmintxfee setting") @@ -118,7 +119,7 @@ def test_blockmintxfee_parameter(self): def run_test(self): node = self.nodes[0] self.wallet = MiniWallet(node) - self.mine_chain() + t = self.mine_chain() def assert_submitblock(block, result_str_1, result_str_2=None): block.solve() @@ -136,6 +137,15 @@ def assert_submitblock(block, result_str_1, result_str_2=None): assert_equal(mining_info['networkhashps'], Decimal('0.003333333333333334')) assert_equal(mining_info['pooledtx'], 0) + self.log.info('check coinbase transaction') + coinbase = node.getblock(node.getbestblockhash(), verbosity=3)['tx'][0] + assert_equal(coinbase['locktime'], 0) + self.restart_node(0, extra_args=[f'-mocktime={t}', '-coinbaselocktime']) + self.connect_nodes(0, 1) + self.generate(self.wallet, 1, sync_fun=self.no_op) + coinbase = node.getblock(node.getbestblockhash(), verbosity=3)['tx'][0] + assert_equal(coinbase['locktime'], 201) + self.log.info("getblocktemplate: Test default witness commitment") txid = int(self.wallet.send_self_transfer(from_node=node)['wtxid'], 16) tmpl = node.getblocktemplate(NORMAL_GBT_REQUEST_PARAMS) @@ -265,7 +275,7 @@ def assert_submitblock(block, result_str_1, result_str_2=None): block.solve() def chain_tip(b_hash, *, status='headers-only', branchlen=1): - return {'hash': b_hash, 'height': 202, 'branchlen': branchlen, 'status': status} + return {'hash': b_hash, 'height': 203, 'branchlen': branchlen, 'status': status} assert chain_tip(block.hash) not in node.getchaintips() node.submitheader(hexdata=block.serialize().hex())