diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -28,7 +28,9 @@ /* Timer-creating functions */ static RPCTimerInterface *timerInterface = nullptr; /* Map of name to timer. */ -static std::map> deadlineTimers; +static Mutex g_deadline_timers_mutex; +static std::map> + deadlineTimers GUARDED_BY(g_deadline_timers_mutex); static bool ExecuteCommand(Config &config, const CRPCCommand &command, const JSONRPCRequest &request, UniValue &result, bool last_handler); @@ -346,7 +348,7 @@ void StopRPC() { LogPrint(BCLog::RPC, "Stopping RPC\n"); - deadlineTimers.clear(); + WITH_LOCK(g_deadline_timers_mutex, deadlineTimers.clear()); DeleteAuthCookie(); g_rpcSignals.Stopped(); } @@ -543,6 +545,7 @@ throw JSONRPCError(RPC_INTERNAL_ERROR, "No timer handler registered for RPC"); } + LOCK(g_deadline_timers_mutex); deadlineTimers.erase(name); LogPrint(BCLog::RPC, "queue run of timer %s in %i seconds (using %s)\n", name, nSeconds, timerInterface->Name()); diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -2328,6 +2328,9 @@ .Check(request); int64_t nSleepTime; + int64_t relock_time; + // Prevent concurrent calls to walletpassphrase with the same wallet. + LOCK(pwallet->m_unlock_mutex); { LOCK(pwallet->cs_wallet); @@ -2375,6 +2378,7 @@ pwallet->TopUpKeyPool(); pwallet->nRelockTime = GetTime() + nSleepTime; + relock_time = pwallet->nRelockTime; } // rpcRunLater must be called without cs_wallet held otherwise a deadlock @@ -2388,9 +2392,13 @@ std::weak_ptr weak_wallet = wallet; pwallet->chain().rpcRunLater( strprintf("lockwallet(%s)", pwallet->GetName()), - [weak_wallet] { + [weak_wallet, relock_time] { if (auto shared_wallet = weak_wallet.lock()) { LOCK(shared_wallet->cs_wallet); + // Skip if this is not the most recent rpcRunLater callback. + if (shared_wallet->nRelockTime != relock_time) { + return; + } shared_wallet->Lock(); shared_wallet->nRelockTime = 0; } diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -1022,8 +1022,10 @@ //! Holds a timestamp at which point the wallet is scheduled (externally) to //! be relocked. Caller must arrange for actual relocking to occur via //! Lock(). - int64_t nRelockTime = 0; + int64_t nRelockTime GUARDED_BY(cs_wallet){0}; + // Used to prevent concurrent calls to walletpassphrase RPC. + Mutex m_unlock_mutex; bool Unlock(const SecureString &strWalletPassphrase, bool accept_no_keys = false); bool ChangeWalletPassphrase(const SecureString &strOldWalletPassphrase,