@@ -2447,33 +2447,66 @@ UniValue lockunspent(const JSONRPCRequest& request)
2447
2447
2448
2448
RPCTypeCheckArgument (request.params [1 ], UniValue::VARR);
2449
2449
2450
- UniValue outputs = request.params [1 ].get_array ();
2451
- for (unsigned int idx = 0 ; idx < outputs.size (); idx++) {
2452
- const UniValue& output = outputs[idx];
2453
- if (!output.isObject ())
2454
- throw JSONRPCError (RPC_INVALID_PARAMETER, " Invalid parameter, expected object" );
2455
- const UniValue& o = output.get_obj ();
2450
+ const UniValue& output_params = request.params [1 ];
2451
+
2452
+ // Create and validate the COutPoints first.
2453
+
2454
+ std::vector<COutPoint> outputs;
2455
+ outputs.reserve (output_params.size ());
2456
+
2457
+ for (unsigned int idx = 0 ; idx < output_params.size (); idx++) {
2458
+ const UniValue& o = output_params[idx].get_obj ();
2456
2459
2457
2460
RPCTypeCheckObj (o,
2458
2461
{
2459
2462
{" txid" , UniValueType (UniValue::VSTR)},
2460
2463
{" vout" , UniValueType (UniValue::VNUM)},
2461
2464
});
2462
2465
2463
- std::string txid = find_value (o, " txid" ).get_str ();
2464
- if (!IsHex (txid))
2466
+ const std::string& txid = find_value (o, " txid" ).get_str ();
2467
+ if (!IsHex (txid)) {
2465
2468
throw JSONRPCError (RPC_INVALID_PARAMETER, " Invalid parameter, expected hex txid" );
2469
+ }
2466
2470
2467
- int nOutput = find_value (o, " vout" ).get_int ();
2468
- if (nOutput < 0 )
2471
+ const int nOutput = find_value (o, " vout" ).get_int ();
2472
+ if (nOutput < 0 ) {
2469
2473
throw JSONRPCError (RPC_INVALID_PARAMETER, " Invalid parameter, vout must be positive" );
2474
+ }
2470
2475
2471
- COutPoint outpt (uint256S (txid), nOutput);
2476
+ const COutPoint outpt (uint256S (txid), nOutput);
2472
2477
2473
- if (fUnlock )
2474
- pwallet->UnlockCoin (outpt);
2475
- else
2476
- pwallet->LockCoin (outpt);
2478
+ const auto it = pwallet->mapWallet .find (outpt.hash );
2479
+ if (it == pwallet->mapWallet .end ()) {
2480
+ throw JSONRPCError (RPC_INVALID_PARAMETER, " Invalid parameter, unknown transaction" );
2481
+ }
2482
+
2483
+ const CWalletTx& trans = it->second ;
2484
+
2485
+ if (outpt.n >= trans.tx ->vout .size ()) {
2486
+ throw JSONRPCError (RPC_INVALID_PARAMETER, " Invalid parameter, vout index out of bounds" );
2487
+ }
2488
+
2489
+ if (pwallet->IsSpent (outpt.hash , outpt.n )) {
2490
+ throw JSONRPCError (RPC_INVALID_PARAMETER, " Invalid parameter, expected unspent output" );
2491
+ }
2492
+
2493
+ const bool is_locked = pwallet->IsLockedCoin (outpt.hash , outpt.n );
2494
+
2495
+ if (fUnlock && !is_locked) {
2496
+ throw JSONRPCError (RPC_INVALID_PARAMETER, " Invalid parameter, expected locked output" );
2497
+ }
2498
+
2499
+ if (!fUnlock && is_locked) {
2500
+ throw JSONRPCError (RPC_INVALID_PARAMETER, " Invalid parameter, output already locked" );
2501
+ }
2502
+
2503
+ outputs.push_back (outpt);
2504
+ }
2505
+
2506
+ // Atomically set (un)locked status for the outputs.
2507
+ for (const COutPoint& outpt : outputs) {
2508
+ if (fUnlock ) pwallet->UnlockCoin (outpt);
2509
+ else pwallet->LockCoin (outpt);
2477
2510
}
2478
2511
2479
2512
return true ;
0 commit comments