mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-02-22 06:52:36 +01:00
test: Add functional tests for sendtxrcncl from inbound
This commit is contained in:
parent
b99ee9d22d
commit
cfcef60779
4 changed files with 195 additions and 0 deletions
163
test/functional/p2p_sendtxrcncl.py
Executable file
163
test/functional/p2p_sendtxrcncl.py
Executable file
|
@ -0,0 +1,163 @@
|
|||
#!/usr/bin/env python3
|
||||
# Copyright (c) 2022 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 SENDTXRCNCL message
|
||||
"""
|
||||
|
||||
from test_framework.messages import (
|
||||
msg_sendtxrcncl,
|
||||
msg_verack,
|
||||
msg_version,
|
||||
msg_wtxidrelay,
|
||||
)
|
||||
from test_framework.p2p import (
|
||||
P2PInterface,
|
||||
P2P_SERVICES,
|
||||
P2P_SUBVERSION,
|
||||
P2P_VERSION,
|
||||
)
|
||||
from test_framework.test_framework import BitcoinTestFramework
|
||||
from test_framework.util import assert_equal
|
||||
|
||||
class PeerNoVerack(P2PInterface):
|
||||
def __init__(self, wtxidrelay=True):
|
||||
super().__init__(wtxidrelay=wtxidrelay)
|
||||
|
||||
def on_version(self, message):
|
||||
# Avoid sending verack in response to version.
|
||||
# When calling add_p2p_connection, wait_for_verack=False must be set (see
|
||||
# comment in add_p2p_connection).
|
||||
if message.nVersion >= 70016 and self.wtxidrelay:
|
||||
self.send_message(msg_wtxidrelay())
|
||||
|
||||
class SendTxrcnclReceiver(P2PInterface):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.sendtxrcncl_msg_received = None
|
||||
|
||||
def on_sendtxrcncl(self, message):
|
||||
self.sendtxrcncl_msg_received = message
|
||||
|
||||
class PeerTrackMsgOrder(P2PInterface):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.messages = []
|
||||
|
||||
def on_message(self, message):
|
||||
super().on_message(message)
|
||||
self.messages.append(message)
|
||||
|
||||
def create_sendtxrcncl_msg(initiator=True):
|
||||
sendtxrcncl_msg = msg_sendtxrcncl()
|
||||
sendtxrcncl_msg.initiator = initiator
|
||||
sendtxrcncl_msg.responder = not initiator
|
||||
sendtxrcncl_msg.version = 1
|
||||
sendtxrcncl_msg.salt = 2
|
||||
return sendtxrcncl_msg
|
||||
|
||||
class SendTxRcnclTest(BitcoinTestFramework):
|
||||
def set_test_params(self):
|
||||
self.num_nodes = 1
|
||||
self.extra_args = [['-txreconciliation']]
|
||||
|
||||
def run_test(self):
|
||||
self.log.info('SENDTXRCNCL sent to an inbound')
|
||||
peer = self.nodes[0].add_p2p_connection(SendTxrcnclReceiver(), send_version=True, wait_for_verack=True)
|
||||
assert peer.sendtxrcncl_msg_received
|
||||
assert not peer.sendtxrcncl_msg_received.initiator
|
||||
assert peer.sendtxrcncl_msg_received.responder
|
||||
assert_equal(peer.sendtxrcncl_msg_received.version, 1)
|
||||
peer.peer_disconnect()
|
||||
|
||||
self.log.info('SENDTXRCNCL should be sent before VERACK')
|
||||
peer = self.nodes[0].add_p2p_connection(PeerTrackMsgOrder(), send_version=True, wait_for_verack=True)
|
||||
peer.wait_for_verack()
|
||||
verack_index = [i for i, msg in enumerate(peer.messages) if msg.msgtype == b'verack'][0]
|
||||
sendtxrcncl_index = [i for i, msg in enumerate(peer.messages) if msg.msgtype == b'sendtxrcncl'][0]
|
||||
assert(sendtxrcncl_index < verack_index)
|
||||
peer.peer_disconnect()
|
||||
|
||||
self.log.info('SENDTXRCNCL on pre-WTXID version should not be sent')
|
||||
peer = self.nodes[0].add_p2p_connection(SendTxrcnclReceiver(), send_version=False, wait_for_verack=False)
|
||||
pre_wtxid_version_msg = msg_version()
|
||||
pre_wtxid_version_msg.nVersion = 70015
|
||||
pre_wtxid_version_msg.strSubVer = P2P_SUBVERSION
|
||||
pre_wtxid_version_msg.nServices = P2P_SERVICES
|
||||
pre_wtxid_version_msg.relay = 1
|
||||
peer.send_message(pre_wtxid_version_msg)
|
||||
peer.wait_for_verack()
|
||||
assert not peer.sendtxrcncl_msg_received
|
||||
peer.peer_disconnect()
|
||||
|
||||
self.log.info('SENDTXRCNCL for fRelay=false should not be sent')
|
||||
peer = self.nodes[0].add_p2p_connection(SendTxrcnclReceiver(), send_version=False, wait_for_verack=False)
|
||||
no_txrelay_version_msg = msg_version()
|
||||
no_txrelay_version_msg.nVersion = P2P_VERSION
|
||||
no_txrelay_version_msg.strSubVer = P2P_SUBVERSION
|
||||
no_txrelay_version_msg.nServices = P2P_SERVICES
|
||||
no_txrelay_version_msg.relay = 0
|
||||
peer.send_message(no_txrelay_version_msg)
|
||||
peer.wait_for_verack()
|
||||
assert not peer.sendtxrcncl_msg_received
|
||||
peer.peer_disconnect()
|
||||
|
||||
self.log.info('valid SENDTXRCNCL received')
|
||||
peer = self.nodes[0].add_p2p_connection(PeerNoVerack(), send_version=True, wait_for_verack=False)
|
||||
peer.send_message(create_sendtxrcncl_msg())
|
||||
self.wait_until(lambda : "sendtxrcncl" in self.nodes[0].getpeerinfo()[-1]["bytesrecv_per_msg"])
|
||||
self.log.info('second SENDTXRCNCL triggers a disconnect')
|
||||
peer.send_message(create_sendtxrcncl_msg())
|
||||
peer.wait_for_disconnect()
|
||||
|
||||
self.log.info('SENDTXRCNCL with initiator=responder=0 triggers a disconnect')
|
||||
sendtxrcncl_no_role = create_sendtxrcncl_msg()
|
||||
sendtxrcncl_no_role.initiator = False
|
||||
sendtxrcncl_no_role.responder = False
|
||||
peer = self.nodes[0].add_p2p_connection(PeerNoVerack(), send_version=True, wait_for_verack=False)
|
||||
peer.send_message(sendtxrcncl_no_role)
|
||||
peer.wait_for_disconnect()
|
||||
|
||||
self.log.info('SENDTXRCNCL with initiator=0 and responder=1 from inbound triggers a disconnect')
|
||||
sendtxrcncl_wrong_role = create_sendtxrcncl_msg(initiator=False)
|
||||
peer = self.nodes[0].add_p2p_connection(PeerNoVerack(), send_version=True, wait_for_verack=False)
|
||||
peer.send_message(sendtxrcncl_wrong_role)
|
||||
peer.wait_for_disconnect()
|
||||
|
||||
self.log.info('SENDTXRCNCL with version=0 triggers a disconnect')
|
||||
sendtxrcncl_low_version = create_sendtxrcncl_msg()
|
||||
sendtxrcncl_low_version.version = 0
|
||||
peer = self.nodes[0].add_p2p_connection(PeerNoVerack(), send_version=True, wait_for_verack=False)
|
||||
peer.send_message(sendtxrcncl_low_version)
|
||||
peer.wait_for_disconnect()
|
||||
|
||||
self.log.info('sending SENDTXRCNCL after sending VERACK triggers a disconnect')
|
||||
# We use PeerNoVerack even though verack is sent right after, to make sure it was actually
|
||||
# sent before sendtxrcncl is sent.
|
||||
peer = self.nodes[0].add_p2p_connection(PeerNoVerack(), send_version=True, wait_for_verack=False)
|
||||
peer.send_and_ping(msg_verack())
|
||||
peer.send_message(create_sendtxrcncl_msg())
|
||||
peer.wait_for_disconnect()
|
||||
|
||||
self.log.info('SENDTXRCNCL without WTXIDRELAY is ignored (recon state is erased after VERACK)')
|
||||
peer = self.nodes[0].add_p2p_connection(PeerNoVerack(wtxidrelay=False), send_version=True, wait_for_verack=False)
|
||||
with self.nodes[0].assert_debug_log(['Forget txreconciliation state of peer']):
|
||||
peer.send_message(create_sendtxrcncl_msg())
|
||||
peer.send_message(msg_verack())
|
||||
peer.peer_disconnect()
|
||||
|
||||
self.log.info('SENDTXRCNCL not sent if -txreconciliation flag is not set')
|
||||
self.restart_node(0, [])
|
||||
peer = self.nodes[0].add_p2p_connection(SendTxrcnclReceiver(), send_version=True, wait_for_verack=True)
|
||||
assert not peer.sendtxrcncl_msg_received
|
||||
peer.peer_disconnect()
|
||||
|
||||
self.log.info('SENDTXRCNCL not sent if blocksonly is set')
|
||||
self.restart_node(0, ["-txreconciliation", "-blocksonly"])
|
||||
peer = self.nodes[0].add_p2p_connection(SendTxrcnclReceiver(), send_version=True, wait_for_verack=True)
|
||||
assert not peer.sendtxrcncl_msg_received
|
||||
peer.peer_disconnect()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
SendTxRcnclTest().main()
|
|
@ -1838,3 +1838,31 @@ class msg_cfcheckpt:
|
|||
def __repr__(self):
|
||||
return "msg_cfcheckpt(filter_type={:#x}, stop_hash={:x})".format(
|
||||
self.filter_type, self.stop_hash)
|
||||
|
||||
class msg_sendtxrcncl:
|
||||
__slots__ = ("initiator", "responder", "version", "salt")
|
||||
msgtype = b"sendtxrcncl"
|
||||
|
||||
def __init__(self):
|
||||
self.initiator = False
|
||||
self.responder = False
|
||||
self.version = 0
|
||||
self.salt = 0
|
||||
|
||||
def deserialize(self, f):
|
||||
self.initiator = struct.unpack("<?", f.read(1))[0]
|
||||
self.responder = struct.unpack("<?", f.read(1))[0]
|
||||
self.version = struct.unpack("<I", f.read(4))[0]
|
||||
self.salt = struct.unpack("<Q", f.read(8))[0]
|
||||
|
||||
def serialize(self):
|
||||
r = b""
|
||||
r += struct.pack("<?", self.initiator)
|
||||
r += struct.pack("<?", self.responder)
|
||||
r += struct.pack("<I", self.version)
|
||||
r += struct.pack("<Q", self.salt)
|
||||
return r
|
||||
|
||||
def __repr__(self):
|
||||
return "msg_sendtxrcncl(initiator=%i, responder=%i, version=%lu, salt=%lu)" %\
|
||||
(self.initiator, self.responder, self.version, self.salt)
|
||||
|
|
|
@ -62,6 +62,7 @@ from test_framework.messages import (
|
|||
msg_sendaddrv2,
|
||||
msg_sendcmpct,
|
||||
msg_sendheaders,
|
||||
msg_sendtxrcncl,
|
||||
msg_tx,
|
||||
MSG_TX,
|
||||
MSG_TYPE_MASK,
|
||||
|
@ -126,6 +127,7 @@ MESSAGEMAP = {
|
|||
b"sendaddrv2": msg_sendaddrv2,
|
||||
b"sendcmpct": msg_sendcmpct,
|
||||
b"sendheaders": msg_sendheaders,
|
||||
b"sendtxrcncl": msg_sendtxrcncl,
|
||||
b"tx": msg_tx,
|
||||
b"verack": msg_verack,
|
||||
b"version": msg_version,
|
||||
|
@ -421,6 +423,7 @@ class P2PInterface(P2PConnection):
|
|||
def on_sendaddrv2(self, message): pass
|
||||
def on_sendcmpct(self, message): pass
|
||||
def on_sendheaders(self, message): pass
|
||||
def on_sendtxrcncl(self, message): pass
|
||||
def on_tx(self, message): pass
|
||||
def on_wtxidrelay(self, message): pass
|
||||
|
||||
|
|
|
@ -318,6 +318,7 @@ BASE_SCRIPTS = [
|
|||
'rpc_deriveaddresses.py --usecli',
|
||||
'p2p_ping.py',
|
||||
'rpc_scanblocks.py',
|
||||
'p2p_sendtxrcncl.py',
|
||||
'rpc_scantxoutset.py',
|
||||
'feature_txindex_compatibility.py',
|
||||
'feature_unsupported_utxo_db.py',
|
||||
|
|
Loading…
Add table
Reference in a new issue