node

package
v0.0.0-...-1f8a15b Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 12, 2023 License: GPL-3.0 Imports: 34 Imported by: 0

Documentation

Overview

Package node sets up multi-protocol Ethereum nodes.

In the model exposed by this package, a node is a collection of services which use shared resources to provide RPC APIs. Services can also offer devp2p protocols, which are wired up to the devp2p network when the node instance is started.

Node Lifecycle

The Node object has a lifecycle consisting of three basic states, INITIALIZING, RUNNING and CLOSED.

●───────┐
     New()
        │
        ▼
  INITIALIZING ────Start()─┐
        │                  │
        │                  ▼
    Close()             RUNNING
        │                  │
        ▼                  │
     CLOSED ◀──────Close()─┘

Creating a Node allocates basic resources such as the data directory and returns the node in its INITIALIZING state. Lifecycle objects, RPC APIs and peer-to-peer networking protocols can be registered in this state. Basic operations such as opening a key-value database are permitted while initializing.

Once everything is registered, the node can be started, which moves it into the RUNNING state. Starting the node starts all registered Lifecycle objects and enables RPC and peer-to-peer networking. Note that no additional Lifecycles, APIs or p2p protocols can be registered while the node is running.

Closing the node releases all held resources. The actions performed by Close depend on the state it was in. When closing a node in INITIALIZING state, resources related to the data directory are released. If the node was RUNNING, closing it also stops all Lifecycle objects and shuts down RPC and peer-to-peer networking.

You must always call Close on Node, even if the node was not started.

Resources Managed By Node

All file-system resources used by a node instance are located in a directory called the data directory. The location of each resource can be overridden through additional node configuration. The data directory is optional. If it is not set and the location of a resource is otherwise unspecified, package node will create the resource in memory.

To access to the devp2p network, Node configures and starts p2p.Server. Each host on the devp2p network has a unique identifier, the node key. The Node instance persists this key across restarts. Node also loads static and trusted node lists and ensures that knowledge about other hosts is persisted.

JSON-RPC servers which run HTTP, WebSocket or IPC can be started on a Node. RPC modules offered by registered services will be offered on those endpoints. Users can restrict any endpoint to a subset of RPC modules. Node itself offers the "debug", "admin" and "web3" modules.

Service implementations can open databases through the service context. Package node chooses the file system location of each database. If the node is configured to run without a data directory, databases are opened in memory instead.

Node also creates the shared store of encrypted Ethereum account keys. Services can access the account manager through the service context.

Sharing Data Directory Among Instances

Multiple node instances can share a single data directory if they have distinct instance names (set through the Name config option). Sharing behaviour depends on the type of resource.

devp2p-related resources (node key, static/trusted node lists, known hosts database) are stored in a directory with the same name as the instance. Thus, multiple node instances using the same data directory will store this information in different subdirectories of the data directory.

Databases are also stored within the instance subdirectory. If multiple node instances use the same data directory, opening the databases with identical names will create one database for each instance.

Data Directory Sharing Example

In this example, two node instances named A and B are started with the same data directory. Node instance A opens the database "db", node instance B opens the databases "db" and "db-2". The following files will be created in the data directory:

data-directory/
     A/
         nodekey            -- devp2p node key of instance A
         nodes/             -- devp2p discovery knowledge database of instance A
         db/                -- data for "db"
     A.ipc                  -- JSON-RPC UNIX domain socket endpoint of instance A
     B/
         nodekey            -- devp2p node key of node B
         nodes/             -- devp2p discovery knowledge database of instance B
         static-nodes.json  -- devp2p static node list of instance B
         db/                -- data for "db"
         db-2/              -- data for "db-2"
     B.ipc                  -- JSON-RPC UNIX domain socket endpoint of instance B

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	ErrNodeStopped = errors.New("node not started")
	ErrNodeRunning = errors.New("node already running")
)

Functions

func CheckTimeouts

func CheckTimeouts(timeouts *rpccfg.HTTPTimeouts)

CheckTimeouts ensures that timeout values are meaningful

func NewHTTPHandlerStack

func NewHTTPHandlerStack(srv http.Handler, cors []string, vhosts []string, compression bool) http.Handler

NewHTTPHandlerStack returns wrapped http-related handlers

func OpenDatabase

func OpenDatabase(ctx context.Context, config *nodecfg.Config, label kv.Label, name string, readonly bool, logger log.Logger) (kv.RwDB, error)

func RegisterApisFromWhitelist

func RegisterApisFromWhitelist(apis []rpc.API, modules []string, srv *rpc.Server, exposeAll bool, logger log.Logger) error

RegisterApisFromWhitelist checks the given modules' availability, generates a whitelist based on the allowed modules, and then registers all of the APIs exposed by the services.

func StartHTTPEndpoint

func StartHTTPEndpoint(urlEndpoint string, cfg *HttpEndpointConfig, handler http.Handler) (*http.Server, net.Addr, error)

StartHTTPEndpoint starts the HTTP RPC endpoint.

func StartHTTPSEndpoint

func StartHTTPSEndpoint(urlEndpoint string,
	keyFile string, certFile string,
	timeouts rpccfg.HTTPTimeouts, handler http.Handler,
) (*http.Server, net.Addr, error)

StartHTTPEndpoint starts the HTTP RPC endpoint.

func StartNode

func StartNode(stack *Node)

Types

type HttpEndpointConfig

type HttpEndpointConfig struct {
	Timeouts rpccfg.HTTPTimeouts
	HTTPS    bool
	CertFile string
	KeyFile  string
}

type Lifecycle

type Lifecycle interface {
	// Start is called after all services have been constructed and the networking
	// layer was also initialized to spawn any goroutines required by the service.
	Start() error

	// Stop terminates all goroutines belonging to the service, blocking until they
	// are all terminated.
	Stop() error
}

Lifecycle encompasses the behavior of services that can be started and stopped on the node. Lifecycle management is delegated to the node, but it is the responsibility of the service-specific package to configure and register the service on the node using the `RegisterLifecycle` method.

Example
package main

import (
	"context"
	"fmt"
	log2 "log"

	"github.com/idrecun/erigon/node"
	"github.com/idrecun/erigon/node/nodecfg"
	"github.com/ledgerwatch/log/v3"
)

// SampleLifecycle is a trivial network service that can be attached to a node for
// life cycle management.
//
// The following methods are needed to implement a node.Lifecycle:
//   - Start() error              - method invoked when the node is ready to start the service
//   - Stop() error               - method invoked when the node terminates the service
type SampleLifecycle struct{}

func (s *SampleLifecycle) Start() error { fmt.Println("Service starting..."); return nil }
func (s *SampleLifecycle) Stop() error  { fmt.Println("Service stopping..."); return nil }

func main() {
	// Create a network node to run protocols with the default values.
	stack, err := node.New(context.Background(), &nodecfg.Config{}, log.New())
	if err != nil {
		log2.Fatalf("Failed to create network node: %v", err)
	}
	defer stack.Close()

	// Create and register a simple network Lifecycle.
	service := new(SampleLifecycle)
	stack.RegisterLifecycle(service)

	// Boot up the entire protocol stack, do a restart and terminate
	if err := stack.Start(); err != nil {
		log2.Fatalf("Failed to start the protocol stack: %v", err)
	}
	if err := stack.Close(); err != nil {
		log2.Fatalf("Failed to stop the protocol stack: %v", err)
	}
}
Output:

Service starting...
Service stopping...

type Node

type Node struct {
	// contains filtered or unexported fields
}

Node is a container on which services can be registered.

func New

func New(ctx context.Context, conf *nodecfg.Config, logger log.Logger) (*Node, error)

New creates a new P2P node, ready for protocol registration.

func (*Node) Close

func (n *Node) Close() error

Close stops the Node and releases resources acquired in Node constructor New.

func (*Node) Config

func (n *Node) Config() *nodecfg.Config

Config returns the configuration of node.

func (*Node) DataDir

func (n *Node) DataDir() string

DataDir retrieves the current datadir used by the protocol stack.

func (*Node) RegisterLifecycle

func (n *Node) RegisterLifecycle(lifecycle Lifecycle)

RegisterLifecycle registers the given Lifecycle on the node.

func (*Node) ResolvePath

func (n *Node) ResolvePath(x string) string

ResolvePath returns the absolute path of a resource in the instance directory.

func (*Node) Start

func (n *Node) Start() error

Start starts all registered lifecycles, RPC services and p2p networking. Node can only be started once.

func (*Node) Wait

func (n *Node) Wait()

Wait blocks until the node is closed.

type StopError

type StopError struct {
	Server   error
	Services map[reflect.Type]error
}

StopError is returned if a Node fails to stop either any of its registered services or itself.

func (*StopError) Error

func (e *StopError) Error() string

Error generates a textual representation of the stop error.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL