mirror of
https://github.com/luxfi/genesis.git
synced 2026-07-27 04:11:41 +00:00
713 lines
28 KiB
Markdown
713 lines
28 KiB
Markdown
# Genesis
|
|
|
|
Canonical genesis configurations for all Lux blockchain networks. **This repo is the single source of truth for chain IDs, genesis hashes, state roots, and required precompiles.** Other repos (`~/work/lux/{node,evm,state}`) reference these values; do not duplicate them.
|
|
|
|
**Latest Tag**: v1.9.6
|
|
|
|
## Post-E2E-PQ State (current)
|
|
|
|
Genesis now pins a `ChainSecurityProfile` for every chain it generates,
|
|
and resolves it at load time. The profile hash is committed into the
|
|
chain's bootstrap so a profile-flip is a wrong-network event, not a
|
|
silent classification change.
|
|
|
|
### Recent significant commits
|
|
|
|
| SHA | Tag | Impact |
|
|
|-----|-----|--------|
|
|
| `85a8fc8` | v1.9.6 | Pin ChainSecurityProfile into Config + Resolve at load (closes F102 genesis layer) |
|
|
| `1d73c8d` | v1.9.6 | Swap mldsa65 keygen from cloudflare/circl to luxfi/crypto/pq/mldsa |
|
|
| `e698307` | v1.9.5 | HD branch hardening + LightMnemonic production refusal (F12/F30/F31/F35) |
|
|
| `fe4781c` | v1.9.5 | `LUX_DISABLE_CCHAIN=1` omits C-Chain from primary genesis |
|
|
| `2b16f45` | v1.9.5 | Operator-overridable C-Chain genesis via `LUX_CCHAIN_GENESIS_FILE` |
|
|
|
|
### Zoo testnet/devnet 39-char alloc address bug (May 2026)
|
|
|
|
`zooai/universe/configs/genesis/{testnet,devnet}/genesis.json` (moved from
|
|
`luxfi/genesis/configs/zoo-*/` in Task #109, 2026-06-04) shipped six alloc addresses with
|
|
only 39 hex chars instead of 40 — the leading `0` nibble was stripped at
|
|
genesis-generation time (commit `2b46a8b`, "regenerate all network configs").
|
|
The six bad addresses on both files were:
|
|
|
|
| Truncated (39ch, shipped) | Correct (40ch, present in C-chain alloc) |
|
|
|---|---|
|
|
| `2aCB0ee16fd2B1bF465F85D7Ee112fA80C055FC` | `02aCB0ee16fd2B1bF465F85D7Ee112fA80C055FC` |
|
|
| `3B8Bd0A20b05AADC9E457A4c967f45eEeC163c4` | `03B8Bd0A20b05AADC9E457A4c967f45eEeC163c4` |
|
|
| `54D2e1dA5A1B5b9Da158acbA42Aed1d45F5CF02` | `054D2e1dA5A1B5b9Da158acbA42Aed1d45F5CF02` |
|
|
| `5CAE5842A08165d4d736dA9E49438574283aaE9` | `05CAE5842A08165d4d736dA9E49438574283aaE9` |
|
|
| `698495959f5570420BAA955dae5eA2864933ACf` | `0698495959f5570420BAA955dae5eA2864933ACf` |
|
|
| `7283AA2c30523E9190A17b9598ff65599BAAe17` | `07283AA2c30523E9190A17b9598ff65599BAAe17` |
|
|
|
|
Symptom: the EVM refused to bootstrap the chain — `parsing genesis:
|
|
hex string of odd length`. The original CreateChainTx (`ZAKw...` on
|
|
testnet, `2nLY...` on devnet) carries the broken genesis bytes
|
|
immutably, so we had to re-issue under a new chain name and rewrite the
|
|
gateway. The 39→40-char fix applied in genesis is now the SAME content
|
|
the EVM expects.
|
|
|
|
Operators bootstrapping a fresh zoo chain should pin the post-fix
|
|
checksums in this file (see `### Verify Checksum`). Mainnet zoo
|
|
(`zoo-mainnet/genesis.json`) was *not* affected — it has only the
|
|
treasury account plus the `0x0200…0005` precompile.
|
|
|
|
### Chain bootstrap: chain-name collision (P-chain)
|
|
|
|
`platform.IsChainNameTaken` is case-insensitive and global across all
|
|
chains. A failed CreateChainTx (e.g. the broken zoo above) still
|
|
permanently squats its `BlockchainName` on the P-chain ledger — you
|
|
cannot reuse the name even after fixing the genesis. Work-around used
|
|
on zoo testnet/devnet: issue under a throwaway name (`ZOOTEST123` /
|
|
`ZOODEVTEST123`), then rewrite the krakend gateway endpoint so
|
|
`/ext/bc/zoo/rpc` → `/ext/bc/<new-bcID>/rpc`. The route
|
|
`/ext/bc/<name>/rpc` is registered by `luxfi/node/chains/manager.go`
|
|
*only* on successful VM init — broken chains never claim the route, so
|
|
gateway-side rewrite is sufficient.
|
|
|
|
### Active versions
|
|
- Repo: `v1.9.6` (next: `v1.9.7`).
|
|
- Pinned by: `luxfi/node v1.26.10`.
|
|
- Pulls: `luxfi/consensus v1.23.4+` (for `ChainSecurityProfile`
|
|
definition + `ComputeHash`), `luxfi/crypto v1.18.4+` (mldsa65 keygen).
|
|
|
|
### Cross-repo dependencies
|
|
- `luxfi/consensus/config` → `ChainSecurityProfile`, `Resolve`,
|
|
`ComputeHash`.
|
|
- `luxfi/crypto/pq/mldsa/mldsa65` → validator key generation.
|
|
- `luxfi/node/genesis/builder` → consumes this repo's JSON config and
|
|
converts types (string → ids.NodeID, uint64 → time.Duration).
|
|
|
|
### Where to look for X
|
|
- ChainSecurityProfile pin: `pkg/genesis/security_profile.go`
|
|
- Profile hash verification: `pkg/genesis/security_profile.go:Resolve`
|
|
- HD branch hardening: `pkg/wallet/hd/*.go`
|
|
- Per-network configs: `configs/{mainnet,testnet,devnet,local}/`
|
|
|
|
### Open follow-ups
|
|
- Mainnet/testnet/devnet genesis JSONs still reference the
|
|
`legacy-compat` profile while operators migrate validator keys. The
|
|
strict-PQ profile is encoded but not yet the default genesis pin.
|
|
|
|
---
|
|
|
|
## Canonical Requirements
|
|
|
|
Every Lux chain genesis MUST satisfy these, or block import / consensus will fail:
|
|
|
|
| Requirement | Mainnet C-Chain | How to verify |
|
|
|---|---|---|
|
|
| chainId | 96369 (NOT 1) | `jq -r .chainId configs/mainnet/cchain.json` |
|
|
| Genesis hash | `0x3f4fa2a0b0ce089f52bf0ae9199c75ffdd76ecafc987794050cb0d286f1ec61e` | `geth init --datadir /tmp/v configs/mainnet/cchain.json 2>&1 \| grep "genesis hash"` |
|
|
| State root | `0x2d1cedac263020c5c56ef962f6abe0da1f5217bdc6468f8c9258a0ea23699e80` | `jq -r .stateRoot configs/mainnet/cchain.json` |
|
|
| Warp precompile in alloc | `0200000000000000000000000000000000000005` `nonce:0x1` `code:0x01` | `jq '.alloc."0200000000000000000000000000000000000005"' configs/mainnet/cchain.json` |
|
|
| `warpConfig.blockTimestamp` | `1730446786` (== genesis ts `0x672485c2`) | must equal genesis timestamp |
|
|
| Treasury | `0x9011E888251AB053B7bD1cdB598Db4f9DEd94714` = 2T LUX | `jq '.alloc."0x9011…"' configs/mainnet/cchain.json` |
|
|
| File determinism | sorted, sha256 matches Canonical Genesis Checksums table below | `shasum -a 256 configs/mainnet/cchain.json` |
|
|
|
|
If genesis hash drifts → check `cChainGenesis` in `genesis.json` is the literal canonical `cchain.json` content. Common drift: `chainId=1` + missing warp = wrong-network template.
|
|
|
|
## Networks
|
|
|
|
### C-Chain (Primary Network)
|
|
|
|
| Network | Network ID | Chain ID | Genesis Hash | Treasury |
|
|
|---------|------------|----------|--------------|----------|
|
|
| Mainnet | 1 | 96369 | `0x3f4fa2a0b0ce089f52bf0ae9199c75ffdd76ecafc987794050cb0d286f1ec61e` | 2T LUX |
|
|
| Testnet | 2 | 96368 | `0xfc909f7e992d9cb91485f114f6d333f3823a12f2c72bbf51ed2c8eea749b2d2e` | 2T LUX |
|
|
| Devnet | 3 | 96367 | `0x836f6053473e4331bb347afc45b641f12075c63a302f4e56e64239a3ba4acd4b` | 2T LUX |
|
|
| Local | 1337 | 1337 | - | 2T LUX |
|
|
|
|
> **Historical note**: testnet was `0x1c5fe37764b8bc146dc88bc1c2e0259cd8369b07a06439bcfa1782b5d4fb0995`
|
|
> and devnet was `0x53fe8be293555d20de41847f96081f4e8beca1ee2c206999ffbf7c70e497cf43`
|
|
> before commits `2bf1ca3` (Shanghai/Cancun/Prague activated at genesis) and
|
|
> `d3cbd78` (gasLimit bumped to 1B). Both networks were "block 0 fresh"
|
|
> with no committed historical state, so the hash update is intentional;
|
|
> rollouts after 2026-05-21 use the new hashes. Mainnet hash is unchanged
|
|
> (its cChainGenesis is locked by the 1.08M-block historical chain).
|
|
|
|
### Primary-Network Letter Chains (all baked into genesis)
|
|
|
|
Every primary network ships **all 10 letter-chain shards**, so every chain
|
|
spawns at startup — no post-launch `CreateBlockchainTx` required. The shard
|
|
schema is `{x,c,d,q,a,b,t,z,g,k}chain.json` (P-Chain is implicit; it is the
|
|
primary network and carries the validator set + chain registry).
|
|
|
|
Letter aliases (LP-134 user-facing naming): **F-Chain ≡ T-Chain** (threshold
|
|
FHE encrypted compute), **M-Chain ≡ K-Chain** (KMS + MPC topology). The
|
|
canonical letter on disk and in VM IDs is T / K; F / M are aliases registered
|
|
on the same VM IDs (`builder.TChainAliases`, `builder.KChainAliases`).
|
|
|
|
| Letter | VM | Mainnet | Testnet | Devnet | Localnet |
|
|
|--------|--------------|---------|---------|--------|----------|
|
|
| X | XVM (UTXO) | — | — | — | — |
|
|
| C | EVM | 96369 | 96368 | 96367 | 31337 |
|
|
| D | DexVM | 96469 | 96468 | 96470 | 31447 |
|
|
| Q | QuantumVM | 96569 | 96568 | 96570 | 31557 |
|
|
| A | AIVM | 96669 | 96668 | 96670 | 31667 |
|
|
| B | BridgeVM | 96769 | 96768 | 96770 | 31777 |
|
|
| T (=F) | ThresholdVM | 96869 | 96868 | 96870 | 31887 |
|
|
| Z | ZKVM | 96969 | 96968 | 96970 | 31997 |
|
|
| G | GraphVM | 97069 | 97068 | 97070 | 32107 |
|
|
| K (=M) | KeyVM | 97169 | 97168 | 97170 | 32217 |
|
|
|
|
Pattern: each letter's mainnet ID is `96369 + 100*Δ_from_C`; testnet = mainnet-1,
|
|
devnet = mainnet+1 (mirrors the C-Chain triple). Localnet uses a separate
|
|
`31337 + 110*Δ` series. All 36 EVM chain IDs are pairwise distinct so a
|
|
misrouted transaction cannot be replayed against the wrong chain.
|
|
|
|
The contract that every primary network ships all 10 shards is locked by
|
|
`configs.TestGetGenesis_AllPrimaryChainsBakedIn` — removing a chain on
|
|
mainnet/testnet/devnet/localnet is now a load-bearing test edit, not a
|
|
silent operator switch.
|
|
|
|
### Application Chains
|
|
|
|
| Chain | Mainnet ID | Testnet ID | Devnet ID | Treasury |
|
|
|-------|-----------|-----------|-----------|----------|
|
|
| Zoo | 200200 | 200201 | 200202 | 2T ZOO |
|
|
| SPC | 36911 | 36910 | 36912 | 1B SPC |
|
|
| Hanzo | 36963 | 36962* | 36964 | 1B AI |
|
|
| Pars | 494949 | 494950 | 494951 | 2T PARS |
|
|
|
|
*Note: Hanzo testnet was deployed with chain ID 36964 (devnet ID) due to a deployment error. The intended ID is 36962.
|
|
|
|
### Deployed Genesis Hashes (All Chains)
|
|
|
|
| Chain | Mainnet | Testnet | Devnet |
|
|
|-------|---------|---------|--------|
|
|
| C-Chain | `0x3f4fa2a...1ec61e` | `0x53fe8be...97cf43` | `0x53fe8be...97cf43` |
|
|
| Zoo | `0x7c548af...14933` | `0x0652fb2...d1979` | `0x0652fb2...d1979` |
|
|
| SPC | `0x4dc9fd5...cfac8` | `0x210fcc1...0b692` | `0x0652fb2...d1979` |
|
|
| Hanzo | `0x6cf786a...48e67` | `0x6cf786a...48e67` | `0x6cf786a...48e67` |
|
|
| Pars | `0xa32921a...b2f34` | `0xa32921a...b2f34` | `0xa32921a...b2f34` |
|
|
|
|
## Genesis Treasury
|
|
|
|
All networks use the same production treasury address:
|
|
|
|
```
|
|
Address: 0x9011E888251AB053B7bD1cdB598Db4f9DEd94714
|
|
Balance: 2,000,000,000,000,000,000,000,000,000,000 wei (2T LUX)
|
|
Hex: 0x193e5939a08ce9dbd480000000
|
|
```
|
|
|
|
## Directory Structure
|
|
|
|
```
|
|
configs/
|
|
├── mainnet/
|
|
│ ├── cchain.json # C-Chain genesis (chain ID 96369)
|
|
│ ├── pchain.json # P-Chain genesis (ProtocolVM)
|
|
│ ├── network.json # Network ID, message, startTime
|
|
│ └── bootstrappers.json # Bootstrap nodes
|
|
├── testnet/
|
|
│ ├── cchain.json # C-Chain genesis (chain ID 96368)
|
|
│ └── genesis.json
|
|
├── devnet/
|
|
│ └── cchain.json
|
|
├── local/
|
|
│ ├── cchain.json
|
|
│ └── genesis.json
|
|
├── zoo-{mainnet,testnet,devnet}/
|
|
│ └── genesis.json # Zoo (200200/200201/200202)
|
|
├── spc-{mainnet,testnet,devnet}/
|
|
│ └── genesis.json # SPC (36911/36910/36912)
|
|
├── hanzo-{mainnet,testnet,devnet}/
|
|
│ └── genesis.json # Hanzo (36963/36962/36964)
|
|
└── pars-{mainnet,testnet,devnet}/
|
|
└── genesis.json # Pars (494949/494950/494951)
|
|
```
|
|
|
|
## C-Chain Configuration
|
|
|
|
### Mainnet (96369)
|
|
|
|
```json
|
|
{
|
|
"chainId": 96369,
|
|
"gasLimit": 12000000,
|
|
"targetBlockRate": 2,
|
|
"minBaseFee": 25000000000,
|
|
"stateRoot": "0x2d1cedac263020c5c56ef962f6abe0da1f5217bdc6468f8c9258a0ea23699e80",
|
|
"baseFeePerGas": "0x5d21dba00"
|
|
}
|
|
```
|
|
|
|
### Network Parameters
|
|
|
|
| Parameter | Mainnet | Testnet | Devnet | Local |
|
|
|-----------|---------|---------|--------|-------|
|
|
| Block Rate | 2s | 2s | 1s | 1s |
|
|
| Gas Limit | 12M | 12M | 20M | 15M |
|
|
| Min Base Fee | 25 gwei | 25 gwei | 1 gwei | 1 gwei |
|
|
| Chain ID | 96369 | 96368 | 96367 | 1337 |
|
|
|
|
### Warp Precompile (Required for Genesis Hash)
|
|
|
|
Both mainnet and testnet C-Chain genesis MUST include the warp precompile:
|
|
|
|
```json
|
|
{
|
|
"alloc": {
|
|
"0200000000000000000000000000000000000005": {
|
|
"balance": "0x0",
|
|
"nonce": "0x1",
|
|
"code": "0x01"
|
|
},
|
|
"0x9011E888251AB053B7bD1cdB598Db4f9DEd94714": {
|
|
"balance": "0x193e5939a08ce9dbd480000000"
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
This produces the canonical state root: `0x2d1cedac263020c5c56ef962f6abe0da1f5217bdc6468f8c9258a0ea23699e80`
|
|
|
|
### Upgrade Timestamps
|
|
|
|
C-Chain protocol upgrades activated Dec 25, 2024 @ 4:20pm UTC (timestamp 1735143600):
|
|
|
|
```json
|
|
{
|
|
"evmTimestamp": 0,
|
|
"durangoTimestamp": 0,
|
|
"quasarTimestamp": 1735143600,
|
|
"fortunaTimestamp": 1735143600,
|
|
"graniteTimestamp": 1735143600
|
|
}
|
|
```
|
|
|
|
## Genesis Package (`pkg/genesis/`)
|
|
|
|
### Core Types
|
|
|
|
```go
|
|
// Config - Top-level genesis configuration
|
|
type Config struct {
|
|
NetworkID uint32
|
|
Allocations []Allocation
|
|
StartTime uint64
|
|
InitialStakeDuration uint64
|
|
InitialStakeDurationOffset uint64
|
|
InitialStakedFunds []ids.ShortID
|
|
InitialStakers []Staker
|
|
CChainGenesis string
|
|
Message string
|
|
}
|
|
|
|
// Staker - Initial validator
|
|
type Staker struct {
|
|
NodeID ids.NodeID
|
|
RewardAddress ids.ShortID
|
|
DelegationFee uint32
|
|
Signer *ProofOfPossession
|
|
Weight uint64
|
|
StartTime uint64
|
|
EndTime uint64
|
|
}
|
|
|
|
// Allocation - Genesis allocation
|
|
type Allocation struct {
|
|
EVMAddr ids.ShortID `json:"evmAddr"`
|
|
UTXOAddr ids.ShortID `json:"utxoAddr"`
|
|
InitialAmount uint64 `json:"initialAmount"`
|
|
UnlockSchedule []LockedAmount `json:"unlockSchedule"`
|
|
}
|
|
```
|
|
|
|
**Address naming — `EVMAddr` + `UTXOAddr`. Always.**
|
|
|
|
- `EVMAddr` (Go) ↔ `evmAddr` (JSON) — address on EVM-modeled chains (C and other EVM letter chains).
|
|
- `UTXOAddr` (Go) ↔ `utxoAddr` (JSON) — address on UTXO-modeled chains (P, X; share the same 20-byte ShortID; bech32 prefix differentiates chain).
|
|
|
|
Never use `ETHAddr` / `LUXAddr` / `ethAddr` / `luxAddr` in new code. The
|
|
fields name the *chain model* (EVM, UTXO), not a specific implementation
|
|
we happen to be wire-compatible with.
|
|
|
|
The one exception is `ParseETHAddress(string) ids.ShortID` — that's the
|
|
*input* description (parses an Ethereum-format hex string like `0x...`).
|
|
The function output binds to `EVMAddr`.
|
|
|
|
### Bech32 Address Format
|
|
|
|
Addresses use chain prefix + bech32 encoding:
|
|
|
|
```
|
|
Format: {chain}-{hrp}1{data}{checksum}
|
|
Example: P-lux1ck0t9h5u7jvvzhx29n99guqjsfkpzt67wgx7wg
|
|
|
|
Chain Prefixes:
|
|
- P-lux1... (P-Chain — ProtocolVM)
|
|
- X-lux1... (X-Chain/Exchange)
|
|
- C-0x... (C-Chain/EVM hex)
|
|
```
|
|
|
|
**Important**: The bech32 checksum is computed using only the HRP ("lux"), not the chain prefix ("P-lux").
|
|
|
|
## CLI Tools
|
|
|
|
### genesis (`cmd/genesis/`)
|
|
|
|
Generate genesis configurations:
|
|
|
|
```bash
|
|
# Generate from mnemonic
|
|
LUX_MNEMONIC="test test..." ./genesis -network-id 96369 -validators 5 -output genesis.json
|
|
|
|
# From existing keys
|
|
./genesis -network mainnet -keys-dir ~/.lux/keys -output genesis.json
|
|
```
|
|
|
|
### extract-genesis (`cmd/extract-genesis/`)
|
|
|
|
Extract genesis from existing chain data:
|
|
|
|
```bash
|
|
./extract-genesis -chaindata /path/to/chaindata -output cchain.json
|
|
```
|
|
|
|
## State Repository Integration
|
|
|
|
Historical blockchain state is maintained separately in [luxfi/state](https://github.com/luxfi/state).
|
|
|
|
### Available State Data
|
|
|
|
| Network | Blocks | RLP Size | Location |
|
|
|---------|--------|----------|----------|
|
|
| Lux Mainnet | 1,082,780 | 1.2 GB | `rlp/lux-mainnet/lux-mainnet-96369.rlp` |
|
|
| Lux Testnet | 218 | 695 KB | `rlp/lux-testnet/lux-testnet-96368.rlp` |
|
|
| Zoo Mainnet | 799 | 1.3 MB | `rlp/zoo-mainnet/zoo-mainnet-200200.rlp` |
|
|
| Zoo Testnet | 84 | 156 KB | `rlp/zoo-testnet/zoo-testnet-200201.rlp` |
|
|
| SPC Mainnet | 11 | 7.8 KB | `rlp/spc-mainnet/spc-mainnet-36911.rlp` |
|
|
|
|
### Import Workflow
|
|
|
|
```bash
|
|
# Clone repos
|
|
git clone https://github.com/luxfi/genesis
|
|
git clone https://github.com/luxfi/state
|
|
|
|
# Initialize with genesis
|
|
geth init --datadir /tmp/lux genesis/configs/mainnet/cchain.json
|
|
|
|
# Import blocks
|
|
geth import --datadir /tmp/lux state/rlp/lux-mainnet/lux-mainnet-96369.rlp
|
|
```
|
|
|
|
### LuxEVM Header Formats
|
|
|
|
State repo RLP uses LuxEVM header encoding:
|
|
|
|
| Fields | Format | Usage |
|
|
|--------|--------|-------|
|
|
| 16 | Genesis block | No optional fields |
|
|
| 17-19 | Post-genesis | ExtDataHash, ExtDataGasUsed, BlockGasCost |
|
|
|
|
**Coreth field order** (positions 15+):
|
|
```
|
|
15: ExtDataHash (common.Hash - value type, required)
|
|
16: BaseFee (*big.Int)
|
|
17: ExtDataGasUsed (*big.Int)
|
|
18: BlockGasCost (*big.Int)
|
|
```
|
|
|
|
## Mainnet Validators
|
|
|
|
| Node | NodeID | P-Chain Address |
|
|
|------|--------|-----------------|
|
|
| 1 | NodeID-FrtEjhat6RUqjEWCJgYZKqBaxY2Woyy5G | P-lux1ck0t9h5u7jvvzhx29n99guqjsfkpzt67wgx7wg |
|
|
| 2 | NodeID-9hq49qGVZN7M7tXxdpF3AqptQGdmPCFnQ | P-lux1dclruwcn9ug8u0jjk3ukh676jr3lsy4er9m3l5 |
|
|
| 3 | NodeID-8osEnSC4LQFdG1LMit12CBsE6BfKGHNAw | P-lux1qdv9zns0gpfesw0h28jqp2up6h77du2damqf88 |
|
|
| 4 | NodeID-MrdgTgPuddyo7anomKr4akMcoKzVKcgbG | P-lux1jjs4nx7ul4d6pnsjtpv2khzu8p4yctegvass46 |
|
|
| 5 | NodeID-Mgd5yHs4pe6qRjkBcW5Y7oqHA51j4afcC | P-lux1970ngvf6s6rsndrkvjzr6lfvf2tdl30529c435 |
|
|
|
|
## Token Decimals
|
|
|
|
```go
|
|
// P-Chain/X-Chain: 6 decimals (microLUX as base unit)
|
|
const (
|
|
MicroLux uint64 = 1 // 0.000001 LUX
|
|
MilliLux uint64 = 1_000 // 0.001 LUX
|
|
Lux uint64 = 1_000_000 // 1 LUX
|
|
)
|
|
|
|
// C-Chain: 18 decimals (wei, standard EVM)
|
|
// 1 LUX = 10^18 wei on C-Chain
|
|
```
|
|
|
|
## Verification
|
|
|
|
### Genesis Hash Check
|
|
|
|
```bash
|
|
# Verify mainnet C-Chain genesis
|
|
geth init --datadir /tmp/verify configs/mainnet/cchain.json 2>&1 | grep "genesis hash"
|
|
# Expected: 0x3f4fa2a0b0ce089f52bf0ae9199c75ffdd76ecafc987794050cb0d286f1ec61e
|
|
|
|
# Verify state root
|
|
cat configs/mainnet/cchain.json | jq -r '.stateRoot'
|
|
# Expected: 0x2d1cedac263020c5c56ef962f6abe0da1f5217bdc6468f8c9258a0ea23699e80
|
|
```
|
|
|
|
### Network ID Verification
|
|
|
|
```bash
|
|
cat configs/mainnet/network.json | jq '.networkID'
|
|
# Expected: 96369
|
|
|
|
cat configs/testnet/network.json | jq '.networkID'
|
|
# Expected: 96368
|
|
```
|
|
|
|
## Fortuna Timestamp Fix (2025-12-25)
|
|
|
|
### Problem
|
|
Block import failed with gas limit mismatch when importing Zoo chain blocks:
|
|
```
|
|
invalid gas limit: have 12000000, want 10000000
|
|
```
|
|
|
|
### Root Cause
|
|
Zoo genesis files had `fortunaTimestamp: 0` which activates Fortuna from block 0. Fortuna uses dynamic gas limits via `state.MaxCapacity()` returning 10M, but original blocks had 12M gas limit (Cortina rules).
|
|
|
|
### Solution
|
|
Set far-future timestamps for the pre-Quasar Edition upgrades that the
|
|
imported Zoo blocks predate (the `quasarTimestamp`/`fortunaTimestamp`/
|
|
`graniteTimestamp` JSON fields are preserved verbatim because they are
|
|
the wire-format identifiers consumed by luxfi/evm; only the prose label
|
|
moves to "Quasar Edition upgrades"):
|
|
|
|
```json
|
|
{
|
|
"quasarTimestamp": 253399622400,
|
|
"fortunaTimestamp": 253399622400,
|
|
"graniteTimestamp": 253399622400
|
|
}
|
|
```
|
|
|
|
### Files Updated
|
|
- `zooai/universe/configs/genesis/mainnet/genesis.json` (moved from `luxfi/genesis/configs/zoo-mainnet/` in Task #109)
|
|
- `zooai/universe/configs/genesis/testnet/genesis.json` (moved from `luxfi/genesis/configs/zoo-testnet/` in Task #109)
|
|
|
|
### Verified Block Counts (2025-12-28)
|
|
|
|
| Network | Chain ID | Blocks | Genesis Hash |
|
|
|---------|----------|--------|--------------|
|
|
| Lux Mainnet | 96369 | **1,082,780** | `0x3f4fa2a0b0ce089f52bf0ae9199c75ffdd76ecafc987794050cb0d286f1ec61e` |
|
|
| Lux Testnet | 96368 | **218** | `0x1c5fe37764b8bc146dc88bc1c2e0259cd8369b07a06439bcfa1782b5d4fb0995` |
|
|
| Zoo Mainnet | 200200 | **799** | `0x7c548af47de27560779ccc67dda32a540944accc71dac3343da3b9cd18f14933` |
|
|
| Zoo Testnet | 200201 | **84** | `0x0652fb2fde1460544a5893e5eba5095ff566861cbc87fcb1c73be2b81d6d1979` |
|
|
| SPC Mainnet | 36911 | **11** | `0x4dc9fd5cf4ee64609f140ba0aa50f320cadf0ae8b59a29415979bc05b17cfac8` |
|
|
|
|
---
|
|
|
|
## Canonical Genesis Checksums (SHA256)
|
|
|
|
**IMPORTANT**: All genesis files are sorted alphabetically by key for determinism.
|
|
These checksums are the canonical reference - if they don't match, the file has been modified.
|
|
|
|
| File | SHA256 |
|
|
|------|--------|
|
|
| `mainnet/cchain.json` | `968e9f3cd19a9b88ca157db3894622272ded02f0f184b5386493ff55897001be` |
|
|
| `testnet/cchain.json` | `ba211e1bbbd7807c2224d240628facb2dfb6c2d6cde2e274eb881a57609ed038` |
|
|
| `zoo-mainnet/genesis.json` | `14c01e8bb5ac13144a3730c695847d53506647efbaada3f3240a16e7b10684f7` |
|
|
| `zoo-testnet/genesis.json` | `b8eea8c6b3276ebadce7e8ef9296bc14b56990ae04cd200a4663f5af21193534` |
|
|
| `zoo-devnet/genesis.json` | `4890a40fe7891722c90efb728f11b14aeef9795c2b897eb0140e1e0ae3b6254c` |
|
|
| `spc-mainnet/genesis.json` | `9c01115559556fc245d4993b193889370bd99edd22a7fa1e9e3d7ddafbb63535` |
|
|
| `spc-testnet/genesis.json` | `af12bb81dd9abce26b7a311f00fa2ac7f5adfb996e698b9f473252199f747b2c` |
|
|
| `spc-devnet/genesis.json` | `317d54ac7846b0f174964552b4949d858072f6ffbc37f6c10092e01d595ce46f` |
|
|
| `hanzo-mainnet/genesis.json` | `adae3c441b34db937dbcd961450bff5bcabd388a5479fe9ba7380ef61f083637` |
|
|
| `hanzo-testnet/genesis.json` | `a2d00685bf7f414815dc3579552e19045183428c520f4f5b23a6726cf4002c32` |
|
|
| `hanzo-devnet/genesis.json` | `1c489d29c08857696909f029a1b2cda554e059e86c630ae64f35a5243f4bd25c` |
|
|
| `pars-mainnet/genesis.json` | `ca35306a73f4cbfeccc8018b71596b122f698a23f3c038993a2ad34ca315e539` |
|
|
| `pars-testnet/genesis.json` | `9d7ff05187bb2570d2a1af8ccfa41a99dfaf8b56558decf127209ac6d5faec85` |
|
|
| `pars-devnet/genesis.json` | `3fc55f6be7b46dd6955ab2ec95186a4aa7da13991650909cb5f9ecbaa51b06c7` |
|
|
|
|
### Verify Checksum
|
|
|
|
```bash
|
|
cd ~/work/lux/genesis/configs
|
|
shasum -a 256 zoo-mainnet/genesis.json
|
|
# Should output: 241fd0209253e7a5a04c55c7a6f4f0ba864a83dd9840c4969d5a1b5b5f6c3366
|
|
```
|
|
|
|
### Re-sort if Modified
|
|
|
|
```bash
|
|
# If file was modified, re-sort it:
|
|
jq -S '.' genesis.json > genesis.sorted.json && mv genesis.sorted.json genesis.json
|
|
```
|
|
|
|
---
|
|
|
|
## Genesis Hash Fix (2025-12-28)
|
|
|
|
### Problem
|
|
Mainnet genesis hash was computing as `0xc3069db32ef986d8e287458e44066eb04205648e602dc2fede561c424a6516de` instead of the expected `0x3f4fa2a0b0ce089f52bf0ae9199c75ffdd76ecafc987794050cb0d286f1ec61e` from historical RLP blocks.
|
|
|
|
### Root Cause
|
|
The `warpConfig.blockTimestamp` was set to 0, which caused `ApplyPrecompileActivations()` in coreth to add the warp precompile to genesis state BEFORE the alloc was applied. When warp wasn't in alloc, this changed the state trie and produced a different genesis hash.
|
|
|
|
**Key insight from `coreth/core/genesis.go:271`:**
|
|
```go
|
|
// ApplyPrecompileActivations runs FIRST (line 271)
|
|
ApplyPrecompileActivations(g.Config, nil, blockContext, statedb)
|
|
|
|
// Then alloc is applied (lines 276-283)
|
|
for addr, account := range g.Alloc {
|
|
// This overwrites precompile if in alloc, leaves it if not
|
|
}
|
|
```
|
|
|
|
### Solution
|
|
The original mainnet genesis was created with warp precompile IN the alloc section:
|
|
|
|
```json
|
|
{
|
|
"alloc": {
|
|
"0200000000000000000000000000000000000005": {
|
|
"balance": "0x0",
|
|
"nonce": "0x1",
|
|
"code": "0x01"
|
|
}
|
|
},
|
|
"warpConfig": {
|
|
"blockTimestamp": 1730446786,
|
|
"quorumNumerator": 67,
|
|
"requirePrimaryNetworkSigners": false
|
|
}
|
|
}
|
|
```
|
|
|
|
The `warpConfig.blockTimestamp` equals the genesis timestamp (`0x672485c2` = 1730446786), meaning warp is activated at genesis. Having warp in both alloc AND warpConfig ensures consistent state.
|
|
|
|
### Files Restored
|
|
- `configs/mainnet/cchain.json` - Restored from git with warp in alloc
|
|
- `configs/mainnet/genesis.json` - Updated cChainGenesis to match
|
|
|
|
### Verification
|
|
```bash
|
|
# Start mainnet
|
|
netrunner start --networks mainnet
|
|
|
|
# Verify genesis hash
|
|
curl -X POST -H 'Content-Type: application/json' \
|
|
--data '{"jsonrpc":"2.0","method":"eth_getBlockByNumber","params":["0x0",false],"id":1}' \
|
|
http://127.0.0.1:9630/ext/bc/C/rpc | jq '.result.hash'
|
|
# Expected: "0x3f4fa2a0b0ce089f52bf0ae9199c75ffdd76ecafc987794050cb0d286f1ec61e"
|
|
|
|
# Verify warp precompile in state
|
|
curl -X POST -H 'Content-Type: application/json' \
|
|
--data '{"jsonrpc":"2.0","method":"eth_getCode","params":["0x0200000000000000000000000000000000000005","0x0"],"id":1}' \
|
|
http://127.0.0.1:9630/ext/bc/C/rpc | jq '.result'
|
|
# Expected: "0x01"
|
|
```
|
|
|
|
---
|
|
|
|
## Known Issues
|
|
|
|
### Documentation Discrepancies
|
|
|
|
1. **Network IDs**: Some older docs reference Network ID 1/2 instead of 96369/96368
|
|
2. **File paths**: Docs may reference `chain.rlp.gz` but actual files are `{network}-{chainid}.rlp`
|
|
3. **Block counts**: Documentation may be outdated - verify against actual RLP files
|
|
|
|
### State Repo Sync
|
|
|
|
The state repo should be periodically updated with:
|
|
- Latest block exports
|
|
- Updated metadata.json files
|
|
- Corrected documentation
|
|
|
|
---
|
|
|
|
## RLP Import via luxd `--import-chain-data`
|
|
|
|
End-to-end auto-import of historical chain data on luxd startup. Replaces the
|
|
prior geth-sidecar workflow.
|
|
|
|
### Flow
|
|
|
|
1. `luxd --import-chain-data=<path.rlp>` (existing flag, was unwired).
|
|
2. `node/config/config.go` *config bridge* injects `import-chain-data` into
|
|
`nodeConfig.ChainConfigs["C"].Config` JSON map. Merges with any existing
|
|
C-Chain config.
|
|
3. EVM plugin reads `vm.config.ImportChainData` in `Initialize()` after
|
|
`initializeChain()` returns. If non-empty, calls `importBlocksFromFile`
|
|
(same code path as `admin_importChain` RPC).
|
|
4. RLP stream decoded in batches of 2,500 blocks. State trie committed every
|
|
`CommitInterval` (4,096) blocks; `acceptedBlockDB` updated atomically with
|
|
each commit so restart-safe.
|
|
5. Final state commit + last-accepted update at end-of-stream.
|
|
|
|
### Required cChainGenesis (NON-NEGOTIABLE)
|
|
|
|
`genesis.json` `cChainGenesis` MUST be the canonical mainnet config:
|
|
- `chainId`: 96369 (NOT 1 — chainId 1 in cChainGenesis means genesis.json was
|
|
overwritten with a wrong-network template; restore from `cchain.json`)
|
|
- Warp precompile in `alloc`: address `0200000000000000000000000000000000000005`,
|
|
`nonce: "0x1"`, `code: "0x01"`
|
|
- `warpConfig.blockTimestamp`: 1730446786 (== genesis timestamp 0x672485c2)
|
|
|
|
If any of these drift, the EVM computes a non-canonical genesis hash (commonly
|
|
`0xcd5083cb…`) and RLP block 1's `parentHash` won't match → import fails with
|
|
`batch 0: block 1 parent mismatch - expected genesis 0xcd…, got 0x3f4fa2a0…`.
|
|
|
|
Restore from canonical:
|
|
```bash
|
|
python3 -c "import json
|
|
canon = json.load(open('configs/mainnet/cchain.json'))
|
|
g = json.load(open('configs/mainnet/genesis.json'))
|
|
g['cChainGenesis'] = json.dumps(canon, separators=(',', ':'), sort_keys=True)
|
|
json.dump(g, open('configs/mainnet/genesis.json', 'w'), indent=2, sort_keys=True)"
|
|
```
|
|
|
|
### Wiring sites (when re-implementing)
|
|
|
|
| Layer | File | What |
|
|
|-------|------|------|
|
|
| Flag | `node/config/keys.go` `ImportChainDataKey` | Already exists |
|
|
| Flag | `node/config/flags.go:370` | Already exists |
|
|
| Bridge | `node/config/config.go:2012-2028` | NEW: inject into `chainConfigs["C"]` after `getChainConfigs` |
|
|
| Plugin config | `evm/plugin/evm/config/config.go` `Config.ImportChainData` | NEW: matches JSON key `import-chain-data` |
|
|
| Plugin init | `evm/plugin/evm/vm.go` `Initialize()` post-`initializeChain` | NEW: calls `importBlocksFromFile` |
|
|
| Import logic | `evm/plugin/evm/admin_api.go:220` `importBlocksFromFile` | Pre-existing — used by `admin_importChain` |
|
|
|
|
### macOS gotcha (kills luxd silently)
|
|
|
|
After `cp` of the luxd binary to a new path, macOS gatekeeper can SIGKILL on
|
|
launch (exit 137, no output). The provenance attribute (`com.apple.provenance`)
|
|
plus an invalidated ad-hoc signature is the cause. Fix:
|
|
```bash
|
|
codesign --force --sign - ~/work/lux/node/build/luxd
|
|
codesign --force --sign - ~/work/lux/node/build/plugins/*
|
|
```
|
|
|
|
### Plugin filename / VM ID
|
|
|
|
The Lux EVM plugin has one canonical VM ID for both C-Chain and other EVM chains:
|
|
|
|
```
|
|
mgj786NP7uDwBCcq6YwThhaN8FLyybkCa4zBWTQbNgmK6k9A6
|
|
```
|
|
|
|
This is `CB58(ids.ID{'e','v','m'})` per `luxfi/constants.EVMID`. luxd's chain manager, the lux-operator, and `luxfi/cli` all reference this one ID. Install the plugin binary at `~/.lux/plugins/mgj786NP7uDwBCcq6YwThhaN8FLyybkCa4zBWTQbNgmK6k9A6` — no other filename, no aliases.
|
|
|
|
### Verified output (mainnet)
|
|
|
|
```
|
|
read last accepted hash=0x3f4fa2a0b0ce089f52bf0ae9199c75ffdd76ecafc987794050cb0d286f1ec61e height=0
|
|
Loaded most recent local header hash=0x3f4fa2a0…
|
|
Initializing snapshots headHash=0x3f4fa2a0… headRoot=0x2d1cedac263020c5c56ef962f6abe0da1f5217bdc6468f8c9258a0ea23699e80
|
|
Auto-importing chain data at startup path=…/lux-mainnet-96369.rlp
|
|
ImportChain: inserting batch batch=0 blocks=2500 firstNum=1
|
|
ImportChain: batch done batch=0 imported=2500 height=2500
|
|
…
|
|
```
|
|
|
|
Throughput: ~550 blocks/sec early, ~150 blocks/sec by ~100k blocks (state-trie
|
|
growth). 1.08M blocks → ~60-90 min wall time on M-series.
|
|
|
|
---
|
|
|