Skip to content

Commit

Permalink
CCIP-3420: Fix IsRequestTriggeredWithinTimeframe (#1445) (#14498)
Browse files Browse the repository at this point in the history
## Motivation
The prior approach to find if there is traffic in a lane was not
detecting the transactions properly. It could be due to the
`CCIPSendRequestedWatcher` captures the event after it is initiated not
any transaction before that.

## Solution
The revised approach is to use the FilterCCIPSendRequested by a past
derived block number and see if there is any traffic. The block number
is derived by this formula:
`filterFromBlock = latestBlockNumber -
(SkipRequestIfAnotherRequestTriggeredWithin/avgBlockTime)`
By this approach, we will be able to find traffic better.

https://smartcontract-it.atlassian.net/browse/CCIP-3420
  • Loading branch information
b-gopalswami authored Sep 19, 2024
1 parent e9a9444 commit 0aa5985
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 1 deletion.
44 changes: 44 additions & 0 deletions integration-tests/ccip-tests/actions/ccip_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -1620,6 +1620,8 @@ func (sourceCCIP *SourceCCIPModule) AssertSendRequestedLogFinalized(
return finalizedAt, finalizedBlockNum.Uint64(), nil
}

// IsRequestTriggeredWithinTimeframe monitors for live events occurring within the specified timeframe.
// Live events refer to those that are triggered after subscribing to the CCIP Send Requested event.
func (sourceCCIP *SourceCCIPModule) IsRequestTriggeredWithinTimeframe(timeframe *commonconfig.Duration) *time.Time {
if timeframe == nil {
return nil
Expand All @@ -1644,6 +1646,48 @@ func (sourceCCIP *SourceCCIPModule) IsRequestTriggeredWithinTimeframe(timeframe
return foundAt
}

// IsPastRequestTriggeredWithinTimeframe determines the average block time and calculates the block numbers
// within the specified timeframe. It then uses FilterCCIPSendRequested to identify the past events.
func (sourceCCIP *SourceCCIPModule) IsPastRequestTriggeredWithinTimeframe(ctx context.Context, timeframe *commonconfig.Duration) (*time.Time, error) {
if timeframe == nil {
return nil, nil
}
//var foundAt *time.Time
latestBlock, err := sourceCCIP.Common.ChainClient.LatestBlockNumber(ctx)
if err != nil {
return nil, fmt.Errorf("error while getting latest source block number. Error: %w", err)
}
avgBlockTime, err := sourceCCIP.Common.ChainClient.AvgBlockTime(ctx)
if err != nil {
return nil, fmt.Errorf("error while getting average source block time. Error: %w", err)
}
filterFromBlock := latestBlock - uint64(timeframe.Duration()/avgBlockTime)

onRampContract, err := evm_2_evm_onramp.NewEVM2EVMOnRamp(common.HexToAddress(sourceCCIP.OnRamp.EthAddress.Hex()),
sourceCCIP.Common.ChainClient.Backend())
if err != nil {
return nil, fmt.Errorf("error while on ramp contract. Error: %w", err)
}
iterator, err := onRampContract.FilterCCIPSendRequested(&bind.FilterOpts{
Start: filterFromBlock,
})
if err != nil {
return nil, fmt.Errorf("error while filtering CCIP send requested starting block number: %d. Error: %w", filterFromBlock, err)
}
defer func() {
_ = iterator.Close()
}()
if iterator.Next() {
hdr, err := sourceCCIP.Common.ChainClient.HeaderByNumber(context.Background(), big.NewInt(int64(iterator.Event.Raw.BlockNumber)))
if err != nil {
return nil, fmt.Errorf("error getting header for block: %d, Error: %w", iterator.Event.Raw.BlockNumber, err)
}
return pointer.ToTime(hdr.Timestamp), nil
}

return nil, nil
}

func (sourceCCIP *SourceCCIPModule) AssertEventCCIPSendRequested(
lggr *zerolog.Logger,
txHash string,
Expand Down
15 changes: 14 additions & 1 deletion integration-tests/ccip-tests/load/ccip_loadgen.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import (
"testing"
"time"

"github.com/smartcontractkit/chainlink-testing-framework/lib/utils/testcontext"

"github.com/AlekSi/pointer"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
Expand Down Expand Up @@ -222,7 +224,18 @@ func (c *CCIPE2ELoad) CCIPMsg() (router.ClientEVM2AnyMessage, *testreporters.Req
func (c *CCIPE2ELoad) Call(_ *wasp.Generator) *wasp.Response {
res := &wasp.Response{}
sourceCCIP := c.Lane.Source
recentRequestFoundAt := sourceCCIP.IsRequestTriggeredWithinTimeframe(c.SkipRequestIfAnotherRequestTriggeredWithin)
var recentRequestFoundAt *time.Time
var err error
// Use IsPastRequestTriggeredWithinTimeframe to check for any historical CCIP send request events
// within the specified timeframe for the first message. Subsequently, use the watcher method to monitor
// and detect any new events as they occur.
if c.CurrentMsgSerialNo.Load() == int64(1) {
recentRequestFoundAt, err = sourceCCIP.IsPastRequestTriggeredWithinTimeframe(testcontext.Get(c.t), c.SkipRequestIfAnotherRequestTriggeredWithin)
require.NoError(c.t, err, "error while filtering past requests")
} else {
recentRequestFoundAt = sourceCCIP.IsRequestTriggeredWithinTimeframe(c.SkipRequestIfAnotherRequestTriggeredWithin)
}

if recentRequestFoundAt != nil {
c.Lane.Logger.
Info().
Expand Down
3 changes: 3 additions & 0 deletions integration-tests/ccip-tests/testconfig/ccip.go
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,9 @@ func (l *LoadProfile) Validate() error {
if l.TestDuration == nil || l.TestDuration.Duration().Minutes() == 0 {
return fmt.Errorf("test duration should be set")
}
if l.SkipRequestIfAnotherRequestTriggeredWithin != nil && l.TimeUnit.Duration() < l.SkipRequestIfAnotherRequestTriggeredWithin.Duration() {
return fmt.Errorf("SkipRequestIfAnotherRequestTriggeredWithin should be set below the TimeUnit duration")
}
return nil
}

Expand Down

0 comments on commit 0aa5985

Please sign in to comment.