package libp2p import ( "context" "crypto/rand" crypto "github.com/libp2p/go-libp2p-crypto" host "github.com/libp2p/go-libp2p-host" pnet "github.com/libp2p/go-libp2p-interface-pnet" metrics "github.com/libp2p/go-libp2p-metrics" peer "github.com/libp2p/go-libp2p-peer" pstore "github.com/libp2p/go-libp2p-peerstore" swarm "github.com/libp2p/go-libp2p-swarm" transport "github.com/libp2p/go-libp2p-transport" bhost "github.com/libp2p/go-libp2p/p2p/host/basic" mux "github.com/libp2p/go-stream-muxer" ma "github.com/multiformats/go-multiaddr" mplex "github.com/whyrusleeping/go-smux-multiplex" msmux "github.com/whyrusleeping/go-smux-multistream" yamux "github.com/whyrusleeping/go-smux-yamux" ) // Config describes a set of settings for a libp2p node type Config struct { Transports []transport.Transport Muxer mux.Transport ListenAddrs []ma.Multiaddr PeerKey crypto.PrivKey Peerstore pstore.Peerstore Protector pnet.Protector Reporter metrics.Reporter DisableSecio bool } type Option func(cfg *Config) error func Transports(tpts []transport.Transport) Option { return func(cfg *Config) error { cfg.Transports = tpts return nil } } 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 } } func ListenAddrs(addrs []ma.Multiaddr) Option { return func(cfg *Config) error { cfg.ListenAddrs = append(cfg.ListenAddrs, addrs...) return nil } } func NoSecio(cfg *Config) error { cfg.DisableSecio = true return nil } func WithMuxer(m mux.Transport) Option { return func(cfg *Config) error { cfg.Muxer = m return nil } } func WithPeerstore(ps pstore.Peerstore) Option { return func(cfg *Config) error { cfg.Peerstore = ps return nil } } func WithNetProtector(prot pnet.Protector) Option { return func(cfg *Config) error { cfg.Protector = prot return nil } } func WithBandwidthReporter(rep metrics.Reporter) Option { return func(cfg *Config) error { cfg.Reporter = rep return nil } } func New(ctx context.Context, opts ...Option) (host.Host, error) { cfg := DefaultConfig() for _, opt := range opts { if err := opt(cfg); err != nil { return nil, err } } return newWithCfg(ctx, cfg) } func WithPeerKey(sk crypto.PrivKey) Option { return func(cfg *Config) error { cfg.PeerKey = sk return nil } } func newWithCfg(ctx context.Context, cfg *Config) (host.Host, error) { if cfg == nil { cfg = DefaultConfig() } // If no key was given, generate a random 2048 bit RSA key if cfg.PeerKey == nil { priv, _, err := crypto.GenerateKeyPairWithReader(crypto.RSA, 2048, rand.Reader) if err != nil { return nil, err } cfg.PeerKey = priv } // Obtain Peer ID from public key pid, err := peer.IDFromPublicKey(cfg.PeerKey.GetPublic()) if err != nil { return nil, err } // Create a new blank peerstore if none was passed in ps := cfg.Peerstore if ps == nil { ps = pstore.NewPeerstore() } // If secio is disabled, don't add our private key to the peerstore if !cfg.DisableSecio { ps.AddPrivKey(pid, cfg.PeerKey) ps.AddPubKey(pid, cfg.PeerKey.GetPublic()) } swrm, err := swarm.NewSwarmWithProtector(ctx, cfg.ListenAddrs, pid, ps, cfg.Protector, cfg.Muxer, cfg.Reporter) if err != nil { return nil, err } netw := (*swarm.Network)(swrm) return bhost.New(netw), nil } func DefaultMuxer() mux.Transport { // Set up stream multiplexer tpt := msmux.NewBlankTransport() // By default, support yamux and multiplex tpt.AddTransport("/yamux/1.0.0", yamux.DefaultTransport) tpt.AddTransport("/mplex/6.3.0", mplex.DefaultTransport) return tpt } func DefaultConfig() *Config { // Create a multiaddress that listens on a random port on all interfaces addr, err := ma.NewMultiaddr("/ip4/0.0.0.0/tcp/0") if err != nil { panic(err) } return &Config{ ListenAddrs: []ma.Multiaddr{addr}, Peerstore: pstore.NewPeerstore(), Muxer: DefaultMuxer(), } }