aboutsummaryrefslogtreecommitdiff
path: root/qa
diff options
context:
space:
mode:
authormrbandrews <bandrewsny@gmail.com>2016-11-29 12:39:19 -0500
committermrbandrews <bandrewsny@gmail.com>2017-01-10 08:14:50 -0500
commit1fc4ec7bf224748d3d6271bffa23d121f015cbf3 (patch)
treea726cadbb46e5e41932be2f06477a145f16df911 /qa
parent5754e0341b7c033d4caf99534aca47e9981bd7ed (diff)
Add pruneblockchain RPC to enable manual block file pruning.
Diffstat (limited to 'qa')
-rwxr-xr-xqa/rpc-tests/pruning.py113
1 files changed, 110 insertions, 3 deletions
diff --git a/qa/rpc-tests/pruning.py b/qa/rpc-tests/pruning.py
index 78b8938e4a..062bc8dda4 100755
--- a/qa/rpc-tests/pruning.py
+++ b/qa/rpc-tests/pruning.py
@@ -25,7 +25,7 @@ class PruneTest(BitcoinTestFramework):
def __init__(self):
super().__init__()
self.setup_clean_chain = True
- self.num_nodes = 3
+ self.num_nodes = 5
# Cache for utxos, as the listunspent may take a long time later in the test
self.utxo_cache_0 = []
@@ -43,10 +43,21 @@ class PruneTest(BitcoinTestFramework):
self.nodes.append(start_node(2, self.options.tmpdir, ["-debug","-maxreceivebuffer=20000","-prune=550"], timewait=900))
self.prunedir = self.options.tmpdir+"/node2/regtest/blocks/"
+ # Create node 3 to test manual pruning (it will be re-started with manual pruning later)
+ self.nodes.append(start_node(3, self.options.tmpdir, ["-debug=0","-maxreceivebuffer=20000","-blockmaxsize=999000"], timewait=900))
+ self.manualdir = self.options.tmpdir+"/node3/regtest/blocks/"
+
+ # Create node 4 to test wallet in prune mode, but do not connect
+ self.nodes.append(start_node(4, self.options.tmpdir, ["-debug=0", "-prune=550"]))
+
+ # Determine default relay fee
+ self.relayfee = self.nodes[0].getnetworkinfo()["relayfee"]
+
connect_nodes(self.nodes[0], 1)
connect_nodes(self.nodes[1], 2)
connect_nodes(self.nodes[2], 0)
- sync_blocks(self.nodes[0:3])
+ connect_nodes(self.nodes[0], 3)
+ sync_blocks(self.nodes[0:4])
def create_big_chain(self):
# Start by creating some coinbases we can spend later
@@ -57,7 +68,7 @@ class PruneTest(BitcoinTestFramework):
for i in range(645):
mine_large_block(self.nodes[0], self.utxo_cache_0)
- sync_blocks(self.nodes[0:3])
+ sync_blocks(self.nodes[0:4])
def test_height_min(self):
if not os.path.isfile(self.prunedir+"blk00000.dat"):
@@ -212,6 +223,93 @@ class PruneTest(BitcoinTestFramework):
# Verify we can now have the data for a block previously pruned
assert(self.nodes[2].getblock(self.forkhash)["height"] == self.forkheight)
+ def manual_test(self):
+ # at this point, node3 has 995 blocks and has not yet run in prune mode
+ self.nodes[3] = start_node(3, self.options.tmpdir, ["-debug=0"], timewait=900)
+ assert_raises_message(JSONRPCException, "not in prune mode", self.nodes[3].pruneblockchain, 500)
+ stop_node(self.nodes[3],3)
+
+ # now re-start in manual pruning mode
+ self.nodes[3] = start_node(3, self.options.tmpdir, ["-debug=0","-prune=1"], timewait=900)
+ assert_equal(self.nodes[3].getblockcount(), 995)
+
+ # should not prune because chain tip of node 3 (995) < PruneAfterHeight (1000)
+ assert_raises_message(JSONRPCException, "Blockchain is too short for pruning", self.nodes[3].pruneblockchain, 500)
+
+ # mine 6 blocks so we are at height 1001 (i.e., above PruneAfterHeight)
+ self.nodes[3].generate(6)
+
+ # negative and zero inputs should raise an exception
+ try:
+ self.nodes[3].pruneblockchain(-10)
+ raise AssertionError("pruneblockchain(-10) should have failed.")
+ except:
+ pass
+
+ try:
+ self.nodes[3].pruneblockchain(0)
+ raise AssertionError("pruneblockchain(0) should have failed.")
+ except:
+ pass
+
+ # height=100 too low to prune first block file so this is a no-op
+ self.nodes[3].pruneblockchain(100)
+ if not os.path.isfile(self.manualdir+"blk00000.dat"):
+ raise AssertionError("blk00000.dat is missing when should still be there")
+
+ # height=500 should prune first file
+ self.nodes[3].pruneblockchain(500)
+ if os.path.isfile(self.manualdir+"blk00000.dat"):
+ raise AssertionError("blk00000.dat is still there, should be pruned by now")
+ if not os.path.isfile(self.manualdir+"blk00001.dat"):
+ raise AssertionError("blk00001.dat is missing when should still be there")
+
+ # height=650 should prune second file
+ self.nodes[3].pruneblockchain(650)
+ if os.path.isfile(self.manualdir+"blk00001.dat"):
+ raise AssertionError("blk00001.dat is still there, should be pruned by now")
+
+ # height=1000 should not prune anything more, because tip-288 is in blk00002.dat.
+ self.nodes[3].pruneblockchain(1000)
+ if not os.path.isfile(self.manualdir+"blk00002.dat"):
+ raise AssertionError("blk00002.dat is still there, should be pruned by now")
+
+ # advance the tip so blk00002.dat and blk00003.dat can be pruned (the last 288 blocks should now be in blk00004.dat)
+ self.nodes[3].generate(288)
+ self.nodes[3].pruneblockchain(1000)
+ if os.path.isfile(self.manualdir+"blk00002.dat"):
+ raise AssertionError("blk00002.dat is still there, should be pruned by now")
+ if os.path.isfile(self.manualdir+"blk00003.dat"):
+ raise AssertionError("blk00003.dat is still there, should be pruned by now")
+
+ # stop node, start back up with auto-prune at 550MB, make sure still runs
+ stop_node(self.nodes[3],3)
+ self.nodes[3] = start_node(3, self.options.tmpdir, ["-debug=0","-prune=550"], timewait=900)
+
+ print("Success")
+
+ def wallet_test(self):
+ # check that the pruning node's wallet is still in good shape
+ print("Stop and start pruning node to trigger wallet rescan")
+ try:
+ stop_node(self.nodes[2], 2)
+ start_node(2, self.options.tmpdir, ["-debug=1","-prune=550"])
+ print("Success")
+ except Exception as detail:
+ raise AssertionError("Wallet test: unable to re-start the pruning node")
+
+ # check that wallet loads loads successfully when restarting a pruned node after IBD.
+ # this was reported to fail in #7494.
+ print ("Syncing node 4 to test wallet")
+ connect_nodes(self.nodes[0], 4)
+ nds = [self.nodes[0], self.nodes[4]]
+ sync_blocks(nds)
+ try:
+ stop_node(self.nodes[4],4) #stop and start to trigger rescan
+ start_node(4, self.options.tmpdir, ["-debug=1","-prune=550"])
+ print ("Success")
+ except Exception as detail:
+ raise AssertionError("Wallet test: unable to re-start node4")
def run_test(self):
print("Warning! This test requires 4GB of disk space and takes over 30 mins (up to 2 hours)")
@@ -226,6 +324,9 @@ class PruneTest(BitcoinTestFramework):
# Start by mining a simple chain that all nodes have
# N0=N1=N2 **...*(995)
+ # stop manual-pruning node with 995 blocks
+ stop_node(self.nodes[3],3)
+
print("Check that we haven't started pruning yet because we're below PruneAfterHeight")
self.test_height_min()
# Extend this chain past the PruneAfterHeight
@@ -308,6 +409,12 @@ class PruneTest(BitcoinTestFramework):
#
# N1 doesn't change because 1033 on main chain (*) is invalid
+ print("Test manual pruning")
+ self.manual_test()
+
+ print("Test wallet re-scan")
+ self.wallet_test()
+
print("Done")
if __name__ == '__main__':