@cryptotaxi247 / kubo / commits / e13305848

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