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