7
7
Generate chains with block versions that appear to be signalling unknown
8
8
soft-forks, and test that warning alerts are generated.
9
9
"""
10
-
11
- from test_framework .mininode import *
12
- from test_framework .test_framework import BitcoinTestFramework
13
- from test_framework .util import *
10
+ import os
14
11
import re
12
+
15
13
from test_framework .blocktools import create_block , create_coinbase
14
+ from test_framework .messages import msg_block
15
+ from test_framework .mininode import P2PInterface , network_thread_start , mininode_lock
16
+ from test_framework .test_framework import BitcoinTestFramework
17
+ from test_framework .util import wait_until
16
18
17
- VB_PERIOD = 144 # versionbits period length for regtest
18
- VB_THRESHOLD = 108 # versionbits activation threshold for regtest
19
+ VB_PERIOD = 144 # versionbits period length for regtest
20
+ VB_THRESHOLD = 108 # versionbits activation threshold for regtest
19
21
VB_TOP_BITS = 0x20000000
20
- VB_UNKNOWN_BIT = 27 # Choose a bit unassigned to any deployment
22
+ VB_UNKNOWN_BIT = 27 # Choose a bit unassigned to any deployment
23
+ VB_UNKNOWN_VERSION = VB_TOP_BITS | (1 << VB_UNKNOWN_BIT )
21
24
22
25
WARN_UNKNOWN_RULES_MINED = "Unknown block versions being mined! It's possible unknown rules are in effect"
23
26
WARN_UNKNOWN_RULES_ACTIVE = "unknown new rules activated (versionbit {})" .format (VB_UNKNOWN_BIT )
24
- VB_PATTERN = re .compile ("^Warning.*versionbit" )
25
-
26
- class TestNode (P2PInterface ):
27
- def on_inv (self , message ):
28
- pass
27
+ VB_PATTERN = re .compile ("Warning: unknown new rules activated.*versionbit" )
29
28
30
29
class VersionBitsWarningTest (BitcoinTestFramework ):
31
30
def set_test_params (self ):
@@ -35,87 +34,79 @@ def set_test_params(self):
35
34
def setup_network (self ):
36
35
self .alert_filename = os .path .join (self .options .tmpdir , "alert.txt" )
37
36
# Open and close to create zero-length file
38
- with open (self .alert_filename , 'w' , encoding = 'utf8' ) as _ :
37
+ with open (self .alert_filename , 'w' , encoding = 'utf8' ):
39
38
pass
40
39
self .extra_args = [["-alertnotify=echo %s >> \" " + self .alert_filename + "\" " ]]
41
40
self .setup_nodes ()
42
41
43
- # Send numblocks blocks via peer with nVersionToUse set.
44
- def send_blocks_with_version ( self , peer , numblocks , nVersionToUse ):
42
+ def send_blocks_with_version ( self , peer , numblocks , version ):
43
+ """Send numblocks blocks to peer with version set"""
45
44
tip = self .nodes [0 ].getbestblockhash ()
46
45
height = self .nodes [0 ].getblockcount ()
47
- block_time = self .nodes [0 ].getblockheader (tip )["time" ]+ 1
46
+ block_time = self .nodes [0 ].getblockheader (tip )["time" ] + 1
48
47
tip = int (tip , 16 )
49
48
50
49
for _ in range (numblocks ):
51
- block = create_block (tip , create_coinbase (height + 1 ), block_time )
52
- block .nVersion = nVersionToUse
50
+ block = create_block (tip , create_coinbase (height + 1 ), block_time )
51
+ block .nVersion = version
53
52
block .solve ()
54
53
peer .send_message (msg_block (block ))
55
54
block_time += 1
56
55
height += 1
57
56
tip = block .sha256
58
57
peer .sync_with_ping ()
59
58
60
- def test_versionbits_in_alert_file (self ):
61
- with open ( self . alert_filename , 'r' , encoding = 'utf8' ) as f :
62
- alert_text = f .read ()
63
- assert ( VB_PATTERN .match (alert_text ))
59
+ def versionbits_in_alert_file (self ):
60
+ """Test that the versionbits warning has been written to the alert file."""
61
+ alert_text = open ( self . alert_filename , 'r' , encoding = 'utf8' ) .read ()
62
+ return VB_PATTERN .search (alert_text ) is not None
64
63
65
64
def run_test (self ):
66
- # Setup the p2p connection and start up the network thread.
67
- self .nodes [0 ]. add_p2p_connection ( TestNode ())
68
-
65
+ # Handy alias
66
+ node = self .nodes [0 ]
67
+ node . add_p2p_connection ( P2PInterface ())
69
68
network_thread_start ()
69
+ node .p2p .wait_for_verack ()
70
70
71
- # Test logic begins here
72
- self .nodes [0 ].p2p .wait_for_verack ()
73
-
74
- # 1. Have the node mine one period worth of blocks
75
- self .nodes [0 ].generate (VB_PERIOD )
76
-
77
- # 2. Now build one period of blocks on the tip, with < VB_THRESHOLD
78
- # blocks signaling some unknown bit.
79
- nVersion = VB_TOP_BITS | (1 << VB_UNKNOWN_BIT )
80
- self .send_blocks_with_version (self .nodes [0 ].p2p , VB_THRESHOLD - 1 , nVersion )
81
-
82
- # Fill rest of period with regular version blocks
83
- self .nodes [0 ].generate (VB_PERIOD - VB_THRESHOLD + 1 )
84
- # Check that we're not getting any versionbit-related errors in
85
- # get*info()
86
- assert (not VB_PATTERN .match (self .nodes [0 ].getmininginfo ()["warnings" ]))
87
- assert (not VB_PATTERN .match (self .nodes [0 ].getnetworkinfo ()["warnings" ]))
88
-
89
- # 3. Now build one period of blocks with >= VB_THRESHOLD blocks signaling
90
- # some unknown bit
91
- self .send_blocks_with_version (self .nodes [0 ].p2p , VB_THRESHOLD , nVersion )
92
- self .nodes [0 ].generate (VB_PERIOD - VB_THRESHOLD )
93
- # Might not get a versionbits-related alert yet, as we should
94
- # have gotten a different alert due to more than 51/100 blocks
95
- # being of unexpected version.
96
- # Check that get*info() shows some kind of error.
97
- assert (WARN_UNKNOWN_RULES_MINED in self .nodes [0 ].getmininginfo ()["warnings" ])
98
- assert (WARN_UNKNOWN_RULES_MINED in self .nodes [0 ].getnetworkinfo ()["warnings" ])
71
+ # Mine one period worth of blocks
72
+ node .generate (VB_PERIOD )
99
73
100
- # Mine a period worth of expected blocks so the generic block-version warning
101
- # is cleared, and restart the node. This should move the versionbit state
102
- # to ACTIVE.
103
- self .nodes [0 ].generate (VB_PERIOD )
104
- self .stop_nodes ()
105
- # Empty out the alert file
106
- with open (self .alert_filename , 'w' , encoding = 'utf8' ) as _ :
107
- pass
108
- self .start_nodes ()
74
+ self .log .info ("Check that there is no warning if previous VB_BLOCKS have <VB_THRESHOLD blocks with unknown versionbits version." )
75
+ # Build one period of blocks with < VB_THRESHOLD blocks signaling some unknown bit
76
+ self .send_blocks_with_version (node .p2p , VB_THRESHOLD - 1 , VB_UNKNOWN_VERSION )
77
+ node .generate (VB_PERIOD - VB_THRESHOLD + 1 )
78
+
79
+ # Check that we're not getting any versionbit-related errors in get*info()
80
+ assert (not VB_PATTERN .match (node .getmininginfo ()["warnings" ]))
81
+ assert (not VB_PATTERN .match (node .getnetworkinfo ()["warnings" ]))
109
82
110
- # Connecting one block should be enough to generate an error.
111
- self .nodes [0 ].generate (1 )
112
- assert (WARN_UNKNOWN_RULES_ACTIVE in self .nodes [0 ].getmininginfo ()["warnings" ])
113
- assert (WARN_UNKNOWN_RULES_ACTIVE in self .nodes [0 ].getnetworkinfo ()["warnings" ])
114
- self .stop_nodes ()
115
- self .test_versionbits_in_alert_file ()
83
+ self .log .info ("Check that there is a warning if >50 blocks in the last 100 were an unknown version" )
84
+ # Build one period of blocks with VB_THRESHOLD blocks signaling some unknown bit
85
+ self .send_blocks_with_version (node .p2p , VB_THRESHOLD , VB_UNKNOWN_VERSION )
86
+ node .generate (VB_PERIOD - VB_THRESHOLD )
116
87
117
- # Test framework expects the node to still be running...
118
- self .start_nodes ()
88
+ # Check that get*info() shows the 51/100 unknown block version error.
89
+ assert (WARN_UNKNOWN_RULES_MINED in node .getmininginfo ()["warnings" ])
90
+ assert (WARN_UNKNOWN_RULES_MINED in node .getnetworkinfo ()["warnings" ])
91
+
92
+ self .log .info ("Check that there is a warning if previous VB_BLOCKS have >=VB_THRESHOLD blocks with unknown versionbits version." )
93
+ # Mine a period worth of expected blocks so the generic block-version warning
94
+ # is cleared. This will move the versionbit state to ACTIVE.
95
+ node .generate (VB_PERIOD )
96
+
97
+ # Stop-start the node. This is required because bitcoind will only warn once about unknown versions or unknown rules activating.
98
+ self .restart_node (0 )
99
+
100
+ # Generating one block guarantees that we'll get out of IBD
101
+ node .generate (1 )
102
+ wait_until (lambda : not node .getblockchaininfo ()['initialblockdownload' ], timeout = 10 , lock = mininode_lock )
103
+ # Generating one more block will be enough to generate an error.
104
+ node .generate (1 )
105
+ # Check that get*info() shows the versionbits unknown rules warning
106
+ assert (WARN_UNKNOWN_RULES_ACTIVE in node .getmininginfo ()["warnings" ])
107
+ assert (WARN_UNKNOWN_RULES_ACTIVE in node .getnetworkinfo ()["warnings" ])
108
+ # Check that the alert file shows the versionbits unknown rules warning
109
+ wait_until (lambda : self .versionbits_in_alert_file (), timeout = 60 )
119
110
120
111
if __name__ == '__main__' :
121
112
VersionBitsWarningTest ().main ()
0 commit comments