Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 38 additions & 1 deletion core/services/ocr2/plugins/ccip/ccipexec/ocr2.go
Original file line number Diff line number Diff line change
Expand Up @@ -226,12 +226,49 @@ func (r *ExecutionReportingPlugin) getExecutableObservations(ctx context.Context
lggr.Infow("Execution batch created", "batchSize", len(batch), "messageStates", msgExecStates)
return batch, nil
}
r.commitRootsCache.Snooze(merkleRoot)
// Skip snoozing if we have token data delays but no serious processing errors
shouldSkipSnooze := shouldSkipSnoozeForTokenDataNotReady(msgExecStates)

if shouldSkipSnooze {
rootLggr.Infow("Skipping snooze - messages waiting for token data with no processing errors")
} else {
r.commitRootsCache.Snooze(merkleRoot)
}
}
}
return []ccip.ObservedMessage{}, nil
}

// shouldSkipSnoozeForTokenDataNotReady checks if we should skip snoozing for token data not ready.
// If there are token data delays but no serious processing errors, we skip snoozing.
func shouldSkipSnoozeForTokenDataNotReady(msgExecStates []messageExecStatus) bool {
if len(msgExecStates) == 0 {
return false
}

hasTokenDataNotReady := false
hasProcessingErrors := false

harmlessStatuses := map[messageStatus]bool{
AlreadyExecuted: true,
TokenDataNotReady: true,
SkippedInflight: true,
AddedToBatch: true,
SuccesfullyValidated: true,
}

for _, state := range msgExecStates {
if state.Status == TokenDataNotReady {
hasTokenDataNotReady = true
}
if !harmlessStatuses[state.Status] {
hasProcessingErrors = true
}
}

return hasTokenDataNotReady && !hasProcessingErrors
}

// Calculates a map that indicates whether a sequence number has already been executed.
// It doesn't matter if the execution succeeded, since we don't retry previous
// attempts even if they failed. Value in the map indicates whether the log is finalized or not.
Expand Down
71 changes: 71 additions & 0 deletions core/services/ocr2/plugins/ccip/ccipexec/ocr2_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1475,3 +1475,74 @@ func TestExecutionReportingPlugin_getConsensusThreshold(t *testing.T) {
})
}
}

func TestExecutionReportingPlugin_SnoozeLogicWithTokenDataNotReady(t *testing.T) {
testCases := []struct {
name string
msgExecStates []messageExecStatus
shouldSnooze bool
description string
}{
{
name: "all messages have TokenDataNotReady - should NOT snooze",
msgExecStates: []messageExecStatus{
{SeqNr: 1, MessageId: "0x1", Status: TokenDataNotReady},
{SeqNr: 2, MessageId: "0x2", Status: TokenDataNotReady},
{SeqNr: 3, MessageId: "0x3", Status: TokenDataNotReady},
},
shouldSnooze: false,
description: "When all messages are waiting for token data, retry quickly instead of snoozing",
},
{
name: "mixed harmless statuses including TokenDataNotReady - should NOT snooze",
msgExecStates: []messageExecStatus{
{SeqNr: 1, MessageId: "0x1", Status: TokenDataNotReady},
{SeqNr: 2, MessageId: "0x2", Status: AlreadyExecuted},
{SeqNr: 3, MessageId: "0x3", Status: TokenDataNotReady},
},
shouldSnooze: false,
description: "When messages have only harmless issues including TokenDataNotReady, don't snooze",
},
{
name: "mixed statuses with processing errors - should snooze",
msgExecStates: []messageExecStatus{
{SeqNr: 1, MessageId: "0x1", Status: TokenDataNotReady},
{SeqNr: 2, MessageId: "0x2", Status: InvalidNonce},
{SeqNr: 3, MessageId: "0x3", Status: TokenDataNotReady},
},
shouldSnooze: true,
description: "When messages have processing errors alongside TokenDataNotReady, snooze as before",
},
{
name: "no TokenDataNotReady statuses - should snooze",
msgExecStates: []messageExecStatus{
{SeqNr: 1, MessageId: "0x1", Status: AlreadyExecuted},
{SeqNr: 2, MessageId: "0x2", Status: InvalidNonce},
{SeqNr: 3, MessageId: "0x3", Status: InsufficientRemainingBatchGas},
},
shouldSnooze: true,
description: "When messages have other issues, snooze as before",
},
{
name: "single message with TokenDataNotReady - should NOT snooze",
msgExecStates: []messageExecStatus{
{SeqNr: 1, MessageId: "0x1", Status: TokenDataNotReady},
},
shouldSnooze: false,
description: "Single message waiting for token data should retry quickly",
},
{
name: "empty message states - should snooze",
msgExecStates: []messageExecStatus{},
shouldSnooze: true,
description: "No messages means unknown issue, should snooze",
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
shouldSkipSnooze := shouldSkipSnoozeForTokenDataNotReady(tc.msgExecStates)
require.Equal(t, tc.shouldSnooze, !shouldSkipSnooze)
})
}
}
Loading