mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-27 15:16:43 +00:00
Merge pull request #95 from ethersphere/network-testing-framework-services
p2p/simulations: Fix starting nodes with multiple services
This commit is contained in:
commit
bdf4ba039c
9 changed files with 201 additions and 210 deletions
|
|
@ -43,8 +43,13 @@ func (d *DockerAdapter) Name() string {
|
||||||
|
|
||||||
// NewNode returns a new DockerNode using the given config
|
// NewNode returns a new DockerNode using the given config
|
||||||
func (d *DockerAdapter) NewNode(config *NodeConfig) (Node, error) {
|
func (d *DockerAdapter) NewNode(config *NodeConfig) (Node, error) {
|
||||||
if _, exists := serviceFuncs[config.Service]; !exists {
|
if len(config.Services) == 0 {
|
||||||
return nil, fmt.Errorf("unknown node service %q", config.Service)
|
return nil, errors.New("node must have at least one service")
|
||||||
|
}
|
||||||
|
for _, service := range config.Services {
|
||||||
|
if _, exists := serviceFuncs[service]; !exists {
|
||||||
|
return nil, fmt.Errorf("unknown node service %q", service)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// generate the config
|
// generate the config
|
||||||
|
|
@ -76,22 +81,18 @@ type DockerNode struct {
|
||||||
// dockerCommand returns a command which exec's the binary in a docker
|
// dockerCommand returns a command which exec's the binary in a docker
|
||||||
// container.
|
// container.
|
||||||
//
|
//
|
||||||
// It uses a shell so that we can pass the _P2P_NODE_CONFIG and _P2P_NODE_KEY
|
// It uses a shell so that we can pass the _P2P_NODE_CONFIG environment
|
||||||
// environment variables to the container using the --env flag.
|
// variable to the container using the --env flag.
|
||||||
func (n *DockerNode) dockerCommand() *exec.Cmd {
|
func (n *DockerNode) dockerCommand() *exec.Cmd {
|
||||||
return exec.Command(
|
return exec.Command(
|
||||||
"sh", "-c",
|
"sh", "-c",
|
||||||
fmt.Sprintf(
|
fmt.Sprintf(
|
||||||
`exec docker run --interactive --env _P2P_NODE_CONFIG="${_P2P_NODE_CONFIG}" --env _P2P_NODE_KEY="${_P2P_NODE_KEY}" %s p2p-node %s %s`,
|
`exec docker run --interactive --env _P2P_NODE_CONFIG="${_P2P_NODE_CONFIG}" %s p2p-node %s %s`,
|
||||||
dockerImage, strings.Join(n.Services, " "), n.ID.String(),
|
dockerImage, strings.Join(n.Config.Node.Services, ","), n.ID.String(),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *DockerNode) GetService(name string) node.Service {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// dockerImage is the name of the docker image
|
// dockerImage is the name of the docker image
|
||||||
const dockerImage = "p2p-node"
|
const dockerImage = "p2p-node"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -46,8 +46,13 @@ func (e *ExecAdapter) Name() string {
|
||||||
|
|
||||||
// NewNode returns a new ExecNode using the given config
|
// NewNode returns a new ExecNode using the given config
|
||||||
func (e *ExecAdapter) NewNode(config *NodeConfig) (Node, error) {
|
func (e *ExecAdapter) NewNode(config *NodeConfig) (Node, error) {
|
||||||
if _, exists := serviceFuncs[config.Service]; !exists {
|
if len(config.Services) == 0 {
|
||||||
return nil, fmt.Errorf("unknown node service %q", config.Service)
|
return nil, errors.New("node must have at least one service")
|
||||||
|
}
|
||||||
|
for _, service := range config.Services {
|
||||||
|
if _, exists := serviceFuncs[service]; !exists {
|
||||||
|
return nil, fmt.Errorf("unknown node service %q", service)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// create the node directory using the first 12 characters of the ID
|
// create the node directory using the first 12 characters of the ID
|
||||||
|
|
@ -93,7 +98,6 @@ type ExecNode struct {
|
||||||
Config *execNodeConfig
|
Config *execNodeConfig
|
||||||
Cmd *exec.Cmd
|
Cmd *exec.Cmd
|
||||||
Info *p2p.NodeInfo
|
Info *p2p.NodeInfo
|
||||||
Services []string
|
|
||||||
|
|
||||||
client *rpc.Client
|
client *rpc.Client
|
||||||
rpcMux *rpcMux
|
rpcMux *rpcMux
|
||||||
|
|
@ -118,7 +122,7 @@ func (n *ExecNode) Client() (*rpc.Client, error) {
|
||||||
// Start exec's the node passing the ID and service as command line arguments
|
// Start exec's the node passing the ID and service as command line arguments
|
||||||
// and the node config encoded as JSON in the _P2P_NODE_CONFIG environment
|
// and the node config encoded as JSON in the _P2P_NODE_CONFIG environment
|
||||||
// variable
|
// variable
|
||||||
func (n *ExecNode) Start(snapshot []byte) (err error) {
|
func (n *ExecNode) Start(snapshots map[string][]byte) (err error) {
|
||||||
if n.Cmd != nil {
|
if n.Cmd != nil {
|
||||||
return errors.New("already started")
|
return errors.New("already started")
|
||||||
}
|
}
|
||||||
|
|
@ -131,7 +135,7 @@ func (n *ExecNode) Start(snapshot []byte) (err error) {
|
||||||
|
|
||||||
// encode a copy of the config containing the snapshot
|
// encode a copy of the config containing the snapshot
|
||||||
confCopy := *n.Config
|
confCopy := *n.Config
|
||||||
confCopy.Snapshot = snapshot
|
confCopy.Snapshots = snapshots
|
||||||
confData, err := json.Marshal(confCopy)
|
confData, err := json.Marshal(confCopy)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error generating node config: %s", err)
|
return fmt.Errorf("error generating node config: %s", err)
|
||||||
|
|
@ -165,17 +169,13 @@ func (n *ExecNode) Start(snapshot []byte) (err error) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *ExecNode) GetService(name string) node.Service {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// execCommand returns a command which runs the node locally by exec'ing
|
// execCommand returns a command which runs the node locally by exec'ing
|
||||||
// the current binary but setting argv[0] to "p2p-node" so that the child
|
// the current binary but setting argv[0] to "p2p-node" so that the child
|
||||||
// runs execP2PNode
|
// runs execP2PNode
|
||||||
func (n *ExecNode) execCommand() *exec.Cmd {
|
func (n *ExecNode) execCommand() *exec.Cmd {
|
||||||
return &exec.Cmd{
|
return &exec.Cmd{
|
||||||
Path: reexec.Self(),
|
Path: reexec.Self(),
|
||||||
Args: []string{"p2p-node", n.Services[0], n.ID.String()},
|
Args: []string{"p2p-node", strings.Join(n.Config.Node.Services, ","), n.ID.String()},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -231,14 +231,14 @@ func (n *ExecNode) ServeRPC(conn net.Conn) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Snapshot creates a snapshot of the service state by calling the
|
// Snapshots creates snapshots of the services by calling the
|
||||||
// simulation_snapshot RPC method
|
// simulation_snapshot RPC method
|
||||||
func (n *ExecNode) Snapshot() ([]byte, error) {
|
func (n *ExecNode) Snapshots() (map[string][]byte, error) {
|
||||||
if n.client == nil {
|
if n.client == nil {
|
||||||
return nil, errors.New("RPC not started")
|
return nil, errors.New("RPC not started")
|
||||||
}
|
}
|
||||||
var snapshot []byte
|
var snapshots map[string][]byte
|
||||||
return snapshot, n.client.Call(&snapshot, "simulation_snapshot")
|
return snapshots, n.client.Call(&snapshots, "simulation_snapshot")
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
@ -252,7 +252,7 @@ func init() {
|
||||||
type execNodeConfig struct {
|
type execNodeConfig struct {
|
||||||
Stack node.Config `json:"stack"`
|
Stack node.Config `json:"stack"`
|
||||||
Node *NodeConfig `json:"node"`
|
Node *NodeConfig `json:"node"`
|
||||||
Snapshot []byte `json:"snapshot,omitempty"`
|
Snapshots map[string][]byte `json:"snapshot,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// execP2PNode starts a devp2p node when the current binary is executed with
|
// execP2PNode starts a devp2p node when the current binary is executed with
|
||||||
|
|
@ -263,8 +263,8 @@ func execP2PNode() {
|
||||||
glogger.Verbosity(log.LvlInfo)
|
glogger.Verbosity(log.LvlInfo)
|
||||||
log.Root().SetHandler(glogger)
|
log.Root().SetHandler(glogger)
|
||||||
|
|
||||||
// read the service and ID from argv
|
// read the services and ID from argv
|
||||||
serviceName := os.Args[1]
|
serviceNames := strings.Split(os.Args[1], ",")
|
||||||
id := NewNodeIdFromHex(os.Args[2])
|
id := NewNodeIdFromHex(os.Args[2])
|
||||||
|
|
||||||
// decode the config
|
// decode the config
|
||||||
|
|
@ -278,12 +278,19 @@ func execP2PNode() {
|
||||||
}
|
}
|
||||||
conf.Stack.P2P.PrivateKey = conf.Node.PrivateKey
|
conf.Stack.P2P.PrivateKey = conf.Node.PrivateKey
|
||||||
|
|
||||||
// initialize the service
|
// initialize the services
|
||||||
serviceFunc, exists := serviceFuncs[serviceName]
|
services := make(map[string]node.Service, len(serviceNames))
|
||||||
|
for _, name := range serviceNames {
|
||||||
|
serviceFunc, exists := serviceFuncs[name]
|
||||||
if !exists {
|
if !exists {
|
||||||
log.Crit(fmt.Sprintf("unknown node service %q", serviceName))
|
log.Crit(fmt.Sprintf("unknown node service %q", name))
|
||||||
|
}
|
||||||
|
var snapshot []byte
|
||||||
|
if conf.Snapshots != nil {
|
||||||
|
snapshot = conf.Snapshots[name]
|
||||||
|
}
|
||||||
|
services[name] = serviceFunc(id, snapshot)
|
||||||
}
|
}
|
||||||
services := serviceFunc(id, conf.Snapshot)
|
|
||||||
|
|
||||||
// use explicit IP address in ListenAddr so that Enode URL is usable
|
// use explicit IP address in ListenAddr so that Enode URL is usable
|
||||||
if strings.HasPrefix(conf.Stack.P2P.ListenAddr, ":") {
|
if strings.HasPrefix(conf.Stack.P2P.ListenAddr, ":") {
|
||||||
|
|
@ -326,52 +333,75 @@ func execP2PNode() {
|
||||||
stack.Wait()
|
stack.Wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
func startP2PNode(conf *node.Config, services []node.Service) (*node.Node, error) {
|
func startP2PNode(conf *node.Config, services map[string]node.Service) (*node.Node, error) {
|
||||||
stack, err := node.New(conf)
|
stack, err := node.New(conf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
for _, svc := range services {
|
constructor := func(service node.Service) func(ctx *node.ServiceContext) (node.Service, error) {
|
||||||
constructor := func(ctx *node.ServiceContext) (node.Service, error) {
|
return func(ctx *node.ServiceContext) (node.Service, error) {
|
||||||
return &snapshotService{svc}, nil
|
return service, nil
|
||||||
}
|
}
|
||||||
if err := stack.Register(constructor); err != nil {
|
}
|
||||||
|
for _, service := range services {
|
||||||
|
if err := stack.Register(constructor(service)); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if err := stack.Register(constructor(&snapshotService{services})); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
if err := stack.Start(); err != nil {
|
if err := stack.Start(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return stack, nil
|
return stack, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// snapshotService wraps a node.Service and injects a snapshot API into the
|
// snapshotService is a node.Service which wraps a list of services and
|
||||||
// list of RPC APIs
|
// exposes an API to generate a snapshot of those services
|
||||||
type snapshotService struct {
|
type snapshotService struct {
|
||||||
node.Service
|
services map[string]node.Service
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *snapshotService) APIs() []rpc.API {
|
func (s *snapshotService) APIs() []rpc.API {
|
||||||
return append([]rpc.API{{
|
return []rpc.API{{
|
||||||
Namespace: "simulation",
|
Namespace: "simulation",
|
||||||
Version: "1.0",
|
Version: "1.0",
|
||||||
Service: SnapshotAPI{s.Service},
|
Service: SnapshotAPI{s.services},
|
||||||
}}, s.Service.APIs()...)
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SnapshotAPI provides an RPC method to create a snapshot of a node.Service
|
func (s *snapshotService) Protocols() []p2p.Protocol {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *snapshotService) Start(*p2p.Server) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *snapshotService) Stop() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SnapshotAPI provides an RPC method to create snapshots of services
|
||||||
type SnapshotAPI struct {
|
type SnapshotAPI struct {
|
||||||
service node.Service
|
services map[string]node.Service
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api SnapshotAPI) Snapshot() ([]byte, error) {
|
func (api SnapshotAPI) Snapshot() (map[string][]byte, error) {
|
||||||
if s, ok := api.service.(interface {
|
snapshots := make(map[string][]byte)
|
||||||
|
for name, service := range api.services {
|
||||||
|
if s, ok := service.(interface {
|
||||||
Snapshot() ([]byte, error)
|
Snapshot() ([]byte, error)
|
||||||
}); ok {
|
}); ok {
|
||||||
return s.Snapshot()
|
snap, err := s.Snapshot()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
return nil, nil
|
snapshots[name] = snap
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return snapshots, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// stdioConn wraps os.Stdin / os.Stdout with a no-op Close method so we can
|
// stdioConn wraps os.Stdin / os.Stdout with a no-op Close method so we can
|
||||||
|
|
|
||||||
|
|
@ -21,11 +21,9 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"net"
|
"net"
|
||||||
"reflect"
|
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
|
||||||
"github.com/ethereum/go-ethereum/node"
|
"github.com/ethereum/go-ethereum/node"
|
||||||
"github.com/ethereum/go-ethereum/p2p"
|
"github.com/ethereum/go-ethereum/p2p"
|
||||||
"github.com/ethereum/go-ethereum/p2p/discover"
|
"github.com/ethereum/go-ethereum/p2p/discover"
|
||||||
|
|
@ -37,6 +35,7 @@ import (
|
||||||
type SimAdapter struct {
|
type SimAdapter struct {
|
||||||
mtx sync.RWMutex
|
mtx sync.RWMutex
|
||||||
nodes map[discover.NodeID]*SimNode
|
nodes map[discover.NodeID]*SimNode
|
||||||
|
services map[string]ServiceFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewSimAdapter creates a SimAdapter which is capable of running in-memory
|
// NewSimAdapter creates a SimAdapter which is capable of running in-memory
|
||||||
|
|
@ -45,6 +44,7 @@ type SimAdapter struct {
|
||||||
func NewSimAdapter(services map[string]ServiceFunc) *SimAdapter {
|
func NewSimAdapter(services map[string]ServiceFunc) *SimAdapter {
|
||||||
return &SimAdapter{
|
return &SimAdapter{
|
||||||
nodes: make(map[discover.NodeID]*SimNode),
|
nodes: make(map[discover.NodeID]*SimNode),
|
||||||
|
services: services,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -55,8 +55,6 @@ func (s *SimAdapter) Name() string {
|
||||||
|
|
||||||
// NewNode returns a new SimNode using the given config
|
// NewNode returns a new SimNode using the given config
|
||||||
func (s *SimAdapter) NewNode(config *NodeConfig) (Node, error) {
|
func (s *SimAdapter) NewNode(config *NodeConfig) (Node, error) {
|
||||||
var nodeprotos []p2p.Protocol
|
|
||||||
|
|
||||||
s.mtx.Lock()
|
s.mtx.Lock()
|
||||||
defer s.mtx.Unlock()
|
defer s.mtx.Unlock()
|
||||||
|
|
||||||
|
|
@ -66,55 +64,23 @@ func (s *SimAdapter) NewNode(config *NodeConfig) (Node, error) {
|
||||||
return nil, fmt.Errorf("node already exists: %s", id)
|
return nil, fmt.Errorf("node already exists: %s", id)
|
||||||
}
|
}
|
||||||
|
|
||||||
// check the service is valid and initialize it
|
// check the services are valid
|
||||||
/*
|
if len(config.Services) == 0 {
|
||||||
serviceFunc, exists := s.services[config.Service]
|
return nil, errors.New("node must have at least one service")
|
||||||
if !exists {
|
}
|
||||||
return nil, fmt.Errorf("unknown node service %q", config.Service)
|
for _, service := range config.Services {
|
||||||
|
if _, exists := s.services[service]; !exists {
|
||||||
|
return nil, fmt.Errorf("unknown node service %q", service)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
node := &SimNode{
|
node := &SimNode{
|
||||||
Id: id,
|
Id: id,
|
||||||
config: config,
|
config: config,
|
||||||
adapter: s,
|
adapter: s,
|
||||||
serviceFunc: serviceFunc,
|
|
||||||
*/
|
|
||||||
//serviceFunc, exists := s.services[config.Service]
|
|
||||||
|
|
||||||
//if !exists {
|
|
||||||
// return nil, fmt.Errorf("unknown node service %q", config.Service)
|
|
||||||
//}
|
|
||||||
//service := serviceFunc(id)
|
|
||||||
|
|
||||||
_, err := node.New(&node.Config{
|
|
||||||
P2P: p2p.Config{
|
|
||||||
PrivateKey: config.PrivateKey,
|
|
||||||
MaxPeers: math.MaxInt32,
|
|
||||||
NoDiscovery: true,
|
|
||||||
Protocols: nodeprotos,
|
|
||||||
Dialer: s,
|
|
||||||
EnableMsgEvents: true,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
|
s.nodes[id.NodeID] = node
|
||||||
for _, service := range serviceFuncs[config.Service](id, nil) {
|
return node, nil
|
||||||
for _, proto := range service.Protocols() {
|
|
||||||
nodeprotos = append(nodeprotos, proto)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
simnode := &SimNode{
|
|
||||||
Id: id,
|
|
||||||
serviceFunc: serviceFuncs[config.Service],
|
|
||||||
adapter: s,
|
|
||||||
config: config,
|
|
||||||
running: []node.Service{},
|
|
||||||
}
|
|
||||||
s.nodes[id.NodeID] = simnode
|
|
||||||
return simnode, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SimAdapter) Dial(dest *discover.Node) (conn net.Conn, err error) {
|
func (s *SimAdapter) Dial(dest *discover.Node) (conn net.Conn, err error) {
|
||||||
|
|
@ -150,11 +116,10 @@ type SimNode struct {
|
||||||
Id *NodeId
|
Id *NodeId
|
||||||
config *NodeConfig
|
config *NodeConfig
|
||||||
adapter *SimAdapter
|
adapter *SimAdapter
|
||||||
serviceFunc ServiceFunc
|
|
||||||
node *node.Node
|
node *node.Node
|
||||||
|
running []node.Service
|
||||||
client *rpc.Client
|
client *rpc.Client
|
||||||
rpcMux *rpcMux
|
rpcMux *rpcMux
|
||||||
running []node.Service
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Addr returns the node's discovery address
|
// Addr returns the node's discovery address
|
||||||
|
|
@ -191,38 +156,37 @@ func (self *SimNode) ServeRPC(conn net.Conn) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Snapshot creates a snapshot of the service state by calling the
|
// Snapshots creates snapshots of the services by calling the
|
||||||
// simulation_snapshot RPC method
|
// simulation_snapshot RPC method
|
||||||
func (self *SimNode) Snapshot() ([]byte, error) {
|
func (self *SimNode) Snapshots() (map[string][]byte, error) {
|
||||||
self.lock.Lock()
|
self.lock.Lock()
|
||||||
defer self.lock.Unlock()
|
defer self.lock.Unlock()
|
||||||
if self.client == nil {
|
if self.client == nil {
|
||||||
return nil, errors.New("RPC not started")
|
return nil, errors.New("RPC not started")
|
||||||
}
|
}
|
||||||
var snapshot []byte
|
var snapshots map[string][]byte
|
||||||
return snapshot, self.client.Call(&snapshot, "simulation_snapshot")
|
return snapshots, self.client.Call(&snapshots, "simulation_snapshot")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start starts the RPC handler and the underlying service
|
// Start starts the RPC handler and the underlying service
|
||||||
func (self *SimNode) Start(snapshot []byte) error {
|
func (self *SimNode) Start(snapshots map[string][]byte) error {
|
||||||
self.lock.Lock()
|
self.lock.Lock()
|
||||||
defer self.lock.Unlock()
|
defer self.lock.Unlock()
|
||||||
if self.node != nil {
|
if self.node != nil {
|
||||||
return errors.New("node already started")
|
return errors.New("node already started")
|
||||||
}
|
}
|
||||||
|
|
||||||
services := []node.ServiceConstructor{}
|
newService := func(name string) func(ctx *node.ServiceContext) (node.Service, error) {
|
||||||
|
return func(ctx *node.ServiceContext) (node.Service, error) {
|
||||||
sf := self.serviceFunc(self.Id, snapshot)
|
var snapshot []byte
|
||||||
|
if snapshots != nil {
|
||||||
for i, _ := range sf {
|
snapshot = snapshots[name]
|
||||||
service := sf[i]
|
}
|
||||||
sc := func(ctx *node.ServiceContext) (node.Service, error) {
|
serviceFunc := self.adapter.services[name]
|
||||||
|
service := serviceFunc(self.Id, snapshot)
|
||||||
|
self.running = append(self.running, service)
|
||||||
return service, nil
|
return service, nil
|
||||||
}
|
}
|
||||||
log.Debug(fmt.Sprintf("servicefunc yield: %v %p %p", reflect.TypeOf(sf[i]), sf[i], sc))
|
|
||||||
services = append(services, sc)
|
|
||||||
self.running = append(self.running, sf[i])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
node, err := node.New(&node.Config{
|
node, err := node.New(&node.Config{
|
||||||
|
|
@ -239,9 +203,8 @@ func (self *SimNode) Start(snapshot []byte) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, service := range services {
|
for _, name := range self.config.Services {
|
||||||
log.Debug(fmt.Sprintf("service %v", service))
|
if err := node.Register(newService(name)); err != nil {
|
||||||
if err := node.Register(service); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -281,17 +244,11 @@ func (self *SimNode) Stop() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Service returns the underlying running node.Service matching the supplied service type
|
// Services returns the underlying services
|
||||||
func (self *SimNode) Service(servicetype interface{}) node.Service {
|
func (self *SimNode) Services() []node.Service {
|
||||||
self.lock.Lock()
|
self.lock.Lock()
|
||||||
defer self.lock.Unlock()
|
defer self.lock.Unlock()
|
||||||
typ := reflect.TypeOf(servicetype)
|
return self.running
|
||||||
for _, service := range self.running {
|
|
||||||
if reflect.TypeOf(service) == typ {
|
|
||||||
return service
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *SimNode) Server() *p2p.Server {
|
func (self *SimNode) Server() *p2p.Server {
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ type Node interface {
|
||||||
ServeRPC(net.Conn) error
|
ServeRPC(net.Conn) error
|
||||||
|
|
||||||
// Start starts the node with the given snapshot
|
// Start starts the node with the given snapshot
|
||||||
Start(snapshot []byte) error
|
Start(snapshots map[string][]byte) error
|
||||||
|
|
||||||
// Stop stops the node
|
// Stop stops the node
|
||||||
Stop() error
|
Stop() error
|
||||||
|
|
@ -60,8 +60,8 @@ type Node interface {
|
||||||
// NodeInfo returns information about the node
|
// NodeInfo returns information about the node
|
||||||
NodeInfo() *p2p.NodeInfo
|
NodeInfo() *p2p.NodeInfo
|
||||||
|
|
||||||
// Snapshot creates a snapshot of the running service
|
// Snapshots creates snapshots of the running services
|
||||||
Snapshot() ([]byte, error)
|
Snapshots() (map[string][]byte, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NodeAdapter is an object which creates Nodes to be used in a simulation
|
// NodeAdapter is an object which creates Nodes to be used in a simulation
|
||||||
|
|
@ -127,11 +127,11 @@ type NodeConfig struct {
|
||||||
// Name is a human friendly name for the node like "node01"
|
// Name is a human friendly name for the node like "node01"
|
||||||
Name string
|
Name string
|
||||||
|
|
||||||
// Service is the name of the services which should be run when starting
|
// Services are the names of the services which should be run when starting
|
||||||
// the node (for SimNodes it should be the names of services contained
|
// the node (for SimNodes it should be the names of services contained
|
||||||
// in SimAdapter.services, for other nodes it should be services
|
// in SimAdapter.services, for other nodes it should be services
|
||||||
// registered by calling the RegisterService function)
|
// registered by calling the RegisterService function)
|
||||||
Service string
|
Services []string
|
||||||
}
|
}
|
||||||
|
|
||||||
// nodeConfigJSON is used to encode and decode NodeConfig as JSON by converting
|
// nodeConfigJSON is used to encode and decode NodeConfig as JSON by converting
|
||||||
|
|
@ -140,13 +140,13 @@ type nodeConfigJSON struct {
|
||||||
Id string `json:"id"`
|
Id string `json:"id"`
|
||||||
PrivateKey string `json:"private_key"`
|
PrivateKey string `json:"private_key"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Service string `json:"service"`
|
Services []string `json:"services"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *NodeConfig) MarshalJSON() ([]byte, error) {
|
func (n *NodeConfig) MarshalJSON() ([]byte, error) {
|
||||||
confJSON := nodeConfigJSON{
|
confJSON := nodeConfigJSON{
|
||||||
Name: n.Name,
|
Name: n.Name,
|
||||||
Service: n.Service,
|
Services: n.Services,
|
||||||
}
|
}
|
||||||
if n.Id != nil {
|
if n.Id != nil {
|
||||||
confJSON.Id = n.Id.String()
|
confJSON.Id = n.Id.String()
|
||||||
|
|
@ -180,7 +180,7 @@ func (n *NodeConfig) UnmarshalJSON(data []byte) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
n.Name = confJSON.Name
|
n.Name = confJSON.Name
|
||||||
n.Service = confJSON.Service
|
n.Services = confJSON.Services
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -202,18 +202,17 @@ func RandomNodeConfig() *NodeConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Services is a collection of services which can be run in a simulation
|
// Services is a collection of services which can be run in a simulation
|
||||||
// it is mapped to strings representing TYPES of nodes
|
|
||||||
type Services map[string]ServiceFunc
|
type Services map[string]ServiceFunc
|
||||||
|
|
||||||
// ServiceFunc returns a node.Service which can be used to boot devp2p nodes
|
// ServiceFunc returns a node.Service which can be used to boot devp2p nodes
|
||||||
type ServiceFunc func(id *NodeId, snapshot []byte) []node.Service
|
type ServiceFunc func(id *NodeId, snapshot []byte) node.Service
|
||||||
|
|
||||||
// serviceFuncs is a map of registered services which are used to boot devp2p
|
// serviceFuncs is a map of registered services which are used to boot devp2p
|
||||||
// nodes
|
// nodes
|
||||||
var serviceFuncs = make(Services)
|
var serviceFuncs = make(Services)
|
||||||
|
|
||||||
// RegisterServices registers the given ServiceFuncs which can then be used to
|
// RegisterServices registers the given ServiceFuncs which can then be used to
|
||||||
// start devp2p nodes
|
// start devp2p nodes using either the Exec or Docker adapters
|
||||||
func RegisterServices(services Services) {
|
func RegisterServices(services Services) {
|
||||||
for name, f := range services {
|
for name, f := range services {
|
||||||
if _, exists := serviceFuncs[name]; exists {
|
if _, exists := serviceFuncs[name]; exists {
|
||||||
|
|
|
||||||
|
|
@ -190,7 +190,7 @@ func (self *Msg) String() string {
|
||||||
// NewNode adds a new node to the network with a random ID
|
// NewNode adds a new node to the network with a random ID
|
||||||
func (self *Network) NewNode() (*Node, error) {
|
func (self *Network) NewNode() (*Node, error) {
|
||||||
conf := adapters.RandomNodeConfig()
|
conf := adapters.RandomNodeConfig()
|
||||||
conf.Service = self.DefaultService
|
conf.Services = []string{self.DefaultService}
|
||||||
return self.NewNodeWithConfig(conf)
|
return self.NewNodeWithConfig(conf)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -203,8 +203,8 @@ func (self *Network) NewNodeWithConfig(conf *adapters.NodeConfig) (*Node, error)
|
||||||
if conf.Name == "" {
|
if conf.Name == "" {
|
||||||
conf.Name = fmt.Sprintf("node%02d", len(self.Nodes)+1)
|
conf.Name = fmt.Sprintf("node%02d", len(self.Nodes)+1)
|
||||||
}
|
}
|
||||||
if conf.Service == "" {
|
if len(conf.Services) == 0 {
|
||||||
conf.Service = self.DefaultService
|
conf.Services = []string{self.DefaultService}
|
||||||
}
|
}
|
||||||
|
|
||||||
_, found := self.nodeMap[id.NodeID]
|
_, found := self.nodeMap[id.NodeID]
|
||||||
|
|
@ -286,10 +286,10 @@ func (self *Network) StopAll() error {
|
||||||
|
|
||||||
// Start(id) starts up the node (relevant only for instance with own p2p or remote)
|
// Start(id) starts up the node (relevant only for instance with own p2p or remote)
|
||||||
func (self *Network) Start(id *adapters.NodeId) error {
|
func (self *Network) Start(id *adapters.NodeId) error {
|
||||||
return self.startWithSnapshot(id, nil)
|
return self.startWithSnapshots(id, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Network) startWithSnapshot(id *adapters.NodeId, snapshot []byte) error {
|
func (self *Network) startWithSnapshots(id *adapters.NodeId, snapshots map[string][]byte) error {
|
||||||
node := self.GetNode(id)
|
node := self.GetNode(id)
|
||||||
if node == nil {
|
if node == nil {
|
||||||
return fmt.Errorf("node %v does not exist", id)
|
return fmt.Errorf("node %v does not exist", id)
|
||||||
|
|
@ -298,7 +298,7 @@ func (self *Network) startWithSnapshot(id *adapters.NodeId, snapshot []byte) err
|
||||||
return fmt.Errorf("node %v already up", id)
|
return fmt.Errorf("node %v already up", id)
|
||||||
}
|
}
|
||||||
log.Trace(fmt.Sprintf("starting node %v: %v using %v", id, node.Up, self.nodeAdapter.Name()))
|
log.Trace(fmt.Sprintf("starting node %v: %v using %v", id, node.Up, self.nodeAdapter.Name()))
|
||||||
if err := node.Start(snapshot); err != nil {
|
if err := node.Start(snapshots); err != nil {
|
||||||
log.Warn(fmt.Sprintf("start up failed: %v", err))
|
log.Warn(fmt.Sprintf("start up failed: %v", err))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -625,8 +625,8 @@ type Snapshot struct {
|
||||||
type NodeSnapshot struct {
|
type NodeSnapshot struct {
|
||||||
Node
|
Node
|
||||||
|
|
||||||
// Snapshot is arbitrary data gathered from calling node.Snapshot()
|
// Snapshot is arbitrary data gathered from calling node.Snapshots()
|
||||||
Snapshot []byte `json:"snapshot,omitempty"`
|
Snapshots map[string][]byte `json:"snapshots,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Snapshot creates a network snapshot
|
// Snapshot creates a network snapshot
|
||||||
|
|
@ -642,11 +642,11 @@ func (self *Network) Snapshot() (*Snapshot, error) {
|
||||||
if !node.Up {
|
if !node.Up {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
snapshot, err := node.Snapshot()
|
snapshots, err := node.Snapshots()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
snap.Nodes[i].Snapshot = snapshot
|
snap.Nodes[i].Snapshots = snapshots
|
||||||
}
|
}
|
||||||
for i, conn := range self.Conns {
|
for i, conn := range self.Conns {
|
||||||
snap.Conns[i] = *conn
|
snap.Conns[i] = *conn
|
||||||
|
|
@ -662,7 +662,7 @@ func (self *Network) Load(snap *Snapshot) error {
|
||||||
if !node.Up {
|
if !node.Up {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if err := self.startWithSnapshot(node.Config.Id, node.Snapshot); err != nil {
|
if err := self.startWithSnapshots(node.Config.Id, node.Snapshots); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ func (self *ProtocolSession) trigger(trig Trigger) error {
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("trigger: peer %v does not exist (1- %v)", trig.Peer, len(self.Ids))
|
return fmt.Errorf("trigger: peer %v does not exist (1- %v)", trig.Peer, len(self.Ids))
|
||||||
}
|
}
|
||||||
mockNode, ok := simNode.Service(&mockNode{}).(*mockNode)
|
mockNode, ok := simNode.Services()[0].(*mockNode)
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("trigger: peer %v is not a mock", trig.Peer)
|
return fmt.Errorf("trigger: peer %v is not a mock", trig.Peer)
|
||||||
}
|
}
|
||||||
|
|
@ -92,7 +92,7 @@ func (self *ProtocolSession) expect(exp Expect) error {
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("trigger: peer %v does not exist (1- %v)", exp.Peer, len(self.Ids))
|
return fmt.Errorf("trigger: peer %v does not exist (1- %v)", exp.Peer, len(self.Ids))
|
||||||
}
|
}
|
||||||
mockNode, ok := simNode.Service(&mockNode{}).(*mockNode)
|
mockNode, ok := simNode.Services()[0].(*mockNode)
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("trigger: peer %v is not a mock", exp.Peer)
|
return fmt.Errorf("trigger: peer %v is not a mock", exp.Peer)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,18 +19,17 @@ type ProtocolTester struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewProtocolTester(t *testing.T, id *adapters.NodeId, n int, run func(*p2p.Peer, p2p.MsgReadWriter) error) *ProtocolTester {
|
func NewProtocolTester(t *testing.T, id *adapters.NodeId, n int, run func(*p2p.Peer, p2p.MsgReadWriter) error) *ProtocolTester {
|
||||||
//func NewProtocolTester(t *testing.T, id *adapters.NodeId, n int, run func(*p2p.Peer, p2p.MsgReadWriter) error) *ProtocolTester {
|
|
||||||
services := adapters.Services{
|
services := adapters.Services{
|
||||||
"test": func(id *adapters.NodeId, _ []byte) []node.Service {
|
"test": func(id *adapters.NodeId, _ []byte) node.Service {
|
||||||
return []node.Service{&testNode{run}}
|
return &testNode{run}
|
||||||
},
|
},
|
||||||
"mock": func(id *adapters.NodeId, _ []byte) []node.Service {
|
"mock": func(id *adapters.NodeId, _ []byte) node.Service {
|
||||||
return []node.Service{newMockNode()}
|
return newMockNode()
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
adapter := adapters.NewSimAdapter(services)
|
adapter := adapters.NewSimAdapter(services)
|
||||||
net := simulations.NewNetwork(adapter, &simulations.NetworkConfig{})
|
net := simulations.NewNetwork(adapter, &simulations.NetworkConfig{})
|
||||||
if _, err := net.NewNodeWithConfig(&adapters.NodeConfig{Id: id, Service: "test"}); err != nil {
|
if _, err := net.NewNodeWithConfig(&adapters.NodeConfig{Id: id, Services: []string{"test"}}); err != nil {
|
||||||
panic(err.Error())
|
panic(err.Error())
|
||||||
}
|
}
|
||||||
if err := net.Start(id); err != nil {
|
if err := net.Start(id); err != nil {
|
||||||
|
|
@ -42,7 +41,7 @@ func NewProtocolTester(t *testing.T, id *adapters.NodeId, n int, run func(*p2p.P
|
||||||
peerIDs := make([]*adapters.NodeId, n)
|
peerIDs := make([]*adapters.NodeId, n)
|
||||||
for i := 0; i < n; i++ {
|
for i := 0; i < n; i++ {
|
||||||
peers[i] = adapters.RandomNodeConfig()
|
peers[i] = adapters.RandomNodeConfig()
|
||||||
peers[i].Service = "mock"
|
peers[i].Services = []string{"mock"}
|
||||||
peerIDs[i] = peers[i].Id
|
peerIDs[i] = peers[i].Id
|
||||||
}
|
}
|
||||||
events := make(chan *p2p.PeerEvent, 1000)
|
events := make(chan *p2p.PeerEvent, 1000)
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ func NewSimulation() *Simulation {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Simulation) NewService(id *adapters.NodeId, snapshot []byte) []node.Service {
|
func (s *Simulation) NewService(id *adapters.NodeId, snapshot []byte) node.Service {
|
||||||
s.mtx.Lock()
|
s.mtx.Lock()
|
||||||
store, ok := s.stores[id.NodeID]
|
store, ok := s.stores[id.NodeID]
|
||||||
if !ok {
|
if !ok {
|
||||||
|
|
@ -64,7 +64,7 @@ func (s *Simulation) NewService(id *adapters.NodeId, snapshot []byte) []node.Ser
|
||||||
HiveParams: hp,
|
HiveParams: hp,
|
||||||
}
|
}
|
||||||
|
|
||||||
return []node.Service{network.NewBzz(config, kad, store)}
|
return network.NewBzz(config, kad, store)
|
||||||
}
|
}
|
||||||
|
|
||||||
func createMockers() map[string]*simulations.MockerConfig {
|
func createMockers() map[string]*simulations.MockerConfig {
|
||||||
|
|
@ -124,7 +124,7 @@ func setupMocker(net *simulations.Network) []*adapters.NodeId {
|
||||||
defer close(ch)
|
defer close(ch)
|
||||||
ch <- network.NewAddrFromNodeId(peerId)
|
ch <- network.NewAddrFromNodeId(peerId)
|
||||||
}()
|
}()
|
||||||
if err := net.GetNode(id).Node.(*adapters.SimNode).Service(&network.Bzz{}).(*network.Bzz).Hive.Register(ch); err != nil {
|
if err := net.GetNode(id).Node.(*adapters.SimNode).Services()[0].(*network.Bzz).Hive.Register(ch); err != nil {
|
||||||
panic(err.Error())
|
panic(err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -243,7 +243,6 @@ func testPssFullRandom(t *testing.T, adapter adapters.NodeAdapter, nodecount int
|
||||||
nodeCount := 5
|
nodeCount := 5
|
||||||
net := simulations.NewNetwork(adapter, &simulations.NetworkConfig{
|
net := simulations.NewNetwork(adapter, &simulations.NetworkConfig{
|
||||||
Id: "0",
|
Id: "0",
|
||||||
DefaultService: "psstest",
|
|
||||||
})
|
})
|
||||||
defer net.Shutdown()
|
defer net.Shutdown()
|
||||||
|
|
||||||
|
|
@ -254,7 +253,7 @@ func testPssFullRandom(t *testing.T, adapter adapters.NodeAdapter, nodecount int
|
||||||
|
|
||||||
for i := 0; i < nodeCount; i++ {
|
for i := 0; i < nodeCount; i++ {
|
||||||
nodeconfig := adapters.RandomNodeConfig()
|
nodeconfig := adapters.RandomNodeConfig()
|
||||||
nodeconfig.Service = "psstest"
|
nodeconfig.Services = []string{"bzz", "pss"}
|
||||||
node, err := net.NewNodeWithConfig(nodeconfig)
|
node, err := net.NewNodeWithConfig(nodeconfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("error starting node: %s", err)
|
t.Fatalf("error starting node: %s", err)
|
||||||
|
|
@ -436,28 +435,25 @@ func triggerChecks(trigger chan *adapters.NodeId, net *simulations.Network, id *
|
||||||
}
|
}
|
||||||
|
|
||||||
func newServices() adapters.Services {
|
func newServices() adapters.Services {
|
||||||
|
stateStore := adapters.NewSimStateStore()
|
||||||
return adapters.Services{
|
kademlias := make(map[*adapters.NodeId]*network.Kademlia)
|
||||||
"psstest": func(id *adapters.NodeId, snapshot []byte) []node.Service {
|
kademlia := func(id *adapters.NodeId) *network.Kademlia {
|
||||||
addr := network.NewAddrFromNodeId(id)
|
if k, ok := kademlias[id]; ok {
|
||||||
|
return k
|
||||||
kadparams := network.NewKadParams()
|
|
||||||
kadparams.MinProxBinSize = 2
|
|
||||||
kadparams.MaxBinSize = 3
|
|
||||||
kadparams.MinBinSize = 1
|
|
||||||
kadparams.MaxRetries = 1000
|
|
||||||
kadparams.RetryExponent = 2
|
|
||||||
kadparams.RetryInterval = 1000000
|
|
||||||
kademlia := network.NewKademlia(addr.Over(), kadparams)
|
|
||||||
|
|
||||||
config := &network.BzzConfig{
|
|
||||||
OverlayAddr: addr.Over(),
|
|
||||||
UnderlayAddr: addr.Under(),
|
|
||||||
HiveParams: network.NewHiveParams(),
|
|
||||||
}
|
}
|
||||||
|
addr := network.NewAddrFromNodeId(id)
|
||||||
config.HiveParams.KeepAliveInterval = time.Second
|
params := network.NewKadParams()
|
||||||
|
params.MinProxBinSize = 2
|
||||||
|
params.MaxBinSize = 3
|
||||||
|
params.MinBinSize = 1
|
||||||
|
params.MaxRetries = 1000
|
||||||
|
params.RetryExponent = 2
|
||||||
|
params.RetryInterval = 1000000
|
||||||
|
kademlias[id] = network.NewKademlia(addr.Over(), params)
|
||||||
|
return kademlias[id]
|
||||||
|
}
|
||||||
|
return adapters.Services{
|
||||||
|
"pss": func(id *adapters.NodeId, snapshot []byte) node.Service {
|
||||||
cachedir, err := ioutil.TempDir("", "pss-cache")
|
cachedir, err := ioutil.TempDir("", "pss-cache")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("create pss cache tmpdir failed", "error", err)
|
log.Error("create pss cache tmpdir failed", "error", err)
|
||||||
|
|
@ -470,7 +466,7 @@ func newServices() adapters.Services {
|
||||||
}
|
}
|
||||||
|
|
||||||
pssp := NewPssParams()
|
pssp := NewPssParams()
|
||||||
ps := NewPss(kademlia, dpa, pssp)
|
ps := NewPss(kademlia(id), dpa, pssp)
|
||||||
|
|
||||||
ping := &pssPing{
|
ping := &pssPing{
|
||||||
quitC: make(chan struct{}),
|
quitC: make(chan struct{}),
|
||||||
|
|
@ -481,7 +477,16 @@ func newServices() adapters.Services {
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
return []node.Service{network.NewBzz(config, kademlia, adapters.NewSimStateStore()), ps}
|
return ps
|
||||||
|
},
|
||||||
|
"bzz": func(id *adapters.NodeId, snapshot []byte) node.Service {
|
||||||
|
addr := network.NewAddrFromNodeId(id)
|
||||||
|
config := &network.BzzConfig{
|
||||||
|
OverlayAddr: addr.Over(),
|
||||||
|
UnderlayAddr: addr.Under(),
|
||||||
|
HiveParams: network.NewHiveParams(),
|
||||||
|
}
|
||||||
|
return network.NewBzz(config, kademlia(id), stateStore)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue