mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-01-25 10:43:19 -03:00
wallet: keep track of when the passphrase is needed when rescanning
Wallet passphrases are needed to top up the keypool during a rescan. The following RPCs need the passphrase when rescanning: - `importdescriptors` - `rescanblockchain` The following RPCs use the information about whether or not the passphrase is being used to ensure that full rescans are able to take place: - `walletlock` - `encryptwallet` - `walletpassphrasechange`
This commit is contained in:
parent
576e16e702
commit
66a86ebabb
4 changed files with 21 additions and 3 deletions
|
@ -1651,7 +1651,7 @@ RPCHelpMan importdescriptors()
|
|||
}
|
||||
|
||||
WalletRescanReserver reserver(*pwallet);
|
||||
if (!reserver.reserve()) {
|
||||
if (!reserver.reserve(/*with_passphrase=*/true)) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Wallet is currently rescanning. Abort existing rescan or wait.");
|
||||
}
|
||||
|
||||
|
|
|
@ -128,6 +128,10 @@ RPCHelpMan walletpassphrasechange()
|
|||
throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
|
||||
}
|
||||
|
||||
if (pwallet->IsScanningWithPassphrase()) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Error: the wallet is currently being used to rescan the blockchain for related transactions. Please call `abortrescan` before changing the passphrase.");
|
||||
}
|
||||
|
||||
// TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
|
||||
// Alternately, find a way to make request.params[0] mlock()'d to begin with.
|
||||
SecureString strOldWalletPass;
|
||||
|
@ -181,6 +185,10 @@ RPCHelpMan walletlock()
|
|||
throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletlock was called.");
|
||||
}
|
||||
|
||||
if (pwallet->IsScanningWithPassphrase()) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Error: the wallet is currently being used to rescan the blockchain for related transactions. Please call `abortrescan` before locking the wallet.");
|
||||
}
|
||||
|
||||
pwallet->Lock();
|
||||
pwallet->nRelockTime = 0;
|
||||
|
||||
|
@ -229,6 +237,10 @@ RPCHelpMan encryptwallet()
|
|||
throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an encrypted wallet, but encryptwallet was called.");
|
||||
}
|
||||
|
||||
if (pwallet->IsScanningWithPassphrase()) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Error: the wallet is currently being used to rescan the blockchain for related transactions. Please call `abortrescan` before encrypting the wallet.");
|
||||
}
|
||||
|
||||
// TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
|
||||
// Alternately, find a way to make request.params[0] mlock()'d to begin with.
|
||||
SecureString strWalletPass;
|
||||
|
|
|
@ -872,15 +872,17 @@ RPCHelpMan rescanblockchain()
|
|||
wallet.BlockUntilSyncedToCurrentChain();
|
||||
|
||||
WalletRescanReserver reserver(*pwallet);
|
||||
if (!reserver.reserve()) {
|
||||
if (!reserver.reserve(/*with_passphrase=*/true)) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Wallet is currently rescanning. Abort existing rescan or wait.");
|
||||
}
|
||||
|
||||
int start_height = 0;
|
||||
std::optional<int> stop_height;
|
||||
uint256 start_block;
|
||||
|
||||
{
|
||||
LOCK(pwallet->cs_wallet);
|
||||
EnsureWalletIsUnlocked(*pwallet);
|
||||
int tip_height = pwallet->GetLastBlockHeight();
|
||||
|
||||
if (!request.params[0].isNull()) {
|
||||
|
|
|
@ -243,6 +243,7 @@ private:
|
|||
std::atomic<bool> fAbortRescan{false};
|
||||
std::atomic<bool> fScanningWallet{false}; // controlled by WalletRescanReserver
|
||||
std::atomic<bool> m_attaching_chain{false};
|
||||
std::atomic<bool> m_scanning_with_passphrase{false};
|
||||
std::atomic<int64_t> m_scanning_start{0};
|
||||
std::atomic<double> m_scanning_progress{0};
|
||||
friend class WalletRescanReserver;
|
||||
|
@ -467,6 +468,7 @@ public:
|
|||
void AbortRescan() { fAbortRescan = true; }
|
||||
bool IsAbortingRescan() const { return fAbortRescan; }
|
||||
bool IsScanning() const { return fScanningWallet; }
|
||||
bool IsScanningWithPassphrase() const { return m_scanning_with_passphrase; }
|
||||
int64_t ScanningDuration() const { return fScanningWallet ? GetTimeMillis() - m_scanning_start : 0; }
|
||||
double ScanningProgress() const { return fScanningWallet ? (double) m_scanning_progress : 0; }
|
||||
|
||||
|
@ -960,12 +962,13 @@ private:
|
|||
public:
|
||||
explicit WalletRescanReserver(CWallet& w) : m_wallet(w) {}
|
||||
|
||||
bool reserve()
|
||||
bool reserve(bool with_passphrase = false)
|
||||
{
|
||||
assert(!m_could_reserve);
|
||||
if (m_wallet.fScanningWallet.exchange(true)) {
|
||||
return false;
|
||||
}
|
||||
m_wallet.m_scanning_with_passphrase.exchange(with_passphrase);
|
||||
m_wallet.m_scanning_start = GetTimeMillis();
|
||||
m_wallet.m_scanning_progress = 0;
|
||||
m_could_reserve = true;
|
||||
|
@ -985,6 +988,7 @@ public:
|
|||
{
|
||||
if (m_could_reserve) {
|
||||
m_wallet.fScanningWallet = false;
|
||||
m_wallet.m_scanning_with_passphrase = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
Loading…
Add table
Reference in a new issue