aboutsummaryrefslogtreecommitdiff
path: root/test/functional/test_framework/mininode.py
diff options
context:
space:
mode:
Diffstat (limited to 'test/functional/test_framework/mininode.py')
-rwxr-xr-xtest/functional/test_framework/mininode.py142
1 files changed, 83 insertions, 59 deletions
diff --git a/test/functional/test_framework/mininode.py b/test/functional/test_framework/mininode.py
index d1ddbbe8ee..ca5734d67d 100755
--- a/test/functional/test_framework/mininode.py
+++ b/test/functional/test_framework/mininode.py
@@ -21,7 +21,38 @@ import struct
import sys
import threading
-from test_framework.messages import CBlockHeader, MIN_VERSION_SUPPORTED, msg_addr, msg_block, MSG_BLOCK, msg_blocktxn, msg_cmpctblock, msg_feefilter, msg_getaddr, msg_getblocks, msg_getblocktxn, msg_getdata, msg_getheaders, msg_headers, msg_inv, msg_mempool, msg_ping, msg_pong, msg_reject, msg_sendcmpct, msg_sendheaders, msg_tx, MSG_TX, MSG_TYPE_MASK, msg_verack, msg_version, NODE_NETWORK, NODE_WITNESS, sha256
+from test_framework.messages import (
+ CBlockHeader,
+ MIN_VERSION_SUPPORTED,
+ msg_addr,
+ msg_block,
+ MSG_BLOCK,
+ msg_blocktxn,
+ msg_cmpctblock,
+ msg_feefilter,
+ msg_getaddr,
+ msg_getblocks,
+ msg_getblocktxn,
+ msg_getdata,
+ msg_getheaders,
+ msg_headers,
+ msg_inv,
+ msg_mempool,
+ msg_notfound,
+ msg_ping,
+ msg_pong,
+ msg_reject,
+ msg_sendcmpct,
+ msg_sendheaders,
+ msg_tx,
+ MSG_TX,
+ MSG_TYPE_MASK,
+ msg_verack,
+ msg_version,
+ NODE_NETWORK,
+ NODE_WITNESS,
+ sha256,
+)
from test_framework.util import wait_until
logger = logging.getLogger("TestFramework.mininode")
@@ -40,6 +71,7 @@ MESSAGEMAP = {
b"headers": msg_headers,
b"inv": msg_inv,
b"mempool": msg_mempool,
+ b"notfound": msg_notfound,
b"ping": msg_ping,
b"pong": msg_pong,
b"reject": msg_reject,
@@ -175,10 +207,13 @@ class P2PConnection(asyncio.Protocol):
This method takes a P2P payload, builds the P2P header and adds
the message to the send buffer to be sent over the socket."""
+ tmsg = self.build_message(message)
+ self._log_message("send", message)
+ return self.send_raw_message(tmsg)
+
+ def send_raw_message(self, raw_message_bytes):
if not self.is_connected:
raise IOError('Not connected')
- self._log_message("send", message)
- tmsg = self._build_message(message)
def maybe_write():
if not self._transport:
@@ -188,12 +223,12 @@ class P2PConnection(asyncio.Protocol):
# Python 3.4 versions.
if hasattr(self._transport, 'is_closing') and self._transport.is_closing():
return
- self._transport.write(tmsg)
+ self._transport.write(raw_message_bytes)
NetworkThread.network_event_loop.call_soon_threadsafe(maybe_write)
# Class utility methods
- def _build_message(self, message):
+ def build_message(self, message):
"""Build a serialized P2P message"""
command = message.command
data = message.serialize()
@@ -295,6 +330,7 @@ class P2PInterface(P2PConnection):
def on_getheaders(self, message): pass
def on_headers(self, message): pass
def on_mempool(self, message): pass
+ def on_notfound(self, message): pass
def on_pong(self, message): pass
def on_reject(self, message): pass
def on_sendcmpct(self, message): pass
@@ -313,7 +349,7 @@ class P2PInterface(P2PConnection):
self.send_message(msg_pong(message.nonce))
def on_verack(self, message):
- self.verack_received = True
+ pass
def on_version(self, message):
assert message.nVersion >= MIN_VERSION_SUPPORTED, "Version {} received. Test framework only supports versions greater than {}".format(message.nVersion, MIN_VERSION_SUPPORTED)
@@ -376,9 +412,9 @@ class P2PInterface(P2PConnection):
# Message sending helper functions
- def send_and_ping(self, message):
+ def send_and_ping(self, message, timeout=60):
self.send_message(message)
- self.sync_with_ping()
+ self.sync_with_ping(timeout=timeout)
# Sync up with the node
def sync_with_ping(self, timeout=60):
@@ -425,8 +461,6 @@ class P2PDataStore(P2PInterface):
def __init__(self):
super().__init__()
- self.reject_code_received = None
- self.reject_reason_received = None
# store of blocks. key is block hash, value is a CBlock object
self.block_store = {}
self.last_block_hash = ''
@@ -477,81 +511,71 @@ class P2PDataStore(P2PInterface):
if response is not None:
self.send_message(response)
- def on_reject(self, message):
- """Store reject reason and code for testing."""
- self.reject_code_received = message.code
- self.reject_reason_received = message.reason
-
- def send_blocks_and_test(self, blocks, rpc, success=True, request_block=True, reject_code=None, reject_reason=None, timeout=60):
+ def send_blocks_and_test(self, blocks, node, *, success=True, force_send=False, reject_reason=None, expect_disconnect=False, timeout=60):
"""Send blocks to test node and test whether the tip advances.
- add all blocks to our block_store
- send a headers message for the final block
- the on_getheaders handler will ensure that any getheaders are responded to
- - if request_block is True: wait for getdata for each of the blocks. The on_getdata handler will
- ensure that any getdata messages are responded to
+ - if force_send is False: wait for getdata for each of the blocks. The on_getdata handler will
+ ensure that any getdata messages are responded to. Otherwise send the full block unsolicited.
- if success is True: assert that the node's tip advances to the most recent block
- if success is False: assert that the node's tip doesn't advance
- - if reject_code and reject_reason are set: assert that the correct reject message is received"""
+ - if reject_reason is set: assert that the correct reject message is logged"""
with mininode_lock:
- self.reject_code_received = None
- self.reject_reason_received = None
-
for block in blocks:
self.block_store[block.sha256] = block
self.last_block_hash = block.sha256
- self.send_message(msg_headers([CBlockHeader(blocks[-1])]))
-
- if request_block:
- wait_until(lambda: blocks[-1].sha256 in self.getdata_requests, timeout=timeout, lock=mininode_lock)
+ reject_reason = [reject_reason] if reject_reason else []
+ with node.assert_debug_log(expected_msgs=reject_reason):
+ if force_send:
+ for b in blocks:
+ self.send_message(msg_block(block=b))
+ else:
+ self.send_message(msg_headers([CBlockHeader(blocks[-1])]))
+ wait_until(lambda: blocks[-1].sha256 in self.getdata_requests, timeout=timeout, lock=mininode_lock)
- if success:
- wait_until(lambda: rpc.getbestblockhash() == blocks[-1].hash, timeout=timeout)
- else:
- assert rpc.getbestblockhash() != blocks[-1].hash
+ if expect_disconnect:
+ self.wait_for_disconnect(timeout=timeout)
+ else:
+ self.sync_with_ping(timeout=timeout)
- if reject_code is not None:
- wait_until(lambda: self.reject_code_received == reject_code, lock=mininode_lock)
- if reject_reason is not None:
- wait_until(lambda: self.reject_reason_received == reject_reason, lock=mininode_lock)
+ if success:
+ wait_until(lambda: node.getbestblockhash() == blocks[-1].hash, timeout=timeout)
+ else:
+ assert node.getbestblockhash() != blocks[-1].hash
- def send_txs_and_test(self, txs, rpc, success=True, expect_disconnect=False, reject_code=None, reject_reason=None):
+ def send_txs_and_test(self, txs, node, *, success=True, expect_disconnect=False, reject_reason=None):
"""Send txs to test node and test whether they're accepted to the mempool.
- add all txs to our tx_store
- send tx messages for all txs
- if success is True/False: assert that the txs are/are not accepted to the mempool
- if expect_disconnect is True: Skip the sync with ping
- - if reject_code and reject_reason are set: assert that the correct reject message is received."""
+ - if reject_reason is set: assert that the correct reject message is logged."""
with mininode_lock:
- self.reject_code_received = None
- self.reject_reason_received = None
-
for tx in txs:
self.tx_store[tx.sha256] = tx
- for tx in txs:
- self.send_message(msg_tx(tx))
-
- if expect_disconnect:
- self.wait_for_disconnect()
- else:
- self.sync_with_ping()
-
- raw_mempool = rpc.getrawmempool()
- if success:
- # Check that all txs are now in the mempool
+ reject_reason = [reject_reason] if reject_reason else []
+ with node.assert_debug_log(expected_msgs=reject_reason):
for tx in txs:
- assert tx.hash in raw_mempool, "{} not found in mempool".format(tx.hash)
- else:
- # Check that none of the txs are now in the mempool
- for tx in txs:
- assert tx.hash not in raw_mempool, "{} tx found in mempool".format(tx.hash)
+ self.send_message(msg_tx(tx))
- if reject_code is not None:
- wait_until(lambda: self.reject_code_received == reject_code, lock=mininode_lock)
- if reject_reason is not None:
- wait_until(lambda: self.reject_reason_received == reject_reason, lock=mininode_lock)
+ if expect_disconnect:
+ self.wait_for_disconnect()
+ else:
+ self.sync_with_ping()
+
+ raw_mempool = node.getrawmempool()
+ if success:
+ # Check that all txs are now in the mempool
+ for tx in txs:
+ assert tx.hash in raw_mempool, "{} not found in mempool".format(tx.hash)
+ else:
+ # Check that none of the txs are now in the mempool
+ for tx in txs:
+ assert tx.hash not in raw_mempool, "{} tx found in mempool".format(tx.hash)