-
-
Notifications
You must be signed in to change notification settings - Fork 108
Description
Problem
PeerKeyLocation currently has a peer_addr: PeerAddr field where PeerAddr can be either Known(SocketAddr) or Unknown. This flexibility is intentional - peers behind NAT don't know their external address until told by the network.
However, this creates a class of bugs where code assumes an address is known when it isn't. Example: #2207 where ConnectResponse.acceptor was created with Unknown address even though the responder must have a known address.
Current Mitigations
- Runtime
debug_assertat construction sites (PR refactor: complete connection-based routing migration (remove PeerId) #2208) - Unit tests that verify address is known in responses
- Defensive handling in places that receive messages (e.g., tracing module)
Proposed Enhancement
Use the type system to distinguish between:
/// Peer location where address may be unknown (for request initiators)
pub struct PeerKeyLocation {
pub pub_key: TransportPublicKey,
pub peer_addr: PeerAddr, // Can be Unknown or Known
}
/// Peer location where address is guaranteed known (for response senders)
pub struct KnownPeerLocation {
pub pub_key: TransportPublicKey,
addr: SocketAddr, // Always known - private field enforced by constructor
}
impl KnownPeerLocation {
/// Only way to construct - requires known address
pub fn new(pub_key: TransportPublicKey, addr: SocketAddr) -> Self {
Self { pub_key, addr }
}
pub fn socket_addr(&self) -> SocketAddr {
self.addr
}
}
impl From<KnownPeerLocation> for PeerKeyLocation {
fn from(known: KnownPeerLocation) -> Self {
PeerKeyLocation {
pub_key: known.pub_key,
peer_addr: PeerAddr::Known(known.addr),
}
}
}Then message types can specify which they require:
// Joiner initiates - may not know own address
pub struct ConnectRequest {
pub joiner: PeerKeyLocation, // Can be Unknown
// ...
}
// Acceptor responds - must have known address
pub struct ConnectResponse {
pub acceptor: KnownPeerLocation, // Compile-time guarantee
}Benefits
- Compile-time safety: Can't create
ConnectResponsewithout a known address - Self-documenting: Message types express their requirements clearly
- No runtime overhead: Zero-cost abstraction, same as current approach
- Gradual migration: Can introduce
KnownPeerLocationincrementally
Drawbacks
- Requires reviewing all message types to determine which needs which
- Adds another type to the codebase
- Some messages might legitimately accept either (though this is rare)
Related
- PeerKeyLocation addr() panics when address is unknown #2207 - Bug caused by missing known address requirement
- refactor: complete connection-based routing migration (remove PeerId) #2208 - Added runtime protections and tests
Scope
This is a refactoring improvement, not urgent. The runtime protections in #2208 provide adequate safety. This issue tracks a potential future enhancement for stronger compile-time guarantees.
[AI-assisted - Claude]
Metadata
Metadata
Assignees
Labels
Type
Projects
Status