mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-01-15 14:22:37 -03:00
907d636e5e
f5ba424cd4
wallet: Add IsAddressUsed / SetAddressUsed methods (Russell Yanofsky)62252c95e5
interfaces: Stop exposing wallet destdata to gui (Russell Yanofsky)985430d9b2
test: Add gui test for wallet receive requests (Russell Yanofsky) Pull request description: Stop giving GUI access to destdata rows in database. Replace with narrow API just for saving and reading receive request information. This simplifies code and should prevent the GUI from interfering with other destdata like address-used status. It also adds some more GUI test coverage. There are no changes in behavior. ACKs for top commit: jarolrod: tACKf5ba424cd4
laanwj: Code review ACKf5ba424cd4
Tree-SHA512: 5423df4786e537a59013cb5bfb9e1bc29a7ca4b8835360c00cc2165a59f925fdc355907a4ceb8bca0285bb4946ba235bffa7645537a951ad03fd3b4cee17b6b0
580 lines
22 KiB
C++
580 lines
22 KiB
C++
// Copyright (c) 2018-2020 The Bitcoin Core developers
|
|
// Distributed under the MIT software license, see the accompanying
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
#include <interfaces/wallet.h>
|
|
|
|
#include <amount.h>
|
|
#include <interfaces/chain.h>
|
|
#include <interfaces/handler.h>
|
|
#include <policy/fees.h>
|
|
#include <primitives/transaction.h>
|
|
#include <rpc/server.h>
|
|
#include <script/standard.h>
|
|
#include <support/allocators/secure.h>
|
|
#include <sync.h>
|
|
#include <uint256.h>
|
|
#include <util/check.h>
|
|
#include <util/system.h>
|
|
#include <util/ui_change_type.h>
|
|
#include <wallet/context.h>
|
|
#include <wallet/feebumper.h>
|
|
#include <wallet/fees.h>
|
|
#include <wallet/ismine.h>
|
|
#include <wallet/load.h>
|
|
#include <wallet/rpcwallet.h>
|
|
#include <wallet/wallet.h>
|
|
|
|
#include <memory>
|
|
#include <string>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
using interfaces::Chain;
|
|
using interfaces::FoundBlock;
|
|
using interfaces::Handler;
|
|
using interfaces::MakeHandler;
|
|
using interfaces::Wallet;
|
|
using interfaces::WalletAddress;
|
|
using interfaces::WalletBalances;
|
|
using interfaces::WalletClient;
|
|
using interfaces::WalletOrderForm;
|
|
using interfaces::WalletTx;
|
|
using interfaces::WalletTxOut;
|
|
using interfaces::WalletTxStatus;
|
|
using interfaces::WalletValueMap;
|
|
|
|
namespace wallet {
|
|
namespace {
|
|
//! Construct wallet tx struct.
|
|
WalletTx MakeWalletTx(CWallet& wallet, const CWalletTx& wtx)
|
|
{
|
|
LOCK(wallet.cs_wallet);
|
|
WalletTx result;
|
|
result.tx = wtx.tx;
|
|
result.txin_is_mine.reserve(wtx.tx->vin.size());
|
|
for (const auto& txin : wtx.tx->vin) {
|
|
result.txin_is_mine.emplace_back(wallet.IsMine(txin));
|
|
}
|
|
result.txout_is_mine.reserve(wtx.tx->vout.size());
|
|
result.txout_address.reserve(wtx.tx->vout.size());
|
|
result.txout_address_is_mine.reserve(wtx.tx->vout.size());
|
|
for (const auto& txout : wtx.tx->vout) {
|
|
result.txout_is_mine.emplace_back(wallet.IsMine(txout));
|
|
result.txout_address.emplace_back();
|
|
result.txout_address_is_mine.emplace_back(ExtractDestination(txout.scriptPubKey, result.txout_address.back()) ?
|
|
wallet.IsMine(result.txout_address.back()) :
|
|
ISMINE_NO);
|
|
}
|
|
result.credit = wtx.GetCredit(ISMINE_ALL);
|
|
result.debit = wtx.GetDebit(ISMINE_ALL);
|
|
result.change = wtx.GetChange();
|
|
result.time = wtx.GetTxTime();
|
|
result.value_map = wtx.mapValue;
|
|
result.is_coinbase = wtx.IsCoinBase();
|
|
return result;
|
|
}
|
|
|
|
//! Construct wallet tx status struct.
|
|
WalletTxStatus MakeWalletTxStatus(const CWallet& wallet, const CWalletTx& wtx)
|
|
{
|
|
WalletTxStatus result;
|
|
result.block_height = wtx.m_confirm.block_height > 0 ? wtx.m_confirm.block_height : std::numeric_limits<int>::max();
|
|
result.blocks_to_maturity = wtx.GetBlocksToMaturity();
|
|
result.depth_in_main_chain = wtx.GetDepthInMainChain();
|
|
result.time_received = wtx.nTimeReceived;
|
|
result.lock_time = wtx.tx->nLockTime;
|
|
result.is_final = wallet.chain().checkFinalTx(*wtx.tx);
|
|
result.is_trusted = wtx.IsTrusted();
|
|
result.is_abandoned = wtx.isAbandoned();
|
|
result.is_coinbase = wtx.IsCoinBase();
|
|
result.is_in_main_chain = wtx.IsInMainChain();
|
|
return result;
|
|
}
|
|
|
|
//! Construct wallet TxOut struct.
|
|
WalletTxOut MakeWalletTxOut(const CWallet& wallet,
|
|
const CWalletTx& wtx,
|
|
int n,
|
|
int depth) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
|
|
{
|
|
WalletTxOut result;
|
|
result.txout = wtx.tx->vout[n];
|
|
result.time = wtx.GetTxTime();
|
|
result.depth_in_main_chain = depth;
|
|
result.is_spent = wallet.IsSpent(wtx.GetHash(), n);
|
|
return result;
|
|
}
|
|
|
|
class WalletImpl : public Wallet
|
|
{
|
|
public:
|
|
explicit WalletImpl(const std::shared_ptr<CWallet>& wallet) : m_wallet(wallet) {}
|
|
|
|
bool encryptWallet(const SecureString& wallet_passphrase) override
|
|
{
|
|
return m_wallet->EncryptWallet(wallet_passphrase);
|
|
}
|
|
bool isCrypted() override { return m_wallet->IsCrypted(); }
|
|
bool lock() override { return m_wallet->Lock(); }
|
|
bool unlock(const SecureString& wallet_passphrase) override { return m_wallet->Unlock(wallet_passphrase); }
|
|
bool isLocked() override { return m_wallet->IsLocked(); }
|
|
bool changeWalletPassphrase(const SecureString& old_wallet_passphrase,
|
|
const SecureString& new_wallet_passphrase) override
|
|
{
|
|
return m_wallet->ChangeWalletPassphrase(old_wallet_passphrase, new_wallet_passphrase);
|
|
}
|
|
void abortRescan() override { m_wallet->AbortRescan(); }
|
|
bool backupWallet(const std::string& filename) override { return m_wallet->BackupWallet(filename); }
|
|
std::string getWalletName() override { return m_wallet->GetName(); }
|
|
bool getNewDestination(const OutputType type, const std::string label, CTxDestination& dest) override
|
|
{
|
|
LOCK(m_wallet->cs_wallet);
|
|
std::string error;
|
|
return m_wallet->GetNewDestination(type, label, dest, error);
|
|
}
|
|
bool getPubKey(const CScript& script, const CKeyID& address, CPubKey& pub_key) override
|
|
{
|
|
std::unique_ptr<SigningProvider> provider = m_wallet->GetSolvingProvider(script);
|
|
if (provider) {
|
|
return provider->GetPubKey(address, pub_key);
|
|
}
|
|
return false;
|
|
}
|
|
SigningResult signMessage(const std::string& message, const PKHash& pkhash, std::string& str_sig) override
|
|
{
|
|
return m_wallet->SignMessage(message, pkhash, str_sig);
|
|
}
|
|
bool isSpendable(const CTxDestination& dest) override
|
|
{
|
|
LOCK(m_wallet->cs_wallet);
|
|
return m_wallet->IsMine(dest) & ISMINE_SPENDABLE;
|
|
}
|
|
bool haveWatchOnly() override
|
|
{
|
|
auto spk_man = m_wallet->GetLegacyScriptPubKeyMan();
|
|
if (spk_man) {
|
|
return spk_man->HaveWatchOnly();
|
|
}
|
|
return false;
|
|
};
|
|
bool setAddressBook(const CTxDestination& dest, const std::string& name, const std::string& purpose) override
|
|
{
|
|
return m_wallet->SetAddressBook(dest, name, purpose);
|
|
}
|
|
bool delAddressBook(const CTxDestination& dest) override
|
|
{
|
|
return m_wallet->DelAddressBook(dest);
|
|
}
|
|
bool getAddress(const CTxDestination& dest,
|
|
std::string* name,
|
|
isminetype* is_mine,
|
|
std::string* purpose) override
|
|
{
|
|
LOCK(m_wallet->cs_wallet);
|
|
auto it = m_wallet->m_address_book.find(dest);
|
|
if (it == m_wallet->m_address_book.end() || it->second.IsChange()) {
|
|
return false;
|
|
}
|
|
if (name) {
|
|
*name = it->second.GetLabel();
|
|
}
|
|
if (is_mine) {
|
|
*is_mine = m_wallet->IsMine(dest);
|
|
}
|
|
if (purpose) {
|
|
*purpose = it->second.purpose;
|
|
}
|
|
return true;
|
|
}
|
|
std::vector<WalletAddress> getAddresses() override
|
|
{
|
|
LOCK(m_wallet->cs_wallet);
|
|
std::vector<WalletAddress> result;
|
|
for (const auto& item : m_wallet->m_address_book) {
|
|
if (item.second.IsChange()) continue;
|
|
result.emplace_back(item.first, m_wallet->IsMine(item.first), item.second.GetLabel(), item.second.purpose);
|
|
}
|
|
return result;
|
|
}
|
|
std::vector<std::string> getAddressReceiveRequests() override {
|
|
LOCK(m_wallet->cs_wallet);
|
|
return m_wallet->GetAddressReceiveRequests();
|
|
}
|
|
bool setAddressReceiveRequest(const CTxDestination& dest, const std::string& id, const std::string& value) override {
|
|
LOCK(m_wallet->cs_wallet);
|
|
WalletBatch batch{m_wallet->GetDatabase()};
|
|
return m_wallet->SetAddressReceiveRequest(batch, dest, id, value);
|
|
}
|
|
void lockCoin(const COutPoint& output) override
|
|
{
|
|
LOCK(m_wallet->cs_wallet);
|
|
return m_wallet->LockCoin(output);
|
|
}
|
|
void unlockCoin(const COutPoint& output) override
|
|
{
|
|
LOCK(m_wallet->cs_wallet);
|
|
return m_wallet->UnlockCoin(output);
|
|
}
|
|
bool isLockedCoin(const COutPoint& output) override
|
|
{
|
|
LOCK(m_wallet->cs_wallet);
|
|
return m_wallet->IsLockedCoin(output.hash, output.n);
|
|
}
|
|
void listLockedCoins(std::vector<COutPoint>& outputs) override
|
|
{
|
|
LOCK(m_wallet->cs_wallet);
|
|
return m_wallet->ListLockedCoins(outputs);
|
|
}
|
|
CTransactionRef createTransaction(const std::vector<CRecipient>& recipients,
|
|
const CCoinControl& coin_control,
|
|
bool sign,
|
|
int& change_pos,
|
|
CAmount& fee,
|
|
bilingual_str& fail_reason) override
|
|
{
|
|
LOCK(m_wallet->cs_wallet);
|
|
CTransactionRef tx;
|
|
FeeCalculation fee_calc_out;
|
|
if (!m_wallet->CreateTransaction(recipients, tx, fee, change_pos,
|
|
fail_reason, coin_control, fee_calc_out, sign)) {
|
|
return {};
|
|
}
|
|
return tx;
|
|
}
|
|
void commitTransaction(CTransactionRef tx,
|
|
WalletValueMap value_map,
|
|
WalletOrderForm order_form) override
|
|
{
|
|
LOCK(m_wallet->cs_wallet);
|
|
m_wallet->CommitTransaction(std::move(tx), std::move(value_map), std::move(order_form));
|
|
}
|
|
bool transactionCanBeAbandoned(const uint256& txid) override { return m_wallet->TransactionCanBeAbandoned(txid); }
|
|
bool abandonTransaction(const uint256& txid) override
|
|
{
|
|
LOCK(m_wallet->cs_wallet);
|
|
return m_wallet->AbandonTransaction(txid);
|
|
}
|
|
bool transactionCanBeBumped(const uint256& txid) override
|
|
{
|
|
return feebumper::TransactionCanBeBumped(*m_wallet.get(), txid);
|
|
}
|
|
bool createBumpTransaction(const uint256& txid,
|
|
const CCoinControl& coin_control,
|
|
std::vector<bilingual_str>& errors,
|
|
CAmount& old_fee,
|
|
CAmount& new_fee,
|
|
CMutableTransaction& mtx) override
|
|
{
|
|
return feebumper::CreateRateBumpTransaction(*m_wallet.get(), txid, coin_control, errors, old_fee, new_fee, mtx) == feebumper::Result::OK;
|
|
}
|
|
bool signBumpTransaction(CMutableTransaction& mtx) override { return feebumper::SignTransaction(*m_wallet.get(), mtx); }
|
|
bool commitBumpTransaction(const uint256& txid,
|
|
CMutableTransaction&& mtx,
|
|
std::vector<bilingual_str>& errors,
|
|
uint256& bumped_txid) override
|
|
{
|
|
return feebumper::CommitTransaction(*m_wallet.get(), txid, std::move(mtx), errors, bumped_txid) ==
|
|
feebumper::Result::OK;
|
|
}
|
|
CTransactionRef getTx(const uint256& txid) override
|
|
{
|
|
LOCK(m_wallet->cs_wallet);
|
|
auto mi = m_wallet->mapWallet.find(txid);
|
|
if (mi != m_wallet->mapWallet.end()) {
|
|
return mi->second.tx;
|
|
}
|
|
return {};
|
|
}
|
|
WalletTx getWalletTx(const uint256& txid) override
|
|
{
|
|
LOCK(m_wallet->cs_wallet);
|
|
auto mi = m_wallet->mapWallet.find(txid);
|
|
if (mi != m_wallet->mapWallet.end()) {
|
|
return MakeWalletTx(*m_wallet, mi->second);
|
|
}
|
|
return {};
|
|
}
|
|
std::vector<WalletTx> getWalletTxs() override
|
|
{
|
|
LOCK(m_wallet->cs_wallet);
|
|
std::vector<WalletTx> result;
|
|
result.reserve(m_wallet->mapWallet.size());
|
|
for (const auto& entry : m_wallet->mapWallet) {
|
|
result.emplace_back(MakeWalletTx(*m_wallet, entry.second));
|
|
}
|
|
return result;
|
|
}
|
|
bool tryGetTxStatus(const uint256& txid,
|
|
interfaces::WalletTxStatus& tx_status,
|
|
int& num_blocks,
|
|
int64_t& block_time) override
|
|
{
|
|
TRY_LOCK(m_wallet->cs_wallet, locked_wallet);
|
|
if (!locked_wallet) {
|
|
return false;
|
|
}
|
|
auto mi = m_wallet->mapWallet.find(txid);
|
|
if (mi == m_wallet->mapWallet.end()) {
|
|
return false;
|
|
}
|
|
num_blocks = m_wallet->GetLastBlockHeight();
|
|
block_time = -1;
|
|
CHECK_NONFATAL(m_wallet->chain().findBlock(m_wallet->GetLastBlockHash(), FoundBlock().time(block_time)));
|
|
tx_status = MakeWalletTxStatus(*m_wallet, mi->second);
|
|
return true;
|
|
}
|
|
WalletTx getWalletTxDetails(const uint256& txid,
|
|
WalletTxStatus& tx_status,
|
|
WalletOrderForm& order_form,
|
|
bool& in_mempool,
|
|
int& num_blocks) override
|
|
{
|
|
LOCK(m_wallet->cs_wallet);
|
|
auto mi = m_wallet->mapWallet.find(txid);
|
|
if (mi != m_wallet->mapWallet.end()) {
|
|
num_blocks = m_wallet->GetLastBlockHeight();
|
|
in_mempool = mi->second.InMempool();
|
|
order_form = mi->second.vOrderForm;
|
|
tx_status = MakeWalletTxStatus(*m_wallet, mi->second);
|
|
return MakeWalletTx(*m_wallet, mi->second);
|
|
}
|
|
return {};
|
|
}
|
|
TransactionError fillPSBT(int sighash_type,
|
|
bool sign,
|
|
bool bip32derivs,
|
|
PartiallySignedTransaction& psbtx,
|
|
bool& complete,
|
|
size_t* n_signed) override
|
|
{
|
|
return m_wallet->FillPSBT(psbtx, complete, sighash_type, sign, bip32derivs, n_signed);
|
|
}
|
|
WalletBalances getBalances() override
|
|
{
|
|
const auto bal = m_wallet->GetBalance();
|
|
WalletBalances result;
|
|
result.balance = bal.m_mine_trusted;
|
|
result.unconfirmed_balance = bal.m_mine_untrusted_pending;
|
|
result.immature_balance = bal.m_mine_immature;
|
|
result.have_watch_only = haveWatchOnly();
|
|
if (result.have_watch_only) {
|
|
result.watch_only_balance = bal.m_watchonly_trusted;
|
|
result.unconfirmed_watch_only_balance = bal.m_watchonly_untrusted_pending;
|
|
result.immature_watch_only_balance = bal.m_watchonly_immature;
|
|
}
|
|
return result;
|
|
}
|
|
bool tryGetBalances(WalletBalances& balances, uint256& block_hash) override
|
|
{
|
|
TRY_LOCK(m_wallet->cs_wallet, locked_wallet);
|
|
if (!locked_wallet) {
|
|
return false;
|
|
}
|
|
block_hash = m_wallet->GetLastBlockHash();
|
|
balances = getBalances();
|
|
return true;
|
|
}
|
|
CAmount getBalance() override { return m_wallet->GetBalance().m_mine_trusted; }
|
|
CAmount getAvailableBalance(const CCoinControl& coin_control) override
|
|
{
|
|
return m_wallet->GetAvailableBalance(&coin_control);
|
|
}
|
|
isminetype txinIsMine(const CTxIn& txin) override
|
|
{
|
|
LOCK(m_wallet->cs_wallet);
|
|
return m_wallet->IsMine(txin);
|
|
}
|
|
isminetype txoutIsMine(const CTxOut& txout) override
|
|
{
|
|
LOCK(m_wallet->cs_wallet);
|
|
return m_wallet->IsMine(txout);
|
|
}
|
|
CAmount getDebit(const CTxIn& txin, isminefilter filter) override
|
|
{
|
|
LOCK(m_wallet->cs_wallet);
|
|
return m_wallet->GetDebit(txin, filter);
|
|
}
|
|
CAmount getCredit(const CTxOut& txout, isminefilter filter) override
|
|
{
|
|
LOCK(m_wallet->cs_wallet);
|
|
return m_wallet->GetCredit(txout, filter);
|
|
}
|
|
CoinsList listCoins() override
|
|
{
|
|
LOCK(m_wallet->cs_wallet);
|
|
CoinsList result;
|
|
for (const auto& entry : m_wallet->ListCoins()) {
|
|
auto& group = result[entry.first];
|
|
for (const auto& coin : entry.second) {
|
|
group.emplace_back(COutPoint(coin.tx->GetHash(), coin.i),
|
|
MakeWalletTxOut(*m_wallet, *coin.tx, coin.i, coin.nDepth));
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
std::vector<WalletTxOut> getCoins(const std::vector<COutPoint>& outputs) override
|
|
{
|
|
LOCK(m_wallet->cs_wallet);
|
|
std::vector<WalletTxOut> result;
|
|
result.reserve(outputs.size());
|
|
for (const auto& output : outputs) {
|
|
result.emplace_back();
|
|
auto it = m_wallet->mapWallet.find(output.hash);
|
|
if (it != m_wallet->mapWallet.end()) {
|
|
int depth = it->second.GetDepthInMainChain();
|
|
if (depth >= 0) {
|
|
result.back() = MakeWalletTxOut(*m_wallet, it->second, output.n, depth);
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
CAmount getRequiredFee(unsigned int tx_bytes) override { return GetRequiredFee(*m_wallet, tx_bytes); }
|
|
CAmount getMinimumFee(unsigned int tx_bytes,
|
|
const CCoinControl& coin_control,
|
|
int* returned_target,
|
|
FeeReason* reason) override
|
|
{
|
|
FeeCalculation fee_calc;
|
|
CAmount result;
|
|
result = GetMinimumFee(*m_wallet, tx_bytes, coin_control, &fee_calc);
|
|
if (returned_target) *returned_target = fee_calc.returnedTarget;
|
|
if (reason) *reason = fee_calc.reason;
|
|
return result;
|
|
}
|
|
unsigned int getConfirmTarget() override { return m_wallet->m_confirm_target; }
|
|
bool hdEnabled() override { return m_wallet->IsHDEnabled(); }
|
|
bool canGetAddresses() override { return m_wallet->CanGetAddresses(); }
|
|
bool privateKeysDisabled() override { return m_wallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS); }
|
|
OutputType getDefaultAddressType() override { return m_wallet->m_default_address_type; }
|
|
CAmount getDefaultMaxTxFee() override { return m_wallet->m_default_max_tx_fee; }
|
|
void remove() override
|
|
{
|
|
RemoveWallet(m_wallet, false /* load_on_start */);
|
|
}
|
|
bool isLegacy() override { return m_wallet->IsLegacy(); }
|
|
std::unique_ptr<Handler> handleUnload(UnloadFn fn) override
|
|
{
|
|
return MakeHandler(m_wallet->NotifyUnload.connect(fn));
|
|
}
|
|
std::unique_ptr<Handler> handleShowProgress(ShowProgressFn fn) override
|
|
{
|
|
return MakeHandler(m_wallet->ShowProgress.connect(fn));
|
|
}
|
|
std::unique_ptr<Handler> handleStatusChanged(StatusChangedFn fn) override
|
|
{
|
|
return MakeHandler(m_wallet->NotifyStatusChanged.connect([fn](CWallet*) { fn(); }));
|
|
}
|
|
std::unique_ptr<Handler> handleAddressBookChanged(AddressBookChangedFn fn) override
|
|
{
|
|
return MakeHandler(m_wallet->NotifyAddressBookChanged.connect(
|
|
[fn](CWallet*, const CTxDestination& address, const std::string& label, bool is_mine,
|
|
const std::string& purpose, ChangeType status) { fn(address, label, is_mine, purpose, status); }));
|
|
}
|
|
std::unique_ptr<Handler> handleTransactionChanged(TransactionChangedFn fn) override
|
|
{
|
|
return MakeHandler(m_wallet->NotifyTransactionChanged.connect(
|
|
[fn](CWallet*, const uint256& txid, ChangeType status) { fn(txid, status); }));
|
|
}
|
|
std::unique_ptr<Handler> handleWatchOnlyChanged(WatchOnlyChangedFn fn) override
|
|
{
|
|
return MakeHandler(m_wallet->NotifyWatchonlyChanged.connect(fn));
|
|
}
|
|
std::unique_ptr<Handler> handleCanGetAddressesChanged(CanGetAddressesChangedFn fn) override
|
|
{
|
|
return MakeHandler(m_wallet->NotifyCanGetAddressesChanged.connect(fn));
|
|
}
|
|
CWallet* wallet() override { return m_wallet.get(); }
|
|
|
|
std::shared_ptr<CWallet> m_wallet;
|
|
};
|
|
|
|
class WalletClientImpl : public WalletClient
|
|
{
|
|
public:
|
|
WalletClientImpl(Chain& chain, ArgsManager& args)
|
|
{
|
|
m_context.chain = &chain;
|
|
m_context.args = &args;
|
|
}
|
|
~WalletClientImpl() override { UnloadWallets(); }
|
|
|
|
//! ChainClient methods
|
|
void registerRpcs() override
|
|
{
|
|
for (const CRPCCommand& command : GetWalletRPCCommands()) {
|
|
m_rpc_commands.emplace_back(command.category, command.name, [this, &command](const JSONRPCRequest& request, UniValue& result, bool last_handler) {
|
|
JSONRPCRequest wallet_request = request;
|
|
wallet_request.context = &m_context;
|
|
return command.actor(wallet_request, result, last_handler);
|
|
}, command.argNames, command.unique_id);
|
|
m_rpc_handlers.emplace_back(m_context.chain->handleRpc(m_rpc_commands.back()));
|
|
}
|
|
}
|
|
bool verify() override { return VerifyWallets(*m_context.chain); }
|
|
bool load() override { return LoadWallets(*m_context.chain); }
|
|
void start(CScheduler& scheduler) override { return StartWallets(scheduler, *Assert(m_context.args)); }
|
|
void flush() override { return FlushWallets(); }
|
|
void stop() override { return StopWallets(); }
|
|
void setMockTime(int64_t time) override { return SetMockTime(time); }
|
|
|
|
//! WalletClient methods
|
|
std::unique_ptr<Wallet> createWallet(const std::string& name, const SecureString& passphrase, uint64_t wallet_creation_flags, bilingual_str& error, std::vector<bilingual_str>& warnings) override
|
|
{
|
|
std::shared_ptr<CWallet> wallet;
|
|
DatabaseOptions options;
|
|
DatabaseStatus status;
|
|
options.require_create = true;
|
|
options.create_flags = wallet_creation_flags;
|
|
options.create_passphrase = passphrase;
|
|
return MakeWallet(CreateWallet(*m_context.chain, name, true /* load_on_start */, options, status, error, warnings));
|
|
}
|
|
std::unique_ptr<Wallet> loadWallet(const std::string& name, bilingual_str& error, std::vector<bilingual_str>& warnings) override
|
|
{
|
|
DatabaseOptions options;
|
|
DatabaseStatus status;
|
|
options.require_existing = true;
|
|
return MakeWallet(LoadWallet(*m_context.chain, name, true /* load_on_start */, options, status, error, warnings));
|
|
}
|
|
std::string getWalletDir() override
|
|
{
|
|
return GetWalletDir().string();
|
|
}
|
|
std::vector<std::string> listWalletDir() override
|
|
{
|
|
std::vector<std::string> paths;
|
|
for (auto& path : ListDatabases(GetWalletDir())) {
|
|
paths.push_back(path.string());
|
|
}
|
|
return paths;
|
|
}
|
|
std::vector<std::unique_ptr<Wallet>> getWallets() override
|
|
{
|
|
std::vector<std::unique_ptr<Wallet>> wallets;
|
|
for (const auto& wallet : GetWallets()) {
|
|
wallets.emplace_back(MakeWallet(wallet));
|
|
}
|
|
return wallets;
|
|
}
|
|
std::unique_ptr<Handler> handleLoadWallet(LoadWalletFn fn) override
|
|
{
|
|
return HandleLoadWallet(std::move(fn));
|
|
}
|
|
|
|
WalletContext m_context;
|
|
const std::vector<std::string> m_wallet_filenames;
|
|
std::vector<std::unique_ptr<Handler>> m_rpc_handlers;
|
|
std::list<CRPCCommand> m_rpc_commands;
|
|
};
|
|
} // namespace
|
|
} // namespace wallet
|
|
|
|
namespace interfaces {
|
|
std::unique_ptr<Wallet> MakeWallet(const std::shared_ptr<CWallet>& wallet) { return wallet ? std::make_unique<wallet::WalletImpl>(wallet) : nullptr; }
|
|
|
|
std::unique_ptr<WalletClient> MakeWalletClient(Chain& chain, ArgsManager& args)
|
|
{
|
|
return std::make_unique<wallet::WalletClientImpl>(chain, args);
|
|
}
|
|
} // namespace interfaces
|