Skip to content

Commit faf3729

Browse files
author
MarcoFalke
committed
wallet: Only fail rescan when blocks have actually been pruned
1 parent 3356799 commit faf3729

File tree

5 files changed

+42
-34
lines changed

5 files changed

+42
-34
lines changed

src/interfaces/chain.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) 2018 The Bitcoin Core developers
1+
// Copyright (c) 2018-2019 The Bitcoin Core developers
22
// Distributed under the MIT software license, see the accompanying
33
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
44

@@ -325,7 +325,11 @@ class ChainImpl : public Chain
325325
CFeeRate relayMinFee() override { return ::minRelayTxFee; }
326326
CFeeRate relayIncrementalFee() override { return ::incrementalRelayFee; }
327327
CFeeRate relayDustFee() override { return ::dustRelayFee; }
328-
bool getPruneMode() override { return ::fPruneMode; }
328+
bool havePruned() override
329+
{
330+
LOCK(cs_main);
331+
return ::fHavePruned;
332+
}
329333
bool p2pEnabled() override { return g_connman != nullptr; }
330334
bool isReadyToBroadcast() override { return !::fImporting && !::fReindex && !IsInitialBlockDownload(); }
331335
bool isInitialBlockDownload() override { return IsInitialBlockDownload(); }

src/interfaces/chain.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) 2018 The Bitcoin Core developers
1+
// Copyright (c) 2018-2019 The Bitcoin Core developers
22
// Distributed under the MIT software license, see the accompanying
33
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
44

@@ -207,8 +207,8 @@ class Chain
207207
//! Relay dust fee setting (-dustrelayfee), reflecting lowest rate it's economical to spend.
208208
virtual CFeeRate relayDustFee() = 0;
209209

210-
//! Check if pruning is enabled.
211-
virtual bool getPruneMode() = 0;
210+
//! Check if any block has been pruned.
211+
virtual bool havePruned() = 0;
212212

213213
//! Check if p2p enabled.
214214
virtual bool p2pEnabled() = 0;

src/wallet/rpcdump.cpp

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -157,8 +157,11 @@ UniValue importprivkey(const JSONRPCRequest& request)
157157
if (!request.params[2].isNull())
158158
fRescan = request.params[2].get_bool();
159159

