mirror of
https://github.com/dashpay/dash.git
synced 2024-12-26 04:22:55 +01:00
Merge #10169: [tests] Remove func test code duplication
2a52ae6
Remove duplicate method definitions in NodeConnCB subclasses (John Newbery)52e15aa
Adds helper functions to NodeConnCB (John Newbery) Tree-SHA512: 2d7909eb85b3bde0fc3ebf133798eca21e561f4b2a2880937750820a42856cfb61fc94e30591c14ac13218bcfae0ebe7c5e8662a7b10f5b02470325c44a86cf1 remove duplicate code 10169 Signed-off-by: Pasta <pasta@dashboost.org>
This commit is contained in:
parent
146cae9569
commit
2d771c95a1
@ -10,63 +10,24 @@ if uploadtarget has been reached.
|
|||||||
if uploadtarget has been reached.
|
if uploadtarget has been reached.
|
||||||
* Verify that the upload counters are reset after 24 hours.
|
* Verify that the upload counters are reset after 24 hours.
|
||||||
"""
|
"""
|
||||||
|
from collections import defaultdict
|
||||||
|
import time
|
||||||
|
|
||||||
from test_framework.mininode import *
|
from test_framework.mininode import *
|
||||||
from test_framework.test_framework import BitcoinTestFramework
|
from test_framework.test_framework import BitcoinTestFramework
|
||||||
from test_framework.util import *
|
from test_framework.util import *
|
||||||
import time
|
|
||||||
|
|
||||||
# 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):
|
class TestNode(NodeConnCB):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.connection = None
|
self.block_receive_map = defaultdict(int)
|
||||||
self.ping_counter = 1
|
|
||||||
self.last_pong = msg_pong()
|
|
||||||
self.block_receive_map = {}
|
|
||||||
|
|
||||||
def add_connection(self, conn):
|
|
||||||
self.connection = conn
|
|
||||||
self.peer_disconnected = False
|
|
||||||
|
|
||||||
def on_inv(self, conn, message):
|
def on_inv(self, conn, message):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# Track the last getdata message we receive (used in the test)
|
|
||||||
def on_getdata(self, conn, message):
|
|
||||||
self.last_getdata = message
|
|
||||||
|
|
||||||
def on_block(self, conn, message):
|
def on_block(self, conn, message):
|
||||||
message.block.calc_sha256()
|
message.block.calc_sha256()
|
||||||
try:
|
self.block_receive_map[message.block.sha256] += 1
|
||||||
self.block_receive_map[message.block.sha256] += 1
|
|
||||||
except KeyError as e:
|
|
||||||
self.block_receive_map[message.block.sha256] = 1
|
|
||||||
|
|
||||||
# Spin until verack message is received from the node.
|
|
||||||
# We use this to signal that our test can begin. This
|
|
||||||
# is called from the testing thread, so it needs to acquire
|
|
||||||
# the global lock.
|
|
||||||
def wait_for_verack(self):
|
|
||||||
def veracked():
|
|
||||||
return self.verack_received
|
|
||||||
return wait_until(veracked, timeout=10)
|
|
||||||
|
|
||||||
def wait_for_disconnect(self):
|
|
||||||
def disconnected():
|
|
||||||
return self.peer_disconnected
|
|
||||||
return wait_until(disconnected, timeout=10)
|
|
||||||
|
|
||||||
# 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
|
|
||||||
|
|
||||||
def on_close(self, conn):
|
|
||||||
self.peer_disconnected = True
|
|
||||||
|
|
||||||
class MaxUploadTest(BitcoinTestFramework):
|
class MaxUploadTest(BitcoinTestFramework):
|
||||||
|
|
||||||
@ -197,33 +158,26 @@ class MaxUploadTest(BitcoinTestFramework):
|
|||||||
stop_node(self.nodes[0], 0)
|
stop_node(self.nodes[0], 0)
|
||||||
self.nodes[0] = start_node(0, self.options.tmpdir, ["-whitelist=127.0.0.1", "-maxuploadtarget=1", "-blockmaxsize=999000", "-maxtipage="+str(2*60*60*24*7)])
|
self.nodes[0] = start_node(0, self.options.tmpdir, ["-whitelist=127.0.0.1", "-maxuploadtarget=1", "-blockmaxsize=999000", "-maxtipage="+str(2*60*60*24*7)])
|
||||||
|
|
||||||
#recreate/reconnect 3 test nodes
|
#recreate/reconnect a test node
|
||||||
test_nodes = []
|
test_nodes = [TestNode()]
|
||||||
connections = []
|
connections = [NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test_nodes[0])]
|
||||||
|
test_nodes[0].add_connection(connections[0])
|
||||||
for i in range(3):
|
|
||||||
test_nodes.append(TestNode())
|
|
||||||
connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test_nodes[i]))
|
|
||||||
test_nodes[i].add_connection(connections[i])
|
|
||||||
|
|
||||||
NetworkThread().start() # Start up network handling in another thread
|
NetworkThread().start() # Start up network handling in another thread
|
||||||
[x.wait_for_verack() for x in test_nodes]
|
test_nodes[0].wait_for_verack()
|
||||||
|
|
||||||
#retrieve 20 blocks which should be enough to break the 1MB limit
|
#retrieve 20 blocks which should be enough to break the 1MB limit
|
||||||
getdata_request.inv = [CInv(2, big_new_block)]
|
getdata_request.inv = [CInv(2, big_new_block)]
|
||||||
for i in range(20):
|
for i in range(20):
|
||||||
test_nodes[1].send_message(getdata_request)
|
test_nodes[0].send_message(getdata_request)
|
||||||
test_nodes[1].sync_with_ping()
|
test_nodes[0].sync_with_ping()
|
||||||
assert_equal(test_nodes[1].block_receive_map[big_new_block], i+1)
|
assert_equal(test_nodes[0].block_receive_map[big_new_block], i+1)
|
||||||
|
|
||||||
getdata_request.inv = [CInv(2, big_old_block)]
|
getdata_request.inv = [CInv(2, big_old_block)]
|
||||||
test_nodes[1].send_message(getdata_request)
|
test_nodes[0].send_and_ping(getdata_request)
|
||||||
test_nodes[1].wait_for_disconnect()
|
assert_equal(len(self.nodes[0].getpeerinfo()), 1) #node is still connected because of the whitelist
|
||||||
assert_equal(len(self.nodes[0].getpeerinfo()), 3) #node is still connected because of the whitelist
|
|
||||||
|
|
||||||
self.log.info("Peer 1 still connected after trying to download old block (whitelisted)")
|
self.log.info("Peer still connected after trying to download old block (whitelisted)")
|
||||||
|
|
||||||
[c.disconnect_node() for c in connections]
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
MaxUploadTest().main()
|
MaxUploadTest().main()
|
||||||
|
@ -54,40 +54,6 @@ from test_framework.util import *
|
|||||||
import time
|
import time
|
||||||
from test_framework.blocktools import create_block, create_coinbase
|
from test_framework.blocktools import create_block, create_coinbase
|
||||||
|
|
||||||
# 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):
|
|
||||||
super().__init__()
|
|
||||||
self.connection = None
|
|
||||||
self.ping_counter = 1
|
|
||||||
self.last_pong = msg_pong()
|
|
||||||
|
|
||||||
def add_connection(self, conn):
|
|
||||||
self.connection = conn
|
|
||||||
|
|
||||||
# Track the last getdata message we receive (used in the test)
|
|
||||||
def on_getdata(self, conn, message):
|
|
||||||
self.last_getdata = message
|
|
||||||
|
|
||||||
# Spin until verack message is received from the node.
|
|
||||||
# We use this to signal that our test can begin. This
|
|
||||||
# is called from the testing thread, so it needs to acquire
|
|
||||||
# the global lock.
|
|
||||||
def wait_for_verack(self):
|
|
||||||
while True:
|
|
||||||
with mininode_lock:
|
|
||||||
if self.verack_received:
|
|
||||||
return
|
|
||||||
time.sleep(0.05)
|
|
||||||
|
|
||||||
# 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
|
|
||||||
|
|
||||||
class AcceptBlockTest(BitcoinTestFramework):
|
class AcceptBlockTest(BitcoinTestFramework):
|
||||||
def add_options(self, parser):
|
def add_options(self, parser):
|
||||||
parser.add_option("--testbinary", dest="testbinary",
|
parser.add_option("--testbinary", dest="testbinary",
|
||||||
@ -112,8 +78,8 @@ class AcceptBlockTest(BitcoinTestFramework):
|
|||||||
|
|
||||||
def run_test(self):
|
def run_test(self):
|
||||||
# Setup the p2p connections and start up the network thread.
|
# Setup the p2p connections and start up the network thread.
|
||||||
test_node = TestNode() # connects to node0 (not whitelisted)
|
test_node = NodeConnCB() # connects to node0 (not whitelisted)
|
||||||
white_node = TestNode() # connects to node1 (whitelisted)
|
white_node = NodeConnCB() # connects to node1 (whitelisted)
|
||||||
|
|
||||||
connections = []
|
connections = []
|
||||||
connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test_node))
|
connections.append(NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], test_node))
|
||||||
@ -239,12 +205,12 @@ class AcceptBlockTest(BitcoinTestFramework):
|
|||||||
# triggers a getdata on block 2 (it should if block 2 is missing).
|
# triggers a getdata on block 2 (it should if block 2 is missing).
|
||||||
with mininode_lock:
|
with mininode_lock:
|
||||||
# Clear state so we can check the getdata request
|
# Clear state so we can check the getdata request
|
||||||
test_node.last_getdata = None
|
test_node.last_message.pop("getdata", None)
|
||||||
test_node.send_message(msg_inv([CInv(2, blocks_h3[0].sha256)]))
|
test_node.send_message(msg_inv([CInv(2, blocks_h3[0].sha256)]))
|
||||||
|
|
||||||
test_node.sync_with_ping()
|
test_node.sync_with_ping()
|
||||||
with mininode_lock:
|
with mininode_lock:
|
||||||
getdata = test_node.last_getdata
|
getdata = test_node.last_message["getdata"]
|
||||||
|
|
||||||
# Check that the getdata includes the right block
|
# Check that the getdata includes the right block
|
||||||
assert_equal(getdata.inv[0].hash, blocks_h2f[0].sha256)
|
assert_equal(getdata.inv[0].hash, blocks_h2f[0].sha256)
|
||||||
|
@ -16,64 +16,31 @@ class TestNode(NodeConnCB):
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.last_sendcmpct = []
|
self.last_sendcmpct = []
|
||||||
self.last_headers = None
|
|
||||||
self.last_inv = None
|
|
||||||
self.last_cmpctblock = None
|
|
||||||
self.block_announced = False
|
self.block_announced = False
|
||||||
self.last_getdata = None
|
|
||||||
self.last_getheaders = None
|
|
||||||
self.last_getblocktxn = None
|
|
||||||
self.last_block = None
|
|
||||||
self.last_blocktxn = None
|
|
||||||
# Store the hashes of blocks we've seen announced.
|
# Store the hashes of blocks we've seen announced.
|
||||||
# This is for synchronizing the p2p message traffic,
|
# This is for synchronizing the p2p message traffic,
|
||||||
# so we can eg wait until a particular block is announced.
|
# so we can eg wait until a particular block is announced.
|
||||||
self.set_announced_blockhashes = set()
|
self.announced_blockhashes = set()
|
||||||
self.connected = False
|
|
||||||
|
|
||||||
def on_open(self, conn):
|
|
||||||
self.connected = True
|
|
||||||
|
|
||||||
def on_close(self, conn):
|
|
||||||
self.connected = False
|
|
||||||
|
|
||||||
def on_sendcmpct(self, conn, message):
|
def on_sendcmpct(self, conn, message):
|
||||||
self.last_sendcmpct.append(message)
|
self.last_sendcmpct.append(message)
|
||||||
|
|
||||||
def on_block(self, conn, message):
|
|
||||||
self.last_block = message
|
|
||||||
|
|
||||||
def on_cmpctblock(self, conn, message):
|
def on_cmpctblock(self, conn, message):
|
||||||
self.last_cmpctblock = message
|
|
||||||
self.block_announced = True
|
self.block_announced = True
|
||||||
self.last_cmpctblock.header_and_shortids.header.calc_sha256()
|
self.last_message["cmpctblock"].header_and_shortids.header.calc_sha256()
|
||||||
self.set_announced_blockhashes.add(self.last_cmpctblock.header_and_shortids.header.sha256)
|
self.announced_blockhashes.add(self.last_message["cmpctblock"].header_and_shortids.header.sha256)
|
||||||
|
|
||||||
def on_headers(self, conn, message):
|
def on_headers(self, conn, message):
|
||||||
self.last_headers = message
|
|
||||||
self.block_announced = True
|
self.block_announced = True
|
||||||
for x in self.last_headers.headers:
|
for x in self.last_message["headers"].headers:
|
||||||
x.calc_sha256()
|
x.calc_sha256()
|
||||||
self.set_announced_blockhashes.add(x.sha256)
|
self.announced_blockhashes.add(x.sha256)
|
||||||
|
|
||||||
def on_inv(self, conn, message):
|
def on_inv(self, conn, message):
|
||||||
self.last_inv = message
|
for x in self.last_message["inv"].inv:
|
||||||
for x in self.last_inv.inv:
|
|
||||||
if x.type == 2:
|
if x.type == 2:
|
||||||
self.block_announced = True
|
self.block_announced = True
|
||||||
self.set_announced_blockhashes.add(x.hash)
|
self.announced_blockhashes.add(x.hash)
|
||||||
|
|
||||||
def on_getdata(self, conn, message):
|
|
||||||
self.last_getdata = message
|
|
||||||
|
|
||||||
def on_getheaders(self, conn, message):
|
|
||||||
self.last_getheaders = message
|
|
||||||
|
|
||||||
def on_getblocktxn(self, conn, message):
|
|
||||||
self.last_getblocktxn = message
|
|
||||||
|
|
||||||
def on_blocktxn(self, conn, message):
|
|
||||||
self.last_blocktxn = message
|
|
||||||
|
|
||||||
# Requires caller to hold mininode_lock
|
# Requires caller to hold mininode_lock
|
||||||
def received_block_announcement(self):
|
def received_block_announcement(self):
|
||||||
@ -82,9 +49,9 @@ class TestNode(NodeConnCB):
|
|||||||
def clear_block_announcement(self):
|
def clear_block_announcement(self):
|
||||||
with mininode_lock:
|
with mininode_lock:
|
||||||
self.block_announced = False
|
self.block_announced = False
|
||||||
self.last_inv = None
|
self.last_message.pop("inv", None)
|
||||||
self.last_headers = None
|
self.last_message.pop("headers", None)
|
||||||
self.last_cmpctblock = None
|
self.last_message.pop("cmpctblock", None)
|
||||||
|
|
||||||
def get_headers(self, locator, hashstop):
|
def get_headers(self, locator, hashstop):
|
||||||
msg = msg_getheaders()
|
msg = msg_getheaders()
|
||||||
@ -100,15 +67,14 @@ class TestNode(NodeConnCB):
|
|||||||
def request_headers_and_sync(self, locator, hashstop=0):
|
def request_headers_and_sync(self, locator, hashstop=0):
|
||||||
self.clear_block_announcement()
|
self.clear_block_announcement()
|
||||||
self.get_headers(locator, hashstop)
|
self.get_headers(locator, hashstop)
|
||||||
assert(wait_until(self.received_block_announcement, timeout=30))
|
assert wait_until(self.received_block_announcement, timeout=30)
|
||||||
assert(self.received_block_announcement())
|
|
||||||
self.clear_block_announcement()
|
self.clear_block_announcement()
|
||||||
|
|
||||||
# Block until a block announcement for a particular block hash is
|
# Block until a block announcement for a particular block hash is
|
||||||
# received.
|
# received.
|
||||||
def wait_for_block_announcement(self, block_hash, timeout=30):
|
def wait_for_block_announcement(self, block_hash, timeout=30):
|
||||||
def received_hash():
|
def received_hash():
|
||||||
return (block_hash in self.set_announced_blockhashes)
|
return (block_hash in self.announced_blockhashes)
|
||||||
return wait_until(received_hash, timeout=timeout)
|
return wait_until(received_hash, timeout=timeout)
|
||||||
|
|
||||||
def send_await_disconnect(self, message, timeout=30):
|
def send_await_disconnect(self, message, timeout=30):
|
||||||
@ -205,14 +171,14 @@ class CompactBlocksTest(BitcoinTestFramework):
|
|||||||
with mininode_lock:
|
with mininode_lock:
|
||||||
assert predicate(peer), (
|
assert predicate(peer), (
|
||||||
"block_hash={!r}, cmpctblock={!r}, inv={!r}".format(
|
"block_hash={!r}, cmpctblock={!r}, inv={!r}".format(
|
||||||
block_hash, peer.last_cmpctblock, peer.last_inv))
|
block_hash, peer.last_message.get("cmpctblock", None), peer.last_message.get("inv", None)))
|
||||||
|
|
||||||
# We shouldn't get any block announcements via cmpctblock yet.
|
# We shouldn't get any block announcements via cmpctblock yet.
|
||||||
check_announcement_of_new_block(node, test_node, lambda p: p.last_cmpctblock is None)
|
check_announcement_of_new_block(node, test_node, lambda p: "cmpctblock" not in p.last_message)
|
||||||
|
|
||||||
# Try one more time, this time after requesting headers.
|
# Try one more time, this time after requesting headers.
|
||||||
test_node.request_headers_and_sync(locator=[tip])
|
test_node.request_headers_and_sync(locator=[tip])
|
||||||
check_announcement_of_new_block(node, test_node, lambda p: p.last_cmpctblock is None and p.last_inv is not None)
|
check_announcement_of_new_block(node, test_node, lambda p: "cmpctblock" not in p.last_message and "inv" in p.last_message)
|
||||||
|
|
||||||
# Test a few ways of using sendcmpct that should NOT
|
# Test a few ways of using sendcmpct that should NOT
|
||||||
# result in compact block announcements.
|
# result in compact block announcements.
|
||||||
@ -224,7 +190,7 @@ class CompactBlocksTest(BitcoinTestFramework):
|
|||||||
sendcmpct.version = preferred_version+1
|
sendcmpct.version = preferred_version+1
|
||||||
sendcmpct.announce = True
|
sendcmpct.announce = True
|
||||||
test_node.send_and_ping(sendcmpct)
|
test_node.send_and_ping(sendcmpct)
|
||||||
check_announcement_of_new_block(node, test_node, lambda p: p.last_cmpctblock is None)
|
check_announcement_of_new_block(node, test_node, lambda p: "cmpctblock" not in p.last_message)
|
||||||
|
|
||||||
# Headers sync before next test.
|
# Headers sync before next test.
|
||||||
test_node.request_headers_and_sync(locator=[tip])
|
test_node.request_headers_and_sync(locator=[tip])
|
||||||
@ -233,7 +199,7 @@ class CompactBlocksTest(BitcoinTestFramework):
|
|||||||
sendcmpct.version = preferred_version
|
sendcmpct.version = preferred_version
|
||||||
sendcmpct.announce = False
|
sendcmpct.announce = False
|
||||||
test_node.send_and_ping(sendcmpct)
|
test_node.send_and_ping(sendcmpct)
|
||||||
check_announcement_of_new_block(node, test_node, lambda p: p.last_cmpctblock is None)
|
check_announcement_of_new_block(node, test_node, lambda p: "cmpctblock" not in p.last_message)
|
||||||
|
|
||||||
# Headers sync before next test.
|
# Headers sync before next test.
|
||||||
test_node.request_headers_and_sync(locator=[tip])
|
test_node.request_headers_and_sync(locator=[tip])
|
||||||
@ -242,20 +208,20 @@ class CompactBlocksTest(BitcoinTestFramework):
|
|||||||
sendcmpct.version = preferred_version
|
sendcmpct.version = preferred_version
|
||||||
sendcmpct.announce = True
|
sendcmpct.announce = True
|
||||||
test_node.send_and_ping(sendcmpct)
|
test_node.send_and_ping(sendcmpct)
|
||||||
check_announcement_of_new_block(node, test_node, lambda p: p.last_cmpctblock is not None)
|
check_announcement_of_new_block(node, test_node, lambda p: "cmpctblock" in p.last_message)
|
||||||
|
|
||||||
# Try one more time (no headers sync should be needed!)
|
# Try one more time (no headers sync should be needed!)
|
||||||
check_announcement_of_new_block(node, test_node, lambda p: p.last_cmpctblock is not None)
|
check_announcement_of_new_block(node, test_node, lambda p: "cmpctblock" in p.last_message)
|
||||||
|
|
||||||
# Try one more time, after turning on sendheaders
|
# Try one more time, after turning on sendheaders
|
||||||
test_node.send_and_ping(msg_sendheaders())
|
test_node.send_and_ping(msg_sendheaders())
|
||||||
check_announcement_of_new_block(node, test_node, lambda p: p.last_cmpctblock is not None)
|
check_announcement_of_new_block(node, test_node, lambda p: "cmpctblock" in p.last_message)
|
||||||
|
|
||||||
# Now turn off announcements
|
# Now turn off announcements
|
||||||
sendcmpct.version = preferred_version
|
sendcmpct.version = preferred_version
|
||||||
sendcmpct.announce = False
|
sendcmpct.announce = False
|
||||||
test_node.send_and_ping(sendcmpct)
|
test_node.send_and_ping(sendcmpct)
|
||||||
check_announcement_of_new_block(node, test_node, lambda p: p.last_cmpctblock is None and p.last_headers is not None)
|
check_announcement_of_new_block(node, test_node, lambda p: "cmpctblock" not in p.last_message and "headers" in p.last_message)
|
||||||
|
|
||||||
# This code should be enabled after increasing cmctblk version
|
# This code should be enabled after increasing cmctblk version
|
||||||
#if old_node is not None:
|
#if old_node is not None:
|
||||||
@ -266,7 +232,7 @@ class CompactBlocksTest(BitcoinTestFramework):
|
|||||||
#old_node.send_and_ping(sendcmpct)
|
#old_node.send_and_ping(sendcmpct)
|
||||||
# Header sync
|
# Header sync
|
||||||
#old_node.request_headers_and_sync(locator=[tip])
|
#old_node.request_headers_and_sync(locator=[tip])
|
||||||
#check_announcement_of_new_block(node, old_node, lambda p: p.last_cmpctblock is not None)
|
#check_announcement_of_new_block(node, old_node, lambda p: "cmpctblock" in p.last_message)
|
||||||
|
|
||||||
# This test actually causes bitcoind to (reasonably!) disconnect us, so do this last.
|
# This test actually causes bitcoind to (reasonably!) disconnect us, so do this last.
|
||||||
def test_invalid_cmpctblock_message(self):
|
def test_invalid_cmpctblock_message(self):
|
||||||
@ -318,9 +284,9 @@ class CompactBlocksTest(BitcoinTestFramework):
|
|||||||
# Now fetch and check the compact block
|
# Now fetch and check the compact block
|
||||||
header_and_shortids = None
|
header_and_shortids = None
|
||||||
with mininode_lock:
|
with mininode_lock:
|
||||||
assert(test_node.last_cmpctblock is not None)
|
assert("cmpctblock" in test_node.last_message)
|
||||||
# Convert the on-the-wire representation to absolute indexes
|
# Convert the on-the-wire representation to absolute indexes
|
||||||
header_and_shortids = HeaderAndShortIDs(test_node.last_cmpctblock.header_and_shortids)
|
header_and_shortids = HeaderAndShortIDs(test_node.last_message["cmpctblock"].header_and_shortids)
|
||||||
self.check_compactblock_construction_from_block(version, header_and_shortids, block_hash, block)
|
self.check_compactblock_construction_from_block(version, header_and_shortids, block_hash, block)
|
||||||
|
|
||||||
# Now fetch the compact block using a normal non-announce getdata
|
# Now fetch the compact block using a normal non-announce getdata
|
||||||
@ -335,9 +301,9 @@ class CompactBlocksTest(BitcoinTestFramework):
|
|||||||
# Now fetch and check the compact block
|
# Now fetch and check the compact block
|
||||||
header_and_shortids = None
|
header_and_shortids = None
|
||||||
with mininode_lock:
|
with mininode_lock:
|
||||||
assert(test_node.last_cmpctblock is not None)
|
assert("cmpctblock" in test_node.last_message)
|
||||||
# Convert the on-the-wire representation to absolute indexes
|
# Convert the on-the-wire representation to absolute indexes
|
||||||
header_and_shortids = HeaderAndShortIDs(test_node.last_cmpctblock.header_and_shortids)
|
header_and_shortids = HeaderAndShortIDs(test_node.last_message["cmpctblock"].header_and_shortids)
|
||||||
self.check_compactblock_construction_from_block(version, header_and_shortids, block_hash, block)
|
self.check_compactblock_construction_from_block(version, header_and_shortids, block_hash, block)
|
||||||
|
|
||||||
def check_compactblock_construction_from_block(self, version, header_and_shortids, block_hash, block):
|
def check_compactblock_construction_from_block(self, version, header_and_shortids, block_hash, block):
|
||||||
@ -384,20 +350,20 @@ class CompactBlocksTest(BitcoinTestFramework):
|
|||||||
for announce in ["inv", "header"]:
|
for announce in ["inv", "header"]:
|
||||||
block = self.build_block_on_tip(node)
|
block = self.build_block_on_tip(node)
|
||||||
with mininode_lock:
|
with mininode_lock:
|
||||||
test_node.last_getdata = None
|
test_node.last_message.pop("getdata", None)
|
||||||
|
|
||||||
if announce == "inv":
|
if announce == "inv":
|
||||||
test_node.send_message(msg_inv([CInv(2, block.sha256)]))
|
test_node.send_message(msg_inv([CInv(2, block.sha256)]))
|
||||||
success = wait_until(lambda: test_node.last_getheaders is not None, timeout=30)
|
success = wait_until(lambda: "getheaders" in test_node.last_message, timeout=30)
|
||||||
assert(success)
|
assert(success)
|
||||||
test_node.send_header_for_blocks([block])
|
test_node.send_header_for_blocks([block])
|
||||||
else:
|
else:
|
||||||
test_node.send_header_for_blocks([block])
|
test_node.send_header_for_blocks([block])
|
||||||
success = wait_until(lambda: test_node.last_getdata is not None, timeout=30)
|
success = wait_until(lambda: "getdata" in test_node.last_message, timeout=30)
|
||||||
assert(success)
|
assert(success)
|
||||||
assert_equal(len(test_node.last_getdata.inv), 1)
|
assert_equal(len(test_node.last_message["getdata"].inv), 1)
|
||||||
assert_equal(test_node.last_getdata.inv[0].type, 20)
|
assert_equal(test_node.last_message["getdata"].inv[0].type, 20)
|
||||||
assert_equal(test_node.last_getdata.inv[0].hash, block.sha256)
|
assert_equal(test_node.last_message["getdata"].inv[0].hash, block.sha256)
|
||||||
|
|
||||||
# Send back a compactblock message that omits the coinbase
|
# Send back a compactblock message that omits the coinbase
|
||||||
comp_block = HeaderAndShortIDs()
|
comp_block = HeaderAndShortIDs()
|
||||||
@ -410,8 +376,8 @@ class CompactBlocksTest(BitcoinTestFramework):
|
|||||||
assert_equal(int(node.getbestblockhash(), 16), block.hashPrevBlock)
|
assert_equal(int(node.getbestblockhash(), 16), block.hashPrevBlock)
|
||||||
# Expect a getblocktxn message.
|
# Expect a getblocktxn message.
|
||||||
with mininode_lock:
|
with mininode_lock:
|
||||||
assert(test_node.last_getblocktxn is not None)
|
assert("getblocktxn" in test_node.last_message)
|
||||||
absolute_indexes = test_node.last_getblocktxn.block_txn_request.to_absolute()
|
absolute_indexes = test_node.last_message["getblocktxn"].block_txn_request.to_absolute()
|
||||||
assert_equal(absolute_indexes, [0]) # should be a coinbase request
|
assert_equal(absolute_indexes, [0]) # should be a coinbase request
|
||||||
|
|
||||||
# Send the coinbase, and verify that the tip advances.
|
# Send the coinbase, and verify that the tip advances.
|
||||||
@ -446,8 +412,8 @@ class CompactBlocksTest(BitcoinTestFramework):
|
|||||||
msg = msg_cmpctblock(compact_block.to_p2p())
|
msg = msg_cmpctblock(compact_block.to_p2p())
|
||||||
peer.send_and_ping(msg)
|
peer.send_and_ping(msg)
|
||||||
with mininode_lock:
|
with mininode_lock:
|
||||||
assert(peer.last_getblocktxn is not None)
|
assert("getblocktxn" in peer.last_message)
|
||||||
absolute_indexes = peer.last_getblocktxn.block_txn_request.to_absolute()
|
absolute_indexes = peer.last_message["getblocktxn"].block_txn_request.to_absolute()
|
||||||
assert_equal(absolute_indexes, expected_result)
|
assert_equal(absolute_indexes, expected_result)
|
||||||
|
|
||||||
def test_tip_after_message(node, peer, msg, tip):
|
def test_tip_after_message(node, peer, msg, tip):
|
||||||
@ -509,14 +475,14 @@ class CompactBlocksTest(BitcoinTestFramework):
|
|||||||
|
|
||||||
# Clear out last request.
|
# Clear out last request.
|
||||||
with mininode_lock:
|
with mininode_lock:
|
||||||
test_node.last_getblocktxn = None
|
test_node.last_message.pop("getblocktxn", None)
|
||||||
|
|
||||||
# Send compact block
|
# Send compact block
|
||||||
comp_block.initialize_from_block(block, prefill_list=[0])
|
comp_block.initialize_from_block(block, prefill_list=[0])
|
||||||
test_tip_after_message(node, test_node, msg_cmpctblock(comp_block.to_p2p()), block.sha256)
|
test_tip_after_message(node, test_node, msg_cmpctblock(comp_block.to_p2p()), block.sha256)
|
||||||
with mininode_lock:
|
with mininode_lock:
|
||||||
# Shouldn't have gotten a request for any transaction
|
# Shouldn't have gotten a request for any transaction
|
||||||
assert(test_node.last_getblocktxn is None)
|
assert("getblocktxn" not in test_node.last_message)
|
||||||
|
|
||||||
# Incorrectly responding to a getblocktxn shouldn't cause the block to be
|
# Incorrectly responding to a getblocktxn shouldn't cause the block to be
|
||||||
# permanently failed.
|
# permanently failed.
|
||||||
@ -542,8 +508,8 @@ class CompactBlocksTest(BitcoinTestFramework):
|
|||||||
test_node.send_and_ping(msg_cmpctblock(comp_block.to_p2p()))
|
test_node.send_and_ping(msg_cmpctblock(comp_block.to_p2p()))
|
||||||
absolute_indexes = []
|
absolute_indexes = []
|
||||||
with mininode_lock:
|
with mininode_lock:
|
||||||
assert(test_node.last_getblocktxn is not None)
|
assert("getblocktxn" in test_node.last_message)
|
||||||
absolute_indexes = test_node.last_getblocktxn.block_txn_request.to_absolute()
|
absolute_indexes = test_node.last_message["getblocktxn"].block_txn_request.to_absolute()
|
||||||
assert_equal(absolute_indexes, [6, 7, 8, 9, 10])
|
assert_equal(absolute_indexes, [6, 7, 8, 9, 10])
|
||||||
|
|
||||||
# Now give an incorrect response.
|
# Now give an incorrect response.
|
||||||
@ -562,11 +528,11 @@ class CompactBlocksTest(BitcoinTestFramework):
|
|||||||
assert_equal(int(node.getbestblockhash(), 16), block.hashPrevBlock)
|
assert_equal(int(node.getbestblockhash(), 16), block.hashPrevBlock)
|
||||||
|
|
||||||
# We should receive a getdata request
|
# We should receive a getdata request
|
||||||
success = wait_until(lambda: test_node.last_getdata is not None, timeout=10)
|
success = wait_until(lambda: "getdata" in test_node.last_message, timeout=10)
|
||||||
assert(success)
|
assert(success)
|
||||||
assert_equal(len(test_node.last_getdata.inv), 1)
|
assert_equal(len(test_node.last_message["getdata"].inv), 1)
|
||||||
assert(test_node.last_getdata.inv[0].type == 2)
|
assert(test_node.last_message["getdata"].inv[0].type == 2)
|
||||||
assert_equal(test_node.last_getdata.inv[0].hash, block.sha256)
|
assert_equal(test_node.last_message["getdata"].inv[0].hash, block.sha256)
|
||||||
|
|
||||||
# Deliver the block
|
# Deliver the block
|
||||||
test_node.send_and_ping(msg_block(block))
|
test_node.send_and_ping(msg_block(block))
|
||||||
@ -587,18 +553,18 @@ class CompactBlocksTest(BitcoinTestFramework):
|
|||||||
num_to_request = random.randint(1, len(block.vtx))
|
num_to_request = random.randint(1, len(block.vtx))
|
||||||
msg.block_txn_request.from_absolute(sorted(random.sample(range(len(block.vtx)), num_to_request)))
|
msg.block_txn_request.from_absolute(sorted(random.sample(range(len(block.vtx)), num_to_request)))
|
||||||
test_node.send_message(msg)
|
test_node.send_message(msg)
|
||||||
success = wait_until(lambda: test_node.last_blocktxn is not None, timeout=10)
|
success = wait_until(lambda: "blocktxn" in test_node.last_message, timeout=10)
|
||||||
assert(success)
|
assert(success)
|
||||||
|
|
||||||
[tx.calc_sha256() for tx in block.vtx]
|
[tx.calc_sha256() for tx in block.vtx]
|
||||||
with mininode_lock:
|
with mininode_lock:
|
||||||
assert_equal(test_node.last_blocktxn.block_transactions.blockhash, int(block_hash, 16))
|
assert_equal(test_node.last_message["blocktxn"].block_transactions.blockhash, int(block_hash, 16))
|
||||||
all_indices = msg.block_txn_request.to_absolute()
|
all_indices = msg.block_txn_request.to_absolute()
|
||||||
for index in all_indices:
|
for index in all_indices:
|
||||||
tx = test_node.last_blocktxn.block_transactions.transactions.pop(0)
|
tx = test_node.last_message["blocktxn"].block_transactions.transactions.pop(0)
|
||||||
tx.calc_sha256()
|
tx.calc_sha256()
|
||||||
assert_equal(tx.sha256, block.vtx[index].sha256)
|
assert_equal(tx.sha256, block.vtx[index].sha256)
|
||||||
test_node.last_blocktxn = None
|
test_node.last_message.pop("blocktxn", None)
|
||||||
current_height -= 1
|
current_height -= 1
|
||||||
|
|
||||||
# Next request should send a full block response, as we're past the
|
# Next request should send a full block response, as we're past the
|
||||||
@ -606,13 +572,13 @@ class CompactBlocksTest(BitcoinTestFramework):
|
|||||||
block_hash = node.getblockhash(current_height)
|
block_hash = node.getblockhash(current_height)
|
||||||
msg.block_txn_request = BlockTransactionsRequest(int(block_hash, 16), [0])
|
msg.block_txn_request = BlockTransactionsRequest(int(block_hash, 16), [0])
|
||||||
with mininode_lock:
|
with mininode_lock:
|
||||||
test_node.last_block = None
|
test_node.last_message.pop("block", None)
|
||||||
test_node.last_blocktxn = None
|
test_node.last_message.pop("blocktxn", None)
|
||||||
test_node.send_and_ping(msg)
|
test_node.send_and_ping(msg)
|
||||||
with mininode_lock:
|
with mininode_lock:
|
||||||
test_node.last_block.block.calc_sha256()
|
test_node.last_message["block"].block.calc_sha256()
|
||||||
assert_equal(test_node.last_block.block.sha256, int(block_hash, 16))
|
assert_equal(test_node.last_message["block"].block.sha256, int(block_hash, 16))
|
||||||
assert_equal(test_node.last_blocktxn, None)
|
assert "blocktxn" not in test_node.last_message
|
||||||
|
|
||||||
def test_compactblocks_not_at_tip(self, node, test_node):
|
def test_compactblocks_not_at_tip(self, node, test_node):
|
||||||
# Test that requesting old compactblocks doesn't work.
|
# Test that requesting old compactblocks doesn't work.
|
||||||
@ -625,7 +591,7 @@ class CompactBlocksTest(BitcoinTestFramework):
|
|||||||
|
|
||||||
test_node.clear_block_announcement()
|
test_node.clear_block_announcement()
|
||||||
test_node.send_message(msg_getdata([CInv(20, int(new_blocks[0], 16))]))
|
test_node.send_message(msg_getdata([CInv(20, int(new_blocks[0], 16))]))
|
||||||
success = wait_until(lambda: test_node.last_cmpctblock is not None, timeout=30)
|
success = wait_until(lambda: "cmpctblock" in test_node.last_message, timeout=30)
|
||||||
assert(success)
|
assert(success)
|
||||||
|
|
||||||
test_node.clear_block_announcement()
|
test_node.clear_block_announcement()
|
||||||
@ -633,13 +599,13 @@ class CompactBlocksTest(BitcoinTestFramework):
|
|||||||
wait_until(test_node.received_block_announcement, timeout=30)
|
wait_until(test_node.received_block_announcement, timeout=30)
|
||||||
test_node.clear_block_announcement()
|
test_node.clear_block_announcement()
|
||||||
with mininode_lock:
|
with mininode_lock:
|
||||||
test_node.last_block = None
|
test_node.last_message.pop("block", None)
|
||||||
test_node.send_message(msg_getdata([CInv(20, int(new_blocks[0], 16))]))
|
test_node.send_message(msg_getdata([CInv(20, int(new_blocks[0], 16))]))
|
||||||
success = wait_until(lambda: test_node.last_block is not None, timeout=30)
|
success = wait_until(lambda: "block" in test_node.last_message, timeout=30)
|
||||||
assert(success)
|
assert(success)
|
||||||
with mininode_lock:
|
with mininode_lock:
|
||||||
test_node.last_block.block.calc_sha256()
|
test_node.last_message["block"].block.calc_sha256()
|
||||||
assert_equal(test_node.last_block.block.sha256, int(new_blocks[0], 16))
|
assert_equal(test_node.last_message["block"].block.sha256, int(new_blocks[0], 16))
|
||||||
|
|
||||||
# Generate an old compactblock, and verify that it's not accepted.
|
# Generate an old compactblock, and verify that it's not accepted.
|
||||||
cur_height = node.getblockcount()
|
cur_height = node.getblockcount()
|
||||||
@ -666,10 +632,10 @@ class CompactBlocksTest(BitcoinTestFramework):
|
|||||||
msg = msg_getblocktxn()
|
msg = msg_getblocktxn()
|
||||||
msg.block_txn_request = BlockTransactionsRequest(block.sha256, [0])
|
msg.block_txn_request = BlockTransactionsRequest(block.sha256, [0])
|
||||||
with mininode_lock:
|
with mininode_lock:
|
||||||
test_node.last_blocktxn = None
|
test_node.last_message.pop("blocktxn", None)
|
||||||
test_node.send_and_ping(msg)
|
test_node.send_and_ping(msg)
|
||||||
with mininode_lock:
|
with mininode_lock:
|
||||||
assert(test_node.last_blocktxn is None)
|
assert "blocktxn" not in test_node.last_message
|
||||||
|
|
||||||
def test_end_to_end_block_relay(self, node, listeners):
|
def test_end_to_end_block_relay(self, node, listeners):
|
||||||
utxo = self.utxos.pop(0)
|
utxo = self.utxos.pop(0)
|
||||||
@ -684,9 +650,9 @@ class CompactBlocksTest(BitcoinTestFramework):
|
|||||||
wait_until(lambda: l.received_block_announcement(), timeout=30)
|
wait_until(lambda: l.received_block_announcement(), timeout=30)
|
||||||
with mininode_lock:
|
with mininode_lock:
|
||||||
for l in listeners:
|
for l in listeners:
|
||||||
assert(l.last_cmpctblock is not None)
|
assert "cmpctblock" in l.last_message
|
||||||
l.last_cmpctblock.header_and_shortids.header.calc_sha256()
|
l.last_message["cmpctblock"].header_and_shortids.header.calc_sha256()
|
||||||
assert_equal(l.last_cmpctblock.header_and_shortids.header.sha256, block.sha256)
|
assert_equal(l.last_message["cmpctblock"].header_and_shortids.header.sha256, block.sha256)
|
||||||
|
|
||||||
# Test that we don't get disconnected if we relay a compact block with valid header,
|
# Test that we don't get disconnected if we relay a compact block with valid header,
|
||||||
# but invalid transactions.
|
# but invalid transactions.
|
||||||
@ -733,7 +699,7 @@ class CompactBlocksTest(BitcoinTestFramework):
|
|||||||
msg = msg_cmpctblock(cmpct_block.to_p2p())
|
msg = msg_cmpctblock(cmpct_block.to_p2p())
|
||||||
peer.send_and_ping(msg)
|
peer.send_and_ping(msg)
|
||||||
with mininode_lock:
|
with mininode_lock:
|
||||||
assert(peer.last_getblocktxn is not None)
|
assert "getblocktxn" in peer.last_message
|
||||||
return block, cmpct_block
|
return block, cmpct_block
|
||||||
|
|
||||||
block, cmpct_block = announce_cmpct_block(node, stalling_peer)
|
block, cmpct_block = announce_cmpct_block(node, stalling_peer)
|
||||||
|
@ -20,15 +20,8 @@ banscore = 10
|
|||||||
class CLazyNode(NodeConnCB):
|
class CLazyNode(NodeConnCB):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.connection = None
|
|
||||||
self.unexpected_msg = False
|
self.unexpected_msg = False
|
||||||
self.connected = False
|
self.ever_connected = False
|
||||||
|
|
||||||
def add_connection(self, conn):
|
|
||||||
self.connection = conn
|
|
||||||
|
|
||||||
def send_message(self, message):
|
|
||||||
self.connection.send_message(message)
|
|
||||||
|
|
||||||
def bad_message(self, message):
|
def bad_message(self, message):
|
||||||
self.unexpected_msg = True
|
self.unexpected_msg = True
|
||||||
@ -36,6 +29,7 @@ class CLazyNode(NodeConnCB):
|
|||||||
|
|
||||||
def on_open(self, conn):
|
def on_open(self, conn):
|
||||||
self.connected = True
|
self.connected = True
|
||||||
|
self.ever_connected = True
|
||||||
|
|
||||||
def on_version(self, conn, message): self.bad_message(message)
|
def on_version(self, conn, message): self.bad_message(message)
|
||||||
def on_verack(self, conn, message): self.bad_message(message)
|
def on_verack(self, conn, message): self.bad_message(message)
|
||||||
@ -62,9 +56,6 @@ class CLazyNode(NodeConnCB):
|
|||||||
# Node that never sends a version. We'll use this to send a bunch of messages
|
# Node that never sends a version. We'll use this to send a bunch of messages
|
||||||
# anyway, and eventually get disconnected.
|
# anyway, and eventually get disconnected.
|
||||||
class CNodeNoVersionBan(CLazyNode):
|
class CNodeNoVersionBan(CLazyNode):
|
||||||
def __init__(self):
|
|
||||||
super().__init__()
|
|
||||||
|
|
||||||
# send a bunch of veracks without sending a message. This should get us disconnected.
|
# send a bunch of veracks without sending a message. This should get us disconnected.
|
||||||
# NOTE: implementation-specific check here. Remove if bitcoind ban behavior changes
|
# NOTE: implementation-specific check here. Remove if bitcoind ban behavior changes
|
||||||
def on_open(self, conn):
|
def on_open(self, conn):
|
||||||
@ -120,7 +111,9 @@ class P2PLeakTest(BitcoinTestFramework):
|
|||||||
|
|
||||||
NetworkThread().start() # Start up network handling in another thread
|
NetworkThread().start() # Start up network handling in another thread
|
||||||
|
|
||||||
assert(wait_until(lambda: no_version_bannode.connected and no_version_idlenode.connected and no_verack_idlenode.version_received, timeout=10))
|
assert wait_until(lambda: no_version_bannode.ever_connected, timeout=10)
|
||||||
|
assert wait_until(lambda: no_version_idlenode.ever_connected, timeout=10)
|
||||||
|
assert wait_until(lambda: no_verack_idlenode.version_received, timeout=10)
|
||||||
|
|
||||||
# Mine a block and make sure that it's not sent to the connected nodes
|
# Mine a block and make sure that it's not sent to the connected nodes
|
||||||
self.nodes[0].generate(1)
|
self.nodes[0].generate(1)
|
||||||
@ -129,7 +122,7 @@ class P2PLeakTest(BitcoinTestFramework):
|
|||||||
time.sleep(5)
|
time.sleep(5)
|
||||||
|
|
||||||
#This node should have been banned
|
#This node should have been banned
|
||||||
assert(no_version_bannode.connection.state == "closed")
|
assert not no_version_bannode.connected
|
||||||
|
|
||||||
[conn.disconnect_node() for conn in connections]
|
[conn.disconnect_node() for conn in connections]
|
||||||
|
|
||||||
|
@ -12,60 +12,6 @@ from test_framework.mininode import *
|
|||||||
from test_framework.test_framework import BitcoinTestFramework
|
from test_framework.test_framework import BitcoinTestFramework
|
||||||
from test_framework.util import *
|
from test_framework.util import *
|
||||||
|
|
||||||
class TestNode(NodeConnCB):
|
|
||||||
def __init__(self):
|
|
||||||
super().__init__()
|
|
||||||
self.connection = None
|
|
||||||
self.ping_counter = 1
|
|
||||||
self.last_pong = msg_pong()
|
|
||||||
self.block_receive_map = {}
|
|
||||||
|
|
||||||
def add_connection(self, conn):
|
|
||||||
self.connection = conn
|
|
||||||
self.peer_disconnected = False
|
|
||||||
|
|
||||||
def on_inv(self, conn, message):
|
|
||||||
pass
|
|
||||||
|
|
||||||
# Track the last getdata message we receive (used in the test)
|
|
||||||
def on_getdata(self, conn, message):
|
|
||||||
self.last_getdata = message
|
|
||||||
|
|
||||||
def on_block(self, conn, message):
|
|
||||||
message.block.calc_sha256()
|
|
||||||
try:
|
|
||||||
self.block_receive_map[message.block.sha256] += 1
|
|
||||||
except KeyError as e:
|
|
||||||
self.block_receive_map[message.block.sha256] = 1
|
|
||||||
|
|
||||||
# Spin until verack message is received from the node.
|
|
||||||
# We use this to signal that our test can begin. This
|
|
||||||
# is called from the testing thread, so it needs to acquire
|
|
||||||
# the global lock.
|
|
||||||
def wait_for_verack(self):
|
|
||||||
def veracked():
|
|
||||||
return self.verack_received
|
|
||||||
return wait_until(veracked, timeout=10)
|
|
||||||
|
|
||||||
def wait_for_disconnect(self):
|
|
||||||
def disconnected():
|
|
||||||
return self.peer_disconnected
|
|
||||||
return wait_until(disconnected, timeout=10)
|
|
||||||
|
|
||||||
# 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
|
|
||||||
|
|
||||||
def on_close(self, conn):
|
|
||||||
self.peer_disconnected = True
|
|
||||||
|
|
||||||
def send_mempool(self):
|
|
||||||
self.lastInv = []
|
|
||||||
self.send_message(msg_mempool())
|
|
||||||
|
|
||||||
class P2PMempoolTests(BitcoinTestFramework):
|
class P2PMempoolTests(BitcoinTestFramework):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@ -74,20 +20,18 @@ class P2PMempoolTests(BitcoinTestFramework):
|
|||||||
self.num_nodes = 2
|
self.num_nodes = 2
|
||||||
|
|
||||||
def setup_network(self):
|
def setup_network(self):
|
||||||
# Start a node with maxuploadtarget of 200 MB (/24h)
|
self.nodes = [start_node(0, self.options.tmpdir, ["-peerbloomfilters=0"])]
|
||||||
self.nodes = []
|
|
||||||
self.nodes.append(start_node(0, self.options.tmpdir, ["-peerbloomfilters=0"]))
|
|
||||||
|
|
||||||
def run_test(self):
|
def run_test(self):
|
||||||
#connect a mininode
|
#connect a mininode
|
||||||
aTestNode = TestNode()
|
aTestNode = NodeConnCB()
|
||||||
node = NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], aTestNode)
|
node = NodeConn('127.0.0.1', p2p_port(0), self.nodes[0], aTestNode)
|
||||||
aTestNode.add_connection(node)
|
aTestNode.add_connection(node)
|
||||||
NetworkThread().start()
|
NetworkThread().start()
|
||||||
aTestNode.wait_for_verack()
|
aTestNode.wait_for_verack()
|
||||||
|
|
||||||
#request mempool
|
#request mempool
|
||||||
aTestNode.send_mempool()
|
aTestNode.send_message(msg_mempool())
|
||||||
aTestNode.wait_for_disconnect()
|
aTestNode.wait_for_disconnect()
|
||||||
|
|
||||||
#mininode must be disconnected at this point
|
#mininode must be disconnected at this point
|
||||||
|
@ -28,20 +28,9 @@ from test_framework.test_framework import BitcoinTestFramework
|
|||||||
from test_framework.util import *
|
from test_framework.util import *
|
||||||
|
|
||||||
class TestNode(NodeConnCB):
|
class TestNode(NodeConnCB):
|
||||||
def __init__(self):
|
|
||||||
super().__init__()
|
|
||||||
self.connected = False
|
|
||||||
self.received_version = False
|
|
||||||
|
|
||||||
def on_open(self, conn):
|
|
||||||
self.connected = True
|
|
||||||
|
|
||||||
def on_close(self, conn):
|
|
||||||
self.connected = False
|
|
||||||
|
|
||||||
def on_version(self, conn, message):
|
def on_version(self, conn, message):
|
||||||
# Don't send a verack in response
|
# Don't send a verack in response
|
||||||
self.received_version = True
|
pass
|
||||||
|
|
||||||
class TimeoutsTest(BitcoinTestFramework):
|
class TimeoutsTest(BitcoinTestFramework):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@ -83,7 +72,7 @@ class TimeoutsTest(BitcoinTestFramework):
|
|||||||
|
|
||||||
sleep(30)
|
sleep(30)
|
||||||
|
|
||||||
assert(self.no_verack_node.received_version)
|
assert "version" in self.no_verack_node.last_message
|
||||||
|
|
||||||
assert(self.no_verack_node.connected)
|
assert(self.no_verack_node.connected)
|
||||||
assert(self.no_version_node.connected)
|
assert(self.no_version_node.connected)
|
||||||
|
@ -24,28 +24,10 @@ WARN_UNKNOWN_RULES_MINED = "Unknown block versions being mined! It's possible un
|
|||||||
WARN_UNKNOWN_RULES_ACTIVE = "unknown new rules activated (versionbit {})".format(VB_UNKNOWN_BIT)
|
WARN_UNKNOWN_RULES_ACTIVE = "unknown new rules activated (versionbit {})".format(VB_UNKNOWN_BIT)
|
||||||
VB_PATTERN = re.compile("^Warning.*versionbit")
|
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):
|
class TestNode(NodeConnCB):
|
||||||
def __init__(self):
|
|
||||||
super().__init__()
|
|
||||||
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):
|
def on_inv(self, conn, message):
|
||||||
pass
|
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
|
|
||||||
|
|
||||||
class VersionBitsWarningTest(BitcoinTestFramework):
|
class VersionBitsWarningTest(BitcoinTestFramework):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
@ -92,23 +92,17 @@ from test_framework.blocktools import create_block, create_coinbase
|
|||||||
|
|
||||||
direct_fetch_response_time = 0.05
|
direct_fetch_response_time = 0.05
|
||||||
|
|
||||||
class BaseNode(NodeConnCB):
|
class TestNode(NodeConnCB):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.last_inv = None
|
|
||||||
self.last_headers = None
|
|
||||||
self.last_block = None
|
|
||||||
self.last_getdata = None
|
|
||||||
self.block_announced = False
|
self.block_announced = False
|
||||||
self.last_getheaders = None
|
|
||||||
self.disconnected = False
|
|
||||||
self.last_blockhash_announced = None
|
self.last_blockhash_announced = None
|
||||||
|
|
||||||
def clear_last_announcement(self):
|
def clear_last_announcement(self):
|
||||||
with mininode_lock:
|
with mininode_lock:
|
||||||
self.block_announced = False
|
self.block_announced = False
|
||||||
self.last_inv = None
|
self.last_message.pop("inv", None)
|
||||||
self.last_headers = None
|
self.last_message.pop("headers", None)
|
||||||
|
|
||||||
# Request data for a list of block hashes
|
# Request data for a list of block hashes
|
||||||
def get_data(self, block_hashes):
|
def get_data(self, block_hashes):
|
||||||
@ -129,29 +123,17 @@ class BaseNode(NodeConnCB):
|
|||||||
self.connection.send_message(msg)
|
self.connection.send_message(msg)
|
||||||
|
|
||||||
def on_inv(self, conn, message):
|
def on_inv(self, conn, message):
|
||||||
self.last_inv = message
|
|
||||||
self.block_announced = True
|
self.block_announced = True
|
||||||
self.last_blockhash_announced = message.inv[-1].hash
|
self.last_blockhash_announced = message.inv[-1].hash
|
||||||
|
|
||||||
def on_headers(self, conn, message):
|
def on_headers(self, conn, message):
|
||||||
self.last_headers = message
|
|
||||||
if len(message.headers):
|
if len(message.headers):
|
||||||
self.block_announced = True
|
self.block_announced = True
|
||||||
message.headers[-1].calc_sha256()
|
message.headers[-1].calc_sha256()
|
||||||
self.last_blockhash_announced = message.headers[-1].sha256
|
self.last_blockhash_announced = message.headers[-1].sha256
|
||||||
|
|
||||||
def on_block(self, conn, message):
|
def on_block(self, conn, message):
|
||||||
self.last_block = message.block
|
self.last_message["block"].calc_sha256()
|
||||||
self.last_block.calc_sha256()
|
|
||||||
|
|
||||||
def on_getdata(self, conn, message):
|
|
||||||
self.last_getdata = message
|
|
||||||
|
|
||||||
def on_getheaders(self, conn, message):
|
|
||||||
self.last_getheaders = message
|
|
||||||
|
|
||||||
def on_close(self, conn):
|
|
||||||
self.disconnected = True
|
|
||||||
|
|
||||||
# Test whether the last announcement we received had the
|
# Test whether the last announcement we received had the
|
||||||
# right header or the right inv
|
# right header or the right inv
|
||||||
@ -166,43 +148,27 @@ class BaseNode(NodeConnCB):
|
|||||||
|
|
||||||
success = True
|
success = True
|
||||||
compare_inv = []
|
compare_inv = []
|
||||||
if self.last_inv != None:
|
if "inv" in self.last_message:
|
||||||
compare_inv = [x.hash for x in self.last_inv.inv]
|
compare_inv = [x.hash for x in self.last_message["inv"].inv]
|
||||||
if compare_inv != expect_inv:
|
if compare_inv != expect_inv:
|
||||||
success = False
|
success = False
|
||||||
|
|
||||||
hash_headers = []
|
hash_headers = []
|
||||||
if self.last_headers != None:
|
if "headers" in self.last_message:
|
||||||
# treat headers as a list of block hashes
|
# treat headers as a list of block hashes
|
||||||
hash_headers = [ x.sha256 for x in self.last_headers.headers ]
|
hash_headers = [ x.sha256 for x in self.last_message["headers"].headers ]
|
||||||
if hash_headers != expect_headers:
|
if hash_headers != expect_headers:
|
||||||
success = False
|
success = False
|
||||||
|
|
||||||
self.last_inv = None
|
self.last_message.pop("inv", None)
|
||||||
self.last_headers = None
|
self.last_message.pop("headers", None)
|
||||||
return success
|
return success
|
||||||
|
|
||||||
# Syncing helpers
|
|
||||||
def wait_for_block(self, blockhash, timeout=60):
|
|
||||||
test_function = lambda: self.last_block != None and self.last_block.sha256 == blockhash
|
|
||||||
assert(wait_until(test_function, timeout=timeout))
|
|
||||||
return
|
|
||||||
|
|
||||||
def wait_for_getheaders(self, timeout=60):
|
|
||||||
test_function = lambda: self.last_getheaders != None
|
|
||||||
assert(wait_until(test_function, timeout=timeout))
|
|
||||||
return
|
|
||||||
|
|
||||||
def wait_for_getdata(self, hash_list, timeout=60):
|
def wait_for_getdata(self, hash_list, timeout=60):
|
||||||
if hash_list == []:
|
if hash_list == []:
|
||||||
return
|
return
|
||||||
|
|
||||||
test_function = lambda: self.last_getdata != None and [x.hash for x in self.last_getdata.inv] == hash_list
|
test_function = lambda: "getdata" in self.last_message and [x.hash for x in self.last_message["getdata"].inv] == hash_list
|
||||||
assert(wait_until(test_function, timeout=timeout))
|
|
||||||
return
|
|
||||||
|
|
||||||
def wait_for_disconnect(self, timeout=60):
|
|
||||||
test_function = lambda: self.disconnected
|
|
||||||
assert(wait_until(test_function, timeout=timeout))
|
assert(wait_until(test_function, timeout=timeout))
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -221,17 +187,6 @@ class BaseNode(NodeConnCB):
|
|||||||
getblocks_message.locator.vHave = locator
|
getblocks_message.locator.vHave = locator
|
||||||
self.send_message(getblocks_message)
|
self.send_message(getblocks_message)
|
||||||
|
|
||||||
# InvNode: This peer should only ever receive inv's, because it doesn't ever send a
|
|
||||||
# "sendheaders" message.
|
|
||||||
class InvNode(BaseNode):
|
|
||||||
def __init__(self):
|
|
||||||
BaseNode.__init__(self)
|
|
||||||
|
|
||||||
# TestNode: This peer is the one we use for most of the testing.
|
|
||||||
class TestNode(BaseNode):
|
|
||||||
def __init__(self):
|
|
||||||
BaseNode.__init__(self)
|
|
||||||
|
|
||||||
class SendHeadersTest(BitcoinTestFramework):
|
class SendHeadersTest(BitcoinTestFramework):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
@ -271,7 +226,7 @@ class SendHeadersTest(BitcoinTestFramework):
|
|||||||
|
|
||||||
def run_test(self):
|
def run_test(self):
|
||||||
# Setup the p2p connections and start up the network thread.
|
# Setup the p2p connections and start up the network thread.
|
||||||
inv_node = InvNode()
|
inv_node = TestNode()
|
||||||
test_node = TestNode()
|
test_node = TestNode()
|
||||||
|
|
||||||
self.p2p_connections = [inv_node, test_node]
|
self.p2p_connections = [inv_node, test_node]
|
||||||
@ -407,8 +362,8 @@ class SendHeadersTest(BitcoinTestFramework):
|
|||||||
inv_node.sync_with_ping()
|
inv_node.sync_with_ping()
|
||||||
# This block should not be announced to the inv node (since it also
|
# This block should not be announced to the inv node (since it also
|
||||||
# broadcast it)
|
# broadcast it)
|
||||||
assert_equal(inv_node.last_inv, None)
|
assert "inv" not in inv_node.last_message
|
||||||
assert_equal(inv_node.last_headers, None)
|
assert "headers" not in inv_node.last_message
|
||||||
tip = self.mine_blocks(1)
|
tip = self.mine_blocks(1)
|
||||||
assert_equal(inv_node.check_last_announcement(inv=[tip]), True)
|
assert_equal(inv_node.check_last_announcement(inv=[tip]), True)
|
||||||
assert_equal(test_node.check_last_announcement(headers=[tip]), True)
|
assert_equal(test_node.check_last_announcement(headers=[tip]), True)
|
||||||
@ -498,12 +453,12 @@ class SendHeadersTest(BitcoinTestFramework):
|
|||||||
inv_node.send_message(msg_block(blocks[-1]))
|
inv_node.send_message(msg_block(blocks[-1]))
|
||||||
|
|
||||||
inv_node.sync_with_ping() # Make sure blocks are processed
|
inv_node.sync_with_ping() # Make sure blocks are processed
|
||||||
test_node.last_getdata = None
|
test_node.last_message.pop("getdata", None)
|
||||||
test_node.send_header_for_blocks(blocks)
|
test_node.send_header_for_blocks(blocks)
|
||||||
test_node.sync_with_ping()
|
test_node.sync_with_ping()
|
||||||
# should not have received any getdata messages
|
# should not have received any getdata messages
|
||||||
with mininode_lock:
|
with mininode_lock:
|
||||||
assert_equal(test_node.last_getdata, None)
|
assert "getdata" not in test_node.last_message
|
||||||
|
|
||||||
# This time, direct fetch should work
|
# This time, direct fetch should work
|
||||||
blocks = []
|
blocks = []
|
||||||
@ -537,11 +492,11 @@ class SendHeadersTest(BitcoinTestFramework):
|
|||||||
|
|
||||||
# Announcing one block on fork should not trigger direct fetch
|
# Announcing one block on fork should not trigger direct fetch
|
||||||
# (less work than tip)
|
# (less work than tip)
|
||||||
test_node.last_getdata = None
|
test_node.last_message.pop("getdata", None)
|
||||||
test_node.send_header_for_blocks(blocks[0:1])
|
test_node.send_header_for_blocks(blocks[0:1])
|
||||||
test_node.sync_with_ping()
|
test_node.sync_with_ping()
|
||||||
with mininode_lock:
|
with mininode_lock:
|
||||||
assert_equal(test_node.last_getdata, None)
|
assert "getdata" not in test_node.last_message
|
||||||
|
|
||||||
# Announcing one more block on fork should trigger direct fetch for
|
# Announcing one more block on fork should trigger direct fetch for
|
||||||
# both blocks (same work as tip)
|
# both blocks (same work as tip)
|
||||||
@ -556,11 +511,11 @@ class SendHeadersTest(BitcoinTestFramework):
|
|||||||
test_node.wait_for_getdata([x.sha256 for x in blocks[2:16]], timeout=direct_fetch_response_time)
|
test_node.wait_for_getdata([x.sha256 for x in blocks[2:16]], timeout=direct_fetch_response_time)
|
||||||
|
|
||||||
# Announcing 1 more header should not trigger any response
|
# Announcing 1 more header should not trigger any response
|
||||||
test_node.last_getdata = None
|
test_node.last_message.pop("getdata", None)
|
||||||
test_node.send_header_for_blocks(blocks[18:19])
|
test_node.send_header_for_blocks(blocks[18:19])
|
||||||
test_node.sync_with_ping()
|
test_node.sync_with_ping()
|
||||||
with mininode_lock:
|
with mininode_lock:
|
||||||
assert_equal(test_node.last_getdata, None)
|
assert "getdata" not in test_node.last_message
|
||||||
|
|
||||||
self.log.info("Part 4: success!")
|
self.log.info("Part 4: success!")
|
||||||
|
|
||||||
@ -571,7 +526,7 @@ class SendHeadersTest(BitcoinTestFramework):
|
|||||||
# First we test that receipt of an unconnecting header doesn't prevent
|
# First we test that receipt of an unconnecting header doesn't prevent
|
||||||
# chain sync.
|
# chain sync.
|
||||||
for i in range(10):
|
for i in range(10):
|
||||||
test_node.last_getdata = None
|
test_node.last_message.pop("getdata", None)
|
||||||
blocks = []
|
blocks = []
|
||||||
# Create two more blocks.
|
# Create two more blocks.
|
||||||
for j in range(2):
|
for j in range(2):
|
||||||
@ -582,7 +537,7 @@ class SendHeadersTest(BitcoinTestFramework):
|
|||||||
height += 1
|
height += 1
|
||||||
# Send the header of the second block -> this won't connect.
|
# Send the header of the second block -> this won't connect.
|
||||||
with mininode_lock:
|
with mininode_lock:
|
||||||
test_node.last_getheaders = None
|
test_node.last_message.pop("getheaders", None)
|
||||||
test_node.send_header_for_blocks([blocks[1]])
|
test_node.send_header_for_blocks([blocks[1]])
|
||||||
test_node.wait_for_getheaders()
|
test_node.wait_for_getheaders()
|
||||||
test_node.send_header_for_blocks(blocks)
|
test_node.send_header_for_blocks(blocks)
|
||||||
@ -605,7 +560,7 @@ class SendHeadersTest(BitcoinTestFramework):
|
|||||||
for i in range(1, MAX_UNCONNECTING_HEADERS):
|
for i in range(1, MAX_UNCONNECTING_HEADERS):
|
||||||
# Send a header that doesn't connect, check that we get a getheaders.
|
# Send a header that doesn't connect, check that we get a getheaders.
|
||||||
with mininode_lock:
|
with mininode_lock:
|
||||||
test_node.last_getheaders = None
|
test_node.last_message.pop("getheaders", None)
|
||||||
test_node.send_header_for_blocks([blocks[i]])
|
test_node.send_header_for_blocks([blocks[i]])
|
||||||
test_node.wait_for_getheaders()
|
test_node.wait_for_getheaders()
|
||||||
|
|
||||||
@ -620,25 +575,21 @@ class SendHeadersTest(BitcoinTestFramework):
|
|||||||
for i in range(5*MAX_UNCONNECTING_HEADERS - 1):
|
for i in range(5*MAX_UNCONNECTING_HEADERS - 1):
|
||||||
# Send a header that doesn't connect, check that we get a getheaders.
|
# Send a header that doesn't connect, check that we get a getheaders.
|
||||||
with mininode_lock:
|
with mininode_lock:
|
||||||
test_node.last_getheaders = None
|
test_node.last_message.pop("getheaders", None)
|
||||||
test_node.send_header_for_blocks([blocks[i%len(blocks)]])
|
test_node.send_header_for_blocks([blocks[i%len(blocks)]])
|
||||||
test_node.wait_for_getheaders()
|
test_node.wait_for_getheaders()
|
||||||
|
|
||||||
# Eventually this stops working.
|
# Eventually this stops working.
|
||||||
with mininode_lock:
|
|
||||||
self.last_getheaders = None
|
|
||||||
test_node.send_header_for_blocks([blocks[-1]])
|
test_node.send_header_for_blocks([blocks[-1]])
|
||||||
|
|
||||||
# Should get disconnected
|
# Should get disconnected
|
||||||
test_node.wait_for_disconnect()
|
test_node.wait_for_disconnect()
|
||||||
with mininode_lock:
|
|
||||||
self.last_getheaders = True
|
|
||||||
|
|
||||||
self.log.info("Part 5: success!")
|
self.log.info("Part 5: success!")
|
||||||
|
|
||||||
# Finally, check that the inv node never received a getdata request,
|
# Finally, check that the inv node never received a getdata request,
|
||||||
# throughout the test
|
# throughout the test
|
||||||
assert_equal(inv_node.last_getdata, None)
|
assert "getdata" not in inv_node.last_message
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
SendHeadersTest().main()
|
SendHeadersTest().main()
|
||||||
|
@ -192,9 +192,7 @@ class TestManager(object):
|
|||||||
return wait_until(disconnected, timeout=10)
|
return wait_until(disconnected, timeout=10)
|
||||||
|
|
||||||
def wait_for_verack(self):
|
def wait_for_verack(self):
|
||||||
def veracked():
|
return all(node.wait_for_verack() for node in self.test_nodes)
|
||||||
return all(node.verack_received for node in self.test_nodes)
|
|
||||||
return wait_until(veracked, timeout=10)
|
|
||||||
|
|
||||||
def wait_for_pings(self, counter, timeout=float('inf')):
|
def wait_for_pings(self, counter, timeout=float('inf')):
|
||||||
def received_pongs():
|
def received_pongs():
|
||||||
|
@ -20,23 +20,24 @@ msg_block, msg_tx, msg_headers, etc.:
|
|||||||
ser_*, deser_*: functions that handle serialization/deserialization
|
ser_*, deser_*: functions that handle serialization/deserialization
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import struct
|
|
||||||
import socket
|
|
||||||
import asyncore
|
import asyncore
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
|
|
||||||
import time
|
|
||||||
import sys
|
|
||||||
import random
|
|
||||||
from .util import hex_str_to_bytes, bytes_to_hex_str
|
|
||||||
from io import BytesIO
|
|
||||||
from codecs import encode
|
from codecs import encode
|
||||||
import hashlib
|
from collections import defaultdict
|
||||||
from threading import RLock
|
|
||||||
from threading import Thread
|
|
||||||
import logging
|
|
||||||
import copy
|
import copy
|
||||||
|
import hashlib
|
||||||
|
from io import BytesIO
|
||||||
|
import logging
|
||||||
|
import random
|
||||||
|
import socket
|
||||||
|
import struct
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
from threading import RLock, Thread
|
||||||
|
|
||||||
from test_framework.siphash import siphash256
|
from test_framework.siphash import siphash256
|
||||||
|
from test_framework.util import hex_str_to_bytes, bytes_to_hex_str
|
||||||
|
|
||||||
import dash_hash
|
import dash_hash
|
||||||
|
|
||||||
@ -1595,30 +1596,57 @@ class msg_islock(object):
|
|||||||
return "msg_islock(inputs=%s, txid=%064x)" % (repr(self.inputs), self.txid)
|
return "msg_islock(inputs=%s, txid=%064x)" % (repr(self.inputs), self.txid)
|
||||||
|
|
||||||
|
|
||||||
# This is what a callback should look like for NodeConn
|
|
||||||
# Reimplement the on_* functions to provide handling for events
|
|
||||||
class NodeConnCB(object):
|
class NodeConnCB(object):
|
||||||
|
"""Callback and helper functions for P2P connection to a bitcoind node.
|
||||||
|
|
||||||
|
Individual testcases should subclass this and override the on_* methods
|
||||||
|
if they want to alter message handling behaviour.
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.verack_received = False
|
# Track whether we have a P2P connection open to the node
|
||||||
|
self.connected = False
|
||||||
|
self.connection = None
|
||||||
|
|
||||||
|
# Track number of messages of each type received and the most recent
|
||||||
|
# message of each type
|
||||||
|
self.message_count = defaultdict(int)
|
||||||
|
self.last_message = {}
|
||||||
|
|
||||||
|
# A count of the number of ping messages we've sent to the node
|
||||||
|
self.ping_counter = 1
|
||||||
|
|
||||||
# deliver_sleep_time is helpful for debugging race conditions in p2p
|
# deliver_sleep_time is helpful for debugging race conditions in p2p
|
||||||
# tests; it causes message delivery to sleep for the specified time
|
# tests; it causes message delivery to sleep for the specified time
|
||||||
# before acquiring the global lock and delivering the next message.
|
# before acquiring the global lock and delivering the next message.
|
||||||
self.deliver_sleep_time = None
|
self.deliver_sleep_time = None
|
||||||
|
|
||||||
# Remember the services our peer has advertised
|
# Remember the services our peer has advertised
|
||||||
self.peer_services = None
|
self.peer_services = None
|
||||||
self.connection = None
|
|
||||||
self.ping_counter = 1
|
# Message receiving methods
|
||||||
self.last_pong = msg_pong()
|
|
||||||
|
|
||||||
def deliver(self, conn, message):
|
def deliver(self, conn, message):
|
||||||
|
"""Receive message and dispatch message to appropriate callback.
|
||||||
|
|
||||||
|
We keep a count of how many of each message type has been received
|
||||||
|
and the most recent message of each type.
|
||||||
|
|
||||||
|
Optionally waits for deliver_sleep_time before dispatching message.
|
||||||
|
"""
|
||||||
|
|
||||||
deliver_sleep = self.get_deliver_sleep_time()
|
deliver_sleep = self.get_deliver_sleep_time()
|
||||||
if deliver_sleep is not None:
|
if deliver_sleep is not None:
|
||||||
time.sleep(deliver_sleep)
|
time.sleep(deliver_sleep)
|
||||||
with mininode_lock:
|
with mininode_lock:
|
||||||
try:
|
try:
|
||||||
getattr(self, 'on_' + message.command.decode('ascii'))(conn, message)
|
command = message.command.decode('ascii')
|
||||||
|
self.message_count[command] += 1
|
||||||
|
self.last_message[command] = message
|
||||||
|
getattr(self, 'on_' + command)(conn, message)
|
||||||
except:
|
except:
|
||||||
logger.exception("ERROR delivering %s" % repr(message))
|
print("ERROR delivering %s (%s)" % (repr(message),
|
||||||
|
sys.exc_info()[0]))
|
||||||
|
|
||||||
def set_deliver_sleep_time(self, value):
|
def set_deliver_sleep_time(self, value):
|
||||||
with mininode_lock:
|
with mininode_lock:
|
||||||
@ -1628,14 +1656,20 @@ class NodeConnCB(object):
|
|||||||
with mininode_lock:
|
with mininode_lock:
|
||||||
return self.deliver_sleep_time
|
return self.deliver_sleep_time
|
||||||
|
|
||||||
# Callbacks which can be overridden by subclasses
|
# Callback methods. Can be overridden by subclasses in individual test
|
||||||
#################################################
|
# cases to provide custom message handling behaviour.
|
||||||
|
|
||||||
|
def on_open(self, conn):
|
||||||
|
self.connected = True
|
||||||
|
|
||||||
|
def on_close(self, conn):
|
||||||
|
self.connected = False
|
||||||
|
self.connection = None
|
||||||
|
|
||||||
def on_addr(self, conn, message): pass
|
def on_addr(self, conn, message): pass
|
||||||
def on_alert(self, conn, message): pass
|
def on_alert(self, conn, message): pass
|
||||||
def on_block(self, conn, message): pass
|
def on_block(self, conn, message): pass
|
||||||
def on_blocktxn(self, conn, message): pass
|
def on_blocktxn(self, conn, message): pass
|
||||||
def on_close(self, conn): pass
|
|
||||||
def on_cmpctblock(self, conn, message): pass
|
def on_cmpctblock(self, conn, message): pass
|
||||||
def on_feefilter(self, conn, message): pass
|
def on_feefilter(self, conn, message): pass
|
||||||
def on_getaddr(self, conn, message): pass
|
def on_getaddr(self, conn, message): pass
|
||||||
@ -1645,7 +1679,7 @@ class NodeConnCB(object):
|
|||||||
def on_getheaders(self, conn, message): pass
|
def on_getheaders(self, conn, message): pass
|
||||||
def on_headers(self, conn, message): pass
|
def on_headers(self, conn, message): pass
|
||||||
def on_mempool(self, conn): pass
|
def on_mempool(self, conn): pass
|
||||||
def on_open(self, conn): pass
|
def on_pong(self, conn, message): pass
|
||||||
def on_reject(self, conn, message): pass
|
def on_reject(self, conn, message): pass
|
||||||
def on_sendcmpct(self, conn, message): pass
|
def on_sendcmpct(self, conn, message): pass
|
||||||
def on_sendheaders(self, conn, message): pass
|
def on_sendheaders(self, conn, message): pass
|
||||||
@ -1663,9 +1697,6 @@ class NodeConnCB(object):
|
|||||||
if conn.ver_send > BIP0031_VERSION:
|
if conn.ver_send > BIP0031_VERSION:
|
||||||
conn.send_message(msg_pong(message.nonce))
|
conn.send_message(msg_pong(message.nonce))
|
||||||
|
|
||||||
def on_pong(self, conn, message):
|
|
||||||
self.last_pong = message
|
|
||||||
|
|
||||||
def on_mnlistdiff(self, conn, message): pass
|
def on_mnlistdiff(self, conn, message): pass
|
||||||
def on_clsig(self, conn, message): pass
|
def on_clsig(self, conn, message): pass
|
||||||
def on_islock(self, conn, message): pass
|
def on_islock(self, conn, message): pass
|
||||||
@ -1682,15 +1713,44 @@ class NodeConnCB(object):
|
|||||||
conn.ver_recv = conn.ver_send
|
conn.ver_recv = conn.ver_send
|
||||||
conn.nServices = message.nServices
|
conn.nServices = message.nServices
|
||||||
|
|
||||||
# Helper functions
|
# Connection helper methods
|
||||||
##################
|
|
||||||
|
|
||||||
def add_connection(self, conn):
|
def add_connection(self, conn):
|
||||||
self.connection = conn
|
self.connection = conn
|
||||||
|
|
||||||
# Wrapper for the NodeConn's send_message function
|
def wait_for_disconnect(self, timeout=60):
|
||||||
|
test_function = lambda: not self.connected
|
||||||
|
assert wait_until(test_function, timeout=timeout)
|
||||||
|
|
||||||
|
# Message receiving helper methods
|
||||||
|
|
||||||
|
def wait_for_block(self, blockhash, timeout=60):
|
||||||
|
test_function = lambda: self.last_message.get("block") and self.last_message["block"].block.rehash() == blockhash
|
||||||
|
assert wait_until(test_function, timeout=timeout)
|
||||||
|
|
||||||
|
def wait_for_getdata(self, timeout=60):
|
||||||
|
test_function = lambda: self.last_message.get("getdata")
|
||||||
|
assert wait_until(test_function, timeout=timeout)
|
||||||
|
|
||||||
|
def wait_for_getheaders(self, timeout=60):
|
||||||
|
test_function = lambda: self.last_message.get("getheaders")
|
||||||
|
assert wait_until(test_function, timeout=timeout)
|
||||||
|
|
||||||
|
def wait_for_inv(self, expected_inv, timeout=60):
|
||||||
|
test_function = lambda: self.last_message.get("inv") and self.last_message["inv"] != expected_inv
|
||||||
|
assert wait_until(test_function, timeout=timeout)
|
||||||
|
|
||||||
|
def wait_for_verack(self, timeout=60):
|
||||||
|
test_function = lambda: self.message_count["verack"]
|
||||||
|
assert wait_until(test_function, timeout=timeout)
|
||||||
|
|
||||||
|
# Message sending helper functions
|
||||||
|
|
||||||
def send_message(self, message):
|
def send_message(self, message):
|
||||||
self.connection.send_message(message)
|
if self.connection:
|
||||||
|
self.connection.send_message(message)
|
||||||
|
else:
|
||||||
|
logger.error("Cannot send message. No connection to node!")
|
||||||
|
|
||||||
def send_and_ping(self, message):
|
def send_and_ping(self, message):
|
||||||
self.send_message(message)
|
self.send_message(message)
|
||||||
@ -1698,27 +1758,11 @@ class NodeConnCB(object):
|
|||||||
|
|
||||||
# Sync up with the node
|
# Sync up with the node
|
||||||
def sync_with_ping(self, timeout=60):
|
def sync_with_ping(self, timeout=60):
|
||||||
def received_pong():
|
|
||||||
return (self.last_pong.nonce == self.ping_counter)
|
|
||||||
self.send_message(msg_ping(nonce=self.ping_counter))
|
self.send_message(msg_ping(nonce=self.ping_counter))
|
||||||
success = wait_until(received_pong, timeout=timeout)
|
test_function = lambda: self.last_message.get("pong") and self.last_message["pong"].nonce == self.ping_counter
|
||||||
if not success:
|
assert wait_until(test_function, timeout=timeout)
|
||||||
logger.error("sync_with_ping failed!")
|
|
||||||
raise AssertionError("sync_with_ping failed!")
|
|
||||||
self.ping_counter += 1
|
self.ping_counter += 1
|
||||||
|
return True
|
||||||
return success
|
|
||||||
|
|
||||||
# Spin until verack message is received from the node.
|
|
||||||
# Tests may want to use this as a signal that the test can begin.
|
|
||||||
# This can be called from the testing thread, so it needs to acquire the
|
|
||||||
# global lock.
|
|
||||||
def wait_for_verack(self):
|
|
||||||
while True:
|
|
||||||
with mininode_lock:
|
|
||||||
if self.verack_received:
|
|
||||||
return
|
|
||||||
time.sleep(0.05)
|
|
||||||
|
|
||||||
# The actual NodeConn class
|
# The actual NodeConn class
|
||||||
# This class provides an interface for a p2p connection to a specified node
|
# This class provides an interface for a p2p connection to a specified node
|
||||||
|
Loading…
Reference in New Issue
Block a user