Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 4 additions & 8 deletions pkg/bzz/address.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,9 @@ func ParseAddress(underlay, overlay, signature, nonce []byte, validateOverlay bo
return nil, fmt.Errorf("deserialize underlays: %w: %w", ErrInvalidAddress, err)
}

if len(multiUnderlays) == 0 {
// no underlays sent
return nil, ErrInvalidAddress
}
// Empty underlays are allowed for inbound-only peers (e.g., browsers, WebRTC, strict NAT)
// that cannot be dialed back. These peers can still use protocols over existing connections
// but won't participate in Kademlia topology or hive gossip.

ethAddress, err := crypto.NewEthereumAddress(*recoveredPK)
if err != nil {
Expand Down Expand Up @@ -144,10 +143,7 @@ func AreUnderlaysEqual(a, b []ma.Multiaddr) bool {
}

func (a *Address) MarshalJSON() ([]byte, error) {
if len(a.Underlays) == 0 {
return nil, fmt.Errorf("no underlays for %s", a.Overlay)
}

// Empty underlays are allowed for inbound-only peers that cannot be dialed back
// select the underlay address for backward compatibility
var underlay string
if v := SelectBestAdvertisedAddress(a.Underlays, nil); v != nil {
Expand Down
14 changes: 12 additions & 2 deletions pkg/p2p/libp2p/libp2p.go
Original file line number Diff line number Diff line change
Expand Up @@ -704,7 +704,9 @@ func (s *Service) handleIncoming(stream network.Stream) {
return
}

if i.FullNode {
// Only persist peers with underlays to addressbook. Inbound-only peers (empty underlays)
// cannot be dialed back, so there's no point in storing them for reconnection.
if i.FullNode && len(i.BzzAddress.Underlays) > 0 {
err = s.addressbook.Put(i.BzzAddress.Overlay, *i.BzzAddress)
if err != nil {
s.logger.Debug("stream handler: addressbook put error", "peer_id", peerID, "error", err)
Expand Down Expand Up @@ -804,6 +806,12 @@ func (s *Service) notifyReacherConnected(overlay swarm.Address, peerID libp2ppee
peerAddrs := s.host.Peerstore().Addrs(peerID)
bestAddr := bzz.SelectBestAdvertisedAddress(peerAddrs, nil)

// Skip reacher notification for peers with no advertisable addresses (inbound-only peers)
if bestAddr == nil {
s.logger.Debug("skipping reacher notification for inbound-only peer", "peer_id", peerID, "overlay", overlay)
return
}

s.logger.Debug("selected reacher address", "peer_id", peerID, "selected_addr", bestAddr.String(), "advertised_count", len(peerAddrs))

underlay, err := buildFullMA(bestAddr, peerID)
Expand Down Expand Up @@ -1124,7 +1132,9 @@ func (s *Service) Connect(ctx context.Context, addrs []ma.Multiaddr) (address *b
return nil, p2p.ErrPeerNotFound
}

if i.FullNode {
// Only persist peers with underlays to addressbook. Inbound-only peers (empty underlays)
// cannot be dialed back, so there's no point in storing them for reconnection.
if i.FullNode && len(i.BzzAddress.Underlays) > 0 {
err = s.addressbook.Put(overlay, *i.BzzAddress)
if err != nil {
_ = s.Disconnect(overlay, "failed storing peer in addressbook")
Expand Down
34 changes: 17 additions & 17 deletions pkg/p2p/libp2p/peer.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ import (
)

type peerRegistry struct {
underlays map[string]libp2ppeer.ID // map overlay address to underlay peer id
overlays map[libp2ppeer.ID]swarm.Address // map underlay peer id to overlay address
full map[libp2ppeer.ID]bool // map to track whether a node is full or light node (true=full)
connections map[libp2ppeer.ID]map[network.Conn]struct{} // list of connections for safe removal on Disconnect notification
streams map[libp2ppeer.ID]map[network.Stream]context.CancelFunc
mu sync.RWMutex
overlayToPeerID map[string]libp2ppeer.ID // map overlay address (as string) to libp2p peer ID
overlays map[libp2ppeer.ID]swarm.Address // map libp2p peer id to overlay address
full map[libp2ppeer.ID]bool // map to track whether a node is full or light node (true=full)
connections map[libp2ppeer.ID]map[network.Conn]struct{} // list of connections for safe removal on Disconnect notification
streams map[libp2ppeer.ID]map[network.Stream]context.CancelFunc
mu sync.RWMutex

//nolint:misspell
disconnecter disconnecter // peerRegistry notifies libp2p on peer disconnection
Expand All @@ -36,11 +36,11 @@ type disconnecter interface {

func newPeerRegistry() *peerRegistry {
return &peerRegistry{
underlays: make(map[string]libp2ppeer.ID),
overlays: make(map[libp2ppeer.ID]swarm.Address),
full: make(map[libp2ppeer.ID]bool),
connections: make(map[libp2ppeer.ID]map[network.Conn]struct{}),
streams: make(map[libp2ppeer.ID]map[network.Stream]context.CancelFunc),
overlayToPeerID: make(map[string]libp2ppeer.ID),
overlays: make(map[libp2ppeer.ID]swarm.Address),
full: make(map[libp2ppeer.ID]bool),
connections: make(map[libp2ppeer.ID]map[network.Conn]struct{}),
streams: make(map[libp2ppeer.ID]map[network.Stream]context.CancelFunc),

Notifiee: new(network.NoopNotifiee),
}
Expand Down Expand Up @@ -75,7 +75,7 @@ func (r *peerRegistry) Disconnected(_ network.Network, c network.Conn) {
delete(r.connections, peerID)
overlay := r.overlays[peerID]
delete(r.overlays, peerID)
delete(r.underlays, overlay.ByteString())
delete(r.overlayToPeerID, overlay.ByteString())
for _, cancel := range r.streams[peerID] {
cancel()
}
Expand Down Expand Up @@ -143,12 +143,12 @@ func (r *peerRegistry) addIfNotExists(c network.Conn, overlay swarm.Address, ful
// this is solving a case of multiple underlying libp2p connections for the same peer
r.connections[peerID][c] = struct{}{}

if _, exists := r.underlays[overlay.ByteString()]; exists {
if _, exists := r.overlayToPeerID[overlay.ByteString()]; exists {
return true
}

r.streams[peerID] = make(map[network.Stream]context.CancelFunc)
r.underlays[overlay.ByteString()] = peerID
r.overlayToPeerID[overlay.ByteString()] = peerID
r.overlays[peerID] = overlay
r.full[peerID] = full
return false
Expand All @@ -157,7 +157,7 @@ func (r *peerRegistry) addIfNotExists(c network.Conn, overlay swarm.Address, ful

func (r *peerRegistry) peerID(overlay swarm.Address) (peerID libp2ppeer.ID, found bool) {
r.mu.RLock()
peerID, found = r.underlays[overlay.ByteString()]
peerID, found = r.overlayToPeerID[overlay.ByteString()]
r.mu.RUnlock()
return peerID, found
}
Expand Down Expand Up @@ -207,9 +207,9 @@ func (r *peerRegistry) isConnected(peerID libp2ppeer.ID, remoteAddr ma.Multiaddr

func (r *peerRegistry) remove(overlay swarm.Address) (found, full bool, peerID libp2ppeer.ID) {
r.mu.Lock()
peerID, found = r.underlays[overlay.ByteString()]
peerID, found = r.overlayToPeerID[overlay.ByteString()]
delete(r.overlays, peerID)
delete(r.underlays, overlay.ByteString())
delete(r.overlayToPeerID, overlay.ByteString())
delete(r.connections, peerID)
for _, cancel := range r.streams[peerID] {
cancel()
Expand Down
Loading