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 [ + - ]: 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 : : {
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 [ + - ]: 2 : }
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
|