Skip to content

test(pr3866): in-process coordinator↔chain FROST DKG end-to-end#4132

Merged
mswilkison merged 2 commits into
feat/frost-schnorr-migration-scaffoldfrom
test/pr3866-coordinator-chain-dkg-e2e
Jul 2, 2026
Merged

test(pr3866): in-process coordinator↔chain FROST DKG end-to-end#4132
mswilkison merged 2 commits into
feat/frost-schnorr-migration-scaffoldfrom
test/pr3866-coordinator-chain-dkg-e2e

Conversation

@mswilkison

Copy link
Copy Markdown
Contributor

What this adds

An in-process integration test that chains the full FROST wallet-creation
coordinator↔chain flow into ONE run
:

local chain emits FrostDKGStarted
  → initializeFrostDKGCoordinator's OnFrostDKGStarted subscription fires
    → handleFrostDKGStarted (dedup → confirm block → GetFrostDKGState →
       PastFrostDKGStartedEvents → resolve group membership)
      → executeFrostDKGIfPossible (readiness announcement → REAL cgo DKG via
         executeFrostDKG/RunDKGWithSeed → signer registration → result assembly
         → DKG-result operator-signature collection)
        → SubmitFrostDKGResult (through the FrostDKGChain interface)
          → wallet verified registered on the local chain

New file: pkg/tbtc/frost_dkg_coordinator_chain_e2e_frost_native_test.go
(build-gated frost_native && frost_tbtc_signer && cgo).

Why

Today the coordinator↔chain wiring and the real cgo DKG execution are tested
separately and never in one flow:

  • frost_dkg_coordinator_test.go drives the chain plumbing with stub results.
  • frost_dkg_execution_frost_native_test.go drives the real DKG in isolation.

This closes that gap: event delivery, confirmation, membership resolution,
readiness announcement, result assembly/signature collection, on-chain
submission, and wallet registration all run together against a real cgo DKG
output.

What is REAL vs REDUCED

Real

  • The DKG output. executeFrostDKG calls the process-global cgo
    tbtc-signer engine (buildTaggedTBTCSignerEngine, registered via
    RegisterNativeExecutionFFISigningPrimitiveForBuild). The x-only group key
    that lands on-chain is the exact key the engine produced.
  • The submission path. The result is submitted through the FrostDKGChain
    interface (SubmitFrostDKGResult) — not injected into chain state directly.
  • The coordinator wiring. The event is delivered through the
    OnFrostDKGStarted subscription registered by
    initializeFrostDKGCoordinator; confirmation, state check, past-event lookup,
    membership resolution, readiness announcement, DKG-result operator-signature
    collection, and delayed submission all run as in production.

Reduced (documented)

  • Group size / custody. The group is a 3-seat group whose 3 seats are all
    held by ONE operator/node. The cgo engine is a process-global
    OnceLock<Mutex>, so N independent real-custody participants cannot run
    concurrently in one OS process. The tbtc-signer development dealer DKG by
    design has a single engine hold every participant's key package — which is
    exactly this shape. The cgo library rejects n == 1
    (participants must contain at least 2 entries), so the minimum honest
    reduction is n >= 2; the test uses GroupSize=3, GroupQuorum=2, HonestThreshold=2.
  • Signer profile. The test sets TBTC_SIGNER_PROFILE=development (plus a
    hermetic state-encryption key + per-process state path, mirroring the existing
    real-cgo reference harness). Bootstrap/dealer DKG is disabled under the
    production profile, which requires distributed DKG wiring across processes.

Nothing about the crypto or the submission is faked: the DKG output comes from
the real engine and the submission goes through the chain interface.

Load-bearing assertion

A thin recording wrapper delegates every engine method to the real cgo engine
and captures the exact x-only key returned by RunDKGWithSeed. The test then
asserts the on-chain submitted Result.XOnlyOutputKey:

  1. equals the captured real engine output byte-for-byte (so no injected /
    fake result can pass),
  2. is non-zero and lifts to a valid secp256k1 curve point, and
  3. the wallet derived from it is registered on the local chain
    (IsFrostWalletRegistered).

How to run

export FROST_LIB_DIR=<path to libfrost_tbtc dir>
export CGO_ENABLED=1
export CGO_LDFLAGS="-L${FROST_LIB_DIR} -Wl,-rpath,${FROST_LIB_DIR} -lfrost_tbtc"
export KEEP_CORE_FROST_REQUIRE_CGO=true
go test -tags "frost_native frost_tbtc_signer cgo" -count=1 -v \
  -run 'TestFrostDKGCoordinatorChainEndToEnd_RealCgo' ./pkg/tbtc/

Proof lines from a passing run:

