Skip to content

Commit e5a00b2

Browse files
committed
Merge bitcoin/bitcoin#32309: bench: close wallets after migration
cad39f8 bench: ensure wallet migration benchmark runs exactly once (Lőrinc) c1f458a ci: re-enable all benchmark runs (Lőrinc) 1da11db bench: clean up migrated descriptor wallets via loader teardown (Lőrinc) Pull request description: The low-priority `WalletMigration` benchmark existed for some time but was never run automatically in our CI. Although the failure first surfaced on Windows as a hang during temporary directory cleanup, it could also be reproduced on Linux and macOS when forcing multiple iterations (e.g. via a long `--min-time`). ### Root causes 1. **Leaked open wallets on Windows** `MigrateLegacyToDescriptor` produces two new descriptor wallets (the primary spendable wallet and a companion watch‑only wallet). Without unloading them, their database files remained open in the `WalletContext`, blocking directory removal and hanging the test harness. <details><summary>Details</summary> ```bash what(): filesystem error: cannot remove all: The process cannot access the file because it is being used by another process [C:\Users\RUNNER\~1\AppData\Local\Temp\test_common bitcoin\WalletMigration\d8ffd89a7700ce01c31f] [C:\Users\RUNNER~1\AppData\Local\Temp\test_common bitcoin\WalletMigration\d8ffd89a7700ce01c31f\regtest\wallet.dat] ``` </details> 2. **Undefined behavior on repeated runs** The benchmark body calls `std::move(wallet)`, invalidating the local `wallet` pointer. Running more than one iteration causes a use-after-move by the sanitizers. <details><summary>Details</summary> ```bash error: bench_bitcoin 0x00067927: DW_TAG_member '_M_local_buf' refers to type 0x00000000000b3ba7 which extends beyond the bounds of 0x0006791d * thread #1, name = 'b-test', stop reason = signal SIGSEGV: address not mapped to object (fault address: 0xc8) * frame #0: 0x00005555556a3f33 bench_bitcoin`... basic_string<char>::length(this=<unavailable>) const at basic_string.h:1079:16 ``` </details> ### Fixes - **Automatic wallet teardown** Wrap the benchmark in a `MakeWalletLoader` (owning a `WalletContext`), so that both migrated wallets are unloaded when the loader goes out of scope, eliminating any lingering open files. - **Re-enable benchmarks in CI** Drop the temporary filter in GitHub Actions. The `-sanity-check` run already executes each benchmark once, so `WalletMigration` now runs automatically without hangs or crashes. - **Single iteration** Configure the microbenchmark with `.epochs(1).epochIterations(1)`, ensuring the migration code runs exactly once and avoiding use-after-move. No measurable change in benchmark performance. ACKs for top commit: maflcko: review ACK cad39f8 🍥 furszy: utACK cad39f8 hebasto: ACK cad39f8, tested on Ubuntu 25.04. Tree-SHA512: 10343ce7ab9b63ba4f51a7673018215577ea7ec188e41d535a66d69d73b85bca6ba301c33f6920c02f8f7d686c75c65c4a4e9bdafb04b60be85d66aa743cfa20
2 parents 8406a9f + cad39f8 commit e5a00b2

File tree

2 files changed

+13
-15
lines changed

2 files changed

+13
-15
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -358,8 +358,7 @@ jobs:
358358
./src/univalue/unitester.exe
359359
360360
- name: Run benchmarks
361-
# TODO: Fix the `WalletMigration` benchmark and re-enable it.
362-
run: ./bin/bench_bitcoin.exe -sanity-check -filter='^(?!WalletMigration$).+$'
361+
run: ./bin/bench_bitcoin.exe -sanity-check
363362

364363
- name: Adjust paths in test/config.ini
365364
shell: pwsh

src/bench/wallet_migration.cpp

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,15 @@
33
// file COPYING or https://www.opensource.org/licenses/mit-license.php.
44

55
#include <bench/bench.h>
6-
#include <kernel/chain.h>
76
#include <interfaces/chain.h>
7+
#include <interfaces/wallet.h>
8+
#include <kernel/chain.h>
89
#include <node/context.h>
910
#include <test/util/mining.h>
1011
#include <test/util/setup_common.h>
11-
#include <wallet/test/util.h>
1212
#include <wallet/context.h>
1313
#include <wallet/receive.h>
14+
#include <wallet/test/util.h>
1415
#include <wallet/wallet.h>
1516

1617
#include <optional>
@@ -19,11 +20,8 @@ namespace wallet{
1920

2021
static void WalletMigration(benchmark::Bench& bench)
2122
{
22-
const auto test_setup = MakeNoLogFileContext<TestingSetup>();
23-
24-
WalletContext context;
25-
context.args = &test_setup->m_args;
26-
context.chain = test_setup->m_node.chain.get();
23+
const auto test_setup{MakeNoLogFileContext<TestingSetup>()};
24+
const auto loader{MakeWalletLoader(*test_setup->m_node.chain, test_setup->m_args)};
2725

2826
// Number of imported watch only addresses
2927
int NUM_WATCH_ONLY_ADDR = 20;
@@ -63,12 +61,13 @@ static void WalletMigration(benchmark::Bench& bench)
6361
batch.WriteKey(pubkey, key.GetPrivKey(), CKeyMetadata());
6462
}
6563

66-
bench.epochs(/*numEpochs=*/1).run([&context, &wallet] {
67-
util::Result<MigrationResult> res = MigrateLegacyToDescriptor(std::move(wallet), /*passphrase=*/"", context, /*was_loaded=*/false);
68-
assert(res);
69-
assert(res->wallet);
70-
assert(res->watchonly_wallet);
71-
});
64+
bench.epochs(/*numEpochs=*/1).epochIterations(/*numIters=*/1) // run the migration exactly once
65+
.run([&] {
66+
auto res{MigrateLegacyToDescriptor(std::move(wallet), /*passphrase=*/"", *loader->context(), /*was_loaded=*/false)};
67+
assert(res);
68+
assert(res->wallet);
69+
assert(res->watchonly_wallet);
70+
});
7271
}
7372

7473
BENCHMARK(WalletMigration, benchmark::PriorityLevel::LOW);

0 commit comments

Comments
 (0)