util.cpp
1 // Copyright (c) 2021-present The Bitcoin Core developers 2 // Distributed under the MIT software license, see the accompanying 3 // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 5 #include <wallet/test/util.h> 6 7 #include <chain.h> 8 #include <key.h> 9 #include <key_io.h> 10 #include <streams.h> 11 #include <test/util/setup_common.h> 12 #include <validationinterface.h> 13 #include <wallet/context.h> 14 #include <wallet/wallet.h> 15 #include <wallet/walletdb.h> 16 17 #include <sqlite3.h> 18 19 #include <memory> 20 21 namespace wallet { 22 std::unique_ptr<CWallet> CreateSyncedWallet(interfaces::Chain& chain, CChain& cchain, const CKey& key) 23 { 24 auto wallet = std::make_unique<CWallet>(&chain, "", CreateMockableWalletDatabase()); 25 { 26 LOCK2(wallet->cs_wallet, ::cs_main); 27 wallet->SetLastBlockProcessed(cchain.Height(), cchain.Tip()->GetBlockHash()); 28 } 29 { 30 LOCK(wallet->cs_wallet); 31 wallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS); 32 wallet->SetupDescriptorScriptPubKeyMans(); 33 34 FlatSigningProvider provider; 35 std::string error; 36 auto descs = Parse("combo(" + EncodeSecret(key) + ")", provider, error, /* require_checksum=*/ false); 37 assert(descs.size() == 1); 38 auto& desc = descs.at(0); 39 WalletDescriptor w_desc(std::move(desc), 0, 0, 1, 1); 40 Assert(wallet->AddWalletDescriptor(w_desc, provider, "", false)); 41 } 42 WalletRescanReserver reserver(*wallet); 43 reserver.reserve(); 44 CWallet::ScanResult result = wallet->ScanForWalletTransactions(cchain.Genesis()->GetBlockHash(), /*start_height=*/0, /*max_height=*/{}, reserver, /*fUpdate=*/false, /*save_progress=*/false); 45 assert(result.status == CWallet::ScanResult::SUCCESS); 46 assert(result.last_scanned_block == cchain.Tip()->GetBlockHash()); 47 assert(*result.last_scanned_height == cchain.Height()); 48 assert(result.last_failed_block.IsNull()); 49 return wallet; 50 } 51 52 std::shared_ptr<CWallet> TestCreateWallet(std::unique_ptr<WalletDatabase> database, WalletContext& context, uint64_t create_flags) 53 { 54 bilingual_str _error; 55 std::vector<bilingual_str> _warnings; 56 auto wallet = CWallet::CreateNew(context, "", std::move(database), create_flags, _error, _warnings); 57 NotifyWalletLoaded(context, wallet); 58 if (context.chain) { 59 wallet->postInitProcess(); 60 } 61 return wallet; 62 } 63 64 std::shared_ptr<CWallet> TestCreateWallet(WalletContext& context) 65 { 66 DatabaseOptions options; 67 options.require_create = true; 68 options.create_flags = WALLET_FLAG_DESCRIPTORS; 69 DatabaseStatus status; 70 bilingual_str error; 71 std::vector<bilingual_str> warnings; 72 auto database = MakeWalletDatabase("", options, status, error); 73 return TestCreateWallet(std::move(database), context, options.create_flags); 74 } 75 76 77 std::shared_ptr<CWallet> TestLoadWallet(std::unique_ptr<WalletDatabase> database, WalletContext& context) 78 { 79 bilingual_str error; 80 std::vector<bilingual_str> warnings; 81 auto wallet = CWallet::LoadExisting(context, "", std::move(database), error, warnings); 82 NotifyWalletLoaded(context, wallet); 83 if (context.chain) { 84 wallet->postInitProcess(); 85 } 86 return wallet; 87 } 88 89 std::shared_ptr<CWallet> TestLoadWallet(WalletContext& context) 90 { 91 DatabaseOptions options; 92 options.require_existing = true; 93 DatabaseStatus status; 94 bilingual_str error; 95 std::vector<bilingual_str> warnings; 96 auto database = MakeWalletDatabase("", options, status, error); 97 return TestLoadWallet(std::move(database), context); 98 } 99 100 void TestUnloadWallet(std::shared_ptr<CWallet>&& wallet) 101 { 102 // Calls SyncWithValidationInterfaceQueue 103 wallet->chain().waitForNotificationsIfTipChanged({}); 104 wallet->m_chain_notifications_handler.reset(); 105 WaitForDeleteWallet(std::move(wallet)); 106 } 107 108 std::unique_ptr<WalletDatabase> DuplicateMockDatabase(WalletDatabase& database) 109 { 110 std::unique_ptr<DatabaseBatch> batch_orig = database.MakeBatch(); 111 std::unique_ptr<DatabaseCursor> cursor_orig = batch_orig->GetNewCursor(); 112 113 std::unique_ptr<WalletDatabase> new_db = CreateMockableWalletDatabase(); 114 std::unique_ptr<DatabaseBatch> new_db_batch = new_db->MakeBatch(); 115 MockableSQLiteBatch* batch_new = dynamic_cast<MockableSQLiteBatch*>(new_db_batch.get()); 116 Assert(batch_new); 117 118 while (true) { 119 DataStream key, value; 120 DatabaseCursor::Status status = cursor_orig->Next(key, value); 121 Assert(status != DatabaseCursor::Status::FAIL); 122 if (status != DatabaseCursor::Status::MORE) break; 123 batch_new->WriteKey(std::move(key), std::move(value)); 124 } 125 126 return new_db; 127 } 128 129 std::string getnewaddress(CWallet& w) 130 { 131 constexpr auto output_type = OutputType::BECH32; 132 return EncodeDestination(getNewDestination(w, output_type)); 133 } 134 135 CTxDestination getNewDestination(CWallet& w, OutputType output_type) 136 { 137 return *Assert(w.GetNewDestination(output_type, "")); 138 } 139 140 MockableSQLiteDatabase::MockableSQLiteDatabase() 141 : SQLiteDatabase(fs::PathFromString("mock/"), fs::PathFromString("mock/wallet.dat"), DatabaseOptions(), SQLITE_OPEN_MEMORY) 142 {} 143 144 std::unique_ptr<WalletDatabase> CreateMockableWalletDatabase() 145 { 146 return std::make_unique<MockableSQLiteDatabase>(); 147 } 148 149 wallet::DescriptorScriptPubKeyMan* CreateDescriptor(CWallet& keystore, const std::string& desc_str, const bool success) 150 { 151 keystore.SetWalletFlag(WALLET_FLAG_DESCRIPTORS); 152 153 FlatSigningProvider keys; 154 std::string error; 155 auto parsed_descs = Parse(desc_str, keys, error, false); 156 Assert(success == (!parsed_descs.empty())); 157 if (!success) return nullptr; 158 auto& desc = parsed_descs.at(0); 159 160 const int64_t range_start = 0, range_end = 1, next_index = 0, timestamp = 1; 161 162 WalletDescriptor w_desc(std::move(desc), timestamp, range_start, range_end, next_index); 163 164 LOCK(keystore.cs_wallet); 165 auto spkm = Assert(keystore.AddWalletDescriptor(w_desc, keys,/*label=*/"", /*internal=*/false)); 166 return &spkm.value().get(); 167 }; 168 } // namespace wallet