mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-12-08 19:53:27 +01:00
Merge bitcoin/bitcoin#30125: test: improve BDB parser (handle internal/overflow pages, support all page sizes)
d45eb3964ftest: compare BDB dumps of test framework parser and wallet tool (Sebastian Falbesoner)01ddd9f646test: complete BDB parser (handle internal/overflow pages, support all page sizes) (Sebastian Falbesoner) Pull request description: This PR adds missing features to our test framework's BDB parser with the goal of hopefully being able to read all legacy wallets that are created with current and past versions of Bitcoin Core. This could be useful both for making review of https://github.com/bitcoin/bitcoin/pull/26606 easier and to also possibly improve our functional tests for the wallet BDB-ro parser by additionally validating it with an alternative implementation. The second commits introduces a test that create a legacy wallet with huge label strings (in order to create overflow pages, i.e. pages needed for key/value data than is larger than the page size) and compares the dump outputs of wallet tool and the extended test framework BDB parser. It can be exercised via `$ ./test/functional/tool_wallet.py --legacy`. BDB support has to be compiled in (obviously). For some manual tests regarding different page sizes, the following patch can be used: ```diff diff --git a/src/wallet/bdb.cpp b/src/wallet/bdb.cpp index 38cca32f80..1bf39323d3 100644 --- a/src/wallet/bdb.cpp +++ b/src/wallet/bdb.cpp @@ -395,6 +395,7 @@ void BerkeleyDatabase::Open() DB_BTREE, // Database type nFlags, // Flags 0); + pdb_temp->set_pagesize(1<<9); /* valid BDB pagesizes are from 1<<9 (=512) to <<16 (=65536) */ if (ret != 0) { throw std::runtime_error(strprintf("BerkeleyDatabase: Error %d, can't open database %s", ret, strFile)); ``` I verified that the newly introduced test passes with all valid page sizes between 512 and 65536. ACKs for top commit: achow101: ACKd45eb3964ffurszy: utACKd45eb3964fbrunoerg: code review ACKd45eb3964fTree-SHA512: 9f8ac80452545f4fcd24a17ea6f9cf91b487cfb1fcb99a0ba9153fa4e3b239daa126454e26109fdcb72eb1c76a4ee3b46fd6af21dc318ab67bd12b3ebd26cfdd
This commit is contained in:
@@ -6,18 +6,23 @@
|
||||
|
||||
import os
|
||||
import platform
|
||||
import random
|
||||
import stat
|
||||
import string
|
||||
import subprocess
|
||||
import textwrap
|
||||
|
||||
from collections import OrderedDict
|
||||
|
||||
from test_framework.bdb import dump_bdb_kv
|
||||
from test_framework.messages import ser_string
|
||||
from test_framework.test_framework import BitcoinTestFramework
|
||||
from test_framework.util import (
|
||||
assert_equal,
|
||||
assert_greater_than,
|
||||
sha256sum_file,
|
||||
)
|
||||
from test_framework.wallet import getnewdestination
|
||||
|
||||
|
||||
class ToolWalletTest(BitcoinTestFramework):
|
||||
@@ -545,6 +550,44 @@ class ToolWalletTest(BitcoinTestFramework):
|
||||
self.stop_node(0)
|
||||
self.assert_tool_output("The dumpfile may contain private keys. To ensure the safety of your Bitcoin, do not share the dumpfile.\n", "-wallet=unclean_lsn", f"-dumpfile={wallet_dump}", "dump")
|
||||
|
||||
def test_compare_legacy_dump_with_framework_bdb_parser(self):
|
||||
self.log.info("Verify that legacy wallet database dump matches the one from the test framework's BDB parser")
|
||||
wallet_name = "bdb_ro_test"
|
||||
self.start_node(0)
|
||||
# add some really large labels (above twice the largest valid page size) to create BDB overflow pages
|
||||
self.nodes[0].createwallet(wallet_name)
|
||||
wallet_rpc = self.nodes[0].get_wallet_rpc(wallet_name)
|
||||
generated_labels = {}
|
||||
for i in range(10):
|
||||
address = getnewdestination()[2]
|
||||
large_label = ''.join([random.choice(string.ascii_letters) for _ in range(150000)])
|
||||
wallet_rpc.setlabel(address, large_label)
|
||||
generated_labels[address] = large_label
|
||||
# fill the keypool to create BDB internal pages
|
||||
wallet_rpc.keypoolrefill(1000)
|
||||
self.stop_node(0)
|
||||
|
||||
wallet_dumpfile = self.nodes[0].datadir_path / "bdb_ro_test.dump"
|
||||
self.assert_tool_output("The dumpfile may contain private keys. To ensure the safety of your Bitcoin, do not share the dumpfile.\n", "-wallet={}".format(wallet_name), "-dumpfile={}".format(wallet_dumpfile), "dump")
|
||||
|
||||
expected_dump = self.read_dump(wallet_dumpfile)
|
||||
# remove extra entries from wallet tool dump that are not actual key/value pairs from the database
|
||||
del expected_dump['BITCOIN_CORE_WALLET_DUMP']
|
||||
del expected_dump['format']
|
||||
del expected_dump['checksum']
|
||||
bdb_ro_parser_dump_raw = dump_bdb_kv(self.nodes[0].wallets_path / wallet_name / "wallet.dat")
|
||||
bdb_ro_parser_dump = OrderedDict()
|
||||
assert any([len(bytes.fromhex(value)) >= 150000 for value in expected_dump.values()])
|
||||
for key, value in sorted(bdb_ro_parser_dump_raw.items()):
|
||||
bdb_ro_parser_dump[key.hex()] = value.hex()
|
||||
assert_equal(bdb_ro_parser_dump, expected_dump)
|
||||
|
||||
# check that all labels were created with the correct address
|
||||
for address, label in generated_labels.items():
|
||||
key_bytes = b'\x04name' + ser_string(address.encode())
|
||||
assert key_bytes in bdb_ro_parser_dump_raw
|
||||
assert_equal(bdb_ro_parser_dump_raw[key_bytes], ser_string(label.encode()))
|
||||
|
||||
def run_test(self):
|
||||
self.wallet_path = self.nodes[0].wallets_path / self.default_wallet_name / self.wallet_data_filename
|
||||
self.test_invalid_tool_commands_and_args()
|
||||
@@ -561,6 +604,9 @@ class ToolWalletTest(BitcoinTestFramework):
|
||||
self.test_dump_createfromdump()
|
||||
self.test_chainless_conflicts()
|
||||
self.test_dump_very_large_records()
|
||||
if not self.options.descriptors and self.is_bdb_compiled() and not self.options.swap_bdb_endian:
|
||||
self.test_compare_legacy_dump_with_framework_bdb_parser()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
ToolWalletTest(__file__).main()
|
||||
|
||||
Reference in New Issue
Block a user