-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Also, make the libp2p constructor fully useful. There should now be no need to manually construct a swarm/host.
- Loading branch information
Showing
28 changed files
with
1,335 additions
and
511 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,176 @@ | ||
package config | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
|
||
bhost "github.com/libp2p/go-libp2p/p2p/host/basic" | ||
|
||
logging "github.com/ipfs/go-log" | ||
circuit "github.com/libp2p/go-libp2p-circuit" | ||
crypto "github.com/libp2p/go-libp2p-crypto" | ||
host "github.com/libp2p/go-libp2p-host" | ||
ifconnmgr "github.com/libp2p/go-libp2p-interface-connmgr" | ||
pnet "github.com/libp2p/go-libp2p-interface-pnet" | ||
metrics "github.com/libp2p/go-libp2p-metrics" | ||
inet "github.com/libp2p/go-libp2p-net" | ||
peer "github.com/libp2p/go-libp2p-peer" | ||
pstore "github.com/libp2p/go-libp2p-peerstore" | ||
swarm "github.com/libp2p/go-libp2p-swarm" | ||
tptu "github.com/libp2p/go-libp2p-transport-upgrader" | ||
filter "github.com/libp2p/go-maddr-filter" | ||
ma "github.com/multiformats/go-multiaddr" | ||
) | ||
|
||
var log = logging.Logger("p2p-config") | ||
|
||
// AddrsFactory is a function that takes a set of multiaddrs we're listening on and | ||
// returns the set of multiaddrs we should advertise to the network. | ||
type AddrsFactory = bhost.AddrsFactory | ||
|
||
// NATManagerC is a NATManager constructor. | ||
type NATManagerC func(inet.Network) bhost.NATManager | ||
|
||
// Config describes a set of settings for a libp2p node | ||
// | ||
// This is *not* a stable interface. Use the options defined in the root | ||
// package. | ||
type Config struct { | ||
PeerKey crypto.PrivKey | ||
|
||
Transports []TptC | ||
Muxers []MsMuxC | ||
SecurityTransports []MsSecC | ||
Insecure bool | ||
Protector pnet.Protector | ||
|
||
Relay bool | ||
RelayOpts []circuit.RelayOpt | ||
|
||
ListenAddrs []ma.Multiaddr | ||
AddrsFactory bhost.AddrsFactory | ||
Filters *filter.Filters | ||
|
||
ConnManager ifconnmgr.ConnManager | ||
NATManager NATManagerC | ||
Peerstore pstore.Peerstore | ||
Reporter metrics.Reporter | ||
} | ||
|
||
// NewNode constructs a new libp2p Host from the Config. | ||
// | ||
// This function consumes the config. Do not reuse it (really!). | ||
func (cfg *Config) NewNode(ctx context.Context) (host.Host, error) { | ||
// Check this early. Prevents us from even *starting* without verifying this. | ||
if pnet.ForcePrivateNetwork && cfg.Protector == nil { | ||
log.Error("tried to create a libp2p node with no Private" + | ||
" Network Protector but usage of Private Networks" + | ||
" is forced by the enviroment") | ||
// Note: This is *also* checked the upgrader itself so it'll be | ||
// enforced even *if* you don't use the libp2p constructor. | ||
return nil, pnet.ErrNotInPrivateNetwork | ||
} | ||
|
||
if cfg.PeerKey == nil { | ||
return nil, fmt.Errorf("no peer key specified") | ||
} | ||
|
||
// Obtain Peer ID from public key | ||
pid, err := peer.IDFromPublicKey(cfg.PeerKey.GetPublic()) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
if cfg.Peerstore == nil { | ||
return nil, fmt.Errorf("no peerstore specified") | ||
} | ||
|
||
if !cfg.Insecure { | ||
cfg.Peerstore.AddPrivKey(pid, cfg.PeerKey) | ||
cfg.Peerstore.AddPubKey(pid, cfg.PeerKey.GetPublic()) | ||
} | ||
|
||
// TODO: Make the swarm implementation configurable. | ||
swrm := swarm.NewSwarm(ctx, pid, cfg.Peerstore, cfg.Reporter) | ||
if cfg.Filters != nil { | ||
swrm.Filters = cfg.Filters | ||
} | ||
|
||
// TODO: make host implementation configurable. | ||
h, err := bhost.NewHost(ctx, swrm, &bhost.HostOpts{ | ||
ConnManager: cfg.ConnManager, | ||
AddrsFactory: cfg.AddrsFactory, | ||
NATManager: cfg.NATManager, | ||
}) | ||
if err != nil { | ||
swrm.Close() | ||
return nil, err | ||
} | ||
|
||
upgrader := new(tptu.Upgrader) | ||
upgrader.Protector = cfg.Protector | ||
upgrader.Filters = swrm.Filters | ||
if cfg.Insecure { | ||
upgrader.Secure = makeInsecureTransport(pid) | ||
} else { | ||
upgrader.Secure, err = makeSecurityTransport(h, cfg.SecurityTransports) | ||
if err != nil { | ||
h.Close() | ||
return nil, err | ||
} | ||
} | ||
|
||
upgrader.Muxer, err = makeMuxer(h, cfg.Muxers) | ||
if err != nil { | ||
h.Close() | ||
return nil, err | ||
} | ||
|
||
tpts, err := makeTransports(h, upgrader, cfg.Transports) | ||
if err != nil { | ||
h.Close() | ||
return nil, err | ||
} | ||
for _, t := range tpts { | ||
err = swrm.AddTransport(t) | ||
if err != nil { | ||
h.Close() | ||
return nil, err | ||
} | ||
} | ||
|
||
if cfg.Relay { | ||
err := circuit.AddRelayTransport(swrm.Context(), h, upgrader, cfg.RelayOpts...) | ||
if err != nil { | ||
h.Close() | ||
return nil, err | ||
} | ||
} | ||
|
||
// TODO: This method succeeds if listening on one address succeeds. We | ||
// should probably fail if listening on *any* addr fails. | ||
if err := h.Network().Listen(cfg.ListenAddrs...); err != nil { | ||
h.Close() | ||
return nil, err | ||
} | ||
|
||
// TODO: Configure routing (it's a pain to setup). | ||
// TODO: Bootstrapping. | ||
|
||
return h, nil | ||
} | ||
|
||
// Option is a libp2p config option that can be given to the libp2p constructor | ||
// (`libp2p.New`). | ||
type Option func(cfg *Config) error | ||
|
||
// Apply applies the given options to the config, returning the first error | ||
// encountered (if any). | ||
func (cfg *Config) Apply(opts ...Option) error { | ||
for _, opt := range opts { | ||
if err := opt(cfg); err != nil { | ||
return err | ||
} | ||
} | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
package config | ||
|
||
import ( | ||
"fmt" | ||
"reflect" | ||
|
||
security "github.com/libp2p/go-conn-security" | ||
crypto "github.com/libp2p/go-libp2p-crypto" | ||
host "github.com/libp2p/go-libp2p-host" | ||
pnet "github.com/libp2p/go-libp2p-interface-pnet" | ||
inet "github.com/libp2p/go-libp2p-net" | ||
peer "github.com/libp2p/go-libp2p-peer" | ||
pstore "github.com/libp2p/go-libp2p-peerstore" | ||
transport "github.com/libp2p/go-libp2p-transport" | ||
tptu "github.com/libp2p/go-libp2p-transport-upgrader" | ||
filter "github.com/libp2p/go-maddr-filter" | ||
mux "github.com/libp2p/go-stream-muxer" | ||
) | ||
|
||
var ( | ||
// interfaces | ||
hostType = reflect.TypeOf((*host.Host)(nil)).Elem() | ||
networkType = reflect.TypeOf((*inet.Network)(nil)).Elem() | ||
transportType = reflect.TypeOf((*transport.Transport)(nil)).Elem() | ||
muxType = reflect.TypeOf((*mux.Transport)(nil)).Elem() | ||
securityType = reflect.TypeOf((*security.Transport)(nil)).Elem() | ||
protectorType = reflect.TypeOf((*pnet.Protector)(nil)).Elem() | ||
privKeyType = reflect.TypeOf((*crypto.PrivKey)(nil)).Elem() | ||
pubKeyType = reflect.TypeOf((*crypto.PubKey)(nil)).Elem() | ||
pstoreType = reflect.TypeOf((*pstore.Peerstore)(nil)).Elem() | ||
|
||
// concrete types | ||
peerIDType = reflect.TypeOf((peer.ID)("")) | ||
filtersType = reflect.TypeOf((*filter.Filters)(nil)) | ||
upgraderType = reflect.TypeOf((*tptu.Upgrader)(nil)) | ||
) | ||
|
||
var argTypes = map[reflect.Type]constructor{ | ||
upgraderType: func(h host.Host, u *tptu.Upgrader) interface{} { return u }, | ||
hostType: func(h host.Host, u *tptu.Upgrader) interface{} { return h }, | ||
networkType: func(h host.Host, u *tptu.Upgrader) interface{} { return h.Network() }, | ||
muxType: func(h host.Host, u *tptu.Upgrader) interface{} { return u.Muxer }, | ||
securityType: func(h host.Host, u *tptu.Upgrader) interface{} { return u.Secure }, | ||
protectorType: func(h host.Host, u *tptu.Upgrader) interface{} { return u.Protector }, | ||
filtersType: func(h host.Host, u *tptu.Upgrader) interface{} { return u.Filters }, | ||
peerIDType: func(h host.Host, u *tptu.Upgrader) interface{} { return h.ID() }, | ||
privKeyType: func(h host.Host, u *tptu.Upgrader) interface{} { return h.Peerstore().PrivKey(h.ID()) }, | ||
pubKeyType: func(h host.Host, u *tptu.Upgrader) interface{} { return h.Peerstore().PubKey(h.ID()) }, | ||
pstoreType: func(h host.Host, u *tptu.Upgrader) interface{} { return h.Peerstore() }, | ||
} | ||
|
||
func newArgTypeSet(types ...reflect.Type) map[reflect.Type]constructor { | ||
result := make(map[reflect.Type]constructor, len(types)) | ||
for _, ty := range types { | ||
c, ok := argTypes[ty] | ||
if !ok { | ||
panic(fmt.Sprintf("missing constructor for type %s", ty)) | ||
} | ||
result[ty] = c | ||
} | ||
return result | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
package config | ||
|
||
import ( | ||
"fmt" | ||
|
||
host "github.com/libp2p/go-libp2p-host" | ||
mux "github.com/libp2p/go-stream-muxer" | ||
msmux "github.com/whyrusleeping/go-smux-multistream" | ||
) | ||
|
||
// MuxC is a stream multiplex transport constructor | ||
type MuxC func(h host.Host) (mux.Transport, error) | ||
|
||
// MsMuxC is a tuple containing a multiplex transport constructor and a protocol | ||
// ID. | ||
type MsMuxC struct { | ||
MuxC | ||
ID string | ||
} | ||
|
||
var muxArgTypes = newArgTypeSet(hostType, networkType, peerIDType, pstoreType) | ||
|
||
// MuxerConstructor creates a multiplex constructor from the passed parameter | ||
// using reflection. | ||
func MuxerConstructor(m interface{}) (MuxC, error) { | ||
// Already constructed? | ||
if t, ok := m.(mux.Transport); ok { | ||
return func(_ host.Host) (mux.Transport, error) { | ||
return t, nil | ||
}, nil | ||
} | ||
|
||
ctor, err := makeConstructor(m, muxType, muxArgTypes) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return func(h host.Host) (mux.Transport, error) { | ||
t, err := ctor(h, nil) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return t.(mux.Transport), nil | ||
}, nil | ||
} | ||
|
||
func makeMuxer(h host.Host, tpts []MsMuxC) (mux.Transport, error) { | ||
muxMuxer := msmux.NewBlankTransport() | ||
transportSet := make(map[string]struct{}, len(tpts)) | ||
for _, tptC := range tpts { | ||
if _, ok := transportSet[tptC.ID]; ok { | ||
return nil, fmt.Errorf("duplicate muxer transport: %s", tptC.ID) | ||
} | ||
} | ||
for _, tptC := range tpts { | ||
tpt, err := tptC.MuxC(h) | ||
if err != nil { | ||
return nil, err | ||
} | ||
muxMuxer.AddTransport(tptC.ID, tpt) | ||
} | ||
return muxMuxer, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
package config | ||
|
||
import ( | ||
"testing" | ||
|
||
peer "github.com/libp2p/go-libp2p-peer" | ||
mux "github.com/libp2p/go-stream-muxer" | ||
yamux "github.com/whyrusleeping/go-smux-yamux" | ||
) | ||
|
||
func TestMuxerSimple(t *testing.T) { | ||
// single | ||
_, err := MuxerConstructor(func(_ peer.ID) mux.Transport { return nil }) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
} | ||
|
||
func TestMuxerByValue(t *testing.T) { | ||
_, err := MuxerConstructor(yamux.DefaultTransport) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
} | ||
func TestMuxerDuplicate(t *testing.T) { | ||
_, err := MuxerConstructor(func(_ peer.ID, _ peer.ID) mux.Transport { return nil }) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
} | ||
|
||
func TestMuxerError(t *testing.T) { | ||
_, err := MuxerConstructor(func() (mux.Transport, error) { return nil, nil }) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
} | ||
|
||
func TestMuxerBadTypes(t *testing.T) { | ||
for i, f := range []interface{}{ | ||
func() error { return nil }, | ||
func() string { return "" }, | ||
func() {}, | ||
func(string) mux.Transport { return nil }, | ||
func(string) (mux.Transport, error) { return nil, nil }, | ||
nil, | ||
"testing", | ||
} { | ||
|
||
if _, err := MuxerConstructor(f); err == nil { | ||
t.Fatalf("constructor %d with type %T should have failed", i, f) | ||
} | ||
} | ||
} |
Oops, something went wrong.