Skip to content

Commit 52dde66

Browse files
committed
[wallet] Add include_unsafe argument to listunspent RPC
1 parent 766e8a4 commit 52dde66

File tree

3 files changed

+36
-14
lines changed

3 files changed

+36
-14
lines changed

src/rpc/server.cpp

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -79,16 +79,20 @@ void RPCTypeCheck(const UniValue& params,
7979
break;
8080

8181
const UniValue& v = params[i];
82-
if (!((v.type() == t) || (fAllowNull && (v.isNull()))))
83-
{
84-
string err = strprintf("Expected type %s, got %s",
85-
uvTypeName(t), uvTypeName(v.type()));
86-
throw JSONRPCError(RPC_TYPE_ERROR, err);
82+
if (!(fAllowNull && v.isNull())) {
83+
RPCTypeCheckArgument(v, t);
8784
}
8885
i++;
8986
}
9087
}
9188

89+
void RPCTypeCheckArgument(const UniValue& value, UniValue::VType typeExpected)
90+
{
91+
if (value.type() != typeExpected) {
92+
throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Expected type %s, got %s", uvTypeName(typeExpected), uvTypeName(value.type())));
93+
}
94+
}
95+
9296
void RPCTypeCheckObj(const UniValue& o,
9397
const map<string, UniValueType>& typesExpected,
9498
bool fAllowNull,

src/rpc/server.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,11 @@ bool RPCIsInWarmup(std::string *statusOut);
7878
void RPCTypeCheck(const UniValue& params,
7979
const std::list<UniValue::VType>& typesExpected, bool fAllowNull=false);
8080

81+
/**
82+
* Type-check one argument; throws JSONRPCError if wrong type given.
83+
*/
84+
void RPCTypeCheckArgument(const UniValue& value, UniValue::VType typeExpected);
85+
8186
/*
8287
Check for expected keys/value types in an Object.
8388
*/

src/wallet/rpcwallet.cpp

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2350,9 +2350,9 @@ UniValue listunspent(const JSONRPCRequest& request)
23502350
if (!EnsureWalletIsAvailable(request.fHelp))
23512351
return NullUniValue;
23522352

2353-
if (request.fHelp || request.params.size() > 3)
2353+
if (request.fHelp || request.params.size() > 4)
23542354
throw runtime_error(
2355-
"listunspent ( minconf maxconf [\"addresses\",...] )\n"
2355+
"listunspent ( minconf maxconf [\"addresses\",...] [include_unsafe] )\n"
23562356
"\nReturns array of unspent transaction outputs\n"
23572357
"with between minconf and maxconf (inclusive) confirmations.\n"
23582358
"Optionally filter to only include txouts paid to specified addresses.\n"
@@ -2364,6 +2364,10 @@ UniValue listunspent(const JSONRPCRequest& request)
23642364
" \"address\" (string) bitcoin address\n"
23652365
" ,...\n"
23662366
" ]\n"
2367+
"4. include_unsafe (bool, optional, default=true) Include outputs that are not safe to spend\n"
2368+
" because they come from unconfirmed untrusted transactions or unconfirmed\n"
2369+
" replacement transactions (cases where we are less sure that a conflicting\n"
2370+
" transaction won't be mined).\n"
23672371
"\nResult\n"
23682372
"[ (array of json object)\n"
23692373
" {\n"
@@ -2387,18 +2391,21 @@ UniValue listunspent(const JSONRPCRequest& request)
23872391
+ HelpExampleRpc("listunspent", "6, 9999999 \"[\\\"1PGFqEzfmQch1gKD3ra4k18PNj3tTUUSqg\\\",\\\"1LtvqCaApEdUGFkpKMM4MstjcaL4dKg8SP\\\"]\"")
23882392
);
23892393

2390-
RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VNUM)(UniValue::VNUM)(UniValue::VARR));
2391-
23922394
int nMinDepth = 1;
2393-
if (request.params.size() > 0)
2395+
if (request.params.size() > 0 && !request.params[0].isNull()) {
2396+
RPCTypeCheckArgument(request.params[0], UniValue::VNUM);
23942397
nMinDepth = request.params[0].get_int();
2398+
}
23952399

23962400
int nMaxDepth = 9999999;
2397-
if (request.params.size() > 1)
2401+
if (request.params.size() > 1 && !request.params[1].isNull()) {
2402+
RPCTypeCheckArgument(request.params[1], UniValue::VNUM);
23982403
nMaxDepth = request.params[1].get_int();
2404+
}
23992405

24002406
set<CBitcoinAddress> setAddress;
2401-
if (request.params.size() > 2) {
2407+
if (request.params.size() > 2 && !request.params[2].isNull()) {
2408+
RPCTypeCheckArgument(request.params[2], UniValue::VARR);
24022409
UniValue inputs = request.params[2].get_array();
24032410
for (unsigned int idx = 0; idx < inputs.size(); idx++) {
24042411
const UniValue& input = inputs[idx];
@@ -2411,11 +2418,17 @@ UniValue listunspent(const JSONRPCRequest& request)
24112418
}
24122419
}
24132420

2421+
bool include_unsafe = true;
2422+
if (request.params.size() > 3 && !request.params[3].isNull()) {
2423+
RPCTypeCheckArgument(request.params[3], UniValue::VBOOL);
2424+
include_unsafe = request.params[3].get_bool();
2425+
}
2426+
24142427
UniValue results(UniValue::VARR);
24152428
vector<COutput> vecOutputs;
24162429
assert(pwalletMain != NULL);
24172430
LOCK2(cs_main, pwalletMain->cs_wallet);
2418-
pwalletMain->AvailableCoins(vecOutputs, false, NULL, true);
2431+
pwalletMain->AvailableCoins(vecOutputs, !include_unsafe, NULL, true);
24192432
BOOST_FOREACH(const COutput& out, vecOutputs) {
24202433
if (out.nDepth < nMinDepth || out.nDepth > nMaxDepth)
24212434
continue;
@@ -2629,7 +2642,7 @@ static const CRPCCommand commands[] =
26292642
{ "wallet", "listreceivedbyaddress", &listreceivedbyaddress, false, {"minconf","include_empty","include_watchonly"} },
26302643
{ "wallet", "listsinceblock", &listsinceblock, false, {"blockhash","target_confirmations","include_watchonly"} },
26312644
{ "wallet", "listtransactions", &listtransactions, false, {"account","count","skip","include_watchonly"} },
2632-
{ "wallet", "listunspent", &listunspent, false, {"minconf","maxconf","addresses"} },
2645+
{ "wallet", "listunspent", &listunspent, false, {"minconf","maxconf","addresses","include_unsafe"} },
26332646
{ "wallet", "lockunspent", &lockunspent, true, {"unlock","transactions"} },
26342647
{ "wallet", "move", &movecmd, false, {"fromaccount","toaccount","amount","minconf","comment"} },
26352648
{ "wallet", "sendfrom", &sendfrom, false, {"fromaccount","toaddress","amount","minconf","comment","comment_to"} },

0 commit comments

Comments
 (0)