aboutsummaryrefslogtreecommitdiff
path: root/src/wallet/rpcwallet.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/wallet/rpcwallet.cpp')
-rw-r--r--src/wallet/rpcwallet.cpp928
1 files changed, 613 insertions, 315 deletions
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index 9364d18d30..c34b166a41 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -4,18 +4,19 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <amount.h>
-#include <base58.h>
#include <chain.h>
#include <consensus/validation.h>
#include <core_io.h>
#include <httpserver.h>
#include <validation.h>
+#include <key_io.h>
#include <net.h>
#include <policy/feerate.h>
#include <policy/fees.h>
#include <policy/policy.h>
#include <policy/rbf.h>
#include <rpc/mining.h>
+#include <rpc/rawtransaction.h>
#include <rpc/safemode.h>
#include <rpc/server.h>
#include <rpc/util.h>
@@ -25,6 +26,7 @@
#include <utilmoneystr.h>
#include <wallet/coincontrol.h>
#include <wallet/feebumper.h>
+#include <wallet/rpcwallet.h>
#include <wallet/wallet.h>
#include <wallet/walletdb.h>
#include <wallet/walletutil.h>
@@ -86,48 +88,48 @@ void EnsureWalletIsUnlocked(CWallet * const pwallet)
void WalletTxToJSON(const CWalletTx& wtx, UniValue& entry)
{
int confirms = wtx.GetDepthInMainChain();
- entry.push_back(Pair("confirmations", confirms));
+ entry.pushKV("confirmations", confirms);
if (wtx.IsCoinBase())
- entry.push_back(Pair("generated", true));
+ entry.pushKV("generated", true);
if (confirms > 0)
{
- entry.push_back(Pair("blockhash", wtx.hashBlock.GetHex()));
- entry.push_back(Pair("blockindex", wtx.nIndex));
- entry.push_back(Pair("blocktime", mapBlockIndex[wtx.hashBlock]->GetBlockTime()));
+ entry.pushKV("blockhash", wtx.hashBlock.GetHex());
+ entry.pushKV("blockindex", wtx.nIndex);
+ entry.pushKV("blocktime", LookupBlockIndex(wtx.hashBlock)->GetBlockTime());
} else {
- entry.push_back(Pair("trusted", wtx.IsTrusted()));
+ entry.pushKV("trusted", wtx.IsTrusted());
}
uint256 hash = wtx.GetHash();
- entry.push_back(Pair("txid", hash.GetHex()));
+ entry.pushKV("txid", hash.GetHex());
UniValue conflicts(UniValue::VARR);
for (const uint256& conflict : wtx.GetConflicts())
conflicts.push_back(conflict.GetHex());
- entry.push_back(Pair("walletconflicts", conflicts));
- entry.push_back(Pair("time", wtx.GetTxTime()));
- entry.push_back(Pair("timereceived", (int64_t)wtx.nTimeReceived));
+ entry.pushKV("walletconflicts", conflicts);
+ entry.pushKV("time", wtx.GetTxTime());
+ entry.pushKV("timereceived", (int64_t)wtx.nTimeReceived);
// Add opt-in RBF status
std::string rbfStatus = "no";
if (confirms <= 0) {
LOCK(mempool.cs);
RBFTransactionState rbfState = IsRBFOptIn(*wtx.tx, mempool);
- if (rbfState == RBF_TRANSACTIONSTATE_UNKNOWN)
+ if (rbfState == RBFTransactionState::UNKNOWN)
rbfStatus = "unknown";
- else if (rbfState == RBF_TRANSACTIONSTATE_REPLACEABLE_BIP125)
+ else if (rbfState == RBFTransactionState::REPLACEABLE_BIP125)
rbfStatus = "yes";
}
- entry.push_back(Pair("bip125-replaceable", rbfStatus));
+ entry.pushKV("bip125-replaceable", rbfStatus);
for (const std::pair<std::string, std::string>& item : wtx.mapValue)
- entry.push_back(Pair(item.first, item.second));
+ entry.pushKV(item.first, item.second);
}
-std::string AccountFromValue(const UniValue& value)
+std::string LabelFromValue(const UniValue& value)
{
- std::string strAccount = value.get_str();
- if (strAccount == "*")
- throw JSONRPCError(RPC_WALLET_INVALID_ACCOUNT_NAME, "Invalid account name");
- return strAccount;
+ std::string label = value.get_str();
+ if (label == "*")
+ throw JSONRPCError(RPC_WALLET_INVALID_LABEL_NAME, "Invalid label name");
+ return label;
}
UniValue getnewaddress(const JSONRPCRequest& request)
@@ -139,12 +141,12 @@ UniValue getnewaddress(const JSONRPCRequest& request)
if (request.fHelp || request.params.size() > 2)
throw std::runtime_error(
- "getnewaddress ( \"account\" \"address_type\" )\n"
+ "getnewaddress ( \"label\" \"address_type\" )\n"
"\nReturns a new Bitcoin address for receiving payments.\n"
- "If 'account' is specified (DEPRECATED), it is added to the address book \n"
- "so payments received with the address will be credited to 'account'.\n"
+ "If 'label' is specified, it is added to the address book \n"
+ "so payments received with the address will be associated with 'label'.\n"
"\nArguments:\n"
- "1. \"account\" (string, optional) DEPRECATED. The account name for the address to be linked to. If not provided, the default account \"\" is used. It can also be set to the empty string \"\" to represent the default account. The account does not need to exist, it will be created if there is no account by the given name.\n"
+ "1. \"label\" (string, optional) The label name for the address to be linked to. If not provided, the default label \"\" is used. It can also be set to the empty string \"\" to represent the default label. The label does not need to exist, it will be created if there is no label by the given name.\n"
"2. \"address_type\" (string, optional) The address type to use. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\". Default is set by -addresstype.\n"
"\nResult:\n"
"\"address\" (string) The new bitcoin address\n"
@@ -155,15 +157,15 @@ UniValue getnewaddress(const JSONRPCRequest& request)
LOCK2(cs_main, pwallet->cs_wallet);
- // Parse the account first so we don't generate a key if there's an error
- std::string strAccount;
+ // Parse the label first so we don't generate a key if there's an error
+ std::string label;
if (!request.params[0].isNull())
- strAccount = AccountFromValue(request.params[0]);
+ label = LabelFromValue(request.params[0]);
- OutputType output_type = g_address_type;
+ OutputType output_type = pwallet->m_default_address_type;
if (!request.params[1].isNull()) {
- output_type = ParseOutputType(request.params[1].get_str(), g_address_type);
- if (output_type == OUTPUT_TYPE_NONE) {
+ output_type = ParseOutputType(request.params[1].get_str(), pwallet->m_default_address_type);
+ if (output_type == OutputType::NONE) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Unknown address type '%s'", request.params[1].get_str()));
}
}
@@ -180,23 +182,23 @@ UniValue getnewaddress(const JSONRPCRequest& request)
pwallet->LearnRelatedScripts(newKey, output_type);
CTxDestination dest = GetDestinationForKey(newKey, output_type);
- pwallet->SetAddressBook(dest, strAccount, "receive");
+ pwallet->SetAddressBook(dest, label, "receive");
return EncodeDestination(dest);
}
-CTxDestination GetAccountDestination(CWallet* const pwallet, std::string strAccount, bool bForceNew=false)
+CTxDestination GetLabelDestination(CWallet* const pwallet, const std::string& label, bool bForceNew=false)
{
CTxDestination dest;
- if (!pwallet->GetAccountDestination(dest, strAccount, bForceNew)) {
+ if (!pwallet->GetLabelDestination(dest, label, bForceNew)) {
throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
}
return dest;
}
-UniValue getaccountaddress(const JSONRPCRequest& request)
+UniValue getlabeladdress(const JSONRPCRequest& request)
{
CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
@@ -205,27 +207,27 @@ UniValue getaccountaddress(const JSONRPCRequest& request)
if (request.fHelp || request.params.size() != 1)
throw std::runtime_error(
- "getaccountaddress \"account\"\n"
- "\nDEPRECATED. Returns the current Bitcoin address for receiving payments to this account.\n"
+ "getlabeladdress \"label\"\n"
+ "\nReturns the current Bitcoin address for receiving payments to this label.\n"
"\nArguments:\n"
- "1. \"account\" (string, required) The account name for the address. It can also be set to the empty string \"\" to represent the default account. The account does not need to exist, it will be created and a new address created if there is no account by the given name.\n"
+ "1. \"label\" (string, required) The label name for the address. It can also be set to the empty string \"\" to represent the default label. The label does not need to exist, it will be created and a new address created if there is no label by the given name.\n"
"\nResult:\n"
- "\"address\" (string) The account bitcoin address\n"
+ "\"address\" (string) The label bitcoin address\n"
"\nExamples:\n"
- + HelpExampleCli("getaccountaddress", "")
- + HelpExampleCli("getaccountaddress", "\"\"")
- + HelpExampleCli("getaccountaddress", "\"myaccount\"")
- + HelpExampleRpc("getaccountaddress", "\"myaccount\"")
+ + HelpExampleCli("getlabeladdress", "")
+ + HelpExampleCli("getlabeladdress", "\"\"")
+ + HelpExampleCli("getlabeladdress", "\"mylabel\"")
+ + HelpExampleRpc("getlabeladdress", "\"mylabel\"")
);
LOCK2(cs_main, pwallet->cs_wallet);
- // Parse the account first so we don't generate a key if there's an error
- std::string strAccount = AccountFromValue(request.params[0]);
+ // Parse the label first so we don't generate a key if there's an error
+ std::string label = LabelFromValue(request.params[0]);
UniValue ret(UniValue::VSTR);
- ret = EncodeDestination(GetAccountDestination(pwallet, strAccount));
+ ret = EncodeDestination(GetLabelDestination(pwallet, label));
return ret;
}
@@ -257,10 +259,10 @@ UniValue getrawchangeaddress(const JSONRPCRequest& request)
pwallet->TopUpKeyPool();
}
- OutputType output_type = g_change_type != OUTPUT_TYPE_NONE ? g_change_type : g_address_type;
+ OutputType output_type = pwallet->m_default_change_type != OutputType::NONE ? pwallet->m_default_change_type : pwallet->m_default_address_type;
if (!request.params[0].isNull()) {
output_type = ParseOutputType(request.params[0].get_str(), output_type);
- if (output_type == OUTPUT_TYPE_NONE) {
+ if (output_type == OutputType::NONE) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Unknown address type '%s'", request.params[0].get_str()));
}
}
@@ -279,7 +281,7 @@ UniValue getrawchangeaddress(const JSONRPCRequest& request)
}
-UniValue setaccount(const JSONRPCRequest& request)
+UniValue setlabel(const JSONRPCRequest& request)
{
CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
@@ -288,14 +290,14 @@ UniValue setaccount(const JSONRPCRequest& request)
if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
throw std::runtime_error(
- "setaccount \"address\" \"account\"\n"
- "\nDEPRECATED. Sets the account associated with the given address.\n"
+ "setlabel \"address\" \"label\"\n"
+ "\nSets the label associated with the given address.\n"
"\nArguments:\n"
- "1. \"address\" (string, required) The bitcoin address to be associated with an account.\n"
- "2. \"account\" (string, required) The account to assign the address to.\n"
+ "1. \"address\" (string, required) The bitcoin address to be associated with a label.\n"
+ "2. \"label\" (string, required) The label to assign the address to.\n"
"\nExamples:\n"
- + HelpExampleCli("setaccount", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"tabby\"")
- + HelpExampleRpc("setaccount", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\", \"tabby\"")
+ + HelpExampleCli("setlabel", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"tabby\"")
+ + HelpExampleRpc("setlabel", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\", \"tabby\"")
);
LOCK2(cs_main, pwallet->cs_wallet);
@@ -305,23 +307,23 @@ UniValue setaccount(const JSONRPCRequest& request)
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
}
- std::string strAccount;
+ std::string label;
if (!request.params[1].isNull())
- strAccount = AccountFromValue(request.params[1]);
+ label = LabelFromValue(request.params[1]);
- // Only add the account if the address is yours.
+ // Only add the label if the address is yours.
if (IsMine(*pwallet, dest)) {
- // Detect when changing the account of an address that is the 'unused current key' of another account:
+ // Detect when changing the label of an address that is the 'unused current key' of another label:
if (pwallet->mapAddressBook.count(dest)) {
- std::string strOldAccount = pwallet->mapAddressBook[dest].name;
- if (dest == GetAccountDestination(pwallet, strOldAccount)) {
- GetAccountDestination(pwallet, strOldAccount, true);
+ std::string old_label = pwallet->mapAddressBook[dest].name;
+ if (dest == GetLabelDestination(pwallet, old_label)) {
+ GetLabelDestination(pwallet, old_label, true);
}
}
- pwallet->SetAddressBook(dest, strAccount, "receive");
+ pwallet->SetAddressBook(dest, label, "receive");
}
else
- throw JSONRPCError(RPC_MISC_ERROR, "setaccount can only be used with own address");
+ throw JSONRPCError(RPC_MISC_ERROR, "setlabel can only be used with own address");
return NullUniValue;
}
@@ -388,7 +390,7 @@ UniValue getaddressesbyaccount(const JSONRPCRequest& request)
LOCK2(cs_main, pwallet->cs_wallet);
- std::string strAccount = AccountFromValue(request.params[0]);
+ std::string strAccount = LabelFromValue(request.params[0]);
// Find all addresses that have the given account
UniValue ret(UniValue::VARR);
@@ -402,7 +404,7 @@ UniValue getaddressesbyaccount(const JSONRPCRequest& request)
return ret;
}
-static void SendMoney(CWallet * const pwallet, const CTxDestination &address, CAmount nValue, bool fSubtractFeeFromAmount, CWalletTx& wtxNew, const CCoinControl& coin_control)
+static CTransactionRef SendMoney(CWallet * const pwallet, const CTxDestination &address, CAmount nValue, bool fSubtractFeeFromAmount, const CCoinControl& coin_control, mapValue_t mapValue, std::string fromAccount)
{
CAmount curBalance = pwallet->GetBalance();
@@ -428,16 +430,18 @@ static void SendMoney(CWallet * const pwallet, const CTxDestination &address, CA
int nChangePosRet = -1;
CRecipient recipient = {scriptPubKey, nValue, fSubtractFeeFromAmount};
vecSend.push_back(recipient);
- if (!pwallet->CreateTransaction(vecSend, wtxNew, reservekey, nFeeRequired, nChangePosRet, strError, coin_control)) {
+ CTransactionRef tx;
+ if (!pwallet->CreateTransaction(vecSend, tx, reservekey, nFeeRequired, nChangePosRet, strError, coin_control)) {
if (!fSubtractFeeFromAmount && nValue + nFeeRequired > curBalance)
strError = strprintf("Error: This transaction requires a transaction fee of at least %s", FormatMoney(nFeeRequired));
throw JSONRPCError(RPC_WALLET_ERROR, strError);
}
CValidationState state;
- if (!pwallet->CommitTransaction(wtxNew, reservekey, g_connman.get(), state)) {
- strError = strprintf("Error: The transaction was rejected! Reason given: %s", state.GetRejectReason());
+ if (!pwallet->CommitTransaction(tx, std::move(mapValue), {} /* orderForm */, std::move(fromAccount), reservekey, g_connman.get(), state)) {
+ strError = strprintf("Error: The transaction was rejected! Reason given: %s", FormatStateMessage(state));
throw JSONRPCError(RPC_WALLET_ERROR, strError);
}
+ return tx;
}
UniValue sendtoaddress(const JSONRPCRequest& request)
@@ -496,11 +500,11 @@ UniValue sendtoaddress(const JSONRPCRequest& request)
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
// Wallet comments
- CWalletTx wtx;
+ mapValue_t mapValue;
if (!request.params[2].isNull() && !request.params[2].get_str().empty())
- wtx.mapValue["comment"] = request.params[2].get_str();
+ mapValue["comment"] = request.params[2].get_str();
if (!request.params[3].isNull() && !request.params[3].get_str().empty())
- wtx.mapValue["to"] = request.params[3].get_str();
+ mapValue["to"] = request.params[3].get_str();
bool fSubtractFeeFromAmount = false;
if (!request.params[4].isNull()) {
@@ -525,9 +529,8 @@ UniValue sendtoaddress(const JSONRPCRequest& request)
EnsureWalletIsUnlocked(pwallet);
- SendMoney(pwallet, dest, nAmount, fSubtractFeeFromAmount, wtx, coin_control);
-
- return wtx.GetHash().GetHex();
+ CTransactionRef tx = SendMoney(pwallet, dest, nAmount, fSubtractFeeFromAmount, coin_control, std::move(mapValue), {} /* fromAccount */);
+ return tx->GetHash().GetHex();
}
UniValue listaddressgroupings(const JSONRPCRequest& request)
@@ -549,7 +552,7 @@ UniValue listaddressgroupings(const JSONRPCRequest& request)
" [\n"
" \"address\", (string) The bitcoin address\n"
" amount, (numeric) The amount in " + CURRENCY_UNIT + "\n"
- " \"account\" (string, optional) DEPRECATED. The account\n"
+ " \"label\" (string, optional) The label\n"
" ]\n"
" ,...\n"
" ]\n"
@@ -717,7 +720,7 @@ UniValue getreceivedbyaddress(const JSONRPCRequest& request)
}
-UniValue getreceivedbyaccount(const JSONRPCRequest& request)
+UniValue getreceivedbylabel(const JSONRPCRequest& request)
{
CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
@@ -726,22 +729,22 @@ UniValue getreceivedbyaccount(const JSONRPCRequest& request)
if (request.fHelp || request.params.size() < 1 || request.params.size() > 2)
throw std::runtime_error(
- "getreceivedbyaccount \"account\" ( minconf )\n"
- "\nDEPRECATED. Returns the total amount received by addresses with <account> in transactions with at least [minconf] confirmations.\n"
+ "getreceivedbylabel \"label\" ( minconf )\n"
+ "\nReturns the total amount received by addresses with <label> in transactions with at least [minconf] confirmations.\n"
"\nArguments:\n"
- "1. \"account\" (string, required) The selected account, may be the default account using \"\".\n"
+ "1. \"label\" (string, required) The selected label, may be the default label using \"\".\n"
"2. minconf (numeric, optional, default=1) Only include transactions confirmed at least this many times.\n"
"\nResult:\n"
- "amount (numeric) The total amount in " + CURRENCY_UNIT + " received for this account.\n"
+ "amount (numeric) The total amount in " + CURRENCY_UNIT + " received for this label.\n"
"\nExamples:\n"
- "\nAmount received by the default account with at least 1 confirmation\n"
- + HelpExampleCli("getreceivedbyaccount", "\"\"") +
- "\nAmount received at the tabby account including unconfirmed amounts with zero confirmations\n"
- + HelpExampleCli("getreceivedbyaccount", "\"tabby\" 0") +
+ "\nAmount received by the default label with at least 1 confirmation\n"
+ + HelpExampleCli("getreceivedbylabel", "\"\"") +
+ "\nAmount received at the tabby label including unconfirmed amounts with zero confirmations\n"
+ + HelpExampleCli("getreceivedbylabel", "\"tabby\" 0") +
"\nThe amount with at least 6 confirmations\n"
- + HelpExampleCli("getreceivedbyaccount", "\"tabby\" 6") +
+ + HelpExampleCli("getreceivedbylabel", "\"tabby\" 6") +
"\nAs a json rpc call\n"
- + HelpExampleRpc("getreceivedbyaccount", "\"tabby\", 6")
+ + HelpExampleRpc("getreceivedbylabel", "\"tabby\", 6")
);
ObserveSafeMode();
@@ -757,9 +760,9 @@ UniValue getreceivedbyaccount(const JSONRPCRequest& request)
if (!request.params[1].isNull())
nMinDepth = request.params[1].get_int();
- // Get the set of pub keys assigned to account
- std::string strAccount = AccountFromValue(request.params[0]);
- std::set<CTxDestination> setAddress = pwallet->GetAccountAddresses(strAccount);
+ // Get the set of pub keys assigned to label
+ std::string label = LabelFromValue(request.params[0]);
+ std::set<CTxDestination> setAddress = pwallet->GetLabelAddresses(label);
// Tally
CAmount nAmount = 0;
@@ -917,8 +920,8 @@ UniValue movecmd(const JSONRPCRequest& request)
ObserveSafeMode();
LOCK2(cs_main, pwallet->cs_wallet);
- std::string strFrom = AccountFromValue(request.params[0]);
- std::string strTo = AccountFromValue(request.params[1]);
+ std::string strFrom = LabelFromValue(request.params[0]);
+ std::string strTo = LabelFromValue(request.params[1]);
CAmount nAmount = AmountFromValue(request.params[2]);
if (nAmount <= 0)
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
@@ -981,7 +984,7 @@ UniValue sendfrom(const JSONRPCRequest& request)
LOCK2(cs_main, pwallet->cs_wallet);
- std::string strAccount = AccountFromValue(request.params[0]);
+ std::string strAccount = LabelFromValue(request.params[0]);
CTxDestination dest = DecodeDestination(request.params[1].get_str());
if (!IsValidDestination(dest)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
@@ -993,12 +996,11 @@ UniValue sendfrom(const JSONRPCRequest& request)
if (!request.params[3].isNull())
nMinDepth = request.params[3].get_int();
- CWalletTx wtx;
- wtx.strFromAccount = strAccount;
+ mapValue_t mapValue;
if (!request.params[4].isNull() && !request.params[4].get_str().empty())
- wtx.mapValue["comment"] = request.params[4].get_str();
+ mapValue["comment"] = request.params[4].get_str();
if (!request.params[5].isNull() && !request.params[5].get_str().empty())
- wtx.mapValue["to"] = request.params[5].get_str();
+ mapValue["to"] = request.params[5].get_str();
EnsureWalletIsUnlocked(pwallet);
@@ -1008,9 +1010,8 @@ UniValue sendfrom(const JSONRPCRequest& request)
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
CCoinControl no_coin_control; // This is a deprecated API
- SendMoney(pwallet, dest, nAmount, false, wtx, no_coin_control);
-
- return wtx.GetHash().GetHex();
+ CTransactionRef tx = SendMoney(pwallet, dest, nAmount, false, no_coin_control, std::move(mapValue), std::move(strAccount));
+ return tx->GetHash().GetHex();
}
@@ -1075,16 +1076,15 @@ UniValue sendmany(const JSONRPCRequest& request)
throw JSONRPCError(RPC_CLIENT_P2P_DISABLED, "Error: Peer-to-peer functionality missing or disabled");
}
- std::string strAccount = AccountFromValue(request.params[0]);
+ std::string strAccount = LabelFromValue(request.params[0]);
UniValue sendTo = request.params[1].get_obj();
int nMinDepth = 1;
if (!request.params[2].isNull())
nMinDepth = request.params[2].get_int();
- CWalletTx wtx;
- wtx.strFromAccount = strAccount;
+ mapValue_t mapValue;
if (!request.params[3].isNull() && !request.params[3].get_str().empty())
- wtx.mapValue["comment"] = request.params[3].get_str();
+ mapValue["comment"] = request.params[3].get_str();
UniValue subtractFeeFromAmount(UniValue::VARR);
if (!request.params[4].isNull())
@@ -1145,21 +1145,25 @@ UniValue sendmany(const JSONRPCRequest& request)
if (totalAmount > nBalance)
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Account has insufficient funds");
+ // Shuffle recipient list
+ std::shuffle(vecSend.begin(), vecSend.end(), FastRandomContext());
+
// Send
CReserveKey keyChange(pwallet);
CAmount nFeeRequired = 0;
int nChangePosRet = -1;
std::string strFailReason;
- bool fCreated = pwallet->CreateTransaction(vecSend, wtx, keyChange, nFeeRequired, nChangePosRet, strFailReason, coin_control);
+ CTransactionRef tx;
+ bool fCreated = pwallet->CreateTransaction(vecSend, tx, keyChange, nFeeRequired, nChangePosRet, strFailReason, coin_control);
if (!fCreated)
throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, strFailReason);
CValidationState state;
- if (!pwallet->CommitTransaction(wtx, keyChange, g_connman.get(), state)) {
- strFailReason = strprintf("Transaction commit failed:: %s", state.GetRejectReason());
+ if (!pwallet->CommitTransaction(tx, std::move(mapValue), {} /* orderForm */, std::move(strAccount), keyChange, g_connman.get(), state)) {
+ strFailReason = strprintf("Transaction commit failed:: %s", FormatStateMessage(state));
throw JSONRPCError(RPC_WALLET_ERROR, strFailReason);
}
- return wtx.GetHash().GetHex();
+ return tx->GetHash().GetHex();
}
UniValue addmultisigaddress(const JSONRPCRequest& request)
@@ -1170,12 +1174,12 @@ UniValue addmultisigaddress(const JSONRPCRequest& request)
}
if (request.fHelp || request.params.size() < 2 || request.params.size() > 4) {
- std::string msg = "addmultisigaddress nrequired [\"key\",...] ( \"account\" \"address_type\" )\n"
+ std::string msg = "addmultisigaddress nrequired [\"key\",...] ( \"label\" \"address_type\" )\n"
"\nAdd a nrequired-to-sign multisignature address to the wallet. Requires a new wallet backup.\n"
"Each key is a Bitcoin address or hex-encoded public key.\n"
"This functionality is only intended for use with non-watchonly addresses.\n"
"See `importaddress` for watchonly p2sh address support.\n"
- "If 'account' is specified (DEPRECATED), assign address to that account.\n"
+ "If 'label' is specified, assign address to that label.\n"
"\nArguments:\n"
"1. nrequired (numeric, required) The number of required signatures out of the n keys or addresses.\n"
@@ -1184,7 +1188,7 @@ UniValue addmultisigaddress(const JSONRPCRequest& request)
" \"address\" (string) bitcoin address or hex-encoded public key\n"
" ...,\n"
" ]\n"
- "3. \"account\" (string, optional) DEPRECATED. An account to assign the addresses to.\n"
+ "3. \"label\" (string, optional) A label to assign the addresses to.\n"
"4. \"address_type\" (string, optional) The address type to use. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\". Default is set by -addresstype.\n"
"\nResult:\n"
@@ -1192,10 +1196,6 @@ UniValue addmultisigaddress(const JSONRPCRequest& request)
" \"address\":\"multisigaddress\", (string) The value of the new multisig address.\n"
" \"redeemScript\":\"script\" (string) The string value of the hex-encoded redemption script.\n"
"}\n"
- "\nResult (DEPRECATED. To see this result in v0.16 instead, please start bitcoind with -deprecatedrpc=addmultisigaddress).\n"
- " clients should transition to the new output api before upgrading to v0.17.\n"
- "\"address\" (string) A bitcoin address associated with the keys.\n"
-
"\nExamples:\n"
"\nAdd a multisig address from 2 addresses\n"
+ HelpExampleCli("addmultisigaddress", "2 \"[\\\"16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\",\\\"171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"") +
@@ -1207,9 +1207,9 @@ UniValue addmultisigaddress(const JSONRPCRequest& request)
LOCK2(cs_main, pwallet->cs_wallet);
- std::string strAccount;
+ std::string label;
if (!request.params[2].isNull())
- strAccount = AccountFromValue(request.params[2]);
+ label = LabelFromValue(request.params[2]);
int required = request.params[0].get_int();
@@ -1224,10 +1224,10 @@ UniValue addmultisigaddress(const JSONRPCRequest& request)
}
}
- OutputType output_type = g_address_type;
+ OutputType output_type = pwallet->m_default_address_type;
if (!request.params[3].isNull()) {
output_type = ParseOutputType(request.params[3].get_str(), output_type);
- if (output_type == OUTPUT_TYPE_NONE) {
+ if (output_type == OutputType::NONE) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Unknown address type '%s'", request.params[3].get_str()));
}
}
@@ -1236,12 +1236,7 @@ UniValue addmultisigaddress(const JSONRPCRequest& request)
CScript inner = CreateMultisigRedeemscript(required, pubkeys);
pwallet->AddCScript(inner);
CTxDestination dest = pwallet->AddAndGetDestinationForScript(inner, output_type);
- pwallet->SetAddressBook(dest, strAccount, "send");
-
- // Return old style interface
- if (IsDeprecatedRPCEnabled("addmultisigaddress")) {
- return EncodeDestination(dest);
- }
+ pwallet->SetAddressBook(dest, label, "send");
UniValue result(UniValue::VOBJ);
result.pushKV("address", EncodeDestination(dest));
@@ -1393,14 +1388,14 @@ struct tallyitem
}
};
-UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bool fByAccounts)
+UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bool by_label)
{
// Minimum confirmations
int nMinDepth = 1;
if (!params[0].isNull())
nMinDepth = params[0].get_int();
- // Whether to include empty accounts
+ // Whether to include empty labels
bool fIncludeEmpty = false;
if (!params[1].isNull())
fIncludeEmpty = params[1].get_bool();
@@ -1410,6 +1405,16 @@ UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bool fByA
if(params[2].get_bool())
filter = filter | ISMINE_WATCH_ONLY;
+ bool has_filtered_address = false;
+ CTxDestination filtered_address = CNoDestination();
+ if (!by_label && params.size() > 3) {
+ if (!IsValidDestinationString(params[3].get_str())) {
+ throw JSONRPCError(RPC_WALLET_ERROR, "address_filter parameter was invalid");
+ }
+ filtered_address = DecodeDestination(params[3].get_str());
+ has_filtered_address = true;
+ }
+
// Tally
std::map<CTxDestination, tallyitem> mapTally;
for (const std::pair<uint256, CWalletTx>& pairWtx : pwallet->mapWallet) {
@@ -1428,6 +1433,10 @@ UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bool fByA
if (!ExtractDestination(txout.scriptPubKey, address))
continue;
+ if (has_filtered_address && !(filtered_address == address)) {
+ continue;
+ }
+
isminefilter mine = IsMine(*pwallet, address);
if(!(mine & filter))
continue;
@@ -1443,11 +1452,25 @@ UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bool fByA
// Reply
UniValue ret(UniValue::VARR);
- std::map<std::string, tallyitem> mapAccountTally;
- for (const std::pair<CTxDestination, CAddressBookData>& item : pwallet->mapAddressBook) {
- const CTxDestination& dest = item.first;
- const std::string& strAccount = item.second.name;
- std::map<CTxDestination, tallyitem>::iterator it = mapTally.find(dest);
+ std::map<std::string, tallyitem> label_tally;
+
+ // Create mapAddressBook iterator
+ // If we aren't filtering, go from begin() to end()
+ auto start = pwallet->mapAddressBook.begin();
+ auto end = pwallet->mapAddressBook.end();
+ // If we are filtering, find() the applicable entry
+ if (has_filtered_address) {
+ start = pwallet->mapAddressBook.find(filtered_address);
+ if (start != end) {
+ end = std::next(start);
+ }
+ }
+
+ for (auto item_it = start; item_it != end; ++item_it)
+ {
+ const CTxDestination& address = item_it->first;
+ const std::string& label = item_it->second.name;
+ auto it = mapTally.find(address);
if (it == mapTally.end() && !fIncludeEmpty)
continue;
@@ -1461,9 +1484,9 @@ UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bool fByA
fIsWatchonly = (*it).second.fIsWatchonly;
}
- if (fByAccounts)
+ if (by_label)
{
- tallyitem& _item = mapAccountTally[strAccount];
+ tallyitem& _item = label_tally[label];
_item.nAmount += nAmount;
_item.nConf = std::min(_item.nConf, nConf);
_item.fIsWatchonly = fIsWatchonly;
@@ -1472,13 +1495,12 @@ UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bool fByA
{
UniValue obj(UniValue::VOBJ);
if(fIsWatchonly)
- obj.push_back(Pair("involvesWatchonly", true));
- obj.push_back(Pair("address", EncodeDestination(dest)));
- obj.push_back(Pair("account", strAccount));
- obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
- obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
- if (!fByAccounts)
- obj.push_back(Pair("label", strAccount));
+ obj.pushKV("involvesWatchonly", true);
+ obj.pushKV("address", EncodeDestination(address));
+ obj.pushKV("account", label);
+ obj.pushKV("amount", ValueFromAmount(nAmount));
+ obj.pushKV("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf));
+ obj.pushKV("label", label);
UniValue transactions(UniValue::VARR);
if (it != mapTally.end())
{
@@ -1487,23 +1509,24 @@ UniValue ListReceived(CWallet * const pwallet, const UniValue& params, bool fByA
transactions.push_back(_item.GetHex());
}
}
- obj.push_back(Pair("txids", transactions));
+ obj.pushKV("txids", transactions);
ret.push_back(obj);
}
}
- if (fByAccounts)
+ if (by_label)
{
- for (const auto& entry : mapAccountTally)
+ for (const auto& entry : label_tally)
{
CAmount nAmount = entry.second.nAmount;
int nConf = entry.second.nConf;
UniValue obj(UniValue::VOBJ);
if (entry.second.fIsWatchonly)
- obj.push_back(Pair("involvesWatchonly", true));
- obj.push_back(Pair("account", entry.first));
- obj.push_back(Pair("amount", ValueFromAmount(nAmount)));
- obj.push_back(Pair("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf)));
+ obj.pushKV("involvesWatchonly", true);
+ obj.pushKV("account", entry.first);
+ obj.pushKV("amount", ValueFromAmount(nAmount));
+ obj.pushKV("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf));
+ obj.pushKV("label", entry.first);
ret.push_back(obj);
}
}
@@ -1518,24 +1541,24 @@ UniValue listreceivedbyaddress(const JSONRPCRequest& request)
return NullUniValue;
}
- if (request.fHelp || request.params.size() > 3)
+ if (request.fHelp || request.params.size() > 4)
throw std::runtime_error(
- "listreceivedbyaddress ( minconf include_empty include_watchonly)\n"
+ "listreceivedbyaddress ( minconf include_empty include_watchonly address_filter )\n"
"\nList balances by receiving address.\n"
"\nArguments:\n"
"1. minconf (numeric, optional, default=1) The minimum number of confirmations before payments are included.\n"
"2. include_empty (bool, optional, default=false) Whether to include addresses that haven't received any payments.\n"
"3. include_watchonly (bool, optional, default=false) Whether to include watch-only addresses (see 'importaddress').\n"
-
+ "4. address_filter (string, optional) If present, only return information on this address.\n"
"\nResult:\n"
"[\n"
" {\n"
" \"involvesWatchonly\" : true, (bool) Only returned if imported addresses were involved in transaction\n"
" \"address\" : \"receivingaddress\", (string) The receiving address\n"
- " \"account\" : \"accountname\", (string) DEPRECATED. The account of the receiving address. The default account is \"\".\n"
+ " \"account\" : \"accountname\", (string) DEPRECATED. Backwards compatible alias for label.\n"
" \"amount\" : x.xxx, (numeric) The total amount in " + CURRENCY_UNIT + " received by the address\n"
" \"confirmations\" : n, (numeric) The number of confirmations of the most recent transaction included\n"
- " \"label\" : \"label\", (string) A comment for the address/transaction, if any\n"
+ " \"label\" : \"label\", (string) The label of the receiving address. The default label is \"\".\n"
" \"txids\": [\n"
" n, (numeric) The ids of transactions received with the address \n"
" ...\n"
@@ -1548,6 +1571,7 @@ UniValue listreceivedbyaddress(const JSONRPCRequest& request)
+ HelpExampleCli("listreceivedbyaddress", "")
+ HelpExampleCli("listreceivedbyaddress", "6 true")
+ HelpExampleRpc("listreceivedbyaddress", "6, true, true")
+ + HelpExampleRpc("listreceivedbyaddress", "6, true, true, \"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\"")
);
ObserveSafeMode();
@@ -1561,7 +1585,7 @@ UniValue listreceivedbyaddress(const JSONRPCRequest& request)
return ListReceived(pwallet, request.params, false);
}
-UniValue listreceivedbyaccount(const JSONRPCRequest& request)
+UniValue listreceivedbylabel(const JSONRPCRequest& request)
{
CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
@@ -1570,29 +1594,29 @@ UniValue listreceivedbyaccount(const JSONRPCRequest& request)
if (request.fHelp || request.params.size() > 3)
throw std::runtime_error(
- "listreceivedbyaccount ( minconf include_empty include_watchonly)\n"
- "\nDEPRECATED. List balances by account.\n"
+ "listreceivedbylabel ( minconf include_empty include_watchonly)\n"
+ "\nList received transactions by label.\n"
"\nArguments:\n"
"1. minconf (numeric, optional, default=1) The minimum number of confirmations before payments are included.\n"
- "2. include_empty (bool, optional, default=false) Whether to include accounts that haven't received any payments.\n"
+ "2. include_empty (bool, optional, default=false) Whether to include labels that haven't received any payments.\n"
"3. include_watchonly (bool, optional, default=false) Whether to include watch-only addresses (see 'importaddress').\n"
"\nResult:\n"
"[\n"
" {\n"
" \"involvesWatchonly\" : true, (bool) Only returned if imported addresses were involved in transaction\n"
- " \"account\" : \"accountname\", (string) The account name of the receiving account\n"
- " \"amount\" : x.xxx, (numeric) The total amount received by addresses with this account\n"
+ " \"account\" : \"accountname\", (string) DEPRECATED. Backwards compatible alias for label.\n"
+ " \"amount\" : x.xxx, (numeric) The total amount received by addresses with this label\n"
" \"confirmations\" : n, (numeric) The number of confirmations of the most recent transaction included\n"
- " \"label\" : \"label\" (string) A comment for the address/transaction, if any\n"
+ " \"label\" : \"label\" (string) The label of the receiving address. The default label is \"\".\n"
" }\n"
" ,...\n"
"]\n"
"\nExamples:\n"
- + HelpExampleCli("listreceivedbyaccount", "")
- + HelpExampleCli("listreceivedbyaccount", "6 true")
- + HelpExampleRpc("listreceivedbyaccount", "6, true, true")
+ + HelpExampleCli("listreceivedbylabel", "")
+ + HelpExampleCli("listreceivedbylabel", "6 true")
+ + HelpExampleRpc("listreceivedbylabel", "6, true, true")
);
ObserveSafeMode();
@@ -1609,7 +1633,7 @@ UniValue listreceivedbyaccount(const JSONRPCRequest& request)
static void MaybePushAddress(UniValue & entry, const CTxDestination &dest)
{
if (IsValidDestination(dest)) {
- entry.push_back(Pair("address", EncodeDestination(dest)));
+ entry.pushKV("address", EncodeDestination(dest));
}
}
@@ -1643,20 +1667,20 @@ void ListTransactions(CWallet* const pwallet, const CWalletTx& wtx, const std::s
{
UniValue entry(UniValue::VOBJ);
if (involvesWatchonly || (::IsMine(*pwallet, s.destination) & ISMINE_WATCH_ONLY)) {
- entry.push_back(Pair("involvesWatchonly", true));
+ entry.pushKV("involvesWatchonly", true);
}
- entry.push_back(Pair("account", strSentAccount));
+ entry.pushKV("account", strSentAccount);
MaybePushAddress(entry, s.destination);
- entry.push_back(Pair("category", "send"));
- entry.push_back(Pair("amount", ValueFromAmount(-s.amount)));
+ entry.pushKV("category", "send");
+ entry.pushKV("amount", ValueFromAmount(-s.amount));
if (pwallet->mapAddressBook.count(s.destination)) {
- entry.push_back(Pair("label", pwallet->mapAddressBook[s.destination].name));
+ entry.pushKV("label", pwallet->mapAddressBook[s.destination].name);
}
- entry.push_back(Pair("vout", s.vout));
- entry.push_back(Pair("fee", ValueFromAmount(-nFee)));
+ entry.pushKV("vout", s.vout);
+ entry.pushKV("fee", ValueFromAmount(-nFee));
if (fLong)
WalletTxToJSON(wtx, entry);
- entry.push_back(Pair("abandoned", wtx.isAbandoned()));
+ entry.pushKV("abandoned", wtx.isAbandoned());
ret.push_back(entry);
}
}
@@ -1674,28 +1698,28 @@ void ListTransactions(CWallet* const pwallet, const CWalletTx& wtx, const std::s
{
UniValue entry(UniValue::VOBJ);
if (involvesWatchonly || (::IsMine(*pwallet, r.destination) & ISMINE_WATCH_ONLY)) {
- entry.push_back(Pair("involvesWatchonly", true));
+ entry.pushKV("involvesWatchonly", true);
}
- entry.push_back(Pair("account", account));
+ entry.pushKV("account", account);
MaybePushAddress(entry, r.destination);
if (wtx.IsCoinBase())
{
if (wtx.GetDepthInMainChain() < 1)
- entry.push_back(Pair("category", "orphan"));
+ entry.pushKV("category", "orphan");
else if (wtx.GetBlocksToMaturity() > 0)
- entry.push_back(Pair("category", "immature"));
+ entry.pushKV("category", "immature");
else
- entry.push_back(Pair("category", "generate"));
+ entry.pushKV("category", "generate");
}
else
{
- entry.push_back(Pair("category", "receive"));
+ entry.pushKV("category", "receive");
}
- entry.push_back(Pair("amount", ValueFromAmount(r.amount)));
+ entry.pushKV("amount", ValueFromAmount(r.amount));
if (pwallet->mapAddressBook.count(r.destination)) {
- entry.push_back(Pair("label", account));
+ entry.pushKV("label", account);
}
- entry.push_back(Pair("vout", r.vout));
+ entry.pushKV("vout", r.vout);
if (fLong)
WalletTxToJSON(wtx, entry);
ret.push_back(entry);
@@ -1711,12 +1735,12 @@ void AcentryToJSON(const CAccountingEntry& acentry, const std::string& strAccoun
if (fAllAccounts || acentry.strAccount == strAccount)
{
UniValue entry(UniValue::VOBJ);
- entry.push_back(Pair("account", acentry.strAccount));
- entry.push_back(Pair("category", "move"));
- entry.push_back(Pair("time", acentry.nTime));
- entry.push_back(Pair("amount", ValueFromAmount(acentry.nCreditDebit)));
- entry.push_back(Pair("otheraccount", acentry.strOtherAccount));
- entry.push_back(Pair("comment", acentry.strComment));
+ entry.pushKV("account", acentry.strAccount);
+ entry.pushKV("category", "move");
+ entry.pushKV("time", acentry.nTime);
+ entry.pushKV("amount", ValueFromAmount(acentry.nCreditDebit));
+ entry.pushKV("otheraccount", acentry.strOtherAccount);
+ entry.pushKV("comment", acentry.strComment);
ret.push_back(entry);
}
}
@@ -1794,8 +1818,6 @@ UniValue listtransactions(const JSONRPCRequest& request)
// the user could have gotten from another RPC command prior to now
pwallet->BlockUntilSyncedToCurrentChain();
- LOCK2(cs_main, pwallet->cs_wallet);
-
std::string strAccount = "*";
if (!request.params[0].isNull())
strAccount = request.params[0].get_str();
@@ -1817,20 +1839,25 @@ UniValue listtransactions(const JSONRPCRequest& request)
UniValue ret(UniValue::VARR);
- const CWallet::TxItems & txOrdered = pwallet->wtxOrdered;
-
- // iterate backwards until we have nCount items to return:
- for (CWallet::TxItems::const_reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
{
- CWalletTx *const pwtx = (*it).second.first;
- if (pwtx != nullptr)
- ListTransactions(pwallet, *pwtx, strAccount, 0, true, ret, filter);
- CAccountingEntry *const pacentry = (*it).second.second;
- if (pacentry != nullptr)
- AcentryToJSON(*pacentry, strAccount, ret);
+ LOCK2(cs_main, pwallet->cs_wallet);
- if ((int)ret.size() >= (nCount+nFrom)) break;
+ const CWallet::TxItems & txOrdered = pwallet->wtxOrdered;
+
+ // iterate backwards until we have nCount items to return:
+ for (CWallet::TxItems::const_reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
+ {
+ CWalletTx *const pwtx = (*it).second.first;
+ if (pwtx != nullptr)
+ ListTransactions(pwallet, *pwtx, strAccount, 0, true, ret, filter);
+ CAccountingEntry *const pacentry = (*it).second.second;
+ if (pacentry != nullptr)
+ AcentryToJSON(*pacentry, strAccount, ret);
+
+ if ((int)ret.size() >= (nCount+nFrom)) break;
+ }
}
+
// ret is newest to oldest
if (nFrom > (int)ret.size())
@@ -1940,7 +1967,7 @@ UniValue listaccounts(const JSONRPCRequest& request)
UniValue ret(UniValue::VOBJ);
for (const std::pair<std::string, CAmount>& accountBalance : mapAccountBalances) {
- ret.push_back(Pair(accountBalance.first, ValueFromAmount(accountBalance.second)));
+ ret.pushKV(accountBalance.first, ValueFromAmount(accountBalance.second));
}
return ret;
}
@@ -1991,7 +2018,7 @@ UniValue listsinceblock(const JSONRPCRequest& request)
" ],\n"
" \"removed\": [\n"
" <structure is the same as \"transactions\" above, only present if include_removed=true>\n"
- " Note: transactions that were readded in the active chain will appear as-is in this array, and may thus have a positive confirmation count.\n"
+ " Note: transactions that were re-added in the active chain will appear as-is in this array, and may thus have a positive confirmation count.\n"
" ],\n"
" \"lastblock\": \"lastblockhash\" (string) The hash of the block (target_confirmations-1) from the best block on the main chain. This is typically used to feed back into listsinceblock the next time you call it. So you would generally use a target_confirmations of say 6, so you will be continually re-notified of transactions until they've reached 6 confirmations plus any new ones\n"
"}\n"
@@ -2018,11 +2045,10 @@ UniValue listsinceblock(const JSONRPCRequest& request)
uint256 blockId;
blockId.SetHex(request.params[0].get_str());
- BlockMap::iterator it = mapBlockIndex.find(blockId);
- if (it == mapBlockIndex.end()) {
+ paltindex = pindex = LookupBlockIndex(blockId);
+ if (!pindex) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
}
- paltindex = pindex = it->second;
if (chainActive[pindex->nHeight] != pindex) {
// the block being asked for is a part of a deactivated chain;
// we don't want to depend on its perceived height in the block
@@ -2080,9 +2106,9 @@ UniValue listsinceblock(const JSONRPCRequest& request)
uint256 lastblock = pblockLast ? pblockLast->GetBlockHash() : uint256();
UniValue ret(UniValue::VOBJ);
- ret.push_back(Pair("transactions", transactions));
- if (include_removed) ret.push_back(Pair("removed", removed));
- ret.push_back(Pair("lastblock", lastblock.GetHex()));
+ ret.pushKV("transactions", transactions);
+ if (include_removed) ret.pushKV("removed", removed);
+ ret.pushKV("lastblock", lastblock.GetHex());
return ret;
}
@@ -2167,18 +2193,18 @@ UniValue gettransaction(const JSONRPCRequest& request)
CAmount nNet = nCredit - nDebit;
CAmount nFee = (wtx.IsFromMe(filter) ? wtx.tx->GetValueOut() - nDebit : 0);
- entry.push_back(Pair("amount", ValueFromAmount(nNet - nFee)));
+ entry.pushKV("amount", ValueFromAmount(nNet - nFee));
if (wtx.IsFromMe(filter))
- entry.push_back(Pair("fee", ValueFromAmount(nFee)));
+ entry.pushKV("fee", ValueFromAmount(nFee));
WalletTxToJSON(wtx, entry);
UniValue details(UniValue::VARR);
ListTransactions(pwallet, wtx, "*", 0, false, details, filter);
- entry.push_back(Pair("details", details));
+ entry.pushKV("details", details);
std::string strHex = EncodeHexTx(*wtx.tx, RPCSerializationFlags());
- entry.push_back(Pair("hex", strHex));
+ entry.pushKV("hex", strHex);
return entry;
}
@@ -2190,14 +2216,14 @@ UniValue abandontransaction(const JSONRPCRequest& request)
return NullUniValue;
}
- if (request.fHelp || request.params.size() != 1)
+ if (request.fHelp || request.params.size() != 1) {
throw std::runtime_error(
"abandontransaction \"txid\"\n"
"\nMark in-wallet transaction <txid> as abandoned\n"
"This will mark this transaction and all its in-wallet descendants as abandoned which will allow\n"
"for their inputs to be respent. It can be used to replace \"stuck\" or evicted transactions.\n"
"It only works on transactions which are not included in a block and are not currently in the mempool.\n"
- "It has no effect on transactions which are already conflicted or abandoned.\n"
+ "It has no effect on transactions which are already abandoned.\n"
"\nArguments:\n"
"1. \"txid\" (string, required) The transaction id\n"
"\nResult:\n"
@@ -2205,6 +2231,7 @@ UniValue abandontransaction(const JSONRPCRequest& request)
+ HelpExampleCli("abandontransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
+ HelpExampleRpc("abandontransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
);
+ }
ObserveSafeMode();
@@ -2339,8 +2366,6 @@ UniValue walletpassphrase(const JSONRPCRequest& request)
LOCK2(cs_main, pwallet->cs_wallet);
- if (request.fHelp)
- return true;
if (!pwallet->IsCrypted()) {
throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
}
@@ -2405,8 +2430,6 @@ UniValue walletpassphrasechange(const JSONRPCRequest& request)
LOCK2(cs_main, pwallet->cs_wallet);
- if (request.fHelp)
- return true;
if (!pwallet->IsCrypted()) {
throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
}
@@ -2461,8 +2484,6 @@ UniValue walletlock(const JSONRPCRequest& request)
LOCK2(cs_main, pwallet->cs_wallet);
- if (request.fHelp)
- return true;
if (!pwallet->IsCrypted()) {
throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletlock was called.");
}
@@ -2508,8 +2529,6 @@ UniValue encryptwallet(const JSONRPCRequest& request)
LOCK2(cs_main, pwallet->cs_wallet);
- if (request.fHelp)
- return true;
if (pwallet->IsCrypted()) {
throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an encrypted wallet, but encryptwallet was called.");
}
@@ -2707,8 +2726,8 @@ UniValue listlockunspent(const JSONRPCRequest& request)
for (COutPoint &outpt : vOutpts) {
UniValue o(UniValue::VOBJ);
- o.push_back(Pair("txid", outpt.hash.GetHex()));
- o.push_back(Pair("vout", (int)outpt.n));
+ o.pushKV("txid", outpt.hash.GetHex());
+ o.pushKV("vout", (int)outpt.n);
ret.push_back(o);
}
@@ -2786,24 +2805,24 @@ UniValue getwalletinfo(const JSONRPCRequest& request)
UniValue obj(UniValue::VOBJ);
size_t kpExternalSize = pwallet->KeypoolCountExternalKeys();
- obj.push_back(Pair("walletname", pwallet->GetName()));
- obj.push_back(Pair("walletversion", pwallet->GetVersion()));
- obj.push_back(Pair("balance", ValueFromAmount(pwallet->GetBalance())));
- obj.push_back(Pair("unconfirmed_balance", ValueFromAmount(pwallet->GetUnconfirmedBalance())));
- obj.push_back(Pair("immature_balance", ValueFromAmount(pwallet->GetImmatureBalance())));
- obj.push_back(Pair("txcount", (int)pwallet->mapWallet.size()));
- obj.push_back(Pair("keypoololdest", pwallet->GetOldestKeyPoolTime()));
- obj.push_back(Pair("keypoolsize", (int64_t)kpExternalSize));
+ obj.pushKV("walletname", pwallet->GetName());
+ obj.pushKV("walletversion", pwallet->GetVersion());
+ obj.pushKV("balance", ValueFromAmount(pwallet->GetBalance()));
+ obj.pushKV("unconfirmed_balance", ValueFromAmount(pwallet->GetUnconfirmedBalance()));
+ obj.pushKV("immature_balance", ValueFromAmount(pwallet->GetImmatureBalance()));
+ obj.pushKV("txcount", (int)pwallet->mapWallet.size());
+ obj.pushKV("keypoololdest", pwallet->GetOldestKeyPoolTime());
+ obj.pushKV("keypoolsize", (int64_t)kpExternalSize);
CKeyID masterKeyID = pwallet->GetHDChain().masterKeyID;
if (!masterKeyID.IsNull() && pwallet->CanSupportFeature(FEATURE_HD_SPLIT)) {
- obj.push_back(Pair("keypoolsize_hd_internal", (int64_t)(pwallet->GetKeyPoolSize() - kpExternalSize)));
+ obj.pushKV("keypoolsize_hd_internal", (int64_t)(pwallet->GetKeyPoolSize() - kpExternalSize));
}
if (pwallet->IsCrypted()) {
- obj.push_back(Pair("unlocked_until", pwallet->nRelockTime));
+ obj.pushKV("unlocked_until", pwallet->nRelockTime);
}
- obj.push_back(Pair("paytxfee", ValueFromAmount(payTxFee.GetFeePerK())));
+ obj.pushKV("paytxfee", ValueFromAmount(payTxFee.GetFeePerK()));
if (!masterKeyID.IsNull())
- obj.push_back(Pair("hdmasterkeyid", masterKeyID.GetHex()));
+ obj.pushKV("hdmasterkeyid", masterKeyID.GetHex());
return obj;
}
@@ -2911,7 +2930,8 @@ UniValue listunspent(const JSONRPCRequest& request)
" \"txid\" : \"txid\", (string) the transaction id \n"
" \"vout\" : n, (numeric) the vout value\n"
" \"address\" : \"address\", (string) the bitcoin address\n"
- " \"account\" : \"account\", (string) DEPRECATED. The associated account, or \"\" for the default account\n"
+ " \"label\" : \"label\", (string) The associated label, or \"\" for the default label\n"
+ " \"account\" : \"account\", (string) DEPRECATED. Backwards compatible alias for label.\n"
" \"scriptPubKey\" : \"key\", (string) the script key\n"
" \"amount\" : x.xxx, (numeric) the transaction output amount in " + CURRENCY_UNIT + "\n"
" \"confirmations\" : n, (numeric) The number of confirmations\n"
@@ -3008,31 +3028,32 @@ UniValue listunspent(const JSONRPCRequest& request)
continue;
UniValue entry(UniValue::VOBJ);
- entry.push_back(Pair("txid", out.tx->GetHash().GetHex()));
- entry.push_back(Pair("vout", out.i));
+ entry.pushKV("txid", out.tx->GetHash().GetHex());
+ entry.pushKV("vout", out.i);
if (fValidAddress) {
- entry.push_back(Pair("address", EncodeDestination(address)));
+ entry.pushKV("address", EncodeDestination(address));
if (pwallet->mapAddressBook.count(address)) {
- entry.push_back(Pair("account", pwallet->mapAddressBook[address].name));
+ entry.pushKV("label", pwallet->mapAddressBook[address].name);
+ entry.pushKV("account", pwallet->mapAddressBook[address].name);
}
if (scriptPubKey.IsPayToScriptHash()) {
const CScriptID& hash = boost::get<CScriptID>(address);
CScript redeemScript;
if (pwallet->GetCScript(hash, redeemScript)) {
- entry.push_back(Pair("redeemScript", HexStr(redeemScript.begin(), redeemScript.end())));
+ entry.pushKV("redeemScript", HexStr(redeemScript.begin(), redeemScript.end()));
}
}
}
- entry.push_back(Pair("scriptPubKey", HexStr(scriptPubKey.begin(), scriptPubKey.end())));
- entry.push_back(Pair("amount", ValueFromAmount(out.tx->tx->vout[out.i].nValue)));
- entry.push_back(Pair("confirmations", out.nDepth));
- entry.push_back(Pair("spendable", out.fSpendable));
- entry.push_back(Pair("solvable", out.fSolvable));
- entry.push_back(Pair("safe", out.fSafe));
+ entry.pushKV("scriptPubKey", HexStr(scriptPubKey.begin(), scriptPubKey.end()));
+ entry.pushKV("amount", ValueFromAmount(out.tx->tx->vout[out.i].nValue));
+ entry.pushKV("confirmations", out.nDepth);
+ entry.pushKV("spendable", out.fSpendable);
+ entry.pushKV("solvable", out.fSolvable);
+ entry.pushKV("safe", out.fSafe);
results.push_back(entry);
}
@@ -3134,7 +3155,6 @@ UniValue fundrawtransaction(const JSONRPCRequest& request)
{"change_type", UniValueType(UniValue::VSTR)},
{"includeWatching", UniValueType(UniValue::VBOOL)},
{"lockUnspents", UniValueType(UniValue::VBOOL)},
- {"reserveChangeKey", UniValueType(UniValue::VBOOL)}, // DEPRECATED (and ignored), should be removed in 0.16 or so.
{"feeRate", UniValueType()}, // will be checked below
{"subtractFeeFromOutputs", UniValueType(UniValue::VARR)},
{"replaceable", UniValueType(UniValue::VBOOL)},
@@ -3160,8 +3180,8 @@ UniValue fundrawtransaction(const JSONRPCRequest& request)
if (options.exists("changeAddress")) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify both changeAddress and address_type options");
}
- coinControl.change_type = ParseOutputType(options["change_type"].get_str(), coinControl.change_type);
- if (coinControl.change_type == OUTPUT_TYPE_NONE) {
+ coinControl.m_change_type = ParseOutputType(options["change_type"].get_str(), pwallet->m_default_change_type);
+ if (coinControl.m_change_type == OutputType::NONE) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Unknown change type '%s'", options["change_type"].get_str()));
}
}
@@ -3234,13 +3254,82 @@ UniValue fundrawtransaction(const JSONRPCRequest& request)
}
UniValue result(UniValue::VOBJ);
- result.push_back(Pair("hex", EncodeHexTx(tx)));
- result.push_back(Pair("changepos", changePosition));
- result.push_back(Pair("fee", ValueFromAmount(nFeeOut)));
+ result.pushKV("hex", EncodeHexTx(tx));
+ result.pushKV("changepos", changePosition);
+ result.pushKV("fee", ValueFromAmount(nFeeOut));
return result;
}
+UniValue signrawtransactionwithwallet(const JSONRPCRequest& request)
+{
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
+ return NullUniValue;
+ }
+
+ if (request.fHelp || request.params.size() < 1 || request.params.size() > 3)
+ throw std::runtime_error(
+ "signrawtransactionwithwallet \"hexstring\" ( [{\"txid\":\"id\",\"vout\":n,\"scriptPubKey\":\"hex\",\"redeemScript\":\"hex\"},...] sighashtype )\n"
+ "\nSign inputs for raw transaction (serialized, hex-encoded).\n"
+ "The second optional argument (may be null) is an array of previous transaction outputs that\n"
+ "this transaction depends on but may not yet be in the block chain.\n"
+ + HelpRequiringPassphrase(pwallet) + "\n"
+
+ "\nArguments:\n"
+ "1. \"hexstring\" (string, required) The transaction hex string\n"
+ "2. \"prevtxs\" (string, optional) An json array of previous dependent transaction outputs\n"
+ " [ (json array of json objects, or 'null' if none provided)\n"
+ " {\n"
+ " \"txid\":\"id\", (string, required) The transaction id\n"
+ " \"vout\":n, (numeric, required) The output number\n"
+ " \"scriptPubKey\": \"hex\", (string, required) script key\n"
+ " \"redeemScript\": \"hex\", (string, required for P2SH or P2WSH) redeem script\n"
+ " \"amount\": value (numeric, required) The amount spent\n"
+ " }\n"
+ " ,...\n"
+ " ]\n"
+ "3. \"sighashtype\" (string, optional, default=ALL) The signature hash type. Must be one of\n"
+ " \"ALL\"\n"
+ " \"NONE\"\n"
+ " \"SINGLE\"\n"
+ " \"ALL|ANYONECANPAY\"\n"
+ " \"NONE|ANYONECANPAY\"\n"
+ " \"SINGLE|ANYONECANPAY\"\n"
+
+ "\nResult:\n"
+ "{\n"
+ " \"hex\" : \"value\", (string) The hex-encoded raw transaction with signature(s)\n"
+ " \"complete\" : true|false, (boolean) If the transaction has a complete set of signatures\n"
+ " \"errors\" : [ (json array of objects) Script verification errors (if there are any)\n"
+ " {\n"
+ " \"txid\" : \"hash\", (string) The hash of the referenced, previous transaction\n"
+ " \"vout\" : n, (numeric) The index of the output to spent and used as input\n"
+ " \"scriptSig\" : \"hex\", (string) The hex-encoded signature script\n"
+ " \"sequence\" : n, (numeric) Script sequence number\n"
+ " \"error\" : \"text\" (string) Verification or signing error related to the input\n"
+ " }\n"
+ " ,...\n"
+ " ]\n"
+ "}\n"
+
+ "\nExamples:\n"
+ + HelpExampleCli("signrawtransactionwithwallet", "\"myhex\"")
+ + HelpExampleRpc("signrawtransactionwithwallet", "\"myhex\"")
+ );
+
+ RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VARR, UniValue::VSTR}, true);
+
+ CMutableTransaction mtx;
+ if (!DecodeHexTx(mtx, request.params[0].get_str(), true)) {
+ throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
+ }
+
+ // Sign the transaction
+ LOCK2(cs_main, pwallet->cs_wallet);
+ return SignTransaction(mtx, request.params[1], pwallet, false, request.params[2]);
+}
+
UniValue bumpfee(const JSONRPCRequest& request)
{
CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
@@ -3257,8 +3346,8 @@ UniValue bumpfee(const JSONRPCRequest& request)
"If the change output is not big enough to cover the increased fee, the command will currently fail\n"
"instead of adding new inputs to compensate. (A future implementation could improve this.)\n"
"The command will fail if the wallet or mempool contains a transaction that spends one of T's outputs.\n"
- "By default, the new fee will be calculated automatically using estimatefee.\n"
- "The user can specify a confirmation target for estimatefee.\n"
+ "By default, the new fee will be calculated automatically using estimatesmartfee.\n"
+ "The user can specify a confirmation target for estimatesmartfee.\n"
"Alternatively, the user can specify totalFee, or use RPC settxfee to set a higher fee rate.\n"
"At a minimum, the new fee rate must be high enough to pay an additional new relay fee (incrementalfee\n"
"returned by getnetworkinfo) to enter the node's mempool.\n"
@@ -3378,14 +3467,14 @@ UniValue bumpfee(const JSONRPCRequest& request)
throw JSONRPCError(RPC_WALLET_ERROR, errors[0]);
}
UniValue result(UniValue::VOBJ);
- result.push_back(Pair("txid", txid.GetHex()));
- result.push_back(Pair("origfee", ValueFromAmount(old_fee)));
- result.push_back(Pair("fee", ValueFromAmount(new_fee)));
+ result.pushKV("txid", txid.GetHex());
+ result.pushKV("origfee", ValueFromAmount(old_fee));
+ result.pushKV("fee", ValueFromAmount(new_fee));
UniValue result_errors(UniValue::VARR);
for (const std::string& error : errors) {
result_errors.push_back(error);
}
- result.push_back(Pair("errors", result_errors));
+ result.pushKV("errors", result_errors);
return result;
}
@@ -3486,7 +3575,7 @@ UniValue rescanblockchain(const JSONRPCRequest& request)
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid stop_height");
}
else if (pindexStop->nHeight < pindexStart->nHeight) {
- throw JSONRPCError(RPC_INVALID_PARAMETER, "stop_height must be greater then start_height");
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "stop_height must be greater than start_height");
}
}
}
@@ -3520,6 +3609,209 @@ UniValue rescanblockchain(const JSONRPCRequest& request)
return response;
}
+class DescribeWalletAddressVisitor : public boost::static_visitor<UniValue>
+{
+public:
+ CWallet * const pwallet;
+
+ void ProcessSubScript(const CScript& subscript, UniValue& obj, bool include_addresses = false) const
+ {
+ // Always present: script type and redeemscript
+ txnouttype which_type;
+ std::vector<std::vector<unsigned char>> solutions_data;
+ Solver(subscript, which_type, solutions_data);
+ obj.pushKV("script", GetTxnOutputType(which_type));
+ obj.pushKV("hex", HexStr(subscript.begin(), subscript.end()));
+
+ CTxDestination embedded;
+ UniValue a(UniValue::VARR);
+ if (ExtractDestination(subscript, embedded)) {
+ // Only when the script corresponds to an address.
+ UniValue subobj(UniValue::VOBJ);
+ UniValue detail = DescribeAddress(embedded);
+ subobj.pushKVs(detail);
+ UniValue wallet_detail = boost::apply_visitor(*this, embedded);
+ subobj.pushKVs(wallet_detail);
+ subobj.pushKV("address", EncodeDestination(embedded));
+ subobj.pushKV("scriptPubKey", HexStr(subscript.begin(), subscript.end()));
+ // Always report the pubkey at the top level, so that `getnewaddress()['pubkey']` always works.
+ if (subobj.exists("pubkey")) obj.pushKV("pubkey", subobj["pubkey"]);
+ obj.pushKV("embedded", std::move(subobj));
+ if (include_addresses) a.push_back(EncodeDestination(embedded));
+ } else if (which_type == TX_MULTISIG) {
+ // Also report some information on multisig scripts (which do not have a corresponding address).
+ // TODO: abstract out the common functionality between this logic and ExtractDestinations.
+ obj.pushKV("sigsrequired", solutions_data[0][0]);
+ UniValue pubkeys(UniValue::VARR);
+ for (size_t i = 1; i < solutions_data.size() - 1; ++i) {
+ CPubKey key(solutions_data[i].begin(), solutions_data[i].end());
+ if (include_addresses) a.push_back(EncodeDestination(key.GetID()));
+ pubkeys.push_back(HexStr(key.begin(), key.end()));
+ }
+ obj.pushKV("pubkeys", std::move(pubkeys));
+ }
+
+ // The "addresses" field is confusing because it refers to public keys using their P2PKH address.
+ // For that reason, only add the 'addresses' field when needed for backward compatibility. New applications
+ // can use the 'embedded'->'address' field for P2SH or P2WSH wrapped addresses, and 'pubkeys' for
+ // inspecting multisig participants.
+ if (include_addresses) obj.pushKV("addresses", std::move(a));
+ }
+
+ explicit DescribeWalletAddressVisitor(CWallet* _pwallet) : pwallet(_pwallet) {}
+
+ UniValue operator()(const CNoDestination& dest) const { return UniValue(UniValue::VOBJ); }
+
+ UniValue operator()(const CKeyID& keyID) const
+ {
+ UniValue obj(UniValue::VOBJ);
+ CPubKey vchPubKey;
+ if (pwallet && pwallet->GetPubKey(keyID, vchPubKey)) {
+ obj.pushKV("pubkey", HexStr(vchPubKey));
+ obj.pushKV("iscompressed", vchPubKey.IsCompressed());
+ }
+ return obj;
+ }
+
+ UniValue operator()(const CScriptID& scriptID) const
+ {
+ UniValue obj(UniValue::VOBJ);
+ CScript subscript;
+ if (pwallet && pwallet->GetCScript(scriptID, subscript)) {
+ ProcessSubScript(subscript, obj, IsDeprecatedRPCEnabled("validateaddress"));
+ }
+ return obj;
+ }
+
+ UniValue operator()(const WitnessV0KeyHash& id) const
+ {
+ UniValue obj(UniValue::VOBJ);
+ CPubKey pubkey;
+ if (pwallet && pwallet->GetPubKey(CKeyID(id), pubkey)) {
+ obj.pushKV("pubkey", HexStr(pubkey));
+ }
+ return obj;
+ }
+
+ UniValue operator()(const WitnessV0ScriptHash& id) const
+ {
+ UniValue obj(UniValue::VOBJ);
+ CScript subscript;
+ CRIPEMD160 hasher;
+ uint160 hash;
+ hasher.Write(id.begin(), 32).Finalize(hash.begin());
+ if (pwallet && pwallet->GetCScript(CScriptID(hash), subscript)) {
+ ProcessSubScript(subscript, obj);
+ }
+ return obj;
+ }
+
+ UniValue operator()(const WitnessUnknown& id) const { return UniValue(UniValue::VOBJ); }
+};
+
+UniValue DescribeWalletAddress(CWallet* pwallet, const CTxDestination& dest)
+{
+ UniValue ret(UniValue::VOBJ);
+ UniValue detail = DescribeAddress(dest);
+ ret.pushKVs(detail);
+ ret.pushKVs(boost::apply_visitor(DescribeWalletAddressVisitor(pwallet), dest));
+ return ret;
+}
+
+UniValue getaddressinfo(const JSONRPCRequest& request)
+{
+ CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
+ if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
+ return NullUniValue;
+ }
+
+ if (request.fHelp || request.params.size() != 1) {
+ throw std::runtime_error(
+ "getaddressinfo \"address\"\n"
+ "\nReturn information about the given bitcoin address. Some information requires the address\n"
+ "to be in the wallet.\n"
+ "\nArguments:\n"
+ "1. \"address\" (string, required) The bitcoin address to get the information of.\n"
+ "\nResult:\n"
+ "{\n"
+ " \"address\" : \"address\", (string) The bitcoin address validated\n"
+ " \"scriptPubKey\" : \"hex\", (string) The hex encoded scriptPubKey generated by the address\n"
+ " \"ismine\" : true|false, (boolean) If the address is yours or not\n"
+ " \"iswatchonly\" : true|false, (boolean) If the address is watchonly\n"
+ " \"isscript\" : true|false, (boolean) If the key is a script\n"
+ " \"iswitness\" : true|false, (boolean) If the address is a witness address\n"
+ " \"witness_version\" : version (numeric, optional) The version number of the witness program\n"
+ " \"witness_program\" : \"hex\" (string, optional) The hex value of the witness program\n"
+ " \"script\" : \"type\" (string, optional) The output script type. Only if \"isscript\" is true and the redeemscript is known. Possible types: nonstandard, pubkey, pubkeyhash, scripthash, multisig, nulldata, witness_v0_keyhash, witness_v0_scripthash, witness_unknown\n"
+ " \"hex\" : \"hex\", (string, optional) The redeemscript for the p2sh address\n"
+ " \"pubkeys\" (string, optional) Array of pubkeys associated with the known redeemscript (only if \"script\" is \"multisig\")\n"
+ " [\n"
+ " \"pubkey\"\n"
+ " ,...\n"
+ " ]\n"
+ " \"sigsrequired\" : xxxxx (numeric, optional) Number of signatures required to spend multisig output (only if \"script\" is \"multisig\")\n"
+ " \"pubkey\" : \"publickeyhex\", (string, optional) The hex value of the raw public key, for single-key addresses (possibly embedded in P2SH or P2WSH)\n"
+ " \"embedded\" : {...}, (object, optional) Information about the address embedded in P2SH or P2WSH, if relevant and known. It includes all getaddressinfo output fields for the embedded address, excluding metadata (\"timestamp\", \"hdkeypath\", \"hdmasterkeyid\") and relation to the wallet (\"ismine\", \"iswatchonly\", \"account\").\n"
+ " \"iscompressed\" : true|false, (boolean) If the address is compressed\n"
+ " \"account\" : \"account\" (string) The account associated with the address, \"\" is the default account\n"
+ " \"timestamp\" : timestamp, (number, optional) The creation time of the key if available in seconds since epoch (Jan 1 1970 GMT)\n"
+ " \"hdkeypath\" : \"keypath\" (string, optional) The HD keypath if the key is HD and available\n"
+ " \"hdmasterkeyid\" : \"<hash160>\" (string, optional) The Hash160 of the HD master pubkey\n"
+ "}\n"
+ "\nExamples:\n"
+ + HelpExampleCli("getaddressinfo", "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"")
+ + HelpExampleRpc("getaddressinfo", "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"")
+ );
+ }
+
+ LOCK(pwallet->cs_wallet);
+
+ UniValue ret(UniValue::VOBJ);
+ CTxDestination dest = DecodeDestination(request.params[0].get_str());
+
+ // Make sure the destination is valid
+ if (!IsValidDestination(dest)) {
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
+ }
+
+ std::string currentAddress = EncodeDestination(dest);
+ ret.pushKV("address", currentAddress);
+
+ CScript scriptPubKey = GetScriptForDestination(dest);
+ ret.pushKV("scriptPubKey", HexStr(scriptPubKey.begin(), scriptPubKey.end()));
+
+ isminetype mine = IsMine(*pwallet, dest);
+ ret.pushKV("ismine", bool(mine & ISMINE_SPENDABLE));
+ ret.pushKV("iswatchonly", bool(mine & ISMINE_WATCH_ONLY));
+ UniValue detail = DescribeWalletAddress(pwallet, dest);
+ ret.pushKVs(detail);
+ if (pwallet->mapAddressBook.count(dest)) {
+ ret.pushKV("account", pwallet->mapAddressBook[dest].name);
+ }
+ const CKeyMetadata* meta = nullptr;
+ CKeyID key_id = GetKeyForDestination(*pwallet, dest);
+ if (!key_id.IsNull()) {
+ auto it = pwallet->mapKeyMetadata.find(key_id);
+ if (it != pwallet->mapKeyMetadata.end()) {
+ meta = &it->second;
+ }
+ }
+ if (!meta) {
+ auto it = pwallet->m_script_metadata.find(CScriptID(scriptPubKey));
+ if (it != pwallet->m_script_metadata.end()) {
+ meta = &it->second;
+ }
+ }
+ if (meta) {
+ ret.pushKV("timestamp", meta->nCreateTime);
+ if (!meta->hdKeypath.empty()) {
+ ret.pushKV("hdkeypath", meta->hdKeypath);
+ ret.pushKV("hdmasterkeyid", meta->hdMasterKeyID.GetHex());
+ }
+ }
+ return ret;
+}
+
extern UniValue abortrescan(const JSONRPCRequest& request); // in rpcdump.cpp
extern UniValue dumpprivkey(const JSONRPCRequest& request); // in rpcdump.cpp
extern UniValue importprivkey(const JSONRPCRequest& request);
@@ -3533,61 +3825,67 @@ extern UniValue importmulti(const JSONRPCRequest& request);
extern UniValue rescanblockchain(const JSONRPCRequest& request);
static const CRPCCommand commands[] =
-{ // category name actor (function) argNames
- // --------------------- ------------------------ ----------------------- ----------
- { "rawtransactions", "fundrawtransaction", &fundrawtransaction, {"hexstring","options","iswitness"} },
- { "hidden", "resendwallettransactions", &resendwallettransactions, {} },
- { "wallet", "abandontransaction", &abandontransaction, {"txid"} },
- { "wallet", "abortrescan", &abortrescan, {} },
- { "wallet", "addmultisigaddress", &addmultisigaddress, {"nrequired","keys","account","address_type"} },
- { "hidden", "addwitnessaddress", &addwitnessaddress, {"address","p2sh"} },
- { "wallet", "backupwallet", &backupwallet, {"destination"} },
- { "wallet", "bumpfee", &bumpfee, {"txid", "options"} },
- { "wallet", "dumpprivkey", &dumpprivkey, {"address"} },
- { "wallet", "dumpwallet", &dumpwallet, {"filename"} },
- { "wallet", "encryptwallet", &encryptwallet, {"passphrase"} },
- { "wallet", "getaccountaddress", &getaccountaddress, {"account"} },
- { "wallet", "getaccount", &getaccount, {"address"} },
- { "wallet", "getaddressesbyaccount", &getaddressesbyaccount, {"account"} },
- { "wallet", "getbalance", &getbalance, {"account","minconf","include_watchonly"} },
- { "wallet", "getnewaddress", &getnewaddress, {"account","address_type"} },
- { "wallet", "getrawchangeaddress", &getrawchangeaddress, {"address_type"} },
- { "wallet", "getreceivedbyaccount", &getreceivedbyaccount, {"account","minconf"} },
- { "wallet", "getreceivedbyaddress", &getreceivedbyaddress, {"address","minconf"} },
- { "wallet", "gettransaction", &gettransaction, {"txid","include_watchonly"} },
- { "wallet", "getunconfirmedbalance", &getunconfirmedbalance, {} },
- { "wallet", "getwalletinfo", &getwalletinfo, {} },
- { "wallet", "importmulti", &importmulti, {"requests","options"} },
- { "wallet", "importprivkey", &importprivkey, {"privkey","label","rescan"} },
- { "wallet", "importwallet", &importwallet, {"filename"} },
- { "wallet", "importaddress", &importaddress, {"address","label","rescan","p2sh"} },
- { "wallet", "importprunedfunds", &importprunedfunds, {"rawtransaction","txoutproof"} },
- { "wallet", "importpubkey", &importpubkey, {"pubkey","label","rescan"} },
- { "wallet", "keypoolrefill", &keypoolrefill, {"newsize"} },
- { "wallet", "listaccounts", &listaccounts, {"minconf","include_watchonly"} },
- { "wallet", "listaddressgroupings", &listaddressgroupings, {} },
- { "wallet", "listlockunspent", &listlockunspent, {} },
- { "wallet", "listreceivedbyaccount", &listreceivedbyaccount, {"minconf","include_empty","include_watchonly"} },
- { "wallet", "listreceivedbyaddress", &listreceivedbyaddress, {"minconf","include_empty","include_watchonly"} },
- { "wallet", "listsinceblock", &listsinceblock, {"blockhash","target_confirmations","include_watchonly","include_removed"} },
- { "wallet", "listtransactions", &listtransactions, {"account","count","skip","include_watchonly"} },
- { "wallet", "listunspent", &listunspent, {"minconf","maxconf","addresses","include_unsafe","query_options"} },
- { "wallet", "listwallets", &listwallets, {} },
- { "wallet", "lockunspent", &lockunspent, {"unlock","transactions"} },
- { "wallet", "move", &movecmd, {"fromaccount","toaccount","amount","minconf","comment"} },
- { "wallet", "sendfrom", &sendfrom, {"fromaccount","toaddress","amount","minconf","comment","comment_to"} },
- { "wallet", "sendmany", &sendmany, {"fromaccount","amounts","minconf","comment","subtractfeefrom","replaceable","conf_target","estimate_mode"} },
- { "wallet", "sendtoaddress", &sendtoaddress, {"address","amount","comment","comment_to","subtractfeefromamount","replaceable","conf_target","estimate_mode"} },
- { "wallet", "setaccount", &setaccount, {"address","account"} },
- { "wallet", "settxfee", &settxfee, {"amount"} },
- { "wallet", "signmessage", &signmessage, {"address","message"} },
- { "wallet", "walletlock", &walletlock, {} },
- { "wallet", "walletpassphrasechange", &walletpassphrasechange, {"oldpassphrase","newpassphrase"} },
- { "wallet", "walletpassphrase", &walletpassphrase, {"passphrase","timeout"} },
- { "wallet", "removeprunedfunds", &removeprunedfunds, {"txid"} },
- { "wallet", "rescanblockchain", &rescanblockchain, {"start_height", "stop_height"} },
-
- { "generating", "generate", &generate, {"nblocks","maxtries"} },
+{ // category name actor (function) argNames
+ // --------------------- ------------------------ ----------------------- ----------
+ { "rawtransactions", "fundrawtransaction", &fundrawtransaction, {"hexstring","options","iswitness"} },
+ { "hidden", "resendwallettransactions", &resendwallettransactions, {} },
+ { "wallet", "abandontransaction", &abandontransaction, {"txid"} },
+ { "wallet", "abortrescan", &abortrescan, {} },
+ { "wallet", "addmultisigaddress", &addmultisigaddress, {"nrequired","keys","label|account","address_type"} },
+ { "hidden", "addwitnessaddress", &addwitnessaddress, {"address","p2sh"} },
+ { "wallet", "backupwallet", &backupwallet, {"destination"} },
+ { "wallet", "bumpfee", &bumpfee, {"txid", "options"} },
+ { "wallet", "dumpprivkey", &dumpprivkey, {"address"} },
+ { "wallet", "dumpwallet", &dumpwallet, {"filename"} },
+ { "wallet", "encryptwallet", &encryptwallet, {"passphrase"} },
+ { "wallet", "getlabeladdress", &getlabeladdress, {"label"} },
+ { "wallet", "getaccountaddress", &getlabeladdress, {"account"} },
+ { "wallet", "getaccount", &getaccount, {"address"} },
+ { "wallet", "getaddressesbyaccount", &getaddressesbyaccount, {"account"} },
+ { "wallet", "getaddressinfo", &getaddressinfo, {"address"} },
+ { "wallet", "getbalance", &getbalance, {"account","minconf","include_watchonly"} },
+ { "wallet", "getnewaddress", &getnewaddress, {"label|account","address_type"} },
+ { "wallet", "getrawchangeaddress", &getrawchangeaddress, {"address_type"} },
+ { "wallet", "getreceivedbylabel", &getreceivedbylabel, {"label","minconf"} },
+ { "wallet", "getreceivedbyaccount", &getreceivedbylabel, {"account","minconf"} },
+ { "wallet", "getreceivedbyaddress", &getreceivedbyaddress, {"address","minconf"} },
+ { "wallet", "gettransaction", &gettransaction, {"txid","include_watchonly"} },
+ { "wallet", "getunconfirmedbalance", &getunconfirmedbalance, {} },
+ { "wallet", "getwalletinfo", &getwalletinfo, {} },
+ { "wallet", "importmulti", &importmulti, {"requests","options"} },
+ { "wallet", "importprivkey", &importprivkey, {"privkey","label","rescan"} },
+ { "wallet", "importwallet", &importwallet, {"filename"} },
+ { "wallet", "importaddress", &importaddress, {"address","label","rescan","p2sh"} },
+ { "wallet", "importprunedfunds", &importprunedfunds, {"rawtransaction","txoutproof"} },
+ { "wallet", "importpubkey", &importpubkey, {"pubkey","label","rescan"} },
+ { "wallet", "keypoolrefill", &keypoolrefill, {"newsize"} },
+ { "wallet", "listaccounts", &listaccounts, {"minconf","include_watchonly"} },
+ { "wallet", "listaddressgroupings", &listaddressgroupings, {} },
+ { "wallet", "listlockunspent", &listlockunspent, {} },
+ { "wallet", "listreceivedbylabel", &listreceivedbylabel, {"minconf","include_empty","include_watchonly"} },
+ { "wallet", "listreceivedbyaccount", &listreceivedbylabel, {"minconf","include_empty","include_watchonly"} },
+ { "wallet", "listreceivedbyaddress", &listreceivedbyaddress, {"minconf","include_empty","include_watchonly","address_filter"} },
+ { "wallet", "listsinceblock", &listsinceblock, {"blockhash","target_confirmations","include_watchonly","include_removed"} },
+ { "wallet", "listtransactions", &listtransactions, {"account","count","skip","include_watchonly"} },
+ { "wallet", "listunspent", &listunspent, {"minconf","maxconf","addresses","include_unsafe","query_options"} },
+ { "wallet", "listwallets", &listwallets, {} },
+ { "wallet", "lockunspent", &lockunspent, {"unlock","transactions"} },
+ { "wallet", "move", &movecmd, {"fromaccount","toaccount","amount","minconf","comment"} },
+ { "wallet", "sendfrom", &sendfrom, {"fromaccount","toaddress","amount","minconf","comment","comment_to"} },
+ { "wallet", "sendmany", &sendmany, {"fromaccount","amounts","minconf","comment","subtractfeefrom","replaceable","conf_target","estimate_mode"} },
+ { "wallet", "sendtoaddress", &sendtoaddress, {"address","amount","comment","comment_to","subtractfeefromamount","replaceable","conf_target","estimate_mode"} },
+ { "wallet", "setlabel", &setlabel, {"address","label"} },
+ { "wallet", "setaccount", &setlabel, {"address","account"} },
+ { "wallet", "settxfee", &settxfee, {"amount"} },
+ { "wallet", "signmessage", &signmessage, {"address","message"} },
+ { "wallet", "signrawtransactionwithwallet", &signrawtransactionwithwallet, {"hexstring","prevtxs","sighashtype"} },
+ { "wallet", "walletlock", &walletlock, {} },
+ { "wallet", "walletpassphrasechange", &walletpassphrasechange, {"oldpassphrase","newpassphrase"} },
+ { "wallet", "walletpassphrase", &walletpassphrase, {"passphrase","timeout"} },
+ { "wallet", "removeprunedfunds", &removeprunedfunds, {"txid"} },
+ { "wallet", "rescanblockchain", &rescanblockchain, {"start_height", "stop_height"} },
+
+ { "generating", "generate", &generate, {"nblocks","maxtries"} },
};
void RegisterWalletRPCCommands(CRPCTable &t)