Line data Source code
1 : // Copyright (c) 2018-2021 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 <interfaces/wallet.h>
6 :
7 : #include <chain.h>
8 : #include <coinjoin/client.h>
9 : #include <consensus/amount.h>
10 : #include <interfaces/chain.h>
11 : #include <interfaces/coinjoin.h>
12 : #include <interfaces/handler.h>
13 : #include <policy/fees.h>
14 : #include <primitives/transaction.h>
15 : #include <rpc/server.h>
16 : #include <script/standard.h>
17 : #include <support/allocators/secure.h>
18 : #include <sync.h>
19 : #include <uint256.h>
20 : #include <util/check.h>
21 : #include <util/system.h>
22 : #include <util/translation.h>
23 : #include <util/ui_change_type.h>
24 : #include <validation.h>
25 : #include <wallet/coinjoin.h>
26 : #include <wallet/context.h>
27 : #include <wallet/fees.h>
28 : #include <wallet/ismine.h>
29 : #include <wallet/load.h>
30 : #include <wallet/receive.h>
31 : #include <wallet/rpc/wallet.h>
32 : #include <wallet/spend.h>
33 : #include <wallet/wallet.h>
34 : #include <wallet/hdchain.h>
35 : #include <wallet/scriptpubkeyman.h>
36 : #include <evo/deterministicmns.h>
37 : #include <masternode/sync.h>
38 : #include <txdb.h>
39 : #include <node/context.h>
40 :
41 : #include <algorithm>
42 : #include <memory>
43 : #include <string>
44 : #include <utility>
45 : #include <vector>
46 :
47 : using interfaces::Chain;
48 : using interfaces::FoundBlock;
49 : using interfaces::Handler;
50 : using interfaces::MakeHandler;
51 : using interfaces::Wallet;
52 : using interfaces::WalletAddress;
53 : using interfaces::WalletBalances;
54 : using interfaces::WalletLoader;
55 : using interfaces::WalletOrderForm;
56 : using interfaces::WalletTx;
57 : using interfaces::WalletTxOut;
58 : using interfaces::WalletTxStatus;
59 : using interfaces::WalletValueMap;
60 : using node::NodeContext;
61 :
62 : namespace wallet {
63 : namespace {
64 : //! Construct wallet tx struct.
65 0 : WalletTx MakeWalletTx(CWallet& wallet, const CWalletTx& wtx)
66 : {
67 0 : LOCK(wallet.cs_wallet);
68 0 : WalletTx result;
69 0 : bool fInputDenomFound{false}, fOutputDenomFound{false};
70 0 : result.tx = wtx.tx;
71 0 : result.txin_is_mine.reserve(wtx.tx->vin.size());
72 0 : for (const auto& txin : wtx.tx->vin) {
73 0 : result.txin_is_mine.emplace_back(InputIsMine(wallet, txin));
74 0 : if (!fInputDenomFound && result.txin_is_mine.back() && wallet.IsDenominated(txin.prevout)) {
75 0 : fInputDenomFound = true;
76 0 : }
77 : }
78 0 : result.txout_is_mine.reserve(wtx.tx->vout.size());
79 0 : result.txout_address.reserve(wtx.tx->vout.size());
80 0 : result.txout_address_is_mine.reserve(wtx.tx->vout.size());
81 0 : for (const auto& txout : wtx.tx->vout) {
82 0 : result.txout_is_mine.emplace_back(wallet.IsMine(txout));
83 0 : result.txout_address.emplace_back();
84 0 : result.txout_address_is_mine.emplace_back(ExtractDestination(txout.scriptPubKey, result.txout_address.back()) ?
85 0 : wallet.IsMine(result.txout_address.back()) :
86 : ISMINE_NO);
87 0 : if (!fOutputDenomFound && result.txout_address_is_mine.back() && CoinJoin::IsDenominatedAmount(txout.nValue)) {
88 0 : fOutputDenomFound = true;
89 0 : }
90 : }
91 0 : result.credit = CachedTxGetCredit(wallet, wtx, ISMINE_ALL);
92 0 : result.debit = CachedTxGetDebit(wallet, wtx, ISMINE_ALL);
93 0 : result.change = CachedTxGetChange(wallet, wtx);
94 0 : result.time = wtx.GetTxTime();
95 0 : result.value_map = wtx.mapValue;
96 0 : result.is_coinbase = wtx.IsCoinBase();
97 0 : result.is_platform_transfer = wtx.IsPlatformTransfer();
98 : // The determination of is_denominate is based on simplified checks here because in this part of the code
99 : // we only want to know about mixing transactions belonging to this specific wallet.
100 0 : result.is_denominate = wtx.tx->vin.size() == wtx.tx->vout.size() && // Number of inputs is same as number of outputs
101 0 : (result.credit - result.debit) == 0 && // Transaction pays no tx fee
102 0 : fInputDenomFound && fOutputDenomFound; // At least 1 input and 1 output are denominated belonging to the provided wallet
103 0 : return result;
104 0 : }
105 :
106 : //! Construct wallet tx status struct.
107 0 : WalletTxStatus MakeWalletTxStatus(const CWallet& wallet, const CWalletTx& wtx)
108 : EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
109 : {
110 0 : AssertLockHeld(wallet.cs_wallet);
111 :
112 : WalletTxStatus result;
113 0 : result.block_height =
114 0 : wtx.state<TxStateConfirmed>() ? wtx.state<TxStateConfirmed>()->confirmed_block_height :
115 0 : wtx.state<TxStateConflicted>() ? wtx.state<TxStateConflicted>()->conflicting_block_height :
116 0 : std::numeric_limits<int>::max();
117 0 : result.blocks_to_maturity = wallet.GetTxBlocksToMaturity(wtx);
118 0 : result.depth_in_main_chain = wallet.GetTxDepthInMainChain(wtx);
119 0 : result.time_received = wtx.nTimeReceived;
120 0 : result.lock_time = wtx.tx->nLockTime;
121 0 : result.is_trusted = CachedTxIsTrusted(wallet, wtx);
122 0 : result.is_abandoned = wtx.isAbandoned();
123 0 : result.is_coinbase = wtx.IsCoinBase();
124 0 : result.is_in_main_chain = wallet.IsTxInMainChain(wtx);
125 0 : result.is_chainlocked = wallet.IsTxChainLocked(wtx);
126 0 : result.is_islocked = wallet.IsTxLockedByInstantSend(wtx);
127 0 : return result;
128 : }
129 :
130 : //! Construct wallet TxOut struct.
131 0 : WalletTxOut MakeWalletTxOut(const CWallet& wallet,
132 : const CWalletTx& wtx,
133 : int n,
134 : int depth) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
135 : {
136 0 : WalletTxOut result;
137 0 : result.txout = wtx.tx->vout[n];
138 0 : result.time = wtx.GetTxTime();
139 0 : result.depth_in_main_chain = depth;
140 0 : result.is_spent = wallet.IsSpent(COutPoint(wtx.GetHash(), n));
141 0 : return result;
142 0 : }
143 :
144 0 : WalletTxOut MakeWalletTxOut(const CWallet& wallet,
145 : const COutput& output) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
146 : {
147 0 : WalletTxOut result;
148 0 : result.txout = output.txout;
149 0 : result.time = output.time;
150 0 : result.depth_in_main_chain = output.depth;
151 0 : result.is_spent = wallet.IsSpent(output.outpoint);
152 0 : return result;
153 0 : }
154 :
155 : class WalletImpl : public Wallet
156 : {
157 : public:
158 26340 : explicit WalletImpl(WalletContext& context, const std::shared_ptr<CWallet>& wallet) : m_context(context), m_wallet(wallet) {}
159 :
160 0 : void markDirty() override
161 : {
162 0 : m_wallet->MarkDirty();
163 0 : }
164 0 : bool encryptWallet(const SecureString& wallet_passphrase) override
165 : {
166 0 : return m_wallet->EncryptWallet(wallet_passphrase);
167 : }
168 0 : bool isCrypted() override { return m_wallet->IsCrypted(); }
169 0 : bool lock(bool fAllowMixing) override { return m_wallet->Lock(fAllowMixing); }
170 0 : bool unlock(const SecureString& wallet_passphrase, bool fAllowMixing) override { return m_wallet->Unlock(wallet_passphrase, fAllowMixing); }
171 12625 : bool isLocked(bool fForMixing) override { return m_wallet->IsLocked(fForMixing); }
172 0 : bool changeWalletPassphrase(const SecureString& old_wallet_passphrase,
173 : const SecureString& new_wallet_passphrase) override
174 : {
175 0 : return m_wallet->ChangeWalletPassphrase(old_wallet_passphrase, new_wallet_passphrase);
176 : }
177 0 : wallet::RescanStatus startRescan(bool from_genesis) override
178 : {
179 0 : int rescan_height{0};
180 0 : if (!from_genesis) {
181 0 : std::optional<int64_t> time_first_key;
182 0 : for (auto spk_man : m_wallet->GetAllScriptPubKeyMans()) {
183 0 : int64_t time = spk_man->GetTimeFirstKey();
184 0 : if (!time_first_key || time < *time_first_key) time_first_key = time;
185 : }
186 0 : if (time_first_key) {
187 0 : m_wallet->chain().findFirstBlockWithTimeAndHeight(*time_first_key - TIMESTAMP_WINDOW, rescan_height,
188 0 : FoundBlock().height(rescan_height));
189 0 : }
190 0 : }
191 :
192 0 : WalletRescanReserver reserver(*m_wallet);
193 0 : if (!reserver.reserve()) {
194 0 : return wallet::RescanStatus::BUSY;
195 : }
196 0 : switch (m_wallet->ScanForWalletTransactions(m_wallet->chain().getBlockHash(rescan_height), rescan_height, /*max_height=*/std::nullopt,
197 0 : reserver, /*fUpdate=*/true, /*save_progress=*/false).status) {
198 : case CWallet::ScanResult::FAILURE:
199 0 : return wallet::RescanStatus::FAILURE;
200 : case CWallet::ScanResult::SUCCESS:
201 0 : return wallet::RescanStatus::SUCCESS;
202 : case CWallet::ScanResult::USER_ABORT:
203 0 : return wallet::RescanStatus::USER_ABORT;
204 : }
205 0 : Assume(false); // unreachable
206 0 : return wallet::RescanStatus::FAILURE; // fallback for release builds
207 0 : }
208 0 : void abortRescan() override { m_wallet->AbortRescan(); }
209 544 : void autoLockMasternodeCollaterals() override { m_wallet->AutoLockMasternodeCollaterals(); }
210 0 : bool backupWallet(const std::string& filename) override { return m_wallet->BackupWallet(filename); }
211 0 : bool autoBackupWallet(const fs::path& wallet_path, bilingual_str& error_string, std::vector<bilingual_str>& warnings) override
212 : {
213 0 : return m_wallet->AutoBackupWallet(wallet_path, error_string, warnings);
214 : }
215 0 : int64_t getKeysLeftSinceAutoBackup() override { return m_wallet->nKeysLeftSinceAutoBackup; }
216 13317 : std::string getWalletName() override { return m_wallet->GetName(); }
217 0 : util::Result<CTxDestination> getNewDestination(const std::string& label) override
218 : {
219 0 : LOCK(m_wallet->cs_wallet);
220 0 : return m_wallet->GetNewDestination(label);
221 0 : }
222 0 : bool getPubKey(const CScript& script, const CKeyID& address, CPubKey& pub_key) override
223 : {
224 0 : std::unique_ptr<SigningProvider> provider = m_wallet->GetSolvingProvider(script);
225 0 : if (provider) {
226 0 : return provider->GetPubKey(address, pub_key);
227 : }
228 0 : return false;
229 0 : }
230 0 : SigningResult signMessage(const std::string& message, const PKHash& pkhash, std::string& str_sig) override
231 : {
232 0 : return m_wallet->SignMessage(message, pkhash, str_sig);
233 : }
234 0 : bool signSpecialTxPayload(const uint256& hash, const CKeyID& keyid, std::vector<unsigned char>& vchSig) override
235 : {
236 0 : return m_wallet->SignSpecialTxPayload(hash, keyid, vchSig);
237 : }
238 0 : bool isSpendable(const CScript& script) override
239 : {
240 0 : LOCK(m_wallet->cs_wallet);
241 0 : return m_wallet->IsMine(script) & ISMINE_SPENDABLE;
242 0 : }
243 0 : bool isSpendable(const CTxDestination& dest) override
244 : {
245 0 : LOCK(m_wallet->cs_wallet);
246 0 : return m_wallet->IsMine(dest) & ISMINE_SPENDABLE;
247 0 : }
248 0 : bool haveWatchOnly() override
249 : {
250 0 : auto spk_man = m_wallet->GetLegacyScriptPubKeyMan();
251 0 : if (spk_man) {
252 0 : return spk_man->HaveWatchOnly();
253 : }
254 0 : return false;
255 0 : };
256 0 : bool setAddressBook(const CTxDestination& dest, const std::string& name, const std::string& purpose) override
257 : {
258 0 : return m_wallet->SetAddressBook(dest, name, purpose);
259 : }
260 0 : bool delAddressBook(const CTxDestination& dest) override
261 : {
262 0 : return m_wallet->DelAddressBook(dest);
263 : }
264 0 : bool getAddress(const CTxDestination& dest,
265 : std::string* name,
266 : wallet::isminetype* is_mine,
267 : std::string* purpose) override
268 : {
269 0 : LOCK(m_wallet->cs_wallet);
270 0 : const auto& entry = m_wallet->FindAddressBookEntry(dest, /*allow_change=*/false);
271 0 : if (!entry) return false; // addr not found
272 0 : if (name) {
273 0 : *name = entry->GetLabel();
274 0 : }
275 0 : if (is_mine) {
276 0 : *is_mine = m_wallet->IsMine(dest);
277 0 : }
278 0 : if (purpose) {
279 0 : *purpose = entry->purpose;
280 0 : }
281 0 : return true;
282 0 : }
283 0 : std::vector<WalletAddress> getAddresses() const override
284 : {
285 0 : LOCK(m_wallet->cs_wallet);
286 0 : std::vector<WalletAddress> result;
287 0 : m_wallet->ForEachAddrBookEntry([&](const CTxDestination& dest, const std::string& label, const std::string& purpose, bool is_change) EXCLUSIVE_LOCKS_REQUIRED(m_wallet->cs_wallet) {
288 0 : if (is_change) return;
289 0 : result.emplace_back(dest, m_wallet->IsMine(dest), label, purpose);
290 0 : });
291 0 : return result;
292 0 : }
293 0 : std::vector<std::string> getAddressReceiveRequests() override {
294 0 : LOCK(m_wallet->cs_wallet);
295 0 : return m_wallet->GetAddressReceiveRequests();
296 0 : }
297 0 : bool setAddressReceiveRequest(const CTxDestination& dest, const std::string& id, const std::string& value) override {
298 : // Note: The setAddressReceiveRequest interface used by the GUI to store
299 : // receive requests is a little awkward and could be improved in the
300 : // future:
301 : //
302 : // - The same method is used to save requests and erase them, but
303 : // having separate methods could be clearer and prevent bugs.
304 : //
305 : // - Request ids are passed as strings even though they are generated as
306 : // integers.
307 : //
308 : // - Multiple requests can be stored for the same address, but it might
309 : // be better to only allow one request or only keep the current one.
310 0 : LOCK(m_wallet->cs_wallet);
311 0 : WalletBatch batch{m_wallet->GetDatabase()};
312 0 : return value.empty() ? m_wallet->EraseAddressReceiveRequest(batch, dest, id)
313 0 : : m_wallet->SetAddressReceiveRequest(batch, dest, id, value);
314 0 : }
315 0 : bool displayAddress(const CTxDestination& dest) override
316 : {
317 0 : LOCK(m_wallet->cs_wallet);
318 0 : return m_wallet->DisplayAddress(dest);
319 0 : }
320 0 : bool lockCoin(const COutPoint& output, const bool write_to_db) override
321 : {
322 0 : LOCK(m_wallet->cs_wallet);
323 0 : std::unique_ptr<WalletBatch> batch = write_to_db ? std::make_unique<WalletBatch>(m_wallet->GetDatabase()) : nullptr;
324 0 : return m_wallet->LockCoin(output, batch.get());
325 0 : }
326 0 : bool unlockCoin(const COutPoint& output) override
327 : {
328 0 : LOCK(m_wallet->cs_wallet);
329 0 : std::unique_ptr<WalletBatch> batch = std::make_unique<WalletBatch>(m_wallet->GetDatabase());
330 0 : return m_wallet->UnlockCoin(output, batch.get());
331 0 : }
332 0 : bool isLockedCoin(const COutPoint& output) override
333 : {
334 0 : LOCK(m_wallet->cs_wallet);
335 0 : return m_wallet->IsLockedCoin(output);
336 0 : }
337 0 : std::set<COutPoint> listLockedCoins() override
338 : {
339 0 : LOCK(m_wallet->cs_wallet);
340 0 : return m_wallet->ListLockedCoins();
341 0 : }
342 0 : bool lockCoins(const std::vector<COutPoint>& outputs) override
343 : {
344 0 : LOCK(m_wallet->cs_wallet);
345 0 : WalletBatch batch(m_wallet->GetDatabase());
346 0 : for (const auto& output : outputs) {
347 0 : if (!m_wallet->LockCoin(output, &batch)) return false;
348 : }
349 0 : return true;
350 0 : }
351 0 : bool unlockCoins(const std::vector<COutPoint>& outputs) override
352 : {
353 0 : LOCK(m_wallet->cs_wallet);
354 0 : WalletBatch batch(m_wallet->GetDatabase());
355 0 : for (const auto& output : outputs) {
356 0 : if (!m_wallet->UnlockCoin(output, &batch)) return false;
357 : }
358 0 : return true;
359 0 : }
360 0 : void setDustProtectionThreshold(CAmount threshold) override
361 : {
362 0 : LOCK(m_wallet->cs_wallet);
363 0 : m_wallet->m_dust_protection_threshold = std::clamp(threshold, CAmount{0}, MAX_DUST_PROTECTION_THRESHOLD);
364 0 : }
365 0 : void lockExistingDustOutputs() override
366 : {
367 0 : LOCK(m_wallet->cs_wallet);
368 0 : m_wallet->LockExistingDustOutputs();
369 0 : }
370 0 : std::vector<COutPoint> listProTxCoins() override
371 : {
372 0 : LOCK(m_wallet->cs_wallet);
373 0 : return m_wallet->ListProTxCoins();
374 0 : }
375 0 : util::Result<CTransactionRef> createTransaction(const std::vector<CRecipient>& recipients,
376 : const CCoinControl& coin_control,
377 : bool sign,
378 : int& change_pos,
379 : CAmount& fee) override
380 : {
381 0 : LOCK(m_wallet->cs_wallet);
382 0 : auto res = CreateTransaction(*m_wallet, recipients, change_pos, coin_control, sign);
383 0 : if (!res) return util::Error{util::ErrorString(res)};
384 0 : const auto& txr = *res;
385 0 : fee = txr.fee;
386 0 : change_pos = txr.change_pos;
387 :
388 0 : return txr.tx;
389 0 : }
390 0 : void commitTransaction(CTransactionRef tx,
391 : WalletValueMap value_map,
392 : WalletOrderForm order_form) override
393 : {
394 0 : LOCK(m_wallet->cs_wallet);
395 0 : m_wallet->CommitTransaction(std::move(tx), std::move(value_map), std::move(order_form));
396 0 : }
397 0 : bool transactionCanBeAbandoned(const uint256& txid) override { return m_wallet->TransactionCanBeAbandoned(txid); }
398 0 : bool transactionCanBeResent(const uint256& txid) override { return m_wallet->TransactionCanBeResent(txid); }
399 0 : bool abandonTransaction(const uint256& txid) override
400 : {
401 0 : LOCK(m_wallet->cs_wallet);
402 0 : return m_wallet->AbandonTransaction(txid);
403 0 : }
404 0 : bool resendTransaction(const uint256& txid) override
405 : {
406 0 : LOCK(m_wallet->cs_wallet);
407 0 : return m_wallet->ResendTransaction(txid);
408 0 : }
409 0 : CTransactionRef getTx(const uint256& txid) override
410 : {
411 0 : LOCK(m_wallet->cs_wallet);
412 0 : auto mi = m_wallet->mapWallet.find(txid);
413 0 : if (mi != m_wallet->mapWallet.end()) {
414 0 : return mi->second.tx;
415 : }
416 0 : return {};
417 0 : }
418 0 : WalletTx getWalletTx(const uint256& txid) override
419 : {
420 0 : LOCK(m_wallet->cs_wallet);
421 0 : auto mi = m_wallet->mapWallet.find(txid);
422 0 : if (mi != m_wallet->mapWallet.end()) {
423 0 : return MakeWalletTx(*m_wallet, mi->second);
424 : }
425 0 : return {};
426 0 : }
427 0 : std::set<WalletTx> getWalletTxs() override
428 : {
429 0 : LOCK(m_wallet->cs_wallet);
430 0 : std::set<WalletTx> result;
431 0 : for (const auto& entry : m_wallet->mapWallet) {
432 0 : result.emplace(MakeWalletTx(*m_wallet, entry.second));
433 : }
434 0 : return result;
435 0 : }
436 0 : bool tryGetTxStatus(const uint256& txid,
437 : interfaces::WalletTxStatus& tx_status,
438 : int& num_blocks,
439 : int64_t& block_time) override
440 : {
441 0 : TRY_LOCK(m_wallet->cs_wallet, locked_wallet);
442 0 : if (!locked_wallet) {
443 0 : return false;
444 : }
445 0 : auto mi = m_wallet->mapWallet.find(txid);
446 0 : if (mi == m_wallet->mapWallet.end()) {
447 0 : return false;
448 : }
449 0 : num_blocks = m_wallet->GetLastBlockHeight();
450 0 : block_time = -1;
451 0 : CHECK_NONFATAL(m_wallet->chain().findBlock(m_wallet->GetLastBlockHash(), FoundBlock().time(block_time)));
452 0 : tx_status = MakeWalletTxStatus(*m_wallet, mi->second);
453 0 : return true;
454 0 : }
455 0 : WalletTx getWalletTxDetails(const uint256& txid,
456 : WalletTxStatus& tx_status,
457 : WalletOrderForm& order_form,
458 : bool& in_mempool,
459 : int& num_blocks) override
460 : {
461 0 : LOCK(m_wallet->cs_wallet);
462 0 : auto mi = m_wallet->mapWallet.find(txid);
463 0 : if (mi != m_wallet->mapWallet.end()) {
464 0 : num_blocks = m_wallet->GetLastBlockHeight();
465 0 : in_mempool = mi->second.InMempool();
466 0 : order_form = mi->second.vOrderForm;
467 0 : tx_status = MakeWalletTxStatus(*m_wallet, mi->second);
468 0 : return MakeWalletTx(*m_wallet, mi->second);
469 : }
470 0 : return {};
471 0 : }
472 0 : int getRealOutpointCoinJoinRounds(const COutPoint& outpoint) override { return m_wallet->GetRealOutpointCoinJoinRounds(outpoint); }
473 0 : bool isFullyMixed(const COutPoint& outpoint) override { return m_wallet->IsFullyMixed(outpoint); }
474 :
475 0 : TransactionError fillPSBT(int sighash_type,
476 : bool sign,
477 : bool bip32derivs,
478 : size_t* n_signed,
479 : PartiallySignedTransaction& psbtx,
480 : bool& complete) override
481 : {
482 0 : return m_wallet->FillPSBT(psbtx, complete, sighash_type, sign, bip32derivs, n_signed);
483 : }
484 0 : WalletBalances getBalances() override
485 : {
486 0 : const auto bal = GetBalance(*m_wallet);
487 0 : WalletBalances result;
488 0 : result.balance = bal.m_mine_trusted;
489 0 : result.unconfirmed_balance = bal.m_mine_untrusted_pending;
490 0 : result.immature_balance = bal.m_mine_immature;
491 0 : result.anonymized_balance = bal.m_anonymized;
492 0 : result.have_watch_only = haveWatchOnly();
493 0 : if (result.have_watch_only) {
494 0 : result.watch_only_balance = bal.m_watchonly_trusted;
495 0 : result.unconfirmed_watch_only_balance = bal.m_watchonly_untrusted_pending;
496 0 : result.immature_watch_only_balance = bal.m_watchonly_immature;
497 0 : }
498 0 : result.denominated_untrusted_pending = bal.m_denominated_untrusted_pending;
499 0 : result.denominated_trusted = bal.m_denominated_trusted;
500 0 : return result;
501 : }
502 0 : bool tryGetBalances(WalletBalances& balances, uint256& block_hash) override
503 : {
504 0 : TRY_LOCK(m_wallet->cs_wallet, locked_wallet);
505 0 : if (!locked_wallet) {
506 0 : return false;
507 : }
508 0 : block_hash = m_wallet->GetLastBlockHash();
509 0 : balances = getBalances();
510 0 : return true;
511 0 : }
512 0 : CAmount getBalance() override { return GetBalance(*m_wallet).m_mine_trusted; }
513 0 : CAmount getAnonymizableBalance(bool fSkipDenominated, bool fSkipUnconfirmed) override
514 : {
515 0 : return m_wallet->GetAnonymizableBalance(fSkipDenominated, fSkipUnconfirmed);
516 : }
517 0 : CAmount getNormalizedAnonymizedBalance() override
518 : {
519 0 : return m_wallet->GetNormalizedAnonymizedBalance();
520 : }
521 0 : CAmount getAverageAnonymizedRounds() override
522 : {
523 0 : return m_wallet->GetAverageAnonymizedRounds();
524 : }
525 0 : CAmount getAvailableBalance(const CCoinControl& coin_control) override
526 : {
527 0 : if (coin_control.IsUsingCoinJoin()) {
528 0 : return GetBalanceAnonymized(*m_wallet, coin_control);
529 : } else {
530 0 : return GetAvailableBalance(*m_wallet, &coin_control);
531 : }
532 0 : }
533 0 : wallet::isminetype txinIsMine(const CTxIn& txin) override
534 : {
535 0 : LOCK(m_wallet->cs_wallet);
536 0 : return InputIsMine(*m_wallet, txin);
537 0 : }
538 0 : wallet::isminetype txoutIsMine(const CTxOut& txout) override
539 : {
540 0 : LOCK(m_wallet->cs_wallet);
541 0 : return m_wallet->IsMine(txout);
542 0 : }
543 0 : CAmount getDebit(const CTxIn& txin, wallet::isminefilter filter) override
544 : {
545 0 : LOCK(m_wallet->cs_wallet);
546 0 : return m_wallet->GetDebit(txin, filter);
547 0 : }
548 0 : CAmount getCredit(const CTxOut& txout, wallet::isminefilter filter) override
549 : {
550 0 : LOCK(m_wallet->cs_wallet);
551 0 : return OutputGetCredit(*m_wallet, txout, filter);
552 0 : }
553 0 : CoinsList listCoins() override
554 : {
555 0 : LOCK(m_wallet->cs_wallet);
556 0 : CoinsList result;
557 0 : for (const auto& entry : ListCoins(*m_wallet)) {
558 0 : auto& group = result[entry.first];
559 0 : for (const auto& coin : entry.second) {
560 0 : group.emplace_back(coin.outpoint,
561 0 : MakeWalletTxOut(*m_wallet, coin));
562 : }
563 : }
564 0 : return result;
565 0 : }
566 0 : std::vector<WalletTxOut> getCoins(const std::vector<COutPoint>& outputs) override
567 : {
568 0 : LOCK(m_wallet->cs_wallet);
569 0 : std::vector<WalletTxOut> result;
570 0 : result.reserve(outputs.size());
571 0 : for (const auto& output : outputs) {
572 0 : result.emplace_back();
573 0 : auto it = m_wallet->mapWallet.find(output.hash);
574 0 : if (it != m_wallet->mapWallet.end()) {
575 0 : int depth = m_wallet->GetTxDepthInMainChain(it->second);
576 0 : if (depth >= 0) {
577 0 : result.back() = MakeWalletTxOut(*m_wallet, it->second, output.n, depth);
578 0 : }
579 0 : }
580 : }
581 0 : return result;
582 0 : }
583 0 : CAmount getRequiredFee(unsigned int tx_bytes) override { return GetRequiredFee(*m_wallet, tx_bytes); }
584 0 : CAmount getMinimumFee(unsigned int tx_bytes,
585 : const CCoinControl& coin_control,
586 : int* returned_target,
587 : FeeReason* reason) override
588 : {
589 0 : FeeCalculation fee_calc;
590 : CAmount result;
591 0 : result = GetMinimumFee(*m_wallet, tx_bytes, coin_control, &fee_calc);
592 0 : if (returned_target) *returned_target = fee_calc.returnedTarget;
593 0 : if (reason) *reason = fee_calc.reason;
594 0 : return result;
595 : }
596 0 : unsigned int getConfirmTarget() override { return m_wallet->m_confirm_target; }
597 0 : bool hdEnabled() override { return m_wallet->IsHDEnabled(); }
598 0 : bool canGetAddresses() override { return m_wallet->CanGetAddresses(); }
599 0 : bool hasExternalSigner() override { return m_wallet->IsWalletFlagSet(WALLET_FLAG_EXTERNAL_SIGNER); }
600 0 : bool privateKeysDisabled() override { return m_wallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS); }
601 0 : CAmount getDefaultMaxTxFee() override { return m_wallet->m_default_max_tx_fee; }
602 0 : void remove() override
603 : {
604 0 : RemoveWallet(m_context, m_wallet, false /* load_on_start */);
605 0 : }
606 0 : bool isLegacy() override { return m_wallet->IsLegacy(); }
607 0 : bool getMnemonic(SecureString& mnemonic_out, SecureString& mnemonic_passphrase_out) override
608 : {
609 0 : LOCK(m_wallet->cs_wallet);
610 :
611 0 : mnemonic_out.clear();
612 0 : mnemonic_passphrase_out.clear();
613 :
614 0 : if (m_wallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
615 0 : return false;
616 : }
617 :
618 0 : if (m_wallet->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) {
619 : // Descriptor wallet
620 0 : for (auto spk_man : m_wallet->GetActiveScriptPubKeyMans()) {
621 0 : if (auto desc_spk_man = dynamic_cast<DescriptorScriptPubKeyMan*>(spk_man)) {
622 0 : if (desc_spk_man->GetMnemonicString(mnemonic_out, mnemonic_passphrase_out)) {
623 0 : return true;
624 : }
625 0 : }
626 : }
627 0 : return false;
628 : } else {
629 : // Legacy wallet
630 0 : auto spk_man = m_wallet->GetLegacyScriptPubKeyMan();
631 0 : if (!spk_man) {
632 0 : return false;
633 : }
634 :
635 0 : CHDChain hdChainCurrent;
636 0 : if (!spk_man->GetHDChain(hdChainCurrent)) {
637 0 : return false;
638 : }
639 :
640 : // Get decrypted HD chain if wallet is encrypted
641 0 : if (m_wallet->IsCrypted()) {
642 0 : if (!spk_man->GetDecryptedHDChain(hdChainCurrent)) {
643 0 : return false;
644 : }
645 0 : }
646 :
647 0 : return hdChainCurrent.GetMnemonic(mnemonic_out, mnemonic_passphrase_out);
648 0 : }
649 0 : }
650 0 : std::unique_ptr<Handler> handleUnload(UnloadFn fn) override
651 : {
652 0 : return MakeHandler(m_wallet->NotifyUnload.connect(fn));
653 0 : }
654 0 : std::unique_ptr<Handler> handleShowProgress(ShowProgressFn fn) override
655 : {
656 0 : return MakeHandler(m_wallet->ShowProgress.connect(fn));
657 0 : }
658 0 : std::unique_ptr<Handler> handleStatusChanged(StatusChangedFn fn) override
659 : {
660 0 : return MakeHandler(m_wallet->NotifyStatusChanged.connect([fn](CWallet*) { fn(); }));
661 0 : }
662 0 : std::unique_ptr<Handler> handleAddressBookChanged(AddressBookChangedFn fn) override
663 : {
664 0 : return MakeHandler(m_wallet->NotifyAddressBookChanged.connect(
665 0 : [fn](const CTxDestination& address, const std::string& label, bool is_mine,
666 0 : const std::string& purpose, ChangeType status) { fn(address, label, is_mine, purpose, status); }));
667 0 : }
668 0 : std::unique_ptr<Handler> handleTransactionChanged(TransactionChangedFn fn) override
669 : {
670 0 : return MakeHandler(m_wallet->NotifyTransactionChanged.connect(
671 0 : [fn](const uint256& txid, ChangeType status) { fn(txid, status); }));
672 0 : }
673 0 : std::unique_ptr<Handler> handleInstantLockReceived(InstantLockReceivedFn fn) override
674 : {
675 0 : return MakeHandler(m_wallet->NotifyISLockReceived.connect(
676 0 : [fn]() { fn(); }));
677 0 : }
678 0 : std::unique_ptr<Handler> handleChainLockReceived(ChainLockReceivedFn fn) override
679 : {
680 0 : return MakeHandler(m_wallet->NotifyChainLockReceived.connect(
681 0 : [fn](int chainLockHeight) { fn(chainLockHeight); }));
682 0 : }
683 0 : std::unique_ptr<Handler> handleWatchOnlyChanged(WatchOnlyChangedFn fn) override
684 : {
685 0 : return MakeHandler(m_wallet->NotifyWatchonlyChanged.connect(fn));
686 0 : }
687 0 : std::unique_ptr<Handler> handleCanGetAddressesChanged(CanGetAddressesChangedFn fn) override
688 : {
689 0 : return MakeHandler(m_wallet->NotifyCanGetAddressesChanged.connect(fn));
690 0 : }
691 0 : std::vector<Governance::Object> getGovernanceObjects() override
692 : {
693 0 : LOCK(m_wallet->cs_wallet);
694 0 : std::vector<Governance::Object> result;
695 0 : for (const auto* obj : m_wallet->GetGovernanceObjects()) {
696 0 : result.push_back(*obj);
697 : }
698 0 : return result;
699 0 : }
700 0 : bool prepareProposal(const uint256& govobj_hash, CAmount fee, int32_t revision, int64_t created_time,
701 : const std::string& data_hex, const COutPoint& outpoint,
702 : std::string& out_fee_txid, std::string& error) override
703 : {
704 0 : LOCK(m_wallet->cs_wallet);
705 0 : CTransactionRef tx;
706 0 : if (!GenBudgetSystemCollateralTx(*m_wallet, tx, govobj_hash, fee, outpoint)) {
707 0 : error = "Error making collateral transaction for governance object.";
708 0 : return false;
709 : }
710 0 : if (!m_wallet->WriteGovernanceObject(Governance::Object{uint256{}, revision, created_time, tx->GetHash(), data_hex})) {
711 0 : error = "WriteGovernanceObject failed";
712 0 : return false;
713 : }
714 0 : m_wallet->CommitTransaction(tx, {}, {});
715 0 : out_fee_txid = tx->GetHash().ToString();
716 0 : return true;
717 0 : }
718 0 : bool signGovernanceVote(const CKeyID& keyID, CGovernanceVote& vote) override
719 : {
720 0 : return m_wallet->SignGovernanceVote(keyID, vote);
721 : }
722 0 : CWallet* wallet() override { return m_wallet.get(); }
723 :
724 : WalletContext& m_context;
725 : std::shared_ptr<CWallet> m_wallet;
726 : };
727 :
728 : class WalletLoaderImpl : public WalletLoader
729 : {
730 : private:
731 7194 : void RegisterRPCs(const Span<const CRPCCommand>& commands)
732 : {
733 157546 : for (const CRPCCommand& command : commands) {
734 348078 : m_rpc_commands.emplace_back(command.category, command.name, [this, &command](const JSONRPCRequest& request, UniValue& result, bool last_handler) {
735 47374 : JSONRPCRequest wallet_request = request;
736 47374 : wallet_request.context = m_context;
737 47374 : return command.actor(wallet_request, result, last_handler);
738 197726 : }, command.argNames, command.unique_id);
739 150352 : m_rpc_handlers.emplace_back(m_context.chain->handleRpc(m_rpc_commands.back()));
740 : }
741 7194 : }
742 :
743 : public:
744 4905 : WalletLoaderImpl(Chain& chain, ArgsManager& args, NodeContext& node_context,
745 : interfaces::CoinJoin::Loader& coinjoin_loader)
746 3270 : {
747 1635 : m_context.chain = &chain;
748 1635 : m_context.args = &args;
749 1635 : m_context.node_context = &node_context;
750 1635 : m_context.coinjoin_loader = &coinjoin_loader;
751 3270 : }
752 4905 : ~WalletLoaderImpl() override { UnloadWallets(m_context); }
753 :
754 : //! ChainClient methods
755 1450 : void registerRpcs() override
756 : {
757 1450 : RegisterRPCs(GetWalletRPCCommands());
758 1450 : }
759 1443 : bool verify() override { return VerifyWallets(m_context); }
760 1354 : bool load() override { return LoadWallets(m_context); }
761 1328 : void start(CScheduler& scheduler) override { return StartWallets(m_context, scheduler); }
762 1436 : void flush() override { return FlushWallets(m_context); }
763 1436 : void stop() override { return StopWallets(m_context); }
764 9763 : void setMockTime(int64_t time) override { return SetMockTime(time); }
765 :
766 : //! WalletLoader methods
767 5744 : void registerOtherRpcs(const Span<const CRPCCommand>& commands) override
768 : {
769 5744 : return RegisterRPCs(commands);
770 : }
771 0 : util::Result<std::unique_ptr<Wallet>> createWallet(const std::string& name, const SecureString& passphrase, uint64_t wallet_creation_flags, std::vector<bilingual_str>& warnings) override
772 : {
773 0 : DatabaseOptions options;
774 : DatabaseStatus status;
775 0 : ReadDatabaseArgs(*m_context.args, options);
776 0 : options.require_create = true;
777 0 : options.create_flags = wallet_creation_flags;
778 0 : options.create_passphrase = passphrase;
779 0 : bilingual_str error;
780 0 : std::unique_ptr<Wallet> wallet{MakeWallet(m_context, CreateWallet(m_context, name, /*load_on_start=*/true, options, status, error, warnings))};
781 0 : if (wallet) {
782 0 : return {std::move(wallet)};
783 : } else {
784 0 : return util::Error{error};
785 : }
786 0 : }
787 0 : util::Result<std::unique_ptr<Wallet>> loadWallet(const std::string& name, std::vector<bilingual_str>& warnings) override
788 : {
789 0 : DatabaseOptions options;
790 : DatabaseStatus status;
791 0 : ReadDatabaseArgs(*m_context.args, options);
792 0 : options.require_existing = true;
793 0 : bilingual_str error;
794 0 : std::unique_ptr<Wallet> wallet{MakeWallet(m_context, LoadWallet(m_context, name, /*load_on_start=*/true, options, status, error, warnings))};
795 0 : if (wallet) {
796 0 : return {std::move(wallet)};
797 : } else {
798 0 : return util::Error{error};
799 : }
800 0 : }
801 0 : util::Result<std::unique_ptr<Wallet>> restoreWallet(const fs::path& backup_file, const std::string& wallet_name, std::vector<bilingual_str>& warnings) override
802 : {
803 : DatabaseStatus status;
804 0 : bilingual_str error;
805 0 : std::unique_ptr<Wallet> wallet{MakeWallet(m_context, RestoreWallet(m_context, backup_file, wallet_name, /*load_on_start=*/true, status, error, warnings))};
806 0 : if (wallet) {
807 0 : return {std::move(wallet)};
808 : } else {
809 0 : return util::Error{error};
810 : }
811 0 : }
812 0 : std::string getWalletDir() override
813 : {
814 0 : return fs::PathToString(GetWalletDir());
815 0 : }
816 0 : std::vector<std::string> listWalletDir() override
817 : {
818 0 : std::vector<std::string> paths;
819 0 : for (auto& path : ListDatabases(GetWalletDir())) {
820 0 : paths.push_back(fs::PathToString(path));
821 : }
822 0 : return paths;
823 0 : }
824 7891 : std::vector<std::unique_ptr<Wallet>> getWallets() override
825 : {
826 7891 : std::vector<std::unique_ptr<Wallet>> wallets;
827 21060 : for (const auto& wallet : GetWallets(m_context)) {
828 13169 : wallets.emplace_back(MakeWallet(m_context, wallet));
829 : }
830 7891 : return wallets;
831 7891 : }
832 0 : std::unique_ptr<Handler> handleLoadWallet(LoadWalletFn fn) override
833 : {
834 0 : return HandleLoadWallet(m_context, std::move(fn));
835 0 : }
836 0 : std::unique_ptr<Handler> handleLoadWalletLoading(LoadWalletFn fn) override
837 : {
838 0 : return HandleLoadWalletLoading(m_context, std::move(fn));
839 0 : }
840 0 : WalletContext* context() override { return &m_context; }
841 :
842 : WalletContext m_context;
843 : const std::vector<std::string> m_wallet_filenames;
844 : std::vector<std::unique_ptr<Handler>> m_rpc_handlers;
845 : std::list<CRPCCommand> m_rpc_commands;
846 : };
847 : } // namespace
848 : } // namespace wallet
849 :
850 : namespace interfaces {
851 13170 : std::unique_ptr<Wallet> MakeWallet(wallet::WalletContext& context, const std::shared_ptr<wallet::CWallet>& wallet) { return wallet ? std::make_unique<wallet::WalletImpl>(context, wallet) : nullptr; }
852 1635 : std::unique_ptr<WalletLoader> MakeWalletLoader(Chain& chain, ArgsManager& args, NodeContext& node_context,
853 : interfaces::CoinJoin::Loader& coinjoin_loader)
854 : {
855 1635 : return std::make_unique<wallet::WalletLoaderImpl>(chain, args, node_context, coinjoin_loader);
856 : }
857 : } // namespace interfaces
|