mirror of
https://github.com/luxfi/chains.git
synced 2026-09-24 00:26:00 +00:00
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.
140 lines
4.2 KiB
Go
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 thresholdvm
|
|
|
|
// 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; thresholdvm 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 ""
|
|
}
|
|
}
|