160-
if (fRescan && pwallet->chain().getPruneMode()) {
161-
throw JSONRPCError(RPC_WALLET_ERROR, "Rescan is disabled in pruned mode");
160+
if (fRescan && pwallet->chain().havePruned()) {
161+
// Exit early and print an error.
162+
// If a block is pruned after this check, we will import the key(s),
163+
// but fail the rescan with a generic error.
164+
throw JSONRPCError(RPC_WALLET_ERROR, "Rescan is disabled when blocks are pruned");
162165
}
163166

164167
if (fRescan && !reserver.reserve()) {
@@ -314,8 +317,11 @@ UniValue importaddress(const JSONRPCRequest& request)
314317
if (!request.params[2].isNull())
315318
fRescan = request.params[2].get_bool();
316319

317-
if (fRescan && pwallet->chain().getPruneMode()) {
318-
throw JSONRPCError(RPC_WALLET_ERROR, "Rescan is disabled in pruned mode");
320+
if (fRescan && pwallet->chain().havePruned()) {
321+
// Exit early and print an error.
322+
// If a block is pruned after this check, we will import the key(s),
323+
// but fail the rescan with a generic error.
324+
throw JSONRPCError(RPC_WALLET_ERROR, "Rescan is disabled when blocks are pruned");
319325
}
320326

321327
WalletRescanReserver reserver(pwallet);
@@ -507,8 +513,11 @@ UniValue importpubkey(const JSONRPCRequest& request)
507513
if (!request.params[2].isNull())
508514
fRescan = request.params[2].get_bool();
509515

510-
if (fRescan && pwallet->chain().getPruneMode()) {
511-
throw JSONRPCError(RPC_WALLET_ERROR, "Rescan is disabled in pruned mode");
516+
if (fRescan && pwallet->chain().havePruned()) {
517+
// Exit early and print an error.
518+
// If a block is pruned after this check, we will import the key(s),
519+
// but fail the rescan with a generic error.
520+
throw JSONRPCError(RPC_WALLET_ERROR, "Rescan is disabled when blocks are pruned");
512521
}
513522

514523
WalletRescanReserver reserver(pwallet);
@@ -573,7 +582,10 @@ UniValue importwallet(const JSONRPCRequest& request)
573582
},
574583
}.ToString());
575584

576-
if (pwallet->chain().getPruneMode()) {
585+
if (pwallet->chain().havePruned()) {
586+
// Exit early and print an error.
587+
// If a block is pruned after this check, we will import the key(s),
588+
// but fail the rescan with a generic error.
577589
throw JSONRPCError(RPC_WALLET_ERROR, "Importing wallets is disabled in pruned mode");
578590
}
579591

src/wallet/wallet.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4219,10 +4219,13 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
42194219

42204220
if (tip_height && *tip_height != rescan_height)
42214221
{
4222-
//We can't rescan beyond non-pruned blocks, stop and throw an error
4223-
//this might happen if a user uses an old wallet within a pruned node
4224-
// or if he ran -disablewallet for a longer time, then decided to re-enable
4225-
if (chain.getPruneMode()) {
4222+
// We can't rescan beyond non-pruned blocks, stop and throw an error.
4223+
// This might happen if a user uses an old wallet within a pruned node
4224+
// or if they ran -disablewallet for a longer time, then decided to re-enable
4225+
if (chain.havePruned()) {
4226+
// Exit early and print an error.
4227+
// If a block is pruned after this check, we will load the wallet,
4228+
// but fail the rescan with a generic error.
42264229
int block_height = *tip_height;
42274230
while (block_height > 0 && locked_chain->haveBlockOnDisk(block_height - 1) && rescan_height != block_height) {
42284231
--block_height;

test/functional/wallet_import_rescan.py

Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121

2222
from test_framework.test_framework import BitcoinTestFramework
2323
from test_framework.util import (
24-
assert_raises_rpc_error,
2524
connect_nodes,
2625
assert_equal,
2726
set_node_times,
@@ -39,23 +38,17 @@
3938
class Variant(collections.namedtuple("Variant", "call data rescan prune")):
4039
"""Helper for importing one key and verifying scanned transactions."""
4140

42-
def try_rpc(self, func, *args, **kwargs):
43-
if self.expect_disabled:
44-
assert_raises_rpc_error(-4, "Rescan is disabled in pruned mode", func, *args, **kwargs)
45-
else:
46-
return func(*args, **kwargs)
47-
4841
def do_import(self, timestamp):
4942
"""Call one key import RPC."""
5043
rescan = self.rescan == Rescan.yes
5144

5245
if self.call == Call.single:
5346
if self.data == Data.address:
54-
response = self.try_rpc(self.node.importaddress, address=self.address["address"], label=self.label, rescan=rescan)
47+
response = self.node.importaddress(address=self.address["address"], label=self.label, rescan=rescan)
5548
elif self.data == Data.pub:
56-
response = self.try_rpc(self.node.importpubkey, pubkey=self.address["pubkey"], label=self.label, rescan=rescan)
49+
response = self.node.importpubkey(pubkey=self.address["pubkey"], label=self.label, rescan=rescan)
5750
elif self.data == Data.priv:
58-
response = self.try_rpc(self.node.importprivkey, privkey=self.key, label=self.label, rescan=rescan)
51+
response = self.node.importprivkey(privkey=self.key, label=self.label, rescan=rescan)
5952
assert_equal(response, None)
6053

6154
elif self.call in (Call.multiaddress, Call.multiscript):
@@ -172,8 +165,7 @@ def run_test(self):
172165
# check the results from getbalance and listtransactions.
173166
for variant in IMPORT_VARIANTS:
174167
self.log.info('Run import for variant {}'.format(variant))
175-
variant.expect_disabled = variant.rescan == Rescan.yes and variant.prune and variant.call == Call.single
176-
expect_rescan = variant.rescan == Rescan.yes and not variant.expect_disabled
168+
expect_rescan = variant.rescan == Rescan.yes
177169
variant.node = self.nodes[2 + IMPORT_NODES.index(ImportNode(variant.prune, expect_rescan))]
178170
variant.do_import(timestamp)
179171
if expect_rescan:
@@ -198,12 +190,9 @@ def run_test(self):
198190
# Check the latest results from getbalance and listtransactions.
199191
for variant in IMPORT_VARIANTS:
200192
self.log.info('Run check for variant {}'.format(variant))
201-
if not variant.expect_disabled:
202-
variant.expected_balance += variant.sent_amount
203-
variant.expected_txs += 1
204-
variant.check(variant.sent_txid, variant.sent_amount, 1)
205-
else:
206-
variant.check()
193+
variant.expected_balance += variant.sent_amount
194+
variant.expected_txs += 1
195+
variant.check(variant.sent_txid, variant.sent_amount, 1)
207196

208197
if __name__ == "__main__":
209198
ImportRescanTest().main()

0 commit comments

Comments
 (0)