tmpnet

package
v1.10.18-rc.9 Latest Latest
Warning

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

Go to latest
Published: Dec 27, 2023 License: BSD-3-Clause Imports: 35 Imported by: 18

README

tmpnet - temporary network orchestration

This package implements a simple orchestrator for the avalanchego nodes of a temporary 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 tmpnetctl cli and e2e test fixture to orchestrate the same temporary networks without the use of an rpc daemon.

What's in a name?

The name of this package was originally testnet and its cli was testnetctl. This name was chosen in ignorance that testnet commonly refers to a persistent blockchain network used for testing.

To avoid confusion, the name was changed to tmpnet and its cli tmpnetctl. tmpnet is short for temporary network since the networks it deploys are likely to live for a limited duration in support of the development and testing of avalanchego and its related repositories.

Package details

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

Filename Types Purpose
defaults.go Defines common default configuration
flags.go FlagsMap Simplifies configuration of avalanchego flags
genesis.go Creates test genesis
network.go Network Orchestrates and configures temporary networks
node.go Node Orchestrates and configures nodes
node_config.go Node Reads and writes node configuration
node_process.go NodeProcess Orchestrates node processes
utils.go Defines shared utility functions

Usage

Via tmpnetctl

A temporary network can be managed by the tmpnetctl cli tool:

# From the root of the avalanchego repo

# Build the tmpnetctl binary
$ ./scripts/build_tmpnetctl.sh

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

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

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

Note the export of the path ending in latest. This is a symlink that is set to the last network created by tmpnetctl start-network. Setting the TMPNET_NETWORK_DIR env var to this symlink ensures that tmpnetctl commands and e2e execution with --use-existing-network will target the most recently deployed temporary network.

Via code

A temporary network can be managed in code:

