mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-05-12 06:53:11 +02:00
Merge bitcoin/bitcoin#33477: Rollback for dumptxoutset without invalidating blocks
fc736013a5rpc: Add in_memory option to dumptxoutset with rollback (Fabian Jahr)d0fd718948test: Extend named pipe sqlite tool test to use rollback (Fabian Jahr)ab9463efactest: Add dumptxoutset fork test (Fabian Jahr)49d5e835a8rpc: Don't invalidate blocks in dumptxoutset (Fabian Jahr)fe58eb9850blockstorage: Add DeletePruneLock (Fabian Jahr) Pull request description: This is an alternative approach to implement `dumptxoutset` with rollback that was discussed a few times. It does not rely on `invalidateblock` and `reconsiderblock` and instead creates a temporary copy of the coins DB, modifies this copy by rolling back as many blocks as necessary and then creating the dump from this temp copy DB. See also https://github.com/bitcoin/bitcoin/pull/29553#issuecomment-1978480989, https://github.com/bitcoin/bitcoin/issues/32817#issuecomment-3012406102 and #29565 discussions. The nice side-effects of this are that forks can not interfere with the rollback and network activity does not have to be suspended. But there are also some downsides when comparing to the current approach: this does require some additional disk space for the copied coins DB and performance is slower (master took 3m 17s vs 9m 16s in my last test with the code here, rolling back ~1500 blocks). However, there is also not much code being added here, network can stay active throughout and performance would stay constant with this approach while it would impact master if there were forks that needed to be invalidated as well (see #33444 for the alternative approach), so this could still be considered a good trade-off. ACKs for top commit: stratospher: tested ACKfc73601. very nice! sedited: Re-ACKfc736013a5theStack: re-ACKfc736013a5Tree-SHA512: d3d674f68184ac3ada87d969d0fca7bc38203ee939853864adcd235ee3a954914c7e351b817800b885a495606e323392c27d88ba8d8e018eaf8567c098eb0e9c
This commit is contained in:
@@ -19,16 +19,35 @@ class DumptxoutsetTest(BitcoinTestFramework):
|
||||
self.setup_clean_chain = True
|
||||
self.num_nodes = 1
|
||||
|
||||
def check_expected_network(self, node, active):
|
||||
rev_file = node.blocks_path / "rev00000.dat"
|
||||
bogus_file = node.blocks_path / "bogus.dat"
|
||||
rev_file.rename(bogus_file)
|
||||
assert_raises_rpc_error(
|
||||
-1, 'Could not roll back to requested height.', node.dumptxoutset, 'utxos.dat', rollback=99)
|
||||
assert_equal(node.getnetworkinfo()['networkactive'], active)
|
||||
def test_dumptxoutset_with_fork(self):
|
||||
node = self.nodes[0]
|
||||
tip = node.getbestblockhash()
|
||||
target_height = node.getblockcount() - 10
|
||||
target_hash = node.getblockhash(target_height)
|
||||
|
||||
# Create a fork of two blocks at the target height
|
||||
invalid_block = node.getblockhash(target_height + 1)
|
||||
node.invalidateblock(invalid_block)
|
||||
# Reset mocktime to not regenerate the same blockhash
|
||||
node.setmocktime(0)
|
||||
self.generate(node, 2)
|
||||
|
||||
# Move back on to actual main chain
|
||||
node.reconsiderblock(invalid_block)
|
||||
self.wait_until(lambda: node.getbestblockhash() == tip)
|
||||
|
||||
# Use dumptxoutset at the forked height
|
||||
out = node.dumptxoutset("txoutset_fork.dat", "rollback", {"rollback": target_height})
|
||||
|
||||
# Verify the snapshot was created at the target height and not the fork tip
|
||||
assert_equal(out['base_height'], target_height)
|
||||
assert_equal(out['base_hash'], target_hash)
|
||||
|
||||
# Cover the same case as above with an in-memory database
|
||||
out_mem = node.dumptxoutset("txoutset_fork_mem.dat", "rollback", {"rollback": target_height, "in_memory": True})
|
||||
assert_equal(out_mem['base_height'], target_height)
|
||||
assert_equal(out_mem['base_hash'], target_hash)
|
||||
|
||||
# Cleanup
|
||||
bogus_file.rename(rev_file)
|
||||
|
||||
def run_test(self):
|
||||
"""Test a trivial usage of the dumptxoutset RPC command."""
|
||||
@@ -71,13 +90,8 @@ class DumptxoutsetTest(BitcoinTestFramework):
|
||||
assert_raises_rpc_error(
|
||||
-8, 'Invalid snapshot type "bogus" specified. Please specify "rollback" or "latest"', node.dumptxoutset, 'utxos.dat', "bogus")
|
||||
|
||||
self.log.info("Test that dumptxoutset failure does not leave the network activity suspended when it was on previously")
|
||||
self.check_expected_network(node, True)
|
||||
|
||||
self.log.info("Test that dumptxoutset failure leaves the network activity suspended when it was off")
|
||||
node.setnetworkactive(False)
|
||||
self.check_expected_network(node, False)
|
||||
node.setnetworkactive(True)
|
||||
self.log.info("Testing dumptxoutset with chain fork at target height")
|
||||
self.test_dumptxoutset_with_fork()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -77,7 +77,7 @@ class UtxoToSqliteTest(BitcoinTestFramework):
|
||||
def set_test_params(self):
|
||||
self.num_nodes = 1
|
||||
# we want to create some UTXOs with non-standard output scripts
|
||||
self.extra_args = [['-acceptnonstdtxn=1']]
|
||||
self.extra_args = [['-acceptnonstdtxn=1', '-coinstatsindex=1']]
|
||||
|
||||
def skip_test_if_missing_module(self):
|
||||
self.skip_if_no_py_sqlite3()
|
||||
@@ -143,10 +143,12 @@ class UtxoToSqliteTest(BitcoinTestFramework):
|
||||
output_direct_filename = os.path.join(self.options.tmpdir, "utxos_direct.sqlite")
|
||||
p = subprocess.Popen([sys.executable, utxo_to_sqlite_path, fifo_filename, output_direct_filename],
|
||||
stderr=subprocess.STDOUT)
|
||||
node.dumptxoutset(fifo_filename, "latest")
|
||||
target_height = node.getblockcount() - 10
|
||||
node.dumptxoutset(fifo_filename, "rollback", {"rollback": target_height})
|
||||
p.wait(timeout=10)
|
||||
muhash_direct_sqlite = calculate_muhash_from_sqlite_utxos(output_direct_filename, "hex", "hex")
|
||||
assert_equal(muhash_sqlite, muhash_direct_sqlite)
|
||||
muhash_index = node.gettxoutsetinfo('muhash', target_height)['muhash']
|
||||
assert_equal(muhash_index, muhash_direct_sqlite)
|
||||
os.remove(fifo_filename)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user