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