Skip to content

Commit

Permalink
Added detailed tests for offramp
Browse files Browse the repository at this point in the history
  • Loading branch information
mateusz-sekara committed Jul 4, 2024
1 parent 6961844 commit 311487b
Show file tree
Hide file tree
Showing 3 changed files with 199 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ import (
"sync"
"time"

"github.com/smartcontractkit/chainlink-common/pkg/types/query"
"github.com/smartcontractkit/chainlink-common/pkg/types/query/primitives"

"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/rpclib"

mapset "github.com/deckarep/golang-set/v2"
Expand Down Expand Up @@ -485,7 +488,79 @@ func (o *OffRamp) GetExecutionStateChangesBetweenSeqNums(ctx context.Context, se
}

func (o *OffRamp) GetExecutionStateChangesForSeqNums(ctx context.Context, seqNums []cciptypes.SequenceNumberRange, confirmations int) ([]cciptypes.ExecutionStateChangedWithTxMeta, error) {
return nil, nil
latestBlock, err := o.lp.LatestBlock(ctx)
if err != nil {
return nil, fmt.Errorf("get lp latest block: %w", err)
}

seqNumRanges := make([]query.Expression, 0, len(seqNums))
for _, seqNr := range seqNums {
seqNumRanges = append(seqNumRanges, query.And(
logpoller.NewEventByTopicFilter(uint64(o.eventIndex), []primitives.ValueComparator{
{Value: logpoller.EvmWord(seqNr.Min).Hex(), Operator: primitives.Gte},
}),
logpoller.NewEventByTopicFilter(uint64(o.eventIndex), []primitives.ValueComparator{
{Value: logpoller.EvmWord(seqNr.Max).Hex(), Operator: primitives.Lte},
}),
))
}

// TODO Move to chainlink-common, querying layer should cover cases like these
var seqNumsFilter query.Expression
if len(seqNumRanges) == 1 {
seqNumsFilter = seqNumRanges[0]
} else {
seqNumsFilter = query.Or(seqNumRanges...)
}

sendRequestsQuery, err := query.Where(
o.addr.String(),
logpoller.NewAddressFilter(o.addr),
logpoller.NewEventSigFilter(o.eventSig),
seqNumsFilter,
query.Confidence(primitives.Unconfirmed),
)
if err != nil {
return nil, err
}

logs, err := o.lp.FilteredLogs(
ctx,
sendRequestsQuery,
query.NewLimitAndSort(query.Limit{}, query.NewSortBySequence(query.Asc)),
"GetExecutionStateChangesForSeqNums",
)
if err != nil {
return nil, err
}

parsedLogs, err := ccipdata.ParseLogs[cciptypes.ExecutionStateChanged](
logs,
o.Logger,
func(log types.Log) (*cciptypes.ExecutionStateChanged, error) {
sc, err1 := o.offRampV100.ParseExecutionStateChanged(log)
if err1 != nil {
return nil, err1
}

return &cciptypes.ExecutionStateChanged{
SequenceNumber: sc.SequenceNumber,
Finalized: sc.Raw.BlockNumber <= uint64(latestBlock.FinalizedBlockNumber),
}, nil
},
)
if err != nil {
return nil, fmt.Errorf("parse logs: %w", err)
}

res := make([]cciptypes.ExecutionStateChangedWithTxMeta, 0, len(parsedLogs))
for _, log := range parsedLogs {
res = append(res, cciptypes.ExecutionStateChangedWithTxMeta{
TxMeta: log.TxMeta,
ExecutionStateChanged: log.Data,
})
}
return res, nil
}

func encodeExecutionReport(args abi.Arguments, report cciptypes.ExecReport) ([]byte, error) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ import (
"math/rand"
"slices"
"testing"
"time"

"github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/rpclib"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/rpclib/rpclibmocks"

Expand Down Expand Up @@ -154,14 +156,126 @@ func generateTokensAndOutputs(nbTokens uint) ([]common.Address, []common.Address
return srcTks, dstTks, outputs
}

func Test_GetExecutionStateChangesForSeqNums(t *testing.T) {
ctx := testutils.Context(t)
chainID := testutils.NewRandomEVMChainID()
orm := logpoller.NewORM(chainID, pgtest.NewSqlxDB(t), logger.TestLogger(t))
lpOpts := logpoller.Opts{
PollPeriod: time.Hour,
FinalityDepth: 2,
BackfillBatchSize: 20,
RpcBatchSize: 10,
KeepFinalizedBlocksDepth: 1000,
}
lp := logpoller.NewLogPoller(orm, nil, logger.TestLogger(t), lpOpts)

offrampAddress := utils.RandomAddress()
inputLogs := []logpoller.Log{
CreateExecutionStateChangeEventLog(t, chainID, offrampAddress, 10, 2, 1, utils.RandomBytes32()),
CreateExecutionStateChangeEventLog(t, chainID, offrampAddress, 11, 3, 1, utils.RandomBytes32()),
CreateExecutionStateChangeEventLog(t, chainID, offrampAddress, 12, 5, 1, utils.RandomBytes32()),
CreateExecutionStateChangeEventLog(t, chainID, offrampAddress, 13, 5, 2, utils.RandomBytes32()),
CreateExecutionStateChangeEventLog(t, chainID, offrampAddress, 14, 5, 3, utils.RandomBytes32()),
CreateExecutionStateChangeEventLog(t, chainID, offrampAddress, 15, 8, 1, utils.RandomBytes32()),
CreateExecutionStateChangeEventLog(t, chainID, offrampAddress, 16, 9, 1, utils.RandomBytes32()),
CreateExecutionStateChangeEventLog(t, chainID, utils.RandomAddress(), 16, 9, 1, utils.RandomBytes32()),
}
require.NoError(t, orm.InsertLogsWithBlock(ctx, inputLogs, logpoller.NewLogPollerBlock(utils.RandomBytes32(), 20, time.Now(), 20)))

tests := []struct {
name string
seqNums []cciptypes.SequenceNumberRange
expectedLogsSeqNrs []uint64
}{
{
name: "no logs are returned",
seqNums: []cciptypes.SequenceNumberRange{
{Min: 1, Max: 9},
},
expectedLogsSeqNrs: []uint64{},
},
{
name: "all logs are returned",
seqNums: []cciptypes.SequenceNumberRange{
{Min: 10, Max: 16},
},
expectedLogsSeqNrs: []uint64{10, 11, 12, 13, 14, 15, 16},
},
{
name: "all logs are returned for wider range",
seqNums: []cciptypes.SequenceNumberRange{
{Min: 8, Max: 17},
},
expectedLogsSeqNrs: []uint64{10, 11, 12, 13, 14, 15, 16},
},
{
name: "some logs are returned for tighter range",
seqNums: []cciptypes.SequenceNumberRange{
{Min: 11, Max: 14},
},
expectedLogsSeqNrs: []uint64{11, 12, 13, 14},
},
{
name: "multiple smaller ranges",
seqNums: []cciptypes.SequenceNumberRange{
{Min: 10, Max: 11},
{Min: 13, Max: 14},
},
expectedLogsSeqNrs: []uint64{10, 11, 13, 14},
},
{
name: "single element ranges",
seqNums: []cciptypes.SequenceNumberRange{
{Min: 10, Max: 10},
{Min: 14, Max: 14},
{Min: 15, Max: 15},
},
expectedLogsSeqNrs: []uint64{10, 14, 15},
},
{
name: "out of order ranges returns logs in proper order",
seqNums: []cciptypes.SequenceNumberRange{
{Min: 14, Max: 14},
{Min: 10, Max: 11},
{Min: 15, Max: 16},
},
expectedLogsSeqNrs: []uint64{10, 11, 14, 15, 16},
},
{
name: "overlapping ranges returns logs only once",
seqNums: []cciptypes.SequenceNumberRange{
{Min: 10, Max: 14},
{Min: 13, Max: 15},
{Min: 11, Max: 12},
},
expectedLogsSeqNrs: []uint64{10, 11, 12, 13, 14, 15},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
offRamp, err1 := NewOffRamp(logger.TestLogger(t), offrampAddress, evmclimocks.NewClient(t), lp, nil, nil)
require.NoError(t, err1)

msgs, err1 := offRamp.GetExecutionStateChangesForSeqNums(ctx, tt.seqNums, 0)
require.NoError(t, err1)

assert.Len(t, msgs, len(tt.expectedLogsSeqNrs))
for i, msg := range msgs {
assert.Equal(t, tt.expectedLogsSeqNrs[i], msg.SequenceNumber)
}
})
}
}

func Test_LogsAreProperlyMarkedAsFinalized(t *testing.T) {
minSeqNr := uint64(10)
maxSeqNr := uint64(14)
inputLogs := []logpoller.Log{
CreateExecutionStateChangeEventLog(t, 10, 2, utils.RandomBytes32()),
CreateExecutionStateChangeEventLog(t, 11, 3, utils.RandomBytes32()),
CreateExecutionStateChangeEventLog(t, 12, 5, utils.RandomBytes32()),
CreateExecutionStateChangeEventLog(t, 14, 7, utils.RandomBytes32()),
CreateExecutionStateChangeEventLog(t, nil, utils.RandomAddress(), 10, 2, 0, utils.RandomBytes32()),
CreateExecutionStateChangeEventLog(t, nil, utils.RandomAddress(), 11, 3, 0, utils.RandomBytes32()),
CreateExecutionStateChangeEventLog(t, nil, utils.RandomAddress(), 12, 5, 0, utils.RandomBytes32()),
CreateExecutionStateChangeEventLog(t, nil, utils.RandomAddress(), 14, 7, 0, utils.RandomBytes32()),
}

tests := []struct {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ import (
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/client"
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils"
ubig "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big"
"github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/evm_2_evm_offramp"
"github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/price_registry_1_0_0"
"github.com/smartcontractkit/chainlink/v2/core/internal/testutils"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipcalc"
)

Expand Down Expand Up @@ -60,7 +60,7 @@ func ApplyPriceRegistryUpdate(t *testing.T, user *bind.TransactOpts, addr common
}
}

func CreateExecutionStateChangeEventLog(t *testing.T, seqNr uint64, blockNumber int64, messageID common.Hash) logpoller.Log {
func CreateExecutionStateChangeEventLog(t *testing.T, chainID *big.Int, address common.Address, seqNr uint64, blockNumber int64, logIndex int64, messageID common.Hash) logpoller.Log {
tAbi, err := evm_2_evm_offramp.EVM2EVMOffRampMetaData.GetAbi()
require.NoError(t, err)
eseEvent, ok := tAbi.Events["ExecutionStateChanged"]
Expand All @@ -80,11 +80,12 @@ func CreateExecutionStateChangeEventLog(t *testing.T, seqNr uint64, blockNumber
messageID[:],
},
Data: logData,
LogIndex: 1,
LogIndex: logIndex,
BlockHash: utils.RandomBytes32(),
BlockNumber: blockNumber,
EventSig: topic0,
Address: testutils.NewAddress(),
Address: address,
TxHash: utils.RandomBytes32(),
EvmChainId: ubig.New(chainID),
}
}

0 comments on commit 311487b

Please sign in to comment.