This LP fixes the shape of ~/work/lux/genesis/configs/. Lux primary
network has three coordination chains (P, X, C) at v1, each with its
own genesis blob keyed by environment (mainnet / testnet / devnet).
Each sovereign L1 (Hanzo, Zoo, Pars, Spc) has a single genesis.json
per environment carrying its EVM chain genesis. The v1 lock fixes
field names (evmAddr + utxoAddr), the precompile activation set
(canonical 18-precompile manifest), and the directory layout. A
genesis file outside this shape is a v1 regression caught by the
genesis verification suite.
Pre-v1 the genesis directory accreted ad-hoc fields, mixed
conventions for address representation, and carried precompile
configs that no longer mapped to a live precompile binary. v1
freezes:
evmAddr + utxoAddr, never eth_address / paddr / x_address etc.)
manifest, with no eciesConfig, no coronaThreshold)
A genesis file that drifts from this shape fails the genesis
verification suite at
~/work/lux/genesis/configs/getgenesis_test.go.
~/work/lux/genesis/configs/
mainnet/
pchain.json P-Chain genesis (Lux primary, networkID=1)
xchain.json X-Chain genesis (UTXO, network-wide settlement)
cchain.json C-Chain genesis (Lux primary EVM ONLY)
bootstrappers.json primary network bootstrappers
testnet/
pchain.json (networkID=2)
xchain.json
cchain.json
bootstrappers.json
devnet/
pchain.json (networkID=3)
xchain.json
cchain.json
bootstrappers.json
hanzo-mainnet/genesis.json Hanzo L1 EVM chain genesis (chainID=36963)
hanzo-testnet/genesis.json Hanzo testnet
hanzo-devnet/genesis.json Hanzo devnet
zoo-mainnet/genesis.json Zoo L1 EVM chain genesis (chainID=200200)
zoo-testnet/genesis.json
zoo-devnet/genesis.json
pars-mainnet/genesis.json Pars L1 EVM chain genesis (chainID=7070)
pars-testnet/genesis.json
pars-devnet/genesis.json
spc-mainnet/genesis.json Spc L1 EVM chain genesis (chainID=36911)
spc-testnet/genesis.json
spc-devnet/genesis.json
NO non-Lux L1 has a pchain.json. The P-Chain is Lux primary's
validator registry; sovereign L1s do not need their own. The
sovereign L1's validator set is bound at spawn time via the
atomic primitive (LP-018) and lives on Lux primary's P-Chain
registration record.
~/work/lux/genesis/configs/<env>/pchain.json carries the Lux
primary network's validator set and allocations. Required
top-level fields:
{
"networkID": 1,
"allocations": [
{
"ethAddr": "0x...", // (deprecated; superseded by evmAddr in v1)
"utxoAddr": "P-lux1...",
"evmAddr": "0x9011e888...",
"initialAmount": ...,
"unlockSchedule": [ ... ]
},
...
],
"initialStakers": [ ... ],
...
}
The v1 canonical address-field invariant: every allocation entry
carries both utxoAddr (bech32 P-Chain address) and evmAddr (20-byte
EVM address, hex). The pre-v1 ethAddr alias is retained for
on-disk compatibility but new tooling reads evmAddr exclusively.
networkID values:
networkID |1 |2 |3 |Setting networkID to any value in 8675xxx is a v1 violation —
those are EVM chain IDs, not primary network IDs (LP-016).
~/work/lux/genesis/configs/<env>/xchain.json carries the X-Chain
UTXO genesis. X-Chain is reserved for network-wide settlement of
primary-network assets. Sovereign L1s do NOT have their own
X-Chain.
~/work/lux/genesis/configs/<env>/cchain.json carries the C-Chain
EVM genesis. C-Chain runs Lux primary's EVM, with EVM chain ID
distinct from any sovereign L1 EVM chain ID. The
LUX_DISABLE_CCHAIN=1 env knob lives in
~/work/lux/node/config/configs.go; downstream L1 builds set it to
harden against accidental C-Chain spawning on a non-Lux primary.
~/work/lux/genesis/configs/<tenant>-<env>/genesis.json is the
ONLY genesis file each sovereign L1 carries. Its shape is the
standard EVM genesis with Lux-specific extensions:
{
"alloc": {
"0xPRECOMPILE_OR_USER_ADDR": {
"balance": "0x...",
"code": "0x...",
"nonce": "0x..."
},
...
},
"baseFeePerGas": "0x...",
"coinbase": "0x0000000000000000000000000000000000000000",
"config": {
"chainId": <int>, // L1's EVM chain ID, distinct per tenant
"feeConfig": { ... },
"warpConfig": { ... },
"precompileUpgrades": [ ... ] // canonical 18-precompile activation
},
...
}
The alloc map funds genesis accounts to the wei. Per-L1 native
funding lives here; cross-L1 funding (e.g. tenant treasury seeded
from Lux primary) is a post-spawn bridge tx, not a genesis field.
Cross-grep against
~/work/lux/genesis/configs/<tenant>-<env>/genesis.json:"chainId":
verifies these.
The v1 lock fixes the precompile manifest a fresh sovereign L1's
precompileUpgrades array must enable. The set is keyed by config
name:
1. aiMiningConfig
2. anchorConfig
3. attestationConfig
4. babyjubjubConfig
5. blake3Config
6. bls12381G1AddConfig, bls12381G1MulConfig,
bls12381G1MSMConfig, bls12381G2AddConfig,
bls12381G2MulConfig, bls12381G2MSMConfig,
bls12381PairingConfig (counted as one BLS12-381 EIP-2537
precompile-set entry, exposed as 7 sub-configs)
7. bridgeRegistrarConfig
8. coronaThreshold (Corona PQ precompile)
9. curve25519Config
10. dexConfig (only on DEX-bearing L1s)
11. fheConfig (only on FHE-bearing L1s)
12. frostVerify
13. hpkeConfig
14. mlkemConfig (FIPS 203 ML-KEM)
15. pedersenConfig
16. poseidonConfig
17. vrfConfig
18. zkConfig
Removed in v1:
eciesConfig — ECIES is superseded by hpkeConfig + mlkemConfigfor v1 PQ-hybrid encapsulation. A fresh L1 SHOULD NOT enable
eciesConfig. Existing tenant genesis files carrying
eciesConfig are post-v1 cleanup targets; the precompile binary
remains for read-back compatibility but new genesis emission
drops it.
coronaThreshold — absent at v1 (NIST PQC round-2 candidatenot advanced; never canonical).
DEX-VM-only and FHE-VM-only precompile entries are conditional:
a non-DEX L1 SHOULD NOT enable dexConfig; a non-FHE L1 SHOULD
NOT enable fheConfig.
evmAddr (lowercase EVM-address hex) and utxoAddr (bech32 P-Chain
address) are the canonical field names across every Lux primary
allocation entry. The v1 test gate at
~/work/lux/genesis/configs/getgenesis_test.go:29-30 asserts
utxoAddr presence on every allocation; evmAddr presence is
asserted in the same suite.
White-label tenants live outside ~/work/lux/genesis/ in their own
trees and may opt out of C-Chain (LP-016) with their own EVM chain
ID space. The LUX_DISABLE_CCHAIN=1 env knob in
~/work/lux/node/config/configs.go is the load-bearing guard that
keeps C-Chain off for any node that does not need it.
The bootstrap-chain CLI at
~/work/lux/genesis/cmd/bootstrap-chain/main.go consumes these
configs to spin up a fresh chain. Key code paths:
~/work/lux/genesis/cmd/bootstrap-chain/main.go:717 — from := evmAddrFromPriv(priv) (the genesis-fund derivation
point uses the canonical evmAddrFromPriv helper, NOT a
bespoke EVM-address derivation).
~/work/lux/genesis/cmd/bootstrap-chain/main.go:768-769 — evmAddrFromPriv definition: keccak256(pubKey)[-20:].
The genesis CLI at ~/work/lux/genesis/cmd/genesis/main.go
emits, edits, and verifies genesis blobs. Its address-emission
path at line 249 (addrHex := fmt.Sprintf("0x%s", a.EVMAddr.Hex()))
uses the canonical field name.
The checkkeys CLI at
~/work/lux/genesis/cmd/checkkeys/main.go:39-47 cross-checks
derived EVM addresses against the genesis allocation map, using
the canonical EVMAddr field name throughout.
genesis.json per sovereign L1A tenant L1 carries one or more chains, but the v1 spawn primitive
(LP-018) registers all chains in one atomic tx. The
genesis.json is the EVM chain's genesis; per-L1 non-EVM chains
(DEX, FHE) embed their genesis as GenesisData inside the spawn
tx's Chains[] array, not as a separate config file.
This keeps the on-disk surface minimal: one genesis file per L1
EVM chain, full stop. Non-EVM chain genesis blobs are inputs to
the spawn CLI, not standing config artifacts.
pchain.jsonP-Chain is Lux primary's validator-set registry. A sovereign L1's
validator set is encoded in the spawn tx (LP-018), not in a
separate genesis file. The pre-v1 pattern of carrying a
per-tenant pchain.json was a workaround for the four-step spawn
flow; v1's atomic spawn removes the need.
evmAddr + utxoAddr over address / eth_addrBoth representations are present in every allocation because Lux
primary's UTXO + EVM bridge needs both views. Naming them as
evmAddr + utxoAddr makes the intent explicit and decomplects
them from chain-specific aliases (paddr, xaddr, cAddress,
etc.) that drifted across the pre-v1 tooling.
eciesConfigECIES (secp256k1 + AES-GCM with KDF over the shared secret) is
not PQ-secure. v1 mandates hpkeConfig (RFC 9180 HPKE, ML-KEM-768
PQ-hybrid) for fresh encryption usage. The ECIES precompile binary
remains for historical bytecode that calls it; new genesis emission
omits it.
None. v1 is the lock-in.
Existing on-disk tenant genesis files that carry the pre-v1 fields
(eciesConfig, ethAddr alias, etc.) remain decodable. New
emission paths (CLI, scripts, infra-as-code) write the v1 shape
exclusively.
~/work/lux/genesis/configs/getgenesis_test.go:29-30 asserts utxoAddr presence on every allocation in every Lux primary
pchain.json.
~/work/lux/genesis/configs/getgenesis_test.go:101-102 assertsthe same property on a parallel path through the resolver.
~/work/lux/genesis/configs/embed_test.go exercises thego-embed surface against every shipped genesis blob; a new file
in the directory must register here.
~/work/lux/genesis/configs/chain_shards_test.go cross-checksper-chain genesis shard consistency.
A v1 compliance test added under
~/work/lux/genesis/configs/v1_canonical_shape_test.go MUST
assert:
1. Every <env>/pchain.json parses with networkID ∈ {1, 2, 3}.
2. Every <tenant>-<env>/genesis.json parses with chainId ∈
the canonical assignment table.
3. No fresh genesis.json enables eciesConfig or
coronaThreshold.
~/work/lux/genesis/configs/mainnet/pchain.json — canonical Lux primary mainnet P-Chain genesis. networkID = 1.
~/work/lux/genesis/configs/testnet/pchain.json — networkID = 2.
~/work/lux/genesis/configs/devnet/pchain.json — networkID = 3.
~/work/lux/genesis/configs/hanzo-mainnet/genesis.json:26 — "chainId": 36963 (Hanzo L1 EVM mainnet).
~/work/lux/genesis/configs/zoo-mainnet/genesis.json:26 — "chainId": 200200 (Zoo L1 EVM mainnet).
~/work/lux/genesis/configs/pars-mainnet/genesis.json:26 — "chainId": 7070 (Pars L1 EVM mainnet).
~/work/lux/genesis/configs/spc-mainnet/genesis.json:26 — "chainId": 36911 (Spc L1 EVM mainnet).
~/work/lux/genesis/configs/mainnet/pchain.json:407-408 — example utxoAddr + evmAddr allocation row.
~/work/lux/genesis/configs/getgenesis_test.go:29-30,101-102 — the utxoAddr invariant.
~/work/lux/genesis/cmd/checkkeys/main.go:39-47 — canonical EVMAddr field name in derivation tooling.
~/work/lux/genesis/cmd/bootstrap-chain/main.go:768-769 — evmAddrFromPriv derivation.
~/work/lux/genesis/cmd/genesis/main.go:249 — genesis emission uses a.EVMAddr.Hex().
The canonical 18-precompile activation pin closes a v0 footgun: a
genesis blob that silently enabled an unaudited precompile gave
that precompile EVM-execution semantics from block 0. v1's pinned
manifest means a reviewer checking the genesis sees exactly which
precompiles are active and can cross-check each against its
binary at ~/work/lux/node/precompile/.
The LUX_DISABLE_CCHAIN=1 env knob is the load-bearing guard
against the historical "C-Chain leak" pattern: a downstream
tenant accidentally inheriting C-Chain because the daemon
was the upstream luxd. The env knob is checked in
~/work/lux/node/config/configs.go and the resulting build refuses
to spawn C-Chain.
The evmAddr + utxoAddr field-naming invariant prevents a class
of address-confusion bug where tooling reads the wrong address
representation and credits funds to the wrong account-model
account. Both representations refer to the same allocation; the
naming pins which is which.
Copyright and related rights waived via CC0.