Skip to content

Commit 8a373a5

Browse files
committed
Merge bitcoin/bitcoin#27191: blockstorage: Adjust fastprune limit if block exceeds blockfile size
8f14fc8 test: cover fastprune with excessive block size (Matthew Zipkin) 271c23e blockstorage: Adjust fastprune limit if block exceeds blockfile size (Martin Zumsande) Pull request description: The debug-only `-fastprune` option used in several tests is not always safe to use: If a `-fastprune` node receives a block larger than the maximum blockfile size of `64kb` bad things happen: The while loop in `BlockManager::FindBlockPos` never terminates, and the node runs oom because memory for `m_blockfile_info` is allocated in each iteration of the loop. The same would happen if a naive user used `-fastprune` on anything other than regtest (so this can be tested by syncing on signet for example, the first block that crashes the node is at height 2232). Change the approach by raising the blockfile size to the size of the block, if that block otherwise wouldn't fit (idea by TheCharlatan). ACKs for top commit: ryanofsky: Code review ACK 8f14fc8. Added new assert, test, and comment since last review TheCharlatan: ACK 8f14fc8 pinheadmz: ACK 8f14fc8 Tree-SHA512: df2fea30613ef9d40ebbc2416eacb574f6d7d96847db5c33dda22a29a2c61a8db831aa9552734ea4477e097f253dbcb6dcb1395d43d2a090cc0588c9ce66eac3
2 parents be0325c + 8f14fc8 commit 8a373a5

File tree

3 files changed

+55
-1
lines changed

3 files changed

+55
-1
lines changed

src/node/blockstorage.cpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -620,7 +620,18 @@ bool BlockManager::FindBlockPos(FlatFilePos& pos, unsigned int nAddSize, unsigne
620620

621621
bool finalize_undo = false;
622622
if (!fKnown) {
623-
while (m_blockfile_info[nFile].nSize + nAddSize >= (gArgs.GetBoolArg("-fastprune", false) ? 0x10000 /* 64kb */ : MAX_BLOCKFILE_SIZE)) {
623+
unsigned int max_blockfile_size{MAX_BLOCKFILE_SIZE};
624+
// Use smaller blockfiles in test-only -fastprune mode - but avoid
625+
// the possibility of having a block not fit into the block file.
626+
if (gArgs.GetBoolArg("-fastprune", false)) {
627+
max_blockfile_size = 0x10000; // 64kiB
628+
if (nAddSize >= max_blockfile_size) {
629+
// dynamically adjust the blockfile size to be larger than the added size
630+
max_blockfile_size = nAddSize + 1;
631+
}
632+
}
633+
assert(nAddSize < max_blockfile_size);
634+
while (m_blockfile_info[nFile].nSize + nAddSize >= max_blockfile_size) {
624635
// when the undo file is keeping up with the block file, we want to flush it explicitly
625636
// when it is lagging behind (more blocks arrive than are being connected), we let the
626637
// undo block write case handle it

test/functional/feature_fastprune.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#!/usr/bin/env python3
2+
# Copyright (c) 2023 The Bitcoin Core developers
3+
# Distributed under the MIT software license, see the accompanying
4+
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
5+
"""Test fastprune mode."""
6+
from test_framework.test_framework import BitcoinTestFramework
7+
from test_framework.util import (
8+
assert_equal
9+
)
10+
from test_framework.blocktools import (
11+
create_block,
12+
create_coinbase,
13+
add_witness_commitment
14+
)
15+
from test_framework.wallet import MiniWallet
16+
17+
18+
class FeatureFastpruneTest(BitcoinTestFramework):
19+
def set_test_params(self):
20+
self.num_nodes = 1
21+
self.extra_args = [["-fastprune"]]
22+
23+
def run_test(self):
24+
self.log.info("ensure that large blocks don't crash or freeze in -fastprune")
25+
wallet = MiniWallet(self.nodes[0])
26+
tx = wallet.create_self_transfer()['tx']
27+
annex = [0x50]
28+
for _ in range(0x10000):
29+
annex.append(0xff)
30+
tx.wit.vtxinwit[0].scriptWitness.stack.append(bytes(annex))
31+
tip = int(self.nodes[0].getbestblockhash(), 16)
32+
time = self.nodes[0].getblock(self.nodes[0].getbestblockhash())['time'] + 1
33+
height = self.nodes[0].getblockcount() + 1
34+
block = create_block(hashprev=tip, ntime=time, txlist=[tx], coinbase=create_coinbase(height=height))
35+
add_witness_commitment(block)
36+
block.solve()
37+
self.nodes[0].submitblock(block.serialize().hex())
38+
assert_equal(int(self.nodes[0].getbestblockhash(), 16), block.sha256)
39+
40+
41+
if __name__ == '__main__':
42+
FeatureFastpruneTest().main()

test/functional/test_runner.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,7 @@
320320
'feature_includeconf.py',
321321
'feature_addrman.py',
322322
'feature_asmap.py',
323+
'feature_fastprune.py',
323324
'mempool_unbroadcast.py',
324325
'mempool_compatibility.py',
325326
'mempool_accept_wtxid.py',

0 commit comments

Comments
 (0)