constructor: break down libp2p logic
License: MIT Signed-off-by: Łukasz Magiera <magik6k@gmail.com>
Łukasz Magiera committed
Apr 30, 2019 at 00:03 UTC
e133058487c61939f928c33e4f0f28a1e19867ba
13 files changed
+613
-508
core/node/groups.go
-1
@@ -38,7 +38,6 @@ var BaseLibP2P = fx.Options(
38
)
39
40
func LibP2P(bcfg *BuildCfg, cfg *config.Config) fx.Option {
41
-
41
// parse ConnMgr config
42
43
grace := config.DefaultConnMgrGracePeriod
core/node/libp2p/addrs.go
new
+117
@@ -0,0 +1,117 @@
1
+package libp2p
2
+
3
+import (
4
+ "fmt"
5
+
6
+ "github.com/libp2p/go-libp2p"
7
+ host "github.com/libp2p/go-libp2p-host"
8
+ p2pbhost "github.com/libp2p/go-libp2p/p2p/host/basic"
9
+ mafilter "github.com/libp2p/go-maddr-filter"
10
+ ma "github.com/multiformats/go-multiaddr"
11
+ mamask "github.com/whyrusleeping/multiaddr-filter"
12
+)
13
+
14
+func AddrFilters(filters []string) func() (opts Libp2pOpts, err error) {
15
+ return func() (opts Libp2pOpts, err error) {
16
+ for _, s := range filters {
17
+ f, err := mamask.NewMask(s)
18
+ if err != nil {
19
+ return opts, fmt.Errorf("incorrectly formatted address filter in config: %s", s)
20
+ }
21
+ opts.Opts = append(opts.Opts, libp2p.FilterAddresses(f))
22
+ }
23
+ return opts, nil
24
+ }
25
+}
26
+
27
+func makeAddrsFactory(announce []string, noAnnounce []string) (p2pbhost.AddrsFactory, error) {
28
+ var annAddrs []ma.Multiaddr
29
+ for _, addr := range announce {
30
+ maddr, err := ma.NewMultiaddr(addr)
31
+ if err != nil {
32
+ return nil, err
33
+ }
34
+ annAddrs = append(annAddrs, maddr)
35
+ }
36
+
37
+ filters := mafilter.NewFilters()
38
+ noAnnAddrs := map[string]bool{}
39
+ for _, addr := range noAnnounce {
40
+ f, err := mamask.NewMask(addr)
41
+ if err == nil {
42
+ filters.AddDialFilter(f)
43
+ continue
44
+ }
45
+ maddr, err := ma.NewMultiaddr(addr)
46
+ if err != nil {
47
+ return nil, err
48
+ }
49
+ noAnnAddrs[string(maddr.Bytes())] = true
50
+ }
51
+
52
+ return func(allAddrs []ma.Multiaddr) []ma.Multiaddr {
53
+ var addrs []ma.Multiaddr
54
+ if len(annAddrs) > 0 {
55
+ addrs = annAddrs
56
+ } else {
57
+ addrs = allAddrs
58
+ }
59
+
60
+ var out []ma.Multiaddr
61
+ for _, maddr := range addrs {
62
+ // check for exact matches
63
+ ok := noAnnAddrs[string(maddr.Bytes())]
64
+ // check for /ipcidr matches
65
+ if !ok && !filters.AddrBlocked(maddr) {
66
+ out = append(out, maddr)
67
+ }
68
+ }
69
+ return out
70
+ }, nil
71
+}
72
+
73
+func AddrsFactory(announce []string, noAnnounce []string) func() (opts Libp2pOpts, err error) {
74
+ return func() (opts Libp2pOpts, err error) {
75
+ addrsFactory, err := makeAddrsFactory(announce, noAnnounce)
76
+ if err != nil {
77
+ return opts, err
78
+ }
79
+ opts.Opts = append(opts.Opts, libp2p.AddrsFactory(addrsFactory))
80
+ return
81
+ }
82
+}
83
+
84
+func listenAddresses(addresses []string) ([]ma.Multiaddr, error) {
85
+ var listen []ma.Multiaddr
86
+ for _, addr := range addresses {
87
+ maddr, err := ma.NewMultiaddr(addr)
88
+ if err != nil {
89
+ return nil, fmt.Errorf("failure to parse config.Addresses.Swarm: %s", addresses)
90
+ }
91
+ listen = append(listen, maddr)
92
+ }
93
+
94
+ return listen, nil
95
+}
96
+
97
+func StartListening(addresses []string) func(host host.Host) error {
98
+ return func(host host.Host) error {
99
+ listenAddrs, err := listenAddresses(addresses)
100
+ if err != nil {
101
+ return err
102
+ }
103
+
104
+ // Actually start listening:
105
+ if err := host.Network().Listen(listenAddrs...); err != nil {
106
+ return err
107
+ }
108
+
109
+ // list out our addresses
110
+ addrs, err := host.Network().InterfaceListenAddresses()
111
+ if err != nil {
112
+ return err
113
+ }
114
+ log.Infof("Swarm listening at: %s", addrs)
115
+ return nil
116
+ }
117
+}
core/node/libp2p/host.go
new
+76
@@ -0,0 +1,76 @@
1
+package libp2p
2
+
3
+import (
4
+ "context"
5
+
6
+ "github.com/libp2p/go-libp2p"
7
+ host "github.com/libp2p/go-libp2p-host"
8
+ peer "github.com/libp2p/go-libp2p-peer"
9
+ peerstore "github.com/libp2p/go-libp2p-peerstore"
10
+ record "github.com/libp2p/go-libp2p-record"
11
+ routing "github.com/libp2p/go-libp2p-routing"
12
+ routedhost "github.com/libp2p/go-libp2p/p2p/host/routed"
13
+ "go.uber.org/fx"
14
+
15
+ "github.com/ipfs/go-ipfs/core/node/helpers"
16
+ "github.com/ipfs/go-ipfs/repo"
17
+)
18
+
19
+type P2PHostIn struct {
20
+ fx.In
21
+
22
+ Repo repo.Repo
23
+ Validator record.Validator
24
+ HostOption HostOption
25
+ RoutingOption RoutingOption
26
+ ID peer.ID
27
+ Peerstore peerstore.Peerstore
28
+
29
+ Opts [][]libp2p.Option `group:"libp2p"`
30
+}
31
+
32
+type P2PHostOut struct {
33
+ fx.Out
34
+
35
+ Host host.Host
36
+ Routing BaseIpfsRouting
37
+}
38
+
39
+func Host(mctx helpers.MetricsCtx, lc fx.Lifecycle, params P2PHostIn) (out P2PHostOut, err error) {
40
+ opts := []libp2p.Option{libp2p.NoListenAddrs}
41
+ for _, o := range params.Opts {
42
+ opts = append(opts, o...)
43
+ }
44
+
45
+ ctx := helpers.LifecycleCtx(mctx, lc)
46
+
47
+ opts = append(opts, libp2p.Routing(func(h host.Host) (routing.PeerRouting, error) {
48
+ r, err := params.RoutingOption(ctx, h, params.Repo.Datastore(), params.Validator)
49
+ out.Routing = r
50
+ return r, err
51
+ }))
52
+
53
+ out.Host, err = params.HostOption(ctx, params.ID, params.Peerstore, opts...)
54
+ if err != nil {
55
+ return P2PHostOut{}, err
56
+ }
57
+
58
+ // this code is necessary just for tests: mock network constructions
59
+ // ignore the libp2p constructor options that actually construct the routing!
60
+ if out.Routing == nil {
61
+ r, err := params.RoutingOption(ctx, out.Host, params.Repo.Datastore(), params.Validator)
62
+ if err != nil {
63
+ return P2PHostOut{}, err
64
+ }
65
+ out.Routing = r
66
+ out.Host = routedhost.Wrap(out.Host, out.Routing)
67
+ }
68
+
69
+ lc.Append(fx.Hook{
70
+ OnStop: func(ctx context.Context) error {
71
+ return out.Host.Close()
72
+ },
73
+ })
74
+
75
+ return out, err
76
+}
core/node/libp2p/hostopt.go
new
+25
@@ -0,0 +1,25 @@
1
+package libp2p
2
+
3
+import (
4
+ "context"
5
+ "fmt"
6
+
7
+ "github.com/libp2p/go-libp2p"
8
+ host "github.com/libp2p/go-libp2p-host"
9
+ peer "github.com/libp2p/go-libp2p-peer"
10
+ peerstore "github.com/libp2p/go-libp2p-peerstore"
11
+)
12
+
13
+type HostOption func(ctx context.Context, id peer.ID, ps peerstore.Peerstore, options ...libp2p.Option) (host.Host, error)
14
+
15
+var DefaultHostOption HostOption = constructPeerHost
16
+
17
+// isolates the complex initialization steps
18
+func constructPeerHost(ctx context.Context, id peer.ID, ps peerstore.Peerstore, options ...libp2p.Option) (host.Host, error) {
19
+ pkey := ps.PrivKey(id)
20
+ if pkey == nil {
21
+ return nil, fmt.Errorf("missing private key for node ID: %s", id.Pretty())
22
+ }
23
+ options = append([]libp2p.Option{libp2p.Identity(pkey), libp2p.Peerstore(ps)}, options...)
24
+ return libp2p.New(ctx, options...)
25
+}
core/node/libp2p/libp2p.go
+4
-507
@@ -1,234 +1,26 @@
1
package libp2p
2
3
import (
4
- "bytes"
5
- "context"
6
- "fmt"
7
- "io/ioutil"
8
- "os"
9
- "sort"
10
- "strings"
4
"time"
5
13
- "github.com/ipfs/go-datastore"
14
- nilrouting "github.com/ipfs/go-ipfs-routing/none"
6
logging "github.com/ipfs/go-log"
7
"github.com/libp2p/go-libp2p"
17
- "github.com/libp2p/go-libp2p-autonat-svc"
18
- "github.com/libp2p/go-libp2p-circuit"
8
"github.com/libp2p/go-libp2p-connmgr"
9
"github.com/libp2p/go-libp2p-crypto"
21
- "github.com/libp2p/go-libp2p-host"
22
- "github.com/libp2p/go-libp2p-kad-dht"
23
- dhtopts "github.com/libp2p/go-libp2p-kad-dht/opts"
24
- "github.com/libp2p/go-libp2p-metrics"
10
"github.com/libp2p/go-libp2p-peer"
11
"github.com/libp2p/go-libp2p-peerstore"
27
- "github.com/libp2p/go-libp2p-pnet"
28
- "github.com/libp2p/go-libp2p-pubsub"
29
- "github.com/libp2p/go-libp2p-pubsub-router"
30
- "github.com/libp2p/go-libp2p-quic-transport"
31
- "github.com/libp2p/go-libp2p-record"
32
- "github.com/libp2p/go-libp2p-routing"
33
- "github.com/libp2p/go-libp2p-routing-helpers"
34
- secio "github.com/libp2p/go-libp2p-secio"
35
- tls "github.com/libp2p/go-libp2p-tls"
36
- p2pbhost "github.com/libp2p/go-libp2p/p2p/host/basic"
37
- "github.com/libp2p/go-libp2p/p2p/host/routed"
38
- mafilter "github.com/libp2p/go-maddr-filter"
39
- smux "github.com/libp2p/go-stream-muxer"
40
- ma "github.com/multiformats/go-multiaddr"
41
- mplex "github.com/whyrusleeping/go-smux-multiplex"
42
- yamux "github.com/whyrusleeping/go-smux-yamux"
43
- mamask "github.com/whyrusleeping/multiaddr-filter"
12
"go.uber.org/fx"
45
-
46
- "github.com/ipfs/go-ipfs/core/node/helpers"
47
- "github.com/ipfs/go-ipfs/repo"
13
)
14
15
var log = logging.Logger("p2pnode")
16
52
-type HostOption func(ctx context.Context, id peer.ID, ps peerstore.Peerstore, options ...libp2p.Option) (host.Host, error)
53
-type RoutingOption func(context.Context, host.Host, datastore.Batching, record.Validator) (routing.IpfsRouting, error)
54
-
55
-var DefaultHostOption HostOption = constructPeerHost
56
-
57
-// isolates the complex initialization steps
58
-func constructPeerHost(ctx context.Context, id peer.ID, ps peerstore.Peerstore, options ...libp2p.Option) (host.Host, error) {
59
- pkey := ps.PrivKey(id)
60
- if pkey == nil {
61
- return nil, fmt.Errorf("missing private key for node ID: %s", id.Pretty())
62
- }
63
- options = append([]libp2p.Option{libp2p.Identity(pkey), libp2p.Peerstore(ps)}, options...)
64
- return libp2p.New(ctx, options...)
65
-}
66
-
67
-func constructDHTRouting(ctx context.Context, host host.Host, dstore datastore.Batching, validator record.Validator) (routing.IpfsRouting, error) {
68
- return dht.New(
69
- ctx, host,
70
- dhtopts.Datastore(dstore),
71
- dhtopts.Validator(validator),
72
- )
73
-}
74
-
75
-func constructClientDHTRouting(ctx context.Context, host host.Host, dstore datastore.Batching, validator record.Validator) (routing.IpfsRouting, error) {
76
- return dht.New(
77
- ctx, host,
78
- dhtopts.Client(true),
79
- dhtopts.Datastore(dstore),
80
- dhtopts.Validator(validator),
81
- )
82
-}
83
-
84
-var DHTOption RoutingOption = constructDHTRouting
85
-var DHTClientOption RoutingOption = constructClientDHTRouting
86
-var NilRouterOption RoutingOption = nilrouting.ConstructNilRouting
87
-
88
-func PstoreAddSelfKeys(id peer.ID, sk crypto.PrivKey, ps peerstore.Peerstore) error {
89
- if err := ps.AddPubKey(id, sk.GetPublic()); err != nil {
90
- return err
91
- }
92
-
93
- return ps.AddPrivKey(id, sk)
94
-}
95
-
96
-func AddrFilters(filters []string) func() (opts Libp2pOpts, err error) {
97
- return func() (opts Libp2pOpts, err error) {
98
- for _, s := range filters {
99
- f, err := mamask.NewMask(s)
100
- if err != nil {
101
- return opts, fmt.Errorf("incorrectly formatted address filter in config: %s", s)
102
- }
103
- opts.Opts = append(opts.Opts, libp2p.FilterAddresses(f))
104
- }
105
- return opts, nil
106
- }
107
-}
108
-
109
-func BandwidthCounter() (opts Libp2pOpts, reporter metrics.Reporter) {
110
- reporter = metrics.NewBandwidthCounter()
111
- opts.Opts = append(opts.Opts, libp2p.BandwidthReporter(reporter))
112
- return opts, reporter
113
-}
114
-
17
type Libp2pOpts struct {
18
fx.Out
19
20
Opts []libp2p.Option `group:"libp2p"`
21
}
22
121
-type PNetFingerprint []byte
122
-
123
-func PNet(repo repo.Repo) (opts Libp2pOpts, fp PNetFingerprint, err error) {
124
- swarmkey, err := repo.SwarmKey()
125
- if err != nil || swarmkey == nil {
126
- return opts, nil, err
127
- }
128
-
129
- protec, err := pnet.NewProtector(bytes.NewReader(swarmkey))
130
- if err != nil {
131
- return opts, nil, fmt.Errorf("failed to configure private network: %s", err)
132
- }
133
- fp = protec.Fingerprint()
134
-
135
- opts.Opts = append(opts.Opts, libp2p.PrivateNetwork(protec))
136
- return opts, fp, nil
137
-}
138
-
139
-func PNetChecker(repo repo.Repo, ph host.Host, lc fx.Lifecycle) error {
140
- // TODO: better check?
141
- swarmkey, err := repo.SwarmKey()
142
- if err != nil || swarmkey == nil {
143
- return err
144
- }
145
-
146
- done := make(chan struct{})
147
- lc.Append(fx.Hook{
148
- OnStart: func(_ context.Context) error {
149
- go func() {
150
- t := time.NewTicker(30 * time.Second)
151
- defer t.Stop()
152
-
153
- <-t.C // swallow one tick
154
- for {
155
- select {
156
- case <-t.C:
157
- if len(ph.Network().Peers()) == 0 {
158
- log.Warning("We are in private network and have no peers.")
159
- log.Warning("This might be configuration mistake.")
160
- }
161
- case <-done:
162
- return
163
- }
164
- }
165
- }()
166
- return nil
167
- },
168
- OnStop: func(_ context.Context) error {
169
- close(done)
170
- return nil
171
- },
172
- })
173
- return nil
174
-}
175
-
176
-func makeAddrsFactory(announce []string, noAnnounce []string) (p2pbhost.AddrsFactory, error) {
177
- var annAddrs []ma.Multiaddr
178
- for _, addr := range announce {
179
- maddr, err := ma.NewMultiaddr(addr)
180
- if err != nil {
181
- return nil, err
182
- }
183
- annAddrs = append(annAddrs, maddr)
184
- }
185
-
186
- filters := mafilter.NewFilters()
187
- noAnnAddrs := map[string]bool{}
188
- for _, addr := range noAnnounce {
189
- f, err := mamask.NewMask(addr)
190
- if err == nil {
191
- filters.AddDialFilter(f)
192
- continue
193
- }
194
- maddr, err := ma.NewMultiaddr(addr)
195
- if err != nil {
196
- return nil, err
197
- }
198
- noAnnAddrs[string(maddr.Bytes())] = true
199
- }
200
-
201
- return func(allAddrs []ma.Multiaddr) []ma.Multiaddr {
202
- var addrs []ma.Multiaddr
203
- if len(annAddrs) > 0 {
204
- addrs = annAddrs
205
- } else {
206
- addrs = allAddrs
207
- }
208
-
209
- var out []ma.Multiaddr
210
- for _, maddr := range addrs {
211
- // check for exact matches
212
- ok := noAnnAddrs[string(maddr.Bytes())]
213
- // check for /ipcidr matches
214
- if !ok && !filters.AddrBlocked(maddr) {
215
- out = append(out, maddr)
216
- }
217
- }
218
- return out
219
- }, nil
220
-}
221
-
222
-func AddrsFactory(announce []string, noAnnounce []string) func() (opts Libp2pOpts, err error) {
223
- return func() (opts Libp2pOpts, err error) {
224
- addrsFactory, err := makeAddrsFactory(announce, noAnnounce)
225
- if err != nil {
226
- return opts, err
227
- }
228
- opts.Opts = append(opts.Opts, libp2p.AddrsFactory(addrsFactory))
229
- return
230
- }
231
-}
23
+// Misc options
24
25
func ConnectionManager(low, high int, grace time.Duration) func() (opts Libp2pOpts, err error) {
26
return func() (opts Libp2pOpts, err error) {
@@ -238,307 +30,12 @@ func ConnectionManager(low, high int, grace time.Duration) func() (opts Libp2pOp
30
}
31
}
32
241
-func makeSmuxTransportOption(mplexExp bool) libp2p.Option {
242
- const yamuxID = "/yamux/1.0.0"
243
- const mplexID = "/mplex/6.7.0"
244
-
245
- ymxtpt := &yamux.Transport{
246
- AcceptBacklog: 512,
247
- ConnectionWriteTimeout: time.Second * 10,
248
- KeepAliveInterval: time.Second * 30,
249
- EnableKeepAlive: true,
250
- MaxStreamWindowSize: uint32(16 * 1024 * 1024), // 16MiB
251
- LogOutput: ioutil.Discard,
252
- }
253
-
254
- if os.Getenv("YAMUX_DEBUG") != "" {
255
- ymxtpt.LogOutput = os.Stderr
256
- }
257
-
258
- muxers := map[string]smux.Transport{yamuxID: ymxtpt}
259
- if mplexExp {
260
- muxers[mplexID] = mplex.DefaultTransport
261
- }
262
-
263
- // Allow muxer preference order overriding
264
- order := []string{yamuxID, mplexID}
265
- if prefs := os.Getenv("LIBP2P_MUX_PREFS"); prefs != "" {
266
- order = strings.Fields(prefs)
267
- }
268
-
269
- opts := make([]libp2p.Option, 0, len(order))
270
- for _, id := range order {
271
- tpt, ok := muxers[id]
272
- if !ok {
273
- log.Warning("unknown or duplicate muxer in LIBP2P_MUX_PREFS: %s", id)
274
- continue
275
- }
276
- delete(muxers, id)
277
- opts = append(opts, libp2p.Muxer(id, tpt))
278
- }
279
-
280
- return libp2p.ChainOptions(opts...)
281
-}
282
-
283
-var NatPortMap = simpleOpt(libp2p.NATPortMap())
284
-var AutoRealy = simpleOpt(libp2p.EnableAutoRelay())
285
-var DefaultTransports = simpleOpt(libp2p.DefaultTransports)
286
-var QUIC = simpleOpt(libp2p.Transport(libp2pquic.NewTransport))
287
-
288
-func SmuxTransport(mplex bool) func() (opts Libp2pOpts, err error) {
289
- return func() (opts Libp2pOpts, err error) {
290
- opts.Opts = append(opts.Opts, makeSmuxTransportOption(mplex))
291
- return
292
- }
293
-}
294
-
295
-func Relay(disable, enableHop bool) func() (opts Libp2pOpts, err error) {
296
- return func() (opts Libp2pOpts, err error) {
297
- if disable {
298
- // Enabled by default.
299
- opts.Opts = append(opts.Opts, libp2p.DisableRelay())
300
- } else {
301
- relayOpts := []relay.RelayOpt{relay.OptDiscovery}
302
- if enableHop {
303
- relayOpts = append(relayOpts, relay.OptHop)
304
- }
305
- opts.Opts = append(opts.Opts, libp2p.EnableRelay(relayOpts...))
306
- }
307
- return
308
- }
309
-}
310
-
311
-func Security(enabled, preferTLS bool) interface{} {
312
- if !enabled {
313
- return func() (opts Libp2pOpts) {
314
- // TODO: shouldn't this be Errorf to guarantee visibility?
315
- log.Warningf(`Your IPFS node has been configured to run WITHOUT ENCRYPTED CONNECTIONS.
316
- You will not be able to connect to any nodes configured to use encrypted connections`)
317
- opts.Opts = append(opts.Opts, libp2p.NoSecurity)
318
- return opts
319
- }
320
- }
321
- return func() (opts Libp2pOpts) {
322
- if preferTLS {
323
- opts.Opts = append(opts.Opts, libp2p.ChainOptions(libp2p.Security(tls.ID, tls.New), libp2p.Security(secio.ID, secio.New)))
324
- } else {
325
- opts.Opts = append(opts.Opts, libp2p.ChainOptions(libp2p.Security(secio.ID, secio.New), libp2p.Security(tls.ID, tls.New)))
326
- }
327
- return opts
328
- }
329
-}
330
-
331
-type P2PHostIn struct {
332
- fx.In
333
-
334
- Repo repo.Repo
335
- Validator record.Validator
336
- HostOption HostOption
337
- RoutingOption RoutingOption
338
- ID peer.ID
339
- Peerstore peerstore.Peerstore
340
-
341
- Opts [][]libp2p.Option `group:"libp2p"`
342
-}
343
-
344
-type BaseIpfsRouting routing.IpfsRouting
345
-type P2PHostOut struct {
346
- fx.Out
347
-
348
- Host host.Host
349
- Routing BaseIpfsRouting
350
-}
351
-
352
-func Host(mctx helpers.MetricsCtx, lc fx.Lifecycle, params P2PHostIn) (out P2PHostOut, err error) {
353
- opts := []libp2p.Option{libp2p.NoListenAddrs}
354
- for _, o := range params.Opts {
355
- opts = append(opts, o...)
356
- }
357
-
358
- ctx := helpers.LifecycleCtx(mctx, lc)
359
-
360
- opts = append(opts, libp2p.Routing(func(h host.Host) (routing.PeerRouting, error) {
361
- r, err := params.RoutingOption(ctx, h, params.Repo.Datastore(), params.Validator)
362
- out.Routing = r
363
- return r, err
364
- }))
365
-
366
- out.Host, err = params.HostOption(ctx, params.ID, params.Peerstore, opts...)
367
- if err != nil {
368
- return P2PHostOut{}, err
369
- }
370
-
371
- // this code is necessary just for tests: mock network constructions
372
- // ignore the libp2p constructor options that actually construct the routing!
373
- if out.Routing == nil {
374
- r, err := params.RoutingOption(ctx, out.Host, params.Repo.Datastore(), params.Validator)
375
- if err != nil {
376
- return P2PHostOut{}, err
377
- }
378
- out.Routing = r
379
- out.Host = routedhost.Wrap(out.Host, out.Routing)
380
- }
381
-
382
- lc.Append(fx.Hook{
383
- OnStop: func(ctx context.Context) error {
384
- return out.Host.Close()
385
- },
386
- })
387
-
388
- return out, err
389
-}
390
-
391
-type Router struct {
392
- routing.IpfsRouting
393
-
394
- Priority int // less = more important
395
-}
396
-
397
-type p2pRouterOut struct {
398
- fx.Out
399
-
400
- Router Router `group:"routers"`
401
-}
402
-
403
-func BaseRouting(lc fx.Lifecycle, in BaseIpfsRouting) (out p2pRouterOut, dr *dht.IpfsDHT) {
404
- if dht, ok := in.(*dht.IpfsDHT); ok {
405
- dr = dht
406
-
407
- lc.Append(fx.Hook{
408
- OnStop: func(ctx context.Context) error {
409
- return dr.Close()
410
- },
411
- })
412
- }
413
-
414
- return p2pRouterOut{
415
- Router: Router{
416
- Priority: 1000,
417
- IpfsRouting: in,
418
- },
419
- }, dr
420
-}
421
-
422
-type p2pOnlineRoutingIn struct {
423
- fx.In
424
-
425
- Routers []Router `group:"routers"`
426
- Validator record.Validator
427
-}
428
-
429
-func Routing(in p2pOnlineRoutingIn) routing.IpfsRouting {
430
- routers := in.Routers
431
-
432
- sort.SliceStable(routers, func(i, j int) bool {
433
- return routers[i].Priority < routers[j].Priority
434
- })
435
-
436
- irouters := make([]routing.IpfsRouting, len(routers))
437
- for i, v := range routers {
438
- irouters[i] = v.IpfsRouting
439
- }
440
-
441
- return routinghelpers.Tiered{
442
- Routers: irouters,
443
- Validator: in.Validator,
444
- }
445
-}
446
-
447
-type p2pPSRoutingIn struct {
448
- fx.In
449
-
450
- BaseRouting BaseIpfsRouting
451
- Repo repo.Repo
452
- Validator record.Validator
453
- Host host.Host
454
- PubSub *pubsub.PubSub `optional:"true"`
455
-}
456
-
457
-func PubsubRouter(mctx helpers.MetricsCtx, lc fx.Lifecycle, in p2pPSRoutingIn) (p2pRouterOut, *namesys.PubsubValueStore) {
458
- psRouter := namesys.NewPubsubValueStore(
459
- helpers.LifecycleCtx(mctx, lc),
460
- in.Host,
461
- in.BaseRouting,
462
- in.PubSub,
463
- in.Validator,
464
- )
465
-
466
- return p2pRouterOut{
467
- Router: Router{
468
- IpfsRouting: &routinghelpers.Compose{
469
- ValueStore: &routinghelpers.LimitedValueStore{
470
- ValueStore: psRouter,
471
- Namespaces: []string{"ipns"},
472
- },
473
- },
474
- Priority: 100,
475
- },
476
- }, psRouter
477
-}
478
-
479
-func AutoNATService(quic bool) func(repo repo.Repo, mctx helpers.MetricsCtx, lc fx.Lifecycle, host host.Host) error {
480
- return func(repo repo.Repo, mctx helpers.MetricsCtx, lc fx.Lifecycle, host host.Host) error {
481
- // collect private net option in case swarm.key is presented
482
- opts, _, err := PNet(repo)
483
- if err != nil {
484
- // swarm key exists but was failed to decode
485
- return err
486
- }
487
-
488
- if quic {
489
- opts.Opts = append(opts.Opts, libp2p.DefaultTransports, libp2p.Transport(libp2pquic.NewTransport))
490
- }
491
-
492
- _, err = autonat.NewAutoNATService(helpers.LifecycleCtx(mctx, lc), host, opts.Opts...)
33
+func PstoreAddSelfKeys(id peer.ID, sk crypto.PrivKey, ps peerstore.Peerstore) error {
34
+ if err := ps.AddPubKey(id, sk.GetPublic()); err != nil {
35
return err
36
}
495
-}
496
-
497
-func FloodSub(pubsubOptions ...pubsub.Option) interface{} {
498
- return func(mctx helpers.MetricsCtx, lc fx.Lifecycle, host host.Host) (service *pubsub.PubSub, err error) {
499
- return pubsub.NewFloodSub(helpers.LifecycleCtx(mctx, lc), host, pubsubOptions...)
500
- }
501
-}
502
-
503
-func GossipSub(pubsubOptions ...pubsub.Option) interface{} {
504
- return func(mctx helpers.MetricsCtx, lc fx.Lifecycle, host host.Host) (service *pubsub.PubSub, err error) {
505
- return pubsub.NewGossipSub(helpers.LifecycleCtx(mctx, lc), host, pubsubOptions...)
506
- }
507
-}
37
509
-func listenAddresses(addresses []string) ([]ma.Multiaddr, error) {
510
- var listen []ma.Multiaddr
511
- for _, addr := range addresses {
512
- maddr, err := ma.NewMultiaddr(addr)
513
- if err != nil {
514
- return nil, fmt.Errorf("failure to parse config.Addresses.Swarm: %s", addresses)
515
- }
516
- listen = append(listen, maddr)
517
- }
518
-
519
- return listen, nil
520
-}
521
-
522
-func StartListening(addresses []string) func(host host.Host) error {
523
- return func(host host.Host) error {
524
- listenAddrs, err := listenAddresses(addresses)
525
- if err != nil {
526
- return err
527
- }
528
-
529
- // Actually start listening:
530
- if err := host.Network().Listen(listenAddrs...); err != nil {
531
- return err
532
- }
533
-
534
- // list out our addresses
535
- addrs, err := host.Network().InterfaceListenAddresses()
536
- if err != nil {
537
- return err
538
- }
539
- log.Infof("Swarm listening at: %s", addrs)
540
- return nil
541
- }
38
+ return ps.AddPrivKey(id, sk)
39
}
40
41
func simpleOpt(opt libp2p.Option) func() (opts Libp2pOpts, err error) {
core/node/libp2p/nat.go
new
+32
@@ -0,0 +1,32 @@
1
+package libp2p
2
+
3
+import (
4
+ "github.com/libp2p/go-libp2p"
5
+ autonat "github.com/libp2p/go-libp2p-autonat-svc"
6
+ host "github.com/libp2p/go-libp2p-host"
7
+ libp2pquic "github.com/libp2p/go-libp2p-quic-transport"
8
+ "go.uber.org/fx"
9
+
10
+ "github.com/ipfs/go-ipfs/core/node/helpers"
11
+ "github.com/ipfs/go-ipfs/repo"
12
+)
13
+
14
+var NatPortMap = simpleOpt(libp2p.NATPortMap())
15
+
16
+func AutoNATService(quic bool) func(repo repo.Repo, mctx helpers.MetricsCtx, lc fx.Lifecycle, host host.Host) error {
17
+ return func(repo repo.Repo, mctx helpers.MetricsCtx, lc fx.Lifecycle, host host.Host) error {
18
+ // collect private net option in case swarm.key is presented
19
+ opts, _, err := PNet(repo)
20
+ if err != nil {
21
+ // swarm key exists but was failed to decode
22
+ return err
23
+ }
24
+
25
+ if quic {
26
+ opts.Opts = append(opts.Opts, libp2p.DefaultTransports, libp2p.Transport(libp2pquic.NewTransport))
27
+ }
28
+
29
+ _, err = autonat.NewAutoNATService(helpers.LifecycleCtx(mctx, lc), host, opts.Opts...)
30
+ return err
31
+ }
32
+}
core/node/libp2p/pnet.go
new
+70
@@ -0,0 +1,70 @@
1
+package libp2p
2
+
3
+import (
4
+ "bytes"
5
+ "context"
6
+ "fmt"
7
+ "time"
8
+
9
+ "github.com/libp2p/go-libp2p"
10
+ host "github.com/libp2p/go-libp2p-host"
11
+ pnet "github.com/libp2p/go-libp2p-pnet"
12
+ "go.uber.org/fx"
13
+
14
+ "github.com/ipfs/go-ipfs/repo"
15
+)
16
+
17
+type PNetFingerprint []byte
18
+
19
+func PNet(repo repo.Repo) (opts Libp2pOpts, fp PNetFingerprint, err error) {
20
+ swarmkey, err := repo.SwarmKey()
21
+ if err != nil || swarmkey == nil {
22
+ return opts, nil, err
23
+ }
24
+
25
+ protec, err := pnet.NewProtector(bytes.NewReader(swarmkey))
26
+ if err != nil {
27
+ return opts, nil, fmt.Errorf("failed to configure private network: %s", err)
28
+ }
29
+ fp = protec.Fingerprint()
30
+
31
+ opts.Opts = append(opts.Opts, libp2p.PrivateNetwork(protec))
32
+ return opts, fp, nil
33
+}
34
+
35
+func PNetChecker(repo repo.Repo, ph host.Host, lc fx.Lifecycle) error {
36
+ // TODO: better check?
37
+ swarmkey, err := repo.SwarmKey()
38
+ if err != nil || swarmkey == nil {
39
+ return err
40
+ }
41
+
42
+ done := make(chan struct{})
43
+ lc.Append(fx.Hook{
44
+ OnStart: func(_ context.Context) error {
45
+ go func() {
46
+ t := time.NewTicker(30 * time.Second)
47
+ defer t.Stop()
48
+
49
+ <-t.C // swallow one tick
50
+ for {
51
+ select {
52
+ case <-t.C:
53
+ if len(ph.Network().Peers()) == 0 {
54
+ log.Warning("We are in private network and have no peers.")
55
+ log.Warning("This might be configuration mistake.")
56
+ }
57
+ case <-done:
58
+ return
59
+ }
60
+ }
61
+ }()
62
+ return nil
63
+ },
64
+ OnStop: func(_ context.Context) error {
65
+ close(done)
66
+ return nil
67
+ },
68
+ })
69
+ return nil
70
+}
core/node/libp2p/pubsub.go
new
+21
@@ -0,0 +1,21 @@
1
+package libp2p
2
+
3
+import (
4
+ host "github.com/libp2p/go-libp2p-host"
5
+ pubsub "github.com/libp2p/go-libp2p-pubsub"
6
+ "go.uber.org/fx"
7
+
8
+ "github.com/ipfs/go-ipfs/core/node/helpers"
9
+)
10
+
11
+func FloodSub(pubsubOptions ...pubsub.Option) interface{} {
12
+ return func(mctx helpers.MetricsCtx, lc fx.Lifecycle, host host.Host) (service *pubsub.PubSub, err error) {
13
+ return pubsub.NewFloodSub(helpers.LifecycleCtx(mctx, lc), host, pubsubOptions...)
14
+ }
15
+}
16
+
17
+func GossipSub(pubsubOptions ...pubsub.Option) interface{} {
18
+ return func(mctx helpers.MetricsCtx, lc fx.Lifecycle, host host.Host) (service *pubsub.PubSub, err error) {
19
+ return pubsub.NewGossipSub(helpers.LifecycleCtx(mctx, lc), host, pubsubOptions...)
20
+ }
21
+}
core/node/libp2p/relay.go
new
+24
@@ -0,0 +1,24 @@
1
+package libp2p
2
+
3
+import (
4
+ "github.com/libp2p/go-libp2p"
5
+ relay "github.com/libp2p/go-libp2p-circuit"
6
+)
7
+
8
+func Relay(disable, enableHop bool) func() (opts Libp2pOpts, err error) {
9
+ return func() (opts Libp2pOpts, err error) {
10
+ if disable {
11
+ // Enabled by default.
12
+ opts.Opts = append(opts.Opts, libp2p.DisableRelay())
13
+ } else {
14
+ relayOpts := []relay.RelayOpt{relay.OptDiscovery}
15
+ if enableHop {
16
+ relayOpts = append(relayOpts, relay.OptHop)
17
+ }
18
+ opts.Opts = append(opts.Opts, libp2p.EnableRelay(relayOpts...))
19
+ }
20
+ return
21
+ }
22
+}
23
+
24
+var AutoRealy = simpleOpt(libp2p.EnableAutoRelay())
core/node/libp2p/routing.go
new
+108
@@ -0,0 +1,108 @@
1
+package libp2p
2
+
3
+import (
4
+ "context"
5
+ "sort"
6
+
7
+ host "github.com/libp2p/go-libp2p-host"
8
+ dht "github.com/libp2p/go-libp2p-kad-dht"
9
+ "github.com/libp2p/go-libp2p-pubsub"
10
+ namesys "github.com/libp2p/go-libp2p-pubsub-router"
11
+ record "github.com/libp2p/go-libp2p-record"
12
+ routing "github.com/libp2p/go-libp2p-routing"
13
+ routinghelpers "github.com/libp2p/go-libp2p-routing-helpers"
14
+ "go.uber.org/fx"
15
+
16
+ "github.com/ipfs/go-ipfs/core/node/helpers"
17
+ "github.com/ipfs/go-ipfs/repo"
18
+)
19
+
20
+type BaseIpfsRouting routing.IpfsRouting
21
+
22
+type Router struct {
23
+ routing.IpfsRouting
24
+
25
+ Priority int // less = more important
26
+}
27
+
28
+type p2pRouterOut struct {
29
+ fx.Out
30
+
31
+ Router Router `group:"routers"`
32
+}
33
+
34
+func BaseRouting(lc fx.Lifecycle, in BaseIpfsRouting) (out p2pRouterOut, dr *dht.IpfsDHT) {
35
+ if dht, ok := in.(*dht.IpfsDHT); ok {
36
+ dr = dht
37
+
38
+ lc.Append(fx.Hook{
39
+ OnStop: func(ctx context.Context) error {
40
+ return dr.Close()
41
+ },
42
+ })
43
+ }
44
+
45
+ return p2pRouterOut{
46
+ Router: Router{
47
+ Priority: 1000,
48
+ IpfsRouting: in,
49
+ },
50
+ }, dr
51
+}
52
+
53
+type p2pOnlineRoutingIn struct {
54
+ fx.In
55
+
56
+ Routers []Router `group:"routers"`
57
+ Validator record.Validator
58
+}
59
+
60
+func Routing(in p2pOnlineRoutingIn) routing.IpfsRouting {
61
+ routers := in.Routers
62
+
63
+ sort.SliceStable(routers, func(i, j int) bool {
64
+ return routers[i].Priority < routers[j].Priority
65
+ })
66
+
67
+ irouters := make([]routing.IpfsRouting, len(routers))
68
+ for i, v := range routers {
69
+ irouters[i] = v.IpfsRouting
70
+ }
71
+
72
+ return routinghelpers.Tiered{
73
+ Routers: irouters,
74
+ Validator: in.Validator,
75
+ }
76
+}
77
+
78
+type p2pPSRoutingIn struct {
79
+ fx.In
80
+
81
+ BaseRouting BaseIpfsRouting
82
+ Repo repo.Repo
83
+ Validator record.Validator
84
+ Host host.Host
85
+ PubSub *pubsub.PubSub `optional:"true"`
86
+}
87
+
88
+func PubsubRouter(mctx helpers.MetricsCtx, lc fx.Lifecycle, in p2pPSRoutingIn) (p2pRouterOut, *namesys.PubsubValueStore) {
89
+ psRouter := namesys.NewPubsubValueStore(
90
+ helpers.LifecycleCtx(mctx, lc),
91
+ in.Host,
92
+ in.BaseRouting,
93
+ in.PubSub,
94
+ in.Validator,
95
+ )
96
+
97
+ return p2pRouterOut{
98
+ Router: Router{
99
+ IpfsRouting: &routinghelpers.Compose{
100
+ ValueStore: &routinghelpers.LimitedValueStore{
101
+ ValueStore: psRouter,
102
+ Namespaces: []string{"ipns"},
103
+ },
104
+ },
105
+ Priority: 100,
106
+ },
107
+ }, psRouter
108
+}
core/node/libp2p/routingopt.go
new
+36
@@ -0,0 +1,36 @@
1
+package libp2p
2
+
3
+import (
4
+ "context"
5
+
6
+ "github.com/ipfs/go-datastore"
7
+ nilrouting "github.com/ipfs/go-ipfs-routing/none"
8
+ host "github.com/libp2p/go-libp2p-host"
9
+ dht "github.com/libp2p/go-libp2p-kad-dht"
10
+ dhtopts "github.com/libp2p/go-libp2p-kad-dht/opts"
11
+ record "github.com/libp2p/go-libp2p-record"
12
+ routing "github.com/libp2p/go-libp2p-routing"
13
+)
14
+
15
+type RoutingOption func(context.Context, host.Host, datastore.Batching, record.Validator) (routing.IpfsRouting, error)
16
+
17
+func constructDHTRouting(ctx context.Context, host host.Host, dstore datastore.Batching, validator record.Validator) (routing.IpfsRouting, error) {
18
+ return dht.New(
19
+ ctx, host,
20
+ dhtopts.Datastore(dstore),
21
+ dhtopts.Validator(validator),
22
+ )
23
+}
24
+
25
+func constructClientDHTRouting(ctx context.Context, host host.Host, dstore datastore.Batching, validator record.Validator) (routing.IpfsRouting, error) {
26
+ return dht.New(
27
+ ctx, host,
28
+ dhtopts.Client(true),
29
+ dhtopts.Datastore(dstore),
30
+ dhtopts.Validator(validator),
31
+ )
32
+}
33
+
34
+var DHTOption RoutingOption = constructDHTRouting
35
+var DHTClientOption RoutingOption = constructClientDHTRouting
36
+var NilRouterOption RoutingOption = nilrouting.ConstructNilRouting
core/node/libp2p/smux.go
new
+62
@@ -0,0 +1,62 @@
1
+package libp2p
2
+
3
+import (
4
+ "io/ioutil"
5
+ "os"
6
+ "strings"
7
+ "time"
8
+
9
+ "github.com/libp2p/go-libp2p"
10
+ smux "github.com/libp2p/go-stream-muxer"
11
+ mplex "github.com/whyrusleeping/go-smux-multiplex"
12
+ yamux "github.com/whyrusleeping/go-smux-yamux"
13
+)
14
+
15
+func makeSmuxTransportOption(mplexExp bool) libp2p.Option {
16
+ const yamuxID = "/yamux/1.0.0"
17
+ const mplexID = "/mplex/6.7.0"
18
+
19
+ ymxtpt := &yamux.Transport{
20
+ AcceptBacklog: 512,
21
+ ConnectionWriteTimeout: time.Second * 10,
22
+ KeepAliveInterval: time.Second * 30,
23
+ EnableKeepAlive: true,
24
+ MaxStreamWindowSize: uint32(16 * 1024 * 1024), // 16MiB
25
+ LogOutput: ioutil.Discard,
26
+ }
27
+
28
+ if os.Getenv("YAMUX_DEBUG") != "" {
29
+ ymxtpt.LogOutput = os.Stderr
30
+ }
31
+
32
+ muxers := map[string]smux.Transport{yamuxID: ymxtpt}
33
+ if mplexExp {
34
+ muxers[mplexID] = mplex.DefaultTransport
35
+ }
36
+
37
+ // Allow muxer preference order overriding
38
+ order := []string{yamuxID, mplexID}
39
+ if prefs := os.Getenv("LIBP2P_MUX_PREFS"); prefs != "" {
40
+ order = strings.Fields(prefs)
41
+ }
42
+
43
+ opts := make([]libp2p.Option, 0, len(order))
44
+ for _, id := range order {
45
+ tpt, ok := muxers[id]
46
+ if !ok {
47
+ log.Warning("unknown or duplicate muxer in LIBP2P_MUX_PREFS: %s", id)
48
+ continue
49
+ }
50
+ delete(muxers, id)
51
+ opts = append(opts, libp2p.Muxer(id, tpt))
52
+ }
53
+
54
+ return libp2p.ChainOptions(opts...)
55
+}
56
+
57
+func SmuxTransport(mplex bool) func() (opts Libp2pOpts, err error) {
58
+ return func() (opts Libp2pOpts, err error) {
59
+ opts.Opts = append(opts.Opts, makeSmuxTransportOption(mplex))
60
+ return
61
+ }
62
+}
core/node/libp2p/transport.go
new
+38
@@ -0,0 +1,38 @@
1
+package libp2p
2
+
3
+import (
4
+ "github.com/libp2p/go-libp2p"
5
+ metrics "github.com/libp2p/go-libp2p-metrics"
6
+ libp2pquic "github.com/libp2p/go-libp2p-quic-transport"
7
+ secio "github.com/libp2p/go-libp2p-secio"
8
+ tls "github.com/libp2p/go-libp2p-tls"
9
+)
10
+
11
+var DefaultTransports = simpleOpt(libp2p.DefaultTransports)
12
+var QUIC = simpleOpt(libp2p.Transport(libp2pquic.NewTransport))
13
+
14
+func Security(enabled, preferTLS bool) interface{} {
15
+ if !enabled {
16
+ return func() (opts Libp2pOpts) {
17
+ // TODO: shouldn't this be Errorf to guarantee visibility?
18
+ log.Warningf(`Your IPFS node has been configured to run WITHOUT ENCRYPTED CONNECTIONS.
19
+ You will not be able to connect to any nodes configured to use encrypted connections`)
20
+ opts.Opts = append(opts.Opts, libp2p.NoSecurity)
21
+ return opts
22
+ }
23
+ }
24
+ return func() (opts Libp2pOpts) {
25
+ if preferTLS {
26
+ opts.Opts = append(opts.Opts, libp2p.ChainOptions(libp2p.Security(tls.ID, tls.New), libp2p.Security(secio.ID, secio.New)))
27
+ } else {
28
+ opts.Opts = append(opts.Opts, libp2p.ChainOptions(libp2p.Security(secio.ID, secio.New), libp2p.Security(tls.ID, tls.New)))
29
+ }
30
+ return opts
31
+ }
32
+}
33
+
34
+func BandwidthCounter() (opts Libp2pOpts, reporter metrics.Reporter) {
35
+ reporter = metrics.NewBandwidthCounter()
36
+ opts.Opts = append(opts.Opts, libp2p.BandwidthReporter(reporter))
37
+ return opts, reporter
38
+}