Coverage Report

Created: 2025-05-14 12:32

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/root/bitcoin/src/wallet/test/util.cpp
Line
Count
Source
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 <memory>
18
19
namespace wallet {
20
std::unique_ptr<CWallet> CreateSyncedWallet(interfaces::Chain& chain, CChain& cchain, const CKey& key)
21
0
{
22
0
    auto wallet = std::make_unique<CWallet>(&chain, "", CreateMockableWalletDatabase());
23
0
    {
24
0
        LOCK2(wallet->cs_wallet, ::cs_main);
25
0
        wallet->SetLastBlockProcessed(cchain.Height(), cchain.Tip()->GetBlockHash());
26
0
    }
27
0
    {
28
0
        LOCK(wallet->cs_wallet);
29
0
        wallet->SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
30
0
        wallet->SetupDescriptorScriptPubKeyMans();
31
32
0
        FlatSigningProvider provider;
33
0
        std::string error;
34
0
        auto descs = Parse("combo(" + EncodeSecret(key) + ")", provider, error, /* require_checksum=*/ false);
35
0
        assert(descs.size() == 1);
36
0
        auto& desc = descs.at(0);
37
0
        WalletDescriptor w_desc(std::move(desc), 0, 0, 1, 1);
38
0
        auto spk_manager = *Assert(wallet->AddWalletDescriptor(w_desc, provider, "", false));
39
0
        assert(spk_manager);
40
0
    }
41
0
    WalletRescanReserver reserver(*wallet);
42
0
    reserver.reserve();
43
0
    CWallet::ScanResult result = wallet->ScanForWalletTransactions(cchain.Genesis()->GetBlockHash(), /*start_height=*/0, /*max_height=*/{}, reserver, /*fUpdate=*/false, /*save_progress=*/false);
44
0
    assert(result.status == CWallet::ScanResult::SUCCESS);
45
0
    assert(result.last_scanned_block == cchain.Tip()->GetBlockHash());
46
0
    assert(*result.last_scanned_height == cchain.Height());
47
0
    assert(result.last_failed_block.IsNull());
48
0
    return wallet;
49
0
}
50
51
std::shared_ptr<CWallet> TestLoadWallet(std::unique_ptr<WalletDatabase> database, WalletContext& context, uint64_t create_flags)
52
0
{
53
0
    bilingual_str error;
54
0
    std::vector<bilingual_str> warnings;
55
0
    auto wallet = CWallet::Create(context, "", std::move(database), create_flags, error, warnings);
56
0
    NotifyWalletLoaded(context, wallet);
57
0
    if (context.chain) {
58
0
        wallet->postInitProcess();
59
0
    }
60
0
    return wallet;
61
0
}
62
63
std::shared_ptr<CWallet> TestLoadWallet(WalletContext& context)
64
0
{
65
0
    DatabaseOptions options;
66
0
    options.create_flags = WALLET_FLAG_DESCRIPTORS;
67
0
    DatabaseStatus status;
68
0
    bilingual_str error;
69
0
    std::vector<bilingual_str> warnings;
70
0
    auto database = MakeWalletDatabase("", options, status, error);
71
0
    return TestLoadWallet(std::move(database), context, options.create_flags);
72
0
}
73
74
void TestUnloadWallet(std::shared_ptr<CWallet>&& wallet)
75
0
{
76
    // Calls SyncWithValidationInterfaceQueue
77
0
    wallet->chain().waitForNotificationsIfTipChanged({});
78
0
    wallet->m_chain_notifications_handler.reset();
79
0
    WaitForDeleteWallet(std::move(wallet));
80
0
}
81
82
std::unique_ptr<WalletDatabase> DuplicateMockDatabase(WalletDatabase& database)
83
0
{
84
0
    return std::make_unique<MockableDatabase>(dynamic_cast<MockableDatabase&>(database).m_records);
85
0
}
86
87
std::string getnewaddress(CWallet& w)
88
0
{
89
0
    constexpr auto output_type = OutputType::BECH32;
90
0
    return EncodeDestination(getNewDestination(w, output_type));
91
0
}
92
93
CTxDestination getNewDestination(CWallet& w, OutputType output_type)
94
0
{
95
0
    return *Assert(w.GetNewDestination(output_type, ""));
96
0
}
97
98
MockableCursor::MockableCursor(const MockableData& records, bool pass, std::span<const std::byte> prefix)
99
0
{
100
0
    m_pass = pass;
101
0
    std::tie(m_cursor, m_cursor_end) = records.equal_range(BytePrefix{prefix});
102
0
}
103
104
DatabaseCursor::Status MockableCursor::Next(DataStream& key, DataStream& value)
105
0
{
106
0
    if (!m_pass) {
107
0
        return Status::FAIL;
108
0
    }
109
0
    if (m_cursor == m_cursor_end) {
110
0
        return Status::DONE;
111
0
    }
112
0
    key.clear();
113
0
    value.clear();
114
0
    const auto& [key_data, value_data] = *m_cursor;
115
0
    key.write(key_data);
116
0
    value.write(value_data);
117
0
    m_cursor++;
118
0
    return Status::MORE;
119
0
}
120
121
bool MockableBatch::ReadKey(DataStream&& key, DataStream& value)
122
0
{
123
0
    if (!m_pass) {
124
0
        return false;
125
0
    }
126
0
    SerializeData key_data{key.begin(), key.end()};
127
0
    const auto& it = m_records.find(key_data);
128
0
    if (it == m_records.end()) {
129
0
        return false;
130
0
    }
131
0
    value.clear();
132
0
    value.write(it->second);
133
0
    return true;
134
0
}
135
136
bool MockableBatch::WriteKey(DataStream&& key, DataStream&& value, bool overwrite)
137
0
{
138
0
    if (!m_pass) {
139
0
        return false;
140
0
    }
141
0
    SerializeData key_data{key.begin(), key.end()};
142
0
    SerializeData value_data{value.begin(), value.end()};
143
0
    auto [it, inserted] = m_records.emplace(key_data, value_data);
144
0
    if (!inserted && overwrite) { // Overwrite if requested
145
0
        it->second = value_data;
146
0
        inserted = true;
147
0
    }
148
0
    return inserted;
149
0
}
150
151
bool MockableBatch::EraseKey(DataStream&& key)
152
0
{
153
0
    if (!m_pass) {
154
0
        return false;
155
0
    }
156
0
    SerializeData key_data{key.begin(), key.end()};
157
0
    m_records.erase(key_data);
158
0
    return true;
159
0
}
160
161
bool MockableBatch::HasKey(DataStream&& key)
162
0
{
163
0
    if (!m_pass) {
164
0
        return false;
165
0
    }
166
0
    SerializeData key_data{key.begin(), key.end()};
167
0
    return m_records.count(key_data) > 0;
168
0
}
169
170
bool MockableBatch::ErasePrefix(std::span<const std::byte> prefix)
171
0
{
172
0
    if (!m_pass) {
173
0
        return false;
174
0
    }
175
0
    auto it = m_records.begin();
176
0
    while (it != m_records.end()) {
177
0
        auto& key = it->first;
178
0
        if (key.size() < prefix.size() || std::search(key.begin(), key.end(), prefix.begin(), prefix.end()) != key.begin()) {
179
0
            it++;
180
0
            continue;
181
0
        }
182
0
        it = m_records.erase(it);
183
0
    }
184
0
    return true;
185
0
}
186
187
std::unique_ptr<WalletDatabase> CreateMockableWalletDatabase(MockableData records)
188
0
{
189
0
    return std::make_unique<MockableDatabase>(records);
190
0
}
191
192
MockableDatabase& GetMockableDatabase(CWallet& wallet)
193
0
{
194
0
    return dynamic_cast<MockableDatabase&>(wallet.GetDatabase());
195
0
}
196
197
wallet::ScriptPubKeyMan* CreateDescriptor(CWallet& keystore, const std::string& desc_str, const bool success)
198
0
{
199
0
    keystore.SetWalletFlag(WALLET_FLAG_DESCRIPTORS);
200
201
0
    FlatSigningProvider keys;
202
0
    std::string error;
203
0
    auto parsed_descs = Parse(desc_str, keys, error, false);
204
0
    Assert(success == (!parsed_descs.empty()));
205
0
    if (!success) return nullptr;
206
0
    auto& desc = parsed_descs.at(0);
207
208
0
    const int64_t range_start = 0, range_end = 1, next_index = 0, timestamp = 1;
209
210
0
    WalletDescriptor w_desc(std::move(desc), timestamp, range_start, range_end, next_index);
211
212
0
    LOCK(keystore.cs_wallet);
213
0
    auto spkm = Assert(keystore.AddWalletDescriptor(w_desc, keys,/*label=*/"", /*internal=*/false));
214
0
    return spkm.value();
215
0
};
216
} // namespace wallet