forked from bitcoin/bitcoin
-
Notifications
You must be signed in to change notification settings - Fork 70
/
Copy pathfeature_sync_coins_tip_after_chain_sync.py
executable file
·145 lines (124 loc) · 4.85 KB
/
feature_sync_coins_tip_after_chain_sync.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
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().main()