fix: final audit — go-ethereum refs, graceful shutdown, turbo cache, deploy reliability

Red team fixes:
- Replace 6 remaining go-ethereum references with luxfi/geth
- DAO title: "Welcome" -> "DAO Governance"

CTO fixes:
- serve.go: add graceful shutdown (signal.NotifyContext + srv.Shutdown)
- turbo.json: add out/** to build outputs for proper caching
- deploy.yml: remove continue-on-error (surface deploy failures)
- Delete stale GENESIS_FLOW.md from repo root

452 pages, zero broken links, zero go-ethereum refs
This commit is contained in:
2026-03-25 00:35:44 -07:00
parent 85aa1fdcc1
commit 80b1850210
11 changed files with 27 additions and 407 deletions
-1
View File
@@ -55,7 +55,6 @@ jobs:
steps:
- name: Deploy to cluster
uses: appleboy/ssh-action@v1
continue-on-error: true
with:
host: ${{ secrets.K8S_HOST }}
username: ${{ secrets.K8S_USER }}
-396
View File
@@ -1,396 +0,0 @@
# Genesis Flow: CLI -> Netrunner -> Node -> EVM
## Critical Investigation Summary
**Date**: 2025-12-27
**Scope**: CLI (`/Users/z/work/lux/cli`) and Netrunner (`/Users/z/work/lux/netrunner`)
**Finding**: `stateRoot` and `genesisHash` are NOT stored in genesis JSON - they are computed by EVM at runtime.
---
## 1. Genesis Structure Overview
The main genesis.json contains **three genesis configurations**:
```
genesis.json (main)
├── networkID: 1 (mainnet) | 2 (testnet) | ...
├── allocations: [...] (P-Chain initial allocations)
├── initialStakers: [...] (validators)
├── cChainGenesis: "{...}" (C-Chain genesis as JSON STRING)
└── startTime, message, etc.
```
**Key Point**: `cChainGenesis` is embedded as an **escaped JSON string**, not a nested object.
---
## 2. Genesis Source Files
### 2.1 Canonical Genesis Package
**Location**: `/Users/z/work/lux/genesis/configs/`
```
genesis/configs/
├── configs.go # Main loader with GetCanonicalGenesisBytes()
├── mainnet/
│ ├── network.json # Network params (networkID, allocations, etc.)
│ ├── pchain.json # P-Chain validators
│ └── cchain.json # C-Chain genesis (raw JSON)
├── testnet/
├── devnet/
└── custom/
```
**`configs.go` key function**:
```go
func GetCanonicalGenesisBytes(networkID uint32) ([]byte, error) {
// Returns pre-serialized bytes to avoid JSON re-serialization
// which would cause "db contains invalid genesis hash" errors
switch networkID {
case constants.MainnetID:
return mainnetFS.ReadFile("mainnet/genesis.json")
case constants.TestnetID:
return testnetFS.ReadFile("testnet/genesis.json")
// ...
}
}
```
### 2.2 Netrunner Default Genesis
**Location**: `/Users/z/work/lux/netrunner/network/default/genesis.json`
This is the fallback genesis used for local/devnet when no canonical genesis exists.
---
## 3. Flow Diagram
```
┌─────────────────────────────────────────────────────────────────────────────┐
│ USER COMMAND │
│ lux network start --mainnet OR lux chain deploy <name> │
└──────────────────────────────────┬──────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ CLI (cmd/networkcmd/start.go) │
│ │
│ 1. Parse flags (--mainnet, --testnet, etc.) │
│ 2. Build globalNodeConfig: │
│ { │
│ "network-id": 1, │
│ "db-type": "badgerdb", │
│ "api-admin-enabled": true, <-- ADMIN API ENABLED HERE │
│ "track-chains": "..." │
│ } │
│ 3. Create gRPC client to netrunner │
│ 4. Call client.Start() with options │
└──────────────────────────────────┬──────────────────────────────────────────┘
│ gRPC
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ NETRUNNER SERVER (server/network.go) │
│ │
│ createConfig() function: │
│ │
│ switch networkID { │
│ case MainnetID: │
│ cfg = local.NewCanonicalMainnetConfig(execPath, numNodes) │
│ // Uses genesis/configs.GetCanonicalGenesisBytes(1) │
│ case TestnetID: │
│ cfg = local.NewCanonicalTestnetConfig(execPath, numNodes) │
│ // Uses genesis/configs.GetCanonicalGenesisBytes(2) │
│ default: │
│ cfg = local.NewDefaultConfig(execPath) │
│ // Uses embedded network/default/genesis.json │
│ } │
└──────────────────────────────────┬──────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ NETRUNNER LOCAL (local/genesis_config.go) │
│ │
│ newCanonicalConfig() function: │
│ │
│ 1. genesisBytes := configs.GetCanonicalGenesisBytes(networkID) │
│ // Returns RAW BYTES - no re-serialization! │
│ │
│ 2. Load validator keys from genesis/configs/keys/ │
│ │
│ 3. Build network.Config{ │
│ Genesis: string(genesisBytes), <-- Genesis as string │
│ NodeConfigs: [...], <-- Per-node configs │
│ } │
└──────────────────────────────────┬──────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ NETRUNNER LOCAL (local/network.go) │
│ │
│ NewNetwork() function: │
│ │
│ 1. Create node directories: │
│ ~/.lux/runs/{network}/run_{timestamp}/node{i}/ │
│ │
│ 2. Write genesis.json to each node: │
│ node{i}/genesis.json <-- Same genesis for all nodes │
│ │
│ 3. Write node config: │
│ node{i}/config.json │
│ │
│ 4. Write chain configs: │
│ node{i}/chainConfigs/C/config.json │
│ │
│ 5. Start luxd processes with: │
│ --genesis-file={node}/genesis.json │
│ --config-file={node}/config.json │
│ --chain-config-dir={node}/chainConfigs │
└──────────────────────────────────┬──────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ LUXD NODE │
│ │
│ 1. Load genesis.json from --genesis-file │
│ │
│ 2. Parse main genesis: │
│ - Extract networkID, allocations, initialStakers │
│ - Extract cChainGenesis as JSON string │
│ │
│ 3. Initialize chains: │
│ - P-Chain: Uses allocations, initialStakers │
│ - X-Chain: Uses xChainGenesis (if present) │
│ - C-Chain: Passes cChainGenesis string to EVM plugin │
└──────────────────────────────────┬──────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ EVM PLUGIN (coreth/evm) │
│ │
│ 1. Receive cChainGenesis JSON string from luxd │
│ │
│ 2. Parse into Genesis struct (core/genesis.go): │
│ type Genesis struct { │
│ Config *params.ChainConfig │
│ Nonce uint64 │
│ Timestamp uint64 │
│ ExtraData []byte │
│ GasLimit uint64 │
│ Difficulty *big.Int │
│ Alloc GenesisAlloc │
│ // NOTE: NO stateRoot or genesisHash fields! │
│ } │
│ │
│ 3. COMPUTE stateRoot from Alloc: │
│ - Create state trie │
│ - Apply all allocations (balances, code, storage) │
│ - Compute Merkle root = stateRoot │
│ │
│ 4. COMPUTE genesisHash: │
│ - Build genesis block header with computed stateRoot │
│ - Hash header = genesisHash │
│ │
│ 5. Write genesis block to database │
└─────────────────────────────────────────────────────────────────────────────┘
```
---
## 4. Where stateRoot/genesisHash Are Lost (They Aren't!)
### 4.1 The Misconception
`stateRoot` and `genesisHash` are **NOT stored** in genesis.json because they are **computed values**, not input values.
### 4.2 How They Work
```
INPUT COMPUTED
┌──────────────────┐ ┌──────────────────────┐
│ genesis.json │ │ Genesis Block │
│ │ │ │
│ - config │ │ - stateRoot │
│ - alloc │──────────▶ │ - genesisHash │
│ - timestamp │ COMPUTE │ - header fields │
│ - gasLimit │ │ │
│ - extraData │ │ │
└──────────────────┘ └──────────────────────┘
```
### 4.3 When genesisHash Mismatch Occurs
**Problem**: If you:
1. Re-serialize genesis.json (field order changes)
2. Modify any alloc entry (balances, code, storage)
3. Change any header field (timestamp, gasLimit, extraData)
**Result**: Different stateRoot → Different genesisHash → "db contains invalid genesis hash" error
### 4.4 Solution: Genesis Hash Override (EVM Feature)
The EVM plugin at `/Users/z/work/lux/evm/core/genesis.go` supports override fields:
```go
type Genesis struct {
// ... standard fields ...
// Override fields for block import compatibility
GenesisHash *common.Hash `json:"genesisHash,omitempty"`
StateRoot *common.Hash `json:"stateRoot,omitempty"`
}
```
When these are set:
- `toBlock()` uses `StateRoot` override (bypasses state computation)
- `Commit()` uses `GenesisHash` override (bypasses hash computation)
---
## 5. Admin API Configuration
### 5.1 How Admin API Is Enabled
**CLI sets in globalNodeConfig**:
```go
// cmd/networkcmd/start.go
globalNodeConfig := fmt.Sprintf(`{
"network-id": %d,
"db-type": "badgerdb",
"api-admin-enabled": true, // <-- HERE
"track-chains": %q
}`, cfg.networkID, trackChainsValue)
```
### 5.2 How It Flows to Nodes
1. CLI creates `globalNodeConfig` JSON string
2. gRPC sends to netrunner via `client.WithGlobalNodeConfig()`
3. Netrunner writes to `node{i}/config.json`
4. luxd reads config and enables admin API
### 5.3 Verification
```bash
# Check if admin API is enabled
curl -X POST http://127.0.0.1:9650/ext/admin \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","method":"admin.getChainAliases","params":{"chain":"C"},"id":1}'
```
---
## 6. admin_importChain Support
### 6.1 CLI Implementation
**Location**: `/Users/z/work/lux/cli/cmd/chaincmd/import.go`
```go
func callAdminImportChain(rpcEndpoint, filePath string) (bool, error) {
req := map[string]interface{}{
"jsonrpc": "2.0",
"method": "admin_importChain",
"params": []string{filePath},
"id": 1,
}
// POST to RPC endpoint
}
```
### 6.2 Usage
```bash
# Import blocks to C-Chain
lux chain import --rlp /path/to/blocks.rlp --rpc http://127.0.0.1:9650/ext/bc/C/rpc
```
### 6.3 Known Issue: Import Persistence
**Problem**: Blocks imported via `admin_importChain` do not persist across network restarts.
**Root Cause**:
- Blocks are written to BadgerDB
- But "last accepted block" pointer is NOT updated in consensus layer
- On restart, chain initializes from genesis
**Status**: Investigating fix in coreth/subnet-evm.
---
## 7. Chain Deploy Flow
### 7.1 Command
```bash
lux chain deploy <chainName> --mainnet|--testnet
```
### 7.2 Flow
```
┌────────────────────────────────────────────────────────────────┐
│ CLI (cmd/chaincmd/deploy.go) │
│ │
│ 1. Load genesis from ~/.lux/chains/{name}/genesis.json │
│ 2. Load sidecar from ~/.lux/chains/{name}/sidecar.json │
│ 3. Validate EVM genesis format │
│ 4. Call DeployToLocalNetwork() via gRPC │
└────────────────────────────────┬───────────────────────────────┘
│ gRPC
▼
┌────────────────────────────────────────────────────────────────┐
│ NETRUNNER │
│ │
│ 1. Receive subnet creation request │
│ 2. Create subnet on P-Chain │
│ 3. Create blockchain with provided genesis │
│ 4. Track blockchain on all validators │
│ 5. Write chain config to nodes │
└────────────────────────────────┬───────────────────────────────┘
│
▼
┌────────────────────────────────────────────────────────────────┐
│ LUXD NODES │
│ │
│ 1. Receive blockchain creation from P-Chain │
│ 2. Load EVM plugin for chain │
│ 3. Initialize chain with provided genesis │
│ 4. Start processing blocks │
└────────────────────────────────────────────────────────────────┘
```
---
## 8. File Reference
| Component | File | Purpose |
|-----------|------|---------|
| CLI | `cmd/networkcmd/start.go` | Network start command |
| CLI | `cmd/chaincmd/deploy.go` | Chain deploy command |
| CLI | `cmd/chaincmd/import.go` | Block import command |
| Netrunner | `server/network.go` | gRPC server, config creation |
| Netrunner | `local/network.go` | Local network management |
| Netrunner | `local/genesis_config.go` | Genesis config factories |
| Netrunner | `network/genesis.go` | Genesis loading/parsing |
| Netrunner | `network/default/genesis.json` | Default genesis template |
| Genesis | `configs/configs.go` | Canonical genesis loader |
| Genesis | `configs/mainnet/*.json` | Mainnet genesis files |
| EVM | `core/genesis.go` | Genesis struct, state computation |
---
## 9. Summary
1. **Genesis is stored as JSON** with cChainGenesis embedded as a string
2. **stateRoot/genesisHash are NOT in genesis.json** - they are computed by EVM
3. **Admin API is enabled** via `api-admin-enabled: true` in node config
4. **admin_importChain exists** in CLI at `cmd/chaincmd/import.go`
5. **Genesis hash mismatch** occurs when genesis is re-serialized or modified
6. **Solution**: Use genesis hash override fields in EVM genesis
---
*Document generated from investigation of CLI and Netrunner codebases.*
@@ -176,7 +176,7 @@ for _, subnet := range subnets {
## EVM (C-Chain) Client
For C-Chain interactions, use the standard Go-Ethereum compatible client from the SDK.
For C-Chain interactions, use the standard Lux Geth compatible client from the SDK.
### Connect and Query
+1 -1
View File
@@ -1,5 +1,5 @@
---
title: Welcome
title: DAO Governance
description: Complete documentation for DAO governance
---
@@ -247,7 +247,7 @@ go test ./memdb/ -v
## Key Design Decisions
1. **Ethereum-compatible interface**: Matches go-ethereum's database API for seamless EVM integration
1. **Ethereum-compatible interface**: Matches Lux Geth's database API for seamless EVM integration
2. **Build-tag backends**: PebbleDB and LevelDB are compile-time optional to minimize binary size
3. **ZapDB as default**: BadgerDB-based ZapDB is always available, registered in `init()`
4. **Wrapper composition**: Encryption, metering, versioning are separate wrappers that can be composed
@@ -173,7 +173,7 @@ The orchestrator runs heterogeneous consensus engines in a single host.
| Engine | Type | Description |
|--------|------|-------------|
| Lux | `lux` | Lux Snow consensus (luxd) |
| Geth | `geth` | Go-Ethereum execution client |
| Geth | `geth` | Lux Geth execution client |
| OP Stack | `op` | Optimism OP node (L2) |
| Eth2 | `eth2` | Ethereum 2.0 beacon + execution |
+1 -1
View File
@@ -29,7 +29,7 @@ Lux SDK is the **official Go SDK** for building and managing Lux networks. It pr
| `github.com/luxfi/ledger` | v1.1.6 | Hardware wallet support |
| `github.com/luxfi/lpm` | v1.9.4 | Lux Plugin Manager |
| `github.com/luxfi/crypto` | v1.17.40 | Cryptographic primitives |
| `github.com/luxfi/geth` | v1.16.75 | Go-Ethereum fork (EVM) |
| `github.com/luxfi/geth` | v1.16.75 | Lux Geth (EVM client) |
| `github.com/luxfi/ids` | v1.2.9 | ID types (ID, ShortID, NodeID) |
| `github.com/luxfi/protocol` | v0.0.3 | P-Chain protocol types |
| `github.com/luxfi/rpc` | v1.0.0 | JSON-RPC client |
@@ -92,7 +92,7 @@ spacesvm/
```
github.com/luxdefi/[email protected] — Lux node (VM interface)
github.com/luxdefi/[email protected] — Network testing
github.com/ethereum/go-ethereum@v1.10.26 — EIP-712 signing
github.com/luxfi/geth@v1.10.26 — EIP-712 signing
github.com/gorilla/[email protected] — JSON-RPC server
github.com/spf13/[email protected] — CLI framework
```
@@ -160,7 +160,7 @@ make amm-zoo network=main # Test AMM on Zoo chain
| Submodule | Description |
|-----------|-------------|
| `node` | Lux consensus node (luxd) |
| `geth` | Go-Ethereum fork (luxfi/geth) |
| `geth` | Lux Geth (EVM client) |
| `evm` | EVM plugin for Lux |
| `cli` | Lux CLI tool |
| `netrunner` | Network testing/orchestration |
+14 -1
View File
@@ -8,7 +8,9 @@ import (
"log"
"net/http"
"os"
"os/signal"
"path/filepath"
"syscall"
static "github.com/hanzoai/static"
)
@@ -91,8 +93,19 @@ func main() {
})
addr := ":" + port
srv := &http.Server{Addr: addr, Handler: mux}
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
defer stop()
go func() {
<-ctx.Done()
log.Println("shutting down...")
srv.Shutdown(context.Background())
}()
log.Printf("serving %s on %s", root, addr)
if err := http.ListenAndServe(addr, mux); err != nil {
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
log.Fatalf("server error: %v", err)
}
}
+6 -2
View File
@@ -2,7 +2,11 @@
"$schema": "https://turbo.build/schema.json",
"tasks": {
"build": {
"outputs": [".next/**", "!.next/cache/**"]
"outputs": [
"out/**",
".next/**",
"!.next/cache/**"
]
},
"dev": {
"cache": false,
@@ -12,4 +16,4 @@
"lint": {},
"types:check": {}
}
}
}