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