rpc: Fix rpcRunLater race in walletpassphrase

This commit is contained in:
João Barbosa 2020-04-01 00:22:14 +01:00
parent d2db25233c
commit 7b8e15728d

View File

@ -1918,6 +1918,8 @@ static UniValue walletpassphrase(const JSONRPCRequest& request)
},
}.Check(request);
int64_t nSleepTime;
{
auto locked_chain = pwallet->chain().lock();
LOCK(pwallet->cs_wallet);
@ -1933,7 +1935,7 @@ static UniValue walletpassphrase(const JSONRPCRequest& request)
strWalletPass = request.params[0].get_str().c_str();
// Get the timeout
int64_t nSleepTime = request.params[1].get_int64();
nSleepTime = request.params[1].get_int64();
// Timeout cannot be negative, otherwise it will relock immediately
if (nSleepTime < 0) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Timeout cannot be negative.");
@ -1955,7 +1957,13 @@ static UniValue walletpassphrase(const JSONRPCRequest& request)
pwallet->TopUpKeyPool();
pwallet->nRelockTime = GetTime() + nSleepTime;
}
// rpcRunLater must be called without cs_wallet held otherwise a deadlock
// can occur. The deadlock would happen when RPCRunLater removes the
// previous timer (and waits for the callback to finish if already running)
// and the callback locks cs_wallet.
AssertLockNotHeld(wallet->cs_wallet);
// Keep a weak pointer to the wallet so that it is possible to unload the
// wallet before the following callback is called. If a valid shared pointer
// is acquired in the callback then the wallet is still loaded.