Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
eebec22
chore: remove legacy code
sbackend123 Mar 25, 2026
af6c38e
chore: remove legacy code for underlay addresses
sbackend123 Mar 30, 2026
71d07fd
chore: noop old migrations and remove legacy underlay test
sbackend123 Mar 30, 2026
2ee43af
chore: remove underlayListPrefix prefix
sbackend123 Mar 31, 2026
68613ec
fix: restore underlay prefix and tests for backward compatibility wit…
sbackend123 Apr 1, 2026
47166e4
Merge branch 'master' into chore/remove-backwards-compatibility-with-…
sbackend123 Apr 22, 2026
fff123b
Merge branch 'refs/heads/master' into chore/remove-backwards-compatib…
sbackend123 Apr 22, 2026
8a068fc
fix: remove empty files
sbackend123 Apr 22, 2026
70022f4
fix: remove legacy migrations files
sbackend123 Apr 22, 2026
5ac22ee
fix: fix broken merge
sbackend123 Apr 22, 2026
1e92169
fix: remove unnecessary changes
sbackend123 Apr 26, 2026
c9674df
fix: revert unnecessary changes
sbackend123 Apr 26, 2026
4758020
fix: revert unnecessary changes 3
sbackend123 Apr 27, 2026
08386b3
fix: return comments
sbackend123 Apr 27, 2026
e0ce20d
fix: clean up
sbackend123 Apr 28, 2026
7adc040
fix: remove single underlay address complitely
sbackend123 Apr 30, 2026
90459ba
fix: added comment
sbackend123 Apr 30, 2026
2a663ab
fix: cleanup
sbackend123 Apr 30, 2026
3058490
Merge branch 'master' into chore/remove-backwards-compatibility-with-…
sbackend123 Jun 1, 2026
5480ccf
fix: merge with master and fix merge
sbackend123 Jun 1, 2026
e5995f7
fix: fix unit tests
sbackend123 Jun 1, 2026
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
25 changes: 20 additions & 5 deletions pkg/bzz/address_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,12 @@ func TestBzzAddress(t *testing.T) {
t.Fatal(err)
}

bzzAddress2, err := bzz.ParseAddress(node1ma.Bytes(), overlay.Bytes(), bzzAddress.Signature, nonce, 1, 3, chequebook.Bytes())
node1maSerialized, err := bzz.SerializeUnderlays([]multiaddr.Multiaddr{node1ma})
if err != nil {
t.Fatal(err)
}

bzzAddress2, err := bzz.ParseAddress(node1maSerialized, overlay.Bytes(), bzzAddress.Signature, nonce, 1, 3, chequebook.Bytes())
if err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -100,8 +105,13 @@ func TestParseAddress_ChequebookIsSigned(t *testing.T) {
t.Fatal(err)
}

node1maSerialized, err := bzz.SerializeUnderlays([]multiaddr.Multiaddr{node1ma})
if err != nil {
t.Fatal(err)
}

// Swapping the chequebook between sign and parse must invalidate the record.
if _, err := bzz.ParseAddress(node1ma.Bytes(), overlay.Bytes(), addr.Signature, nonce, 1, 3, tamperedChequebook.Bytes()); !errors.Is(err, bzz.ErrInvalidAddress) {
if _, err := bzz.ParseAddress(node1maSerialized, overlay.Bytes(), addr.Signature, nonce, 1, 3, tamperedChequebook.Bytes()); !errors.Is(err, bzz.ErrInvalidAddress) {
t.Fatalf("ParseAddress with tampered chequebook: want ErrInvalidAddress, got %v", err)
}
}
Expand Down Expand Up @@ -148,9 +158,14 @@ func TestParseAddress_RejectsNonCanonicalChequebookLength(t *testing.T) {
{"long 48 bytes", long48},
}

node1maSerialized, err := bzz.SerializeUnderlays([]multiaddr.Multiaddr{node1ma})
if err != nil {
t.Fatal(err)
}

