interfaces.cpp
1 // Copyright (c) 2018-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 <interfaces/wallet.h> 6 7 #include <common/args.h> 8 #include <consensus/amount.h> 9 #include <interfaces/chain.h> 10 #include <interfaces/handler.h> 11 #include <policy/fees.h> 12 #include <primitives/transaction.h> 13 #include <rpc/server.h> 14 #include <scheduler.h> 15 #include <support/allocators/secure.h> 16 #include <sync.h> 17 #include <uint256.h> 18 #include <util/check.h> 19 #include <util/translation.h> 20 #include <util/ui_change_type.h> 21 #include <wallet/coincontrol.h> 22 #include <wallet/context.h> 23 #include <wallet/feebumper.h> 24 #include <wallet/fees.h> 25 #include <wallet/types.h> 26 #include <wallet/load.h> 27 #include <wallet/receive.h> 28 #include <wallet/rpc/wallet.h> 29 #include <wallet/spend.h> 30 #include <wallet/wallet.h> 31 32 #include <memory> 33 #include <string> 34 #include <utility> 35 #include <vector> 36 37 using interfaces::Chain; 38 using interfaces::FoundBlock; 39 using interfaces::Handler; 40 using interfaces::MakeSignalHandler; 41 using interfaces::Wallet; 42 using interfaces::WalletAddress; 43 using interfaces::WalletBalances; 44 using interfaces::WalletLoader; 45 using interfaces::WalletMigrationResult; 46 using interfaces::WalletOrderForm; 47 using interfaces::WalletTx; 48 using interfaces::WalletTxOut; 49 using interfaces::WalletTxStatus; 50 using interfaces::WalletValueMap; 51 52 namespace wallet { 53 // All members of the classes in this namespace are intentionally public, as the 54 // classes themselves are private. 55 namespace { 56 //! Construct wallet tx struct. 57 WalletTx MakeWalletTx(CWallet& wallet, const CWalletTx& wtx) 58 { 59 LOCK(wallet.cs_wallet); 60 WalletTx result; 61 result.tx = wtx.tx; 62 result.txin_is_mine.reserve(wtx.tx->vin.size()); 63 for (const auto& txin : wtx.tx->vin) { 64 result.txin_is_mine.emplace_back(InputIsMine(wallet, txin)); 65 } 66 result.txout_is_mine.reserve(wtx.tx->vout.size()); 67 result.txout_address.reserve(wtx.tx->vout.size()); 68 result.txout_address_is_mine.reserve(wtx.tx->vout.size()); 69 for (const auto& txout : wtx.tx->vout) { 70 result.txout_is_mine.emplace_back(wallet.IsMine(txout)); 71 result.txout_is_change.push_back(OutputIsChange(wallet, txout)); 72 result.txout_address.emplace_back(); 73 result.txout_address_is_mine.emplace_back(ExtractDestination(txout.scriptPubKey, result.txout_address.back()) ? 74 wallet.IsMine(result.txout_address.back()) : 75 ISMINE_NO); 76 } 77 result.credit = CachedTxGetCredit(wallet, wtx, ISMINE_ALL); 78 result.debit = CachedTxGetDebit(wallet, wtx, ISMINE_ALL); 79 result.change = CachedTxGetChange(wallet, wtx); 80 result.time = wtx.GetTxTime(); 81 result.value_map = wtx.mapValue; 82 result.is_coinbase = wtx.IsCoinBase(); 83 return result; 84 } 85 86 //! Construct wallet tx status struct. 87 WalletTxStatus MakeWalletTxStatus(const CWallet& wallet, const CWalletTx& wtx) 88 EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet) 89 { 90 AssertLockHeld(wallet.cs_wallet); 91 92 WalletTxStatus result; 93 result.block_height = 94 wtx.state<TxStateConfirmed>() ? wtx.state<TxStateConfirmed>()->confirmed_block_height : 95 wtx.state<TxStateBlockConflicted>() ? wtx.state<TxStateBlockConflicted>()->conflicting_block_height : 96 std::numeric_limits<int>::max(); 97 result.blocks_to_maturity = wallet.GetTxBlocksToMaturity(wtx); 98 result.depth_in_main_chain = wallet.GetTxDepthInMainChain(wtx); 99 result.time_received = wtx.nTimeReceived; 100 result.lock_time = wtx.tx->nLockTime; 101 result.is_trusted = CachedTxIsTrusted(wallet, wtx); 102 result.is_abandoned = wtx.isAbandoned(); 103 result.is_coinbase = wtx.IsCoinBase(); 104 result.is_in_main_chain = wtx.isConfirmed(); 105 return result; 106 } 107 108 //! Construct wallet TxOut struct. 109 WalletTxOut MakeWalletTxOut(const CWallet& wallet, 110 const CWalletTx& wtx, 111 int n, 112 int depth) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet) 113 { 114 WalletTxOut result; 115 result.txout = wtx.tx->vout[n]; 116 result.time = wtx.GetTxTime(); 117 result.depth_in_main_chain = depth; 118 result.is_spent = wallet.IsSpent(COutPoint(wtx.GetHash(), n)); 119 return result; 120 } 121 122 WalletTxOut MakeWalletTxOut(const CWallet& wallet, 123 const COutput& output) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet) 124 { 125 WalletTxOut result; 126 result.txout = output.txout; 127 result.time = output.time; 128 result.depth_in_main_chain = output.depth; 129 result.is_spent = wallet.IsSpent(output.outpoint); 130 return result; 131 } 132 133 class WalletImpl : public Wallet 134 { 135 public: 136 explicit WalletImpl(WalletContext& context, const std::shared_ptr<CWallet>& wallet) : m_context(context), m_wallet(wallet) {} 137 138 bool encryptWallet(const SecureString& wallet_passphrase) override 139 { 140 return m_wallet->EncryptWallet(wallet_passphrase); 141 } 142 bool isCrypted() override { return m_wallet->IsCrypted(); } 143 bool lock() override { return m_wallet->Lock(); } 144 bool unlock(const SecureString& wallet_passphrase) override { return m_wallet->Unlock(wallet_passphrase); } 145 bool isLocked() override { return m_wallet->IsLocked(); } 146 bool changeWalletPassphrase(const SecureString& old_wallet_passphrase, 147 const SecureString& new_wallet_passphrase) override 148 { 149 return m_wallet->ChangeWalletPassphrase(old_wallet_passphrase, new_wallet_passphrase); 150 } 151 void abortRescan() override { m_wallet->AbortRescan(); } 152 bool backupWallet(const std::string& filename) override { return m_wallet->BackupWallet(filename); } 153 std::string getWalletName() override { return m_wallet->GetName(); } 154 util::Result<CTxDestination> getNewDestination(const OutputType type, const std::string& label) override 155 { 156 LOCK(m_wallet->cs_wallet); 157 return m_wallet->GetNewDestination(type, label); 158 } 159 bool getPubKey(const CScript& script, const CKeyID& address, CPubKey& pub_key) override 160 { 161 std::unique_ptr<SigningProvider> provider = m_wallet->GetSolvingProvider(script); 162 if (provider) { 163 return provider->GetPubKey(address, pub_key); 164 } 165 return false; 166 } 167 SigningResult signMessage(const std::string& message, const PKHash& pkhash, std::string& str_sig) override 168 { 169 return m_wallet->SignMessage(message, pkhash, str_sig); 170 } 171 bool isSpendable(const CTxDestination& dest) override 172 { 173 LOCK(m_wallet->cs_wallet); 174 return m_wallet->IsMine(dest) & ISMINE_SPENDABLE; 175 } 176 bool haveWatchOnly() override 177 { 178 auto spk_man = m_wallet->GetLegacyScriptPubKeyMan(); 179 if (spk_man) { 180 return spk_man->HaveWatchOnly(); 181 } 182 return false; 183 }; 184 bool setAddressBook(const CTxDestination& dest, const std::string& name, const std::optional<AddressPurpose>& purpose) override 185 { 186 return m_wallet->SetAddressBook(dest, name, purpose); 187 } 188 bool delAddressBook(const CTxDestination& dest) override 189 { 190 return m_wallet->DelAddressBook(dest); 191 } 192 bool getAddress(const CTxDestination& dest, 193 std::string* name, 194 isminetype* is_mine, 195 AddressPurpose* purpose) override 196 { 197 LOCK(m_wallet->cs_wallet); 198 const auto& entry = m_wallet->FindAddressBookEntry(dest, /*allow_change=*/false); 199 if (!entry) return false; // addr not found 200 if (name) { 201 *name = entry->GetLabel(); 202 } 203 std::optional<isminetype> dest_is_mine; 204 if (is_mine || purpose) { 205 dest_is_mine = m_wallet->IsMine(dest); 206 } 207 if (is_mine) { 208 *is_mine = *dest_is_mine; 209 } 210 if (purpose) { 211 // In very old wallets, address purpose may not be recorded so we derive it from IsMine 212 *purpose = entry->purpose.value_or(*dest_is_mine ? AddressPurpose::RECEIVE : AddressPurpose::SEND); 213 } 214 return true; 215 } 216 std::vector<WalletAddress> getAddresses() override 217 { 218 LOCK(m_wallet->cs_wallet); 219 std::vector<WalletAddress> result; 220 m_wallet->ForEachAddrBookEntry([&](const CTxDestination& dest, const std::string& label, bool is_change, const std::optional<AddressPurpose>& purpose) EXCLUSIVE_LOCKS_REQUIRED(m_wallet->cs_wallet) { 221 if (is_change) return; 222 isminetype is_mine = m_wallet->IsMine(dest); 223 // In very old wallets, address purpose may not be recorded so we derive it from IsMine 224 result.emplace_back(dest, is_mine, purpose.value_or(is_mine ? AddressPurpose::RECEIVE : AddressPurpose::SEND), label); 225 }); 226 return result; 227 } 228 std::vector<std::string> getAddressReceiveRequests() override { 229 LOCK(m_wallet->cs_wallet); 230 return m_wallet->GetAddressReceiveRequests(); 231 } 232 bool setAddressReceiveRequest(const CTxDestination& dest, const std::string& id, const std::string& value) override { 233 // Note: The setAddressReceiveRequest interface used by the GUI to store 234 // receive requests is a little awkward and could be improved in the 235 // future: 236 // 237 // - The same method is used to save requests and erase them, but 238 // having separate methods could be clearer and prevent bugs. 239 // 240 // - Request ids are passed as strings even though they are generated as 241 // integers. 242 // 243 // - Multiple requests can be stored for the same address, but it might 244 // be better to only allow one request or only keep the current one. 245 LOCK(m_wallet->cs_wallet); 246 WalletBatch batch{m_wallet->GetDatabase()}; 247 return value.empty() ? m_wallet->EraseAddressReceiveRequest(batch, dest, id) 248 : m_wallet->SetAddressReceiveRequest(batch, dest, id, value); 249 } 250 bool displayAddress(const CTxDestination& dest) override 251 { 252 LOCK(m_wallet->cs_wallet); 253 return m_wallet->DisplayAddress(dest); 254 } 255 bool lockCoin(const COutPoint& output, const bool write_to_db) override 256 { 257 LOCK(m_wallet->cs_wallet); 258 std::unique_ptr<WalletBatch> batch = write_to_db ? std::make_unique<WalletBatch>(m_wallet->GetDatabase()) : nullptr; 259 return m_wallet->LockCoin(output, batch.get()); 260 } 261 bool unlockCoin(const COutPoint& output) override 262 { 263 LOCK(m_wallet->cs_wallet); 264 std::unique_ptr<WalletBatch> batch = std::make_unique<WalletBatch>(m_wallet->GetDatabase()); 265 return m_wallet->UnlockCoin(output, batch.get()); 266 } 267 bool isLockedCoin(const COutPoint& output) override 268 { 269 LOCK(m_wallet->cs_wallet); 270 return m_wallet->IsLockedCoin(output); 271 } 272 void listLockedCoins(std::vector<COutPoint>& outputs) override 273 { 274 LOCK(m_wallet->cs_wallet); 275 return m_wallet->ListLockedCoins(outputs); 276 } 277 util::Result<CTransactionRef> createTransaction(const std::vector<CRecipient>& recipients, 278 const CCoinControl& coin_control, 279 bool sign, 280 int& change_pos, 281 CAmount& fee) override 282 { 283 LOCK(m_wallet->cs_wallet); 284 auto res = CreateTransaction(*m_wallet, recipients, change_pos == -1 ? std::nullopt : std::make_optional(change_pos), 285 coin_control, sign); 286 if (!res) return util::Error{util::ErrorString(res)}; 287 const auto& txr = *res; 288 fee = txr.fee; 289 change_pos = txr.change_pos ? *txr.change_pos : -1; 290 291 return txr.tx; 292 } 293 void commitTransaction(CTransactionRef tx, 294 WalletValueMap value_map, 295 WalletOrderForm order_form) override 296 { 297 LOCK(m_wallet->cs_wallet); 298 m_wallet->CommitTransaction(std::move(tx), std::move(value_map), std::move(order_form)); 299 } 300 bool transactionCanBeAbandoned(const uint256& txid) override { return m_wallet->TransactionCanBeAbandoned(txid); } 301 bool abandonTransaction(const uint256& txid) override 302 { 303 LOCK(m_wallet->cs_wallet); 304 return m_wallet->AbandonTransaction(txid); 305 } 306 bool transactionCanBeBumped(const uint256& txid) override 307 { 308 return feebumper::TransactionCanBeBumped(*m_wallet.get(), txid); 309 } 310 bool createBumpTransaction(const uint256& txid, 311 const CCoinControl& coin_control, 312 std::vector<bilingual_str>& errors, 313 CAmount& old_fee, 314 CAmount& new_fee, 315 CMutableTransaction& mtx) override 316 { 317 std::vector<CTxOut> outputs; // just an empty list of new recipients for now 318 return feebumper::CreateRateBumpTransaction(*m_wallet.get(), txid, coin_control, errors, old_fee, new_fee, mtx, /* require_mine= */ true, outputs) == feebumper::Result::OK; 319 } 320 bool signBumpTransaction(CMutableTransaction& mtx) override { return feebumper::SignTransaction(*m_wallet.get(), mtx); } 321 bool commitBumpTransaction(const uint256& txid, 322 CMutableTransaction&& mtx, 323 std::vector<bilingual_str>& errors, 324 uint256& bumped_txid) override 325 { 326 return feebumper::CommitTransaction(*m_wallet.get(), txid, std::move(mtx), errors, bumped_txid) == 327 feebumper::Result::OK; 328 } 329 CTransactionRef getTx(const uint256& txid) override 330 { 331 LOCK(m_wallet->cs_wallet); 332 auto mi = m_wallet->mapWallet.find(txid); 333 if (mi != m_wallet->mapWallet.end()) { 334 return mi->second.tx; 335 } 336 return {}; 337 } 338 WalletTx getWalletTx(const uint256& txid) override 339 { 340 LOCK(m_wallet->cs_wallet); 341 auto mi = m_wallet->mapWallet.find(txid); 342 if (mi != m_wallet->mapWallet.end()) { 343 return MakeWalletTx(*m_wallet, mi->second); 344 } 345 return {}; 346 } 347 std::set<WalletTx> getWalletTxs() override 348 { 349 LOCK(m_wallet->cs_wallet); 350 std::set<WalletTx> result; 351 for (const auto& entry : m_wallet->mapWallet) { 352 result.emplace(MakeWalletTx(*m_wallet, entry.second)); 353 } 354 return result; 355 } 356 bool tryGetTxStatus(const uint256& txid, 357 interfaces::WalletTxStatus& tx_status, 358 int& num_blocks, 359 int64_t& block_time) override 360 { 361 TRY_LOCK(m_wallet->cs_wallet, locked_wallet); 362 if (!locked_wallet) { 363 return false; 364 } 365 auto mi = m_wallet->mapWallet.find(txid); 366 if (mi == m_wallet->mapWallet.end()) { 367 return false; 368 } 369 num_blocks = m_wallet->GetLastBlockHeight(); 370 block_time = -1; 371 CHECK_NONFATAL(m_wallet->chain().findBlock(m_wallet->GetLastBlockHash(), FoundBlock().time(block_time))); 372 tx_status = MakeWalletTxStatus(*m_wallet, mi->second); 373 return true; 374 } 375 WalletTx getWalletTxDetails(const uint256& txid, 376 WalletTxStatus& tx_status, 377 WalletOrderForm& order_form, 378 bool& in_mempool, 379 int& num_blocks) override 380 { 381 LOCK(m_wallet->cs_wallet); 382 auto mi = m_wallet->mapWallet.find(txid); 383 if (mi != m_wallet->mapWallet.end()) { 384 num_blocks = m_wallet->GetLastBlockHeight(); 385 in_mempool = mi->second.InMempool(); 386 order_form = mi->second.vOrderForm; 387 tx_status = MakeWalletTxStatus(*m_wallet, mi->second); 388 return MakeWalletTx(*m_wallet, mi->second); 389 } 390 return {}; 391 } 392 TransactionError fillPSBT(int sighash_type, 393 bool sign, 394 bool bip32derivs, 395 size_t* n_signed, 396 PartiallySignedTransaction& psbtx, 397 bool& complete) override 398 { 399 return m_wallet->FillPSBT(psbtx, complete, sighash_type, sign, bip32derivs, n_signed); 400 } 401 WalletBalances getBalances() override 402 { 403 const auto bal = GetBalance(*m_wallet); 404 WalletBalances result; 405 result.balance = bal.m_mine_trusted; 406 result.unconfirmed_balance = bal.m_mine_untrusted_pending; 407 result.immature_balance = bal.m_mine_immature; 408 result.have_watch_only = haveWatchOnly(); 409 if (result.have_watch_only) { 410 result.watch_only_balance = bal.m_watchonly_trusted; 411 result.unconfirmed_watch_only_balance = bal.m_watchonly_untrusted_pending; 412 result.immature_watch_only_balance = bal.m_watchonly_immature; 413 } 414 return result; 415 } 416 bool tryGetBalances(WalletBalances& balances, uint256& block_hash) override 417 { 418 TRY_LOCK(m_wallet->cs_wallet, locked_wallet); 419 if (!locked_wallet) { 420 return false; 421 } 422 block_hash = m_wallet->GetLastBlockHash(); 423 balances = getBalances(); 424 return true; 425 } 426 CAmount getBalance() override { return GetBalance(*m_wallet).m_mine_trusted; } 427 CAmount getAvailableBalance(const CCoinControl& coin_control) override 428 { 429 LOCK(m_wallet->cs_wallet); 430 CAmount total_amount = 0; 431 // Fetch selected coins total amount 432 if (coin_control.HasSelected()) { 433 FastRandomContext rng{}; 434 CoinSelectionParams params(rng); 435 // Note: for now, swallow any error. 436 if (auto res = FetchSelectedInputs(*m_wallet, coin_control, params)) { 437 total_amount += res->total_amount; 438 } 439 } 440 441 // And fetch the wallet available coins 442 if (coin_control.m_allow_other_inputs) { 443 total_amount += AvailableCoins(*m_wallet, &coin_control).GetTotalAmount(); 444 } 445 446 return total_amount; 447 } 448 isminetype txinIsMine(const CTxIn& txin) override 449 { 450 LOCK(m_wallet->cs_wallet); 451 return InputIsMine(*m_wallet, txin); 452 } 453 isminetype txoutIsMine(const CTxOut& txout) override 454 { 455 LOCK(m_wallet->cs_wallet); 456 return m_wallet->IsMine(txout); 457 } 458 CAmount getDebit(const CTxIn& txin, isminefilter filter) override 459 { 460 LOCK(m_wallet->cs_wallet); 461 return m_wallet->GetDebit(txin, filter); 462 } 463 CAmount getCredit(const CTxOut& txout, isminefilter filter) override 464 { 465 LOCK(m_wallet->cs_wallet); 466 return OutputGetCredit(*m_wallet, txout, filter); 467 } 468 CoinsList listCoins() override 469 { 470 LOCK(m_wallet->cs_wallet); 471 CoinsList result; 472 for (const auto& entry : ListCoins(*m_wallet)) { 473 auto& group = result[entry.first]; 474 for (const auto& coin : entry.second) { 475 group.emplace_back(coin.outpoint, 476 MakeWalletTxOut(*m_wallet, coin)); 477 } 478 } 479 return result; 480 } 481 std::vector<WalletTxOut> getCoins(const std::vector<COutPoint>& outputs) override 482 { 483 LOCK(m_wallet->cs_wallet); 484 std::vector<WalletTxOut> result; 485 result.reserve(outputs.size()); 486 for (const auto& output : outputs) { 487 result.emplace_back(); 488 auto it = m_wallet->mapWallet.find(output.hash); 489 if (it != m_wallet->mapWallet.end()) { 490 int depth = m_wallet->GetTxDepthInMainChain(it->second); 491 if (depth >= 0) { 492 result.back() = MakeWalletTxOut(*m_wallet, it->second, output.n, depth); 493 } 494 } 495 } 496 return result; 497 } 498 CAmount getRequiredFee(unsigned int tx_bytes) override { return GetRequiredFee(*m_wallet, tx_bytes); } 499 CAmount getMinimumFee(unsigned int tx_bytes, 500 const CCoinControl& coin_control, 501 int* returned_target, 502 FeeReason* reason) override 503 { 504 FeeCalculation fee_calc; 505 CAmount result; 506 result = GetMinimumFee(*m_wallet, tx_bytes, coin_control, &fee_calc); 507 if (returned_target) *returned_target = fee_calc.returnedTarget; 508 if (reason) *reason = fee_calc.reason; 509 return result; 510 } 511 unsigned int getConfirmTarget() override { return m_wallet->m_confirm_target; } 512 bool hdEnabled() override { return m_wallet->IsHDEnabled(); } 513 bool canGetAddresses() override { return m_wallet->CanGetAddresses(); } 514 bool hasExternalSigner() override { return m_wallet->IsWalletFlagSet(WALLET_FLAG_EXTERNAL_SIGNER); } 515 bool privateKeysDisabled() override { return m_wallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS); } 516 bool taprootEnabled() override { 517 if (m_wallet->IsLegacy()) return false; 518 auto spk_man = m_wallet->GetScriptPubKeyMan(OutputType::BECH32M, /*internal=*/false); 519 return spk_man != nullptr; 520 } 521 OutputType getDefaultAddressType() override { return m_wallet->m_default_address_type; } 522 CAmount getDefaultMaxTxFee() override { return m_wallet->m_default_max_tx_fee; } 523 void remove() override 524 { 525 RemoveWallet(m_context, m_wallet, /*load_on_start=*/false); 526 } 527 bool isLegacy() override { return m_wallet->IsLegacy(); } 528 std::unique_ptr<Handler> handleUnload(UnloadFn fn) override 529 { 530 return MakeSignalHandler(m_wallet->NotifyUnload.connect(fn)); 531 } 532 std::unique_ptr<Handler> handleShowProgress(ShowProgressFn fn) override 533 { 534 return MakeSignalHandler(m_wallet->ShowProgress.connect(fn)); 535 } 536 std::unique_ptr<Handler> handleStatusChanged(StatusChangedFn fn) override 537 { 538 return MakeSignalHandler(m_wallet->NotifyStatusChanged.connect([fn](CWallet*) { fn(); })); 539 } 540 std::unique_ptr<Handler> handleAddressBookChanged(AddressBookChangedFn fn) override 541 { 542 return MakeSignalHandler(m_wallet->NotifyAddressBookChanged.connect( 543 [fn](const CTxDestination& address, const std::string& label, bool is_mine, 544 AddressPurpose purpose, ChangeType status) { fn(address, label, is_mine, purpose, status); })); 545 } 546 std::unique_ptr<Handler> handleTransactionChanged(TransactionChangedFn fn) override 547 { 548 return MakeSignalHandler(m_wallet->NotifyTransactionChanged.connect( 549 [fn](const uint256& txid, ChangeType status) { fn(txid, status); })); 550 } 551 std::unique_ptr<Handler> handleWatchOnlyChanged(WatchOnlyChangedFn fn) override 552 { 553 return MakeSignalHandler(m_wallet->NotifyWatchonlyChanged.connect(fn)); 554 } 555 std::unique_ptr<Handler> handleCanGetAddressesChanged(CanGetAddressesChangedFn fn) override 556 { 557 return MakeSignalHandler(m_wallet->NotifyCanGetAddressesChanged.connect(fn)); 558 } 559 CWallet* wallet() override { return m_wallet.get(); } 560 561 WalletContext& m_context; 562 std::shared_ptr<CWallet> m_wallet; 563 }; 564 565 class WalletLoaderImpl : public WalletLoader 566 { 567 public: 568 WalletLoaderImpl(Chain& chain, ArgsManager& args) 569 { 570 m_context.chain = &chain; 571 m_context.args = &args; 572 } 573 ~WalletLoaderImpl() override { UnloadWallets(m_context); } 574 575 //! ChainClient methods 576 void registerRpcs() override 577 { 578 for (const CRPCCommand& command : GetWalletRPCCommands()) { 579 m_rpc_commands.emplace_back(command.category, command.name, [this, &command](const JSONRPCRequest& request, UniValue& result, bool last_handler) { 580 JSONRPCRequest wallet_request = request; 581 wallet_request.context = &m_context; 582 return command.actor(wallet_request, result, last_handler); 583 }, command.argNames, command.unique_id); 584 m_rpc_handlers.emplace_back(m_context.chain->handleRpc(m_rpc_commands.back())); 585 } 586 } 587 bool verify() override { return VerifyWallets(m_context); } 588 bool load() override { return LoadWallets(m_context); } 589 void start(CScheduler& scheduler) override 590 { 591 m_context.scheduler = &scheduler; 592 return StartWallets(m_context); 593 } 594 void flush() override { return FlushWallets(m_context); } 595 void stop() override { return StopWallets(m_context); } 596 void setMockTime(int64_t time) override { return SetMockTime(time); } 597 void schedulerMockForward(std::chrono::seconds delta) override { Assert(m_context.scheduler)->MockForward(delta); } 598 599 //! WalletLoader methods 600 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 601 { 602 DatabaseOptions options; 603 DatabaseStatus status; 604 ReadDatabaseArgs(*m_context.args, options); 605 options.require_create = true; 606 options.create_flags = wallet_creation_flags; 607 options.create_passphrase = passphrase; 608 bilingual_str error; 609 std::unique_ptr<Wallet> wallet{MakeWallet(m_context, CreateWallet(m_context, name, /*load_on_start=*/true, options, status, error, warnings))}; 610 if (wallet) { 611 return wallet; 612 } else { 613 return util::Error{error}; 614 } 615 } 616 util::Result<std::unique_ptr<Wallet>> loadWallet(const std::string& name, std::vector<bilingual_str>& warnings) override 617 { 618 DatabaseOptions options; 619 DatabaseStatus status; 620 ReadDatabaseArgs(*m_context.args, options); 621 options.require_existing = true; 622 bilingual_str error; 623 std::unique_ptr<Wallet> wallet{MakeWallet(m_context, LoadWallet(m_context, name, /*load_on_start=*/true, options, status, error, warnings))}; 624 if (wallet) { 625 return wallet; 626 } else { 627 return util::Error{error}; 628 } 629 } 630 util::Result<std::unique_ptr<Wallet>> restoreWallet(const fs::path& backup_file, const std::string& wallet_name, std::vector<bilingual_str>& warnings) override 631 { 632 DatabaseStatus status; 633 bilingual_str error; 634 std::unique_ptr<Wallet> wallet{MakeWallet(m_context, RestoreWallet(m_context, backup_file, wallet_name, /*load_on_start=*/true, status, error, warnings))}; 635 if (wallet) { 636 return wallet; 637 } else { 638 return util::Error{error}; 639 } 640 } 641 util::Result<WalletMigrationResult> migrateWallet(const std::string& name, const SecureString& passphrase) override 642 { 643 auto res = wallet::MigrateLegacyToDescriptor(name, passphrase, m_context); 644 if (!res) return util::Error{util::ErrorString(res)}; 645 WalletMigrationResult out{ 646 .wallet = MakeWallet(m_context, res->wallet), 647 .watchonly_wallet_name = res->watchonly_wallet ? std::make_optional(res->watchonly_wallet->GetName()) : std::nullopt, 648 .solvables_wallet_name = res->solvables_wallet ? std::make_optional(res->solvables_wallet->GetName()) : std::nullopt, 649 .backup_path = res->backup_path, 650 }; 651 return out; 652 } 653 std::string getWalletDir() override 654 { 655 return fs::PathToString(GetWalletDir()); 656 } 657 std::vector<std::string> listWalletDir() override 658 { 659 std::vector<std::string> paths; 660 for (auto& path : ListDatabases(GetWalletDir())) { 661 paths.push_back(fs::PathToString(path)); 662 } 663 return paths; 664 } 665 std::vector<std::unique_ptr<Wallet>> getWallets() override 666 { 667 std::vector<std::unique_ptr<Wallet>> wallets; 668 for (const auto& wallet : GetWallets(m_context)) { 669 wallets.emplace_back(MakeWallet(m_context, wallet)); 670 } 671 return wallets; 672 } 673 std::unique_ptr<Handler> handleLoadWallet(LoadWalletFn fn) override 674 { 675 return HandleLoadWallet(m_context, std::move(fn)); 676 } 677 WalletContext* context() override { return &m_context; } 678 679 WalletContext m_context; 680 const std::vector<std::string> m_wallet_filenames; 681 std::vector<std::unique_ptr<Handler>> m_rpc_handlers; 682 std::list<CRPCCommand> m_rpc_commands; 683 }; 684 } // namespace 685 } // namespace wallet 686 687 namespace interfaces { 688 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; } 689 690 std::unique_ptr<WalletLoader> MakeWalletLoader(Chain& chain, ArgsManager& args) 691 { 692 return std::make_unique<wallet::WalletLoaderImpl>(chain, args); 693 } 694 } // namespace interfaces