Skip to content

Commit 096af00

Browse files
committed
[GH-846] AddrInfo/AddrInfoSlice reworked.
We now correctly handle multiaddresses for one peer. Both AddrInfo and AddrInfoSlice are always serialized by a flat list of all multiaddresses of all peers. During deserialization in case of AddrInfoSlice we group by PeerID.
1 parent c6e4e74 commit 096af00

16 files changed

+343
-97
lines changed

nil/cmd/nild/devnet.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"github.com/NilFoundation/nil/nil/internal/telemetry"
1919
"github.com/NilFoundation/nil/nil/services/nilservice"
2020
"github.com/ethereum/go-ethereum/crypto"
21+
"github.com/libp2p/go-libp2p/core/peer"
2122
"github.com/spf13/cobra"
2223
"gopkg.in/yaml.v3"
2324
)
@@ -463,7 +464,7 @@ func getPeer(srv server) network.AddrInfo {
463464
func getPeers(servers []server, indices []int) network.AddrInfoSlice {
464465
peers := make(network.AddrInfoSlice, len(indices))
465466
for i, idx := range indices {
466-
peers[i] = getPeer(servers[idx])
467+
peers[i] = peer.AddrInfo(getPeer(servers[idx]))
467468
}
468469
return peers
469470
}

nil/common/p_value_slice.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import (
44
"bytes"
55
"encoding"
66
"encoding/csv"
7-
"fmt"
87
"strings"
98

109
"github.com/spf13/pflag"
@@ -27,7 +26,7 @@ var (
2726
)
2827

2928
func (s *PValueSlice[T, S]) Set(value string) error {
30-
parts, err := readAsCSV(value)
29+
parts, err := ReadAsCSV(value)
3130
if err != nil {
3231
return err
3332
}
@@ -56,7 +55,7 @@ func (s *PValueSlice[T, S]) String() string {
5655
}
5756

5857
func (s *PValueSlice[T, S]) Type() string {
59-
return fmt.Sprintf("PValueSlice[%s]", T(new(S)).Type())
58+
return "[]" + T(new(S)).Type()
6059
}
6160

6261
func (s PValueSlice[T, S]) MarshalYAML() (any, error) {
@@ -85,7 +84,7 @@ func (s *PValueSlice[T, S]) UnmarshalYAML(value *yaml.Node) error {
8584
}
8685

8786
// Copy of private functions from pflag used in stringSliceValue implementation.
88-
func readAsCSV(val string) ([]string, error) {
87+
func ReadAsCSV(val string) ([]string, error) {
8988
if val == "" {
9089
return []string{}, nil
9190
}

nil/common/p_value_slice_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ func TestValueSlice_Type(t *testing.T) {
6161
t.Parallel()
6262

6363
var vs PValueSlice[*MockValue, MockValue]
64-
require.Equal(t, "PValueSlice[mock]", vs.Type())
64+
require.Equal(t, "[]mock", vs.Type())
6565
}
6666

6767
type TestConfig struct {

nil/internal/collate/syncer.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ type SyncerConfig struct {
3737
Name string
3838
ShardId types.ShardId
3939
Timeout time.Duration // pull blocks if no new blocks appear in the topic for this duration
40-
BootstrapPeers []network.AddrInfo
40+
BootstrapPeers network.AddrInfoSlice
4141
ZeroStateConfig *execution.ZeroStateConfig
4242
}
4343

@@ -130,7 +130,7 @@ func (s *Syncer) fetchRemoteVersion(ctx context.Context) (NodeVersion, error) {
130130
var err error
131131
for _, peer := range s.config.BootstrapPeers {
132132
var peerId network.PeerID
133-
peerId, err = s.networkManager.Connect(ctx, peer)
133+
peerId, err = s.networkManager.Connect(ctx, network.AddrInfo(peer))
134134
if err != nil {
135135
continue
136136
}
@@ -153,7 +153,7 @@ func (s *Syncer) fetchRemoteVersion(ctx context.Context) (NodeVersion, error) {
153153
func (s *Syncer) fetchSnapshot(ctx context.Context) error {
154154
var err error
155155
for _, peer := range s.config.BootstrapPeers {
156-
err = fetchSnapshot(ctx, s.networkManager, peer, s.db, s.logger)
156+
err = fetchSnapshot(ctx, s.networkManager, network.AddrInfo(peer), s.db, s.logger)
157157
if err == nil {
158158
return nil
159159
}

nil/internal/network/addr_info.go

Lines changed: 146 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,41 +2,42 @@ package network
22

33
import (
44
"errors"
5+
"fmt"
6+
"slices"
7+
"strings"
58

69
"github.com/NilFoundation/nil/nil/common"
710
"github.com/libp2p/go-libp2p/core/peer"
11+
ma "github.com/multiformats/go-multiaddr"
12+
"github.com/spf13/pflag"
813
"gopkg.in/yaml.v3"
914
)
1015

1116
type AddrInfo peer.AddrInfo
1217

18+
var _ pflag.Value = (*AddrInfo)(nil)
19+
1320
func (a AddrInfo) Empty() bool {
1421
return errors.Is(a.ID.Validate(), peer.ErrEmptyPeerID)
1522
}
1623

1724
func (a *AddrInfo) Set(value string) error {
18-
addr, err := peer.AddrInfoFromString(value)
25+
addrInfos, err := addrInfosFromString(value)
1926
if err != nil {
2027
return err
2128
}
22-
*a = AddrInfo(*addr)
29+
if len(addrInfos) == 0 {
30+
return fmt.Errorf("%s is not a valid address", value)
31+
}
32+
if len(addrInfos) > 1 {
33+
return fmt.Errorf("not all multiaddresses belong to the same peer: %s", value)
34+
}
35+
*a = AddrInfo(addrInfos[0])
2336
return nil
2437
}
2538

2639
func (a AddrInfo) String() string {
27-
mu, err := peer.AddrInfoToP2pAddrs((*peer.AddrInfo)(&a))
28-
if err != nil {
29-
return err.Error()
30-
}
31-
values := make([]string, len(mu))
32-
for i, val := range mu {
33-
values[i] = val.String()
34-
}
35-
str, err := common.WriteAsCSV(values)
36-
if err != nil {
37-
return err.Error()
38-
}
39-
return str
40+
return addrInfosToString(peer.AddrInfo(a))
4041
}
4142

4243
func (a *AddrInfo) Type() string {
@@ -59,12 +60,136 @@ func (a *AddrInfo) UnmarshalYAML(value *yaml.Node) error {
5960
return a.UnmarshalText([]byte(value.Value))
6061
}
6162

62-
type AddrInfoSlice = common.PValueSlice[*AddrInfo, AddrInfo]
63+
type AddrInfoSlice []peer.AddrInfo
64+
65+
func AsAddrInfoSlice(addrInfos ...AddrInfo) AddrInfoSlice {
66+
return slices.Collect(
67+
common.Transform(
68+
slices.Values(addrInfos),
69+
func(a AddrInfo) peer.AddrInfo { return peer.AddrInfo(a) }))
70+
}
71+
72+
var _ pflag.Value = (*AddrInfoSlice)(nil)
73+
74+
func (s *AddrInfoSlice) Set(value string) (err error) {
75+
*s, err = addrInfosFromString(value)
76+
return
77+
}
78+
79+
// String returns one multiaddress per item including PeerID, comma-separated
80+
func (s *AddrInfoSlice) String() string {
81+
return addrInfosToString(*s...)
82+
}
83+
84+
func (s *AddrInfoSlice) Type() string {
85+
return "[]AddrInfo"
86+
}
87+
88+
// Strings returns one multiaddress per item including PeerID, in each array element
89+
func (s *AddrInfoSlice) Strings() ([]string, error) {
90+
return addrInfosToStrings(*s...)
91+
}
92+
93+
func (s *AddrInfoSlice) FromStrings(addrs []string) (err error) {
94+
*s, err = addrInfosFromStrings(addrs)
95+
return
96+
}
97+
98+
func (s AddrInfoSlice) MarshalText() ([]byte, error) {
99+
return []byte(s.String()), nil
100+
}
101+
102+
func (s *AddrInfoSlice) UnmarshalText(text []byte) (err error) {
103+
return s.Set(string(text))
104+
}
105+
106+
func (s AddrInfoSlice) MarshalYAML() (any, error) {
107+
return addrInfosToStrings(s...)
108+
}
109+
110+
func (s *AddrInfoSlice) UnmarshalYAML(node *yaml.Node) error {
111+
if node.Kind != yaml.SequenceNode {
112+
return fmt.Errorf("expected sequence node for AddrInfoSlice, got %s", kindToString(node.Kind))
113+
}
114+
115+
addrs := make([]string, len(node.Content))
116+
for i, item := range node.Content {
117+
if item.Kind != yaml.ScalarNode {
118+
return fmt.Errorf("expected scalar value at index %d, got %s", i, kindToString(item.Kind))
119+
}
120+
addrs[i] = item.Value
121+
}
122+
return s.FromStrings(addrs)
123+
}
124+
125+
func addrInfosFromStrings(addrs []string) ([]peer.AddrInfo, error) {
126+
var err error
127+
mas := make([]ma.Multiaddr, len(addrs))
128+
for i, addr := range addrs {
129+
mas[i], err = ma.NewMultiaddr(addr)
130+
if err != nil {
131+
return nil, err
132+
}
133+
}
134+
135+
addrInfos, err := peer.AddrInfosFromP2pAddrs(mas...)
136+
if err != nil {
137+
return nil, err
138+
}
139+
slices.SortFunc(addrInfos, func(l, r peer.AddrInfo) int {
140+
return strings.Compare(string(l.ID), string(r.ID))
141+
})
142+
return addrInfos, nil
143+
}
144+
145+
func addrInfosFromString(value string) ([]peer.AddrInfo, error) {
146+
addrs, err := common.ReadAsCSV(value)
147+
if err != nil {
148+
return nil, err
149+
}
150+
return addrInfosFromStrings(addrs)
151+
}
152+
153+
func addrInfosToStrings(addrInfos ...peer.AddrInfo) ([]string, error) {
154+
result := make([]string, 0, len(addrInfos))
155+
for _, addrInfo := range addrInfos {
156+
multiAddrs, err := peer.AddrInfoToP2pAddrs(&addrInfo)
157+
if err != nil {
158+
return nil, err
159+
}
160+
result = slices.AppendSeq(
161+
result,
162+
common.Transform(
163+
slices.Values(multiAddrs),
164+
func(addr ma.Multiaddr) string { return addr.String() }))
165+
}
166+
return result, nil
167+
}
168+
169+
func addrInfosToString(addrInfos ...peer.AddrInfo) string {
170+
addrs, err := addrInfosToStrings(addrInfos...)
171+
if err != nil {
172+
return err.Error()
173+
}
174+
result, err := common.WriteAsCSV(addrs)
175+
if err != nil {
176+
return err.Error()
177+
}
178+
return result
179+
}
63180

64-
func ToLibP2pAddrInfoSlice(s AddrInfoSlice) []peer.AddrInfo {
65-
res := make([]peer.AddrInfo, len(s))
66-
for i, a := range s {
67-
res[i] = peer.AddrInfo(a)
181+
func kindToString(kind yaml.Kind) string {
182+
switch kind {
183+
case yaml.DocumentNode:
184+
return "document node"
185+
case yaml.SequenceNode:
186+
return "sequence node"
187+
case yaml.MappingNode:
188+
return "mapping node"
189+
case yaml.ScalarNode:
190+
return "scalar node"
191+
case yaml.AliasNode:
192+
return "alias node"
68193
}
69-
return res
194+
return "unknown node type"
70195
}

0 commit comments

Comments
 (0)