Skip to content

Commit 5bb3163

Browse files
committed
test: add -blockmaxweight startup option functional test
1 parent 2c7d90a commit 5bb3163

File tree

1 file changed

+84
-0
lines changed

1 file changed

+84
-0
lines changed

test/functional/mining_basic.py

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@
2727
CBlockHeader,
2828
COIN,
2929
DEFAULT_BLOCK_RESERVED_WEIGHT,
30+
MAX_BLOCK_WEIGHT,
3031
ser_uint256,
32+
WITNESS_SCALE_FACTOR
3133
)
3234
from test_framework.p2p import P2PDataStore
3335
from test_framework.test_framework import BitcoinTestFramework
@@ -194,6 +196,87 @@ def test_pruning(self):
194196
assert_equal(result, "inconclusive")
195197
assert_equal(prune_node.getblock(pruned_blockhash, verbosity=0), pruned_block)
196198

199+
200+
def send_transactions(self, utxos, fee_rate, target_vsize):
201+
"""
202+
Helper to create and send transactions with the specified target virtual size and fee rate.
203+
"""
204+
for utxo in utxos:
205+
self.wallet.send_self_transfer(
206+
from_node=self.nodes[0],
207+
utxo_to_spend=utxo,
208+
target_vsize=target_vsize,
209+
fee_rate=fee_rate,
210+
)
211+
212+
def verify_block_template(self, expected_tx_count, expected_weight):
213+
"""
214+
Create a block template and check that it satisfies the expected transaction count and total weight.
215+
"""
216+
response = self.nodes[0].getblocktemplate(NORMAL_GBT_REQUEST_PARAMS)
217+
self.log.info(f"Testing block template: contains {expected_tx_count} transactions, and total weight <= {expected_weight}")
218+
assert_equal(len(response["transactions"]), expected_tx_count)
219+
total_weight = sum(transaction["weight"] for transaction in response["transactions"])
220+
assert_greater_than_or_equal(expected_weight, total_weight)
221+
222+
def test_block_max_weight(self):
223+
self.log.info("Testing default and custom -blockmaxweight startup options.")
224+
225+
# Restart the node to allow large transactions
226+
LARGE_TXS_COUNT = 10
227+
LARGE_VSIZE = int(((MAX_BLOCK_WEIGHT - DEFAULT_BLOCK_RESERVED_WEIGHT) / WITNESS_SCALE_FACTOR) / LARGE_TXS_COUNT)
228+
HIGH_FEERATE = Decimal("0.0003")
229+
self.restart_node(0, extra_args=[f"-datacarriersize={LARGE_VSIZE}"])
230+
231+
# Ensure the mempool is empty
232+
assert_equal(len(self.nodes[0].getrawmempool()), 0)
233+
234+
# Generate UTXOs and send 10 large transactions with a high fee rate
235+
utxos = [self.wallet.get_utxo(confirmed_only=True) for _ in range(LARGE_TXS_COUNT + 4)] # Add 4 more utxos that will be used in the test later
236+
self.send_transactions(utxos[:LARGE_TXS_COUNT], HIGH_FEERATE, LARGE_VSIZE)
237+
238+
# Send 2 normal transactions with a lower fee rate
239+
NORMAL_VSIZE = int(2000 / WITNESS_SCALE_FACTOR)
240+
NORMAL_FEERATE = Decimal("0.0001")
241+
self.send_transactions(utxos[LARGE_TXS_COUNT:LARGE_TXS_COUNT + 2], NORMAL_FEERATE, NORMAL_VSIZE)
242+
243+
# Check that the mempool contains all transactions
244+
self.log.info(f"Testing that the mempool contains {LARGE_TXS_COUNT + 2} transactions.")
245+
assert_equal(len(self.nodes[0].getrawmempool()), LARGE_TXS_COUNT + 2)
246+
247+
# Verify the block template includes only the 10 high-fee transactions
248+
self.log.info("Testing that the block template includes only the 10 large transactions.")
249+
self.verify_block_template(
250+
expected_tx_count=LARGE_TXS_COUNT,
251+
expected_weight=MAX_BLOCK_WEIGHT - DEFAULT_BLOCK_RESERVED_WEIGHT,
252+
)
253+
254+
# Test block template creation with custom -blockmaxweight
255+
custom_block_weight = MAX_BLOCK_WEIGHT - 2000
256+
# Reducing the weight by 2000 units will prevent 1 large transaction from fitting into the block.
257+
self.restart_node(0, extra_args=[f"-datacarriersize={LARGE_VSIZE}", f"-blockmaxweight={custom_block_weight}"])
258+
259+
self.log.info("Testing the block template with custom -blockmaxweight to include 9 large and 2 normal transactions.")
260+
self.verify_block_template(
261+
expected_tx_count=11,
262+
expected_weight=MAX_BLOCK_WEIGHT - DEFAULT_BLOCK_RESERVED_WEIGHT - 2000,
263+
)
264+
265+
# Ensure the block weight does not exceed the maximum
266+
self.log.info(f"Testing that the block weight will never exceed {MAX_BLOCK_WEIGHT - DEFAULT_BLOCK_RESERVED_WEIGHT}.")
267+
self.restart_node(0, extra_args=[f"-datacarriersize={LARGE_VSIZE}", f"-blockmaxweight={MAX_BLOCK_WEIGHT}"])
268+
self.log.info("Sending 2 additional normal transactions to fill the mempool to the maximum block weight.")
269+
self.send_transactions(utxos[LARGE_TXS_COUNT + 2:], NORMAL_FEERATE, NORMAL_VSIZE)
270+
self.log.info(f"Testing that the mempool's weight matches the maximum block weight: {MAX_BLOCK_WEIGHT}.")
271+
assert_equal(self.nodes[0].getmempoolinfo()['bytes'] * WITNESS_SCALE_FACTOR, MAX_BLOCK_WEIGHT)
272+
273+
self.log.info("Testing that the block template includes only 10 transactions and cannot reach full block weight.")
274+
self.verify_block_template(
275+
expected_tx_count=LARGE_TXS_COUNT,
276+
expected_weight=MAX_BLOCK_WEIGHT - DEFAULT_BLOCK_RESERVED_WEIGHT,
277+
)
278+
279+
197280
def run_test(self):
198281
node = self.nodes[0]
199282
self.wallet = MiniWallet(node)
@@ -419,6 +502,7 @@ def chain_tip(b_hash, *, status='headers-only', branchlen=1):
419502
assert_equal(node.submitblock(hexdata=block.serialize().hex()), 'duplicate') # valid
420503

421504
self.test_blockmintxfee_parameter()
505+
self.test_block_max_weight()
422506
self.test_timewarp()
423507
self.test_pruning()
424508

0 commit comments

Comments
 (0)