network, _ := tmpnet.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 (~/.tmpnet)
    &tmpnet.Network{
        NodeRuntimeConfig: tmpnet.NodeRuntimeConfig{
            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 Network instance supplied to StartNetwork() can be initialized with explicit node configuration and by supplying a nodeCount argument of 0:

network, _ := tmpnet.StartNetwork(
    ctx,
    ginkgo.GinkgoWriter,
    "",
    &tmpnet.Network{
        NodeRuntimeConfig: tmpnet.NodeRuntimeConfig{
            ExecPath: "/path/to/avalanchego",
        },
        Nodes: []*Node{
            {                                                       // 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 temporary network will be started with staking and API ports set to 0 to ensure that ports will be dynamically chosen. The tmpnet 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 temporary networks without having to manually select compatible port ranges.

Configuration on disk

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

HOME
└── .tmpnet                                              // Root path for the temporary network fixture
    └── networks                                         // Default parent directory for temporary 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 runtime configuration
            │   ├── db
            │   │   └── ...
            │   ├── flags.json                           // Node flags
            │   ├── 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 var to simplify network usage
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 temporary 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 TMPNET_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 tmpnetctl cli to target the network path specified in the env var.

Set TMPNET_ROOT_DIR to specify the root directory in which to create the configuration directory of new networks (e.g. $TMPNET_ROOT_DIR/[network-dir]). The default root directory is ~/.tmpdir/networks. Configuring the root directory is only relevant when creating new networks as the path of existing networks will already have been set.

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.

Runtime config

The details required to configure a node's execution are written to [network-path]/[node-id]/config.json. This file contains the runtime-specific details like the path of the avalanchego binary to start the node with.

Flags

All flags used to configure a node are written to [network-path]/[node-id]/flags.json so that a node can be configured with only a single argument: --config-file=/path/to/flags.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 temporary network orchestration.
	NetworkDirEnvName = "TMPNET_NETWORK_DIR"
	RootDirEnvName    = "TMPNET_ROOT_DIR"

	DefaultNetworkTimeout = 2 * time.Minute

	// Minimum required to ensure connectivity-based health checks will pass
	DefaultNodeCount = 2

	// Arbitrary number of pre-funded keys to create by default
	DefaultPreFundedKeyCount = 50

	// A short minimum stake duration enables testing of staking logic.
	DefaultMinStakeDuration = time.Second
)
View Source
const (
	AvalancheGoPathEnvName = "AVALANCHEGO_PATH"
)
View Source
const (
	DefaultNodeTickerInterval = 50 * time.Millisecond
)

Variables

View Source
var ErrNotRunning = errors.New("not running")

Functions

func DefaultJSONMarshal

func DefaultJSONMarshal(v interface{}) ([]byte, error)

Marshal to json with default prefix and indent.

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 NewPrivateKeys added in v1.10.18

func NewPrivateKeys(keyCount int) ([]*secp256k1.PrivateKey, error)

Helper simplifying creation of a set of private keys

func NewTestGenesis

func NewTestGenesis(
	networkID uint32,
	nodes []*Node,
	keysToFund []*secp256k1.PrivateKey,
) (*genesis.UnparsedConfig, error)

Create a genesis struct valid for bootstrapping a test network. Note that many of the genesis fields (e.g. reward addresses) are randomly generated or hard-coded.

func StopNetwork added in v1.10.18

func StopNetwork(ctx context.Context, dir string) error

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

func WaitForHealthy

func WaitForHealthy(ctx context.Context, node *Node) error

WaitForHealthy blocks until Node.IsHealthy returns true or an error (including context timeout) is observed.

Types

type FlagsMap

type FlagsMap map[string]interface{}

Defines a mapping of flag keys to values intended to be supplied to an invocation of an AvalancheGo node.

func DefaultCChainConfig

func DefaultCChainConfig() FlagsMap

C-Chain config for testing.

func DefaultFlags added in v1.10.18

func DefaultFlags() FlagsMap

A set of flags appropriate for testing.

func ReadFlagsMap

func ReadFlagsMap(path string, description string) (*FlagsMap, error)

Utility function simplifying construction of a FlagsMap from a file.

func (FlagsMap) GetStringVal

func (f FlagsMap) GetStringVal(key string) (string, error)

GetStringVal simplifies retrieving a map value as a string.

func (FlagsMap) SetDefaults

func (f FlagsMap) SetDefaults(defaults FlagsMap)

SetDefaults ensures the effectiveness of flag overrides by only setting values supplied in the defaults map that are not already explicitly set.

func (FlagsMap) Write

func (f FlagsMap) Write(path string, description string) error

Write simplifies writing a FlagsMap to the provided path. The description is used in error messages.

type Network

type Network struct {
	NodeRuntimeConfig

	Genesis       *genesis.UnparsedConfig
	CChainConfig  FlagsMap
	DefaultFlags  FlagsMap
	PreFundedKeys []*secp256k1.PrivateKey

	// Nodes comprising the network
	Nodes []*Node

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

Defines the configuration required for a tempoary network

func ReadNetwork added in v1.10.18

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

Read a network from the provided directory.

func StartNetwork

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

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

func (*Network) AddEphemeralNode

func (n *Network) AddEphemeralNode(ctx context.Context, w io.Writer, flags FlagsMap) (*Node, error)

Adds a backend-agnostic ephemeral node to the network

func (*Network) AddNode

func (n *Network) AddNode(ctx context.Context, w io.Writer, node *Node, isEphemeral bool) (*Node, error)

func (*Network) EnvFileContents added in v1.10.18

func (n *Network) EnvFileContents() string

func (*Network) EnvFilePath added in v1.10.18

func (n *Network) EnvFilePath() string

func (*Network) GetBootstrapIPsAndIDs

func (n *Network) GetBootstrapIPsAndIDs() ([]string, []string, error)

func (*Network) GetCChainConfigPath

func (n *Network) GetCChainConfigPath() string

func (*Network) GetChainConfigDir added in v1.11.10

func (n *Network) GetChainConfigDir() string

func (*Network) GetDefaultsPath

func (n *Network) GetDefaultsPath() string

func (*Network) GetGenesisPath

func (n *Network) GetGenesisPath() string

func (*Network) GetURIs

func (n *Network) GetURIs() []NodeURI

Retrieve API URIs for all running primary validator nodes. URIs for ephemeral nodes are not returned.

func (*Network) PopulateNetworkConfig

func (n *Network) PopulateNetworkConfig(networkID uint32, nodeCount int, keyCount int) error

Ensure the network has the configuration it needs to start.

func (*Network) PopulateNodeConfig

func (n *Network) PopulateNodeConfig(node *Node, nodeParentDir string) error

Ensure the provided node has the configuration it needs to start. If the data dir is not set, it will be defaulted to [nodeParentDir]/[node ID]. Requires that the network has valid genesis data.

func (*Network) ReadAll

func (n *Network) ReadAll() error

Read network and node configuration from disk.

func (*Network) ReadCChainConfig

func (n *Network) ReadCChainConfig() error

func (*Network) ReadConfig

func (n *Network) ReadConfig() error

Read network configuration from disk.

func (*Network) ReadDefaults

func (n *Network) ReadDefaults() error

func (*Network) ReadGenesis

func (n *Network) ReadGenesis() error

func (*Network) ReadNodes

func (n *Network) ReadNodes() error

Read node configuration and process context from disk.

func (*Network) Start added in v1.10.18

func (n *Network) Start(w io.Writer) error

Starts a network for the first time

func (*Network) Stop added in v1.10.18

func (n *Network) Stop(ctx context.Context) error

Stop all nodes in the network.

func (*Network) WaitForHealthy added in v1.10.18

func (n *Network) WaitForHealthy(ctx context.Context, w io.Writer) error

Wait until all nodes in the network are healthy.

func (*Network) WriteAll

func (n *Network) WriteAll() error

Write network configuration to disk.

func (*Network) WriteCChainConfig

func (n *Network) WriteCChainConfig() error

func (*Network) WriteDefaults

func (n *Network) WriteDefaults() error

func (*Network) WriteEnvFile

func (n *Network) WriteEnvFile() error

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

func (*Network) WriteGenesis

func (n *Network) WriteGenesis() error

func (*Network) WriteNodes

func (n *Network) WriteNodes() error

type Node

type Node struct {
	// Set by EnsureNodeID which is also called when the node is read.
	NodeID ids.NodeID

	// Flags that will be supplied to the node at startup
	Flags FlagsMap

	// An ephemeral node is not expected to be a persistent member of the network and
	// should therefore not be used as for bootstrapping purposes.
	IsEphemeral bool

	// The configuration used to initialize the node runtime.
	RuntimeConfig *NodeRuntimeConfig

	// Runtime state, intended to be set by NodeRuntime
	URI            string
	StakingAddress string
	// contains filtered or unexported fields
}

Node supports configuring and running a node participating in a temporary network.

func NewNode added in v1.10.18

func NewNode(dataDir string) *Node

Initializes a new node with only the data dir set

func ReadNode added in v1.10.18

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

Reads a node's configuration from the specified directory.

func ReadNodes added in v1.10.18

func ReadNodes(networkDir string) ([]*Node, error)

Reads nodes from the specified network directory.

func (*Node) EnsureBLSSigningKey added in v1.10.18

func (n *Node) EnsureBLSSigningKey() error

Ensures a BLS signing key is generated if not already present.

func (*Node) EnsureKeys added in v1.10.18

func (n *Node) EnsureKeys() error

Ensures staking and signing keys are generated if not already present and that the node ID (derived from the staking keypair) is set.

func (*Node) EnsureNodeID added in v1.10.18

func (n *Node) EnsureNodeID() error

Derives the node ID. Requires that a tls keypair is present.

func (*Node) EnsureStakingKeypair added in v1.10.18

func (n *Node) EnsureStakingKeypair() error

Ensures a staking keypair is generated if not already present.

func (*Node) GetProofOfPossession added in v1.10.18

func (n *Node) GetProofOfPossession() (*signer.ProofOfPossession, error)

Derives the nodes proof-of-possession. Requires the node to have a BLS signing key.

func (*Node) InitiateStop added in v1.10.18

func (n *Node) InitiateStop() error

func (*Node) IsHealthy

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

func (*Node) Read added in v1.10.18

func (n *Node) Read() error

func (*Node) SetNetworkingConfig added in v1.10.18

func (n *Node) SetNetworkingConfig(bootstrapIDs []string, bootstrapIPs []string)

Sets networking configuration for the node. Convenience method for setting networking flags.

func (*Node) Start added in v1.10.18

func (n *Node) Start(w io.Writer) error

func (*Node) Stop

func (n *Node) Stop(ctx context.Context) error

Initiates node shutdown and waits for the node to stop.

func (*Node) WaitForStopped added in v1.10.18

func (n *Node) WaitForStopped(ctx context.Context) error

func (*Node) Write added in v1.10.18

func (n *Node) Write() error

type NodeProcess added in v1.10.18

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

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

func (*NodeProcess) InitiateStop added in v1.10.18

func (p *NodeProcess) InitiateStop() error

Signals the node process to stop.

func (*NodeProcess) IsHealthy added in v1.10.18

func (p *NodeProcess) IsHealthy(ctx context.Context) (bool, error)

func (*NodeProcess) Start added in v1.10.18

func (p *NodeProcess) Start(w io.Writer) error

Start waits for the process context to be written which indicates that the node will be accepting connections on its staking port. The network will start faster with this synchronization due to the avoidance of exponential backoff if a node tries to connect to a beacon that is not ready.

func (*NodeProcess) WaitForStopped added in v1.10.18

func (p *NodeProcess) WaitForStopped(ctx context.Context) error

Waits for the node process to stop.

type NodeRuntime added in v1.10.18

type NodeRuntime interface {
	Start(w io.Writer) error
	InitiateStop() error
	WaitForStopped(ctx context.Context) error
	IsHealthy(ctx context.Context) (bool, error)
	// contains filtered or unexported methods
}

NodeRuntime defines the methods required to support running a node.

type NodeRuntimeConfig added in v1.10.18

type NodeRuntimeConfig struct {
	AvalancheGoPath string
}

Configuration required to configure a node runtime.

type NodeURI

type NodeURI struct {
	NodeID ids.NodeID
	URI    string
}

NodeURI associates a node ID with its API URI.

func GetNodeURIs added in v1.10.18

func GetNodeURIs(nodes []*Node) []NodeURI

type XChainBalanceMap

type XChainBalanceMap map[ids.ShortID]uint64

Helper type to simplify configuring X-Chain genesis balances

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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