aboutsummaryrefslogtreecommitdiff
path: root/test/functional
diff options
context:
space:
mode:
Diffstat (limited to 'test/functional')
-rwxr-xr-xtest/functional/feature_notifications.py2
-rwxr-xr-xtest/functional/p2p_addr_relay.py170
-rwxr-xr-xtest/functional/p2p_blocksonly.py6
-rwxr-xr-xtest/functional/p2p_filter.py3
-rwxr-xr-xtest/functional/p2p_segwit.py33
-rwxr-xr-xtest/functional/rpc_misc.py3
-rwxr-xr-xtest/functional/test_framework/p2p.py10
7 files changed, 186 insertions, 41 deletions
diff --git a/test/functional/feature_notifications.py b/test/functional/feature_notifications.py
index 4e2de1daf4..6fc8773ee3 100755
--- a/test/functional/feature_notifications.py
+++ b/test/functional/feature_notifications.py
@@ -166,6 +166,8 @@ class NotificationsTest(BitcoinTestFramework):
# Should now verify contents of each file
for tx_id, blockheight, blockhash in tx_details:
fname = os.path.join(self.walletnotify_dir, notify_outputname(self.wallet, tx_id))
+ # Wait for the cached writes to hit storage
+ self.wait_until(lambda: os.path.getsize(fname) > 0, timeout=10)
with open(fname, 'rt', encoding='utf-8') as f:
text = f.read()
# Universal newline ensures '\n' on 'nt'
diff --git a/test/functional/p2p_addr_relay.py b/test/functional/p2p_addr_relay.py
index 69821763bd..87297989ba 100755
--- a/test/functional/p2p_addr_relay.py
+++ b/test/functional/p2p_addr_relay.py
@@ -11,6 +11,7 @@ from test_framework.messages import (
NODE_NETWORK,
NODE_WITNESS,
msg_addr,
+ msg_getaddr
)
from test_framework.p2p import P2PInterface
from test_framework.test_framework import BitcoinTestFramework
@@ -19,18 +20,6 @@ from test_framework.util import (
)
import time
-# Keep this with length <= 10. Addresses from larger messages are not relayed.
-ADDRS = []
-num_ipv4_addrs = 10
-
-for i in range(num_ipv4_addrs):
- addr = CAddress()
- addr.time = int(time.time()) + i
- addr.nServices = NODE_NETWORK | NODE_WITNESS
- addr.ip = "123.123.123.{}".format(i % 256)
- addr.port = 8333 + i
- ADDRS.append(addr)
-
class AddrReceiver(P2PInterface):
num_ipv4_received = 0
@@ -44,36 +33,87 @@ class AddrReceiver(P2PInterface):
self.num_ipv4_received += 1
+class GetAddrStore(P2PInterface):
+ getaddr_received = False
+ num_ipv4_received = 0
+
+ def on_getaddr(self, message):
+ self.getaddr_received = True
+
+ def on_addr(self, message):
+ for addr in message.addrs:
+ self.num_ipv4_received += 1
+
+ def addr_received(self):
+ return self.num_ipv4_received != 0
+
+
class AddrTest(BitcoinTestFramework):
+ counter = 0
+ mocktime = int(time.time())
+
def set_test_params(self):
self.num_nodes = 1
def run_test(self):
- self.log.info('Create connection that sends addr messages')
- addr_source = self.nodes[0].add_p2p_connection(P2PInterface())
+ self.oversized_addr_test()
+ self.relay_tests()
+ self.getaddr_tests()
+ self.blocksonly_mode_tests()
+
+ def setup_addr_msg(self, num):
+ addrs = []
+ for i in range(num):
+ addr = CAddress()
+ addr.time = self.mocktime + i
+ addr.nServices = NODE_NETWORK | NODE_WITNESS
+ addr.ip = f"123.123.123.{self.counter % 256}"
+ addr.port = 8333 + i
+ addrs.append(addr)
+ self.counter += 1
+
msg = msg_addr()
+ msg.addrs = addrs
+ return msg
+
+ def send_addr_msg(self, source, msg, receivers):
+ source.send_and_ping(msg)
+ # pop m_next_addr_send timer
+ self.mocktime += 5 * 60
+ self.nodes[0].setmocktime(self.mocktime)
+ for peer in receivers:
+ peer.sync_send_with_ping()
- self.log.info('Send too-large addr message')
- msg.addrs = ADDRS * 101 # more than 1000 addresses in one message
+ def oversized_addr_test(self):
+ self.log.info('Send an addr message that is too large')
+ addr_source = self.nodes[0].add_p2p_connection(P2PInterface())
+
+ msg = self.setup_addr_msg(1010)
with self.nodes[0].assert_debug_log(['addr message size = 1010']):
addr_source.send_and_ping(msg)
+ self.nodes[0].disconnect_p2ps()
+
+ def relay_tests(self):
+ self.log.info('Test address relay')
self.log.info('Check that addr message content is relayed and added to addrman')
+ addr_source = self.nodes[0].add_p2p_connection(P2PInterface())
num_receivers = 7
receivers = []
for _ in range(num_receivers):
receivers.append(self.nodes[0].add_p2p_connection(AddrReceiver()))
- msg.addrs = ADDRS
+
+ # Keep this with length <= 10. Addresses from larger messages are not
+ # relayed.
+ num_ipv4_addrs = 10
+ msg = self.setup_addr_msg(num_ipv4_addrs)
with self.nodes[0].assert_debug_log(
[
'Added {} addresses from 127.0.0.1: 0 tried'.format(num_ipv4_addrs),
- 'received: addr (301 bytes) peer=0',
+ 'received: addr (301 bytes) peer=1',
]
):
- addr_source.send_and_ping(msg)
- self.nodes[0].setmocktime(int(time.time()) + 30 * 60)
- for receiver in receivers:
- receiver.sync_with_ping()
+ self.send_addr_msg(addr_source, msg, receivers)
total_ipv4_received = sum(r.num_ipv4_received for r in receivers)
@@ -82,6 +122,92 @@ class AddrTest(BitcoinTestFramework):
ipv4_branching_factor = 2
assert_equal(total_ipv4_received, num_ipv4_addrs * ipv4_branching_factor)
+ self.nodes[0].disconnect_p2ps()
+
+ self.log.info('Check relay of addresses received from outbound peers')
+ inbound_peer = self.nodes[0].add_p2p_connection(AddrReceiver())
+ full_outbound_peer = self.nodes[0].add_outbound_p2p_connection(GetAddrStore(), p2p_idx=0, connection_type="outbound-full-relay")
+ msg = self.setup_addr_msg(2)
+ self.send_addr_msg(full_outbound_peer, msg, [inbound_peer])
+ self.log.info('Check that the first addr message received from an outbound peer is not relayed')
+ # Currently, there is a flag that prevents the first addr message received
+ # from a new outbound peer to be relayed to others. Originally meant to prevent
+ # large GETADDR responses from being relayed, it now typically affects the self-announcement
+ # of the outbound peer which is often sent before the GETADDR response.
+ assert_equal(inbound_peer.num_ipv4_received, 0)
+
+ self.log.info('Check that subsequent addr messages sent from an outbound peer are relayed')
+ msg2 = self.setup_addr_msg(2)
+ self.send_addr_msg(full_outbound_peer, msg2, [inbound_peer])
+ assert_equal(inbound_peer.num_ipv4_received, 2)
+
+ self.log.info('Check address relay to outbound peers')
+ block_relay_peer = self.nodes[0].add_outbound_p2p_connection(GetAddrStore(), p2p_idx=1, connection_type="block-relay-only")
+ msg3 = self.setup_addr_msg(2)
+ self.send_addr_msg(inbound_peer, msg3, [full_outbound_peer, block_relay_peer])
+
+ self.log.info('Check that addresses are relayed to full outbound peers')
+ assert_equal(full_outbound_peer.num_ipv4_received, 2)
+ self.log.info('Check that addresses are not relayed to block-relay-only outbound peers')
+ assert_equal(block_relay_peer.num_ipv4_received, 0)
+
+ self.nodes[0].disconnect_p2ps()
+
+ def getaddr_tests(self):
+ self.log.info('Test getaddr behavior')
+ self.log.info('Check that we send a getaddr message upon connecting to an outbound-full-relay peer')
+ full_outbound_peer = self.nodes[0].add_outbound_p2p_connection(GetAddrStore(), p2p_idx=0, connection_type="outbound-full-relay")
+ full_outbound_peer.sync_with_ping()
+ assert full_outbound_peer.getaddr_received
+
+ self.log.info('Check that we do not send a getaddr message upon connecting to a block-relay-only peer')
+ block_relay_peer = self.nodes[0].add_outbound_p2p_connection(GetAddrStore(), p2p_idx=1, connection_type="block-relay-only")
+ block_relay_peer.sync_with_ping()
+ assert_equal(block_relay_peer.getaddr_received, False)
+
+ self.log.info('Check that we answer getaddr messages only from inbound peers')
+ inbound_peer = self.nodes[0].add_p2p_connection(GetAddrStore())
+ inbound_peer.sync_with_ping()
+
+ # Add some addresses to addrman
+ for i in range(1000):
+ first_octet = i >> 8
+ second_octet = i % 256
+ a = f"{first_octet}.{second_octet}.1.1"
+ self.nodes[0].addpeeraddress(a, 8333)
+
+ full_outbound_peer.send_and_ping(msg_getaddr())
+ block_relay_peer.send_and_ping(msg_getaddr())
+ inbound_peer.send_and_ping(msg_getaddr())
+
+ self.mocktime += 5 * 60
+ self.nodes[0].setmocktime(self.mocktime)
+ inbound_peer.wait_until(inbound_peer.addr_received)
+
+ assert_equal(full_outbound_peer.num_ipv4_received, 0)
+ assert_equal(block_relay_peer.num_ipv4_received, 0)
+ assert inbound_peer.num_ipv4_received > 100
+
+ self.nodes[0].disconnect_p2ps()
+
+ def blocksonly_mode_tests(self):
+ self.log.info('Test addr relay in -blocksonly mode')
+ self.restart_node(0, ["-blocksonly"])
+ self.mocktime = int(time.time())
+
+ self.log.info('Check that we send getaddr messages')
+ full_outbound_peer = self.nodes[0].add_outbound_p2p_connection(GetAddrStore(), p2p_idx=0, connection_type="outbound-full-relay")
+ full_outbound_peer.sync_with_ping()
+ assert full_outbound_peer.getaddr_received
+
+ self.log.info('Check that we relay address messages')
+ addr_source = self.nodes[0].add_p2p_connection(P2PInterface())
+ msg = self.setup_addr_msg(2)
+ self.send_addr_msg(addr_source, msg, [full_outbound_peer])
+ assert_equal(full_outbound_peer.num_ipv4_received, 2)
+
+ self.nodes[0].disconnect_p2ps()
+
if __name__ == '__main__':
AddrTest().main()
diff --git a/test/functional/p2p_blocksonly.py b/test/functional/p2p_blocksonly.py
index 6584efae79..445cea6186 100755
--- a/test/functional/p2p_blocksonly.py
+++ b/test/functional/p2p_blocksonly.py
@@ -89,11 +89,7 @@ class P2PBlocksOnly(BitcoinTestFramework):
# Bump time forward to ensure nNextInvSend timer pops
self.nodes[0].setmocktime(int(time.time()) + 60)
- # Calling sync_with_ping twice requires that the node calls
- # `ProcessMessage` twice, and thus ensures `SendMessages` must have
- # been called at least once
- conn.sync_with_ping()
- conn.sync_with_ping()
+ conn.sync_send_with_ping()
assert(int(txid, 16) not in conn.get_invs())
def check_p2p_tx_violation(self, index=1):
diff --git a/test/functional/p2p_filter.py b/test/functional/p2p_filter.py
index 4bee33f825..359cfb9c34 100755
--- a/test/functional/p2p_filter.py
+++ b/test/functional/p2p_filter.py
@@ -174,8 +174,7 @@ class FilterTest(BitcoinTestFramework):
filter_peer.merkleblock_received = False
filter_peer.tx_received = False
self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 90)
- filter_peer.sync_with_ping()
- filter_peer.sync_with_ping()
+ filter_peer.sync_send_with_ping()
assert not filter_peer.merkleblock_received
assert not filter_peer.tx_received
diff --git a/test/functional/p2p_segwit.py b/test/functional/p2p_segwit.py
index 54891b07e1..14a4afc2d7 100755
--- a/test/functional/p2p_segwit.py
+++ b/test/functional/p2p_segwit.py
@@ -1956,22 +1956,33 @@ class SegWitTest(BitcoinTestFramework):
def test_upgrade_after_activation(self):
"""Test the behavior of starting up a segwit-aware node after the softfork has activated."""
- self.restart_node(2, extra_args=["-segwitheight={}".format(SEGWIT_HEIGHT)])
+ # All nodes are caught up and node 2 is a pre-segwit node that will soon upgrade.
+ for n in range(2):
+ assert_equal(self.nodes[n].getblockcount(), self.nodes[2].getblockcount())
+ assert softfork_active(self.nodes[n], "segwit")
+ assert SEGWIT_HEIGHT < self.nodes[2].getblockcount()
+ assert 'segwit' not in self.nodes[2].getblockchaininfo()['softforks']
+
+ # Restarting node 2 should result in a shutdown because the blockchain consists of
+ # insufficiently validated blocks per segwit consensus rules.
+ self.stop_node(2)
+ with self.nodes[2].assert_debug_log(expected_msgs=[
+ f"Witness data for blocks after height {SEGWIT_HEIGHT} requires validation. Please restart with -reindex."], timeout=10):
+ self.nodes[2].start([f"-segwitheight={SEGWIT_HEIGHT}"])
+
+ # As directed, the user restarts the node with -reindex
+ self.start_node(2, extra_args=["-reindex", f"-segwitheight={SEGWIT_HEIGHT}"])
+
+ # With the segwit consensus rules, the node is able to validate only up to SEGWIT_HEIGHT - 1
+ assert_equal(self.nodes[2].getblockcount(), SEGWIT_HEIGHT - 1)
self.connect_nodes(0, 2)
# We reconnect more than 100 blocks, give it plenty of time
+ # sync_blocks() also verifies the best block hash is the same for all nodes
self.sync_blocks(timeout=240)
- # Make sure that this peer thinks segwit has activated.
- assert softfork_active(self.nodes[2], 'segwit')
-
- # Make sure this peer's blocks match those of node0.
- height = self.nodes[2].getblockcount()
- while height >= 0:
- block_hash = self.nodes[2].getblockhash(height)
- assert_equal(block_hash, self.nodes[0].getblockhash(height))
- assert_equal(self.nodes[0].getblock(block_hash), self.nodes[2].getblock(block_hash))
- height -= 1
+ # The upgraded node should now have segwit activated
+ assert softfork_active(self.nodes[2], "segwit")
@subtest # type: ignore
def test_witness_sigops(self):
diff --git a/test/functional/rpc_misc.py b/test/functional/rpc_misc.py
index 1398d1237f..a80fa596cd 100755
--- a/test/functional/rpc_misc.py
+++ b/test/functional/rpc_misc.py
@@ -61,6 +61,9 @@ class RpcMiscTest(BitcoinTestFramework):
node.logging(include=['qt'])
assert_equal(node.logging()['qt'], True)
+ self.log.info("test echoipc (testing spawned process in multiprocess build)")
+ assert_equal(node.echoipc("hello"), "hello")
+
self.log.info("test getindexinfo")
# Without any indices running the RPC returns an empty object
assert_equal(node.getindexinfo(), {})
diff --git a/test/functional/test_framework/p2p.py b/test/functional/test_framework/p2p.py
index 05099f3339..cc80b543cd 100755
--- a/test/functional/test_framework/p2p.py
+++ b/test/functional/test_framework/p2p.py
@@ -539,8 +539,16 @@ class P2PInterface(P2PConnection):
self.send_message(message)
self.sync_with_ping(timeout=timeout)
- # Sync up with the node
+ def sync_send_with_ping(self, timeout=60):
+ """Ensure SendMessages is called on this connection"""
+ # Calling sync_with_ping twice requires that the node calls
+ # `ProcessMessage` twice, and thus ensures `SendMessages` must have
+ # been called at least once
+ self.sync_with_ping()
+ self.sync_with_ping()
+
def sync_with_ping(self, timeout=60):
+ """Ensure ProcessMessages is called on this connection"""
self.send_message(msg_ping(nonce=self.ping_counter))
def test_function():