6 #include <bitcoin-build-config.h> 22 #include <string_view> 29 "You need to rescan the blockchain in order to correctly mark used " 30 "destinations in the past. Until this is done, some destinations may " 31 "be considered unused, even if the opposite is the case."},
37 "Returns an object containing various wallet state info.\n",
44 {
RPCResult::Type::NUM,
"walletversion",
"(DEPRECATED) only related to unsupported legacy wallet, returns the latest version 169900 for backwards compatibility"},
47 {
RPCResult::Type::NUM,
"keypoolsize",
"how many new keys are pre-generated (only counts external keys)"},
48 {
RPCResult::Type::NUM,
"keypoolsize_hd_internal",
true,
"how many new keys are pre-generated for internal use (used for change outputs, only appears if the wallet is using this feature, otherwise external keys are used)"},
49 {
RPCResult::Type::NUM_TIME,
"unlocked_until",
true,
"the " +
UNIX_EPOCH_TIME +
" until which the wallet is unlocked for transfers, or 0 if the wallet is locked (only present for passphrase-encrypted wallets)"},
50 {
RPCResult::Type::BOOL,
"private_keys_enabled",
"false if privatekeys are disabled for this wallet (enforced watch-only wallet)"},
51 {
RPCResult::Type::BOOL,
"avoid_reuse",
"whether this wallet tracks clean/dirty coins in terms of reuse"},
52 {
RPCResult::Type::OBJ,
"scanning",
"current scanning details, or false if no scan is in progress",
57 {
RPCResult::Type::BOOL,
"descriptors",
"whether this wallet uses descriptors for output script management"},
58 {
RPCResult::Type::BOOL,
"external_signer",
"whether this wallet is configured to use an external signer such as a hardware wallet"},
59 {
RPCResult::Type::BOOL,
"blank",
"Whether this wallet intentionally does not contain any keys, scripts, or descriptors"},
60 {
RPCResult::Type::NUM_TIME,
"birthtime",
true,
"The start time for blocks scanning. It could be modified by (re)importing any descriptor with an earlier timestamp."},
79 pwallet->BlockUntilSyncedToCurrentChain();
81 LOCK(pwallet->cs_wallet);
85 const int latest_legacy_wallet_minversion{169900};
87 size_t kpExternalSize = pwallet->KeypoolCountExternalKeys();
88 obj.
pushKV(
"walletname", pwallet->GetName());
89 obj.
pushKV(
"walletversion", latest_legacy_wallet_minversion);
90 obj.
pushKV(
"format", pwallet->GetDatabase().Format());
91 obj.
pushKV(
"txcount", pwallet->mapWallet.size());
92 obj.
pushKV(
"keypoolsize", kpExternalSize);
93 obj.
pushKV(
"keypoolsize_hd_internal", pwallet->GetKeyPoolSize() - kpExternalSize);
95 if (pwallet->HasEncryptionKeys()) {
96 obj.
pushKV(
"unlocked_until", pwallet->nRelockTime);
100 if (pwallet->IsScanning()) {
102 scanning.
pushKV(
"duration", Ticks<std::chrono::seconds>(pwallet->ScanningDuration()));
103 scanning.
pushKV(
"progress", pwallet->ScanningProgress());
104 obj.
pushKV(
"scanning", std::move(scanning));
106 obj.
pushKV(
"scanning",
false);
111 if (int64_t birthtime = pwallet->GetBirthTime(); birthtime !=
UNKNOWN_TIME) {
112 obj.
pushKV(
"birthtime", birthtime);
117 uint64_t wallet_flags = pwallet->GetWalletFlags();
118 for (uint64_t i = 0; i < 64; ++i) {
119 uint64_t flag = uint64_t{1} << i;
120 if (flag & wallet_flags) {
139 "Returns a list of wallets in the wallet directory.\n",
149 {
RPCResult::Type::ARR,
"warnings",
true,
"Warning messages, if any, related to loading the wallet.",
166 wallet.pushKV(
"name", path.utf8string());
168 if (db_type ==
"bdb") {
169 warnings.
push_back(
"This wallet is a legacy wallet and will need to be migrated with migratewallet before it can be loaded");
171 wallet.pushKV(
"warnings", warnings);
176 result.pushKV(
"wallets", std::move(wallets));
185 "Returns a list of currently loaded wallets.\n" 186 "For full information on the wallet, use \"getwalletinfo\"\n",
217 "Loads a wallet from a wallet file or directory." 218 "\nNote that all wallet command-line options used when starting bitcoind will be" 219 "\napplied to the new wallet.\n",
221 {
"filename",
RPCArg::Type::STR,
RPCArg::Optional::NO,
"The path to the directory of the wallet to be loaded, either absolute or relative to the \"wallets\" directory. The \"wallets\" directory is set by the -walletdir option and defaults to the \"wallets\" folder within the data directory."},
228 {
RPCResult::Type::ARR,
"warnings",
true,
"Warning messages, if any, related to loading the wallet.",
235 "\nLoad wallet from the wallet dir:\n" 238 +
"\nLoad wallet using absolute path (Unix):\n" 241 +
"\nLoad wallet using absolute path (Windows):\n" 242 +
HelpExampleCli(
"loadwallet",
"\"DriveLetter:\\path\\to\\walletname\\\"")
243 +
HelpExampleRpc(
"loadwallet",
"\"DriveLetter:\\path\\to\\walletname\\\"")
248 const std::string
name(request.params[0].get_str());
253 options.require_existing =
true;
255 std::vector<bilingual_str> warnings;
256 std::optional<bool> load_on_start = request.params[1].isNull() ? std::nullopt : std::optional<bool>(request.params[1].get_bool());
260 if (std::any_of(context.wallets.begin(), context.wallets.end(), [&
name](
const auto&
wallet) {
return wallet->GetName() ==
name; })) {
265 std::shared_ptr<CWallet>
const wallet =
LoadWallet(context,
name, load_on_start, options, status, error, warnings);
283 flags += (
flags ==
"" ?
"" :
", ") + it.first;
287 "Change the state of the given wallet flag for a wallet.\n",
309 std::string flag_str = request.params[0].get_str();
310 bool value = request.params[1].isNull() || request.params[1].get_bool();
324 if (pwallet->IsWalletFlagSet(flag) == value) {
328 res.pushKV(
"flag_name", flag_str);
329 res.pushKV(
"flag_state", value);
332 pwallet->SetWalletFlag(flag);
334 pwallet->UnsetWalletFlag(flag);
350 "Creates and loads a new wallet.\n",
356 {
"avoid_reuse",
RPCArg::Type::BOOL,
RPCArg::Default{
false},
"Keep track of coin reuse, and treat dirty and clean coins differently with privacy considerations in mind."},
359 {
"external_signer",
RPCArg::Type::BOOL,
RPCArg::Default{
false},
"Use an external signer such as a hardware wallet. Requires -signer to be configured. Wallet creation will fail if keys cannot be fetched. Requires disable_private_keys and descriptors set to true."},
364 {
RPCResult::Type::STR,
"name",
"The wallet name if created successfully. If the wallet was created using a full path, the wallet_name will be the full path."},
365 {
RPCResult::Type::ARR,
"warnings",
true,
"Warning messages, if any, related to creating and loading the wallet.",
374 +
HelpExampleCliNamed(
"createwallet", {{
"wallet_name",
"descriptors"}, {
"avoid_reuse",
true}, {
"load_on_startup",
true}})
375 +
HelpExampleRpcNamed(
"createwallet", {{
"wallet_name",
"descriptors"}, {
"avoid_reuse",
true}, {
"load_on_startup",
true}})
381 if (!request.params[1].isNull() && request.params[1].get_bool()) {
385 if (!request.params[2].isNull() && request.params[2].get_bool()) {
389 passphrase.reserve(100);
390 std::vector<bilingual_str> warnings;
391 if (!request.params[3].isNull()) {
392 passphrase = std::string_view{request.params[3].get_str()};
393 if (passphrase.empty()) {
395 warnings.emplace_back(
Untranslated(
"Empty string given as passphrase, wallet will not be encrypted."));
399 if (!request.params[4].isNull() && request.params[4].get_bool()) {
403 if (!
self.Arg<bool>(
"descriptors")) {
404 throw JSONRPCError(
RPC_WALLET_ERROR,
"descriptors argument must be set to \"true\"; it is no longer possible to create a legacy wallet.");
406 if (!request.params[7].isNull() && request.params[7].get_bool()) {
407 #ifdef ENABLE_EXTERNAL_SIGNER 421 std::optional<bool> load_on_start = request.params[6].isNull() ? std::nullopt : std::optional<bool>(request.params[6].get_bool());
422 const std::shared_ptr<CWallet>
wallet =
CreateWallet(context, request.params[0].get_str(), load_on_start, options, status, error, warnings);
437 "Unloads the wallet referenced by the request endpoint or the wallet_name argument.\n" 438 "If both are specified, they must be identical.",
440 {
"wallet_name",
RPCArg::Type::STR,
RPCArg::DefaultHint{
"the wallet name from the RPC endpoint"},
"The name of the wallet to unload. If provided both here and in the RPC endpoint, the two must be identical."},
444 {
RPCResult::Type::ARR,
"warnings",
true,
"Warning messages, if any, related to unloading the wallet.",
455 const std::string wallet_name{
EnsureUniqueWalletName(request,
self.MaybeArg<std::string_view>(
"wallet_name"))};
463 std::vector<bilingual_str> warnings;
473 std::optional<bool> load_on_start{
self.MaybeArg<
bool>(
"load_on_startup")};
492 "simulaterawtransaction",
493 "Calculate the balance change resulting in the signing and broadcasting of the given transaction(s).\n",
524 const auto& txs = request.params[0].get_array();
526 std::map<COutPoint, CAmount> new_utxos;
527 std::set<COutPoint> spent;
529 for (
size_t i = 0; i < txs.size(); ++i) {
531 if (!
DecodeHexTx(mtx, txs[i].get_str(),
true,
true)) {
536 std::map<COutPoint, Coin> coins;
540 wallet.chain().findCoins(coins);
544 for (
const auto& txin : mtx.
vin) {
545 const auto& outpoint = txin.
prevout;
546 if (spent.contains(outpoint)) {
549 if (new_utxos.contains(outpoint)) {
550 changes -= new_utxos.at(outpoint);
551 new_utxos.erase(outpoint);
553 if (coins.at(outpoint).IsSpent()) {
556 changes -=
wallet.GetDebit(txin);
558 spent.insert(outpoint);
566 const auto& hash = mtx.
GetHash();
567 for (
size_t i = 0; i < mtx.
vout.size(); ++i) {
568 const auto& txout = mtx.
vout[i];
569 bool is_mine =
wallet.IsMine(txout);
570 changes += new_utxos[
COutPoint(hash, i)] = is_mine ? txout.nValue : 0;
586 "Migrate the wallet to a descriptor wallet.\n" 587 "A new wallet backup will need to be made.\n" 588 "\nThe migration process will create a backup of the wallet before migrating. This backup\n" 589 "file will be named <wallet name>-<timestamp>.legacy.bak and can be found in the directory\n" 590 "for this wallet. In the event of an incorrect migration, the backup can be restored using restorewallet." 591 "\nEncrypted wallets must have the passphrase provided as an argument to this call.\n" 592 "\nThis RPC may take a long time to complete. Increasing the RPC client timeout is recommended.",
594 {
"wallet_name",
RPCArg::Type::STR,
RPCArg::DefaultHint{
"the wallet name from the RPC endpoint"},
"The name of the wallet to migrate. If provided both here and in the RPC endpoint, the two must be identical."},
601 {
RPCResult::Type::STR,
"watchonly_name",
true,
"The name of the migrated wallet containing the watchonly scripts"},
602 {
RPCResult::Type::STR,
"solvables_name",
true,
"The name of the migrated wallet containing solvable but not watched scripts"},
612 const std::string wallet_name{
EnsureUniqueWalletName(request,
self.MaybeArg<std::string_view>(
"wallet_name"))};
615 wallet_pass.reserve(100);
616 if (!request.params[1].isNull()) {
617 wallet_pass = std::string_view{request.params[1].get_str()};
627 r.pushKV(
"wallet_name", res->wallet_name);
628 if (res->watchonly_wallet) {
629 r.pushKV(
"watchonly_name", res->watchonly_wallet->GetName());
631 if (res->solvables_wallet) {
632 r.pushKV(
"solvables_name", res->solvables_wallet->GetName());
634 r.pushKV(
"backup_path", res->backup_path.utf8string());
645 "List all BIP 32 HD keys in the wallet and which descriptors use them.\n",
662 {
RPCResult::Type::BOOL,
"active",
"Whether this descriptor is currently used to generate new addresses"},
680 const bool active_only{options.exists(
"active_only") ? options[
"active_only"].get_bool() :
false};
681 const bool priv{options.exists(
"private") ? options[
"private"].get_bool() :
false};
687 std::set<ScriptPubKeyMan*> spkms;
689 spkms =
wallet->GetActiveScriptPubKeyMans();
691 spkms =
wallet->GetAllScriptPubKeyMans();
694 std::map<CExtPubKey, std::set<std::tuple<std::string, bool, bool>>> wallet_xpubs;
695 std::map<CExtPubKey, CExtKey> wallet_xprvs;
696 for (
auto* spkm : spkms) {
699 LOCK(desc_spkm->cs_desc_man);
703 std::set<CPubKey> desc_pubkeys;
704 std::set<CExtPubKey> desc_xpubs;
705 w_desc.
descriptor->GetPubKeys(desc_pubkeys, desc_xpubs);
707 std::string desc_str;
708 bool ok = desc_spkm->GetDescriptorString(desc_str,
false);
710 wallet_xpubs[xpub].emplace(desc_str,
wallet->IsActiveScriptPubKeyMan(*spkm), desc_spkm->HasPrivKey(xpub.pubkey.GetID()));
711 if (std::optional<CKey> key = priv ? desc_spkm->GetKey(xpub.pubkey.GetID()) : std::nullopt) {
712 wallet_xprvs[xpub] =
CExtKey(xpub, *key);
718 for (
const auto& [xpub, descs] : wallet_xpubs) {
719 bool has_xprv =
false;
721 for (
const auto& [desc, active, has_priv] : descs) {
724 d.
pushKV(
"active", active);
725 has_xprv |= has_priv;
731 xpub_info.
pushKV(
"has_private", has_xprv);
735 xpub_info.
pushKV(
"descriptors", std::move(descriptors));
737 response.
push_back(std::move(xpub_info));
748 "Creates the wallet's descriptor for the given address type. " 749 "The address type must be one that the wallet does not already have a descriptor for." 754 {
"internal",
RPCArg::Type::BOOL,
RPCArg::DefaultHint{
"Both external and internal will be generated unless this parameter is specified"},
"Whether to only make one descriptor that is internal (if parameter is true) or external (if parameter is false)"},
755 {
"hdkey",
RPCArg::Type::STR,
RPCArg::DefaultHint{
"The HD key used by all other active descriptors"},
"The HD key that the wallet knows the private key of, listed using 'gethdkeys', to use for this descriptor's key"},
775 std::optional<OutputType> output_type =
ParseOutputType(request.params[0].get_str());
781 UniValue internal_only{options[
"internal"]};
784 std::vector<bool> internals;
785 if (internal_only.isNull()) {
787 internals.push_back(
true);
789 internals.push_back(internal_only.get_bool());
792 LOCK(pwallet->cs_wallet);
796 if (hdkey.isNull()) {
797 std::set<CExtPubKey> active_xpubs = pwallet->GetActiveHDPubKeys();
798 if (active_xpubs.size() != 1) {
801 xpub = *active_xpubs.begin();
809 std::optional<CKey> key = pwallet->GetKey(xpub.
pubkey.
GetID());
813 CExtKey active_hdkey(xpub, *key);
815 std::vector<std::reference_wrapper<DescriptorScriptPubKeyMan>> spkms;
817 for (
bool internal : internals) {
820 if (!pwallet->GetScriptPubKeyMan(w_id)) {
821 spkms.emplace_back(pwallet->SetupDescriptorScriptPubKeyMan(batch, active_hdkey, *output_type,
internal));
830 for (
const auto& spkm : spkms) {
831 std::string desc_str;
832 bool ok = spkm.get().GetDescriptorString(desc_str,
false);
834 descs.push_back(desc_str);
837 out.pushKV(
"descs", std::move(descs));
852 #ifdef ENABLE_EXTERNAL_SIGNER 854 #endif // ENABLE_EXTERNAL_SIGNER 958 #ifdef ENABLE_EXTERNAL_SIGNER 960 #endif // ENABLE_EXTERNAL_SIGNER
void push_back(UniValue val)
void ReadDatabaseArgs(const ArgsManager &args, DatabaseOptions &options)
RPCHelpMan listlockunspent()
static RPCHelpMan listwalletdir()
RPCHelpMan simulaterawtransaction()
static RPCHelpMan setwalletflag()
std::string HelpExampleRpcNamed(const std::string &methodname, const RPCArgList &args)
static const std::map< std::string, WalletFlags > STRING_TO_WALLET_FLAG
UniValue ValueFromAmount(const CAmount amount)
RPCHelpMan restorewallet()
std::vector< std::pair< fs::path, std::string > > ListDatabases(const fs::path &wallet_dir)
Recursively list database paths in directory.
static RPCHelpMan loadwallet()
RPCHelpMan walletpassphrase()
RPCHelpMan sendtoaddress()
RPCHelpMan getreceivedbylabel()
WalletDescriptor GenerateWalletDescriptor(const CExtPubKey &master_key, const OutputType &addr_type, bool internal)
bilingual_str Untranslated(std::string original)
Mark a bilingual_str as untranslated.
std::shared_ptr< CWallet > LoadWallet(WalletContext &context, const std::string &name, std::optional< bool > load_on_start, const DatabaseOptions &options, DatabaseStatus &status, bilingual_str &error, std::vector< bilingual_str > &warnings)
RPCHelpMan listtransactions()
RPCHelpMan abandontransaction()
#define CHECK_NONFATAL(condition)
Identity function.
Special type that behaves almost exactly like OBJ, defining an options object with a list of pre-defi...
std::basic_string< char, std::char_traits< char >, secure_allocator< char > > SecureString
RAII object to check and reserve a wallet rescan.
static const RPCResult RESULT_LAST_PROCESSED_BLOCK
bool reserve(bool with_passphrase=false)
RPCHelpMan getaddressinfo()
Access to the wallet database.
fs::path GetWalletDir()
Get the path of the wallet directory.
CExtPubKey DecodeExtPubKey(const std::string &str)
This same wallet is already loaded.
CKeyID GetID() const
Get the KeyID of this public key (hash of its serialization)
Flag set when a wallet contains no HD seed and no private keys, scripts, addresses, and other watch only things, and is therefore "blank.".
Invalid, missing or duplicate parameter.
static constexpr uint64_t MUTABLE_WALLET_FLAGS
static RPCHelpMan getwalletinfo()
static RPCHelpMan unloadwallet()
RPCHelpMan rescanblockchain()
RPCHelpMan walletdisplayaddress()
RPCHelpMan walletcreatefundedpsbt()
int64_t CAmount
Amount in satoshis (Can be negative)
Special type that is a STR with only hex chars.
RPCHelpMan walletpassphrasechange()
Indicates that the wallet needs an external signer.
void HandleWalletError(const std::shared_ptr< CWallet > &wallet, DatabaseStatus &status, bilingual_str &error)
std::string HelpExampleRpc(const std::string &methodname, const std::string &args)
RPCHelpMan fundrawtransaction()
static constexpr int64_t UNKNOWN_TIME
Constant representing an unknown spkm creation time.
std::string FormatAllOutputTypes()
UniValue JSONRPCError(int code, const std::string &message)
void WaitForDeleteWallet(std::shared_ptr< CWallet > &&wallet)
Explicitly delete the wallet.
RPCHelpMan signrawtransactionwithwallet()
SecureString create_passphrase
RPCHelpMan listsinceblock()
bool RemoveWallet(WalletContext &context, const std::shared_ptr< CWallet > &wallet, std::optional< bool > load_on_start)
RPCHelpMan walletprocesspsbt()
An input of a transaction.
static constexpr uint64_t KNOWN_WALLET_FLAGS
static RPCHelpMan createwallet()
static const std::map< WalletFlags, std::string > WALLET_FLAG_TO_STRING
RPCHelpMan listreceivedbylabel()
std::shared_ptr< Descriptor > descriptor
std::string EnsureUniqueWalletName(const JSONRPCRequest &request, std::optional< std::string_view > wallet_name)
Ensures that a wallet name is specified across the endpoint and wallet_name.
WalletContext & EnsureWalletContext(const std::any &context)
RPCHelpMan listdescriptors()
Indicate that this wallet supports DescriptorScriptPubKeyMan.
A CWallet maintains a set of transactions and balances, and provides the ability to create new transa...
General application defined errors.
std::string DefaultHint
Hint for default value.
util::Result< MigrationResult > MigrateLegacyToDescriptor(std::shared_ptr< CWallet > local_wallet, const SecureString &passphrase, WalletContext &context)
Requirement: The wallet provided to this function must be isolated, with no attachment to the node's ...
std::string HelpExampleCliNamed(const std::string &methodname, const RPCArgList &args)
void PushWarnings(const UniValue &warnings, UniValue &obj)
Push warning messages to an RPC "warnings" field as a JSON array of strings.
void ReadDatabaseArgs(const ArgsManager &args, DBOptions &options)
Txid GetHash() const
Compute the hash of this CMutableTransaction.
Invalid wallet specified.
An outpoint - a combination of a transaction hash and an index n into its vout.
std::string HelpExampleCli(const std::string &methodname, const std::string &args)
std::vector< CTxOut > vout
const std::string HELP_REQUIRING_PASSPHRASE
Special numeric to denote unix epoch time.
RPCHelpMan listreceivedbyaddress()
RPCHelpMan importdescriptors()
Descriptor with some wallet metadata.
RPCHelpMan encryptwallet()
std::shared_ptr< CWallet > GetWallet(WalletContext &context, const std::string &name)
Optional argument for which the default value is omitted from help text for one of two reasons: ...
std::string EncodeExtPubKey(const CExtPubKey &key)
std::vector< std::shared_ptr< CWallet > > GetWallets(WalletContext &context)
RPCHelpMan importprunedfunds()
Special string to represent a floating point amount.
void pushKV(std::string key, UniValue val)
RPCHelpMan gettransaction()
bool DecodeHexTx(CMutableTransaction &tx, const std::string &hex_tx, bool try_no_witness, bool try_witness)
RPCHelpMan getaddressesbylabel()
uint256 DescriptorID(const Descriptor &desc)
Unique identifier that may not change over time, unless explicitly marked as not backwards compatible...
WalletContext struct containing references to state shared between CWallet instances, like the reference to the chain interface, and the list of opened wallets.
void EnsureWalletIsUnlocked(const CWallet &wallet)
std::span< const CRPCCommand > GetWalletRPCCommands()
bilingual_str ErrorString(const Result< T > &result)
RPCHelpMan keypoolrefill()
A mutable version of CTransaction.
RPCHelpMan getreceivedbyaddress()
RPCHelpMan listaddressgroupings()
RPCHelpMan removeprunedfunds()
RPCHelpMan backupwallet()
static RPCHelpMan migratewallet()
std::shared_ptr< CWallet > CreateWallet(WalletContext &context, const std::string &name, std::optional< bool > load_on_start, DatabaseOptions &options, DatabaseStatus &status, bilingual_str &error, std::vector< bilingual_str > &warnings)
std::optional< OutputType > ParseOutputType(std::string_view type)
RPCHelpMan getnewaddress()
static RPCHelpMan listwallets()
static RPCHelpMan createwalletdescriptor()
RPCHelpMan getrawchangeaddress()
std::string EncodeExtKey(const CExtKey &key)
void AppendLastProcessedBlock(UniValue &entry, const CWallet &wallet)
std::shared_ptr< CWallet > GetWalletForJSONRPCRequest(const JSONRPCRequest &request)
Figures out what wallet, if any, to use for a JSONRPCRequest.
static const std::map< uint64_t, std::string > WALLET_FLAG_CAVEATS
Error parsing or validating structure in raw format.
const std::string UNIX_EPOCH_TIME
String used to describe UNIX epoch time in documentation, factored out to a constant for consistency...