2021-10-27 17:42:39 -04:00
|
|
|
package local
|
2021-10-23 00:58:12 -03:00
|
|
|
|
|
|
|
|
import (
|
2022-03-16 14:45:22 -05:00
|
|
|
"context"
|
2022-03-18 09:27:43 -05:00
|
|
|
"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"
|
2022-03-18 09:27:43 -05:00
|
|
|
"time"
|
2021-10-24 09:33:28 -03:00
|
|
|
|
2026-01-03 07:05:17 -08: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"
|
2025-11-28 22:20:44 +00:00
|
|
|
"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"
|
2026-01-03 07:05:17 -08:00
|
|
|
"github.com/luxfi/node/utils/compression"
|
2025-07-17 16:56:43 -05:00
|
|
|
"github.com/luxfi/node/version"
|
2022-03-18 09:27:43 -05:00
|
|
|
"github.com/prometheus/client_golang/prometheus"
|
2021-10-23 00:58:12 -03:00
|
|
|
)
|
|
|
|
|
|
2021-11-04 17:24:40 -04:00
|
|
|
var (
|
2022-03-23 07:51:00 -04:00
|
|
|
_ getConnFunc = defaultGetConnFunc
|
2022-07-12 18:42:42 -03:00
|
|
|
_ node.Node = (*localNode)(nil)
|
2021-10-27 13:29:22 -04:00
|
|
|
)
|
|
|
|
|
|
2022-03-23 07:51:00 -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 {
|
2021-10-27 17:54:15 -04:00
|
|
|
// 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.
|
2021-11-12 14:26:38 -05:00
|
|
|
// 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
|
2021-11-04 17:24:40 -04:00
|
|
|
// The process running this node.
|
|
|
|
|
process NodeProcess
|
2021-11-17 14:14:36 -03:00
|
|
|
// The API port
|
2021-12-01 14:52:31 -05:00
|
|
|
apiPort uint16
|
|
|
|
|
// The P2P (staking) port
|
|
|
|
|
p2pPort uint16
|
2022-03-18 09:19:57 -04:00
|
|
|
// Returns a connection to this node
|
2022-03-23 07:51:00 -04:00
|
|
|
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
|
2023-01-05 17:32:34 -05:00
|
|
|
// The plugin dir of the node
|
|
|
|
|
pluginDir string
|
2022-05-19 16:22:16 -03:00
|
|
|
// The node config
|
|
|
|
|
config node.Config
|
2022-07-13 15:20:44 -03:00
|
|
|
// 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
|
|
|
}
|
|
|
|
|
|
2022-03-18 09:27:43 -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) {
|
2022-03-18 09:27:43 -05:00
|
|
|
tlsCert, err := staking.NewTLSCert()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2022-09-05 10:46:30 -05:00
|
|
|
tlsConfg := peer.TLSConfig(*tlsCert, nil)
|
2025-09-19 05:37:42 +00:00
|
|
|
clientUpgrader := peer.NewTLSClientUpgrader(tlsConfg, metric.NewCounter(metric.CounterOpts{}))
|
2022-03-23 07:51:00 -04:00
|
|
|
conn, err := node.getConnFunc(ctx, node)
|
2022-03-18 09:27:43 -05:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
mc, err := message.NewCreator(
|
2025-11-28 22:20:44 +00:00
|
|
|
prometheus.NewRegistry(),
|
2025-12-29 10:07:43 -08:00
|
|
|
compression.TypeZstd,
|
2022-03-18 09:27:43 -05:00
|
|
|
10*time.Second,
|
|
|
|
|
)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
metrics, err := peer.NewMetrics(
|
|
|
|
|
prometheus.NewRegistry(),
|
|
|
|
|
)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2025-11-28 22:20:44 +00:00
|
|
|
// 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
|
2025-08-01 18:32:54 +00:00
|
|
|
blsKey, err := bls.NewSecretKey()
|
2025-07-18 12:31:39 -05:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2022-03-18 09:27:43 -05:00
|
|
|
config := &peer.Config{
|
2022-12-07 19:20:00 -03:00
|
|
|
Metrics: metrics,
|
|
|
|
|
MessageCreator: mc,
|
2025-12-22 12:38:25 -08:00
|
|
|
Log: log.NewNoOpLogger(),
|
2022-12-07 19:20:00 -03:00
|
|
|
InboundMsgThrottler: throttling.NewNoInboundThrottler(),
|
|
|
|
|
Network: peer.TestNetwork,
|
2022-03-18 09:27:43 -05:00
|
|
|
Router: router,
|
2025-11-28 22:20:44 +00:00
|
|
|
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,
|
2022-03-18 09:27:43 -05:00
|
|
|
PingFrequency: constants.DefaultPingFrequency,
|
|
|
|
|
PongTimeout: constants.DefaultPingPongTimeout,
|
|
|
|
|
MaxClockDifference: time.Minute,
|
2022-05-27 15:19:35 -03:00
|
|
|
ResourceTracker: resourceTracker,
|
2025-08-01 18:32:54 +00:00
|
|
|
IPSigner: peer.NewIPSigner(signerIP, tls, blsKey),
|
2022-03-18 09:27:43 -05:00
|
|
|
}
|
2022-04-18 09:23:44 -04:00
|
|
|
_, conn, cert, err := clientUpgrader.Upgrade(conn)
|
2022-03-18 09:27:43 -05:00
|
|
|
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,
|
2025-12-22 12:38:25 -08:00
|
|
|
log.NewNoOpLogger(),
|
2022-05-27 20:57:19 -03:00
|
|
|
peerMsgQueueBufferSize,
|
2022-05-27 15:07:04 -03:00
|
|
|
),
|
2025-11-28 22:20:44 +00:00
|
|
|
false, // isIngress - this is an outbound connection
|
2022-03-18 09:27:43 -05:00
|
|
|
)
|
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()
|
2022-03-18 09:27:43 -05:00
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-19 12:24:50 -05:00
|
|
|
node.attachedPeers[p.ID().String()] = p
|
2022-03-18 09:27:43 -05:00
|
|
|
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)
|
|
|
|
|
}
|
2022-11-04 18:19:38 -04:00
|
|
|
msg := NewTestMsg(message.Op(op), content, false)
|
2022-07-19 12:24:50 -05:00
|
|
|
return attachedPeer.Send(ctx, msg), nil
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-01 14:52:31 -05:00
|
|
|
// See node.Node
|
2021-10-27 17:54:15 -04:00
|
|
|
func (node *localNode) GetName() string {
|
|
|
|
|
return node.name
|
2021-10-23 01:10:59 -03:00
|
|
|
}
|
|
|
|
|
|
2021-12-01 14:52:31 -05: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
|
|
|
}
|
|
|
|
|
|
2021-12-01 14:52:31 -05: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-10-23 00:58:12 -03:00
|
|
|
}
|
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).
|
2021-12-01 14:52:31 -05:00
|
|
|
// See node.Node
|
2025-12-22 05:07:52 -08:00
|
|
|
func (node *localNode) GetHost() string {
|
2022-07-13 15:20:44 -03:00
|
|
|
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)
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-01 14:52:31 -05:00
|
|
|
// 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
|
|
|
|
2022-07-12 18:42:42 -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
|
2023-01-05 17:32:34 -05:00
|
|
|
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
|
|
|
}
|
2022-06-11 16:21:53 -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
|
|
|
|
|
}
|