aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rwxr-xr-xtest/functional/feature_pruning.py2
-rwxr-xr-xtest/functional/p2p_sendtxrcncl.py191
-rwxr-xr-xtest/functional/test_framework/messages.py28
-rwxr-xr-xtest/functional/test_framework/p2p.py3
-rwxr-xr-xtest/functional/test_framework/test_node.py7
-rwxr-xr-xtest/functional/test_runner.py1
6 files changed, 229 insertions, 3 deletions
diff --git a/test/functional/feature_pruning.py b/test/functional/feature_pruning.py
index 7dbeccbc09..4126ffcd51 100755
--- a/test/functional/feature_pruning.py
+++ b/test/functional/feature_pruning.py
@@ -358,6 +358,8 @@ class PruneTest(BitcoinTestFramework):
self.restart_node(2, extra_args=["-prune=550"])
self.log.info("Success")
+ assert_raises_rpc_error(-4, "Importing wallets is disabled when blocks are pruned", self.nodes[2].importwallet, "abc")
+
# check that wallet loads successfully when restarting a pruned node after IBD.
# this was reported to fail in #7494.
self.log.info("Syncing node 5 to test wallet")
diff --git a/test/functional/p2p_sendtxrcncl.py b/test/functional/p2p_sendtxrcncl.py
new file mode 100755
index 0000000000..f4c5dd4586
--- /dev/null
+++ b/test/functional/p2p_sendtxrcncl.py
@@ -0,0 +1,191 @@
+#!/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 sent to an outbound')
+ peer = self.nodes[0].add_outbound_p2p_connection(
+ SendTxrcnclReceiver(), wait_for_verack=True, p2p_idx=1, connection_type="outbound-full-relay")
+ assert peer.sendtxrcncl_msg_received
+ assert peer.sendtxrcncl_msg_received.initiator
+ assert not peer.sendtxrcncl_msg_received.responder
+ assert_equal(peer.sendtxrcncl_msg_received.version, 1)
+ peer.peer_disconnect()
+
+ self.log.info('SENDTXRCNCL should not be sent if block-relay-only')
+ peer = self.nodes[0].add_outbound_p2p_connection(
+ SendTxrcnclReceiver(), wait_for_verack=True, p2p_idx=2, connection_type="block-relay-only")
+ assert not peer.sendtxrcncl_msg_received
+ peer.peer_disconnect()
+
+ self.log.info('SENDTXRCNCL if block-relay-only triggers a disconnect')
+ peer = self.nodes[0].add_outbound_p2p_connection(
+ PeerNoVerack(), wait_for_verack=False, p2p_idx=3, connection_type="block-relay-only")
+ peer.send_message(create_sendtxrcncl_msg(initiator=False))
+ peer.wait_for_disconnect()
+
+ self.log.info('SENDTXRCNCL with initiator=1 and responder=0 from outbound triggers a disconnect')
+ sendtxrcncl_wrong_role = create_sendtxrcncl_msg(initiator=True)
+ peer = self.nodes[0].add_outbound_p2p_connection(
+ P2PInterface(), wait_for_verack=False, p2p_idx=4, connection_type="outbound-full-relay")
+ peer.send_message(sendtxrcncl_wrong_role)
+ peer.wait_for_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()
diff --git a/test/functional/test_framework/messages.py b/test/functional/test_framework/messages.py
index 8a928a1e50..252b49cc6d 100755
--- a/test/functional/test_framework/messages.py
+++ b/test/functional/test_framework/messages.py
@@ -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)
diff --git a/test/functional/test_framework/p2p.py b/test/functional/test_framework/p2p.py
index fc72a9ab73..8830b0de63 100755
--- a/test/functional/test_framework/p2p.py
+++ b/test/functional/test_framework/p2p.py
@@ -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
diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py
index e35cae006f..2367a9a8fa 100755
--- a/test/functional/test_framework/test_node.py
+++ b/test/functional/test_framework/test_node.py
@@ -618,7 +618,7 @@ class TestNode():
return p2p_conn
- def add_outbound_p2p_connection(self, p2p_conn, *, p2p_idx, connection_type="outbound-full-relay", **kwargs):
+ def add_outbound_p2p_connection(self, p2p_conn, *, wait_for_verack=True, p2p_idx, connection_type="outbound-full-relay", **kwargs):
"""Add an outbound p2p connection from node. Must be an
"outbound-full-relay", "block-relay-only", "addr-fetch" or "feeler" connection.
@@ -640,8 +640,9 @@ class TestNode():
p2p_conn.wait_for_connect()
self.p2ps.append(p2p_conn)
- p2p_conn.wait_for_verack()
- p2p_conn.sync_with_ping()
+ if wait_for_verack:
+ p2p_conn.wait_for_verack()
+ p2p_conn.sync_with_ping()
return p2p_conn
diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py
index 628450f278..e20de8ea8e 100755
--- a/test/functional/test_runner.py
+++ b/test/functional/test_runner.py
@@ -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',