From 8591f46eae8aa78165eee1e6ac383421982982ac Mon Sep 17 00:00:00 2001 From: Makram Kamaleddine Date: Thu, 14 Nov 2024 17:39:12 +0400 Subject: [PATCH 1/4] integration-tests/smoke: add manual exec test Manually execute the message that failed to execute due to low callback gas. This is the first manual exec scenario, others will be covered in future PRs. --- deployment/ccip/add_lane_test.go | 14 +- .../ccip/changeset/active_candidate_test.go | 4 +- deployment/ccip/changeset/add_chain_test.go | 6 +- .../ccip/changeset/initial_deploy_test.go | 4 +- deployment/ccip/test_helpers.go | 33 +-- .../smoke/ccip_messaging_test.go | 205 ++++++++++++++++-- integration-tests/smoke/ccip_rmn_test.go | 6 +- integration-tests/smoke/ccip_test.go | 12 +- 8 files changed, 224 insertions(+), 60 deletions(-) diff --git a/deployment/ccip/add_lane_test.go b/deployment/ccip/add_lane_test.go index 02fea79c911..40fa5455118 100644 --- a/deployment/ccip/add_lane_test.go +++ b/deployment/ccip/add_lane_test.go @@ -96,14 +96,14 @@ func TestAddLane(t *testing.T) { startBlock := latesthdr.Number.Uint64() // Send traffic on the first lane and it should not be processed by the plugin as onRamp is disabled // we will check this by confirming that the message is not executed by the end of the test - seqNum1 := TestSendRequest(t, e.Env, state, chain1, chain2, false, router.ClientEVM2AnyMessage{ + msgSentEvent1 := TestSendRequest(t, e.Env, state, chain1, chain2, false, router.ClientEVM2AnyMessage{ Receiver: common.LeftPadBytes(state.Chains[chain2].Receiver.Address().Bytes(), 32), Data: []byte("hello world"), TokenAmounts: nil, FeeToken: common.HexToAddress("0x0"), ExtraArgs: nil, }) - require.Equal(t, uint64(1), seqNum1) + require.Equal(t, uint64(1), msgSentEvent1.SequenceNumber) // Add another lane require.NoError(t, AddLane(e.Env, state, chain2, chain1)) @@ -112,18 +112,18 @@ func TestAddLane(t *testing.T) { latesthdr, err = e.Env.Chains[chain1].Client.HeaderByNumber(testcontext.Get(t), nil) require.NoError(t, err) startBlock2 := latesthdr.Number.Uint64() - seqNum2 := TestSendRequest(t, e.Env, state, chain2, chain1, false, router.ClientEVM2AnyMessage{ + msgSentEvent2 := TestSendRequest(t, e.Env, state, chain2, chain1, false, router.ClientEVM2AnyMessage{ Receiver: common.LeftPadBytes(state.Chains[chain2].Receiver.Address().Bytes(), 32), Data: []byte("hello world"), TokenAmounts: nil, FeeToken: common.HexToAddress("0x0"), ExtraArgs: nil, }) - require.Equal(t, uint64(1), seqNum2) - require.NoError(t, commonutils.JustError(ConfirmExecWithSeqNr(t, e.Env.Chains[chain2], e.Env.Chains[chain1], state.Chains[chain1].OffRamp, &startBlock2, seqNum2))) + require.Equal(t, uint64(1), msgSentEvent2.SequenceNumber) + require.NoError(t, commonutils.JustError(ConfirmExecWithSeqNr(t, e.Env.Chains[chain2], e.Env.Chains[chain1], state.Chains[chain1].OffRamp, &startBlock2, msgSentEvent2.SequenceNumber))) // now check for the previous message from chain 1 to chain 2 that it has not been executed till now as the onRamp was disabled - ConfirmNoExecConsistentlyWithSeqNr(t, e.Env.Chains[chain1], e.Env.Chains[chain2], state.Chains[chain2].OffRamp, seqNum1, 30*time.Second) + ConfirmNoExecConsistentlyWithSeqNr(t, e.Env.Chains[chain1], e.Env.Chains[chain2], state.Chains[chain2].OffRamp, msgSentEvent1.SequenceNumber, 30*time.Second) // enable the onRamp on OffRamp enableRampTx, err := state.Chains[chain2].OffRamp.ApplySourceChainConfigUpdates(e.Env.Chains[chain2].DeployerKey, []offramp.OffRampSourceChainConfigArgs{ @@ -146,5 +146,5 @@ func TestAddLane(t *testing.T) { ReplayLogs(t, e.Env.Offchain, replayBlocks) time.Sleep(30 * time.Second) // Now that the onRamp is enabled, the request should be processed - require.NoError(t, commonutils.JustError(ConfirmExecWithSeqNr(t, e.Env.Chains[chain1], e.Env.Chains[chain2], state.Chains[chain2].OffRamp, &startBlock, seqNum1))) + require.NoError(t, commonutils.JustError(ConfirmExecWithSeqNr(t, e.Env.Chains[chain1], e.Env.Chains[chain2], state.Chains[chain2].OffRamp, &startBlock, msgSentEvent1.SequenceNumber))) } diff --git a/deployment/ccip/changeset/active_candidate_test.go b/deployment/ccip/changeset/active_candidate_test.go index 9daf383c971..c64f7bf8c9f 100644 --- a/deployment/ccip/changeset/active_candidate_test.go +++ b/deployment/ccip/changeset/active_candidate_test.go @@ -84,14 +84,14 @@ func TestActiveCandidate(t *testing.T) { require.NoError(t, err) block := latesthdr.Number.Uint64() startBlocks[dest] = &block - seqNum := ccdeploy.TestSendRequest(t, e, state, src, dest, false, router.ClientEVM2AnyMessage{ + msgSentEvent := ccdeploy.TestSendRequest(t, e, state, src, dest, false, router.ClientEVM2AnyMessage{ Receiver: common.LeftPadBytes(state.Chains[dest].Receiver.Address().Bytes(), 32), Data: []byte("hello world"), TokenAmounts: nil, FeeToken: common.HexToAddress("0x0"), ExtraArgs: nil, }) - expectedSeqNum[dest] = seqNum + expectedSeqNum[dest] = msgSentEvent.SequenceNumber } } diff --git a/deployment/ccip/changeset/add_chain_test.go b/deployment/ccip/changeset/add_chain_test.go index 6a87bdd0a0a..04fa8a71ad9 100644 --- a/deployment/ccip/changeset/add_chain_test.go +++ b/deployment/ccip/changeset/add_chain_test.go @@ -212,7 +212,7 @@ func TestAddChainInbound(t *testing.T) { latesthdr, err := e.Env.Chains[newChain].Client.HeaderByNumber(testcontext.Get(t), nil) require.NoError(t, err) startBlock := latesthdr.Number.Uint64() - seqNr := ccipdeployment.TestSendRequest(t, e.Env, state, initialDeploy[0], newChain, true, router.ClientEVM2AnyMessage{ + msgSentEvent := ccipdeployment.TestSendRequest(t, e.Env, state, initialDeploy[0], newChain, true, router.ClientEVM2AnyMessage{ Receiver: common.LeftPadBytes(state.Chains[newChain].Receiver.Address().Bytes(), 32), Data: []byte("hello world"), TokenAmounts: nil, @@ -222,10 +222,10 @@ func TestAddChainInbound(t *testing.T) { require.NoError(t, ccipdeployment.ConfirmCommitWithExpectedSeqNumRange(t, e.Env.Chains[initialDeploy[0]], e.Env.Chains[newChain], state.Chains[newChain].OffRamp, &startBlock, cciptypes.SeqNumRange{ cciptypes.SeqNum(1), - cciptypes.SeqNum(seqNr), + cciptypes.SeqNum(msgSentEvent.SequenceNumber), })) require.NoError(t, - commonutils.JustError(ccipdeployment.ConfirmExecWithSeqNr(t, e.Env.Chains[initialDeploy[0]], e.Env.Chains[newChain], state.Chains[newChain].OffRamp, &startBlock, seqNr))) + commonutils.JustError(ccipdeployment.ConfirmExecWithSeqNr(t, e.Env.Chains[initialDeploy[0]], e.Env.Chains[newChain], state.Chains[newChain].OffRamp, &startBlock, msgSentEvent.SequenceNumber))) linkAddress := state.Chains[newChain].LinkToken.Address() feeQuoter := state.Chains[newChain].FeeQuoter diff --git a/deployment/ccip/changeset/initial_deploy_test.go b/deployment/ccip/changeset/initial_deploy_test.go index b7dbdfcc972..4d3c070ec45 100644 --- a/deployment/ccip/changeset/initial_deploy_test.go +++ b/deployment/ccip/changeset/initial_deploy_test.go @@ -74,14 +74,14 @@ func TestInitialDeploy(t *testing.T) { require.NoError(t, err) block := latesthdr.Number.Uint64() startBlocks[dest] = &block - seqNum := ccdeploy.TestSendRequest(t, e, state, src, dest, false, router.ClientEVM2AnyMessage{ + msgSentEvent := ccdeploy.TestSendRequest(t, e, state, src, dest, false, router.ClientEVM2AnyMessage{ Receiver: common.LeftPadBytes(state.Chains[dest].Receiver.Address().Bytes(), 32), Data: []byte("hello"), TokenAmounts: nil, FeeToken: common.HexToAddress("0x0"), ExtraArgs: nil, }) - expectedSeqNum[dest] = seqNum + expectedSeqNum[dest] = msgSentEvent.SequenceNumber } } diff --git a/deployment/ccip/test_helpers.go b/deployment/ccip/test_helpers.go index f12a475bc2f..79210e5f188 100644 --- a/deployment/ccip/test_helpers.go +++ b/deployment/ccip/test_helpers.go @@ -42,6 +42,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/burn_mint_token_pool" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/mock_v3_aggregator_contract" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/onramp" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/aggregator_v3_interface" ) @@ -262,7 +263,7 @@ func TestSendRequest( src, dest uint64, testRouter bool, evm2AnyMessage router.ClientEVM2AnyMessage, -) (seqNum uint64) { +) (msgSentEvent *onramp.OnRampCCIPMessageSent) { t.Logf("Sending CCIP request from chain selector %d to chain selector %d", src, dest) tx, blockNum, err := CCIPSendRequest( @@ -280,12 +281,16 @@ func TestSendRequest( }, []uint64{dest}, []uint64{}) require.NoError(t, err) require.True(t, it.Next()) - seqNum = it.Event.Message.Header.SequenceNumber - nonce := it.Event.Message.Header.Nonce - sender := it.Event.Message.Sender - t.Logf("CCIP message sent from chain selector %d to chain selector %d tx %s seqNum %d nonce %d sender %s", - src, dest, tx.Hash().String(), seqNum, nonce, sender.String()) - return seqNum + t.Logf("CCIP message (id %x) sent from chain selector %d to chain selector %d tx %s seqNum %d nonce %d sender %s", + it.Event.Message.Header.MessageId[:], + src, + dest, + tx.Hash().String(), + it.Event.SequenceNumber, + it.Event.Message.Header.Nonce, + it.Event.Message.Sender.String(), + ) + return it.Event } // MakeEVMExtraArgsV2 creates the extra args for the EVM2Any message that is destined @@ -440,23 +445,23 @@ func ConfirmRequestOnSourceAndDest(t *testing.T, env deployment.Environment, sta require.NoError(t, err) startBlock := latesthdr.Number.Uint64() fmt.Printf("startblock %d", startBlock) - seqNum := TestSendRequest(t, env, state, sourceCS, destCS, false, router.ClientEVM2AnyMessage{ + msgSentEvent := TestSendRequest(t, env, state, sourceCS, destCS, false, router.ClientEVM2AnyMessage{ Receiver: common.LeftPadBytes(state.Chains[destCS].Receiver.Address().Bytes(), 32), Data: []byte("hello world"), TokenAmounts: nil, FeeToken: common.HexToAddress("0x0"), ExtraArgs: nil, }) - require.Equal(t, expectedSeqNr, seqNum) + require.Equal(t, expectedSeqNr, msgSentEvent.SequenceNumber) - fmt.Printf("Request sent for seqnr %d", seqNum) + fmt.Printf("Request sent for seqnr %d", msgSentEvent.SequenceNumber) require.NoError(t, ConfirmCommitWithExpectedSeqNumRange(t, env.Chains[sourceCS], env.Chains[destCS], state.Chains[destCS].OffRamp, &startBlock, cciptypes.SeqNumRange{ - cciptypes.SeqNum(seqNum), - cciptypes.SeqNum(seqNum), + cciptypes.SeqNum(msgSentEvent.SequenceNumber), + cciptypes.SeqNum(msgSentEvent.SequenceNumber), })) - fmt.Printf("Commit confirmed for seqnr %d", seqNum) + fmt.Printf("Commit confirmed for seqnr %d", msgSentEvent.SequenceNumber) require.NoError( t, commonutils.JustError( @@ -466,7 +471,7 @@ func ConfirmRequestOnSourceAndDest(t *testing.T, env deployment.Environment, sta env.Chains[destCS], state.Chains[destCS].OffRamp, &startBlock, - seqNum, + msgSentEvent.SequenceNumber, ), ), ) diff --git a/integration-tests/smoke/ccip_messaging_test.go b/integration-tests/smoke/ccip_messaging_test.go index 55309598c8c..f021a937444 100644 --- a/integration-tests/smoke/ccip_messaging_test.go +++ b/integration-tests/smoke/ccip_messaging_test.go @@ -1,6 +1,8 @@ package smoke import ( + "context" + "math/big" "testing" "time" @@ -9,13 +11,16 @@ import ( "github.com/stretchr/testify/require" "golang.org/x/exp/maps" + "github.com/smartcontractkit/chainlink-common/pkg/hashutil" + "github.com/smartcontractkit/chainlink-common/pkg/merklemulti" "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" jobv1 "github.com/smartcontractkit/chainlink-protos/job-distributor/v1/job" "github.com/smartcontractkit/chainlink/deployment" ccdeploy "github.com/smartcontractkit/chainlink/deployment/ccip" - ccipdeployment "github.com/smartcontractkit/chainlink/deployment/ccip" "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" "github.com/smartcontractkit/chainlink/integration-tests/ccip-tests/testsetups" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/offramp" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/onramp" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router" "github.com/smartcontractkit/chainlink/v2/core/logger" ) @@ -23,8 +28,8 @@ import ( type testCaseSetup struct { t *testing.T sender []byte - deployedEnv ccipdeployment.DeployedEnv - onchainState ccipdeployment.CCIPOnChainState + deployedEnv ccdeploy.DeployedEnv + onchainState ccdeploy.CCIPOnChainState sourceChain, destChain uint64 } @@ -35,8 +40,9 @@ type messagingTestCase struct { } type messagingTestCaseOutput struct { - replayed bool - nonce uint64 + replayed bool + nonce uint64 + msgSentEvent *onramp.OnRampCCIPMessageSent } func Test_CCIPMessaging(t *testing.T) { @@ -59,7 +65,7 @@ func Test_CCIPMessaging(t *testing.T) { ", dest chain selector:", destChain, ) - tokenConfig := ccipdeployment.NewTestTokenConfig(state.Chains[e.FeedChainSel].USDFeeds) + tokenConfig := ccdeploy.NewTestTokenConfig(state.Chains[e.FeedChainSel].USDFeeds) // Apply migration output, err := changeset.InitialDeploy(e.Env, ccdeploy.DeployCCIPContractConfig{ HomeChainSel: e.HomeChainSel, @@ -92,7 +98,7 @@ func Test_CCIPMessaging(t *testing.T) { } // connect a single lane, source to dest - require.NoError(t, ccipdeployment.AddLane(e.Env, state, sourceChain, destChain)) + require.NoError(t, ccdeploy.AddLane(e.Env, state, sourceChain, destChain)) var ( replayed bool @@ -117,8 +123,8 @@ func Test_CCIPMessaging(t *testing.T) { }, common.HexToAddress("0xdead"), []byte("hello eoa"), - nil, // default extraArgs - ccipdeployment.EXECUTION_STATE_SUCCESS, // success because offRamp won't call an EOA + nil, // default extraArgs + ccdeploy.EXECUTION_STATE_SUCCESS, // success because offRamp won't call an EOA ) }) @@ -131,8 +137,8 @@ func Test_CCIPMessaging(t *testing.T) { }, state.Chains[destChain].FeeQuoter.Address(), []byte("hello FeeQuoter"), - nil, // default extraArgs - ccipdeployment.EXECUTION_STATE_SUCCESS, // success because offRamp won't call a contract not implementing CCIPReceiver + nil, // default extraArgs + ccdeploy.EXECUTION_STATE_SUCCESS, // success because offRamp won't call a contract not implementing CCIPReceiver ) }) @@ -146,7 +152,7 @@ func Test_CCIPMessaging(t *testing.T) { state.Chains[destChain].Receiver.Address(), []byte("hello CCIPReceiver"), nil, // default extraArgs - ccipdeployment.EXECUTION_STATE_SUCCESS, + ccdeploy.EXECUTION_STATE_SUCCESS, func(t *testing.T) { iter, err := state.Chains[destChain].Receiver.FilterMessageReceived(nil) require.NoError(t, err) @@ -165,18 +171,159 @@ func Test_CCIPMessaging(t *testing.T) { }, state.Chains[destChain].Receiver.Address(), []byte("hello CCIPReceiver with low exec gas"), - ccipdeployment.MakeEVMExtraArgsV2(1, false), // 1 gas is too low. - ccipdeployment.EXECUTION_STATE_FAILURE, // state would be failed onchain due to low gas + ccdeploy.MakeEVMExtraArgsV2(1, false), // 1 gas is too low. + ccdeploy.EXECUTION_STATE_FAILURE, // state would be failed onchain due to low gas ) + + manuallyExecute(t, ctx, state, destChain, out, sourceChain, e, sender) + + t.Logf("successfully manually executed message %x", + out.msgSentEvent.Message.Header.MessageId) }) } -func sleepAndReplay(t *testing.T, e ccipdeployment.DeployedEnv, sourceChain, destChain uint64) { +func manuallyExecute( + t *testing.T, + ctx context.Context, + state ccdeploy.CCIPOnChainState, + destChain uint64, + out messagingTestCaseOutput, + sourceChain uint64, + e ccdeploy.DeployedEnv, + sender []byte, +) { + merkleRoot := getMerkleRoot( + t, + state.Chains[destChain].OffRamp, + out.msgSentEvent.SequenceNumber, + ) + messageHash := getMessageHash( + t, + state.Chains[destChain].OffRamp, + sourceChain, + out.msgSentEvent.SequenceNumber, + out.msgSentEvent.Message.Header.MessageId, + ) + tree, err := merklemulti.NewTree(hashutil.NewKeccak(), [][32]byte{messageHash}) + require.NoError(t, err) + proof, err := tree.Prove([]int{0}) + require.NoError(t, err) + require.Equal(t, merkleRoot, tree.Root()) + + tx, err := state.Chains[destChain].OffRamp.ManuallyExecute( + e.Env.Chains[destChain].DeployerKey, + []offramp.InternalExecutionReport{ + { + SourceChainSelector: sourceChain, + Messages: []offramp.InternalAny2EVMRampMessage{ + { + Header: offramp.InternalRampMessageHeader{ + MessageId: out.msgSentEvent.Message.Header.MessageId, + SourceChainSelector: sourceChain, + DestChainSelector: destChain, + SequenceNumber: out.msgSentEvent.SequenceNumber, + Nonce: out.msgSentEvent.Message.Header.Nonce, + }, + Sender: sender, + Data: []byte("hello CCIPReceiver with low exec gas"), + Receiver: state.Chains[destChain].Receiver.Address(), + GasLimit: big.NewInt(1), + TokenAmounts: []offramp.InternalAny2EVMTokenTransfer{}, + }, + }, + OffchainTokenData: [][][]byte{ + {}, + }, + Proofs: proof.Hashes, + ProofFlagBits: boolsToBitFlags(proof.SourceFlags), + }, + }, + [][]offramp.OffRampGasLimitOverride{ + { + { + ReceiverExecutionGasLimit: big.NewInt(200_000), + TokenGasOverrides: nil, + }, + }, + }, + ) + _, err = deployment.ConfirmIfNoError(e.Env.Chains[destChain], tx, err) + require.NoError(t, err, "failed to send/confirm manuallyExecute tx") + + receipt, err := e.Env.Chains[destChain].Client.TransactionReceipt(ctx, tx.Hash()) + require.NoError(t, err) + + var found bool + for _, lg := range receipt.Logs { + topic := offramp.OffRampExecutionStateChanged{}.Topic() + if lg.Topics[0] == topic { + + parsed, err := state.Chains[destChain].OffRamp.ParseExecutionStateChanged(*lg) + require.NoError(t, err) + + require.Equal(t, sourceChain, parsed.SourceChainSelector) + require.Equal(t, out.msgSentEvent.SequenceNumber, parsed.SequenceNumber) + require.Equal(t, out.msgSentEvent.Message.Header.MessageId, parsed.MessageId) + require.Equal(t, messageHash, parsed.MessageHash) + require.Equal(t, uint8(ccdeploy.EXECUTION_STATE_SUCCESS), parsed.State) + found = true + } + } + require.True(t, found, "no ExecutionStateChanged event found in manual execution receipt logs") +} + +func getMerkleRoot( + t *testing.T, + offRamp *offramp.OffRamp, + seqNr uint64, +) (merkleRoot [32]byte) { + iter, err := offRamp.FilterCommitReportAccepted(nil) + require.NoError(t, err) + for iter.Next() { + for _, mr := range iter.Event.MerkleRoots { + if mr.MinSeqNr >= seqNr || mr.MaxSeqNr <= seqNr { + merkleRoot = mr.MerkleRoot + break + } + } + } + require.NotEqualf( + t, + [32]byte{}, + merkleRoot, + "no merkle root found for sequence number %d", + seqNr, + ) + return merkleRoot +} + +func getMessageHash( + t *testing.T, + offRamp *offramp.OffRamp, + sourceChainSelector, + seqNr uint64, + msgID [32]byte, +) (messageHash [32]byte) { + iter, err := offRamp.FilterExecutionStateChanged(nil, + []uint64{sourceChainSelector}, + []uint64{seqNr}, + [][32]byte{msgID}, + ) + require.NoError(t, err) + require.True(t, iter.Next()) + require.Equal(t, sourceChainSelector, iter.Event.SourceChainSelector) + require.Equal(t, seqNr, iter.Event.SequenceNumber) + require.Equal(t, msgID, iter.Event.MessageId) + + return iter.Event.MessageHash +} + +func sleepAndReplay(t *testing.T, e ccdeploy.DeployedEnv, sourceChain, destChain uint64) { time.Sleep(30 * time.Second) replayBlocks := make(map[uint64]uint64) replayBlocks[sourceChain] = 1 replayBlocks[destChain] = 1 - ccipdeployment.ReplayLogs(t, e.Env.Offchain, replayBlocks) + ccdeploy.ReplayLogs(t, e.Env.Offchain, replayBlocks) } func runMessagingTestCase( @@ -195,7 +342,7 @@ func runMessagingTestCase( require.Equal(tc.t, tc.nonce, latestNonce) startBlocks := make(map[uint64]*uint64) - seqNum := ccipdeployment.TestSendRequest(tc.t, tc.deployedEnv.Env, tc.onchainState, tc.sourceChain, tc.destChain, false, router.ClientEVM2AnyMessage{ + msgSentEvent := ccdeploy.TestSendRequest(tc.t, tc.deployedEnv.Env, tc.onchainState, tc.sourceChain, tc.destChain, false, router.ClientEVM2AnyMessage{ Receiver: common.LeftPadBytes(receiver.Bytes(), 32), Data: msgData, TokenAmounts: nil, @@ -203,7 +350,8 @@ func runMessagingTestCase( ExtraArgs: extraArgs, }) expectedSeqNum := make(map[uint64]uint64) - expectedSeqNum[tc.destChain] = seqNum + expectedSeqNum[tc.destChain] = msgSentEvent.SequenceNumber + out.msgSentEvent = msgSentEvent // hack if !tc.replayed { @@ -211,17 +359,17 @@ func runMessagingTestCase( out.replayed = true } - ccipdeployment.ConfirmCommitForAllWithExpectedSeqNums(tc.t, tc.deployedEnv.Env, tc.onchainState, expectedSeqNum, startBlocks) - execStates := ccipdeployment.ConfirmExecWithSeqNrForAll(tc.t, tc.deployedEnv.Env, tc.onchainState, expectedSeqNum, startBlocks) + ccdeploy.ConfirmCommitForAllWithExpectedSeqNums(tc.t, tc.deployedEnv.Env, tc.onchainState, expectedSeqNum, startBlocks) + execStates := ccdeploy.ConfirmExecWithSeqNrForAll(tc.t, tc.deployedEnv.Env, tc.onchainState, expectedSeqNum, startBlocks) require.Equalf( tc.t, expectedExecutionState, - execStates[seqNum], + execStates[msgSentEvent.SequenceNumber], "wrong execution state for seq nr %d, expected %d, got %d", - seqNum, + msgSentEvent.SequenceNumber, expectedExecutionState, - execStates[seqNum], + execStates[msgSentEvent.SequenceNumber], ) // check the sender latestNonce on the dest, should be incremented @@ -239,3 +387,14 @@ func runMessagingTestCase( return } + +// boolsToBitFlags transforms a list of boolean flags to a *big.Int encoded number. +func boolsToBitFlags(bools []bool) *big.Int { + encodedFlags := big.NewInt(0) + for i := 0; i < len(bools); i++ { + if bools[i] { + encodedFlags.SetBit(encodedFlags, i, 1) + } + } + return encodedFlags +} diff --git a/integration-tests/smoke/ccip_rmn_test.go b/integration-tests/smoke/ccip_rmn_test.go index d058b3c0e72..7372e10550c 100644 --- a/integration-tests/smoke/ccip_rmn_test.go +++ b/integration-tests/smoke/ccip_rmn_test.go @@ -361,15 +361,15 @@ func runRmnTestCase(t *testing.T, tc rmnTestCase) { toChain := chainSelectors[msg.toChainIdx] for i := 0; i < msg.count; i++ { - seqNum := ccipdeployment.TestSendRequest(t, envWithRMN.Env, onChainState, fromChain, toChain, false, router.ClientEVM2AnyMessage{ + msgSentEvent := ccipdeployment.TestSendRequest(t, envWithRMN.Env, onChainState, fromChain, toChain, false, router.ClientEVM2AnyMessage{ Receiver: common.LeftPadBytes(onChainState.Chains[toChain].Receiver.Address().Bytes(), 32), Data: []byte("hello world"), TokenAmounts: nil, FeeToken: common.HexToAddress("0x0"), ExtraArgs: nil, }) - expectedSeqNum[toChain] = seqNum - t.Logf("Sent message from chain %d to chain %d with seqNum %d", fromChain, toChain, seqNum) + expectedSeqNum[toChain] = msgSentEvent.SequenceNumber + t.Logf("Sent message from chain %d to chain %d with seqNum %d", fromChain, toChain, msgSentEvent.SequenceNumber) } zero := uint64(0) diff --git a/integration-tests/smoke/ccip_test.go b/integration-tests/smoke/ccip_test.go index 5b0ba285527..0e021b04b85 100644 --- a/integration-tests/smoke/ccip_test.go +++ b/integration-tests/smoke/ccip_test.go @@ -84,14 +84,14 @@ func TestInitialDeployOnLocal(t *testing.T) { require.NoError(t, err) block := latesthdr.Number.Uint64() startBlocks[dest] = &block - seqNum := ccdeploy.TestSendRequest(t, e, state, src, dest, false, router.ClientEVM2AnyMessage{ + msgSentEvent := ccdeploy.TestSendRequest(t, e, state, src, dest, false, router.ClientEVM2AnyMessage{ Receiver: common.LeftPadBytes(state.Chains[dest].Receiver.Address().Bytes(), 32), Data: []byte("hello world"), TokenAmounts: nil, FeeToken: common.HexToAddress("0x0"), ExtraArgs: nil, }) - expectedSeqNum[dest] = seqNum + expectedSeqNum[dest] = msgSentEvent.SequenceNumber } } @@ -236,23 +236,23 @@ func TestTokenTransfer(t *testing.T) { feeToken = common.HexToAddress("0x0") ) if src == tenv.HomeChainSel && dest == tenv.FeedChainSel { - seqNum := ccdeploy.TestSendRequest(t, e, state, src, dest, false, router.ClientEVM2AnyMessage{ + msgSentEvent := ccdeploy.TestSendRequest(t, e, state, src, dest, false, router.ClientEVM2AnyMessage{ Receiver: receiver, Data: data, TokenAmounts: tokens[src], FeeToken: feeToken, ExtraArgs: nil, }) - expectedSeqNum[dest] = seqNum + expectedSeqNum[dest] = msgSentEvent.SequenceNumber } else { - seqNum := ccdeploy.TestSendRequest(t, e, state, src, dest, false, router.ClientEVM2AnyMessage{ + msgSentEvent := ccdeploy.TestSendRequest(t, e, state, src, dest, false, router.ClientEVM2AnyMessage{ Receiver: receiver, Data: data, TokenAmounts: nil, FeeToken: feeToken, ExtraArgs: nil, }) - expectedSeqNum[dest] = seqNum + expectedSeqNum[dest] = msgSentEvent.SequenceNumber } } } From eefe926e4e0102929a36a1b738c1edd300768b98 Mon Sep 17 00:00:00 2001 From: Makram Kamaleddine Date: Thu, 14 Nov 2024 19:05:41 +0400 Subject: [PATCH 2/4] fix lint --- integration-tests/smoke/ccip_messaging_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/integration-tests/smoke/ccip_messaging_test.go b/integration-tests/smoke/ccip_messaging_test.go index f021a937444..85fab263578 100644 --- a/integration-tests/smoke/ccip_messaging_test.go +++ b/integration-tests/smoke/ccip_messaging_test.go @@ -175,7 +175,7 @@ func Test_CCIPMessaging(t *testing.T) { ccdeploy.EXECUTION_STATE_FAILURE, // state would be failed onchain due to low gas ) - manuallyExecute(t, ctx, state, destChain, out, sourceChain, e, sender) + manuallyExecute(ctx, t, state, destChain, out, sourceChain, e, sender) t.Logf("successfully manually executed message %x", out.msgSentEvent.Message.Header.MessageId) @@ -183,8 +183,8 @@ func Test_CCIPMessaging(t *testing.T) { } func manuallyExecute( - t *testing.T, ctx context.Context, + t *testing.T, state ccdeploy.CCIPOnChainState, destChain uint64, out messagingTestCaseOutput, From 1dc4bc3a82b872d448baeb727f7640470feaec94 Mon Sep 17 00:00:00 2001 From: Makram Kamaleddine Date: Fri, 15 Nov 2024 10:27:33 +0400 Subject: [PATCH 3/4] updates after PR feedback --- .../smoke/ccip_messaging_test.go | 32 ++++--------------- 1 file changed, 6 insertions(+), 26 deletions(-) diff --git a/integration-tests/smoke/ccip_messaging_test.go b/integration-tests/smoke/ccip_messaging_test.go index 85fab263578..b765fc68d0a 100644 --- a/integration-tests/smoke/ccip_messaging_test.go +++ b/integration-tests/smoke/ccip_messaging_test.go @@ -2,6 +2,7 @@ package smoke import ( "context" + "fmt" "math/big" "testing" "time" @@ -250,26 +251,9 @@ func manuallyExecute( _, err = deployment.ConfirmIfNoError(e.Env.Chains[destChain], tx, err) require.NoError(t, err, "failed to send/confirm manuallyExecute tx") - receipt, err := e.Env.Chains[destChain].Client.TransactionReceipt(ctx, tx.Hash()) + newExecutionState, err := state.Chains[destChain].OffRamp.GetExecutionState(&bind.CallOpts{Context: ctx}, sourceChain, out.msgSentEvent.SequenceNumber) require.NoError(t, err) - - var found bool - for _, lg := range receipt.Logs { - topic := offramp.OffRampExecutionStateChanged{}.Topic() - if lg.Topics[0] == topic { - - parsed, err := state.Chains[destChain].OffRamp.ParseExecutionStateChanged(*lg) - require.NoError(t, err) - - require.Equal(t, sourceChain, parsed.SourceChainSelector) - require.Equal(t, out.msgSentEvent.SequenceNumber, parsed.SequenceNumber) - require.Equal(t, out.msgSentEvent.Message.Header.MessageId, parsed.MessageId) - require.Equal(t, messageHash, parsed.MessageHash) - require.Equal(t, uint8(ccdeploy.EXECUTION_STATE_SUCCESS), parsed.State) - found = true - } - } - require.True(t, found, "no ExecutionStateChanged event found in manual execution receipt logs") + require.Equal(t, uint8(ccdeploy.EXECUTION_STATE_SUCCESS), newExecutionState) } func getMerkleRoot( @@ -282,17 +266,13 @@ func getMerkleRoot( for iter.Next() { for _, mr := range iter.Event.MerkleRoots { if mr.MinSeqNr >= seqNr || mr.MaxSeqNr <= seqNr { - merkleRoot = mr.MerkleRoot - break + return mr.MerkleRoot } } } - require.NotEqualf( + require.Fail( t, - [32]byte{}, - merkleRoot, - "no merkle root found for sequence number %d", - seqNr, + fmt.Sprintf("no merkle root found for seq nr %d", seqNr), ) return merkleRoot } From 78158c25546d580647801633cce85affb4e6ab97 Mon Sep 17 00:00:00 2001 From: Makram Kamaleddine Date: Fri, 15 Nov 2024 15:26:12 +0400 Subject: [PATCH 4/4] use ctx, fill out filteropts --- .../smoke/ccip_messaging_test.go | 33 ++++++++++++++++--- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/integration-tests/smoke/ccip_messaging_test.go b/integration-tests/smoke/ccip_messaging_test.go index b765fc68d0a..67d17ef8742 100644 --- a/integration-tests/smoke/ccip_messaging_test.go +++ b/integration-tests/smoke/ccip_messaging_test.go @@ -144,6 +144,8 @@ func Test_CCIPMessaging(t *testing.T) { }) t.Run("message to contract implementing CCIPReceiver", func(t *testing.T) { + latestHead, err := e.Env.Chains[destChain].Client.HeaderByNumber(ctx, nil) + require.NoError(t, err) out = runMessagingTestCase( messagingTestCase{ testCaseSetup: setup, @@ -155,7 +157,10 @@ func Test_CCIPMessaging(t *testing.T) { nil, // default extraArgs ccdeploy.EXECUTION_STATE_SUCCESS, func(t *testing.T) { - iter, err := state.Chains[destChain].Receiver.FilterMessageReceived(nil) + iter, err := state.Chains[destChain].Receiver.FilterMessageReceived(&bind.FilterOpts{ + Context: ctx, + Start: latestHead.Number.Uint64(), + }) require.NoError(t, err) require.True(t, iter.Next()) // MessageReceived doesn't emit the data unfortunately, so can't check that. @@ -164,6 +169,8 @@ func Test_CCIPMessaging(t *testing.T) { }) t.Run("message to contract implementing CCIPReceiver with low exec gas", func(t *testing.T) { + latestHead, err := e.Env.Chains[destChain].Client.HeaderByNumber(ctx, nil) + require.NoError(t, err) out = runMessagingTestCase( messagingTestCase{ testCaseSetup: setup, @@ -176,7 +183,7 @@ func Test_CCIPMessaging(t *testing.T) { ccdeploy.EXECUTION_STATE_FAILURE, // state would be failed onchain due to low gas ) - manuallyExecute(ctx, t, state, destChain, out, sourceChain, e, sender) + manuallyExecute(ctx, t, latestHead.Number.Uint64(), state, destChain, out, sourceChain, e, sender) t.Logf("successfully manually executed message %x", out.msgSentEvent.Message.Header.MessageId) @@ -186,6 +193,7 @@ func Test_CCIPMessaging(t *testing.T) { func manuallyExecute( ctx context.Context, t *testing.T, + startBlock uint64, state ccdeploy.CCIPOnChainState, destChain uint64, out messagingTestCaseOutput, @@ -194,16 +202,20 @@ func manuallyExecute( sender []byte, ) { merkleRoot := getMerkleRoot( + ctx, t, state.Chains[destChain].OffRamp, out.msgSentEvent.SequenceNumber, + startBlock, ) messageHash := getMessageHash( + ctx, t, state.Chains[destChain].OffRamp, sourceChain, out.msgSentEvent.SequenceNumber, out.msgSentEvent.Message.Header.MessageId, + startBlock, ) tree, err := merklemulti.NewTree(hashutil.NewKeccak(), [][32]byte{messageHash}) require.NoError(t, err) @@ -257,11 +269,16 @@ func manuallyExecute( } func getMerkleRoot( + ctx context.Context, t *testing.T, offRamp *offramp.OffRamp, - seqNr uint64, + seqNr, + startBlock uint64, ) (merkleRoot [32]byte) { - iter, err := offRamp.FilterCommitReportAccepted(nil) + iter, err := offRamp.FilterCommitReportAccepted(&bind.FilterOpts{ + Context: ctx, + Start: startBlock, + }) require.NoError(t, err) for iter.Next() { for _, mr := range iter.Event.MerkleRoots { @@ -278,13 +295,19 @@ func getMerkleRoot( } func getMessageHash( + ctx context.Context, t *testing.T, offRamp *offramp.OffRamp, sourceChainSelector, seqNr uint64, msgID [32]byte, + startBlock uint64, ) (messageHash [32]byte) { - iter, err := offRamp.FilterExecutionStateChanged(nil, + iter, err := offRamp.FilterExecutionStateChanged( + &bind.FilterOpts{ + Context: ctx, + Start: startBlock, + }, []uint64{sourceChainSelector}, []uint64{seqNr}, [][32]byte{msgID},