@@ -1918,44 +1918,52 @@ static UniValue walletpassphrase(const JSONRPCRequest& request)
1918
1918
},
1919
1919
}.Check (request);
1920
1920
1921
- auto locked_chain = pwallet->chain ().lock ();
1922
- LOCK (pwallet->cs_wallet );
1923
-
1924
- if (!pwallet->IsCrypted ()) {
1925
- throw JSONRPCError (RPC_WALLET_WRONG_ENC_STATE, " Error: running with an unencrypted wallet, but walletpassphrase was called." );
1926
- }
1921
+ int64_t nSleepTime;
1922
+ {
1923
+ auto locked_chain = pwallet->chain ().lock ();
1924
+ LOCK (pwallet->cs_wallet );
1927
1925
1928
- // Note that the walletpassphrase is stored in request.params[0] which is not mlock()ed
1929
- SecureString strWalletPass;
1930
- strWalletPass.reserve (100 );
1931
- // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1932
- // Alternately, find a way to make request.params[0] mlock()'d to begin with.
1933
- strWalletPass = request.params [0 ].get_str ().c_str ();
1926
+ if (!pwallet->IsCrypted ()) {
1927
+ throw JSONRPCError (RPC_WALLET_WRONG_ENC_STATE, " Error: running with an unencrypted wallet, but walletpassphrase was called." );
1928
+ }
1934
1929
1935
- // Get the timeout
1936
- int64_t nSleepTime = request.params [1 ].get_int64 ();
1937
- // Timeout cannot be negative, otherwise it will relock immediately
1938
- if (nSleepTime < 0 ) {
1939
- throw JSONRPCError (RPC_INVALID_PARAMETER, " Timeout cannot be negative." );
1940
- }
1941
- // Clamp timeout
1942
- constexpr int64_t MAX_SLEEP_TIME = 100000000 ; // larger values trigger a macos/libevent bug?
1943
- if (nSleepTime > MAX_SLEEP_TIME) {
1944
- nSleepTime = MAX_SLEEP_TIME;
1945
- }
1930
+ // Note that the walletpassphrase is stored in request.params[0] which is not mlock()ed
1931
+ SecureString strWalletPass;
1932
+ strWalletPass.reserve (100 );
1933
+ // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1934
+ // Alternately, find a way to make request.params[0] mlock()'d to begin with.
1935
+ strWalletPass = request.params [0 ].get_str ().c_str ();
1936
+
1937
+ // Get the timeout
1938
+ nSleepTime = request.params [1 ].get_int64 ();
1939
+ // Timeout cannot be negative, otherwise it will relock immediately
1940
+ if (nSleepTime < 0 ) {
1941
+ throw JSONRPCError (RPC_INVALID_PARAMETER, " Timeout cannot be negative." );
1942
+ }
1943
+ // Clamp timeout
1944
+ constexpr int64_t MAX_SLEEP_TIME = 100000000 ; // larger values trigger a macos/libevent bug?
1945
+ if (nSleepTime > MAX_SLEEP_TIME) {
1946
+ nSleepTime = MAX_SLEEP_TIME;
1947
+ }
1946
1948
1947
- if (strWalletPass.empty ()) {
1948
- throw JSONRPCError (RPC_INVALID_PARAMETER, " passphrase can not be empty" );
1949
- }
1949
+ if (strWalletPass.empty ()) {
1950
+ throw JSONRPCError (RPC_INVALID_PARAMETER, " passphrase can not be empty" );
1951
+ }
1950
1952
1951
- if (!pwallet->Unlock (strWalletPass)) {
1952
- throw JSONRPCError (RPC_WALLET_PASSPHRASE_INCORRECT, " Error: The wallet passphrase entered was incorrect." );
1953
- }
1953
+ if (!pwallet->Unlock (strWalletPass)) {
1954
+ throw JSONRPCError (RPC_WALLET_PASSPHRASE_INCORRECT, " Error: The wallet passphrase entered was incorrect." );
1955
+ }
1954
1956
1955
- pwallet->TopUpKeyPool ();
1957
+ pwallet->TopUpKeyPool ();
1956
1958
1957
- pwallet->nRelockTime = GetTime () + nSleepTime;
1959
+ pwallet->nRelockTime = GetTime () + nSleepTime;
1960
+ }
1958
1961
1962
+ // rpcRunLater must be called without cs_wallet held otherwise a deadlock
1963
+ // can occur. The deadlock would happen when RPCRunLater removes the
1964
+ // previous timer (and waits for the callback to finish if already running)
1965
+ // and the callback locks cs_wallet.
1966
+ AssertLockNotHeld (wallet->cs_wallet );
1959
1967
// Keep a weak pointer to the wallet so that it is possible to unload the
1960
1968
// wallet before the following callback is called. If a valid shared pointer
1961
1969
// is acquired in the callback then the wallet is still loaded.
0 commit comments