Skip to content

Commit 4d05672

Browse files
jonasschnellirandom-zebra
authored andcommitted
Add RAII wallet rescan reserver
1 parent c3fc22d commit 4d05672

File tree

3 files changed

+59
-4
lines changed

3 files changed

+59
-4
lines changed

src/wallet/rpcdump.cpp

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,12 @@ UniValue importaddress(const JSONRPCRequest& request)
221221
const std::string strLabel = (request.params.size() > 1 ? request.params[1].get_str() : "");
222222
// Whether to perform rescan after import
223223
const bool fRescan = (request.params.size() > 2 ? request.params[2].get_bool() : true);
224+
225+
WalletRescanReserver reserver(pwalletMain);
226+
if (fRescan && !reserver.reserve()) {
227+
throw JSONRPCError(RPC_WALLET_ERROR, "Wallet is currently rescanning. Abort existing rescan or wait.");
228+
}
229+
224230
// Whether to import a p2sh version, too
225231
const bool fP2SH = (request.params.size() > 3 ? request.params[3].get_bool() : false);
226232

@@ -276,6 +282,11 @@ UniValue importpubkey(const JSONRPCRequest& request)
276282
// Whether to perform rescan after import
277283
const bool fRescan = (request.params.size() > 2 ? request.params[2].get_bool() : true);
278284

285+
WalletRescanReserver reserver(pwalletMain);
286+
if (fRescan && !reserver.reserve()) {
287+
throw JSONRPCError(RPC_WALLET_ERROR, "Wallet is currently rescanning. Abort existing rescan or wait.");
288+
}
289+
279290
if (!IsHex(request.params[0].get_str()))
280291
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Pubkey must be a hex string");
281292
std::vector<unsigned char> data(ParseHex(request.params[0].get_str()));
@@ -317,19 +328,23 @@ UniValue importwallet(const JSONRPCRequest& request)
317328
"\nImport using the json rpc call\n" +
318329
HelpExampleRpc("importwallet", "\"test\""));
319330

320-
321331
std::ifstream file;
322332
file.open(request.params[0].get_str().c_str(), std::ios::in | std::ios::ate);
323333
if (!file.is_open())
324334
throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file");
325335

326-
int64_t nTimeBegin = chainActive.Tip()->GetBlockTime();
336+
WalletRescanReserver reserver(pwalletMain);
337+
if (!reserver.reserve()) {
338+
throw JSONRPCError(RPC_WALLET_ERROR, "Wallet is currently rescanning. Abort existing rescan or wait.");
339+
}
327340

341+
int64_t nTimeBegin = 0;
328342
bool fGood = true;
329343
{
330344
LOCK2(cs_main, pwalletMain->cs_wallet);
331345
EnsureWalletIsUnlocked();
332346

347+
nTimeBegin = chainActive.Tip()->GetBlockTime();
333348
int64_t nFilesize = std::max((int64_t)1, (int64_t)file.tellg());
334349
file.seekg(0, file.beg);
335350

@@ -973,6 +988,11 @@ UniValue importmulti(const JSONRPCRequest& mainRequest)
973988
}
974989
}
975990

991+
WalletRescanReserver reserver(pwalletMain);
992+
if (fRescan && !reserver.reserve()) {
993+
throw JSONRPCError(RPC_WALLET_ERROR, "Wallet is currently rescanning. Abort existing rescan or wait.");
994+
}
995+
976996
int64_t now = 0;
977997
bool fRunScan = false;
978998
int64_t nLowestTimestamp = 0;

src/wallet/rpcwallet.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4207,7 +4207,8 @@ UniValue rescanblockchain(const JSONRPCRequest& request)
42074207
}
42084208

42094209
EnsureWallet();
4210-
if (pwalletMain->IsScanning()) {
4210+
WalletRescanReserver reserver(pwalletMain);
4211+
if (!reserver.reserve()) {
42114212
throw JSONRPCError(RPC_WALLET_ERROR, "Wallet is currently rescanning. Abort existing rescan or wait.");
42124213
}
42134214

src/wallet/wallet.h

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@
4444
#include <utility>
4545
#include <vector>
4646

47-
extern CWallet* pwalletMain;
47+
typedef CWallet* CWalletRef;
48+
extern CWalletRef pwalletMain;
4849

4950
/**
5051
* Settings
@@ -564,6 +565,9 @@ class CWallet : public CCryptoKeyStore, public CValidationInterface
564565
static std::atomic<bool> fFlushScheduled;
565566
std::atomic<bool> fAbortRescan;
566567
std::atomic<bool> fScanningWallet;
568+
std::mutex mutexScanning;
569+
friend class WalletRescanReserver;
570+
567571

568572
//! keeps track of whether Unlock has run a thorough check before
569573
bool fDecryptionThoroughlyChecked{false};
@@ -1229,4 +1233,34 @@ class CStakeableOutput : public COutput
12291233

12301234
};
12311235

1236+
/** RAII object to check and reserve a wallet rescan */
1237+
class WalletRescanReserver
1238+
{
1239+
private:
1240+
CWalletRef m_wallet;
1241+
bool m_could_reserve;
1242+
public:
1243+
explicit WalletRescanReserver(CWalletRef w) : m_wallet(w), m_could_reserve(false) {}
1244+
1245+
bool reserve()
1246+
{
1247+
assert(!m_could_reserve);
1248+
std::lock_guard<std::mutex> lock(m_wallet->mutexScanning);
1249+
if (m_wallet->fScanningWallet) {
1250+
return false;
1251+
}
1252+
m_wallet->fScanningWallet = true;
1253+
m_could_reserve = true;
1254+
return true;
1255+
}
1256+
1257+
~WalletRescanReserver()
1258+
{
1259+
std::lock_guard<std::mutex> lock(m_wallet->mutexScanning);
1260+
if (m_could_reserve) {
1261+
m_wallet->fScanningWallet = false;
1262+
}
1263+
}
1264+
};
1265+
12321266
#endif // BITCOIN_WALLET_H

0 commit comments

Comments
 (0)