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

deployment/ccip/changeset: add messaging test #15166

Merged
merged 9 commits into from
Nov 11, 2024
Merged
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
Expand Up @@ -439,7 +439,7 @@ func TestCCIPReader_Nonces(t *testing.T) {
// Add some nonces.
for chain, addrs := range nonces {
for addr, nonce := range addrs {
_, err := s.contract.SetInboundNonce(s.auth, uint64(chain), nonce, addr.Bytes())
_, err := s.contract.SetInboundNonce(s.auth, uint64(chain), nonce, common.LeftPadBytes(addr.Bytes(), 32))
assert.NoError(t, err)
}
}
Expand Down
2 changes: 1 addition & 1 deletion core/scripts/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ require (
github.com/shirou/gopsutil/v3 v3.24.3 // indirect
github.com/smartcontractkit/ccip-owner-contracts v0.0.0-20240926212305-a6deabdfce86 // indirect
github.com/smartcontractkit/chain-selectors v1.0.27 // indirect
github.com/smartcontractkit/chainlink-ccip v0.0.0-20241106140121-4c9ee21ab422 // indirect
github.com/smartcontractkit/chainlink-ccip v0.0.0-20241111114733-aa3b2f8e9f94 // indirect
github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20241017133723-5277829bd53f // indirect
github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20241018134907-a00ba3729b5e // indirect
github.com/smartcontractkit/chainlink-feeds v0.1.1 // indirect
Expand Down
4 changes: 2 additions & 2 deletions core/scripts/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1090,8 +1090,8 @@ github.com/smartcontractkit/chain-selectors v1.0.27 h1:VE/ftX9Aae4gnw67yR1raKi+3
github.com/smartcontractkit/chain-selectors v1.0.27/go.mod h1:d4Hi+E1zqjy9HqMkjBE5q1vcG9VGgxf5VxiRHfzi2kE=
github.com/smartcontractkit/chainlink-automation v0.8.1 h1:sTc9LKpBvcKPc1JDYAmgBc2xpDKBco/Q4h4ydl6+UUU=
github.com/smartcontractkit/chainlink-automation v0.8.1/go.mod h1:Iij36PvWZ6blrdC5A/nrQUBuf3MH3JvsBB9sSyc9W08=
github.com/smartcontractkit/chainlink-ccip v0.0.0-20241106140121-4c9ee21ab422 h1:VfH/AW5NtTmroY9zz6OYCPFbFTqpMyJ2ubgT9ahYf3U=
github.com/smartcontractkit/chainlink-ccip v0.0.0-20241106140121-4c9ee21ab422/go.mod h1:4adKaHNaxFsRvV/lYfqtbsWyyvIPUMLR0FdOJN/ljis=
github.com/smartcontractkit/chainlink-ccip v0.0.0-20241111114733-aa3b2f8e9f94 h1:BeLnOf2KKQpJj9nzfnE7QEg9ZqJ2jy/sbpNYVixVM2Y=
github.com/smartcontractkit/chainlink-ccip v0.0.0-20241111114733-aa3b2f8e9f94/go.mod h1:4adKaHNaxFsRvV/lYfqtbsWyyvIPUMLR0FdOJN/ljis=
github.com/smartcontractkit/chainlink-common v0.3.1-0.20241109002240-af894848b3b4 h1:e+uFsxQ21tMQKRu4oBXKycNzoR30vO/7STBtqtDvQJQ=
github.com/smartcontractkit/chainlink-common v0.3.1-0.20241109002240-af894848b3b4/go.mod h1:ny87uTW6hLjCTLiBqBRNFEhETSXhHWevYlPclT5lSco=
github.com/smartcontractkit/chainlink-cosmos v0.5.2-0.20241017133723-5277829bd53f h1:BwrIaQIx5Iy6eT+DfLhFfK2XqjxRm74mVdlX8gbu4dw=
Expand Down
17 changes: 15 additions & 2 deletions deployment/ccip/add_lane_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (

"github.com/smartcontractkit/chainlink/deployment"
"github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/offramp"
"github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router"
"github.com/smartcontractkit/chainlink/v2/core/logger"
)

Expand Down Expand Up @@ -94,7 +95,13 @@ 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, nil)
seqNum1 := 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)

// Add another lane
Expand All @@ -104,7 +111,13 @@ 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, nil)
seqNum2 := 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, ConfirmExecWithSeqNr(t, e.Env.Chains[chain2], e.Env.Chains[chain1], state.Chains[chain1].OffRamp, &startBlock2, seqNum2))

