Skip to content
Draft
2 changes: 1 addition & 1 deletion cmd/bee/cmd/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ func dbRepairReserve(cmd *cobra.Command) {
}
defer db.Close()

err = migration.ReserveRepairer(db.Storage(), storage.ChunkType, logger)()
err = migration.ReserveRepair(db.Storage(), storage.ChunkType, logger)()
if err != nil {
return fmt.Errorf("repair: %w", err)
}
Expand Down
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"
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 just ""?

}
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
Loading