Skip to content

Commit 80d4423

Browse files
committed
Test buffered valid message
A message can be broken across two buffers, with the split inside its header. Usually this will occur when sending many messages, such that the first buffer fills. This test uses the RPC to verify that the message is actually being received in two pieces. There is a very rare chance of a race condition where the test framework sends a message in between the two halves of the message under test. In this case the peer will almost certainly disconnect and the test will fail. An assert has been added to help debugging that rare case.
1 parent 39bd9dd commit 80d4423

File tree

1 file changed

+29
-3
lines changed

1 file changed

+29
-3
lines changed

test/functional/p2p_invalid_messages.py

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@
33
# Distributed under the MIT software license, see the accompanying
44
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
55
"""Test node responses to invalid network messages."""
6+
67
from test_framework.messages import (
78
CBlockHeader,
89
CInv,
910
msg_getdata,
1011
msg_headers,
1112
msg_inv,
13+
msg_ping,
1214
MSG_TX,
1315
ser_string,
1416
)
@@ -17,6 +19,10 @@
1719
P2PInterface,
1820
)
1921
from test_framework.test_framework import BitcoinTestFramework
22+
from test_framework.util import (
23+
assert_equal,
24+
wait_until,
25+
)
2026

2127
MSG_LIMIT = 4 * 1000 * 1000 # 4MB, per MAX_PROTOCOL_MESSAGE_LENGTH
2228
VALID_DATA_LIMIT = MSG_LIMIT - 5 # Account for the 5-byte length prefix
@@ -42,13 +48,33 @@ def set_test_params(self):
4248
self.setup_clean_chain = True
4349

4450
def run_test(self):
51+
self.test_buffer()
4552
self.test_magic_bytes()
4653
self.test_checksum()
4754
self.test_size()
4855
self.test_msgtype()
4956
self.test_large_inv()
5057
self.test_resource_exhaustion()
5158

59+
def test_buffer(self):
60+
self.log.info("Test message with header split across two buffers, should be received")
61+
conn = self.nodes[0].add_p2p_connection(P2PDataStore())
62+
# Create valid message
63+
msg = conn.build_message(msg_ping(nonce=12345))
64+
cut_pos = 12 # Chosen at an arbitrary position within the header
65+
# Send message in two pieces
66+
before = int(self.nodes[0].getnettotals()['totalbytesrecv'])
67+
conn.send_raw_message(msg[:cut_pos])
68+
# Wait until node has processed the first half of the message
69+
wait_until(lambda: int(self.nodes[0].getnettotals()['totalbytesrecv']) != before)
70+
middle = int(self.nodes[0].getnettotals()['totalbytesrecv'])
71+
# If this assert fails, we've hit an unlikely race
72+
# where the test framework sent a message in between the two halves
73+
assert_equal(middle, before + cut_pos)
74+
conn.send_raw_message(msg[cut_pos:])
75+
conn.sync_with_ping(timeout=1)
76+
self.nodes[0].disconnect_p2ps()
77+
5278
def test_magic_bytes(self):
5379
conn = self.nodes[0].add_p2p_connection(P2PDataStore())
5480
with self.nodes[0].assert_debug_log(['PROCESSMESSAGE: INVALID MESSAGESTART badmsg']):
@@ -95,13 +121,13 @@ def test_msgtype(self):
95121

96122
def test_large_inv(self):
97123
conn = self.nodes[0].add_p2p_connection(P2PInterface())
98-
with self.nodes[0].assert_debug_log(['Misbehaving', 'peer=4 (0 -> 20): message inv size() = 50001']):
124+
with self.nodes[0].assert_debug_log(['Misbehaving', '(0 -> 20): message inv size() = 50001']):
99125
msg = msg_inv([CInv(MSG_TX, 1)] * 50001)
100126
conn.send_and_ping(msg)
101-
with self.nodes[0].assert_debug_log(['Misbehaving', 'peer=4 (20 -> 40): message getdata size() = 50001']):
127+
with self.nodes[0].assert_debug_log(['Misbehaving', '(20 -> 40): message getdata size() = 50001']):
102128
msg = msg_getdata([CInv(MSG_TX, 1)] * 50001)
103129
conn.send_and_ping(msg)
104-
with self.nodes[0].assert_debug_log(['Misbehaving', 'peer=4 (40 -> 60): headers message size = 2001']):
130+
with self.nodes[0].assert_debug_log(['Misbehaving', '(40 -> 60): headers message size = 2001']):
105131
msg = msg_headers([CBlockHeader()] * 2001)
106132
conn.send_and_ping(msg)
107133
self.nodes[0].disconnect_p2ps()

0 commit comments

Comments
 (0)