mirror of
https://github.com/Retropex/bitcoin.git
synced 2025-05-12 19:20:42 +02:00
test: add test for SyncCoinsTipAfterChainSync
Github-Pull: #15218 Rebased-From: 8887d28a014420668801d7e4c5d1bf45c5e93684
This commit is contained in:
parent
2f1bf089f7
commit
bbcec3aed7
145
test/functional/feature_sync_coins_tip_after_chain_sync.py
Executable file
145
test/functional/feature_sync_coins_tip_after_chain_sync.py
Executable file
@ -0,0 +1,145 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright (c) 2024- The Bitcoin Core developers
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
"""
|
||||
Test SyncCoinsTipAfterChainSync logic
|
||||
"""
|
||||
|
||||
|
||||
from test_framework.blocktools import create_block, create_coinbase
|
||||
from test_framework.messages import (
|
||||
MSG_BLOCK,
|
||||
MSG_TYPE_MASK,
|
||||
)
|
||||
from test_framework.p2p import (
|
||||
CBlockHeader,
|
||||
msg_block,
|
||||
msg_headers,
|
||||
P2PDataStore,
|
||||
)
|
||||
from test_framework.test_framework import BitcoinTestFramework
|
||||
from test_framework.util import (
|
||||
assert_equal,
|
||||
)
|
||||
|
||||
|
||||
class P2PBlockDelay(P2PDataStore):
|
||||
def __init__(self, delay_block):
|
||||
self.delay_block = delay_block
|
||||
super().__init__()
|
||||
|
||||
def on_getdata(self, message):
|
||||
for inv in message.inv:
|
||||
self.getdata_requests.append(inv.hash)
|
||||
if (inv.type & MSG_TYPE_MASK) == MSG_BLOCK:
|
||||
if inv.hash != self.delay_block:
|
||||
self.send_message(msg_block(self.block_store[inv.hash]))
|
||||
|
||||
def on_getheaders(self, message):
|
||||
pass
|
||||
|
||||
def send_delayed(self):
|
||||
self.send_message(msg_block(self.block_store[self.delay_block]))
|
||||
|
||||
|
||||
SYNC_CHECK_INTERVAL = 30
|
||||
|
||||
|
||||
class SyncCoinsTipAfterChainSyncTest(BitcoinTestFramework):
|
||||
def set_test_params(self):
|
||||
self.setup_clean_chain = True
|
||||
self.num_nodes = 1
|
||||
# Set maxtipage to 1 to get us out of IBD after 1 block past our mocktime
|
||||
self.extra_args = [[f"-maxtipage=1"]]
|
||||
|
||||
def run_test(self):
|
||||
NUM_BLOCKS = 3
|
||||
node = self.nodes[0]
|
||||
tip = int(node.getbestblockhash(), 16)
|
||||
blocks = []
|
||||
height = 1
|
||||
block_time = node.getblock(node.getbestblockhash())["time"] + 1
|
||||
# Set mock time to 2 past block time, so second block will exit IBD
|
||||
node.setmocktime(block_time + 2)
|
||||
|
||||
# Prepare blocks without sending them to the node
|
||||
block_dict = {}
|
||||
for _ in range(NUM_BLOCKS):
|
||||
blocks.append(create_block(tip, create_coinbase(height), block_time))
|
||||
blocks[-1].solve()
|
||||
tip = blocks[-1].sha256
|
||||
block_time += 1
|
||||
height += 1
|
||||
block_dict[blocks[-1].sha256] = blocks[-1]
|
||||
delay_block = blocks[-1].sha256
|
||||
|
||||
# Create peer which will not automatically send last block
|
||||
peer = node.add_outbound_p2p_connection(
|
||||
P2PBlockDelay(delay_block),
|
||||
p2p_idx=1,
|
||||
connection_type="outbound-full-relay",
|
||||
)
|
||||
peer.block_store = block_dict
|
||||
|
||||
self.log.info(
|
||||
"Send headers message for first block, verify it won't sync because node is still in IBD"
|
||||
)
|
||||
headers_message = msg_headers()
|
||||
headers_message.headers = [CBlockHeader(blocks[0])]
|
||||
peer.send_message(headers_message)
|
||||
peer.sync_with_ping()
|
||||
assert_equal(node.getblockchaininfo()["initialblockdownload"], True)
|
||||
with node.assert_debug_log(
|
||||
["Node is still in IBD, rescheduling post-IBD chainstate disk sync..."]
|
||||
):
|
||||
node.mockscheduler(SYNC_CHECK_INTERVAL)
|
||||
|
||||
self.log.info(
|
||||
"Send headers message for second block, verify it won't sync because node height has changed"
|
||||
)
|
||||
headers_message.headers = [CBlockHeader(blocks[1])]
|
||||
peer.send_message(headers_message)
|
||||
peer.sync_with_ping()
|
||||
assert_equal(node.getblockchaininfo()["initialblockdownload"], False)
|
||||
with node.assert_debug_log(
|
||||
[
|
||||
"Chain height updated since last check, rescheduling post-IBD chainstate disk sync..."
|
||||
]
|
||||
):
|
||||
node.mockscheduler(SYNC_CHECK_INTERVAL)
|
||||
|
||||
self.log.info(
|
||||
"Send headers message for last block, verify it won't sync because node is still downloading the block"
|
||||
)
|
||||
headers_message.headers = [CBlockHeader(blocks[2])]
|
||||
peer.send_message(headers_message)
|
||||
peer.sync_with_ping()
|
||||
with node.assert_debug_log(
|
||||
[
|
||||
"Still downloading blocks from peers, rescheduling post-IBD chainstate disk sync..."
|
||||
]
|
||||
):
|
||||
node.mockscheduler(SYNC_CHECK_INTERVAL)
|
||||
|
||||
self.log.info(
|
||||
"Send last block, verify it won't sync because node height has changed"
|
||||
)
|
||||
peer.send_delayed()
|
||||
peer.sync_with_ping()
|
||||
with node.assert_debug_log(
|
||||
[
|
||||
"Chain height updated since last check, rescheduling post-IBD chainstate disk sync..."
|
||||
]
|
||||
):
|
||||
node.mockscheduler(SYNC_CHECK_INTERVAL)
|
||||
|
||||
self.log.info("Verify node syncs chainstate to disk on next scheduler update")
|
||||
with node.assert_debug_log(
|
||||
["Finished syncing to tip, syncing chainstate to disk"]
|
||||
):
|
||||
node.mockscheduler(SYNC_CHECK_INTERVAL)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
SyncCoinsTipAfterChainSyncTest(__file__).main()
|
@ -366,6 +366,7 @@ BASE_SCRIPTS = [
|
||||
'feature_asmap.py',
|
||||
'feature_fastprune.py',
|
||||
'feature_framework_miniwallet.py',
|
||||
'feature_sync_coins_tip_after_chain_sync.py',
|
||||
'mempool_unbroadcast.py',
|
||||
'mempool_compatibility.py',
|
||||
'mempool_accept_wtxid.py',
|
||||
|
Loading…
Reference in New Issue
Block a user