Files
netrunner/local/node.go
T

294 lines
7.3 KiB
Go
Raw Normal View History

2021-10-27 17:42:39 -04:00
package local
import (
2022-03-16 14:45:22 -05:00
"context"
"crypto"
2022-08-01 16:00:08 -03:00
"encoding/json"
2022-03-16 14:45:22 -05:00
"fmt"
"net"
2025-07-18 12:31:39 -05:00
"net/netip"
"time"
2021-10-24 09:33:28 -03:00
validators "github.com/luxfi/consensus/validator" // package name is validators
constants "github.com/luxfi/const"
"github.com/luxfi/crypto/bls"
"github.com/luxfi/ids"
"github.com/luxfi/log"
"github.com/luxfi/math/set"
"github.com/luxfi/metric"
2025-07-17 16:56:43 -05:00
"github.com/luxfi/netrunner/api"
"github.com/luxfi/netrunner/network/node"
"github.com/luxfi/netrunner/network/node/status"
"github.com/luxfi/node/message"
"github.com/luxfi/node/network/peer"
"github.com/luxfi/node/network/throttling"
"github.com/luxfi/node/network/tracker"
2025-07-17 16:56:43 -05:00
"github.com/luxfi/node/staking"
2025-07-18 12:31:39 -05:00
"github.com/luxfi/node/utils"
"github.com/luxfi/node/utils/compression"
2025-07-17 16:56:43 -05:00
"github.com/luxfi/node/version"
"github.com/prometheus/client_golang/prometheus"
)
var (
_ getConnFunc = defaultGetConnFunc
_ node.Node = (*localNode)(nil)
2021-10-27 13:29:22 -04:00
)
type getConnFunc func(context.Context, node.Node) (net.Conn, error)
2022-05-27 20:57:19 -03:00
const (
peerMsgQueueBufferSize = 1024
peerResourceTrackerDuration = 10 * time.Second
2022-08-01 16:52:46 -05:00
peerStartWaitTimeout = 30 * time.Second
2022-05-27 20:57:19 -03:00
)
2024-01-02 20:55:14 +01:00
// Gives access to basic node info, and to most node apis
2021-10-27 11:50:46 -04:00
type localNode struct {
// Must be unique across all nodes in this network.
name string
2024-01-02 20:55:14 +01:00
// [nodeID] is this node's Lux Node ID.
// Set in network.AddNode
2022-05-27 15:07:04 -03:00
nodeID ids.NodeID
2022-03-23 06:47:58 -04:00
// The ID of the network this node exists in
networkID uint32
2021-10-27 09:42:19 -04:00
// Allows user to make API calls to this node.
2021-10-27 11:50:46 -04:00
client api.Client
// The process running this node.
process NodeProcess
2021-11-17 14:14:36 -03:00
// The API port
apiPort uint16
// The P2P (staking) port
p2pPort uint16
2022-03-18 09:19:57 -04:00
// Returns a connection to this node
getConnFunc getConnFunc
2023-02-10 11:59:49 -03:00
// The data dir of the node
dataDir string
2022-05-18 22:40:23 -03:00
// The db dir of the node
dbDir string
// The logs dir of the node
logsDir string
// The plugin dir of the node
pluginDir string
2022-05-19 16:22:16 -03:00
// The node config
config node.Config
// The node httpHost
httpHost string
2022-07-19 12:24:50 -05:00
// maps from peer ID to peer object
attachedPeers map[string]peer.Peer
2023-02-10 11:59:49 -03:00
// signals that the process is stopped but the information is valid
// and can be resumed
paused bool
2022-03-16 14:45:22 -05:00
}
func defaultGetConnFunc(ctx context.Context, node node.Node) (net.Conn, error) {
dialer := net.Dialer{}
2025-12-22 05:07:52 -08:00
return dialer.DialContext(ctx, constants.NetworkType, net.JoinHostPort(node.GetHost(), fmt.Sprintf("%d", node.GetP2PPort())))
2022-03-16 14:45:22 -05:00
}
// AttachPeer: see Network
2025-12-23 10:32:48 -08:00
func (node *localNode) AttachPeer(ctx context.Context, router peer.InboundHandler) (peer.Peer, error) {
tlsCert, err := staking.NewTLSCert()
if err != nil {
return nil, err
}
2022-09-05 10:46:30 -05:00
tlsConfg := peer.TLSConfig(*tlsCert, nil)
clientUpgrader := peer.NewTLSClientUpgrader(tlsConfg, metric.NewCounter(metric.CounterOpts{}))
conn, err := node.getConnFunc(ctx, node)
if err != nil {
return nil, err
}
mc, err := message.NewCreator(
prometheus.NewRegistry(),
compression.TypeZstd,
10*time.Second,
)
if err != nil {
return nil, err
}
metrics, err := peer.NewMetrics(
prometheus.NewRegistry(),
)
if err != nil {
return nil, err
}
// Use a nil resource tracker for now - this is acceptable for netrunner testing
var resourceTracker tracker.ResourceTracker = nil
2025-07-18 12:31:39 -05:00
signerIP := utils.NewAtomic(netip.AddrPortFrom(netip.IPv6Unspecified(), 0))
2022-12-07 19:20:00 -03:00
tls := tlsCert.PrivateKey.(crypto.Signer)
2025-07-18 12:31:39 -05:00
// Create a dummy BLS signer for now
blsKey, err := bls.NewSecretKey()
2025-07-18 12:31:39 -05:00
if err != nil {
return nil, err
}
config := &peer.Config{
2022-12-07 19:20:00 -03:00
Metrics: metrics,
MessageCreator: mc,
Log: log.NewNoOpLogger(),
2022-12-07 19:20:00 -03:00
InboundMsgThrottler: throttling.NewNoInboundThrottler(),
Network: peer.TestNetwork,
Router: router,
VersionCompatibility: version.GetCompatibility(time.Now()),
2025-12-21 11:12:41 -08:00
MyChains: set.Set[ids.ID]{},
2025-07-18 12:31:39 -05:00
Beacons: validators.NewManager(),
Validators: validators.NewManager(),
2022-03-23 06:47:58 -04:00
NetworkID: node.networkID,
PingFrequency: constants.DefaultPingFrequency,
PongTimeout: constants.DefaultPingPongTimeout,
MaxClockDifference: time.Minute,
2022-05-27 15:19:35 -03:00
ResourceTracker: resourceTracker,
IPSigner: peer.NewIPSigner(signerIP, tls, blsKey),
}
_, conn, cert, err := clientUpgrader.Upgrade(conn)
if err != nil {
return nil, err
}
p := peer.Start(
config,
conn,
cert,
2025-08-06 04:56:44 +00:00
ids.NodeIDFromCert(&ids.Certificate{
Raw: cert.Raw,
PublicKey: cert.PublicKey,
}),
2022-05-27 20:57:19 -03:00
peer.NewBlockingMessageQueue(
2022-05-27 15:07:04 -03:00
config.Metrics,
log.NewNoOpLogger(),
2022-05-27 20:57:19 -03:00
peerMsgQueueBufferSize,
2022-05-27 15:07:04 -03:00
),
false, // isIngress - this is an outbound connection
)
2022-08-01 16:52:46 -05:00
cctx, cancel := context.WithTimeout(ctx, peerStartWaitTimeout)
2022-07-19 12:24:50 -05:00
err = p.AwaitReady(cctx)
cancel()
if err != nil {
return nil, err
}
2022-07-19 12:24:50 -05:00
node.attachedPeers[p.ID().String()] = p
return p, nil
}
2022-07-19 12:24:50 -05:00
func (node *localNode) SendOutboundMessage(ctx context.Context, peerID string, content []byte, op uint32) (bool, error) {
attachedPeer, ok := node.attachedPeers[peerID]
if !ok {
return false, fmt.Errorf("peer with ID %s is not attached here", peerID)
}
msg := NewTestMsg(message.Op(op), content, false)
2022-07-19 12:24:50 -05:00
return attachedPeer.Send(ctx, msg), nil
}
// See node.Node
func (node *localNode) GetName() string {
return node.name
2021-10-23 01:10:59 -03:00
}
// See node.Node
2022-05-27 15:07:04 -03:00
func (node *localNode) GetNodeID() ids.NodeID {
2021-11-04 08:01:44 -03:00
return node.nodeID
2021-10-24 09:33:28 -03:00
}
// See node.Node
2021-10-27 11:50:46 -04:00
func (node *localNode) GetAPIClient() api.Client {
2021-10-23 01:05:04 -03:00
return node.client
}
2021-11-17 14:14:36 -03:00
2025-12-22 05:07:52 -08:00
// GetHost returns the node's host/IP (e.g. 127.0.0.1).
// See node.Node
2025-12-22 05:07:52 -08:00
func (node *localNode) GetHost() string {
if node.httpHost == "0.0.0.0" || node.httpHost == "." {
return "0.0.0.0"
}
2022-03-16 14:45:22 -05:00
return "127.0.0.1"
2021-11-17 14:14:36 -03:00
}
2025-12-22 05:07:52 -08:00
// GetURL returns the full HTTP API URL (e.g. http://127.0.0.1:9630).
// See node.Node
func (node *localNode) GetURL() string {
return fmt.Sprintf("http://%s:%d", node.GetHost(), node.apiPort)
}
// See node.Node
func (node *localNode) GetP2PPort() uint16 {
return node.p2pPort
}
// See node.Node
func (node *localNode) GetAPIPort() uint16 {
return node.apiPort
2021-11-17 14:14:36 -03:00
}
2022-05-18 21:45:32 -03:00
func (node *localNode) Status() status.Status {
return node.process.Status()
}
2022-05-18 22:40:23 -03:00
// See node.Node
2022-05-18 21:45:32 -03:00
func (node *localNode) GetBinaryPath() string {
2022-05-19 16:22:16 -03:00
return node.config.BinaryPath
2022-05-18 21:45:32 -03:00
}
2022-06-16 00:52:00 -03:00
// See node.Node
func (node *localNode) GetPluginDir() string {
return node.pluginDir
2022-06-16 00:52:00 -03:00
}
2023-02-10 11:59:49 -03:00
// See node.Node
func (node *localNode) GetDataDir() string {
return node.dataDir
}
2022-05-18 22:40:23 -03:00
// See node.Node
2022-12-19 14:53:41 -05:00
// TODO rename method so linter doesn't complain.
func (node *localNode) GetDbDir() string { //nolint
2022-05-18 21:45:32 -03:00
return node.dbDir
}
2022-05-18 22:40:23 -03:00
// See node.Node
2022-05-18 21:45:32 -03:00
func (node *localNode) GetLogsDir() string {
return node.logsDir
}
2022-05-18 22:36:48 -03:00
2022-05-18 22:40:23 -03:00
// See node.Node
2022-05-18 22:36:48 -03:00
func (node *localNode) GetConfigFile() string {
2022-05-19 16:22:16 -03:00
return node.config.ConfigFile
2022-05-18 22:36:48 -03:00
}
// See node.Node
func (node *localNode) GetConfig() node.Config {
return node.config
}
2022-08-01 16:00:08 -03:00
// See node.Node
func (node *localNode) GetFlag(k string) (string, error) {
var v string
if node.config.ConfigFile != "" {
var configFileMap map[string]interface{}
if err := json.Unmarshal([]byte(node.config.ConfigFile), &configFileMap); err != nil {
return "", err
}
vIntf, ok := configFileMap[k]
if ok {
v, ok = vIntf.(string)
if !ok {
return "", fmt.Errorf("unexpected type for %q expected string got %T", k, vIntf)
}
}
} else if node.config.Flags != nil {
vIntf, ok := node.config.Flags[k]
if ok {
v, ok = vIntf.(string)
if !ok {
return "", fmt.Errorf("unexpected type for %q expected string got %T", k, vIntf)
}
}
}
return v, nil
}
2023-02-10 17:28:45 -03:00
// See node.Node
func (node *localNode) GetPaused() bool {
return node.paused
}