From 105bb20c0d7b72f173b50c376c4a2084e3066e9b Mon Sep 17 00:00:00 2001 From: Andrew Gouin Date: Mon, 11 Dec 2023 14:54:35 -0700 Subject: [PATCH] mitigate unexpected state --- signer/cosigner_nonce_cache.go | 20 +++++++++++++++++--- signer/cosigner_nonce_cache_test.go | 16 ++++++++++++++++ signer/threshold_validator.go | 9 ++++++++- 3 files changed, 41 insertions(+), 4 deletions(-) diff --git a/signer/cosigner_nonce_cache.go b/signer/cosigner_nonce_cache.go index bc934289..c82a4ad4 100644 --- a/signer/cosigner_nonce_cache.go +++ b/signer/cosigner_nonce_cache.go @@ -375,7 +375,8 @@ func (cnc *CosignerNonceCache) PruneNonces() int { cnc.cache.mu.Lock() defer cnc.cache.mu.Unlock() nonExpiredIndex := len(cnc.cache.cache) - 1 - for i := len(cnc.cache.cache) - 1; i >= 0; i-- { + total := len(cnc.cache.cache) + for i := total - 1; i >= 0; i-- { if time.Now().Before(cnc.cache.cache[i].Expiration) { nonExpiredIndex = i break @@ -383,13 +384,20 @@ func (cnc *CosignerNonceCache) PruneNonces() int { if i == 0 { deleteCount := len(cnc.cache.cache) cnc.cache.cache = nil + cnc.logger.Debug("Pruned all nonces due to expiration", "deleted", deleteCount, "total", total) return deleteCount } } - deleteCount := len(cnc.cache.cache) - nonExpiredIndex - 1 - if nonExpiredIndex != len(cnc.cache.cache)-1 { + deleteCount := total - nonExpiredIndex - 1 + if nonExpiredIndex != total-1 { cnc.cache.cache = cnc.cache.cache[:nonExpiredIndex+1] } + if deleteCount > 0 { + cnc.logger.Debug("Pruned some nonces due to expiration", "deleted", deleteCount, "total", total) + } else { + cnc.logger.Debug("No nonces pruned due to expiration", "total", total) + } + return deleteCount } @@ -418,3 +426,9 @@ func (cnc *CosignerNonceCache) ClearNonces(cosigner Cosigner) { } } } + +func (cnc *CosignerNonceCache) ClearAllNonces() { + cnc.cache.mu.Lock() + defer cnc.cache.mu.Unlock() + cnc.cache.cache = nil +} diff --git a/signer/cosigner_nonce_cache_test.go b/signer/cosigner_nonce_cache_test.go index 756f5960..ca666674 100644 --- a/signer/cosigner_nonce_cache_test.go +++ b/signer/cosigner_nonce_cache_test.go @@ -98,7 +98,23 @@ func TestClearNonces(t *testing.T) { for _, n := range cnc.cache.cache { require.Len(t, n.Nonces, 2) + oneFound := false + twoFound := false + for _, cnr := range n.Nonces { + if cnr.Cosigner == cosigners[1] { + oneFound = true + } + if cnr.Cosigner == cosigners[2] { + twoFound = true + } + } + require.True(t, oneFound) + require.True(t, twoFound) } + + cnc.ClearNonces(cosigners[1]) + + require.Equal(t, 0, cnc.cache.Size()) } type mockPruner struct { diff --git a/signer/threshold_validator.go b/signer/threshold_validator.go index f9dede6d..e0300f92 100644 --- a/signer/threshold_validator.go +++ b/signer/threshold_validator.go @@ -6,6 +6,7 @@ import ( "errors" "fmt" "os" + "strings" "sync" "time" @@ -734,7 +735,13 @@ func (pv *ThresholdValidator) Sign(ctx context.Context, chainID string, block Bl "err", err.Error(), ) - if cosigner.GetID() == pv.myCosigner.GetID() { + isMyCosigner := cosigner.GetID() == pv.myCosigner.GetID() + + if strings.Contains(err.Error(), "unexpected state, metadata does not exist for U:") { + pv.nonceCache.ClearNonces(cosigner) + } + + if isMyCosigner { return err }