Documentation
¶
Index ¶
- Constants
- Variables
- func BuildGenesis(tempDir string, cfg GenesisConfig, validators []*Node) error
- func CleanupNodes(logger *slog.Logger, nodes []*Node)
- func ConfigureConsensusForSync(node *Node) error
- func ConfigureP2PTopology(validators []*Node) error
- func CopySharedGenesis(tempDir string, node *Node) error
- func DefaultNodeConfig() *config.Config
- func FindAvailablePort() (int, error)
- func PrintGenesisConfig(gen *bft.GenesisDoc)
- func ResolveGenesisState(cfg GenesisConfig) (gnoland.GnoGenesisState, error)
- func StartGnolandNode(ctx context.Context, binaryPath string, node *Node, opts GnolandStartOpts) error
- func StartNode(ctx context.Context, binaryPath string, node *Node, args []string, ...) error
- func ValidateGenesisParams(overrides []Override) error
- func ValidateGenesisState(state gnoland.GnoGenesisState) error
- func ValidateNodeConfig(overrides []Override) error
- func WaitForFirstBlock(ctx context.Context, node *Node) error
- func WaitForNodeReady(ctx context.Context, node *Node) error
- type Cluster
- type ClusterConfig
- type GenesisConfig
- type GnolandStartOpts
- type Node
- type Override
Constants ¶
const ( DefaultValidatorKeyName = "priv_validator_key.json" DefaultNodeKeyName = "node_key.json" // File permissions DirPermissions = 0o755 FilePermissions = 0o644 )
Default file names for node secrets
const DefaultChainID = "test-e2e"
Variables ¶
var ( ErrUnknownValidator = errors.New("no validator") ErrValidatorRunning = errors.New("validator is already running") )
The ways a caller can name something the cluster cannot act on. Separate from the errors a stop or a restart produces by trying, because these say the action was never attempted: a verb that lets a script negate one of these would pass a scenario whose cluster never lost a node at all.
Functions ¶
func BuildGenesis ¶
func BuildGenesis(tempDir string, cfg GenesisConfig, validators []*Node) error
BuildGenesis creates a shared genesis file in tempDir using the given config.
func CleanupNodes ¶
CleanupNodes terminates all node processes. A nil logger reports through slog.Default().
Waits through Node.Exited rather than Process.Wait: since readiness polling began reaping, every started node already has a waiter, and a second concurrent wait on the same process is not something os.Process supports.
func ConfigureConsensusForSync ¶
ConfigureConsensusForSync writes the cluster's own consensus and gossip timings into a node's config.toml, with the RPC address it answers on.
func ConfigureP2PTopology ¶
ConfigureP2PTopology gives every validator a peer list naming the others, so the set is a full mesh.
func CopySharedGenesis ¶
CopySharedGenesis copies the shared genesis file to each node's directory.
func DefaultNodeConfig ¶
DefaultNodeConfig returns the config a validator boots with when a scenario sets nothing of its own: tm2's defaults with the harness's passes applied. The listen addresses are left as they come, since the harness assigns each node its own at boot.
func FindAvailablePort ¶
FindAvailablePort finds an available TCP port dynamically. Note: there is an inherent TOCTOU race between closing this listener and the node process binding to the port.
func PrintGenesisConfig ¶
func PrintGenesisConfig(gen *bft.GenesisDoc)
PrintGenesisConfig prints genesis configuration for debugging.
func ResolveGenesisState ¶
func ResolveGenesisState(cfg GenesisConfig) (gnoland.GnoGenesisState, error)
ResolveGenesisState settles what the chain will really boot with: the named fields first, then the generic `genesis.` family, which is applied last so a path spelling wins over the named key covering the same field.
Anything that needs to know what a scenario asked for reads this rather than the named fields, which a path can supersede without ever touching them.
func StartGnolandNode ¶
func StartGnolandNode(ctx context.Context, binaryPath string, node *Node, opts GnolandStartOpts) error
StartGnolandNode starts a gnoland node and returns once it answers RPC.
func StartNode ¶
func StartNode(ctx context.Context, binaryPath string, node *Node, args []string, opts GnolandStartOpts) error
StartNode starts a gnoland node process. opts says where its output goes beyond the per-node log files; the zero value writes only those.
func ValidateGenesisParams ¶
ValidateGenesisParams reports whether overrides resolve, parse and leave the modules they touch valid, checked against the genesis a cluster starts from.
The counterpart to ValidateNodeConfig, and there for the same reason: a misspelled key fails when the scenario is read rather than when its own cluster is built.
func ValidateGenesisState ¶
func ValidateGenesisState(state gnoland.GnoGenesisState) error
ValidateGenesisState reports a genesis no scenario can be written against.
Separate from GenesisConfig.Validate, and checked on the resolved state rather than on the fields, for two reasons: the `genesis.` family reaches the same settings without touching those fields, and `run` fills the approver set per scenario, so its flag template legitimately holds an inert policy with nobody in it.
func ValidateNodeConfig ¶
ValidateNodeConfig reports whether overrides resolve and parse against the config a validator boots with, writing nothing.
This is what lets a misspelled key fail when the scenario is read rather than when its own cluster is built, which in a run is after every scenario ahead of it has already booted one.
func WaitForFirstBlock ¶
WaitForFirstBlock waits until the chain has committed a block.
Per-node readiness cannot cover this. A node reports ready once its ABCI app answers, which is before InitChain has written genesis, and it cannot report a committed block either: nodes start one at a time, and a validator set needing a quorum has none until the last of them is up. So the first transaction of a run can reach a node whose store holds no accounts yet, and is refused for a signature that is in fact correct.
Types ¶
type Cluster ¶
type Cluster struct {
Validators []*Node
RPCAddr string // RPC address of the first validator
BinaryPath string
TempDir string
// contains filtered or unexported fields
}
Cluster holds the running state of a local validator cluster.
func StartCluster ¶
func StartCluster(ctx context.Context, cfg ClusterConfig, binaryPath string) (_ *Cluster, retErr error)
StartCluster sets up validators from genesis and starts the cluster on the gnoland at binaryPath.
The binary is the caller's to produce: a run boots a cluster per scenario and the binary is the same for all of them, so building here would repeat identical work per boot.
func (*Cluster) Cleanup ¶
func (c *Cluster) Cleanup()
Cleanup stops all nodes and cleans up resources. Node logs remain in TempDir/validator_N/{stdout,stderr}.log until TempDir is removed.
func (*Cluster) RestartValidator ¶
RestartValidator starts a stopped validator again from its existing data dir and waits for it to serve RPC.
The node keeps the identity, keys, genesis and ports it had before, so it rejoins the same chain rather than forming a new one -- which is what makes "did it catch up, and does its state match?" answerable.
ctx governs the restarted process, not just this call: the node is killed when it is cancelled. Callers that want the node to outlive the request that restarted it -- a test script command, say -- pass a context that outlives it too.
func (*Cluster) StopValidator ¶
StopValidator terminates one validator and leaves the rest of the cluster running.
Cleanup takes every validator down at once, which is the whole cluster going away rather than a node failing, so fault injection needs this instead: losing one validator of three is survivable and the chain should keep producing blocks, and that is only observable if the others stay up.
The node keeps its data dir and its identity, so RestartValidator can bring the same validator back. Only the process is released, which is what marks it stopped.
type ClusterConfig ¶
type ClusterConfig struct {
NumValidators int
TeeNodeLogs bool // tee node stdout/stderr to os.Stderr
Genesis GenesisConfig
Logger *slog.Logger // if nil, uses slog.Default()
// NodeConfig sets node config options by `gnoland config set` key. Applied
// to every validator after the harness's own configuration, so it can
// override consensus timing -- but never the listen addresses, which the
// harness assigns and hands to the scripts.
NodeConfig []Override
}
ClusterConfig controls how the local validator cluster is set up.
func DefaultClusterConfig ¶
func DefaultClusterConfig() ClusterConfig
DefaultClusterConfig returns cluster defaults.
func (*ClusterConfig) RegisterFlags ¶
func (c *ClusterConfig) RegisterFlags(fs *flag.FlagSet)
func (*ClusterConfig) Validate ¶
func (c *ClusterConfig) Validate() error
type GenesisConfig ¶
type GenesisConfig struct {
ChainID string
MaxGas int64
MaxTxBytes int64
MaxDataBytes int64
TimeIotaMS int64
LoadExamples bool
Balances map[string]int64 // extra funded accounts (addr -> ugnot)
// CodeSubmissionPolicy governs what MsgAddPackage does at heights above
// genesis. Empty leaves the chain default. "inert" parks submissions until
// an address in PkgApprovers enables them.
CodeSubmissionPolicy vm.CodeSubmissionPolicy
// PkgApprovers may send MsgEnablePackage. Required under "inert".
PkgApprovers []crypto.Address
// Params sets auth, vm and bank genesis params by `gnogenesis params set`
// key. Applied after the policy and approver fields above, so an explicit
// path wins over them.
Params []Override
}
GenesisConfig controls the genesis document for a local cluster.
func DefaultGenesisConfig ¶
func DefaultGenesisConfig() GenesisConfig
DefaultGenesisConfig returns the genesis parameters a cluster starts from when a scenario declares none of its own.
func (*GenesisConfig) RegisterFlags ¶
func (g *GenesisConfig) RegisterFlags(fs *flag.FlagSet)
func (*GenesisConfig) Validate ¶
func (g *GenesisConfig) Validate() error
type GnolandStartOpts ¶
type GnolandStartOpts struct {
// TeeNodeLogs copies node stdout/stderr to os.Stderr in addition to
// the per-node log files.
TeeNodeLogs bool
// contains filtered or unexported fields
}
GnolandStartOpts tunes how a node is started: what its argv carries and where its stdout/stderr are tee'd beyond the per-node log files.
type Node ¶
type Node struct {
Index int
NodeID string
DataDir string
P2PPort int
RPCAddr string
Genesis string
Process *os.Process
// contains filtered or unexported fields
}
Node represents a gnoland node instance
func SetupValidatorNode ¶
SetupValidatorNode creates and initializes a validator node under tempDir.
func (*Node) Cleanup ¶
func (n *Node) Cleanup()
Cleanup closes the node's log files. Idempotent, and safe on a node that was never started.
func (*Node) Exited ¶
func (n *Node) Exited() <-chan struct{}
Exited returns a channel closed once the node's process has exited and been reaped, starting the reaper on first call. Safe to call from several goroutines and more than once; every caller observes the same wait.
Callers need this rather than os.Process.Wait because that may only be called once, and because a child that has exited without being reaped is a zombie whose PID still answers signals -- so the usual liveness probes report a dead node as alive.
A node with no process is treated as already gone: nothing will start it, so a caller waiting on it would wait forever.
func (*Node) WaitErr ¶
WaitErr reports why the process ended. Only meaningful once the channel from Exited is closed. A process the harness started reports the *exec.ExitError of a non-zero exit, the ones a signal causes included; a node assembled from a bare process reports an error only when the wait itself failed.
type Override ¶
type Override struct{ Key, Value string }
Override is one dotted key a scenario sets on the node config or on the genesis params, kept as text until it is applied to the typed target.
func ConfigDefaults ¶
func ConfigDefaults() []Override
ConfigDefaults lists every "config." key a scenario can set in its "-- cluster --" section, with the value a validator boots with.
func GenesisDefaults ¶
func GenesisDefaults() []Override
GenesisDefaults lists every "genesis." key a scenario can set in its "-- cluster --" section, with the value the chain starts from.