diff --git a/integration-tests/deployment/ccip/add_lane_test.go b/integration-tests/deployment/ccip/add_lane_test.go index 040b7f781b0..bf8c4d2d513 100644 --- a/integration-tests/deployment/ccip/add_lane_test.go +++ b/integration-tests/deployment/ccip/add_lane_test.go @@ -2,31 +2,46 @@ package ccipdeployment import ( "testing" + "time" + "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-testing-framework/lib/utils/testcontext" + "github.com/smartcontractkit/chainlink/integration-tests/deployment" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/offramp" "github.com/smartcontractkit/chainlink/v2/core/logger" ) -// TestAddLane covers the workflow of adding a lane -// between existing supported chains in CCIP. +// TestAddLane covers the workflow of adding a lane between two chains and enabling it. +// It also covers the case where the onRamp is disabled on the OffRamp contract initially and then enabled. func TestAddLane(t *testing.T) { - // TODO: The offchain code doesn't yet support partial lane - // enablement, need to address then re-enable this test. - t.Skip() - e := NewMemoryEnvironmentWithJobs(t, logger.TestLogger(t), 3, 4) + // We add more chains to the chainlink nodes than the number of chains where CCIP is deployed. + e := NewMemoryEnvironmentWithJobs(t, logger.TestLogger(t), 4, 4) // Here we have CR + nodes set up, but no CCIP contracts deployed. state, err := LoadOnchainState(e.Env, e.Ab) require.NoError(t, err) + + selectors := e.Env.AllChainSelectors() + // deploy CCIP contracts on two chains + chain1, chain2 := selectors[0], selectors[1] + + feeds := state.Chains[e.FeedChainSel].USDFeeds + tokenConfig := NewTestTokenConfig(feeds) + + feeTokenContracts := make(map[uint64]FeeTokenContracts) + for _, sel := range []uint64{chain1, chain2} { + feeTokenContracts[sel] = e.FeeTokenContracts[sel] + } // Set up CCIP contracts and a DON per chain. err = DeployCCIPContracts(e.Env, e.Ab, DeployCCIPContractConfig{ HomeChainSel: e.HomeChainSel, FeedChainSel: e.FeedChainSel, - TokenConfig: NewTokenConfig(), + TokenConfig: tokenConfig, MCMSConfig: NewTestMCMSConfig(t, e.Env), - FeeTokenContracts: e.FeeTokenContracts, + FeeTokenContracts: feeTokenContracts, + ChainsToDeploy: []uint64{chain1, chain2}, CapabilityRegistry: state.Chains[e.HomeChainSel].CapabilityRegistry.Address(), OCRSecrets: deployment.XXXGenerateTestOCRSecrets(), }) @@ -35,32 +50,90 @@ func TestAddLane(t *testing.T) { // We expect no lanes available on any chain. state, err = LoadOnchainState(e.Env, e.Ab) require.NoError(t, err) - for _, chain := range state.Chains { + for _, sel := range []uint64{chain1, chain2} { + chain := state.Chains[sel] offRamps, err := chain.Router.GetOffRamps(nil) require.NoError(t, err) require.Len(t, offRamps, 0) } - // Add one lane and send traffic. - from, to := e.Env.AllChainSelectors()[0], e.Env.AllChainSelectors()[1] - require.NoError(t, AddLane(e.Env, state, from, to)) + replayBlocks, err := LatestBlocksByChain(testcontext.Get(t), e.Env.Chains) + require.NoError(t, err) + + // Add one lane from chain1 to chain 2 and send traffic. + require.NoError(t, AddLane(e.Env, state, chain1, chain2)) + + ReplayLogs(t, e.Env.Offchain, replayBlocks) + time.Sleep(30 * time.Second) + // disable the onRamp initially on OffRamp + disableRampTx, err := state.Chains[chain2].OffRamp.ApplySourceChainConfigUpdates(e.Env.Chains[chain2].DeployerKey, []offramp.OffRampSourceChainConfigArgs{ + { + Router: state.Chains[chain2].Router.Address(), + SourceChainSelector: chain1, + IsEnabled: false, + OnRamp: common.LeftPadBytes(state.Chains[chain1].OnRamp.Address().Bytes(), 32), + }, + }) + _, err = deployment.ConfirmIfNoError(e.Env.Chains[chain2], disableRampTx, err) + require.NoError(t, err) - for sel, chain := range state.Chains { + for _, sel := range []uint64{chain1, chain2} { + chain := state.Chains[sel] offRamps, err := chain.Router.GetOffRamps(nil) require.NoError(t, err) - if sel == to { + if sel == chain2 { require.Len(t, offRamps, 1) + srcCfg, err := chain.OffRamp.GetSourceChainConfig(nil, chain1) + require.NoError(t, err) + require.Equal(t, common.LeftPadBytes(state.Chains[chain1].OnRamp.Address().Bytes(), 32), srcCfg.OnRamp) + require.False(t, srcCfg.IsEnabled) } else { require.Len(t, offRamps, 0) } } - latesthdr, err := e.Env.Chains[to].Client.HeaderByNumber(testcontext.Get(t), nil) + + latesthdr, err := e.Env.Chains[chain2].Client.HeaderByNumber(testcontext.Get(t), nil) require.NoError(t, err) startBlock := latesthdr.Number.Uint64() - seqNum := SendRequest(t, e.Env, state, from, to, false) - require.Equal(t, uint64(1), seqNum) - require.NoError(t, ConfirmExecWithSeqNr(t, e.Env.Chains[from], e.Env.Chains[to], state.Chains[to].OffRamp, &startBlock, seqNum)) + // 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) + require.Equal(t, uint64(1), seqNum1) + + // Add another lane + require.NoError(t, AddLane(e.Env, state, chain2, chain1)) + + // Send traffic on the second lane and it should succeed + 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) + 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)) + + // 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) + + // enable the onRamp on OffRamp + enableRampTx, err := state.Chains[chain2].OffRamp.ApplySourceChainConfigUpdates(e.Env.Chains[chain2].DeployerKey, []offramp.OffRampSourceChainConfigArgs{ + { + Router: state.Chains[chain2].Router.Address(), + SourceChainSelector: chain1, + IsEnabled: true, + OnRamp: common.LeftPadBytes(state.Chains[chain1].OnRamp.Address().Bytes(), 32), + }, + }) + _, err = deployment.ConfirmIfNoError(e.Env.Chains[chain2], enableRampTx, err) + require.NoError(t, err) + + srcCfg, err := state.Chains[chain2].OffRamp.GetSourceChainConfig(nil, chain1) + require.NoError(t, err) + require.Equal(t, common.LeftPadBytes(state.Chains[chain1].OnRamp.Address().Bytes(), 32), srcCfg.OnRamp) + require.True(t, srcCfg.IsEnabled) - // TODO: Add a second lane, then disable the first and - // ensure we can send on the second but not the first. + // we need the replay here otherwise plugin is not able to locate the message + 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, ConfirmExecWithSeqNr(t, e.Env.Chains[chain1], e.Env.Chains[chain2], state.Chains[chain2].OffRamp, &startBlock, seqNum1)) } diff --git a/integration-tests/deployment/ccip/changeset/active_candidate_test.go b/integration-tests/deployment/ccip/changeset/active_candidate_test.go index edfffee925f..6f258bf95c5 100644 --- a/integration-tests/deployment/ccip/changeset/active_candidate_test.go +++ b/integration-tests/deployment/ccip/changeset/active_candidate_test.go @@ -7,15 +7,18 @@ import ( "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" cciptypes "github.com/smartcontractkit/chainlink-ccip/pkg/types/ccipocr3" "github.com/smartcontractkit/chainlink-ccip/pluginconfig" + "github.com/smartcontractkit/chainlink/integration-tests/deployment" "github.com/stretchr/testify/require" jobv1 "github.com/smartcontractkit/chainlink-protos/job-distributor/v1/job" + ccdeploy "github.com/smartcontractkit/chainlink/integration-tests/deployment/ccip" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -98,7 +101,7 @@ func TestActiveCandidate(t *testing.T) { require.NoError(t, err) block := latesthdr.Number.Uint64() startBlocks[dest] = &block - seqNum := ccdeploy.SendRequest(t, e, state, src, dest, false) + seqNum := ccdeploy.TestSendRequest(t, e, state, src, dest, false) expectedSeqNum[dest] = seqNum } } diff --git a/integration-tests/deployment/ccip/changeset/add_chain_test.go b/integration-tests/deployment/ccip/changeset/add_chain_test.go index 3544e9cb9a4..20a37fad07e 100644 --- a/integration-tests/deployment/ccip/changeset/add_chain_test.go +++ b/integration-tests/deployment/ccip/changeset/add_chain_test.go @@ -12,12 +12,11 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/rmn_home" - cciptypes "github.com/smartcontractkit/chainlink-ccip/pkg/types/ccipocr3" - "github.com/smartcontractkit/chainlink-ccip/pluginconfig" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + cciptypes "github.com/smartcontractkit/chainlink-ccip/pkg/types/ccipocr3" + "github.com/smartcontractkit/chainlink-testing-framework/lib/utils/testcontext" "github.com/smartcontractkit/chainlink/integration-tests/deployment" @@ -37,22 +36,7 @@ func TestAddChainInbound(t *testing.T) { // We deploy to the rest. initialDeploy := e.Env.AllChainSelectorsExcluding([]uint64{newChain}) - feeds := state.Chains[e.FeedChainSel].USDFeeds - tokenConfig := ccipdeployment.NewTokenConfig() - tokenConfig.UpsertTokenInfo(ccipdeployment.LinkSymbol, - pluginconfig.TokenInfo{ - AggregatorAddress: cciptypes.UnknownEncodedAddress(feeds[ccipdeployment.LinkSymbol].Address().String()), - Decimals: ccipdeployment.LinkDecimals, - DeviationPPB: cciptypes.NewBigIntFromInt64(1e9), - }, - ) - tokenConfig.UpsertTokenInfo(ccipdeployment.WethSymbol, - pluginconfig.TokenInfo{ - AggregatorAddress: cciptypes.UnknownEncodedAddress(feeds[ccipdeployment.WethSymbol].Address().String()), - Decimals: ccipdeployment.WethDecimals, - DeviationPPB: cciptypes.NewBigIntFromInt64(1e9), - }, - ) + tokenConfig := ccipdeployment.NewTestTokenConfig(state.Chains[e.FeedChainSel].USDFeeds) err = ccipdeployment.DeployCCIPContracts(e.Env, e.Ab, ccipdeployment.DeployCCIPContractConfig{ HomeChainSel: e.HomeChainSel, FeedChainSel: e.FeedChainSel, @@ -149,7 +133,7 @@ func TestAddChainInbound(t *testing.T) { } // TODO This currently is not working - Able to send the request here but request gets stuck in execution // Send a new message and expect that this is delivered once the chain is completely set up as inbound - //SendRequest(t, e.Env, state, initialDeploy[0], newChain, true) + //TestSendRequest(t, e.Env, state, initialDeploy[0], newChain, true) t.Logf("Executing add don and set candidate proposal for commit plugin on chain %d", newChain) addDonProp, err := AddDonAndSetCandidateProposal(state, e.Env, nodes, deployment.XXXGenerateTestOCRSecrets(), e.HomeChainSel, e.FeedChainSel, newChain, tokenConfig, types.PluginTypeCCIPCommit) @@ -226,7 +210,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.SendRequest(t, e.Env, state, initialDeploy[0], newChain, true) + seqNr := ccipdeployment.TestSendRequest(t, e.Env, state, initialDeploy[0], newChain, true) 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), diff --git a/integration-tests/deployment/ccip/changeset/initial_deploy_test.go b/integration-tests/deployment/ccip/changeset/initial_deploy_test.go index 844a3be715e..9ca771e8c0d 100644 --- a/integration-tests/deployment/ccip/changeset/initial_deploy_test.go +++ b/integration-tests/deployment/ccip/changeset/initial_deploy_test.go @@ -3,9 +3,6 @@ package changeset import ( "testing" - cciptypes "github.com/smartcontractkit/chainlink-ccip/pkg/types/ccipocr3" - "github.com/smartcontractkit/chainlink-ccip/pluginconfig" - "github.com/smartcontractkit/chainlink/integration-tests/deployment" ccdeploy "github.com/smartcontractkit/chainlink/integration-tests/deployment/ccip" @@ -28,28 +25,11 @@ func TestInitialDeploy(t *testing.T) { require.NoError(t, err) require.NotNil(t, state.Chains[tenv.HomeChainSel].LinkToken) - feeds := state.Chains[tenv.FeedChainSel].USDFeeds - tokenConfig := ccdeploy.NewTokenConfig() - tokenConfig.UpsertTokenInfo(ccdeploy.LinkSymbol, - pluginconfig.TokenInfo{ - AggregatorAddress: cciptypes.UnknownEncodedAddress(feeds[ccdeploy.LinkSymbol].Address().String()), - Decimals: ccdeploy.LinkDecimals, - DeviationPPB: cciptypes.NewBigIntFromInt64(1e9), - }, - ) - tokenConfig.UpsertTokenInfo(ccdeploy.WethSymbol, - pluginconfig.TokenInfo{ - AggregatorAddress: cciptypes.UnknownEncodedAddress(feeds[ccdeploy.WethSymbol].Address().String()), - Decimals: ccdeploy.WethDecimals, - DeviationPPB: cciptypes.NewBigIntFromInt64(1e9), - }, - ) - output, err := InitialDeployChangeSet(tenv.Ab, tenv.Env, ccdeploy.DeployCCIPContractConfig{ HomeChainSel: tenv.HomeChainSel, FeedChainSel: tenv.FeedChainSel, ChainsToDeploy: tenv.Env.AllChainSelectors(), - TokenConfig: tokenConfig, + TokenConfig: ccdeploy.NewTestTokenConfig(state.Chains[tenv.FeedChainSel].USDFeeds), MCMSConfig: ccdeploy.NewTestMCMSConfig(t, e), CapabilityRegistry: state.Chains[tenv.HomeChainSel].CapabilityRegistry.Address(), FeeTokenContracts: tenv.FeeTokenContracts, @@ -92,7 +72,7 @@ func TestInitialDeploy(t *testing.T) { require.NoError(t, err) block := latesthdr.Number.Uint64() startBlocks[dest] = &block - seqNum := ccdeploy.SendRequest(t, e, state, src, dest, false) + seqNum := ccdeploy.TestSendRequest(t, e, state, src, dest, false) expectedSeqNum[dest] = seqNum } } diff --git a/integration-tests/deployment/ccip/deploy_home_chain.go b/integration-tests/deployment/ccip/deploy_home_chain.go index c86e39321b5..202a750c053 100644 --- a/integration-tests/deployment/ccip/deploy_home_chain.go +++ b/integration-tests/deployment/ccip/deploy_home_chain.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "encoding/hex" + "encoding/json" "fmt" "math/big" "os" @@ -27,6 +28,8 @@ import ( "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3confighelper" "github.com/smartcontractkit/chainlink/integration-tests/deployment" + p2ptypes "github.com/smartcontractkit/chainlink/v2/core/services/p2p/types" + cctypes "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/ccip_home" @@ -201,6 +204,18 @@ func DeployCapReg(lggr logger.Logger, ab deployment.AddressBook, chain deploymen return capReg, nil } +func isEqualCapabilitiesRegistryNodeParams(a, b capabilities_registry.CapabilitiesRegistryNodeParams) (bool, error) { + aBytes, err := json.Marshal(a) + if err != nil { + return false, err + } + bBytes, err := json.Marshal(b) + if err != nil { + return false, err + } + return bytes.Equal(aBytes, bBytes), nil +} + func AddNodes( lggr logger.Logger, capReg *capabilities_registry.CapabilitiesRegistry, @@ -208,6 +223,19 @@ func AddNodes( p2pIDs [][32]byte, ) error { var nodeParams []capabilities_registry.CapabilitiesRegistryNodeParams + nodes, err := capReg.GetNodes(nil) + if err != nil { + return err + } + existingNodeParams := make(map[p2ptypes.PeerID]capabilities_registry.CapabilitiesRegistryNodeParams) + for _, node := range nodes { + existingNodeParams[node.P2pId] = capabilities_registry.CapabilitiesRegistryNodeParams{ + NodeOperatorId: node.NodeOperatorId, + Signer: node.Signer, + P2pId: node.P2pId, + HashedCapabilityIds: node.HashedCapabilityIds, + } + } for _, p2pID := range p2pIDs { // if any p2pIDs are empty throw error if bytes.Equal(p2pID[:], make([]byte, 32)) { @@ -220,8 +248,19 @@ func AddNodes( EncryptionPublicKey: p2pID, // Not used in tests HashedCapabilityIds: [][32]byte{CCIPCapabilityID}, } + if existing, ok := existingNodeParams[p2pID]; ok { + if isEqual, err := isEqualCapabilitiesRegistryNodeParams(existing, nodeParam); err != nil && isEqual { + lggr.Infow("Node already exists", "p2pID", p2pID) + continue + } + } + nodeParams = append(nodeParams, nodeParam) } + if len(nodeParams) == 0 { + lggr.Infow("No new nodes to add") + return nil + } tx, err := capReg.AddNodes(chain.DeployerKey, nodeParams) if err != nil { lggr.Errorw("Failed to add nodes", "err", deployment.MaybeDataErr(err)) diff --git a/integration-tests/deployment/ccip/rmn_test.go b/integration-tests/deployment/ccip/rmn_test.go index 6bcf6c040d2..d7867929378 100644 --- a/integration-tests/deployment/ccip/rmn_test.go +++ b/integration-tests/deployment/ccip/rmn_test.go @@ -12,6 +12,7 @@ import ( jobv1 "github.com/smartcontractkit/chainlink-protos/job-distributor/v1/job" "github.com/smartcontractkit/chainlink-testing-framework/lib/utils/testcontext" + "github.com/smartcontractkit/chainlink/integration-tests/deployment" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/rmn_home" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/rmn_remote" @@ -181,7 +182,7 @@ func TestRMN(t *testing.T) { require.NoError(t, err) block := latesthdr.Number.Uint64() startBlocks[dstChain.Selector] = &block - seqNum := SendRequest(t, envWithRMN.Env, onChainState, srcChain.Selector, dstChain.Selector, false) + seqNum := TestSendRequest(t, envWithRMN.Env, onChainState, srcChain.Selector, dstChain.Selector, false) t.Logf("expected seqNum: %d", seqNum) expectedSeqNum := make(map[uint64]uint64) diff --git a/integration-tests/deployment/ccip/test_assertions.go b/integration-tests/deployment/ccip/test_assertions.go index c40955f7a5b..7b7f8c9e5ad 100644 --- a/integration-tests/deployment/ccip/test_assertions.go +++ b/integration-tests/deployment/ccip/test_assertions.go @@ -2,16 +2,14 @@ package ccipdeployment import ( "context" - "fmt" "math/big" "testing" "time" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/accounts/abi/bind/backends" + "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" "golang.org/x/sync/errgroup" @@ -322,22 +320,7 @@ func ConfirmExecWithSeqNr( for { select { case <-tick.C: - // TODO: Clean this up - // if it's simulated backend, commit to ensure mining - if backend, ok := source.Client.(*backends.SimulatedBackend); ok { - backend.Commit() - } - if backend, ok := dest.Client.(*backends.SimulatedBackend); ok { - backend.Commit() - } - scc, err := offRamp.GetSourceChainConfig(nil, source.Selector) - if err != nil { - return fmt.Errorf("error to get source chain config : %w", err) - } - executionState, err := offRamp.GetExecutionState(nil, source.Selector, expectedSeqNr) - if err != nil { - return fmt.Errorf("error to get execution state : %w", err) - } + scc, executionState := GetExecutionState(t, source, dest, offRamp, expectedSeqNr) t.Logf("Waiting for ExecutionStateChanged on chain %d (offramp %s) from chain %d with expected sequence number %d, current onchain minSeqNr: %d, execution state: %s", dest.Selector, offRamp.Address().String(), source.Selector, expectedSeqNr, scc.MinSeqNr, executionStateToString(executionState)) if executionState == EXECUTION_STATE_SUCCESS { @@ -362,6 +345,58 @@ func ConfirmExecWithSeqNr( } } +func ConfirmNoExecConsistentlyWithSeqNr( + t *testing.T, + source, dest deployment.Chain, + offRamp *offramp.OffRamp, + expectedSeqNr uint64, + timeout time.Duration, +) { + RequireConsistently(t, func() bool { + scc, executionState := GetExecutionState(t, source, dest, offRamp, expectedSeqNr) + t.Logf("Waiting for ExecutionStateChanged on chain %d (offramp %s) from chain %d with expected sequence number %d, current onchain minSeqNr: %d, execution state: %s", + dest.Selector, offRamp.Address().String(), source.Selector, expectedSeqNr, scc.MinSeqNr, executionStateToString(executionState)) + if executionState == EXECUTION_STATE_UNTOUCHED { + return true + } + t.Logf("Observed %s execution state on chain %d (offramp %s) from chain %d with expected sequence number %d", + executionStateToString(executionState), dest.Selector, offRamp.Address().String(), source.Selector, expectedSeqNr) + return false + }, timeout, 3*time.Second, "Expected no execution state change on chain %d (offramp %s) from chain %d with expected sequence number %d", dest.Selector, offRamp.Address().String(), source.Selector, expectedSeqNr) +} + +func GetExecutionState(t *testing.T, source, dest deployment.Chain, offRamp *offramp.OffRamp, expectedSeqNr uint64) (offramp.OffRampSourceChainConfig, uint8) { + // if it's simulated backend, commit to ensure mining + if backend, ok := source.Client.(*backends.SimulatedBackend); ok { + backend.Commit() + } + if backend, ok := dest.Client.(*backends.SimulatedBackend); ok { + backend.Commit() + } + scc, err := offRamp.GetSourceChainConfig(nil, source.Selector) + require.NoError(t, err) + executionState, err := offRamp.GetExecutionState(nil, source.Selector, expectedSeqNr) + require.NoError(t, err) + return scc, executionState +} + +func RequireConsistently(t *testing.T, condition func() bool, duration time.Duration, tick time.Duration, msgAndArgs ...interface{}) { + timer := time.NewTimer(duration) + defer timer.Stop() + tickTimer := time.NewTicker(tick) + defer tickTimer.Stop() + for { + select { + case <-tickTimer.C: + if !condition() { + require.FailNow(t, "Condition failed", msgAndArgs...) + } + case <-timer.C: + return + } + } +} + const ( EXECUTION_STATE_UNTOUCHED = 0 EXECUTION_STATE_INPROGRESS = 1 diff --git a/integration-tests/deployment/ccip/test_helpers.go b/integration-tests/deployment/ccip/test_helpers.go index 5c42afbf539..dba4af8eb15 100644 --- a/integration-tests/deployment/ccip/test_helpers.go +++ b/integration-tests/deployment/ccip/test_helpers.go @@ -9,13 +9,13 @@ import ( "time" "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/core/types" "github.com/pkg/errors" "golang.org/x/sync/errgroup" "github.com/smartcontractkit/chainlink-testing-framework/lib/blockchain" cciptypes "github.com/smartcontractkit/chainlink-ccip/pkg/types/ccipocr3" - "github.com/smartcontractkit/chainlink-ccip/pluginconfig" "github.com/smartcontractkit/chainlink-testing-framework/lib/utils/testcontext" "github.com/smartcontractkit/chainlink-testing-framework/lib/logging" @@ -195,33 +195,54 @@ func NewMemoryEnvironmentWithJobs(t *testing.T, lggr logger.Logger, numChains in return e } -func SendRequest(t *testing.T, e deployment.Environment, state CCIPOnChainState, src, dest uint64, testRouter bool) uint64 { +func CCIPSendRequest( + e deployment.Environment, + state CCIPOnChainState, + src, dest uint64, + data []byte, + tokensAndAmounts []router.ClientEVMTokenAmount, + feeToken common.Address, + testRouter bool, + extraArgs []byte, +) (*types.Transaction, uint64, error) { msg := router.ClientEVM2AnyMessage{ Receiver: common.LeftPadBytes(state.Chains[dest].Receiver.Address().Bytes(), 32), - Data: []byte("hello"), - TokenAmounts: nil, // TODO: no tokens for now - // Pay native. - FeeToken: common.HexToAddress("0x0"), - ExtraArgs: nil, // TODO: no extra args for now, falls back to default + Data: data, + TokenAmounts: tokensAndAmounts, + FeeToken: feeToken, + ExtraArgs: extraArgs, } - router := state.Chains[src].Router + r := state.Chains[src].Router if testRouter { - router = state.Chains[src].TestRouter + r = state.Chains[src].TestRouter } - fee, err := router.GetFee( + fee, err := r.GetFee( &bind.CallOpts{Context: context.Background()}, dest, msg) - require.NoError(t, err, deployment.MaybeDataErr(err)) - - t.Logf("Sending CCIP request from chain selector %d to chain selector %d", - src, dest) - e.Chains[src].DeployerKey.Value = fee - tx, err := router.CcipSend( + if err != nil { + return nil, 0, errors.Wrap(deployment.MaybeDataErr(err), "failed to get fee") + } + if msg.FeeToken == common.HexToAddress("0x0") { + e.Chains[src].DeployerKey.Value = fee + defer func() { e.Chains[src].DeployerKey.Value = nil }() + } + tx, err := r.CcipSend( e.Chains[src].DeployerKey, dest, msg) - require.NoError(t, err) - e.Chains[src].DeployerKey.Value = nil + if err != nil { + return nil, 0, errors.Wrap(err, "failed to send CCIP message") + } blockNum, err := e.Chains[src].Confirm(tx) + if err != nil { + return tx, 0, errors.Wrap(err, "failed to confirm CCIP message") + } + return tx, blockNum, nil +} + +func TestSendRequest(t *testing.T, e deployment.Environment, state CCIPOnChainState, src, dest uint64, testRouter bool) uint64 { + t.Logf("Sending CCIP request from chain selector %d to chain selector %d", + src, dest) + tx, blockNum, err := CCIPSendRequest(e, state, src, dest, []byte("hello"), nil, common.HexToAddress("0x0"), testRouter, nil) require.NoError(t, err) it, err := state.Chains[src].OnRamp.FilterCCIPMessageSent(&bind.FilterOpts{ Start: blockNum, @@ -310,28 +331,12 @@ func NewLocalDevEnvironmentWithRMN(t *testing.T, lggr logger.Logger) (DeployedEn state, err := LoadOnchainState(tenv.Env, tenv.Ab) require.NoError(t, err) - feeds := state.Chains[tenv.FeedChainSel].USDFeeds - tokenConfig := NewTokenConfig() - tokenConfig.UpsertTokenInfo(LinkSymbol, - pluginconfig.TokenInfo{ - AggregatorAddress: cciptypes.UnknownEncodedAddress(feeds[LinkSymbol].Address().String()), - Decimals: LinkDecimals, - DeviationPPB: cciptypes.NewBigIntFromInt64(1e9), - }, - ) - tokenConfig.UpsertTokenInfo(WethSymbol, - pluginconfig.TokenInfo{ - AggregatorAddress: cciptypes.UnknownEncodedAddress(feeds[WethSymbol].Address().String()), - Decimals: WethDecimals, - DeviationPPB: cciptypes.NewBigIntFromInt64(1e9), - }, - ) // Deploy CCIP contracts. err = DeployCCIPContracts(tenv.Env, tenv.Ab, DeployCCIPContractConfig{ HomeChainSel: tenv.HomeChainSel, FeedChainSel: tenv.FeedChainSel, ChainsToDeploy: tenv.Env.AllChainSelectors(), - TokenConfig: tokenConfig, + TokenConfig: NewTestTokenConfig(state.Chains[tenv.FeedChainSel].USDFeeds), MCMSConfig: NewTestMCMSConfig(t, tenv.Env), CapabilityRegistry: state.Chains[tenv.HomeChainSel].CapabilityRegistry.Address(), FeeTokenContracts: tenv.FeeTokenContracts, @@ -575,7 +580,7 @@ func ConfirmRequestOnSourceAndDest(t *testing.T, env deployment.Environment, sta require.NoError(t, err) startBlock := latesthdr.Number.Uint64() fmt.Printf("startblock %d", startBlock) - seqNum := SendRequest(t, env, state, sourceCS, destCS, false) + seqNum := TestSendRequest(t, env, state, sourceCS, destCS, false) require.Equal(t, expectedSeqNr, seqNum) fmt.Printf("Request sent for seqnr %d", seqNum) diff --git a/integration-tests/deployment/ccip/token_info.go b/integration-tests/deployment/ccip/token_info.go index b02402f603e..559c961e3d4 100644 --- a/integration-tests/deployment/ccip/token_info.go +++ b/integration-tests/deployment/ccip/token_info.go @@ -5,11 +5,16 @@ import ( "github.com/smartcontractkit/chainlink-ccip/pluginconfig" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/weth9" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/aggregator_v3_interface" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/shared/generated/burn_mint_erc677" "github.com/smartcontractkit/chainlink-common/pkg/logger" ) +var ( + TestDeviationPPB = ccipocr3.NewBigIntFromInt64(1e9) +) + // TokenConfig mapping between token Symbol (e.g. LinkSymbol, WethSymbol) // and the respective token info. type TokenConfig struct { @@ -22,6 +27,25 @@ func NewTokenConfig() TokenConfig { } } +func NewTestTokenConfig(feeds map[TokenSymbol]*aggregator_v3_interface.AggregatorV3Interface) TokenConfig { + tc := NewTokenConfig() + tc.UpsertTokenInfo(LinkSymbol, + pluginconfig.TokenInfo{ + AggregatorAddress: ccipocr3.UnknownEncodedAddress(feeds[LinkSymbol].Address().String()), + Decimals: LinkDecimals, + DeviationPPB: TestDeviationPPB, + }, + ) + tc.UpsertTokenInfo(WethSymbol, + pluginconfig.TokenInfo{ + AggregatorAddress: ccipocr3.UnknownEncodedAddress(feeds[WethSymbol].Address().String()), + Decimals: WethDecimals, + DeviationPPB: TestDeviationPPB, + }, + ) + return tc +} + func (tc *TokenConfig) UpsertTokenInfo( symbol TokenSymbol, info pluginconfig.TokenInfo, diff --git a/integration-tests/deployment/environment.go b/integration-tests/deployment/environment.go index 42ee24aea29..99c15233dfa 100644 --- a/integration-tests/deployment/environment.go +++ b/integration-tests/deployment/environment.go @@ -23,6 +23,7 @@ import ( nodev1 "github.com/smartcontractkit/chainlink-protos/job-distributor/v1/node" "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" ) diff --git a/integration-tests/deployment/memory/environment.go b/integration-tests/deployment/memory/environment.go index 641a88d72bb..cc8c6ffee48 100644 --- a/integration-tests/deployment/memory/environment.go +++ b/integration-tests/deployment/memory/environment.go @@ -44,6 +44,7 @@ func NewMemoryChainsWithChainIDs(t *testing.T, chainIDs []uint64) map[uint64]dep func generateMemoryChain(t *testing.T, inputs map[uint64]EVMChain) map[uint64]deployment.Chain { chains := make(map[uint64]deployment.Chain) for cid, chain := range inputs { + chain := chain sel, err := chainsel.SelectorFromChainId(cid) require.NoError(t, err) chains[sel] = deployment.Chain{ diff --git a/integration-tests/smoke/ccip_test.go b/integration-tests/smoke/ccip_test.go index d0f12ec908d..dd9213cd789 100644 --- a/integration-tests/smoke/ccip_test.go +++ b/integration-tests/smoke/ccip_test.go @@ -6,6 +6,7 @@ import ( "github.com/stretchr/testify/require" cciptypes "github.com/smartcontractkit/chainlink-ccip/pkg/types/ccipocr3" + "github.com/smartcontractkit/chainlink/integration-tests/deployment" "github.com/smartcontractkit/chainlink-ccip/pluginconfig" @@ -85,7 +86,7 @@ func TestInitialDeployOnLocal(t *testing.T) { require.NoError(t, err) block := latesthdr.Number.Uint64() startBlocks[dest] = &block - seqNum := ccdeploy.SendRequest(t, e, state, src, dest, false) + seqNum := ccdeploy.TestSendRequest(t, e, state, src, dest, false) expectedSeqNum[dest] = seqNum } }