luxfi/node is being retired. Six of the seven packages chains once reached
into it for already come from their new homes; the fee types were the last,
and they were held here only by the oraclevm and relayvm feegate tests.
Those two assert on the policy value that luxfi/oracle and luxfi/relay hand
back, so they could not move before those modules did. oracle v1.1.3 and
relay v1.1.2 build against luxfi/vm/vms/types/fee, so the tests now compare
against the same type the VM returns rather than a look-alike from the node.
With that, no source or requirement in chains names luxfi/node.
Co-authored-by: Hanzo Dev <[email protected]>
A plugin is its own binary; the daemon that loads it has no business being
linked into it. Twelve VMs reached into github.com/luxfi/node for four things,
and each one now programs against a home that is actually its own:
- fee admission (Policy, FlatPolicy, NoUserTxPolicy, Validate) joins the
settlement half already in chains/fee. One fee package, and the nodefee alias
that marked the split is gone.
- the cross-chain artifact types move to chains/artifacts.
- the factory the daemon registers is luxfi/vm/manager.Factory, and the version
types are luxfi/version. Both are ordinary modules the daemon reads too, so a
VM imports them directly rather than through anything of ours.
The GPU switch is deleted, not moved. It was a global set during daemon startup
that a separate process could never observe, so every plugin read its default;
FHEOptions.Backend is the switch that was really there.
go list -deps names no luxfi/node for aivm, bridgevm, dexvm, evm, fhevm,
graphvm, identityvm, keyvm, mpcvm, quantumvm, schain or zkvm, and the built
plugin binaries carry no such string. oraclevm and relayvm still do: they are
re-export shims over luxfi/oracle and luxfi/relay, which build their fee
policies upstream. Their tests keep naming the daemon's fee package because
that is the type their value has.
zkvm and quantumvm accepted transactions and never built a block from them.
Consensus calls WaitForEvent and builds nothing until it returns; both answered
with <-ctx.Done(), which never returns. So BuildBlock was never called and
neither chain could leave genesis, however many transactions arrived. The
comment on one of them said it had to block to avoid flooding the engine, and
the flooding was real — but never returning is not the way to avoid it.
The pool that accepted the transaction is what knows there is work, whichever
path it arrived by, so the pool holds the latch and signals on a successful add.
That covers the paths that reach it directly as well as the HTTP handler, and
the VM's WaitForEvent is then one line. aivm had grown its own copy of this;
it now uses the shared one.
Each test fails without its signal, waiting the full timeout for a wake that
never comes.
Bridge and graph VMs are untouched: bridgevm has nothing in production that
writes a pending request, and graphvm's BuildBlock is not implemented, so a
latch in either would signal work that cannot be built.
Co-authored-by: Hanzo Dev <[email protected]>
The evm plugin turns cgo on for blst. Doing so also pulled in two
optional native backends keyed on bare cgo, neither of which a build
host carries by default, so `go build ./evm` needed a luxcpp and a
luxgpu install or it did not compile:
# github.com/luxfi/chains/evm/cevm
# [pkg-config --cflags -- lux-cevm lux-crypto-secp256k1]
Package lux-cevm was not found in the pkg-config search path.
# github.com/luxfi/accel/ops/code
code_cpu.go:102:10: fatal error: lux/gpu/hqc.h:
No such file or directory
Both are the same conflation: "a C compiler exists" is being written
where "this C library is installed" is meant. evm/cevm gets the second
predicate it was missing, lux_cevm_native, and accel v1.3.2 restores
lux_hqc_native on its side. cevm_nocgo.go and cevm_secp256k1_nocgo.go
already mirrored the full API for exactly this case, so the default
build takes them and reports CPUSequential; -tags=lux_cevm_native links
libevm/libevm-gpu unchanged.
The tests move with the predicate they actually need. TestABIVersion
locks the linked library's ABI constant, so it belongs beside
TestLibraryABIVersion in the native file rather than in the untagged
one, where it asserted 6 against the stub's documented 0 and failed
every CGO_ENABLED=0 run.
Verified: all twelve VMs build at their images.json cgo setting;
go build ./... and go test ./evm/cevm/... green at CGO=0 and CGO=1;
-tags=lux_cevm_native still selects cevm_cgo.go + cevm_secp256k1.go.
Sign now asks the key for its ML-DSA form instead of rebuilding one per
call. A key that arrives as bytes parses on first use and reuses that
key for every signature after; a freshly generated key already holds its
parsed form. A secret that will not parse fails closed on every call.
Takes crypto v1.20.5, where a private key copies the secret it is given
and hands back a copy, so the bytes a caller persists out of a generated
key stay readable for as long as the caller holds them.
Co-authored-by: Hanzo Dev <[email protected]>
The C-Chain discarded any assembled block with no transactions, which reads
"nobody asked for anything" and also reads "the assembler missed work that is
sitting in the pool". The second one is fatal: no block means no nonce advances,
so the pending transaction is never mined, so the pool never drains.
lux-devnet stopped at 20:38 UTC on 2026-08-11 holding one executable transaction
and stayed down 41 hours. v1.104.29 asks the pool instead of the block.
Skips .11 through .28, which this module never pinned.
Co-authored-by: Hanzo Dev <[email protected]>
The S3 client moves off hanzos3/go-sdk, and consensus, database, geth, container
and zapdb all come up to the releases where each stopped resolving minio.
go-sdk pointed at our checksum forks with `replace`, which Go ignores in a
non-main module — so it redirected nothing for anything importing chains, and the
real minio packages resolved regardless.
What remains is github.com/minio/sha256-simd, reached through
github.com/ferranbt/fastssz. Third-party, and not this repo's to remove.
Verified package by package against an untouched clone, because a full build
cannot run on this machine — luxfi/dex needs dex_gpu.h and cevm needs pkg-config
lux-cevm, neither installed. Both trees: 48 packages build, the same 4 fail.
Identical.
go directive held at 1.26.4.
Recorded from direct VCS fetches made while GOPRIVATE covered
github.com/luxfi/*, which switches off the proxy and checksum verification
together. proxy.golang.org still serves the originally-published bytes and they
verify against the log, so dropping only the disagreeing lines restores a
verified graph with no version change.
Co-authored-by: Hanzo Dev <[email protected]>
deps: gpu v1.1.2 — the older tags name the wrong pkg-config package
gpu v1.0.1/v1.1.0 declare `#cgo pkg-config: lux-gpu` while including
<lux/gpu.h>. Those are two different libraries with confusingly similar names:
luxgpu.pc unified GPU acceleration, -lluxgpu, Cflags -I${includedir}
lux-gpu.pc the DEX order matcher, -llux_gpu, Cflags -I${includedir}/lux
Under lux-gpu the include resolves to .../include/lux/lux/gpu.h, so every cgo
build failed with "fatal error: lux/gpu.h file not found" — the arm64 stall
signature. libluxgpu.dylib is also what actually exports _lux_gpu_ecrecover_batch.
gpu v1.1.2 already declares luxgpu; only the pin was stale.
With that fixed the link got one step further and hit a duplicate symbol:
cevm and dex/pkg/lx both define a global lux_secp256k1_metal_anchor, so any
binary linking both refuses. The anchor exists only to keep the Metal driver
alive through linker dead-code elimination — luxcpp resolves the DRIVER symbol
(secp256k1_ecrecover_address_batch_metal) via dlsym, never the anchor, so the
anchor name is internal and safe to qualify. Named lux_cevm_secp256k1_metal_anchor
after the package that owns it.
Co-authored-by: Hanzo Dev <[email protected]>
These hashes were recorded from direct VCS fetches made while GOPRIVATE covered
github.com/luxfi/*, which switches off the module proxy and checksum
verification together. Tags moved afterwards, so what was written down no longer
matches what sum.golang.org holds, and the build refuses to verify.
proxy.golang.org still serves the originally-published bytes and those verify
against the log, so dropping only the disagreeing lines and re-tidying restores
the build with no version change. Lines that agree were left alone — this is not
a regenerated go.sum.
The mismatch followed the machine, not the repository: the same commit built
wherever the cache was clean. Any machine or CI runner that fetched luxfi
modules under the old GOPRIVATE holds the same poisoned entries.
Co-authored-by: Hanzo Dev <[email protected]>
Panic-driven denial of service in the AWS SDK for Go v2 EventStream decoder:
eventstream -> v1.7.8, service/s3 -> v1.97.3 (minimum patched versions, so the
change carries the fix and nothing else).
Verified against a measured baseline: go build ./... exit 0, and go test ./...
is 23 ok / 3 fail BOTH with and without this change — identical, so any failures are
pre-existing and none is a regression from this commit.
Only go.mod/go.sum staged; other working-tree changes in this repo are left
untouched.
M-Chain is the MPC/threshold-custody VM that replaces off-chain signer
clusters for bridge custody. This makes it one.
vmID — the one-way door. factory.go declared a private `thresholdvm`
literal that matched nothing else in the stack, and node/Dockerfile
installed the plugin under that name's CB58 while genesis declares
constants.MPCVMID. The two never met, so M-Chain could not have started.
VMID is now the shared constant, and TestVMID_IsCanonicalAndStable pins
the CB58 (qCURact1n41Fco...) with the list of every declaration that must
move together if it ever changes before launch.
k vs t. types.Ceremony carried Threshold/Total as bare uint16s: Validate
read Threshold as the signer count (enforcing threshold*2 > total) while
the VM read it as the polynomial degree and passed it straight to
cmp.Keygen. The same field meant K in one file and t in another, and the
two differ by one — the same silent off-by-one that produces a 4-of-5
wallet from a config saying 3-of-5. Both now carry a quorum.Policy, and t
is only ever obtained by calling Degree(). The majority floor survives as
types.HasUniqueQuorum, defined once and enforced on every key record.
State. The VM kept its custody keys in a map persisted only on a clean
Shutdown, with the key share excluded from the wire entirely, and reset
lastAccepted to a recomputed genesis block on every Initialize — so a
restart discarded the chain and came back unable to sign. State is now
persisted at the moment each fact becomes true, split into a replicated
c/ keyspace (key registry, ceremony log, blocks, height index, root) and
a node-private n/ keyspace (this validator's shares), and Initialize
resumes the accepted tip.
Blocks verify. A block carries its post-state root and every operation's
artifact. Verify re-checks a signature against the group key already in
the registry — a proposer cannot fabricate one without forging ECDSA — and
recomputes the root, so two validators that would diverge cannot both
accept. Keygen operations carry a proof of possession by the new group key
over its own registration; a participant additionally cross-checks the
declared degree against its own share, so one honest participant rejects a
mis-declared key.
Ceremonies are leaderless. The id is derived from the task
(key, digest, sorted signers), so every validator converges on the same
ceremony with no announce round and no coordinator, and the committee is
the chain's own validator set rather than an operator roster.
Address derivation was SHA-256 where every EVM chain uses Keccak-256, so
the published custody address did not belong to the group key. Funds sent
there would have been unspendable.
Deletes the duplicate signing paths and the in-memory session machinery:
one way to generate a key, one way to sign.
Co-authored-by: Hanzo Dev <[email protected]>
Completes the "one and only one way" wire migration: every VM in this repo now
serializes blocks and txs through luxfi/zap struct-is-wire at fixed field
offsets — no encoding/json, no hand-rolled big-endian, no cursor codec.
- aivm: Block + AIVertex + nested CIntent native-encoded. Fixes a latent
data-loss bug — AIVertex had unexported fields, so encoding/json silently
marshalled it as {}; the native encoder round-trips every field.
- keyvm: Transaction (signing preimage = SigningBytes(), excludes Auth/Sig;
full wire = signing || sig object, so the signed bytes stay a genuine prefix
and authenticate() re-derives a byte-identical preimage) + Block.
- quantumvm: Block + BaseTransaction. Block wire is the quantum-signature
preimage (deterministic fixed offsets, ordered tx list).
- dexvm: block envelope (txs were already ZAP). Preserves UnixNano timestamps,
deterministic tx order, and content-addressed carried fills.
Hardening from the adversarial crypto review (must-holds all verified: no
keyvm signature malleability/replay, no aivm CIntent id-forgery/escrow tamper,
no dexvm ordering/fill tamper, all parsers fail closed):
- keyvm (M1): make the wire strictly canonical. zap follows the root offset
and ignores unreferenced padding inside a message's declared size, so a twin
buffer could decode to identical fields with a different hash (id-malleability).
ParseTransaction now binds the id to the re-serialized (canonical) form and
rejects any non-canonical input at the door — exactly one byte-string
authenticates per logical tx. Regression test: the padded twin is rejected.
- quantumvm (M2): derive block + tx ids as sha256(Bytes()), matching the other
three VMs. The prior ids.ToID(parent||height) over 40 bytes (and ids.ToID over
the >=32-byte tx wire) silently yielded ids.Empty for every block/tx,
collapsing the block store and tx pool to a single slot. The block id is no
longer stored in the wire, so the invariant id == sha256(Bytes()) holds
unconditionally. Regression tests: ids are non-Empty and collision-distinct.
Not in scope (tracked separately, fail-closed today): aivm RewardPerOperator is
escrowed but not bound by ComputeIntentID — a pre-existing design gap that needs
a coordinated A-side + C-side intent-id preimage bump before any non-fail-closed
CCommitVerifier ships.
Builds + tests green under the canonical CGO=0 -mod=readonly recipe; go.mod/go.sum
are the go mod tidy canonical set (indirect deps resolved forward, all within
major). Cryptographer verdict: SAFE TO PUBLISH.
Co-authored-by: Hanzo Dev <[email protected]>
Bumps the plugin subgraph off wiped intermediate tags (was node v1.36.4 → utxo
v0.5.1) onto the current surviving set. dexvm/txs/wire.go: setBase helpers take
zap.ObjectBuilder by value (v1.2.4+ StartObject returns a value type). Full
chains build clean; migrated-VM + mpcvm/bridgevm suites green.
Co-authored-by: Hanzo Dev <[email protected]>
chains pinned github.com/luxfi/[email protected].6 — a tag that no longer exists on the
remote (node's tags were mass-wiped; v1.30.6's lineage is disjoint anyway), which
broke every hermetic build of the VM plugins with 'unknown revision v1.30.6'.
Repin to node v1.36.4 (the current published codec-kill release; all 10 VM
cmd/plugin targets verified compiling against it). No local replace directive.
Realigned genproto so the split googleapis/rpc resolves by longest-prefix (no
monolith ambiguity), matching node's go.mod. tidy + -mod=readonly build clean;
bridgevm/zkvm/mpcvm tests green.
Co-authored-by: Hanzo Dev <[email protected]>
Kills the stale evm v1.99.51 / precompile v0.16.0 (matcher-bearing) pins. chains
now transitively carries precompile v0.19.1 (settle-only 0x9999, no embedded
matcher). go.sum regenerated (rm + go mod tidy -e; the -e tolerates a pre-existing
genproto/googleapis/rpc/status TEST-import ambiguity in aivm/cmd/plugin, unrelated
to this bump — chains builds clean). luxfi re-tag checksums (zap/age) refreshed.
Co-authored-by: Hanzo Dev <[email protected]>
chains pinned consensus v1.25.35, whose protocol/quasar/polaris.go imports
the OLD github.com/luxfi/pulsar/ref/go/pkg/pulsar path that pulsar v1.9.0
removed (it moved to pulsar/pkg/pulsar). The quantumvm + mpcvm plugins —
which transitively pull that consensus — failed to build in the node
Docker image ("module luxfi/pulsar found, but does not contain package
.../ref/go/pkg/pulsar"), breaking the node:v1.34.10/11 image builds.
Bump to consensus v1.35.22 (current path + the ProposalKey liveness fix).
go mod tidy resolves a consistent graph; all 10 chain VM plugins
(aivm/bridgevm/graphvm/identityvm/keyvm/oraclevm/quantumvm/relayvm/mpcvm/
zkvm) build clean standalone (GOWORK=off, -mod=mod, verified).
Co-authored-by: Hanzo Dev <[email protected]>
The dex venue (v1.14.0) froze its ZAP wire to EXACT INTEGERS: order/fill
price is uint64 fixed-point ×1e8 (the PriceInt grid), size is uint64 atomic
base units — no IEEE-754 float64. This eliminated every value-bearing
float→int conversion from the settlement path, whose out-of-range result is
implementation-defined per the Go spec and differs by CPU arch (arm64
saturates, amd64 wraps) — the cross-arch consensus fork (F1-F5).
The stateless atomic ZAP proxy still encoded/decoded the OLD float wire, so
it could no longer interoperate with the new venue. This propagates the
frozen frame byte-identically:
- relay.go: Fill{Price,Size} float64 -> uint64; DecodeFills reads big-endian
uint64s and rejects zero price/size. New PriceScale const == zapwire.PriceScale.
- carried_fills.go: block-carried fills encode/decode as exact uint64s.
- atomic.go: drop the float→int rounding machinery (quantToCredit/quantToCharge/
nearestIntWithin/settlementRoundEpsilon/maxSettlementUnit/float64FromBits/
isFinitePositive). Add quoteUnits (floor(size×price/PriceScale) in big.Int,
mirroring dex v4BalanceDelta / the matcher's quoteUnitsFor) and settleUint64
(refuses an aggregate that exceeds uint64 rather than wrapping).
- vm.go settleFromFills: aggregate base=Σsize, quote=Σ per-fill floor as exact
integers; slippage limit compared as fixed-point uint64; no float. Refund/
proceeds are the venue's own integers — escrow-truncation mint is structurally
impossible; spent>locked still refused.
- vm.go encodeCLOBPlace: price = tx.Price×PriceScale, size passthrough (no float).
- feegate.go: swapNativeFeeToLUX takes a fixed-point Fill.Price and floors via
quoteUnits.
- txs/tx.go: RelayOrderTx.PriceLimit is fixed-point ×PriceScale (was float64-bits).
Dep: github.com/luxfi/dex v1.5.20 (indirect) -> v1.14.0 (direct, test imports
the pure-Go zapwire leaf as the parity oracle).
Tests: all conservation/atomicity/redteam tests translated to the integer
semantics WITHOUT weakening any invariant (the no-mint / overflow-refusal /
mixed-side / slippage / determinism proofs are preserved, re-anchored to the
venue's exact per-fill floor). New frame_parity_test.go asserts the proxy's
Place/Submit/Fill frames are BYTE-IDENTICAL to dex v1.14.0 zapwire.
Co-authored-by: Hanzo Dev <[email protected]>
Picks up the WaitForEvent builder-ready race fix + target-rate build pacing
that un-freezes the C-Chain (it stalled at the imported frontier: WaitForEvent
blocked forever on a nil builder, and too-early high-fee blocks rejected
small-tip txs). Realigned go.sum for the upstream luxfi/age v1.5.0 tag-move
(zip content hash G69H... -> zC/Fw...; matches evm v1.99.51 + the live module
source). C-Chain VM plugin builds clean.
Standardize all of chains on github.com/luxfi/warp v1.23.0 (the standalone
ZAP-native warp that precompile/evm/bridgevm already use). zkvm/fhe and
thresholdvm/fhe are migrated OFF github.com/luxfi/node/vms/platformvm/warp;
there are now ZERO platformvm/warp imports in chains.
The build->sign->wrap sequence (previously copy-pasted in three places and
split across two warp libraries) now lives in exactly one place:
internal/warpmsg.BuildSigned(signer, networkID, sourceChainID, payload)
-> (*warp.Envelope, error). It builds a content Message (NewMessage), signs
it over the Beam domain with the node BLS key, and wraps the signature at
validator bit index 0 into a single-signer Envelope. All three send sites
call it:
- bridgevm/vm.go reshare-request gossip
- zkvm/fhe/coprocessor FHE task-result callback
- thresholdvm/fhe/relayer decryption fulfillment
v1.23.0 split the signature from the Message: the signed/transmittable unit
is now *warp.Envelope (Message + Beam BitSetSignature + PQ lanes), not a
combined Message. The receive path moves with it: onMessage callbacks and
WarpHandler.HandleMessage now carry *warp.Envelope and read authenticated
content from env.Message. MPC/BLS single-signer semantics are preserved
exactly (bit-0 signer, Beam-domain BLS, receiver aggregates/verifies the
BitSetSignature against the canonical validator set via warp.VerifyEnvelope).
CGO_ENABLED=0 build/vet clean; bridgevm/zkvm/thresholdvm test suites green.
InitializeDualThreshold called consensus quasar.GenerateDualKeys, a
trusted-dealer keygen (one process mints+holds every validator's BLS+Corona
share, defeating threshold security). Consensus relocated that helper to
test-only (keygen_testsupport_test.go) as corona-genesis hardening, so
production chains no longer compiles against it.
The method was dead: zero callers anywhere, and it already discarded the
generated signer (_ = signer, used only for two log lines) and inited fake
v0/v1/v2 validator IDs. The live Quasar bridge signs through the consensus
core with per-validator keys (ML-DSA fallback on the VM paths); real
validators join via AddValidator. Removing it is a no-op at runtime and
restores the build against consensus v1.25.35. Any future per-epoch group
key must come from a dealerless DKG, never a trusted dealer.
The full chains build hit a go.sum SECURITY ERROR — luxfi/[email protected] was
re-tagged (recorded hash no longer matched served bits), blocking everything that
pulls the consensus-adjacent module tree. Fixed PROPERLY, NO bypass
(GONOSUMCHECK/GOSUMDB=off never used):
- staking v1.5.0 → v1.5.1 (clean tag), records the real hash
- consensus v1.25.21 → v1.25.29 (was drifted behind; CROSS-REPO-VERSION-PIN), pulls
crypto v1.19.26
- added luxfi/dex v1.5.20 require + recorded the transitive sums (shopspring/decimal
et al) the evm/precompile dex wiring needs
Consensus path now builds + tests clean: schain + schain/cmd/plugin exit 0, full
./schain/... suite green. (Remaining full-tree ./... failure is the luxfi/evm+dex
CGO native link needing luxcpp prebuilt Metal/secp256k1 libs — a heavyweight-VM
native-build concern, NOT consensus and NOT in the schain path.)
CRYPTO (Red/cryptographer HIGH): manifest state root was a hand-rolled
len||k||len||v SHA-256 fold (length-extendable, no domain sep). Now SHAKE256 +
SP 800-185 leftEncode framing + 'SCHAIN_STATE_ROOT_V1' domain, mirroring the
validator NodeID scheme (ids/node_id_scheme.go) — not length-extendable,
domain-separated, PQ-strength. Full schain suite green (determinism +
change-sensitivity + Verify-rejects-tampered-root), NO sum bypass.
DEPS (integrity, NOT bypassed): luxfi/[email protected] had been re-tagged (go.sum
recorded an immutable-tag hash that no longer matched the served bits). Fixed
PROPERLY by moving to the clean v0.8.11 and recording the real hashes; added the
private hanzos3 org to GOPRIVATE (it was missing) so luxfi/zapdb's hanzos3/go-sdk
dep resolves via git+go.sum, not the public sumdb. go.sum is now correct, not skipped.
CI: registered schain in .github/images.json (build matrix); added the canonical
schain/cmd/plugin/main.go (ZAP-native vm/rpc.Serve, no build tag — the path the
release workflow builds), removing M0's grpc-tagged rpcchainvm plugin. Plugin
builds clean via ./schain/cmd/plugin.
consensus v1.25.18 quasar.go/epoch.go call corona/threshold.Round1 single-value,
but corona's Round1 now returns (Round1Data, error) -> the quantumvm plugin (and
any consensus consumer) fails to compile. v1.25.19 has the Round1 fix. All 11 VM
plugins build clean.
Bump to the clean-go.sum builds of evm/precompile and regenerate chains' go.sum
from a clean module cache (v1.3.12's consensus/geth hashes were poisoned by a
tampered local cache, breaking clean-CI plugin builds). No chains code change.
go mod verify clean; build + bridgevm + dexvm tests green.
orderbook/perpetuals/lending/mev dirs + backend.go deleted; vm.go 2230->830 lines.
NEW atomic.go (shared-memory import/export at Block.Accept) + relay.go (rpc.ZAPDial,
frame byte-identical to zapwire, no luxfi/dex dep). State holds only nonce:/receipt:/
consumed: -- no order/pool/position keys. txs reduced to import/export/relay. NEW
conservation_test.go::TestEndToEndAtomicValueConservation. Verified -tags dchain build+tests
green -race; grep matchAllOrders|tryMatch|crossOrders empty.
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.
The user's verbatim demand:
> "fix ALL of a-chain so it works in MULTI-CHAIN for any Lux public L1 L2
> we must work without any trusted daler or other"
WHAT CHANGED
DefaultConfig (PUBLIC-BFT-SAFE DEFAULTS):
- VerificationMode: ModeOptimistic (default) — providers post results
with bond; N-block challenge period; uncontested = finalised;
challenged = fraud-proof flow with slashing. NO trusted dealer,
NO TEE assumption, NO single point of trust.
- RequireTEEAttestation: false (was true) — TEE is OPTIONAL
acceleration, NOT a registration gate. Providers without TEE can
register and operate under the optimistic-verification flow.
- HostChainID: "primary" — AIVM is chain-agnostic. Override per
L1/L2 instance (Hanzo, Zoo, Pars, Liquidity, etc.).
- ChallengeWindowBlocks: 100 (~5-10 min finality)
- RedundancyFactor: 3 (for ModeMultiPartyRedundant — M-of-N consensus)
- MinProviderBond: 1000 LUX equivalent (slashed on fraud proof or
majority divergence)
DefaultPermissionedConfig (OPT-IN, NOT public mainnet):
- VerificationMode: ModeTEEAttested
- RequireTEEAttestation: true
- For regulated/KYC'd subnets where TEE-vendor trust is acceptable
by policy
THREE VERIFICATION MODES
1. ModeOptimistic (default, public-BFT): post + challenge + fraud proof.
2. ModeMultiPartyRedundant: M-of-N validators run same task, consensus
on output hash. Public-BFT-safe. M× compute cost.
3. ModeTEEAttested: opt-in, permissioned subnets only. TEE is folded
into the trust score as ACCELERATION (skip challenge for high
trust score); NEVER changes the trust root.
RegisterProvider:
- Public-chain path: no TEE required. Provider bond + challenge flow
enforce correctness.
- Permissioned path (RequireTEEAttestation=true): TEE attestation
required, must meet MinTrustScore. Error message points operators
at the public-chain alternative.
MULTI-CHAIN DEPLOYABILITY
- HostChainID tells AIVM which L1/L2 it's running on.
- "primary" = anchor to Q-Chain via MerkleAnchorFreq blocks.
- White-label L1/L2 = anchor to host chain's own finality (Pulsar
for PQ-finality, Corona for Corona-finality, etc.).
- AIVM code is identical across all chains; only the HostChainID
config field differs.
TESTS
- TestDefaultConfig pins public-BFT-safe defaults: TEE NOT required,
mode is Optimistic, HostChainID is "primary".
- TestDefaultPermissionedConfig pins the opt-in permissioned path.
- TestVerificationMode_PublicBFTSafe asserts default mode is always
one of (Optimistic, MultiPartyRedundant), NEVER TEE-attested as
the trust root.
go.mod refresh as side-effect of adding luxfi/node@latest for
vms/types/fee.
The local replace block (luxfi/{evm,precompile,threshold} => ../*) was
transient pending tags that include LP-4200 precompile registry + corona
keyera-lifecycle. All three lines now have shipped tags:
- luxfi/evm v0.18.13
- luxfi/precompile v0.5.23
- luxfi/threshold v1.8.0
Local replaces removed → repo builds cleanly in any isolated context
(Docker, fresh GOPATH, etc.).
Verified locally with GOWORK=off go build ./cmd/plugin per chain:
aivm/bridgevm/dexvm/graphvm/identityvm/keyvm/oraclevm/relayvm/
thresholdvm/zkvm → OK
quantumvm → FAIL (Corona→Corona source migration deferred —
references quasar.CoronaSignature/qcore.CoronaRound1 that
threshold v1.8.0 renamed).
VM consolidation (one module, one place only):
- Removed per-VM go.mod/go.sum/VERSION from {aivm,bridgevm,dexvm,evm,
graphvm,identityvm,keyvm,oraclevm,quantumvm,relayvm,thresholdvm,zkvm}
- All VMs now compile under github.com/luxfi/chains root module
- aivm/, dexvm/, identityvm/, keyvm/, oraclevm/ factory.go + vm.go updated
for AccelHost wiring
cevm Go-side (evm/cevm/):
- cevm.go, cevm_cgo.go, cevm_nocgo.go: ExecuteBlockV4(backend, threads,
txs, ctx, state) with StateAccount snapshot
- cevm_secp256k1.go: BatchRecoverSenders Metal LDFLAGS
- cevm_secp256k1_metal_anchor_darwin.{c,go}: anchor to keep linker from
dropping libsecp256k1_metal.a
- cevm_secp256k1_nocgo.go: stub for non-cgo builds
- plugin.go, fetch-luxcpp.sh, luxcpp-SHA256SUMS, LUXCPP_VERSION:
pinned luxcpp consumption
- evm/cevm/parallel/parallel.go: BlockExecutor adapter calls
cevm.ExecuteBlockV4 with state snapshot built from txs+statedb
Quantum/ZK witness:
- quantumvm/quasar_witness.go, zkvm/zwitness.go
go.mod: removed dead `replace github.com/ethereum/go-ethereum => luxfi/geth`
directive (caused dual-path conflict after math semver bump; no remaining
ethereum/go-ethereum imports in source). go mod tidy clean.
Tests: TestBatchRecoverSenders PASS through Metal anchor (cevm package).