for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
if _, err := bzz.ParseAddress(node1ma.Bytes(), overlay.Bytes(), addr.Signature, nonce, 1, 3, tc.wire); !errors.Is(err, bzz.ErrInvalidAddress) {
if _, err := bzz.ParseAddress(node1maSerialized, overlay.Bytes(), addr.Signature, nonce, 1, 3, tc.wire); !errors.Is(err, bzz.ErrInvalidAddress) {
t.Fatalf("want ErrInvalidAddress for %d-byte chequebook wire, got %v", len(tc.wire), err)
}
})
Expand All @@ -161,10 +176,10 @@ func TestParseAddress_RejectsNonCanonicalChequebookLength(t *testing.T) {
if err != nil {
t.Fatal(err)
}
if _, err := bzz.ParseAddress(node1ma.Bytes(), overlay.Bytes(), emptyAddr.Signature, nonce, 1, 3, nil); err != nil {
if _, err := bzz.ParseAddress(node1maSerialized, overlay.Bytes(), emptyAddr.Signature, nonce, 1, 3, nil); err != nil {
t.Fatalf("empty chequebook must parse, got %v", err)
}
if _, err := bzz.ParseAddress(node1ma.Bytes(), overlay.Bytes(), addr.Signature, nonce, 1, 3, cbBytes); err != nil {
if _, err := bzz.ParseAddress(node1maSerialized, overlay.Bytes(), addr.Signature, nonce, 1, 3, cbBytes); err != nil {
t.Fatalf("20-byte chequebook must parse, got %v", err)
}
}
Expand Down
1 change: 0 additions & 1 deletion pkg/bzz/export_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
package bzz

const (
UnderlayListPrefix = underlayListPrefix
MaxUnderlaysPerPeer = maxUnderlaysPerPeer
MaxUnderlayBytes = maxUnderlayBytes
)
Expand Down
44 changes: 4 additions & 40 deletions pkg/bzz/underlay.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,6 @@ var (
ErrUnderlayCountExceeded = errors.New("underlay count exceeded")
)

// underlayListPrefix is a magic byte designated for identifying a serialized list of multiaddrs.
// A value of 0x99 (153) was chosen as it is not a defined multiaddr protocol code.
// This ensures that a failure is triggered by the original multiaddr.NewMultiaddrBytes function,
// which expects a valid protocol code at the start of the data.
const underlayListPrefix byte = 0x99

// maxUnderlaysPerPeer is the maximum number of underlay addresses allowed per peer.
// This prevents abuse where a malicious peer sends a huge number of multiaddrs.
const maxUnderlaysPerPeer = 20
Expand All @@ -39,29 +33,13 @@ const maxUnderlaysPerPeer = 20
const maxUnderlayBytes = 2048

// 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.
// Returns an error wrapping ErrUnderlayCountExceeded or ErrUnderlayByteSizeExceeded
// if the limits are violated.
func SerializeUnderlays(addrs []multiaddr.Multiaddr) ([]byte, error) {
if len(addrs) > maxUnderlaysPerPeer {
return nil, fmt.Errorf("underlay count %d exceeds maximum of %d: %w", len(addrs), maxUnderlaysPerPeer, ErrUnderlayCountExceeded)
}

// Backward compatibility if exactly one address is present.
if len(addrs) == 1 {
b := addrs[0].Bytes()
if len(b) > maxUnderlayBytes {
return nil, fmt.Errorf("underlay data size %d exceeds maximum of %d bytes: %w", len(b), maxUnderlayBytes, ErrUnderlayByteSizeExceeded)
}
return b, nil
}

// 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]...
// The format is: [varint_len_1][addr_1_bytes]...
var buf bytes.Buffer
buf.WriteByte(underlayListPrefix)

for _, addr := range addrs {
addrBytes := addr.Bytes()
Expand All @@ -77,33 +55,19 @@ func SerializeUnderlays(addrs []multiaddr.Multiaddr) ([]byte, error) {
}

// 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")
return nil, nil
}

if len(data) > maxUnderlayBytes {
return nil, fmt.Errorf("underlay data size %d exceeds maximum of %d bytes: %w", len(data), maxUnderlayBytes, ErrUnderlayByteSizeExceeded)
}

// If the data begins with the magic prefix, it is handled as a list.
if data[0] == underlayListPrefix {
return deserializeList(data[1:])
}

// Otherwise, the data is handled as a single, backward-compatible multiaddr.
addr, err := multiaddr.NewMultiaddrBytes(data)
if err != nil {
return nil, fmt.Errorf("failed to parse as single multiaddr: %w", err)
}
// The result is returned as a single-element slice for a consistent return type.
return []multiaddr.Multiaddr{addr}, nil
return deserializeList(data)
}

// deserializeList handles the parsing of the custom list format.
// The provided data is expected to have already been stripped of the underlayListPrefix.
// deserializeList handles the parsing of the underlays list format.
func deserializeList(data []byte) ([]multiaddr.Multiaddr, error) {
var addrs []multiaddr.Multiaddr
r := bytes.NewReader(data)
Expand Down
90 changes: 9 additions & 81 deletions pkg/bzz/underlay_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,28 +24,15 @@ func TestSerializeUnderlays(t *testing.T) {
addrs := []multiaddr.Multiaddr{ip4TCPAddr, p2pAddr, wssAddr, dnsSwarmAddr}
serialized := mustSerializeUnderlays(t, addrs)

if serialized[0] != bzz.UnderlayListPrefix {
t.Errorf("expected prefix %x for multiple addresses, got %x", bzz.UnderlayListPrefix, serialized[0])
}
})

t.Run("single address list", func(t *testing.T) {
addrs := []multiaddr.Multiaddr{dnsSwarmAddr}
serialized := mustSerializeUnderlays(t, 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")
if len(serialized) == 0 {
t.Error("expected serialized bytes for non-empty list")
}
})

t.Run("empty list", func(t *testing.T) {
addrs := []multiaddr.Multiaddr{}
serialized := mustSerializeUnderlays(t, addrs)
expected := []byte{bzz.UnderlayListPrefix}
expected := []byte{}
if !bytes.Equal(serialized, expected) {
t.Errorf("expected %x for empty list, got %x", expected, serialized)
}
Expand All @@ -54,7 +41,7 @@ func TestSerializeUnderlays(t *testing.T) {
t.Run("nil list", func(t *testing.T) {
var addrs []multiaddr.Multiaddr = nil
serialized := mustSerializeUnderlays(t, addrs)
expected := []byte{bzz.UnderlayListPrefix}
expected := []byte{}
if !bytes.Equal(serialized, expected) {
t.Errorf("expected %x for nil list, got %x", expected, serialized)
}
Expand Down Expand Up @@ -90,26 +77,8 @@ 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 {
t.Error("expected an error for empty slice, but got nil")
}
})

t.Run("list with only prefix", func(t *testing.T) {
deserialized, err := bzz.DeserializeUnderlays([]byte{bzz.UnderlayListPrefix})
deserialized, err := bzz.DeserializeUnderlays([]byte{})
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
Expand All @@ -121,8 +90,8 @@ func TestDeserializeUnderlays(t *testing.T) {
t.Run("serialize deserialize empty list", func(t *testing.T) {
addrs := []multiaddr.Multiaddr{}
serialized := mustSerializeUnderlays(t, addrs)
if !bytes.Equal(serialized, []byte{bzz.UnderlayListPrefix}) {
t.Errorf("expected %v, got %v", []byte{bzz.UnderlayListPrefix}, serialized)
if !bytes.Equal(serialized, []byte{}) {
t.Errorf("expected %v, got %v", []byte{}, serialized)
}
deserialized, err := bzz.DeserializeUnderlays(serialized)
if err != nil {
Expand All @@ -135,8 +104,8 @@ func TestDeserializeUnderlays(t *testing.T) {

t.Run("serialize deserialize nil list", func(t *testing.T) {
serialized := mustSerializeUnderlays(t, nil)
if !bytes.Equal(serialized, []byte{bzz.UnderlayListPrefix}) {
t.Errorf("expected %v, got %v", []byte{bzz.UnderlayListPrefix}, serialized)
if !bytes.Equal(serialized, []byte{}) {
t.Errorf("expected %v, got %v", []byte{}, serialized)
}
deserialized, err := bzz.DeserializeUnderlays(serialized)
if err != nil {
Expand All @@ -150,7 +119,6 @@ func TestDeserializeUnderlays(t *testing.T) {
t.Run("corrupted list - length too long", func(t *testing.T) {
maBytes := ip4TCPAddr.Bytes()
var buf bytes.Buffer
buf.WriteByte(bzz.UnderlayListPrefix)
buf.Write(varint.ToUvarint(uint64(len(maBytes) + 5))) // Write a length that is too long
buf.Write(maBytes)

Expand All @@ -163,7 +131,6 @@ func TestDeserializeUnderlays(t *testing.T) {
t.Run("corrupted list - invalid multiaddr bytes", func(t *testing.T) {
invalidAddrBytes := []byte{0xde, 0xad, 0xbe, 0xef}
var buf bytes.Buffer
buf.WriteByte(bzz.UnderlayListPrefix)
buf.Write(varint.ToUvarint(uint64(len(invalidAddrBytes))))
buf.Write(invalidAddrBytes)

Expand All @@ -177,7 +144,6 @@ func TestDeserializeUnderlays(t *testing.T) {
// Build a list with MaxUnderlaysPerPeer+1 entries.
addr := mustNewMultiaddr(t, "/ip4/1.2.3.4/tcp/80")
var buf bytes.Buffer
buf.WriteByte(bzz.UnderlayListPrefix)
for range bzz.MaxUnderlaysPerPeer + 1 {
addrBytes := addr.Bytes()
buf.Write(varint.ToUvarint(uint64(len(addrBytes))))
Expand All @@ -193,7 +159,6 @@ func TestDeserializeUnderlays(t *testing.T) {
// Build a list with exactly MaxUnderlaysPerPeer entries.
addr := mustNewMultiaddr(t, "/ip4/1.2.3.4/tcp/80")
var buf bytes.Buffer
buf.WriteByte(bzz.UnderlayListPrefix)
for range bzz.MaxUnderlaysPerPeer {
addrBytes := addr.Bytes()
buf.Write(varint.ToUvarint(uint64(len(addrBytes))))
Expand All @@ -212,7 +177,6 @@ func TestDeserializeUnderlays(t *testing.T) {
// Build a payload larger than MaxUnderlayBytes.
addr := mustNewMultiaddr(t, "/ip4/1.2.3.4/tcp/80")
var buf bytes.Buffer
buf.WriteByte(bzz.UnderlayListPrefix)
for buf.Len() <= bzz.MaxUnderlayBytes {
addrBytes := addr.Bytes()
buf.Write(varint.ToUvarint(uint64(len(addrBytes))))
Expand Down Expand Up @@ -268,42 +232,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 := mustSerializeUnderlays(t, 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 := mustSerializeUnderlays(t, 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 mustSerializeUnderlays(tb testing.TB, addrs []multiaddr.Multiaddr) []byte {
tb.Helper()
b, err := bzz.SerializeUnderlays(addrs)
Expand Down
4 changes: 2 additions & 2 deletions pkg/hive/hive.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ type Options struct {
}

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

func New(streamer p2p.Bee260CompatibilityStreamer, addressbook addressbook.GetPutter, networkID uint64, overlay swarm.Address, logger log.Logger, o Options) *Service {
func New(streamer p2p.Streamer, addressbook addressbook.GetPutter, networkID uint64, overlay swarm.Address, logger log.Logger, o Options) *Service {
svc := &Service{
streamer: streamer,
logger: logger.WithName(loggerName).Register(),
Expand Down
Loading
Loading