bridgevm runs as a standalone rpcchainvm plugin; mpc.go called
threshold.GetScheme(SchemeBLS) but never imported crypto/threshold/bls,
whose init() registers it. The full node binary pulled it in via
platformvm, but the v1.30.16 plugin build didn't -> B-Chain failed VM
init ('threshold: scheme not registered'). Blank-import to self-register.
OSS public chains module must not reference the private GPU plugin
implementation by repo name or filesystem path. Two leak types fixed:
1. Hard compile-time dependency in quantumvm:
`#cgo CFLAGS: -I${SRCDIR}/../../../lux-private/gpu-kernels/include`
Vendor the public ABI v14 header (backend_plugin.h + crypto.h, 1475
LOC total) into chains/internal/luxgpu/include/lux/gpu/ and point
CFLAGS at the in-tree path. Plugin DSO is still dlopen'd at runtime
— only the public C ABI surface is vendored.
2. Soft leakage — `LUX_PRIVATE_GPU_KERNELS_DIR` env vocabulary, dev-tree
probe paths to ~/work/lux-private/gpu-kernels/build/..., prose
mentions of "lux-private/gpu-kernels" in package comments.
All replaced with `LUX_GPU_PLUGIN_DIR` (universal env) and generic
"GPU plugin" prose.
Bridges affected: aivm, bridgevm, dexvm, quantumvm, thresholdvm.
All 139 tests PASS post-scrub under both build tags. No functional
behavior change — only path / env / prose.
Mirrors the evm/cevm pattern (cevm_cgo.go / cevm_nocgo.go +
backend_cgo.go). Three new files in bridgevm/:
backend.go — Backend enum, layout structs (byte-equal to
ops/bridgevm/cuda/bridgevm_kernels_common.cuh),
ErrGPUNotAvailable, GPUBackend interface,
unsafe.Sizeof asserts in init().
bridgevm_gpu.go cgo — direct dlopen(3) + dlsym(3) for the per-backend
plugin libluxgpu_backend_<bk>.{so,dylib}.
Probes cuda → hip → metal → vulkan → webgpu in
order; first plugin exposing all five
lux_<bk>_bridgevm_* launchers wins.
bridgevm_gpu_nocgo.go — stub returning ErrGPUNotAvailable on every method.
Direct dlopen (NOT pkg-config) so the public chains module builds without
the private gpu-kernels repo present. Search path: \$LUX_GPU_PLUGIN_DIR,
\$LUXCPP_PREFIX/lib/lux-gpu, \$LUXCPP_PREFIX/lib, the dev tree under
~/work/lux-private/gpu-kernels/build/backends/<bk>, CWD, and finally the
system loader's default.
Five launcher signatures dispatched via cgo trampolines (one per shape) —
matches the C ABI in include/lux/gpu/bridgevm.h. Layout structs include
explicit '_pad*' fields to keep Go sizeof() byte-equal to the C++
alignas(16) layout; the init() sizeof asserts catch any drift at process
start with a per-struct panic message.
vm.go / bridge_signing.go / mpc.go are NOT touched — this is a thin
substrate; the round applier opts in later when it's ready to route
through ActiveGPUBackend().
bridgevm_gpu_test.go — four tests under //go:build cgo:
TestActiveBackend — AutoBackend() returns a known tag.
TestStubReturnsErrGPUNotAvailable
— BackendNone path returns the sentinel.
TestLayoutSizesMatchHeader — runtime-equivalent of the C++ static_asserts.
TestSignerApplyZeroFixture — dlopen + dlsym + zero-fixture round trip
through lux_<best>_bridgevm_signer_apply.
Builds verified under both CGO_ENABLED=0 (nocgo path active) and
CGO_ENABLED=1 -tags cgo (cgo path active). All four cgo-tagged tests
pass on the local dev box (Vulkan plugin auto-detected from the
gpu-kernels build tree).
The luxfi/bridge daemon's bchain client (internal/bchain.Client) calls
bridge_getInfo / bridge_getSupportedChains / bridge_getChainConfig /
bridge_getSignature against the B-Chain RPC for permissionless discovery
+ MPC signature retrieval. Until now BridgeVM only implemented the
settlement subset (estimateFee, submitRequest, getStatus, cancelRequest,
health, getMPCPublicKey) — daemons fell back to assumed local values
for the discovery surface, a centralization vector.
This commit:
- Adds GetBridgeInfo, GetSupportedChains, GetChainConfig, GetSignature
to bridgevm.Service.
- Wires all four into the JSON-RPC dispatcher (bridge_* and bridge.*
aliases).
- GetSignature reads from the swap-store record (populated by the MPC
signing pipeline once the threshold quorum aggregates shares).
Distinguishes "no such swap" from "still signing" via separate errors
so callers can poll without dispatching on a generic error code.
- GetChainConfig matches the ChainID case-insensitively and surfaces
the requested id in the error message when the chain is not in
SupportedChains.
- Adds 6 table-driven tests covering happy paths, not-found, empty
params, and the not-yet-available signature poll.
After this lands the luxfi/bridge daemon stops needing any cached
fallback for these four endpoints — the B-Chain VM is authoritative
end-to-end. Daemon code itself needs no change; its bchain.Client
already calls these method names.
Tests: go test ./bridgevm/... — 36/36 pass (30 pre-existing + 6 new).
The bridge is permissionless and non-custodial. Authoritative quote
math and swap state must live where the validator quorum runs
consensus — in this VM — not in any single daemon's local cache.
This change moves both into bridgevm and exposes them via JSON-RPC
so any client can reach the same settlement decisions.
New RPC methods:
bridge_estimateFee — authoritative quote computation
bridge_submitRequest — create + quote-snapshot
bridge_getStatus — read swap by id
bridge_cancelRequest — idempotent cancel
bridge_health — liveness probe
bridge_getMPCPublicKey — threshold group public key
Architecture:
- QuoteEngine (quote.go) StaticPriceFeed → quorum oracle later
- SwapStore (swap_store.go) in-memory genesis impl; block-persistence next
- Service methods (rpc.go) JSON-RPC dispatch (snake + dot aliases)
Attestation aggregation already lived in bridge_signing.go via
BridgeSigner + BridgeMessageValidator — no changes needed there.
LP-333 signer-set methods unchanged.
InitiateBridgeTransfer is the canonical user-tx admission point on
B-Chain — it drives MPC signing capacity. Add a Fee uint64 field to
BridgeMessage and attach a FlatPolicy at MinTxFeeFloor in
Initialize. The fee gate refuses zero-fee transfers before any MPC
signing capacity is consumed. Consensus-internal callers bypass
via pendingBridges / bridgeSigner direct access.
Update Go package doc comments and code comments in thresholdvm/,
bridgevm/, and zkvm/ to reflect LP-134 split: M-Chain (MPC ceremonies
for bridge custody of external wallets) and F-Chain (FHE compute).
Legacy T-Chain naming clarified inline.
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).
- evm: bump precompile to v0.5.12 + fhe to v1.8.0 + gpu to v0.31.1
(gpu v0.30.0 had unresolved C.mlx_* CGO symbols)
- aivm, bridgevm, quantumvm: go mod tidy
- thresholdvm, zkvm: bump genproto to v0.0.0-20260217215200-42d3e9bedb6d
to resolve ambiguous googleapis/api/annotations import
All 12 chains now build and tests pass with GOWORK=off.
Refs #248
VMs now live in ONE place: chains/<name>/ owns the full implementation.
Previously split across node/vms/<name>/ (impl) + chains/<name>/main.go
(plugin wrapper). Now consolidated.
New layout:
chains/<name>vm/*.go — package <name>vm (VM code)
chains/<name>vm/cmd/plugin/main.go — package main (plugin binary)
chains/<name>vm/go.mod — module github.com/luxfi/chains/<name>vm
Moved 11 VMs: aivm, bridgevm, dexvm, graphvm, identityvm, keyvm,
oraclevm, quantumvm, relayvm, thresholdvm, zkvm.
External callers now import github.com/luxfi/chains/<name> directly.
Each VM builds as a standalone binary that the Lux node loads via
--plugin-dir. Node no longer bakes optional VMs in-process.
VMs: evm, dexvm, aivm, bridgevm, graphvm, identityvm, keyvm,
oraclevm, quantumvm, relayvm, servicenodevm, teleportvm,
thresholdvm, zkvm.
All 13 node-dependent VMs compile and report version correctly.
EVM requires CGo (luxcpp) — builds in CI only.