Commit Graph
565 Commits
Author SHA1 Message Date
zeekay 34cb5c1684 txs package GREEN: pure zap struct-is-wire compiles (Convert + CreateSovereign done)
All 21 real P-chain tx types are now the zap buffer — no codec, no marshal/
unmarshal, no Manager, no version, decompounded, on luxfi/zap. ConvertNetworkToL1Tx
+ CreateSovereignL1Tx hand-written with a shared ConvertNetworkToL1Validator
nested encoder (fixed-stride records + shared NodeID/addr pools) and a
SovereignL1Chain encoder. go build ./vms/platformvm/txs/ = exit 0.

Next: round-trip correctness test, then the external consumer flip.
2026-07-10 10:53:14 -07:00
zeekay e288b67008 Decomplect P-chain tx set: rip Slash + P-chain CreateAsset/Operation, restore staker ifaces
- SlashValidatorTx ripped (unwired stub; Avalanche has no slashing; consensus
  only detects, never enforces). Type+executor+tests+Visitor surface removed.
- CreateAssetTx + OperationTx ripped from P-CHAIN (X-chain/AVM types; LP-0130:
  asset creation + fx ops are X-chain money-rail, not P staking-rail; no P
  producer). xvm/avm untouched.
- Staker interfaces (StakerTx/ValidatorTx/DelegatorTx/ScheduledStaker) restored
  on the 5 validator types via pure accessors + FxID-on-stake preserved.
- Remaining real complex types: ConvertNetworkToL1Tx + CreateSovereignL1Tx.
2026-07-10 10:36:35 -07:00
zeekay 33e005c869 fix register_l1 verifyBaseTx (return-form) 2026-07-10 09:18:19 -07:00
zeekay 949210730d Pure zap tx: 18 type files converted (parallel) + verifyBaseTx reconciled
Batches 1-3 (proposal + spending + validator-family) landed pure: struct is
the buffer, New*Tx builds, accessors read, SyntacticVerify via verifyBaseTx.
Remaining package-internal: 5 complex types (Convert/CreateSovereign/CreateAsset/
Operation/Slash) + staker interface methods + consumer flip.
2026-07-10 09:17:15 -07:00
zeekay 8d2fb750b6 Remove stale codec tests (codec deleted) 2026-07-10 09:08:31 -07:00
zeekay 1bc07cb1ca Pure zap tx: pure Tx (Parse=wrap+split, Sign=build) + delete reflection codec
tx.go: Tx holds Unsigned (zap-backed) + Creds; Parse wraps signed bytes and
splits unsigned/creds at the self-delimiting boundary; Sign builds unsigned‖creds;
no codec.Manager param anywhere. Deleted codec.go (V0/V1/V2 reflection Manager)
and codec_activation.go. WIP: consumer sites that passed txs.Codec / called the
old Parse(codec, bytes) flip next.
2026-07-10 09:08:15 -07:00
zeekay 1dede2e3d2 Pure zap tx: Parse kind-dispatch + native credential wire (no codec)
Parse wraps the buffer zero-copy and dispatches on the 1-byte kind. Signed =
unsigned ‖ creds (both self-delimiting), so unsigned is a byte-prefix of
signed. writeCredsBuf/parseCredsBuf encode credentials natively (shared 65B
sig-blob array). No Marshal/Unmarshal/Manager. WIP: references the 24 pure
type constructors (5 hand-written + 18 in parallel conversion + 1 template).
2026-07-10 09:07:13 -07:00
zeekay 636944a63a Pure zap tx: spendingTx embedded base (envelope surface for all types) 2026-07-10 09:02:58 -07:00
zeekay 7750ca1829 gofmt spending.go 2026-07-10 01:43:56 -07:00
zeekayandHanzo Dev c526c0aaa4 Pure zap tx: reusable delta encoders (owner/auth/validator/signer/idlist)
Shared delta-field encoders every non-proposal tx composes on the spending
envelope: owner (fx.Owner), auth (*secp256k1fx.Input), inline Validator (44B)
+ Signer (145B: kind+BLS pubkey+PoP), id lists, extra spending lists. Built on
luxfi/zap. With spending.go, the full reusable foundation — type files are now
pure compositions.

Co-authored-by: Hanzo Dev <dev@hanzo.ai>
2026-07-10 01:42:43 -07:00
zeekayandHanzo Dev 7354ce84b9 Pure zap tx: shared spending wire (envelope + Output/Input/owner/creds)
The envelope (NetworkID/BlockchainID/Outs/Ins/Memo) + multisig/stakeable
Output/Input entries + shared owner-address/sig-index arrays, built on
luxfi/zap generic primitives — no codec, no zap_native package. writeSpending/
setEnvelope build inside New*Tx; readEnvelope reads lazily. Polymorphism
(TransferOutput/LockOut, TransferInput/LockIn) handled in explode/assemble.
Foundation every non-proposal tx composes.

Co-authored-by: Hanzo Dev <dev@hanzo.ai>
2026-07-10 01:40:27 -07:00
zeekayandHanzo Dev 8e7253a3c5 Pure zap tx: kind dispatch + AdvanceTimeTx template (struct IS the wire)
kind.go: 1-byte discriminator @ object offset 0 = the whole dispatch. No
codec, no version, no slot map. AdvanceTimeTx converted to the pure model:
holds *zap.Message, Time() is an offset read, NewAdvanceTimeTx builds once,
Bytes() returns the buffer. No marshal/unmarshal anywhere.

