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