node: refactor package node (#21105)
This PR significantly changes the APIs for instantiating Ethereum nodes in a Go program. The new APIs are not backwards-compatible, but we feel that this is made up for by the much simpler way of registering services on node.Node. You can find more information and rationale in the design document: https://gist.github.com/renaynay/5bec2de19fde66f4d04c535fd24f0775. There is also a new feature in Node's Go API: it is now possible to register arbitrary handlers on the user-facing HTTP server. In geth, this facility is used to enable GraphQL. There is a single minor change relevant for geth users in this PR: The GraphQL API is no longer available separately from the JSON-RPC HTTP server. If you want GraphQL, you need to enable it using the ./geth --http --graphql flag combination. The --graphql.port and --graphql.addr flags are no longer available.
This commit is contained in:
@ -75,11 +75,11 @@ func (e *ExecAdapter) Name() string {
|
||||
|
||||
// NewNode returns a new ExecNode using the given config
|
||||
func (e *ExecAdapter) NewNode(config *NodeConfig) (Node, error) {
|
||||
if len(config.Services) == 0 {
|
||||
return nil, errors.New("node must have at least one service")
|
||||
if len(config.Lifecycles) == 0 {
|
||||
return nil, errors.New("node must have at least one service lifecycle")
|
||||
}
|
||||
for _, service := range config.Services {
|
||||
if _, exists := serviceFuncs[service]; !exists {
|
||||
for _, service := range config.Lifecycles {
|
||||
if _, exists := lifecycleConstructorFuncs[service]; !exists {
|
||||
return nil, fmt.Errorf("unknown node service %q", service)
|
||||
}
|
||||
}
|
||||
@ -263,7 +263,7 @@ func (n *ExecNode) waitForStartupJSON(ctx context.Context) (string, chan nodeSta
|
||||
func (n *ExecNode) execCommand() *exec.Cmd {
|
||||
return &exec.Cmd{
|
||||
Path: reexec.Self(),
|
||||
Args: []string{"p2p-node", strings.Join(n.Config.Node.Services, ","), n.ID.String()},
|
||||
Args: []string{"p2p-node", strings.Join(n.Config.Node.Lifecycles, ","), n.ID.String()},
|
||||
}
|
||||
}
|
||||
|
||||
@ -400,7 +400,7 @@ func execP2PNode() {
|
||||
defer signal.Stop(sigc)
|
||||
<-sigc
|
||||
log.Info("Received SIGTERM, shutting down...")
|
||||
stack.Stop()
|
||||
stack.Close()
|
||||
}()
|
||||
stack.Wait() // Wait for the stack to exit.
|
||||
}
|
||||
@ -434,44 +434,36 @@ func startExecNodeStack() (*node.Node, error) {
|
||||
return nil, fmt.Errorf("error creating node stack: %v", err)
|
||||
}
|
||||
|
||||
// register the services, collecting them into a map so we can wrap
|
||||
// them in a snapshot service
|
||||
services := make(map[string]node.Service, len(serviceNames))
|
||||
// Register the services, collecting them into a map so they can
|
||||
// be accessed by the snapshot API.
|
||||
services := make(map[string]node.Lifecycle, len(serviceNames))
|
||||
for _, name := range serviceNames {
|
||||
serviceFunc, exists := serviceFuncs[name]
|
||||
lifecycleFunc, exists := lifecycleConstructorFuncs[name]
|
||||
if !exists {
|
||||
return nil, fmt.Errorf("unknown node service %q", err)
|
||||
}
|
||||
constructor := func(nodeCtx *node.ServiceContext) (node.Service, error) {
|
||||
ctx := &ServiceContext{
|
||||
RPCDialer: &wsRPCDialer{addrs: conf.PeerAddrs},
|
||||
NodeContext: nodeCtx,
|
||||
Config: conf.Node,
|
||||
}
|
||||
if conf.Snapshots != nil {
|
||||
ctx.Snapshot = conf.Snapshots[name]
|
||||
}
|
||||
service, err := serviceFunc(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
services[name] = service
|
||||
return service, nil
|
||||
ctx := &ServiceContext{
|
||||
RPCDialer: &wsRPCDialer{addrs: conf.PeerAddrs},
|
||||
Config: conf.Node,
|
||||
}
|
||||
if err := stack.Register(constructor); err != nil {
|
||||
return stack, fmt.Errorf("error registering service %q: %v", name, err)
|
||||
if conf.Snapshots != nil {
|
||||
ctx.Snapshot = conf.Snapshots[name]
|
||||
}
|
||||
service, err := lifecycleFunc(ctx, stack)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
services[name] = service
|
||||
stack.RegisterLifecycle(service)
|
||||
}
|
||||
|
||||
// register the snapshot service
|
||||
err = stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
|
||||
return &snapshotService{services}, nil
|
||||
})
|
||||
if err != nil {
|
||||
return stack, fmt.Errorf("error starting snapshot service: %v", err)
|
||||
}
|
||||
// Add the snapshot API.
|
||||
stack.RegisterAPIs([]rpc.API{{
|
||||
Namespace: "simulation",
|
||||
Version: "1.0",
|
||||
Service: SnapshotAPI{services},
|
||||
}})
|
||||
|
||||
// start the stack
|
||||
if err = stack.Start(); err != nil {
|
||||
err = fmt.Errorf("error starting stack: %v", err)
|
||||
}
|
||||
@ -490,35 +482,9 @@ type nodeStartupJSON struct {
|
||||
NodeInfo *p2p.NodeInfo
|
||||
}
|
||||
|
||||
// snapshotService is a node.Service which wraps a list of services and
|
||||
// exposes an API to generate a snapshot of those services
|
||||
type snapshotService struct {
|
||||
services map[string]node.Service
|
||||
}
|
||||
|
||||
func (s *snapshotService) APIs() []rpc.API {
|
||||
return []rpc.API{{
|
||||
Namespace: "simulation",
|
||||
Version: "1.0",
|
||||
Service: SnapshotAPI{s.services},
|
||||
}}
|
||||
}
|
||||
|
||||
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 {
|
||||
services map[string]node.Service
|
||||
services map[string]node.Lifecycle
|
||||
}
|
||||
|
||||
func (api SnapshotAPI) Snapshot() (map[string][]byte, error) {
|
||||
|
Reference in New Issue
Block a user