Files
chains/mpcvm/backend.go
T
zeekayandHanzo Dev bbce4b6975 chains: rename thresholdvm → mpcvm (LP-134 T-Chain retirement finished)
Under LP-0130's canonical roster, chains/thresholdvm/ hosts the M-Chain
VM (MPC threshold signing). The package name "thresholdvm" was the last
piece of T-Chain nomenclature still shipping in code — legacy from the
pre-LP-134 shared-substrate design. Renamed to mpcvm/ so the package
name matches the M-Chain letter and LP-7100 spec.

- chains/thresholdvm/ → chains/mpcvm/ (dir + inner files + package decl)
- Sed-replace thresholdvm → mpcvm across .go / .md / .yml / .json / .sh
- Fee/settlement primitive references now say mpcvm
- LLM.md canonical chain roster (LP-0130) already points at mpcvm/

F-Chain runtime pieces (fhe/, protocol/tfhe_keygen/,
runtime/f_chain_adapter.go) stay under mpcvm/ for now — they consume
the same shared threshold primitives. A follow-up extract to
chains/fhevm/ can happen once F-Chain runtime graduates.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-03 01:22:30 -07:00

140 lines
4.2 KiB
Go

// Copyright (C) 2026, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
//go:build cgo
package mpcvm
// dlopen probe for the MPCVM GPU plugin. Runs once at package init() and
// pins the resolved GPUBackend into the gpuBackend singleton. Probe order
// matches the LP-186 substrate priority: native (CUDA, HIP, Metal) over
// portable (Vulkan, WebGPU), discrete over UMA.
//
// cuda → hip → metal → vulkan → webgpu
//
// Each backend has a small set of candidate dylib names. We try the
// LUXCPP_PREFIX install path first, then the lux-gpu-kernels build-tree
// path, then the bare leaf-name (relying on the dynamic linker's default
// search path: $DYLD_LIBRARY_PATH, $LD_LIBRARY_PATH, system dirs).
//
// The probe is intentionally silent on failure: a host with no GPU still
// boots; mpcvm just runs on the CPU reference (the existing
// protocol/, factory.go, executor.go state machine, unchanged by this
// bridge).
import (
"os"
"path/filepath"
)
// init runs the dlopen probe exactly once at package load. The size
// assertions run first so any wire-struct drift fails fast at process
// start instead of producing silently-wrong kernel results.
func init() {
gpuBackendOnce.Do(func() {
assertSizes()
gpuBackend = probeGPUBackend()
})
}
// probeGPUBackend walks the canonical backend priority list and returns the
// first one that dlopens AND resolves the required symbol pair. Returns
// nil when nothing matches (CPU-only mode).
func probeGPUBackend() *GPUBackend {
order := []GPUBackendKind{
GPUBackendCUDA,
GPUBackendHIP,
GPUBackendMetal,
GPUBackendVulkan,
GPUBackendWebGPU,
}
for _, kind := range order {
if b := tryLoadPlugin(kind, candidatesFor(kind)...); b != nil {
return b
}
}
return nil
}
// candidatesFor returns up to three dylib filename candidates for the given
// backend, ordered: LUXCPP_PREFIX/lib install path, lux-gpu-kernels build-tree
// path under LUX_GPU_PLUGIN_DIR, then bare leaf-name for the
// dynamic-linker default search path.
//
// On darwin the convention is libluxgpu_backend_<X>.dylib; on linux it's
// .so. WebGPU has both .dylib (when built locally on macOS) and .so
// (linux), so we include both extensions in its candidate list to maximize
// dlopen hit rate without per-platform compile-time branching.
func candidatesFor(kind GPUBackendKind) []string {
leaves := backendDylibLeaves(kind)
out := make([]string, 0, len(leaves)*3)
prefix := os.Getenv("LUXCPP_PREFIX")
if prefix == "" {
if home := os.Getenv("HOME"); home != "" {
prefix = filepath.Join(home, "work", "luxcpp", "install")
}
}
for _, leaf := range leaves {
if prefix != "" {
out = append(out, filepath.Join(prefix, "lib", leaf))
}
}
if dir := os.Getenv("LUX_GPU_PLUGIN_DIR"); dir != "" {
for _, leaf := range leaves {
out = append(out, filepath.Join(dir, leaf))
}
}
// Bare leaf names — dynamic-linker default search picks them up if
// LD_LIBRARY_PATH / DYLD_LIBRARY_PATH or /usr/local/lib has them.
out = append(out, leaves...)
return out
}
// backendDylibLeaves returns the OS-appropriate leaf filenames for one
// backend. WebGPU has two valid extensions across platforms — we include
// both so the same probe works on macOS and linux.
func backendDylibLeaves(kind GPUBackendKind) []string {
switch kind {
case GPUBackendCUDA:
return []string{"libluxgpu_backend_cuda.so"}
case GPUBackendHIP:
return []string{"libluxgpu_backend_hip.so"}
case GPUBackendMetal:
return []string{"libluxgpu_backend_metal.dylib"}
case GPUBackendVulkan:
return []string{
"libluxgpu_backend_vulkan.so",
"libluxgpu_backend_vulkan.dylib",
}
case GPUBackendWebGPU:
return []string{
"libluxgpu_backend_webgpu.dylib",
"libluxgpu_backend_webgpu.so",
}
default:
return nil
}
}
// backendBuildDirname maps each backend to its cmake build subdirectory
// under the lux GPU plugin build/.
func backendBuildDirname(kind GPUBackendKind) string {
switch kind {
case GPUBackendCUDA:
return "cuda_backend"
case GPUBackendHIP:
return "hip_backend"
case GPUBackendMetal:
return "metal_backend"
case GPUBackendVulkan:
return "vulkan_backend"
case GPUBackendWebGPU:
return "webgpu_backend"
default:
return ""
}
}