[wallet] Add include_unsafe argument to listunspent RPC

This commit is contained in:
Russell Yanofsky 2017-01-17 10:40:41 -05:00
parent 766e8a40b4
commit 52dde66770
3 changed files with 36 additions and 14 deletions

View File

@ -79,16 +79,20 @@ void RPCTypeCheck(const UniValue& params,
break; break;
const UniValue& v = params[i]; const UniValue& v = params[i];
if (!((v.type() == t) || (fAllowNull && (v.isNull())))) if (!(fAllowNull && v.isNull())) {
{ RPCTypeCheckArgument(v, t);
string err = strprintf("Expected type %s, got %s",
uvTypeName(t), uvTypeName(v.type()));
throw JSONRPCError(RPC_TYPE_ERROR, err);
} }
i++; i++;
} }
} }
void RPCTypeCheckArgument(const UniValue& value, UniValue::VType typeExpected)
{
if (value.type() != typeExpected) {
throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Expected type %s, got %s", uvTypeName(typeExpected), uvTypeName(value.type())));
}
}
void RPCTypeCheckObj(const UniValue& o, void RPCTypeCheckObj(const UniValue& o,
const map<string, UniValueType>& typesExpected, const map<string, UniValueType>& typesExpected,
bool fAllowNull, bool fAllowNull,

View File

@ -78,6 +78,11 @@ bool RPCIsInWarmup(std::string *statusOut);
void RPCTypeCheck(const UniValue& params, void RPCTypeCheck(const UniValue& params,
const std::list<UniValue::VType>& typesExpected, bool fAllowNull=false); const std::list<UniValue::VType>& typesExpected, bool fAllowNull=false);
/**
* Type-check one argument; throws JSONRPCError if wrong type given.
*/
void RPCTypeCheckArgument(const UniValue& value, UniValue::VType typeExpected);
/* /*
Check for expected keys/value types in an Object. Check for expected keys/value types in an Object.
*/ */

View File

@ -2350,9 +2350,9 @@ UniValue listunspent(const JSONRPCRequest& request)
if (!EnsureWalletIsAvailable(request.fHelp)) if (!EnsureWalletIsAvailable(request.fHelp))
return NullUniValue; return NullUniValue;
if (request.fHelp || request.params.size() > 3) if (request.fHelp || request.params.size() > 4)
throw runtime_error( throw runtime_error(
"listunspent ( minconf maxconf [\"addresses\",...] )\n" "listunspent ( minconf maxconf [\"addresses\",...] [include_unsafe] )\n"
"\nReturns array of unspent transaction outputs\n" "\nReturns array of unspent transaction outputs\n"
"with between minconf and maxconf (inclusive) confirmations.\n" "with between minconf and maxconf (inclusive) confirmations.\n"
"Optionally filter to only include txouts paid to specified addresses.\n" "Optionally filter to only include txouts paid to specified addresses.\n"
@ -2364,6 +2364,10 @@ UniValue listunspent(const JSONRPCRequest& request)
" \"address\" (string) bitcoin address\n" " \"address\" (string) bitcoin address\n"
" ,...\n" " ,...\n"
" ]\n" " ]\n"
"4. include_unsafe (bool, optional, default=true) Include outputs that are not safe to spend\n"
" because they come from unconfirmed untrusted transactions or unconfirmed\n"
" replacement transactions (cases where we are less sure that a conflicting\n"
" transaction won't be mined).\n"
"\nResult\n" "\nResult\n"
"[ (array of json object)\n" "[ (array of json object)\n"
" {\n" " {\n"
@ -2387,18 +2391,21 @@ UniValue listunspent(const JSONRPCRequest& request)
+ HelpExampleRpc("listunspent", "6, 9999999 \"[\\\"1PGFqEzfmQch1gKD3ra4k18PNj3tTUUSqg\\\",\\\"1LtvqCaApEdUGFkpKMM4MstjcaL4dKg8SP\\\"]\"") + HelpExampleRpc("listunspent", "6, 9999999 \"[\\\"1PGFqEzfmQch1gKD3ra4k18PNj3tTUUSqg\\\",\\\"1LtvqCaApEdUGFkpKMM4MstjcaL4dKg8SP\\\"]\"")
); );
RPCTypeCheck(request.params, boost::assign::list_of(UniValue::VNUM)(UniValue::VNUM)(UniValue::VARR));
int nMinDepth = 1; int nMinDepth = 1;
if (request.params.size() > 0) if (request.params.size() > 0 && !request.params[0].isNull()) {
RPCTypeCheckArgument(request.params[0], UniValue::VNUM);
nMinDepth = request.params[0].get_int(); nMinDepth = request.params[0].get_int();
}
int nMaxDepth = 9999999; int nMaxDepth = 9999999;
if (request.params.size() > 1) if (request.params.size() > 1 && !request.params[1].isNull()) {
RPCTypeCheckArgument(request.params[1], UniValue::VNUM);
nMaxDepth = request.params[1].get_int(); nMaxDepth = request.params[1].get_int();
}
set<CBitcoinAddress> setAddress; set<CBitcoinAddress> setAddress;
if (request.params.size() > 2) { if (request.params.size() > 2 && !request.params[2].isNull()) {
RPCTypeCheckArgument(request.params[2], UniValue::VARR);
UniValue inputs = request.params[2].get_array(); UniValue inputs = request.params[2].get_array();
for (unsigned int idx = 0; idx < inputs.size(); idx++) { for (unsigned int idx = 0; idx < inputs.size(); idx++) {
const UniValue& input = inputs[idx]; const UniValue& input = inputs[idx];
@ -2411,11 +2418,17 @@ UniValue listunspent(const JSONRPCRequest& request)
} }
} }
bool include_unsafe = true;
if (request.params.size() > 3 && !request.params[3].isNull()) {
RPCTypeCheckArgument(request.params[3], UniValue::VBOOL);
include_unsafe = request.params[3].get_bool();
}
UniValue results(UniValue::VARR); UniValue results(UniValue::VARR);
vector<COutput> vecOutputs; vector<COutput> vecOutputs;
assert(pwalletMain != NULL); assert(pwalletMain != NULL);
LOCK2(cs_main, pwalletMain->cs_wallet); LOCK2(cs_main, pwalletMain->cs_wallet);
pwalletMain->AvailableCoins(vecOutputs, false, NULL, true); pwalletMain->AvailableCoins(vecOutputs, !include_unsafe, NULL, true);
BOOST_FOREACH(const COutput& out, vecOutputs) { BOOST_FOREACH(const COutput& out, vecOutputs) {
if (out.nDepth < nMinDepth || out.nDepth > nMaxDepth) if (out.nDepth < nMinDepth || out.nDepth > nMaxDepth)
continue; continue;
@ -2629,7 +2642,7 @@ static const CRPCCommand commands[] =
{ "wallet", "listreceivedbyaddress", &listreceivedbyaddress, false, {"minconf","include_empty","include_watchonly"} }, { "wallet", "listreceivedbyaddress", &listreceivedbyaddress, false, {"minconf","include_empty","include_watchonly"} },
{ "wallet", "listsinceblock", &listsinceblock, false, {"blockhash","target_confirmations","include_watchonly"} }, { "wallet", "listsinceblock", &listsinceblock, false, {"blockhash","target_confirmations","include_watchonly"} },
{ "wallet", "listtransactions", &listtransactions, false, {"account","count","skip","include_watchonly"} }, { "wallet", "listtransactions", &listtransactions, false, {"account","count","skip","include_watchonly"} },
{ "wallet", "listunspent", &listunspent, false, {"minconf","maxconf","addresses"} }, { "wallet", "listunspent", &listunspent, false, {"minconf","maxconf","addresses","include_unsafe"} },
{ "wallet", "lockunspent", &lockunspent, true, {"unlock","transactions"} }, { "wallet", "lockunspent", &lockunspent, true, {"unlock","transactions"} },
{ "wallet", "move", &movecmd, false, {"fromaccount","toaccount","amount","minconf","comment"} }, { "wallet", "move", &movecmd, false, {"fromaccount","toaccount","amount","minconf","comment"} },
{ "wallet", "sendfrom", &sendfrom, false, {"fromaccount","toaddress","amount","minconf","comment","comment_to"} }, { "wallet", "sendfrom", &sendfrom, false, {"fromaccount","toaddress","amount","minconf","comment","comment_to"} },