// Copyright (c) 2021-2022 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 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()); } wallet->LoadWallet(); { LOCK(wallet->cs_wallet); wallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS); wallet->SetupDescriptorScriptPubKeyMans(); FlatSigningProvider provider; std::string error; std::unique_ptr desc = Parse("combo(" + EncodeSecret(key) + ")", provider, error, /* require_checksum=*/ false); assert(desc); WalletDescriptor w_desc(std::move(desc), 0, 0, 1, 1); if (!wallet->AddWalletDescriptor(w_desc, provider, "", false)) assert(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::unique_ptr DuplicateMockDatabase(WalletDatabase& database) { return std::make_unique(dynamic_cast(database).m_records); } 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, "")); } DatabaseCursor::Status MockableCursor::Next(DataStream& key, DataStream& value) { if (!m_pass) { return Status::FAIL; } if (m_cursor == m_cursor_end) { return Status::DONE; } const auto& [key_data, value_data] = *m_cursor; key.write(key_data); value.write(value_data); m_cursor++; return Status::MORE; } bool MockableBatch::ReadKey(DataStream&& key, DataStream& value) { if (!m_pass) { return false; } SerializeData key_data{key.begin(), key.end()}; const auto& it = m_records.find(key_data); if (it == m_records.end()) { return false; } value.write(it->second); return true; } bool MockableBatch::WriteKey(DataStream&& key, DataStream&& value, bool overwrite) { if (!m_pass) { return false; } SerializeData key_data{key.begin(), key.end()}; SerializeData value_data{value.begin(), value.end()}; auto [it, inserted] = m_records.emplace(key_data, value_data); if (!inserted && overwrite) { // Overwrite if requested it->second = value_data; inserted = true; } return inserted; } bool MockableBatch::EraseKey(DataStream&& key) { if (!m_pass) { return false; } SerializeData key_data{key.begin(), key.end()}; m_records.erase(key_data); return true; } bool MockableBatch::HasKey(DataStream&& key) { if (!m_pass) { return false; } SerializeData key_data{key.begin(), key.end()}; return m_records.count(key_data) > 0; } bool MockableBatch::ErasePrefix(Span prefix) { if (!m_pass) { return false; } auto it = m_records.begin(); while (it != m_records.end()) { auto& key = it->first; if (key.size() < prefix.size() || std::search(key.begin(), key.end(), prefix.begin(), prefix.end()) != key.begin()) { it++; continue; } it = m_records.erase(it); } return true; } std::unique_ptr CreateMockableWalletDatabase(std::map records) { return std::make_unique(records); } MockableDatabase& GetMockableDatabase(CWallet& wallet) { return dynamic_cast(wallet.GetDatabase()); } } // namespace wallet