From 9bfac80f094cb002da5f2a4f4570a1846b54cd0d Mon Sep 17 00:00:00 2001 From: Akshay Aggarwal Date: Mon, 25 Sep 2023 19:31:26 +0100 Subject: [PATCH] [auto-2.5.1] Upgrade to latest libocr (#10778) * Upgrade to latest libocr * fix smoke tests * fix tests * port fix --- .../features/ocr2/features_ocr2_test.go | 50 ++- core/scripts/go.mod | 4 +- core/scripts/go.sum | 8 +- core/services/relay/evm/config_poller.go | 143 ++++++- core/services/relay/evm/config_poller_test.go | 388 ++++++++++++++---- core/services/relay/evm/evm.go | 18 +- .../relay/evm/functions/config_poller.go | 3 + .../relay/evm/functions/config_poller_test.go | 30 +- core/services/relay/evm/ocr2keeper.go | 3 + core/services/relay/evm/ocr2vrf.go | 6 +- core/services/relay/evm/types/types.go | 7 +- go.mod | 4 +- go.sum | 8 +- .../actions/ocr2_helpers_local.go | 40 +- integration-tests/go.mod | 4 +- integration-tests/go.sum | 8 +- 16 files changed, 597 insertions(+), 127 deletions(-) diff --git a/core/internal/features/ocr2/features_ocr2_test.go b/core/internal/features/ocr2/features_ocr2_test.go index 82d4fadd708..d40377a8566 100644 --- a/core/internal/features/ocr2/features_ocr2_test.go +++ b/core/internal/features/ocr2/features_ocr2_test.go @@ -24,13 +24,15 @@ import ( "github.com/onsi/gomega" "github.com/smartcontractkit/libocr/commontypes" "github.com/smartcontractkit/libocr/gethwrappers2/ocr2aggregator" - testoffchainaggregator2 "github.com/smartcontractkit/libocr/gethwrappers2/testocr2aggregator" - confighelper2 "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" - ocrtypes2 "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "golang.org/x/exp/maps" + "github.com/smartcontractkit/libocr/bigbigendian" + testoffchainaggregator2 "github.com/smartcontractkit/libocr/gethwrappers2/testocr2aggregator" + confighelper2 "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" + ocrtypes2 "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + "github.com/smartcontractkit/chainlink/v2/core/assets" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/forwarders" @@ -238,12 +240,19 @@ func TestIntegration_OCR2(t *testing.T) { require.NoError(t, err) blockBeforeConfig, err := b.BlockByNumber(testutils.Context(t), nil) require.NoError(t, err) - signers, transmitters, threshold, onchainConfig, encodedConfigVersion, encodedConfig, err := confighelper2.ContractSetConfigArgsForEthereumIntegrationTest( + signers, transmitters, threshold, _, encodedConfigVersion, encodedConfig, err := confighelper2.ContractSetConfigArgsForEthereumIntegrationTest( oracles, 1, 1000000000/100, // threshold PPB ) require.NoError(t, err) + + minAnswer, maxAnswer := new(big.Int), new(big.Int) + minAnswer.Exp(big.NewInt(-2), big.NewInt(191), nil) + maxAnswer.Exp(big.NewInt(2), big.NewInt(191), nil) + maxAnswer.Sub(maxAnswer, big.NewInt(1)) + + onchainConfig := generateDefaultOCR2OnchainConfig(t, minAnswer, maxAnswer) lggr.Debugw("Setting Config on Oracle Contract", "signers", signers, "transmitters", transmitters, @@ -506,13 +515,20 @@ func TestIntegration_OCR2_ForwarderFlow(t *testing.T) { require.NoError(t, err) blockBeforeConfig, err := b.BlockByNumber(testutils.Context(t), nil) require.NoError(t, err) - signers, effectiveTransmitters, threshold, onchainConfig, encodedConfigVersion, encodedConfig, err := confighelper2.ContractSetConfigArgsForEthereumIntegrationTest( + signers, effectiveTransmitters, threshold, _, encodedConfigVersion, encodedConfig, err := confighelper2.ContractSetConfigArgsForEthereumIntegrationTest( oracles, 1, 1000000000/100, // threshold PPB ) require.NoError(t, err) + minAnswer, maxAnswer := new(big.Int), new(big.Int) + minAnswer.Exp(big.NewInt(-2), big.NewInt(191), nil) + maxAnswer.Exp(big.NewInt(2), big.NewInt(191), nil) + maxAnswer.Sub(maxAnswer, big.NewInt(1)) + + onchainConfig := generateDefaultOCR2OnchainConfig(t, minAnswer, maxAnswer) + lggr.Debugw("Setting Config on Oracle Contract", "signers", signers, "transmitters", transmitters, @@ -722,4 +738,28 @@ juelsPerFeeCoinSource = """ assert.Equal(t, digestAndEpoch.Epoch, epoch) } +func generateDefaultOCR2OnchainConfig(t *testing.T, minValue *big.Int, maxValue *big.Int) []byte { + serializedConfig := make([]byte, 0) + + s1, err := bigbigendian.SerializeSigned(1, big.NewInt(1)) //version + if err != nil { + t.Fatal(err) + } + serializedConfig = append(serializedConfig, s1...) + + s2, err := bigbigendian.SerializeSigned(24, minValue) //min + if err != nil { + t.Fatal(err) + } + serializedConfig = append(serializedConfig, s2...) + + s3, err := bigbigendian.SerializeSigned(24, maxValue) //max + if err != nil { + t.Fatal(err) + } + serializedConfig = append(serializedConfig, s3...) + + return serializedConfig +} + func ptr[T any](v T) *T { return &v } diff --git a/core/scripts/go.mod b/core/scripts/go.mod index 6edbe2387d9..543f3d76491 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -18,8 +18,8 @@ require ( github.com/pelletier/go-toml/v2 v2.0.9 github.com/shopspring/decimal v1.3.1 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 - github.com/smartcontractkit/libocr v0.0.0-20230918212407-dbd4e505b3e6 - github.com/smartcontractkit/ocr2keepers v0.7.26 + github.com/smartcontractkit/libocr v0.0.0-20230922131214-122accb19ea6 + github.com/smartcontractkit/ocr2keepers v0.7.27 github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687 github.com/smartcontractkit/sqlx v1.3.5-0.20210805004948-4be295aacbeb github.com/spf13/cobra v1.6.1 diff --git a/core/scripts/go.sum b/core/scripts/go.sum index 3af52ec0c54..c822b469979 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -1387,10 +1387,10 @@ github.com/smartcontractkit/go-plugin v0.0.0-20230605132010-0f4d515d1472 h1:x3kN github.com/smartcontractkit/go-plugin v0.0.0-20230605132010-0f4d515d1472/go.mod h1:6/1TEzT0eQznvI/gV2CM29DLSkAK/e58mUWKVsPaph0= github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f h1:hgJif132UCdjo8u43i7iPN1/MFnu49hv7lFGFftCHKU= github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f/go.mod h1:MvMXoufZAtqExNexqi4cjrNYE9MefKddKylxjS+//n0= -github.com/smartcontractkit/libocr v0.0.0-20230918212407-dbd4e505b3e6 h1:w+8TI2Vcm3vk8XQz40ddcwy9BNZgoakXIby35Y54iDU= -github.com/smartcontractkit/libocr v0.0.0-20230918212407-dbd4e505b3e6/go.mod h1:2lyRkw/qLQgUWlrWWmq5nj0y90rWeO6Y+v+fCakRgb0= -github.com/smartcontractkit/ocr2keepers v0.7.26 h1:8Usfdsa6GtliMQPThL1qb36d4J5xMyTCFJYgbGp4ecA= -github.com/smartcontractkit/ocr2keepers v0.7.26/go.mod h1:4e1ZDRz7fpLgcRUjJpq+5mkoD0ga11BxrSp2JTWKADQ= +github.com/smartcontractkit/libocr v0.0.0-20230922131214-122accb19ea6 h1:eSo9r53fARv2MnIO5pqYvQOXMBsTlAwhHyQ6BAVp6bY= +github.com/smartcontractkit/libocr v0.0.0-20230922131214-122accb19ea6/go.mod h1:2lyRkw/qLQgUWlrWWmq5nj0y90rWeO6Y+v+fCakRgb0= +github.com/smartcontractkit/ocr2keepers v0.7.27 h1:kwqMrzmEdq6gH4yqNuLQCbdlED0KaIjwZzu3FF+Gves= +github.com/smartcontractkit/ocr2keepers v0.7.27/go.mod h1:1QGzJURnoWpysguPowOe2bshV0hNp1YX10HHlhDEsas= github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687 h1:NwC3SOc25noBTe1KUQjt45fyTIuInhoE2UfgcHAdihM= github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687/go.mod h1:YYZq52t4wcHoMQeITksYsorD+tZcOyuVU5+lvot3VFM= github.com/smartcontractkit/sqlx v1.3.5-0.20210805004948-4be295aacbeb h1:OMaBUb4X9IFPLbGbCHsMU+kw/BPCrewaVwWGIBc0I4A= diff --git a/core/services/relay/evm/config_poller.go b/core/services/relay/evm/config_poller.go index aada1242303..504155bf1e8 100644 --- a/core/services/relay/evm/config_poller.go +++ b/core/services/relay/evm/config_poller.go @@ -3,23 +3,41 @@ package evm import ( "context" "database/sql" + "fmt" "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/client_golang/prometheus/promauto" "github.com/smartcontractkit/libocr/gethwrappers2/ocr2aggregator" + "github.com/smartcontractkit/libocr/gethwrappers2/ocrconfigurationstoreevmsimple" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/pg" evmRelayTypes "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" + "github.com/smartcontractkit/chainlink/v2/core/utils" ) -// ConfigSet Common to all OCR2 evm based contracts: https://github.com/smartcontractkit/libocr/blob/master/contract2/dev/OCR2Abstract.sol -var ConfigSet common.Hash +var ( + failedRPCContractCalls = promauto.NewCounterVec(prometheus.CounterOpts{ + Name: "ocr2_failed_rpc_contract_calls", + Help: "Running count of failed RPC contract calls by chain/contract", + }, + []string{"chainID", "contractAddress"}, + ) +) + +var ( + // ConfigSet Common to all OCR2 evm based contracts: https://github.com/smartcontractkit/libocr/blob/master/contract2/dev/OCR2Abstract.sol + ConfigSet common.Hash -var defaultABI abi.ABI + defaultABI abi.ABI +) const configSetEventName = "ConfigSet" @@ -50,7 +68,7 @@ func configFromLog(logData []byte) (ocrtypes.ContractConfig, error) { var transmitAccounts []ocrtypes.Account for _, addr := range unpacked.Transmitters { - transmitAccounts = append(transmitAccounts, ocrtypes.Account(addr.String())) + transmitAccounts = append(transmitAccounts, ocrtypes.Account(addr.Hex())) } var signers []ocrtypes.OnchainPublicKey for _, addr := range unpacked.Signers { @@ -71,36 +89,63 @@ func configFromLog(logData []byte) (ocrtypes.ContractConfig, error) { } type configPoller struct { + utils.StartStopOnce + lggr logger.Logger filterName string destChainLogPoller logpoller.LogPoller - addr common.Address + client client.Client + + aggregatorContractAddr common.Address + aggregatorContract *ocr2aggregator.OCR2Aggregator + + // Some chains "manage" state bloat by deleting older logs. The ConfigStore + // contract allows us work around such restrictions. + configStoreContractAddr *common.Address + configStoreContract *ocrconfigurationstoreevmsimple.OCRConfigurationStoreEVMSimple } func configPollerFilterName(addr common.Address) string { return logpoller.FilterName("OCR2ConfigPoller", addr.String()) } -func NewConfigPoller(lggr logger.Logger, destChainPoller logpoller.LogPoller, addr common.Address) (evmRelayTypes.ConfigPoller, error) { - err := destChainPoller.RegisterFilter(logpoller.Filter{Name: configPollerFilterName(addr), EventSigs: []common.Hash{ConfigSet}, Addresses: []common.Address{addr}}) +func NewConfigPoller(lggr logger.Logger, client client.Client, destChainPoller logpoller.LogPoller, aggregatorContractAddr common.Address, configStoreAddr *common.Address) (evmRelayTypes.ConfigPoller, error) { + return newConfigPoller(lggr, client, destChainPoller, aggregatorContractAddr, configStoreAddr) +} + +func newConfigPoller(lggr logger.Logger, client client.Client, destChainPoller logpoller.LogPoller, aggregatorContractAddr common.Address, configStoreAddr *common.Address) (*configPoller, error) { + err := destChainPoller.RegisterFilter(logpoller.Filter{Name: configPollerFilterName(aggregatorContractAddr), EventSigs: []common.Hash{ConfigSet}, Addresses: []common.Address{aggregatorContractAddr}}) + if err != nil { + return nil, err + } + + aggregatorContract, err := ocr2aggregator.NewOCR2Aggregator(aggregatorContractAddr, client) if err != nil { return nil, err } cp := &configPoller{ - lggr: lggr, - filterName: configPollerFilterName(addr), - destChainLogPoller: destChainPoller, - addr: addr, + lggr: lggr, + filterName: configPollerFilterName(aggregatorContractAddr), + destChainLogPoller: destChainPoller, + aggregatorContractAddr: aggregatorContractAddr, + client: client, + aggregatorContract: aggregatorContract, + } + + if configStoreAddr != nil { + cp.configStoreContractAddr = configStoreAddr + cp.configStoreContract, err = ocrconfigurationstoreevmsimple.NewOCRConfigurationStoreEVMSimple(*configStoreAddr, client) + if err != nil { + return nil, err + } } return cp, nil } -// Start noop method func (cp *configPoller) Start() {} -// Close noop method func (cp *configPoller) Close() error { return nil } @@ -117,10 +162,14 @@ func (cp *configPoller) Replay(ctx context.Context, fromBlock int64) error { // LatestConfigDetails returns the latest config details from the logs func (cp *configPoller) LatestConfigDetails(ctx context.Context) (changedInBlock uint64, configDigest ocrtypes.ConfigDigest, err error) { - latest, err := cp.destChainLogPoller.LatestLogByEventSigWithConfs(ConfigSet, cp.addr, 1, pg.WithParentCtx(ctx)) + latest, err := cp.destChainLogPoller.LatestLogByEventSigWithConfs(ConfigSet, cp.aggregatorContractAddr, 1, pg.WithParentCtx(ctx)) if err != nil { - // If contract is not configured, we will not have the log. if errors.Is(err, sql.ErrNoRows) { + if cp.isConfigStoreAvailable() { + // Fallback to RPC call in case logs have been pruned and configStoreContract is available + return cp.callLatestConfigDetails(ctx) + } + // log not found means return zero config digest return 0, ocrtypes.ConfigDigest{}, nil } return 0, ocrtypes.ConfigDigest{}, err @@ -134,10 +183,17 @@ func (cp *configPoller) LatestConfigDetails(ctx context.Context) (changedInBlock // LatestConfig returns the latest config from the logs on a certain block func (cp *configPoller) LatestConfig(ctx context.Context, changedInBlock uint64) (ocrtypes.ContractConfig, error) { - lgs, err := cp.destChainLogPoller.Logs(int64(changedInBlock), int64(changedInBlock), ConfigSet, cp.addr, pg.WithParentCtx(ctx)) + lgs, err := cp.destChainLogPoller.Logs(int64(changedInBlock), int64(changedInBlock), ConfigSet, cp.aggregatorContractAddr, pg.WithParentCtx(ctx)) if err != nil { return ocrtypes.ContractConfig{}, err } + if len(lgs) == 0 { + if cp.isConfigStoreAvailable() { + // Fallback to RPC call in case logs have been pruned + return cp.callReadConfigFromStore(ctx) + } + return ocrtypes.ContractConfig{}, fmt.Errorf("no logs found for config on contract %s (chain %s) at block %d", cp.aggregatorContractAddr.Hex(), cp.client.ConfiguredChainID().String(), changedInBlock) + } latestConfigSet, err := configFromLog(lgs[len(lgs)-1].Data) if err != nil { return ocrtypes.ContractConfig{}, err @@ -157,3 +213,58 @@ func (cp *configPoller) LatestBlockHeight(ctx context.Context) (blockHeight uint } return uint64(latest), nil } + +func (cp *configPoller) isConfigStoreAvailable() bool { + return cp.configStoreContract != nil +} + +// RPC call for latest config details +func (cp *configPoller) callLatestConfigDetails(ctx context.Context) (changedInBlock uint64, configDigest ocrtypes.ConfigDigest, err error) { + details, err := cp.aggregatorContract.LatestConfigDetails(&bind.CallOpts{ + Context: ctx, + }) + if err != nil { + failedRPCContractCalls.WithLabelValues(cp.client.ConfiguredChainID().String(), cp.aggregatorContractAddr.Hex()).Inc() + } + return uint64(details.BlockNumber), details.ConfigDigest, err +} + +// RPC call to read config from config store contract +func (cp *configPoller) callReadConfigFromStore(ctx context.Context) (cfg ocrtypes.ContractConfig, err error) { + _, configDigest, err := cp.LatestConfigDetails(ctx) + if err != nil { + failedRPCContractCalls.WithLabelValues(cp.client.ConfiguredChainID().String(), cp.aggregatorContractAddr.Hex()).Inc() + return cfg, fmt.Errorf("failed to get latest config details: %w", err) + } + if configDigest == (ocrtypes.ConfigDigest{}) { + return cfg, fmt.Errorf("config details missing while trying to lookup config in store; no logs found for contract %s (chain %s)", cp.aggregatorContractAddr.Hex(), cp.client.ConfiguredChainID().String()) + } + + storedConfig, err := cp.configStoreContract.ReadConfig(&bind.CallOpts{ + Context: ctx, + }, configDigest) + if err != nil { + failedRPCContractCalls.WithLabelValues(cp.client.ConfiguredChainID().String(), cp.configStoreContractAddr.Hex()).Inc() + return cfg, fmt.Errorf("failed to read config from config store contract: %w", err) + } + + signers := make([]ocrtypes.OnchainPublicKey, len(storedConfig.Signers)) + for i := range signers { + signers[i] = storedConfig.Signers[i].Bytes() + } + transmitters := make([]ocrtypes.Account, len(storedConfig.Transmitters)) + for i := range transmitters { + transmitters[i] = ocrtypes.Account(storedConfig.Transmitters[i].Hex()) + } + + return ocrtypes.ContractConfig{ + ConfigDigest: configDigest, + ConfigCount: uint64(storedConfig.ConfigCount), + Signers: signers, + Transmitters: transmitters, + F: storedConfig.F, + OnchainConfig: storedConfig.OnchainConfig, + OffchainConfigVersion: storedConfig.OffchainConfigVersion, + OffchainConfig: storedConfig.OffchainConfig, + }, err +} diff --git a/core/services/relay/evm/config_poller_test.go b/core/services/relay/evm/config_poller_test.go index 724c303210b..69d389aa718 100644 --- a/core/services/relay/evm/config_poller_test.go +++ b/core/services/relay/evm/config_poller_test.go @@ -1,27 +1,39 @@ package evm import ( + "database/sql" "math/big" "testing" "time" + "github.com/ethereum/go-ethereum" + "github.com/smartcontractkit/libocr/bigbigendian" + "github.com/smartcontractkit/libocr/gethwrappers2/ocrconfigurationstoreevmsimple" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/accounts/abi/bind/backends" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/eth/ethconfig" "github.com/onsi/gomega" + "github.com/pkg/errors" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "github.com/smartcontractkit/libocr/gethwrappers2/ocr2aggregator" testoffchainaggregator2 "github.com/smartcontractkit/libocr/gethwrappers2/testocr2aggregator" "github.com/smartcontractkit/libocr/offchainreporting2/reportingplugin/median" confighelper2 "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" + ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" ocrtypes2 "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" evmclient "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" + evmClientMocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/link_token_interface" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" @@ -30,80 +42,284 @@ import ( ) func TestConfigPoller(t *testing.T) { - key, err := crypto.GenerateKey() - require.NoError(t, err) - user, err := bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337)) - require.NoError(t, err) - b := backends.NewSimulatedBackend(core.GenesisAlloc{ - user.From: {Balance: big.NewInt(1000000000000000000)}}, - 5*ethconfig.Defaults.Miner.GasCeil) - linkTokenAddress, _, _, err := link_token_interface.DeployLinkToken(user, b) - require.NoError(t, err) - accessAddress, _, _, err := testoffchainaggregator2.DeploySimpleWriteAccessController(user, b) - require.NoError(t, err, "failed to deploy test access controller contract") - ocrAddress, _, ocrContract, err := ocr2aggregator.DeployOCR2Aggregator( - user, - b, - linkTokenAddress, - big.NewInt(0), - big.NewInt(10), - accessAddress, - accessAddress, - 9, - "TEST", - ) - require.NoError(t, err) - b.Commit() - - db := pgtest.NewSqlxDB(t) - cfg := pgtest.NewQConfig(false) - ethClient := evmclient.NewSimulatedBackendClient(t, b, big.NewInt(1337)) lggr := logger.TestLogger(t) - ctx := testutils.Context(t) - lorm := logpoller.NewORM(big.NewInt(1337), db, lggr, cfg) - lp := logpoller.NewLogPoller(lorm, ethClient, lggr, 100*time.Millisecond, 1, 2, 2, 1000) - require.NoError(t, lp.Start(ctx)) - t.Cleanup(func() { lp.Close() }) - logPoller, err := NewConfigPoller(lggr, lp, ocrAddress) - require.NoError(t, err) - // Should have no config to begin with. - _, config, err := logPoller.LatestConfigDetails(testutils.Context(t)) - require.NoError(t, err) - require.Equal(t, ocrtypes2.ConfigDigest{}, config) - // Set the config - contractConfig := setConfig(t, median.OffchainConfig{ - AlphaReportInfinite: false, - AlphaReportPPB: 0, - AlphaAcceptInfinite: true, - AlphaAcceptPPB: 0, - DeltaC: 10, - }, ocrContract, user) - b.Commit() - latest, err := b.BlockByNumber(testutils.Context(t), nil) - require.NoError(t, err) - // Ensure we capture this config set log. - require.NoError(t, lp.Replay(testutils.Context(t), latest.Number().Int64()-1)) + var ethClient *client.SimulatedBackendClient + var lp logpoller.LogPoller + var ocrAddress common.Address + var ocrContract *ocr2aggregator.OCR2Aggregator + var configStoreContractAddr common.Address + var configStoreContract *ocrconfigurationstoreevmsimple.OCRConfigurationStoreEVMSimple + var user *bind.TransactOpts + var b *backends.SimulatedBackend + var linkTokenAddress common.Address + var accessAddress common.Address - // Send blocks until we see the config updated. - var configBlock uint64 - var digest [32]byte - gomega.NewGomegaWithT(t).Eventually(func() bool { + { + key, err := crypto.GenerateKey() + require.NoError(t, err) + user, err = bind.NewKeyedTransactorWithChainID(key, big.NewInt(1337)) + require.NoError(t, err) + b = backends.NewSimulatedBackend(core.GenesisAlloc{ + user.From: {Balance: big.NewInt(1000000000000000000)}}, + 5*ethconfig.Defaults.Miner.GasCeil) + linkTokenAddress, _, _, err = link_token_interface.DeployLinkToken(user, b) + require.NoError(t, err) + accessAddress, _, _, err = testoffchainaggregator2.DeploySimpleWriteAccessController(user, b) + require.NoError(t, err, "failed to deploy test access controller contract") + ocrAddress, _, ocrContract, err = ocr2aggregator.DeployOCR2Aggregator( + user, + b, + linkTokenAddress, + big.NewInt(0), + big.NewInt(10), + accessAddress, + accessAddress, + 9, + "TEST", + ) + require.NoError(t, err) + configStoreContractAddr, _, configStoreContract, err = ocrconfigurationstoreevmsimple.DeployOCRConfigurationStoreEVMSimple(user, b) + require.NoError(t, err) b.Commit() - configBlock, digest, err = logPoller.LatestConfigDetails(testutils.Context(t)) + + db := pgtest.NewSqlxDB(t) + cfg := pgtest.NewQConfig(false) + ethClient = evmclient.NewSimulatedBackendClient(t, b, testutils.SimulatedChainID) + ctx := testutils.Context(t) + lorm := logpoller.NewORM(testutils.SimulatedChainID, db, lggr, cfg) + lp = logpoller.NewLogPoller(lorm, ethClient, lggr, 100*time.Millisecond, 1, 2, 2, 1000) + require.NoError(t, lp.Start(ctx)) + t.Cleanup(func() { lp.Close() }) + } + + t.Run("LatestConfig errors if there is no config in logs and config store is unconfigured", func(t *testing.T) { + cp, err := NewConfigPoller(lggr, ethClient, lp, ocrAddress, nil) require.NoError(t, err) - return ocrtypes2.ConfigDigest{} != digest - }, testutils.WaitTimeout(t), 100*time.Millisecond).Should(gomega.BeTrue()) - // Assert the config returned is the one we configured. - newConfig, err := logPoller.LatestConfig(testutils.Context(t), configBlock) - require.NoError(t, err) - // Note we don't check onchainConfig, as that is populated in the contract itself. - assert.Equal(t, digest, [32]byte(newConfig.ConfigDigest)) - assert.Equal(t, contractConfig.Signers, newConfig.Signers) - assert.Equal(t, contractConfig.Transmitters, newConfig.Transmitters) - assert.Equal(t, contractConfig.F, newConfig.F) - assert.Equal(t, contractConfig.OffchainConfigVersion, newConfig.OffchainConfigVersion) - assert.Equal(t, contractConfig.OffchainConfig, newConfig.OffchainConfig) + _, err = cp.LatestConfig(testutils.Context(t), 0) + require.Error(t, err) + assert.Contains(t, err.Error(), "no logs found for config on contract") + }) + + t.Run("happy path (with config store)", func(t *testing.T) { + cp, err := NewConfigPoller(lggr, ethClient, lp, ocrAddress, &configStoreContractAddr) + require.NoError(t, err) + // Should have no config to begin with. + _, configDigest, err := cp.LatestConfigDetails(testutils.Context(t)) + require.NoError(t, err) + require.Equal(t, ocrtypes2.ConfigDigest{}, configDigest) + // Should error because there are no logs for config at block 0 + _, err = cp.LatestConfig(testutils.Context(t), 0) + require.Error(t, err) + assert.Contains(t, err.Error(), "config details missing while trying to lookup config in store") + + // Set the config + contractConfig := setConfig(t, median.OffchainConfig{ + AlphaReportInfinite: false, + AlphaReportPPB: 0, + AlphaAcceptInfinite: true, + AlphaAcceptPPB: 0, + DeltaC: 10, + }, ocrContract, user) + b.Commit() + latest, err := b.BlockByNumber(testutils.Context(t), nil) + require.NoError(t, err) + // Ensure we capture this config set log. + require.NoError(t, lp.Replay(testutils.Context(t), latest.Number().Int64()-1)) + + // Send blocks until we see the config updated. + var configBlock uint64 + var digest [32]byte + gomega.NewGomegaWithT(t).Eventually(func() bool { + b.Commit() + configBlock, digest, err = cp.LatestConfigDetails(testutils.Context(t)) + require.NoError(t, err) + return ocrtypes2.ConfigDigest{} != digest + }, testutils.WaitTimeout(t), 100*time.Millisecond).Should(gomega.BeTrue()) + + // Assert the config returned is the one we configured. + newConfig, err := cp.LatestConfig(testutils.Context(t), configBlock) + require.NoError(t, err) + // Note we don't check onchainConfig, as that is populated in the contract itself. + assert.Equal(t, digest, [32]byte(newConfig.ConfigDigest)) + assert.Equal(t, contractConfig.Signers, newConfig.Signers) + assert.Equal(t, contractConfig.Transmitters, newConfig.Transmitters) + assert.Equal(t, contractConfig.F, newConfig.F) + assert.Equal(t, contractConfig.OffchainConfigVersion, newConfig.OffchainConfigVersion) + assert.Equal(t, contractConfig.OffchainConfig, newConfig.OffchainConfig) + }) + + { + var err error + ocrAddress, _, ocrContract, err = ocr2aggregator.DeployOCR2Aggregator( + user, + b, + linkTokenAddress, + big.NewInt(0), + big.NewInt(10), + accessAddress, + accessAddress, + 9, + "TEST", + ) + require.NoError(t, err) + b.Commit() + } + + t.Run("LatestConfigDetails, when logs have been pruned and config store contract is configured", func(t *testing.T) { + // Give it a log poller that will never return logs + mp := new(mocks.LogPoller) + mp.On("RegisterFilter", mock.Anything).Return(nil) + mp.On("LatestLogByEventSigWithConfs", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, sql.ErrNoRows) + + t.Run("if callLatestConfigDetails succeeds", func(t *testing.T) { + cp, err := newConfigPoller(lggr, ethClient, mp, ocrAddress, &configStoreContractAddr) + require.NoError(t, err) + + t.Run("when config has not been set, returns zero values", func(t *testing.T) { + changedInBlock, configDigest, err := cp.LatestConfigDetails(testutils.Context(t)) + require.NoError(t, err) + + assert.Equal(t, 0, int(changedInBlock)) + assert.Equal(t, ocrtypes.ConfigDigest{}, configDigest) + }) + t.Run("when config has been set, returns config details", func(t *testing.T) { + setConfig(t, median.OffchainConfig{ + AlphaReportInfinite: false, + AlphaReportPPB: 0, + AlphaAcceptInfinite: true, + AlphaAcceptPPB: 0, + DeltaC: 10, + }, ocrContract, user) + b.Commit() + + changedInBlock, configDigest, err := cp.LatestConfigDetails(testutils.Context(t)) + require.NoError(t, err) + + latest, err := b.BlockByNumber(testutils.Context(t), nil) + require.NoError(t, err) + + onchainDetails, err := ocrContract.LatestConfigDetails(nil) + require.NoError(t, err) + + assert.Equal(t, latest.Number().Int64(), int64(changedInBlock)) + assert.Equal(t, onchainDetails.ConfigDigest, [32]byte(configDigest)) + }) + }) + t.Run("returns error if callLatestConfigDetails fails", func(t *testing.T) { + failingClient := new(evmClientMocks.Client) + failingClient.On("ConfiguredChainID").Return(big.NewInt(42)) + failingClient.On("CallContract", mock.Anything, mock.Anything, mock.Anything).Return(nil, errors.New("something exploded")) + cp, err := newConfigPoller(lggr, failingClient, mp, ocrAddress, &configStoreContractAddr) + require.NoError(t, err) + + cp.configStoreContractAddr = &configStoreContractAddr + cp.configStoreContract = configStoreContract + + _, _, err = cp.LatestConfigDetails(testutils.Context(t)) + assert.EqualError(t, err, "something exploded") + + failingClient.AssertExpectations(t) + }) + }) + + { + var err error + // deploy it again to reset to empty config + ocrAddress, _, ocrContract, err = ocr2aggregator.DeployOCR2Aggregator( + user, + b, + linkTokenAddress, + big.NewInt(0), + big.NewInt(10), + accessAddress, + accessAddress, + 9, + "TEST", + ) + require.NoError(t, err) + b.Commit() + } + + t.Run("LatestConfig, when logs have been pruned and config store contract is configured", func(t *testing.T) { + // Give it a log poller that will never return logs + mp := mocks.NewLogPoller(t) + mp.On("RegisterFilter", mock.Anything).Return(nil) + mp.On("Logs", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, nil) + mp.On("LatestLogByEventSigWithConfs", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, sql.ErrNoRows) + + t.Run("if callReadConfig succeeds", func(t *testing.T) { + cp, err := newConfigPoller(lggr, ethClient, mp, ocrAddress, &configStoreContractAddr) + require.NoError(t, err) + + t.Run("when config has not been set, returns error", func(t *testing.T) { + _, err := cp.LatestConfig(testutils.Context(t), 0) + require.Error(t, err) + + assert.Contains(t, err.Error(), "config details missing while trying to lookup config in store") + }) + t.Run("when config has been set, returns config", func(t *testing.T) { + b.Commit() + onchainDetails, err := ocrContract.LatestConfigDetails(nil) + require.NoError(t, err) + + contractConfig := setConfig(t, median.OffchainConfig{ + AlphaReportInfinite: false, + AlphaReportPPB: 0, + AlphaAcceptInfinite: true, + AlphaAcceptPPB: 0, + DeltaC: 10, + }, ocrContract, user) + + signerAddresses, err := OnchainPublicKeyToAddress(contractConfig.Signers) + require.NoError(t, err) + transmitterAddresses, err := AccountToAddress(contractConfig.Transmitters) + require.NoError(t, err) + + configuration := ocrconfigurationstoreevmsimple.OCRConfigurationStoreEVMSimpleConfigurationEVMSimple{ + Signers: signerAddresses, + Transmitters: transmitterAddresses, + OnchainConfig: contractConfig.OnchainConfig, + OffchainConfig: contractConfig.OffchainConfig, + ContractAddress: ocrAddress, + OffchainConfigVersion: contractConfig.OffchainConfigVersion, + ConfigCount: 1, + F: contractConfig.F, + } + + addConfig(t, user, configStoreContract, configuration) + + b.Commit() + onchainDetails, err = ocrContract.LatestConfigDetails(nil) + require.NoError(t, err) + + newConfig, err := cp.LatestConfig(testutils.Context(t), 0) + require.NoError(t, err) + + assert.Equal(t, onchainDetails.ConfigDigest, [32]byte(newConfig.ConfigDigest)) + assert.Equal(t, contractConfig.Signers, newConfig.Signers) + assert.Equal(t, contractConfig.Transmitters, newConfig.Transmitters) + assert.Equal(t, contractConfig.F, newConfig.F) + assert.Equal(t, contractConfig.OffchainConfigVersion, newConfig.OffchainConfigVersion) + assert.Equal(t, contractConfig.OffchainConfig, newConfig.OffchainConfig) + }) + }) + t.Run("returns error if callReadConfig fails", func(t *testing.T) { + failingClient := new(evmClientMocks.Client) + failingClient.On("ConfiguredChainID").Return(big.NewInt(42)) + failingClient.On("CallContract", mock.Anything, mock.MatchedBy(func(callArgs ethereum.CallMsg) bool { + // initial call to retrieve config store address from aggregator + return *callArgs.To == ocrAddress + }), mock.Anything).Return(nil, errors.New("something exploded")).Once() + cp, err := newConfigPoller(lggr, failingClient, mp, ocrAddress, &configStoreContractAddr) + require.NoError(t, err) + + _, err = cp.LatestConfig(testutils.Context(t), 0) + assert.EqualError(t, err, "failed to get latest config details: something exploded") + + failingClient.AssertExpectations(t) + }) + }) } func setConfig(t *testing.T, pluginConfig median.OffchainConfig, ocrContract *ocr2aggregator.OCR2Aggregator, user *bind.TransactOpts) ocrtypes2.ContractConfig { @@ -113,7 +329,7 @@ func setConfig(t *testing.T, pluginConfig median.OffchainConfig, ocrContract *oc oracles = append(oracles, confighelper2.OracleIdentityExtra{ OracleIdentity: confighelper2.OracleIdentity{ OnchainPublicKey: utils.RandomAddress().Bytes(), - TransmitAccount: ocrtypes2.Account(utils.RandomAddress().String()), + TransmitAccount: ocrtypes2.Account(utils.RandomAddress().Hex()), OffchainPublicKey: utils.RandomBytes32(), PeerID: utils.MustNewPeerID(), }, @@ -137,7 +353,7 @@ func setConfig(t *testing.T, pluginConfig median.OffchainConfig, ocrContract *oc 50*time.Millisecond, 50*time.Millisecond, 1, // faults - nil, + generateDefaultOCR2OnchainConfig(t, big.NewInt(0), big.NewInt(10)), ) require.NoError(t, err) signerAddresses, err := OnchainPublicKeyToAddress(signers) @@ -155,3 +371,33 @@ func setConfig(t *testing.T, pluginConfig median.OffchainConfig, ocrContract *oc OffchainConfig: offchainConfig, } } + +func addConfig(t *testing.T, user *bind.TransactOpts, configStoreContract *ocrconfigurationstoreevmsimple.OCRConfigurationStoreEVMSimple, config ocrconfigurationstoreevmsimple.OCRConfigurationStoreEVMSimpleConfigurationEVMSimple) { + + _, err := configStoreContract.AddConfig(user, config) + require.NoError(t, err) +} + +func generateDefaultOCR2OnchainConfig(t *testing.T, minValue *big.Int, maxValue *big.Int) []byte { + serializedConfig := make([]byte, 0) + + s1, err := bigbigendian.SerializeSigned(1, big.NewInt(1)) //version + if err != nil { + t.Fatal(err) + } + serializedConfig = append(serializedConfig, s1...) + + s2, err := bigbigendian.SerializeSigned(24, minValue) //min + if err != nil { + t.Fatal(err) + } + serializedConfig = append(serializedConfig, s2...) + + s3, err := bigbigendian.SerializeSigned(24, maxValue) //max + if err != nil { + t.Fatal(err) + } + serializedConfig = append(serializedConfig, s3...) + + return serializedConfig +} diff --git a/core/services/relay/evm/evm.go b/core/services/relay/evm/evm.go index 1ce68f2d944..f1731b9c438 100644 --- a/core/services/relay/evm/evm.go +++ b/core/services/relay/evm/evm.go @@ -292,7 +292,7 @@ func newConfigProvider(lggr logger.Logger, chain evm.Chain, opts *types.RelayOpt return nil, errors.Errorf("invalid contractID, expected hex address") } - contractAddress := common.HexToAddress(opts.ContractID) + aggregatorAddress := common.HexToAddress(opts.ContractID) contractABI, err := abi.JSON(strings.NewReader(ocr2aggregator.OCR2AggregatorMetaData.ABI)) if err != nil { return nil, errors.Wrap(err, "could not get contract ABI JSON") @@ -307,14 +307,18 @@ func newConfigProvider(lggr logger.Logger, chain evm.Chain, opts *types.RelayOpt cp, err = mercury.NewConfigPoller( lggr, chain.LogPoller(), - contractAddress, + aggregatorAddress, *relayConfig.FeedID, eventBroadcaster, + // TODO: Does mercury need to support config contract? DF-19182 ) } else { - cp, err = NewConfigPoller(lggr, + cp, err = NewConfigPoller( + lggr, + chain.Client(), chain.LogPoller(), - contractAddress, + aggregatorAddress, + relayConfig.ConfigContractAddress, ) } if err != nil { @@ -324,15 +328,15 @@ func newConfigProvider(lggr logger.Logger, chain evm.Chain, opts *types.RelayOpt var offchainConfigDigester ocrtypes.OffchainConfigDigester if relayConfig.FeedID != nil { // Mercury - offchainConfigDigester = mercury.NewOffchainConfigDigester(*relayConfig.FeedID, chain.Config().EVM().ChainID(), contractAddress) + offchainConfigDigester = mercury.NewOffchainConfigDigester(*relayConfig.FeedID, chain.Config().EVM().ChainID(), aggregatorAddress) } else { // Non-mercury offchainConfigDigester = evmutil.EVMOffchainConfigDigester{ ChainID: chain.Config().EVM().ChainID().Uint64(), - ContractAddress: contractAddress, + ContractAddress: aggregatorAddress, } } - return newConfigWatcher(lggr, contractAddress, contractABI, offchainConfigDigester, cp, chain, relayConfig.FromBlock, opts.New), nil + return newConfigWatcher(lggr, aggregatorAddress, contractABI, offchainConfigDigester, cp, chain, relayConfig.FromBlock, opts.New), nil } func newContractTransmitter(lggr logger.Logger, rargs relaytypes.RelayArgs, transmitterID string, configWatcher *configWatcher, ethKeystore keystore.Eth) (*contractTransmitter, error) { diff --git a/core/services/relay/evm/functions/config_poller.go b/core/services/relay/evm/functions/config_poller.go index 4feff842ce3..f068f13cc77 100644 --- a/core/services/relay/evm/functions/config_poller.go +++ b/core/services/relay/evm/functions/config_poller.go @@ -162,6 +162,9 @@ func (cp *configPoller) LatestConfig(ctx context.Context, changedInBlock uint64) if err != nil { return ocrtypes.ContractConfig{}, err } + if len(lgs) == 0 { + return ocrtypes.ContractConfig{}, errors.New("no logs found") + } latestConfigSet, err := configFromLog(lgs[len(lgs)-1].Data, cp.pluginType) if err != nil { return ocrtypes.ContractConfig{}, err diff --git a/core/services/relay/evm/functions/config_poller_test.go b/core/services/relay/evm/functions/config_poller_test.go index b6de78b49df..24296192318 100644 --- a/core/services/relay/evm/functions/config_poller_test.go +++ b/core/services/relay/evm/functions/config_poller_test.go @@ -6,6 +6,8 @@ import ( "testing" "time" + "github.com/smartcontractkit/libocr/bigbigendian" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/accounts/abi/bind/backends" "github.com/ethereum/go-ethereum/core" @@ -89,6 +91,8 @@ func runTest(t *testing.T, pluginType functions.FunctionsPluginType, expectedDig _, config, err := configPoller.LatestConfigDetails(testutils.Context(t)) require.NoError(t, err) require.Equal(t, ocrtypes2.ConfigDigest{}, config) + _, err = configPoller.LatestConfig(testutils.Context(t), 0) + require.Error(t, err) pluginConfig := &functionsConfig.ReportingPluginConfigWrapper{ Config: &functionsConfig.ReportingPluginConfig{ @@ -184,7 +188,7 @@ func setFunctionsConfig(t *testing.T, pluginConfig *functionsConfig.ReportingPlu 50*time.Millisecond, 50*time.Millisecond, 1, // faults - nil, + generateDefaultOCR2OnchainConfig(t, big.NewInt(0), big.NewInt(10)), ) require.NoError(t, err) @@ -203,3 +207,27 @@ func setFunctionsConfig(t *testing.T, pluginConfig *functionsConfig.ReportingPlu OffchainConfig: offchainConfig, } } + +func generateDefaultOCR2OnchainConfig(t *testing.T, minValue *big.Int, maxValue *big.Int) []byte { + var serializedConfig []byte + + s1, err := bigbigendian.SerializeSigned(1, big.NewInt(1)) //version + if err != nil { + t.Fatal(err) + } + serializedConfig = append(serializedConfig, s1...) + + s2, err := bigbigendian.SerializeSigned(24, minValue) //min + if err != nil { + t.Fatal(err) + } + serializedConfig = append(serializedConfig, s2...) + + s3, err := bigbigendian.SerializeSigned(24, maxValue) //max + if err != nil { + t.Fatal(err) + } + serializedConfig = append(serializedConfig, s3...) + + return serializedConfig +} diff --git a/core/services/relay/evm/ocr2keeper.go b/core/services/relay/evm/ocr2keeper.go index c6f4f1ad395..baf98b9b006 100644 --- a/core/services/relay/evm/ocr2keeper.go +++ b/core/services/relay/evm/ocr2keeper.go @@ -147,8 +147,11 @@ func newOCR2KeeperConfigProvider(lggr logger.Logger, chain evm.Chain, rargs rela configPoller, err := NewConfigPoller( lggr.With("contractID", rargs.ContractID), + chain.Client(), chain.LogPoller(), contractAddress, + // TODO: Does ocr2keeper need to support config contract? DF-19182 + nil, ) if err != nil { return nil, errors.Wrap(err, "failed to create config poller") diff --git a/core/services/relay/evm/ocr2vrf.go b/core/services/relay/evm/ocr2vrf.go index 6e440112e92..14004d0b1aa 100644 --- a/core/services/relay/evm/ocr2vrf.go +++ b/core/services/relay/evm/ocr2vrf.go @@ -135,8 +135,12 @@ func newOCR2VRFConfigProvider(lggr logger.Logger, chain evm.Chain, rargs relayty } configPoller, err := NewConfigPoller( lggr.With("contractID", rargs.ContractID), + chain.Client(), chain.LogPoller(), - contractAddress) + contractAddress, + // TODO: Does ocr2vrf need to support config contract? DF-19182 + nil, + ) if err != nil { return nil, err } diff --git a/core/services/relay/evm/types/types.go b/core/services/relay/evm/types/types.go index 8671082db25..97eddd7d9cf 100644 --- a/core/services/relay/evm/types/types.go +++ b/core/services/relay/evm/types/types.go @@ -20,9 +20,10 @@ import ( ) type RelayConfig struct { - ChainID *utils.Big `json:"chainID"` - FromBlock uint64 `json:"fromBlock"` - EffectiveTransmitterID null.String `json:"effectiveTransmitterID"` + ChainID *utils.Big `json:"chainID"` + FromBlock uint64 `json:"fromBlock"` + EffectiveTransmitterID null.String `json:"effectiveTransmitterID"` + ConfigContractAddress *common.Address `json:"configContractAddress"` // Contract-specific SendingKeys pq.StringArray `json:"sendingKeys"` diff --git a/go.mod b/go.mod index 895e8cb2c27..0bbf1d72915 100644 --- a/go.mod +++ b/go.mod @@ -70,8 +70,8 @@ require ( github.com/smartcontractkit/chainlink-relay v0.1.7-0.20230908162043-e2f9fcf758d8 github.com/smartcontractkit/chainlink-solana v1.0.3-0.20230831134610-680240b97aca github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20230901115736-bbabe542a918 - github.com/smartcontractkit/libocr v0.0.0-20230918212407-dbd4e505b3e6 - github.com/smartcontractkit/ocr2keepers v0.7.26 + github.com/smartcontractkit/libocr v0.0.0-20230922131214-122accb19ea6 + github.com/smartcontractkit/ocr2keepers v0.7.27 github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687 github.com/smartcontractkit/sqlx v1.3.5-0.20210805004948-4be295aacbeb github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 diff --git a/go.sum b/go.sum index bf25f87b80a..676348c0b60 100644 --- a/go.sum +++ b/go.sum @@ -1387,10 +1387,10 @@ github.com/smartcontractkit/go-plugin v0.0.0-20230605132010-0f4d515d1472 h1:x3kN github.com/smartcontractkit/go-plugin v0.0.0-20230605132010-0f4d515d1472/go.mod h1:6/1TEzT0eQznvI/gV2CM29DLSkAK/e58mUWKVsPaph0= github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f h1:hgJif132UCdjo8u43i7iPN1/MFnu49hv7lFGFftCHKU= github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f/go.mod h1:MvMXoufZAtqExNexqi4cjrNYE9MefKddKylxjS+//n0= -github.com/smartcontractkit/libocr v0.0.0-20230918212407-dbd4e505b3e6 h1:w+8TI2Vcm3vk8XQz40ddcwy9BNZgoakXIby35Y54iDU= -github.com/smartcontractkit/libocr v0.0.0-20230918212407-dbd4e505b3e6/go.mod h1:2lyRkw/qLQgUWlrWWmq5nj0y90rWeO6Y+v+fCakRgb0= -github.com/smartcontractkit/ocr2keepers v0.7.26 h1:8Usfdsa6GtliMQPThL1qb36d4J5xMyTCFJYgbGp4ecA= -github.com/smartcontractkit/ocr2keepers v0.7.26/go.mod h1:4e1ZDRz7fpLgcRUjJpq+5mkoD0ga11BxrSp2JTWKADQ= +github.com/smartcontractkit/libocr v0.0.0-20230922131214-122accb19ea6 h1:eSo9r53fARv2MnIO5pqYvQOXMBsTlAwhHyQ6BAVp6bY= +github.com/smartcontractkit/libocr v0.0.0-20230922131214-122accb19ea6/go.mod h1:2lyRkw/qLQgUWlrWWmq5nj0y90rWeO6Y+v+fCakRgb0= +github.com/smartcontractkit/ocr2keepers v0.7.27 h1:kwqMrzmEdq6gH4yqNuLQCbdlED0KaIjwZzu3FF+Gves= +github.com/smartcontractkit/ocr2keepers v0.7.27/go.mod h1:1QGzJURnoWpysguPowOe2bshV0hNp1YX10HHlhDEsas= github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687 h1:NwC3SOc25noBTe1KUQjt45fyTIuInhoE2UfgcHAdihM= github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687/go.mod h1:YYZq52t4wcHoMQeITksYsorD+tZcOyuVU5+lvot3VFM= github.com/smartcontractkit/sqlx v1.3.5-0.20210805004948-4be295aacbeb h1:OMaBUb4X9IFPLbGbCHsMU+kw/BPCrewaVwWGIBc0I4A= diff --git a/integration-tests/actions/ocr2_helpers_local.go b/integration-tests/actions/ocr2_helpers_local.go index c1e863561da..9851b888568 100644 --- a/integration-tests/actions/ocr2_helpers_local.go +++ b/integration-tests/actions/ocr2_helpers_local.go @@ -4,6 +4,10 @@ import ( "crypto/ed25519" "encoding/hex" "fmt" + "math/big" + "strings" + "time" + "github.com/ethereum/go-ethereum/common" "github.com/google/uuid" "github.com/lib/pq" @@ -14,13 +18,12 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/chaintype" "github.com/smartcontractkit/chainlink/v2/core/store/models" + "github.com/smartcontractkit/libocr/bigbigendian" "github.com/smartcontractkit/libocr/offchainreporting2/reportingplugin/median" "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "golang.org/x/sync/errgroup" "gopkg.in/guregu/null.v4" - "strings" - "time" ) func CreateOCRv2JobsLocal( @@ -133,7 +136,7 @@ func BuildMedianOCR2ConfigLocal(workerNodes []*client.ChainlinkClient) (*contrac if err != nil { return nil, err } - signerKeys, transmitterAccounts, f_, onchainConfig, offchainConfigVersion, offchainConfig, err := confighelper.ContractSetConfigArgsForTests( + signerKeys, transmitterAccounts, f_, _, offchainConfigVersion, offchainConfig, err := confighelper.ContractSetConfigArgsForTests( 30*time.Second, // deltaProgress time.Duration, 30*time.Second, // deltaResend time.Duration, 10*time.Second, // deltaRound time.Duration, @@ -173,6 +176,9 @@ func BuildMedianOCR2ConfigLocal(workerNodes []*client.ChainlinkClient) (*contrac transmitterAddresses = append(transmitterAddresses, common.HexToAddress(string(account))) } + minAnswer, maxAnswer := big.NewInt(1), big.NewInt(50000000000000000) + onchainConfig, err := generateDefaultOCR2OnchainConfig(minAnswer, maxAnswer) + return &contracts.OCRv2Config{ Signers: signerAddresses, Transmitters: transmitterAddresses, @@ -180,7 +186,31 @@ func BuildMedianOCR2ConfigLocal(workerNodes []*client.ChainlinkClient) (*contrac OnchainConfig: onchainConfig, OffchainConfigVersion: offchainConfigVersion, OffchainConfig: []byte(fmt.Sprintf("0x%s", offchainConfig)), - }, nil + }, err +} + +func generateDefaultOCR2OnchainConfig(minValue *big.Int, maxValue *big.Int) ([]byte, error) { + serializedConfig := make([]byte, 0) + + s1, err := bigbigendian.SerializeSigned(1, big.NewInt(1)) //version + if err != nil { + return nil, err + } + serializedConfig = append(serializedConfig, s1...) + + s2, err := bigbigendian.SerializeSigned(24, minValue) //min + if err != nil { + return nil, err + } + serializedConfig = append(serializedConfig, s2...) + + s3, err := bigbigendian.SerializeSigned(24, maxValue) //max + if err != nil { + return nil, err + } + serializedConfig = append(serializedConfig, s3...) + + return serializedConfig, nil } func GetOracleIdentitiesWithKeyIndexLocal( @@ -266,4 +296,4 @@ func GetOracleIdentitiesWithKeyIndexLocal( } return S, oracleIdentities, eg.Wait() -} +} \ No newline at end of file diff --git a/integration-tests/go.mod b/integration-tests/go.mod index 54e8b8f3665..fb3f4c40d40 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -22,8 +22,8 @@ require ( github.com/smartcontractkit/chainlink-env v0.36.0 github.com/smartcontractkit/chainlink-testing-framework v1.16.5-0.20230908202859-e75102cf5f40 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 - github.com/smartcontractkit/libocr v0.0.0-20230918212407-dbd4e505b3e6 - github.com/smartcontractkit/ocr2keepers v0.7.26 + github.com/smartcontractkit/libocr v0.0.0-20230922131214-122accb19ea6 + github.com/smartcontractkit/ocr2keepers v0.7.27 github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687 github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 github.com/smartcontractkit/wasp v0.3.0 diff --git a/integration-tests/go.sum b/integration-tests/go.sum index e4dcb9a8d3d..75e9d2d11ad 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -2264,10 +2264,10 @@ github.com/smartcontractkit/go-plugin v0.0.0-20230605132010-0f4d515d1472 h1:x3kN github.com/smartcontractkit/go-plugin v0.0.0-20230605132010-0f4d515d1472/go.mod h1:6/1TEzT0eQznvI/gV2CM29DLSkAK/e58mUWKVsPaph0= github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f h1:hgJif132UCdjo8u43i7iPN1/MFnu49hv7lFGFftCHKU= github.com/smartcontractkit/grpc-proxy v0.0.0-20230731113816-f1be6620749f/go.mod h1:MvMXoufZAtqExNexqi4cjrNYE9MefKddKylxjS+//n0= -github.com/smartcontractkit/libocr v0.0.0-20230918212407-dbd4e505b3e6 h1:w+8TI2Vcm3vk8XQz40ddcwy9BNZgoakXIby35Y54iDU= -github.com/smartcontractkit/libocr v0.0.0-20230918212407-dbd4e505b3e6/go.mod h1:2lyRkw/qLQgUWlrWWmq5nj0y90rWeO6Y+v+fCakRgb0= -github.com/smartcontractkit/ocr2keepers v0.7.26 h1:8Usfdsa6GtliMQPThL1qb36d4J5xMyTCFJYgbGp4ecA= -github.com/smartcontractkit/ocr2keepers v0.7.26/go.mod h1:4e1ZDRz7fpLgcRUjJpq+5mkoD0ga11BxrSp2JTWKADQ= +github.com/smartcontractkit/libocr v0.0.0-20230922131214-122accb19ea6 h1:eSo9r53fARv2MnIO5pqYvQOXMBsTlAwhHyQ6BAVp6bY= +github.com/smartcontractkit/libocr v0.0.0-20230922131214-122accb19ea6/go.mod h1:2lyRkw/qLQgUWlrWWmq5nj0y90rWeO6Y+v+fCakRgb0= +github.com/smartcontractkit/ocr2keepers v0.7.27 h1:kwqMrzmEdq6gH4yqNuLQCbdlED0KaIjwZzu3FF+Gves= +github.com/smartcontractkit/ocr2keepers v0.7.27/go.mod h1:1QGzJURnoWpysguPowOe2bshV0hNp1YX10HHlhDEsas= github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687 h1:NwC3SOc25noBTe1KUQjt45fyTIuInhoE2UfgcHAdihM= github.com/smartcontractkit/ocr2vrf v0.0.0-20230804151440-2f1eb1e20687/go.mod h1:YYZq52t4wcHoMQeITksYsorD+tZcOyuVU5+lvot3VFM= github.com/smartcontractkit/sqlx v1.3.5-0.20210805004948-4be295aacbeb h1:OMaBUb4X9IFPLbGbCHsMU+kw/BPCrewaVwWGIBc0I4A=