// Copyright (c) 2021-present The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include #include #include #include #include #include #include #include #include #include #include #include namespace wallet { std::unique_ptr CreateSyncedWallet(interfaces::Chain& chain, CChain& cchain, const CKey& key) { auto wallet = std::make_unique(&chain, "", CreateMockableWalletDatabase()); { LOCK2(wallet->cs_wallet, ::cs_main); wallet->SetLastBlockProcessed(cchain.Height(), cchain.Tip()->GetBlockHash()); } { LOCK(wallet->cs_wallet); wallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS); wallet->SetupDescriptorScriptPubKeyMans(); FlatSigningProvider provider; std::string error; auto descs = Parse("combo(" + EncodeSecret(key) + ")", provider, error, /* require_checksum=*/ false); assert(descs.size() == 1); auto& desc = descs.at(0); WalletDescriptor w_desc(std::move(desc), 0, 0, 1, 1); Assert(wallet->AddWalletDescriptor(w_desc, provider, "", false)); } WalletRescanReserver reserver(*wallet); reserver.reserve(); CWallet::ScanResult result = wallet->ScanForWalletTransactions(cchain.Genesis()->GetBlockHash(), /*start_height=*/0, /*max_height=*/{}, reserver, /*fUpdate=*/false, /*save_progress=*/false); assert(result.status == CWallet::ScanResult::SUCCESS); assert(result.last_scanned_block == cchain.Tip()->GetBlockHash()); assert(*result.last_scanned_height == cchain.Height()); assert(result.last_failed_block.IsNull()); return wallet; } std::shared_ptr TestCreateWallet(std::unique_ptr database, WalletContext& context, uint64_t create_flags) { bilingual_str _error; std::vector _warnings; auto wallet = CWallet::CreateNew(context, "", std::move(database), create_flags, _error, _warnings); NotifyWalletLoaded(context, wallet); if (context.chain) { wallet->postInitProcess(); } return wallet; } std::shared_ptr TestCreateWallet(WalletContext& context) { DatabaseOptions options; options.require_create = true; options.create_flags = WALLET_FLAG_DESCRIPTORS; DatabaseStatus status; bilingual_str error; std::vector warnings; auto database = MakeWalletDatabase("", options, status, error); return TestCreateWallet(std::move(database), context, options.create_flags); } std::shared_ptr TestLoadWallet(std::unique_ptr database, WalletContext& context) { bilingual_str error; std::vector warnings; auto wallet = CWallet::LoadExisting(context, "", std::move(database), error, warnings); NotifyWalletLoaded(context, wallet); if (context.chain) { wallet->postInitProcess(); } return wallet; } std::shared_ptr TestLoadWallet(WalletContext& context) { DatabaseOptions options; options.require_existing = true; DatabaseStatus status; bilingual_str error; std::vector warnings; auto database = MakeWalletDatabase("", options, status, error); return TestLoadWallet(std::move(database), context); } void TestUnloadWallet(std::shared_ptr&& wallet) { // Calls SyncWithValidationInterfaceQueue wallet->chain().waitForNotificationsIfTipChanged({}); wallet->m_chain_notifications_handler.reset(); WaitForDeleteWallet(std::move(wallet)); } std::unique_ptr DuplicateMockDatabase(WalletDatabase& database) { std::unique_ptr batch_orig = database.MakeBatch(); std::unique_ptr cursor_orig = batch_orig->GetNewCursor(); std::unique_ptr new_db = CreateMockableWalletDatabase(); std::unique_ptr new_db_batch = new_db->MakeBatch(); MockableSQLiteBatch* batch_new = dynamic_cast(new_db_batch.get()); Assert(batch_new); while (true) { DataStream key, value; DatabaseCursor::Status status = cursor_orig->Next(key, value); Assert(status != DatabaseCursor::Status::FAIL); if (status != DatabaseCursor::Status::MORE) break; batch_new->WriteKey(std::move(key), std::move(value)); } return new_db; } std::string getnewaddress(CWallet& w) { constexpr auto output_type = OutputType::BECH32; return EncodeDestination(getNewDestination(w, output_type)); } CTxDestination getNewDestination(CWallet& w, OutputType output_type) { return *Assert(w.GetNewDestination(output_type, "")); } MockableSQLiteDatabase::MockableSQLiteDatabase() : SQLiteDatabase(fs::PathFromString("mock/"), fs::PathFromString("mock/wallet.dat"), DatabaseOptions(), SQLITE_OPEN_MEMORY) {} std::unique_ptr CreateMockableWalletDatabase() { return std::make_unique(); } wallet::DescriptorScriptPubKeyMan* CreateDescriptor(CWallet& keystore, const std::string& desc_str, const bool success) { keystore.SetWalletFlag(WALLET_FLAG_DESCRIPTORS); FlatSigningProvider keys; std::string error; auto parsed_descs = Parse(desc_str, keys, error, false); Assert(success == (!parsed_descs.empty())); if (!success) return nullptr; auto& desc = parsed_descs.at(0); const int64_t range_start = 0, range_end = 1, next_index = 0, timestamp = 1; WalletDescriptor w_desc(std::move(desc), timestamp, range_start, range_end, next_index); LOCK(keystore.cs_wallet); auto spkm = Assert(keystore.AddWalletDescriptor(w_desc, keys,/*label=*/"", /*internal=*/false)); return &spkm.value().get(); }; } // namespace wallet