From fd9e98a7636867c318cea030c203d1094e3254c0 Mon Sep 17 00:00:00 2001 From: anirudhwarrier <12178754+anirudhwarrier@users.noreply.github.com> Date: Fri, 20 Sep 2024 15:54:48 +0530 Subject: [PATCH] add multicall contract in pre-deployed contracts --- .../actions/automation_ocr_helpers.go | 53 ++++++++- integration-tests/actions/keeper_helpers.go | 4 +- .../chaos/automation_chaos_test.go | 4 +- .../reorg/automation_reorg_test.go | 1 + integration-tests/smoke/automation_test.go | 109 ++---------------- integration-tests/smoke/log_poller_test.go | 15 +-- .../testconfig/automation/config.go | 32 +++++ .../testsetups/keeper_benchmark.go | 2 +- 8 files changed, 100 insertions(+), 120 deletions(-) diff --git a/integration-tests/actions/automation_ocr_helpers.go b/integration-tests/actions/automation_ocr_helpers.go index f1845804677..c6cbd2b51e2 100644 --- a/integration-tests/actions/automation_ocr_helpers.go +++ b/integration-tests/actions/automation_ocr_helpers.go @@ -6,6 +6,10 @@ import ( "math/big" "testing" + "github.com/ethereum/go-ethereum/common" + + tt "github.com/smartcontractkit/chainlink/integration-tests/types" + "github.com/pkg/errors" "github.com/smartcontractkit/chainlink-testing-framework/seth" @@ -34,10 +38,10 @@ func DeployAutoOCRRegistryAndRegistrar( // DeployConsumers deploys and registers keeper consumers. If ephemeral addresses are enabled, it will deploy and register the consumers from ephemeral addresses, but each upkpeep will be registered with root key address as the admin. Which means // that functions like setting upkeep configuration, pausing, unpausing, etc. will be done by the root key address. It deploys multicall contract and sends link funds to each deployment address. -func DeployConsumers(t *testing.T, chainClient *seth.Client, registry contracts.KeeperRegistry, registrar contracts.KeeperRegistrar, linkToken contracts.LinkToken, numberOfUpkeeps int, linkFundsForEachUpkeep *big.Int, upkeepGasLimit uint32, isLogTrigger bool, isMercury bool, isBillingTokenNative bool, wethToken contracts.WETHToken) ([]contracts.KeeperConsumer, []*big.Int) { +func DeployConsumers(t *testing.T, chainClient *seth.Client, registry contracts.KeeperRegistry, registrar contracts.KeeperRegistrar, linkToken contracts.LinkToken, numberOfUpkeeps int, linkFundsForEachUpkeep *big.Int, upkeepGasLimit uint32, isLogTrigger bool, isMercury bool, isBillingTokenNative bool, wethToken contracts.WETHToken, config tt.AutomationTestConfig) ([]contracts.KeeperConsumer, []*big.Int) { // Fund deployers with LINK, no need to do this for Native token if !isBillingTokenNative { - err := DeployMultiCallAndFundDeploymentAddresses(chainClient, linkToken, numberOfUpkeeps, linkFundsForEachUpkeep) + err := SetupMultiCallAndFundDeploymentAddresses(chainClient, linkToken, numberOfUpkeeps, linkFundsForEachUpkeep, config) require.NoError(t, err, "Sending link funds to deployment addresses shouldn't fail") } @@ -69,12 +73,13 @@ func DeployPerformanceConsumers( blockInterval, // Interval of blocks that upkeeps are expected to be performed checkGasToBurn, // How much gas should be burned on checkUpkeep() calls performGasToBurn int64, // How much gas should be burned on performUpkeep() calls + config tt.AutomationTestConfig, ) ([]contracts.KeeperConsumerPerformance, []*big.Int) { upkeeps := DeployKeeperConsumersPerformance( t, chainClient, numberOfUpkeeps, blockRange, blockInterval, checkGasToBurn, performGasToBurn, ) - err := DeployMultiCallAndFundDeploymentAddresses(chainClient, linkToken, numberOfUpkeeps, linkFundsForEachUpkeep) + err := SetupMultiCallAndFundDeploymentAddresses(chainClient, linkToken, numberOfUpkeeps, linkFundsForEachUpkeep, config) require.NoError(t, err, "Sending link funds to deployment addresses shouldn't fail") var upkeepsAddresses []string @@ -97,10 +102,11 @@ func DeployPerformDataCheckerConsumers( linkFundsForEachUpkeep *big.Int, upkeepGasLimit uint32, expectedData []byte, + config tt.AutomationTestConfig, ) ([]contracts.KeeperPerformDataChecker, []*big.Int) { upkeeps := DeployPerformDataChecker(t, chainClient, numberOfUpkeeps, expectedData) - err := DeployMultiCallAndFundDeploymentAddresses(chainClient, linkToken, numberOfUpkeeps, linkFundsForEachUpkeep) + err := SetupMultiCallAndFundDeploymentAddresses(chainClient, linkToken, numberOfUpkeeps, linkFundsForEachUpkeep, config) require.NoError(t, err, "Sending link funds to deployment addresses shouldn't fail") var upkeepsAddresses []string @@ -111,6 +117,45 @@ func DeployPerformDataCheckerConsumers( return upkeeps, upkeepIds } +func SetupMultiCallAddress(chainClient *seth.Client, testConfig tt.AutomationTestConfig) (common.Address, error) { + if testConfig.GetAutomationConfig().UseExistingMultiCallContract() { + multiCallAddress, err := testConfig.GetAutomationConfig().MultiCallContractAddress() + if err != nil { + return common.Address{}, errors.Wrap(err, "Error getting existing multicall contract address") + } + return multiCallAddress, nil + } + + multicallAddress, err := contracts.DeployMultiCallContract(chainClient) + if err != nil { + return common.Address{}, errors.Wrap(err, "Error deploying multicall contract") + } + return multicallAddress, nil +} + +// SetupMultiCallAndFundDeploymentAddresses setups multicall contract and sends link funds to each deployment address +func SetupMultiCallAndFundDeploymentAddresses( + chainClient *seth.Client, + linkToken contracts.LinkToken, + numberOfUpkeeps int, + linkFundsForEachUpkeep *big.Int, + testConfig tt.AutomationTestConfig, +) error { + concurrency, err := GetAndAssertCorrectConcurrency(chainClient, 1) + if err != nil { + return err + } + + operationsPerAddress := numberOfUpkeeps / concurrency + + multicallAddress, err := SetupMultiCallAddress(chainClient, testConfig) + if err != nil { + return errors.Wrap(err, "Error deploying multicall contract") + } + + return SendLinkFundsToDeploymentAddresses(chainClient, concurrency, numberOfUpkeeps, operationsPerAddress, multicallAddress, linkFundsForEachUpkeep, linkToken) +} + // DeployMultiCallAndFundDeploymentAddresses deploys multicall contract and sends link funds to each deployment address func DeployMultiCallAndFundDeploymentAddresses( chainClient *seth.Client, diff --git a/integration-tests/actions/keeper_helpers.go b/integration-tests/actions/keeper_helpers.go index 80822a95af4..45445ff5420 100644 --- a/integration-tests/actions/keeper_helpers.go +++ b/integration-tests/actions/keeper_helpers.go @@ -8,6 +8,8 @@ import ( "strconv" "testing" + "github.com/smartcontractkit/chainlink/integration-tests/testconfig" + "github.com/ethereum/go-ethereum/core/types" "github.com/google/uuid" "github.com/pkg/errors" @@ -117,7 +119,7 @@ func DeployKeeperContracts( } registrar := DeployKeeperRegistrar(t, client, registryVersion, linkToken, registrarSettings, registry) - upkeeps, upkeepIds := DeployConsumers(t, client, registry, registrar, linkToken, numberOfUpkeeps, linkFundsForEachUpkeep, upkeepGasLimit, false, false, false, nil) + upkeeps, upkeepIds := DeployConsumers(t, client, registry, registrar, linkToken, numberOfUpkeeps, linkFundsForEachUpkeep, upkeepGasLimit, false, false, false, nil, &testconfig.TestConfig{}) return registry, registrar, upkeeps, upkeepIds } diff --git a/integration-tests/chaos/automation_chaos_test.go b/integration-tests/chaos/automation_chaos_test.go index 474018aa1e1..c0823f482ad 100644 --- a/integration-tests/chaos/automation_chaos_test.go +++ b/integration-tests/chaos/automation_chaos_test.go @@ -259,11 +259,11 @@ func TestAutomationChaos(t *testing.T) { var consumersLogTrigger, consumersConditional []contracts.KeeperConsumer var upkeepidsConditional, upkeepidsLogTrigger []*big.Int - consumersConditional, upkeepidsConditional = actions.DeployConsumers(t, a.ChainClient, a.Registry, a.Registrar, a.LinkToken, numberOfUpkeeps, big.NewInt(defaultLinkFunds), defaultUpkeepGasLimit, false, false, false, nil) + consumersConditional, upkeepidsConditional = actions.DeployConsumers(t, a.ChainClient, a.Registry, a.Registrar, a.LinkToken, numberOfUpkeeps, big.NewInt(defaultLinkFunds), defaultUpkeepGasLimit, false, false, false, nil, &config) consumers := consumersConditional upkeepIDs := upkeepidsConditional if rv >= eth_contracts.RegistryVersion_2_1 { - consumersLogTrigger, upkeepidsLogTrigger = actions.DeployConsumers(t, a.ChainClient, a.Registry, a.Registrar, a.LinkToken, numberOfUpkeeps, big.NewInt(defaultLinkFunds), defaultUpkeepGasLimit, true, false, false, nil) + consumersLogTrigger, upkeepidsLogTrigger = actions.DeployConsumers(t, a.ChainClient, a.Registry, a.Registrar, a.LinkToken, numberOfUpkeeps, big.NewInt(defaultLinkFunds), defaultUpkeepGasLimit, true, false, false, nil, &config) consumers = append(consumersConditional, consumersLogTrigger...) upkeepIDs = append(upkeepidsConditional, upkeepidsLogTrigger...) diff --git a/integration-tests/reorg/automation_reorg_test.go b/integration-tests/reorg/automation_reorg_test.go index e2d333747ac..fde37d9f06f 100644 --- a/integration-tests/reorg/automation_reorg_test.go +++ b/integration-tests/reorg/automation_reorg_test.go @@ -169,6 +169,7 @@ func TestAutomationReorg(t *testing.T) { false, false, a.WETHToken, + &config, ) if isLogTrigger { diff --git a/integration-tests/smoke/automation_test.go b/integration-tests/smoke/automation_test.go index aa89e90ab60..2e56237e9ca 100644 --- a/integration-tests/smoke/automation_test.go +++ b/integration-tests/smoke/automation_test.go @@ -142,6 +142,7 @@ func SetupAutomationBasic(t *testing.T, nodeUpgrade bool) { isMercury, isBillingTokenNative, a.WETHToken, + &cfg, ) // Do it in two separate loops, so we don't end up setting up one upkeep, but starting the consumer for another one @@ -268,20 +269,7 @@ func TestSetUpkeepTriggerConfig(t *testing.T) { sb, err := a.ChainClient.Client.BlockNumber(context.Background()) require.NoError(t, err, "Failed to get start block") - consumers, upkeepIDs := actions.DeployConsumers( - t, - a.ChainClient, - a.Registry, - a.Registrar, - a.LinkToken, - defaultAmountOfUpkeeps, - big.NewInt(automationDefaultLinkFunds), - automationDefaultUpkeepGasLimit, - true, - false, - false, - nil, - ) + consumers, upkeepIDs := actions.DeployConsumers(t, a.ChainClient, a.Registry, a.Registrar, a.LinkToken, defaultAmountOfUpkeeps, big.NewInt(automationDefaultLinkFunds), automationDefaultUpkeepGasLimit, true, false, false, nil, &config) // Start log trigger based upkeeps for all consumers for i := 0; i < len(consumers); i++ { @@ -451,20 +439,7 @@ func TestAutomationAddFunds(t *testing.T) { sb, err := a.ChainClient.Client.BlockNumber(context.Background()) require.NoError(t, err, "Failed to get start block") - consumers, upkeepIDs := actions.DeployConsumers( - t, - a.ChainClient, - a.Registry, - a.Registrar, - a.LinkToken, - defaultAmountOfUpkeeps, - big.NewInt(1), - automationDefaultUpkeepGasLimit, - false, - false, - false, - nil, - ) + consumers, upkeepIDs := actions.DeployConsumers(t, a.ChainClient, a.Registry, a.Registrar, a.LinkToken, defaultAmountOfUpkeeps, big.NewInt(1), automationDefaultUpkeepGasLimit, false, false, false, nil, &config) t.Cleanup(func() { actions.GetStalenessReportCleanupFn(t, a.Logger, a.ChainClient, sb, a.Registry, registryVersion)() @@ -531,20 +506,7 @@ func TestAutomationPauseUnPause(t *testing.T) { sb, err := a.ChainClient.Client.BlockNumber(context.Background()) require.NoError(t, err, "Failed to get start block") - consumers, upkeepIDs := actions.DeployConsumers( - t, - a.ChainClient, - a.Registry, - a.Registrar, - a.LinkToken, - defaultAmountOfUpkeeps, - big.NewInt(automationDefaultLinkFunds), - automationDefaultUpkeepGasLimit, - false, - false, - false, - nil, - ) + consumers, upkeepIDs := actions.DeployConsumers(t, a.ChainClient, a.Registry, a.Registrar, a.LinkToken, defaultAmountOfUpkeeps, big.NewInt(automationDefaultLinkFunds), automationDefaultUpkeepGasLimit, false, false, false, nil, &config) t.Cleanup(func() { actions.GetStalenessReportCleanupFn(t, a.Logger, a.ChainClient, sb, a.Registry, registryVersion)() @@ -632,20 +594,7 @@ func TestAutomationRegisterUpkeep(t *testing.T) { sb, err := a.ChainClient.Client.BlockNumber(context.Background()) require.NoError(t, err, "Failed to get start block") - consumers, upkeepIDs := actions.DeployConsumers( - t, - a.ChainClient, - a.Registry, - a.Registrar, - a.LinkToken, - defaultAmountOfUpkeeps, - big.NewInt(automationDefaultLinkFunds), - automationDefaultUpkeepGasLimit, - false, - false, - false, - nil, - ) + consumers, upkeepIDs := actions.DeployConsumers(t, a.ChainClient, a.Registry, a.Registrar, a.LinkToken, defaultAmountOfUpkeeps, big.NewInt(automationDefaultLinkFunds), automationDefaultUpkeepGasLimit, false, false, false, nil, &config) t.Cleanup(func() { actions.GetStalenessReportCleanupFn(t, a.Logger, a.ChainClient, sb, a.Registry, registryVersion)() @@ -728,20 +677,7 @@ func TestAutomationPauseRegistry(t *testing.T) { sb, err := a.ChainClient.Client.BlockNumber(context.Background()) require.NoError(t, err, "Failed to get start block") - consumers, upkeepIDs := actions.DeployConsumers( - t, - a.ChainClient, - a.Registry, - a.Registrar, - a.LinkToken, - defaultAmountOfUpkeeps, - big.NewInt(automationDefaultLinkFunds), - automationDefaultUpkeepGasLimit, - false, - false, - false, - nil, - ) + consumers, upkeepIDs := actions.DeployConsumers(t, a.ChainClient, a.Registry, a.Registrar, a.LinkToken, defaultAmountOfUpkeeps, big.NewInt(automationDefaultLinkFunds), automationDefaultUpkeepGasLimit, false, false, false, nil, &config) t.Cleanup(func() { actions.GetStalenessReportCleanupFn(t, a.Logger, a.ChainClient, sb, a.Registry, registryVersion)() @@ -808,20 +744,7 @@ func TestAutomationKeeperNodesDown(t *testing.T) { sb, err := a.ChainClient.Client.BlockNumber(context.Background()) require.NoError(t, err, "Failed to get start block") - consumers, upkeepIDs := actions.DeployConsumers( - t, - a.ChainClient, - a.Registry, - a.Registrar, - a.LinkToken, - defaultAmountOfUpkeeps, - big.NewInt(automationDefaultLinkFunds), - automationDefaultUpkeepGasLimit, - false, - false, - false, - nil, - ) + consumers, upkeepIDs := actions.DeployConsumers(t, a.ChainClient, a.Registry, a.Registrar, a.LinkToken, defaultAmountOfUpkeeps, big.NewInt(automationDefaultLinkFunds), automationDefaultUpkeepGasLimit, false, false, false, nil, &config) t.Cleanup(func() { actions.GetStalenessReportCleanupFn(t, a.Logger, a.ChainClient, sb, a.Registry, registryVersion)() @@ -929,6 +852,7 @@ func TestAutomationPerformSimulation(t *testing.T) { 5, // Interval of blocks that upkeeps are expected to be performed 100000, // How much gas should be burned on checkUpkeep() calls 4000000, // How much gas should be burned on performUpkeep() calls. Initially set higher than defaultUpkeepGasLimit + &config, ) t.Cleanup(func() { @@ -1000,6 +924,7 @@ func TestAutomationCheckPerformGasLimit(t *testing.T) { 5, // Interval of blocks that upkeeps are expected to be performed 100000, // How much gas should be burned on checkUpkeep() calls 4000000, // How much gas should be burned on performUpkeep() calls. Initially set higher than defaultUpkeepGasLimit + &config, ) t.Cleanup(func() { @@ -1152,6 +1077,7 @@ func TestUpdateCheckData(t *testing.T) { big.NewInt(automationDefaultLinkFunds), automationDefaultUpkeepGasLimit, []byte(automationExpectedData), + &config, ) t.Cleanup(func() { @@ -1223,20 +1149,7 @@ func TestSetOffchainConfigWithMaxGasPrice(t *testing.T) { sb, err := a.ChainClient.Client.BlockNumber(context.Background()) require.NoError(t, err, "Failed to get start block") - consumers, upkeepIDs := actions.DeployConsumers( - t, - a.ChainClient, - a.Registry, - a.Registrar, - a.LinkToken, - defaultAmountOfUpkeeps, - big.NewInt(automationDefaultLinkFunds), - automationDefaultUpkeepGasLimit, - false, - false, - false, - nil, - ) + consumers, upkeepIDs := actions.DeployConsumers(t, a.ChainClient, a.Registry, a.Registrar, a.LinkToken, defaultAmountOfUpkeeps, big.NewInt(automationDefaultLinkFunds), automationDefaultUpkeepGasLimit, false, false, false, nil, &config) t.Cleanup(func() { actions.GetStalenessReportCleanupFn(t, a.Logger, a.ChainClient, sb, a.Registry, registryVersion)() diff --git a/integration-tests/smoke/log_poller_test.go b/integration-tests/smoke/log_poller_test.go index c7f5483ac15..a0fd039806c 100644 --- a/integration-tests/smoke/log_poller_test.go +++ b/integration-tests/smoke/log_poller_test.go @@ -306,20 +306,7 @@ func prepareEnvironment(l zerolog.Logger, t *testing.T, testConfig *tc.TestConfi logScannerSettings, ) - _, upkeepIDs := actions.DeployConsumers( - t, - chainClient, - registry, - registrar, - linkToken, - upKeepsNeeded, - big.NewInt(int64(9e18)), - uint32(2500000), - true, - false, - false, - nil, - ) + _, upkeepIDs := actions.DeployConsumers(t, chainClient, registry, registrar, linkToken, upKeepsNeeded, big.NewInt(int64(9e18)), uint32(2500000), true, false, false, nil, &tc.TestConfig{}) err = logpoller.AssertUpkeepIdsUniqueness(upkeepIDs) require.NoError(t, err, "Error asserting upkeep ids uniqueness") diff --git a/integration-tests/testconfig/automation/config.go b/integration-tests/testconfig/automation/config.go index 0f7db3be4b9..cd052caa3b8 100644 --- a/integration-tests/testconfig/automation/config.go +++ b/integration-tests/testconfig/automation/config.go @@ -434,6 +434,7 @@ type Contracts struct { EthUSDFeedAddress *string `toml:"eth_usd_feed"` LinkUSDFeedAddress *string `toml:"link_usd_feed"` UpkeepContractAddresses []string `toml:"upkeep_contracts"` + MultiCallAddress *string `toml:"multicall"` Settings map[string]ContractSetting `toml:"Settings"` } @@ -465,6 +466,9 @@ func (o *Contracts) Validate() error { if o.LinkUSDFeedAddress != nil && !common.IsHexAddress(*o.LinkUSDFeedAddress) { return errors.New("link_usd_feed must be a valid ethereum address") } + if o.MultiCallAddress != nil && !common.IsHexAddress(*o.MultiCallAddress) { + return errors.New("multicall must be a valid ethereum address") + } if o.UpkeepContractAddresses != nil { allEnabled := make(map[bool]int) allConfigure := make(map[bool]int) @@ -595,6 +599,14 @@ func (c *Config) UpkeepContractAddresses() ([]common.Address, error) { return nil, errors.New("upkeep contract addresses must be set") } +func (c *Config) MultiCallContractAddress() (common.Address, error) { + if c.Contracts != nil && c.Contracts.MultiCallAddress != nil { + return common.HexToAddress(*c.Contracts.MultiCallAddress), nil + } + + return common.Address{}, errors.New("multicall address must be set") +} + func (c *Config) UseExistingLinkTokenContract() bool { if !c.UseExistingContracts() { return false @@ -799,6 +811,26 @@ func (c *Config) UseExistingUpkeepContracts() bool { return false } +func (c *Config) UseExistingMultiCallContract() bool { + if !c.UseExistingContracts() { + return false + } + + if c.Contracts.MultiCallAddress == nil { + return false + } + + if len(c.Contracts.Settings) == 0 { + return true + } + + if v, ok := c.Contracts.Settings[*c.Contracts.MultiCallAddress]; ok { + return v.ShouldBeUsed != nil && *v.ShouldBeUsed + } + + return true +} + type ContractSetting struct { ShouldBeUsed *bool `toml:"use"` Configure *bool `toml:"configure"` diff --git a/integration-tests/testsetups/keeper_benchmark.go b/integration-tests/testsetups/keeper_benchmark.go index c5d61e2c8f3..f9550c581cb 100644 --- a/integration-tests/testsetups/keeper_benchmark.go +++ b/integration-tests/testsetups/keeper_benchmark.go @@ -712,7 +712,7 @@ func (k *KeeperBenchmarkTest) DeployBenchmarkKeeperContracts(index int, a *autom linkFunds = big.NewInt(0).Add(linkFunds, minLinkBalance) k.linkToken = a.LinkToken - err = actions.DeployMultiCallAndFundDeploymentAddresses(k.chainClient, k.linkToken, upkeep.NumberOfUpkeeps, linkFunds) + err = actions.SetupMultiCallAndFundDeploymentAddresses(k.chainClient, k.linkToken, upkeep.NumberOfUpkeeps, linkFunds, a.TestConfig) require.NoError(k.t, err, "Sending link funds to deployment addresses shouldn't fail") upkeepIds := actions.RegisterUpkeepContractsWithCheckData(k.t, k.chainClient, k.linkToken, linkFunds, uint32(upkeep.UpkeepGasLimit), a.Registry, a.Registrar, upkeep.NumberOfUpkeeps, upkeepAddresses, checkData, false, false, false, nil)