-
Notifications
You must be signed in to change notification settings - Fork 1.1k
/
options.go
657 lines (595 loc) · 21 KB
/
options.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
package libp2p
// This file contains all libp2p configuration options (except the defaults,
// those are in defaults.go).
import (
"crypto/rand"
"encoding/binary"
"errors"
"fmt"
"reflect"
"time"
"github.com/libp2p/go-libp2p/config"
"github.com/libp2p/go-libp2p/core/connmgr"
"github.com/libp2p/go-libp2p/core/crypto"
"github.com/libp2p/go-libp2p/core/metrics"
"github.com/libp2p/go-libp2p/core/network"
"github.com/libp2p/go-libp2p/core/peer"
"github.com/libp2p/go-libp2p/core/peerstore"
"github.com/libp2p/go-libp2p/core/pnet"
"github.com/libp2p/go-libp2p/core/protocol"
"github.com/libp2p/go-libp2p/core/transport"
"github.com/libp2p/go-libp2p/p2p/host/autorelay"
bhost "github.com/libp2p/go-libp2p/p2p/host/basic"
"github.com/libp2p/go-libp2p/p2p/net/swarm"
tptu "github.com/libp2p/go-libp2p/p2p/net/upgrader"
relayv2 "github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/relay"
"github.com/libp2p/go-libp2p/p2p/protocol/holepunch"
"github.com/libp2p/go-libp2p/p2p/transport/quicreuse"
"github.com/prometheus/client_golang/prometheus"
ma "github.com/multiformats/go-multiaddr"
"go.uber.org/fx"
)
// ListenAddrStrings configures libp2p to listen on the given (unparsed)
// addresses.
func ListenAddrStrings(s ...string) Option {
return func(cfg *Config) error {
for _, addrstr := range s {
a, err := ma.NewMultiaddr(addrstr)
if err != nil {
return err
}
cfg.ListenAddrs = append(cfg.ListenAddrs, a)
}
return nil
}
}
// ListenAddrs configures libp2p to listen on the given addresses.
func ListenAddrs(addrs ...ma.Multiaddr) Option {
return func(cfg *Config) error {
cfg.ListenAddrs = append(cfg.ListenAddrs, addrs...)
return nil
}
}
// Security configures libp2p to use the given security transport (or transport
// constructor).
//
// Name is the protocol name.
//
// The transport can be a constructed security.Transport or a function taking
// any subset of this libp2p node's:
// * Public key
// * Private key
// * Peer ID
// * Host
// * Network
// * Peerstore
func Security(name string, constructor interface{}) Option {
return func(cfg *Config) error {
if cfg.Insecure {
return fmt.Errorf("cannot use security transports with an insecure libp2p configuration")
}
cfg.SecurityTransports = append(cfg.SecurityTransports, config.Security{ID: protocol.ID(name), Constructor: constructor})
return nil
}
}
// NoSecurity is an option that completely disables all transport security.
// It's incompatible with all other transport security protocols.
var NoSecurity Option = func(cfg *Config) error {
if len(cfg.SecurityTransports) > 0 {
return fmt.Errorf("cannot use security transports with an insecure libp2p configuration")
}
cfg.Insecure = true
return nil
}
// Muxer configures libp2p to use the given stream multiplexer.
// name is the protocol name.
func Muxer(name string, muxer network.Multiplexer) Option {
return func(cfg *Config) error {
cfg.Muxers = append(cfg.Muxers, tptu.StreamMuxer{Muxer: muxer, ID: protocol.ID(name)})
return nil
}
}
func QUICReuse(constructor interface{}, opts ...quicreuse.Option) Option {
return func(cfg *Config) error {
tag := `group:"quicreuseopts"`
typ := reflect.ValueOf(constructor).Type()
numParams := typ.NumIn()
isVariadic := typ.IsVariadic()
if !isVariadic && len(opts) > 0 {
return errors.New("QUICReuse constructor doesn't take any options")
}
var params []string
if isVariadic && len(opts) > 0 {
// If there are options, apply the tag.
// Since options are variadic, they have to be the last argument of the constructor.
params = make([]string, numParams)
params[len(params)-1] = tag
}
cfg.QUICReuse = append(cfg.QUICReuse, fx.Provide(fx.Annotate(constructor, fx.ParamTags(params...))))
for _, opt := range opts {
cfg.QUICReuse = append(cfg.QUICReuse, fx.Supply(fx.Annotate(opt, fx.ResultTags(tag))))
}
return nil
}
}
// Transport configures libp2p to use the given transport (or transport
// constructor).
//
// The transport can be a constructed transport.Transport or a function taking
// any subset of this libp2p node's:
// * Transport Upgrader (*tptu.Upgrader)
// * Host
// * Stream muxer (muxer.Transport)
// * Security transport (security.Transport)
// * Private network protector (pnet.Protector)
// * Peer ID
// * Private Key
// * Public Key
// * Address filter (filter.Filter)
// * Peerstore
func Transport(constructor interface{}, opts ...interface{}) Option {
return func(cfg *Config) error {
// generate a random identifier, so that fx can associate the constructor with its options
b := make([]byte, 8)
rand.Read(b)
id := binary.BigEndian.Uint64(b)
tag := fmt.Sprintf(`group:"transportopt_%d"`, id)
typ := reflect.ValueOf(constructor).Type()
numParams := typ.NumIn()
isVariadic := typ.IsVariadic()
if !isVariadic && len(opts) > 0 {
return errors.New("transport constructor doesn't take any options")
}
if isVariadic && numParams >= 1 {
paramType := typ.In(numParams - 1).Elem()
for _, opt := range opts {
if typ := reflect.TypeOf(opt); !typ.AssignableTo(paramType) {
return fmt.Errorf("transport option of type %s not assignable to %s", typ, paramType)
}
}
}
var params []string
if isVariadic && len(opts) > 0 {
// If there are transport options, apply the tag.
// Since options are variadic, they have to be the last argument of the constructor.
params = make([]string, numParams)
params[len(params)-1] = tag
}
cfg.Transports = append(cfg.Transports, fx.Provide(
fx.Annotate(
constructor,
fx.ParamTags(params...),
fx.As(new(transport.Transport)),
fx.ResultTags(`group:"transport"`),
),
))
for _, opt := range opts {
cfg.Transports = append(cfg.Transports, fx.Supply(
fx.Annotate(
opt,
fx.ResultTags(tag),
),
))
}
return nil
}
}
// Peerstore configures libp2p to use the given peerstore.
func Peerstore(ps peerstore.Peerstore) Option {
return func(cfg *Config) error {
if cfg.Peerstore != nil {
return fmt.Errorf("cannot specify multiple peerstore options")
}
cfg.Peerstore = ps
return nil
}
}
// PrivateNetwork configures libp2p to use the given private network protector.
func PrivateNetwork(psk pnet.PSK) Option {
return func(cfg *Config) error {
if cfg.PSK != nil {
return fmt.Errorf("cannot specify multiple private network options")
}
cfg.PSK = psk
return nil
}
}
// BandwidthReporter configures libp2p to use the given bandwidth reporter.
func BandwidthReporter(rep metrics.Reporter) Option {
return func(cfg *Config) error {
if cfg.Reporter != nil {
return fmt.Errorf("cannot specify multiple bandwidth reporter options")
}
cfg.Reporter = rep
return nil
}
}
// Identity configures libp2p to use the given private key to identify itself.
func Identity(sk crypto.PrivKey) Option {
return func(cfg *Config) error {
if cfg.PeerKey != nil {
return fmt.Errorf("cannot specify multiple identities")
}
cfg.PeerKey = sk
return nil
}
}
// ConnectionManager configures libp2p to use the given connection manager.
//
// The current "standard" connection manager lives in github.com/libp2p/go-libp2p-connmgr. See
// https://pkg.go.dev/github.com/libp2p/go-libp2p-connmgr?utm_source=godoc#NewConnManager.
func ConnectionManager(connman connmgr.ConnManager) Option {
return func(cfg *Config) error {
if cfg.ConnManager != nil {
return fmt.Errorf("cannot specify multiple connection managers")
}
cfg.ConnManager = connman
return nil
}
}
// AddrsFactory configures libp2p to use the given address factory.
func AddrsFactory(factory config.AddrsFactory) Option {
return func(cfg *Config) error {
if cfg.AddrsFactory != nil {
return fmt.Errorf("cannot specify multiple address factories")
}
cfg.AddrsFactory = factory
return nil
}
}
// EnableRelay configures libp2p to enable the relay transport.
// This option only configures libp2p to accept inbound connections from relays
// and make outbound connections_through_ relays when requested by the remote peer.
// This option supports both circuit v1 and v2 connections.
// (default: enabled)
func EnableRelay() Option {
return func(cfg *Config) error {
cfg.RelayCustom = true
cfg.Relay = true
return nil
}
}
// DisableRelay configures libp2p to disable the relay transport.
func DisableRelay() Option {
return func(cfg *Config) error {
cfg.RelayCustom = true
cfg.Relay = false
return nil
}
}
// EnableRelayService configures libp2p to run a circuit v2 relay,
// if we detect that we're publicly reachable.
func EnableRelayService(opts ...relayv2.Option) Option {
return func(cfg *Config) error {
cfg.EnableRelayService = true
cfg.RelayServiceOpts = opts
return nil
}
}
// EnableAutoRelay configures libp2p to enable the AutoRelay subsystem.
//
// Dependencies:
// - Relay (enabled by default)
// - Either:
// 1. A list of static relays
// 2. A PeerSource function that provides a chan of relays. See `autorelay.WithPeerSource`
//
// This subsystem performs automatic address rewriting to advertise relay addresses when it
// detects that the node is publicly unreachable (e.g. behind a NAT).
//
// Deprecated: Use EnableAutoRelayWithStaticRelays or EnableAutoRelayWithPeerSource
func EnableAutoRelay(opts ...autorelay.Option) Option {
return func(cfg *Config) error {
cfg.EnableAutoRelay = true
cfg.AutoRelayOpts = opts
return nil
}
}
// EnableAutoRelayWithStaticRelays configures libp2p to enable the AutoRelay subsystem using
// the provided relays as relay candidates.
// This subsystem performs automatic address rewriting to advertise relay addresses when it
// detects that the node is publicly unreachable (e.g. behind a NAT).
func EnableAutoRelayWithStaticRelays(static []peer.AddrInfo, opts ...autorelay.Option) Option {
return func(cfg *Config) error {
cfg.EnableAutoRelay = true
cfg.AutoRelayOpts = append([]autorelay.Option{autorelay.WithStaticRelays(static)}, opts...)
return nil
}
}
// EnableAutoRelayWithPeerSource configures libp2p to enable the AutoRelay
// subsystem using the provided PeerSource callback to get more relay
// candidates. This subsystem performs automatic address rewriting to advertise
// relay addresses when it detects that the node is publicly unreachable (e.g.
// behind a NAT).
func EnableAutoRelayWithPeerSource(peerSource autorelay.PeerSource, opts ...autorelay.Option) Option {
return func(cfg *Config) error {
cfg.EnableAutoRelay = true
cfg.AutoRelayOpts = append([]autorelay.Option{autorelay.WithPeerSource(peerSource)}, opts...)
return nil
}
}
// ForceReachabilityPublic overrides automatic reachability detection in the AutoNAT subsystem,
// forcing the local node to believe it is reachable externally.
func ForceReachabilityPublic() Option {
return func(cfg *Config) error {
public := network.ReachabilityPublic
cfg.AutoNATConfig.ForceReachability = &public
return nil
}
}
// ForceReachabilityPrivate overrides automatic reachability detection in the AutoNAT subsystem,
// forceing the local node to believe it is behind a NAT and not reachable externally.
func ForceReachabilityPrivate() Option {
return func(cfg *Config) error {
private := network.ReachabilityPrivate
cfg.AutoNATConfig.ForceReachability = &private
return nil
}
}
// EnableNATService configures libp2p to provide a service to peers for determining
// their reachability status. When enabled, the host will attempt to dial back
// to peers, and then tell them if it was successful in making such connections.
func EnableNATService() Option {
return func(cfg *Config) error {
cfg.AutoNATConfig.EnableService = true
return nil
}
}
// AutoNATServiceRateLimit changes the default rate limiting configured in helping
// other peers determine their reachability status. When set, the host will limit
// the number of requests it responds to in each 60 second period to the set
// numbers. A value of '0' disables throttling.
func AutoNATServiceRateLimit(global, perPeer int, interval time.Duration) Option {
return func(cfg *Config) error {
cfg.AutoNATConfig.ThrottleGlobalLimit = global
cfg.AutoNATConfig.ThrottlePeerLimit = perPeer
cfg.AutoNATConfig.ThrottleInterval = interval
return nil
}
}
// ConnectionGater configures libp2p to use the given ConnectionGater
// to actively reject inbound/outbound connections based on the lifecycle stage
// of the connection.
//
// For more information, refer to go-libp2p/core.ConnectionGater.
func ConnectionGater(cg connmgr.ConnectionGater) Option {
return func(cfg *Config) error {
if cfg.ConnectionGater != nil {
return errors.New("cannot configure multiple connection gaters, or cannot configure both Filters and ConnectionGater")
}
cfg.ConnectionGater = cg
return nil
}
}
// ResourceManager configures libp2p to use the given ResourceManager.
// When using the p2p/host/resource-manager implementation of the ResourceManager interface,
// it is recommended to set limits for libp2p protocol by calling SetDefaultServiceLimits.
func ResourceManager(rcmgr network.ResourceManager) Option {
return func(cfg *Config) error {
if cfg.ResourceManager != nil {
return errors.New("cannot configure multiple resource managers")
}
cfg.ResourceManager = rcmgr
return nil
}
}
// NATPortMap configures libp2p to use the default NATManager. The default
// NATManager will attempt to open a port in your network's firewall using UPnP.
func NATPortMap() Option {
return NATManager(bhost.NewNATManager)
}
// NATManager will configure libp2p to use the requested NATManager. This
// function should be passed a NATManager *constructor* that takes a libp2p Network.
func NATManager(nm config.NATManagerC) Option {
return func(cfg *Config) error {
if cfg.NATManager != nil {
return fmt.Errorf("cannot specify multiple NATManagers")
}
cfg.NATManager = nm
return nil
}
}
// Ping will configure libp2p to support the ping service; enable by default.
func Ping(enable bool) Option {
return func(cfg *Config) error {
cfg.DisablePing = !enable
return nil
}
}
// Routing will configure libp2p to use routing.
func Routing(rt config.RoutingC) Option {
return func(cfg *Config) error {
if cfg.Routing != nil {
return fmt.Errorf("cannot specify multiple routing options")
}
cfg.Routing = rt
return nil
}
}
// NoListenAddrs will configure libp2p to not listen by default.
//
// This will both clear any configured listen addrs and prevent libp2p from
// applying the default listen address option. It also disables relay, unless the
// user explicitly specifies with an option, as the transport creates an implicit
// listen address that would make the node dialable through any relay it was connected to.
var NoListenAddrs = func(cfg *Config) error {
cfg.ListenAddrs = []ma.Multiaddr{}
if !cfg.RelayCustom {
cfg.RelayCustom = true
cfg.Relay = false
}
return nil
}
// NoTransports will configure libp2p to not enable any transports.
//
// This will both clear any configured transports (specified in prior libp2p
// options) and prevent libp2p from applying the default transports.
var NoTransports = func(cfg *Config) error {
cfg.Transports = []fx.Option{}
return nil
}
// ProtocolVersion sets the protocolVersion string required by the
// libp2p Identify protocol.
func ProtocolVersion(s string) Option {
return func(cfg *Config) error {
cfg.ProtocolVersion = s
return nil
}
}
// UserAgent sets the libp2p user-agent sent along with the identify protocol
func UserAgent(userAgent string) Option {
return func(cfg *Config) error {
cfg.UserAgent = userAgent
return nil
}
}
// MultiaddrResolver sets the libp2p dns resolver
func MultiaddrResolver(rslv network.MultiaddrDNSResolver) Option {
return func(cfg *Config) error {
cfg.MultiaddrResolver = rslv
return nil
}
}
// Experimental
// EnableHolePunching enables NAT traversal by enabling NATT'd peers to both initiate and respond to hole punching attempts
// to create direct/NAT-traversed connections with other peers. (default: disabled)
//
// Dependencies:
// - Relay (enabled by default)
//
// This subsystem performs two functions:
//
// 1. On receiving an inbound Relay connection, it attempts to create a direct connection with the remote peer
// by initiating and co-ordinating a hole punch over the Relayed connection.
// 2. If a peer sees a request to co-ordinate a hole punch on an outbound Relay connection,
// it will participate in the hole-punch to create a direct connection with the remote peer.
//
// If the hole punch is successful, all new streams will thereafter be created on the hole-punched connection.
// The Relayed connection will eventually be closed after a grace period.
//
// All existing indefinite long-lived streams on the Relayed connection will have to re-opened on the hole-punched connection by the user.
// Users can make use of the `Connected`/`Disconnected` notifications emitted by the Network for this purpose.
//
// It is not mandatory but nice to also enable the `AutoRelay` option (See `EnableAutoRelay`)
// so the peer can discover and connect to Relay servers if it discovers that it is NATT'd and has private reachability via AutoNAT.
// This will then enable it to advertise Relay addresses which can be used to accept inbound Relay connections to then co-ordinate
// a hole punch.
//
// If `EnableAutoRelay` is configured and the user is confident that the peer has private reachability/is NATT'd,
// the `ForceReachabilityPrivate` option can be configured to short-circuit reachability discovery via AutoNAT
// so the peer can immediately start connecting to Relay servers.
//
// If `EnableAutoRelay` is configured, the `StaticRelays` option can be used to configure a static set of Relay servers
// for `AutoRelay` to connect to so that it does not need to discover Relay servers via Routing.
func EnableHolePunching(opts ...holepunch.Option) Option {
return func(cfg *Config) error {
cfg.EnableHolePunching = true
cfg.HolePunchingOptions = opts
return nil
}
}
func WithDialTimeout(t time.Duration) Option {
return func(cfg *Config) error {
if t <= 0 {
return errors.New("dial timeout needs to be non-negative")
}
cfg.DialTimeout = t
return nil
}
}
// DisableMetrics configures libp2p to disable prometheus metrics
func DisableMetrics() Option {
return func(cfg *Config) error {
cfg.DisableMetrics = true
return nil
}
}
// PrometheusRegisterer configures libp2p to use reg as the Registerer for all metrics subsystems
func PrometheusRegisterer(reg prometheus.Registerer) Option {
return func(cfg *Config) error {
if cfg.DisableMetrics {
return errors.New("cannot set registerer when metrics are disabled")
}
if cfg.PrometheusRegisterer != nil {
return errors.New("registerer already set")
}
if reg == nil {
return errors.New("registerer cannot be nil")
}
cfg.PrometheusRegisterer = reg
return nil
}
}
// DialRanker configures libp2p to use d as the dial ranker. To enable smart
// dialing use `swarm.DefaultDialRanker`. use `swarm.NoDelayDialRanker` to
// disable smart dialing.
//
// Deprecated: use SwarmOpts(swarm.WithDialRanker(d)) instead
func DialRanker(d network.DialRanker) Option {
return func(cfg *Config) error {
if cfg.DialRanker != nil {
return errors.New("dial ranker already configured")
}
cfg.DialRanker = d
return nil
}
}
// SwarmOpts configures libp2p to use swarm with opts
func SwarmOpts(opts ...swarm.Option) Option {
return func(cfg *Config) error {
cfg.SwarmOpts = opts
return nil
}
}
// DisableIdentifyAddressDiscovery disables address discovery using peer provided observed addresses
// in identify. If you know your public addresses upfront, the recommended way is to use
// AddressFactory to provide the external adddress to the host and use this option to disable
// discovery from identify.
func DisableIdentifyAddressDiscovery() Option {
return func(cfg *Config) error {
cfg.DisableIdentifyAddressDiscovery = true
return nil
}
}
// EnableAutoNATv2 enables autonat v2
func EnableAutoNATv2() Option {
return func(cfg *Config) error {
cfg.EnableAutoNATv2 = true
return nil
}
}
// UDPBlackHoleSuccessCounter configures libp2p to use f as the black hole filter for UDP addrs
func UDPBlackHoleSuccessCounter(f *swarm.BlackHoleSuccessCounter) Option {
return func(cfg *Config) error {
cfg.UDPBlackHoleSuccessCounter = f
cfg.CustomUDPBlackHoleSuccessCounter = true
return nil
}
}
// IPv6BlackHoleSuccessCounter configures libp2p to use f as the black hole filter for IPv6 addrs
func IPv6BlackHoleSuccessCounter(f *swarm.BlackHoleSuccessCounter) Option {
return func(cfg *Config) error {
cfg.IPv6BlackHoleSuccessCounter = f
cfg.CustomIPv6BlackHoleSuccessCounter = true
return nil
}
}
// WithFxOption adds a user provided fx.Option to the libp2p constructor.
// Experimental: This option is subject to change or removal.
func WithFxOption(opts ...fx.Option) Option {
return func(cfg *Config) error {
cfg.UserFxOptions = append(cfg.UserFxOptions, opts...)
return nil
}
}
// ShareTCPListener shares the same listen address between TCP and Websocket
// transports. This lets both transports use the same TCP port.
//
// Currently this behavior is Opt-in. In a future release this will be the
// default, and this option will be removed.
func ShareTCPListener() Option {
return func(cfg *Config) error {
cfg.ShareTCPListener = true
return nil
}
}