wallet_encrypt.cpp
1 // Copyright (c) 2025-present 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 <key_io.h> 7 #include <outputtype.h> 8 #include <random.h> 9 #include <support/allocators/secure.h> 10 #include <test/util/setup_common.h> 11 #include <util/time.h> 12 #include <wallet/context.h> 13 #include <wallet/test/util.h> 14 #include <wallet/wallet.h> 15 #include <wallet/walletutil.h> 16 17 #include <cassert> 18 19 namespace wallet { 20 static void WalletEncrypt(benchmark::Bench& bench, unsigned int key_count) 21 { 22 auto test_setup = MakeNoLogFileContext<TestingSetup>(); 23 FastRandomContext rand{/*fDeterministic=*/true}; 24 25 auto password{rand.randbytes(20)}; 26 SecureString secure_pass{password.begin(), password.end()}; 27 28 WalletContext context; 29 context.args = &test_setup->m_args; 30 context.chain = test_setup->m_node.chain.get(); 31 32 uint64_t create_flags = WALLET_FLAG_DESCRIPTORS; 33 auto database = CreateMockableWalletDatabase(); 34 auto wallet = TestCreateWallet(std::move(database), context, create_flags); 35 36 { 37 LOCK(wallet->cs_wallet); 38 for (unsigned int i = 0; i < key_count; i++) { 39 CKey key = GenerateRandomKey(); 40 FlatSigningProvider keys; 41 std::string error; 42 std::vector<std::unique_ptr<Descriptor>> desc = Parse("combo(" + EncodeSecret(key) + ")", keys, error, /*require_checksum=*/false); 43 WalletDescriptor w_desc(std::move(desc.at(0)), /*creation_time=*/0, /*range_start=*/0, /*range_end=*/0, /*next_index=*/0); 44 Assert(wallet->AddWalletDescriptor(w_desc, keys, /*label=*/"", /*internal=*/false)); 45 } 46 } 47 48 database = DuplicateMockDatabase(wallet->GetDatabase()); 49 50 // reload the wallet for the actual benchmark 51 TestUnloadWallet(std::move(wallet)); 52 53 // Setting a mock time is necessary to force default derive iteration count during 54 // wallet encryption. 55 SetMockTime(1); 56 57 // This benchmark has a lot of overhead, this should be good enough to catch 58 // any regressions, but for an accurate measurement of how long wallet 59 // encryption takes, this should be reworked after something like 60 // https://github.com/bitcoin/bitcoin/pull/34208 is merged. 61 bench.batch(key_count).unit("key").run([&] { 62 wallet = TestLoadWallet(std::move(database), context); 63 64 // Save a copy of the db before encrypting 65 database = DuplicateMockDatabase(wallet->GetDatabase()); 66 67 wallet->EncryptWallet(secure_pass); 68 69 for (const auto& [_, key] : wallet->mapMasterKeys){ 70 assert(key.nDeriveIterations == CMasterKey::DEFAULT_DERIVE_ITERATIONS); 71 } 72 73 TestUnloadWallet(std::move(wallet)); 74 }); 75 } 76 77 constexpr unsigned int KEY_COUNT = 2000; 78 79 static void WalletEncryptDescriptors(benchmark::Bench& bench) { WalletEncrypt(bench, /*key_count=*/KEY_COUNT); } 80 BENCHMARK(WalletEncryptDescriptors); 81 82 } // namespace wallet