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