/ src / bench / wallet_migration.cpp
wallet_migration.cpp
 1  // Copyright (c) 2024 The Bitcoin Core developers
 2  // Distributed under the MIT software license, see the accompanying
 3  // file COPYING or https://www.opensource.org/licenses/mit-license.php.
 4  
 5  #include <bench/bench.h>
 6  #include <interfaces/chain.h>
 7  #include <interfaces/wallet.h>
 8  #include <kernel/chain.h>
 9  #include <node/context.h>
10  #include <test/util/mining.h>
11  #include <test/util/setup_common.h>
12  #include <wallet/context.h>
13  #include <wallet/receive.h>
14  #include <wallet/test/util.h>
15  #include <wallet/wallet.h>
16  
17  #include <optional>
18  
19  namespace wallet{
20  
21  static void WalletMigration(benchmark::Bench& bench)
22  {
23      const auto test_setup{MakeNoLogFileContext<TestingSetup>()};
24      const auto loader{MakeWalletLoader(*test_setup->m_node.chain, test_setup->m_args)};
25  
26      // Number of imported watch only addresses
27      int NUM_WATCH_ONLY_ADDR = 20;
28  
29      // Setup legacy wallet
30      std::unique_ptr<CWallet> wallet = std::make_unique<CWallet>(test_setup->m_node.chain.get(), "", CreateMockableWalletDatabase());
31      LegacyDataSPKM* legacy_spkm = wallet->GetOrCreateLegacyDataSPKM();
32      WalletBatch batch{wallet->GetDatabase()};
33  
34      // Write a best block record as migration expects one to exist
35      CBlockLocator loc;
36      batch.WriteBestBlock(loc);
37  
38      // Add watch-only addresses
39      std::vector<CScript> scripts_watch_only;
40      for (int w = 0; w < NUM_WATCH_ONLY_ADDR; ++w) {
41          CKey key = GenerateRandomKey();
42          LOCK(wallet->cs_wallet);
43          const PKHash dest{key.GetPubKey()};
44          const CScript& script = scripts_watch_only.emplace_back(GetScriptForDestination(dest));
45          assert(legacy_spkm->LoadWatchOnly(script));
46          assert(wallet->SetAddressBook(dest, strprintf("watch_%d", w), /*purpose=*/std::nullopt));
47          batch.WriteWatchOnly(script, CKeyMetadata());
48      }
49  
50      // Generate transactions and local addresses
51      for (int j = 0; j < 500; ++j) {
52          CKey key = GenerateRandomKey();
53          CPubKey pubkey = key.GetPubKey();
54          // Load key, scripts and create address book record
55          Assert(legacy_spkm->LoadKey(key, pubkey));
56          CTxDestination dest{PKHash(pubkey)};
57          Assert(wallet->SetAddressBook(dest, strprintf("legacy_%d", j), /*purpose=*/std::nullopt));
58  
59          CMutableTransaction mtx;
60          mtx.vout.emplace_back(COIN, GetScriptForDestination(dest));
61          mtx.vout.emplace_back(COIN, scripts_watch_only.at(j % NUM_WATCH_ONLY_ADDR));
62          mtx.vin.resize(2);
63          wallet->AddToWallet(MakeTransactionRef(mtx), TxStateInactive{}, /*update_wtx=*/nullptr, /*rescanning_old_block=*/true);
64          batch.WriteKey(pubkey, key.GetPrivKey(), CKeyMetadata());
65      }
66  
67      bench.epochs(/*numEpochs=*/1).epochIterations(/*numIters=*/1) // run the migration exactly once
68           .run([&] {
69               auto res{MigrateLegacyToDescriptor(std::move(wallet), /*passphrase=*/"", *loader->context())};
70               assert(res);
71               assert(res->wallet);
72               assert(res->watchonly_wallet);
73           });
74  }
75  
76  BENCHMARK(WalletMigration, benchmark::PriorityLevel::LOW);
77  
78  } // namespace wallet