Skip to content

Commit 8a17657

Browse files
committed
use WalletContext scheduler for walletpassphrase callback
1 parent a92e8b1 commit 8a17657

File tree

2 files changed

+14
-11
lines changed

2 files changed

+14
-11
lines changed

src/wallet/rpc/encrypt.cpp

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
44

55
#include <rpc/util.h>
6+
#include <scheduler.h>
7+
#include <wallet/context.h>
68
#include <wallet/rpc/util.h>
79
#include <wallet/wallet.h>
810

@@ -88,24 +90,24 @@ RPCHelpMan walletpassphrase()
8890
relock_time = pwallet->nRelockTime;
8991
}
9092

91-
// rpcRunLater must be called without cs_wallet held otherwise a deadlock
92-
// can occur. The deadlock would happen when RPCRunLater removes the
93-
// previous timer (and waits for the callback to finish if already running)
94-
// and the callback locks cs_wallet.
95-
AssertLockNotHeld(wallet->cs_wallet);
93+
// Get wallet scheduler to queue up the relock callback in the future.
94+
// Scheduled events don't get destructed until they are executed,
95+
// and they are executed in series in a single scheduler thread so
96+
// no cs_wallet lock is needed.
97+
WalletContext& context = EnsureWalletContext(request.context);
9698
// Keep a weak pointer to the wallet so that it is possible to unload the
9799
// wallet before the following callback is called. If a valid shared pointer
98100
// is acquired in the callback then the wallet is still loaded.
99101
std::weak_ptr<CWallet> weak_wallet = wallet;
100-
pwallet->chain().rpcRunLater(strprintf("lockwallet(%s)", pwallet->GetName()), [weak_wallet, relock_time] {
102+
context.scheduler->scheduleFromNow([weak_wallet, relock_time] {
101103
if (auto shared_wallet = weak_wallet.lock()) {
102104
LOCK2(shared_wallet->m_relock_mutex, shared_wallet->cs_wallet);
103-
// Skip if this is not the most recent rpcRunLater callback.
105+
// Skip if this is not the most recent relock callback.
104106
if (shared_wallet->nRelockTime != relock_time) return;
105107
shared_wallet->Lock();
106108
shared_wallet->nRelockTime = 0;
107109
}
108-
}, nSleepTime);
110+
}, std::chrono::seconds(nSleepTime));
109111

110112
return UniValue::VNULL;
111113
},

test/functional/wallet_keypool.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
55
"""Test the wallet keypool and interaction with wallet encryption/locking."""
66

7-
import time
87
from decimal import Decimal
98

109
from test_framework.test_framework import BitcoinTestFramework
@@ -127,8 +126,10 @@ def run_test(self):
127126
nodes[0].keypoolrefill(3)
128127

129128
# test walletpassphrase timeout
130-
time.sleep(1.1)
131-
assert_equal(nodes[0].getwalletinfo()["unlocked_until"], 0)
129+
# CScheduler relies on condition_variable::wait_until() which does not
130+
# guarantee accurate timing. We'll wait up to 5 seconds to execute a 1
131+
# second scheduled event.
132+
nodes[0].wait_until(lambda: nodes[0].getwalletinfo()["unlocked_until"] == 0, timeout=5)
132133

133134
# drain the keypool
134135
for _ in range(3):

0 commit comments

Comments
 (0)