mirror of
https://github.com/luxfi/evm.git
synced 2026-09-24 00:27:44 +00:00
ROOT CAUSE of the C-Chain bootstrap ancestry-descent stall: ParseBlock was STATEFUL.
BlockGasCost is NOT in the RLP block — it is DERIVED from the parent header. UnmarshalBlock
computed it via vm.blockChain.GetHeaderByHash(parent), and SyntacticVerify REQUIRED it non-nil
(errNilBlockGasCostEVM). For a bootstrap descent parsing ancestry blocks AHEAD of the accepted
height the parent is not present, so every such block failed to parse — masked by the ZAP
errorToZAP mapping as the misleading "malformed block id (does not connect to accepted chain)".
The Lux bootstrapper indexes the whole fetched batch by (id,height,parent) up front, so it could
not index the ancestry, never found the frontier tip in the batch, and re-requested forever ->
ErrStalled. Confirmed on devnet: "syntactic block verification failed: nil blockGasCost is
invalid after EVM activation".
FIX — decomplect parse from verify (matches upstream avalanchego coreth: parse decodes, Verify
enforces connectivity):
- block.go: new ensureBlockGasCost() fills BlockGasCost from the parent header WHEN PRESENT
(SetHeaderExtra is hash-keyed, so it persists for a block first parsed while its parent was
absent). Best-effort at parse; authoritative at Verify (AcceptBootstrapBlock calls blk.Verify
only after the contiguity gate height==finalized+1, so the parent is ACCEPTED/present).
- block_verification.go: SyntacticVerify no longer requires BlockGasCost (stateless,
block-intrinsic checks only); keeps the uint64 sanity check when it IS set.
- vm.go UnmarshalBlock: replace the inline parent-lookup with block.ensureBlockGasCost().
SAFETY (parse != accept): parse only decodes + stateless syntactic checks; no non-connecting or
gas-cost-invalid block can be ACCEPTED just because it now parses. Verify/Accept
(InsertBlockManual -> consensus/dummy header verification) recomputes the expected BlockGasCost
from the (present) parent and rejects a mismatch; the bootstrap contiguity gate accepts blocks
oldest-first (parent finalized). A wrong-hash block is rejected off-path by the content-addressed
descent. BlockGasCost is not in the block hash -> no malleability.
evm plugin/evm tests pass.
Co-authored-by: Hanzo Dev <[email protected]>