mirror of
https://github.com/dashpay/dash.git
synced 2024-12-26 20:42:59 +01:00
dad8c67d38
64c0800
Use logging in individual tests (John Newbery)38ad281
Use logging in test_framework/comptool.py (John Newbery)ff19073
Use logging in test_framework/blockstore.py (John Newbery)2a9c7c7
Use logging in test_framework/util.py (John Newbery)b0dec4a
Remove manual debug settings in qa tests. (John Newbery)af1363c
Always enable debug log and microsecond logging for test nodes. (John Newbery)6d0e325
Use logging in mininode.py (John Newbery)553a976
Add logging to p2p-segwit.py (John Newbery)0e6d23d
Add logging to test_framework.py (John Newbery) Tree-SHA512: 42ee2acbf444ec32d796f930f9f6e272da03c75e93d974a126d4ea9b2dbaa77cc57ab5e63ce3fd33d609049d884eb8d9f65272c08922d10f8db69d4a60ad05a3
164 lines
6.6 KiB
Python
Executable File
164 lines
6.6 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
# Copyright (c) 2016 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 version bits warning system.
|
|
|
|
Generate chains with block versions that appear to be signalling unknown
|
|
soft-forks, and test that warning alerts are generated.
|
|
"""
|
|
|
|
from test_framework.mininode import *
|
|
from test_framework.test_framework import BitcoinTestFramework
|
|
from test_framework.util import *
|
|
import re
|
|
import time
|
|
from test_framework.blocktools import create_block, create_coinbase
|
|
|
|
VB_PERIOD = 144 # versionbits period length for regtest
|
|
VB_THRESHOLD = 108 # versionbits activation threshold for regtest
|
|
VB_TOP_BITS = 0x20000000
|
|
VB_UNKNOWN_BIT = 27 # Choose a bit unassigned to any deployment
|
|
|
|
WARN_UNKNOWN_RULES_MINED = "Unknown block versions being mined! It's possible unknown rules are in effect"
|
|
WARN_UNKNOWN_RULES_ACTIVE = "unknown new rules activated (versionbit {})".format(VB_UNKNOWN_BIT)
|
|
VB_PATTERN = re.compile("^Warning.*versionbit")
|
|
|
|
# TestNode: bare-bones "peer". Used mostly as a conduit for a test to sending
|
|
# p2p messages to a node, generating the messages in the main testing logic.
|
|
class TestNode(NodeConnCB):
|
|
def __init__(self):
|
|
NodeConnCB.__init__(self)
|
|
self.connection = None
|
|
self.ping_counter = 1
|
|
self.last_pong = msg_pong()
|
|
|
|
def add_connection(self, conn):
|
|
self.connection = conn
|
|
|
|
def on_inv(self, conn, message):
|
|
pass
|
|
|
|
# Wrapper for the NodeConn's send_message function
|
|
def send_message(self, message):
|
|
self.connection.send_message(message)
|
|
|
|
def on_pong(self, conn, message):
|
|
self.last_pong = message
|
|
|
|
# Sync up with the node after delivery of a block
|
|
def sync_with_ping(self, timeout=30):
|
|
self.connection.send_message(msg_ping(nonce=self.ping_counter))
|
|
received_pong = False
|
|
sleep_time = 0.05
|
|
while not received_pong and timeout > 0:
|
|
time.sleep(sleep_time)
|
|
timeout -= sleep_time
|
|
with mininode_lock:
|
|
if self.last_pong.nonce == self.ping_counter:
|
|
received_pong = True
|
|
self.ping_counter += 1
|
|
return received_pong
|
|
|
|
|
|
class VersionBitsWarningTest(BitcoinTestFramework):
|
|
def __init__(self):
|
|
super().__init__()
|
|
self.setup_clean_chain = True
|
|
self.num_nodes = 1
|
|
|
|
def setup_network(self):
|
|
self.alert_filename = os.path.join(self.options.tmpdir, "alert.txt")
|
|
# Open and close to create zero-length file
|
|
with open(self.alert_filename, 'w', encoding='utf8') as _:
|
|
pass
|
|
self.extra_args = [["-alertnotify=echo %s >> \"" + self.alert_filename + "\""]]
|
|
self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, self.extra_args)
|
|
|
|
# Send numblocks blocks via peer with nVersionToUse set.
|
|
def send_blocks_with_version(self, peer, numblocks, nVersionToUse):
|
|
tip = self.nodes[0].getbestblockhash()
|
|
height = self.nodes[0].getblockcount()
|
|
block_time = self.nodes[0].getblockheader(tip)["time"]+1
|
|
tip = int(tip, 16)
|
|
|
|
for _ in range(numblocks):
|
|
block = create_block(tip, create_coinbase(height+1), block_time)
|
|
block.nVersion = nVersionToUse
|
|
block.solve()
|
|
peer.send_message(msg_block(block))
|
|
block_time += 1
|
|
height += 1
|
|
tip = block.sha256
|
|
peer.sync_with_ping()
|
|
|
|
def test_versionbits_in_alert_file(self):
|
|
with open(self.alert_filename, 'r', encoding='utf8') as f:
|
|
alert_text = f.read()
|
|
assert(VB_PATTERN.match(alert_text))
|
|
|
|
def run_test(self):
|
|
# Setup the p2p connection and start up the network thread.
|
|
test_node = TestNode()
|
|
|
|
connections = []
|
|
connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test_node))
|
|
test_node.add_connection(connections[0])
|
|
|
|
NetworkThread().start() # Start up network handling in another thread
|
|
|
|
# Test logic begins here
|
|
test_node.wait_for_verack()
|
|
|
|
# 1. Have the node mine one period worth of blocks
|
|
self.nodes[0].generate(VB_PERIOD)
|
|
|
|
# 2. Now build one period of blocks on the tip, with < VB_THRESHOLD
|
|
# blocks signaling some unknown bit.
|
|
nVersion = VB_TOP_BITS | (1<<VB_UNKNOWN_BIT)
|
|
self.send_blocks_with_version(test_node, VB_THRESHOLD-1, nVersion)
|
|
|
|
# Fill rest of period with regular version blocks
|
|
self.nodes[0].generate(VB_PERIOD - VB_THRESHOLD + 1)
|
|
# Check that we're not getting any versionbit-related errors in
|
|
# get*info()
|
|
assert(not VB_PATTERN.match(self.nodes[0].getinfo()["errors"]))
|
|
assert(not VB_PATTERN.match(self.nodes[0].getmininginfo()["errors"]))
|
|
assert(not VB_PATTERN.match(self.nodes[0].getnetworkinfo()["warnings"]))
|
|
|
|
# 3. Now build one period of blocks with >= VB_THRESHOLD blocks signaling
|
|
# some unknown bit
|
|
self.send_blocks_with_version(test_node, VB_THRESHOLD, nVersion)
|
|
self.nodes[0].generate(VB_PERIOD - VB_THRESHOLD)
|
|
# Might not get a versionbits-related alert yet, as we should
|
|
# have gotten a different alert due to more than 51/100 blocks
|
|
# being of unexpected version.
|
|
# Check that get*info() shows some kind of error.
|
|
assert(WARN_UNKNOWN_RULES_MINED in self.nodes[0].getinfo()["errors"])
|
|
assert(WARN_UNKNOWN_RULES_MINED in self.nodes[0].getmininginfo()["errors"])
|
|
assert(WARN_UNKNOWN_RULES_MINED in self.nodes[0].getnetworkinfo()["warnings"])
|
|
|
|
# Mine a period worth of expected blocks so the generic block-version warning
|
|
# is cleared, and restart the node. This should move the versionbit state
|
|
# to ACTIVE.
|
|
self.nodes[0].generate(VB_PERIOD)
|
|
stop_nodes(self.nodes)
|
|
# Empty out the alert file
|
|
with open(self.alert_filename, 'w', encoding='utf8') as _:
|
|
pass
|
|
self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, self.extra_args)
|
|
|
|
# Connecting one block should be enough to generate an error.
|
|
self.nodes[0].generate(1)
|
|
assert(WARN_UNKNOWN_RULES_ACTIVE in self.nodes[0].getinfo()["errors"])
|
|
assert(WARN_UNKNOWN_RULES_ACTIVE in self.nodes[0].getmininginfo()["errors"])
|
|
assert(WARN_UNKNOWN_RULES_ACTIVE in self.nodes[0].getnetworkinfo()["warnings"])
|
|
stop_nodes(self.nodes)
|
|
self.test_versionbits_in_alert_file()
|
|
|
|
# Test framework expects the node to still be running...
|
|
self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, self.extra_args)
|
|
|
|
if __name__ == '__main__':
|
|
VersionBitsWarningTest().main()
|