The KMS fetch was migrated to the canonical /v1/kms/orgs/{org}/secrets path, but
the file header and the usage example were left describing the Infisical v3 raw
API and telling operators to export KMS_WORKSPACE_ID — a variable this program
does not read. Following the header got you a tool that could not resolve the
org and failed with no obvious reason.
Both now match resolveMnemonic: KMS_ENDPOINT + KMS_TOKEN + KMS_ORG, fetching
GET ${KMS_ENDPOINT}/v1/kms/orgs/<org>/secrets/lux/<env>/staking/mnemonic.
Co-authored-by: Hanzo Dev <dev@hanzo.ai>
`go build ./...` failed outright — the v1.16.x line was DELETED from
github.com/luxfi/geth (newest is v1.20.1) while proxy.golang.org still serves
it, and GOPRIVATE forces a direct fetch for luxfi/*, so resolution fails with
"unknown revision v1.16.98".
Not fixable by tidying here: the requirement is baked into PUBLISHED modules,
which pin the dead tag and in some cases explicitly `exclude` the alternative.
The first versions that moved off it:
luxfi/crypto v1.20.2 (every version through v1.20.0 pins the dead tag)
luxfi/constants v1.6.2
luxfi/warp v1.24.1
Requiring those is what escapes it; geth then resolves to v1.20.1. Companion
luxfi modules moved with them at minor level within v1.x / v0.x — no major jumps.
Verified: go build ./... goes from exit 1 to exit 0. go test ./... is 1 ok / 3 fail. Those tests were NOT reachable before —
the packages could not compile — so this exposes pre-existing failures rather
than causing them.
fetchKMSMnemonic called Infisical v3 raw secrets:
GET ${KMS_ENDPOINT}/api/v3/secrets/raw?workspaceId=..&environment=prod&secretPath=..
That endpoint is not served by kms.lux.network or kms.hanzo.ai. Both answer it
with the console SPA HTML, so the JSON decode failed and no mnemonic was ever
retrievable this way — while the function, its env vars and its log line all
called it KMS.
Now it speaks the one documented HTTP surface, which luxfi/kms describes as the
only way to read a secret:
GET ${KMS_ENDPOINT}/v1/kms/orgs/<org>/secrets/lux/<env>/staking/mnemonic
Authorization: Bearer ${KMS_TOKEN} (IAM-signed, resolved to <org>)
-> {"secret": {"value": "..."}}
The server splits the path at its last slash into (path, name), so the secret
path still disambiguates the luxd env. ?env= is the KMS environment slug and
defaults to "default", matching the luxfi/kms client KMS_ENV.
KMS_WORKSPACE_ID is gone — an Infisical concept with no meaning here. Scope is
the org in the path: KMS_ORG, defaulting to lux. No compat shim; the old call
never worked.
Co-authored-by: Hanzo Dev <dev@hanzo.ai>
mainnet's mchain.json asked for 7-of-10 while mainnet genesis declares
five validators, and localnet asked for 3-of-5 with three. Nothing read
those fields before, so the mismatch was inert; now that the policy is
authoritative it would fail closed forever — RunKeygen refuses a policy
needing more parties than the committee has, so no custody key could ever
be generated.
Policies now match the validator set each network actually has: 3-of-5 on
mainnet/testnet/devnet, 2-of-3 on localnet. Both keep 2K > N, so neither
admits two disjoint quorums.
Co-authored-by: Hanzo Dev <dev@hanzo.ai>
mchain.json carried "mpcThreshold": 7 alongside "mpcParties": 10. A bare
threshold number is exactly the ambiguity that produced degree-0 (1-of-n)
custody keys elsewhere in this stack: an operator reads it as the number
of signers, every threshold library reads it as the polynomial degree,
and the two differ by one. Nothing in the VM read these fields, so the
genesis blob stated a quorum that had no effect and could not be trusted
if it ever did.
Replaced by a single "policy" field in operator form — "7-of-10" on
mainnet, "3-of-5" on testnet/devnet/localnet, sized so each network's
validator count can actually satisfy it. M-Chain decodes it through
quorum.Policy and derives the protocol degree from it at one place, so
genesis is now the authority on how many custodians must cooperate to
move bridged funds.
Also renames the vm field from the retired "ThresholdVM" to "mpcvm".
Co-authored-by: Hanzo Dev <dev@hanzo.ai>
stateUpgrades[1]@1784415311 (Multicall3 at 0xcA11...CA11, added in b6f6170) is a
latent brick for C-Chain 96369. The C-Chain EVM is github.com/luxfi/evm, whose
config load is strict:
- plugin/evm/vm.go:962 dec.DisallowUnknownFields()
- params/extras/state_upgrade.go checkStateUpgradesCompatible():
len(newUpgrades) > len(activeUpgrades) => "cannot retroactively enable
StateUpgrade[N]" => ConfigCompatError => VM init refused
Timestamp 1784415311 (2026-07-19) is already in the past. The live 5/5 run the
proven-canonical config (c3a1763) which has exactly ONE applied stateUpgrade,
[0]@1766708400 (23-account Path-A). The moment any luxfi/evm node rolls this
config with head past 1784415311, it computes 2 activated stateUpgrades vs the
1 in applied history -> retroactive error -> C-Chain bricks (warpConfig class).
Fix: remove stateUpgrades[1] entirely. Eliminates the retroactive-state-upgrade
brick class. File is now content-identical to proven-canonical c3a1763
(stateUpgrades=[0] only). Repo-config change ONLY — not rolled to live nodes.
Mainnet Multicall3 predeploy must instead use a FUTURE-dated monotonic
stateUpgrade or a deterministic factory (see deploy plan) — never a retroactive
one. Devnet got Multicall3 via CreateX factory with ZERO stateUpgrades.
Co-authored-by: Hanzo Dev <dev@hanzo.ai>
Canonical upstream mirror of the universe luxd-startup change. Adds a stateUpgrade at
blockTimestamp 1784415311 deploying the canonical Multicall3 runtime (3808 bytes, verified
byte-identical to Ethereum's live 0xcA11). Purely additive; strictly-increasing timestamps.
Co-authored-by: Hanzo Dev <dev@hanzo.ai>
The LP-018 (family,env)->EVMChainID source-of-truth map carried the stale
7070 for Pars mainnet, but the live chain reports 494949 (api.pars.network
eth_chainId=0x78d65 / net_version=494949), and the map's own Pars testnet/devnet
(494950/494951) are already on the 4949xx base. Align mainnet to 494949 so the
map, its reverse lookup, and the tests agree with reality and with the rest of
the map. brand-genesis-homes.md updated to match. Dated l2-*.json inventory
snapshots left as historical records.
Co-authored-by: Hanzo Dev <dev@hanzo.ai>
constants v1.6.1 references ids.MChainID/ids.FChainID (M-Chain=MPC,
F-Chain=FHE); ids v1.3.1 is the first tag that defines them. Unblocks
the module build (was: undefined: ids.MChainID). Builds green: go build
./... exit 0, pkg/genesis tests pass.
genesis.LightMnemonic becomes a backward-compat re-export of
light.Mnemonic (github.com/luxfi/light v1.0.0) — one source of truth for
the public dev seed, no local replace directive, published semver.
Orthogonal to the pre-existing constants v1.6.1 <-> ids MChainID/FChainID
skew that blocks this module's full build (verified: ids resolves to
v1.2.10 with and without this change; identical errors either way).
Co-authored-by: Hanzo AI <ai@hanzo.ai>
Was 242 lines / 4 near-identical funcs with per-chain include-lists AND
banned-lists — the redundancy bred two self-contradiction bugs (F and M each
listed a required alias in their own banned list; 'mpcvm' twice on F).
Rob Pike: data dominates. One spec table + one loop. Exact alias-set equality
IS the whole invariant — it subsumes must-include, must-not-claim-the-other's,
and no-collision in a single assertion, and makes contradictory lists
impossible by construction. Exact-match also surfaced K-Chain's real alias set
{k,key,keyvm,kms} that the lenient old test never pinned.
Co-authored-by: Hanzo Dev <dev@hanzo.ai>
The last thresholdvm braid: F-Chain and M-Chain shared constants.ThresholdVMID
and were disambiguated by BlockchainName string-match (mode dispatch). Flip to
distinct VMs per LP-134/LP-7050:
- builder.go:604 F-Chain VMID ThresholdVMID -> FHEVMID
- builder.go:608 M-Chain VMID ThresholdVMID -> MPCVMID
- alias map + Aliases() now dispatch directly on FHEVMID/MPCVMID (no
BlockchainName string-match, no shared-VM path)
- zero ThresholdVMID remains in live genesis wiring
Shard JSON 'vm' fields left as-is to preserve per-chain GenesisData byte-stability
(routing is by builder VMID). Fixed a pre-existing self-contradictory test
(TestLP134_MChainIsMPCOnly required AND banned alias 'mpcvm').
Gate: configs + builder suites green (chainID locks + LP-134 split tests pass).
Prod unaffected — node pins genesis v1.13.16 (T-model); this is un-adopted branch
state pending a coordinated node release.
Co-authored-by: Hanzo Dev <dev@hanzo.ai>
The genesis/builder submodule go.sum pinned the pre-retag h1 hash
(pFlQm1...) for luxfi/pq v1.0.3, which no longer matches the module the
proxy and the rest of the fleet resolve. Every active repo that depends on
pq v1.0.3 (api, chains, cli, consensus, dex, evm, node, ...) records the
current hash ksw1dmf...; only a few stale/archived trees still carry the
old one. This submodule was one of the stale ones, which broke
`go build`/`go test` in the builder module with a checksum-mismatch
SECURITY ERROR. Reconcile to the fleet-canonical hash (verified against the
already-extracted local module cache). Dependency-hygiene only; no genesis
content, chain ID, or code changes.
Co-authored-by: Hanzo Dev <dev@hanzo.ai>
Devnet had all precompiles at genesis-0 while mainnet/testnet gate the new-feature
wave at 1766708400. One and one way only: all three networks now share the single
canonical fork-activation schedule. This is also what makes RLP re-import clean
(pre-activation blocks re-execute with new precompiles inactive).
Co-authored-by: Hanzo Dev <dev@hanzo.ai>
Drop the Avalanche-heritage /ext prefix; /v1 is the single canonical route
surface (one way, no backward compat). The node's baseURL is the source of
truth; clients, SDKs, CLI, indexer, maker, genesis, netrunner, and the
k8s/compose/gateway/explorer configs are updated to match.
Co-authored-by: Hanzo Dev <dev@hanzo.ai>
--brands=hanzo,zoo issues CreateChainTx only for the named brands, in
canonical list order (deterministic chain ordering). Unknown brand names
are a hard error (a typo must not silently create a different chain set).
Pure stdlib; zero new deps. Default (empty) = all five brands as before.
Co-authored-by: Hanzo Dev <dev@hanzo.ai>
bootstrap-chain defaulted --track-chain-ids=hanzo,zoo,pars,spc — it created
brand L2 EVMs INSIDE luxd, the dead WAY-1 that produced the phantom brand
chains which decayed into dangling chain-aliases. Per brand_sovereign_node_one_way
luxd runs the LUX primary network ONLY; brands run their own sovereign node.
- default --track-chain-ids is now empty
- hard-refuse brand names (hanzo/zoo/pars/spc/osage) before any P-chain spend
- doc updated; retires alongside cmd/createchaintx (deleted on
decomplect/retire-brand-l2-in-luxd)
The legacy T-Chain conflated two orthogonal threshold primitives on one
ThresholdVM substrate. LP-134 decomplects them into two distinct
primary-network chains, both served by the shared ThresholdVM library:
F-Chain (F/fhe/fhevm) — threshold FHE, confidential compute / off-EVM
threshold DECRYPT. ThresholdVM in FHE mode.
M-Chain (M/mpc/mpcvm) — threshold MPC, CGGMP21/FROST bridge-custody
SIGNING. ThresholdVM in MPC mode. EVM verify
surface = 0x0800..02 (FROST) + 0x0800..03
(CGGMP21), verify-only, ceremony off-EVM.
Forward-only: tchain.json is retired on all 4 nets (T was never bootstrapped
with live state — a clean 404 forward-split, no state migration). F-Chain
occupies T's vacated shard slot (same VM, keeps Z/G/K byte-stable); M-Chain
is appended. Fresh non-colliding chainIds at the next free indices 9/10
(F: 97269/97268/97270/32327, M: 97369/97368/97370/32437); T's 96869-series
is not recycled.
K-Chain decomplect ("K stays keyvm" per LP-134): the M/mpc/mpcvm aliases and
MPC params were erroneously carried on the KeyVM shard (the "mpc->K backwards"
wiring). Moved them to M-Chain; kchain.json is now pure KMS key management.
Chain-level wiring (one way, data-driven by shard presence):
- pkg/genesis: ConfigOutput/Config gain FChainGenesis (T's slot) +
MChainGenesis; TChainGenesis removed.
- configs.go chainSet/primaryChainShardFiles/slots + config.go
optionalChainShards: tchain.json -> fchain.json, append mchain.json.
- builder: F and M both map to constants.ThresholdVMID (shared substrate)
and are disambiguated in Aliases() by CreateChainTx.BlockchainName.
- chain_mapping role taxonomy: RoleThreshold("T") retired -> RoleFHE("F")
+ RoleMPC("M"); RoleKMS unchanged. (Canonical native FChainID/MChainID
await a luxfi/ids change; the closed P/C/X/Q/A/B/T/Z/G/I/K/D set is
out of scope here. Active path pins EVM chainIds in the shards.)
Tests: chain_shards_test updated to 11 chains + new F/M chainIds; builder
emits 11 chains; new lp134_split_test asserts the decomplect invariants
(F is FHE-only, M is MPC-only, K is KMS-only, no alias collision across
{F,M,K}, tchain.json retired). go build/vet/test green (GOWORK=off).
github.com/luxfi/constants@v1.5.7 and github.com/luxfi/crypto@v1.19.15 had
their git tags re-cut upstream (same go.mod, new module-zip content), so the
pinned h1: content hashes no longer matched what GOPROXY=direct serves and
GOWORK=off builds failed the checksum gate. Refresh the two content hashes to
the current tag state (versions unchanged). Pre-existing environmental drift,
independent of the LP-134 split that follows.
The strictPQTimestamp networkUpgradeOverride drove the EVM strict-PQ
precompile-refusal gate, which is removed (luxfi/evm enable-everything:
the field no longer exists on extras.NetworkUpgrades, so it is silently
ignored). Drop it from every env's upgrade.json so the canonical config
matches the new policy — builder precompile surface enables everything;
Lux PQ security is at consensus, not by refusing EVM verifiers.
Network reboot, no backward compat: delete the AI-slop pqcrypto bundle + every
gate pinning it (pqcryptoConfig genesis activation, relaunch-safety test pin).
ML-KEM stays via standalone mlkem (0x012201). pqcryptoConfig removed from all
upgrade.json/yaml; 0x9003 retired, never reuse.
20 precompiles (p3qVerify, pulsar/magnetar/corona/hqc, curve25519/x25519/sr25519,
babyjubjub/pedersen/poseidon/pasta/xwing, computeMarket/bridgeRegistrar/stableSwap/
vrf/attestation/anchor/fixedPointMath) were forward-dated to 2026-07-01; realigned to
the canonical Dec-25-2025 activation (1766708400) that testnet already uses. All
networks now activate the full surface as of Dec 25 2025 — zero future-dated upgrades.
The mainnet/testnet C-Chain upgrade.json scheduled 17 already-live
precompiles (aiMiningConfig, blake3Config, cggmp21Verify, deadZeroConfig,
deadConfig, deadFullConfig, routerConfig, fheConfig, frostVerify,
graphConfig, hpkeConfig, mldsaVerify, mlkemConfig, pqcryptoConfig,
ringConfig, slhdsaVerify, zkConfig) at blockTimestamp 1766708400 — a
future (2025-12-26) timestamp. On the running mainnet these precompiles
are active at BLOCK 0 (the deployed luxd UPGRADE_JSON in luxfi/universe
k8s/lux-mainnet/luxd-startup.yaml has always carried them at 0).
Leaving the canonical genesis file at 1766708400 is a relaunch fork /
boot-refusal hazard: a relaunch from the canonical genesis would treat
each as INACTIVE before that timestamp and diverge from the canonical
chain where it is active at block 0 — or checkPrecompileCompatible would
refuse boot ("missing PrecompileUpgrade"). Pin all 17 to blockTimestamp 0
so IsForkTransition(0, nil, genesisTime) = (0 <= genesisTime) activates
them idempotently at block 0 on any relaunch, matching the deployed set.
warpConfig is unchanged in intent: it lives in the genesis chainConfig
(cchain.json config.warpConfig @ genesis time 1730446786,
requirePrimaryNetworkSigners=false). The upgrade schedule keeps its
genuine FUTURE strict-PQ toggle (disable@1766708399, re-enable@1766708400
with quorumNumerator=67, requirePrimaryNetworkSigners=true). The array is
reordered so all blockTimestamp:0 entries lead, preserving the
non-decreasing monotonicity rule in verifyPrecompileUpgrades. Every
non-zero timestamp is strictly greater than the genesis time, so a
relaunch re-fires no already-applied activation.
UPGRADE_NOTES.md documents the live-at-0 / strict-PQ-toggle / BLS /
Quasar-Edition tiers and the relaunch-safety contract.
node v1.30.27/28 dropped the 0x9010 DEX precompile; its config key
`dexConfig` is no longer registered, so any C-Chain upgrade/genesis
config carrying it is rejected at boot with "unknown precompile config:
dexConfig" -> C-Chain VM init fails. Remove the dead dexConfig entry from
every per-env upgrade.json and the devnet cchain.json. 0x9999 (live DEX
settlement) is config-free, so no key is added; routerConfig and all
other registered keys are preserved. Verified each file remains valid
JSON with dexConfig absent.
Files:
- configs/{mainnet,testnet,devnet,local,localnet}/upgrade.json
- configs/devnet/cchain.json
Replaces non-canonical scale-set / org-prefixed labels with the
existing labels every arcd host registers with. Matches evo for
amd64 and spark for arm64. No new labels added.
Picks up the 2026-06-06 relicensing:
- luxfi/vm v1.2.0 → Lux Ecosystem License v1.2 (was Lux Research v1.0).
License-only retag of the extracted runtime; patent reservation
preserved for runtime optimization surfaces, royalty-free for
Descending Chains.
- luxfi/sampler v1.1.0 → BSD-3-Clause (was Lux Research v1.0).
License restored to match the luxfi/node provenance (originally
extracted from node/utils/sampler).
- luxfi/staking v1.5.0 → BSD-3-Clause (was Lux Research v1.0).
License restored to match the luxfi/node provenance.
No code changes in this commit — go.mod/go.sum only.
Wave 2G-Archive completes the genesis-builder migration: the staging
shim builder/zap_codec.go (created during Wave 2G-Genesis to mirror
proto/zap_codec's surface before it was tagged) is now deleted, and
builder.go imports proto/zap_codec directly.
Changes:
- builder.go: pvmGenesisCodec / newXVMParserCodecs swap to
proto/zap_codec.NewPVMGenesis / NewXVMParser
- builder/zap_codec.go: deleted (staging shim no longer needed)
- go.mod: bump luxfi/proto v1.1.0 → v1.3.0 (first tag that exposes
proto/zap_codec; v1.3.0 also includes the proto/internal test
helper migration from Wave 2G-Internal)
luxfi/codec demoted to // indirect — kept transitively via deps that
haven't re-tagged yet. Will drop on the next upstream tagging cascade.
Migrates pvmGenesisCodec() and newXVMParserCodecs() off the legacy
linearcodec big-endian wire format onto the ZAP-native zapcodec
little-endian wire format. Aligned with LP-023 ZAP-native activation
(proto/zap_native: ZAPActivationUnix=0 — "ZAP mandatory from genesis"),
forward-only.
Wire-format verdict: BREAK.
ZAP-native bytes are NOT byte-equivalent to legacy linearcodec bytes —
endianness flips for every uint16/uint32/uint64/string-length prefix.
The canonical signature (PVM Genesis with Timestamp=0x0102030405060708,
InitialSupply=0x1112131415161718, Message="z"):
legacy linearcodec (BE): ... 01 02 03 04 05 06 07 08 11 12 13 14 15 16 17 18 ...
ZAP-native zapcodec (LE): ... 08 07 06 05 04 03 02 01 18 17 16 15 14 13 12 11 ...
No coordinated network upgrade needed: this is the first ZAP-native
genesis tag, and no production validator was running legacy linearcodec
in the post-LP-023 fleet. Mainnet/testnet/devnet/localnet all bootstrap
ZAP-only from genesis.
Code changes:
- builder.go:
Drop github.com/luxfi/codec + .../linearcodec direct imports.
Drop math.MaxInt32 inline construction.
pvmGenesisCodec() calls newZapCodecPVMGenesis(CodecVersion)
+ pchainblock.RegisterTypes(cm).
newXVMParserCodecs() calls newZapCodecXVMParser(CodecVersion).
Mirrors sdk/wallet/chain/p/pcodecs.NewPVMGenesisCodec and
sdk/wallet/chain/x/constants.go::newXVMParserCodecs which already
moved to proto/zap_codec in Wave 2G-Wallet.
- zap_codec.go (new):
Staging shim mirroring proto/zap_codec's public surface
(NewPVMGenesis, NewXVMParser, Manager.{Marshal,Unmarshal,Size,
RegisterType,SkipRegistrations}). When Wave 2G-Wallet lands and
tags github.com/luxfi/proto/zap_codec, this file deletes and the
two helpers in builder.go swap to that import — mechanical, no
behavioural change because both shim and target wrap the same
zapcodec.Codec backend.
- wire_test.go (new):
TestWire_PVMGenesisRoundtrip — bytes-out, parse-back, re-marshal stable
TestWire_PVMGenesisVersion — LE codec-version prefix
TestWire_PVMGenesisDeterministic — same Config → same bytes + UTXOAssetID
TestWire_XVMGenesisRoundtrip — XVM ParserCodecs construction smoke
TestWire_XVMGenesisDeterministic — UTXOAssetID stability across builds
TestWire_HexSignature_PVMGenesis — mainnet 32-byte prefix tripwire
TestWire_FormatBreak_Documented — pinned hex wire-format signature
- go.mod:
luxfi/codec v1.1.4 (indirect) → v1.1.5 (direct: zapcodec backend)
luxfi/accel v1.1.4 (indirect) → v1.1.8 (transitive)
Constraint-compliance:
- NO github.com/luxfi/codec imports in builder.go (verified by grep).
- NO snow/avalanche/subnet naming.
- All builder tests pass (go test ./...).
- All parent genesis + cmd modules build clean.
- Race detector clean.
TODO (wave-2g-wallet): once luxfi/proto tags include the zap_codec
subpackage, swap zap_codec.go's shim for the canonical
github.com/luxfi/proto/zap_codec import in builder.go and delete the
shim file.
proto/p Wave 2A (#101) rips github.com/luxfi/codec from p/genesis —
genesis.New, Genesis.Bytes and genesis.Parse now take a block.Codec
parameter at the call site (the same genesis-sized codec.Manager
already constructed inline elsewhere in the wallet stack).
Adds pvmGenesisCodec() helper mirroring the existing
newXVMParserCodecs() pattern in this file. Uses math.MaxInt32 budget
because PVM genesis blobs (full set of initial validator stake txs
plus CreateChainTx entries for X/C/D/Q/A/B/T/Z/G/K) can exceed runtime
tx-size limits. block.RegisterTypes seeds the full Apricot/Banff/
Durango/Quasar block + tx type set.
Threads pvmGenesisCodec() through:
- FromConfig: genesis.New + Genesis.Bytes (one codec, two uses)
- VMGenesis: genesis.Parse
- Aliases: genesis.Parse
Also fixes the X-chain genesis serialization path that was broken by
Wave 1A: xvmCodecs.GenesisCodec was used directly without going
through xchaintxs.NewParser, so the canonical XVM tx types
(BaseTx/CreateAsset/Operation/Import/Export) and fx-owned
secp256k1fx.TransferOutput were never registered. The xvm genesis now
flows through NewParser, mirroring how UTXOAssetID already uses it.
builder_test.go's TestFromConfig_ChainSetIsShardDriven gains a single
pvmGenesisCodec() construction and threads it through both pgenesis.Parse
call sites.
go build ./... + go test ./... green.
The proto pin remains at v1.1.0; the workspace go.work consumes the
local proto/ which is on branch chore/proto-p-codec-rip with the new
API. This commit goes live once proto v1.2.0 is tagged.
Re-fired CreateChainTx for hanzo/zoo/pars/spc/osage on clean P-state after
pars-testnet genesis fix (added quasarTimestamp:253399622400 to satisfy
fork-ordering check). All 5 testnet brand L1s now isBootstrapped=true.
Cross-check via api.lux-test.network/ext/bc/<brand>/rpc all returning
chainId successfully. eth_blockNumber=0x0 (BOOTSTRAP-ONLY mode — block 1
will roll on first txn).
Two related fixes, both validated live on do-sfo3-lux-k8s lux-testnet:
genesis.json:
Replaced the embedded cChainGenesis field with the canonical 2-alloc
A-form (matches standalone configs/testnet/cchain.json per 14b85b2).
Old: gasLimit 0x3b9aca00, warpConfig blockTimestamp:0, embedded
genesisHash + stateRoot annotations.
New: gasLimit 0xb71b00, warpConfig blockTimestamp:1730517266,
skipPostMergeFields:true. Empirically produces block 0 hash
0x1c5fe37764b8bc146dc88bc1c2e0259cd8369b07a06439bcfa1782b5d4fb0995 —
the canonical RLP-matching hash from lux-testnet-96368.rlp.
upgrade.json:
Dropped two entries that were breaking luxd boot:
- warpConfig {blockTimestamp:0, requirePrimaryNetworkSigners:true}
Fails luxd validation: "invalid precompile upgrades: PrecompileUpgrade
(warpConfig) at [0]: disable should be [true]". Warp is already
pre-allocated in the C-Chain genesis alloc at address 0x02..05
(code:0x01, nonce:1), so an explicit upgrade entry is redundant and
breaks block 0 identity if it touches state.
- feeManagerConfig at blockTimestamp:900000000 (Sep 1998!)
Fails luxd validation: "config block timestamp (900000000) <
previous timestamp (1766708400)". The list is required to be
monotonically non-decreasing; 900000000 placed mid-list between
strictPQ entries at 1766708400 broke that. Mainnet doesn't have
this entry; testnet inherited it as drift and it's never
activated cleanly. Drop and re-introduce later via a properly
ordered timestamp if/when fee admin is needed.
Live verification:
- all 5 lux-testnet pods boot to block 0 = 0x1c5fe377…
- RLP imports cleanly to h=218 (0xda)
- external eth_blockNumber at api.lux-test.network/ext/bc/C/rpc → 0xda