mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-09-13 14:13:52 +02:00
The intermediate watchonly wallet created during exportwatchonlywallet is
a pure build artifact — it is always discarded once BackupWallet() copies
it to the destination. Creating it as an in-memory SQLiteDatabase
(SQLITE_OPEN_MEMORY) removes the need to write files to the wallets
directory and eliminates the cleanup handler that deleted those files on
both success and failure paths.
Introduces InMemoryWalletDatabase (a minimal SQLiteDatabase subclass) and
MakeInMemoryWalletDatabase() factory in sqlite.h/cpp, following the same
pattern as MockableSQLiteDatabase / CreateMockableWalletDatabase() in the
test utilities. MockableSQLiteDatabase now derives from InMemoryWalletDatabase,
removing its redundant Files() override.
The wallet is named after the source wallet ("<name>_watchonly_temp") so
concurrent exports of different wallets use distinct names and log lines
remain traceable to the source wallet.
147 lines
4.9 KiB
C++
147 lines
4.9 KiB
C++
// 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 <wallet/test/util.h>
|
|
|
|
#include <chain.h>
|
|
#include <key.h>
|
|
#include <key_io.h>
|
|
#include <test/util/setup_common.h>
|
|
#include <validationinterface.h>
|
|
#include <wallet/context.h>
|
|
#include <wallet/wallet.h>
|
|
#include <wallet/walletdb.h>
|
|
|
|
#include <sqlite3.h>
|
|
|
|
#include <memory>
|
|
|
|
namespace wallet {
|
|
std::unique_ptr<CWallet> CreateSyncedWallet(interfaces::Chain& chain, CChain& cchain, const CKey& key)
|
|
{
|
|
auto wallet = std::make_unique<CWallet>(&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, /*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<CWallet> TestCreateWallet(std::unique_ptr<WalletDatabase> database, WalletContext& context, uint64_t create_flags)
|
|
{
|
|
bilingual_str _error;
|
|
std::vector<bilingual_str> _warnings;
|
|
auto wallet = CWallet::CreateNew(context, "", std::move(database), create_flags, /*born_encrypted=*/false, _error, _warnings);
|
|
NotifyWalletLoaded(context, wallet);
|
|
if (context.chain) {
|
|
wallet->postInitProcess();
|
|
}
|
|
return wallet;
|
|
}
|
|
|
|
std::shared_ptr<CWallet> TestCreateWallet(WalletContext& context)
|
|
{
|
|
DatabaseOptions options;
|
|
options.require_create = true;
|
|
options.create_flags = WALLET_FLAG_DESCRIPTORS;
|
|
DatabaseStatus status;
|
|
bilingual_str error;
|
|
std::vector<bilingual_str> warnings;
|
|
auto database = MakeWalletDatabase("", options, status, error);
|
|
return TestCreateWallet(std::move(database), context, options.create_flags);
|
|
}
|
|
|
|
|
|
std::shared_ptr<CWallet> TestLoadWallet(std::unique_ptr<WalletDatabase> database, WalletContext& context)
|
|
{
|
|
bilingual_str error;
|
|
std::vector<bilingual_str> warnings;
|
|
auto wallet = CWallet::LoadExisting(context, "", std::move(database), error, warnings);
|
|
NotifyWalletLoaded(context, wallet);
|
|
if (context.chain) {
|
|
wallet->postInitProcess();
|
|
}
|
|
return wallet;
|
|
}
|
|
|
|
std::shared_ptr<CWallet> TestLoadWallet(WalletContext& context)
|
|
{
|
|
DatabaseOptions options;
|
|
options.require_existing = true;
|
|
DatabaseStatus status;
|
|
bilingual_str error;
|
|
std::vector<bilingual_str> warnings;
|
|
auto database = MakeWalletDatabase("", options, status, error);
|
|
return TestLoadWallet(std::move(database), context);
|
|
}
|
|
|
|
void TestUnloadWallet(std::shared_ptr<CWallet>&& wallet)
|
|
{
|
|
// Calls SyncWithValidationInterfaceQueue
|
|
wallet->chain().waitForNotificationsIfTipChanged({});
|
|
wallet->m_chain_notifications_handler.reset();
|
|
WaitForDeleteWallet(std::move(wallet));
|
|
}
|
|
|
|
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()
|
|
: InMemoryWalletDatabase()
|
|
{}
|
|
|
|
std::unique_ptr<WalletDatabase> CreateMockableWalletDatabase()
|
|
{
|
|
return std::make_unique<MockableSQLiteDatabase>();
|
|
}
|
|
|
|
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
|