STEP 2: emitting FrostDKGStarted seed=0x42ef0705...
STEP 3+4: chain received SubmitFrostDKGResult x-only=3971f8481d56...d03d wallet=00...453a
STEP 4: SubmitFrostDKGResult observed on-chain
LOAD-BEARING: real cgo DKG x-only key 3971f8481d56...d03d landed on-chain via the coordinator
STEP 5: wallet 00...453a registered on-chain
--- PASS: TestFrostDKGCoordinatorChainEndToEnd_RealCgo

Without the cgo lib linked the test skips (or fails when
KEEP_CORE_FROST_REQUIRE_CGO=true), so it stays inert where real crypto is
unavailable. It is excluded from the plain frost_native build, so the existing
coordinator tests are unaffected (go test -tags frost_native ./pkg/tbtc/
stays green).

Not covered / follow-up

This is an in-process rehearsal with one node holding all seats. It does NOT
cover the fully-live path:

  • N distinct node processes each holding real per-seat custody, running the
    production distributed DKG (not the development dealer DKG), which is what
    TBTC_SIGNER_PROFILE=production requires.
  • A real chain (hardhat / Ethereum) with staked operators and sortition
    emitting DkgStarted, real SelectFrostGroup, and on-chain result
    validation / challenge / approve, instead of the test-local FrostDKGChain.
  • DKG-result signature collection across multiple operators over a live
    network (here a single operator's signature satisfies the reduced group's
    threshold with no network round-trip).

Those belong in a multi-process / system-test rehearsal and are out of scope for
this in-process integration test.

🤖 Generated with Claude Code

Chain the full FROST wallet-creation coordinator↔chain flow into ONE
in-process run: a local FrostDKGChain emits FrostDKGStarted, the
coordinator's OnFrostDKGStarted subscription handles it (dedup, block
confirmation, DKG-state check, past-event lookup, group-membership
resolution), executeFrostDKGIfPossible announces readiness and runs the
REAL cgo tbtc-signer DKG, and the assembled result is submitted back
through SubmitFrostDKGResult, after which the wallet is verified
registered on the chain.

Previously the coordinator↔chain wiring and the real cgo DKG execution
were covered separately (frost_dkg_coordinator_test.go with stub results;
frost_dkg_execution_frost_native_test.go in isolation) and never in one
flow.

The DKG output is real: a thin recording wrapper delegates to the cgo
engine and captures the x-only group key, which the test asserts equals
the key submitted on-chain byte-for-byte (no injected/fake result can
pass), is a valid secp256k1 point, and backs a registered wallet. The
group is reduced to 3 seats held by one node because the cgo engine is a
process-global OnceLock<Mutex> and its development dealer DKG holds all
key packages in one engine (n>=2; the library rejects n==1). Gated
frost_native && frost_tbtc_signer && cgo, so plain frost_native builds
are unaffected.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 7ea45a16-6689-4a7b-8287-93bf3edce04e

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch test/pr3866-coordinator-chain-dkg-e2e

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

P1: probe the real linked libfrost_tbtc up front. The build-tagged
tbtc-signer engine registers whether or not the lib is linked, so the
prior availability check passed even with an absent/stale lib and the
missing ABI only surfaced inside the coordinator goroutine's
RunDKGWithSeed, making the test hang until the 90s deadline instead of
skipping. Now exercise the once-per-process ABI preflight up front via a
raw seeded RunDKGWithSeed and route the result through a helper mirroring
the reference skipFrostUnavailable: ErrNativeCryptographyUnavailable SKIPS
(or FATALs under KEEP_CORE_FROST_REQUIRE_CGO), any other error fails. The
probe runs on the raw engine so it never pollutes the recording wrapper's
captured key.

P2: remove the recovery-goroutine race. initializeFrostDKGCoordinator also
launches recoverFrostDKGCoordinatorState; if it observed AwaitingResult
before the OnFrostDKGStarted subscription, it could drive the DKG via the
waitForConfirmation=false bypass and the deduplicator would suppress the
subscription path, passing the test without exercising the confirmation
flow. The chain now signals when recovery has completed its initial IDLE
scan (the first GetFrostDKGState reader), and the test waits for that
signal before flipping to AwaitingResult+emitting - so only the
subscription's block-confirmation path can run. A deterministic assertion
(submit block >= emit block + dkgStartedConfirmationBlocks) proves the
confirmation waitForBlockHeight path was exercised and guards against
silent regression.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@mswilkison mswilkison merged commit 24bb1b5 into feat/frost-schnorr-migration-scaffold Jul 2, 2026
18 checks passed
@mswilkison mswilkison deleted the test/pr3866-coordinator-chain-dkg-e2e branch July 2, 2026 23:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant