local

package
v1.10.8-rc.3 Latest Latest
Warning

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

Go to latest
Published: Aug 28, 2023 License: BSD-3-Clause Imports: 23 Imported by: 0

README

Local network orchestration

This package implements a simple orchestrator for the avalanchego nodes of a local network. Configuration is stored on disk, and nodes run as independent processes whose process details are also written to disk. Using the filesystem to store configuration and process details allows for the testnetctl cli and e2e test fixture to orchestrate the same local networks without the use of an rpc daemon.

Package details

The functionality in this package is grouped by logical purpose into the following non-test files:

Filename Types Purpose
config.go Common configuration
network.go LocalNetwork Network-level orchestration and configuration
node.go Local{Config,Node} Node-level orchestration and configuration

This package depends on its parent package for implementation-agnostic network and node configuration. Only configuration and code specific to orchestrating local networks belongs in this package to ensure that other orchestration implementations can reuse the shared configuration abstractions.

Usage

Via testnetctl

A local network can be managed by the testnetctl cli tool:

# From the root of the avalanchego repo

# Build the testnetctl binary
$ ./scripts/build_testnetctl.sh

# Start a new network
$ ./build/testnetctl start-network --avalanchego-path=/path/to/avalanchego
...
Started network 1000 @ /home/me/.testnetctl/networks/1000

Configure testnetctl to target this network by default with one of the following statements:
 - source /home/me/.testnetctl/networks/1000/network.env
 - export TESTNETCTL_NETWORK_DIR=/home/me/.testnetctl/networks/1000
 - export TESTNETCTL_NETWORK_DIR=/home/me/.testnetctl/networks/latest

# Stop the network
$ ./build/testnetctl stop-network --network-dir=/path/to/network

Note the export of the path ending in latest. This is a symlink that set to the last network created by testnetctl start-network. Setting the TESTNETCTL_NETWORK_DIR env var to this symlink ensures that testnetctl commands will target the most recently deployed local network.

Via code

A local network can be managed in code:

network, _ := local.StartNetwork(
    ctx,                                       // Context used to limit duration of waiting for network health
    ginkgo.GinkgoWriter,                       // Writer to report progress of network start
    "",                                        // Use default root dir (~/.testnetctl)
    &local.LocalNetwork{
        LocalConfig: local.LocalConfig{
            ExecPath: "/path/to/avalanchego",  // Defining the avalanchego exec path is required
        },
    },
    5,                                         // Number of initial validating nodes
    50,                                        // Number of pre-funded keys to create
)

uris := network.GetURIs()

// Use URIs to interact with the network

// Stop all nodes in the network
network.Stop()

If non-default node behavior is required, the LocalNetwork instance supplied to StartNetwork() can be initialized with explicit node configuration and by supplying a nodeCount argument of 0:

network, _ := local.StartNetwork(
    ctx,
    ginkgo.GinkgoWriter,
    "",
    &local.LocalNetwork{
        LocalConfig: local.LocalConfig{
            ExecPath: "/path/to/avalanchego",
        },
        Nodes: []*LocalNode{
            {                                                       // node1 configuration is customized
                Flags: FlagsMap{                                    // Any and all node flags can be configured here
                    config.DataDirKey: "/custom/path/to/node/data",
                }
            },
        },
        {},                                                         // node2 uses default configuration
        {},                                                         // node3 uses default configuration
        {},                                                         // node4 uses default configuration
        {},                                                         // node5 uses default configuration
    },
    0,                                                              // Node count must be zero when setting node config
    50,
)

Further examples of code-based usage are located in the e2e tests.

Networking configuration

By default, nodes in a local network will be started with staking and API ports set to 0 to ensure that ports will be dynamically chosen. The testnet fixture discovers the ports used by a given node by reading the [base-data-dir]/process.json file written by avalanchego on node start. The use of dynamic ports supports testing with many local networks without having to manually select compatible port ranges.

Configuration on disk

A local network relies on configuration written to disk in the following structure:

HOME
└── .testnetctl                                          // Root path for tool
    └── networks                                         // Default parent directory for local networks
        └── 1000                                         // The networkID is used to name the network dir and starts at 1000
            ├── NodeID-37E8UK3x2YFsHE3RdALmfWcppcZ1eTuj9 // The ID of a node is the name of its data dir
            │   ├── chainData
            │   │   └── ...
            │   ├── config.json                          // Node flags
            │   ├── db
            │   │   └── ...
            │   ├── logs
            │   │   └── ...
            │   ├── plugins
            │   │   └── ...
            │   └── process.json                         // Node process details (PID, API URI, staking address)
            ├── chains
            │   └── C
            │       └── config.json                      // C-Chain config for all nodes
            ├── defaults.json                            // Default flags and configuration for network
            ├── genesis.json                             // Genesis for all nodes
            └── network.env                              // Sets network dir env to simplify use of network

Default flags and configuration

The default avalanchego node flags (e.g. --staking-port=) and default configuration like the avalanchego path are stored at [network-dir]/defaults.json. The value for a given defaulted flag will be set on initial and subsequently added nodes that do not supply values for a given defaulted flag.

Genesis

The genesis file is stored at [network-dir]/genesis.json and referenced by default by all nodes in the network. The genesis file content will be generated with reasonable defaults if not supplied. Each node in the network can override the default by setting an explicit value for --genesis-file or --genesis-file-content.

C-Chain config

The C-Chain config for a local network is stored at [network-dir]/chains/C/config.json and referenced by default by all nodes in the network. The C-Chain config will be generated with reasonable defaults if not supplied. Each node in the network can override the default by setting an explicit value for --chain-config-dir and ensuring the C-Chain config file exists at [chain-config-dir]/C/config.json.

TODO(marun) Enable configuration of X-Chain and P-Chain.

Network env

A shell script that sets the TESTNETCTL_NETWORK_DIR env var to the path of the network is stored at [network-dir]/network.env. Sourcing this file (i.e. source network.env) in a shell will configure ginkgo e2e and the testnetctl cli to target the network path specified in the env var.

Node configuration

The data dir for a node is set by default to [network-path]/[node-id]. A node can be configured to use a non-default path by explicitly setting the --data-dir flag.

Flags

All flags used to configure a node are written to [network-path]/[node-id]/config.json so that a node can be configured with only a single argument: --config-file=/path/to/config.json. This simplifies node launch and ensures all parameters used to launch a node can be modified by editing the config file.

Process details

The process details of a node are written by avalanchego to [base-data-dir]/process.json. The file contains the PID of the node process, the URI of the node's API, and the address other nodes can use to bootstrap themselves (aka staking address).

Documentation

Index

Constants

View Source
const (
	// Constants defining the names of shell variables whose value can
	// configure local network orchestration.
	AvalancheGoPathEnvName = "AVALANCHEGO_PATH"
	NetworkDirEnvName      = "TESTNETCTL_NETWORK_DIR"
	RootDirEnvName         = "TESTNETCTL_ROOT_DIR"

	DefaultNetworkStartTimeout = 2 * time.Minute
	DefaultNodeInitTimeout     = 10 * time.Second
	DefaultNodeStopTimeout     = 5 * time.Second
	DefaultNodeTickerInterval  = 50 * time.Millisecond
)

Variables

This section is empty.

Functions

func FindNextNetworkID

func FindNextNetworkID(rootDir string) (uint32, string, error)

Find the next available network ID by attempting to create a directory numbered from 1000 until creation succeeds. Returns the network id and the full path of the created directory.

func GetDefaultRootDir

func GetDefaultRootDir() (string, error)

Default root dir for storing networks and their configuration.

func LocalCChainConfig

func LocalCChainConfig() testnet.FlagsMap

C-Chain config for local testing.

func LocalFlags

func LocalFlags() testnet.FlagsMap

A set of flags appropriate for local testing.

func StopNetwork

func StopNetwork(dir string) error

Stop the nodes of the network configured in the provided directory.

Types

type LocalConfig

type LocalConfig struct {
	// Path to avalanchego binary
	ExecPath string
}

Defines local-specific node configuration. Supports setting default and node-specific values.

TODO(marun) Support persisting this configuration per-node when node restart is implemented. Currently it can be supplied for node start but won't survive restart.

type LocalNetwork

type LocalNetwork struct {
	testnet.NetworkConfig
	LocalConfig

	// Nodes with local configuration
	Nodes []*LocalNode

	// Path where network configuration will be stored
	Dir string
}

Defines the configuration required for a local network (i.e. one composed of local processes).

func ReadNetwork

func ReadNetwork(dir string) (*LocalNetwork, error)

Read a network from the provided directory.

func StartNetwork

func StartNetwork(
	ctx context.Context,
	w io.Writer,
	rootDir string,
	network *LocalNetwork,
	nodeCount int,
	keyCount int,
) (*LocalNetwork, error)

Starts a new network stored under the provided root dir. Required configuration will be defaulted if not provided.

func (*LocalNetwork) EnvFileContents

func (ln *LocalNetwork) EnvFileContents() string

func (*LocalNetwork) EnvFilePath

func (ln *LocalNetwork) EnvFilePath() string

func (*LocalNetwork) GetCChainConfigPath

func (ln *LocalNetwork) GetCChainConfigPath() string

func (*LocalNetwork) GetChainConfigDir

func (ln *LocalNetwork) GetChainConfigDir() string

func (*LocalNetwork) GetConfig

func (ln *LocalNetwork) GetConfig() testnet.NetworkConfig

Returns the configuration of the network in backend-agnostic form.

func (*LocalNetwork) GetDefaultsPath

func (ln *LocalNetwork) GetDefaultsPath() string

func (*LocalNetwork) GetGenesisPath

func (ln *LocalNetwork) GetGenesisPath() string

func (*LocalNetwork) GetNodes

func (ln *LocalNetwork) GetNodes() []testnet.Node

Returns the nodes of the network in backend-agnostic form.

func (*LocalNetwork) GetURIs

func (ln *LocalNetwork) GetURIs() []string

Retrieve API URIs for all nodes in the network. Assumes nodes have been loaded.

func (*LocalNetwork) PopulateLocalNetworkConfig

func (ln *LocalNetwork) PopulateLocalNetworkConfig(networkID uint32, nodeCount int, keyCount int) error

Ensure the network has the configuration it needs to start.

func (*LocalNetwork) PopulateNodeConfig

func (ln *LocalNetwork) PopulateNodeConfig(node *LocalNode) error

Ensure the provided node has the configuration it needs to start. Requires that the network has valid genesis data.

func (*LocalNetwork) ReadAll

func (ln *LocalNetwork) ReadAll() error

Read network and node configuration from disk.

func (*LocalNetwork) ReadCChainConfig

func (ln *LocalNetwork) ReadCChainConfig() error

func (*LocalNetwork) ReadConfig

func (ln *LocalNetwork) ReadConfig() error

Read network configuration from disk.

func (*LocalNetwork) ReadDefaults

func (ln *LocalNetwork) ReadDefaults() error

func (*LocalNetwork) ReadGenesis

func (ln *LocalNetwork) ReadGenesis() error

func (*LocalNetwork) ReadNodes

func (ln *LocalNetwork) ReadNodes() error

Read node configuration and process context from disk.

func (*LocalNetwork) Start

func (ln *LocalNetwork) Start(w io.Writer) error

Starts a network for the first time

func (*LocalNetwork) Stop

func (ln *LocalNetwork) Stop() error

Stop all nodes in the network.

func (*LocalNetwork) WaitForHealthy

func (ln *LocalNetwork) WaitForHealthy(ctx context.Context, w io.Writer) error

Wait until all nodes in the network are healthy.

func (*LocalNetwork) WriteAll

func (ln *LocalNetwork) WriteAll() error

Write network configuration to disk.

func (*LocalNetwork) WriteCChainConfig

func (ln *LocalNetwork) WriteCChainConfig() error

func (*LocalNetwork) WriteDefaults

func (ln *LocalNetwork) WriteDefaults() error

func (*LocalNetwork) WriteEnvFile

func (ln *LocalNetwork) WriteEnvFile() error

Write an env file that sets the network dir env when sourced.

func (*LocalNetwork) WriteGenesis

func (ln *LocalNetwork) WriteGenesis() error

func (*LocalNetwork) WriteNodes

func (ln *LocalNetwork) WriteNodes() error

type LocalNode

Stores the configuration and process details of a node in a local network.

func NewLocalNode

func NewLocalNode(dataDir string) *LocalNode

func ReadNode

func ReadNode(dataDir string) (*LocalNode, error)

Attempt to read configuration and process details for a local node from the specified directory.

func (*LocalNode) GetConfig

func (n *LocalNode) GetConfig() testnet.NodeConfig

Retrieve backend-agnostic node configuration.

func (*LocalNode) GetConfigPath

func (n *LocalNode) GetConfigPath() string

func (*LocalNode) GetDataDir

func (n *LocalNode) GetDataDir() string

func (*LocalNode) GetID

func (n *LocalNode) GetID() ids.NodeID

Retrieve the ID of the node. The returned value may be nil if the node configuration has not yet been populated or read.

func (*LocalNode) GetProcess

func (n *LocalNode) GetProcess() (*os.Process, error)

Retrieve the node process if it is running. As part of determining process liveness, the node's process context will be refreshed if live or cleared if not running.

func (*LocalNode) GetProcessContext

func (n *LocalNode) GetProcessContext() node.NodeProcessContext

Retrieve backend-agnostic process details.

func (*LocalNode) GetProcessContextPath

func (n *LocalNode) GetProcessContextPath() string

func (*LocalNode) IsHealthy

func (n *LocalNode) IsHealthy(ctx context.Context) (bool, error)

func (*LocalNode) ReadAll

func (n *LocalNode) ReadAll() error

func (*LocalNode) ReadConfig

func (n *LocalNode) ReadConfig() error

func (*LocalNode) ReadProcessContext

func (n *LocalNode) ReadProcessContext() error

func (*LocalNode) Start

func (n *LocalNode) Start(w io.Writer, defaultExecPath string) error

func (*LocalNode) Stop

func (n *LocalNode) Stop() error

Signals the node process to stop and waits for the node process to stop running.

func (*LocalNode) WaitForProcessContext

func (n *LocalNode) WaitForProcessContext(ctx context.Context) error

func (*LocalNode) WriteConfig

func (n *LocalNode) WriteConfig() error

type NetworkStopError

type NetworkStopError struct {
	Errors []*NodeStopError
}

func (*NetworkStopError) Error

func (e *NetworkStopError) Error() string

type NodeStopError

type NodeStopError struct {
	NodeID    ids.NodeID
	StopError error
}

func (*NodeStopError) Error

func (e *NodeStopError) Error() string

Jump to

Keyboard shortcuts

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