feat(frost): real-crypto multi-node e2e + pre-merge cgo CI gate (handoff Items 1+2)#4102
Merged
mswilkison merged 2 commits intoJun 21, 2026
Conversation
… real engine Item 1 of the pre-production handoff (design locked via Codex consult, shape A): the union of the two half-faked e2es. roast_runner_bus_net_e2e proves runner+transport with a FAKE engine; roast_real_cgo_interactive_e2e proves the REAL engine with no runner and no transport. Neither exercises the real-engine <-> real-pkg/net-transport <-> runner seam together. This does: n interactive signing runners, each over its own real pkg/net BroadcastChannel bus, driving the real cgo engine to a real BIP-340 signature, in one process (full-included 2-of-2 and t-of-included 3/threshold-2 subset). Key wiring discovery (no engine change needed): the Go RFC-21 coordinator election seeds on SHA256(dkgGroupPublicKey || sessionID || messageDigest), and the Rust engine seeds the same shuffle on SHA256(keyGroup || sessionID || messageDigest) where keyGroup is the DKG handle string. Passing []byte(keyGroup) as the binding's dkgGroupPublicKey makes the two independent derivations agree, so the runner's engine-vs-binding coordinator cross-check (never before exercised against the real engine) passes. RunDKG persists a resolvable key group, so there is no loadInteractiveKeyGroup gap on this path. Shape (A) shares ONE process-global engine across all seats (ENGINE_STATE is a process-global OnceLock<Mutex>; the multi-seat fix #4098 is what lets one engine serve every local member). The seam surfaced a real, correct boundary: the engine's aggregate completion marker is per-ATTEMPT (attempt_id, message, root), not per-member, so the first seat to aggregate produces the signature and co-resident seats observe interactive_attempt_already_aggregated. That is faithful — in production each node has its own engine — and every seat still drives its FULL transport (commitments + shares broadcast/collected over real pkg/net) before aggregate. Assertion: exactly one seat aggregates a real 64-byte signature and reaches Succeeded; every other seat reached aggregate and hit the per-attempt idempotency marker (no other failure). Skip-guarded (absent/stale libfrost_tbtc skips at the up-front DKG). Verified vs the rebuilt lib: both tests pass, -race -count=3 clean (exactly one winner, no races), skip without the lib, cgo vet + gofmt clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
…crypto tests Item 2 of the pre-production handoff (design locked via Codex consult). CI builds NONE of the frost_native/frost_tbtc_signer/cgo tags, so the real-crypto interactive tests (incl. the multi-node e2e in this PR) are validated locally only and can silently rot. Adds .github/workflows/frost-cgo-integration.yml: it checks out the Go branch, checks out a PINNED mirror commit (ci/frost-signer-pin.env - an explicit SHA, not the moving tip, so an engine/bridge drift fails CI loudly in one reviewed unit instead of silently turning the real-crypto tests into skips), builds libfrost_tbtc, verifies the exported frost_tbtc_* ABI symbols, and runs the cgo-tagged tests with skips FORBIDDEN. The require-cgo gate is KEEP_CORE_FROST_REQUIRE_CGO=true, which flips skipFrostUnavailable's lib-unavailable SKIP to a FATAL - so an absent/stale/unloadable lib fails the job rather than quietly dropping coverage. Linker note (Codex): -Wl,--no-as-needed retains the DT_NEEDED on the lib even though the bridge references it only via dlsym(RTLD_DEFAULT). The Go interactive code and the signer crate live on separate branches today, so the gate checks the pinned mirror commit out into a side path and builds from there; after the branches merge, swap the cross-branch checkout for an in-tree cargo build and keep the gate. Locally validated: require-mode FAILS without the lib (was a skip), SKIPS when unset, PASSES with the lib; the workflow YAML parses (7 steps); the verified ABI symbols are present in the built lib. A CI workflow can only be fully exercised by running it on a PR. Production binary packaging + a structured ABI-version assertion are deliberately left as follow-ups (release pipeline / mirror), noted in the handoff. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
8747c82
into
feat/frost-schnorr-migration-scaffold
16 of 17 checks passed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Pre-production handoff Items 1 and 2, bundled because the CI gate's whole purpose is to run the new e2e (and the gate's require-mode enforcement lives in the e2e's helper file).
Item 1 — real-crypto multi-node e2e
The union of the two half-faked e2es —
roast_runner_bus_net_e2e(real runner+transport, fake engine) androast_real_cgo_interactive_e2e(real engine, no runner/transport). Neither exercises the real-engine ⇄ real-pkg/net-transport ⇄ runner seam together; this does: n runners, each over its own realpkg/netbus, driving the real cgo engine to a real BIP-340 signature in one process (full-included 2-of-2 and t-of-included 3/threshold-2 subset).SHA256(dkgGroupPublicKey ‖ sessionID ‖ messageDigest)and the Rust engine onSHA256(keyGroup ‖ …); passing[]byte(keyGroup)as the binding'sdkgGroupPublicKeymakes them agree, so the runner's engine-vs-binding coordinator cross-check — never before run against the real engine — passes.interactive_attempt_already_aggregatedafter completing their full transport. In production each node has its own engine. Asserted precisely (exactly one winner + Succeeded; all others reached aggregate and hit the marker).Item 2 — pre-merge cgo CI gate
.github/workflows/frost-cgo-integration.yml: checks out the Go branch + a pinned mirror commit (ci/frost-signer-pin.env), buildslibfrost_tbtc, verifies exportedfrost_tbtc_*symbols, and runs the cgo-tagged tests with skips forbidden (KEEP_CORE_FROST_REQUIRE_CGO=trueflipsskipFrostUnavailable's lib-unavailable skip → fatal). An explicit SHA pin (not the moving tip) makes an engine/bridge drift fail loudly in one reviewed unit instead of silently dropping coverage.-Wl,--no-as-neededretains theDT_NEEDEDunder the bridge'sdlsym(RTLD_DEFAULT)model.Validation
-race -count=3clean (exactly one winner, no races), skip without the lib, cgo vet + gofmt clean.Deliberately deferred (noted in the handoff)
.soalongsidekeep-client, rpath, fail-closed startup preflight) — release-pipeline / MacLane.frost_tbtc_versionstring isn't an ABI contract) — mirror.🤖 Generated with Claude Code