Diagnose unsuitable outputs in lockunspent().

Fixes #2667.
This commit is contained in:
Eelis
2017-08-18 14:21:40 +02:00
parent f74459dba6
commit 28f8b66577
2 changed files with 60 additions and 15 deletions

View File

@@ -2447,12 +2447,15 @@ UniValue lockunspent(const JSONRPCRequest& request)
RPCTypeCheckArgument(request.params[1], UniValue::VARR);
UniValue outputs = request.params[1].get_array();
for (unsigned int idx = 0; idx < outputs.size(); idx++) {
const UniValue& output = outputs[idx];
if (!output.isObject())
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected object");
const UniValue& o = output.get_obj();
const UniValue& output_params = request.params[1];
// Create and validate the COutPoints first.
std::vector<COutPoint> outputs;
outputs.reserve(output_params.size());
for (unsigned int idx = 0; idx < output_params.size(); idx++) {
const UniValue& o = output_params[idx].get_obj();
RPCTypeCheckObj(o,
{
@@ -2460,20 +2463,50 @@ UniValue lockunspent(const JSONRPCRequest& request)
{"vout", UniValueType(UniValue::VNUM)},
});
std::string txid = find_value(o, "txid").get_str();
if (!IsHex(txid))
const std::string& txid = find_value(o, "txid").get_str();
if (!IsHex(txid)) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected hex txid");
}
int nOutput = find_value(o, "vout").get_int();
if (nOutput < 0)
const int nOutput = find_value(o, "vout").get_int();
if (nOutput < 0) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout must be positive");
}
COutPoint outpt(uint256S(txid), nOutput);
const COutPoint outpt(uint256S(txid), nOutput);
if (fUnlock)
pwallet->UnlockCoin(outpt);
else
pwallet->LockCoin(outpt);
const auto it = pwallet->mapWallet.find(outpt.hash);
if (it == pwallet->mapWallet.end()) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, unknown transaction");
}
const CWalletTx& trans = it->second;
if (outpt.n >= trans.tx->vout.size()) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout index out of bounds");
}
if (pwallet->IsSpent(outpt.hash, outpt.n)) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected unspent output");
}
const bool is_locked = pwallet->IsLockedCoin(outpt.hash, outpt.n);
if (fUnlock && !is_locked) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected locked output");
}
if (!fUnlock && is_locked) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, output already locked");
}
outputs.push_back(outpt);
}
// Atomically set (un)locked status for the outputs.
for (const COutPoint& outpt : outputs) {
if (fUnlock) pwallet->UnlockCoin(outpt);
else pwallet->LockCoin(outpt);
}
return true;