wallet/rpc: add 'avoid_reuse' option to RPC commands
createwallet, getbalance, getwalletinfo, listunspent, sendtoaddress rpc/wallet: listunspent include reused flag and show reused utxos by default
This commit is contained in:
parent
f904723e0d
commit
0bdfbd34cf
2 changed files with 33 additions and 8 deletions
|
@ -36,6 +36,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
|
|||
{ "sendtoaddress", 4, "subtractfeefromamount" },
|
||||
{ "sendtoaddress", 5 , "replaceable" },
|
||||
{ "sendtoaddress", 6 , "conf_target" },
|
||||
{ "sendtoaddress", 8, "avoid_reuse" },
|
||||
{ "settxfee", 0, "amount" },
|
||||
{ "sethdseed", 0, "newkeypool" },
|
||||
{ "getreceivedbyaddress", 1, "minconf" },
|
||||
|
@ -48,6 +49,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
|
|||
{ "listreceivedbylabel", 2, "include_watchonly" },
|
||||
{ "getbalance", 1, "minconf" },
|
||||
{ "getbalance", 2, "include_watchonly" },
|
||||
{ "getbalance", 3, "avoid_reuse" },
|
||||
{ "getblockhash", 0, "height" },
|
||||
{ "waitforblockheight", 0, "height" },
|
||||
{ "waitforblockheight", 1, "timeout" },
|
||||
|
@ -163,6 +165,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
|
|||
{ "rescanblockchain", 1, "stop_height"},
|
||||
{ "createwallet", 1, "disable_private_keys"},
|
||||
{ "createwallet", 2, "blank"},
|
||||
{ "createwallet", 4, "avoid_reuse"},
|
||||
{ "getnodeaddresses", 0, "count"},
|
||||
{ "stop", 0, "wait" },
|
||||
};
|
||||
|
|
|
@ -321,7 +321,7 @@ static UniValue setlabel(const JSONRPCRequest& request)
|
|||
|
||||
static CTransactionRef SendMoney(interfaces::Chain::Lock& locked_chain, CWallet * const pwallet, const CTxDestination &address, CAmount nValue, bool fSubtractFeeFromAmount, const CCoinControl& coin_control, mapValue_t mapValue)
|
||||
{
|
||||
CAmount curBalance = pwallet->GetBalance().m_mine_trusted;
|
||||
CAmount curBalance = pwallet->GetBalance(0, coin_control.m_avoid_address_reuse).m_mine_trusted;
|
||||
|
||||
// Check amount
|
||||
if (nValue <= 0)
|
||||
|
@ -368,7 +368,7 @@ static UniValue sendtoaddress(const JSONRPCRequest& request)
|
|||
return NullUniValue;
|
||||
}
|
||||
|
||||
if (request.fHelp || request.params.size() < 2 || request.params.size() > 8)
|
||||
if (request.fHelp || request.params.size() < 2 || request.params.size() > 9)
|
||||
throw std::runtime_error(
|
||||
RPCHelpMan{"sendtoaddress",
|
||||
"\nSend an amount to a given address." +
|
||||
|
@ -389,6 +389,8 @@ static UniValue sendtoaddress(const JSONRPCRequest& request)
|
|||
" \"UNSET\"\n"
|
||||
" \"ECONOMICAL\"\n"
|
||||
" \"CONSERVATIVE\""},
|
||||
{"avoid_reuse", RPCArg::Type::BOOL, /* default */ pwallet->IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE) ? "true" : "unavailable", "Avoid spending from dirty addresses; addresses are considered\n"
|
||||
" dirty if they have previously been used in a transaction."},
|
||||
},
|
||||
RPCResult{
|
||||
"\"txid\" (string) The transaction id.\n"
|
||||
|
@ -445,6 +447,7 @@ static UniValue sendtoaddress(const JSONRPCRequest& request)
|
|||
}
|
||||
}
|
||||
|
||||
coin_control.m_avoid_address_reuse = GetAvoidReuseFlag(pwallet, request.params[8]);
|
||||
|
||||
EnsureWalletIsUnlocked(pwallet);
|
||||
|
||||
|
@ -734,7 +737,7 @@ static UniValue getbalance(const JSONRPCRequest& request)
|
|||
return NullUniValue;
|
||||
}
|
||||
|
||||
if (request.fHelp || (request.params.size() > 3 ))
|
||||
if (request.fHelp || request.params.size() > 4)
|
||||
throw std::runtime_error(
|
||||
RPCHelpMan{"getbalance",
|
||||
"\nReturns the total available balance.\n"
|
||||
|
@ -744,6 +747,7 @@ static UniValue getbalance(const JSONRPCRequest& request)
|
|||
{"dummy", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "Remains for backward compatibility. Must be excluded or set to \"*\"."},
|
||||
{"minconf", RPCArg::Type::NUM, /* default */ "0", "Only include transactions confirmed at least this many times."},
|
||||
{"include_watchonly", RPCArg::Type::BOOL, /* default */ "false", "Also include balance in watch-only addresses (see 'importaddress')"},
|
||||
{"avoid_reuse", RPCArg::Type::BOOL, /* default */ pwallet->IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE) ? "true" : "unavailable", "Do not include balance in dirty outputs; addresses are considered dirty if they have previously been used in a transaction."},
|
||||
},
|
||||
RPCResult{
|
||||
"amount (numeric) The total amount in " + CURRENCY_UNIT + " received for this wallet.\n"
|
||||
|
@ -780,7 +784,9 @@ static UniValue getbalance(const JSONRPCRequest& request)
|
|||
include_watchonly = true;
|
||||
}
|
||||
|
||||
const auto bal = pwallet->GetBalance(min_depth);
|
||||
bool avoid_reuse = GetAvoidReuseFlag(pwallet, request.params[3]);
|
||||
|
||||
const auto bal = pwallet->GetBalance(min_depth, avoid_reuse);
|
||||
|
||||
return ValueFromAmount(bal.m_mine_trusted + (include_watchonly ? bal.m_watchonly_trusted : 0));
|
||||
}
|
||||
|
@ -2474,6 +2480,7 @@ static UniValue getwalletinfo(const JSONRPCRequest& request)
|
|||
" \"paytxfee\": x.xxxx, (numeric) the transaction fee configuration, set in " + CURRENCY_UNIT + "/kB\n"
|
||||
" \"hdseedid\": \"<hash160>\" (string, optional) the Hash160 of the HD seed (only present when HD is enabled)\n"
|
||||
" \"private_keys_enabled\": true|false (boolean) false if privatekeys are disabled for this wallet (enforced watch-only wallet)\n"
|
||||
" \"avoid_reuse\": true|false (boolean) whether this wallet tracks clean/dirty coins in terms of reuse\n"
|
||||
" \"scanning\": (json object) current scanning details, or false if no scan is in progress\n"
|
||||
" {\n"
|
||||
" \"duration\" : xxxx (numeric) elapsed seconds since scan start\n"
|
||||
|
@ -2522,6 +2529,7 @@ static UniValue getwalletinfo(const JSONRPCRequest& request)
|
|||
obj.pushKV("hdseedid", seed_id.GetHex());
|
||||
}
|
||||
obj.pushKV("private_keys_enabled", !pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS));
|
||||
obj.pushKV("avoid_reuse", pwallet->IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE));
|
||||
if (pwallet->IsScanning()) {
|
||||
UniValue scanning(UniValue::VOBJ);
|
||||
scanning.pushKV("duration", pwallet->ScanningDuration() / 1000);
|
||||
|
@ -2730,6 +2738,7 @@ static UniValue createwallet(const JSONRPCRequest& request)
|
|||
{"disable_private_keys", RPCArg::Type::BOOL, /* default */ "false", "Disable the possibility of private keys (only watchonlys are possible in this mode)."},
|
||||
{"blank", RPCArg::Type::BOOL, /* default */ "false", "Create a blank wallet. A blank wallet has no keys or HD seed. One can be set using sethdseed."},
|
||||
{"passphrase", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Encrypt the wallet with this passphrase."},
|
||||
{"avoid_reuse", RPCArg::Type::BOOL, /* default */ "false", "Keep track of coin reuse, and treat dirty and clean coins differently with privacy considerations in mind."},
|
||||
},
|
||||
RPCResult{
|
||||
"{\n"
|
||||
|
@ -2771,6 +2780,10 @@ static UniValue createwallet(const JSONRPCRequest& request)
|
|||
flags |= WALLET_FLAG_BLANK_WALLET;
|
||||
}
|
||||
|
||||
if (!request.params[4].isNull() && request.params[4].get_bool()) {
|
||||
flags |= WALLET_FLAG_AVOID_REUSE;
|
||||
}
|
||||
|
||||
WalletLocation location(request.params[0].get_str());
|
||||
if (location.Exists()) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Wallet " + location.GetName() + " already exists.");
|
||||
|
@ -2872,6 +2885,8 @@ static UniValue listunspent(const JSONRPCRequest& request)
|
|||
return NullUniValue;
|
||||
}
|
||||
|
||||
bool avoid_reuse = pwallet->IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE);
|
||||
|
||||
if (request.fHelp || request.params.size() > 5)
|
||||
throw std::runtime_error(
|
||||
RPCHelpMan{"listunspent",
|
||||
|
@ -2911,6 +2926,9 @@ static UniValue listunspent(const JSONRPCRequest& request)
|
|||
" \"witnessScript\" : \"script\" (string) witnessScript if the scriptPubKey is P2WSH or P2SH-P2WSH\n"
|
||||
" \"spendable\" : xxx, (bool) Whether we have the private keys to spend this output\n"
|
||||
" \"solvable\" : xxx, (bool) Whether we know how to spend this output, ignoring the lack of keys\n"
|
||||
+ (avoid_reuse ?
|
||||
" \"reused\" : xxx, (bool) Whether this output is reused/dirty (sent to an address that was previously spent from)\n" :
|
||||
"") +
|
||||
" \"desc\" : xxx, (string, only when solvable) A descriptor for spending this output\n"
|
||||
" \"safe\" : xxx (bool) Whether this output is considered safe to spend. Unconfirmed transactions\n"
|
||||
" from outside keys and unconfirmed replacement transactions are considered unsafe\n"
|
||||
|
@ -2990,9 +3008,11 @@ static UniValue listunspent(const JSONRPCRequest& request)
|
|||
UniValue results(UniValue::VARR);
|
||||
std::vector<COutput> vecOutputs;
|
||||
{
|
||||
CCoinControl cctl;
|
||||
cctl.m_avoid_address_reuse = false;
|
||||
auto locked_chain = pwallet->chain().lock();
|
||||
LOCK(pwallet->cs_wallet);
|
||||
pwallet->AvailableCoins(*locked_chain, vecOutputs, !include_unsafe, nullptr, nMinimumAmount, nMaximumAmount, nMinimumSumAmount, nMaximumCount, nMinDepth, nMaxDepth);
|
||||
pwallet->AvailableCoins(*locked_chain, vecOutputs, !include_unsafe, &cctl, nMinimumAmount, nMaximumAmount, nMinimumSumAmount, nMaximumCount, nMinDepth, nMaxDepth);
|
||||
}
|
||||
|
||||
LOCK(pwallet->cs_wallet);
|
||||
|
@ -3001,6 +3021,7 @@ static UniValue listunspent(const JSONRPCRequest& request)
|
|||
CTxDestination address;
|
||||
const CScript& scriptPubKey = out.tx->tx->vout[out.i].scriptPubKey;
|
||||
bool fValidAddress = ExtractDestination(scriptPubKey, address);
|
||||
bool reused = avoid_reuse && pwallet->IsUsedDestination(address);
|
||||
|
||||
if (destinations.size() && (!fValidAddress || !destinations.count(address)))
|
||||
continue;
|
||||
|
@ -3057,6 +3078,7 @@ static UniValue listunspent(const JSONRPCRequest& request)
|
|||
auto descriptor = InferDescriptor(scriptPubKey, *pwallet);
|
||||
entry.pushKV("desc", descriptor->ToString());
|
||||
}
|
||||
if (avoid_reuse) entry.pushKV("reused", reused);
|
||||
entry.pushKV("safe", out.fSafe);
|
||||
results.push_back(entry);
|
||||
}
|
||||
|
@ -4261,13 +4283,13 @@ static const CRPCCommand commands[] =
|
|||
{ "wallet", "addmultisigaddress", &addmultisigaddress, {"nrequired","keys","label","address_type"} },
|
||||
{ "wallet", "backupwallet", &backupwallet, {"destination"} },
|
||||
{ "wallet", "bumpfee", &bumpfee, {"txid", "options"} },
|
||||
{ "wallet", "createwallet", &createwallet, {"wallet_name", "disable_private_keys", "blank", "passphrase"} },
|
||||
{ "wallet", "createwallet", &createwallet, {"wallet_name", "disable_private_keys", "blank", "passphrase", "avoid_reuse"} },
|
||||
{ "wallet", "dumpprivkey", &dumpprivkey, {"address"} },
|
||||
{ "wallet", "dumpwallet", &dumpwallet, {"filename"} },
|
||||
{ "wallet", "encryptwallet", &encryptwallet, {"passphrase"} },
|
||||
{ "wallet", "getaddressesbylabel", &getaddressesbylabel, {"label"} },
|
||||
{ "wallet", "getaddressinfo", &getaddressinfo, {"address"} },
|
||||
{ "wallet", "getbalance", &getbalance, {"dummy","minconf","include_watchonly"} },
|
||||
{ "wallet", "getbalance", &getbalance, {"dummy","minconf","include_watchonly","avoid_reuse"} },
|
||||
{ "wallet", "getnewaddress", &getnewaddress, {"label","address_type"} },
|
||||
{ "wallet", "getrawchangeaddress", &getrawchangeaddress, {"address_type"} },
|
||||
{ "wallet", "getreceivedbyaddress", &getreceivedbyaddress, {"address","minconf"} },
|
||||
|
@ -4298,7 +4320,7 @@ static const CRPCCommand commands[] =
|
|||
{ "wallet", "removeprunedfunds", &removeprunedfunds, {"txid"} },
|
||||
{ "wallet", "rescanblockchain", &rescanblockchain, {"start_height", "stop_height"} },
|
||||
{ "wallet", "sendmany", &sendmany, {"dummy","amounts","minconf","comment","subtractfeefrom","replaceable","conf_target","estimate_mode"} },
|
||||
{ "wallet", "sendtoaddress", &sendtoaddress, {"address","amount","comment","comment_to","subtractfeefromamount","replaceable","conf_target","estimate_mode"} },
|
||||
{ "wallet", "sendtoaddress", &sendtoaddress, {"address","amount","comment","comment_to","subtractfeefromamount","replaceable","conf_target","estimate_mode","avoid_reuse"} },
|
||||
{ "wallet", "sethdseed", &sethdseed, {"newkeypool","seed"} },
|
||||
{ "wallet", "setlabel", &setlabel, {"address","label"} },
|
||||
{ "wallet", "settxfee", &settxfee, {"amount"} },
|
||||
|
|
Loading…
Reference in a new issue