Expand Down
10 changes: 9 additions & 1 deletion deployment/ccip/changeset/active_candidate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ package changeset
import (
"testing"

"github.com/ethereum/go-ethereum/common"
"github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/mcms"
"github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/timelock"

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

cctypes "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/types"
"github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router"

"github.com/smartcontractkit/chainlink/deployment"

Expand Down Expand Up @@ -82,7 +84,13 @@ 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, nil)
seqNum := 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
}
}
Expand Down
8 changes: 7 additions & 1 deletion deployment/ccip/changeset/add_chain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,13 @@ 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, nil)
seqNr := 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,
FeeToken: common.HexToAddress("0x0"),
ExtraArgs: nil,
})
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),
Expand Down
10 changes: 9 additions & 1 deletion deployment/ccip/changeset/initial_deploy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package changeset
import (
"testing"

"github.com/ethereum/go-ethereum/common"
"github.com/smartcontractkit/chainlink/deployment"

ccdeploy "github.com/smartcontractkit/chainlink/deployment/ccip"
Expand All @@ -11,6 +12,7 @@ import (

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

"github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router"
"github.com/smartcontractkit/chainlink/v2/core/logger"

"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -72,7 +74,13 @@ 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, nil)
seqNum := 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
}
}
Expand Down
209 changes: 209 additions & 0 deletions deployment/ccip/changeset/messaging_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
package changeset

import (
"testing"
"time"

"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/smartcontractkit/chainlink-common/pkg/utils/tests"
"github.com/smartcontractkit/chainlink/deployment"
ccipdeployment "github.com/smartcontractkit/chainlink/deployment/ccip"
"github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router"
"github.com/smartcontractkit/chainlink/v2/core/logger"
"github.com/test-go/testify/require"
"golang.org/x/exp/maps"
)

type testCaseSetup struct {
t *testing.T
sender []byte
deployedEnv ccipdeployment.DeployedEnv
onchainState ccipdeployment.CCIPOnChainState
sourceChain, destChain uint64
}

type messagingTestCase struct {
testCaseSetup
replayed bool
nonce uint64
}

type messagingTestCaseOutput struct {
replayed bool
nonce uint64
}

func Test_Messaging(t *testing.T) {
t.Parallel()

// Setup 2 chains and a single lane.
e := ccipdeployment.NewMemoryEnvironmentWithJobs(t, logger.TestLogger(t), 2, 4)
state, err := ccipdeployment.LoadOnchainState(e.Env)
require.NoError(t, err)

allChainSelectors := maps.Keys(e.Env.Chains)
require.Len(t, allChainSelectors, 2)
sourceChain := allChainSelectors[0]
destChain := allChainSelectors[1]
t.Log("All chain selectors:", allChainSelectors,
", home chain selector:", e.HomeChainSel,
", feed chain selector:", e.FeedChainSel,
", source chain selector:", sourceChain,
", dest chain selector:", destChain,
)

tokenConfig := ccipdeployment.NewTestTokenConfig(state.Chains[e.FeedChainSel].USDFeeds)
newAddresses := deployment.NewMemoryAddressBook()
err = ccipdeployment.DeployCCIPContracts(e.Env, newAddresses, ccipdeployment.DeployCCIPContractConfig{
HomeChainSel: e.HomeChainSel,
FeedChainSel: e.FeedChainSel,
ChainsToDeploy: allChainSelectors,
TokenConfig: tokenConfig,
MCMSConfig: ccipdeployment.NewTestMCMSConfig(t, e.Env),
OCRSecrets: deployment.XXXGenerateTestOCRSecrets(),
})
require.NoError(t, err)
require.NoError(t, e.Env.ExistingAddresses.Merge(newAddresses))
state, err = ccipdeployment.LoadOnchainState(e.Env)
require.NoError(t, err)

// connect a single lane, source to dest
require.NoError(t, ccipdeployment.AddLane(e.Env, state, sourceChain, destChain))

var (
replayed bool
nonce uint64
sender = common.LeftPadBytes(e.Env.Chains[sourceChain].DeployerKey.From.Bytes(), 32)
out messagingTestCaseOutput
setup = testCaseSetup{
t: t,
sender: sender,
deployedEnv: e,
onchainState: state,
sourceChain: sourceChain,
destChain: destChain,
}
)

t.Run("data message to eoa", func(t *testing.T) {
out = runMessagingTestCase(messagingTestCase{
testCaseSetup: setup,
replayed: replayed,
nonce: nonce,
},
common.HexToAddress("0xdead"),
[]byte("hello eoa"),
)
})

t.Run("message to contract not implementing CCIPReceiver", func(t *testing.T) {
out = runMessagingTestCase(
messagingTestCase{
testCaseSetup: setup,
replayed: out.replayed,
nonce: out.nonce,
},
state.Chains[destChain].FeeQuoter.Address(),
[]byte("hello FeeQuoter"),
)
})

t.Run("message to contract implementing CCIPReceiver", func(t *testing.T) {
out = runMessagingTestCase(
messagingTestCase{
testCaseSetup: setup,
replayed: out.replayed,
nonce: out.nonce,
},
state.Chains[destChain].Receiver.Address(),
[]byte("hello CCIPReceiver"),
func(t *testing.T) {
iter, err := state.Chains[destChain].Receiver.FilterMessageReceived(nil)
require.NoError(t, err)
require.True(t, iter.Next())
// MessageReceived doesn't emit the data unfortunately, so can't check that.
},
)
})

t.Run("message to contract implementing CCIPReceiver with low exec gas", func(t *testing.T) {
out = runMessagingTestCase(
messagingTestCase{
testCaseSetup: setup,
replayed: out.replayed,
nonce: out.nonce,
},
state.Chains[destChain].Receiver.Address(),
[]byte("hello CCIPReceiver with low exec gas"),
func(t *testing.T) {
// Message should not be emitted, not enough gas to emit log.
// TODO: this is still returning a log, probably the older one since FAILURE is the execution state.
// Not enough ctx in the message received log to confirm that it's from another test.
// Maybe check the log block number and assert that its < the header before block number from above?
// iter, err := ccipReceiver.FilterMessageReceived(&bind.FilterOpts{
// Start: headerBefore.Number.Uint64(),
// })
// require.NoError(t, err)
// require.False(t, iter.Next(), "MessageReceived should not be emitted in this test case since gas is too low")
},
)
})
}

