Skip to content

Commit d9f9042

Browse files
mswilkisonclaude
andcommitted
test(frost): make the real-cgo interactive test repeatable in-process (Codex P2)
A fresh t.TempDir() per invocation broke in-process repeats (go test -count=2) against a linked signer: the signer binds its process-global state-file lock to the first TBTC_SIGNER_STATE_PATH and refuses to switch, so the second invocation failed in RunDKG. This reconciles with the earlier "fresh state" need: - process-STABLE state path keyed by PID (stable across -count=N, unique across separate processes so they don't contend on one lock), and - a UNIQUE session id per invocation (atomic counter), so repeats add a fresh DKG session in the shared persisted state rather than conflicting on a fixed one. The encryption key stays fixed so the persisted state remains decryptable across in-process repeats. Verified against a linked libfrost_tbtc: `go test -count=2 -run TestRealCgoInteractiveSigning_MemberContribution -tags "frost_native frost_tbtc_signer"` now PASSES both invocations (was failing the second); still skips without the lib; cgo vet + gofmt clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 76f686a commit d9f9042

1 file changed

Lines changed: 29 additions & 7 deletions

File tree

pkg/frost/signing/roast_real_cgo_interactive_e2e_frost_native_test.go

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,21 @@ package signing
55
import (
66
"encoding/hex"
77
"errors"
8+
"fmt"
9+
"os"
810
"path/filepath"
11+
"sync/atomic"
912
"testing"
1013

1114
"github.com/keep-network/keep-core/pkg/chain/local_v1"
1215
"github.com/keep-network/keep-core/pkg/operator"
1316
)
1417

18+
// realCgoSessionSeq gives each invocation a unique session id so that in-process
19+
// repeats (go test -count=N) over the shared, process-stable signer state path add
20+
// a fresh DKG session instead of conflicting on a fixed one.
21+
var realCgoSessionSeq atomic.Uint64
22+
1523
// This file is the REAL-cgo interactive signing test: a full FROST DKG that
1624
// PERSISTS a key group, followed by one signer's interactive ROAST contribution
1725
// driven through the engine's INTERACTIVE session API
@@ -68,25 +76,39 @@ func TestRealCgoInteractiveSigning_MemberContribution(t *testing.T) {
6876
t.Setenv("TBTC_SIGNER_PROFILE", "development")
6977
t.Setenv("TBTC_SIGNER_ENFORCE_PROVENANCE_GATE", "false")
7078
// RunDKG persists the DKG result in the signer's ENCRYPTED state, so a linked
71-
// signer needs a state encryption key and an ISOLATED, fresh state path. Without
72-
// them a clean linked environment fails before signing (missing key), and a
73-
// shared/default state path makes reruns conflict on the fixed session id.
74-
// t.TempDir() yields a fresh path per run, so each run starts clean.
79+
// signer needs a state encryption key and a state path. The path must be STABLE
80+
// within the process: the signer binds its process-global state-file lock to the
81+
// first path it sees and refuses to switch, so a fresh t.TempDir() per invocation
82+
// would break in-process repeats (go test -count=2 fails on the second run). Use
83+
// a per-PROCESS path (stable across -count=N, unique across processes so separate
84+
// runs do not contend on one lock) plus a unique session id per invocation
85+
// (below), so repeats add a fresh DKG session rather than conflicting on a fixed
86+
// one. The encryption key is fixed so the persisted state stays decryptable across
87+
// in-process repeats.
7588
stateKey := make([]byte, 32)
7689
for i := range stateKey {
7790
stateKey[i] = byte(i + 1)
7891
}
7992
t.Setenv("TBTC_SIGNER_STATE_ENCRYPTION_KEY_HEX", hex.EncodeToString(stateKey))
80-
t.Setenv("TBTC_SIGNER_STATE_PATH", filepath.Join(t.TempDir(), "signer-state"))
93+
stateDir := filepath.Join(
94+
os.TempDir(),
95+
fmt.Sprintf("keep-frost-realcgo-state-%d", os.Getpid()),
96+
)
97+
if err := os.MkdirAll(stateDir, 0o700); err != nil {
98+
t.Fatalf("create signer state dir: %v", err)
99+
}
100+
t.Setenv("TBTC_SIGNER_STATE_PATH", filepath.Join(stateDir, "signer-state"))
81101

82102
engine := &buildTaggedTBTCSignerEngine{}
83103

84104
// The engine requires threshold >= 2; the attempt's included set is the t-subset
85105
// {1,2} over a 3-party DKG. This process drives the one local signer (member 1).
86106
const threshold = 2
87107
// One session id for the whole flow: the engine keys the interactive session by
88-
// the DKG session id, so RunDKG, derive, and open all use sessionID.
89-
const sessionID = "real-cgo-session-1"
108+
// the DKG session id, so RunDKG, derive, and open all use sessionID. It is unique
109+
// per invocation so in-process repeats over the stable state path add a fresh
110+
// session instead of conflicting on a fixed one.
111+
sessionID := fmt.Sprintf("real-cgo-session-%d", realCgoSessionSeq.Add(1))
90112
const localMember = uint16(1)
91113
participantIDs := []byte{1, 2, 3}
92114
includedMembers := []byte{1, 2}

0 commit comments

Comments
 (0)