wallet: Only fail rescan when blocks have actually been pruned
This commit is contained in:
parent
3356799ee3
commit
faf3729242
5 changed files with 42 additions and 34 deletions
|
@ -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.
|
||||
|
||||
|
@ -325,7 +325,11 @@ public:
|
|||
CFeeRate relayMinFee() override { return ::minRelayTxFee; }
|
||||
CFeeRate relayIncrementalFee() override { return ::incrementalRelayFee; }
|
||||
CFeeRate relayDustFee() override { return ::dustRelayFee; }
|
||||
bool getPruneMode() override { return ::fPruneMode; }
|
||||
bool havePruned() override
|
||||
{
|
||||
LOCK(cs_main);
|
||||
return ::fHavePruned;
|
||||
}
|
||||
bool p2pEnabled() override { return g_connman != nullptr; }
|
||||
bool isReadyToBroadcast() override { return !::fImporting && !::fReindex && !IsInitialBlockDownload(); }
|
||||
bool isInitialBlockDownload() override { return IsInitialBlockDownload(); }
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
@ -207,8 +207,8 @@ public:
|
|||
//! Relay dust fee setting (-dustrelayfee), reflecting lowest rate it's 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;
|
||||
|
|
|
@ -157,8 +157,11 @@ UniValue importprivkey(const JSONRPCRequest& request)
|
|||
if (!request.params[2].isNull())
|
||||
fRescan = request.params[2].get_bool();
|
||||
|
||||
if (fRescan && pwallet->chain().getPruneMode()) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Rescan is disabled in pruned mode");
|
||||
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 when blocks are pruned");
|
||||
}
|
||||
|
||||
if (fRescan && !reserver.reserve()) {
|
||||
|
@ -314,8 +317,11 @@ UniValue importaddress(const JSONRPCRequest& request)
|
|||
if (!request.params[2].isNull())
|
||||
fRescan = request.params[2].get_bool();
|
||||
|
||||
if (fRescan && pwallet->chain().getPruneMode()) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Rescan is disabled in pruned mode");
|
||||
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 when blocks are pruned");
|
||||
}
|
||||
|
||||
WalletRescanReserver reserver(pwallet);
|
||||
|
@ -507,8 +513,11 @@ UniValue importpubkey(const JSONRPCRequest& request)
|
|||
if (!request.params[2].isNull())
|
||||
fRescan = request.params[2].get_bool();
|
||||
|
||||
if (fRescan && pwallet->chain().getPruneMode()) {
|
||||
throw JSONRPCError(RPC_WALLET_ERROR, "Rescan is disabled in pruned mode");
|
||||
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 when blocks are pruned");
|
||||
}
|
||||
|
||||
WalletRescanReserver reserver(pwallet);
|
||||
|
@ -573,7 +582,10 @@ UniValue importwallet(const JSONRPCRequest& request)
|
|||
},
|
||||
}.ToString());
|
||||
|
||||
if (pwallet->chain().getPruneMode()) {
|
||||
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 in pruned mode");
|
||||
}
|
||||
|
||||
|
|
|
@ -4219,10 +4219,13 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
|
|||
|
||||
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()) {
|
||||
// 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 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) && rescan_height != block_height) {
|
||||
--block_height;
|
||||
|
|
|
@ -21,7 +21,6 @@ happened previously.
|
|||
|
||||
from test_framework.test_framework import BitcoinTestFramework
|
||||
from test_framework.util import (
|
||||
assert_raises_rpc_error,
|
||||
connect_nodes,
|
||||
assert_equal,
|
||||
set_node_times,
|
||||
|
@ -39,23 +38,17 @@ Rescan = enum.Enum("Rescan", "no yes late_timestamp")
|
|||
class Variant(collections.namedtuple("Variant", "call data rescan prune")):
|
||||
"""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):
|
||||
|
@ -172,8 +165,7 @@ class ImportRescanTest(BitcoinTestFramework):
|
|||
# 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
|
||||
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:
|
||||
|
@ -198,12 +190,9 @@ class ImportRescanTest(BitcoinTestFramework):
|
|||
# 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__":
|
||||
ImportRescanTest().main()
|
||||
|
|
Loading…
Reference in a new issue