diff --git a/integration-tests/contracts/contract_deployer.go b/integration-tests/contracts/contract_deployer.go index 464ae7a340b..ef1eb34e4ea 100644 --- a/integration-tests/contracts/contract_deployer.go +++ b/integration-tests/contracts/contract_deployer.go @@ -1,11 +1,15 @@ package contracts import ( + "context" "errors" "fmt" "math/big" + "strings" "time" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" @@ -145,6 +149,7 @@ type ContractDeployer interface { DeployMercuryFeeManager(linkAddress common.Address, nativeAddress common.Address, proxyAddress common.Address, rewardManagerAddress common.Address) (MercuryFeeManager, error) DeployMercuryRewardManager(linkAddress common.Address) (MercuryRewardManager, error) DeployLogEmitterContract() (LogEmitter, error) + DeployMultiCallContract() (common.Address, error) } // NewContractDeployer returns an instance of a contract deployer based on the client type @@ -1711,3 +1716,32 @@ func (e *EthereumContractDeployer) DeployLogEmitterContract() (LogEmitter, error l: e.l, }, err } + +func (e *EthereumContractDeployer) DeployMultiCallContract() (common.Address, error) { + multiCallABI, err := abi.JSON(strings.NewReader(MultiCallABI)) + if err != nil { + return common.Address{}, err + } + address, tx, _, err := e.client.DeployContract("MultiCall Contract", func( + auth *bind.TransactOpts, + backend bind.ContractBackend, + ) (common.Address, *types.Transaction, interface{}, error) { + address, tx, contract, err := bind.DeployContract(auth, multiCallABI, common.FromHex(MultiCallBIN), backend) + if err != nil { + return common.Address{}, nil, nil, err + } + return address, tx, contract, err + }) + if err != nil { + return common.Address{}, err + } + r, err := bind.WaitMined(context.Background(), e.client.DeployBackend(), tx) + if err != nil { + return common.Address{}, err + } + if r.Status != types.ReceiptStatusSuccessful { + return common.Address{}, fmt.Errorf("deploy multicall failed") + } + return *address, nil + +} diff --git a/integration-tests/contracts/multicall.go b/integration-tests/contracts/multicall.go new file mode 100644 index 00000000000..b423482dd55 --- /dev/null +++ b/integration-tests/contracts/multicall.go @@ -0,0 +1,95 @@ +package contracts + +import ( + "context" + "fmt" + "math/big" + "strings" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/pkg/errors" + "github.com/rs/zerolog/log" + + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" +) + +const ( + MultiCallABI = "[{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"internalType\":\"struct Multicall3.Call[]\",\"name\":\"calls\",\"type\":\"tuple[]\"}],\"name\":\"aggregate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"},{\"internalType\":\"bytes[]\",\"name\":\"returnData\",\"type\":\"bytes[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"allowFailure\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"internalType\":\"struct Multicall3.Call3[]\",\"name\":\"calls\",\"type\":\"tuple[]\"}],\"name\":\"aggregate3\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"internalType\":\"struct Multicall3.Result[]\",\"name\":\"returnData\",\"type\":\"tuple[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bool\",\"name\":\"allowFailure\",\"type\":\"bool\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"internalType\":\"struct Multicall3.Call3Value[]\",\"name\":\"calls\",\"type\":\"tuple[]\"}],\"name\":\"aggregate3Value\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"internalType\":\"struct Multicall3.Result[]\",\"name\":\"returnData\",\"type\":\"tuple[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"internalType\":\"struct Multicall3.Call[]\",\"name\":\"calls\",\"type\":\"tuple[]\"}],\"name\":\"blockAndAggregate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"blockHash\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"internalType\":\"struct Multicall3.Result[]\",\"name\":\"returnData\",\"type\":\"tuple[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getBasefee\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"basefee\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"}],\"name\":\"getBlockHash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"blockHash\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getBlockNumber\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getChainId\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"chainid\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentBlockCoinbase\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"coinbase\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentBlockDifficulty\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"difficulty\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentBlockGasLimit\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"gaslimit\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getCurrentBlockTimestamp\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"timestamp\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"getEthBalance\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"balance\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"getLastBlockHash\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"blockHash\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"requireSuccess\",\"type\":\"bool\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"internalType\":\"struct Multicall3.Call[]\",\"name\":\"calls\",\"type\":\"tuple[]\"}],\"name\":\"tryAggregate\",\"outputs\":[{\"components\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"internalType\":\"struct Multicall3.Result[]\",\"name\":\"returnData\",\"type\":\"tuple[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bool\",\"name\":\"requireSuccess\",\"type\":\"bool\"},{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"callData\",\"type\":\"bytes\"}],\"internalType\":\"struct Multicall3.Call[]\",\"name\":\"calls\",\"type\":\"tuple[]\"}],\"name\":\"tryBlockAndAggregate\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"blockNumber\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"blockHash\",\"type\":\"bytes32\"},{\"components\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"returnData\",\"type\":\"bytes\"}],\"internalType\":\"struct Multicall3.Result[]\",\"name\":\"returnData\",\"type\":\"tuple[]\"}],\"stateMutability\":\"payable\",\"type\":\"function\"}]" + MultiCallBIN = "0x608060405234801561001057600080fd5b50610ee0806100206000396000f3fe6080604052600436106100f35760003560e01c80634d2301cc1161008a578063a8b0574e11610059578063a8b0574e1461025a578063bce38bd714610275578063c3077fa914610288578063ee82ac5e1461029b57600080fd5b80634d2301cc146101ec57806372425d9d1461022157806382ad56cb1461023457806386d516e81461024757600080fd5b80633408e470116100c65780633408e47014610191578063399542e9146101a45780633e64a696146101c657806342cbb15c146101d957600080fd5b80630f28c97d146100f8578063174dea711461011a578063252dba421461013a57806327e86d6e1461015b575b600080fd5b34801561010457600080fd5b50425b6040519081526020015b60405180910390f35b61012d610128366004610a85565b6102ba565b6040516101119190610bbe565b61014d610148366004610a85565b6104ef565b604051610111929190610bd8565b34801561016757600080fd5b50437fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0140610107565b34801561019d57600080fd5b5046610107565b6101b76101b2366004610c60565b610690565b60405161011193929190610cba565b3480156101d257600080fd5b5048610107565b3480156101e557600080fd5b5043610107565b3480156101f857600080fd5b50610107610207366004610ce2565b73ffffffffffffffffffffffffffffffffffffffff163190565b34801561022d57600080fd5b5044610107565b61012d610242366004610a85565b6106ab565b34801561025357600080fd5b5045610107565b34801561026657600080fd5b50604051418152602001610111565b61012d610283366004610c60565b61085a565b6101b7610296366004610a85565b610a1a565b3480156102a757600080fd5b506101076102b6366004610d18565b4090565b60606000828067ffffffffffffffff8111156102d8576102d8610d31565b60405190808252806020026020018201604052801561031e57816020015b6040805180820190915260008152606060208201528152602001906001900390816102f65790505b5092503660005b8281101561047757600085828151811061034157610341610d60565b6020026020010151905087878381811061035d5761035d610d60565b905060200281019061036f9190610d8f565b6040810135958601959093506103886020850185610ce2565b73ffffffffffffffffffffffffffffffffffffffff16816103ac6060870187610dcd565b6040516103ba929190610e32565b60006040518083038185875af1925050503d80600081146103f7576040519150601f19603f3d011682016040523d82523d6000602084013e6103fc565b606091505b50602080850191909152901515808452908501351761046d577f08c379a000000000000000000000000000000000000000000000000000000000600052602060045260176024527f4d756c746963616c6c333a2063616c6c206661696c656400000000000000000060445260846000fd5b5050600101610325565b508234146104e6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4d756c746963616c6c333a2076616c7565206d69736d6174636800000000000060448201526064015b60405180910390fd5b50505092915050565b436060828067ffffffffffffffff81111561050c5761050c610d31565b60405190808252806020026020018201604052801561053f57816020015b606081526020019060019003908161052a5790505b5091503660005b8281101561068657600087878381811061056257610562610d60565b90506020028101906105749190610e42565b92506105836020840184610ce2565b73ffffffffffffffffffffffffffffffffffffffff166105a66020850185610dcd565b6040516105b4929190610e32565b6000604051808303816000865af19150503d80600081146105f1576040519150601f19603f3d011682016040523d82523d6000602084013e6105f6565b606091505b5086848151811061060957610609610d60565b602090810291909101015290508061067d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f4d756c746963616c6c333a2063616c6c206661696c656400000000000000000060448201526064016104dd565b50600101610546565b5050509250929050565b43804060606106a086868661085a565b905093509350939050565b6060818067ffffffffffffffff8111156106c7576106c7610d31565b60405190808252806020026020018201604052801561070d57816020015b6040805180820190915260008152606060208201528152602001906001900390816106e55790505b5091503660005b828110156104e657600084828151811061073057610730610d60565b6020026020010151905086868381811061074c5761074c610d60565b905060200281019061075e9190610e76565b925061076d6020840184610ce2565b73ffffffffffffffffffffffffffffffffffffffff166107906040850185610dcd565b60405161079e929190610e32565b6000604051808303816000865af19150503d80600081146107db576040519150601f19603f3d011682016040523d82523d6000602084013e6107e0565b606091505b506020808401919091529015158083529084013517610851577f08c379a000000000000000000000000000000000000000000000000000000000600052602060045260176024527f4d756c746963616c6c333a2063616c6c206661696c656400000000000000000060445260646000fd5b50600101610714565b6060818067ffffffffffffffff81111561087657610876610d31565b6040519080825280602002602001820160405280156108bc57816020015b6040805180820190915260008152606060208201528152602001906001900390816108945790505b5091503660005b82811015610a105760008482815181106108df576108df610d60565b602002602001015190508686838181106108fb576108fb610d60565b905060200281019061090d9190610e42565b925061091c6020840184610ce2565b73ffffffffffffffffffffffffffffffffffffffff1661093f6020850185610dcd565b60405161094d929190610e32565b6000604051808303816000865af19150503d806000811461098a576040519150601f19603f3d011682016040523d82523d6000602084013e61098f565b606091505b506020830152151581528715610a07578051610a07576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f4d756c746963616c6c333a2063616c6c206661696c656400000000000000000060448201526064016104dd565b506001016108c3565b5050509392505050565b6000806060610a2b60018686610690565b919790965090945092505050565b60008083601f840112610a4b57600080fd5b50813567ffffffffffffffff811115610a6357600080fd5b6020830191508360208260051b8501011115610a7e57600080fd5b9250929050565b60008060208385031215610a9857600080fd5b823567ffffffffffffffff811115610aaf57600080fd5b610abb85828601610a39565b90969095509350505050565b6000815180845260005b81811015610aed57602081850181015186830182015201610ad1565b81811115610aff576000602083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b600082825180855260208086019550808260051b84010181860160005b84811015610bb1578583037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001895281518051151584528401516040858501819052610b9d81860183610ac7565b9a86019a9450505090830190600101610b4f565b5090979650505050505050565b602081526000610bd16020830184610b32565b9392505050565b600060408201848352602060408185015281855180845260608601915060608160051b870101935082870160005b82811015610c52577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa0888703018452610c40868351610ac7565b95509284019290840190600101610c06565b509398975050505050505050565b600080600060408486031215610c7557600080fd5b83358015158114610c8557600080fd5b9250602084013567ffffffffffffffff811115610ca157600080fd5b610cad86828701610a39565b9497909650939450505050565b838152826020820152606060408201526000610cd96060830184610b32565b95945050505050565b600060208284031215610cf457600080fd5b813573ffffffffffffffffffffffffffffffffffffffff81168114610bd157600080fd5b600060208284031215610d2a57600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81833603018112610dc357600080fd5b9190910192915050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112610e0257600080fd5b83018035915067ffffffffffffffff821115610e1d57600080fd5b602001915036819003821315610a7e57600080fd5b8183823760009101908152919050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc1833603018112610dc357600080fd5b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa1833603018112610dc357600080fdfea2646970667358221220bb2b5c71a328032f97c676ae39a1ec2148d3e5d6f73d95e9b17910152d61f16264736f6c634300080c0033" +) + +type CallWithValue struct { + Target common.Address + AllowFailure bool + Value *big.Int + CallData []byte +} + +type Call struct { + Target common.Address + AllowFailure bool + CallData []byte +} + +type Result struct { + Success bool + ReturnData []byte +} + +func WaitForSuccessfulTxMined(evmClient blockchain.EVMClient, tx *types.Transaction) error { + log.Info().Str("tx", tx.Hash().Hex()).Msg("waiting for tx to be mined") + receipt, err := bind.WaitMined(context.Background(), evmClient.DeployBackend(), tx) + if err != nil { + return err + } + if receipt.Status != types.ReceiptStatusSuccessful { + return fmt.Errorf("tx failed %s", tx.Hash().Hex()) + } + log.Info().Str("tx", tx.Hash().Hex()).Str("Network", evmClient.GetNetworkName()).Msg("tx mined successfully") + return nil +} + +func MultiCallLogTriggerLoadGen( + evmClient blockchain.EVMClient, + multiCallAddress string, + logTriggerAddress []string, + logTriggerData [][]byte, +) (*types.Transaction, error) { + + contractAddress := common.HexToAddress(multiCallAddress) + multiCallABI, err := abi.JSON(strings.NewReader(MultiCallABI)) + if err != nil { + return nil, err + } + boundContract := bind.NewBoundContract(contractAddress, multiCallABI, evmClient.Backend(), evmClient.Backend(), evmClient.Backend()) + + var call []Call + for i, d := range logTriggerData { + data := Call{Target: common.HexToAddress(logTriggerAddress[i]), AllowFailure: false, CallData: d} + call = append(call, data) + } + + opts, err := evmClient.TransactionOpts(evmClient.GetDefaultWallet()) + if err != nil { + return nil, err + } + + // call aggregate3 to group all msg call data and send them in a single transaction + tx, err := boundContract.Transact(opts, "aggregate3", call) + if err != nil { + return nil, err + } + err = evmClient.MarkTxAsSentOnL2(tx) + if err != nil { + return nil, err + } + err = WaitForSuccessfulTxMined(evmClient, tx) + if err != nil { + return nil, errors.Wrapf(err, "multicall failed for log trigger load gen; multicall %s", contractAddress.Hex()) + } + return tx, nil + +} diff --git a/integration-tests/load/automationv2_1/automationv2_1_test.go b/integration-tests/load/automationv2_1/automationv2_1_test.go index ab18fee19fe..0f7964c25d3 100644 --- a/integration-tests/load/automationv2_1/automationv2_1_test.go +++ b/integration-tests/load/automationv2_1/automationv2_1_test.go @@ -131,9 +131,9 @@ var ( ) type Load struct { - NumberOfEvents int `toml:",omitempty"` - NumberOfSpamMatchingEvents int `toml:",omitempty"` - NumberOfSpamNonMatchingEvents int `toml:",omitempty"` + NumberOfEvents int64 `toml:",omitempty"` + NumberOfSpamMatchingEvents int64 `toml:",omitempty"` + NumberOfSpamNonMatchingEvents int64 `toml:",omitempty"` CheckBurnAmount *big.Int `toml:",omitempty"` PerformBurnAmount *big.Int `toml:",omitempty"` UpkeepGasLimit uint32 `toml:",omitempty"` @@ -343,6 +343,9 @@ Load Config: chainClient.ParallelTransactions(true) + multicallAddress, err := contractDeployer.DeployMultiCallContract() + require.NoError(t, err, "Error deploying multicall contract") + a := automationv2.NewAutomationTestK8s(chainClient, contractDeployer, chainlinkNodes) a.RegistrySettings = *registrySettings a.RegistrarSettings = contracts.KeeperRegistrarSettings{ @@ -503,28 +506,39 @@ Load Config: p := wasp.NewProfile() + configs := make([]LogTriggerConfig, 0) + var numberOfEventsEmitted int64 + for i, triggerContract := range triggerContracts { - g, err := wasp.NewGenerator(&wasp.Config{ - T: t, - LoadType: wasp.RPS, - GenName: fmt.Sprintf("log_trigger_gen_%s", triggerContract.Address().String()), - CallTimeout: time.Second * 10, - Schedule: wasp.Plain( - 1, - loadDuration, - ), - Gun: NewLogTriggerUser( - triggerContract, - l, - loadConfigs[i].NumberOfEvents, - loadConfigs[i].NumberOfSpamMatchingEvents, - loadConfigs[i].NumberOfSpamNonMatchingEvents, - ), - CallResultBufLen: 1000000, - }) - p.Add(g, err) + c := LogTriggerConfig{ + Address: triggerContract.Address().String(), + NumberOfEvents: loadConfigs[i].NumberOfEvents, + NumberOfSpamMatchingEvents: loadConfigs[i].NumberOfSpamMatchingEvents, + NumberOfSpamNonMatchingEvents: loadConfigs[i].NumberOfSpamNonMatchingEvents, + } + numberOfEventsEmitted = numberOfEventsEmitted + loadConfigs[i].NumberOfEvents + configs = append(configs, c) } + g, err := wasp.NewGenerator(&wasp.Config{ + T: t, + LoadType: wasp.RPS, + GenName: fmt.Sprint("log_trigger_gen"), + CallTimeout: time.Second * 10, + Schedule: wasp.Plain( + 1, + loadDuration, + ), + Gun: NewLogTriggerUser( + l, + configs, + cEVMClient, + multicallAddress.Hex(), + ), + CallResultBufLen: 1000000, + }) + p.Add(g, err) + l.Info().Msg("Starting load generators") startTime := time.Now() ts, err := sendSlackNotification("Started", l, testEnvironment.Cfg.Namespace, strconv.Itoa(numberofNodes), @@ -549,13 +563,13 @@ Load Config: upkeepDelaysFast := make([][]int64, 0) upkeepDelaysRecovery := make([][]int64, 0) - var numberOfEventsEmitted int + var batchSize uint64 = 500 - for i, gen := range p.Generators { - numberOfEventsEmitted = numberOfEventsEmitted + (len(gen.GetData().OKData.Data) * loadConfigs[i].NumberOfEvents) + for _, gen := range p.Generators { + numberOfEventsEmitted = numberOfEventsEmitted * int64(len(gen.GetData().OKData.Data)) } - l.Info().Int("Number of Events Emitted", numberOfEventsEmitted).Msg("Number of Events Emitted") + l.Info().Int64("Number of Events Emitted", numberOfEventsEmitted).Msg("Number of Events Emitted") if endBlock-startBlock < batchSize { batchSize = endBlock - startBlock @@ -646,7 +660,7 @@ Load Config: avgF, medianF, ninetyPctF, ninetyNinePctF, maximumF := testreporters.IntListStats(allUpkeepDelaysFast) avgR, medianR, ninetyPctR, ninetyNinePctR, maximumR := testreporters.IntListStats(allUpkeepDelaysRecovery) - eventsMissed := numberOfEventsEmitted - len(allUpkeepDelays) + eventsMissed := (numberOfEventsEmitted) - int64(len(allUpkeepDelays)) percentMissed := float64(eventsMissed) / float64(numberOfEventsEmitted) * 100 l.Info(). Float64("Average", avgF).Int64("Median", medianF). @@ -660,8 +674,8 @@ Load Config: Int("Total Perform Count", len(allUpkeepDelays)). Int("Perform Count Fast Execution", len(allUpkeepDelaysFast)). Int("Perform Count Recovery Execution", len(allUpkeepDelaysRecovery)). - Int("Total Events Emitted", numberOfEventsEmitted). - Int("Total Events Missed", eventsMissed). + Int64("Total Events Emitted", numberOfEventsEmitted). + Int64("Total Events Missed", eventsMissed). Float64("Percent Missed", percentMissed). Msg("Test completed") diff --git a/integration-tests/load/automationv2_1/gun.go b/integration-tests/load/automationv2_1/gun.go index 938ce8708e6..958ce79084e 100644 --- a/integration-tests/load/automationv2_1/gun.go +++ b/integration-tests/load/automationv2_1/gun.go @@ -1,59 +1,86 @@ package automationv2_1 import ( + "math/big" + "github.com/rs/zerolog" "github.com/smartcontractkit/wasp" + "github.com/smartcontractkit/chainlink-testing-framework/blockchain" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/log_emitter" + "github.com/smartcontractkit/chainlink/integration-tests/contracts" ) +type LogTriggerConfig struct { + Address string + NumberOfEvents int64 + NumberOfSpamMatchingEvents int64 + NumberOfSpamNonMatchingEvents int64 +} + type LogTriggerGun struct { - triggerContract contracts.LogEmitter - logger zerolog.Logger - numberOfEvents int - numberOfSpamMatchingEvents int - numberOfSpamNonMatchingEvents int + data [][]byte + addresses []string + multiCallAddress string + evmClient blockchain.EVMClient + logger zerolog.Logger +} + +func generateCallData(int1 int64, int2 int64, count int64) []byte { + abi, err := log_emitter.LogEmitterMetaData.GetAbi() + if err != nil { + panic(err) + } + data, err := abi.Pack("EmitLog4", big.NewInt(int1), big.NewInt(int2), big.NewInt(count)) + if err != nil { + panic(err) + } + return data } func NewLogTriggerUser( - triggerContract contracts.LogEmitter, logger zerolog.Logger, - numberOfEvents int, - numberOfSpamMatchingEvents int, - numberOfSpamNonMatchingEvents int, + TriggerConfigs []LogTriggerConfig, + evmClient blockchain.EVMClient, + multicallAddress string, ) *LogTriggerGun { - return &LogTriggerGun{ - triggerContract: triggerContract, - logger: logger, - numberOfEvents: numberOfEvents, - numberOfSpamMatchingEvents: numberOfSpamMatchingEvents, - numberOfSpamNonMatchingEvents: numberOfSpamNonMatchingEvents, - } -} + var data [][]byte + var addresses []string -func (m *LogTriggerGun) Call(_ *wasp.Generator) *wasp.Response { - m.logger.Debug().Str("Trigger address", m.triggerContract.Address().String()).Msg("Triggering upkeep") - - if m.numberOfEvents > 0 { - _, err := m.triggerContract.EmitLogIntMultiIndexed(1, 1, m.numberOfEvents) - if err != nil { - return &wasp.Response{Error: err.Error(), Failed: true} + for _, c := range TriggerConfigs { + if c.NumberOfEvents > 0 { + d := generateCallData(1, 1, c.NumberOfEvents) + data = append(data, d) + addresses = append(addresses, c.Address) + } + if c.NumberOfSpamMatchingEvents > 0 { + d := generateCallData(1, 2, c.NumberOfSpamMatchingEvents) + data = append(data, d) + addresses = append(addresses, c.Address) + } + if c.NumberOfSpamNonMatchingEvents > 0 { + d := generateCallData(2, 2, c.NumberOfSpamNonMatchingEvents) + data = append(data, d) + addresses = append(addresses, c.Address) } } - if m.numberOfSpamMatchingEvents > 0 { - _, err := m.triggerContract.EmitLogIntMultiIndexed(1, 2, m.numberOfSpamMatchingEvents) - if err != nil { - return &wasp.Response{Error: err.Error(), Failed: true} - } + return &LogTriggerGun{ + addresses: addresses, + data: data, + logger: logger, + multiCallAddress: multicallAddress, + evmClient: evmClient, } +} - if m.numberOfSpamNonMatchingEvents > 0 { - _, err := m.triggerContract.EmitLogIntMultiIndexed(2, 2, m.numberOfSpamNonMatchingEvents) - if err != nil { - return &wasp.Response{Error: err.Error(), Failed: true} - } +func (m *LogTriggerGun) Call(_ *wasp.Generator) *wasp.Response { + + _, err := contracts.MultiCallLogTriggerLoadGen(m.evmClient, m.multiCallAddress, m.addresses, m.data) + if err != nil { + return &wasp.Response{Error: err.Error(), Failed: true} } return &wasp.Response{}