Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
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
15 changes: 0 additions & 15 deletions pkg/bzz/address.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import (
"encoding/json"
"errors"
"fmt"
"slices"

"github.com/ethereum/go-ethereum/common"
"github.com/ethersphere/bee/v2/pkg/crypto"
Expand All @@ -38,7 +37,6 @@ type Address struct {

type addressJSON struct {
Overlay string `json:"overlay"`
Underlay string `json:"underlay"` // For backward compatibility
Underlays []string `json:"underlays"`
Signature string `json:"signature"`
Nonce string `json:"transaction"`
Expand Down Expand Up @@ -145,16 +143,8 @@ func (a *Address) MarshalJSON() ([]byte, error) {
if len(a.Underlays) == 0 {
return nil, fmt.Errorf("no underlays for %s", a.Overlay)
}

// select the underlay address for backward compatibility
var underlay string
if v := SelectBestAdvertisedAddress(a.Underlays, nil); v != nil {
underlay = v.String()
}

return json.Marshal(&addressJSON{
Overlay: a.Overlay.String(),
Underlay: underlay,
Underlays: a.underlaysAsStrings(),
Signature: base64.StdEncoding.EncodeToString(a.Signature),
Nonce: common.Bytes2Hex(a.Nonce),
Expand All @@ -175,11 +165,6 @@ func (a *Address) UnmarshalJSON(b []byte) error {

a.Overlay = addr

// append the underlay for backward compatibility
if !slices.Contains(v.Underlays, v.Underlay) {
v.Underlays = append(v.Underlays, v.Underlay)
}

multiaddrs, err := parseMultiaddrs(v.Underlays)
if err != nil {
return err
Expand Down
2 changes: 1 addition & 1 deletion pkg/bzz/address_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ func TestBzzAddress(t *testing.T) {
t.Fatal(err)
}

bzzAddress2, err := bzz.ParseAddress(node1ma.Bytes(), overlay.Bytes(), bzzAddress.Signature, nonce, true, 3)
bzzAddress2, err := bzz.ParseAddress(bzz.SerializeUnderlays([]multiaddr.Multiaddr{node1ma}), overlay.Bytes(), bzzAddress.Signature, nonce, true, 3)
if err != nil {
t.Fatal(err)
}
Expand Down
12 changes: 0 additions & 12 deletions pkg/bzz/underlay.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,7 @@ import (
const underlayListPrefix byte = 0x99

// SerializeUnderlays serializes a slice of multiaddrs into a single byte slice.
// If the slice contains exactly one address, the standard, backward-compatible
// multiaddr format is used. For zero or more than one address, a custom list format
// prefixed with a magic byte is utilized.
func SerializeUnderlays(addrs []multiaddr.Multiaddr) []byte {
// Backward compatibility if exactly one address is present.
if len(addrs) == 1 {
return addrs[0].Bytes()
}

// For 0 or 2+ addresses, the custom list format with the prefix is used.
// The format is: [prefix_byte][varint_len_1][addr_1_bytes]...
var buf bytes.Buffer
Expand All @@ -43,14 +35,10 @@ func SerializeUnderlays(addrs []multiaddr.Multiaddr) []byte {
}

// DeserializeUnderlays deserializes a byte slice into a slice of multiaddrs.
// The data format is automatically detected as either a single legacy multiaddr
// or a list of multiaddrs (identified by underlayListPrefix), and is parsed accordingly.
func DeserializeUnderlays(data []byte) ([]multiaddr.Multiaddr, error) {
if len(data) == 0 {
return nil, errors.New("cannot deserialize empty byte slice")
}

// If the data begins with the magic prefix, it is handled as a list.
if data[0] == underlayListPrefix {
return deserializeList(data[1:])
}
Expand Down
60 changes: 0 additions & 60 deletions pkg/bzz/underlay_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,19 +29,6 @@ func TestSerializeUnderlays(t *testing.T) {
}
})

t.Run("single address list", func(t *testing.T) {
addrs := []multiaddr.Multiaddr{dnsSwarmAddr}
serialized := bzz.SerializeUnderlays(addrs)
expected := dnsSwarmAddr.Bytes() // Should be legacy format without prefix

if !bytes.Equal(serialized, expected) {
t.Errorf("expected single address to serialize to legacy format %x, got %x", expected, serialized)
}
if serialized[0] == bzz.UnderlayListPrefix {
t.Error("single address serialization should not have the list prefix")
}
})

t.Run("empty list", func(t *testing.T) {
addrs := []multiaddr.Multiaddr{}
serialized := bzz.SerializeUnderlays(addrs)
Expand Down Expand Up @@ -78,17 +65,6 @@ func TestDeserializeUnderlays(t *testing.T) {
}
})

t.Run("single legacy multiaddr", func(t *testing.T) {
singleBytes := wssAddr.Bytes()
deserialized, err := bzz.DeserializeUnderlays(singleBytes)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if len(deserialized) != 1 || !deserialized[0].Equal(wssAddr) {
t.Errorf("expected [%v], got %v", wssAddr, deserialized)
}
})

t.Run("empty byte slice", func(t *testing.T) {
_, err := bzz.DeserializeUnderlays([]byte{})
if err == nil {
Expand Down Expand Up @@ -205,42 +181,6 @@ func TestSerializeUnderlaysDeserializeUnderlays(t *testing.T) {
})
}

func TestLegacyCompatibility(t *testing.T) {
ip4TCPAddr := mustNewMultiaddr(t, "/ip4/1.2.3.4/tcp/5678/p2p/QmWqeeHEqG2db37JsuKUxyJ2JF8LtVJMGohKVT8h3aeCVH")
p2pAddr := mustNewMultiaddr(t, "/ip4/65.108.66.216/tcp/16341/p2p/QmVuCJ3M96c7vwv4MQBv7WY1HWQacyCEHvM99R8MUDj95d")
dnsSwarmAddr := mustNewMultiaddr(t, "/dnsaddr/mainnet.ethswarm.org")

t.Run("legacy parser fails on new list format", func(t *testing.T) {
addrs := []multiaddr.Multiaddr{ip4TCPAddr, p2pAddr, dnsSwarmAddr}
listBytes := bzz.SerializeUnderlays(addrs) // This will have the prefix
_, err := multiaddr.NewMultiaddrBytes(listBytes)
if err == nil {
t.Error("expected legacy NewMultiaddrBytes to fail on list format, but it succeeded")
}
})

t.Run("legacy parser succeeds on new single-addr format", func(t *testing.T) {
addrs := []multiaddr.Multiaddr{dnsSwarmAddr}
singleBytes := bzz.SerializeUnderlays(addrs) // This will NOT have the prefix
_, err := multiaddr.NewMultiaddrBytes(singleBytes)
if err != nil {
t.Errorf("expected legacy NewMultiaddrBytes to succeed on single-addr format, but it failed: %v", err)
}
})

t.Run("new parser succeeds on legacy format", func(t *testing.T) {
singleBytes := p2pAddr.Bytes()
deserialized, err := bzz.DeserializeUnderlays(singleBytes)
if err != nil {
t.Fatalf("Deserialize failed on legacy bytes: %v", err)
}
expected := []multiaddr.Multiaddr{p2pAddr}
if !reflect.DeepEqual(expected, deserialized) {
t.Errorf("expected %v, got %v", expected, deserialized)
}
})
}

func mustNewMultiaddr(tb testing.TB, s string) multiaddr.Multiaddr {
tb.Helper()

Expand Down
6 changes: 2 additions & 4 deletions pkg/hive/hive.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ var (
)

type Service struct {
streamer p2p.Bee260CompatibilityStreamer
streamer p2p.Streamer
addressBook addressbook.GetPutter
addPeersHandler func(...swarm.Address)
networkID uint64
Expand All @@ -67,7 +67,7 @@ type Service struct {
overlay swarm.Address
}

func New(streamer p2p.Bee260CompatibilityStreamer, addressbook addressbook.GetPutter, networkID uint64, bootnode bool, allowPrivateCIDRs bool, overlay swarm.Address, logger log.Logger) *Service {
func New(streamer p2p.Streamer, addressbook addressbook.GetPutter, networkID uint64, bootnode bool, allowPrivateCIDRs bool, overlay swarm.Address, logger log.Logger) *Service {
svc := &Service{
streamer: streamer,
logger: logger.WithName(loggerName).Register(),
Expand Down Expand Up @@ -196,8 +196,6 @@ func (s *Service) sendPeers(ctx context.Context, peer swarm.Address, peers []swa
continue
}

advertisableUnderlays = p2p.FilterBee260CompatibleUnderlays(s.streamer.IsBee260(peer), advertisableUnderlays)

peersRequest.Peers = append(peersRequest.Peers, &pb.BzzAddress{
Overlay: addr.Overlay.Bytes(),
Underlay: bzz.SerializeUnderlays(advertisableUnderlays),
Expand Down
64 changes: 29 additions & 35 deletions pkg/p2p/libp2p/internal/handshake/handshake.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,20 +67,6 @@ type Addresser interface {
AdvertizableAddrs() ([]ma.Multiaddr, error)
}

type Option struct {
bee260compatibility bool
}

// WithBee260Compatibility option ensures that only one underlay address is
// passed to the peer in p2p protocol messages, so that nodes with version 2.6.0
// and older can deserialize it. This option can be safely removed when bee
// version 2.6.0 is deprecated.
func WithBee260Compatibility(yes bool) func(*Option) {
return func(o *Option) {
o.bee260compatibility = yes
}
}

// Service can perform initiate or handle a handshake between peers.
type Service struct {
signer crypto.Signer
Expand Down Expand Up @@ -144,23 +130,18 @@ func (s *Service) SetPicker(n p2p.Picker) {
}

// Handshake initiates a handshake with a peer.
func (s *Service) Handshake(ctx context.Context, stream p2p.Stream, peerMultiaddrs []ma.Multiaddr, opts ...func(*Option)) (i *Info, err error) {
func (s *Service) Handshake(ctx context.Context, stream p2p.Stream, peerMultiaddrs []ma.Multiaddr) (i *Info, err error) {
loggerV1 := s.logger.V(1).Register()

o := new(Option)
for _, set := range opts {
set(o)
}

ctx, cancel := context.WithTimeout(ctx, handshakeTimeout)
defer cancel()

w, r := protobuf.NewWriterAndReader(stream)

peerMultiaddrs = p2p.FilterBee260CompatibleUnderlays(o.bee260compatibility, peerMultiaddrs)
synUnderlay := bzz.SerializeUnderlays(peerMultiaddrs)
s.logger.Debug("handshake outbound syn underlay", "payload_len", len(synUnderlay), "first_byte", firstByteString(synUnderlay), "payload_prefix", payloadPrefix(synUnderlay))

if err := w.WriteMsgWithContext(ctx, &pb.Syn{
ObservedUnderlay: bzz.SerializeUnderlays(peerMultiaddrs),
ObservedUnderlay: synUnderlay,
}); err != nil {
return nil, fmt.Errorf("write syn message: %w", err)
}
Expand All @@ -172,6 +153,7 @@ func (s *Service) Handshake(ctx context.Context, stream p2p.Stream, peerMultiadd

observedUnderlays, err := bzz.DeserializeUnderlays(resp.Syn.ObservedUnderlay)
if err != nil {
s.logger.Debug("handshake invalid synack observed underlay payload", "payload_len", len(resp.Syn.ObservedUnderlay), "first_byte", firstByteString(resp.Syn.ObservedUnderlay), "payload_prefix", payloadPrefix(resp.Syn.ObservedUnderlay), "error", err)
return nil, ErrInvalidSyn
}

Expand Down Expand Up @@ -212,8 +194,6 @@ func (s *Service) Handshake(ctx context.Context, stream p2p.Stream, peerMultiadd
return a.Equal(b)
})

advertisableUnderlays = p2p.FilterBee260CompatibleUnderlays(o.bee260compatibility, advertisableUnderlays)

bzzAddress, err := bzz.NewAddress(s.signer, advertisableUnderlays, s.overlay, s.networkID, s.nonce)
if err != nil {
return nil, err
Expand Down Expand Up @@ -258,14 +238,9 @@ func (s *Service) Handshake(ctx context.Context, stream p2p.Stream, peerMultiadd
}

// Handle handles an incoming handshake from a peer.
func (s *Service) Handle(ctx context.Context, stream p2p.Stream, peerMultiaddrs []ma.Multiaddr, opts ...func(*Option)) (i *Info, err error) {
func (s *Service) Handle(ctx context.Context, stream p2p.Stream, peerMultiaddrs []ma.Multiaddr) (i *Info, err error) {
loggerV1 := s.logger.V(1).Register()

o := new(Option)
for _, set := range opts {
set(o)
}

ctx, cancel := context.WithTimeout(ctx, handshakeTimeout)
defer cancel()

Expand All @@ -280,6 +255,7 @@ func (s *Service) Handle(ctx context.Context, stream p2p.Stream, peerMultiaddrs

observedUnderlays, err := bzz.DeserializeUnderlays(syn.ObservedUnderlay)
if err != nil {
s.logger.Debug("handshake invalid inbound syn observed underlay payload", "payload_len", len(syn.ObservedUnderlay), "first_byte", firstByteString(syn.ObservedUnderlay), "payload_prefix", payloadPrefix(syn.ObservedUnderlay), "error", err)
return nil, ErrInvalidSyn
}

Expand Down Expand Up @@ -310,20 +286,19 @@ func (s *Service) Handle(ctx context.Context, stream p2p.Stream, peerMultiaddrs
return a.Equal(b)
})

advertisableUnderlays = p2p.FilterBee260CompatibleUnderlays(o.bee260compatibility, advertisableUnderlays)

bzzAddress, err := bzz.NewAddress(s.signer, advertisableUnderlays, s.overlay, s.networkID, s.nonce)
if err != nil {
return nil, err
}

welcomeMessage := s.GetWelcomeMessage()

peerMultiaddrs = p2p.FilterBee260CompatibleUnderlays(o.bee260compatibility, peerMultiaddrs)
synAckObservedUnderlay := bzz.SerializeUnderlays(peerMultiaddrs)
s.logger.Debug("handshake outbound synack observed underlay", "payload_len", len(synAckObservedUnderlay), "first_byte", firstByteString(synAckObservedUnderlay), "payload_prefix", payloadPrefix(synAckObservedUnderlay))

if err := w.WriteMsgWithContext(ctx, &pb.SynAck{
Syn: &pb.Syn{
ObservedUnderlay: bzz.SerializeUnderlays(peerMultiaddrs),
ObservedUnderlay: synAckObservedUnderlay,
},
Ack: &pb.Ack{
Address: &pb.BzzAddress{
Expand Down Expand Up @@ -398,8 +373,27 @@ func (s *Service) GetWelcomeMessage() string {
func (s *Service) parseCheckAck(ack *pb.Ack) (*bzz.Address, error) {
bzzAddress, err := bzz.ParseAddress(ack.Address.Underlay, ack.Address.Overlay, ack.Address.Signature, ack.Nonce, s.validateOverlay, s.networkID)
if err != nil {
s.logger.Debug("handshake invalid ack address payload", "underlay_len", len(ack.Address.Underlay), "underlay_first_byte", firstByteString(ack.Address.Underlay), "underlay_prefix", payloadPrefix(ack.Address.Underlay), "overlay_len", len(ack.Address.Overlay), "error", err)
return nil, ErrInvalidAck
}

return bzzAddress, nil
}

func firstByteString(data []byte) string {
if len(data) == 0 {
return "none"
}
return fmt.Sprintf("0x%02x", data[0])
}

func payloadPrefix(data []byte) string {
if len(data) == 0 {
return ""
}
n := 16
if len(data) < n {
n = len(data)
}
return fmt.Sprintf("%x", data[:n])
}
Loading