Skip to content

Commit f13fc16

Browse files
committed
Allow lockunspent to store the lock in the wallet DB
1 parent c527893 commit f13fc16

File tree

2 files changed

+23
-7
lines changed

2 files changed

+23
-7
lines changed

src/rpc/client.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
131131
{ "gettxoutsetinfo", 2, "use_index"},
132132
{ "lockunspent", 0, "unlock" },
133133
{ "lockunspent", 1, "transactions" },
134+
{ "lockunspent", 2, "persistent" },
134135
{ "send", 0, "outputs" },
135136
{ "send", 1, "conf_target" },
136137
{ "send", 3, "fee_rate"},

src/wallet/rpcwallet.cpp

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2137,8 +2137,9 @@ static RPCHelpMan lockunspent()
21372137
"If no transaction outputs are specified when unlocking then all current locked transaction outputs are unlocked.\n"
21382138
"A locked transaction output will not be chosen by automatic coin selection, when spending bitcoins.\n"
21392139
"Manually selected coins are automatically unlocked.\n"
2140-
"Locks are stored in memory only. Nodes start with zero locked outputs, and the locked output list\n"
2141-
"is always cleared (by virtue of process exit) when a node stops or fails.\n"
2140+
"Locks are stored in memory only, unless persistent=true, in which case they will be written to the\n"
2141+
"wallet database and loaded on node start. Unwritten (persistent=false) locks are always cleared\n"
2142+
"(by virtue of process exit) when a node stops or fails. Unlocking will clear both persistent and not.\n"
21422143
"Also see the listunspent call\n",
21432144
{
21442145
{"unlock", RPCArg::Type::BOOL, RPCArg::Optional::NO, "Whether to unlock (true) or lock (false) the specified transactions"},
@@ -2152,6 +2153,7 @@ static RPCHelpMan lockunspent()
21522153
},
21532154
},
21542155
},
2156+
{"persistent", RPCArg::Type::BOOL, RPCArg::Default{false}, "Whether to write/erase this lock in the wallet database, or keep the change in memory only. Ignored for unlocking."},
21552157
},
21562158
RPCResult{
21572159
RPCResult::Type::BOOL, "", "Whether the command was successful or not"
@@ -2165,6 +2167,8 @@ static RPCHelpMan lockunspent()
21652167
+ HelpExampleCli("listlockunspent", "") +
21662168
"\nUnlock the transaction again\n"
21672169
+ HelpExampleCli("lockunspent", "true \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
2170+
"\nLock the transaction persistently in the wallet database\n"
2171+
+ HelpExampleCli("lockunspent", "false \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\" true") +
21682172
"\nAs a JSON-RPC call\n"
21692173
+ HelpExampleRpc("lockunspent", "false, \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"")
21702174
},
@@ -2183,9 +2187,13 @@ static RPCHelpMan lockunspent()
21832187

21842188
bool fUnlock = request.params[0].get_bool();
21852189

2190+
const bool persistent{request.params[2].isNull() ? false : request.params[2].get_bool()};
2191+
21862192
if (request.params[1].isNull()) {
2187-
if (fUnlock)
2188-
pwallet->UnlockAllCoins();
2193+
if (fUnlock) {
2194+
if (!pwallet->UnlockAllCoins())
2195+
throw JSONRPCError(RPC_WALLET_ERROR, "Unlocking coins failed");
2196+
}
21892197
return true;
21902198
}
21912199

@@ -2236,17 +2244,24 @@ static RPCHelpMan lockunspent()
22362244
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected locked output");
22372245
}
22382246

2239-
if (!fUnlock && is_locked) {
2247+
if (!fUnlock && is_locked && !persistent) {
22402248
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, output already locked");
22412249
}
22422250

22432251
outputs.push_back(outpt);
22442252
}
22452253

2254+
std::unique_ptr<WalletBatch> batch = nullptr;
2255+
// Unlock is always persistent
2256+
if (fUnlock || persistent) batch = std::make_unique<WalletBatch>(pwallet->GetDatabase());
2257+
22462258
// Atomically set (un)locked status for the outputs.
22472259
for (const COutPoint& outpt : outputs) {
2248-
if (fUnlock) pwallet->UnlockCoin(outpt);
2249-
else pwallet->LockCoin(outpt);
2260+
if (fUnlock) {
2261+
if (!pwallet->UnlockCoin(outpt, batch.get())) throw JSONRPCError(RPC_WALLET_ERROR, "Unlocking coin failed");
2262+
} else {
2263+
if (!pwallet->LockCoin(outpt, batch.get())) throw JSONRPCError(RPC_WALLET_ERROR, "Locking coin failed");
2264+
}
22502265
}
22512266

22522267
return true;

0 commit comments

Comments
 (0)