mirror of
https://github.com/luxfi/netrunner.git
synced 2026-07-27 00:04:23 +00:00
- Remove ledger-lux-go transitive dependency - Fix Network ID vs Chain ID confusion in genesis_config.go - Use constants.MainnetID/TestnetID instead of configs.ChainID - Fix port base calculation for multi-network mode - Add snapshot server functionality - Update protobuf definitions with new RPC methods - Add mnemonic test coverage
159 lines
5.7 KiB
Go
159 lines
5.7 KiB
Go
package node
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
|
|
"github.com/luxfi/netrunner/api"
|
|
"github.com/luxfi/netrunner/network/node/status"
|
|
"github.com/luxfi/node/config"
|
|
"github.com/luxfi/ids"
|
|
"github.com/luxfi/node/network/peer"
|
|
)
|
|
|
|
// Node represents an Lux node
|
|
type Node interface {
|
|
// Return this node's name, which is unique
|
|
// across all the nodes in its network.
|
|
GetName() string
|
|
// Return this node's Lux node ID.
|
|
GetNodeID() ids.NodeID
|
|
// Return a client that can be used to make API calls.
|
|
GetAPIClient() api.Client
|
|
// Return this node's host/IP (e.g. 127.0.0.1).
|
|
GetHost() string
|
|
// Return this node's full HTTP API URL (e.g. http://127.0.0.1:9630).
|
|
GetURL() string
|
|
// Return this node's P2P (staking) port.
|
|
GetP2PPort() uint16
|
|
// Return this node's HTTP API port.
|
|
GetAPIPort() uint16
|
|
// Starts a new test peer, connects it to the given node, and returns the peer.
|
|
// [handler] defines how the test peer handles messages it receives.
|
|
// The test peer can be used to send messages to the node it's attached to.
|
|
// It's left to the caller to maintain a reference to the returned peer.
|
|
// The caller should call StartClose() on the peer when they're done with it.
|
|
AttachPeer(ctx context.Context, handler peer.InboundHandler) (peer.Peer, error)
|
|
// Sends a message from the attached peer to the node
|
|
SendOutboundMessage(ctx context.Context, peerID string, content []byte, op uint32) (bool, error)
|
|
// Return the state of the node process
|
|
Status() status.Status
|
|
// Return this node's node binary path
|
|
GetBinaryPath() string
|
|
// Return this node's data dir
|
|
GetDataDir() string
|
|
// Return this node's db dir
|
|
GetDbDir() string
|
|
// Return this node's logs dir
|
|
GetLogsDir() string
|
|
// Return this node's plugin dir
|
|
GetPluginDir() string
|
|
// Return this node's config file contents
|
|
GetConfigFile() string
|
|
// Return this node's config
|
|
GetConfig() Config
|
|
// Return this node's flag value
|
|
GetFlag(string) (string, error)
|
|
// Return this node's paused status
|
|
GetPaused() bool
|
|
}
|
|
|
|
// Config encapsulates an node configuration
|
|
type Config struct {
|
|
// A node's name must be unique from all other nodes
|
|
// in a network. If Name is the empty string, a
|
|
// unique name is assigned on node creation.
|
|
Name string `json:"name"`
|
|
// True if other nodes should use this node
|
|
// as a bootstrap beacon.
|
|
IsBeacon bool `json:"isBeacon"`
|
|
// Must not be nil.
|
|
StakingKey string `json:"stakingKey"`
|
|
// Must not be nil.
|
|
StakingCert string `json:"stakingCert"`
|
|
// Must not be nil.
|
|
StakingSigningKey string `json:"stakingSigningKey"`
|
|
// May be nil.
|
|
ConfigFile string `json:"configFile"`
|
|
// May be nil.
|
|
ChainConfigFiles map[string]string `json:"chainConfigFiles"`
|
|
// May be nil. Genesis files for EVM chains (genesis.json)
|
|
GenesisConfigFiles map[string]string `json:"genesisConfigFiles"`
|
|
// May be nil.
|
|
UpgradeConfigFiles map[string]string `json:"upgradeConfigFiles"`
|
|
// May be nil. P-Chain chain (formerly subnet) config files.
|
|
PChainConfigFiles map[string]string `json:"pChainConfigFiles"`
|
|
// Flags can hold additional flags for the node.
|
|
// It can be empty.
|
|
// The precedence of flags handling is:
|
|
// 1. Flags defined in node.Config (this struct) override
|
|
// 2. Flags defined in network.Config override
|
|
// 3. Flags defined in the json config file
|
|
Flags map[string]interface{} `json:"flags"`
|
|
// What type of node this is
|
|
BinaryPath string `json:"binaryPath"`
|
|
// If non-nil, direct this node's Stdout to os.Stdout
|
|
RedirectStdout bool `json:"redirectStdout"`
|
|
// If non-nil, direct this node's Stderr to os.Stderr
|
|
RedirectStderr bool `json:"redirectStderr"`
|
|
}
|
|
|
|
// Validate returns an error if this config is invalid
|
|
func (c *Config) Validate(expectedNetworkID uint32) error {
|
|
switch {
|
|
case c.StakingKey == "":
|
|
return errors.New("staking key not given")
|
|
case c.StakingCert == "":
|
|
return errors.New("staking cert not given")
|
|
default:
|
|
return validateConfigFile([]byte(c.ConfigFile), expectedNetworkID)
|
|
}
|
|
}
|
|
|
|
// Returns an error if config file [configFile] is invalid.
|
|
// If len([configFile]) == 0, returns nil.
|
|
func validateConfigFile(configFile []byte, expectedNetworkID uint32) error {
|
|
if len(configFile) == 0 {
|
|
// No config file given. Skip.
|
|
return nil
|
|
}
|
|
// Validate that values given in the config file,
|
|
// if any, are the correct type.
|
|
var configMap map[string]interface{}
|
|
if err := json.Unmarshal(configFile, &configMap); err != nil {
|
|
return fmt.Errorf("could not unmarshal config file: %w", err)
|
|
}
|
|
if networkIDIntf, ok := configMap[config.NetworkNameKey]; ok {
|
|
networkID, ok := networkIDIntf.(float64)
|
|
if !ok {
|
|
return fmt.Errorf("wrong type for field %q in config expected float64 got %T", config.NetworkNameKey, networkIDIntf)
|
|
}
|
|
if uint32(networkID) != expectedNetworkID {
|
|
return fmt.Errorf("config file network id %d differs from genesis network id %d", int(networkID), expectedNetworkID)
|
|
}
|
|
}
|
|
if dbPathIntf, ok := configMap[config.DBPathKey]; ok {
|
|
if _, ok := dbPathIntf.(string); !ok {
|
|
return fmt.Errorf("wrong type for field %q in config expected string got %T", config.DBPathKey, dbPathIntf)
|
|
}
|
|
}
|
|
if logsDirIntf, ok := configMap[config.LogsDirKey]; ok {
|
|
if _, ok := logsDirIntf.(string); !ok {
|
|
return fmt.Errorf("wrong type for field %q in config expected string got %T", config.LogsDirKey, logsDirIntf)
|
|
}
|
|
}
|
|
if apiPortIntf, ok := configMap[config.HTTPPortKey]; ok {
|
|
if _, ok := apiPortIntf.(float64); !ok {
|
|
return fmt.Errorf("wrong type for field %q in config expected float64 got %T", config.HTTPPortKey, apiPortIntf)
|
|
}
|
|
}
|
|
if p2pPortIntf, ok := configMap[config.StakingPortKey]; ok {
|
|
if _, ok := p2pPortIntf.(float64); !ok {
|
|
return fmt.Errorf("wrong type for field %q in config expected float64 got %T", config.StakingPortKey, p2pPortIntf)
|
|
}
|
|
}
|
|
return nil
|
|
}
|