package lp2p import ( "crypto/rand" "time" logging "github.com/ipfs/go-log/v2" "github.com/libp2p/go-libp2p" connmgr "github.com/libp2p/go-libp2p-connmgr" "github.com/libp2p/go-libp2p-core/crypto" "github.com/libp2p/go-libp2p-core/peer" "github.com/libp2p/go-libp2p-core/peerstore" "go.uber.org/fx" "golang.org/x/xerrors" "github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/chain/types" ) var log = logging.Logger("p2pnode") const ( KLibp2pHost = "libp2p-host" KTLibp2pHost types.KeyType = KLibp2pHost ) type Libp2pOpts struct { fx.Out Opts []libp2p.Option `group:"libp2p"` } func PrivKey(ks types.KeyStore) (crypto.PrivKey, error) { k, err := ks.Get(KLibp2pHost) if err == nil { return crypto.UnmarshalPrivateKey(k.PrivateKey) } if !xerrors.Is(err, types.ErrKeyInfoNotFound) { return nil, err } pk, err := genLibp2pKey() if err != nil { return nil, err } kbytes, err := crypto.MarshalPrivateKey(pk) if err != nil { return nil, err } if err := ks.Put(KLibp2pHost, types.KeyInfo{ Type: KTLibp2pHost, PrivateKey: kbytes, }); err != nil { return nil, err } return pk, nil } func genLibp2pKey() (crypto.PrivKey, error) { pk, _, err := crypto.GenerateEd25519Key(rand.Reader) if err != nil { return nil, err } return pk, nil } // Misc options func ConnectionManager(low, high uint, grace time.Duration, protected []string) func() (opts Libp2pOpts, err error) { return func() (Libp2pOpts, error) { cm, err := connmgr.NewConnManager(int(low), int(high), connmgr.WithGracePeriod(grace)) if err != nil { return Libp2pOpts{}, err } for _, p := range protected { pid, err := peer.Decode(p) if err != nil { return Libp2pOpts{}, xerrors.Errorf("failed to parse peer ID in protected peers array: %w", err) } cm.Protect(pid, "config-prot") } infos, err := build.BuiltinBootstrap() if err != nil { return Libp2pOpts{}, xerrors.Errorf("failed to get bootstrap peers: %w", err) } for _, inf := range infos { cm.Protect(inf.ID, "bootstrap") } return Libp2pOpts{ Opts: []libp2p.Option{libp2p.ConnectionManager(cm)}, }, nil } } func PstoreAddSelfKeys(id peer.ID, sk crypto.PrivKey, ps peerstore.Peerstore) error { if err := ps.AddPubKey(id, sk.GetPublic()); err != nil { return err } return ps.AddPrivKey(id, sk) } func simpleOpt(opt libp2p.Option) func() (opts Libp2pOpts, err error) { return func() (opts Libp2pOpts, err error) { opts.Opts = append(opts.Opts, opt) return } }