@@ -35,19 +35,21 @@ type NonceTracker struct {
3535 blockCount int
3636 candidateFroze bool // whether candidate nonce was frozen this epoch
3737 networkMagic int
38- fullMode bool // true = genesis-seeded rolling nonce, false = lite (zero-seeded)
38+ fullMode bool // true = genesis-seeded rolling nonce, false = lite (zero-seeded)
39+ verifiedNonces map [int ][]byte // in-memory cache of verified epoch nonces (full mode only)
3940}
4041
4142// NewNonceTracker creates a NonceTracker and attempts to restore state from DB.
4243// In full mode, the initial nonce is seeded with the Shelley genesis hash.
4344// In lite mode, the initial nonce is zero (current behavior).
4445func NewNonceTracker (store Store , koiosClient * koios.Client , epoch , networkMagic int , fullMode bool ) * NonceTracker {
4546 nt := & NonceTracker {
46- store : store ,
47- koiosClient : koiosClient ,
48- currentEpoch : epoch ,
49- networkMagic : networkMagic ,
50- fullMode : fullMode ,
47+ store : store ,
48+ koiosClient : koiosClient ,
49+ currentEpoch : epoch ,
50+ networkMagic : networkMagic ,
51+ fullMode : fullMode ,
52+ verifiedNonces : make (map [int ][]byte ),
5153 }
5254
5355 // Try to restore evolving nonce from DB for current epoch
@@ -319,24 +321,39 @@ func (nt *NonceTracker) GetNonceForEpoch(epoch int) ([]byte, error) {
319321// GetVerifiedNonceForEpoch returns a nonce that is verified against canonical
320322// data for that epoch, repairing stale DB cache entries if needed.
321323//
322- // Full mode: always recompute from local chain data and upsert DB cache.
324+ // Full mode: check in-memory cache first, then recompute from local chain data
325+ // if not cached. Repairs stale DB entries on mismatch.
323326// Lite mode: use existing lookup priority (DB -> Koios).
324327func (nt * NonceTracker ) GetVerifiedNonceForEpoch (epoch int ) ([]byte , error ) {
325328 if ! nt .fullMode {
326329 return nt .GetNonceForEpoch (epoch )
327330 }
328331
332+ // Check in-memory cache first (prevents repeated genesis recomputation)
333+ nt .mu .Lock ()
334+ if cached , ok := nt .verifiedNonces [epoch ]; ok {
335+ nt .mu .Unlock ()
336+ return cached , nil
337+ }
338+ nt .mu .Unlock ()
339+
340+ // Not in cache — recompute from local chain data
329341 computeCtx , computeCancel := context .WithTimeout (context .Background (), 10 * time .Minute )
330342 defer computeCancel ()
331343 computed , err := nt .ComputeEpochNonce (computeCtx , epoch )
332344 if err != nil {
333345 return nil , fmt .Errorf ("failed to verify nonce for epoch %d: %w" , epoch , err )
334346 }
335347
348+ // Check if DB cache needs repair
336349 checkCtx , checkCancel := context .WithTimeout (context .Background (), 5 * time .Second )
337350 defer checkCancel ()
338351 cached , cacheErr := nt .store .GetFinalNonce (checkCtx , epoch )
339352 if cacheErr == nil && cached != nil && bytes .Equal (cached , computed ) {
353+ // DB matches — store in memory cache and return
354+ nt .mu .Lock ()
355+ nt .verifiedNonces [epoch ] = computed
356+ nt .mu .Unlock ()
340357 return cached , nil
341358 }
342359
@@ -352,6 +369,11 @@ func (nt *NonceTracker) GetVerifiedNonceForEpoch(epoch int) ([]byte, error) {
352369 log .Printf ("Failed to persist verified nonce for epoch %d: %v" , epoch , err )
353370 }
354371
372+ // Store in memory cache
373+ nt .mu .Lock ()
374+ nt .verifiedNonces [epoch ] = computed
375+ nt .mu .Unlock ()
376+
355377 return computed , nil
356378}
357379
0 commit comments