Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CCIP-5118] Refactor Test_CCIPMessageLimitations logic into helper pkg #16680

Open
wants to merge 9 commits into
base: develop
Choose a base branch
from
Open
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
package messagelimitationstest

import (
"testing"

"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/require"

"github.com/smartcontractkit/chainlink/deployment"
"github.com/smartcontractkit/chainlink/deployment/ccip/changeset"
"github.com/smartcontractkit/chainlink/deployment/ccip/changeset/testhelpers"
"github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/v1_2_0/router"
"github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/v1_6_0/fee_quoter"
"github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/v1_6_0/onramp"
)

// Use this when testhelpers.DeployedEnv is available (usually in ephemeral test environments).
func NewTestSetupWithDeployedEnv(
t *testing.T,
depEnv testhelpers.DeployedEnv,
onchainState changeset.CCIPOnChainState,
sourceChain,
destChain uint64,
srctoken common.Address,
srcFeeQuoterDestChainConfig fee_quoter.FeeQuoterDestChainConfig,
testRouter,
validateResp bool,
) TestSetup {
return TestSetup{
T: t,
Env: depEnv.Env,
DeployedEnv: &depEnv,
OnchainState: onchainState,
SrcChain: sourceChain,
DestChain: destChain,
SrcToken: srctoken,
SrcFeeQuoterDestChainConfig: srcFeeQuoterDestChainConfig,
TestRouter: testRouter,
ValidateResp: validateResp,
}
}

// Use this when testhelpers.DeployedEnv is not available (usually in long-running test environments like staging).
func NewTestSetup(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: how about using functional opts here?

t *testing.T,
env deployment.Environment,
onchainState changeset.CCIPOnChainState,
sourceChain,
destChain uint64,
srctoken common.Address,
srcFeeQuoterDestChainConfig fee_quoter.FeeQuoterDestChainConfig,
testRouter,
validateResp bool,
) TestSetup {
return TestSetup{
T: t,
Env: env,
// no DeployedEnv
OnchainState: onchainState,
SrcChain: sourceChain,
DestChain: destChain,
SrcToken: srctoken,
SrcFeeQuoterDestChainConfig: srcFeeQuoterDestChainConfig,
TestRouter: testRouter,
ValidateResp: validateResp,
}
}

type TestSetup struct {
T *testing.T
Env deployment.Environment
DeployedEnv *testhelpers.DeployedEnv
OnchainState changeset.CCIPOnChainState
SrcChain uint64
DestChain uint64
SrcToken common.Address
SrcFeeQuoterDestChainConfig fee_quoter.FeeQuoterDestChainConfig
TestRouter bool
ValidateResp bool
}

type TestCase struct {
TestSetup
Name string
Msg router.ClientEVM2AnyMessage
ExpRevert bool
}

type TestCaseOutput struct {
MsgSentEvent *onramp.OnRampCCIPMessageSent
}

