Import libp2p modules

License: MIT
Signed-off-by: Jakub Sztandera <kubuxu@protonmail.ch>
This commit is contained in:
Łukasz Magiera
2019-07-01 23:11:33 +02:00
committed by Jakub Sztandera
parent 795621ed27
commit 63627e863e
15 changed files with 911 additions and 1 deletions
+25
View File
@@ -0,0 +1,25 @@
package helpers
import (
"context"
"go.uber.org/fx"
)
type MetricsCtx context.Context
// LifecycleCtx creates a context which will be cancelled when lifecycle stops
//
// This is a hack which we need because most of our services use contexts in a
// wrong way
func LifecycleCtx(mctx MetricsCtx, lc fx.Lifecycle) context.Context {
ctx, cancel := context.WithCancel(mctx)
lc.Append(fx.Hook{
OnStop: func(_ context.Context) error {
cancel()
return nil
},
})
return ctx
}
-1
View File
@@ -1 +0,0 @@
package modules
+117
View File
@@ -0,0 +1,117 @@
package libp2p
import (
"fmt"
"github.com/libp2p/go-libp2p"
host "github.com/libp2p/go-libp2p-core/host"
p2pbhost "github.com/libp2p/go-libp2p/p2p/host/basic"
mafilter "github.com/libp2p/go-maddr-filter"
ma "github.com/multiformats/go-multiaddr"
mamask "github.com/whyrusleeping/multiaddr-filter"
)
func AddrFilters(filters []string) func() (opts Libp2pOpts, err error) {
return func() (opts Libp2pOpts, err error) {
for _, s := range filters {
f, err := mamask.NewMask(s)
if err != nil {
return opts, fmt.Errorf("incorrectly formatted address filter in config: %s", s)
}
opts.Opts = append(opts.Opts, libp2p.FilterAddresses(f))
}
return opts, nil
}
}
func makeAddrsFactory(announce []string, noAnnounce []string) (p2pbhost.AddrsFactory, error) {
var annAddrs []ma.Multiaddr
for _, addr := range announce {
maddr, err := ma.NewMultiaddr(addr)
if err != nil {
return nil, err
}
annAddrs = append(annAddrs, maddr)
}
filters := mafilter.NewFilters()
noAnnAddrs := map[string]bool{}
for _, addr := range noAnnounce {
f, err := mamask.NewMask(addr)
if err == nil {
filters.AddFilter(*f, mafilter.ActionDeny)
continue
}
maddr, err := ma.NewMultiaddr(addr)
if err != nil {
return nil, err
}
noAnnAddrs[string(maddr.Bytes())] = true
}
return func(allAddrs []ma.Multiaddr) []ma.Multiaddr {
var addrs []ma.Multiaddr
if len(annAddrs) > 0 {
addrs = annAddrs
} else {
addrs = allAddrs
}
var out []ma.Multiaddr
for _, maddr := range addrs {
// check for exact matches
ok := noAnnAddrs[string(maddr.Bytes())]
// check for /ipcidr matches
if !ok && !filters.AddrBlocked(maddr) {
out = append(out, maddr)
}
}
return out
}, nil
}
func AddrsFactory(announce []string, noAnnounce []string) func() (opts Libp2pOpts, err error) {
return func() (opts Libp2pOpts, err error) {
addrsFactory, err := makeAddrsFactory(announce, noAnnounce)
if err != nil {
return opts, err
}
opts.Opts = append(opts.Opts, libp2p.AddrsFactory(addrsFactory))
return
}
}
func listenAddresses(addresses []string) ([]ma.Multiaddr, error) {
var listen []ma.Multiaddr
for _, addr := range addresses {
maddr, err := ma.NewMultiaddr(addr)
if err != nil {
return nil, fmt.Errorf("failure to parse config.Addresses.Swarm: %s", addresses)
}
listen = append(listen, maddr)
}
return listen, nil
}
func StartListening(addresses []string) func(host host.Host) error {
return func(host host.Host) error {
listenAddrs, err := listenAddresses(addresses)
if err != nil {
return err
}
// Actually start listening:
if err := host.Network().Listen(listenAddrs...); err != nil {
return err
}
// list out our addresses
addrs, err := host.Network().InterfaceListenAddresses()
if err != nil {
return err
}
log.Infof("Swarm listening at: %s", addrs)
return nil
}
}
+53
View File
@@ -0,0 +1,53 @@
package libp2p
import (
"context"
"time"
"github.com/libp2p/go-libp2p-core/host"
"github.com/libp2p/go-libp2p-core/peer"
"github.com/libp2p/go-libp2p/p2p/discovery"
"go.uber.org/fx"
"github.com/filecoin-project/go-lotus/node/modules/helpers"
)
const discoveryConnTimeout = time.Second * 30
type discoveryHandler struct {
ctx context.Context
host host.Host
}
func (dh *discoveryHandler) HandlePeerFound(p peer.AddrInfo) {
log.Warning("trying peer info: ", p)
ctx, cancel := context.WithTimeout(dh.ctx, discoveryConnTimeout)
defer cancel()
if err := dh.host.Connect(ctx, p); err != nil {
log.Warning("Failed to connect to peer found by discovery: ", err)
}
}
func DiscoveryHandler(mctx helpers.MetricsCtx, lc fx.Lifecycle, host host.Host) *discoveryHandler {
return &discoveryHandler{
ctx: helpers.LifecycleCtx(mctx, lc),
host: host,
}
}
func SetupDiscovery(mdns bool, mdnsInterval int) func(helpers.MetricsCtx, fx.Lifecycle, host.Host, *discoveryHandler) error {
return func(mctx helpers.MetricsCtx, lc fx.Lifecycle, host host.Host, handler *discoveryHandler) error {
if mdns {
if mdnsInterval == 0 {
mdnsInterval = 5
}
service, err := discovery.NewMdnsService(helpers.LifecycleCtx(mctx, lc), host, time.Duration(mdnsInterval)*time.Second, discovery.ServiceTag)
if err != nil {
log.Error("mdns error: ", err)
return nil
}
service.RegisterNotifee(handler)
}
return nil
}
}
+98
View File
@@ -0,0 +1,98 @@
package libp2p
import (
"context"
"fmt"
"github.com/ipfs/go-datastore"
nilrouting "github.com/ipfs/go-ipfs-routing/none"
"github.com/libp2p/go-libp2p"
host "github.com/libp2p/go-libp2p-core/host"
peer "github.com/libp2p/go-libp2p-core/peer"
peerstore "github.com/libp2p/go-libp2p-core/peerstore"
dht "github.com/libp2p/go-libp2p-kad-dht"
dhtopts "github.com/libp2p/go-libp2p-kad-dht/opts"
record "github.com/libp2p/go-libp2p-record"
routedhost "github.com/libp2p/go-libp2p/p2p/host/routed"
mocknet "github.com/libp2p/go-libp2p/p2p/net/mock"
"go.uber.org/fx"
"github.com/filecoin-project/go-lotus/node/modules/helpers"
)
type P2PHostIn struct {
fx.In
ID peer.ID
Peerstore peerstore.Peerstore
Opts [][]libp2p.Option `group:"libp2p"`
}
// ////////////////////////
type RawHost host.Host
func Host(mctx helpers.MetricsCtx, lc fx.Lifecycle, params P2PHostIn) (RawHost, error) {
ctx := helpers.LifecycleCtx(mctx, lc)
pkey := params.Peerstore.PrivKey(params.ID)
if pkey == nil {
return nil, fmt.Errorf("missing private key for node ID: %s", params.ID.Pretty())
}
opts := []libp2p.Option{libp2p.Identity(pkey), libp2p.Peerstore(params.Peerstore), libp2p.NoListenAddrs}
for _, o := range params.Opts {
opts = append(opts, o...)
}
h, err := libp2p.New(ctx, opts...)
if err != nil {
return nil, err
}
lc.Append(fx.Hook{
OnStop: func(ctx context.Context) error {
return h.Close()
},
})
return h, nil
}
func MockHost(mn mocknet.Mocknet, id peer.ID, ps peerstore.Peerstore) (RawHost, error) {
return mn.AddPeerWithPeerstore(id, ps)
}
func DHTRouting(client bool) interface{} {
return func(mctx helpers.MetricsCtx, lc fx.Lifecycle, host RawHost, dstore datastore.Batching, validator record.Validator) (BaseIpfsRouting, error) {
ctx := helpers.LifecycleCtx(mctx, lc)
d, err := dht.New(
ctx, host,
dhtopts.Client(client),
dhtopts.Datastore(dstore),
dhtopts.Validator(validator),
)
if err != nil {
return nil, err
}
lc.Append(fx.Hook{
OnStop: func(ctx context.Context) error {
return d.Close()
},
})
return d, nil
}
}
func NilRouting(mctx helpers.MetricsCtx) (BaseIpfsRouting, error) {
return nilrouting.ConstructNilRouting(mctx, nil, nil, nil)
}
func RoutedHost(rh RawHost, r BaseIpfsRouting) host.Host {
return routedhost.Wrap(rh, r)
}
+46
View File
@@ -0,0 +1,46 @@
package libp2p
import (
"time"
logging "github.com/ipfs/go-log"
"github.com/libp2p/go-libp2p"
"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"
)
var log = logging.Logger("p2pnode")
type Libp2pOpts struct {
fx.Out
Opts []libp2p.Option `group:"libp2p"`
}
// Misc options
func ConnectionManager(low, high int, grace time.Duration) func() (opts Libp2pOpts, err error) {
return func() (opts Libp2pOpts, err error) {
cm := connmgr.NewConnManager(low, high, grace)
opts.Opts = append(opts.Opts, libp2p.ConnectionManager(cm))
return
}
}
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
}
}
+34
View File
@@ -0,0 +1,34 @@
package libp2p
/*import (
"github.com/libp2p/go-libp2p"
autonat "github.com/libp2p/go-libp2p-autonat-svc"
host "github.com/libp2p/go-libp2p-core/host"
libp2pquic "github.com/libp2p/go-libp2p-quic-transport"
"go.uber.org/fx"
"github.com/ipfs/go-ipfs/repo"
"github.com/filecoin-project/go-lotus/node/modules/helpers"
)
var NatPortMap = simpleOpt(libp2p.NATPortMap())
func AutoNATService(quic bool) func(repo repo.Repo, mctx helpers.MetricsCtx, lc fx.Lifecycle, host host.Host) error {
return func(repo repo.Repo, mctx helpers.MetricsCtx, lc fx.Lifecycle, host host.Host) error {
// collect private net option in case swarm.key is presented
opts, _, err := PNet(repo)
if err != nil {
// swarm key exists but was failed to decode
return err
}
if quic {
opts.Opts = append(opts.Opts, libp2p.DefaultTransports, libp2p.Transport(libp2pquic.NewTransport))
}
_, err = autonat.NewAutoNATService(helpers.LifecycleCtx(mctx, lc), host, opts.Opts...)
return err
}
}
*/
+71
View File
@@ -0,0 +1,71 @@
package libp2p
/*import (
"bytes"
"context"
"fmt"
"time"
"github.com/libp2p/go-libp2p"
host "github.com/libp2p/go-libp2p-core/host"
pnet "github.com/libp2p/go-libp2p-pnet"
"go.uber.org/fx"
"github.com/ipfs/go-ipfs/repo"
)
type PNetFingerprint []byte
func PNet(repo repo.Repo) (opts Libp2pOpts, fp PNetFingerprint, err error) {
swarmkey, err := repo.SwarmKey()
if err != nil || swarmkey == nil {
return opts, nil, err
}
protec, err := pnet.NewProtector(bytes.NewReader(swarmkey))
if err != nil {
return opts, nil, fmt.Errorf("failed to configure private network: %s", err)
}
fp = protec.Fingerprint()
opts.Opts = append(opts.Opts, libp2p.PrivateNetwork(protec))
return opts, fp, nil
}
func PNetChecker(repo repo.Repo, ph host.Host, lc fx.Lifecycle) error {
// TODO: better check?
swarmkey, err := repo.SwarmKey()
if err != nil || swarmkey == nil {
return err
}
done := make(chan struct{})
lc.Append(fx.Hook{
OnStart: func(_ context.Context) error {
go func() {
t := time.NewTicker(30 * time.Second)
defer t.Stop()
<-t.C // swallow one tick
for {
select {
case <-t.C:
if len(ph.Network().Peers()) == 0 {
log.Warning("We are in private network and have no peers.")
log.Warning("This might be configuration mistake.")
}
case <-done:
return
}
}
}()
return nil
},
OnStop: func(_ context.Context) error {
close(done)
return nil
},
})
return nil
}
*/
+21
View File
@@ -0,0 +1,21 @@
package libp2p
import (
host "github.com/libp2p/go-libp2p-core/host"
pubsub "github.com/libp2p/go-libp2p-pubsub"
"go.uber.org/fx"
"github.com/filecoin-project/go-lotus/node/modules/helpers"
)
func FloodSub(pubsubOptions ...pubsub.Option) interface{} {
return func(mctx helpers.MetricsCtx, lc fx.Lifecycle, host host.Host) (service *pubsub.PubSub, err error) {
return pubsub.NewFloodSub(helpers.LifecycleCtx(mctx, lc), host, pubsubOptions...)
}
}
func GossipSub(pubsubOptions ...pubsub.Option) interface{} {
return func(mctx helpers.MetricsCtx, lc fx.Lifecycle, host host.Host) (service *pubsub.PubSub, err error) {
return pubsub.NewGossipSub(helpers.LifecycleCtx(mctx, lc), host, pubsubOptions...)
}
}
+56
View File
@@ -0,0 +1,56 @@
package libp2p
import (
"fmt"
"github.com/libp2p/go-libp2p"
circuit "github.com/libp2p/go-libp2p-circuit"
coredisc "github.com/libp2p/go-libp2p-core/discovery"
routing "github.com/libp2p/go-libp2p-core/routing"
discovery "github.com/libp2p/go-libp2p-discovery"
basichost "github.com/libp2p/go-libp2p/p2p/host/basic"
relay "github.com/libp2p/go-libp2p/p2p/host/relay"
"go.uber.org/fx"
"github.com/filecoin-project/go-lotus/node/modules/helpers"
)
func Relay(disable, enableHop bool) func() (opts Libp2pOpts, err error) {
return func() (opts Libp2pOpts, err error) {
if disable {
// Enabled by default.
opts.Opts = append(opts.Opts, libp2p.DisableRelay())
} else {
relayOpts := []circuit.RelayOpt{circuit.OptDiscovery}
if enableHop {
relayOpts = append(relayOpts, circuit.OptHop)
}
opts.Opts = append(opts.Opts, libp2p.EnableRelay(relayOpts...))
}
return
}
}
// TODO: should be use baseRouting or can we use higher level router here?
func Discovery(router BaseIpfsRouting) (coredisc.Discovery, error) {
crouter, ok := router.(routing.ContentRouting)
if !ok {
return nil, fmt.Errorf("no suitable routing for discovery")
}
return discovery.NewRoutingDiscovery(crouter), nil
}
// NOTE: only set when relayHop is set
func AdvertiseRelay(mctx helpers.MetricsCtx, d coredisc.Discovery) {
relay.Advertise(mctx, d)
}
// NOTE: only set when relayHop is not set
func AutoRelay(mctx helpers.MetricsCtx, lc fx.Lifecycle, router BaseIpfsRouting, h RawHost, d coredisc.Discovery) error {
ctx := helpers.LifecycleCtx(mctx, lc)
// TODO: review: LibP2P doesn't set this as host in config.go, why?
_ = relay.NewAutoRelay(ctx, h.(*basichost.BasicHost), d, router)
return nil
}
+70
View File
@@ -0,0 +1,70 @@
package libp2p
import (
"context"
"sort"
routing "github.com/libp2p/go-libp2p-core/routing"
dht "github.com/libp2p/go-libp2p-kad-dht"
record "github.com/libp2p/go-libp2p-record"
routinghelpers "github.com/libp2p/go-libp2p-routing-helpers"
"go.uber.org/fx"
)
type BaseIpfsRouting routing.Routing
type Router struct {
routing.Routing
Priority int // less = more important
}
type p2pRouterOut struct {
fx.Out
Router Router `group:"routers"`
}
func BaseRouting(lc fx.Lifecycle, in BaseIpfsRouting) (out p2pRouterOut, dr *dht.IpfsDHT) {
if dht, ok := in.(*dht.IpfsDHT); ok {
dr = dht
lc.Append(fx.Hook{
OnStop: func(ctx context.Context) error {
return dr.Close()
},
})
}
return p2pRouterOut{
Router: Router{
Priority: 1000,
Routing: in,
},
}, dr
}
type p2pOnlineRoutingIn struct {
fx.In
Routers []Router `group:"routers"`
Validator record.Validator
}
func Routing(in p2pOnlineRoutingIn) routing.Routing {
routers := in.Routers
sort.SliceStable(routers, func(i, j int) bool {
return routers[i].Priority < routers[j].Priority
})
irouters := make([]routing.Routing, len(routers))
for i, v := range routers {
irouters[i] = v.Routing
}
return routinghelpers.Tiered{
Routers: irouters,
Validator: in.Validator,
}
}
+54
View File
@@ -0,0 +1,54 @@
package libp2p
import (
"os"
"strings"
"github.com/libp2p/go-libp2p"
smux "github.com/libp2p/go-libp2p-core/mux"
mplex "github.com/libp2p/go-libp2p-mplex"
yamux "github.com/libp2p/go-libp2p-yamux"
)
func makeSmuxTransportOption(mplexExp bool) libp2p.Option {
const yamuxID = "/yamux/1.0.0"
const mplexID = "/mplex/6.7.0"
ymxtpt := *yamux.DefaultTransport
ymxtpt.AcceptBacklog = 512
if os.Getenv("YAMUX_DEBUG") != "" {
ymxtpt.LogOutput = os.Stderr
}
muxers := map[string]smux.Multiplexer{yamuxID: &ymxtpt}
if mplexExp {
muxers[mplexID] = mplex.DefaultTransport
}
// Allow muxer preference order overriding
order := []string{yamuxID, mplexID}
if prefs := os.Getenv("LIBP2P_MUX_PREFS"); prefs != "" {
order = strings.Fields(prefs)
}
opts := make([]libp2p.Option, 0, len(order))
for _, id := range order {
tpt, ok := muxers[id]
if !ok {
log.Warning("unknown or duplicate muxer in LIBP2P_MUX_PREFS: %s", id)
continue
}
delete(muxers, id)
opts = append(opts, libp2p.Muxer(id, tpt))
}
return libp2p.ChainOptions(opts...)
}
func SmuxTransport(mplex bool) func() (opts Libp2pOpts, err error) {
return func() (opts Libp2pOpts, err error) {
opts.Opts = append(opts.Opts, makeSmuxTransportOption(mplex))
return
}
}
+38
View File
@@ -0,0 +1,38 @@
package libp2p
import (
"github.com/libp2p/go-libp2p"
metrics "github.com/libp2p/go-libp2p-core/metrics"
libp2pquic "github.com/libp2p/go-libp2p-quic-transport"
secio "github.com/libp2p/go-libp2p-secio"
tls "github.com/libp2p/go-libp2p-tls"
)
var DefaultTransports = simpleOpt(libp2p.DefaultTransports)
var QUIC = simpleOpt(libp2p.Transport(libp2pquic.NewTransport))
func Security(enabled, preferTLS bool) interface{} {
if !enabled {
return func() (opts Libp2pOpts) {
// TODO: shouldn't this be Errorf to guarantee visibility?
log.Warningf(`Your IPFS node has been configured to run WITHOUT ENCRYPTED CONNECTIONS.
You will not be able to connect to any nodes configured to use encrypted connections`)
opts.Opts = append(opts.Opts, libp2p.NoSecurity)
return opts
}
}
return func() (opts Libp2pOpts) {
if preferTLS {
opts.Opts = append(opts.Opts, libp2p.ChainOptions(libp2p.Security(tls.ID, tls.New), libp2p.Security(secio.ID, secio.New)))
} else {
opts.Opts = append(opts.Opts, libp2p.ChainOptions(libp2p.Security(secio.ID, secio.New), libp2p.Security(tls.ID, tls.New)))
}
return opts
}
}
func BandwidthCounter() (opts Libp2pOpts, reporter metrics.Reporter) {
reporter = metrics.NewBandwidthCounter()
opts.Opts = append(opts.Opts, libp2p.BandwidthReporter(reporter))
return opts, reporter
}