diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp index 37524176e20..af9388d4b9f 100644 --- a/src/node/interfaces.cpp +++ b/src/node/interfaces.cpp @@ -67,6 +67,7 @@ #include #include #include +#include #include #include @@ -969,6 +970,16 @@ public: std::unique_ptr createNewBlock(const BlockCreateOptions& options) override { + // Reject too-small values instead of clamping so callers don't silently + // end up mining with different options than requested. This matches the + // behavior of the `-blockreservedweight` startup option, which rejects + // values below MINIMUM_BLOCK_RESERVED_WEIGHT. + if (options.block_reserved_weight && options.block_reserved_weight < MINIMUM_BLOCK_RESERVED_WEIGHT) { + throw std::runtime_error(strprintf("block_reserved_weight (%zu) must be at least %u weight units", + *options.block_reserved_weight, + MINIMUM_BLOCK_RESERVED_WEIGHT)); + } + // Ensure m_tip_block is set so consumers of BlockTemplate can rely on that. if (!waitTipChanged(uint256::ZERO, MillisecondsDouble::max())) return {}; diff --git a/src/node/types.h b/src/node/types.h index 1eea9460535..e3ee05dd0d9 100644 --- a/src/node/types.h +++ b/src/node/types.h @@ -43,7 +43,8 @@ struct BlockCreateOptions { bool use_mempool{true}; /** * The default reserved weight for the fixed-size block header, - * transaction count and coinbase transaction. + * transaction count and coinbase transaction. Minimum: 2000 weight units + * (MINIMUM_BLOCK_RESERVED_WEIGHT). * * Providing a value overrides the `-blockreservedweight` startup setting. * Cap'n Proto IPC clients currently cannot leave this field unset, so they diff --git a/test/functional/interface_ipc_mining.py b/test/functional/interface_ipc_mining.py index d1bdf609ad1..61c050e74fe 100755 --- a/test/functional/interface_ipc_mining.py +++ b/test/functional/interface_ipc_mining.py @@ -257,6 +257,15 @@ class IPCMiningTest(BitcoinTestFramework): empty_block = await mining_get_block(empty_template, ctx) assert_equal(len(empty_block.vtx), 1) + self.log.debug("Enforce minimum reserved weight for IPC clients too") + opts.blockReservedWeight = 0 + try: + await mining.createNewBlock(opts) + raise AssertionError("createNewBlock unexpectedly succeeded") + except capnp.lib.capnp.KjException as e: + assert_equal(e.description, "remote exception: std::exception: block_reserved_weight (0) must be at least 2000 weight units") + assert_equal(e.type, "FAILED") + asyncio.run(capnp.run(async_routine())) def run_coinbase_and_submission_test(self):