Template for the remaining 21 types. Package migrates atomically (codec.go +
all types + Parse/Sign together), so it compiles green again only when the
whole set + concentrated consumers (executor/builder/fee/api, ~63 New sites)
are converted. WIP.

Co-authored-by: Hanzo Dev <dev@hanzo.ai>
2026-07-10 01:24:10 -07:00
zeekayandHanzo Dev 67ec31a344 Rip the marshal/unmarshal bridge — it was a codec by another name
ZAP has no serialization step. The bridge copied fields between plain txs.*
structs and the buffer, which is exactly the codec ZAP deletes. Removed.
The right way: tx type IS the zap buffer (accessors, Parse=wrap, Bytes=buffer),
no codec / manager / compat / version. Wire primitives stay in luxfi/zap.

Co-authored-by: Hanzo Dev <dev@hanzo.ai>
2026-07-10 01:13:02 -07:00
zeekayandHanzo Dev 77389092c2 LP-023: bridge 5 more tx types (extra-list/bytes/idlist deltas)
Shared extra-out/in list helpers (Import/Export second spending set), id-list
+ BLS-PoP encoders. Bridges TransferChainOwnership, RegisterL1Validator,
Import, Export, CreateChain. Round-trip green (13/22 P-tx types native).

Co-authored-by: Hanzo Dev <dev@hanzo.ai>
2026-07-10 01:03:37 -07:00
zeekayandHanzo Dev 13cca30a71 LP-023: bridge 5 delta tx types (owner/auth/scalar deltas)
Shared delta-encoders (owner=fx.Owner->OutputOwners, auth=verify.Verifiable->
secp256k1fx.Input, fixed-id helpers). Bridges IncreaseL1ValidatorBalance,
SetL1ValidatorWeight, DisableL1Validator, RemoveChainValidator, CreateNetwork
= spending envelope + fixed-offset delta fields. Round-trip green (8/22 P-tx
types now native: proposal x2 + BaseTx + these 5).

Co-authored-by: Hanzo Dev <dev@hanzo.ai>
2026-07-10 01:00:42 -07:00
zeekayandHanzo Dev ae3e3a45f5 LP-023: native spending envelope + full component converters
Shared spending envelope (NetworkID/BlockchainID/Outs/Ins/Memo) + polymorphic
converters bridging the txs struct graph to proto/zap_native primitives with
zero reflection: TransferOutput/stakeable.LockOut, TransferInput/stakeable.LockIn,
secp256k1fx.Credential. BaseTx (TxKindBaseFull) bridged; creds travel in the
separate creds buffer of the unsigned‖creds envelope.

Round-trip GREEN: 2-of-3 multisig + owner-locktime output, stakeable.LockOut,
stakeable.LockIn input, memo, AND signed secp256k1 credentials all survive
Marshal->Unmarshal with exact field equality; unsigned stays a byte-prefix of
signed. Every embedding tx type now composes this envelope + its delta fields.

Co-authored-by: Hanzo Dev <dev@hanzo.ai>
2026-07-09 21:39:14 -07:00
zeekayandHanzo Dev be18fce176 LP-023 keystone: native-ZAP tx Manager (drop-in, zero reflection)
Adds nativeManager implementing pcodecs.Manager by bridging txs structs to
proto/zap_native buffers — no reflection, no serialize-tag walk, no version
dispatch. Signed wire = unsigned_zap_buffer ‖ creds_zap_buffer (ZAP buffers
are self-delimiting), preserving tx.go's unsigned-is-prefix-of-signed
invariant with no tx.go change. AdvanceTimeTx + RewardValidatorTx bridged
and round-trip green (build->Marshal->Unmarshal field equality, byte-stable,
prefix invariant, non-ZAP reject). Added alongside the reflection Codec;
flip + reflection deletion lands once all registered types are bridged.

Co-authored-by: Hanzo Dev <dev@hanzo.ai>
2026-07-09 16:53:16 -07:00
zeekayandHanzo Dev 74be89840c v1.34.28: consensus v1.35.36 -> v1.35.37 (F1 stale-alias prevote-lock rebase)
Third-layer mainnet finality fix. v1.34.27 (consensus v1.35.36) proved the
dynamic committee (alpha=4 n=5) and topology.go cert-receive canonical resolve
work live — consensus climbed past 1085755 to round-height 1085761 — but hit the
next layer: a stale-alias prevote-lock. viewForLocked seeds lockBlock from a
pre-canonical-fix durable committedSlot (an OUTER proposervm-wrapper id); a
round-0 lock on an outer alias makes prevoteTarget compare the stale outer id
against the inner-canonical winner by raw id, mismatch forever, no POL, freeze.

v1.35.37 (742696baf): stepViewChange rebases a stale-alias lock onto the inner
canonical winner IFF it resolves (via the same vmCanonicalResolver the cert
rebase uses) to exactly winnerCanon — a genuinely different inner (real fork) or
unresolvable lock is left fail-closed frozen, never merged. lockRound preserved,
2a-n>f untouched, alpha inner-precommits were always inner (CanonicalVoteMessage
binds inner, excludes outer). Full engine/chain green (356s, 0 fail); -race
clean; RED safety gate proves divergent inners still refused.

Roll note: luxd-4 first releases its lock (log 'vc stale-alias lock REBASED');
finality past 1085755 needs >=4 nodes on this build, so height climbs as 3->2->
1->0 come up. EVM stays v1.104.7 (head-pin).

Co-authored-by: Hanzo Dev <dev@hanzo.ai>
2026-07-09 12:05:51 -07:00
zeekayandHanzo Dev 9a0800065f v1.34.27: consensus v1.35.33 -> v1.35.36 (EVM-accept unstick + dynamic committee + snowman purge)
Unsticks mainnet C-Chain finality. Root cause (consensus-layer, proven): under
pChainHeight=0 anyone-can-propose, each validator wraps the same inner block in
its own outer proposervm envelope; votes are canonical-keyed so an α-of-K cert
forms network-wide, but HandleIncomingCert did a strict envelope-id lookup — a
node holding a different alias of the same inner block missed it and requested
catchup instead of finalizing the local wrapper it held, so VM.Accept was never
called and the EVM head froze at 1085755 while consensus logged 'finalized
voters=4'. v1.35.34 (66438a23b) resolves the local wrapper by canonical id and
rebases the verified cert (outer ids unsigned; α votes verify unchanged), no
fork (per-height gate keys on canonical id, idempotent).

Also: dynamic committee 1→N proven (v1.35.35, effectiveCommittee sizes cert +
view-change from live validator count; n=1→1/1,2→2/2,3→3/3,4→3/4,5→4/5 — the
BFT-safe ⌊2n/3⌋+1); view-change safety gate realigned to the effective
committee (RED#2); snowman comment-purge (Quasar/Nova); dynamic committee logs.
Node commits: 4e71814e58 (proposervm→EVM Accept-cascade test, RED#1),
c13681108f (purge), a02611413e (logs). EVM stays v1.104.7 (head-pin). Full
engine/chain suite green under -race (369s, 0 fail/0 race); RED adversarial
suite proves scale-invariance 1→1M + RLP seam byte-exact on real mainnet state.

Co-authored-by: Hanzo Dev <dev@hanzo.ai>
2026-07-09 11:11:58 -07:00
zeekayandHanzo Dev 4e71814e58 vms/proposervm: prove proposervm-finalize → inner-EVM Accept propagation (RED #1, choke #4)
The mainnet 1085755 freeze had consensus finalizing an outer proposervm block while the
inner EVM lastAccepted stayed frozen. The consensus engine's ledger advancing on VM.Accept
is proven in engine/chain; this proves the OTHER half at the NODE layer — that VM.Accept on
a proposervm wrapper cascades to the inner block's Accept:

  postForkBlock.Accept → acceptOuterBlk → acceptInnerBlk → Tree.Accept(innerBlk) →
  innerBlk.Accept  ⇒ inner VM lastAccepted advances

- TestAcceptCascade_InnerHeadAdvances_AtScale: 1000 heights through the REAL Accept path;
  the inner EVM head + proposervm head advance in lock-step at every height.
- TestAcceptCascade_SiblingStorm_WinnerAdvancesInnerOnce: five distinct outer envelopes wrap
  ONE inner block (the anyone-can-propose alias set); accepting the finalized wrapper advances
  the shared inner exactly once.

Confirms the propagation was sound, not a node-layer bug — the freeze was the consensus-layer
storm-alias resolution gap (fixed in consensus v1.35.34). The real luxfi/evm RLP-import→produce
→tip byte-exactness is proven separately in evm/core rlp_seam_red_test.go; composed, they cover
the full engine→proposervm→EVM Accept path.

Co-authored-by: Hanzo Dev <dev@hanzo.ai>
2026-07-09 10:57:31 -07:00
zeekayandHanzo Dev c13681108f node: purge 'snowman' comment references — Quasar/Nova terminology (comment-only, no behavior change)
Removes the forbidden Avalanche term from code comments in chains/manager.go,
chains/quorum.go, and vms/proposervm/proposer/windower_determinism_test.go. Reworded to
preserve exact meaning; comments only, no identifier/behavior change.

Co-authored-by: Hanzo Dev <dev@hanzo.ai>
2026-07-09 10:50:27 -07:00
zeekayandHanzo Dev a02611413e chains: view-change ENABLED log prints the PRESET, not the committee (#5 dynamic logs)
The "round-scoped view-change ENABLED for chain K=21 alpha=15" line read as if K=21/α=15
were the finality committee — misleading. It is the Snowman SAMPLE preset. The α-of-K
cert and the view-change POL/precommit are sized to the LIVE validator set at runtime
(effectiveCommittee/bftCommittee; 5 validators → K=5/α=4), and the engine already logs
the effective (K,α) on each committee re-clamp. Relabel the fields presetK/presetAlpha
and add a note pointing at the runtime committee-clamp log. Log-only; no behavior change.

Co-authored-by: Hanzo Dev <dev@hanzo.ai>
2026-07-09 10:30:30 -07:00
zeekayandHanzo Dev 7720d00baa v1.34.26: consensus v1.35.29 -> v1.35.33 (finality committee sizing) + quorum ValidatorCount
Restores mainnet C-Chain finality. The prior stall: with 5 live validators but
MainnetParams K=21/alpha=15, BOTH finality gates (assembleCertLocked cert-alpha
AND view-change POL) required 15 distinct votes — impossible from 5 validators,
so the chain froze (safe, no fork). consensus v1.35.33 sizes both gates from the
live validator count via effectiveCommittee (alpha=4 for n=5), inheriting the
minBFTCommittee K=4/alpha=3 floor (1085013 self-finality guard preserved);
Snowman K=21 sample untouched. node chains/quorum.go adds
validatorStakeSource.ValidatorCount (height-indexed, deterministic). EVM stays
v1.104.7 (head-state pin). Test: 5-validator MainnetParams control freezes,
fix converges in 0.35s.

Co-authored-by: Hanzo Dev <dev@hanzo.ai>
2026-07-09 08:59:42 -07:00
zeekayandHanzo Dev 439f2768e0 docs/postmortem: mark residual #1 (proposer-preference restart loop) FIXED
BuildBlock last-accepted fallback landed in 2dc15620e4 (ships v1.34.26).

Co-authored-by: Hanzo Dev <dev@hanzo.ai>
2026-07-08 23:27:42 -07:00
zeekayandHanzo Dev 2dc15620e4 vms/proposervm: BuildBlock falls back to last-accepted on unheld preferred
Closes postmortem residual #1 (proposer-preference restart loop / mute-voter
wedge). Build-side companion to the defect #1 SetPreference validate-before-
assign hardening.

vm.preferred is only adopted after a successful getBlock, but a block fetchable
at preference time can later become unfetchable: an unaccepted sibling consensus
dropped, or a never-persisted outer block referenced after heavy sibling churn.
The old BuildBlock returned after the single getBlock(preferred) miss with
"failed to fetch preferred block", so every attempt failed in a tight loop and
the node's voter went mute (~170 err/s). Quasar cert-finality has no re-converge
poll, so the fleet never recovered on its own — the liveness wedge behind the
mainnet 1082879->1085755 window (heartbeat-pause + full-fleet-restart churn).

Fix: on an unfetchable preferred, build the child on last-accepted (always held:
committed state). The node keeps producing on a valid tip while the catch-up
path pulls the gap; a later SetPreference(held tip) re-advances the preference.
Only surface the original error when last-accepted is itself the unfetchable id.

Tests (hermetic, mirror vm_rejoin_wedge_test.go): spy inner VM asserts the fetch
sequence — BuildBlock consults last-accepted on an unheld preferred (old code
never did), and does not spuriously fetch when no distinct fallback exists.

Co-authored-by: Hanzo Dev <dev@hanzo.ai>
2026-07-08 23:20:41 -07:00
zeekayandHanzo Dev 2bbe067f60 docs: postmortem — C-Chain accepted-head state GC eviction (mainnet freeze)
Failure mode, preconditions (pruning + state-history 32 + commit-interval 4096
+ idle), affected (evm ≤v1.104.6 / node v1.34.14-23) and fixed versions (evm
v1.104.7 / node v1.34.25), the head-state-pin invariant, the recovery recipe
(restart-as-recovery, healthy-peer PVC restore at replicas=0, repair-cchain
rewind), and the two residual restart-liveness follow-ups.

Co-authored-by: Hanzo Dev <dev@hanzo.ai>
2026-07-08 06:10:11 -07:00
zeekayandHanzo Dev ae15850e1a v1.34.25: proper semver — EVM pin v1.104.7 (head-state-pin fix), drop stale replace-cascade comment
Same content as v1.34.24 (v1.104.3-headpin == v1.104.7, retagged per semver
policy: real monotonic patch versions, no suffix tags). go.mod has no replace
directives; removes the leftover comment from an already-completed cascade.

Co-authored-by: Hanzo Dev <dev@hanzo.ai>
2026-07-07 21:39:48 -07:00
zeekayandHanzo Dev 092ed0459e v1.34.24: EVM v1.104.3-hotfix -> v1.104.3-headpin (durable idle-freeze fix)
Pins luxfi/evm v1.104.3-headpin: dedicated unbalanced GC pin on the accepted
head state root (transferred head-to-head in Accept + startup + direct
setters) so the head can never be evicted by the tipBuffer/Cap while idle —
the durable fix for the 1085200 'missing trie node at head' freeze. Also
carries vm v1.2.6 parity. Base: v1.34.22 (mainnet matcher lineage), no other
changes.

Co-authored-by: Hanzo Dev <dev@hanzo.ai>
2026-07-07 20:33:36 -07:00
zeekayandHanzo Dev aa884628a0 v1.34.22: consensus v1.35.28 -> v1.35.29 (complete fix: self-finality safety + canonical cert aggregation + clone-resign inner->outer)
The COMPLETE mainnet reliability build. v1.35.29 adds FIX #1 (self-finality floor — a
transient bftCommittee count can never self-finalize without quorum; the 1085016 accept-
without-quorum safety hole) + FIX #3 (canonical vote aggregation — sibling wrappers of the
same inner block combine into ONE cert; the block-288 wrapper-split cert-termination stall)
+ the v4 clone-resign inner->outer fix (my v1.35.28 re-sign silently no-op'd on real wrapped
blocks). Matcher EVM v1.104.3-hotfix + Bug B UNCHANGED — execution-identical to mainnet.

Co-authored-by: Hanzo Dev <dev@hanzo.ai>
2026-07-07 12:33:23 -07:00
zeekayandHanzo Dev 3d65b1c0c2 v1.34.22: MAINNET FINAL — matcher+Reference EVM (v1.104.3-hotfix) + consensus v1.35.28
Bundles BOTH reliability fixes on the mainnet-compatible line (the live test proved they
COMPOUND — Bug A catch-up alone can't reconcile the tip-loss Bug B causes on restart):
- Bug A (consensus v1.35.28, merged to consensus main): catch-up #1/#2/#3/#5 + vote-guard clone re-sign.
- Bug B (EVM v1.104.3-hotfix): head-state Reference one-liner — EXECUTION-IDENTICAL to mainnet
  (golden roots identical RED vs GREEN), matcher EVM (precompile v0.19.0), NO settle-only.
go.mod delta vs mainnet v1.34.14 = consensus-only; EVM = matcher+Reference (the only exec delta is
the proven-identical GC pin). STAGED for mainnet recovery — NOT rolled (gated on RED + canary).

Co-authored-by: Hanzo Dev <dev@hanzo.ai>
2026-07-07 11:00:24 -07:00
zeekayandHanzo Dev a8971630b5 v1.34.21: bump consensus v1.35.24 -> v1.35.28 (#2 steer-guard + vote-guard clone fix)
MAINNET-COMPATIBLE node-only patch: the v1.34.14 line + catch-up/preference fixes + vote-
guard, EVM PLUGIN UNCHANGED (EVM_VERSION=v1.104.3, precompile v0.19.0, chains v1.7.2, vm
v1.2.5 — byte-identical to mainnet; NO settle-only, NO state-transition change). go.mod delta
vs v1.34.14 = consensus ONLY. Consensus v1.35.28 touches vote/cert LIVENESS only (engine is
byte-identical across the lines); it carries #2 (GetBlock-guarded build-tip steer) + the
vote-guard clone-artifact re-sign fallback. Cherry-picked #1/#3/#5 (proposervm validate-
before-assign, EmptyNodeID->real peers, have-block!=not-behind cert-fetch) on the prior commit.

Co-authored-by: Hanzo Dev <dev@hanzo.ai>
2026-07-05 20:02:08 -07:00
zeekayandHanzo Dev 09ab817ee5 node: cure the lagging-validator rejoin wedge (proposervm #1 + peer-select #3)
The recurring freeze: a validator that fell behind could never rejoin, spamming
"sentTo=0" and "failed to fetch preferred block" until bounced. Two node-layer
defects, both BFT-safe (compared against ava avalanchego proposervm):

#1 proposervm.SetPreference (vms/proposervm/vm.go): assigned vm.preferred BEFORE
   fetching, so a build-tip the node doesn't hold POISONED vm.preferred forever
   (BuildBlock errors on every attempt; Quasar cert-finality has no re-converge
   poll). Now: getBlock (both post-fork + inner stores) FIRST, delegate to inner,
   adopt the preference only on success; on a total miss keep the last held tip
   and stay live. Identical to ava in every case its single-store invariant
   produces; only adds recovery for Lux's build-tip steering (never bricks).
   SetPreference is not an acceptance gate, so safety/agreement is untouched.

#3 peer selection (chains/manager.go): consensus signals "fetch a certified-but-
   untracked block" via ids.EmptyNodeID; the old code Add(EmptyNodeID)+Send, so
   GetAncestors went to ZERO peers and the cert-verified gap was never fetched.
   Now: when nodeID is Empty, sample real connected peers that track this chain's
   network (same selection pollFrontierOnce uses); the cert already gated the ask.

Adds vm_rejoin_wedge_test.go. (Defect #2 — the engine build-tip steering in
consensus/engine/chain — is the upstream root cause, tracked separately.)

Co-authored-by: Hanzo Dev <dev@hanzo.ai>
2026-07-05 19:57:53 -07:00
zeekayandHanzo Dev 98911842db docker: guard all mandatory chain-VM plugins, not just bridgevm
The chain-VM plugins are built with '|| echo WARN' (optional) but hard-COPY'd in
the runtime stage (a build miss -> cryptic COPY failure). Replace the single
bridgevm test-s check with a guard over every mandatory plugin so a missing/empty
binary fails loudly at the build stage with the real cause.

Co-authored-by: Hanzo Dev <dev@hanzo.ai>
2026-07-03 21:26:08 -07:00
zeekayandHanzo Dev 0f185bd813 proposervm: implement canonicalCommitter — inner id is the finality canonical (Part A of 1082879 unfreeze)
The consensus engine's finality object is VotePosition.CanonicalID (the signed
accept vote binds it and EXCLUDES the outer envelope id). It reads it via a
structural canonicalCommitter assertion (engine/chain canonicalIDOf); until now
NO block type implemented it, so canonicalIDOf fell back to the OUTER proposervm
envelope id. On the stuck C-Chain the designated proposer re-wraps the SAME inner
block each slot -> 758 distinct outer ids over ONE inner block 25Q837Lw -> 758
distinct canonicals -> votes scatter -> no alpha-of-K cert -> frozen at 1082879.

postForkCommonComponents now returns the inner block's id as CanonicalID and the
inner parent's id as ParentCanonicalID, so every outer wrapper of one inner block
(and a forked parent) collapses to ONE consensus object. Enables the consensus
v1.35.23/24 canonical-representative determinism fix to actually engage; neither
part alone unfreezes mainnet.

Co-authored-by: Hanzo Dev <dev@hanzo.ai>
2026-07-03 21:26:08 -07:00
zeekayandHanzo Dev a2f5c6c37b build: node canary v1.34.13 — consensus v1.35.24 (fix BLS double-register panic)
v1.34.12 crash-looped on boot:
  panic: threshold: scheme BLS already registered

consensus <= v1.35.22 blank-imported the OLD crypto/threshold/bls in
quasar.go while node imports the NEW threshold/scheme/bls; both register
BLS into the crypto/threshold registry -> panic. consensus v1.35.24
repoints quasar.go to threshold/scheme/bls.

Verified on the FULL node binary dep closure (go list -deps ./main, 1028
pkgs): luxfi/crypto/threshold/bls = 0, luxfi/threshold/scheme/bls = 1 —
exactly one BLS registration path, the panic cannot recur.

Pins: consensus v1.35.24, chains v1.7.2, evm v1.104.3.

Co-authored-by: Hanzo Dev <dev@hanzo.ai>
2026-07-03 21:14:17 -07:00
zeekayandHanzo Dev b3e92ce979 build: node canary v1.34.12 — chains v1.7.2 (pulsar-path fix) + consensus v1.35.22
Supersedes the v1.34.11 image build, which failed in the Docker plugin
stage: chains v1.7.1 pulled consensus v1.25.35, whose polaris.go imports
the removed pulsar/ref/go/pkg/pulsar path — the quantumvm + mpcvm plugins
could not build and their hard COPY failed.

- chains v1.7.1 -> v1.7.2 (consensus bumped to v1.35.22 there; consistent
  pulsar graph; all 10 chain VM plugins verified building standalone).
- Dockerfile CHAINS_REF v1.7.1 -> v1.7.2.
- consensus v1.35.21 -> v1.35.22 (Pike-clean of the ProposalKey liveness
  fix; logic identical to v1.35.21).

Pins: consensus v1.35.22, chains v1.7.2, evm v1.104.3. Off origin/main,
no WIP.

Co-authored-by: Hanzo Dev <dev@hanzo.ai>
2026-07-03 20:50:05 -07:00
zeekayandHanzo Dev 0428445890 build: node canary v1.34.11 — buildable image with decomplected consensus
IMAGE/BUILD change (packaging only — the consensus behavior change ships
separately as luxfi/consensus v1.35.21). Two edits make the deployable
node image build with the fixed consensus and the current chain plugins:

- consensus pin v1.35.20 -> v1.35.21 (ProposalKey decomplection, commit
  776a5119c: outer block IDs are transport aliases, proposal identity is
  ProposalKey{ParentID,Height} — proposervm envelope churn can no longer
  spawn own sibling candidates that split votes; the mainnet 1082880 fix).
- Dockerfile ARG CHAINS_REF v1.7.0 -> v1.7.1. v1.7.0 still shipped the
  pre-rename `thresholdvm` dir, so the Dockerfile's `cd /tmp/chains/mpcvm`
  plugin build produced nothing (swallowed by `|| echo WARN`) and the hard
  COPY of the mpcvm plugin (tGVBwRxp...) failed — the v1.34.10 Docker build
  break. v1.7.1 carries the mpcvm rename; the mpcvm plugin builds clean
  (verified standalone, 16MB) and all 10 chain plugins are present.

Pins verified for the canary image: consensus v1.35.21 (=776a5119c),
chains v1.7.1, evm v1.104.3, cevm v0.19.0, dex v1.5.15. Built off
origin/main — no WIP from any other worktree.

Co-authored-by: Hanzo Dev <dev@hanzo.ai>
2026-07-03 19:38:25 -07:00
zeekayandHanzo Dev 86a342ae7b deps: bump to released graph — ids v1.3.1, constants v1.6.1, genesis v1.16.1, chains v1.7.1, consensus v1.35.20, threshold v1.12.1
Pins node to the published tags carrying this session's LP-0130 work:
ids/constants add M/F chain identifiers (drop T-Chain), genesis adds
M/FChainGenesis, chains has the mpcvm rename, consensus has the
mempool-churn pre-build gate + threshold scheme/bls repoint.

Co-authored-by: Hanzo Dev <dev@hanzo.ai>
2026-07-03 19:08:20 -07:00
zeekay 52fd2cef35 Merge branch 'feat/thresholdvm-decomplect' into integrate/node-release-plus-mpcvm 2026-07-03 16:20:21 -07:00
zeekayandHanzo Dev 89bb0e718c build: pin EVM_VERSION v1.104.1 -> v1.104.3 (ZAP VM-state serialization fix)
v1.34.9 = v1.34.8 + the C-Chain EVM plugin rebuilt from evm v1.104.3
(= evm v1.104.1 + luxfi/vm v1.2.6). The only change is the plugin's
ZAP RPC server now serializes VM state calls, fixing the concurrent-map
crash (chain.State.verifiedBlocks) that killed the EVM subprocess under a
concurrent ParseBlock storm and froze Lux mainnet C-Chain at block 1082879.
Node binary, consensus, genesis, and all other plugins are unchanged;
block output is byte-identical, so v1.34.9 is consensus-compatible with the
running v1.34.8 fleet (verified on devnet/testnet before the mainnet roll).

Co-authored-by: Hanzo Dev <dev@hanzo.ai>
2026-07-03 15:15:10 -07:00
zeekayandHanzo Dev 6c6b256418 deps: repoint BLS threshold scheme registration to luxfi/threshold/scheme/bls
The BLS Scheme impl moved from crypto/threshold/bls to
luxfi/threshold/scheme/bls (all threshold impls now live in one module;
the interface stays in crypto/threshold). One-line blank-import path
change; no behavior change.

Co-authored-by: Hanzo Dev <dev@hanzo.ai>
2026-07-03 14:14:39 -07:00
zeekayandHanzo Dev c7e0eef6f6 vms/types/fee: quantumvm moved to NoUserTxPolicy (LP-0130 §6)
Doc-comment + LLM.md updated to reflect chains/quantumvm feegate flip.

Co-authored-by: Hanzo Dev <dev@hanzo.ai>
2026-07-03 12:32:41 -07:00
zeekayandHanzo Dev b4720c9f57 node v1.34.8: consensus v1.35.16 -> v1.35.17 (VC liveness) + proposervm slot-snap
Pairs the proposervm stale-parent slot-snap churn-fix (f840336167) with consensus
v1.35.17 (view-change abandonment must never silence a height). Together they close the
distributed VC liveness stall that keeps mainnet C-Chain safe-but-paused: slot-snap kills
the stale-parent rebuild sibling explosion at the source (one stable candidate per slot),
and v1.35.17 keeps the round machinery driving the height to convergence instead of going
silent after rePoll's 8-attempt cap. Liveness-only; decided-floor / no-double-finalize
safety invariant untouched. Gated on the live idle-inclusive devnet re-storm + RED before
any testnet/mainnet roll.

Co-authored-by: Hanzo Dev <dev@hanzo.ai>
2026-07-03 11:57:47 -07:00
zeekayandHanzo Dev f840336167 fix(proposervm): slot-snap child timestamp — kill stale-parent rebuild churn (VC liveness)
Off a stale parent (idle past the proposer window → anyone-can-propose), buildChild
was stamping a raw wall-clock timestamp (Time().Truncate(1s)), so every rebuild of the
same inner block produced a DISTINCT envelope id. That is an unbounded, ever-growing
sibling set at one height: the round-scoped view-change can never gather α aligned
prevotes on a single candidate (no proof-of-lock forms) and finality stalls fleet-wide
(the distributed liveness stall).

Snap the child timestamp DOWN to the parent-anchored proposer-window grid
(parentTimestamp + slot*WindowDuration, slot = TimeToSlot(parent, now)) so all rebuilds
WITHIN one slot are byte-identical → one stable candidate the view-change converges on.

Safe by construction: TimeToSlot(parent, snapped) == slot == TimeToSlot(parent, now), so
the block's slot — hence ExpectedProposer's proposer-window / signed-unsigned verdict and
the derived epoch — is unchanged. Only slot>0 snapped, so a fresh in-window child keeps
its exact timestamp (zero live-chain change), and a snapped time is strictly > parent
(monotonic) and <= now (not advanced). Liveness-only; no safety surface touched.

Extracted as slotSnappedChildTimestamp + unit-proven (idempotence, slot-invariance,
monotonicity). Full proposervm suite green.

Co-authored-by: Hanzo Dev <dev@hanzo.ai>
2026-07-03 10:52:51 -07:00
zeekayandHanzo Dev d4323da799 node: rename thresholdvm → mpcvm; split M/F registries (LP-0130)
- vms/thresholdvm/ → vms/mpcvm/ (dir + inner files + package decl).
- node/vms.go optional-VM registry: drop ThresholdVMID row, add
  MPCVMID and FHEVMID rows (matching the new split).
- genesis/builder/registry.go: T-Chain entry → M-Chain (MPCVMID) +
  F-Chain (FHEVMID); registry_test.go parity assertions updated.
- genesis/builder/builder.go: TChainAliases → MChainAliases +
  FChainAliases; ThresholdVMID switch case split to MPCVMID / FHEVMID;
  optIn chain slice uses config.MChainGenesis + config.FChainGenesis
  (T-Chain slot retired).
- LLM.md: point at LP-0130 as canonical topology + fee spec; correct
  the quantumvm posture to service-only per LP-0130 §6 (Q-Chain has
  no user-payable blockspace).

Build + vet clean on chains/mpcvm/... + node/{vms/mpcvm,genesis,node}/...

Co-authored-by: Hanzo Dev <dev@hanzo.ai>
2026-07-03 01:23:03 -07:00
zeekayandHanzo Dev 97d9745ea9 fix(platformvm): guard validator-set cache + decouple TrackedChains snapshot (multi-validator data races)
Two concurrent-map races on the consensus-adjacent validator-set path,
both surfaced by the 5-node storm re-gate, both RED-verified fixed:

1. m.caches concurrent map write (getValidatorSetCache check-then-insert,
   reached via proposervm windower.ExpectedProposer across chains during
   buildBlocksLocked): guarded with a dedicated cachesLock sync.Mutex
   (atomic check-create-store; plain Mutex, no lost-update).
2. TrackedChains concurrent map read/write: getValidatorSetCache read the
   network's runtime-mutable cfg.TrackedChains lock-free (the admin
   setTrackedChains RPC .Add's it under peersLock). Decoupled via an
   immutable startup snapshot (set.Of(cfg.TrackedChains.List()...) in
   NewManager); the false 'immutable after startup' comment is corrected.
   Snapshot is correct (caching is pure-perf; cache.Empty recomputes),
   and the construction clone provably happens-before any writer (P-chain
   init is synchronous, admin API serves only post-node.Dispatch()).

Gates multi-validator restart-storm crash-freedom (before validator #2).
-race regression tests reproduce both races pre-fix, clean post-fix
(-count=5). Tracked follow-up (same class, network's live alias, admin-API
default-off, NOT this path): config/internal.go:120-121 + health.go:30 —
fix before ever enabling the admin API.

Co-authored-by: Hanzo Dev <dev@hanzo.ai>
2026-07-02 23:03:25 -07:00
zeekay 6e7f0b3d7e Merge tag 'v1.34.5' into blue/bootstrap-finality-split
node v1.34.5: EVM plugin v1.104.1 (0x9999 genesis-injection fix), forward-integrated on v1.34.4
2026-07-02 17:50:31 -07:00
zeekayandHanzo Dev 6a87c69010 node: signed-checkpoint bootstrap anchor (INVARIANT 4) + consensus v1.35.16
Harden the bootstrap checkpoint — the one path that bypasses the beacon quorum —
into a cryptographically SIGNED weak-subjectivity anchor.

- Checkpoint carries an authority Signature over a domain-separated canonical
  (id,height); CheckpointVerifier (injected, backed by a proven primitive —
  Ed25519/BLS, never custom crypto) authenticates it. The policy stays crypto-free
  exactly like AncestrySource/heightOf.
- AcceptsFrontier trusts a pinned checkpoint ONLY when the configured authority
  signed that exact (id,height). Present-but-unsigned, signed-by-a-non-authority,
  signature-transplanted-to-another-(id,height), and no-verifier-wired all FAIL
  CLOSED. A compromised flag cannot inject a false sync anchor without also forging
  the authority's signature. It is a cryptographic vouch, NEVER a ⅔-live-stake tally.
- No production path pins a checkpoint yet (opt-in operator escape hatch), so the
  invariant is enforced for when it is activated; nothing to wire now.

Folds consensus v1.35.16 (single ⅔ formula + leaf-lock doctrine) into the node.

Co-authored-by: Hanzo Dev <dev@hanzo.ai>
2026-07-02 17:49:54 -07:00
zeekayandHanzo Dev 3db595a637 node v1.34.5: bump C-Chain EVM plugin pin v1.104.0 -> v1.104.1
Picks up the DEX 0x9999 genesis-injection fix (evm v1.104.1): 0x9999's
EXTCODESIZE marker is no longer baked into pre-2025 genesis state, so the
archived Lux mainnet (0x3f4fa2a0), Lux testnet (0x1c5fe377) and Zoo mainnet
(0x7c548af4) RLPs re-import byte-identical. 0x9999 activates at its protocol
timestamp (2025-12-25) during replay. rpcChainVM protocol 42 unchanged.

Forward-integrated on v1.34.4 (bootstrap/finality split, consensus v1.35.15) —
v1.34.4 was already taken and still pinned evm v1.104.0. This is a minimal
patch on top: EVM pin only.

Co-authored-by: Hanzo Dev <dev@hanzo.ai>
2026-07-02 17:49:22 -07:00
zeekayandHanzo Dev 15ff32fbdc node: bootstrap/finality type split (FinalityQuorum vs BootstrapTrust) + consensus v1.35.15
Make the bootstrap-trust vs live-finality boundary a HARD API split so neither
can impersonate the other — the mass-recovery deadlock was bootstrap reusing the
finality quorum (>2/3 of CURRENT stake), which is unsatisfiable when the
recovery targets are themselves down validators.

- FinalityQuorum.HasFinality(weight,total): the live rule, strict >2/3 of current
  stake (unchanged). Renamed from ConsensusQuorum to the reviewer's exact spec.
- BootstrapTrust.AcceptsFrontier(replies): selects a weak-subjective sync anchor
  from AUTHENTICATED CONFIGURED beacons — a response FLOOR (MinResponses) plus a
  supermajority over the RESPONDERS, NEVER over the whole set. Distinct type, so
  bootstrap cannot call the finality predicate (INVARIANT 3: acceptance != finality;
  the node re-executes every synced block before re-entering consensus).
- Contrast proven: 3-of-5 bootstrap ACCEPTS a frontier, yet HasFinality(3/5) is
  false and STAYS false after sync — bootstrap is not a finality bypass.

Folds consensus v1.35.15 (the global unlock-before-call-out invariant + the
n=1..10 quorum acceptance matrix) into the node binary.

Co-authored-by: Hanzo Dev <dev@hanzo.ai>
2026-07-02 16:49:47 -07:00