-
Notifications
You must be signed in to change notification settings - Fork 115
Add P2P addr/addrv2 tests + oversized/spam message checks #897
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
moisesPompilio
wants to merge
6
commits into
getfloresta:master
Choose a base branch
from
moisesPompilio:add-test-p2p
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
3102cc4
feat(integration): use `wait_until` for interactive condition checks …
moisesPompilio 74c9a4b
fix(wire): disconnect peers sending SendAddrV2 post-handshake and han…
moisesPompilio 3947dcb
feat(integration): add Bitcoin P2P test utilities and expose node con…
moisesPompilio c7facfe
test(integration): add P2P address relay test suite for Floresta
moisesPompilio 9b58e5e
test(integration): add oversized P2P message validation test
moisesPompilio fb04180
test(integration): add P2P message spam and rate limiting test
moisesPompilio File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,181 @@ | ||
| """ | ||
| p2p_addr_relay.py | ||
|
|
||
| Test suite for P2P address relay functionality in Floresta. | ||
| Verifies that the node correctly handles address messages (addr and addrv2), | ||
| enforces message size limits, and responds to getaddr requests appropriately. | ||
| """ | ||
|
|
||
| import time | ||
| import random | ||
|
|
||
| from test_framework import FlorestaTestFramework | ||
| from test_framework.node import NodeType | ||
| from test_framework.messages import msg_addrv2, msg_sendaddrv2, msg_getaddr | ||
| from test_framework.p2p import ( | ||
| P2PInterface, | ||
| P2P_SERVICES, | ||
| ) | ||
| from test_framework.util import wait_until | ||
|
|
||
|
|
||
| class AddrReceiver(P2PInterface): | ||
| """ | ||
| A custom P2P interface that listens for and validates address messages. | ||
| Tracks whether addr (v1) and addrv2 messages are received. | ||
| """ | ||
|
|
||
| addr_received_and_checked = False | ||
| addrv2_received_and_checked = False | ||
|
|
||
| def __init__(self, support_addrv2=True): | ||
| super().__init__(support_addrv2=support_addrv2) | ||
|
|
||
| def on_addr(self, message): | ||
| # Floresta does not send peer addresses to other nodes | ||
| if len(message.addrs) == 0: | ||
| self.addr_received_and_checked = True | ||
|
|
||
| def on_addrv2(self, message): | ||
| # Floresta does not send peer addresses to other nodes | ||
| if len(message.addrs) == 0: | ||
| self.addrv2_received_and_checked = True | ||
|
|
||
| def wait_for_addr(self): | ||
| """Wait for an addr message to be received.""" | ||
| self.wait_until(lambda: "addr" in self.last_message) | ||
|
|
||
| def wait_for_addrv2(self): | ||
| """Wait for an addrv2 message to be received.""" | ||
| self.wait_until(lambda: "addrv2" in self.last_message) | ||
|
|
||
|
|
||
| class TestP2pAddrRelay(FlorestaTestFramework): | ||
| """ | ||
| Test that Floresta returns addresses when receiving GetAddr. | ||
| """ | ||
|
|
||
| def set_test_params(self): | ||
| """ | ||
| Here we define setup for test | ||
| """ | ||
|
|
||
| self.florestad = self.add_node_default_args( | ||
| variant=NodeType.FLORESTAD, | ||
| ) | ||
|
|
||
| def run_test(self): | ||
| """ | ||
| Execute the address relay tests. | ||
| """ | ||
|
|
||
| self.run_node(self.florestad) | ||
| self.default_msg = msg_addrv2() | ||
| self.default_msg.addrs = self.create_node_address(10) | ||
|
|
||
| self.log("Testing sendaddrv2 message after handshake") | ||
| self.connect_p2p() | ||
|
|
||
| self.p2p_conn.send_without_ping(msg_sendaddrv2()) | ||
| self.check_disconnection(self.p2p_conn) | ||
|
|
||
| self.log("Testing addrv2 message ") | ||
| self.connect_p2p() | ||
| self.p2p_conn.send_and_ping(self.default_msg) | ||
| assert self.p2p_conn.is_connected | ||
| assert self.floresta_has_peer_count(expected_peer_count=1) | ||
|
|
||
| self.log( | ||
| "Testing addrv2 message with varying number of addresses to check for disconnection on oversized messages" | ||
| ) | ||
| msg_oversized = msg_addrv2() | ||
|
|
||
| for quantity in range(998, 1002): | ||
| addr = self.create_node_address(quantity) | ||
| msg_oversized.addrs = addr | ||
| msg_size = self.calc_addrv2_msg_size(addr) | ||
| self.log( | ||
| f"Testing addrv2 message with {len(msg_oversized.addrs)} addresses (size: {msg_size} bytes)" | ||
| ) | ||
| if quantity > 1000: | ||
| self.p2p_conn.send_without_ping(msg_oversized) | ||
| self.check_disconnection(self.p2p_conn) | ||
| else: | ||
| self.p2p_conn.send_and_ping(msg_oversized) | ||
| assert ( | ||
| self.p2p_conn.is_connected | ||
| ), f"Node should still be connected after sending addrv2 message with {len(msg_oversized.addrs)} addresses" | ||
|
|
||
| self.log( | ||
| "Node disconnected as expected after sending an oversized addrv2 message" | ||
| ) | ||
| assert ( | ||
| not self.p2p_conn.is_connected | ||
| ), "p2p_default should be disconnected after sending an oversized addrv2 message" | ||
| assert ( | ||
| len(self.florestad.rpc.get_peerinfo()) == 0 | ||
| ), "Floresta node should have no peers connected" | ||
|
|
||
| self.log("Testing getaddr message") | ||
| self.p2p_receiver_v2 = self.add_p2p_connection( | ||
| node=self.florestad, p2p_idx=0, p2p_conn=AddrReceiver() | ||
| ) | ||
| self.p2p_receiver_v2.send_without_ping(msg_getaddr()) | ||
| self.p2p_receiver_v2.wait_for_addrv2() | ||
| assert self.p2p_receiver_v2.addrv2_received_and_checked | ||
|
|
||
| self.p2p_receiver_v1 = self.add_p2p_connection( | ||
| node=self.florestad, | ||
| p2p_idx=1, | ||
| p2p_conn=AddrReceiver(support_addrv2=False), | ||
| ) | ||
| self.p2p_receiver_v1.send_without_ping(msg_getaddr()) | ||
| self.p2p_receiver_v1.wait_for_addr() | ||
| assert self.p2p_receiver_v1.addr_received_and_checked | ||
|
|
||
| def connect_p2p(self, expected_peer_count: int = 1): | ||
| """Establish a P2P connection to the Floresta node.""" | ||
| self.log("Connecting to interface P2P...") | ||
| self.p2p_conn = self.add_p2p_connection_default( | ||
| node=self.florestad, | ||
| p2p_idx=0, | ||
| ) | ||
| wait_until( | ||
| predicate=lambda: self.floresta_has_peer_count( | ||
| expected_peer_count=expected_peer_count | ||
| ), | ||
| error_msg="Floresta node did not connect as expected", | ||
| ) | ||
|
|
||
| def floresta_has_peer_count(self, expected_peer_count: int = 0) -> bool: | ||
| """Check if the Floresta node has the expected number of peers.""" | ||
| self.florestad.rpc.ping() | ||
| return len(self.florestad.rpc.get_peerinfo()) == expected_peer_count | ||
|
|
||
| def check_disconnection(self, p2p, expected_peer_count: int = 0): | ||
| """Check if the Floresta node has the expected number of peers after disconnection.""" | ||
| self.log("Checking disconnection...") | ||
| p2p.wait_for_disconnect() | ||
| wait_until( | ||
| predicate=lambda: self.floresta_has_peer_count( | ||
| expected_peer_count=expected_peer_count | ||
| ), | ||
| error_msg="Floresta node did not disconnect as expected", | ||
| ) | ||
|
|
||
| def calc_addrv2_msg_size(self, addrs): | ||
| """Calculate the serialized size of an addrv2 message in bytes.""" | ||
| size = 1 # vector length byte | ||
| for addr in addrs: | ||
| size += 4 # time | ||
| size += 1 # services, COMPACTSIZE(P2P_SERVICES) | ||
| size += 1 # network id | ||
| size += 1 # address length byte | ||
| size += addr.ADDRV2_ADDRESS_LENGTH[addr.net] # address | ||
| size += 2 # port | ||
|
|
||
| return size | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| TestP2pAddrRelay().main() | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.