Skip to content

Commit

Permalink
refactor: Decouple net config (sourcenetwork#2258)
Browse files Browse the repository at this point in the history
## Relevant issue(s)
Resolves sourcenetwork#2263

## Description

This is part of a larger refactor of the config package.

## Tasks

- [x] I made sure the code is well commented, particularly
hard-to-understand areas.
- [x] I made sure the repository-held documentation is changed
accordingly.
- [x] I made sure the pull request title adheres to the conventional
commit style (the subset used in the project can be found in
[tools/configs/chglog/config.yml](tools/configs/chglog/config.yml)).
- [x] I made sure to discuss its limitations such as threats to
validity, vulnerability to mistake and misuse, robustness to
invalidation of assumptions, resource requirements, ...

## How has this been tested?

make test

Specify the platform(s) on which this was tested:
- MacOS
  • Loading branch information
nasdf authored Jan 30, 2024
1 parent f333332 commit ca37736
Show file tree
Hide file tree
Showing 15 changed files with 130 additions and 248 deletions.
14 changes: 11 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ Read the documentation on [docs.source.network](https://docs.source.network/).
- [Install](#install)
- [Start](#start)
- [Configuration](#configuration)
- [External port binding](#external-port-binding)
- [Add a schema type](#add-a-schema-type)
- [Create a document instance](#create-a-document-instance)
- [Query documents](#query-documents)
Expand Down Expand Up @@ -72,6 +73,14 @@ In this document, we use the default configuration, which has the following beha

The GraphQL endpoint can be used with a GraphQL client (e.g., Altair) to conveniently perform requests (`query`, `mutation`) and obtain schema introspection.

## External port binding

By default the HTTP API and P2P network will use localhost. If you want to expose the ports externally you need to specify the addresses in the config or command line parameters.

```
defradb start --p2paddr /ip4/0.0.0.0/tcp/9171 --url 0.0.0.0:9181
```

## Add a schema type

Schemas are used to structure documents using a type system.
Expand Down Expand Up @@ -235,7 +244,6 @@ DQL is compatible with GraphQL but features various extensions.

Read its documentation at [docs.source.network](https://docs.source.network/references/query-specification/query-language-overview) to discover its filtering, ordering, limiting, relationships, variables, aggregate functions, and other useful features.


## Peer-to-peer data synchronization

DefraDB leverages peer-to-peer networking for data exchange, synchronization, and replication of documents and commits.
Expand Down Expand Up @@ -280,14 +288,14 @@ In this example, we use `12D3KooWNXm3dmrwCYSxGoRUyZstaKYiHPdt8uZH5vgVaEJyzU8B`,
For *nodeB*, we provide the following configuration:

```shell
defradb start --rootdir ~/.defradb-nodeB --url localhost:9182 --p2paddr /ip4/0.0.0.0/tcp/9172 --peers /ip4/0.0.0.0/tcp/9171/p2p/12D3KooWNXm3dmrwCYSxGoRUyZstaKYiHPdt8uZH5vgVaEJyzU8B
defradb start --rootdir ~/.defradb-nodeB --url localhost:9182 --p2paddr /ip4/127.0.0.1/tcp/9172 --peers /ip4/127.0.0.1/tcp/9171/p2p/12D3KooWNXm3dmrwCYSxGoRUyZstaKYiHPdt8uZH5vgVaEJyzU8B
```

About the flags:

- `--rootdir` specifies the root dir (config and data) to use
- `--url` is the address to listen on for the client HTTP and GraphQL API
- `--p2paddr` is the multiaddress for the P2P networking to listen on
- `--p2paddr` is a comma-separated list of multiaddresses to listen on for p2p networking
- `--peers` is a comma-separated list of peer multiaddresses

This starts two nodes and connects them via pubsub networking.
Expand Down
14 changes: 8 additions & 6 deletions cli/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,11 @@ func MakeStartCommand(cfg *config.Config) *cobra.Command {
log.FeedbackFatalE(context.Background(), "Could not bind datastore.badger.valuelogfilesize", err)
}

cmd.Flags().String(
"p2paddr", cfg.Net.P2PAddress,
"Listener address for the p2p network (formatted as a libp2p MultiAddr)",
cmd.Flags().StringSlice(
"p2paddr", cfg.Net.P2PAddresses,
"Listen addresses for the p2p network (formatted as a libp2p MultiAddr)",
)
err = cfg.BindFlag("net.p2paddress", cmd.Flags().Lookup("p2paddr"))
err = cfg.BindFlag("net.p2paddresses", cmd.Flags().Lookup("p2paddr"))
if err != nil {
log.FeedbackFatalE(context.Background(), "Could not bind net.p2paddress", err)
}
Expand Down Expand Up @@ -220,7 +220,9 @@ func start(ctx context.Context, cfg *config.Config) (*defraInstance, error) {
var node *net.Node
if !cfg.Net.P2PDisabled {
nodeOpts := []net.NodeOpt{
net.WithConfig(cfg),
net.WithListenAddresses(cfg.Net.P2PAddresses...),
net.WithEnablePubSub(cfg.Net.PubSubEnabled),
net.WithEnableRelay(cfg.Net.RelayEnabled),
}
if cfg.Datastore.Store == badgerDatastoreName {
// It would be ideal to not have the key path tied to the datastore.
Expand All @@ -233,7 +235,7 @@ func start(ctx context.Context, cfg *config.Config) (*defraInstance, error) {
}
nodeOpts = append(nodeOpts, net.WithPrivateKey(key))
}
log.FeedbackInfo(ctx, "Starting P2P node", logging.NewKV("P2P address", cfg.Net.P2PAddress))
log.FeedbackInfo(ctx, "Starting P2P node", logging.NewKV("P2P addresses", cfg.Net.P2PAddresses))
node, err = net.NewNode(ctx, db, nodeOpts...)
if err != nil {
db.Close()
Expand Down
14 changes: 8 additions & 6 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,7 @@ func (apicfg *APIConfig) AddressToURL() string {

// NetConfig configures aspects of network and peer-to-peer.
type NetConfig struct {
P2PAddress string
P2PAddresses []string
P2PDisabled bool
Peers string
PubSubEnabled bool `mapstructure:"pubsub"`
Expand All @@ -363,7 +363,7 @@ type NetConfig struct {

func defaultNetConfig() *NetConfig {
return &NetConfig{
P2PAddress: "/ip4/0.0.0.0/tcp/9171",
P2PAddresses: []string{"/ip4/127.0.0.1/tcp/9171"},
P2PDisabled: false,
Peers: "",
PubSubEnabled: true,
Expand All @@ -372,9 +372,11 @@ func defaultNetConfig() *NetConfig {
}

func (netcfg *NetConfig) validate() error {
_, err := ma.NewMultiaddr(netcfg.P2PAddress)
if err != nil {
return NewErrInvalidP2PAddress(err, netcfg.P2PAddress)
for _, addr := range netcfg.P2PAddresses {
_, err := ma.NewMultiaddr(addr)
if err != nil {
return NewErrInvalidP2PAddress(err, addr)
}
}
if len(netcfg.Peers) > 0 {
peers := strings.Split(netcfg.Peers, ",")
Expand Down Expand Up @@ -688,12 +690,12 @@ func (c *Config) String() string {
}

func (c *Config) toBytes() ([]byte, error) {
var buffer bytes.Buffer
tmpl := template.New("configTemplate")
configTemplate, err := tmpl.Parse(defaultConfigTemplate)
if err != nil {
return nil, NewErrConfigTemplateFailed(err)
}
var buffer bytes.Buffer
if err := configTemplate.Execute(&buffer, c); err != nil {
return nil, NewErrConfigTemplateFailed(err)
}
Expand Down
6 changes: 3 additions & 3 deletions config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ var envVarsDifferent = map[string]string{
"DEFRA_DATASTORE_BADGER_PATH": "defra_data",
"DEFRA_API_ADDRESS": "localhost:9999",
"DEFRA_NET_P2PDISABLED": "true",
"DEFRA_NET_P2PADDRESS": "/ip4/0.0.0.0/tcp/9876",
"DEFRA_NET_P2PADDRESSES": "/ip4/0.0.0.0/tcp/9876",
"DEFRA_NET_PUBSUB": "false",
"DEFRA_NET_RELAY": "false",
"DEFRA_LOG_LEVEL": "error",
Expand All @@ -37,7 +37,7 @@ var envVarsInvalid = map[string]string{
"DEFRA_DATASTORE_BADGER_PATH": "^=+()&**()*(&))",
"DEFRA_API_ADDRESS": "^=+()&**()*(&))",
"DEFRA_NET_P2PDISABLED": "^=+()&**()*(&))",
"DEFRA_NET_P2PADDRESS": "^=+()&**()*(&))",
"DEFRA_NET_P2PADDRESSES": "^=+()&**()*(&))",
"DEFRA_NET_PUBSUB": "^=+()&**()*(&))",
"DEFRA_NET_RELAY": "^=+()&**()*(&))",
"DEFRA_LOG_LEVEL": "^=+()&**()*(&))",
Expand Down Expand Up @@ -172,7 +172,7 @@ func TestEnvVariablesAllConsidered(t *testing.T) {
assert.Equal(t, filepath.Join(cfg.Rootdir, "defra_data"), cfg.Datastore.Badger.Path)
assert.Equal(t, "memory", cfg.Datastore.Store)
assert.Equal(t, true, cfg.Net.P2PDisabled)
assert.Equal(t, "/ip4/0.0.0.0/tcp/9876", cfg.Net.P2PAddress)
assert.Equal(t, []string{"/ip4/0.0.0.0/tcp/9876"}, cfg.Net.P2PAddresses)
assert.Equal(t, false, cfg.Net.PubSubEnabled)
assert.Equal(t, false, cfg.Net.RelayEnabled)
assert.Equal(t, "error", cfg.Log.Level)
Expand Down
5 changes: 4 additions & 1 deletion config/configfile_yaml.gotmpl
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,10 @@ net:
# Whether the P2P is disabled
p2pdisabled: {{ .Net.P2PDisabled }}
# Listening address of the P2P network
p2paddress: {{ .Net.P2PAddress }}
p2paddresses:
{{ range $addr := .Net.P2PAddresses }}
- {{ . }}
{{ end }}
# Whether the node has pubsub enabled or not
pubsub: {{ .Net.PubSubEnabled }}
# Enable libp2p's Circuit relay transport protocol https://docs.libp2p.io/concepts/circuit-relay/
Expand Down
92 changes: 17 additions & 75 deletions net/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,113 +13,55 @@
package net

import (
"time"

cconnmgr "github.com/libp2p/go-libp2p/core/connmgr"
"github.com/libp2p/go-libp2p/core/crypto"
"github.com/libp2p/go-libp2p/p2p/net/connmgr"
ma "github.com/multiformats/go-multiaddr"
"google.golang.org/grpc"

"github.com/sourcenetwork/defradb/config"
)

// Options is the node options.
type Options struct {
ListenAddrs []ma.Multiaddr
ListenAddresses []string
PrivateKey crypto.PrivKey
EnablePubSub bool
EnableRelay bool
GRPCServerOptions []grpc.ServerOption
GRPCDialOptions []grpc.DialOption
ConnManager cconnmgr.ConnManager
}

type NodeOpt func(*Options) error

// NewMergedOptions obtains Options by applying given NodeOpts.
func NewMergedOptions(opts ...NodeOpt) (*Options, error) {
var options Options
for _, opt := range opts {
if opt == nil {
continue
}
if err := opt(&options); err != nil {
return nil, err
}
// DefaultOptions returns the default net options.
func DefaultOptions() *Options {
return &Options{
ListenAddresses: []string{"/ip4/0.0.0.0/tcp/9171"},
EnablePubSub: true,
EnableRelay: false,
}
return &options, nil
}

// NewConnManager gives a new ConnManager.
func NewConnManager(low int, high int, grace time.Duration) (cconnmgr.ConnManager, error) {
c, err := connmgr.NewConnManager(low, high, connmgr.WithGracePeriod(grace))
if err != nil {
return nil, err
}
return c, nil
}

// WithConfig provides the Node-specific configuration, from the top-level Net config.
func WithConfig(cfg *config.Config) NodeOpt {
return func(opt *Options) error {
var err error
err = WithListenP2PAddrStrings(cfg.Net.P2PAddress)(opt)
if err != nil {
return err
}
opt.EnableRelay = cfg.Net.RelayEnabled
opt.EnablePubSub = cfg.Net.PubSubEnabled
opt.ConnManager, err = NewConnManager(100, 400, time.Second*20)
if err != nil {
return err
}
return nil
}
}
type NodeOpt func(*Options)

// WithPrivateKey sets the p2p host private key.
func WithPrivateKey(priv crypto.PrivKey) NodeOpt {
return func(opt *Options) error {
return func(opt *Options) {
opt.PrivateKey = priv
return nil
}
}

// WithPubSub enables the pubsub feature.
func WithPubSub(enable bool) NodeOpt {
return func(opt *Options) error {
// WithEnablePubSub enables the pubsub feature.
func WithEnablePubSub(enable bool) NodeOpt {
return func(opt *Options) {
opt.EnablePubSub = enable
return nil
}
}

// WithEnableRelay enables the relay feature.
func WithEnableRelay(enable bool) NodeOpt {
return func(opt *Options) error {
return func(opt *Options) {
opt.EnableRelay = enable
return nil
}
}

// ListenP2PAddrStrings sets the address to listen on given as strings.
func WithListenP2PAddrStrings(addrs ...string) NodeOpt {
return func(opt *Options) error {
for _, addrstr := range addrs {
a, err := ma.NewMultiaddr(addrstr)
if err != nil {
return err
}
opt.ListenAddrs = append(opt.ListenAddrs, a)
}
return nil
}
}

// ListenAddrs sets the address to listen on given as MultiAddr(s).
func WithListenAddrs(addrs ...ma.Multiaddr) NodeOpt {
return func(opt *Options) error {
opt.ListenAddrs = addrs
return nil
// WithListenAddress sets the address to listen on given as a multiaddress string.
func WithListenAddresses(addresses ...string) NodeOpt {
return func(opt *Options) {
opt.ListenAddresses = addresses
}
}
Loading

0 comments on commit ca37736

Please sign in to comment.