Skip to content

Commit

Permalink
ccip: Return an error from ParseLogs. (#408)
Browse files Browse the repository at this point in the history
  • Loading branch information
winder authored Jan 10, 2024
1 parent 9c45680 commit b9ac048
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 17 deletions.
26 changes: 15 additions & 11 deletions core/services/ocr2/plugins/ccip/internal/ccipdata/reader.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package ccipdata

import (
"fmt"
"time"

"github.com/ethereum/go-ethereum/common"
Expand Down Expand Up @@ -43,23 +44,26 @@ func LogsConfirmations(finalized bool) logpoller.Confirmations {

func ParseLogs[T any](logs []logpoller.Log, lggr logger.Logger, parseFunc func(log types.Log) (*T, error)) ([]Event[T], error) {
reqs := make([]Event[T], 0, len(logs))

for _, log := range logs {
data, err := parseFunc(log.ToGethLog())
if err == nil {
reqs = append(reqs, Event[T]{
Data: *data,
Meta: Meta{
BlockTimestamp: log.BlockTimestamp,
BlockNumber: log.BlockNumber,
TxHash: log.TxHash,
LogIndex: uint(log.LogIndex),
},
})
if err != nil {
lggr.Errorw("Unable to parse log", "err", err)
continue
}
reqs = append(reqs, Event[T]{
Data: *data,
Meta: Meta{
BlockTimestamp: log.BlockTimestamp,
BlockNumber: log.BlockNumber,
TxHash: log.TxHash,
LogIndex: uint(log.LogIndex),
},
})
}

if len(logs) != len(reqs) {
lggr.Warnw("Some logs were not parsed", "logs", len(logs), "requests", len(reqs))
return nil, fmt.Errorf("%d logs were not parsed", len(logs)-len(reqs))
}
return reqs, nil
}
42 changes: 36 additions & 6 deletions core/services/ocr2/plugins/ccip/internal/ccipdata/reader_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import (

"github.com/ethereum/go-ethereum/core/types"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/zap/zapcore"

"github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
"github.com/smartcontractkit/chainlink/v2/core/logger"
Expand All @@ -22,16 +24,12 @@ func Test_parseLogs(t *testing.T) {
}

parseFn := func(log types.Log) (*uint, error) {
// Simulate some random error
if log.Index == 100 {
return nil, fmt.Errorf("some error")
}
return &log.Index, nil
}

parsedEvents, err := ParseLogs[uint](logs, logger.TestLogger(t), parseFn)
assert.NoError(t, err)
assert.Len(t, parsedEvents, 99)
require.NoError(t, err)
assert.Len(t, parsedEvents, 100)

// Make sure everything is parsed according to the parse func
for i, ev := range parsedEvents {
Expand All @@ -40,3 +38,35 @@ func Test_parseLogs(t *testing.T) {
assert.Greater(t, ev.BlockTimestamp, time.Now().Add(-time.Minute))
}
}

func Test_parseLogs_withErrors(t *testing.T) {
// generate 50 valid logs and 50 errors
actualErrorCount := 50
logs := make([]logpoller.Log, actualErrorCount*2)
for i := range logs {
logs[i].LogIndex = int64(i + 1)
}

// return an error for half of the logs.
parseFn := func(log types.Log) (*uint, error) {
if log.Index%2 == 0 {
return nil, fmt.Errorf("cannot parse %d", log.Index)
}
return &log.Index, nil
}

log, observed := logger.TestLoggerObserved(t, zapcore.DebugLevel)
parsedEvents, err := ParseLogs[uint](logs, log, parseFn)
assert.ErrorContains(t, err, fmt.Sprintf("%d logs were not parsed", len(logs)/2))
assert.Nil(t, parsedEvents, "No events are returned if there was an error.")

// logs are written for errors.
require.Equal(t, actualErrorCount, observed.Len(), "Expect 51 warnings: one for each error and a summary.")
for i, entry := range observed.All() {
assert.Equal(t, zapcore.ErrorLevel, entry.Level)
assert.Contains(t, entry.Message, "Unable to parse log")
contextMap := entry.ContextMap()
require.Contains(t, contextMap, "err")
assert.Contains(t, contextMap["err"], fmt.Sprintf("cannot parse %d", (i+1)*2), "each error should be logged as a warning")
}
}

0 comments on commit b9ac048

Please sign in to comment.