func Run(tc TestCase) TestCaseOutput {
Comment on lines +89 to +93
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, can we use this helper struct + method in the current message limitations test as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this is the one item I have left in the TODOs.

tc.T.Logf("Sending msg: %s", tc.Name)
require.NotEqual(tc.T, tc.SrcChain, tc.DestChain, "fromChain and toChain cannot be the same")

// Approve router to send token only on long-running environments
if tc.DeployedEnv == nil && tc.SrcToken != (common.Address{}) {
routerAddress := tc.OnchainState.Chains[tc.SrcChain].Router.Address()
if tc.TestRouter {
routerAddress = tc.OnchainState.Chains[tc.SrcChain].TestRouter.Address()
}
err := testhelpers.ApproveToken(tc.Env, tc.SrcChain, tc.SrcToken, routerAddress, testhelpers.OneCoin)
require.NoError(tc.T, err)
}

msgSentEvent, err := testhelpers.DoSendRequest(
tc.T, tc.Env, tc.OnchainState,
testhelpers.WithSourceChain(tc.SrcChain),
testhelpers.WithDestChain(tc.DestChain),
testhelpers.WithTestRouter(tc.TestRouter),
testhelpers.WithEvm2AnyMessage(tc.Msg))

if tc.ExpRevert {
tc.T.Logf("Message reverted as expected")
require.Error(tc.T, err)
require.Contains(tc.T, err.Error(), "execution reverted")
return TestCaseOutput{}
}
require.NoError(tc.T, err)

tc.T.Logf("Message not reverted as expected")

return TestCaseOutput{
MsgSentEvent: msgSentEvent,
}
}
23 changes: 23 additions & 0 deletions deployment/ccip/changeset/testhelpers/test_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ import (
"github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/mock_ethusd_aggregator_wrapper"
"github.com/smartcontractkit/chainlink/v2/core/gethwrappers/shared/generated/aggregator_v3_interface"
"github.com/smartcontractkit/chainlink/v2/core/gethwrappers/shared/generated/burn_mint_erc677"
"github.com/smartcontractkit/chainlink/v2/core/gethwrappers/shared/generated/erc20"
"github.com/smartcontractkit/chainlink/v2/core/gethwrappers/shared/generated/mock_v3_aggregator_contract"
"github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/abihelpers"

Expand All @@ -87,6 +88,8 @@ var (
DefaultLinkPrice = deployment.E18Mult(20)
DefaultWethPrice = deployment.E18Mult(4000)
DefaultGasPrice = ToPackedFee(big.NewInt(8e14), big.NewInt(0))

OneCoin = new(big.Int).Mul(big.NewInt(1e18), big.NewInt(1))
)

// Context returns a context with the test's deadline, if available.
Expand Down Expand Up @@ -1254,6 +1257,26 @@ func NewMintTokenWithCustomSender(auth *bind.TransactOpts, sender *bind.Transact
return MintTokenInfo{auth: auth, sender: sender, tokens: tokens}
}

// ApproveToken approves the router to spend the given amount of tokens
func ApproveToken(env deployment.Environment, src uint64, tokenAddress common.Address, routerAddress common.Address, amount *big.Int) error {
token, err := erc20.NewERC20(tokenAddress, env.Chains[src].Client)
if err != nil {
return err
}

tx, err := token.Approve(env.Chains[src].DeployerKey, routerAddress, amount)
if err != nil {
return err
}

_, err = env.Chains[src].Confirm(tx)
if err != nil {
return err
}

return nil
}

// MintAndAllow mints tokens for deployers and allow router to spend them
func MintAndAllow(
t *testing.T,
Expand Down
139 changes: 63 additions & 76 deletions integration-tests/smoke/ccip/ccip_message_limitations_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/smartcontractkit/chainlink/deployment"
"github.com/smartcontractkit/chainlink/deployment/ccip/changeset"
"github.com/smartcontractkit/chainlink/deployment/ccip/changeset/testhelpers"
mlt "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/testhelpers/messagelimitationstest"
testsetups "github.com/smartcontractkit/chainlink/integration-tests/testsetups/ccip"
"github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/v1_2_0/router"
)
Expand Down Expand Up @@ -46,44 +47,47 @@ func Test_CCIPMessageLimitations(t *testing.T) {
require.NoError(t, err)
t.Logf("0->1 destination config: %+v", chain0DestConfig)

testMsgs := []struct {
name string
fromChain uint64
toChain uint64
msg router.ClientEVM2AnyMessage
expRevert bool
}{
testSetup := mlt.NewTestSetupWithDeployedEnv(
t,
testEnv,
onChainState,
chains[0],
chains[1],
srcToken.Address(),
chain0DestConfig,
false, // testRouter
true, // validateResp
)

tcs := []mlt.TestCase{
{
name: "hit limit on data",
fromChain: chains[0],
toChain: chains[1],
msg: router.ClientEVM2AnyMessage{
Receiver: common.LeftPadBytes(onChainState.Chains[chains[1]].Receiver.Address().Bytes(), 32),
Data: []byte(strings.Repeat("0", int(chain0DestConfig.MaxDataBytes))),
TestSetup: testSetup,
Name: "hit limit on data",
Msg: router.ClientEVM2AnyMessage{
Receiver: common.LeftPadBytes(onChainState.Chains[testSetup.DestChain].Receiver.Address().Bytes(), 32),
Data: []byte(strings.Repeat("0", int(testSetup.SrcFeeQuoterDestChainConfig.MaxDataBytes))),
FeeToken: common.HexToAddress("0x0"),
},
},
{
name: "hit limit on tokens",
fromChain: chains[0],
toChain: chains[1],
msg: router.ClientEVM2AnyMessage{
Receiver: common.LeftPadBytes(onChainState.Chains[chains[1]].Receiver.Address().Bytes(), 32),
TestSetup: testSetup,
Name: "hit limit on tokens",
Msg: router.ClientEVM2AnyMessage{
Receiver: common.LeftPadBytes(onChainState.Chains[testSetup.DestChain].Receiver.Address().Bytes(), 32),
TokenAmounts: slices.Repeat([]router.ClientEVMTokenAmount{
{Token: srcToken.Address(), Amount: big.NewInt(1)},
}, int(chain0DestConfig.MaxNumberOfTokensPerMsg)),
{Token: testSetup.SrcToken, Amount: big.NewInt(1)},
}, int(testSetup.SrcFeeQuoterDestChainConfig.MaxNumberOfTokensPerMsg)),
FeeToken: common.HexToAddress("0x0"),
},
},
{
name: "hit limit on gas limit",
fromChain: chains[0],
toChain: chains[1],
msg: router.ClientEVM2AnyMessage{
Receiver: common.LeftPadBytes(onChainState.Chains[chains[1]].Receiver.Address().Bytes(), 32),
Data: []byte(strings.Repeat("0", int(chain0DestConfig.MaxDataBytes))),
TestSetup: testSetup,
Name: "hit limit on gas limit",
Msg: router.ClientEVM2AnyMessage{
Receiver: common.LeftPadBytes(onChainState.Chains[testSetup.DestChain].Receiver.Address().Bytes(), 32),
Data: []byte(strings.Repeat("0", int(testSetup.SrcFeeQuoterDestChainConfig.MaxDataBytes))),
FeeToken: common.HexToAddress("0x0"),
ExtraArgs: testhelpers.MakeEVMExtraArgsV2(uint64(chain0DestConfig.MaxPerMsgGasLimit), true),
ExtraArgs: testhelpers.MakeEVMExtraArgsV2(uint64(testSetup.SrcFeeQuoterDestChainConfig.MaxPerMsgGasLimit), true),
},
},
//{ // TODO: exec plugin never executed this message. CCIP-4471
Expand All @@ -101,45 +105,42 @@ func Test_CCIPMessageLimitations(t *testing.T) {
// },
//},
{
name: "exceeding maxDataBytes",
fromChain: chains[0],
toChain: chains[1],
msg: router.ClientEVM2AnyMessage{
Receiver: common.LeftPadBytes(onChainState.Chains[chains[1]].Receiver.Address().Bytes(), 32),
Data: []byte(strings.Repeat("0", int(chain0DestConfig.MaxDataBytes)+1)),
TestSetup: testSetup,
Name: "exceeding maxDataBytes",
Msg: router.ClientEVM2AnyMessage{
Receiver: common.LeftPadBytes(onChainState.Chains[testSetup.DestChain].Receiver.Address().Bytes(), 32),
Data: []byte(strings.Repeat("0", int(testSetup.SrcFeeQuoterDestChainConfig.MaxDataBytes)+1)),
TokenAmounts: []router.ClientEVMTokenAmount{},
FeeToken: common.HexToAddress("0x0"),
ExtraArgs: nil,
},
expRevert: true,
ExpRevert: true,
},
{
name: "exceeding number of tokens",
fromChain: chains[0],
toChain: chains[1],
msg: router.ClientEVM2AnyMessage{
Receiver: common.LeftPadBytes(onChainState.Chains[chains[1]].Receiver.Address().Bytes(), 32),
TestSetup: testSetup,
Name: "exceeding number of tokens",
Msg: router.ClientEVM2AnyMessage{
Receiver: common.LeftPadBytes(onChainState.Chains[testSetup.DestChain].Receiver.Address().Bytes(), 32),
Data: []byte("abc"),
TokenAmounts: slices.Repeat([]router.ClientEVMTokenAmount{
{Token: srcToken.Address(), Amount: big.NewInt(1)},
}, int(chain0DestConfig.MaxNumberOfTokensPerMsg)+1),
{Token: testSetup.SrcToken, Amount: big.NewInt(1)},
}, int(testSetup.SrcFeeQuoterDestChainConfig.MaxNumberOfTokensPerMsg)+1),
FeeToken: common.HexToAddress("0x0"),
ExtraArgs: nil,
},
expRevert: true,
ExpRevert: true,
},
{
name: "exceeding gas limit",
fromChain: chains[0],
toChain: chains[1],
msg: router.ClientEVM2AnyMessage{
Receiver: common.LeftPadBytes(onChainState.Chains[chains[1]].Receiver.Address().Bytes(), 32),
TestSetup: testSetup,
Name: "exceeding gas limit",
Msg: router.ClientEVM2AnyMessage{
Receiver: common.LeftPadBytes(onChainState.Chains[testSetup.DestChain].Receiver.Address().Bytes(), 32),
Data: []byte("abc"),
TokenAmounts: []router.ClientEVMTokenAmount{},
FeeToken: common.HexToAddress("0x0"),
ExtraArgs: testhelpers.MakeEVMExtraArgsV2(uint64(chain0DestConfig.MaxPerMsgGasLimit)+1, true),
ExtraArgs: testhelpers.MakeEVMExtraArgsV2(uint64(testSetup.SrcFeeQuoterDestChainConfig.MaxPerMsgGasLimit)+1, true),
},
expRevert: true,
ExpRevert: true,
},
}

Expand All @@ -148,36 +149,22 @@ func Test_CCIPMessageLimitations(t *testing.T) {
// Send a message from each chain to every other chain.
expectedSeqNum := make(map[testhelpers.SourceDestPair]uint64)
expectedSeqNumExec := make(map[testhelpers.SourceDestPair][]uint64)
for _, msg := range testMsgs {
t.Logf("Sending msg: %s", msg.name)
require.NotEqual(t, msg.fromChain, msg.toChain, "fromChain and toChain cannot be the same")
startBlocks[msg.toChain] = nil
msgSentEvent, err := testhelpers.DoSendRequest(
t, testEnv.Env, onChainState,
testhelpers.WithSourceChain(msg.fromChain),
testhelpers.WithDestChain(msg.toChain),
testhelpers.WithTestRouter(false),
testhelpers.WithEvm2AnyMessage(msg.msg))

if msg.expRevert {
t.Logf("Message reverted as expected")
require.Error(t, err)
require.Contains(t, err.Error(), "execution reverted")
continue
}
require.NoError(t, err)
for _, tc := range tcs {
startBlocks[tc.DestChain] = nil

t.Logf("Message not reverted as expected")
tco := mlt.Run(tc)

expectedSeqNum[testhelpers.SourceDestPair{
SourceChainSelector: msg.fromChain,
DestChainSelector: msg.toChain,
}] = msgSentEvent.SequenceNumber
if tco.MsgSentEvent != nil {
expectedSeqNum[testhelpers.SourceDestPair{
SourceChainSelector: tc.SrcChain,
DestChainSelector: tc.DestChain,
}] = tco.MsgSentEvent.SequenceNumber

expectedSeqNumExec[testhelpers.SourceDestPair{
SourceChainSelector: msg.fromChain,
DestChainSelector: msg.toChain,
}] = []uint64{msgSentEvent.SequenceNumber}
expectedSeqNumExec[testhelpers.SourceDestPair{
SourceChainSelector: tc.SrcChain,
DestChainSelector: tc.DestChain,
}] = []uint64{tco.MsgSentEvent.SequenceNumber}
}
}

// Wait for all commit reports to land.
Expand Down
Loading