mirror of
https://github.com/luxfi/netrunner.git
synced 2026-07-27 00:04:23 +00:00
chore: remove local replace directives and update dependencies
- Update github.com/luxfi/keys v1.0.5 → v1.0.6 - Update github.com/luxfi/genesis v1.5.18 → v1.5.19 - Remove local replace directives for keys and genesis - Use published package versions for reproducible builds
This commit is contained in:
+38
-101
@@ -1,113 +1,50 @@
|
||||
# https://golangci-lint.run/usage/configuration/
|
||||
# golangci-lint v2 configuration
|
||||
version: "2"
|
||||
|
||||
run:
|
||||
timeout: 10m
|
||||
# skip auto-generated files.
|
||||
skip-files:
|
||||
- ".*\\.pb\\.go$"
|
||||
- ".*mock.*"
|
||||
|
||||
issues:
|
||||
# Maximum count of issues with the same text. Set to 0 to disable. Default is 3.
|
||||
max-same-issues: 0
|
||||
formatters:
|
||||
enable:
|
||||
- gofmt
|
||||
- goimports
|
||||
|
||||
linters:
|
||||
# please, do not use `enable-all`: it's deprecated and will be removed soon.
|
||||
# inverted configuration with `enable-all` and `disable` is not scalable during updates of golangci-lint
|
||||
disable-all: true
|
||||
default: none
|
||||
enable:
|
||||
- asciicheck
|
||||
- depguard
|
||||
- errcheck
|
||||
- errorlint
|
||||
- exportloopref
|
||||
- goconst
|
||||
- gocritic
|
||||
- gofmt
|
||||
- gofumpt
|
||||
- goimports
|
||||
- revive
|
||||
- gosec
|
||||
- gosimple
|
||||
- govet
|
||||
- ineffassign
|
||||
- misspell
|
||||
- nakedret
|
||||
- nolintlint
|
||||
- prealloc
|
||||
- stylecheck
|
||||
- unconvert
|
||||
- unparam
|
||||
- unused
|
||||
- unconvert
|
||||
- whitespace
|
||||
- staticcheck
|
||||
# - bodyclose
|
||||
# - structcheck
|
||||
# - lll
|
||||
# - gomnd
|
||||
# - goprintffuncname
|
||||
# - interfacer
|
||||
# - typecheck
|
||||
# - goerr113
|
||||
# - noctx
|
||||
- misspell
|
||||
|
||||
linters-settings:
|
||||
errorlint:
|
||||
# Check for plain type assertions and type switches.
|
||||
asserts: false
|
||||
# Check for plain error comparisons.
|
||||
comparison: false
|
||||
revive:
|
||||
settings:
|
||||
staticcheck:
|
||||
checks:
|
||||
- "all"
|
||||
- "-SA6002"
|
||||
- "-SA1019"
|
||||
- "-ST1000"
|
||||
- "-ST1021"
|
||||
- "-QF1008"
|
||||
|
||||
exclusions:
|
||||
generated: lax
|
||||
presets:
|
||||
- comments
|
||||
rules:
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#bool-literal-in-expr
|
||||
- name: bool-literal-in-expr
|
||||
disabled: false
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#early-return
|
||||
- name: early-return
|
||||
disabled: false
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#empty-lines
|
||||
- name: empty-lines
|
||||
disabled: false
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#struct-tag
|
||||
- name: struct-tag
|
||||
disabled: false
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#unexported-naming
|
||||
- name: unexported-naming
|
||||
disabled: false
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#unhandled-error
|
||||
- name: unhandled-error
|
||||
disabled: false
|
||||
arguments:
|
||||
- "fmt.Fprint"
|
||||
- "fmt.Fprintf"
|
||||
- "fmt.Print"
|
||||
- "fmt.Printf"
|
||||
- "fmt.Println"
|
||||
- "rand.Read"
|
||||
- "sb.WriteString"
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#unused-parameter
|
||||
- name: unused-parameter
|
||||
disabled: false
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#unused-receiver
|
||||
- name: unused-receiver
|
||||
disabled: false
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#useless-break
|
||||
- name: useless-break
|
||||
disabled: false
|
||||
staticcheck:
|
||||
go: "1.19"
|
||||
# https://staticcheck.io/docs/options#checks
|
||||
checks:
|
||||
- "all"
|
||||
- "-SA6002" # argument should be pointer-like to avoid allocation, for sync.Pool
|
||||
- "-SA1019" # deprecated packages e.g., golang.org/x/crypto/ripemd160
|
||||
# https://golangci-lint.run/usage/linters#gosec
|
||||
gosec:
|
||||
excludes:
|
||||
- G107 # https://securego.io/docs/rules/g107.html
|
||||
depguard:
|
||||
list-type: blacklist
|
||||
packages-with-error-message:
|
||||
- io/ioutil: 'io/ioutil is deprecated. Use package io or os instead.'
|
||||
- github.com/stretchr/testify/assert: 'github.com/stretchr/testify/require should be used instead.'
|
||||
include-go-root: true
|
||||
- path: ".*\\.pb\\.go$"
|
||||
linters:
|
||||
- all
|
||||
- path: ".*mock.*"
|
||||
linters:
|
||||
- all
|
||||
- path: _test\.go
|
||||
linters:
|
||||
- errcheck
|
||||
- linters:
|
||||
- errcheck
|
||||
text: "Error return value of .*(Close|Flush|Fprintln|Fprintf|Print|Printf|Println|Write|Signal|Kill|RemoveAll|Sync|Sscanf|MarkFlagRequired).*is not checked"
|
||||
|
||||
issues:
|
||||
max-same-issues: 0
|
||||
|
||||
+1
-1
@@ -68,7 +68,7 @@ type Client interface {
|
||||
PChainAPI() *platformvm.Client
|
||||
XChainAPI() *exchangevm.Client
|
||||
XChainWalletAPI() *exchangevm.WalletClient
|
||||
CChainAPI() interface{} // evmclient.Client
|
||||
CChainAPI() interface{} // evmclient.Client
|
||||
CChainEthAPI() EthClient // ethclient websocket wrapper that adds mutexed calls, and lazy conn init (on first call)
|
||||
InfoAPI() *info.Client
|
||||
HealthAPI() HealthClient
|
||||
|
||||
@@ -131,4 +131,4 @@ func (c *ethClientStub) SuggestGasTipCap(ctx context.Context) (*big.Int, error)
|
||||
// TransactionReceipt stub implementation
|
||||
func (c *ethClientStub) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) {
|
||||
return nil, fmt.Errorf("TransactionReceipt not implemented in stub")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,7 +87,6 @@ func (_m *EthClient) AcceptedNonceAt(_a0 context.Context, _a1 common.Address) (u
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
|
||||
// BalanceAt provides a mock function with given fields: _a0, _a1, _a2
|
||||
func (_m *EthClient) BalanceAt(_a0 context.Context, _a1 common.Address, _a2 *big.Int) (*big.Int, error) {
|
||||
ret := _m.Called(_a0, _a1, _a2)
|
||||
|
||||
+1
-1
@@ -178,4 +178,4 @@ func (_m *Client) XChainWalletAPI() *exchangevm.WalletClient {
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
}
|
||||
|
||||
+21
-21
@@ -12,9 +12,9 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/luxfi/log"
|
||||
"github.com/luxfi/netrunner/local"
|
||||
"github.com/luxfi/netrunner/rpcpb"
|
||||
"github.com/luxfi/log"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
@@ -59,7 +59,7 @@ type Client interface {
|
||||
}
|
||||
|
||||
type client struct {
|
||||
cfg Config
|
||||
cfg Config
|
||||
logger log.Logger
|
||||
|
||||
conn *grpc.ClientConn
|
||||
@@ -88,7 +88,7 @@ func New(cfg Config, logger log.Logger) (Client, error) {
|
||||
|
||||
return &client{
|
||||
cfg: cfg,
|
||||
logger: logger,
|
||||
logger: logger,
|
||||
conn: conn,
|
||||
pingc: rpcpb.NewPingServiceClient(conn),
|
||||
controlc: rpcpb.NewControlServiceClient(conn),
|
||||
@@ -114,11 +114,11 @@ func (c *client) Start(ctx context.Context, execPath string, opts ...OpOption) (
|
||||
ret.applyOpts(opts)
|
||||
|
||||
req := &rpcpb.StartRequest{
|
||||
ExecPath: execPath,
|
||||
NumNodes: &ret.numNodes,
|
||||
ChainConfigs: ret.chainConfigs,
|
||||
UpgradeConfigs: ret.upgradeConfigs,
|
||||
ChainConfigFiles: ret.chainConfigs,
|
||||
ExecPath: execPath,
|
||||
NumNodes: &ret.numNodes,
|
||||
ChainConfigs: ret.chainConfigs,
|
||||
UpgradeConfigs: ret.upgradeConfigs,
|
||||
ChainConfigFiles: ret.chainConfigs,
|
||||
}
|
||||
if ret.trackChains != "" {
|
||||
req.WhitelistedChains = &ret.trackChains
|
||||
@@ -271,12 +271,12 @@ func (c *client) AddNode(ctx context.Context, name string, execPath string, opts
|
||||
ret.applyOpts(opts)
|
||||
|
||||
req := &rpcpb.AddNodeRequest{
|
||||
Name: name,
|
||||
ExecPath: execPath,
|
||||
NodeConfig: &ret.globalNodeConfig,
|
||||
ChainConfigs: ret.chainConfigs,
|
||||
UpgradeConfigs: ret.upgradeConfigs,
|
||||
ChainConfigFiles: ret.chainConfigs,
|
||||
Name: name,
|
||||
ExecPath: execPath,
|
||||
NodeConfig: &ret.globalNodeConfig,
|
||||
ChainConfigs: ret.chainConfigs,
|
||||
UpgradeConfigs: ret.upgradeConfigs,
|
||||
ChainConfigFiles: ret.chainConfigs,
|
||||
}
|
||||
|
||||
if ret.pluginDir != "" {
|
||||
@@ -354,10 +354,10 @@ func (c *client) LoadSnapshot(ctx context.Context, snapshotName string, opts ...
|
||||
ret := &Op{}
|
||||
ret.applyOpts(opts)
|
||||
req := rpcpb.LoadSnapshotRequest{
|
||||
SnapshotName: snapshotName,
|
||||
ChainConfigs: ret.chainConfigs,
|
||||
UpgradeConfigs: ret.upgradeConfigs,
|
||||
ChainConfigFiles: ret.chainConfigs,
|
||||
SnapshotName: snapshotName,
|
||||
ChainConfigs: ret.chainConfigs,
|
||||
UpgradeConfigs: ret.upgradeConfigs,
|
||||
ChainConfigFiles: ret.chainConfigs,
|
||||
}
|
||||
if ret.execPath != "" {
|
||||
req.ExecPath = &ret.execPath
|
||||
@@ -399,13 +399,13 @@ func (c *client) Close() error {
|
||||
type Op struct {
|
||||
numNodes uint32
|
||||
execPath string
|
||||
trackChains string
|
||||
trackChains string
|
||||
globalNodeConfig string
|
||||
rootDataDir string
|
||||
pluginDir string
|
||||
chainSpecs []*rpcpb.BlockchainSpec
|
||||
chainSpecs []*rpcpb.BlockchainSpec
|
||||
customNodeConfigs map[string]string
|
||||
numChains uint32
|
||||
numChains uint32
|
||||
chainConfigs map[string]string
|
||||
upgradeConfigs map[string]string
|
||||
pChainConfigs map[string]string
|
||||
|
||||
@@ -40,7 +40,7 @@ func main() {
|
||||
return nil
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
if err != nil {
|
||||
fmt.Printf("Error: %v\n", err)
|
||||
} else {
|
||||
@@ -54,7 +54,7 @@ func main() {
|
||||
opts.PrefetchValues = false
|
||||
it := txn.NewIterator(opts)
|
||||
defer it.Close()
|
||||
|
||||
|
||||
prefix := []byte("n")
|
||||
for it.Seek(prefix); it.ValidForPrefix(prefix); it.Next() {
|
||||
key := it.Item().Key()
|
||||
|
||||
@@ -14,14 +14,14 @@ import (
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/luxfi/log"
|
||||
"github.com/luxfi/log/level"
|
||||
"github.com/luxfi/netrunner/client"
|
||||
"github.com/luxfi/netrunner/local"
|
||||
"github.com/luxfi/netrunner/rpcpb"
|
||||
"github.com/luxfi/netrunner/utils"
|
||||
"github.com/luxfi/netrunner/utils/constants"
|
||||
"github.com/luxfi/netrunner/ux"
|
||||
"github.com/luxfi/log"
|
||||
"github.com/luxfi/log/level"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@@ -34,11 +34,11 @@ const clientRootDirPrefix = "client"
|
||||
var (
|
||||
logLevel string
|
||||
logDir string
|
||||
trackChains string
|
||||
trackChains string
|
||||
endpoint string
|
||||
dialTimeout time.Duration
|
||||
requestTimeout time.Duration
|
||||
logger log.Logger
|
||||
logger log.Logger
|
||||
)
|
||||
|
||||
// NOTE: Naming convention for node names is currently `node` + number, i.e. `node1,node2,node3,...node101`
|
||||
@@ -86,12 +86,12 @@ func NewCommand() *cobra.Command {
|
||||
}
|
||||
|
||||
var (
|
||||
luxdBinPath string
|
||||
luxdBinPath string
|
||||
numNodes uint32
|
||||
pluginDir string
|
||||
globalNodeConfig string
|
||||
addNodeConfig string
|
||||
chainSpecsStr string
|
||||
chainSpecsStr string
|
||||
customNodeConfigs string
|
||||
rootDataDir string
|
||||
chainConfigs string
|
||||
|
||||
+9
-3
@@ -51,14 +51,14 @@ func main() {
|
||||
|
||||
for i, vk := range validators {
|
||||
name := fmt.Sprintf("node%d", i)
|
||||
|
||||
|
||||
fmt.Printf("--- Validator %d (%s) ---\n", i, name)
|
||||
fmt.Printf(" NodeID: %s\n", vk.NodeID.String())
|
||||
fmt.Printf(" P-Chain Addr: %s\n", vk.PChainAddr.String())
|
||||
fmt.Printf(" C-Chain Addr: %s\n", vk.CChainAddrHex())
|
||||
fmt.Printf(" BLS PubKey: %s\n", vk.BLSPublicKeyHex())
|
||||
fmt.Printf(" BLS PoP: %s\n", vk.BLSPoPHex())
|
||||
|
||||
|
||||
// Save to disk
|
||||
if err := ks.Save(name, vk); err != nil {
|
||||
fmt.Printf(" ERROR saving: %v\n", err)
|
||||
@@ -117,6 +117,12 @@ func main() {
|
||||
"proofOfPossession": "%s"
|
||||
}
|
||||
}%s
|
||||
`, vk.NodeID.String(), vk.BLSPublicKeyHex(), vk.BLSPoPHex(), func() string { if i < 4 { return "," } else { return "" } }())
|
||||
`, vk.NodeID.String(), vk.BLSPublicKeyHex(), vk.BLSPoPHex(), func() string {
|
||||
if i < 4 {
|
||||
return ","
|
||||
} else {
|
||||
return ""
|
||||
}
|
||||
}())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,9 +4,10 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"github.com/luxfi/log"
|
||||
"fmt"
|
||||
|
||||
"github.com/luxfi/log"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@@ -16,13 +17,13 @@ func NewBridgeCmd(logger log.Logger) *cobra.Command {
|
||||
Use: "bridge",
|
||||
Short: "Manage cross-chain bridges",
|
||||
}
|
||||
|
||||
|
||||
cmd.AddCommand(
|
||||
newBridgeCreateCmd(logger),
|
||||
newBridgeStatusCmd(logger),
|
||||
newBridgeStopCmd(logger),
|
||||
)
|
||||
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
@@ -32,16 +33,16 @@ func newBridgeCreateCmd(logger log.Logger) *cobra.Command {
|
||||
source string
|
||||
dest string
|
||||
)
|
||||
|
||||
|
||||
return &cobra.Command{
|
||||
Use: "create",
|
||||
Short: "Create a bridge between two chains",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
fmt.Printf("🌉 Creating %s bridge from %s to %s...\n", bridgeType, source, dest)
|
||||
|
||||
|
||||
// TODO: Implement bridge creation
|
||||
fmt.Println("(Bridge creation not yet implemented)")
|
||||
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
@@ -54,12 +55,12 @@ func newBridgeStatusCmd(logger log.Logger) *cobra.Command {
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
bridgeID := args[0]
|
||||
|
||||
|
||||
fmt.Printf("📊 Status of bridge '%s':\n", bridgeID)
|
||||
|
||||
|
||||
// TODO: Implement bridge status
|
||||
fmt.Println("(Bridge status not yet implemented)")
|
||||
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
@@ -72,13 +73,13 @@ func newBridgeStopCmd(logger log.Logger) *cobra.Command {
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
bridgeID := args[0]
|
||||
|
||||
|
||||
fmt.Printf("⏹ Stopping bridge '%s'...\n", bridgeID)
|
||||
|
||||
|
||||
// TODO: Implement bridge stopping
|
||||
fmt.Println("(Bridge stopping not yet implemented)")
|
||||
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"github.com/luxfi/log"
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
@@ -12,8 +11,9 @@ import (
|
||||
"text/tabwriter"
|
||||
"time"
|
||||
|
||||
"github.com/luxfi/log"
|
||||
|
||||
"github.com/luxfi/netrunner/engines"
|
||||
_ "github.com/luxfi/netrunner/engines/lux"
|
||||
_ "github.com/luxfi/netrunner/engines/geth"
|
||||
_ "github.com/luxfi/netrunner/engines/lux"
|
||||
"github.com/spf13/cobra"
|
||||
@@ -48,11 +48,11 @@ func newEngineStartCmd(logger log.Logger) *cobra.Command {
|
||||
dataDir string
|
||||
binary string
|
||||
logLevel string
|
||||
|
||||
|
||||
// OP Stack specific
|
||||
l1RPC string
|
||||
sequencer bool
|
||||
|
||||
|
||||
// Eth2 specific
|
||||
consensusClient string
|
||||
executionClient string
|
||||
@@ -65,7 +65,7 @@ func newEngineStartCmd(logger log.Logger) *cobra.Command {
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
name := args[0]
|
||||
|
||||
|
||||
// Create engine configuration
|
||||
config := &engines.NodeConfig{
|
||||
NetworkID: networkID,
|
||||
@@ -76,7 +76,7 @@ func newEngineStartCmd(logger log.Logger) *cobra.Command {
|
||||
LogLevel: logLevel,
|
||||
Extra: make(map[string]interface{}),
|
||||
}
|
||||
|
||||
|
||||
// Add engine-specific configuration
|
||||
switch engineType {
|
||||
case "op":
|
||||
@@ -87,39 +87,39 @@ func newEngineStartCmd(logger log.Logger) *cobra.Command {
|
||||
config.Extra["execution_client"] = executionClient
|
||||
config.Extra["validator_enabled"] = validator
|
||||
}
|
||||
|
||||
|
||||
// Create the engine
|
||||
engine, err := createEngine(engineType, name, binary)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create engine: %w", err)
|
||||
}
|
||||
|
||||
|
||||
// Start the engine
|
||||
ctx := cmd.Context()
|
||||
logger.Info("Starting engine",
|
||||
logger.Info("Starting engine",
|
||||
log.String("name", name),
|
||||
log.String("type", engineType),
|
||||
log.Uint32("network_id", networkID))
|
||||
|
||||
|
||||
if err := engine.Start(ctx, config); err != nil {
|
||||
return fmt.Errorf("failed to start engine: %w", err)
|
||||
}
|
||||
|
||||
|
||||
// Wait for engine to be healthy
|
||||
logger.Info("Waiting for engine to be healthy...")
|
||||
ticker := time.NewTicker(2 * time.Second)
|
||||
defer ticker.Stop()
|
||||
|
||||
|
||||
timeout := time.After(2 * time.Minute)
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
health, err := engine.Health(ctx)
|
||||
if err == nil && health.Healthy {
|
||||
logger.Info("Engine is healthy",
|
||||
logger.Info("Engine is healthy",
|
||||
log.String("name", name),
|
||||
log.String("version", health.Version))
|
||||
|
||||
|
||||
fmt.Printf("✅ Engine '%s' started successfully\n", name)
|
||||
fmt.Printf(" Type: %s\n", engineType)
|
||||
fmt.Printf(" RPC: %s\n", engine.RPCEndpoint())
|
||||
@@ -137,7 +137,7 @@ func newEngineStartCmd(logger log.Logger) *cobra.Command {
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
// General flags
|
||||
cmd.Flags().StringVarP(&engineType, "type", "t", "lux", "Engine type (lux, lux, geth, op, eth2)")
|
||||
cmd.Flags().Uint32Var(&networkID, "network-id", 1337, "Network ID")
|
||||
@@ -147,16 +147,16 @@ func newEngineStartCmd(logger log.Logger) *cobra.Command {
|
||||
cmd.Flags().StringVar(&dataDir, "data-dir", "", "Data directory (auto-generated if empty)")
|
||||
cmd.Flags().StringVar(&binary, "binary", "", "Path to engine binary")
|
||||
cmd.Flags().StringVar(&logLevel, "log-level", "info", "Log level")
|
||||
|
||||
|
||||
// OP Stack flags
|
||||
cmd.Flags().StringVar(&l1RPC, "l1-rpc", "", "L1 RPC endpoint (OP Stack only)")
|
||||
cmd.Flags().BoolVar(&sequencer, "sequencer", false, "Enable sequencer mode (OP Stack only)")
|
||||
|
||||
|
||||
// Eth2 flags
|
||||
cmd.Flags().StringVar(&consensusClient, "consensus-client", "lighthouse", "Consensus client (eth2 only)")
|
||||
cmd.Flags().StringVar(&executionClient, "execution-client", "geth", "Execution client (eth2 only)")
|
||||
cmd.Flags().BoolVar(&validator, "validator", false, "Enable validator (eth2 only)")
|
||||
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
@@ -167,10 +167,10 @@ func newEngineStopCmd(logger log.Logger) *cobra.Command {
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
name := args[0]
|
||||
|
||||
|
||||
// TODO: Implement engine registry to track running engines
|
||||
fmt.Printf("⏹ Stopping engine '%s'...\n", name)
|
||||
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
@@ -183,10 +183,10 @@ func newEngineStatusCmd(logger log.Logger) *cobra.Command {
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
name := args[0]
|
||||
|
||||
|
||||
// TODO: Implement engine registry
|
||||
fmt.Printf("📊 Status of engine '%s':\n", name)
|
||||
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
@@ -199,7 +199,7 @@ func newEngineListCmd(logger log.Logger) *cobra.Command {
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
fmt.Println("Available engine types:")
|
||||
fmt.Println()
|
||||
|
||||
|
||||
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
|
||||
fmt.Fprintln(w, "TYPE\tDESCRIPTION\tSTATUS")
|
||||
fmt.Fprintln(w, "----\t-----------\t------")
|
||||
@@ -209,7 +209,7 @@ func newEngineListCmd(logger log.Logger) *cobra.Command {
|
||||
fmt.Fprintln(w, "op\tOP Stack L2\t✅ Ready")
|
||||
fmt.Fprintln(w, "eth2\tEthereum 2.0\t✅ Ready")
|
||||
w.Flush()
|
||||
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
@@ -223,7 +223,7 @@ func newEngineTestCmd(logger log.Logger) *cobra.Command {
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
engineType := args[0]
|
||||
|
||||
|
||||
// Test configuration
|
||||
config := &engines.NodeConfig{
|
||||
NetworkID: 99999,
|
||||
@@ -234,7 +234,7 @@ func newEngineTestCmd(logger log.Logger) *cobra.Command {
|
||||
LogLevel: "debug",
|
||||
Extra: make(map[string]interface{}),
|
||||
}
|
||||
|
||||
|
||||
// Add type-specific test config
|
||||
switch engineType {
|
||||
case "op":
|
||||
@@ -246,24 +246,24 @@ func newEngineTestCmd(logger log.Logger) *cobra.Command {
|
||||
config.Extra["execution_client"] = "geth"
|
||||
config.Extra["network_name"] = "testnet"
|
||||
}
|
||||
|
||||
|
||||
// Create test engine
|
||||
name := fmt.Sprintf("test-%s-%d", engineType, time.Now().Unix())
|
||||
engine, err := createEngine(engineType, name, "")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create engine: %w", err)
|
||||
}
|
||||
|
||||
|
||||
// Start engine
|
||||
ctx := cmd.Context()
|
||||
logger.Info("Starting test engine",
|
||||
logger.Info("Starting test engine",
|
||||
log.String("type", engineType),
|
||||
log.String("name", name))
|
||||
|
||||
|
||||
if err := engine.Start(ctx, config); err != nil {
|
||||
return fmt.Errorf("failed to start engine: %w", err)
|
||||
}
|
||||
|
||||
|
||||
// Defer cleanup
|
||||
defer func() {
|
||||
logger.Info("Cleaning up test engine")
|
||||
@@ -272,11 +272,11 @@ func newEngineTestCmd(logger log.Logger) *cobra.Command {
|
||||
}
|
||||
os.RemoveAll(config.DataDir)
|
||||
}()
|
||||
|
||||
|
||||
// Test health check
|
||||
fmt.Printf("🧪 Testing %s engine...\n", engineType)
|
||||
fmt.Println(" ⏳ Waiting for engine to be healthy...")
|
||||
|
||||
|
||||
// Poll for health
|
||||
maxAttempts := 30
|
||||
for i := 0; i < maxAttempts; i++ {
|
||||
@@ -287,7 +287,7 @@ func newEngineTestCmd(logger log.Logger) *cobra.Command {
|
||||
fmt.Printf(" 🔗 RPC: %s\n", engine.RPCEndpoint())
|
||||
fmt.Printf(" 🌐 WebSocket: %s\n", engine.WSEndpoint())
|
||||
fmt.Printf(" ⏱️ Uptime: %s\n", engine.Uptime())
|
||||
|
||||
|
||||
// Type-specific tests
|
||||
switch engineType {
|
||||
case "lux":
|
||||
@@ -306,14 +306,14 @@ func newEngineTestCmd(logger log.Logger) *cobra.Command {
|
||||
fmt.Printf(" ⚙️ Execution: %s\n", ec)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fmt.Println("\n✅ Test passed!")
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
time.Sleep(2 * time.Second)
|
||||
}
|
||||
|
||||
|
||||
return fmt.Errorf("engine failed to become healthy after %d attempts", maxAttempts)
|
||||
},
|
||||
}
|
||||
@@ -336,7 +336,7 @@ func createEngine(engineType, name, binary string) (engines.Engine, error) {
|
||||
return nil, fmt.Errorf("unknown engine type: %s", engineType)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// For multi-binary engines, validate format
|
||||
if strings.Contains(engineType, "op") || strings.Contains(engineType, "eth2") {
|
||||
parts := strings.Split(binary, ":")
|
||||
@@ -344,7 +344,7 @@ func createEngine(engineType, name, binary string) (engines.Engine, error) {
|
||||
return nil, fmt.Errorf("%s requires two binaries separated by colon (e.g., 'op-node:op-geth')", engineType)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Create engine using factory
|
||||
return engines.New(engines.EngineType(engineType), name, binary)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,9 +4,10 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"github.com/luxfi/log"
|
||||
"fmt"
|
||||
|
||||
"github.com/luxfi/log"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@@ -16,25 +17,25 @@ func NewLogsCmd(logger log.Logger) *cobra.Command {
|
||||
follow bool
|
||||
tail int
|
||||
)
|
||||
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "logs [engine]",
|
||||
Short: "View engine logs",
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
engineName := args[0]
|
||||
|
||||
|
||||
fmt.Printf("📜 Logs for engine '%s':\n", engineName)
|
||||
|
||||
|
||||
// TODO: Implement log streaming
|
||||
fmt.Println("(Log streaming not yet implemented)")
|
||||
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
cmd.Flags().BoolVarP(&follow, "follow", "f", false, "Follow log output")
|
||||
cmd.Flags().IntVar(&tail, "tail", 100, "Number of lines to show")
|
||||
|
||||
|
||||
return cmd
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,13 +4,14 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"github.com/luxfi/log"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"text/tabwriter"
|
||||
"time"
|
||||
|
||||
"github.com/luxfi/log"
|
||||
|
||||
"github.com/luxfi/netrunner/orchestrator"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
@@ -47,38 +48,38 @@ func newStackDeployCmd(logger log.Logger) *cobra.Command {
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
stackName := args[0]
|
||||
|
||||
|
||||
// Load manifest
|
||||
manifest, err := orchestrator.LoadManifest(manifestPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to load manifest: %w", err)
|
||||
}
|
||||
|
||||
|
||||
// Validate manifest
|
||||
if err := manifest.Validate(); err != nil {
|
||||
return fmt.Errorf("invalid manifest: %w", err)
|
||||
}
|
||||
|
||||
|
||||
// Create orchestrator host
|
||||
host := orchestrator.NewHost()
|
||||
|
||||
|
||||
ctx := cmd.Context()
|
||||
logger.Info("Deploying stack",
|
||||
logger.Info("Deploying stack",
|
||||
log.String("name", stackName),
|
||||
log.String("manifest", manifestPath),
|
||||
log.Int("engines", len(manifest.Engines)))
|
||||
|
||||
|
||||
fmt.Printf("🚀 Deploying stack '%s' with %d engines...\n", stackName, len(manifest.Engines))
|
||||
|
||||
|
||||
// Deploy engines in dependency order
|
||||
deployed := make(map[string]bool)
|
||||
remaining := make([]orchestrator.EngineConfig, len(manifest.Engines))
|
||||
copy(remaining, manifest.Engines)
|
||||
|
||||
|
||||
for len(remaining) > 0 {
|
||||
progress := false
|
||||
newRemaining := []orchestrator.EngineConfig{}
|
||||
|
||||
|
||||
for _, engineCfg := range remaining {
|
||||
// Check if dependencies are satisfied
|
||||
ready := true
|
||||
@@ -88,15 +89,15 @@ func newStackDeployCmd(logger log.Logger) *cobra.Command {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if !ready {
|
||||
newRemaining = append(newRemaining, engineCfg)
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
// Deploy this engine
|
||||
fmt.Printf(" ⚙️ Starting %s engine '%s'...\n", engineCfg.Type, engineCfg.Name)
|
||||
|
||||
|
||||
if err := host.StartEngine(ctx, engineCfg.Name, engineCfg.Type, &orchestrator.EngineOptions{
|
||||
NetworkID: engineCfg.NetworkID,
|
||||
HTTPPort: engineCfg.HTTPPort,
|
||||
@@ -109,7 +110,7 @@ func newStackDeployCmd(logger log.Logger) *cobra.Command {
|
||||
}); err != nil {
|
||||
return fmt.Errorf("failed to start engine %s: %w", engineCfg.Name, err)
|
||||
}
|
||||
|
||||
|
||||
// Wait for health if requested
|
||||
if engineCfg.WaitHealthy && wait {
|
||||
fmt.Printf(" ⏳ Waiting for health check...\n")
|
||||
@@ -118,43 +119,43 @@ func newStackDeployCmd(logger log.Logger) *cobra.Command {
|
||||
}
|
||||
fmt.Printf(" ✅ Healthy!\n")
|
||||
}
|
||||
|
||||
|
||||
deployed[engineCfg.Name] = true
|
||||
progress = true
|
||||
}
|
||||
|
||||
|
||||
if !progress && len(newRemaining) > 0 {
|
||||
return fmt.Errorf("circular dependency detected or unsatisfied dependencies")
|
||||
}
|
||||
|
||||
|
||||
remaining = newRemaining
|
||||
}
|
||||
|
||||
|
||||
// Deploy bridge if configured
|
||||
if manifest.Bridge != nil {
|
||||
fmt.Printf(" 🌉 Setting up bridge from %s to %s...\n",
|
||||
fmt.Printf(" 🌉 Setting up bridge from %s to %s...\n",
|
||||
manifest.Bridge.Source, manifest.Bridge.Destination)
|
||||
|
||||
|
||||
if err := host.SetupBridge(ctx, manifest.Bridge); err != nil {
|
||||
return fmt.Errorf("failed to setup bridge: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fmt.Printf("\n✅ Stack '%s' deployed successfully!\n", stackName)
|
||||
|
||||
|
||||
// Print endpoints
|
||||
fmt.Println("\n📊 Engine Endpoints:")
|
||||
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
|
||||
fmt.Fprintln(w, "ENGINE\tTYPE\tRPC\tWEBSOCKET")
|
||||
fmt.Fprintln(w, "------\t----\t---\t---------")
|
||||
|
||||
|
||||
for _, engine := range manifest.Engines {
|
||||
rpc := fmt.Sprintf("http://localhost:%d", engine.HTTPPort)
|
||||
ws := fmt.Sprintf("ws://localhost:%d", engine.WSPort)
|
||||
fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", engine.Name, engine.Type, rpc, ws)
|
||||
}
|
||||
w.Flush()
|
||||
|
||||
|
||||
// Save stack info
|
||||
stackDir := filepath.Join(os.Getenv("HOME"), ".netrunner", "stacks", stackName)
|
||||
if err := os.MkdirAll(stackDir, 0755); err != nil {
|
||||
@@ -165,23 +166,23 @@ func newStackDeployCmd(logger log.Logger) *cobra.Command {
|
||||
if err := manifest.Save(manifestCopy); err != nil {
|
||||
logger.Warn("Failed to save manifest copy", log.Err(err))
|
||||
}
|
||||
|
||||
|
||||
// Save host state
|
||||
stateFile := filepath.Join(stackDir, "state.json")
|
||||
if err := host.SaveState(stateFile); err != nil {
|
||||
logger.Warn("Failed to save host state", log.Err(err))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
cmd.Flags().StringVarP(&manifestPath, "manifest", "f", "", "Path to stack manifest file")
|
||||
cmd.Flags().BoolVarP(&wait, "wait", "w", true, "Wait for engines to be healthy")
|
||||
cmd.Flags().DurationVar(&timeout, "timeout", 5*time.Minute, "Deployment timeout")
|
||||
cmd.MarkFlagRequired("manifest")
|
||||
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
@@ -192,29 +193,29 @@ func newStackDestroyCmd(logger log.Logger) *cobra.Command {
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
stackName := args[0]
|
||||
|
||||
|
||||
// Load stack state
|
||||
stackDir := filepath.Join(os.Getenv("HOME"), ".netrunner", "stacks", stackName)
|
||||
stateFile := filepath.Join(stackDir, "state.json")
|
||||
|
||||
|
||||
host := orchestrator.NewHost()
|
||||
if err := host.LoadState(stateFile); err != nil {
|
||||
return fmt.Errorf("failed to load stack state: %w", err)
|
||||
}
|
||||
|
||||
|
||||
ctx := cmd.Context()
|
||||
fmt.Printf("🛑 Destroying stack '%s'...\n", stackName)
|
||||
|
||||
|
||||
// Stop all engines
|
||||
if err := host.StopAll(ctx); err != nil {
|
||||
return fmt.Errorf("failed to stop engines: %w", err)
|
||||
}
|
||||
|
||||
|
||||
// Clean up stack directory
|
||||
if err := os.RemoveAll(stackDir); err != nil {
|
||||
logger.Warn("Failed to remove stack directory", log.Err(err))
|
||||
}
|
||||
|
||||
|
||||
fmt.Printf("✅ Stack '%s' destroyed\n", stackName)
|
||||
return nil
|
||||
},
|
||||
@@ -228,35 +229,35 @@ func newStackStatusCmd(logger log.Logger) *cobra.Command {
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
stackName := args[0]
|
||||
|
||||
|
||||
// Load stack state
|
||||
stackDir := filepath.Join(os.Getenv("HOME"), ".netrunner", "stacks", stackName)
|
||||
stateFile := filepath.Join(stackDir, "state.json")
|
||||
|
||||
|
||||
host := orchestrator.NewHost()
|
||||
if err := host.LoadState(stateFile); err != nil {
|
||||
return fmt.Errorf("failed to load stack state: %w", err)
|
||||
}
|
||||
|
||||
|
||||
ctx := cmd.Context()
|
||||
fmt.Printf("📊 Status of stack '%s':\n\n", stackName)
|
||||
|
||||
|
||||
// Get status of all engines
|
||||
statuses, err := host.GetAllStatus(ctx)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get status: %w", err)
|
||||
}
|
||||
|
||||
|
||||
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
|
||||
fmt.Fprintln(w, "ENGINE\tTYPE\tSTATUS\tBLOCK HEIGHT\tPEERS\tVERSION")
|
||||
fmt.Fprintln(w, "------\t----\t------\t------------\t-----\t-------")
|
||||
|
||||
|
||||
for name, status := range statuses {
|
||||
health := "❌ Unhealthy"
|
||||
if status.Health.Healthy {
|
||||
health = "✅ Healthy"
|
||||
}
|
||||
|
||||
|
||||
fmt.Fprintf(w, "%s\t%s\t%s\t%d\t%d\t%s\n",
|
||||
name,
|
||||
status.Type,
|
||||
@@ -266,7 +267,7 @@ func newStackStatusCmd(logger log.Logger) *cobra.Command {
|
||||
status.Health.Version)
|
||||
}
|
||||
w.Flush()
|
||||
|
||||
|
||||
// Show metrics
|
||||
fmt.Println("\n📈 Metrics:")
|
||||
metrics := host.GetMetrics()
|
||||
@@ -276,7 +277,7 @@ func newStackStatusCmd(logger log.Logger) *cobra.Command {
|
||||
fmt.Printf(" %s: %v\n", k, v)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
@@ -288,50 +289,50 @@ func newStackListCmd(logger log.Logger) *cobra.Command {
|
||||
Short: "List all deployed stacks",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
stacksDir := filepath.Join(os.Getenv("HOME"), ".netrunner", "stacks")
|
||||
|
||||
|
||||
// Ensure directory exists
|
||||
if _, err := os.Stat(stacksDir); os.IsNotExist(err) {
|
||||
fmt.Println("No stacks deployed")
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
// List stack directories
|
||||
entries, err := os.ReadDir(stacksDir)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to list stacks: %w", err)
|
||||
}
|
||||
|
||||
|
||||
if len(entries) == 0 {
|
||||
fmt.Println("No stacks deployed")
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
fmt.Println("Deployed stacks:")
|
||||
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
|
||||
fmt.Fprintln(w, "NAME\tCREATED\tENGINES")
|
||||
fmt.Fprintln(w, "----\t-------\t-------")
|
||||
|
||||
|
||||
for _, entry := range entries {
|
||||
if !entry.IsDir() {
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
info, _ := entry.Info()
|
||||
|
||||
|
||||
// Try to load manifest to get engine count
|
||||
manifestPath := filepath.Join(stacksDir, entry.Name(), "manifest.yaml")
|
||||
engineCount := "?"
|
||||
if manifest, err := orchestrator.LoadManifest(manifestPath); err == nil {
|
||||
engineCount = fmt.Sprintf("%d", len(manifest.Engines))
|
||||
}
|
||||
|
||||
fmt.Fprintf(w, "%s\t%s\t%s\n",
|
||||
|
||||
fmt.Fprintf(w, "%s\t%s\t%s\n",
|
||||
entry.Name(),
|
||||
info.ModTime().Format("2006-01-02 15:04"),
|
||||
engineCount)
|
||||
}
|
||||
w.Flush()
|
||||
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
@@ -344,39 +345,39 @@ func newStackValidateCmd(logger log.Logger) *cobra.Command {
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
manifestPath := args[0]
|
||||
|
||||
|
||||
// Load manifest
|
||||
manifest, err := orchestrator.LoadManifest(manifestPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to load manifest: %w", err)
|
||||
}
|
||||
|
||||
|
||||
// Validate
|
||||
if err := manifest.Validate(); err != nil {
|
||||
fmt.Printf("❌ Manifest validation failed: %v\n", err)
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
fmt.Printf("✅ Manifest is valid\n")
|
||||
fmt.Printf("\n📋 Summary:\n")
|
||||
fmt.Printf(" Name: %s\n", manifest.Name)
|
||||
fmt.Printf(" Version: %s\n", manifest.Version)
|
||||
fmt.Printf(" Engines: %d\n", len(manifest.Engines))
|
||||
|
||||
|
||||
if manifest.Bridge != nil {
|
||||
fmt.Printf(" Bridge: %s → %s\n", manifest.Bridge.Source, manifest.Bridge.Destination)
|
||||
}
|
||||
|
||||
|
||||
// Check for dependency cycles
|
||||
fmt.Printf("\n🔍 Checking dependencies...\n")
|
||||
visited := make(map[string]bool)
|
||||
recStack := make(map[string]bool)
|
||||
|
||||
|
||||
var hasCycle func(string) bool
|
||||
hasCycle = func(name string) bool {
|
||||
visited[name] = true
|
||||
recStack[name] = true
|
||||
|
||||
|
||||
// Find engine config
|
||||
var engine *orchestrator.EngineConfig
|
||||
for i := range manifest.Engines {
|
||||
@@ -385,7 +386,7 @@ func newStackValidateCmd(logger log.Logger) *cobra.Command {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if engine != nil {
|
||||
for _, dep := range engine.DependsOn {
|
||||
if !visited[dep] {
|
||||
@@ -397,11 +398,11 @@ func newStackValidateCmd(logger log.Logger) *cobra.Command {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
recStack[name] = false
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
for _, engine := range manifest.Engines {
|
||||
if !visited[engine.Name] {
|
||||
if hasCycle(engine.Name) {
|
||||
@@ -410,10 +411,10 @@ func newStackValidateCmd(logger log.Logger) *cobra.Command {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fmt.Printf(" ✅ No circular dependencies\n")
|
||||
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,11 +4,12 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"github.com/luxfi/log"
|
||||
"fmt"
|
||||
"os"
|
||||
"text/tabwriter"
|
||||
|
||||
"github.com/luxfi/log"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@@ -20,22 +21,22 @@ func NewStatusCmd(logger log.Logger) *cobra.Command {
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
fmt.Println("🔍 Netrunner System Status")
|
||||
fmt.Println()
|
||||
|
||||
|
||||
// Show running engines
|
||||
fmt.Println("Running Engines:")
|
||||
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
|
||||
fmt.Fprintln(w, "NAME\tTYPE\tSTATUS\tUPTIME\tRPC")
|
||||
fmt.Fprintln(w, "----\t----\t------\t------\t---")
|
||||
|
||||
|
||||
// TODO: Implement global registry
|
||||
fmt.Fprintln(w, "(No engines running)")
|
||||
w.Flush()
|
||||
|
||||
|
||||
fmt.Println()
|
||||
fmt.Println("Deployed Stacks: 0")
|
||||
fmt.Println("Active Bridges: 0")
|
||||
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,11 +4,12 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"github.com/luxfi/log"
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/luxfi/log"
|
||||
|
||||
"github.com/luxfi/netrunner/engines"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
@@ -20,13 +21,13 @@ func NewTestCmd(logger log.Logger) *cobra.Command {
|
||||
Short: "Run integration tests",
|
||||
Long: "Run various integration tests to verify engine functionality",
|
||||
}
|
||||
|
||||
|
||||
cmd.AddCommand(
|
||||
newTestAllCmd(logger),
|
||||
newTestEngineCmd(logger),
|
||||
newTestStackCmd(logger),
|
||||
)
|
||||
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
@@ -36,23 +37,23 @@ func newTestAllCmd(logger log.Logger) *cobra.Command {
|
||||
Short: "Test all engine types",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
ctx := cmd.Context()
|
||||
|
||||
|
||||
fmt.Println("🧪 Testing all engine types...")
|
||||
fmt.Println()
|
||||
|
||||
|
||||
engineTypes := []string{"lux", "lux", "geth", "op", "eth2"}
|
||||
results := make(map[string]bool)
|
||||
|
||||
|
||||
for _, engineType := range engineTypes {
|
||||
fmt.Printf("Testing %s...\n", engineType)
|
||||
|
||||
|
||||
// Skip engines that need additional setup
|
||||
if engineType == "op" {
|
||||
fmt.Println(" ⏭️ Skipping (requires L1)")
|
||||
results[engineType] = false
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
if err := testEngine(ctx, logger, engineType); err != nil {
|
||||
fmt.Printf(" ❌ Failed: %v\n", err)
|
||||
results[engineType] = false
|
||||
@@ -62,7 +63,7 @@ func newTestAllCmd(logger log.Logger) *cobra.Command {
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
|
||||
// Summary
|
||||
fmt.Println("📊 Test Summary:")
|
||||
passed := 0
|
||||
@@ -74,13 +75,13 @@ func newTestAllCmd(logger log.Logger) *cobra.Command {
|
||||
}
|
||||
fmt.Printf(" %s: %s\n", engine, status)
|
||||
}
|
||||
|
||||
|
||||
fmt.Printf("\nTotal: %d/%d passed\n", passed, len(engineTypes))
|
||||
|
||||
|
||||
if passed < len(engineTypes) {
|
||||
return fmt.Errorf("some tests failed")
|
||||
}
|
||||
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
@@ -94,14 +95,14 @@ func newTestEngineCmd(logger log.Logger) *cobra.Command {
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
engineType := args[0]
|
||||
ctx := cmd.Context()
|
||||
|
||||
|
||||
fmt.Printf("🧪 Testing %s engine...\n", engineType)
|
||||
|
||||
|
||||
if err := testEngine(ctx, logger, engineType); err != nil {
|
||||
fmt.Printf("❌ Test failed: %v\n", err)
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
fmt.Println("✅ Test passed!")
|
||||
return nil
|
||||
},
|
||||
@@ -114,10 +115,10 @@ func newTestStackCmd(logger log.Logger) *cobra.Command {
|
||||
Short: "Test multi-engine stack deployment",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
ctx := cmd.Context()
|
||||
|
||||
|
||||
fmt.Println("🧪 Testing multi-engine stack...")
|
||||
fmt.Println()
|
||||
|
||||
|
||||
// Test simple two-engine stack
|
||||
fmt.Println("1. Testing Lux + Geth stack...")
|
||||
if err := testSimpleStack(ctx, logger); err != nil {
|
||||
@@ -126,7 +127,7 @@ func newTestStackCmd(logger log.Logger) *cobra.Command {
|
||||
}
|
||||
fmt.Println("✅ Passed")
|
||||
fmt.Println()
|
||||
|
||||
|
||||
// Test dependency ordering
|
||||
fmt.Println("2. Testing dependency ordering...")
|
||||
if err := testDependencyStack(ctx, logger); err != nil {
|
||||
@@ -134,7 +135,7 @@ func newTestStackCmd(logger log.Logger) *cobra.Command {
|
||||
return err
|
||||
}
|
||||
fmt.Println("✅ Passed")
|
||||
|
||||
|
||||
fmt.Println("\n✅ All stack tests passed!")
|
||||
return nil
|
||||
},
|
||||
@@ -153,7 +154,7 @@ func testEngine(ctx context.Context, logger log.Logger, engineType string) error
|
||||
LogLevel: "info",
|
||||
Extra: make(map[string]interface{}),
|
||||
}
|
||||
|
||||
|
||||
// Type-specific config
|
||||
var binary string
|
||||
switch engineType {
|
||||
@@ -172,26 +173,26 @@ func testEngine(ctx context.Context, logger log.Logger, engineType string) error
|
||||
default:
|
||||
return fmt.Errorf("unknown engine type: %s", engineType)
|
||||
}
|
||||
|
||||
|
||||
// Create engine
|
||||
name := fmt.Sprintf("test-%s", engineType)
|
||||
engine, err := engines.New(engines.EngineType(engineType), name, binary)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create engine: %w", err)
|
||||
}
|
||||
|
||||
|
||||
// Start engine
|
||||
if err := engine.Start(ctx, config); err != nil {
|
||||
return fmt.Errorf("failed to start engine: %w", err)
|
||||
}
|
||||
|
||||
|
||||
// Defer cleanup
|
||||
defer func() {
|
||||
if err := engine.Stop(context.Background()); err != nil {
|
||||
logger.Error("Failed to stop test engine", log.Err(err))
|
||||
}
|
||||
}()
|
||||
|
||||
|
||||
// Wait for health
|
||||
maxAttempts := 30
|
||||
for i := 0; i < maxAttempts; i++ {
|
||||
@@ -207,10 +208,10 @@ func testEngine(ctx context.Context, logger log.Logger, engineType string) error
|
||||
if engine.NetworkID() != config.NetworkID {
|
||||
return fmt.Errorf("network ID mismatch")
|
||||
}
|
||||
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
@@ -218,7 +219,7 @@ func testEngine(ctx context.Context, logger log.Logger, engineType string) error
|
||||
// Continue
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return fmt.Errorf("engine failed to become healthy")
|
||||
}
|
||||
|
||||
@@ -232,4 +233,4 @@ func testSimpleStack(ctx context.Context, logger log.Logger) error {
|
||||
func testDependencyStack(ctx context.Context, logger log.Logger) error {
|
||||
// TODO: Implement dependency stack test
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,4 +66,4 @@ OP Stack, and more.`,
|
||||
logger.Error("Command failed", log.Err(err))
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -7,11 +7,11 @@ import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/luxfi/log"
|
||||
"github.com/luxfi/log/level"
|
||||
"github.com/luxfi/netrunner/client"
|
||||
"github.com/luxfi/netrunner/utils/constants"
|
||||
"github.com/luxfi/netrunner/ux"
|
||||
"github.com/luxfi/log"
|
||||
"github.com/luxfi/log/level"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
|
||||
@@ -11,11 +11,11 @@ import (
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/luxfi/log"
|
||||
"github.com/luxfi/log/level"
|
||||
"github.com/luxfi/netrunner/server"
|
||||
"github.com/luxfi/netrunner/utils"
|
||||
"github.com/luxfi/netrunner/utils/constants"
|
||||
"github.com/luxfi/log"
|
||||
"github.com/luxfi/log/level"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
|
||||
+54
-54
@@ -25,15 +25,15 @@ func init() {
|
||||
|
||||
// LuxEngine wraps luxd node management
|
||||
type LuxEngine struct {
|
||||
name string
|
||||
binary string
|
||||
dataDir string
|
||||
config *engines.NodeConfig
|
||||
process *exec.Cmd
|
||||
httpClient *http.Client
|
||||
rpcEndpoint string
|
||||
startTime time.Time
|
||||
|
||||
name string
|
||||
binary string
|
||||
dataDir string
|
||||
config *engines.NodeConfig
|
||||
process *exec.Cmd
|
||||
httpClient *http.Client
|
||||
rpcEndpoint string
|
||||
startTime time.Time
|
||||
|
||||
// Cached info
|
||||
networkID uint32
|
||||
chainID ids.ID
|
||||
@@ -50,26 +50,26 @@ func NewLuxEngine(name string, binary string) (engines.Engine, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (e *LuxEngine) Name() string { return e.name }
|
||||
func (e *LuxEngine) Type() engines.EngineType { return engines.EngineLux }
|
||||
func (e *LuxEngine) NetworkID() uint32 { return e.networkID }
|
||||
func (e *LuxEngine) ChainID() ids.ID { return e.chainID }
|
||||
func (e *LuxEngine) Name() string { return e.name }
|
||||
func (e *LuxEngine) Type() engines.EngineType { return engines.EngineLux }
|
||||
func (e *LuxEngine) NetworkID() uint32 { return e.networkID }
|
||||
func (e *LuxEngine) ChainID() ids.ID { return e.chainID }
|
||||
func (e *LuxEngine) ParentChain() *engines.ChainInfo { return nil } // L1
|
||||
|
||||
func (e *LuxEngine) Start(ctx context.Context, config *engines.NodeConfig) error {
|
||||
e.config = config
|
||||
e.networkID = config.NetworkID
|
||||
|
||||
|
||||
// Setup data directory
|
||||
if config.DataDir == "" {
|
||||
config.DataDir = filepath.Join(os.TempDir(), "lux", e.name)
|
||||
}
|
||||
e.dataDir = config.DataDir
|
||||
|
||||
|
||||
if err := os.MkdirAll(e.dataDir, 0755); err != nil {
|
||||
return fmt.Errorf("failed to create data dir: %w", err)
|
||||
}
|
||||
|
||||
|
||||
// Build command arguments
|
||||
args := []string{
|
||||
fmt.Sprintf("--network-id=%s", getLuxNetwork(config.NetworkID)),
|
||||
@@ -81,23 +81,23 @@ func (e *LuxEngine) Start(ctx context.Context, config *engines.NodeConfig) error
|
||||
"--http-allowed-hosts=*",
|
||||
"--http-allowed-origins=*",
|
||||
}
|
||||
|
||||
|
||||
// Add bootstrap nodes if custom network
|
||||
if len(config.BootstrapIPs) > 0 {
|
||||
for _, ip := range config.BootstrapIPs {
|
||||
args = append(args, fmt.Sprintf("--bootstrap-ips=%s", ip))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Add extra configs
|
||||
for k, v := range config.Extra {
|
||||
args = append(args, fmt.Sprintf("--%s=%v", k, v))
|
||||
}
|
||||
|
||||
|
||||
// Start the process
|
||||
e.process = exec.CommandContext(ctx, e.binary, args...)
|
||||
e.process.Dir = e.dataDir
|
||||
|
||||
|
||||
// Setup logs
|
||||
logFile, err := os.Create(filepath.Join(e.dataDir, "node.log"))
|
||||
if err != nil {
|
||||
@@ -105,19 +105,19 @@ func (e *LuxEngine) Start(ctx context.Context, config *engines.NodeConfig) error
|
||||
}
|
||||
e.process.Stdout = logFile
|
||||
e.process.Stderr = logFile
|
||||
|
||||
|
||||
if err := e.process.Start(); err != nil {
|
||||
return fmt.Errorf("failed to start luxd: %w", err)
|
||||
}
|
||||
|
||||
|
||||
e.startTime = time.Now()
|
||||
e.rpcEndpoint = e.RPCEndpoint()
|
||||
e.httpClient = &http.Client{Timeout: 10 * time.Second}
|
||||
|
||||
|
||||
// Wait for node to be responsive
|
||||
ticker := time.NewTicker(500 * time.Millisecond)
|
||||
defer ticker.Stop()
|
||||
|
||||
|
||||
timeout := time.After(60 * time.Second) // Lux can take longer
|
||||
for {
|
||||
select {
|
||||
@@ -141,17 +141,17 @@ func (e *LuxEngine) Stop(ctx context.Context) error {
|
||||
if e.process == nil || e.process.Process == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
// Try graceful shutdown first
|
||||
if err := e.process.Process.Signal(os.Interrupt); err != nil {
|
||||
return e.process.Process.Kill()
|
||||
}
|
||||
|
||||
|
||||
done := make(chan error, 1)
|
||||
go func() {
|
||||
done <- e.process.Wait()
|
||||
}()
|
||||
|
||||
|
||||
select {
|
||||
case <-done:
|
||||
return nil
|
||||
@@ -174,23 +174,23 @@ func (e *LuxEngine) Health(ctx context.Context) (*engines.HealthStatus, error) {
|
||||
if e.httpClient == nil {
|
||||
return &engines.HealthStatus{Healthy: false}, nil
|
||||
}
|
||||
|
||||
|
||||
// Get node health
|
||||
healthy, err := e.getHealth(ctx)
|
||||
if err != nil {
|
||||
return &engines.HealthStatus{Healthy: false}, nil
|
||||
}
|
||||
|
||||
|
||||
// Get peers
|
||||
peerCount, _ := e.getPeerCount(ctx)
|
||||
|
||||
|
||||
// Get version
|
||||
version, _ := e.getNodeVersion(ctx)
|
||||
|
||||
|
||||
return &engines.HealthStatus{
|
||||
Healthy: healthy,
|
||||
PeerCount: peerCount,
|
||||
Version: version,
|
||||
Healthy: healthy,
|
||||
PeerCount: peerCount,
|
||||
Version: version,
|
||||
// BlockHeight from C-Chain would require eth client
|
||||
}, nil
|
||||
}
|
||||
@@ -262,29 +262,29 @@ func (e *LuxEngine) callRPC(ctx context.Context, endpoint string, method string,
|
||||
"method": method,
|
||||
"params": params,
|
||||
}
|
||||
|
||||
|
||||
data, err := json.Marshal(reqBody)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, "POST", e.rpcEndpoint+endpoint, bytes.NewReader(data))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
|
||||
resp, err := e.httpClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
||||
var result struct {
|
||||
Result json.RawMessage `json:"result"`
|
||||
Error *struct {
|
||||
@@ -292,15 +292,15 @@ func (e *LuxEngine) callRPC(ctx context.Context, endpoint string, method string,
|
||||
Message string `json:"message"`
|
||||
} `json:"error"`
|
||||
}
|
||||
|
||||
|
||||
if err := json.Unmarshal(body, &result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
||||
if result.Error != nil {
|
||||
return nil, fmt.Errorf("RPC error %d: %s", result.Error.Code, result.Error.Message)
|
||||
}
|
||||
|
||||
|
||||
return result.Result, nil
|
||||
}
|
||||
|
||||
@@ -309,14 +309,14 @@ func (e *LuxEngine) getNodeID(ctx context.Context) (string, error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
|
||||
var resp struct {
|
||||
NodeID string `json:"nodeID"`
|
||||
}
|
||||
if err := json.Unmarshal(result, &resp); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
|
||||
return resp.NodeID, nil
|
||||
}
|
||||
|
||||
@@ -325,14 +325,14 @@ func (e *LuxEngine) getBlockchainID(ctx context.Context, alias string) (ids.ID,
|
||||
if err != nil {
|
||||
return ids.Empty, err
|
||||
}
|
||||
|
||||
|
||||
var resp struct {
|
||||
BlockchainID string `json:"blockchainID"`
|
||||
}
|
||||
if err := json.Unmarshal(result, &resp); err != nil {
|
||||
return ids.Empty, err
|
||||
}
|
||||
|
||||
|
||||
return ids.FromString(resp.BlockchainID)
|
||||
}
|
||||
|
||||
@@ -341,14 +341,14 @@ func (e *LuxEngine) getHealth(ctx context.Context) (bool, error) {
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
|
||||
var resp struct {
|
||||
Healthy bool `json:"healthy"`
|
||||
}
|
||||
if err := json.Unmarshal(result, &resp); err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
|
||||
return resp.Healthy, nil
|
||||
}
|
||||
|
||||
@@ -357,9 +357,9 @@ func (e *LuxEngine) getPeerCount(ctx context.Context) (int, error) {
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
|
||||
var resp struct {
|
||||
NumPeers int `json:"numPeers"`
|
||||
NumPeers int `json:"numPeers"`
|
||||
Peers []interface{} `json:"peers"`
|
||||
}
|
||||
if err := json.Unmarshal(result, &resp); err != nil {
|
||||
@@ -370,7 +370,7 @@ func (e *LuxEngine) getPeerCount(ctx context.Context) (int, error) {
|
||||
}
|
||||
return len(peers), nil
|
||||
}
|
||||
|
||||
|
||||
if resp.NumPeers > 0 {
|
||||
return resp.NumPeers, nil
|
||||
}
|
||||
@@ -382,13 +382,13 @@ func (e *LuxEngine) getNodeVersion(ctx context.Context) (string, error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
|
||||
var resp struct {
|
||||
Version string `json:"version"`
|
||||
}
|
||||
if err := json.Unmarshal(result, &resp); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
|
||||
return resp.Version, nil
|
||||
}
|
||||
}
|
||||
|
||||
+17
-15
@@ -53,18 +53,20 @@ type mockEngine struct {
|
||||
name string
|
||||
}
|
||||
|
||||
func (m *mockEngine) Name() string { return m.name }
|
||||
func (m *mockEngine) Type() EngineType { return "test" }
|
||||
func (m *mockEngine) NetworkID() uint32 { return 1337 }
|
||||
func (m *mockEngine) ChainID() ids.ID { return ids.Empty }
|
||||
func (m *mockEngine) ParentChain() *ChainInfo { return nil }
|
||||
func (m *mockEngine) Start(_ context.Context, _ *NodeConfig) error { return nil }
|
||||
func (m *mockEngine) Stop(_ context.Context) error { return nil }
|
||||
func (m *mockEngine) Restart(_ context.Context) error { return nil }
|
||||
func (m *mockEngine) Health(_ context.Context) (*HealthStatus, error) { return &HealthStatus{Healthy: true}, nil }
|
||||
func (m *mockEngine) IsRunning() bool { return true }
|
||||
func (m *mockEngine) Uptime() time.Duration { return 0 }
|
||||
func (m *mockEngine) RPCEndpoint() string { return "http://localhost:8545" }
|
||||
func (m *mockEngine) WSEndpoint() string { return "ws://localhost:8546" }
|
||||
func (m *mockEngine) P2PEndpoint() string { return "localhost:30303" }
|
||||
func (m *mockEngine) Metrics() map[string]interface{} { return map[string]interface{}{} }
|
||||
func (m *mockEngine) Name() string { return m.name }
|
||||
func (m *mockEngine) Type() EngineType { return "test" }
|
||||
func (m *mockEngine) NetworkID() uint32 { return 1337 }
|
||||
func (m *mockEngine) ChainID() ids.ID { return ids.Empty }
|
||||
func (m *mockEngine) ParentChain() *ChainInfo { return nil }
|
||||
func (m *mockEngine) Start(_ context.Context, _ *NodeConfig) error { return nil }
|
||||
func (m *mockEngine) Stop(_ context.Context) error { return nil }
|
||||
func (m *mockEngine) Restart(_ context.Context) error { return nil }
|
||||
func (m *mockEngine) Health(_ context.Context) (*HealthStatus, error) {
|
||||
return &HealthStatus{Healthy: true}, nil
|
||||
}
|
||||
func (m *mockEngine) IsRunning() bool { return true }
|
||||
func (m *mockEngine) Uptime() time.Duration { return 0 }
|
||||
func (m *mockEngine) RPCEndpoint() string { return "http://localhost:8545" }
|
||||
func (m *mockEngine) WSEndpoint() string { return "ws://localhost:8546" }
|
||||
func (m *mockEngine) P2PEndpoint() string { return "localhost:30303" }
|
||||
func (m *mockEngine) Metrics() map[string]interface{} { return map[string]interface{}{} }
|
||||
|
||||
+38
-38
@@ -23,17 +23,17 @@ import (
|
||||
|
||||
// Eth2Engine implements Ethereum 2.0 consensus (Beacon Chain + Execution Layer)
|
||||
type Eth2Engine struct {
|
||||
mu sync.RWMutex
|
||||
name string
|
||||
beaconBinary string // Consensus client (e.g., Prysm, Lighthouse, Teku)
|
||||
executionBinary string // Execution client (e.g., Geth, Erigon, Nethermind)
|
||||
beaconCmd *exec.Cmd
|
||||
executionCmd *exec.Cmd
|
||||
config *NodeConfig
|
||||
startTime time.Time
|
||||
running bool
|
||||
dataDir string
|
||||
|
||||
mu sync.RWMutex
|
||||
name string
|
||||
beaconBinary string // Consensus client (e.g., Prysm, Lighthouse, Teku)
|
||||
executionBinary string // Execution client (e.g., Geth, Erigon, Nethermind)
|
||||
beaconCmd *exec.Cmd
|
||||
executionCmd *exec.Cmd
|
||||
config *NodeConfig
|
||||
startTime time.Time
|
||||
running bool
|
||||
dataDir string
|
||||
|
||||
// Eth2 specific
|
||||
chainID uint64
|
||||
networkName string
|
||||
@@ -66,27 +66,27 @@ const (
|
||||
|
||||
// Eth2Config contains Ethereum 2.0 specific configuration
|
||||
type Eth2Config struct {
|
||||
ChainID uint64 `json:"chain_id"`
|
||||
NetworkName string `json:"network_name"`
|
||||
ConsensusClient ConsensusClient `json:"consensus_client"`
|
||||
ExecutionClient ExecutionClient `json:"execution_client"`
|
||||
ValidatorEnabled bool `json:"validator_enabled"`
|
||||
ValidatorKeys []string `json:"validator_keys,omitempty"`
|
||||
InitialValidators []string `json:"initial_validators,omitempty"`
|
||||
TerminalTotalDifficulty string `json:"terminal_total_difficulty"`
|
||||
GenesisTime uint64 `json:"genesis_time"`
|
||||
ChainID uint64 `json:"chain_id"`
|
||||
NetworkName string `json:"network_name"`
|
||||
ConsensusClient ConsensusClient `json:"consensus_client"`
|
||||
ExecutionClient ExecutionClient `json:"execution_client"`
|
||||
ValidatorEnabled bool `json:"validator_enabled"`
|
||||
ValidatorKeys []string `json:"validator_keys,omitempty"`
|
||||
InitialValidators []string `json:"initial_validators,omitempty"`
|
||||
TerminalTotalDifficulty string `json:"terminal_total_difficulty"`
|
||||
GenesisTime uint64 `json:"genesis_time"`
|
||||
}
|
||||
|
||||
// BeaconNodeStatus represents beacon chain status
|
||||
type BeaconNodeStatus struct {
|
||||
HeadSlot uint64 `json:"head_slot"`
|
||||
SyncDistance uint64 `json:"sync_distance"`
|
||||
IsSyncing bool `json:"is_syncing"`
|
||||
IsOptimistic bool `json:"is_optimistic"`
|
||||
ElOffline bool `json:"el_offline"`
|
||||
CurrentEpoch uint64 `json:"current_epoch"`
|
||||
FinalizedEpoch uint64 `json:"finalized_epoch"`
|
||||
JustifiedEpoch uint64 `json:"justified_epoch"`
|
||||
HeadSlot uint64 `json:"head_slot"`
|
||||
SyncDistance uint64 `json:"sync_distance"`
|
||||
IsSyncing bool `json:"is_syncing"`
|
||||
IsOptimistic bool `json:"is_optimistic"`
|
||||
ElOffline bool `json:"el_offline"`
|
||||
CurrentEpoch uint64 `json:"current_epoch"`
|
||||
FinalizedEpoch uint64 `json:"finalized_epoch"`
|
||||
JustifiedEpoch uint64 `json:"justified_epoch"`
|
||||
}
|
||||
|
||||
// NewEth2Engine creates a new Ethereum 2.0 engine
|
||||
@@ -185,7 +185,7 @@ func (e *Eth2Engine) loadEth2Config() error {
|
||||
|
||||
func (e *Eth2Engine) generateJWTSecret() error {
|
||||
jwtPath := filepath.Join(e.dataDir, "jwt.hex")
|
||||
|
||||
|
||||
// Check if already exists
|
||||
if _, err := os.Stat(jwtPath); err == nil {
|
||||
data, err := os.ReadFile(jwtPath)
|
||||
@@ -201,14 +201,14 @@ func (e *Eth2Engine) generateJWTSecret() error {
|
||||
if _, err := rand.Read(secret); err != nil {
|
||||
return fmt.Errorf("failed to generate random JWT secret: %w", err)
|
||||
}
|
||||
|
||||
|
||||
e.jwtSecret = hex.EncodeToString(secret)
|
||||
return os.WriteFile(jwtPath, []byte(e.jwtSecret), 0600)
|
||||
}
|
||||
|
||||
func (e *Eth2Engine) startExecutionClient(ctx context.Context) error {
|
||||
var args []string
|
||||
|
||||
|
||||
switch e.executionClient {
|
||||
case Geth:
|
||||
args = e.getGethArgs()
|
||||
@@ -305,7 +305,7 @@ func (e *Eth2Engine) getBesuArgs() []string {
|
||||
|
||||
func (e *Eth2Engine) startConsensusClient(ctx context.Context) error {
|
||||
var args []string
|
||||
|
||||
|
||||
switch e.consensusClient {
|
||||
case Prysm:
|
||||
args = e.getPrysmArgs()
|
||||
@@ -424,7 +424,7 @@ func (e *Eth2Engine) Stop(ctx context.Context) error {
|
||||
go func() {
|
||||
done <- e.beaconCmd.Wait()
|
||||
}()
|
||||
|
||||
|
||||
select {
|
||||
case <-done:
|
||||
case <-time.After(10 * time.Second):
|
||||
@@ -446,7 +446,7 @@ func (e *Eth2Engine) stopExecutionClient() {
|
||||
go func() {
|
||||
done <- e.executionCmd.Wait()
|
||||
}()
|
||||
|
||||
|
||||
select {
|
||||
case <-done:
|
||||
case <-time.After(10 * time.Second):
|
||||
@@ -499,7 +499,7 @@ func (e *Eth2Engine) Health(ctx context.Context) (*HealthStatus, error) {
|
||||
|
||||
func (e *Eth2Engine) getBeaconNodeStatus() (*BeaconNodeStatus, error) {
|
||||
url := fmt.Sprintf("http://localhost:%d/eth/v1/node/syncing", e.config.HTTPPort+2000)
|
||||
|
||||
|
||||
client := &http.Client{Timeout: 5 * time.Second}
|
||||
resp, err := client.Get(url)
|
||||
if err != nil {
|
||||
@@ -578,7 +578,7 @@ func (e *Eth2Engine) ParentChain() *ChainInfo {
|
||||
func (e *Eth2Engine) Metrics() map[string]interface{} {
|
||||
e.mu.RLock()
|
||||
defer e.mu.RUnlock()
|
||||
|
||||
|
||||
metrics := map[string]interface{}{
|
||||
"running": e.running,
|
||||
"uptime": e.Uptime().Seconds(),
|
||||
@@ -589,7 +589,7 @@ func (e *Eth2Engine) Metrics() map[string]interface{} {
|
||||
"network": e.networkName,
|
||||
"validator": e.validatorEnabled,
|
||||
}
|
||||
|
||||
|
||||
return metrics
|
||||
}
|
||||
|
||||
@@ -605,4 +605,4 @@ func Eth2Factory(name string, binary string) (Engine, error) {
|
||||
|
||||
func init() {
|
||||
Register(EngineEth2, Eth2Factory)
|
||||
}
|
||||
}
|
||||
|
||||
+29
-29
@@ -33,7 +33,7 @@ type GethEngine struct {
|
||||
config *engines.NodeConfig
|
||||
process *exec.Cmd
|
||||
startTime time.Time
|
||||
|
||||
|
||||
// Cached info
|
||||
networkID uint32
|
||||
chainID ids.ID
|
||||
@@ -50,32 +50,32 @@ func NewGethEngine(name string, binary string) (engines.Engine, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (e *GethEngine) Name() string { return e.name }
|
||||
func (e *GethEngine) Type() engines.EngineType { return engines.EngineGeth }
|
||||
func (e *GethEngine) NetworkID() uint32 { return e.networkID }
|
||||
func (e *GethEngine) ChainID() ids.ID { return e.chainID }
|
||||
func (e *GethEngine) Name() string { return e.name }
|
||||
func (e *GethEngine) Type() engines.EngineType { return engines.EngineGeth }
|
||||
func (e *GethEngine) NetworkID() uint32 { return e.networkID }
|
||||
func (e *GethEngine) ChainID() ids.ID { return e.chainID }
|
||||
func (e *GethEngine) ParentChain() *engines.ChainInfo { return nil } // L1
|
||||
|
||||
func (e *GethEngine) Start(ctx context.Context, config *engines.NodeConfig) error {
|
||||
e.config = config
|
||||
e.networkID = config.NetworkID
|
||||
|
||||
|
||||
// Generate chain ID from network ID
|
||||
chainIDBytes := make([]byte, 32)
|
||||
chainIDBig := big.NewInt(int64(config.NetworkID))
|
||||
chainIDBig.FillBytes(chainIDBytes)
|
||||
copy(e.chainID[:], chainIDBytes)
|
||||
|
||||
|
||||
// Setup data directory
|
||||
if config.DataDir == "" {
|
||||
config.DataDir = filepath.Join(os.TempDir(), "geth", e.name)
|
||||
}
|
||||
e.dataDir = config.DataDir
|
||||
|
||||
|
||||
if err := os.MkdirAll(e.dataDir, 0755); err != nil {
|
||||
return fmt.Errorf("failed to create data dir: %w", err)
|
||||
}
|
||||
|
||||
|
||||
// Initialize genesis if needed
|
||||
if _, err := os.Stat(filepath.Join(e.dataDir, "geth", "chaindata")); os.IsNotExist(err) {
|
||||
// Create simple genesis
|
||||
@@ -99,19 +99,19 @@ func (e *GethEngine) Start(ctx context.Context, config *engines.NodeConfig) erro
|
||||
"gasLimit": "0x8000000",
|
||||
"alloc": {}
|
||||
}`, config.NetworkID)
|
||||
|
||||
|
||||
genesisPath := filepath.Join(e.dataDir, "genesis.json")
|
||||
if err := os.WriteFile(genesisPath, []byte(genesis), 0644); err != nil {
|
||||
return fmt.Errorf("failed to write genesis: %w", err)
|
||||
}
|
||||
|
||||
|
||||
// Initialize geth with genesis
|
||||
initCmd := exec.CommandContext(ctx, e.binary, "init", genesisPath, "--datadir", e.dataDir)
|
||||
if err := initCmd.Run(); err != nil {
|
||||
return fmt.Errorf("failed to init geth: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Build command arguments
|
||||
args := []string{
|
||||
"--datadir", e.dataDir,
|
||||
@@ -133,17 +133,17 @@ func (e *GethEngine) Start(ctx context.Context, config *engines.NodeConfig) erro
|
||||
"--syncmode", "full",
|
||||
"--gcmode", "archive",
|
||||
}
|
||||
|
||||
|
||||
// Add dev mode for testing
|
||||
if config.NetworkID > 90000 {
|
||||
args = append(args, "--dev", "--dev.period", "1")
|
||||
}
|
||||
|
||||
|
||||
// Add bootstrap nodes
|
||||
for _, bootnode := range config.BootstrapIPs {
|
||||
args = append(args, "--bootnodes", bootnode)
|
||||
}
|
||||
|
||||
|
||||
// Add extra configs
|
||||
for k, v := range config.Extra {
|
||||
switch k {
|
||||
@@ -157,11 +157,11 @@ func (e *GethEngine) Start(ctx context.Context, config *engines.NodeConfig) erro
|
||||
args = append(args, "--password", v.(string))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Start the process
|
||||
e.process = exec.CommandContext(ctx, e.binary, args...)
|
||||
e.process.Dir = e.dataDir
|
||||
|
||||
|
||||
// Setup logs
|
||||
logFile, err := os.Create(filepath.Join(e.dataDir, "geth.log"))
|
||||
if err != nil {
|
||||
@@ -169,17 +169,17 @@ func (e *GethEngine) Start(ctx context.Context, config *engines.NodeConfig) erro
|
||||
}
|
||||
e.process.Stdout = logFile
|
||||
e.process.Stderr = logFile
|
||||
|
||||
|
||||
if err := e.process.Start(); err != nil {
|
||||
return fmt.Errorf("failed to start geth: %w", err)
|
||||
}
|
||||
|
||||
|
||||
e.startTime = time.Now()
|
||||
|
||||
|
||||
// Wait for node to be responsive
|
||||
ticker := time.NewTicker(500 * time.Millisecond)
|
||||
defer ticker.Stop()
|
||||
|
||||
|
||||
timeout := time.After(30 * time.Second)
|
||||
for {
|
||||
select {
|
||||
@@ -200,17 +200,17 @@ func (e *GethEngine) Stop(ctx context.Context) error {
|
||||
if e.process == nil || e.process.Process == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
// Try graceful shutdown first
|
||||
if err := e.process.Process.Signal(os.Interrupt); err != nil {
|
||||
return e.process.Process.Kill()
|
||||
}
|
||||
|
||||
|
||||
done := make(chan error, 1)
|
||||
go func() {
|
||||
done <- e.process.Wait()
|
||||
}()
|
||||
|
||||
|
||||
select {
|
||||
case <-done:
|
||||
return nil
|
||||
@@ -233,10 +233,10 @@ func (e *GethEngine) Health(ctx context.Context) (*engines.HealthStatus, error)
|
||||
if !e.IsRunning() {
|
||||
return &engines.HealthStatus{Healthy: false}, nil
|
||||
}
|
||||
|
||||
|
||||
// Check if RPC is responsive
|
||||
healthy := e.checkRPC()
|
||||
|
||||
|
||||
return &engines.HealthStatus{
|
||||
Healthy: healthy,
|
||||
PeerCount: 0, // Would need JSON-RPC client to get real peer count
|
||||
@@ -292,11 +292,11 @@ func (e *GethEngine) checkRPC() bool {
|
||||
if e.process == nil || e.process.Process == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
// Check if process is still alive
|
||||
if err := e.process.Process.Signal(os.Signal(nil)); err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
+28
-28
@@ -36,7 +36,7 @@ type LuxEngine struct {
|
||||
infoClient *info.Client
|
||||
healthClient *health.Client
|
||||
startTime time.Time
|
||||
|
||||
|
||||
// Cached info
|
||||
networkID uint32
|
||||
chainID ids.ID
|
||||
@@ -53,26 +53,26 @@ func NewLuxEngine(name string, binary string) (engines.Engine, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (e *LuxEngine) Name() string { return e.name }
|
||||
func (e *LuxEngine) Type() engines.EngineType { return engines.EngineLux }
|
||||
func (e *LuxEngine) NetworkID() uint32 { return e.networkID }
|
||||
func (e *LuxEngine) ChainID() ids.ID { return e.chainID }
|
||||
func (e *LuxEngine) Name() string { return e.name }
|
||||
func (e *LuxEngine) Type() engines.EngineType { return engines.EngineLux }
|
||||
func (e *LuxEngine) NetworkID() uint32 { return e.networkID }
|
||||
func (e *LuxEngine) ChainID() ids.ID { return e.chainID }
|
||||
func (e *LuxEngine) ParentChain() *engines.ChainInfo { return nil } // L1
|
||||
|
||||
func (e *LuxEngine) Start(ctx context.Context, config *engines.NodeConfig) error {
|
||||
e.config = config
|
||||
e.networkID = config.NetworkID
|
||||
|
||||
|
||||
// Setup data directory
|
||||
if config.DataDir == "" {
|
||||
config.DataDir = filepath.Join(os.TempDir(), "lux", e.name)
|
||||
}
|
||||
e.dataDir = config.DataDir
|
||||
|
||||
|
||||
if err := os.MkdirAll(e.dataDir, 0755); err != nil {
|
||||
return fmt.Errorf("failed to create data dir: %w", err)
|
||||
}
|
||||
|
||||
|
||||
// Build command arguments
|
||||
args := []string{
|
||||
fmt.Sprintf("--network-id=%d", config.NetworkID),
|
||||
@@ -83,23 +83,23 @@ func (e *LuxEngine) Start(ctx context.Context, config *engines.NodeConfig) error
|
||||
"--http-host=0.0.0.0",
|
||||
"--http-allowed-hosts=*",
|
||||
}
|
||||
|
||||
|
||||
// Add bootstrap nodes
|
||||
if len(config.BootstrapIPs) > 0 {
|
||||
for _, ip := range config.BootstrapIPs {
|
||||
args = append(args, fmt.Sprintf("--bootstrap-ips=%s", ip))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Add extra configs
|
||||
for k, v := range config.Extra {
|
||||
args = append(args, fmt.Sprintf("--%s=%v", k, v))
|
||||
}
|
||||
|
||||
|
||||
// Start the process
|
||||
e.process = exec.CommandContext(ctx, e.binary, args...)
|
||||
e.process.Dir = e.dataDir
|
||||
|
||||
|
||||
// Setup logs
|
||||
logFile, err := os.Create(filepath.Join(e.dataDir, "node.log"))
|
||||
if err != nil {
|
||||
@@ -107,21 +107,21 @@ func (e *LuxEngine) Start(ctx context.Context, config *engines.NodeConfig) error
|
||||
}
|
||||
e.process.Stdout = logFile
|
||||
e.process.Stderr = logFile
|
||||
|
||||
|
||||
if err := e.process.Start(); err != nil {
|
||||
return fmt.Errorf("failed to start luxd: %w", err)
|
||||
}
|
||||
|
||||
|
||||
e.startTime = time.Now()
|
||||
|
||||
|
||||
// Setup RPC clients
|
||||
e.infoClient = info.NewClient(e.RPCEndpoint())
|
||||
e.healthClient = health.NewClient(e.RPCEndpoint())
|
||||
|
||||
|
||||
// Wait for node to be responsive
|
||||
ticker := time.NewTicker(500 * time.Millisecond)
|
||||
defer ticker.Stop()
|
||||
|
||||
|
||||
timeout := time.After(30 * time.Second)
|
||||
for {
|
||||
select {
|
||||
@@ -145,17 +145,17 @@ func (e *LuxEngine) Stop(ctx context.Context) error {
|
||||
if e.process == nil || e.process.Process == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
// Try graceful shutdown first
|
||||
if err := e.process.Process.Signal(os.Interrupt); err != nil {
|
||||
return e.process.Process.Kill()
|
||||
}
|
||||
|
||||
|
||||
done := make(chan error, 1)
|
||||
go func() {
|
||||
done <- e.process.Wait()
|
||||
}()
|
||||
|
||||
|
||||
select {
|
||||
case <-done:
|
||||
return nil
|
||||
@@ -178,29 +178,29 @@ func (e *LuxEngine) Health(ctx context.Context) (*engines.HealthStatus, error) {
|
||||
if e.healthClient == nil || e.infoClient == nil {
|
||||
return &engines.HealthStatus{Healthy: false}, nil
|
||||
}
|
||||
|
||||
|
||||
// Get node health
|
||||
healthResp, err := e.healthClient.Health(ctx, nil)
|
||||
if err != nil {
|
||||
return &engines.HealthStatus{Healthy: false}, nil
|
||||
}
|
||||
|
||||
|
||||
// Get peers
|
||||
peers, err := e.infoClient.Peers(ctx, nil)
|
||||
if err != nil {
|
||||
peers = []info.Peer{}
|
||||
}
|
||||
|
||||
|
||||
// Get version
|
||||
versions, err := e.infoClient.GetNodeVersion(ctx)
|
||||
if err != nil {
|
||||
versions = &info.GetNodeVersionReply{}
|
||||
}
|
||||
|
||||
|
||||
return &engines.HealthStatus{
|
||||
Healthy: healthResp.Healthy,
|
||||
PeerCount: len(peers),
|
||||
Version: versions.Version,
|
||||
Healthy: healthResp.Healthy,
|
||||
PeerCount: len(peers),
|
||||
Version: versions.Version,
|
||||
// BlockHeight from C-Chain would require eth client
|
||||
}, nil
|
||||
}
|
||||
@@ -248,4 +248,4 @@ func (e *LuxEngine) Metrics() map[string]interface{} {
|
||||
"network_id": e.networkID,
|
||||
"chain_id": e.chainID.String(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+19
-19
@@ -29,7 +29,7 @@ type OPStackEngine struct {
|
||||
startTime time.Time
|
||||
running bool
|
||||
dataDir string
|
||||
|
||||
|
||||
// OP Stack specific
|
||||
l1RPC string
|
||||
sequencer bool
|
||||
@@ -38,14 +38,14 @@ type OPStackEngine struct {
|
||||
|
||||
// RollupConfig contains OP Stack rollup configuration
|
||||
type RollupConfig struct {
|
||||
Genesis RollupGenesis `json:"genesis"`
|
||||
BlockTime uint64 `json:"block_time"`
|
||||
MaxSequencerDrift uint64 `json:"max_sequencer_drift"`
|
||||
SeqWindowSize uint64 `json:"seq_window_size"`
|
||||
ChannelTimeout uint64 `json:"channel_timeout"`
|
||||
L1ChainID uint64 `json:"l1_chain_id"`
|
||||
L2ChainID uint64 `json:"l2_chain_id"`
|
||||
P2PSequencerAddress string `json:"p2p_sequencer_address"`
|
||||
Genesis RollupGenesis `json:"genesis"`
|
||||
BlockTime uint64 `json:"block_time"`
|
||||
MaxSequencerDrift uint64 `json:"max_sequencer_drift"`
|
||||
SeqWindowSize uint64 `json:"seq_window_size"`
|
||||
ChannelTimeout uint64 `json:"channel_timeout"`
|
||||
L1ChainID uint64 `json:"l1_chain_id"`
|
||||
L2ChainID uint64 `json:"l2_chain_id"`
|
||||
P2PSequencerAddress string `json:"p2p_sequencer_address"`
|
||||
}
|
||||
|
||||
// RollupGenesis contains OP Stack genesis configuration
|
||||
@@ -195,7 +195,7 @@ func (e *OPStackEngine) startNode(ctx context.Context) error {
|
||||
}
|
||||
|
||||
if e.sequencer {
|
||||
args = append(args,
|
||||
args = append(args,
|
||||
"--sequencer.enabled",
|
||||
"--sequencer.l1-confs", "3",
|
||||
"--verifier.l1-confs", "3",
|
||||
@@ -233,14 +233,14 @@ func (e *OPStackEngine) loadRollupConfig() error {
|
||||
L1ChainID: uint64(e.config.NetworkID),
|
||||
L2ChainID: uint64(e.config.NetworkID) + 10000,
|
||||
}
|
||||
|
||||
|
||||
// Set genesis
|
||||
e.rollupConfig.Genesis.L1.Number = 0
|
||||
e.rollupConfig.Genesis.L1.Hash = "0x0000000000000000000000000000000000000000000000000000000000000000"
|
||||
e.rollupConfig.Genesis.L2.Number = 0
|
||||
e.rollupConfig.Genesis.L2.Hash = "0x0000000000000000000000000000000000000000000000000000000000000000"
|
||||
e.rollupConfig.Genesis.L2Time = uint64(time.Now().Unix())
|
||||
|
||||
|
||||
// Save config
|
||||
data, err := json.MarshalIndent(e.rollupConfig, "", " ")
|
||||
if err != nil {
|
||||
@@ -254,7 +254,7 @@ func (e *OPStackEngine) loadRollupConfig() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
return json.Unmarshal(data, &e.rollupConfig)
|
||||
}
|
||||
|
||||
@@ -273,7 +273,7 @@ func (e *OPStackEngine) Stop(ctx context.Context) error {
|
||||
go func() {
|
||||
done <- e.nodeCmd.Wait()
|
||||
}()
|
||||
|
||||
|
||||
select {
|
||||
case <-done:
|
||||
case <-time.After(10 * time.Second):
|
||||
@@ -295,7 +295,7 @@ func (e *OPStackEngine) stopGeth() {
|
||||
go func() {
|
||||
done <- e.gethCmd.Wait()
|
||||
}()
|
||||
|
||||
|
||||
select {
|
||||
case <-done:
|
||||
case <-time.After(10 * time.Second):
|
||||
@@ -408,20 +408,20 @@ func (e *OPStackEngine) ParentChain() *ChainInfo {
|
||||
func (e *OPStackEngine) Metrics() map[string]interface{} {
|
||||
e.mu.RLock()
|
||||
defer e.mu.RUnlock()
|
||||
|
||||
|
||||
metrics := map[string]interface{}{
|
||||
"running": e.running,
|
||||
"uptime": e.Uptime().Seconds(),
|
||||
"type": "op-stack",
|
||||
"sequencer": e.sequencer,
|
||||
}
|
||||
|
||||
|
||||
if e.rollupConfig != nil {
|
||||
metrics["l1_chain_id"] = e.rollupConfig.L1ChainID
|
||||
metrics["l2_chain_id"] = e.rollupConfig.L2ChainID
|
||||
metrics["block_time"] = e.rollupConfig.BlockTime
|
||||
}
|
||||
|
||||
|
||||
return metrics
|
||||
}
|
||||
|
||||
@@ -437,4 +437,4 @@ func OPStackFactory(name string, binary string) (Engine, error) {
|
||||
|
||||
func init() {
|
||||
Register(EngineOP, OPStackFactory)
|
||||
}
|
||||
}
|
||||
|
||||
+9
-9
@@ -15,10 +15,10 @@ import (
|
||||
type EngineType string
|
||||
|
||||
const (
|
||||
EngineLux EngineType = "lux"
|
||||
EngineGeth EngineType = "geth"
|
||||
EngineOP EngineType = "op"
|
||||
EngineEth2 EngineType = "eth2"
|
||||
EngineLux EngineType = "lux"
|
||||
EngineGeth EngineType = "geth"
|
||||
EngineOP EngineType = "op"
|
||||
EngineEth2 EngineType = "eth2"
|
||||
)
|
||||
|
||||
// ChainInfo describes a blockchain's network properties
|
||||
@@ -58,22 +58,22 @@ type Engine interface {
|
||||
Start(ctx context.Context, config *NodeConfig) error
|
||||
Stop(ctx context.Context) error
|
||||
Restart(ctx context.Context) error
|
||||
|
||||
|
||||
// Status
|
||||
Health(ctx context.Context) (*HealthStatus, error)
|
||||
IsRunning() bool
|
||||
Uptime() time.Duration
|
||||
|
||||
|
||||
// Network info
|
||||
NetworkID() uint32
|
||||
ChainID() ids.ID
|
||||
RPCEndpoint() string
|
||||
WSEndpoint() string
|
||||
P2PEndpoint() string
|
||||
|
||||
|
||||
// Chain relationships
|
||||
ParentChain() *ChainInfo // nil for L1s
|
||||
|
||||
|
||||
// Metrics
|
||||
Metrics() map[string]interface{}
|
||||
}
|
||||
@@ -95,4 +95,4 @@ func New(typ EngineType, name string, binary string) (Engine, error) {
|
||||
return nil, fmt.Errorf("unknown engine type: %s", typ)
|
||||
}
|
||||
return factory(name, binary)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,10 +9,10 @@ import (
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/luxfi/netrunner/local"
|
||||
"github.com/luxfi/netrunner/network"
|
||||
"github.com/luxfi/log"
|
||||
"github.com/luxfi/log/level"
|
||||
"github.com/luxfi/netrunner/local"
|
||||
"github.com/luxfi/netrunner/network"
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
@@ -8,13 +8,13 @@ import (
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/luxfi/log"
|
||||
"github.com/luxfi/log/level"
|
||||
"github.com/luxfi/netrunner/local"
|
||||
"github.com/luxfi/netrunner/network"
|
||||
"github.com/luxfi/netrunner/network/node"
|
||||
"github.com/luxfi/node/config"
|
||||
"github.com/luxfi/node/staking"
|
||||
"github.com/luxfi/log"
|
||||
"github.com/luxfi/log/level"
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
@@ -12,11 +12,11 @@ import (
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/luxfi/log"
|
||||
"github.com/luxfi/log/level"
|
||||
"github.com/luxfi/netrunner/local"
|
||||
"github.com/luxfi/netrunner/network"
|
||||
"github.com/luxfi/node/config"
|
||||
"github.com/luxfi/log"
|
||||
"github.com/luxfi/log/level"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -209,9 +209,9 @@ func run(logger log.Logger) error {
|
||||
createCtx, createCancel := context.WithTimeout(context.Background(), createBlockchainTimeout)
|
||||
chainSpec := []network.ChainSpec{
|
||||
{
|
||||
VMName: chain.VMName,
|
||||
Genesis: genesis,
|
||||
Alias: chain.Alias,
|
||||
VMName: chain.VMName,
|
||||
Genesis: genesis,
|
||||
Alias: chain.Alias,
|
||||
BlockchainName: chain.Alias, // Use unique name for each chain
|
||||
},
|
||||
}
|
||||
|
||||
@@ -15,11 +15,11 @@ require (
|
||||
github.com/luxfi/consensus v1.22.47
|
||||
github.com/luxfi/const v1.4.0
|
||||
github.com/luxfi/crypto v1.17.32
|
||||
github.com/luxfi/genesis v1.5.18
|
||||
github.com/luxfi/genesis v1.5.19
|
||||
github.com/luxfi/geth v1.16.67
|
||||
github.com/luxfi/go-bip39 v1.1.2
|
||||
github.com/luxfi/ids v1.2.6
|
||||
github.com/luxfi/keys v1.0.5
|
||||
github.com/luxfi/keys v1.0.6
|
||||
github.com/luxfi/log v1.2.1
|
||||
github.com/luxfi/math v1.2.0
|
||||
github.com/luxfi/metric v1.4.8
|
||||
|
||||
@@ -249,8 +249,8 @@ github.com/luxfi/crypto v1.17.32 h1:qEKDETNMeU7T82UMEEGYh0bbJ0ZZdx0sAMRwFXt69aQ=
|
||||
github.com/luxfi/crypto v1.17.32/go.mod h1:laZTnEq0BD/fnPhd5ke/79WgFhV3TZjmfPxk+b8zbrE=
|
||||
github.com/luxfi/database v1.2.18 h1:yppRuZf3FKnr3v4o+UHNfSW+cXtUIUibtyki0+EqiIs=
|
||||
github.com/luxfi/database v1.2.18/go.mod h1:dYxaF30KGJQzuxA3VH7+WGU5/dhwRyzLgzSk9F3wje0=
|
||||
github.com/luxfi/genesis v1.5.18 h1:DDNFDyYT+AtSX78XBV1nGeuvR4404XPAkXnnrlJSV78=
|
||||
github.com/luxfi/genesis v1.5.18/go.mod h1:888i1w8e67HIpgLuveIdd+3ESWCXHgnz7cijF6dDAKI=
|
||||
github.com/luxfi/genesis v1.5.19 h1:q9ETV3NXTlJBhhkVKYDidaQqBDb1jgY3TdaLPfBGu0k=
|
||||
github.com/luxfi/genesis v1.5.19/go.mod h1:888i1w8e67HIpgLuveIdd+3ESWCXHgnz7cijF6dDAKI=
|
||||
github.com/luxfi/geth v1.16.67 h1:ILPG59XNnNKIz1YNO1fJFV+doZXBjcQkb4oXQyz1HUM=
|
||||
github.com/luxfi/geth v1.16.67/go.mod h1:QWPyY3vlGQfm8SX/PE6q4XHTBe7X4Gw+SGDJi5QU1pg=
|
||||
github.com/luxfi/go-bip32 v1.0.2 h1:7vFbb+Wr4Z499q2tuCLdd7wWjtn8sH+HWBlx76mhH9Y=
|
||||
@@ -261,8 +261,8 @@ github.com/luxfi/ids v1.2.6 h1:Ru86pltAcWPhCT7FH/MwwuAYXkeZbt9ZwfuR883c8MI=
|
||||
github.com/luxfi/ids v1.2.6/go.mod h1:svLsj7e6ixJVfRYaQqv9RWjBIW11Vz738+d08BVpeCg=
|
||||
github.com/luxfi/keychain v1.0.1 h1:8tTzPnZSi0M6UtKRBCypnGFrLNry9BvWfS5ol33yDF0=
|
||||
github.com/luxfi/keychain v1.0.1/go.mod h1:X7HLk5QRZ1VHJxovAyBL6z7f/nlosoXlveEtvUGhoaw=
|
||||
github.com/luxfi/keys v1.0.5 h1:ZzE2wHDxSiIcufkYlp7twmTKGB0mczjE67uM3uAP2Ag=
|
||||
github.com/luxfi/keys v1.0.5/go.mod h1:hVqfOm6n4/ZN2O6AirlLEpgBhW8bsxNo2EbiNvggGUk=
|
||||
github.com/luxfi/keys v1.0.6 h1:mKB0xjQoNpJxj59UNfdPfuqUoRT48Itt7PvRXU+X3iY=
|
||||
github.com/luxfi/keys v1.0.6/go.mod h1:hVqfOm6n4/ZN2O6AirlLEpgBhW8bsxNo2EbiNvggGUk=
|
||||
github.com/luxfi/log v1.2.1 h1:L2JM8MjGPF8rBnY+EXODS9x5OQTGSgeQ1SPFmeB+oPY=
|
||||
github.com/luxfi/log v1.2.1/go.mod h1:0vJzb4Hl9fvgwWDMKcbCD/SYH3bO0iSmgZMcYdfdl1o=
|
||||
github.com/luxfi/math v1.2.0 h1:cZVQQj1PrIWh3Oy6xfbBL44xay4QFuAXZBg9+pWPBmE=
|
||||
|
||||
+28
-27
@@ -26,26 +26,27 @@ import (
|
||||
"github.com/luxfi/node/vms/components/verify"
|
||||
"github.com/luxfi/node/wallet/chain/x"
|
||||
|
||||
"maps"
|
||||
"slices"
|
||||
|
||||
luxconfig "github.com/luxfi/config"
|
||||
constants "github.com/luxfi/const"
|
||||
"github.com/luxfi/crypto/bls"
|
||||
"github.com/luxfi/crypto/secp256k1"
|
||||
"github.com/luxfi/ids"
|
||||
"github.com/luxfi/log"
|
||||
"github.com/luxfi/math/set"
|
||||
"github.com/luxfi/netrunner/network"
|
||||
"github.com/luxfi/netrunner/network/node"
|
||||
"github.com/luxfi/netrunner/utils"
|
||||
luxconfig "github.com/luxfi/config"
|
||||
"github.com/luxfi/node/api/admin"
|
||||
"github.com/luxfi/node/config"
|
||||
"github.com/luxfi/crypto/secp256k1"
|
||||
"github.com/luxfi/ids"
|
||||
"github.com/luxfi/const"
|
||||
"github.com/luxfi/math/set"
|
||||
"github.com/luxfi/crypto/bls"
|
||||
"github.com/luxfi/log"
|
||||
"github.com/luxfi/node/vms/platformvm"
|
||||
"github.com/luxfi/node/vms/platformvm/signer"
|
||||
"github.com/luxfi/node/vms/platformvm/txs"
|
||||
"github.com/luxfi/node/vms/secp256k1fx"
|
||||
pwallet "github.com/luxfi/node/wallet/chain/p"
|
||||
pwalletwallet "github.com/luxfi/node/wallet/chain/p/wallet"
|
||||
"maps"
|
||||
"slices"
|
||||
|
||||
pbuilder "github.com/luxfi/node/wallet/chain/p/builder"
|
||||
psigner "github.com/luxfi/node/wallet/chain/p/signer"
|
||||
@@ -73,7 +74,7 @@ const (
|
||||
// Most P-chain API calls should complete in <5s on localhost
|
||||
defaultTimeout = 30 * time.Second
|
||||
stakingMinimumLeadTime = 25 * time.Second
|
||||
minStakeDuration = 24 * 14 * time.Hour
|
||||
minStakeDuration = 24 * 14 * time.Hour
|
||||
// FAIL FAST: Reduced from 45s to 30s for local deployments
|
||||
// For local networks, validators activate quickly (5-10s). If it takes longer,
|
||||
// something is wrong - fail fast with clear error rather than waiting forever.
|
||||
@@ -88,7 +89,7 @@ var (
|
||||
type blockchainInfo struct {
|
||||
chainName string
|
||||
vmID ids.ID
|
||||
chainID ids.ID
|
||||
chainID ids.ID
|
||||
blockchainID ids.ID
|
||||
}
|
||||
|
||||
@@ -963,16 +964,16 @@ func (ln *localNetwork) installCustomChains(
|
||||
// This ensures P-Chain is synchronized across all nodes after blockchain creation
|
||||
// TEMPORARILY DISABLED - debugging P-Chain sync issue
|
||||
/*
|
||||
blockchainIDs := make([]ids.ID, len(blockchainTxs))
|
||||
for i, tx := range blockchainTxs {
|
||||
blockchainIDs[i] = tx.ID()
|
||||
}
|
||||
if err := ln.waitForBlockchainOnPChain(ctx, blockchainIDs); err != nil {
|
||||
ln.logger.Error("installCustomChains: P-Chain sync failed",
|
||||
"error", err.Error(),
|
||||
)
|
||||
return nil, fmt.Errorf("P-Chain sync failed: %w", err)
|
||||
}
|
||||
blockchainIDs := make([]ids.ID, len(blockchainTxs))
|
||||
for i, tx := range blockchainTxs {
|
||||
blockchainIDs[i] = tx.ID()
|
||||
}
|
||||
if err := ln.waitForBlockchainOnPChain(ctx, blockchainIDs); err != nil {
|
||||
ln.logger.Error("installCustomChains: P-Chain sync failed",
|
||||
"error", err.Error(),
|
||||
)
|
||||
return nil, fmt.Errorf("P-Chain sync failed: %w", err)
|
||||
}
|
||||
*/
|
||||
|
||||
// Nodes need to be restarted after blockchain creation to discover the new chains
|
||||
@@ -1032,7 +1033,7 @@ func (ln *localNetwork) installCustomChains(
|
||||
// as there is no way to recover VM name from VM ID
|
||||
chainName: chainSpec.VMName,
|
||||
vmID: vmID,
|
||||
chainID: chainID,
|
||||
chainID: chainID,
|
||||
blockchainID: blockchainTxs[i].ID(),
|
||||
}
|
||||
}
|
||||
@@ -1333,7 +1334,7 @@ func getDefaultKey() (*secp256k1.PrivateKey, error) {
|
||||
// (keys.DeriveValidatorFromMnemonic uses m/44'/9000'/0'/0/{index})
|
||||
if mnemonic := os.Getenv("LUX_MNEMONIC"); mnemonic != "" {
|
||||
fmt.Printf("🔑 getDefaultKey: Using LUX_MNEMONIC (len=%d)\n", len(mnemonic))
|
||||
|
||||
|
||||
// Use the SAME derivation function as genesis allocations
|
||||
// This ensures wallet operations use keys that have funds allocated in genesis
|
||||
vk, err := keys.DeriveValidatorFromMnemonic(mnemonic, 0)
|
||||
@@ -1344,11 +1345,11 @@ func getDefaultKey() (*secp256k1.PrivateKey, error) {
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to convert key: %w", err)
|
||||
}
|
||||
|
||||
|
||||
pubKey := privKey.PublicKey()
|
||||
walletAddr := ids.ShortID(pubKey.Address())
|
||||
fmt.Printf("🔑 Wallet address (from mnemonic m/44'/9000'/0'/0/0): %s\n", walletAddr.String())
|
||||
|
||||
|
||||
return privKey, nil
|
||||
}
|
||||
|
||||
@@ -1435,9 +1436,9 @@ func newWallet(
|
||||
}
|
||||
pTXs[id] = tx
|
||||
}
|
||||
pUTXOs := common.NewChainUTXOs(constants.PlatformChainID, luxState.UTXOs)
|
||||
pUTXOs := common.NewChainUTXOs(constants.PlatformChainID, luxState.UTXOs)
|
||||
xChainID := luxState.XCTX.BlockchainID
|
||||
xUTXOs := common.NewChainUTXOs(xChainID, luxState.UTXOs)
|
||||
xUTXOs := common.NewChainUTXOs(xChainID, luxState.UTXOs)
|
||||
var w wallet
|
||||
w.addr = privKey.PublicKey().Address()
|
||||
// TODO: Create owners map instead of pTXs
|
||||
|
||||
+71
-34
@@ -13,10 +13,11 @@ import (
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/luxfi/const"
|
||||
"maps"
|
||||
|
||||
constants "github.com/luxfi/const"
|
||||
"github.com/luxfi/crypto/bls"
|
||||
"github.com/luxfi/crypto/bls/signer/localsigner"
|
||||
"github.com/luxfi/node/vms/platformvm/signer"
|
||||
luxcrypto "github.com/luxfi/crypto/secp256k1"
|
||||
"github.com/luxfi/genesis/configs"
|
||||
"github.com/luxfi/ids"
|
||||
@@ -25,7 +26,7 @@ import (
|
||||
"github.com/luxfi/netrunner/network/node"
|
||||
"github.com/luxfi/netrunner/utils"
|
||||
"github.com/luxfi/node/config"
|
||||
"maps"
|
||||
"github.com/luxfi/node/vms/platformvm/signer"
|
||||
|
||||
"github.com/luxfi/node/staking"
|
||||
"github.com/luxfi/node/utils/formatting/address"
|
||||
@@ -267,12 +268,10 @@ func NewConfigForNetwork(binaryPath string, numNodes uint32, networkID uint32) (
|
||||
m["allocations"] = mustJSON(newAllocations)
|
||||
}
|
||||
|
||||
// Check if we need to generate initialStakers
|
||||
var existingStakers []interface{}
|
||||
if raw, ok := m["initialStakers"]; ok {
|
||||
json.Unmarshal(raw, &existingStakers)
|
||||
}
|
||||
if len(existingStakers) == 0 {
|
||||
// ALWAYS replace initialStakers with embedded validator keys for local network testing.
|
||||
// The genesis file may have different validators than netrunner's embedded keys,
|
||||
// so we must replace them to ensure nodes can actually validate.
|
||||
{
|
||||
// Generate initialStakers from embedded validator keys
|
||||
var generatedStakers []map[string]interface{}
|
||||
for i := uint32(0); i < numEmbeddedToUse; i++ {
|
||||
@@ -423,6 +422,10 @@ func NewCanonicalCustomConfig(binaryPath string, numNodes uint32) (network.Confi
|
||||
|
||||
// newCanonicalConfig creates a network config with canonical (pre-serialized) genesis bytes
|
||||
// and loads validator keys from ~/.lux/keys/node{0..n-1}/
|
||||
//
|
||||
// IMPORTANT: This function patches the genesis initialStakers with the BLS keys from the
|
||||
// loaded validator keys. This ensures the validators' BLS Proof of Possession (PoP) in genesis
|
||||
// matches the actual signer.key files the nodes will use.
|
||||
func newCanonicalConfig(binaryPath string, numNodes uint32, networkID uint32, portBase int) (network.Config, error) {
|
||||
// Load CANONICAL genesis bytes - no parsing/re-serialization
|
||||
originalGenesisBytes, err := configs.GetCanonicalGenesisBytes(networkID)
|
||||
@@ -430,13 +433,61 @@ func newCanonicalConfig(binaryPath string, numNodes uint32, networkID uint32, po
|
||||
return network.Config{}, fmt.Errorf("failed to load canonical genesis: %w", err)
|
||||
}
|
||||
|
||||
// For LOCAL TESTING: Update startTime to now so bootstrap starts immediately.
|
||||
// Load validator keys from ~/.lux/keys/ FIRST so we can patch genesis with them
|
||||
keysDir := os.Getenv("LUX_KEYS_DIR")
|
||||
if keysDir == "" {
|
||||
keysDir = validatorKeysDir()
|
||||
}
|
||||
ks := keys.NewKeyStore(keysDir)
|
||||
|
||||
// Load all validator keys and build initialStakers
|
||||
hrp := constants.GetHRP(networkID)
|
||||
validatorKeys := make([]*keys.ValidatorKey, numNodes)
|
||||
initialStakers := make([]map[string]interface{}, numNodes)
|
||||
|
||||
for i := uint32(0); i < numNodes; i++ {
|
||||
name := fmt.Sprintf("node%d", i)
|
||||
vk, err := ks.Load(name)
|
||||
if err != nil {
|
||||
return network.Config{}, fmt.Errorf("failed to load validator key %s from %s: %w (run 'lux key generate' first)", name, keysDir, err)
|
||||
}
|
||||
validatorKeys[i] = vk
|
||||
|
||||
// Build initialStaker entry with BLS keys from loaded validator
|
||||
rewardAddr, err := address.Format("P", hrp, vk.PChainAddr[:])
|
||||
if err != nil {
|
||||
return network.Config{}, fmt.Errorf("couldn't format reward address for node %d: %w", i, err)
|
||||
}
|
||||
|
||||
staker := map[string]interface{}{
|
||||
"nodeID": vk.NodeID.String(),
|
||||
"rewardAddress": rewardAddr,
|
||||
"delegationFee": 20000,
|
||||
"weight": GigaLux, // 1 billion nLUX = 1000 LUX
|
||||
}
|
||||
|
||||
if len(vk.BLSPublicKey) > 0 && len(vk.BLSPoP) > 0 {
|
||||
staker["signer"] = map[string]interface{}{
|
||||
"publicKey": vk.BLSPublicKeyHex(),
|
||||
"proofOfPossession": vk.BLSPoPHex(),
|
||||
}
|
||||
fmt.Printf(" Validator %d: %s (BLS: %s...)\n", i, vk.NodeID.String(), vk.BLSPublicKeyHex()[:20])
|
||||
} else {
|
||||
fmt.Printf(" Validator %d: %s (no BLS key)\n", i, vk.NodeID.String())
|
||||
}
|
||||
|
||||
initialStakers[i] = staker
|
||||
}
|
||||
|
||||
// For LOCAL TESTING: Update startTime to now AND patch initialStakers with our keys
|
||||
// CRITICAL: Use patchGenesisPreservingRaw to preserve cChainGenesis exact bytes.
|
||||
now := time.Now().Unix()
|
||||
fmt.Printf("📅 Updated genesis startTime to %d (now) for local testing\n", now)
|
||||
fmt.Printf("🔑 Patching genesis initialStakers with %d validators from %s\n", numNodes, keysDir)
|
||||
|
||||
genesisBytes, err := patchGenesisPreservingRaw(originalGenesisBytes, evmGenesisKeys, func(m map[string]json.RawMessage) error {
|
||||
m["startTime"] = mustJSON(uint64(now))
|
||||
m["initialStakers"] = mustJSON(initialStakers)
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
@@ -447,22 +498,10 @@ func newCanonicalConfig(binaryPath string, numNodes uint32, networkID uint32, po
|
||||
netConfig := NewDefaultConfig(binaryPath)
|
||||
netConfig.Genesis = string(genesisBytes)
|
||||
|
||||
// Load validator keys from ~/.lux/keys/
|
||||
keysDir := os.Getenv("LUX_KEYS_DIR")
|
||||
if keysDir == "" {
|
||||
keysDir = validatorKeysDir()
|
||||
}
|
||||
ks := keys.NewKeyStore(keysDir)
|
||||
|
||||
// Load keys for each node
|
||||
// Build node configs from loaded keys
|
||||
nodeConfigs := make([]node.Config, numNodes)
|
||||
for i := uint32(0); i < numNodes; i++ {
|
||||
name := fmt.Sprintf("node%d", i)
|
||||
vk, err := ks.Load(name)
|
||||
if err != nil {
|
||||
return network.Config{}, fmt.Errorf("failed to load validator key %s from %s: %w (run 'lux key generate' first)", name, keysDir, err)
|
||||
}
|
||||
|
||||
vk := validatorKeys[i]
|
||||
port := portBase + int(i)*2
|
||||
nodeConfigs[i] = node.Config{
|
||||
Flags: map[string]interface{}{
|
||||
@@ -477,11 +516,10 @@ func newCanonicalConfig(binaryPath string, numNodes uint32, networkID uint32, po
|
||||
UpgradeConfigFiles: map[string]string{},
|
||||
PChainConfigFiles: map[string]string{},
|
||||
}
|
||||
fmt.Printf(" Loaded validator %d: %s\n", i, vk.NodeID.String())
|
||||
}
|
||||
netConfig.NodeConfigs = nodeConfigs
|
||||
|
||||
fmt.Printf("✅ Loaded canonical genesis for network %d with %d validators\n", networkID, numNodes)
|
||||
fmt.Printf("✅ Loaded canonical genesis for network %d with %d validators (BLS keys patched)\n", networkID, numNodes)
|
||||
return netConfig, nil
|
||||
}
|
||||
|
||||
@@ -724,13 +762,13 @@ func NewConfigWithPreExistingKeys(binaryPath string, networkID uint32, keysDir s
|
||||
config.HTTPPortKey: port,
|
||||
config.StakingPortKey: port + 1,
|
||||
},
|
||||
StakingKey: string(vk.StakerKey),
|
||||
StakingCert: string(vk.StakerCert),
|
||||
StakingSigningKey: base64.StdEncoding.EncodeToString(vk.BLSSecretKey),
|
||||
IsBeacon: true,
|
||||
ChainConfigFiles: map[string]string{},
|
||||
StakingKey: string(vk.StakerKey),
|
||||
StakingCert: string(vk.StakerCert),
|
||||
StakingSigningKey: base64.StdEncoding.EncodeToString(vk.BLSSecretKey),
|
||||
IsBeacon: true,
|
||||
ChainConfigFiles: map[string]string{},
|
||||
UpgradeConfigFiles: map[string]string{},
|
||||
PChainConfigFiles: map[string]string{},
|
||||
PChainConfigFiles: map[string]string{},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1016,8 +1054,7 @@ func NewConfigFromMnemonic(binaryPath string, networkID uint32, numNodes uint32)
|
||||
// Add per-node specific flags
|
||||
nodeFlags[config.HTTPPortKey] = port
|
||||
nodeFlags[config.StakingPortKey] = port + 1
|
||||
// Enable sybil protection for mainnet - validators have proper keys
|
||||
// The genesis validators have matching NodeIDs from deterministic TLS certs
|
||||
// Sybil protection MUST be enabled - validators come from genesis initialStakers
|
||||
nodeFlags[config.SybilProtectionEnabledKey] = true
|
||||
|
||||
netConfig.NodeConfigs[i] = node.Config{
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@ import (
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/luxfi/const"
|
||||
constants "github.com/luxfi/const"
|
||||
"github.com/luxfi/log"
|
||||
"github.com/luxfi/netrunner/network/node"
|
||||
"github.com/luxfi/netrunner/utils"
|
||||
|
||||
@@ -13,9 +13,9 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/luxfi/genesis/configs"
|
||||
"github.com/luxfi/netrunner/local"
|
||||
"github.com/luxfi/log"
|
||||
"github.com/luxfi/log/level"
|
||||
"github.com/luxfi/netrunner/local"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
|
||||
+65
-65
@@ -1,72 +1,72 @@
|
||||
package local
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/btcutil/hdkeychain"
|
||||
"github.com/btcsuite/btcd/chaincfg"
|
||||
"github.com/luxfi/go-bip39"
|
||||
luxcrypto "github.com/luxfi/crypto/secp256k1"
|
||||
"golang.org/x/crypto/sha3"
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/btcutil/hdkeychain"
|
||||
"github.com/btcsuite/btcd/chaincfg"
|
||||
luxcrypto "github.com/luxfi/crypto/secp256k1"
|
||||
"github.com/luxfi/go-bip39"
|
||||
"golang.org/x/crypto/sha3"
|
||||
)
|
||||
|
||||
func TestMnemonicDerivation(t *testing.T) {
|
||||
mnemonic := os.Getenv("LUX_MNEMONIC")
|
||||
if mnemonic == "" {
|
||||
t.Skip("LUX_MNEMONIC not set")
|
||||
}
|
||||
|
||||
fmt.Printf("Mnemonic: %s...\n", mnemonic[:20])
|
||||
|
||||
if !bip39.IsMnemonicValid(mnemonic) {
|
||||
t.Fatal("Invalid mnemonic")
|
||||
}
|
||||
|
||||
seed := bip39.NewSeed(mnemonic, "")
|
||||
|
||||
// Derive using BIP44 m/44'/60'/0'/0/0
|
||||
masterKey, _ := hdkeychain.NewMaster(seed, &chaincfg.MainNetParams)
|
||||
purpose, _ := masterKey.Derive(hdkeychain.HardenedKeyStart + 44)
|
||||
coinType, _ := purpose.Derive(hdkeychain.HardenedKeyStart + 60)
|
||||
account, _ := coinType.Derive(hdkeychain.HardenedKeyStart + 0)
|
||||
change, _ := account.Derive(0)
|
||||
addressKey, _ := change.Derive(0)
|
||||
|
||||
ecPrivKey, _ := addressKey.ECPrivKey()
|
||||
privKeyBytes := ecPrivKey.Serialize()
|
||||
|
||||
privKey, err := luxcrypto.ToPrivateKey(privKeyBytes)
|
||||
if err != nil {
|
||||
t.Fatalf("Error: %v", err)
|
||||
}
|
||||
pubKey := privKey.PublicKey()
|
||||
shortID := pubKey.Address()
|
||||
|
||||
// Get Ethereum address
|
||||
pubKeyBytes := pubKey.Bytes()
|
||||
hash := sha3.NewLegacyKeccak256()
|
||||
hash.Write(pubKeyBytes[1:]) // skip the 0x04 prefix
|
||||
ethAddr := hash.Sum(nil)[12:]
|
||||
|
||||
fmt.Printf("\n=== Key Derivation Results (m/44'/60'/0'/0/0) ===\n")
|
||||
fmt.Printf("Lux Short ID: %s\n", shortID.String())
|
||||
fmt.Printf("Ethereum Address: 0x%x\n", ethAddr)
|
||||
fmt.Printf("Expected Treasury: 0x9011E888251AB053B7bD1cdB598Db4f9DEd94714\n")
|
||||
|
||||
// Also derive using coin type 9000 for comparison
|
||||
coinType9000, _ := purpose.Derive(hdkeychain.HardenedKeyStart + 9000)
|
||||
account9000, _ := coinType9000.Derive(hdkeychain.HardenedKeyStart + 0)
|
||||
change9000, _ := account9000.Derive(0)
|
||||
addressKey9000, _ := change9000.Derive(0)
|
||||
ecPrivKey9000, _ := addressKey9000.ECPrivKey()
|
||||
privKey9000, _ := luxcrypto.ToPrivateKey(ecPrivKey9000.Serialize())
|
||||
shortID9000 := privKey9000.PublicKey().Address()
|
||||
|
||||
fmt.Printf("\n=== Comparison: Coin Type 9000 (m/44'/9000'/0'/0/0) ===\n")
|
||||
fmt.Printf("Lux Short ID (9000): %s\n", shortID9000.String())
|
||||
|
||||
fmt.Printf("\n=== Genesis Treasury P-chain Address ===\n")
|
||||
fmt.Printf("Expected: P-lux1jqg73zp9r2c98daarnd4nrd5l80dj3c5eha5fl\n")
|
||||
mnemonic := os.Getenv("LUX_MNEMONIC")
|
||||
if mnemonic == "" {
|
||||
t.Skip("LUX_MNEMONIC not set")
|
||||
}
|
||||
|
||||
fmt.Printf("Mnemonic: %s...\n", mnemonic[:20])
|
||||
|
||||
if !bip39.IsMnemonicValid(mnemonic) {
|
||||
t.Fatal("Invalid mnemonic")
|
||||
}
|
||||
|
||||
seed := bip39.NewSeed(mnemonic, "")
|
||||
|
||||
// Derive using BIP44 m/44'/60'/0'/0/0
|
||||
masterKey, _ := hdkeychain.NewMaster(seed, &chaincfg.MainNetParams)
|
||||
purpose, _ := masterKey.Derive(hdkeychain.HardenedKeyStart + 44)
|
||||
coinType, _ := purpose.Derive(hdkeychain.HardenedKeyStart + 60)
|
||||
account, _ := coinType.Derive(hdkeychain.HardenedKeyStart + 0)
|
||||
change, _ := account.Derive(0)
|
||||
addressKey, _ := change.Derive(0)
|
||||
|
||||
ecPrivKey, _ := addressKey.ECPrivKey()
|
||||
privKeyBytes := ecPrivKey.Serialize()
|
||||
|
||||
privKey, err := luxcrypto.ToPrivateKey(privKeyBytes)
|
||||
if err != nil {
|
||||
t.Fatalf("Error: %v", err)
|
||||
}
|
||||
pubKey := privKey.PublicKey()
|
||||
shortID := pubKey.Address()
|
||||
|
||||
// Get Ethereum address
|
||||
pubKeyBytes := pubKey.Bytes()
|
||||
hash := sha3.NewLegacyKeccak256()
|
||||
hash.Write(pubKeyBytes[1:]) // skip the 0x04 prefix
|
||||
ethAddr := hash.Sum(nil)[12:]
|
||||
|
||||
fmt.Printf("\n=== Key Derivation Results (m/44'/60'/0'/0/0) ===\n")
|
||||
fmt.Printf("Lux Short ID: %s\n", shortID.String())
|
||||
fmt.Printf("Ethereum Address: 0x%x\n", ethAddr)
|
||||
fmt.Printf("Expected Treasury: 0x9011E888251AB053B7bD1cdB598Db4f9DEd94714\n")
|
||||
|
||||
// Also derive using coin type 9000 for comparison
|
||||
coinType9000, _ := purpose.Derive(hdkeychain.HardenedKeyStart + 9000)
|
||||
account9000, _ := coinType9000.Derive(hdkeychain.HardenedKeyStart + 0)
|
||||
change9000, _ := account9000.Derive(0)
|
||||
addressKey9000, _ := change9000.Derive(0)
|
||||
ecPrivKey9000, _ := addressKey9000.ECPrivKey()
|
||||
privKey9000, _ := luxcrypto.ToPrivateKey(ecPrivKey9000.Serialize())
|
||||
shortID9000 := privKey9000.PublicKey().Address()
|
||||
|
||||
fmt.Printf("\n=== Comparison: Coin Type 9000 (m/44'/9000'/0'/0/0) ===\n")
|
||||
fmt.Printf("Lux Short ID (9000): %s\n", shortID9000.String())
|
||||
|
||||
fmt.Printf("\n=== Genesis Treasury P-chain Address ===\n")
|
||||
fmt.Printf("Expected: P-lux1jqg73zp9r2c98daarnd4nrd5l80dj3c5eha5fl\n")
|
||||
}
|
||||
|
||||
+23
-22
@@ -19,6 +19,9 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"maps"
|
||||
"slices"
|
||||
|
||||
luxconfig "github.com/luxfi/config"
|
||||
"github.com/luxfi/crypto/bls"
|
||||
luxcrypto "github.com/luxfi/crypto/secp256k1"
|
||||
@@ -36,8 +39,6 @@ import (
|
||||
"github.com/luxfi/node/network/peer"
|
||||
"github.com/luxfi/node/staking"
|
||||
"github.com/luxfi/node/utils/beacon"
|
||||
"maps"
|
||||
"slices"
|
||||
|
||||
"github.com/luxfi/node/utils/formatting/address"
|
||||
"github.com/luxfi/node/utils/wrappers"
|
||||
@@ -55,12 +56,12 @@ const (
|
||||
genesisFileName = "genesis.json"
|
||||
stopTimeout = 30 * time.Second
|
||||
// healthCheckFreq reduced from 3s to 1s for faster health polling
|
||||
healthCheckFreq = 1 * time.Second
|
||||
DefaultNumNodes = 5
|
||||
snapshotPrefix = "lux-snapshot-"
|
||||
networkRootDirPrefix = "network"
|
||||
defaultDBSubdir = "db"
|
||||
defaultLogsSubdir = "logs"
|
||||
healthCheckFreq = 1 * time.Second
|
||||
DefaultNumNodes = 5
|
||||
snapshotPrefix = "lux-snapshot-"
|
||||
networkRootDirPrefix = "network"
|
||||
defaultDBSubdir = "db"
|
||||
defaultLogsSubdir = "logs"
|
||||
// difference between unlock schedule locktime and startime in original genesis
|
||||
genesisLocktimeStartimeDelta = 2836800
|
||||
)
|
||||
@@ -75,8 +76,8 @@ var (
|
||||
config.BootstrapIPsKey: {},
|
||||
config.BootstrapIDsKey: {},
|
||||
}
|
||||
chainConfigSubDir = "chainConfigs"
|
||||
pChainConfigSubDir = "pChainConfigs"
|
||||
chainConfigSubDir = "chainConfigs"
|
||||
pChainConfigSubDir = "pChainConfigs"
|
||||
|
||||
snapshotsRelPath = filepath.Join(".netrunner", "snapshots")
|
||||
|
||||
@@ -85,7 +86,7 @@ var (
|
||||
|
||||
// network keeps information uses for network management, and accessing all the nodes
|
||||
type localNetwork struct {
|
||||
lock sync.RWMutex
|
||||
lock sync.RWMutex
|
||||
logger log.Logger
|
||||
// This network's ID.
|
||||
networkID uint32
|
||||
@@ -261,7 +262,7 @@ func init() {
|
||||
"C": string(cChainConfig),
|
||||
},
|
||||
UpgradeConfigFiles: map[string]string{},
|
||||
PChainConfigFiles: map[string]string{},
|
||||
PChainConfigFiles: map[string]string{},
|
||||
}
|
||||
|
||||
for i := 0; i < len(defaultNetworkConfig.NodeConfigs); i++ {
|
||||
@@ -366,16 +367,16 @@ func newNetwork(
|
||||
}
|
||||
// Create the network
|
||||
net := &localNetwork{
|
||||
nextNodeSuffix: 1,
|
||||
nodes: map[string]*localNode{},
|
||||
onStopCh: make(chan struct{}),
|
||||
logger: logger,
|
||||
bootstraps: beacon.NewSet(),
|
||||
newAPIClientF: newAPIClientF,
|
||||
nodeProcessCreator: nodeProcessCreator,
|
||||
rootDir: rootDir,
|
||||
snapshotsDir: snapshotsDir,
|
||||
reassignPortsIfUsed: reassignPortsIfUsed,
|
||||
nextNodeSuffix: 1,
|
||||
nodes: map[string]*localNode{},
|
||||
onStopCh: make(chan struct{}),
|
||||
logger: logger,
|
||||
bootstraps: beacon.NewSet(),
|
||||
newAPIClientF: newAPIClientF,
|
||||
nodeProcessCreator: nodeProcessCreator,
|
||||
rootDir: rootDir,
|
||||
snapshotsDir: snapshotsDir,
|
||||
reassignPortsIfUsed: reassignPortsIfUsed,
|
||||
chainID2ElasticChainID: map[ids.ID]ids.ID{},
|
||||
}
|
||||
return net, nil
|
||||
|
||||
+14
-14
@@ -13,6 +13,8 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/luxfi/ids"
|
||||
"github.com/luxfi/log"
|
||||
"github.com/luxfi/netrunner/api"
|
||||
apimocks "github.com/luxfi/netrunner/api/mocks"
|
||||
"github.com/luxfi/netrunner/local/mocks"
|
||||
@@ -23,10 +25,8 @@ import (
|
||||
"github.com/luxfi/netrunner/utils"
|
||||
"github.com/luxfi/node/api/health"
|
||||
"github.com/luxfi/node/config"
|
||||
"github.com/luxfi/ids"
|
||||
"github.com/luxfi/node/message"
|
||||
"github.com/luxfi/node/network/peer"
|
||||
"github.com/luxfi/log"
|
||||
"github.com/luxfi/node/utils/rpc"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"github.com/stretchr/testify/require"
|
||||
@@ -38,12 +38,12 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
_ NodeProcessCreator = &localTestSuccessfulNodeProcessCreator{}
|
||||
_ NodeProcessCreator = &localTestFailedStartProcessCreator{}
|
||||
_ NodeProcessCreator = &localTestProcessUndefNodeProcessCreator{}
|
||||
_ NodeProcessCreator = &localTestFlagCheckProcessCreator{}
|
||||
_ api.NewAPIClientF = newMockAPISuccessful
|
||||
_ api.NewAPIClientF = newMockAPIUnhealthy
|
||||
_ NodeProcessCreator = &localTestSuccessfulNodeProcessCreator{}
|
||||
_ NodeProcessCreator = &localTestFailedStartProcessCreator{}
|
||||
_ NodeProcessCreator = &localTestProcessUndefNodeProcessCreator{}
|
||||
_ NodeProcessCreator = &localTestFlagCheckProcessCreator{}
|
||||
_ api.NewAPIClientF = newMockAPISuccessful
|
||||
_ api.NewAPIClientF = newMockAPIUnhealthy
|
||||
_ peer.InboundHandler = &noOpInboundHandler{}
|
||||
)
|
||||
|
||||
@@ -1185,9 +1185,9 @@ func TestWriteFiles(t *testing.T) {
|
||||
config.StakingTLSKeyPathKey: stakingKeyPath,
|
||||
config.StakingCertPathKey: stakingCertPath,
|
||||
config.StakingSignerKeyPathKey: stakingSigningKeyPath,
|
||||
config.GenesisFileKey: genesisPath,
|
||||
config.GenesisFileKey: genesisPath,
|
||||
config.ChainConfigDirKey: chainConfigDir,
|
||||
config.NetConfigDirKey: subnetConfigDir,
|
||||
config.NetConfigDirKey: subnetConfigDir,
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -1203,9 +1203,9 @@ func TestWriteFiles(t *testing.T) {
|
||||
config.StakingTLSKeyPathKey: stakingKeyPath,
|
||||
config.StakingCertPathKey: stakingCertPath,
|
||||
config.StakingSignerKeyPathKey: stakingSigningKeyPath,
|
||||
config.GenesisFileKey: genesisPath,
|
||||
config.GenesisFileKey: genesisPath,
|
||||
config.ChainConfigDirKey: chainConfigDir,
|
||||
config.NetConfigDirKey: subnetConfigDir,
|
||||
config.NetConfigDirKey: subnetConfigDir,
|
||||
config.ConfigFileKey: configFilePath,
|
||||
},
|
||||
},
|
||||
@@ -1223,9 +1223,9 @@ func TestWriteFiles(t *testing.T) {
|
||||
config.StakingTLSKeyPathKey: stakingKeyPath,
|
||||
config.StakingCertPathKey: stakingCertPath,
|
||||
config.StakingSignerKeyPathKey: stakingSigningKeyPath,
|
||||
config.GenesisFileKey: genesisPath,
|
||||
config.GenesisFileKey: genesisPath,
|
||||
config.ChainConfigDirKey: chainConfigDir,
|
||||
config.NetConfigDirKey: subnetConfigDir,
|
||||
config.NetConfigDirKey: subnetConfigDir,
|
||||
config.ConfigFileKey: configFilePath,
|
||||
},
|
||||
},
|
||||
|
||||
+8
-8
@@ -9,23 +9,23 @@ import (
|
||||
"net/netip"
|
||||
"time"
|
||||
|
||||
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"
|
||||
"github.com/luxfi/netrunner/api"
|
||||
"github.com/luxfi/netrunner/network/node"
|
||||
"github.com/luxfi/netrunner/network/node/status"
|
||||
"github.com/luxfi/const"
|
||||
"github.com/luxfi/ids"
|
||||
"github.com/luxfi/node/message"
|
||||
"github.com/luxfi/node/network/peer"
|
||||
"github.com/luxfi/node/network/throttling"
|
||||
"github.com/luxfi/node/network/tracker"
|
||||
"github.com/luxfi/node/utils/compression"
|
||||
"github.com/luxfi/consensus/validator" // package name is validators
|
||||
"github.com/luxfi/node/staking"
|
||||
"github.com/luxfi/node/utils"
|
||||
"github.com/luxfi/crypto/bls"
|
||||
"github.com/luxfi/log"
|
||||
"github.com/luxfi/math/set"
|
||||
"github.com/luxfi/metric"
|
||||
"github.com/luxfi/node/utils/compression"
|
||||
"github.com/luxfi/node/version"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
@@ -8,10 +8,10 @@ import (
|
||||
"os/exec"
|
||||
"sync"
|
||||
|
||||
"github.com/luxfi/log"
|
||||
"github.com/luxfi/netrunner/network/node"
|
||||
"github.com/luxfi/netrunner/network/node/status"
|
||||
"github.com/luxfi/netrunner/utils"
|
||||
"github.com/luxfi/log"
|
||||
"github.com/shirou/gopsutil/process"
|
||||
)
|
||||
|
||||
@@ -81,10 +81,10 @@ func (npc *nodeProcessCreator) NewNodeProcess(config node.Config, args ...string
|
||||
}
|
||||
|
||||
type nodeProcess struct {
|
||||
name string
|
||||
logger log.Logger
|
||||
lock sync.RWMutex
|
||||
cmd *exec.Cmd
|
||||
name string
|
||||
logger log.Logger
|
||||
lock sync.RWMutex
|
||||
cmd *exec.Cmd
|
||||
// Process status
|
||||
state status.Status
|
||||
// Closed when the process exits.
|
||||
|
||||
+3
-5
@@ -15,18 +15,16 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/luxfi/netrunner/network/node"
|
||||
constants "github.com/luxfi/const"
|
||||
"github.com/luxfi/geth/metrics"
|
||||
"github.com/luxfi/ids"
|
||||
"github.com/luxfi/netrunner/network/node"
|
||||
"github.com/luxfi/node/message"
|
||||
"github.com/luxfi/node/network/peer"
|
||||
"github.com/luxfi/node/staking"
|
||||
"github.com/luxfi/const"
|
||||
"github.com/luxfi/node/utils/ips"
|
||||
luxlog "github.com/luxfi/log"
|
||||
"github.com/luxfi/node/utils/wrappers"
|
||||
"github.com/luxfi/node/version"
|
||||
"github.com/luxfi/metric"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
|
||||
+4
-3
@@ -9,16 +9,17 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"maps"
|
||||
"slices"
|
||||
|
||||
luxconfig "github.com/luxfi/config"
|
||||
"github.com/luxfi/const"
|
||||
constants "github.com/luxfi/const"
|
||||
"github.com/luxfi/ids"
|
||||
"github.com/luxfi/log"
|
||||
"github.com/luxfi/netrunner/api"
|
||||
"github.com/luxfi/netrunner/network"
|
||||
"github.com/luxfi/netrunner/network/node"
|
||||
"github.com/luxfi/netrunner/utils"
|
||||
"maps"
|
||||
"slices"
|
||||
|
||||
"github.com/luxfi/node/config"
|
||||
dircopy "github.com/otiai10/copy"
|
||||
|
||||
@@ -31,11 +31,11 @@ func (w *walletClient) IssueTx(tx *txs.Tx, options ...common.Option) error {
|
||||
if ctx == nil {
|
||||
ctx = context.Background()
|
||||
}
|
||||
|
||||
|
||||
// Serialize the transaction
|
||||
txBytes := tx.Bytes()
|
||||
|
||||
|
||||
// Issue through platform client
|
||||
_, err := w.platformClient.IssueTx(ctx, txBytes)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
+30
-30
@@ -9,9 +9,9 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/dgraph-io/badger/v4"
|
||||
"github.com/luxfi/netrunner/network"
|
||||
"github.com/luxfi/ids"
|
||||
"github.com/luxfi/log"
|
||||
"github.com/luxfi/netrunner/network"
|
||||
)
|
||||
|
||||
// NetworkType represents the type of network
|
||||
@@ -19,29 +19,29 @@ type NetworkType string
|
||||
|
||||
const (
|
||||
NetworkTypePrimary NetworkType = "primary" // Mainnet or Testnet
|
||||
NetworkTypeChain NetworkType = "chain" // L1/L2 chains
|
||||
NetworkTypeChain NetworkType = "chain" // L1/L2 chains
|
||||
)
|
||||
|
||||
// NetworkConfig defines configuration for a single network
|
||||
type NetworkConfig struct {
|
||||
NetworkID uint32 `json:"networkID"`
|
||||
Name string `json:"name"`
|
||||
Type NetworkType `json:"type"`
|
||||
ParentID uint32 `json:"parentID,omitempty"` // For chains
|
||||
HTTPPort int `json:"httpPort"`
|
||||
StakingPort int `json:"stakingPort"`
|
||||
DataDir string `json:"dataDir"`
|
||||
Validators int `json:"validators"`
|
||||
NetworkID uint32 `json:"networkID"`
|
||||
Name string `json:"name"`
|
||||
Type NetworkType `json:"type"`
|
||||
ParentID uint32 `json:"parentID,omitempty"` // For chains
|
||||
HTTPPort int `json:"httpPort"`
|
||||
StakingPort int `json:"stakingPort"`
|
||||
DataDir string `json:"dataDir"`
|
||||
Validators int `json:"validators"`
|
||||
ChainConfig []ChainConfig `json:"chains,omitempty"`
|
||||
}
|
||||
|
||||
// ChainConfig defines configuration for a chain within a network
|
||||
type ChainConfig struct {
|
||||
ChainID string `json:"chainID"`
|
||||
VMID string `json:"vmID"`
|
||||
PChainID string `json:"pChainID,omitempty"`
|
||||
Genesis []byte `json:"genesis,omitempty"`
|
||||
IsEVM bool `json:"isEVM"`
|
||||
ChainID string `json:"chainID"`
|
||||
VMID string `json:"vmID"`
|
||||
PChainID string `json:"pChainID,omitempty"`
|
||||
Genesis []byte `json:"genesis,omitempty"`
|
||||
IsEVM bool `json:"isEVM"`
|
||||
}
|
||||
|
||||
// MultiNetworkManager manages multiple networks running in parallel
|
||||
@@ -73,7 +73,7 @@ type NetworkInstance struct {
|
||||
Config NetworkConfig
|
||||
Network network.Network
|
||||
Status NetworkStatus
|
||||
Chains map[string]*ChainInstance
|
||||
Chains map[string]*ChainInstance
|
||||
StartTime time.Time
|
||||
}
|
||||
|
||||
@@ -107,13 +107,13 @@ type ConsensusManager struct {
|
||||
|
||||
// ConsensusParams defines consensus parameters
|
||||
type ConsensusParams struct {
|
||||
K int `json:"k"`
|
||||
Alpha int `json:"alpha"`
|
||||
BetaVirtuous int `json:"betaVirtuous"`
|
||||
BetaRogue int `json:"betaRogue"`
|
||||
ConcurrentPolls int `json:"concurrentPolls"`
|
||||
OptimalProcessing int `json:"optimalProcessing"`
|
||||
MaxProcessing int `json:"maxProcessing"`
|
||||
K int `json:"k"`
|
||||
Alpha int `json:"alpha"`
|
||||
BetaVirtuous int `json:"betaVirtuous"`
|
||||
BetaRogue int `json:"betaRogue"`
|
||||
ConcurrentPolls int `json:"concurrentPolls"`
|
||||
OptimalProcessing int `json:"optimalProcessing"`
|
||||
MaxProcessing int `json:"maxProcessing"`
|
||||
MaxTimeProcessing time.Duration `json:"maxTimeProcessing"`
|
||||
}
|
||||
|
||||
@@ -146,10 +146,10 @@ type CrossChainTx struct {
|
||||
type TxStatus string
|
||||
|
||||
const (
|
||||
TxStatusPending TxStatus = "pending"
|
||||
TxStatusPending TxStatus = "pending"
|
||||
TxStatusValidating TxStatus = "validating"
|
||||
TxStatusCommitted TxStatus = "committed"
|
||||
TxStatusFailed TxStatus = "failed"
|
||||
TxStatusCommitted TxStatus = "committed"
|
||||
TxStatusFailed TxStatus = "failed"
|
||||
)
|
||||
|
||||
// NewMultiNetworkManager creates a new multi-network manager
|
||||
@@ -170,7 +170,7 @@ func NewMultiNetworkManager(logger log.Logger, sharedDBPath string) (*MultiNetwo
|
||||
networks: make(map[uint32]*NetworkInstance),
|
||||
consensusManagers: make(map[uint32]*ConsensusManager),
|
||||
txCoordinator: NewCrossChainTxCoordinator(sharedDB),
|
||||
logger: logger,
|
||||
logger: logger,
|
||||
ctx: ctx,
|
||||
cancel: cancel,
|
||||
}, nil
|
||||
@@ -195,8 +195,8 @@ func (m *MultiNetworkManager) AddNetwork(config NetworkConfig) error {
|
||||
}
|
||||
|
||||
instance := &NetworkInstance{
|
||||
Config: config,
|
||||
Status: NetworkStatusStopped,
|
||||
Config: config,
|
||||
Status: NetworkStatusStopped,
|
||||
Chains: make(map[string]*ChainInstance),
|
||||
}
|
||||
|
||||
@@ -471,4 +471,4 @@ func (m *MultiNetworkManager) Shutdown() error {
|
||||
|
||||
m.logger.Info("Multi-network manager shutdown complete")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
+5
-4
@@ -8,11 +8,12 @@ import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/luxfi/const"
|
||||
"maps"
|
||||
|
||||
constants "github.com/luxfi/const"
|
||||
"github.com/luxfi/genesis/pkg/genesis"
|
||||
"github.com/luxfi/ids"
|
||||
"github.com/luxfi/netrunner/network/node"
|
||||
"maps"
|
||||
|
||||
"github.com/luxfi/netrunner/utils"
|
||||
"github.com/luxfi/node/utils/formatting/address"
|
||||
@@ -152,8 +153,8 @@ func NewGenesis(
|
||||
NetworkID: networkID,
|
||||
Allocations: []genesis.UnparsedAllocation{
|
||||
{
|
||||
ETHAddr: zeroEthAddr, // Zero address as hex string
|
||||
LUXAddr: genesisVdrStakeAddr, // Bech32 formatted address
|
||||
ETHAddr: zeroEthAddr, // Zero address as hex string
|
||||
LUXAddr: genesisVdrStakeAddr, // Bech32 formatted address
|
||||
InitialAmount: 0,
|
||||
UnlockSchedule: []genesis.LockedAmount{ // Provides stake to validators
|
||||
{
|
||||
|
||||
+1
-1
@@ -5,8 +5,8 @@ import (
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/luxfi/netrunner/network/node"
|
||||
"github.com/luxfi/ids"
|
||||
"github.com/luxfi/netrunner/network/node"
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
@@ -6,10 +6,10 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/luxfi/ids"
|
||||
"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"
|
||||
)
|
||||
|
||||
|
||||
+46
-46
@@ -16,12 +16,12 @@ import (
|
||||
|
||||
// Host manages multiple consensus engines
|
||||
type Host struct {
|
||||
mu sync.RWMutex
|
||||
engines map[string]engines.Engine
|
||||
ports *PortManager
|
||||
indexer *Indexer
|
||||
metrics *MetricsCollector
|
||||
networks map[string]*NetworkInfo
|
||||
mu sync.RWMutex
|
||||
engines map[string]engines.Engine
|
||||
ports *PortManager
|
||||
indexer *Indexer
|
||||
metrics *MetricsCollector
|
||||
networks map[string]*NetworkInfo
|
||||
}
|
||||
|
||||
// NetworkInfo describes a network's properties
|
||||
@@ -62,12 +62,12 @@ type EngineOptions struct {
|
||||
func (h *Host) StartEngine(ctx context.Context, name string, typ string, options *EngineOptions) error {
|
||||
h.mu.Lock()
|
||||
defer h.mu.Unlock()
|
||||
|
||||
|
||||
// Check if already running
|
||||
if _, exists := h.engines[name]; exists {
|
||||
return fmt.Errorf("engine %s already running", name)
|
||||
}
|
||||
|
||||
|
||||
// Convert options to NodeConfig
|
||||
config := &engines.NodeConfig{
|
||||
NetworkID: options.NetworkID,
|
||||
@@ -79,7 +79,7 @@ func (h *Host) StartEngine(ctx context.Context, name string, typ string, options
|
||||
BootstrapIPs: options.BootstrapIPs,
|
||||
Extra: options.Extra,
|
||||
}
|
||||
|
||||
|
||||
// Allocate ports if not specified
|
||||
if config.HTTPPort == 0 {
|
||||
config.HTTPPort = h.ports.AllocateHTTP()
|
||||
@@ -90,22 +90,22 @@ func (h *Host) StartEngine(ctx context.Context, name string, typ string, options
|
||||
if config.StakingPort == 0 {
|
||||
config.StakingPort = h.ports.AllocateP2P()
|
||||
}
|
||||
|
||||
|
||||
// Create engine using factory
|
||||
engine, err := engines.New(engines.EngineType(typ), name, options.Binary)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create engine: %w", err)
|
||||
}
|
||||
|
||||
|
||||
// Start engine
|
||||
if err := engine.Start(ctx, config); err != nil {
|
||||
h.ports.Release(config.HTTPPort)
|
||||
h.ports.Release(config.StakingPort)
|
||||
return fmt.Errorf("failed to start engine: %w", err)
|
||||
}
|
||||
|
||||
|
||||
h.engines[name] = engine
|
||||
|
||||
|
||||
// Register network info
|
||||
h.networks[name] = &NetworkInfo{
|
||||
Name: name,
|
||||
@@ -115,10 +115,10 @@ func (h *Host) StartEngine(ctx context.Context, name string, typ string, options
|
||||
RPC: engine.RPCEndpoint(),
|
||||
WS: engine.WSEndpoint(),
|
||||
}
|
||||
|
||||
|
||||
// Start metrics collection
|
||||
go h.collectMetrics(name, engine)
|
||||
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -126,19 +126,19 @@ func (h *Host) StartEngine(ctx context.Context, name string, typ string, options
|
||||
func (h *Host) StopEngine(ctx context.Context, name string) error {
|
||||
h.mu.Lock()
|
||||
defer h.mu.Unlock()
|
||||
|
||||
|
||||
engine, exists := h.engines[name]
|
||||
if !exists {
|
||||
return fmt.Errorf("engine %s not found", name)
|
||||
}
|
||||
|
||||
|
||||
if err := engine.Stop(ctx); err != nil {
|
||||
return fmt.Errorf("failed to stop engine: %w", err)
|
||||
}
|
||||
|
||||
|
||||
delete(h.engines, name)
|
||||
delete(h.networks, name)
|
||||
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -146,7 +146,7 @@ func (h *Host) StopEngine(ctx context.Context, name string) error {
|
||||
func (h *Host) ListEngines() []EngineInfo {
|
||||
h.mu.RLock()
|
||||
defer h.mu.RUnlock()
|
||||
|
||||
|
||||
var infos []EngineInfo
|
||||
for name, engine := range h.engines {
|
||||
health, _ := engine.Health(context.Background())
|
||||
@@ -182,7 +182,7 @@ func (h *Host) StartStack(ctx context.Context, manifest *StackManifest) error {
|
||||
if err := manifest.Validate(); err != nil {
|
||||
return fmt.Errorf("invalid manifest: %w", err)
|
||||
}
|
||||
|
||||
|
||||
// Start engines in order (L1 first, then L2, then L3)
|
||||
for _, engine := range manifest.Engines {
|
||||
config := &engines.NodeConfig{
|
||||
@@ -194,7 +194,7 @@ func (h *Host) StartStack(ctx context.Context, manifest *StackManifest) error {
|
||||
BootstrapIPs: engine.BootstrapIPs,
|
||||
Extra: engine.Extra,
|
||||
}
|
||||
|
||||
|
||||
options := &EngineOptions{
|
||||
NetworkID: config.NetworkID,
|
||||
HTTPPort: config.HTTPPort,
|
||||
@@ -207,26 +207,26 @@ func (h *Host) StartStack(ctx context.Context, manifest *StackManifest) error {
|
||||
}
|
||||
if err := h.StartEngine(ctx, engine.Name, engine.Type, options); err != nil {
|
||||
// Rollback on failure
|
||||
h.StopStack(ctx, manifest.Name)
|
||||
_ = h.StopStack(ctx, manifest.Name)
|
||||
return fmt.Errorf("failed to start %s: %w", engine.Name, err)
|
||||
}
|
||||
|
||||
|
||||
// Wait for health before starting dependent engines
|
||||
if engine.WaitHealthy {
|
||||
if err := h.waitHealthy(ctx, engine.Name, 30*time.Second); err != nil {
|
||||
h.StopStack(ctx, manifest.Name)
|
||||
_ = h.StopStack(ctx, manifest.Name)
|
||||
return fmt.Errorf("engine %s failed health check: %w", engine.Name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Configure bridges if specified
|
||||
if manifest.Bridge != nil {
|
||||
if err := h.configureBridge(ctx, manifest.Bridge); err != nil {
|
||||
return fmt.Errorf("failed to configure bridge: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -240,7 +240,7 @@ func (h *Host) StopStack(ctx context.Context, stackName string) error {
|
||||
engines = append(engines, name)
|
||||
}
|
||||
h.mu.Unlock()
|
||||
|
||||
|
||||
var lastErr error
|
||||
for _, name := range engines {
|
||||
if err := h.StopEngine(ctx, name); err != nil {
|
||||
@@ -255,15 +255,15 @@ func (h *Host) waitHealthy(ctx context.Context, name string, timeout time.Durati
|
||||
h.mu.RLock()
|
||||
engine, exists := h.engines[name]
|
||||
h.mu.RUnlock()
|
||||
|
||||
|
||||
if !exists {
|
||||
return fmt.Errorf("engine %s not found", name)
|
||||
}
|
||||
|
||||
|
||||
deadline := time.Now().Add(timeout)
|
||||
ticker := time.NewTicker(1 * time.Second)
|
||||
defer ticker.Stop()
|
||||
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
@@ -294,7 +294,7 @@ func (h *Host) configureBridge(ctx context.Context, bridge *BridgeConfig) error
|
||||
func (h *Host) collectMetrics(name string, engine engines.Engine) {
|
||||
ticker := time.NewTicker(10 * time.Second)
|
||||
defer ticker.Stop()
|
||||
|
||||
|
||||
for range ticker.C {
|
||||
h.mu.RLock()
|
||||
if _, exists := h.engines[name]; !exists {
|
||||
@@ -302,7 +302,7 @@ func (h *Host) collectMetrics(name string, engine engines.Engine) {
|
||||
return // Engine stopped
|
||||
}
|
||||
h.mu.RUnlock()
|
||||
|
||||
|
||||
metrics := engine.Metrics()
|
||||
h.metrics.Record(name, metrics)
|
||||
}
|
||||
@@ -328,7 +328,7 @@ func (h *Host) StopAll(ctx context.Context) error {
|
||||
engines = append(engines, name)
|
||||
}
|
||||
h.mu.Unlock()
|
||||
|
||||
|
||||
var lastErr error
|
||||
for _, name := range engines {
|
||||
if err := h.StopEngine(ctx, name); err != nil {
|
||||
@@ -348,7 +348,7 @@ type EngineStatus struct {
|
||||
func (h *Host) GetAllStatus(ctx context.Context) (map[string]*EngineStatus, error) {
|
||||
h.mu.RLock()
|
||||
defer h.mu.RUnlock()
|
||||
|
||||
|
||||
statuses := make(map[string]*EngineStatus)
|
||||
for name, engine := range h.engines {
|
||||
health, err := engine.Health(ctx)
|
||||
@@ -375,12 +375,12 @@ func (h *Host) GetMetrics() map[string]*EngineMetrics {
|
||||
func (h *Host) SaveState(path string) error {
|
||||
h.mu.RLock()
|
||||
defer h.mu.RUnlock()
|
||||
|
||||
|
||||
state := &HostState{
|
||||
Engines: make(map[string]*EngineState),
|
||||
Networks: h.networks,
|
||||
}
|
||||
|
||||
|
||||
for name, engine := range h.engines {
|
||||
state.Engines[name] = &EngineState{
|
||||
Name: name,
|
||||
@@ -392,12 +392,12 @@ func (h *Host) SaveState(path string) error {
|
||||
Uptime: engine.Uptime().Seconds(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
data, err := json.MarshalIndent(state, "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
return os.WriteFile(path, data, 0644)
|
||||
}
|
||||
|
||||
@@ -407,25 +407,25 @@ func (h *Host) LoadState(path string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
var state HostState
|
||||
if err := json.Unmarshal(data, &state); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
h.mu.Lock()
|
||||
defer h.mu.Unlock()
|
||||
|
||||
|
||||
h.networks = state.Networks
|
||||
// Note: Engines need to be restarted separately
|
||||
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// HostState represents the persistent state of the host
|
||||
type HostState struct {
|
||||
Engines map[string]*EngineState `json:"engines"`
|
||||
Networks map[string]*NetworkInfo `json:"networks"`
|
||||
Engines map[string]*EngineState `json:"engines"`
|
||||
Networks map[string]*NetworkInfo `json:"networks"`
|
||||
}
|
||||
|
||||
// EngineState represents the state of an engine
|
||||
@@ -437,4 +437,4 @@ type EngineState struct {
|
||||
RPC string `json:"rpc"`
|
||||
WS string `json:"ws"`
|
||||
Uptime float64 `json:"uptime_seconds"`
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,7 +169,7 @@ func TestPortManager(t *testing.T) {
|
||||
|
||||
t.Run("ReservePorts", func(t *testing.T) {
|
||||
pm := orchestrator.NewPortManager()
|
||||
|
||||
|
||||
// Reserve specific ports
|
||||
err := pm.Reserve(20000, 20001, 20002)
|
||||
require.NoError(t, err)
|
||||
@@ -231,4 +231,4 @@ func TestMetricsCollector(t *testing.T) {
|
||||
require.Equal(t, 350.0, summary["total_uptime_seconds"])
|
||||
require.Equal(t, 2, summary["healthy_engines"])
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,8 +10,8 @@ import (
|
||||
|
||||
// Indexer provides cross-engine blockchain indexing
|
||||
type Indexer struct {
|
||||
mu sync.RWMutex
|
||||
data map[string]*IndexData
|
||||
mu sync.RWMutex
|
||||
data map[string]*IndexData
|
||||
}
|
||||
|
||||
// IndexData contains indexed blockchain data
|
||||
@@ -35,7 +35,7 @@ func NewIndexer() *Indexer {
|
||||
func (i *Indexer) Update(engine string, data *IndexData) {
|
||||
i.mu.Lock()
|
||||
defer i.mu.Unlock()
|
||||
|
||||
|
||||
data.Engine = engine
|
||||
data.LastUpdate = time.Now()
|
||||
i.data[engine] = data
|
||||
@@ -45,7 +45,7 @@ func (i *Indexer) Update(engine string, data *IndexData) {
|
||||
func (i *Indexer) Get(engine string) *IndexData {
|
||||
i.mu.RLock()
|
||||
defer i.mu.RUnlock()
|
||||
|
||||
|
||||
return i.data[engine]
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ func (i *Indexer) Get(engine string) *IndexData {
|
||||
func (i *Indexer) GetAll() map[string]*IndexData {
|
||||
i.mu.RLock()
|
||||
defer i.mu.RUnlock()
|
||||
|
||||
|
||||
result := make(map[string]*IndexData)
|
||||
for k, v := range i.data {
|
||||
result[k] = v
|
||||
@@ -65,6 +65,6 @@ func (i *Indexer) GetAll() map[string]*IndexData {
|
||||
func (i *Indexer) Clear(engine string) {
|
||||
i.mu.Lock()
|
||||
defer i.mu.Unlock()
|
||||
|
||||
|
||||
delete(i.data, engine)
|
||||
}
|
||||
}
|
||||
|
||||
+34
-34
@@ -15,12 +15,12 @@ import (
|
||||
|
||||
// StackManifest defines a multi-engine stack configuration
|
||||
type StackManifest struct {
|
||||
Name string `yaml:"name" json:"name"`
|
||||
Version string `yaml:"version" json:"version"`
|
||||
Description string `yaml:"description" json:"description"`
|
||||
Engines []EngineConfig `yaml:"engines" json:"engines"`
|
||||
Bridge *BridgeConfig `yaml:"bridge,omitempty" json:"bridge,omitempty"`
|
||||
Networks []NetworkConfig `yaml:"networks,omitempty" json:"networks,omitempty"`
|
||||
Name string `yaml:"name" json:"name"`
|
||||
Version string `yaml:"version" json:"version"`
|
||||
Description string `yaml:"description" json:"description"`
|
||||
Engines []EngineConfig `yaml:"engines" json:"engines"`
|
||||
Bridge *BridgeConfig `yaml:"bridge,omitempty" json:"bridge,omitempty"`
|
||||
Networks []NetworkConfig `yaml:"networks,omitempty" json:"networks,omitempty"`
|
||||
}
|
||||
|
||||
// EngineConfig defines an engine configuration
|
||||
@@ -38,23 +38,23 @@ type EngineConfig struct {
|
||||
Extra map[string]interface{} `yaml:"extra,omitempty" json:"extra,omitempty"`
|
||||
WaitHealthy bool `yaml:"wait_healthy,omitempty" json:"wait_healthy,omitempty"`
|
||||
DependsOn []string `yaml:"depends_on,omitempty" json:"depends_on,omitempty"`
|
||||
|
||||
|
||||
// OP Stack specific
|
||||
L1RPC string `yaml:"l1_rpc,omitempty" json:"l1_rpc,omitempty"`
|
||||
Sequencer bool `yaml:"sequencer,omitempty" json:"sequencer,omitempty"`
|
||||
|
||||
L1RPC string `yaml:"l1_rpc,omitempty" json:"l1_rpc,omitempty"`
|
||||
Sequencer bool `yaml:"sequencer,omitempty" json:"sequencer,omitempty"`
|
||||
|
||||
// Eth2 specific
|
||||
ConsensusClient string `yaml:"consensus_client,omitempty" json:"consensus_client,omitempty"`
|
||||
ExecutionClient string `yaml:"execution_client,omitempty" json:"execution_client,omitempty"`
|
||||
ValidatorEnabled bool `yaml:"validator_enabled,omitempty" json:"validator_enabled,omitempty"`
|
||||
ConsensusClient string `yaml:"consensus_client,omitempty" json:"consensus_client,omitempty"`
|
||||
ExecutionClient string `yaml:"execution_client,omitempty" json:"execution_client,omitempty"`
|
||||
ValidatorEnabled bool `yaml:"validator_enabled,omitempty" json:"validator_enabled,omitempty"`
|
||||
}
|
||||
|
||||
// BridgeConfig defines bridge configuration between engines
|
||||
type BridgeConfig struct {
|
||||
Type string `yaml:"type" json:"type"` // awm, ibc, ccip
|
||||
Source string `yaml:"source" json:"source"`
|
||||
Destination string `yaml:"destination" json:"destination"`
|
||||
RelayerKey string `yaml:"relayer_key,omitempty" json:"relayer_key,omitempty"`
|
||||
Type string `yaml:"type" json:"type"` // awm, ibc, ccip
|
||||
Source string `yaml:"source" json:"source"`
|
||||
Destination string `yaml:"destination" json:"destination"`
|
||||
RelayerKey string `yaml:"relayer_key,omitempty" json:"relayer_key,omitempty"`
|
||||
Contracts map[string]string `yaml:"contracts,omitempty" json:"contracts,omitempty"`
|
||||
}
|
||||
|
||||
@@ -73,11 +73,11 @@ func (m *StackManifest) Validate() error {
|
||||
if m.Name == "" {
|
||||
return fmt.Errorf("manifest name is required")
|
||||
}
|
||||
|
||||
|
||||
if len(m.Engines) == 0 {
|
||||
return fmt.Errorf("at least one engine is required")
|
||||
}
|
||||
|
||||
|
||||
// Check engine names are unique
|
||||
names := make(map[string]bool)
|
||||
for _, e := range m.Engines {
|
||||
@@ -88,7 +88,7 @@ func (m *StackManifest) Validate() error {
|
||||
return fmt.Errorf("duplicate engine name: %s", e.Name)
|
||||
}
|
||||
names[e.Name] = true
|
||||
|
||||
|
||||
// Validate engine type
|
||||
switch e.Type {
|
||||
case "lux", "geth", "op", "eth2":
|
||||
@@ -96,7 +96,7 @@ func (m *StackManifest) Validate() error {
|
||||
default:
|
||||
return fmt.Errorf("invalid engine type: %s", e.Type)
|
||||
}
|
||||
|
||||
|
||||
// Check dependencies exist
|
||||
for _, dep := range e.DependsOn {
|
||||
depFound := false
|
||||
@@ -111,13 +111,13 @@ func (m *StackManifest) Validate() error {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Validate bridge if present
|
||||
if m.Bridge != nil {
|
||||
if m.Bridge.Source == "" || m.Bridge.Destination == "" {
|
||||
return fmt.Errorf("bridge source and destination are required")
|
||||
}
|
||||
|
||||
|
||||
// Check source and destination exist
|
||||
sourceFound := false
|
||||
destFound := false
|
||||
@@ -136,7 +136,7 @@ func (m *StackManifest) Validate() error {
|
||||
return fmt.Errorf("bridge destination %s not found in engines", m.Bridge.Destination)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -146,19 +146,19 @@ func LoadManifest(path string) (*StackManifest, error) {
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read manifest: %w", err)
|
||||
}
|
||||
|
||||
|
||||
var manifest StackManifest
|
||||
|
||||
|
||||
// Try YAML first
|
||||
if err := yaml.Unmarshal(data, &manifest); err == nil {
|
||||
return &manifest, nil
|
||||
}
|
||||
|
||||
|
||||
// Try JSON
|
||||
if err := json.Unmarshal(data, &manifest); err == nil {
|
||||
return &manifest, nil
|
||||
}
|
||||
|
||||
|
||||
return nil, fmt.Errorf("failed to parse manifest as YAML or JSON")
|
||||
}
|
||||
|
||||
@@ -169,11 +169,11 @@ func (m *StackManifest) Save(path string) error {
|
||||
if err := os.MkdirAll(dir, 0755); err != nil {
|
||||
return fmt.Errorf("failed to create directory: %w", err)
|
||||
}
|
||||
|
||||
|
||||
// Marshal based on extension
|
||||
var data []byte
|
||||
var err error
|
||||
|
||||
|
||||
ext := filepath.Ext(path)
|
||||
switch ext {
|
||||
case ".json":
|
||||
@@ -184,14 +184,14 @@ func (m *StackManifest) Save(path string) error {
|
||||
// Default to YAML
|
||||
data, err = yaml.Marshal(m)
|
||||
}
|
||||
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal manifest: %w", err)
|
||||
}
|
||||
|
||||
|
||||
if err := ioutil.WriteFile(path, data, 0644); err != nil {
|
||||
return fmt.Errorf("failed to write manifest: %w", err)
|
||||
}
|
||||
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
+12
-12
@@ -39,7 +39,7 @@ func NewMetricsCollector() *MetricsCollector {
|
||||
func (mc *MetricsCollector) Record(engine string, values map[string]interface{}) {
|
||||
mc.mu.Lock()
|
||||
defer mc.mu.Unlock()
|
||||
|
||||
|
||||
em, exists := mc.metrics[engine]
|
||||
if !exists {
|
||||
em = &EngineMetrics{
|
||||
@@ -48,10 +48,10 @@ func (mc *MetricsCollector) Record(engine string, values map[string]interface{})
|
||||
}
|
||||
mc.metrics[engine] = em
|
||||
}
|
||||
|
||||
|
||||
em.LastUpdated = time.Now()
|
||||
em.Values = values
|
||||
|
||||
|
||||
// Add to history (keep last 100 snapshots)
|
||||
snapshot := MetricSnapshot{
|
||||
Timestamp: em.LastUpdated,
|
||||
@@ -67,7 +67,7 @@ func (mc *MetricsCollector) Record(engine string, values map[string]interface{})
|
||||
func (mc *MetricsCollector) Get(engine string) *EngineMetrics {
|
||||
mc.mu.RLock()
|
||||
defer mc.mu.RUnlock()
|
||||
|
||||
|
||||
return mc.metrics[engine]
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ func (mc *MetricsCollector) Get(engine string) *EngineMetrics {
|
||||
func (mc *MetricsCollector) GetAll() map[string]*EngineMetrics {
|
||||
mc.mu.RLock()
|
||||
defer mc.mu.RUnlock()
|
||||
|
||||
|
||||
result := make(map[string]*EngineMetrics)
|
||||
for k, v := range mc.metrics {
|
||||
result[k] = v
|
||||
@@ -87,7 +87,7 @@ func (mc *MetricsCollector) GetAll() map[string]*EngineMetrics {
|
||||
func (mc *MetricsCollector) Clear(engine string) {
|
||||
mc.mu.Lock()
|
||||
defer mc.mu.Unlock()
|
||||
|
||||
|
||||
delete(mc.metrics, engine)
|
||||
}
|
||||
|
||||
@@ -95,13 +95,13 @@ func (mc *MetricsCollector) Clear(engine string) {
|
||||
func (mc *MetricsCollector) Summary() map[string]interface{} {
|
||||
mc.mu.RLock()
|
||||
defer mc.mu.RUnlock()
|
||||
|
||||
|
||||
summary := make(map[string]interface{})
|
||||
summary["engines"] = len(mc.metrics)
|
||||
|
||||
|
||||
var totalUptime float64
|
||||
var healthyCount int
|
||||
|
||||
|
||||
for _, em := range mc.metrics {
|
||||
if uptime, ok := em.Values["uptime_seconds"].(float64); ok {
|
||||
totalUptime += uptime
|
||||
@@ -110,9 +110,9 @@ func (mc *MetricsCollector) Summary() map[string]interface{} {
|
||||
healthyCount++
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
summary["total_uptime_seconds"] = totalUptime
|
||||
summary["healthy_engines"] = healthyCount
|
||||
|
||||
|
||||
return summary
|
||||
}
|
||||
}
|
||||
|
||||
+12
-12
@@ -11,10 +11,10 @@ import (
|
||||
|
||||
// PortManager manages port allocation for engines
|
||||
type PortManager struct {
|
||||
mu sync.Mutex
|
||||
allocated map[uint16]bool
|
||||
httpBase uint16
|
||||
p2pBase uint16
|
||||
mu sync.Mutex
|
||||
allocated map[uint16]bool
|
||||
httpBase uint16
|
||||
p2pBase uint16
|
||||
}
|
||||
|
||||
// NewPortManager creates a new port manager
|
||||
@@ -30,12 +30,12 @@ func NewPortManager() *PortManager {
|
||||
func (pm *PortManager) AllocateHTTP() uint16 {
|
||||
pm.mu.Lock()
|
||||
defer pm.mu.Unlock()
|
||||
|
||||
|
||||
port := pm.httpBase
|
||||
for pm.isInUse(port) || pm.allocated[port] {
|
||||
port += 10 // Skip by 10 to avoid conflicts with P2P ports
|
||||
}
|
||||
|
||||
|
||||
pm.allocated[port] = true
|
||||
return port
|
||||
}
|
||||
@@ -44,12 +44,12 @@ func (pm *PortManager) AllocateHTTP() uint16 {
|
||||
func (pm *PortManager) AllocateP2P() uint16 {
|
||||
pm.mu.Lock()
|
||||
defer pm.mu.Unlock()
|
||||
|
||||
|
||||
port := pm.p2pBase
|
||||
for pm.isInUse(port) || pm.allocated[port] {
|
||||
port += 10
|
||||
}
|
||||
|
||||
|
||||
pm.allocated[port] = true
|
||||
return port
|
||||
}
|
||||
@@ -75,7 +75,7 @@ func (pm *PortManager) isInUse(port uint16) bool {
|
||||
func (pm *PortManager) Reserve(ports ...uint16) error {
|
||||
pm.mu.Lock()
|
||||
defer pm.mu.Unlock()
|
||||
|
||||
|
||||
// Check all ports are available first
|
||||
for _, port := range ports {
|
||||
if pm.allocated[port] {
|
||||
@@ -85,11 +85,11 @@ func (pm *PortManager) Reserve(ports ...uint16) error {
|
||||
return fmt.Errorf("port %d already in use", port)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Reserve all ports
|
||||
for _, port := range ports {
|
||||
pm.allocated[port] = true
|
||||
}
|
||||
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
+4
-3
@@ -7,12 +7,13 @@
|
||||
package rpcpb
|
||||
|
||||
import (
|
||||
_ "google.golang.org/genproto/googleapis/api/annotations"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
unsafe "unsafe"
|
||||
|
||||
_ "google.golang.org/genproto/googleapis/api/annotations"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
@@ -8,6 +8,7 @@ package rpcpb
|
||||
|
||||
import (
|
||||
context "context"
|
||||
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
|
||||
+22
-21
@@ -13,6 +13,10 @@ import (
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"maps"
|
||||
"slices"
|
||||
|
||||
"github.com/luxfi/ids"
|
||||
"github.com/luxfi/netrunner/local"
|
||||
"github.com/luxfi/netrunner/network"
|
||||
"github.com/luxfi/netrunner/network/node"
|
||||
@@ -20,9 +24,6 @@ import (
|
||||
"github.com/luxfi/netrunner/utils/constants"
|
||||
"github.com/luxfi/netrunner/ux"
|
||||
"github.com/luxfi/node/config"
|
||||
"github.com/luxfi/ids"
|
||||
"maps"
|
||||
"slices"
|
||||
|
||||
luxd_constants "github.com/luxfi/const"
|
||||
"github.com/luxfi/log"
|
||||
@@ -80,7 +81,7 @@ type localNetwork struct {
|
||||
|
||||
type chainInfo struct {
|
||||
info *rpcpb.CustomChainInfo
|
||||
chainID ids.ID
|
||||
chainID ids.ID
|
||||
blockchainID ids.ID
|
||||
}
|
||||
|
||||
@@ -88,7 +89,7 @@ type localNetworkOptions struct {
|
||||
execPath string
|
||||
rootDataDir string
|
||||
numNodes uint32
|
||||
trackChains string
|
||||
trackChains string
|
||||
redirectNodesOutput bool
|
||||
globalNodeConfig string
|
||||
|
||||
@@ -132,7 +133,7 @@ func newLocalNetwork(opts localNetworkOptions) (*localNetwork, error) {
|
||||
customChainIDToInfo: make(map[ids.ID]chainInfo),
|
||||
stopCh: make(chan struct{}),
|
||||
nodeInfos: make(map[string]*rpcpb.NodeInfo),
|
||||
chains: make(map[string]*rpcpb.ChainInfo),
|
||||
chains: make(map[string]*rpcpb.ChainInfo),
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -705,12 +706,12 @@ func (lc *localNetwork) updateChainInfo(ctx context.Context) error {
|
||||
}
|
||||
lc.customChainIDToInfo[blockchain.ID] = chainInfo{
|
||||
info: &rpcpb.CustomChainInfo{
|
||||
ChainName: blockchain.Name,
|
||||
VmId: blockchain.VMID.String(),
|
||||
PchainId: blockchain.NetID.String(),
|
||||
BlockchainId: blockchain.ID.String(),
|
||||
ChainName: blockchain.Name,
|
||||
VmId: blockchain.VMID.String(),
|
||||
PchainId: blockchain.NetID.String(),
|
||||
BlockchainId: blockchain.ID.String(),
|
||||
},
|
||||
chainID: blockchain.NetID,
|
||||
chainID: blockchain.NetID,
|
||||
blockchainID: blockchain.ID,
|
||||
}
|
||||
}
|
||||
@@ -758,7 +759,7 @@ func (lc *localNetwork) updateChainInfo(ctx context.Context) error {
|
||||
}
|
||||
|
||||
lc.chains[chainIDStr] = &rpcpb.ChainInfo{
|
||||
IsElastic: isElastic,
|
||||
IsElastic: isElastic,
|
||||
ElasticChainId: elasticChainID.String(),
|
||||
ChainParticipants: &rpcpb.ChainParticipants{NodeNames: nodeNameList},
|
||||
}
|
||||
@@ -858,16 +859,16 @@ func (lc *localNetwork) updateNodeInfo() error {
|
||||
}
|
||||
|
||||
lc.nodeInfos[name] = &rpcpb.NodeInfo{
|
||||
Name: node.GetName(),
|
||||
Uri: node.GetURL(),
|
||||
Id: node.GetNodeID().String(),
|
||||
ExecPath: node.GetBinaryPath(),
|
||||
LogDir: node.GetLogsDir(),
|
||||
DbDir: node.GetDbDir(),
|
||||
Config: []byte(node.GetConfigFile()),
|
||||
PluginDir: node.GetPluginDir(),
|
||||
Name: node.GetName(),
|
||||
Uri: node.GetURL(),
|
||||
Id: node.GetNodeID().String(),
|
||||
ExecPath: node.GetBinaryPath(),
|
||||
LogDir: node.GetLogsDir(),
|
||||
DbDir: node.GetDbDir(),
|
||||
Config: []byte(node.GetConfigFile()),
|
||||
PluginDir: node.GetPluginDir(),
|
||||
WhitelistedChains: trackChains,
|
||||
Paused: node.GetPaused(),
|
||||
Paused: node.GetPaused(),
|
||||
}
|
||||
|
||||
// update default exec and pluginDir if empty (snapshots started without these params)
|
||||
|
||||
+22
-21
@@ -21,6 +21,11 @@ import (
|
||||
|
||||
"go.uber.org/multierr"
|
||||
|
||||
"maps"
|
||||
"slices"
|
||||
|
||||
"github.com/luxfi/consensus/core"
|
||||
"github.com/luxfi/ids"
|
||||
"github.com/luxfi/netrunner/network"
|
||||
"github.com/luxfi/netrunner/network/node"
|
||||
"github.com/luxfi/netrunner/rpcpb"
|
||||
@@ -28,15 +33,11 @@ import (
|
||||
"github.com/luxfi/netrunner/utils/constants"
|
||||
"github.com/luxfi/node/config"
|
||||
"github.com/luxfi/node/message"
|
||||
"github.com/luxfi/consensus/core"
|
||||
"github.com/luxfi/node/network/peer"
|
||||
"github.com/luxfi/ids"
|
||||
"maps"
|
||||
"slices"
|
||||
|
||||
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
|
||||
"github.com/luxfi/log"
|
||||
"github.com/luxfi/math/set"
|
||||
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
@@ -51,8 +52,8 @@ const (
|
||||
MinNodes uint32 = 1
|
||||
DefaultNodes uint32 = 5
|
||||
|
||||
stopTimeout = 5 * time.Second
|
||||
defaultStartTimeout = 5 * time.Minute
|
||||
stopTimeout = 5 * time.Second
|
||||
defaultStartTimeout = 5 * time.Minute
|
||||
// waitForHealthyTimeout - 60s for local 5-node network bootstrap
|
||||
// First startup takes longer as nodes need to establish consensus
|
||||
// Subsequent restarts are faster (<10s) but initial bootstrap needs time
|
||||
@@ -75,9 +76,9 @@ var (
|
||||
ErrNodeNotFound = errors.New("node not found")
|
||||
ErrPeerNotFound = errors.New("peer not found")
|
||||
ErrStatusCanceled = errors.New("gRPC stream status canceled")
|
||||
ErrNoChainSpec = errors.New("no blockchain spec was provided")
|
||||
ErrNoChainID = errors.New("chainID is missing")
|
||||
ErrNoElasticChainSpec = errors.New("no elastic chain spec was provided")
|
||||
ErrNoChainSpec = errors.New("no blockchain spec was provided")
|
||||
ErrNoChainID = errors.New("chainID is missing")
|
||||
ErrNoElasticChainSpec = errors.New("no elastic chain spec was provided")
|
||||
ErrNoValidatorSpec = errors.New("no validator spec was provided")
|
||||
)
|
||||
|
||||
@@ -175,7 +176,7 @@ type Server interface {
|
||||
type server struct {
|
||||
mu *sync.RWMutex
|
||||
|
||||
cfg Config
|
||||
cfg Config
|
||||
logger log.Logger
|
||||
|
||||
rootCtx context.Context
|
||||
@@ -221,7 +222,7 @@ func New(cfg Config, logger log.Logger) (Server, error) {
|
||||
|
||||
s := &server{
|
||||
cfg: cfg,
|
||||
logger: logger,
|
||||
logger: logger,
|
||||
closed: make(chan struct{}),
|
||||
ln: listener,
|
||||
gRPCServer: grpc.NewServer(),
|
||||
@@ -381,7 +382,7 @@ func (s *server) Start(_ context.Context, req *rpcpb.StartRequest) (*rpcpb.Start
|
||||
var (
|
||||
execPath = req.GetExecPath()
|
||||
numNodes = req.GetNumNodes()
|
||||
trackChains = req.GetWhitelistedChains()
|
||||
trackChains = req.GetWhitelistedChains()
|
||||
rootDataDir = req.GetRootDataDir()
|
||||
pid = int32(os.Getpid())
|
||||
globalNodeConfig = req.GetGlobalNodeConfig()
|
||||
@@ -410,7 +411,7 @@ func (s *server) Start(_ context.Context, req *rpcpb.StartRequest) (*rpcpb.Start
|
||||
} else {
|
||||
// CLI provided a specific rootDataDir - use it directly
|
||||
// Trust the CLI to provide a properly structured path
|
||||
networkName = getNetworkNameFromRootDir(rootDataDir)
|
||||
_ = getNetworkNameFromRootDir(rootDataDir)
|
||||
|
||||
// Ensure the provided directory exists
|
||||
if err = os.MkdirAll(rootDataDir, os.ModePerm); err != nil {
|
||||
@@ -432,7 +433,7 @@ func (s *server) Start(_ context.Context, req *rpcpb.StartRequest) (*rpcpb.Start
|
||||
execPath: execPath,
|
||||
rootDataDir: rootDataDir,
|
||||
numNodes: numNodes,
|
||||
trackChains: trackChains,
|
||||
trackChains: trackChains,
|
||||
redirectNodesOutput: s.cfg.RedirectNodesOutput,
|
||||
pluginDir: pluginDir,
|
||||
globalNodeConfig: globalNodeConfig,
|
||||
@@ -1278,7 +1279,7 @@ var _ peer.InboundHandler = &loggingInboundHandler{}
|
||||
|
||||
type loggingInboundHandler struct {
|
||||
nodeName string
|
||||
logger log.Logger
|
||||
logger log.Logger
|
||||
}
|
||||
|
||||
func (lh *loggingInboundHandler) HandleInbound(_ context.Context, msg message.InboundMessage) {
|
||||
@@ -1601,7 +1602,7 @@ func getNetworkElasticChainSpec(
|
||||
maxStakeDuration := time.Duration(spec.MaxStakeDuration) * time.Hour
|
||||
|
||||
elasticParticipantsSpec := network.ElasticChainSpec{
|
||||
ChainID: &spec.ChainId,
|
||||
ChainID: &spec.ChainId,
|
||||
AssetName: spec.AssetName,
|
||||
AssetSymbol: spec.AssetSymbol,
|
||||
InitialSupply: spec.InitialSupply,
|
||||
@@ -1638,7 +1639,7 @@ func getPermissionlessValidatorSpec(
|
||||
stakeDuration := time.Duration(spec.StakeDuration) * time.Hour
|
||||
|
||||
validatorSpec := network.PermissionlessValidatorSpec{
|
||||
ChainID: spec.ChainId,
|
||||
ChainID: spec.ChainId,
|
||||
AssetID: spec.AssetId,
|
||||
NodeName: spec.NodeName,
|
||||
StakedAmount: spec.StakedTokenAmount,
|
||||
@@ -1652,7 +1653,7 @@ func getRemoveChainValidatorSpec(
|
||||
spec *rpcpb.RemoveChainValidatorSpec,
|
||||
) network.RemoveChainValidatorSpec {
|
||||
validatorSpec := network.RemoveChainValidatorSpec{
|
||||
ChainID: spec.ChainId,
|
||||
ChainID: spec.ChainId,
|
||||
NodeNames: spec.GetNodeNames(),
|
||||
}
|
||||
return validatorSpec
|
||||
@@ -1730,13 +1731,13 @@ func getNetworkChainSpec(
|
||||
PerNodeChainConfig: perNodeChainConfig,
|
||||
// Use BlockchainAlias as the blockchain name for the P-Chain transaction
|
||||
// This allows multiple chains to use the same VM (e.g., multiple EVM chains)
|
||||
BlockchainName: spec.BlockchainAlias,
|
||||
BlockchainName: spec.BlockchainAlias,
|
||||
}
|
||||
|
||||
if spec.ChainSpec != nil {
|
||||
participantsSpec := network.ParticipantsSpec{
|
||||
Participants: spec.ChainSpec.Participants,
|
||||
ChainConfig: chainConfigBytes,
|
||||
ChainConfig: chainConfigBytes,
|
||||
}
|
||||
chainSpec.ParticipantsSpec = &participantsSpec
|
||||
}
|
||||
|
||||
+16
-15
@@ -17,23 +17,24 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/luxfi/node/api/admin"
|
||||
"github.com/luxfi/node/message"
|
||||
luxd_constants "github.com/luxfi/const"
|
||||
"maps"
|
||||
"slices"
|
||||
|
||||
luxd_constants "github.com/luxfi/const"
|
||||
"github.com/luxfi/node/api/admin"
|
||||
"github.com/luxfi/node/message"
|
||||
|
||||
"github.com/luxfi/node/vms/platformvm"
|
||||
|
||||
"github.com/luxfi/ids"
|
||||
"github.com/luxfi/log"
|
||||
"github.com/luxfi/metric"
|
||||
"github.com/luxfi/netrunner/client"
|
||||
"github.com/luxfi/netrunner/rpcpb"
|
||||
"github.com/luxfi/netrunner/server"
|
||||
"github.com/luxfi/netrunner/utils"
|
||||
"github.com/luxfi/netrunner/utils/constants"
|
||||
"github.com/luxfi/netrunner/ux"
|
||||
"github.com/luxfi/ids"
|
||||
"github.com/luxfi/log"
|
||||
"github.com/luxfi/metric"
|
||||
ginkgo "github.com/onsi/ginkgo/v2"
|
||||
"github.com/onsi/gomega"
|
||||
)
|
||||
@@ -55,7 +56,7 @@ var (
|
||||
gRPCGatewayEp string
|
||||
execPath1 string
|
||||
execPath2 string
|
||||
evmPath string
|
||||
evmPath string
|
||||
genesisPath string
|
||||
genesisContents string
|
||||
|
||||
@@ -332,8 +333,8 @@ var _ = ginkgo.Describe("[Start/Remove/Restart/Add/Stop]", func() {
|
||||
resp, err := cli.CreateChains(ctx,
|
||||
[]*rpcpb.BlockchainSpec{
|
||||
{
|
||||
VmName: "evm",
|
||||
Genesis: genesisContents,
|
||||
VmName: "evm",
|
||||
Genesis: genesisContents,
|
||||
ParticipantsSpec: &rpcpb.ParticipantsSpec{Participants: subnetParticipants},
|
||||
},
|
||||
},
|
||||
@@ -364,8 +365,8 @@ var _ = ginkgo.Describe("[Start/Remove/Restart/Add/Stop]", func() {
|
||||
resp, err := cli.CreateChains(ctx,
|
||||
[]*rpcpb.BlockchainSpec{
|
||||
{
|
||||
VmName: "evm",
|
||||
Genesis: genesisContents,
|
||||
VmName: "evm",
|
||||
Genesis: genesisContents,
|
||||
ParticipantsSpec: &rpcpb.ParticipantsSpec{Participants: subnetParticipants2},
|
||||
},
|
||||
},
|
||||
@@ -423,13 +424,13 @@ var _ = ginkgo.Describe("[Start/Remove/Restart/Add/Stop]", func() {
|
||||
resp, err := cli.CreateChains(ctx,
|
||||
[]*rpcpb.BlockchainSpec{
|
||||
{
|
||||
VmName: "evm",
|
||||
Genesis: genesisContents,
|
||||
VmName: "evm",
|
||||
Genesis: genesisContents,
|
||||
ParticipantsSpec: &rpcpb.ParticipantsSpec{Participants: disjointNewSubnetParticipants[0]},
|
||||
},
|
||||
{
|
||||
VmName: "evm",
|
||||
Genesis: genesisContents,
|
||||
VmName: "evm",
|
||||
Genesis: genesisContents,
|
||||
ParticipantsSpec: &rpcpb.ParticipantsSpec{Participants: disjointNewSubnetParticipants[1]},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -12,16 +12,16 @@ const (
|
||||
|
||||
// Network run directory structure (flat, no nesting)
|
||||
// Structure: ~/.lux/runs/<networkName>/run_<timestamp>/node1/, node2/, ...
|
||||
RunsDir = "runs" // Top-level runs directory
|
||||
RunDirPrefix = "run" // Prefix for timestamped run directories
|
||||
DefaultNetwork = "local" // Default network name
|
||||
RunsDir = "runs" // Top-level runs directory
|
||||
RunDirPrefix = "run" // Prefix for timestamped run directories
|
||||
DefaultNetwork = "local" // Default network name
|
||||
|
||||
// Unified chain config directory (shared across all nodes)
|
||||
// Structure: ~/.lux/chains/<chainName>/genesis.json, config.json, upgrade.json
|
||||
ChainsDir = "chains"
|
||||
ChainGenesisFile = "genesis.json"
|
||||
ChainConfigFile = "config.json"
|
||||
ChainUpgradeFile = "upgrade.json"
|
||||
ChainsDir = "chains"
|
||||
ChainGenesisFile = "genesis.json"
|
||||
ChainConfigFile = "config.json"
|
||||
ChainUpgradeFile = "upgrade.json"
|
||||
|
||||
// Unified plugins directory
|
||||
// Structure: ~/.lux/plugins/current/<vmid> (symlinks to actual binaries)
|
||||
|
||||
+2
-2
@@ -8,11 +8,11 @@ import (
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/luxfi/ids"
|
||||
"github.com/luxfi/log"
|
||||
rpcb "github.com/luxfi/netrunner/rpcpb"
|
||||
"github.com/luxfi/netrunner/ux"
|
||||
"github.com/luxfi/ids"
|
||||
"github.com/luxfi/node/staking"
|
||||
"github.com/luxfi/log"
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
Reference in New Issue
Block a user