77Generate chains with block versions that appear to be signalling unknown
88soft-forks, and test that warning alerts are generated.
99"""
10-
11- from test_framework .mininode import *
12- from test_framework .test_framework import BitcoinTestFramework
13- from test_framework .util import *
10+ import os
1411import re
12+
1513from 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
1618
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
1921VB_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 )
2124
2225WARN_UNKNOWN_RULES_MINED = "Unknown block versions being mined! It's possible unknown rules are in effect"
2326WARN_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" )
2928
3029class VersionBitsWarningTest (BitcoinTestFramework ):
3130 def set_test_params (self ):
@@ -35,87 +34,79 @@ def set_test_params(self):
3534 def setup_network (self ):
3635 self .alert_filename = os .path .join (self .options .tmpdir , "alert.txt" )
3736 # 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' ):
3938 pass
4039 self .extra_args = [["-alertnotify=echo %s >> \" " + self .alert_filename + "\" " ]]
4140 self .setup_nodes ()
4241
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"""
4544 tip = self .nodes [0 ].getbestblockhash ()
4645 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
4847 tip = int (tip , 16 )
4948
5049 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
5352 block .solve ()
5453 peer .send_message (msg_block (block ))
5554 block_time += 1
5655 height += 1
5756 tip = block .sha256
5857 peer .sync_with_ping ()
5958
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
6463
6564 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 ())
6968 network_thread_start ()
69+ node .p2p .wait_for_verack ()
7070
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 )
9973
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" ]))
10982
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 )
11687
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 )
119110
120111if __name__ == '__main__' :
121112 VersionBitsWarningTest ().main ()
0 commit comments