diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -2285,12 +2285,6 @@ return NullUniValue; } -static void LockWallet(CWallet *pWallet) { - LOCK(pWallet->cs_wallet); - pWallet->nRelockTime = 0; - pWallet->Lock(); -} - static UniValue walletpassphrase(const Config &config, const JSONRPCRequest &request) { std::shared_ptr const wallet = GetWalletForJSONRPCRequest(request); @@ -2380,8 +2374,21 @@ pwallet->TopUpKeyPool(); pwallet->nRelockTime = GetTime() + nSleepTime; - RPCRunLater(strprintf("lockwallet(%s)", pwallet->GetName()), - std::bind(LockWallet, pwallet), nSleepTime); + + // 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. + std::weak_ptr weak_wallet = wallet; + RPCRunLater( + strprintf("lockwallet(%s)", pwallet->GetName()), + [weak_wallet] { + if (auto shared_wallet = weak_wallet.lock()) { + LOCK(shared_wallet->cs_wallet); + shared_wallet->Lock(); + shared_wallet->nRelockTime = 0; + } + }, + nSleepTime); return NullUniValue; } diff --git a/test/functional/wallet_multiwallet.py b/test/functional/wallet_multiwallet.py --- a/test/functional/wallet_multiwallet.py +++ b/test/functional/wallet_multiwallet.py @@ -8,6 +8,7 @@ """ import os import shutil +import time from test_framework.test_framework import BitcoinTestFramework from test_framework.test_node import ErrorMatch @@ -354,7 +355,11 @@ assert 'w1' not in self.nodes[0].listwallets() # Successfully unload the wallet referenced by the request endpoint + # Also ensure unload works during walletpassphrase timeout + w2.encryptwallet('test') + w2.walletpassphrase('test', 1) w2.unloadwallet() + time.sleep(1.1) assert 'w2' not in self.nodes[0].listwallets() # Successfully unload all wallets