@@ -2531,33 +2531,66 @@ UniValue lockunspent(const JSONRPCRequest& request)
2531
2531
2532
2532
RPCTypeCheckArgument (request.params [1 ], UniValue::VARR);
2533
2533
2534
- UniValue outputs = request.params [1 ].get_array ();
2535
- for (unsigned int idx = 0 ; idx < outputs.size (); idx++) {
2536
- const UniValue& output = outputs[idx];
2537
- if (!output.isObject ())
2538
- throw JSONRPCError (RPC_INVALID_PARAMETER, " Invalid parameter, expected object" );
2539
- const UniValue& o = output.get_obj ();
2534
+ const UniValue& output_params = request.params [1 ];
2535
+
2536
+ // Create and validate the COutPoints first.
2537
+
2538
+ std::vector<COutPoint> outputs;
2539
+ outputs.reserve (output_params.size ());
2540
+
2541
+ for (unsigned int idx = 0 ; idx < output_params.size (); idx++) {
2542
+ const UniValue& o = output_params[idx].get_obj ();
2540
2543
2541
2544
RPCTypeCheckObj (o,
2542
2545
{
2543
2546
{" txid" , UniValueType (UniValue::VSTR)},
2544
2547
{" vout" , UniValueType (UniValue::VNUM)},
2545
2548
});
2546
2549
2547
- std::string txid = find_value (o, " txid" ).get_str ();
2548
- if (!IsHex (txid))
2550
+ const std::string& txid = find_value (o, " txid" ).get_str ();
2551
+ if (!IsHex (txid)) {
2549
2552
throw JSONRPCError (RPC_INVALID_PARAMETER, " Invalid parameter, expected hex txid" );
2553
+ }
2550
2554
2551
- int nOutput = find_value (o, " vout" ).get_int ();
2552
- if (nOutput < 0 )
2555
+ const int nOutput = find_value (o, " vout" ).get_int ();
2556
+ if (nOutput < 0 ) {
2553
2557
throw JSONRPCError (RPC_INVALID_PARAMETER, " Invalid parameter, vout must be positive" );
2558
+ }
2554
2559
2555
- COutPoint outpt (uint256S (txid), nOutput);
2560
+ const COutPoint outpt (uint256S (txid), nOutput);
2556
2561
2557
- if (fUnlock )
2558
- pwallet->UnlockCoin (outpt);
2559
- else
2560
- pwallet->LockCoin (outpt);
2562
+ const auto it = pwallet->mapWallet .find (outpt.hash );
2563
+ if (it == pwallet->mapWallet .end ()) {
2564
+ throw JSONRPCError (RPC_INVALID_PARAMETER, " Invalid parameter, unknown transaction" );
2565
+ }
2566
+
2567
+ const CWalletTx& trans = it->second ;
2568
+
2569
+ if (outpt.n >= trans.tx ->vout .size ()) {
2570
+ throw JSONRPCError (RPC_INVALID_PARAMETER, " Invalid parameter, vout index out of bounds" );
2571
+ }
2572
+
2573
+ if (pwallet->IsSpent (outpt.hash , outpt.n )) {
2574
+ throw JSONRPCError (RPC_INVALID_PARAMETER, " Invalid parameter, expected unspent output" );
2575
+ }
2576
+
2577
+ const bool is_locked = pwallet->IsLockedCoin (outpt.hash , outpt.n );
2578
+
2579
+ if (fUnlock && !is_locked) {
2580
+ throw JSONRPCError (RPC_INVALID_PARAMETER, " Invalid parameter, expected locked output" );
2581
+ }
2582
+
2583
+ if (!fUnlock && is_locked) {
2584
+ throw JSONRPCError (RPC_INVALID_PARAMETER, " Invalid parameter, output already locked" );
2585
+ }
2586
+
2587
+ outputs.push_back (outpt);
2588
+ }
2589
+
2590
+ // Atomically set (un)locked status for the outputs.
2591
+ for (const COutPoint& outpt : outputs) {
2592
+ if (fUnlock ) pwallet->UnlockCoin (outpt);
2593
+ else pwallet->LockCoin (outpt);
2561
2594
}
2562
2595
2563
2596
return true ;
0 commit comments