mirror of
https://github.com/luxfi/docs.git
synced 2026-09-24 00:25:32 +00:00
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:
@@ -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
@@ -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,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 |
|
||||
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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
@@ -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": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user