Skip to content

Conversation

w0xlt
Copy link
Contributor

@w0xlt w0xlt commented Aug 13, 2025

This PR adds test coverage for migrating legacy Bitcoin Core wallets from v0.14.3 (released in 2017) to the descriptor wallet format. The test validates that users can safely upgrade their wallets while preserving all funds, transaction history, and addresses.

This test was originally developed on top of #32977, as it was requested in reviews.
However, since it also increases test coverage, it can be merged independently.

The test covers two wallet migration scenarios:

  • Non-HD Wallet Migration - Tests migration of non-HD wallets (created with -usehd=0)
  • Single Chain HD Wallet Migration - Tests migration of HD wallets from v0.14.3 (VERSION_HD_BASE)

The node v0.14.3 cannot be synced because it doesn't have the syncwithvalidationinterfacequeue RPC implemented (required by test_framework.py), so the solution is to copy the block folder to the modern node and start it with -reindex-chainstate. Because of this additional complexity, this testing is best managed in a separate file rather than in the existing migration test files.

@DrahtBot
Copy link
Contributor

DrahtBot commented Aug 13, 2025

The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

Code Coverage & Benchmarks

For details see: https://corecheck.dev/bitcoin/bitcoin/pulls/33186.

Reviews

See the guideline for information on the review process.

Type Reviewers
Concept ACK pablomartin4btc

If your review is incorrectly listed, please react with 👎 to this comment and the bot will ignore it on the next update.

@DrahtBot
Copy link
Contributor

🚧 At least one of the CI tasks failed.
Task lint: https://github.com/bitcoin/bitcoin/runs/48028643718
LLM reason (✨ experimental): The CI failure is caused by a lint error due to trailing whitespace in the code.

Hints

Try to run the tests locally, according to the documentation. However, a CI failure may still
happen due to a number of reasons, for example:

  • Possibly due to a silent merge conflict (the changes in this pull request being
    incompatible with the current code in the target branch). If so, make sure to rebase on the latest
    commit of the target branch.

  • A sanitizer issue, which can only be found by compiling with the sanitizer and running the
    affected test.

  • An intermittent issue.

Leave a comment here, if you need help tracking down a confusing failure.

@w0xlt w0xlt force-pushed the test_no_or_base_hd_wallet_migration branch 2 times, most recently from 0116ce0 to 5237377 Compare August 13, 2025 19:08
@w0xlt w0xlt force-pushed the test_no_or_base_hd_wallet_migration branch from 5237377 to 3b1b154 Compare August 13, 2025 19:12

# Setup fresh nodes for this test
self.add_nodes(
2,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
2,
self.num_nodes,

Copy link
Member

@pablomartin4btc pablomartin4btc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Concept ACK

Left a couple of suggestions.

@@ -428,7 +429,12 @@ def main():
logging.basicConfig(format='%(message)s', level=logging_level)

# Create base test directory
tmpdir = "%s/test_runner_₿_🏃_%s" % (args.tmpdirprefix, datetime.datetime.now().strftime("%Y%m%d_%H%M%S"))
# Special case for tests using old binaries (e.g. version v0.14.3) that don't handle Unicode on Windows
has_migration_tests = any('wallet_ancient_migration' in script for script in BASE_SCRIPTS)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

more than has_migration_tests shouldn't indicate like it's an old binary? (there are other tests that uses migration and feature_unsupported_utxo_db.py uses a node v0.14.3 as well)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without this, the Windows, test cross-built CI task will fail because it can't handle non-ASCII characters in -datadir.

feature_unsupported_utxo_db.py doesn't copy the directory from one node to another. This test needs to do this because version 0.14.3 doesn't have the syncwithvalidationinterfacequeue RPC, so it can't be synchronized.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, it's already well explained in the PR description. Then perhaps the variable name could be supports_unicode_datadir/ (requires_ascii_datadir) or something like that.

Suggested change
has_migration_tests = any('wallet_ancient_migration' in script for script in BASE_SCRIPTS)
requires_ascii_datadir = any('wallet_ancient_migration' in script for script in BASE_SCRIPTS)
tmpdirprefix = "%s/test_runner_₿_🏃_%s"
if platform.system() == 'Windows' and requires_ascii_datadir:
tmpdir = "%s/test_runner_btc_run_%s"
tmpdir = tmpdirprefix % (args.tmpdirprefix, datetime.datetime.now().strftime("%Y%m%d_%H%M%S"))

Wouldn't this affect the datadir for all the tests running on Windows platform?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the suggestion. It's much clearer.
Yes, it affects all tests run on the Windows platform. As far as I know, there's no way to filter by this task specifically.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

feature_unsupported_utxo_db.py doesn't copy the directory from one node to another. This test needs to do this because version 0.14.3 doesn't have the syncwithvalidationinterfacequeue RPC, so it can't be synchronized.

What's the error message? It seems odd that one test works fine with unicode and the other does not. See also the suggestion https://github.com/bitcoin/bitcoin/pull/33186/files#r2281561637

Comment on lines +134 to +167
# Stop the old node
self.log.info("Stopping old node...")
self.stop_node(0)

# Copy blockchain data from node0 to node1
self.log.info("Copying blockchain data from old node to modern node...")
old_blocks_dir = os.path.join(node0_datadir, self.chain, "blocks")
new_blocks_dir = os.path.join(node1_datadir, self.chain, "blocks")

# Clean up any existing blocks directory in node1
if os.path.exists(new_blocks_dir):
shutil.rmtree(new_blocks_dir)

if os.path.exists(old_blocks_dir):
shutil.copytree(old_blocks_dir, new_blocks_dir)
self.log.info(" Copied blocks directory")
assert(os.path.exists(new_blocks_dir))

# Start the modern node with -reindex-chainstate
self.log.info("Starting modern node with -reindex-chainstate...")
self.start_node(1, extra_args=["-reindex-chainstate"])

# Wait for reindex to complete
self.log.info("Waiting for chainstate reindex to complete...")
self.wait_until(
lambda: self.nodes[1].getblockcount() == 102,
timeout=30
)

# Verify the blockchain was loaded correctly
node1_info = self.nodes[1].getblockchaininfo()
self.log.info(f"Modern node blockchain info: height={node1_info['blocks']}")
assert_equal(node1_info['blocks'], 102)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you may be able to skip this by using dumb_sync_blocks from c847dee#diff-e48d83ef13f93a84b5686eb797eeed80dd194cf39db7f2972cf82a5ed25415a7L78-L95

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants