diff --git a/deployment/ccip/changeset/accept_ownership_test.go b/deployment/ccip/changeset/accept_ownership_test.go index 47c1cd423da..7164fe1786a 100644 --- a/deployment/ccip/changeset/accept_ownership_test.go +++ b/deployment/ccip/changeset/accept_ownership_test.go @@ -11,6 +11,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" commonchangeset "github.com/smartcontractkit/chainlink/deployment/common/changeset" + "github.com/smartcontractkit/chainlink/deployment/environment/memory" "github.com/stretchr/testify/require" "golang.org/x/exp/maps" @@ -19,7 +20,12 @@ import ( ) func Test_NewAcceptOwnershipChangeset(t *testing.T) { - e := NewMemoryEnvironmentWithJobsAndContracts(t, logger.TestLogger(t), 2, 4, &TestConfigs{}) + e := NewMemoryEnvironmentWithJobsAndContracts(t, logger.TestLogger(t), memory.MemoryEnvironmentConfig{ + Chains: 2, + NumOfUsersPerChain: 1, + Nodes: 4, + Bootstraps: 1, + }, &TestConfigs{}) state, err := LoadOnchainState(e.Env) require.NoError(t, err) diff --git a/deployment/ccip/changeset/cs_active_candidate_test.go b/deployment/ccip/changeset/cs_active_candidate_test.go index 671a06b5de0..6efdacc3b7c 100644 --- a/deployment/ccip/changeset/cs_active_candidate_test.go +++ b/deployment/ccip/changeset/cs_active_candidate_test.go @@ -12,6 +12,7 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/lib/utils/testcontext" "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/internal" + "github.com/smartcontractkit/chainlink/deployment/environment/memory" cctypes "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/types" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router" @@ -29,7 +30,12 @@ func TestActiveCandidate(t *testing.T) { t.Skipf("to be enabled after latest cl-ccip is compatible") lggr := logger.TestLogger(t) - tenv := NewMemoryEnvironmentWithJobsAndContracts(t, lggr, 3, 5, nil) + tenv := NewMemoryEnvironmentWithJobsAndContracts(t, lggr, memory.MemoryEnvironmentConfig{ + Chains: 3, + NumOfUsersPerChain: 1, + Nodes: 5, + Bootstraps: 1, + }, nil) e := tenv.Env state, err := LoadOnchainState(tenv.Env) require.NoError(t, err) diff --git a/deployment/ccip/changeset/cs_add_chain_test.go b/deployment/ccip/changeset/cs_add_chain_test.go index 96727d0e4f8..aebf246dbe5 100644 --- a/deployment/ccip/changeset/cs_add_chain_test.go +++ b/deployment/ccip/changeset/cs_add_chain_test.go @@ -10,6 +10,7 @@ import ( "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/internal" commonchangeset "github.com/smartcontractkit/chainlink/deployment/common/changeset" commontypes "github.com/smartcontractkit/chainlink/deployment/common/types" + "github.com/smartcontractkit/chainlink/deployment/environment/memory" "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/types" "github.com/ethereum/go-ethereum/common" @@ -33,7 +34,12 @@ import ( func TestAddChainInbound(t *testing.T) { // 4 chains where the 4th is added after initial deployment. - e := NewMemoryEnvironmentWithJobs(t, logger.TestLogger(t), 4, 4) + e := NewMemoryEnvironmentWithJobs(t, logger.TestLogger(t), memory.MemoryEnvironmentConfig{ + Chains: 4, + NumOfUsersPerChain: 1, + Nodes: 4, + Bootstraps: 1, + }) state, err := LoadOnchainState(e.Env) require.NoError(t, err) // Take first non-home chain as the new chain. diff --git a/deployment/ccip/changeset/cs_add_lane_test.go b/deployment/ccip/changeset/cs_add_lane_test.go index bb5e678c6cb..fbceeaa8472 100644 --- a/deployment/ccip/changeset/cs_add_lane_test.go +++ b/deployment/ccip/changeset/cs_add_lane_test.go @@ -11,13 +11,18 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/lib/utils/testcontext" "github.com/smartcontractkit/chainlink/deployment" + "github.com/smartcontractkit/chainlink/deployment/environment/memory" "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" ) func TestAddLanesWithTestRouter(t *testing.T) { - e := NewMemoryEnvironmentWithJobsAndContracts(t, logger.TestLogger(t), 2, 4, nil) + e := NewMemoryEnvironmentWithJobsAndContracts(t, logger.TestLogger(t), memory.MemoryEnvironmentConfig{ + Chains: 2, + Nodes: 4, + Bootstraps: 1, + }, nil) // Here we have CR + nodes set up, but no CCIP contracts deployed. state, err := LoadOnchainState(e.Env) require.NoError(t, err) @@ -67,7 +72,11 @@ func TestAddLane(t *testing.T) { t.Parallel() // We add more chains to the chainlink nodes than the number of chains where CCIP is deployed. - e := NewMemoryEnvironmentWithJobsAndContracts(t, logger.TestLogger(t), 2, 4, nil) + e := NewMemoryEnvironmentWithJobsAndContracts(t, logger.TestLogger(t), memory.MemoryEnvironmentConfig{ + Chains: 2, + Nodes: 4, + Bootstraps: 1, + }, nil) // Here we have CR + nodes set up, but no CCIP contracts deployed. state, err := LoadOnchainState(e.Env) require.NoError(t, err) diff --git a/deployment/ccip/changeset/cs_deploy_chain_test.go b/deployment/ccip/changeset/cs_deploy_chain_test.go index f599ab2d6f3..7965fe8e725 100644 --- a/deployment/ccip/changeset/cs_deploy_chain_test.go +++ b/deployment/ccip/changeset/cs_deploy_chain_test.go @@ -96,7 +96,11 @@ func TestDeployChainContractsChangeset(t *testing.T) { func TestDeployCCIPContracts(t *testing.T) { lggr := logger.TestLogger(t) - e := NewMemoryEnvironmentWithJobsAndContracts(t, lggr, 2, 4, nil) + e := NewMemoryEnvironmentWithJobsAndContracts(t, lggr, memory.MemoryEnvironmentConfig{ + Chains: 2, + Nodes: 4, + Bootstraps: 1, + }, nil) // Deploy all the CCIP contracts. state, err := LoadOnchainState(e.Env) require.NoError(t, err) diff --git a/deployment/ccip/changeset/initial_deploy_test.go b/deployment/ccip/changeset/initial_deploy_test.go index 0318af8ffbb..97e516c8f94 100644 --- a/deployment/ccip/changeset/initial_deploy_test.go +++ b/deployment/ccip/changeset/initial_deploy_test.go @@ -7,6 +7,7 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/lib/utils/testcontext" + "github.com/smartcontractkit/chainlink/deployment/environment/memory" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -15,9 +16,13 @@ import ( func TestInitialDeploy(t *testing.T) { lggr := logger.TestLogger(t) - tenv := NewMemoryEnvironmentWithJobsAndContracts(t, lggr, 3, 4, nil) + tenv := NewMemoryEnvironmentWithJobsAndContracts(t, lggr, memory.MemoryEnvironmentConfig{ + Chains: 3, + Nodes: 4, + Bootstraps: 1, + NumOfUsersPerChain: 1, + }, nil) e := tenv.Env - state, err := LoadOnchainState(e) require.NoError(t, err) // Add all lanes @@ -37,13 +42,21 @@ func TestInitialDeploy(t *testing.T) { require.NoError(t, err) block := latesthdr.Number.Uint64() startBlocks[dest] = &block - msgSentEvent := 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, - }) + require.GreaterOrEqual(t, len(tenv.Users[src]), 1) + msgSentEvent, err := DoSendRequest(t, e, state, + WithTestRouter(false), + WithSourceChain(src), + WithDestChain(dest), + WithEvm2AnyMessage(router.ClientEVM2AnyMessage{ + Receiver: common.LeftPadBytes(state.Chains[dest].Receiver.Address().Bytes(), 32), + Data: []byte("hello"), + TokenAmounts: nil, + FeeToken: common.HexToAddress("0x0"), + ExtraArgs: nil, + }), + WithSender(tenv.Users[src][0]), + ) + require.NoError(t, err) expectedSeqNum[SourceDestPair{ SourceChainSelector: src, DestChainSelector: dest, diff --git a/deployment/ccip/changeset/test_helpers.go b/deployment/ccip/changeset/test_helpers.go index cd135cf7975..fc9bb0f83ef 100644 --- a/deployment/ccip/changeset/test_helpers.go +++ b/deployment/ccip/changeset/test_helpers.go @@ -25,6 +25,7 @@ import ( commonchangeset "github.com/smartcontractkit/chainlink/deployment/common/changeset" commontypes "github.com/smartcontractkit/chainlink/deployment/common/types" + "github.com/smartcontractkit/chainlink/v2/core/services/relay" "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" @@ -93,6 +94,7 @@ type DeployedEnv struct { HomeChainSel uint64 FeedChainSel uint64 ReplayBlocks map[uint64]uint64 + Users map[uint64][]*bind.TransactOpts } func (e *DeployedEnv) SetupJobs(t *testing.T) { @@ -150,8 +152,9 @@ func DeployTestContracts(t *testing.T, require.NoError(t, err) return deployment.CapabilityRegistryConfig{ - EVMChainID: evmChainID, - Contract: capReg.Address, + EVMChainID: evmChainID, + Contract: capReg.Address, + NetworkType: relay.NetworkEVM, } } @@ -187,21 +190,20 @@ func allocateCCIPChainSelectors(chains map[uint64]deployment.Chain) (homeChainSe func NewMemoryEnvironment( t *testing.T, lggr logger.Logger, - numChains int, - numNodes int, + config memory.MemoryEnvironmentConfig, linkPrice *big.Int, wethPrice *big.Int) DeployedEnv { - require.GreaterOrEqual(t, numChains, 2, "numChains must be at least 2 for home and feed chains") - require.GreaterOrEqual(t, numNodes, 4, "numNodes must be at least 4") + require.GreaterOrEqual(t, config.Chains, 2, "numChains must be at least 2 for home and feed chains") + require.GreaterOrEqual(t, config.Nodes, 4, "numNodes must be at least 4") ctx := testcontext.Get(t) - chains := memory.NewMemoryChains(t, numChains) + chains, users := memory.NewMemoryChains(t, config.Chains, config.NumOfUsersPerChain) homeChainSel, feedSel := allocateCCIPChainSelectors(chains) replayBlocks, err := LatestBlocksByChain(ctx, chains) require.NoError(t, err) ab := deployment.NewMemoryAddressBook() crConfig := DeployTestContracts(t, lggr, ab, homeChainSel, feedSel, chains, linkPrice, wethPrice) - nodes := memory.NewNodes(t, zapcore.InfoLevel, chains, numNodes, 1, crConfig) + nodes := memory.NewNodes(t, zapcore.InfoLevel, chains, config.Nodes, config.Bootstraps, crConfig) for _, node := range nodes { require.NoError(t, node.App.Start(ctx)) t.Cleanup(func() { @@ -227,13 +229,14 @@ func NewMemoryEnvironment( HomeChainSel: homeChainSel, FeedChainSel: feedSel, ReplayBlocks: replayBlocks, + Users: users, } } // NewMemoryEnvironmentWithJobs creates a new CCIP environment // with capreg, fee tokens, feeds, nodes and jobs set up. -func NewMemoryEnvironmentWithJobs(t *testing.T, lggr logger.Logger, numChains int, numNodes int) DeployedEnv { - e := NewMemoryEnvironment(t, lggr, numChains, numNodes, MockLinkPrice, MockWethPrice) +func NewMemoryEnvironmentWithJobs(t *testing.T, lggr logger.Logger, config memory.MemoryEnvironmentConfig) DeployedEnv { + e := NewMemoryEnvironment(t, lggr, config, MockLinkPrice, MockWethPrice) e.SetupJobs(t) return e } @@ -263,9 +266,9 @@ type TestConfigs struct { OCRConfigOverride func(CCIPOCRParams) CCIPOCRParams } -func NewMemoryEnvironmentWithJobsAndContracts(t *testing.T, lggr logger.Logger, numChains int, numNodes int, tCfg *TestConfigs) DeployedEnv { +func NewMemoryEnvironmentWithJobsAndContracts(t *testing.T, lggr logger.Logger, config memory.MemoryEnvironmentConfig, tCfg *TestConfigs) DeployedEnv { var err error - e := NewMemoryEnvironment(t, lggr, numChains, numNodes, MockLinkPrice, MockWethPrice) + e := NewMemoryEnvironment(t, lggr, config, MockLinkPrice, MockWethPrice) allChains := e.Env.AllChainSelectors() mcmsCfg := make(map[uint64]commontypes.MCMSWithTimelockConfig) for _, c := range e.Env.AllChainSelectors() { @@ -393,31 +396,29 @@ func NewMemoryEnvironmentWithJobsAndContracts(t *testing.T, lggr logger.Logger, func CCIPSendRequest( e deployment.Environment, state CCIPOnChainState, - src, dest uint64, - testRouter bool, - evm2AnyMessage router.ClientEVM2AnyMessage, + cfg *CCIPSendReqConfig, ) (*types.Transaction, uint64, error) { msg := router.ClientEVM2AnyMessage{ - Receiver: evm2AnyMessage.Receiver, - Data: evm2AnyMessage.Data, - TokenAmounts: evm2AnyMessage.TokenAmounts, - FeeToken: evm2AnyMessage.FeeToken, - ExtraArgs: evm2AnyMessage.ExtraArgs, + Receiver: cfg.Evm2AnyMessage.Receiver, + Data: cfg.Evm2AnyMessage.Data, + TokenAmounts: cfg.Evm2AnyMessage.TokenAmounts, + FeeToken: cfg.Evm2AnyMessage.FeeToken, + ExtraArgs: cfg.Evm2AnyMessage.ExtraArgs, } - r := state.Chains[src].Router - if testRouter { - r = state.Chains[src].TestRouter + r := state.Chains[cfg.SourceChain].Router + if cfg.IsTestRouter { + r = state.Chains[cfg.SourceChain].TestRouter } if msg.FeeToken == common.HexToAddress("0x0") { // fee is in native token - return retryCcipSendUntilNativeFeeIsSufficient(e, r, src, dest, msg) + return retryCcipSendUntilNativeFeeIsSufficient(e, r, cfg) } - tx, err := r.CcipSend(e.Chains[src].DeployerKey, dest, msg) + tx, err := r.CcipSend(cfg.Sender, cfg.DestChain, msg) if err != nil { return nil, 0, errors.Wrap(err, "failed to send CCIP message") } - blockNum, err := e.Chains[src].Confirm(tx) + blockNum, err := e.Chains[cfg.SourceChain].Confirm(tx) if err != nil { return tx, 0, errors.Wrap(err, "failed to confirm CCIP message") } @@ -430,27 +431,25 @@ func CCIPSendRequest( func retryCcipSendUntilNativeFeeIsSufficient( e deployment.Environment, r *router.Router, - src, - dest uint64, - msg router.ClientEVM2AnyMessage, + cfg *CCIPSendReqConfig, ) (*types.Transaction, uint64, error) { const errCodeInsufficientFee = "0x07da6ee6" - defer func() { e.Chains[src].DeployerKey.Value = nil }() + defer func() { cfg.Sender.Value = nil }() for { - fee, err := r.GetFee(&bind.CallOpts{Context: context.Background()}, dest, msg) + fee, err := r.GetFee(&bind.CallOpts{Context: context.Background()}, cfg.DestChain, cfg.Evm2AnyMessage) if err != nil { return nil, 0, fmt.Errorf("failed to get fee: %w", deployment.MaybeDataErr(err)) } - e.Chains[src].DeployerKey.Value = fee + cfg.Sender.Value = fee - tx, err := r.CcipSend(e.Chains[src].DeployerKey, dest, msg) + tx, err := r.CcipSend(cfg.Sender, cfg.DestChain, cfg.Evm2AnyMessage) if err != nil { return nil, 0, fmt.Errorf("failed to send CCIP message: %w", err) } - blockNum, err := e.Chains[src].Confirm(tx) + blockNum, err := e.Chains[cfg.SourceChain].Confirm(tx) if err != nil { if strings.Contains(err.Error(), errCodeInsufficientFee) { continue @@ -489,38 +488,83 @@ func TestSendRequest( testRouter bool, evm2AnyMessage router.ClientEVM2AnyMessage, ) (msgSentEvent *onramp.OnRampCCIPMessageSent) { - msgSentEvent, err := DoSendRequest(t, e, state, src, dest, testRouter, evm2AnyMessage) + msgSentEvent, err := DoSendRequest(t, e, state, + WithSender(e.Chains[src].DeployerKey), + WithSourceChain(src), + WithDestChain(dest), + WithTestRouter(testRouter), + WithEvm2AnyMessage(evm2AnyMessage)) require.NoError(t, err) return msgSentEvent } +type CCIPSendReqConfig struct { + SourceChain uint64 + DestChain uint64 + IsTestRouter bool + Sender *bind.TransactOpts + Evm2AnyMessage router.ClientEVM2AnyMessage +} + +type SendReqOpts func(*CCIPSendReqConfig) + +func WithSender(sender *bind.TransactOpts) SendReqOpts { + return func(c *CCIPSendReqConfig) { + c.Sender = sender + } +} + +func WithEvm2AnyMessage(msg router.ClientEVM2AnyMessage) SendReqOpts { + return func(c *CCIPSendReqConfig) { + c.Evm2AnyMessage = msg + } +} + +func WithTestRouter(isTestRouter bool) SendReqOpts { + return func(c *CCIPSendReqConfig) { + c.IsTestRouter = isTestRouter + } +} + +func WithSourceChain(sourceChain uint64) SendReqOpts { + return func(c *CCIPSendReqConfig) { + c.SourceChain = sourceChain + } +} + +func WithDestChain(destChain uint64) SendReqOpts { + return func(c *CCIPSendReqConfig) { + c.DestChain = destChain + } +} + // DoSendRequest similar to TestSendRequest but returns an error. func DoSendRequest( t *testing.T, e deployment.Environment, state CCIPOnChainState, - src, dest uint64, - testRouter bool, - evm2AnyMessage router.ClientEVM2AnyMessage, + opts ...SendReqOpts, ) (*onramp.OnRampCCIPMessageSent, error) { - t.Logf("Sending CCIP request from chain selector %d to chain selector %d", - src, dest) - tx, blockNum, err := CCIPSendRequest( - e, - state, - src, dest, - testRouter, - evm2AnyMessage, - ) + cfg := &CCIPSendReqConfig{} + for _, opt := range opts { + opt(cfg) + } + // Set default sender if not provided + if cfg.Sender == nil { + cfg.Sender = e.Chains[cfg.SourceChain].DeployerKey + } + t.Logf("Sending CCIP request from chain selector %d to chain selector %d from sender %s", + cfg.SourceChain, cfg.DestChain, cfg.Sender.From.String()) + tx, blockNum, err := CCIPSendRequest(e, state, cfg) if err != nil { return nil, err } - it, err := state.Chains[src].OnRamp.FilterCCIPMessageSent(&bind.FilterOpts{ + it, err := state.Chains[cfg.SourceChain].OnRamp.FilterCCIPMessageSent(&bind.FilterOpts{ Start: blockNum, End: &blockNum, Context: context.Background(), - }, []uint64{dest}, []uint64{}) + }, []uint64{cfg.DestChain}, []uint64{}) if err != nil { return nil, err } @@ -528,8 +572,8 @@ func DoSendRequest( require.True(t, it.Next()) 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, + cfg.SourceChain, + cfg.DestChain, tx.Hash().String(), it.Event.SequenceNumber, it.Event.Message.Header.Nonce, diff --git a/deployment/environment.go b/deployment/environment.go index d356148c225..bdf9fe6d5de 100644 --- a/deployment/environment.go +++ b/deployment/environment.go @@ -409,6 +409,7 @@ func NodeInfo(nodeIDs []string, oc NodeChainConfigsLister) (Nodes, error) { } type CapabilityRegistryConfig struct { - EVMChainID uint64 // chain id of the chain the CR is deployed on - Contract common.Address // address of the CR contract + EVMChainID uint64 // chain id of the chain the CR is deployed on + Contract common.Address // address of the CR contract + NetworkType string // network type of the chain } diff --git a/deployment/environment/devenv/chain.go b/deployment/environment/devenv/chain.go index cdbaf35e860..ae381e448da 100644 --- a/deployment/environment/devenv/chain.go +++ b/deployment/environment/devenv/chain.go @@ -3,10 +3,12 @@ package devenv import ( "context" "fmt" + "math/big" "time" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethclient" chainselectors "github.com/smartcontractkit/chain-selectors" @@ -21,12 +23,69 @@ const ( // ChainConfig holds the configuration for a with a deployer key which can be used to send transactions to the chain. type ChainConfig struct { - ChainID uint64 // chain id as per EIP-155, mainly applicable for EVM chains - ChainName string // name of the chain populated from chainselector repo - ChainType string // should denote the chain family. Acceptable values are EVM, COSMOS, SOLANA, STARKNET, APTOS etc - WSRPCs []string // websocket rpcs to connect to the chain - HTTPRPCs []string // http rpcs to connect to the chain - DeployerKey *bind.TransactOpts // key to send transactions to the chain + ChainID uint64 // chain id as per EIP-155, mainly applicable for EVM chains + ChainName string // name of the chain populated from chainselector repo + ChainType string // should denote the chain family. Acceptable values are EVM, COSMOS, SOLANA, STARKNET, APTOS etc + WSRPCs []string // websocket rpcs to connect to the chain + HTTPRPCs []string // http rpcs to connect to the chain + DeployerKey *bind.TransactOpts // key to deploy and configure contracts on the chain + Users []*bind.TransactOpts // map of addresses to their transact opts to interact with the chain as users +} + +func (c *ChainConfig) SetUsers(pvtkeys []string) error { + if pvtkeys == nil { + // if no private keys are provided, set deployer key as the user + if c.DeployerKey != nil { + c.Users = []*bind.TransactOpts{c.DeployerKey} + return nil + } else { + return fmt.Errorf("no private keys provided for users, deployer key is also not set") + } + } + c.Users = make([]*bind.TransactOpts, len(pvtkeys)) + for _, pvtKeyStr := range pvtkeys { + pvtKey, err := crypto.HexToECDSA(pvtKeyStr) + if err != nil { + return fmt.Errorf("failed to convert private key to ECDSA: %w", err) + } + user, err := bind.NewKeyedTransactorWithChainID(pvtKey, new(big.Int).SetUint64(c.ChainID)) + if err != nil { + return fmt.Errorf("failed to create transactor: %w", err) + } + c.Users = append(c.Users, user) + } + return nil +} + +// SetDeployerKey sets the deployer key for the chain. If private key is not provided, it fetches the deployer key from KMS. +func (c *ChainConfig) SetDeployerKey(pvtKeyStr *string) error { + if pvtKeyStr != nil && *pvtKeyStr != "" { + pvtKey, err := crypto.HexToECDSA(*pvtKeyStr) + if err != nil { + return fmt.Errorf("failed to convert private key to ECDSA: %w", err) + } + deployer, err := bind.NewKeyedTransactorWithChainID(pvtKey, new(big.Int).SetUint64(c.ChainID)) + if err != nil { + return fmt.Errorf("failed to create transactor: %w", err) + } + fmt.Printf("Deployer Address: %s for chain id %d\n", deployer.From.Hex(), c.ChainID) + c.DeployerKey = deployer + return nil + } + kmsConfig, err := deployment.KMSConfigFromEnvVars() + if err != nil { + return fmt.Errorf("failed to get kms config from env vars: %w", err) + } + kmsClient, err := deployment.NewKMSClient(kmsConfig) + if err != nil { + return fmt.Errorf("failed to create KMS client: %w", err) + } + evmKMSClient := deployment.NewEVMKMSClient(kmsClient, kmsConfig.KmsDeployerKeyId) + c.DeployerKey, err = evmKMSClient.GetKMSTransactOpts(context.Background(), new(big.Int).SetUint64(c.ChainID)) + if err != nil { + return fmt.Errorf("failed to get transactor from KMS client: %w", err) + } + return nil } func NewChains(logger logger.Logger, configs []ChainConfig) (map[uint64]deployment.Chain, error) { diff --git a/deployment/environment/devenv/environment.go b/deployment/environment/devenv/environment.go index e9586467acd..094eba99adf 100644 --- a/deployment/environment/devenv/environment.go +++ b/deployment/environment/devenv/environment.go @@ -14,10 +14,8 @@ const ( ) type EnvironmentConfig struct { - Chains []ChainConfig - HomeChainSelector uint64 - FeedChainSelector uint64 - JDConfig JDConfig + Chains []ChainConfig + JDConfig JDConfig } func NewEnvironment(ctx func() context.Context, lggr logger.Logger, config EnvironmentConfig) (*deployment.Environment, *DON, error) { diff --git a/deployment/environment/memory/chain.go b/deployment/environment/memory/chain.go index 1bb359f9c53..cbb3e67df7a 100644 --- a/deployment/environment/memory/chain.go +++ b/deployment/environment/memory/chain.go @@ -20,6 +20,7 @@ import ( type EVMChain struct { Backend *simulated.Backend DeployerKey *bind.TransactOpts + Users []*bind.TransactOpts } func fundAddress(t *testing.T, from *bind.TransactOpts, to common.Address, amount *big.Int, backend *simulated.Backend) { @@ -42,7 +43,7 @@ func fundAddress(t *testing.T, from *bind.TransactOpts, to common.Address, amoun backend.Commit() } -func GenerateChains(t *testing.T, numChains int) map[uint64]EVMChain { +func GenerateChains(t *testing.T, numChains int, numUsers int) map[uint64]EVMChain { chains := make(map[uint64]EVMChain) for i := 0; i < numChains; i++ { chainID := chainsel.TEST_90000001.EvmChainID + uint64(i) @@ -50,14 +51,25 @@ func GenerateChains(t *testing.T, numChains int) map[uint64]EVMChain { require.NoError(t, err) owner, err := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337)) require.NoError(t, err) + genesis := types.GenesisAlloc{ + owner.From: {Balance: big.NewInt(0).Mul(big.NewInt(7000), big.NewInt(params.Ether))}} + // create a set of user keys + var users []*bind.TransactOpts + for j := 0; j < numUsers; j++ { + key, err := crypto.GenerateKey() + require.NoError(t, err) + user, err := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337)) + require.NoError(t, err) + users = append(users, user) + genesis[user.From] = types.Account{Balance: big.NewInt(0).Mul(big.NewInt(7000), big.NewInt(params.Ether))} + } // there have to be enough initial funds on each chain to allocate for all the nodes that share the given chain in the test - backend := simulated.NewBackend(types.GenesisAlloc{ - owner.From: {Balance: big.NewInt(0).Mul(big.NewInt(7000), big.NewInt(params.Ether))}}, - simulated.WithBlockGasLimit(50000000)) + backend := simulated.NewBackend(genesis, simulated.WithBlockGasLimit(50000000)) backend.Commit() // ts will be now. chains[chainID] = EVMChain{ Backend: backend, DeployerKey: owner, + Users: users, } } return chains diff --git a/deployment/environment/memory/environment.go b/deployment/environment/memory/environment.go index f91bf896c8f..83346a60602 100644 --- a/deployment/environment/memory/environment.go +++ b/deployment/environment/memory/environment.go @@ -14,6 +14,7 @@ import ( chainsel "github.com/smartcontractkit/chain-selectors" "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" + "github.com/smartcontractkit/chainlink/deployment" "github.com/smartcontractkit/chainlink-common/pkg/logger" @@ -24,10 +25,11 @@ const ( ) type MemoryEnvironmentConfig struct { - Chains int - Nodes int - Bootstraps int - RegistryConfig deployment.CapabilityRegistryConfig + Chains int + NumOfUsersPerChain int + Nodes int + Bootstraps int + RegistryConfig deployment.CapabilityRegistryConfig } // For placeholders like aptos @@ -44,9 +46,15 @@ func NewMemoryChain(t *testing.T, selector uint64) deployment.Chain { // Needed for environment variables on the node which point to prexisitng addresses. // i.e. CapReg. -func NewMemoryChains(t *testing.T, numChains int) map[uint64]deployment.Chain { - mchains := GenerateChains(t, numChains) - return generateMemoryChain(t, mchains) +func NewMemoryChains(t *testing.T, numChains int, numUsers int) (map[uint64]deployment.Chain, map[uint64][]*bind.TransactOpts) { + mchains := GenerateChains(t, numChains, numUsers) + users := make(map[uint64][]*bind.TransactOpts) + for id, chain := range mchains { + sel, err := chainsel.SelectorFromChainId(id) + require.NoError(t, err) + users[sel] = chain.Users + } + return generateMemoryChain(t, mchains), users } func NewMemoryChainsWithChainIDs(t *testing.T, chainIDs []uint64) map[uint64]deployment.Chain { @@ -134,7 +142,7 @@ func NewMemoryEnvironmentFromChainsNodes( // To be used by tests and any kind of deployment logic. func NewMemoryEnvironment(t *testing.T, lggr logger.Logger, logLevel zapcore.Level, config MemoryEnvironmentConfig) deployment.Environment { - chains := NewMemoryChains(t, config.Chains) + chains, _ := NewMemoryChains(t, config.Chains, config.NumOfUsersPerChain) nodes := NewNodes(t, logLevel, chains, config.Nodes, config.Bootstraps, config.RegistryConfig) var nodeIDs []string for id := range nodes { diff --git a/deployment/environment/memory/node_test.go b/deployment/environment/memory/node_test.go index 7cbcb66d04a..78bc2db90e5 100644 --- a/deployment/environment/memory/node_test.go +++ b/deployment/environment/memory/node_test.go @@ -8,11 +8,12 @@ import ( "go.uber.org/zap/zapcore" "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" + "github.com/smartcontractkit/chainlink/deployment" ) func TestNode(t *testing.T) { - chains := NewMemoryChains(t, 3) + chains, _ := NewMemoryChains(t, 3, 5) ports := freeport.GetN(t, 1) node := NewNode(t, ports[0], chains, zapcore.DebugLevel, false, deployment.CapabilityRegistryConfig{}) // We expect 3 transmitter keys diff --git a/deployment/evm_kmsclient.go b/deployment/evm_kmsclient.go index 07af77523c8..b28a3842930 100644 --- a/deployment/evm_kmsclient.go +++ b/deployment/evm_kmsclient.go @@ -8,6 +8,7 @@ import ( "encoding/hex" "fmt" "math/big" + "os" "github.com/aws/aws-sdk-go/aws/session" @@ -231,3 +232,21 @@ var awsSessionFromProfileFn = func(config KMS) *session.Session { }, })) } + +func KMSConfigFromEnvVars() (KMS, error) { + var config KMS + var exists bool + config.KmsDeployerKeyId, exists = os.LookupEnv("KMS_DEPLOYER_KEY_ID") + if !exists { + return config, fmt.Errorf("KMS_DEPLOYER_KEY_ID is required") + } + config.KmsDeployerKeyRegion, exists = os.LookupEnv("KMS_DEPLOYER_KEY_REGION") + if !exists { + return config, fmt.Errorf("KMS_DEPLOYER_KEY_REGION is required") + } + config.AwsProfileName, exists = os.LookupEnv("AWS_PROFILE") + if !exists { + return config, fmt.Errorf("AWS_PROFILE is required") + } + return config, nil +} diff --git a/deployment/keystone/changeset/internal/test/utils.go b/deployment/keystone/changeset/internal/test/utils.go index 7c0ab557a83..268ad169ca7 100644 --- a/deployment/keystone/changeset/internal/test/utils.go +++ b/deployment/keystone/changeset/internal/test/utils.go @@ -18,7 +18,7 @@ import ( "github.com/smartcontractkit/chainlink/deployment/environment/memory" kslib "github.com/smartcontractkit/chainlink/deployment/keystone" - internal "github.com/smartcontractkit/chainlink/deployment/keystone/changeset/internal" + "github.com/smartcontractkit/chainlink/deployment/keystone/changeset/internal" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/capabilities_registry" kcr "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/capabilities_registry" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" @@ -242,7 +242,7 @@ func (cc *CapabilityCache) AddCapabilities(lggr logger.Logger, chain deployment. } func testChain(t *testing.T) deployment.Chain { - chains := memory.NewMemoryChains(t, 1) + chains, _ := memory.NewMemoryChains(t, 1, 5) var chain deployment.Chain for _, c := range chains { chain = c diff --git a/deployment/keystone/changeset/internal/update_nodes_test.go b/deployment/keystone/changeset/internal/update_nodes_test.go index 395f1060465..b167f210811 100644 --- a/deployment/keystone/changeset/internal/update_nodes_test.go +++ b/deployment/keystone/changeset/internal/update_nodes_test.go @@ -14,9 +14,10 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink/deployment" kslib "github.com/smartcontractkit/chainlink/deployment/keystone" - internal "github.com/smartcontractkit/chainlink/deployment/keystone/changeset/internal" + "github.com/smartcontractkit/chainlink/deployment/keystone/changeset/internal" kstest "github.com/smartcontractkit/chainlink/deployment/keystone/changeset/internal/test" "github.com/smartcontractkit/chainlink/deployment/environment/memory" @@ -679,7 +680,7 @@ func testPeerID(t *testing.T, s string) p2pkey.PeerID { } func testChain(t *testing.T) deployment.Chain { - chains := memory.NewMemoryChains(t, 1) + chains, _ := memory.NewMemoryChains(t, 1, 5) var chain deployment.Chain for _, c := range chains { chain = c diff --git a/integration-tests/contracts/ccipreader_test.go b/integration-tests/contracts/ccipreader_test.go index 0144ddf05f1..5f17bb61d85 100644 --- a/integration-tests/contracts/ccipreader_test.go +++ b/integration-tests/contracts/ccipreader_test.go @@ -18,6 +18,7 @@ import ( "golang.org/x/exp/maps" "github.com/smartcontractkit/chainlink-ccip/plugintypes" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" "github.com/smartcontractkit/chainlink/deployment/environment/memory" "github.com/smartcontractkit/chainlink/integration-tests/utils/pgtest" @@ -519,7 +520,11 @@ func TestCCIPReader_GetExpectedNextSequenceNumber(t *testing.T) { t.Parallel() ctx := tests.Context(t) //env := NewMemoryEnvironmentContractsOnly(t, logger.TestLogger(t), 2, 4, nil) - env := changeset.NewMemoryEnvironmentWithJobsAndContracts(t, logger.TestLogger(t), 2, 4, nil) + env := changeset.NewMemoryEnvironmentWithJobsAndContracts(t, logger.TestLogger(t), memory.MemoryEnvironmentConfig{ + Chains: 2, + Nodes: 4, + Bootstraps: 1, + }, nil) state, err := changeset.LoadOnchainState(env.Env) require.NoError(t, err) @@ -628,7 +633,11 @@ func TestCCIPReader_Nonces(t *testing.T) { func Test_GetChainFeePriceUpdates(t *testing.T) { t.Parallel() ctx := tests.Context(t) - env := changeset.NewMemoryEnvironmentWithJobsAndContracts(t, logger.TestLogger(t), 2, 4, nil) + env := changeset.NewMemoryEnvironmentWithJobsAndContracts(t, logger.TestLogger(t), memory.MemoryEnvironmentConfig{ + Chains: 2, + Nodes: 4, + Bootstraps: 1, + }, nil) state, err := changeset.LoadOnchainState(env.Env) require.NoError(t, err) @@ -684,7 +693,11 @@ func Test_GetChainFeePriceUpdates(t *testing.T) { func Test_LinkPriceUSD(t *testing.T) { t.Parallel() ctx := tests.Context(t) - env := changeset.NewMemoryEnvironmentWithJobsAndContracts(t, logger.TestLogger(t), 2, 4, nil) + env := changeset.NewMemoryEnvironmentWithJobsAndContracts(t, logger.TestLogger(t), memory.MemoryEnvironmentConfig{ + Chains: 2, + Nodes: 4, + Bootstraps: 1, + }, nil) state, err := changeset.LoadOnchainState(env.Env) require.NoError(t, err) @@ -719,7 +732,11 @@ func Test_LinkPriceUSD(t *testing.T) { func Test_GetMedianDataAvailabilityGasConfig(t *testing.T) { t.Parallel() ctx := tests.Context(t) - env := changeset.NewMemoryEnvironmentWithJobsAndContracts(t, logger.TestLogger(t), 4, 4, nil) + env := changeset.NewMemoryEnvironmentWithJobsAndContracts(t, logger.TestLogger(t), memory.MemoryEnvironmentConfig{ + Chains: 4, + Nodes: 4, + Bootstraps: 1, + }, nil) state, err := changeset.LoadOnchainState(env.Env) require.NoError(t, err) @@ -778,7 +795,11 @@ func Test_GetMedianDataAvailabilityGasConfig(t *testing.T) { func Test_GetWrappedNativeTokenPriceUSD(t *testing.T) { t.Parallel() ctx := tests.Context(t) - env := changeset.NewMemoryEnvironmentWithJobsAndContracts(t, logger.TestLogger(t), 2, 4, nil) + env := changeset.NewMemoryEnvironmentWithJobsAndContracts(t, logger.TestLogger(t), memory.MemoryEnvironmentConfig{ + Chains: 2, + Nodes: 4, + Bootstraps: 1, + }, nil) state, err := changeset.LoadOnchainState(env.Env) require.NoError(t, err) diff --git a/integration-tests/smoke/ccip/ccip_fee_boosting_test.go b/integration-tests/smoke/ccip/ccip_fee_boosting_test.go index f376fb15b4a..1fe9d5817c9 100644 --- a/integration-tests/smoke/ccip/ccip_fee_boosting_test.go +++ b/integration-tests/smoke/ccip/ccip_fee_boosting_test.go @@ -19,10 +19,13 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" "github.com/smartcontractkit/chainlink-testing-framework/lib/utils/testcontext" + + "github.com/smartcontractkit/chainlink/deployment/environment/memory" "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/ccipevm" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/fee_quoter" cciptypes "github.com/smartcontractkit/chainlink-ccip/pkg/types/ccipocr3" + "github.com/smartcontractkit/chainlink/deployment" "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/onramp" @@ -36,19 +39,24 @@ var ( ) func Test_CCIPFeeBoosting(t *testing.T) { - e := changeset.NewMemoryEnvironmentWithJobsAndContracts(t, logger.TestLogger(t), 2, 4, &changeset.TestConfigs{ - OCRConfigOverride: func(params changeset.CCIPOCRParams) changeset.CCIPOCRParams { - // Only 1 boost (=OCR round) is enough to cover the fee - params.ExecuteOffChainConfig.RelativeBoostPerWaitHour = 10 - // Disable token price updates - params.CommitOffChainConfig.TokenPriceBatchWriteFrequency = *config.MustNewDuration(1_000_000 * time.Hour) - // Disable gas price updates - params.CommitOffChainConfig.RemoteGasPriceBatchWriteFrequency = *config.MustNewDuration(1_000_000 * time.Hour) - // Disable token price updates - params.CommitOffChainConfig.TokenInfo = nil - return params - }, - }) + e := changeset.NewMemoryEnvironmentWithJobsAndContracts(t, logger.TestLogger(t), + memory.MemoryEnvironmentConfig{ + Chains: 2, + Nodes: 4, + Bootstraps: 1, + }, &changeset.TestConfigs{ + OCRConfigOverride: func(params changeset.CCIPOCRParams) changeset.CCIPOCRParams { + // Only 1 boost (=OCR round) is enough to cover the fee + params.ExecuteOffChainConfig.RelativeBoostPerWaitHour = 10 + // Disable token price updates + params.CommitOffChainConfig.TokenPriceBatchWriteFrequency = *config.MustNewDuration(1_000_000 * time.Hour) + // Disable gas price updates + params.CommitOffChainConfig.RemoteGasPriceBatchWriteFrequency = *config.MustNewDuration(1_000_000 * time.Hour) + // Disable token price updates + params.CommitOffChainConfig.TokenInfo = nil + return params + }, + }) state, err := changeset.LoadOnchainState(e.Env) require.NoError(t, err) diff --git a/integration-tests/smoke/ccip/ccip_fees_test.go b/integration-tests/smoke/ccip/ccip_fees_test.go index adf73edad7a..791ba8f2619 100644 --- a/integration-tests/smoke/ccip/ccip_fees_test.go +++ b/integration-tests/smoke/ccip/ccip_fees_test.go @@ -11,8 +11,10 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" "github.com/smartcontractkit/chainlink-testing-framework/lib/utils/testcontext" + "github.com/smartcontractkit/chainlink/deployment" "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" + "github.com/smartcontractkit/chainlink/deployment/environment/memory" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/weth9_wrapper" @@ -99,7 +101,11 @@ func setupTokens( func Test_CCIPFees(t *testing.T) { t.Parallel() - tenv := changeset.NewMemoryEnvironmentWithJobsAndContracts(t, logger.TestLogger(t), 2, 4, nil) + tenv := changeset.NewMemoryEnvironmentWithJobsAndContracts(t, logger.TestLogger(t), memory.MemoryEnvironmentConfig{ + Chains: 2, + Nodes: 4, + Bootstraps: 1, + }, nil) e := tenv.Env allChains := tenv.Env.AllChainSelectors() @@ -220,9 +226,13 @@ func Test_CCIPFees(t *testing.T) { _, _, err = changeset.CCIPSendRequest( e, state, - sourceChain, destChain, - true, - ccipMessage, + &changeset.CCIPSendReqConfig{ + Sender: e.Chains[sourceChain].DeployerKey, + IsTestRouter: true, + SourceChain: sourceChain, + DestChain: destChain, + Evm2AnyMessage: ccipMessage, + }, ) require.Error(t, err) }) diff --git a/integration-tests/smoke/ccip/ccip_message_limitations_test.go b/integration-tests/smoke/ccip/ccip_message_limitations_test.go index a86644bae7e..902d07aec5c 100644 --- a/integration-tests/smoke/ccip/ccip_message_limitations_test.go +++ b/integration-tests/smoke/ccip/ccip_message_limitations_test.go @@ -12,6 +12,7 @@ import ( "golang.org/x/exp/maps" "github.com/smartcontractkit/chainlink-testing-framework/lib/utils/testcontext" + "github.com/smartcontractkit/chainlink/deployment" "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" testsetups "github.com/smartcontractkit/chainlink/integration-tests/testsetups/ccip" @@ -153,7 +154,11 @@ func Test_CCIPMessageLimitations(t *testing.T) { require.NotEqual(t, msg.fromChain, msg.toChain, "fromChain and toChain cannot be the same") startBlocks[msg.toChain] = nil msgSentEvent, err := changeset.DoSendRequest( - t, testEnv.Env, onChainState, msg.fromChain, msg.toChain, false, msg.msg) + t, testEnv.Env, onChainState, + changeset.WithSourceChain(msg.fromChain), + changeset.WithDestChain(msg.toChain), + changeset.WithTestRouter(false), + changeset.WithEvm2AnyMessage(msg.msg)) if msg.expRevert { t.Logf("Message reverted as expected") diff --git a/integration-tests/smoke/ccip/ccip_messaging_test.go b/integration-tests/smoke/ccip/ccip_messaging_test.go index 446f21898a0..07e237451c8 100644 --- a/integration-tests/smoke/ccip/ccip_messaging_test.go +++ b/integration-tests/smoke/ccip/ccip_messaging_test.go @@ -15,8 +15,10 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/hashutil" "github.com/smartcontractkit/chainlink-common/pkg/merklemulti" "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" + "github.com/smartcontractkit/chainlink/deployment" "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" + "github.com/smartcontractkit/chainlink/deployment/environment/memory" "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" @@ -46,7 +48,11 @@ type messagingTestCaseOutput struct { func Test_CCIPMessaging(t *testing.T) { // Setup 2 chains and a single lane. ctx := changeset.Context(t) - e := changeset.NewMemoryEnvironmentWithJobsAndContracts(t, logger.TestLogger(t), 2, 4, nil) + e := changeset.NewMemoryEnvironmentWithJobsAndContracts(t, logger.TestLogger(t), memory.MemoryEnvironmentConfig{ + Chains: 2, + Nodes: 4, + Bootstraps: 1, + }, nil) state, err := changeset.LoadOnchainState(e.Env) require.NoError(t, err) diff --git a/integration-tests/smoke/ccip/ccip_test.go b/integration-tests/smoke/ccip/ccip_test.go index fb6fb2cf960..ca30c9281c4 100644 --- a/integration-tests/smoke/ccip/ccip_test.go +++ b/integration-tests/smoke/ccip/ccip_test.go @@ -7,6 +7,7 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-testing-framework/lib/utils/testcontext" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" testsetups "github.com/smartcontractkit/chainlink/integration-tests/testsetups/ccip" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router" @@ -38,13 +39,20 @@ func TestInitialDeployOnLocal(t *testing.T) { require.NoError(t, err) block := latesthdr.Number.Uint64() startBlocks[dest] = &block - msgSentEvent := changeset.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, - }) + require.GreaterOrEqual(t, len(tenv.Users[src]), 2) + msgSentEvent, err := changeset.DoSendRequest(t, e, state, + changeset.WithSender(tenv.Users[src][1]), + changeset.WithSourceChain(src), + changeset.WithDestChain(dest), + changeset.WithTestRouter(false), + changeset.WithEvm2AnyMessage(router.ClientEVM2AnyMessage{ + Receiver: common.LeftPadBytes(state.Chains[dest].Receiver.Address().Bytes(), 32), + Data: []byte("hello world"), + TokenAmounts: nil, + FeeToken: common.HexToAddress("0x0"), + ExtraArgs: nil, + })) + require.NoError(t, err) expectedSeqNum[changeset.SourceDestPair{ SourceChainSelector: src, DestChainSelector: dest, diff --git a/integration-tests/testconfig/ccip/ccip.toml b/integration-tests/testconfig/ccip/ccip.toml index 85e645ed0b9..3f4ba43c48c 100644 --- a/integration-tests/testconfig/ccip/ccip.toml +++ b/integration-tests/testconfig/ccip/ccip.toml @@ -9,8 +9,17 @@ selected_networks = ['SIMULATED_1', 'SIMULATED_2'] evm_name = 'chain-1337' evm_chain_id = 1337 evm_keys = [ - "ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80", "59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d", + "ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80", + "5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a", + "7c852118294e51e653712a81e05800f419141751be58f605c371e15141b007a6", + "47e179ec197488593b187f80a00eb0da91f1b9d0b13f8733639f19c30a34926a", + "8b3a350cf5c34c9194ca85829a2df0ec3153be0318b5e2d3348e872092edffba", + "92db14e403b83dfe3df233f83dfa3a0d7096f21ca9b0d6d6b8d88b2b4ec1564e", + "4bbbf85ce3377467afe5d46f804f221813b2bb87f24d81f60f1fcdbf7cbf4356", + "dbda1821b80551c9d65939329250298aa3472ba22feea921c0cf5d620ea67b97", + "2a871d0798f97d79848a013d4936a73bf4cc922c825d33c1cf7073dff6d409c6", + "f214f2b2cd398c806f84e317254e0f0b801d0643303237d97a22a48e01628897" ] evm_simulated = true client_implementation = 'Ethereum' @@ -28,6 +37,15 @@ evm_chain_id = 2337 evm_keys = [ "59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d", "ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80", + "5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a", + "7c852118294e51e653712a81e05800f419141751be58f605c371e15141b007a6", + "47e179ec197488593b187f80a00eb0da91f1b9d0b13f8733639f19c30a34926a", + "8b3a350cf5c34c9194ca85829a2df0ec3153be0318b5e2d3348e872092edffba", + "92db14e403b83dfe3df233f83dfa3a0d7096f21ca9b0d6d6b8d88b2b4ec1564e", + "4bbbf85ce3377467afe5d46f804f221813b2bb87f24d81f60f1fcdbf7cbf4356", + "dbda1821b80551c9d65939329250298aa3472ba22feea921c0cf5d620ea67b97", + "2a871d0798f97d79848a013d4936a73bf4cc922c825d33c1cf7073dff6d409c6", + "f214f2b2cd398c806f84e317254e0f0b801d0643303237d97a22a48e01628897" ] evm_simulated = true client_implementation = 'Ethereum' @@ -45,6 +63,15 @@ evm_chain_id = 3337 evm_keys = [ "59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d", "ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80", + "5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a", + "7c852118294e51e653712a81e05800f419141751be58f605c371e15141b007a6", + "47e179ec197488593b187f80a00eb0da91f1b9d0b13f8733639f19c30a34926a", + "8b3a350cf5c34c9194ca85829a2df0ec3153be0318b5e2d3348e872092edffba", + "92db14e403b83dfe3df233f83dfa3a0d7096f21ca9b0d6d6b8d88b2b4ec1564e", + "4bbbf85ce3377467afe5d46f804f221813b2bb87f24d81f60f1fcdbf7cbf4356", + "dbda1821b80551c9d65939329250298aa3472ba22feea921c0cf5d620ea67b97", + "2a871d0798f97d79848a013d4936a73bf4cc922c825d33c1cf7073dff6d409c6", + "f214f2b2cd398c806f84e317254e0f0b801d0643303237d97a22a48e01628897" ] evm_simulated = true client_implementation = 'Ethereum' @@ -144,6 +171,15 @@ chain_id = 1337 addresses_to_fund = [ "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", "0x70997970C51812dc3A010C7d01b50e0d17dc79C8", + "0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc", + "0x90f79bf6eb2c4f870365e785982e1f101e93b906", + "0x15d34aaf54267db7d7c367839aaf71a00a2c6a65", + "0x9965507d1a55bcc2695c58ba16fb37d819b0a4dc", + "0x976ea74026e726554db657fa54763abd0c3a0aa9", + "0x14dc79964da2c08b23698b3d3cc7ca32193d9955", + "0x23618e81e3f5cdf7f54c3d65f7fbc0abf5b21e8f", + "0xa0ee7a142d267c1f36714e4a8f75612f20a79720", + "0xBcd4042DE499D14e55001CcbB24a551F3b954096" ] @@ -166,6 +202,15 @@ chain_id = 2337 addresses_to_fund = [ "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", "0x70997970C51812dc3A010C7d01b50e0d17dc79C8", + "0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc", + "0x90f79bf6eb2c4f870365e785982e1f101e93b906", + "0x15d34aaf54267db7d7c367839aaf71a00a2c6a65", + "0x9965507d1a55bcc2695c58ba16fb37d819b0a4dc", + "0x976ea74026e726554db657fa54763abd0c3a0aa9", + "0x14dc79964da2c08b23698b3d3cc7ca32193d9955", + "0x23618e81e3f5cdf7f54c3d65f7fbc0abf5b21e8f", + "0xa0ee7a142d267c1f36714e4a8f75612f20a79720", + "0xBcd4042DE499D14e55001CcbB24a551F3b954096" ] [CCIP.PrivateEthereumNetworks.SIMULATED_3] @@ -181,6 +226,15 @@ chain_id = 3337 addresses_to_fund = [ "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", "0x70997970C51812dc3A010C7d01b50e0d17dc79C8", + "0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc", + "0x90f79bf6eb2c4f870365e785982e1f101e93b906", + "0x15d34aaf54267db7d7c367839aaf71a00a2c6a65", + "0x9965507d1a55bcc2695c58ba16fb37d819b0a4dc", + "0x976ea74026e726554db657fa54763abd0c3a0aa9", + "0x14dc79964da2c08b23698b3d3cc7ca32193d9955", + "0x23618e81e3f5cdf7f54c3d65f7fbc0abf5b21e8f", + "0xa0ee7a142d267c1f36714e4a8f75612f20a79720", + "0xBcd4042DE499D14e55001CcbB24a551F3b954096" ] [Seth] diff --git a/integration-tests/testconfig/ccip/config.go b/integration-tests/testconfig/ccip/config.go index 6c1bfcbe560..72c81f05f47 100644 --- a/integration-tests/testconfig/ccip/config.go +++ b/integration-tests/testconfig/ccip/config.go @@ -8,8 +8,6 @@ import ( "github.com/AlekSi/pointer" chainselectors "github.com/smartcontractkit/chain-selectors" - "github.com/smartcontractkit/chainlink-testing-framework/lib/blockchain" - ctfconfig "github.com/smartcontractkit/chainlink-testing-framework/lib/config" "github.com/smartcontractkit/chainlink/deployment/environment/nodeclient" @@ -147,40 +145,46 @@ func (o *JDConfig) GetJDDBVersion() string { } func (o *Config) Validate() error { - return nil -} - -func (o *Config) GetHomeChainSelector(evmNetworks []blockchain.EVMNetwork) (uint64, error) { + var chainIds []int64 + for _, net := range o.PrivateEthereumNetworks { + chainIds = append(chainIds, int64(net.EthereumChainConfig.ChainID)) + } homeChainSelector, err := strconv.ParseUint(pointer.GetString(o.HomeChainSelector), 10, 64) if err != nil { - return 0, err + return err } - isValid, err := IsSelectorValid(homeChainSelector, evmNetworks) + isValid, err := IsSelectorValid(homeChainSelector, chainIds) if err != nil { - return 0, err + return err } if !isValid { - return 0, ErrInvalidHomeChainSelector + return ErrInvalidHomeChainSelector } - return homeChainSelector, nil -} - -func (o *Config) GetFeedChainSelector(evmNetworks []blockchain.EVMNetwork) (uint64, error) { feedChainSelector, err := strconv.ParseUint(pointer.GetString(o.FeedChainSelector), 10, 64) if err != nil { - return 0, err + return err } - isValid, err := IsSelectorValid(feedChainSelector, evmNetworks) + isValid, err = IsSelectorValid(feedChainSelector, chainIds) if err != nil { - return 0, err + return err } if !isValid { - return 0, ErrInvalidFeedChainSelector + return ErrInvalidFeedChainSelector } - return feedChainSelector, nil + return nil +} + +func (o *Config) GetHomeChainSelector() uint64 { + selector, _ := strconv.ParseUint(pointer.GetString(o.HomeChainSelector), 10, 64) + return selector +} + +func (o *Config) GetFeedChainSelector() uint64 { + selector, _ := strconv.ParseUint(pointer.GetString(o.FeedChainSelector), 10, 64) + return selector } -func IsSelectorValid(selector uint64, evmNetworks []blockchain.EVMNetwork) (bool, error) { +func IsSelectorValid(selector uint64, chainIds []int64) (bool, error) { chainId, err := chainselectors.ChainIdFromSelector(selector) if err != nil { return false, err @@ -188,9 +192,9 @@ func IsSelectorValid(selector uint64, evmNetworks []blockchain.EVMNetwork) (bool if chainId >= math.MaxInt64 { return false, fmt.Errorf("chain id overflows int64: %d", chainId) } - id := int64(chainId) - for _, net := range evmNetworks { - if net.ChainID == id { + expId := int64(chainId) + for _, id := range chainIds { + if id == expId { return true, nil } } diff --git a/integration-tests/testsetups/ccip/test_helpers.go b/integration-tests/testsetups/ccip/test_helpers.go index 8ffce77cc6b..ca46357e1d0 100644 --- a/integration-tests/testsetups/ccip/test_helpers.go +++ b/integration-tests/testsetups/ccip/test_helpers.go @@ -10,6 +10,7 @@ import ( "testing" "time" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/smartcontractkit/ccip-owner-contracts/pkg/gethwrappers" chainsel "github.com/smartcontractkit/chain-selectors" @@ -34,6 +35,14 @@ import ( evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" corechainlink "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" + "github.com/AlekSi/pointer" + "github.com/ethereum/go-ethereum/common" + "github.com/rs/zerolog" + "github.com/stretchr/testify/require" + "github.com/subosito/gotenv" + "golang.org/x/sync/errgroup" + "google.golang.org/grpc/credentials/insecure" + "github.com/smartcontractkit/chainlink/deployment/environment/devenv" clclient "github.com/smartcontractkit/chainlink/deployment/environment/nodeclient" "github.com/smartcontractkit/chainlink/integration-tests/actions" @@ -43,17 +52,6 @@ import ( tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig" "github.com/smartcontractkit/chainlink/integration-tests/utils" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/relay" - - "github.com/AlekSi/pointer" - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/crypto" - "github.com/rs/zerolog" - "github.com/stretchr/testify/require" - "github.com/subosito/gotenv" - "golang.org/x/sync/errgroup" - "google.golang.org/grpc/credentials/insecure" ) // DeployedLocalDevEnvironment is a helper struct for setting up a local dev environment with docker @@ -104,12 +102,18 @@ func NewLocalDevEnvironment( require.NotNil(t, envConfig) require.NotEmpty(t, envConfig.Chains, "chainConfigs should not be empty") require.NotEmpty(t, envConfig.JDConfig, "jdUrl should not be empty") + users := make(map[uint64][]*bind.TransactOpts) + for _, chain := range envConfig.Chains { + sel, err := chainsel.SelectorFromChainId(chain.ChainID) + require.NoError(t, err) + users[sel] = chain.Users + } chains, err := devenv.NewChains(lggr, envConfig.Chains) require.NoError(t, err) // locate the home chain - homeChainSel := envConfig.HomeChainSelector + homeChainSel := cfg.CCIP.GetHomeChainSelector() require.NotEmpty(t, homeChainSel, "homeChainSel should not be empty") - feedSel := envConfig.FeedChainSelector + feedSel := cfg.CCIP.GetFeedChainSelector() require.NotEmpty(t, feedSel, "feedSel should not be empty") replayBlocks, err := changeset.LatestBlocksByChain(ctx, chains) require.NoError(t, err) @@ -254,6 +258,7 @@ func NewLocalDevEnvironment( HomeChainSel: homeChainSel, FeedChainSel: feedSel, ReplayBlocks: replayBlocks, + Users: users, }, testEnv, cfg } @@ -460,16 +465,9 @@ func CreateDockerEnv(t *testing.T) ( } require.NotEmpty(t, jdConfig, "JD config is empty") - homeChainSelector, err := cfg.CCIP.GetHomeChainSelector(evmNetworks) - require.NoError(t, err, "Error getting home chain selector") - feedChainSelector, err := cfg.CCIP.GetFeedChainSelector(evmNetworks) - require.NoError(t, err, "Error getting feed chain selector") - return &devenv.EnvironmentConfig{ - Chains: chains, - JDConfig: jdConfig, - HomeChainSelector: homeChainSelector, - FeedChainSelector: feedChainSelector, + Chains: chains, + JDConfig: jdConfig, }, env, cfg } @@ -515,7 +513,7 @@ func StartChainlinkNodes( cfg.NodeConfig.ChainConfigTOMLByChainID, ) - toml.Capabilities.ExternalRegistry.NetworkID = ptr.Ptr(relay.NetworkEVM) + toml.Capabilities.ExternalRegistry.NetworkID = ptr.Ptr(registryConfig.NetworkType) toml.Capabilities.ExternalRegistry.ChainID = ptr.Ptr(strconv.FormatUint(registryConfig.EVMChainID, 10)) toml.Capabilities.ExternalRegistry.Address = ptr.Ptr(registryConfig.Contract.String()) @@ -658,62 +656,73 @@ func CreateChainConfigFromNetworks( networkConfig *ctfconfig.NetworkConfig, ) []devenv.ChainConfig { evmNetworks := networks.MustGetSelectedNetworkConfig(networkConfig) - networkPvtKeys := make(map[int64]string) + networkPvtKeys := make(map[uint64][]string) for _, net := range evmNetworks { require.Greater(t, len(net.PrivateKeys), 0, "No private keys found for network") - networkPvtKeys[net.ChainID] = net.PrivateKeys[0] + if net.ChainID < 0 { + t.Fatalf("negative chain ID: %d", net.ChainID) + } + networkPvtKeys[uint64(net.ChainID)] = net.PrivateKeys + } + type chainDetails struct { + chainId uint64 + wsRPCs []string + httpRPCs []string } var chains []devenv.ChainConfig - // if private ethereum networks are not provided, we will create chains from the network URLs + var chaindetails []chainDetails if len(privateEthereumNetworks) == 0 { for _, net := range evmNetworks { chainId := net.ChainID if chainId < 0 { t.Fatalf("negative chain ID: %d", chainId) } - chainName, err := chainsel.NameFromChainId(uint64(chainId)) - require.NoError(t, err, "Error getting chain name") - pvtKeyStr, exists := networkPvtKeys[chainId] - require.Truef(t, exists, "Private key not found for chain id %d", chainId) - pvtKey, err := crypto.HexToECDSA(pvtKeyStr) - require.NoError(t, err) - deployer, err := bind.NewKeyedTransactorWithChainID(pvtKey, big.NewInt(chainId)) - require.NoError(t, err) - deployer.GasLimit = net.DefaultGasLimit - chains = append(chains, devenv.ChainConfig{ - ChainID: uint64(chainId), - ChainName: chainName, - ChainType: "EVM", - WSRPCs: net.URLs, - HTTPRPCs: net.HTTPURLs, - DeployerKey: deployer, + chaindetails = append(chaindetails, chainDetails{ + chainId: uint64(chainId), + wsRPCs: net.URLs, + httpRPCs: net.HTTPURLs, + }) + } + } else { + for _, net := range privateEthereumNetworks { + chainId := net.EthereumChainConfig.ChainID + if chainId < 0 { + t.Fatalf("negative chain ID: %d", chainId) + } + rpcProvider, err := env.GetRpcProvider(int64(chainId)) + require.NoError(t, err, "Error getting rpc provider") + chaindetails = append(chaindetails, chainDetails{ + chainId: uint64(chainId), + wsRPCs: rpcProvider.PublicWsUrls(), + httpRPCs: rpcProvider.PublicHttpUrls(), }) } - return chains } - for _, networkCfg := range privateEthereumNetworks { - chainId := networkCfg.EthereumChainConfig.ChainID - chainName, err := chainsel.NameFromChainId(uint64(chainId)) + for _, cd := range chaindetails { + chainId := cd.chainId + chainName, err := chainsel.NameFromChainId(chainId) require.NoError(t, err, "Error getting chain name") - rpcProvider, err := env.GetRpcProvider(int64(chainId)) - require.NoError(t, err, "Error getting rpc provider") - pvtKeyStr, exists := networkPvtKeys[int64(chainId)] - require.Truef(t, exists, "Private key not found for chain id %d", chainId) - pvtKey, err := crypto.HexToECDSA(pvtKeyStr) - require.NoError(t, err) - deployer, err := bind.NewKeyedTransactorWithChainID(pvtKey, big.NewInt(int64(chainId))) - require.NoError(t, err) - if chainId < 0 { - t.Fatalf("negative chain ID: %d", chainId) + chainCfg := devenv.ChainConfig{ + ChainID: chainId, + ChainName: chainName, + ChainType: "EVM", + WSRPCs: cd.wsRPCs, + HTTPRPCs: cd.httpRPCs, } - chains = append(chains, devenv.ChainConfig{ - ChainID: uint64(chainId), - ChainName: chainName, - ChainType: devenv.EVMChainType, - WSRPCs: rpcProvider.PublicWsUrls(), - HTTPRPCs: rpcProvider.PublicHttpUrls(), - DeployerKey: deployer, - }) + var pvtKey *string + // if private keys are provided, use the first private key as deployer key + // otherwise it will try to load the private key from KMS + if len(networkPvtKeys[chainId]) > 0 { + pvtKey = ptr.Ptr(networkPvtKeys[chainId][0]) + } + require.NoError(t, chainCfg.SetDeployerKey(pvtKey), "Error setting deployer key") + var additionalPvtKeys []string + if len(networkPvtKeys[chainId]) > 1 { + additionalPvtKeys = networkPvtKeys[chainId][1:] + } + // if no additional private keys are provided, this will set the users to default deployer key + require.NoError(t, chainCfg.SetUsers(additionalPvtKeys), "Error setting users") + chains = append(chains, chainCfg) } return chains }