Skip to content

feat(wire)!: Add a new BitcoinSocketAddr struct to unify address parsing#984

Open
Davidson-Souza wants to merge 4 commits into
getfloresta:masterfrom
Davidson-Souza:refactor/BitcoinSocketAddr
Open

feat(wire)!: Add a new BitcoinSocketAddr struct to unify address parsing#984
Davidson-Souza wants to merge 4 commits into
getfloresta:masterfrom
Davidson-Souza:refactor/BitcoinSocketAddr

Conversation

@Davidson-Souza
Copy link
Copy Markdown
Member

Description and Notes

Our code represents addresses in a scattered and messy way. Some places we use SocketAddr, some AddrV2 and some Strings. SocketAddr and Strings already wraps ports, while AddrV2 and IpAddr don't. Therefore some functions will ask for a u16 and other won't. We also have parsing logic for addresses all over the code, repeating logic and creating inconsistecies. Finally, in some APIs we support names, and others don't, which is frustrating.

This type will encapsulate both addresses and ports, as AddrV2 it will work with non-ip addresses such as Tor and I2P. It also supports name resolution.

It exposes a few conversion primitives to make it into other types if this is required in specific scopes, but overall we should use this type to represent Bitcoin node addresses.

Note: This used to be part of another PR to implement Onion addresses (we currently can't connect to .onion addresses), but got too big and I decided to split it up. Without these changes, it would be impossible to have those as well.

@Davidson-Souza Davidson-Souza self-assigned this Apr 23, 2026
@Davidson-Souza Davidson-Souza added the reliability Related to runtime reliability, stability and production readiness label Apr 23, 2026
@github-project-automation github-project-automation Bot moved this to Backlog in Floresta Apr 23, 2026
@luisschwab
Copy link
Copy Markdown
Member

cACK. I was actually thinking about this lately. To me, it would make sense to eventually upstream this to bitcoin-p2p.

@Davidson-Souza Davidson-Souza force-pushed the refactor/BitcoinSocketAddr branch from 2d92b13 to 45785e1 Compare April 28, 2026 23:37
@Davidson-Souza Davidson-Souza changed the title [Seeking Conceptual Review]feat(wire)!: Add a new BitcoinSocketAddr struct to unify address parsing feat(wire)!: Add a new BitcoinSocketAddr struct to unify address parsing Apr 28, 2026
@Davidson-Souza Davidson-Souza force-pushed the refactor/BitcoinSocketAddr branch 4 times, most recently from 1646cab to 4017323 Compare April 29, 2026 20:17
@Davidson-Souza Davidson-Souza marked this pull request as ready for review April 29, 2026 21:19
@Davidson-Souza Davidson-Souza moved this from Backlog to In progress in Floresta Apr 29, 2026
@Davidson-Souza
Copy link
Copy Markdown
Member Author

Ready for a first round of reviews

Comment on lines +118 to +122
// Don't connect to the same peer twice
let is_connected = |(_, peer_addr): (_, &LocalPeerView)| peer_addr.address == peer_address;

if self.common.peers.iter().any(is_connected) {
return Err(WireError::PeerAlreadyExists(peer_address));
Copy link
Copy Markdown
Contributor

@lorenzolfm lorenzolfm May 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT
You can use .values() to avoid the clunky |(_, peer_addr): (_, &LocalPeerView)| peer_addr.address == peer_address; syntax

:P

        // Don't connect to the same peer twice
        if self
            .common
            .peers
            .values()
            .any(|p| p.address == peer_address)
        {
            return Err(WireError::PeerAlreadyExists(peer_address));
        }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

0,
AddressState::NeverTried,
ServiceFlags::NONE,
0,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe dumb question, but why is id hardcoded to zero?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These come from the AddrMan and we use it to ban/update that address. But since this is coming from somewhere else, we don't know if AddrMan have it or what's the internal id for it.

debug!("Trying to remove peer {addr}");

let address = self.to_addr_v2(addr);
let index = self
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT

        let index = self
            .added_peers
            .iter()
            .position(|info| addr == info.address)
            .ok_or(WireError::PeerNotFoundAtAddress(addr))?;

        self.added_peers.remove(index);

if your in for a more idiomatic rust approach

/// Handles the node request for immediate disconnection from a peer.
pub fn handle_disconnect_peer(&mut self, addr: IpAddr, port: u16) -> Result<(), WireError> {
pub fn handle_disconnect_peer(&mut self, addr: BitcoinSocketAddr) -> Result<(), WireError> {
// Get the peer's index in the [`AddressMan`]'s list, if it exists.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also nit :p

        // Get the peer's index in the [`AddressMan`]'s list, if it exists.
        let peer_id = self
            .peers
            .iter()
            .find_map(|(&id, peer)| (*peer.address.as_bitcoin_socket_addr() == addr).then_some(id))
            .ok_or(WireError::PeerNotFoundAtAddress(addr))?;

        self.send_to_peer(peer_id, NodeRequest::Shutdown)

.write_all(&[SOCKS_VERSION, 1, SOCKS_AUTH_METHOD_NONE])
.await
.unwrap();
.await?;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice catch

Copy link
Copy Markdown
Contributor

@lorenzolfm lorenzolfm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK ✅

Network::Signet => 38333,
Network::Bitcoin => 8333,
Network::Testnet => 18333,
Network::Regtest => 48444,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

18444 i think

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Davidson-Souza use the get_p2p_port function I added I while back

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Davidson-Souza use the get_p2p_port function I added I while back

Where is this function? Maybe it was removed

Copy link
Copy Markdown
Member

@luisschwab luisschwab May 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is this function? Maybe it was removed

Floresta/crates/floresta-wire/src/p2p_wire/node/conn.rs#L475

It's named get_port. Maybe you could rename it to get_p2p_port.

@Davidson-Souza Davidson-Souza force-pushed the refactor/BitcoinSocketAddr branch from 4017323 to 7635a87 Compare May 7, 2026 18:18
@Davidson-Souza
Copy link
Copy Markdown
Member Author

Pushed 7635a87 applying @lorenzolfm's code styling suggestions.

false,
"Valid address with out-of-range port",
)
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing test coverage for CJDNS addresses.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice catch! Will add!

@csgui
Copy link
Copy Markdown
Collaborator

csgui commented May 8, 2026

Those PRs changing several files are hard to reason about, but it seems consistent 👍 Maybe we should tackle validation with more tests and corner cases.

@csgui csgui added this to the Q2/2026 milestone May 8, 2026
@Davidson-Souza
Copy link
Copy Markdown
Member Author

Those PRs changing several files are hard to reason about, but it seems consistent 👍 Maybe we should tackle validation with more tests and corner cases.

Yeah, it's annoying. But I can't break it further because it wouldn't compile. Most of the changes however, are just changing types, so this is easy to use.

As for testing; most of the API parts changes are covered by our functional tests (addnode and connect mainly), I've added several parsing tests and fuzzing to make sure it won't break. Do you have any further suggestion for how to test it?

@Davidson-Souza Davidson-Souza force-pushed the refactor/BitcoinSocketAddr branch from 7635a87 to 3381963 Compare May 11, 2026 16:21
@Davidson-Souza
Copy link
Copy Markdown
Member Author

Added tests for CJDNS

@luisschwab
Copy link
Copy Markdown
Member

luisschwab commented May 11, 2026

Needs rebase thanks to @JoseSK999 @moisesPompilio

@Davidson-Souza Davidson-Souza moved this from In progress to Needs review in Floresta May 11, 2026
@Davidson-Souza
Copy link
Copy Markdown
Member Author

Needs rebase thanks to @JoseSK999

It's actually @moisesPompilio's fault. @JoseSK999 didn't touch RPC.

@luisschwab
Copy link
Copy Markdown
Member

Fixed lol

Our code represents addresses in a scattered and messy way. Some places we use
SocketAddr, some AddrV2 and some Strings. SocketAddr and Strings already wraps
ports, while AddrV2 and IpAddr don't. Therefore some functions will ask for a
`u16` and other won't. We also have parsing logic for addresses all over the
code, repeating logic and creating inconsistecies. Finally, in some APIs
we support names, and others don't, which is frustrating.

This type will encapsulate both addresses and ports, as AddrV2 it will work
with non-ip addresses such as Tor and I2P. It also supports name resolution.

It exposes a few conversion primitives to make it into other types if this
is required in specific scopes, but overall we should use this type to
represent Bitcoin node addresses.
Use BitcoinSocketAddr where we need to represent a node addressess, simplify
some code and improve debug message for addresses.
…nSocketAddr

This function was just calling BitcoinSocketAddr, and didn't have any reason to exist.

The tests also tested BitcoinSocketAddr, instead of something inside `conn.rs`, so
I've moved them.
@Davidson-Souza Davidson-Souza force-pushed the refactor/BitcoinSocketAddr branch from 3381963 to 8470e4d Compare May 12, 2026 16:57
@Davidson-Souza
Copy link
Copy Markdown
Member Author

Rebased and fixed tests.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

architecture reliability Related to runtime reliability, stability and production readiness

Projects

Status: Needs review

Development

Successfully merging this pull request may close these issues.

4 participants