One toolchain across the estate. The tree carried 1.26.0, .1, .3, .4 and .5
at once, so which compiler built a binary depended on which repo it came
from.
Co-authored-by: Hanzo Dev <[email protected]>
The image lane failed at the private-module fetch, and the module it could not
reach is one the binary does not contain:
fatal: Authentication failed for 'https://github.com/hanzoai/replicate/'
$ go mod why -m github.com/hanzoai/replicate
(main module does not need module github.com/hanzoai/replicate)
It is in go.sum and in no require. luxfi/hsm is the same shape — imported only
by cmd/mpcd/airgap_command_test.go, so it never appears in
`go list -deps ./cmd/mpcd`. Both were being fetched because the step said
`go mod download all`, and `all` means the entire module graph rather than the
build.
So the release was gated on reaching private repositories that contribute
nothing to the artifact, and the three failures before this one — an empty
UNIVERSE_PAT, a token inside a URL, a base64 header — were all attempts to make
that unnecessary fetch succeed.
Bare `download` takes the main module's own requirements, which is what the two
builds compile; GOFLAGS=-mod=mod records any sum still missing. The credential
stays for the private modules that ARE linked.
Two shapes failed here in turn, and each failed by a different mechanism:
in a URL, any byte the grammar ends on truncates it — git then read the
credential prefix as a hostname ('Could not resolve host: x-access-token');
in an Authorization header, the value is base64, and when that produces
nothing git offers NO credential at all and asks for a username
('could not read Username for https://github.com: terminal prompts disabled').
A credential helper hands over username and password as themselves. Nothing is
parsed, nothing is encoded, so neither failure has a way in.
The private-module fetch put the token in the URL, so any byte the URL grammar
ends on truncated it and git read the credential prefix as a hostname:
fatal: unable to access 'https://x-access-token:***@github.com/…':
Could not resolve host: x-access-token
Both existing defences were already in place — the workflow strips \r\n from the
secret, and command substitution eats a trailing newline — and it broke anyway.
That is the argument against the shape rather than against the value: a URL is
the wrong container for bytes that are not ours to control. luxfi/node hit this
same failure.
http.extraheader carries the credential as a header, so nothing the token
contains can change how the address parses. The value is base64 of
'x-access-token:<token>', which is what actions/checkout itself sends.
go.work names ../threshold, a sibling checkout. Correct for a developer,
impossible in a container — the build context is this repo alone, so the
path resolves to /threshold and `go mod download all` dies before anything
compiles. Every containerized build has failed that way since the entry
landed: v1.17.16 and v1.17.17 are tags with NO image, and the fleet still
runs v1.17.15, so two releases' worth of fixes never shipped and nothing
said so.
GOWORK=off rather than deleting the entry — the workspace is a local
convenience; the build resolves the published graph, which go.mod already
pins at github.com/luxfi/threshold v1.12.5.
Co-authored-by: Hanzo Dev <[email protected]>
Currency bump: golang builder images -> 1.26.5 (latest stable).
Adds ENV GOTOOLCHAIN=auto to each Go builder stage. The official golang
images set GOTOOLCHAIN=local, so a builder image older than the module's
go directive is a hard mid-build failure. The pin stays the hermetic fast
path; auto is the safety net for the next go.mod bump.
No go.mod go directive was changed. Builder images move; directives stay.
Co-authored-by: Hanzo Dev <[email protected]>
The GOPRIVATE list carried twelve named luxfi modules because they were private
and 404 on proxy.golang.org: bridge, broker, compliance, erc20-go, fasthttp,
graph, hsm, indexer, mpc, ordering, password, pool. All twelve are open source
now, all twelve serve from the proxy, so the exceptions have nothing left to do.
GOPRIVATE disables the module proxy AND checksum verification together, so every
name on that list was a module Go fetched from git and trusted unverified. The
list is now exactly the orgs that are actually private, and every luxfi module —
all ~150 of them — verifies against sum.golang.org.
Co-authored-by: Hanzo Dev <[email protected]>
A post-v1.17.9 commit stripped the BuildKit gh_token secret + GOPRIVATE=hsm
+ GOSUMDB=off + in-build go.sum regen from the Dockerfile, and the
--secret id=gh_token,env=GH_TOKEN (UNIVERSE_PAT) from docker.yml, on the
false premise that all luxfi/* modules are public. luxfi/hsm is PRIVATE
and absent from proxy.golang.org (all versions 404), so the alpine
builder's plain 'go mod download' fell back to unauthenticated direct git
-> exit 128. Every tag since (v1.17.10/11) failed here, independent of the
threshold + dep fixes.
Restore the v1.17.9 Dockerfile verbatim (authed direct git for private
first-party modules, proxy for public, regenerate-not-bypass go.sum) and
re-add the secret to docker.yml, preserving the ARC lux-build-amd64
routing. Combined with the coherent dep graph (geth v1.17.12), this is
the full green-build set for the CGGMP21 threshold fix.
Co-authored-by: Hanzo Dev <[email protected]>
go.mod requires go 1.26.4 (and cc v0.3.0 requires >= 1.26.4). The alpine
golang image pins GOTOOLCHAIN=local, so 1.26.3-alpine refuses to build:
'go.mod requires go >= 1.26.4 (running go 1.26.3; GOTOOLCHAIN=local)'.
Match the base image to the go directive — hermetic, no toolchain download.
luxfi/* and hanzoai/* are PUBLIC Go modules. The GOPRIVATE / GONOSUMDB /
GOPROXY=direct env in Dockerfile + release.yml routed fetches around
proxy.golang.org + sum.golang.org, "working" only by skipping checksum
verification — which poisons go.sum with force-republished git bytes that no
longer match the immutable checksum db. Drop the bypass; resolve every
luxfi/hanzoai checksum from the public proxy + sumdb instead.
Poisoned deps resolved (strip luxfi/hanzoai go.sum lines, then go mod tidy):
- github.com/luxfi/edwards25519 v0.1.0 -> v0.1.1 (the agl/ed25519 replace
target, in both go.mod and e2e/go.mod): v0.1.0 was force-republished, its zip
hash diverges from the sum.golang.org pin and no copy verifies; v0.1.1 is the
clean patch the proxy + sumdb agree on.
- github.com/luxfi/age v1.4.0, github.com/luxfi/zap v0.8.1: version healthy, but
go.sum carried poisoned zip hashes — corrected to the sumdb canonical values.
- e2e/go.sum: also completed to the full canonical checksum set (hack-era builds
with GOPROXY=direct skip go.sum completion).
Verified with GOWORK=off (matching the .dockerignore'd workspace + CI):
- go mod verify -> all modules verified (main + e2e)
- CGO_ENABLED=0 go build ./... clean (main + e2e)
- go test ./... -> 35 ok / 0 FAIL; signing, threshold, keygen, attestation, kms,
ristretto255 curve, sr25519, and policy-gated sign-flow tests all pass. No
crypto regression from the edwards25519 curve-lib bump.
luxfi/* and hanzoai/* Go modules are public; GONOSUMDB/GOPRIVATE routed them
direct and bypassed sum.golang.org, so a force-republished tag could poison the
build. Resolve via the public proxy+sumdb (canonical immutable hashes).
* build(mpc): GOEXPERIMENT=jsonv2 alongside runtimesecret per SCALE_STANDARD
Per SCALE_STANDARD.md §2 (~/work/hanzo/hips/docs/SCALE_STANDARD.md) —
every Go production Dockerfile that emits JSON to a client builds with
GOEXPERIMENT=jsonv2. Verified on hanzoai/zip's json_bench_test.go:
- Edge POST roundtrip: -12% time, -23% allocs
- Marshal-only: -22% time
- Unmarshal-only: -19% time, -25% allocs
GOEXPERIMENT is comma-separated, so jsonv2 composes cleanly with the
pre-existing runtimesecret experiment used by the MPC data plane.
* ci: switch workflows to lux-build (luxfi-scoped ARC pool)
Cross-org runs-on dispatch failure: hanzo-build-linux-amd64 scale set is
registered to github.com/hanzoai and silently rejects luxfi/* jobs.
Switch to lux-build (githubConfigUrl=github.com/luxfi, max 20).
* test/zapauth: deterministic invalid-signature test (was flaky)
TestZapAuthInvalidSignature flipped one base64 char of the signature
segment. ECDSA accepts a wrong sig with probability ≈ 1/2^6 per
single-char flip (alphabet is 64), making the test ~1.5% flake rate
in CI.
Fix: replace the entire signature segment with all-A's. Still
decodable as base64url but cryptographically guaranteed-invalid
bytes — Verify rejection is now deterministic.
Verified: ran -count=10 ./pkg/zapauth/ — all pass.
* deps: bump accel/crypto/corona/threshold/fhe/lens/math to current tags
* api/db: decomplect — KeccakAddress on Wallet / TreasuryWallet / KeygenResult
Wave 5 of the workspace-wide eth* naming purge.
pkg/db/models.go — Wallet + TreasuryWallet:
- New canonical KeccakAddress *string field with json `keccakAddress`
- EthAddress kept with json `ethAddress` as `// Deprecated:` alias
- NormalizeAddresses() method on both structs mirrors the two fields
via the package-private mirrorAddrPtrPair helper
pkg/api/server.go — KeygenResult (backend response):
- New canonical KeccakAddress string field with json `keccak_address`
- EthAddress kept with json `eth_address` as `// Deprecated:` alias
- NormalizeAddresses() method mirrors both fields
pkg/api/handlers_wallets.go, handlers_treasury.go, handlers_bridge.go,
handlers_mpc.go — all sites that constructed wallet rows from MPC
backend results now:
1. Call result.NormalizeAddresses() on the backend response so both
KeccakAddress / EthAddress carry the same value before copy
2. Copy both fields onto the persisted Wallet / TreasuryWallet row
3. Call wal.NormalizeAddresses() to ensure DB row has both
4. Read from the canonical KeccakAddress at response-construction
sites (toWalletResponse, treasury response, bridge response)
The "ethereum"/"lux"/"xrp" labels in addresses map (handleGetWalletAddresses)
are per-chain DISPLAY labels keyed by chain name a client knows;
the values are the Keccak-derived 20-byte address. Map keys NOT
decomplected here — they're per-chain UI labels, not internal naming.
Effect on the wire:
- API consumers reading wallet.ethAddress see the same value as
wallet.keccakAddress
- New consumers can switch to keccakAddress today
- ORM persistence stores both fields (eventually consistent via
NormalizeAddresses calls at handler boundaries)
Tests: pkg/api unit tests pass (1.8s); pkg/db has no test files.
Deprecation alias retention means downstream KMS / dashboards
keep working at every step of the migration.
Per CLAUDE.md x.x.x+1.
* strip KeccakAddress + EthAddress dual-field bridge (no aliases)
Forward-only completion of the workspace strip-aliases cascade. The
canonical JSON field is evmAddress, the Go field is EVMAddress. No
NormalizeAddresses helpers, no mirrorAddrPtrPair, no deprecated
KeccakAddress, no deprecated EthAddress.
Touched:
pkg/api/server.go KeygenResult drops KeccakAddress +
EthAddress + NormalizeAddresses
pkg/db/models.go Wallet drops KeccakAddress + EthAddress
TreasuryWallet drops KeccakAddress +
EthAddress
Drops NormalizeAddresses + mirrorAddrPtrPair
pkg/api/handlers_wallets.go rip mirror calls; only EVMAddress
populated on Wallet rows
pkg/api/handlers_treasury.go rip mirror calls on TreasuryWallet
pkg/api/handlers_mpc.go rip NormalizeAddresses calls; rename
filter("ethAddress=") → ("evmAddress=")
pkg/api/handlers_bridge.go local var keccakAddress → evmAddr
pkg/api/handlers_smart_wallets.go wallet.EthAddress → wallet.EVMAddress
pkg/api/treasury_test.go mock KeygenResult EthAddress → EVMAddress
pkg/api/zap_kms_server_test.go same
cmd/mpcd/main.go pubKeyToEthAddress → pubKeyToEVMAddress,
\"eth_address\" → \"evm_address\",
local var ethAddr → evmAddr, KeygenResult
EthAddress → EVMAddress field
Deps: bump luxfi/metric v1.5.1 → v1.5.7 to pick up ExponentialBuckets
(via transitive luxfi/threshold dep).
The value IS \"EVM-runtime account address\" — that's the data model.
The Keccak256(secp256k1 pubkey) derivation is HOW.
Docker build was failing on `pnpm install` because corepack pulled the
latest pnpm (v11.x) which exits non-zero when build scripts (esbuild)
are present without explicit approval. Pin to v10.16.1 (stable, ships
the same `onlyBuiltDependencies` shape) and declare the esbuild build
script in package.json so future v11+ upgrades stay non-interactive.
Also swap `2>/dev/null || pnpm install` for `|| pnpm install --no-frozen-lockfile`
so we don't swallow real diagnostics — fall back to a controlled lockfile
update only when --frozen-lockfile fails.
* corona: fix lux/mpc go.sum corruption (luxfi/edwards25519)
The recorded go.sum hash for github.com/luxfi/[email protected] was
stale — the proxy now serves go.mod content (`module github.com/luxfi/
edwards25519\n\ngo 1.21\n`) that hashes to MBoV+bPE..., while go.sum had
the older tFuuyXvI... value (matching whatever go.mod content was first
published, evidently `module github.com/agl/ed25519`). Result: every Go
build in the workspace, including corona's dkg tests, errored with a
checksum mismatch SECURITY ERROR.
Fix: remove the two stale edwards25519 lines and re-run go mod tidy so
the current proxy content is re-pinned. New hashes:
h1:YPoT831TZMslvNyy/KuTtpHi4BGZWgpwak06RCaYLzo= (zip)
h1:MBoV+bPEz1tSMADPMSUaYdZ+agY3syG8B6z7RmJBH0A= (mod)
Verified: `cd ~/work/lux/corona && go test ./dkg/...` passes
TestDKG_2of3, TestDKG_3of5, TestDKG_InvalidParams, TestDKG_MissingData
(env override GOENV=/dev/null + GOPROXY=https://proxy.golang.org,direct
to bypass the unrelated GONOPROXY=hanzoai/* setting in the user's global
go env that prevents the proxy from serving the cached but git-deleted
hanzoai/[email protected] — that's a separate workspace-config issue,
not a go.sum corruption).
* fix(build): enable CGO so go-sqlite3 driver registers
The /v1/mpc/wallets HTTP API was 503'ing because CGO_ENABLED=0
left mattn/go-sqlite3 unregistered, so the wallet tables couldn't
open. Workaround was seeding wallets into TA's user_wallets table.
Switch to CGO=1 with statically-linked external linker so the binary
still runs in a scratch/alpine runtime without sqlite-libs at runtime.
No GITHUB_TOKEN needed. No git config override. No GOPRIVATE.
Proxy downloads everything. GONOSUMDB skips sum DB for our repos.
go.sum checksums match proxy (not direct).
Matches the sshd/ssh, httpd/http unix pattern. Single Docker image
now ships both binaries: ENTRYPOINT is mpcd (the daemon); override
with 'mpc <subcommand>' for CLI ops (peers, identity, recover, etc).
Also aligns with lux/kms (single binary with subcommands) — operators
get the same shape across all Base-family daemons.
Add GOEXPERIMENT=runtimesecret to Makefile, CI, and Dockerfile builds.
Wrap key share loading in all 5 signing session types with
withSecretErasure() so stack/register state containing raw share bytes
is zeroed after parsing. Build-tagged stub ensures everything compiles
without the experiment flag.
- Replace github.com/dgraph-io/badger/v4 with github.com/luxfi/zapdb/v4 v4.9.2
throughout pkg/kvstore/, pkg/transport/, cmd/mpcd/, e2e/, scripts/
- Rename BadgerPath/BadgerPassword → ZapDBPath/ZapDBPassword in FactoryConfig
- Remove local replace directives from go.mod:
- hanzoai/orm: now uses published v0.3.2 (tagged on GitHub)
- hanzoai/kv-go/v9: now uses published v9.17.2-hanzo.1
- Only remaining replace: agl/ed25519 → luxfi/edwards25519
- Add vendor/ directory (GOWORK=off go mod vendor) for reproducible builds
- Update Dockerfile to golang:1.26-alpine + -mod=vendor build flag
- Update CI/CD to use self-hosted linux/amd64 runners (no cross-compilation)
- Add k8s/valkey.yaml for session KV store
- Update k8s manifests: api-kv support, ZapDB password env, fresh secrets
- Dashboard API and MPC nodes all tested running on cluster (3/3 nodes healthy)
- Fix go.mod: move chi, cors, jwt, pgx from indirect to direct deps
- Add jackc/puddle/v2 and golang.org/x/sync as indirect deps
- Add Dockerfile ARG TARGETARCH for multi-arch builds
- Add white-label hostname branding (mpc.lux.network vs cloud.lux.network)
- Add imagePullSecrets to K8s deployments
- Remove stale docker-publish.yml and docker.yml workflows
- Remove Dockerfile.go123 placeholder
- Fix release.yml Go version to 1.25.5
- Update Dockerfile from golang:1.23-alpine to golang:1.25-alpine
matching go.mod requirement (go 1.25.5)
- Add public /healthz endpoint for K8s liveness/readiness probes
- Update api-deployment.yaml probes to use /healthz instead of
JWT-protected /api/v1/status
- Run go mod tidy to fix missing go.sum entries
- Add S3 backup manager (pkg/backup/s3.go) for periodic encrypted BadgerDB
backups with upload to S3-compatible storage (MinIO)
- Add 30s keepalive pings in transport layer to prevent idle read timeouts
- Increase read timeout from 30s to 5 minutes
- Add connection tie-breaking for simultaneous peer connections (lower node
ID keeps outbound) to prevent connection storms
- Add pointer-specific peer removal (removePeerConn) to prevent orphaned
goroutines from removing replacement connections
- Export BadgerBackupExecutor type for use by backup package
- Add /backup HTTP endpoint for on-demand backup triggers
- Bump version to 0.3.2
Explicit COPY destinations and symlink from lux-mpc to mpcd so
StatefulSet commands expecting /usr/local/bin/lux-mpc still work.
Dockerfile.prebuilt allows packaging pre-compiled binaries without
a Go build step.
- Upgrade base image from golang:1.24.5-alpine to golang:1.25-alpine
to match go.mod requirement (go 1.25.5)
- Fix binary build paths: use ./cmd/mpcd instead of non-existent ./cmd/lux-mpc
- Remove non-existent lux-mpc-bridge binary
- Update CMD to use mpcd binary
- Remove GOTOOLCHAIN=local from CI
- Fix cache keys to remove github.sha suffix
- Update Dockerfile to use golang:1.24.5-alpine
- Remove all sed workarounds and vendor mode attempts
- Use main Dockerfile instead of compatibility version
- Go 1.24.5 is now released, full native support
- Add Dockerfile.go123 for compatibility with Go 1.23
- Create placeholder binaries to maintain container structure
- Update Docker workflow to use compatibility Dockerfile
- Add comprehensive Docker build documentation
- This is a temporary solution until Go 1.24.5 is released
The compatibility image maintains the correct structure but requires
mounting actual binaries built with Go 1.24.5 for functionality.
- Add replace directives for luxfi/log and luxfi/threshold
- Use older versions that don't require Go 1.24.5
- Set GOTOOLCHAIN=local for builds
- This allows Docker builds to succeed with Go 1.23
- Create new go.mod with Go 1.23 requirement
- Use go mod tidy to resolve dependencies
- This bypasses all Go 1.24.5 version requirements
- Add docker-build.sh helper script for local builds