diff --git a/src/interfaces/chain.h b/src/interfaces/chain.h --- a/src/interfaces/chain.h +++ b/src/interfaces/chain.h @@ -1,4 +1,4 @@ -// Copyright (c) 2018 The Bitcoin Core developers +// Copyright (c) 2018-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -189,8 +189,8 @@ //! economical to spend. virtual CFeeRate relayDustFee() = 0; - //! Check if pruning is enabled. - virtual bool getPruneMode() = 0; + //! Check if any block has been pruned. + virtual bool havePruned() = 0; //! Check if p2p enabled. virtual bool p2pEnabled() = 0; diff --git a/src/interfaces/chain.cpp b/src/interfaces/chain.cpp --- a/src/interfaces/chain.cpp +++ b/src/interfaces/chain.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2018 The Bitcoin Core developers +// Copyright (c) 2018-2019 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -340,7 +340,10 @@ } CFeeRate relayMinFee() override { return ::minRelayTxFee; } CFeeRate relayDustFee() override { return ::dustRelayFee; } - bool getPruneMode() override { return ::fPruneMode; } + bool havePruned() override { + LOCK(cs_main); + return ::fHavePruned; + } bool p2pEnabled() override { return m_node.connman != nullptr; } bool isReadyToBroadcast() override { return !::fImporting && !::fReindex && !isInitialBlockDownload(); diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -160,9 +160,12 @@ fRescan = request.params[2].get_bool(); } - if (fRescan && pwallet->chain().getPruneMode()) { + if (fRescan && pwallet->chain().havePruned()) { + // Exit early and print an error. + // If a block is pruned after this check, we will import the key(s), + // but fail the rescan with a generic error. throw JSONRPCError(RPC_WALLET_ERROR, - "Rescan is disabled in pruned mode"); + "Rescan is disabled when blocks are pruned"); } if (fRescan && !reserver.reserve()) { @@ -291,9 +294,12 @@ fRescan = request.params[2].get_bool(); } - if (fRescan && pwallet->chain().getPruneMode()) { + if (fRescan && pwallet->chain().havePruned()) { + // Exit early and print an error. + // If a block is pruned after this check, we will import the key(s), + // but fail the rescan with a generic error. throw JSONRPCError(RPC_WALLET_ERROR, - "Rescan is disabled in pruned mode"); + "Rescan is disabled when blocks are pruned"); } WalletRescanReserver reserver(pwallet); @@ -538,9 +544,12 @@ fRescan = request.params[2].get_bool(); } - if (fRescan && pwallet->chain().getPruneMode()) { + if (fRescan && pwallet->chain().havePruned()) { + // Exit early and print an error. + // If a block is pruned after this check, we will import the key(s), + // but fail the rescan with a generic error. throw JSONRPCError(RPC_WALLET_ERROR, - "Rescan is disabled in pruned mode"); + "Rescan is disabled when blocks are pruned"); } WalletRescanReserver reserver(pwallet); @@ -617,9 +626,13 @@ } .Check(request); - if (pwallet->chain().getPruneMode()) { - throw JSONRPCError(RPC_WALLET_ERROR, - "Importing wallets is disabled in pruned mode"); + if (pwallet->chain().havePruned()) { + // Exit early and print an error. + // If a block is pruned after this check, we will import the key(s), + // but fail the rescan with a generic error. + throw JSONRPCError( + RPC_WALLET_ERROR, + "Importing wallets is disabled when blocks are pruned"); } WalletRescanReserver reserver(pwallet); diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -5009,9 +5009,12 @@ if (tip_height && *tip_height != rescan_height) { // We can't rescan beyond non-pruned blocks, stop and throw an error. // This might happen if a user uses an old wallet within a pruned node - // or if he ran -disablewallet for a longer time, then decided to - // re-enable. - if (chain.getPruneMode()) { + // or if they ran -disablewallet for a longer time, then decided to + // re-enable + if (chain.havePruned()) { + // Exit early and print an error. + // If a block is pruned after this check, we will load the wallet, + // but fail the rescan with a generic error. int block_height = *tip_height; while (block_height > 0 && locked_chain->haveBlockOnDisk(block_height - 1) && diff --git a/test/functional/wallet_import_rescan.py b/test/functional/wallet_import_rescan.py --- a/test/functional/wallet_import_rescan.py +++ b/test/functional/wallet_import_rescan.py @@ -26,7 +26,6 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, - assert_raises_rpc_error, connect_nodes, set_node_times, ) @@ -41,36 +40,20 @@ """Helper for importing one key and verifying scanned transactions.""" - def try_rpc(self, func, *args, **kwargs): - if self.expect_disabled: - assert_raises_rpc_error(-4, "Rescan is disabled in pruned mode", - func, *args, **kwargs) - else: - return func(*args, **kwargs) - def do_import(self, timestamp): """Call one key import RPC.""" rescan = self.rescan == Rescan.yes if self.call == Call.single: if self.data == Data.address: - response = self.try_rpc( - self.node.importaddress, - address=self.address["address"], - label=self.label, - rescan=rescan) + response = self.node.importaddress( + address=self.address["address"], label=self.label, rescan=rescan) elif self.data == Data.pub: - response = self.try_rpc( - self.node.importpubkey, - pubkey=self.address["pubkey"], - label=self.label, - rescan=rescan) + response = self.node.importpubkey( + pubkey=self.address["pubkey"], label=self.label, rescan=rescan) elif self.data == Data.priv: - response = self.try_rpc( - self.node.importprivkey, - privkey=self.key, - label=self.label, - rescan=rescan) + response = self.node.importprivkey( + privkey=self.key, label=self.label, rescan=rescan) assert_equal(response, None) elif self.call in (Call.multiaddress, Call.multiscript): @@ -196,10 +179,9 @@ # check the results from getbalance and listtransactions. for variant in IMPORT_VARIANTS: self.log.info('Run import for variant {}'.format(variant)) - variant.expect_disabled = variant.rescan == Rescan.yes and variant.prune and variant.call == Call.single - expect_rescan = variant.rescan == Rescan.yes and not variant.expect_disabled - variant.node = self.nodes[ - 2 + IMPORT_NODES.index(ImportNode(variant.prune, expect_rescan))] + expect_rescan = variant.rescan == Rescan.yes + variant.node = self.nodes[2 + IMPORT_NODES.index( + ImportNode(variant.prune, expect_rescan))] variant.do_import(timestamp) if expect_rescan: variant.expected_balance = variant.initial_amount @@ -224,12 +206,9 @@ # Check the latest results from getbalance and listtransactions. for variant in IMPORT_VARIANTS: self.log.info('Run check for variant {}'.format(variant)) - if not variant.expect_disabled: - variant.expected_balance += variant.sent_amount - variant.expected_txs += 1 - variant.check(variant.sent_txid, variant.sent_amount, 1) - else: - variant.check() + variant.expected_balance += variant.sent_amount + variant.expected_txs += 1 + variant.check(variant.sent_txid, variant.sent_amount, 1) if __name__ == "__main__":