From 2c1acd7f2f2d5a1dae3fd7892b3f2fe4d6ca9ab0 Mon Sep 17 00:00:00 2001 From: Balamurali Gopalswami Date: Mon, 16 Sep 2024 17:21:01 -0400 Subject: [PATCH 1/5] CCIP-3420: Fix IsRequestTriggeredWithinTimeframe --- .../ccip-tests/actions/ccip_helpers.go | 55 ++++++++++++------- .../ccip-tests/load/ccip_loadgen.go | 10 +++- .../ccip-tests/testconfig/ccip.go | 3 + 3 files changed, 48 insertions(+), 20 deletions(-) diff --git a/integration-tests/ccip-tests/actions/ccip_helpers.go b/integration-tests/ccip-tests/actions/ccip_helpers.go index 15a737c031..4cf6ff238f 100644 --- a/integration-tests/ccip-tests/actions/ccip_helpers.go +++ b/integration-tests/ccip-tests/actions/ccip_helpers.go @@ -1616,28 +1616,45 @@ func (sourceCCIP *SourceCCIPModule) AssertSendRequestedLogFinalized( return finalizedAt, finalizedBlockNum.Uint64(), nil } -func (sourceCCIP *SourceCCIPModule) IsRequestTriggeredWithinTimeframe(timeframe *commonconfig.Duration) *time.Time { +// IsRequestTriggeredWithinTimeframe finds the average block time and picks the block number based on given timeframe and FilterCCIPSendRequested +func (sourceCCIP *SourceCCIPModule) IsRequestTriggeredWithinTimeframe(timeframe *commonconfig.Duration, ctx context.Context) (*time.Time, error) { if timeframe == nil { - return nil + return nil, fmt.Errorf("nil timeframe") } - var foundAt *time.Time - lastSeenTimestamp := time.Now().UTC().Add(-timeframe.Duration()) - sourceCCIP.CCIPSendRequestedWatcher.Range(func(_, value any) bool { - if sendRequestedEvents, exists := value.([]*evm_2_evm_onramp.EVM2EVMOnRampCCIPSendRequested); exists { - for _, sendRequestedEvent := range sendRequestedEvents { - raw := sendRequestedEvent.Raw - hdr, err := sourceCCIP.Common.ChainClient.HeaderByNumber(context.Background(), big.NewInt(int64(raw.BlockNumber))) - if err == nil { - if hdr.Timestamp.After(lastSeenTimestamp) { - foundAt = pointer.ToTime(hdr.Timestamp) - return false - } - } - } - } - return true + //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: %v", err) + } + avgBlockTime, err := sourceCCIP.Common.ChainClient.AvgBlockTime(ctx) + if err != nil { + return nil, fmt.Errorf("error while getting average source block time. Error: %v", 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: %v", err) + } + iterator, err := onRampContract.FilterCCIPSendRequested(&bind.FilterOpts{ + Start: filterFromBlock, }) - return foundAt + if err != nil { + return nil, fmt.Errorf("error while filtering CCIP send requested starting block number: %d. Error: %v", 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: %v", iterator.Event.Raw.BlockNumber, err) + } + return pointer.ToTime(hdr.Timestamp), nil + } else { + return nil, nil + } } func (sourceCCIP *SourceCCIPModule) AssertEventCCIPSendRequested( diff --git a/integration-tests/ccip-tests/load/ccip_loadgen.go b/integration-tests/ccip-tests/load/ccip_loadgen.go index 9dc8ce16e5..31fcf6a816 100644 --- a/integration-tests/ccip-tests/load/ccip_loadgen.go +++ b/integration-tests/ccip-tests/load/ccip_loadgen.go @@ -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" @@ -204,7 +206,13 @@ 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) + recentRequestFoundAt, err := sourceCCIP.IsRequestTriggeredWithinTimeframe(c.SkipRequestIfAnotherRequestTriggeredWithin, + testcontext.Get(c.t)) + if err != nil { + res.Failed = true + res.Error = fmt.Sprintf("error while checking if there is any recent transactions. Error: %v", err.Error()) + return res + } if recentRequestFoundAt != nil { c.Lane.Logger. Info(). diff --git a/integration-tests/ccip-tests/testconfig/ccip.go b/integration-tests/ccip-tests/testconfig/ccip.go index a3e322b70a..6d5ca4881f 100644 --- a/integration-tests/ccip-tests/testconfig/ccip.go +++ b/integration-tests/ccip-tests/testconfig/ccip.go @@ -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 } From 12ad7e168e47f75413d4c8c314e725ca5fb249dd Mon Sep 17 00:00:00 2001 From: Balamurali Gopalswami Date: Tue, 17 Sep 2024 13:05:58 -0400 Subject: [PATCH 2/5] Use filter for first msg and rest use watcher --- .../ccip-tests/actions/ccip_helpers.go | 44 +++++++++++++++++++ .../ccip-tests/load/ccip_loadgen.go | 17 ++++--- 2 files changed, 55 insertions(+), 6 deletions(-) diff --git a/integration-tests/ccip-tests/actions/ccip_helpers.go b/integration-tests/ccip-tests/actions/ccip_helpers.go index f0af063ac6..f359ae19ab 100644 --- a/integration-tests/ccip-tests/actions/ccip_helpers.go +++ b/integration-tests/ccip-tests/actions/ccip_helpers.go @@ -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 @@ -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(timeframe *commonconfig.Duration, ctx context.Context) (*time.Time, error) { + if timeframe == nil { + return nil, fmt.Errorf("nil timeframe") + } + //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: %v", err) + } + avgBlockTime, err := sourceCCIP.Common.ChainClient.AvgBlockTime(ctx) + if err != nil { + return nil, fmt.Errorf("error while getting average source block time. Error: %v", 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: %v", 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: %v", 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: %v", iterator.Event.Raw.BlockNumber, err) + } + return pointer.ToTime(hdr.Timestamp), nil + } else { + return nil, nil + } +} + func (sourceCCIP *SourceCCIPModule) AssertEventCCIPSendRequested( lggr *zerolog.Logger, txHash string, diff --git a/integration-tests/ccip-tests/load/ccip_loadgen.go b/integration-tests/ccip-tests/load/ccip_loadgen.go index 61ee4c89a4..63bfddfba6 100644 --- a/integration-tests/ccip-tests/load/ccip_loadgen.go +++ b/integration-tests/ccip-tests/load/ccip_loadgen.go @@ -225,13 +225,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, err := sourceCCIP.IsRequestTriggeredWithinTimeframe(c.SkipRequestIfAnotherRequestTriggeredWithin, - testcontext.Get(c.t)) - if err != nil { - res.Failed = true - res.Error = fmt.Sprintf("error while checking if there is any recent transactions. Error: %v", err.Error()) - return res + 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(c.SkipRequestIfAnotherRequestTriggeredWithin, testcontext.Get(c.t)) + require.NoError(c.t, err, "error while filtering past requests") + } else { + recentRequestFoundAt = sourceCCIP.IsRequestTriggeredWithinTimeframe(c.SkipRequestIfAnotherRequestTriggeredWithin) } + if recentRequestFoundAt != nil { c.Lane.Logger. Info(). From 0a8d42a6d5c80e773c08b2fc37767eb53d33a49d Mon Sep 17 00:00:00 2001 From: Balamurali Gopalswami Date: Tue, 17 Sep 2024 13:26:55 -0400 Subject: [PATCH 3/5] Fix lint --- .../ccip-tests/actions/ccip_helpers.go | 16 ++++++++-------- .../ccip-tests/load/ccip_loadgen.go | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/integration-tests/ccip-tests/actions/ccip_helpers.go b/integration-tests/ccip-tests/actions/ccip_helpers.go index f359ae19ab..0f9cd81d9c 100644 --- a/integration-tests/ccip-tests/actions/ccip_helpers.go +++ b/integration-tests/ccip-tests/actions/ccip_helpers.go @@ -1648,31 +1648,31 @@ func (sourceCCIP *SourceCCIPModule) IsRequestTriggeredWithinTimeframe(timeframe // 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(timeframe *commonconfig.Duration, ctx context.Context) (*time.Time, error) { +func (sourceCCIP *SourceCCIPModule) IsPastRequestTriggeredWithinTimeframe(ctx context.Context, timeframe *commonconfig.Duration) (*time.Time, error) { if timeframe == nil { return nil, fmt.Errorf("nil timeframe") } //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: %v", err) + 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: %v", err) + 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: %v", err) + 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: %v", filterFromBlock, err) + return nil, fmt.Errorf("error while filtering CCIP send requested starting block number: %d. Error: %w", filterFromBlock, err) } defer func() { _ = iterator.Close() @@ -1680,12 +1680,12 @@ func (sourceCCIP *SourceCCIPModule) IsPastRequestTriggeredWithinTimeframe(timefr 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: %v", iterator.Event.Raw.BlockNumber, err) + return nil, fmt.Errorf("error getting header for block: %d, Error: %w", iterator.Event.Raw.BlockNumber, err) } return pointer.ToTime(hdr.Timestamp), nil - } else { - return nil, nil } + + return nil, nil } func (sourceCCIP *SourceCCIPModule) AssertEventCCIPSendRequested( diff --git a/integration-tests/ccip-tests/load/ccip_loadgen.go b/integration-tests/ccip-tests/load/ccip_loadgen.go index 63bfddfba6..d3af128309 100644 --- a/integration-tests/ccip-tests/load/ccip_loadgen.go +++ b/integration-tests/ccip-tests/load/ccip_loadgen.go @@ -231,7 +231,7 @@ func (c *CCIPE2ELoad) Call(_ *wasp.Generator) *wasp.Response { // 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(c.SkipRequestIfAnotherRequestTriggeredWithin, testcontext.Get(c.t)) + 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) From 454c8b3da72dcc4831d238db8a3ad078f575ff5b Mon Sep 17 00:00:00 2001 From: Balamurali Gopalswami Date: Tue, 17 Sep 2024 13:46:06 -0400 Subject: [PATCH 4/5] Not or and it should be and --- integration-tests/ccip-tests/testconfig/ccip.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration-tests/ccip-tests/testconfig/ccip.go b/integration-tests/ccip-tests/testconfig/ccip.go index 7dc6e407f5..1f4dfaac51 100644 --- a/integration-tests/ccip-tests/testconfig/ccip.go +++ b/integration-tests/ccip-tests/testconfig/ccip.go @@ -242,7 +242,7 @@ 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() { + if l.SkipRequestIfAnotherRequestTriggeredWithin != nil && l.TimeUnit.Duration() < l.SkipRequestIfAnotherRequestTriggeredWithin.Duration() { return fmt.Errorf("SkipRequestIfAnotherRequestTriggeredWithin should be set below the TimeUnit duration") } return nil From a7b070fd526b16e830e2c759883c2a49f50772bb Mon Sep 17 00:00:00 2001 From: Balamurali Gopalswami Date: Tue, 17 Sep 2024 15:03:53 -0400 Subject: [PATCH 5/5] Remove nil timeframe error --- integration-tests/ccip-tests/actions/ccip_helpers.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration-tests/ccip-tests/actions/ccip_helpers.go b/integration-tests/ccip-tests/actions/ccip_helpers.go index 0f9cd81d9c..2bbc77f1c2 100644 --- a/integration-tests/ccip-tests/actions/ccip_helpers.go +++ b/integration-tests/ccip-tests/actions/ccip_helpers.go @@ -1650,7 +1650,7 @@ func (sourceCCIP *SourceCCIPModule) IsRequestTriggeredWithinTimeframe(timeframe // 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, fmt.Errorf("nil timeframe") + return nil, nil } //var foundAt *time.Time latestBlock, err := sourceCCIP.Common.ChainClient.LatestBlockNumber(ctx)