func sleepAndReplay(t *testing.T, e ccipdeployment.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)
}

func runMessagingTestCase(
tc messagingTestCase,
receiver common.Address,
msgData []byte,
extraAssertions ...func(t *testing.T),
) (out messagingTestCaseOutput) {
// check latest nonce
latestNonce, err := tc.onchainState.Chains[tc.destChain].NonceManager.GetInboundNonce(&bind.CallOpts{
Context: tests.Context(tc.t),
}, tc.sourceChain, tc.sender)
require.NoError(tc.t, err)
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{
Receiver: common.LeftPadBytes(receiver.Bytes(), 32),
Data: msgData,
TokenAmounts: nil,
FeeToken: common.HexToAddress("0x0"),
ExtraArgs: nil,
})
expectedSeqNum := make(map[uint64]uint64)
expectedSeqNum[tc.destChain] = seqNum

// hack
if !tc.replayed {
sleepAndReplay(tc.t, tc.deployedEnv, tc.sourceChain, tc.destChain)
0xnogo marked this conversation as resolved.
Show resolved Hide resolved
out.replayed = true
}

ccipdeployment.ConfirmCommitForAllWithExpectedSeqNums(tc.t, tc.deployedEnv.Env, tc.onchainState, expectedSeqNum, startBlocks)
ccipdeployment.ConfirmExecWithSeqNrForAll(tc.t, tc.deployedEnv.Env, tc.onchainState, expectedSeqNum, startBlocks)

// check the sender latestNonce on the dest, should be incremented
latestNonce, err = tc.onchainState.Chains[tc.destChain].NonceManager.GetInboundNonce(&bind.CallOpts{
Context: tests.Context(tc.t),
}, tc.sourceChain, tc.sender)
require.NoError(tc.t, err)
require.Equal(tc.t, tc.nonce+1, latestNonce)
out.nonce = latestNonce
tc.t.Logf("confirmed nonce bump for sender %x, latestNonce %d", tc.sender, latestNonce)

for _, assertion := range extraAssertions {
assertion(tc.t)
}

return
}
9 changes: 8 additions & 1 deletion deployment/ccip/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -573,8 +573,15 @@ func DeployChainContracts(
tx, err = tokenAdminRegistry.Contract.AddRegistryModule(chain.DeployerKey, customRegistryModule.Address)
if err != nil {
e.Logger.Errorw("Failed to assign registry module on token admin registry", "err", err)
return err
return fmt.Errorf("failed to assign registry module on token admin registry: %w", err)
}

_, err = chain.Confirm(tx)
if err != nil {
e.Logger.Errorw("Failed to confirm assign registry module on token admin registry", "err", err)
return fmt.Errorf("failed to confirm assign registry module on token admin registry: %w", err)
}

e.Logger.Infow("assigned registry module on token admin registry")

nonceManager, err := deployContract(e.Logger, chain, ab,
Expand Down
Loading
Loading