@@ -14,12 +14,15 @@ import (
1414 "encoding/json"
1515 "errors"
1616 "fmt"
17+ "slices"
18+ "sort"
1719
1820 "github.com/ethereum/go-ethereum/common"
1921 "github.com/ethersphere/bee/v2/pkg/crypto"
2022 "github.com/ethersphere/bee/v2/pkg/swarm"
2123
2224 ma "github.com/multiformats/go-multiaddr"
25+ manet "github.com/multiformats/go-multiaddr/net"
2326)
2427
2528var ErrInvalidAddress = errors .New ("invalid address" )
@@ -28,33 +31,31 @@ var ErrInvalidAddress = errors.New("invalid address")
2831// It consists of a peers underlay (physical) address, overlay (topology) address and signature.
2932// Signature is used to verify the `Overlay/Underlay` pair, as it is based on `underlay|networkID`, signed with the public key of Overlay address
3033type Address struct {
31- Underlay ma.Multiaddr
34+ Underlays [] ma.Multiaddr
3235 Overlay swarm.Address
3336 Signature []byte
3437 Nonce []byte
3538 EthereumAddress []byte
3639}
3740
3841type addressJSON struct {
39- Overlay string `json:"overlay"`
40- Underlay string `json:"underlay"`
41- Signature string `json:"signature"`
42- Nonce string `json:"transaction"`
42+ Overlay string `json:"overlay"`
43+ Underlay string `json:"underlay"` // For backward compatibility
44+ Underlays []string `json:"underlays"`
45+ Signature string `json:"signature"`
46+ Nonce string `json:"transaction"`
4347}
4448
45- func NewAddress (signer crypto.Signer , underlay ma.Multiaddr , overlay swarm.Address , networkID uint64 , nonce []byte ) (* Address , error ) {
46- underlayBinary , err := underlay .MarshalBinary ()
47- if err != nil {
48- return nil , err
49- }
49+ func NewAddress (signer crypto.Signer , underlays []ma.Multiaddr , overlay swarm.Address , networkID uint64 , nonce []byte ) (* Address , error ) {
50+ underlaysBinary := SerializeUnderlays (underlays )
5051
51- signature , err := signer .Sign (generateSignData (underlayBinary , overlay .Bytes (), networkID ))
52+ signature , err := signer .Sign (generateSignData (underlaysBinary , overlay .Bytes (), networkID ))
5253 if err != nil {
5354 return nil , err
5455 }
5556
5657 return & Address {
57- Underlay : underlay ,
58+ Underlays : underlays ,
5859 Overlay : overlay ,
5960 Signature : signature ,
6061 Nonce : nonce ,
@@ -77,8 +78,13 @@ func ParseAddress(underlay, overlay, signature, nonce []byte, validateOverlay bo
7778 }
7879 }
7980
80- multiUnderlay , err := ma . NewMultiaddrBytes (underlay )
81+ multiUnderlays , err := DeserializeUnderlays (underlay )
8182 if err != nil {
83+ return nil , fmt .Errorf ("deserialize underlays: %w: %w" , ErrInvalidAddress , err )
84+ }
85+
86+ if len (multiUnderlays ) == 0 {
87+ // no underlays sent
8288 return nil , ErrInvalidAddress
8389 }
8490
@@ -88,7 +94,7 @@ func ParseAddress(underlay, overlay, signature, nonce []byte, validateOverlay bo
8894 }
8995
9096 return & Address {
91- Underlay : multiUnderlay ,
97+ Underlays : multiUnderlays ,
9298 Overlay : swarm .NewAddress (overlay ),
9399 Signature : signature ,
94100 Nonce : nonce ,
@@ -109,21 +115,49 @@ func (a *Address) Equal(b *Address) bool {
109115 return a == b
110116 }
111117
112- return a .Overlay .Equal (b .Overlay ) && multiaddrEqual (a .Underlay , b .Underlay ) && bytes .Equal (a .Signature , b .Signature ) && bytes .Equal (a .Nonce , b .Nonce )
118+ return a .Overlay .Equal (b .Overlay ) && AreUnderlaysEqual (a .Underlays , b .Underlays ) && bytes .Equal (a .Signature , b .Signature ) && bytes .Equal (a .Nonce , b .Nonce )
113119}
114120
115- func multiaddrEqual (a , b ma.Multiaddr ) bool {
116- if a == nil || b == nil {
117- return a == b
121+ func AreUnderlaysEqual (a , b [] ma.Multiaddr ) bool {
122+ if len ( a ) != len ( b ) {
123+ return false
118124 }
119125
120- return a .Equal (b )
126+ used := make ([]bool , len (b ))
127+ for i := range len (a ) {
128+ found := false
129+ for j := range len (b ) {
130+ if used [j ] {
131+ continue
132+ }
133+ if a [i ].Equal (b [j ]) {
134+ used [j ] = true
135+ found = true
136+ break
137+ }
138+ }
139+ if ! found {
140+ return false
141+ }
142+ }
143+ return true
121144}
122145
123146func (a * Address ) MarshalJSON () ([]byte , error ) {
147+ if len (a .Underlays ) == 0 {
148+ return nil , fmt .Errorf ("no underlays for %s" , a .Overlay )
149+ }
150+
151+ // select the underlay address for backward compatibility
152+ var underlay string
153+ if v := SelectBestAdvertisedAddress (a .Underlays , nil ); v != nil {
154+ underlay = v .String ()
155+ }
156+
124157 return json .Marshal (& addressJSON {
125158 Overlay : a .Overlay .String (),
126- Underlay : a .Underlay .String (),
159+ Underlay : underlay ,
160+ Underlays : a .underlaysAsStrings (),
127161 Signature : base64 .StdEncoding .EncodeToString (a .Signature ),
128162 Nonce : common .Bytes2Hex (a .Nonce ),
129163 })
@@ -143,23 +177,80 @@ func (a *Address) UnmarshalJSON(b []byte) error {
143177
144178 a .Overlay = addr
145179
146- m , err := ma .NewMultiaddr (v .Underlay )
180+ // append the underlay for backward compatibility
181+ if ! slices .Contains (v .Underlays , v .Underlay ) {
182+ v .Underlays = append (v .Underlays , v .Underlay )
183+ }
184+
185+ multiaddrs , err := parseMultiaddrs (v .Underlays )
147186 if err != nil {
148187 return err
149188 }
150189
151- a .Underlay = m
190+ a .Underlays = multiaddrs
152191 a .Signature , err = base64 .StdEncoding .DecodeString (v .Signature )
153192 a .Nonce = common .Hex2Bytes (v .Nonce )
154193 return err
155194}
156195
157196func (a * Address ) String () string {
158- return fmt .Sprintf ("[Underlay: %v, Overlay %v, Signature %x, Transaction %x]" , a .Underlay , a .Overlay , a .Signature , a .Nonce )
197+ return fmt .Sprintf ("[Underlay: %v, Overlay %v, Signature %x, Transaction %x]" , a .underlaysAsStrings () , a .Overlay , a .Signature , a .Nonce )
159198}
160199
161200// ShortString returns shortened versions of bzz address in a format: [Overlay, Underlay]
162201// It can be used for logging
163202func (a * Address ) ShortString () string {
164- return fmt .Sprintf ("[Overlay: %s, Underlay: %s]" , a .Overlay .String (), a .Underlay .String ())
203+ return fmt .Sprintf ("[Overlay: %s, Underlays: %v]" , a .Overlay .String (), a .underlaysAsStrings ())
204+ }
205+
206+ func (a * Address ) underlaysAsStrings () []string {
207+ underlays := make ([]string , len (a .Underlays ))
208+ for i , underlay := range a .Underlays {
209+ underlays [i ] = underlay .String ()
210+ }
211+ return underlays
212+ }
213+
214+ func parseMultiaddrs (addrs []string ) ([]ma.Multiaddr , error ) {
215+ multiAddrs := make ([]ma.Multiaddr , len (addrs ))
216+ for i , addr := range addrs {
217+ multiAddr , err := ma .NewMultiaddr (addr )
218+ if err != nil {
219+ return nil , err
220+ }
221+ multiAddrs [i ] = multiAddr
222+ }
223+ return multiAddrs , nil
224+ }
225+
226+ func SelectBestAdvertisedAddress (addrs []ma.Multiaddr , fallback ma.Multiaddr ) ma.Multiaddr {
227+ if len (addrs ) == 0 {
228+ return fallback
229+ }
230+
231+ hasTCPProtocol := func (addr ma.Multiaddr ) bool {
232+ _ , err := addr .ValueForProtocol (ma .P_TCP )
233+ return err == nil
234+ }
235+
236+ // Sort addresses to prioritize TCP over other protocols
237+ sort .SliceStable (addrs , func (i , j int ) bool {
238+ iTCP := hasTCPProtocol (addrs [i ])
239+ jTCP := hasTCPProtocol (addrs [j ])
240+ return iTCP && ! jTCP
241+ })
242+
243+ for _ , addr := range addrs {
244+ if manet .IsPublicAddr (addr ) {
245+ return addr
246+ }
247+ }
248+
249+ for _ , addr := range addrs {
250+ if ! manet .IsPrivateAddr (addr ) {
251+ return addr
252+ }
253+ }
254+
255+ return addrs [0 ]
165256}
0 commit comments