Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TT-1345] option to use predeployed contracts in OCR tests #13758

Merged
merged 14 commits into from
Sep 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
110 changes: 75 additions & 35 deletions integration-tests/actions/actions.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import (
"github.com/smartcontractkit/chainlink-testing-framework/lib/utils/testcontext"

"github.com/smartcontractkit/chainlink/integration-tests/client"
"github.com/smartcontractkit/chainlink/integration-tests/testconfig/ocr"
"github.com/smartcontractkit/chainlink/integration-tests/types/config/node"
"github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/link_token_interface"
"github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/operator_factory"
Expand Down Expand Up @@ -609,29 +610,48 @@ func TrackForwarder(
Msg("Forwarder tracked")
}

// DeployOCRv2Contracts deploys a number of OCRv2 contracts and configures them with defaults
func DeployOCRv2Contracts(
// SetupOCRv2Contracts deploys a number of OCRv2 contracts and configures them with defaults
func SetupOCRv2Contracts(
l zerolog.Logger,
seth *seth.Client,
numberOfContracts int,
ocrContractsConfig ocr.OffChainAggregatorsConfig,
lukaszcl marked this conversation as resolved.
Show resolved Hide resolved
linkTokenAddress common.Address,
transmitters []string,
ocrOptions contracts.OffchainOptions,
) ([]contracts.OffchainAggregatorV2, error) {
var ocrInstances []contracts.OffchainAggregatorV2
for contractCount := 0; contractCount < numberOfContracts; contractCount++ {
ocrInstance, err := contracts.DeployOffchainAggregatorV2(
l,
seth,
linkTokenAddress,
ocrOptions,
)
if err != nil {
return nil, fmt.Errorf("OCRv2 instance deployment have failed: %w", err)

if ocrContractsConfig == nil {
return nil, fmt.Errorf("you need to pass non-nil OffChainAggregatorsConfig to setup OCR contracts")
}

if !ocrContractsConfig.UseExistingOffChainAggregatorsContracts() {
for contractCount := 0; contractCount < ocrContractsConfig.NumberOfContractsToDeploy(); contractCount++ {
ocrInstance, err := contracts.DeployOffchainAggregatorV2(
l,
seth,
linkTokenAddress,
ocrOptions,
)
if err != nil {
return nil, fmt.Errorf("OCRv2 instance deployment have failed: %w", err)
}
ocrInstances = append(ocrInstances, &ocrInstance)
if (contractCount+1)%ContractDeploymentInterval == 0 { // For large amounts of contract deployments, space things out some
time.Sleep(2 * time.Second)
}
}
ocrInstances = append(ocrInstances, &ocrInstance)
if (contractCount+1)%ContractDeploymentInterval == 0 { // For large amounts of contract deployments, space things out some
time.Sleep(2 * time.Second)
} else {
for _, address := range ocrContractsConfig.OffChainAggregatorsContractsAddresses() {
ocrInstance, err := contracts.LoadOffchainAggregatorV2(l, seth, address)
if err != nil {
return nil, fmt.Errorf("OCRv2 instance loading have failed: %w", err)
}
ocrInstances = append(ocrInstances, &ocrInstance)
}

if !ocrContractsConfig.ConfigureExistingOffChainAggregatorsContracts() {
return ocrInstances, nil
}
}

Expand Down Expand Up @@ -780,7 +800,7 @@ func StartNewRound(
func DeployOCRContractsForwarderFlow(
logger zerolog.Logger,
seth *seth.Client,
numberOfContracts int,
ocrContractsConfig ocr.OffChainAggregatorsConfig,
linkTokenContractAddress common.Address,
workerNodes []contracts.ChainlinkNodeWithKeysAndAddress,
forwarderAddresses []common.Address,
Expand All @@ -801,23 +821,23 @@ func DeployOCRContractsForwarderFlow(
return forwarderAddresses, nil
}

return deployAnyOCRv1Contracts(logger, seth, numberOfContracts, linkTokenContractAddress, workerNodes, transmitterPayeesFn, transmitterAddressesFn)
return setupAnyOCRv1Contracts(logger, seth, ocrContractsConfig, linkTokenContractAddress, workerNodes, transmitterPayeesFn, transmitterAddressesFn)
}

// DeployOCRv1Contracts deploys and funds a certain number of offchain aggregator contracts
func DeployOCRv1Contracts(
// SetupOCRv1Contracts deploys and funds a certain number of offchain aggregator contracts or uses existing ones and returns a slice of contract wrappers.
func SetupOCRv1Contracts(
logger zerolog.Logger,
seth *seth.Client,
numberOfContracts int,
ocrContractsConfig ocr.OffChainAggregatorsConfig,
linkTokenContractAddress common.Address,
workerNodes []contracts.ChainlinkNodeWithKeysAndAddress,
) ([]contracts.OffchainAggregator, error) {
transmitterPayeesFn := func() (transmitters []string, payees []string, err error) {
transmitters = make([]string, 0)
payees = make([]string, 0)
for _, node := range workerNodes {
for _, n := range workerNodes {
var addr string
addr, err = node.PrimaryEthAddress()
addr, err = n.PrimaryEthAddress()
if err != nil {
err = fmt.Errorf("error getting node's primary ETH address: %w", err)
return
Expand All @@ -831,8 +851,8 @@ func DeployOCRv1Contracts(

transmitterAddressesFn := func() ([]common.Address, error) {
transmitterAddresses := make([]common.Address, 0)
for _, node := range workerNodes {
primaryAddress, err := node.PrimaryEthAddress()
for _, n := range workerNodes {
primaryAddress, err := n.PrimaryEthAddress()
if err != nil {
return nil, err
}
Expand All @@ -842,28 +862,48 @@ func DeployOCRv1Contracts(
return transmitterAddresses, nil
}

return deployAnyOCRv1Contracts(logger, seth, numberOfContracts, linkTokenContractAddress, workerNodes, transmitterPayeesFn, transmitterAddressesFn)
return setupAnyOCRv1Contracts(logger, seth, ocrContractsConfig, linkTokenContractAddress, workerNodes, transmitterPayeesFn, transmitterAddressesFn)
}

func deployAnyOCRv1Contracts(
func setupAnyOCRv1Contracts(
logger zerolog.Logger,
seth *seth.Client,
numberOfContracts int,
ocrContractsConfig ocr.OffChainAggregatorsConfig,
linkTokenContractAddress common.Address,
workerNodes []contracts.ChainlinkNodeWithKeysAndAddress,
getTransmitterAndPayeesFn func() ([]string, []string, error),
getTransmitterAddressesFn func() ([]common.Address, error),
) ([]contracts.OffchainAggregator, error) {
// Deploy contracts
var ocrInstances []contracts.OffchainAggregator
for contractCount := 0; contractCount < numberOfContracts; contractCount++ {
ocrInstance, err := contracts.DeployOffchainAggregator(logger, seth, linkTokenContractAddress, contracts.DefaultOffChainAggregatorOptions())
if err != nil {
return nil, fmt.Errorf("OCR instance deployment have failed: %w", err)

if ocrContractsConfig == nil {
return nil, fmt.Errorf("you need to pass non-nil OffChainAggregatorsConfig to setup OCR contracts")
}

if !ocrContractsConfig.UseExistingOffChainAggregatorsContracts() {
// Deploy contracts
for contractCount := 0; contractCount < ocrContractsConfig.NumberOfContractsToDeploy(); contractCount++ {
ocrInstance, err := contracts.DeployOffchainAggregator(logger, seth, linkTokenContractAddress, contracts.DefaultOffChainAggregatorOptions())
if err != nil {
return nil, fmt.Errorf("OCR instance deployment have failed: %w", err)
}
ocrInstances = append(ocrInstances, &ocrInstance)
if (contractCount+1)%ContractDeploymentInterval == 0 { // For large amounts of contract deployments, space things out some
time.Sleep(2 * time.Second)
}
}
ocrInstances = append(ocrInstances, &ocrInstance)
if (contractCount+1)%ContractDeploymentInterval == 0 { // For large amounts of contract deployments, space things out some
time.Sleep(2 * time.Second)
} else {
// Load contract wrappers
for _, address := range ocrContractsConfig.OffChainAggregatorsContractsAddresses() {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Tofel, out of curiosity, why do we use an interface like OffChainAggregatorsConfig? Wouldn’t it be simpler to use config methods or fields directly?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have some logic underneath that returns empty array if contracts are disabled on some level. That way the caller doesn't have to know anything about that logic.

ocrInstance, err := contracts.LoadOffChainAggregator(logger, seth, address)
if err != nil {
return nil, fmt.Errorf("OCR instance loading have failed: %w", err)
}
ocrInstances = append(ocrInstances, &ocrInstance)
}

if !ocrContractsConfig.ConfigureExistingOffChainAggregatorsContracts() {
return ocrInstances, nil
}
}

Expand Down
23 changes: 23 additions & 0 deletions integration-tests/actions/contracts.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package actions

import (
"github.com/rs/zerolog"

"github.com/smartcontractkit/chainlink-testing-framework/seth"

"github.com/smartcontractkit/chainlink/integration-tests/contracts"
tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig"
)

// LinkTokenContract returns a link token contract instance. Depending on test configuration, it either deploys a new one or uses an existing one.
func LinkTokenContract(l zerolog.Logger, sethClient *seth.Client, configWithLinkToken tc.LinkTokenContractConfig) (*contracts.EthereumLinkToken, error) {
if configWithLinkToken != nil && configWithLinkToken.UseExistingLinkTokenContract() {
linkAddress, err := configWithLinkToken.LinkTokenContractAddress()
if err != nil {
return nil, err
}

return contracts.LoadLinkTokenContract(l, sethClient, linkAddress)
}
return contracts.DeployLinkTokenContract(l, sethClient)
}
8 changes: 6 additions & 2 deletions integration-tests/actions/ocr_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import (

"github.com/smartcontractkit/chainlink/integration-tests/client"
"github.com/smartcontractkit/chainlink/integration-tests/contracts"
tc "github.com/smartcontractkit/chainlink/integration-tests/testconfig"
"github.com/smartcontractkit/chainlink/integration-tests/testconfig/ocr"
)

// This actions file often returns functions, rather than just values. These are used as common test helpers, and are
Expand Down Expand Up @@ -229,13 +231,14 @@ func BuildNodeContractPairID(node contracts.ChainlinkNodeWithKeysAndAddress, ocr
func SetupOCRv1Cluster(
l zerolog.Logger,
seth *seth.Client,
configWithLinkToken tc.LinkTokenContractConfig,
workerNodes []*client.ChainlinkK8sClient,
) (common.Address, error) {
err := FundChainlinkNodesFromRootAddress(l, seth, contracts.ChainlinkK8sClientToChainlinkNodeWithKeysAndAddress(workerNodes), big.NewFloat(3))
if err != nil {
return common.Address{}, err
}
linkContract, err := contracts.DeployLinkTokenContract(l, seth)
linkContract, err := LinkTokenContract(l, seth, configWithLinkToken)
if err != nil {
return common.Address{}, err
}
Expand All @@ -246,11 +249,12 @@ func SetupOCRv1Feed(
l zerolog.Logger,
seth *seth.Client,
lta common.Address,
ocrContractsConfig ocr.OffChainAggregatorsConfig,
msClient *ctfClient.MockserverClient,
bootstrapNode *client.ChainlinkK8sClient,
workerNodes []*client.ChainlinkK8sClient,
) ([]contracts.OffchainAggregator, error) {
ocrInstances, err := DeployOCRv1Contracts(l, seth, 1, lta, contracts.ChainlinkK8sClientToChainlinkNodeWithKeysAndAddress(workerNodes))
ocrInstances, err := SetupOCRv1Contracts(l, seth, ocrContractsConfig, lta, contracts.ChainlinkK8sClientToChainlinkNodeWithKeysAndAddress(workerNodes))
if err != nil {
return nil, err
}
Expand Down
4 changes: 2 additions & 2 deletions integration-tests/chaos/ocr_chaos_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,13 +179,13 @@ func TestOCRChaos(t *testing.T) {
})

ms := ctfClient.ConnectMockServer(testEnvironment)
linkContract, err := contracts.DeployLinkTokenContract(l, seth)
linkContract, err := actions.LinkTokenContract(l, seth, config.OCR)
require.NoError(t, err, "Error deploying link token contract")

err = actions.FundChainlinkNodesFromRootAddress(l, seth, contracts.ChainlinkK8sClientToChainlinkNodeWithKeysAndAddress(chainlinkNodes), big.NewFloat(10))
require.NoError(t, err)

ocrInstances, err := actions.DeployOCRv1Contracts(l, seth, 1, common.HexToAddress(linkContract.Address()), contracts.ChainlinkK8sClientToChainlinkNodeWithKeysAndAddress(workerNodes))
ocrInstances, err := actions.SetupOCRv1Contracts(l, seth, config.OCR, common.HexToAddress(linkContract.Address()), contracts.ChainlinkK8sClientToChainlinkNodeWithKeysAndAddress(workerNodes))
require.NoError(t, err)
err = actions.CreateOCRJobs(ocrInstances, bootstrapNode, workerNodes, 5, ms, fmt.Sprint(seth.ChainID))
require.NoError(t, err)
Expand Down
59 changes: 22 additions & 37 deletions integration-tests/contracts/ethereum_contracts.go
Original file line number Diff line number Diff line change
Expand Up @@ -204,22 +204,17 @@ type EthereumOffchainAggregator struct {
l zerolog.Logger
}

func LoadOffchainAggregator(l zerolog.Logger, seth *seth.Client, contractAddress common.Address) (EthereumOffchainAggregator, error) {
abi, err := offchainaggregator.OffchainAggregatorMetaData.GetAbi()
if err != nil {
return EthereumOffchainAggregator{}, fmt.Errorf("failed to get OffChain Aggregator ABI: %w", err)
}
seth.ContractStore.AddABI("OffChainAggregator", *abi)
seth.ContractStore.AddBIN("OffChainAggregator", common.FromHex(offchainaggregator.OffchainAggregatorMetaData.Bin))
func LoadOffChainAggregator(l zerolog.Logger, sethClient *seth.Client, contractAddress common.Address) (EthereumOffchainAggregator, error) {
loader := seth.NewContractLoader[offchainaggregator.OffchainAggregator](sethClient)
instance, err := loader.LoadContract("LinkToken", contractAddress, offchainaggregator.OffchainAggregatorMetaData.GetAbi, offchainaggregator.NewOffchainAggregator)

ocr, err := offchainaggregator.NewOffchainAggregator(contractAddress, wrappers.MustNewWrappedContractBackend(nil, seth))
if err != nil {
return EthereumOffchainAggregator{}, fmt.Errorf("failed to instantiate OCR instance: %w", err)
return EthereumOffchainAggregator{}, fmt.Errorf("failed to instantiate OCR v2 instance: %w", err)
}

return EthereumOffchainAggregator{
client: seth,
ocr: ocr,
client: sethClient,
ocr: instance,
address: &contractAddress,
l: l,
}, nil
Expand Down Expand Up @@ -357,10 +352,6 @@ func (o *EthereumOffchainAggregator) SetConfig(
return err
}

// fails with error setting OCR config for contract '0x0DCd1Bf9A1b36cE34237eEaFef220932846BCD82': both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified
// but we only have gasPrice set... It also fails with the same error when we enable EIP-1559
// fails when we wait for it to be minted, inside the wrapper there's no error when we call it, so it must be something inside smart contract
// that's reverting it and maybe the error message is completely off
_, err = o.client.Decode(o.ocr.SetConfig(o.client.NewTXOpts(), signers, transmitters, threshold, encodedConfigVersion, encodedConfig))
return err
}
Expand Down Expand Up @@ -584,36 +575,36 @@ type EthereumOffchainAggregatorV2 struct {
l zerolog.Logger
}

func LoadOffChainAggregatorV2(l zerolog.Logger, seth *seth.Client, contractAddress common.Address) (EthereumOffchainAggregatorV2, error) {
oAbi, err := ocr2aggregator.OCR2AggregatorMetaData.GetAbi()
func LoadOffchainAggregatorV2(l zerolog.Logger, seth *seth.Client, address common.Address) (EthereumOffchainAggregatorV2, error) {
contractAbi, err := ocr2aggregator.OCR2AggregatorMetaData.GetAbi()
if err != nil {
return EthereumOffchainAggregatorV2{}, fmt.Errorf("failed to get OffChain Aggregator ABI: %w", err)
return EthereumOffchainAggregatorV2{}, fmt.Errorf("failed to get OffChain Aggregator v2 ABI: %w", err)
}
seth.ContractStore.AddABI("OffChainAggregatorV2", *oAbi)
seth.ContractStore.AddABI("OffChainAggregatorV2", *contractAbi)
seth.ContractStore.AddBIN("OffChainAggregatorV2", common.FromHex(ocr2aggregator.OCR2AggregatorMetaData.Bin))

ocr2, err := ocr2aggregator.NewOCR2Aggregator(contractAddress, seth.Client)
ocr2, err := ocr2aggregator.NewOCR2Aggregator(address, seth.Client)
if err != nil {
return EthereumOffchainAggregatorV2{}, fmt.Errorf("failed to instantiate OCR instance: %w", err)
return EthereumOffchainAggregatorV2{}, fmt.Errorf("failed to instantiate OCRv2 instance: %w", err)
}

return EthereumOffchainAggregatorV2{
client: seth,
contract: ocr2,
address: &contractAddress,
address: &address,
l: l,
}, nil
}

func DeployOffchainAggregatorV2(l zerolog.Logger, seth *seth.Client, linkTokenAddress common.Address, offchainOptions OffchainOptions) (EthereumOffchainAggregatorV2, error) {
oAbi, err := ocr2aggregator.OCR2AggregatorMetaData.GetAbi()
contractAbi, err := ocr2aggregator.OCR2AggregatorMetaData.GetAbi()
if err != nil {
return EthereumOffchainAggregatorV2{}, fmt.Errorf("failed to get OffChain Aggregator ABI: %w", err)
return EthereumOffchainAggregatorV2{}, fmt.Errorf("failed to get OffChain Aggregator v2 ABI: %w", err)
}
seth.ContractStore.AddABI("OffChainAggregatorV2", *oAbi)
seth.ContractStore.AddABI("OffChainAggregatorV2", *contractAbi)
seth.ContractStore.AddBIN("OffChainAggregatorV2", common.FromHex(ocr2aggregator.OCR2AggregatorMetaData.Bin))

ocrDeploymentData2, err := seth.DeployContract(seth.NewTXOpts(), "OffChainAggregatorV2", *oAbi, common.FromHex(ocr2aggregator.OCR2AggregatorMetaData.Bin),
ocrDeploymentData2, err := seth.DeployContract(seth.NewTXOpts(), "OffChainAggregatorV2", *contractAbi, common.FromHex(ocr2aggregator.OCR2AggregatorMetaData.Bin),
linkTokenAddress,
offchainOptions.MinimumAnswer,
offchainOptions.MaximumAnswer,
Expand All @@ -624,12 +615,12 @@ func DeployOffchainAggregatorV2(l zerolog.Logger, seth *seth.Client, linkTokenAd
)

if err != nil {
return EthereumOffchainAggregatorV2{}, fmt.Errorf("OCR instance deployment have failed: %w", err)
return EthereumOffchainAggregatorV2{}, fmt.Errorf("OCRv2 instance deployment have failed: %w", err)
}

ocr2, err := ocr2aggregator.NewOCR2Aggregator(ocrDeploymentData2.Address, wrappers.MustNewWrappedContractBackend(nil, seth))
if err != nil {
return EthereumOffchainAggregatorV2{}, fmt.Errorf("failed to instantiate OCR instance: %w", err)
return EthereumOffchainAggregatorV2{}, fmt.Errorf("failed to instantiate OCRv2 instance: %w", err)
}

return EthereumOffchainAggregatorV2{
Expand Down Expand Up @@ -772,22 +763,16 @@ func DeployLinkTokenContract(l zerolog.Logger, client *seth.Client) (*EthereumLi
}

func LoadLinkTokenContract(l zerolog.Logger, client *seth.Client, address common.Address) (*EthereumLinkToken, error) {
linkABI, err := link_token_interface.LinkTokenMetaData.GetAbi()
if err != nil {
return &EthereumLinkToken{}, fmt.Errorf("failed to get LinkToken ABI: %w", err)
}
loader := seth.NewContractLoader[link_token_interface.LinkToken](client)
instance, err := loader.LoadContract("LinkToken", address, link_token_interface.LinkTokenMetaData.GetAbi, link_token_interface.NewLinkToken)

client.ContractStore.AddABI("LinkToken", *linkABI)
client.ContractStore.AddBIN("LinkToken", common.FromHex(link_token_interface.LinkTokenMetaData.Bin))

linkToken, err := link_token_interface.NewLinkToken(address, wrappers.MustNewWrappedContractBackend(nil, client))
if err != nil {
return &EthereumLinkToken{}, fmt.Errorf("failed to instantiate LinkToken instance: %w", err)
}

return &EthereumLinkToken{
client: client,
instance: linkToken,
instance: instance,
address: address,
l: l,
}, nil
Expand Down
Loading
Loading