From d3ecbdac9976222ca2d370c2a2ca9c4368964339 Mon Sep 17 00:00:00 2001 From: Ryan Tinianov Date: Thu, 16 May 2024 09:11:45 -0400 Subject: [PATCH] Allow re-use of chain reader tests outside go testing to allow applications to test against actual chains and optomize the use of the contracts. --- core/capabilities/streams/codec.go | 4 +- core/capabilities/syncer.go | 3 +- .../evm/client/simulated_backend_client.go | 2 +- core/scripts/go.mod | 2 +- core/scripts/go.sum | 4 +- core/services/relay/evm/chain_reader_test.go | 425 ++---------------- core/services/relay/evm/codec_test.go | 39 +- .../chain_reader_interface_tester.go | 327 ++++++++++++++ .../relay/evm/evmtesting/run_tests.go | 80 ++++ go.mod | 2 +- go.sum | 4 +- integration-tests/go.mod | 2 +- integration-tests/go.sum | 4 +- integration-tests/load/go.mod | 2 +- integration-tests/load/go.sum | 4 +- 15 files changed, 504 insertions(+), 400 deletions(-) create mode 100644 core/services/relay/evm/evmtesting/chain_reader_interface_tester.go create mode 100644 core/services/relay/evm/evmtesting/run_tests.go diff --git a/core/capabilities/streams/codec.go b/core/capabilities/streams/codec.go index 48befd602ac..7c1a62c6f71 100644 --- a/core/capabilities/streams/codec.go +++ b/core/capabilities/streams/codec.go @@ -8,9 +8,9 @@ import ( type Codec struct { } -func (c Codec) Unwrap(raw values.Value) ([]datastreams.FeedReport, error) { +func (c Codec) UnwrapValid(wrapped values.Value, allowedSigners [][]byte, minRequiredSignatures int) ([]datastreams.FeedReport, error) { dest := []datastreams.FeedReport{} - err := raw.UnwrapTo(&dest) + err := wrapped.UnwrapTo(&dest) // TODO (KS-196): validate reports return dest, err } diff --git a/core/capabilities/syncer.go b/core/capabilities/syncer.go index 98a77dc458a..04458f58a7c 100644 --- a/core/capabilities/syncer.go +++ b/core/capabilities/syncer.go @@ -113,7 +113,8 @@ func (s *registrySyncer) Start(ctx context.Context) error { if slices.Contains(workflowDONPeers, myId) { s.lggr.Info("member of a workflow DON - starting remote subscribers") codec := streams.NewCodec() - aggregator := triggers.NewMercuryRemoteAggregator(codec, s.lggr) + // TODO (KS-196): validate reports + aggregator := triggers.NewMercuryRemoteAggregator(codec, nil, 0, s.lggr) triggerCap := remote.NewTriggerSubscriber(config, triggerInfo, triggerCapabilityDonInfo, workflowDonInfo, s.dispatcher, aggregator, s.lggr) err = s.registry.Add(ctx, triggerCap) if err != nil { diff --git a/core/chains/evm/client/simulated_backend_client.go b/core/chains/evm/client/simulated_backend_client.go index 9fe2ff88ba7..6bcc1f36960 100644 --- a/core/chains/evm/client/simulated_backend_client.go +++ b/core/chains/evm/client/simulated_backend_client.go @@ -451,7 +451,7 @@ func (c *SimulatedBackendClient) EstimateGas(ctx context.Context, call ethereum. // SuggestGasPrice recommends a gas price. func (c *SimulatedBackendClient) SuggestGasPrice(ctx context.Context) (*big.Int, error) { - panic("unimplemented") + return c.b.SuggestGasPrice(ctx) } // BatchCallContext makes a batch rpc call. diff --git a/core/scripts/go.mod b/core/scripts/go.mod index 0595d5f065c..567217f761f 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -21,7 +21,7 @@ require ( github.com/prometheus/client_golang v1.17.0 github.com/shopspring/decimal v1.3.1 github.com/smartcontractkit/chainlink-automation v1.0.3 - github.com/smartcontractkit/chainlink-common v0.1.7-0.20240517134904-f4446b816a28 + github.com/smartcontractkit/chainlink-common v0.1.7-0.20240521170829-83ce604cf618 github.com/smartcontractkit/chainlink-vrf v0.0.0-20240222010609-cd67d123c772 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 github.com/smartcontractkit/libocr v0.0.0-20240419185742-fd3cab206b2c diff --git a/core/scripts/go.sum b/core/scripts/go.sum index e15c02cd9be..b4faaec511f 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -1185,8 +1185,8 @@ github.com/smartcontractkit/chain-selectors v1.0.10 h1:t9kJeE6B6G+hKD0GYR4kGJSCq github.com/smartcontractkit/chain-selectors v1.0.10/go.mod h1:d4Hi+E1zqjy9HqMkjBE5q1vcG9VGgxf5VxiRHfzi2kE= github.com/smartcontractkit/chainlink-automation v1.0.3 h1:h/ijT0NiyV06VxYVgcNfsE3+8OEzT3Q0Z9au0z1BPWs= github.com/smartcontractkit/chainlink-automation v1.0.3/go.mod h1:RjboV0Qd7YP+To+OrzHGXaxUxoSONveCoAK2TQ1INLU= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20240517134904-f4446b816a28 h1:Pr8/CdiTNnzRwpYc2z7NpHYbw3Dpl1eqiqt9/J/Bcqc= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20240517134904-f4446b816a28/go.mod h1:s+68EchlrXqHKRW3JJgZLEARvzMSKRI5+cE5Zx7pVJA= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240521170829-83ce604cf618 h1:0aR8bbEaUXObEVvn6jayWO0zE0Hn0m+xv1R5V2hvQ6w= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240521170829-83ce604cf618/go.mod h1:s+68EchlrXqHKRW3JJgZLEARvzMSKRI5+cE5Zx7pVJA= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240508101745-af1ed7bc8a69 h1:Sec/GpBpUVaTEax1kSHlTvkzF/+d3w5roAQXaj5+SLA= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240508101745-af1ed7bc8a69/go.mod h1:ZQKf+0OLzCLYIisH/OdOIQuFRI6bDuw+jPBTATyHfFM= github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240220203239-09be0ea34540 h1:xFSv8561jsLtF6gYZr/zW2z5qUUAkcFkApin2mnbYTo= diff --git a/core/services/relay/evm/chain_reader_test.go b/core/services/relay/evm/chain_reader_test.go index 662d5258bfb..802972d43d6 100644 --- a/core/services/relay/evm/chain_reader_test.go +++ b/core/services/relay/evm/chain_reader_test.go @@ -1,437 +1,102 @@ package evm_test import ( - "crypto/ecdsa" + "context" "fmt" "math" "math/big" "os" - "reflect" "strconv" "testing" "time" - "github.com/ethereum/go-ethereum/accounts/abi" "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/common/hexutil" "github.com/ethereum/go-ethereum/core" - evmtypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" - "github.com/smartcontractkit/libocr/commontypes" - "github.com/stretchr/testify/assert" + "github.com/jmoiron/sqlx" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink-common/pkg/codec" - - clcommontypes "github.com/smartcontractkit/chainlink-common/pkg/types" . "github.com/smartcontractkit/chainlink-common/pkg/types/interfacetests" //nolint common practice to import test mods with . commontestutils "github.com/smartcontractkit/chainlink-common/pkg/loop/testutils" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/chain_reader_tester" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" - "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" - "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" + . "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/evmtesting" //nolint common practice to import test mods with . ) -const ( - commonGasLimitOnEvms = uint64(4712388) - triggerWithDynamicTopic = "TriggeredEventWithDynamicTopic" - triggerWithAllTopics = "TriggeredWithFourTopics" -) +const commonGasLimitOnEvms = uint64(4712388) -func TestChainReaderInterfaceTests(t *testing.T) { +func TestChainReader(t *testing.T) { t.Parallel() - it := &chainReaderInterfaceTester{} - - RunChainReaderInterfaceTests(t, it) - RunChainReaderInterfaceTests(t, commontestutils.WrapChainReaderTesterForLoop(it)) - - t.Run("Dynamically typed topics can be used to filter and have type correct in return", func(t *testing.T) { - it.Setup(t) - - // bind event before firing it to avoid log poller race - ctx := testutils.Context(t) - cr := it.GetChainReader(t) - require.NoError(t, cr.Bind(ctx, it.GetBindings(t))) - - anyString := "foo" - tx, err := it.evmTest.TriggerEventWithDynamicTopic(it.auth, anyString) - require.NoError(t, err) - it.sim.Commit() - it.incNonce() - it.awaitTx(t, tx) - - input := struct{ Field string }{Field: anyString} - tp := cr.(clcommontypes.ContractTypeProvider) - output, err := tp.CreateContractType(AnyContractName, triggerWithDynamicTopic, false) - require.NoError(t, err) - rOutput := reflect.Indirect(reflect.ValueOf(output)) - - require.Eventually(t, func() bool { - return cr.GetLatestValue(ctx, AnyContractName, triggerWithDynamicTopic, input, output) == nil - }, it.MaxWaitTimeForEvents(), time.Millisecond*10) - - assert.Equal(t, &anyString, rOutput.FieldByName("Field").Interface()) - topic, err := abi.MakeTopics([]any{anyString}) - require.NoError(t, err) - assert.Equal(t, &topic[0][0], rOutput.FieldByName("FieldHash").Interface()) - }) - - t.Run("Multiple topics can filter together", func(t *testing.T) { - it.Setup(t) - - // bind event before firing it to avoid log poller race - ctx := testutils.Context(t) - cr := it.GetChainReader(t) - require.NoError(t, cr.Bind(ctx, it.GetBindings(t))) - - triggerFourTopics(t, it, int32(1), int32(2), int32(3)) - triggerFourTopics(t, it, int32(2), int32(2), int32(3)) - triggerFourTopics(t, it, int32(1), int32(3), int32(3)) - triggerFourTopics(t, it, int32(1), int32(2), int32(4)) - - var latest struct{ Field1, Field2, Field3 int32 } - params := struct{ Field1, Field2, Field3 int32 }{Field1: 1, Field2: 2, Field3: 3} - - require.Eventually(t, func() bool { - return cr.GetLatestValue(ctx, AnyContractName, triggerWithAllTopics, params, &latest) == nil - }, it.MaxWaitTimeForEvents(), time.Millisecond*10) - - assert.Equal(t, int32(1), latest.Field1) - assert.Equal(t, int32(2), latest.Field2) - assert.Equal(t, int32(3), latest.Field3) - }) -} - -func triggerFourTopics(t *testing.T, it *chainReaderInterfaceTester, i1, i2, i3 int32) { - tx, err := it.evmTest.ChainReaderTesterTransactor.TriggerWithFourTopics(it.auth, i1, i2, i3) - require.NoError(t, err) - require.NoError(t, err) - it.sim.Commit() - it.incNonce() - it.awaitTx(t, tx) -} - -type chainReaderInterfaceTester struct { - client client.Client - address string - address2 string - chainConfig types.ChainReaderConfig - auth *bind.TransactOpts - sim *backends.SimulatedBackend - pk *ecdsa.PrivateKey - evmTest *chain_reader_tester.ChainReaderTester - cr evm.ChainReaderService -} - -func (it *chainReaderInterfaceTester) MaxWaitTimeForEvents() time.Duration { - // From trial and error, when running on CI, sometimes the boxes get slow - maxWaitTime := time.Second * 20 - maxWaitTimeStr, ok := os.LookupEnv("MAX_WAIT_TIME_FOR_EVENTS_S") - if ok { - waitS, err := strconv.ParseInt(maxWaitTimeStr, 10, 64) - if err != nil { - fmt.Printf("Error parsing MAX_WAIT_TIME_FOR_EVENTS_S: %v, defaulting to %v\n", err, maxWaitTime) - } - maxWaitTime = time.Second * time.Duration(waitS) - } - - return maxWaitTime -} - -func (it *chainReaderInterfaceTester) Setup(t *testing.T) { - t.Cleanup(func() { - // DB may be closed by the test already, ignore errors - if it.cr != nil { - _ = it.cr.Close() - } - it.cr = nil - it.evmTest = nil - }) - - // can re-use the same chain for tests, just make new contract for each test - if it.client != nil { - it.deployNewContracts(t) - return - } - - it.setupChainNoClient(t) - - testStruct := CreateTestStruct(0, it) - - it.chainConfig = types.ChainReaderConfig{ - Contracts: map[string]types.ChainContractReader{ - AnyContractName: { - ContractABI: chain_reader_tester.ChainReaderTesterMetaData.ABI, - Configs: map[string]*types.ChainReaderDefinition{ - MethodTakingLatestParamsReturningTestStruct: { - ChainSpecificName: "getElementAtIndex", - OutputModifications: codec.ModifiersConfig{ - &codec.RenameModifierConfig{Fields: map[string]string{"NestedStruct.Inner.IntVal": "I"}}, - }, - }, - MethodReturningUint64: { - ChainSpecificName: "getPrimitiveValue", - }, - DifferentMethodReturningUint64: { - ChainSpecificName: "getDifferentPrimitiveValue", - }, - MethodReturningUint64Slice: { - ChainSpecificName: "getSliceValue", - }, - EventName: { - ChainSpecificName: "Triggered", - ReadType: types.Event, - OutputModifications: codec.ModifiersConfig{ - &codec.RenameModifierConfig{Fields: map[string]string{"NestedStruct.Inner.IntVal": "I"}}, - }, - }, - EventWithFilterName: { - ChainSpecificName: "Triggered", - ReadType: types.Event, - EventInputFields: []string{"Field"}, - }, - triggerWithDynamicTopic: { - ChainSpecificName: triggerWithDynamicTopic, - ReadType: types.Event, - EventInputFields: []string{"fieldHash"}, - InputModifications: codec.ModifiersConfig{ - &codec.RenameModifierConfig{Fields: map[string]string{"FieldHash": "Field"}}, - }, - }, - triggerWithAllTopics: { - ChainSpecificName: triggerWithAllTopics, - ReadType: types.Event, - EventInputFields: []string{"Field1", "Field2", "Field3"}, - }, - MethodReturningSeenStruct: { - ChainSpecificName: "returnSeen", - InputModifications: codec.ModifiersConfig{ - &codec.HardCodeModifierConfig{ - OnChainValues: map[string]any{ - "BigField": testStruct.BigField.String(), - "Account": hexutil.Encode(testStruct.Account), - }, - }, - &codec.RenameModifierConfig{Fields: map[string]string{"NestedStruct.Inner.IntVal": "I"}}, - }, - OutputModifications: codec.ModifiersConfig{ - &codec.HardCodeModifierConfig{OffChainValues: map[string]any{"ExtraField": anyExtraValue}}, - &codec.RenameModifierConfig{Fields: map[string]string{"NestedStruct.Inner.IntVal": "I"}}, - }, - }, - }, - }, - AnySecondContractName: { - ContractABI: chain_reader_tester.ChainReaderTesterMetaData.ABI, - Configs: map[string]*types.ChainReaderDefinition{ - MethodReturningUint64: { - ChainSpecificName: "getDifferentPrimitiveValue", - }, - }, - }, - }, - } - it.client = client.NewSimulatedBackendClient(t, it.sim, big.NewInt(1337)) - it.deployNewContracts(t) -} - -func (it *chainReaderInterfaceTester) Name() string { - return "EVM" + it := &EvmChainReaderInterfaceTester[*testing.T]{Helper: &helper{}} + RunChainReaderEvmTests(t, it) + RunChainReaderInterfaceTests[*testing.T](t, commontestutils.WrapChainReaderTesterForLoop(it)) } -func (it *chainReaderInterfaceTester) GetAccountBytes(i int) []byte { - account := [20]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10} - account[i%20] += byte(i) - account[(i+3)%20] += byte(i + 3) - return account[:] +type helper struct { + sim *backends.SimulatedBackend + auth *bind.TransactOpts } -func (it *chainReaderInterfaceTester) GetChainReader(t *testing.T) clcommontypes.ChainReader { - ctx := testutils.Context(t) - if it.cr != nil { - return it.cr - } - - lggr := logger.NullLogger - db := pgtest.NewSqlxDB(t) - lpOpts := logpoller.Opts{ - PollPeriod: time.Millisecond, - FinalityDepth: 4, - BackfillBatchSize: 1, - RpcBatchSize: 1, - KeepFinalizedBlocksDepth: 10000, - } - lp := logpoller.NewLogPoller(logpoller.NewORM(testutils.SimulatedChainID, db, lggr), it.client, lggr, lpOpts) - require.NoError(t, lp.Start(ctx)) - cr, err := evm.NewChainReaderService(ctx, lggr, lp, it.client, it.chainConfig) - require.NoError(t, err) - require.NoError(t, cr.Start(ctx)) - it.cr = cr - return cr -} - -func (it *chainReaderInterfaceTester) SetLatestValue(t *testing.T, testStruct *TestStruct) { - it.sendTxWithTestStruct(t, testStruct, (*chain_reader_tester.ChainReaderTesterTransactor).AddTestStruct) +func (h *helper) GasPriceBufferPercent() int64 { + return 0 } -func (it *chainReaderInterfaceTester) TriggerEvent(t *testing.T, testStruct *TestStruct) { - it.sendTxWithTestStruct(t, testStruct, (*chain_reader_tester.ChainReaderTesterTransactor).TriggerEvent) -} - -func (it *chainReaderInterfaceTester) GetBindings(_ *testing.T) []clcommontypes.BoundContract { - return []clcommontypes.BoundContract{ - {Name: AnyContractName, Address: it.address, Pending: true}, - {Name: AnySecondContractName, Address: it.address2, Pending: true}, - } -} - -type testStructFn = func(*chain_reader_tester.ChainReaderTesterTransactor, *bind.TransactOpts, int32, string, uint8, [32]uint8, common.Address, []common.Address, *big.Int, chain_reader_tester.MidLevelTestStruct) (*evmtypes.Transaction, error) - -func (it *chainReaderInterfaceTester) sendTxWithTestStruct(t *testing.T, testStruct *TestStruct, fn testStructFn) { - tx, err := fn( - &it.evmTest.ChainReaderTesterTransactor, - it.auth, - *testStruct.Field, - testStruct.DifferentField, - uint8(testStruct.OracleID), - convertOracleIDs(testStruct.OracleIDs), - common.Address(testStruct.Account), - convertAccounts(testStruct.Accounts), - testStruct.BigField, - midToInternalType(testStruct.NestedStruct), - ) - require.NoError(t, err) - it.sim.Commit() - it.incNonce() - it.awaitTx(t, tx) -} - -func convertOracleIDs(oracleIDs [32]commontypes.OracleID) [32]byte { - convertedIds := [32]byte{} - for i, id := range oracleIDs { - convertedIds[i] = byte(id) - } - return convertedIds -} - -func convertAccounts(accounts [][]byte) []common.Address { - convertedAccounts := make([]common.Address, len(accounts)) - for i, a := range accounts { - convertedAccounts[i] = common.Address(a) - } - return convertedAccounts -} - -func (it *chainReaderInterfaceTester) setupChainNoClient(t require.TestingT) { +func (h *helper) SetupAuth(t *testing.T) *bind.TransactOpts { privateKey, err := crypto.GenerateKey() require.NoError(t, err) - it.pk = privateKey - it.auth, err = bind.NewKeyedTransactorWithChainID(privateKey, big.NewInt(1337)) + h.auth, err = bind.NewKeyedTransactorWithChainID(privateKey, big.NewInt(1337)) require.NoError(t, err) - it.sim = backends.NewSimulatedBackend(core.GenesisAlloc{it.auth.From: {Balance: big.NewInt(math.MaxInt64)}}, commonGasLimitOnEvms*5000) - it.sim.Commit() -} - -func (it *chainReaderInterfaceTester) deployNewContracts(t *testing.T) { - it.address = it.deployNewContract(t) - it.address2 = it.deployNewContract(t) + h.Backend() + h.Commit() + return h.auth } -func (it *chainReaderInterfaceTester) deployNewContract(t *testing.T) string { - ctx := testutils.Context(t) - gasPrice, err := it.sim.SuggestGasPrice(ctx) - require.NoError(t, err) - it.auth.GasPrice = gasPrice - - // 105528 was in the error: gas too low: have 0, want 105528 - // Not sure if there's a better way to get it. - it.auth.GasLimit = 10552800 - - address, tx, ts, err := chain_reader_tester.DeployChainReaderTester(it.auth, it.sim) - - require.NoError(t, err) - it.sim.Commit() - if it.evmTest == nil { - it.evmTest = ts +func (h *helper) Backend() bind.ContractBackend { + if h.sim == nil { + h.sim = backends.NewSimulatedBackend( + core.GenesisAlloc{h.auth.From: {Balance: big.NewInt(math.MaxInt64)}}, commonGasLimitOnEvms*5000) } - it.incNonce() - it.awaitTx(t, tx) - return address.String() -} -func (it *chainReaderInterfaceTester) awaitTx(t *testing.T, tx *evmtypes.Transaction) { - ctx := testutils.Context(t) - receipt, err := it.sim.TransactionReceipt(ctx, tx.Hash()) - require.NoError(t, err) - require.Equal(t, evmtypes.ReceiptStatusSuccessful, receipt.Status) + return h.sim } -func (it *chainReaderInterfaceTester) incNonce() { - if it.auth.Nonce == nil { - it.auth.Nonce = big.NewInt(1) - } else { - it.auth.Nonce = it.auth.Nonce.Add(it.auth.Nonce, big.NewInt(1)) - } +func (h *helper) Commit() { + h.sim.Commit() } -func getAccounts(first TestStruct) []common.Address { - accountBytes := make([]common.Address, len(first.Accounts)) - for i, account := range first.Accounts { - accountBytes[i] = common.Address(account) - } - return accountBytes +func (h *helper) Client(t *testing.T) client.Client { + return client.NewSimulatedBackendClient(t, h.sim, big.NewInt(1337)) } -func argsFromTestStruct(ts TestStruct) []any { - return []any{ - ts.Field, - ts.DifferentField, - uint8(ts.OracleID), - getOracleIDs(ts), - common.Address(ts.Account), - getAccounts(ts), - ts.BigField, - midToInternalType(ts.NestedStruct), - } +func (h *helper) ChainID() *big.Int { + return testutils.SimulatedChainID } -func getOracleIDs(first TestStruct) [32]byte { - oracleIDs := [32]byte{} - for i, oracleID := range first.OracleIDs { - oracleIDs[i] = byte(oracleID) - } - return oracleIDs +func (h *helper) NewSqlxDB(t *testing.T) *sqlx.DB { + return pgtest.NewSqlxDB(t) } -func toInternalType(testStruct TestStruct) chain_reader_tester.TestStruct { - return chain_reader_tester.TestStruct{ - Field: *testStruct.Field, - DifferentField: testStruct.DifferentField, - OracleId: byte(testStruct.OracleID), - OracleIds: convertOracleIDs(testStruct.OracleIDs), - Account: common.Address(testStruct.Account), - Accounts: convertAccounts(testStruct.Accounts), - BigField: testStruct.BigField, - NestedStruct: midToInternalType(testStruct.NestedStruct), - } +func (h *helper) Context(t *testing.T) context.Context { + return testutils.Context(t) } -func midToInternalType(m MidLevelTestStruct) chain_reader_tester.MidLevelTestStruct { - return chain_reader_tester.MidLevelTestStruct{ - FixedBytes: m.FixedBytes, - Inner: chain_reader_tester.InnerTestStruct{ - IntVal: int64(m.Inner.I), - S: m.Inner.S, - }, +func (h *helper) MaxWaitTimeForEvents() time.Duration { + // From trial and error, when running on CI, sometimes the boxes get slow + maxWaitTime := time.Second * 30 + maxWaitTimeStr, ok := os.LookupEnv("MAX_WAIT_TIME_FOR_EVENTS_S") + if ok { + waitS, err := strconv.ParseInt(maxWaitTimeStr, 10, 64) + if err != nil { + fmt.Printf("Error parsing MAX_WAIT_TIME_FOR_EVENTS_S: %v, defaulting to %v\n", err, maxWaitTime) + } + maxWaitTime = time.Second * time.Duration(waitS) } + + return maxWaitTime } diff --git a/core/services/relay/evm/codec_test.go b/core/services/relay/evm/codec_test.go index 0597560aaec..7ea0a6684da 100644 --- a/core/services/relay/evm/codec_test.go +++ b/core/services/relay/evm/codec_test.go @@ -5,6 +5,7 @@ import ( "testing" "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" ocr2types "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "github.com/stretchr/testify/assert" @@ -19,6 +20,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/chain_reader_tester" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" + "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/evmtesting" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" ) @@ -100,7 +102,7 @@ func (it *codecInterfaceTester) EncodeFields(t *testing.T, request *EncodeReques func (it *codecInterfaceTester) GetCodec(t *testing.T) commontypes.Codec { codecConfig := types.CodecConfig{Configs: map[string]types.ChainCodecConfig{}} - testStruct := CreateTestStruct(0, it) + testStruct := CreateTestStruct[*testing.T](0, it) for k, v := range codecDefs { defBytes, err := json.Marshal(v) require.NoError(t, err) @@ -148,13 +150,13 @@ func encodeFieldsOnSliceOrArray(t *testing.T, request *EncodeRequest) []byte { switch request.TestOn { case TestItemArray1Type: - args[0] = [1]chain_reader_tester.TestStruct{toInternalType(request.TestStructs[0])} + args[0] = [1]chain_reader_tester.TestStruct{evmtesting.ToInternalType(request.TestStructs[0])} case TestItemArray2Type: - args[0] = [2]chain_reader_tester.TestStruct{toInternalType(request.TestStructs[0]), toInternalType(request.TestStructs[1])} + args[0] = [2]chain_reader_tester.TestStruct{evmtesting.ToInternalType(request.TestStructs[0]), evmtesting.ToInternalType(request.TestStructs[1])} default: tmp := make([]chain_reader_tester.TestStruct, len(request.TestStructs)) for i, ts := range request.TestStructs { - tmp[i] = toInternalType(ts) + tmp[i] = evmtesting.ToInternalType(ts) } args[0] = tmp } @@ -233,3 +235,32 @@ func parseDefs(t *testing.T) map[string]abi.Arguments { require.NoError(t, json.Unmarshal(bytes, &results)) return results } + +func getAccounts(first TestStruct) []common.Address { + accountBytes := make([]common.Address, len(first.Accounts)) + for i, account := range first.Accounts { + accountBytes[i] = common.Address(account) + } + return accountBytes +} + +func getOracleIDs(first TestStruct) [32]byte { + oracleIDs := [32]byte{} + for i, oracleID := range first.OracleIDs { + oracleIDs[i] = byte(oracleID) + } + return oracleIDs +} + +func argsFromTestStruct(ts TestStruct) []any { + return []any{ + ts.Field, + ts.DifferentField, + uint8(ts.OracleID), + getOracleIDs(ts), + common.Address(ts.Account), + getAccounts(ts), + ts.BigField, + evmtesting.MidToInternalType(ts.NestedStruct), + } +} diff --git a/core/services/relay/evm/evmtesting/chain_reader_interface_tester.go b/core/services/relay/evm/evmtesting/chain_reader_interface_tester.go new file mode 100644 index 00000000000..e36c76bdc3f --- /dev/null +++ b/core/services/relay/evm/evmtesting/chain_reader_interface_tester.go @@ -0,0 +1,327 @@ +package evmtesting + +import ( + "context" + "math/big" + "time" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/jmoiron/sqlx" + "github.com/smartcontractkit/libocr/commontypes" + + "github.com/smartcontractkit/chainlink-common/pkg/codec" + clcommontypes "github.com/smartcontractkit/chainlink-common/pkg/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/gethwrappers/generated/chain_reader_tester" + _ "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" // force binding for tx type + "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" + "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" + + evmtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/stretchr/testify/require" + + . "github.com/smartcontractkit/chainlink-common/pkg/types/interfacetests" //nolint common practice to import test mods with . +) + +const ( + triggerWithDynamicTopic = "TriggeredEventWithDynamicTopic" + triggerWithAllTopics = "TriggeredWithFourTopics" +) + +type EvmChainReaderInterfaceTesterHelper[T TestingT[T]] interface { + SetupAuth(t T) *bind.TransactOpts + Client(t T) client.Client + Commit() + Backend() bind.ContractBackend + ChainID() *big.Int + Context(t T) context.Context + NewSqlxDB(t T) *sqlx.DB + MaxWaitTimeForEvents() time.Duration + GasPriceBufferPercent() int64 +} + +type EvmChainReaderInterfaceTester[T TestingT[T]] struct { + Helper EvmChainReaderInterfaceTesterHelper[T] + client client.Client + address string + address2 string + chainConfig types.ChainReaderConfig + auth *bind.TransactOpts + evmTest *chain_reader_tester.ChainReaderTester + cr evm.ChainReaderService + dirtyContracts bool +} + +func (it *EvmChainReaderInterfaceTester[T]) Setup(t T) { + t.Cleanup(func() { + // DB may be closed by the test already, ignore errors + if it.cr != nil { + _ = it.cr.Close() + } + it.cr = nil + + if it.dirtyContracts { + it.evmTest = nil + } + }) + + // can re-use the same chain for tests, just make new contract for each test + if it.client != nil { + it.deployNewContracts(t) + return + } + + it.auth = it.Helper.SetupAuth(t) + + testStruct := CreateTestStruct[T](0, it) + + it.chainConfig = types.ChainReaderConfig{ + Contracts: map[string]types.ChainContractReader{ + AnyContractName: { + ContractABI: chain_reader_tester.ChainReaderTesterMetaData.ABI, + Configs: map[string]*types.ChainReaderDefinition{ + MethodTakingLatestParamsReturningTestStruct: { + ChainSpecificName: "getElementAtIndex", + OutputModifications: codec.ModifiersConfig{ + &codec.RenameModifierConfig{Fields: map[string]string{"NestedStruct.Inner.IntVal": "I"}}, + }, + }, + MethodReturningUint64: { + ChainSpecificName: "getPrimitiveValue", + }, + DifferentMethodReturningUint64: { + ChainSpecificName: "getDifferentPrimitiveValue", + }, + MethodReturningUint64Slice: { + ChainSpecificName: "getSliceValue", + }, + EventName: { + ChainSpecificName: "Triggered", + ReadType: types.Event, + OutputModifications: codec.ModifiersConfig{ + &codec.RenameModifierConfig{Fields: map[string]string{"NestedStruct.Inner.IntVal": "I"}}, + }, + }, + EventWithFilterName: { + ChainSpecificName: "Triggered", + ReadType: types.Event, + EventInputFields: []string{"Field"}, + }, + triggerWithDynamicTopic: { + ChainSpecificName: triggerWithDynamicTopic, + ReadType: types.Event, + EventInputFields: []string{"fieldHash"}, + InputModifications: codec.ModifiersConfig{ + &codec.RenameModifierConfig{Fields: map[string]string{"FieldHash": "Field"}}, + }, + }, + triggerWithAllTopics: { + ChainSpecificName: triggerWithAllTopics, + ReadType: types.Event, + EventInputFields: []string{"Field1", "Field2", "Field3"}, + }, + MethodReturningSeenStruct: { + ChainSpecificName: "returnSeen", + InputModifications: codec.ModifiersConfig{ + &codec.HardCodeModifierConfig{ + OnChainValues: map[string]any{ + "BigField": testStruct.BigField.String(), + "Account": hexutil.Encode(testStruct.Account), + }, + }, + &codec.RenameModifierConfig{Fields: map[string]string{"NestedStruct.Inner.IntVal": "I"}}, + }, + OutputModifications: codec.ModifiersConfig{ + &codec.HardCodeModifierConfig{OffChainValues: map[string]any{"ExtraField": AnyExtraValue}}, + &codec.RenameModifierConfig{Fields: map[string]string{"NestedStruct.Inner.IntVal": "I"}}, + }, + }, + }, + }, + AnySecondContractName: { + ContractABI: chain_reader_tester.ChainReaderTesterMetaData.ABI, + Configs: map[string]*types.ChainReaderDefinition{ + MethodReturningUint64: { + ChainSpecificName: "getDifferentPrimitiveValue", + }, + }, + }, + }, + } + it.client = it.Helper.Client(t) + + it.deployNewContracts(t) +} + +func (it *EvmChainReaderInterfaceTester[T]) Name() string { + return "EVM" +} + +func (it *EvmChainReaderInterfaceTester[T]) GetAccountBytes(i int) []byte { + account := [20]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10} + account[i%20] += byte(i) + account[(i+3)%20] += byte(i + 3) + return account[:] +} + +func (it *EvmChainReaderInterfaceTester[T]) GetChainReader(t T) clcommontypes.ChainReader { + ctx := it.Helper.Context(t) + if it.cr != nil { + return it.cr + } + + lggr := logger.NullLogger + db := it.Helper.NewSqlxDB(t) + lpOpts := logpoller.Opts{ + PollPeriod: time.Millisecond, + FinalityDepth: 4, + BackfillBatchSize: 1, + RpcBatchSize: 1, + KeepFinalizedBlocksDepth: 10000, + } + lp := logpoller.NewLogPoller(logpoller.NewORM(it.Helper.ChainID(), db, lggr), it.client, lggr, lpOpts) + require.NoError(t, lp.Start(ctx)) + + cr, err := evm.NewChainReaderService(ctx, lggr, lp, it.client, it.chainConfig) + require.NoError(t, err) + require.NoError(t, cr.Start(ctx)) + it.cr = cr + return cr +} + +func (it *EvmChainReaderInterfaceTester[T]) SetLatestValue(t T, testStruct *TestStruct) { + it.sendTxWithTestStruct(t, testStruct, (*chain_reader_tester.ChainReaderTesterTransactor).AddTestStruct) +} + +func (it *EvmChainReaderInterfaceTester[T]) TriggerEvent(t T, testStruct *TestStruct) { + it.sendTxWithTestStruct(t, testStruct, (*chain_reader_tester.ChainReaderTesterTransactor).TriggerEvent) +} + +func (it *EvmChainReaderInterfaceTester[T]) GetBindings(_ T) []clcommontypes.BoundContract { + return []clcommontypes.BoundContract{ + {Name: AnyContractName, Address: it.address, Pending: true}, + {Name: AnySecondContractName, Address: it.address2, Pending: true}, + } +} + +type testStructFn = func(*chain_reader_tester.ChainReaderTesterTransactor, *bind.TransactOpts, int32, string, uint8, [32]uint8, common.Address, []common.Address, *big.Int, chain_reader_tester.MidLevelTestStruct) (*evmtypes.Transaction, error) + +func (it *EvmChainReaderInterfaceTester[T]) sendTxWithTestStruct(t T, testStruct *TestStruct, fn testStructFn) { + tx, err := fn( + &it.evmTest.ChainReaderTesterTransactor, + it.GetAuthWithGasSet(t), + *testStruct.Field, + testStruct.DifferentField, + uint8(testStruct.OracleID), + ConvertOracleIDs(testStruct.OracleIDs), + common.Address(testStruct.Account), + ConvertAccounts(testStruct.Accounts), + testStruct.BigField, + MidToInternalType(testStruct.NestedStruct), + ) + require.NoError(t, err) + it.Helper.Commit() + it.IncNonce() + it.AwaitTx(t, tx) + it.dirtyContracts = true +} + +func (it *EvmChainReaderInterfaceTester[T]) GetAuthWithGasSet(t T) *bind.TransactOpts { + gasPrice, err := it.client.SuggestGasPrice(it.Helper.Context(t)) + require.NoError(t, err) + extra := new(big.Int).Mul(gasPrice, big.NewInt(it.Helper.GasPriceBufferPercent())) + extra = extra.Div(extra, big.NewInt(100)) + it.auth.GasPrice = gasPrice.Add(gasPrice, extra) + return it.auth +} + +func (it *EvmChainReaderInterfaceTester[T]) IncNonce() { + if it.auth.Nonce == nil { + it.auth.Nonce = big.NewInt(1) + } else { + it.auth.Nonce = it.auth.Nonce.Add(it.auth.Nonce, big.NewInt(1)) + } +} + +func (it *EvmChainReaderInterfaceTester[T]) AwaitTx(t T, tx *evmtypes.Transaction) { + ctx := it.Helper.Context(t) + receipt, err := bind.WaitMined(ctx, it.client, tx) + require.NoError(t, err) + require.Equal(t, evmtypes.ReceiptStatusSuccessful, receipt.Status) +} + +func (it *EvmChainReaderInterfaceTester[T]) deployNewContracts(t T) { + // First test deploy both contracts, otherwise only deploy contracts if cleanup decides that we need to. + if it.address == "" { + it.address = it.deployNewContract(t) + it.address2 = it.deployNewContract(t) + } else if it.evmTest == nil { + it.address = it.deployNewContract(t) + it.dirtyContracts = false + } +} + +func (it *EvmChainReaderInterfaceTester[T]) deployNewContract(t T) string { + // 105528 was in the error: gas too low: have 0, want 105528 + // Not sure if there's a better way to get it. + it.auth.GasLimit = 10552800 + + address, tx, ts, err := chain_reader_tester.DeployChainReaderTester(it.GetAuthWithGasSet(t), it.Helper.Backend()) + require.NoError(t, err) + it.Helper.Commit() + if it.evmTest == nil { + it.evmTest = ts + } + + it.IncNonce() + it.AwaitTx(t, tx) + return address.String() +} + +func (it *EvmChainReaderInterfaceTester[T]) MaxWaitTimeForEvents() time.Duration { + return it.Helper.MaxWaitTimeForEvents() +} + +func ConvertOracleIDs(oracleIDs [32]commontypes.OracleID) [32]byte { + convertedIds := [32]byte{} + for i, id := range oracleIDs { + convertedIds[i] = byte(id) + } + return convertedIds +} + +func ConvertAccounts(accounts [][]byte) []common.Address { + convertedAccounts := make([]common.Address, len(accounts)) + for i, a := range accounts { + convertedAccounts[i] = common.Address(a) + } + return convertedAccounts +} + +func ToInternalType(testStruct TestStruct) chain_reader_tester.TestStruct { + return chain_reader_tester.TestStruct{ + Field: *testStruct.Field, + DifferentField: testStruct.DifferentField, + OracleId: byte(testStruct.OracleID), + OracleIds: ConvertOracleIDs(testStruct.OracleIDs), + Account: common.Address(testStruct.Account), + Accounts: ConvertAccounts(testStruct.Accounts), + BigField: testStruct.BigField, + NestedStruct: MidToInternalType(testStruct.NestedStruct), + } +} + +func MidToInternalType(m MidLevelTestStruct) chain_reader_tester.MidLevelTestStruct { + return chain_reader_tester.MidLevelTestStruct{ + FixedBytes: m.FixedBytes, + Inner: chain_reader_tester.InnerTestStruct{ + IntVal: int64(m.Inner.I), + S: m.Inner.S, + }, + } +} diff --git a/core/services/relay/evm/evmtesting/run_tests.go b/core/services/relay/evm/evmtesting/run_tests.go new file mode 100644 index 00000000000..f6a19f1785d --- /dev/null +++ b/core/services/relay/evm/evmtesting/run_tests.go @@ -0,0 +1,80 @@ +package evmtesting + +import ( + "reflect" + "time" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + clcommontypes "github.com/smartcontractkit/chainlink-common/pkg/types" + + . "github.com/smartcontractkit/chainlink-common/pkg/types/interfacetests" //nolint common practice to import test mods with . +) + +func RunChainReaderEvmTests[T TestingT[T]](t T, it *EvmChainReaderInterfaceTester[T]) { + RunChainReaderInterfaceTests[T](t, it) + + t.Run("Dynamically typed topics can be used to filter and have type correct in return", func(t T) { + it.Setup(t) + + anyString := "foo" + it.dirtyContracts = true + tx, err := it.evmTest.ChainReaderTesterTransactor.TriggerEventWithDynamicTopic(it.GetAuthWithGasSet(t), anyString) + require.NoError(t, err) + it.Helper.Commit() + it.IncNonce() + it.AwaitTx(t, tx) + ctx := it.Helper.Context(t) + + cr := it.GetChainReader(t) + require.NoError(t, cr.Bind(ctx, it.GetBindings(t))) + + input := struct{ Field string }{Field: anyString} + tp := cr.(clcommontypes.ContractTypeProvider) + output, err := tp.CreateContractType(AnyContractName, triggerWithDynamicTopic, false) + require.NoError(t, err) + rOutput := reflect.Indirect(reflect.ValueOf(output)) + + require.Eventually(t, func() bool { + return cr.GetLatestValue(ctx, AnyContractName, triggerWithDynamicTopic, input, output) == nil + }, it.MaxWaitTimeForEvents(), time.Millisecond*10) + + assert.Equal(t, &anyString, rOutput.FieldByName("Field").Interface()) + topic, err := abi.MakeTopics([]any{anyString}) + require.NoError(t, err) + assert.Equal(t, &topic[0][0], rOutput.FieldByName("FieldHash").Interface()) + }) + + t.Run("Multiple topics can filter together", func(t T) { + it.Setup(t) + it.dirtyContracts = true + triggerFourTopics(t, it, int32(1), int32(2), int32(3)) + triggerFourTopics(t, it, int32(2), int32(2), int32(3)) + triggerFourTopics(t, it, int32(1), int32(3), int32(3)) + triggerFourTopics(t, it, int32(1), int32(2), int32(4)) + + ctx := it.Helper.Context(t) + cr := it.GetChainReader(t) + require.NoError(t, cr.Bind(ctx, it.GetBindings(t))) + var latest struct{ Field1, Field2, Field3 int32 } + params := struct{ Field1, Field2, Field3 int32 }{Field1: 1, Field2: 2, Field3: 3} + + time.Sleep(it.MaxWaitTimeForEvents()) + + require.NoError(t, cr.GetLatestValue(ctx, AnyContractName, triggerWithAllTopics, params, &latest)) + assert.Equal(t, int32(1), latest.Field1) + assert.Equal(t, int32(2), latest.Field2) + assert.Equal(t, int32(3), latest.Field3) + }) +} + +func triggerFourTopics[T TestingT[T]](t T, it *EvmChainReaderInterfaceTester[T], i1, i2, i3 int32) { + tx, err := it.evmTest.ChainReaderTesterTransactor.TriggerWithFourTopics(it.GetAuthWithGasSet(t), i1, i2, i3) + require.NoError(t, err) + require.NoError(t, err) + it.Helper.Commit() + it.IncNonce() + it.AwaitTx(t, tx) +} diff --git a/go.mod b/go.mod index 8ba80e67eba..0affd57cc48 100644 --- a/go.mod +++ b/go.mod @@ -72,7 +72,7 @@ require ( github.com/shopspring/decimal v1.3.1 github.com/smartcontractkit/chain-selectors v1.0.10 github.com/smartcontractkit/chainlink-automation v1.0.3 - github.com/smartcontractkit/chainlink-common v0.1.7-0.20240517134904-f4446b816a28 + github.com/smartcontractkit/chainlink-common v0.1.7-0.20240521170829-83ce604cf618 github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240508101745-af1ed7bc8a69 github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240220203239-09be0ea34540 github.com/smartcontractkit/chainlink-feeds v0.0.0-20240422130241-13c17a91b2ab diff --git a/go.sum b/go.sum index 70edbdfb066..63c9a03a220 100644 --- a/go.sum +++ b/go.sum @@ -1171,8 +1171,8 @@ github.com/smartcontractkit/chain-selectors v1.0.10 h1:t9kJeE6B6G+hKD0GYR4kGJSCq github.com/smartcontractkit/chain-selectors v1.0.10/go.mod h1:d4Hi+E1zqjy9HqMkjBE5q1vcG9VGgxf5VxiRHfzi2kE= github.com/smartcontractkit/chainlink-automation v1.0.3 h1:h/ijT0NiyV06VxYVgcNfsE3+8OEzT3Q0Z9au0z1BPWs= github.com/smartcontractkit/chainlink-automation v1.0.3/go.mod h1:RjboV0Qd7YP+To+OrzHGXaxUxoSONveCoAK2TQ1INLU= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20240517134904-f4446b816a28 h1:Pr8/CdiTNnzRwpYc2z7NpHYbw3Dpl1eqiqt9/J/Bcqc= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20240517134904-f4446b816a28/go.mod h1:s+68EchlrXqHKRW3JJgZLEARvzMSKRI5+cE5Zx7pVJA= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240521170829-83ce604cf618 h1:0aR8bbEaUXObEVvn6jayWO0zE0Hn0m+xv1R5V2hvQ6w= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240521170829-83ce604cf618/go.mod h1:s+68EchlrXqHKRW3JJgZLEARvzMSKRI5+cE5Zx7pVJA= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240508101745-af1ed7bc8a69 h1:Sec/GpBpUVaTEax1kSHlTvkzF/+d3w5roAQXaj5+SLA= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240508101745-af1ed7bc8a69/go.mod h1:ZQKf+0OLzCLYIisH/OdOIQuFRI6bDuw+jPBTATyHfFM= github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240220203239-09be0ea34540 h1:xFSv8561jsLtF6gYZr/zW2z5qUUAkcFkApin2mnbYTo= diff --git a/integration-tests/go.mod b/integration-tests/go.mod index db33fef86b1..2926d1eea3e 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -27,7 +27,7 @@ require ( github.com/shopspring/decimal v1.3.1 github.com/slack-go/slack v0.12.2 github.com/smartcontractkit/chainlink-automation v1.0.3 - github.com/smartcontractkit/chainlink-common v0.1.7-0.20240517134904-f4446b816a28 + github.com/smartcontractkit/chainlink-common v0.1.7-0.20240521170829-83ce604cf618 github.com/smartcontractkit/chainlink-testing-framework v1.28.15 github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000 diff --git a/integration-tests/go.sum b/integration-tests/go.sum index aa9e4a55fb1..927ba0518e5 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -1512,8 +1512,8 @@ github.com/smartcontractkit/chain-selectors v1.0.10 h1:t9kJeE6B6G+hKD0GYR4kGJSCq github.com/smartcontractkit/chain-selectors v1.0.10/go.mod h1:d4Hi+E1zqjy9HqMkjBE5q1vcG9VGgxf5VxiRHfzi2kE= github.com/smartcontractkit/chainlink-automation v1.0.3 h1:h/ijT0NiyV06VxYVgcNfsE3+8OEzT3Q0Z9au0z1BPWs= github.com/smartcontractkit/chainlink-automation v1.0.3/go.mod h1:RjboV0Qd7YP+To+OrzHGXaxUxoSONveCoAK2TQ1INLU= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20240517134904-f4446b816a28 h1:Pr8/CdiTNnzRwpYc2z7NpHYbw3Dpl1eqiqt9/J/Bcqc= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20240517134904-f4446b816a28/go.mod h1:s+68EchlrXqHKRW3JJgZLEARvzMSKRI5+cE5Zx7pVJA= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240521170829-83ce604cf618 h1:0aR8bbEaUXObEVvn6jayWO0zE0Hn0m+xv1R5V2hvQ6w= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240521170829-83ce604cf618/go.mod h1:s+68EchlrXqHKRW3JJgZLEARvzMSKRI5+cE5Zx7pVJA= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240508101745-af1ed7bc8a69 h1:Sec/GpBpUVaTEax1kSHlTvkzF/+d3w5roAQXaj5+SLA= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240508101745-af1ed7bc8a69/go.mod h1:ZQKf+0OLzCLYIisH/OdOIQuFRI6bDuw+jPBTATyHfFM= github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240220203239-09be0ea34540 h1:xFSv8561jsLtF6gYZr/zW2z5qUUAkcFkApin2mnbYTo= diff --git a/integration-tests/load/go.mod b/integration-tests/load/go.mod index 0b389c3118a..60afb07638d 100644 --- a/integration-tests/load/go.mod +++ b/integration-tests/load/go.mod @@ -16,7 +16,7 @@ require ( github.com/rs/zerolog v1.30.0 github.com/slack-go/slack v0.12.2 github.com/smartcontractkit/chainlink-automation v1.0.3 - github.com/smartcontractkit/chainlink-common v0.1.7-0.20240517134904-f4446b816a28 + github.com/smartcontractkit/chainlink-common v0.1.7-0.20240521170829-83ce604cf618 github.com/smartcontractkit/chainlink-testing-framework v1.28.15 github.com/smartcontractkit/chainlink/integration-tests v0.0.0-20240214231432-4ad5eb95178c github.com/smartcontractkit/chainlink/v2 v2.9.0-beta0.0.20240216210048-da02459ddad8 diff --git a/integration-tests/load/go.sum b/integration-tests/load/go.sum index 07ebb37aff0..fa03d25e060 100644 --- a/integration-tests/load/go.sum +++ b/integration-tests/load/go.sum @@ -1502,8 +1502,8 @@ github.com/smartcontractkit/chain-selectors v1.0.10 h1:t9kJeE6B6G+hKD0GYR4kGJSCq github.com/smartcontractkit/chain-selectors v1.0.10/go.mod h1:d4Hi+E1zqjy9HqMkjBE5q1vcG9VGgxf5VxiRHfzi2kE= github.com/smartcontractkit/chainlink-automation v1.0.3 h1:h/ijT0NiyV06VxYVgcNfsE3+8OEzT3Q0Z9au0z1BPWs= github.com/smartcontractkit/chainlink-automation v1.0.3/go.mod h1:RjboV0Qd7YP+To+OrzHGXaxUxoSONveCoAK2TQ1INLU= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20240517134904-f4446b816a28 h1:Pr8/CdiTNnzRwpYc2z7NpHYbw3Dpl1eqiqt9/J/Bcqc= -github.com/smartcontractkit/chainlink-common v0.1.7-0.20240517134904-f4446b816a28/go.mod h1:s+68EchlrXqHKRW3JJgZLEARvzMSKRI5+cE5Zx7pVJA= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240521170829-83ce604cf618 h1:0aR8bbEaUXObEVvn6jayWO0zE0Hn0m+xv1R5V2hvQ6w= +github.com/smartcontractkit/chainlink-common v0.1.7-0.20240521170829-83ce604cf618/go.mod h1:s+68EchlrXqHKRW3JJgZLEARvzMSKRI5+cE5Zx7pVJA= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240508101745-af1ed7bc8a69 h1:Sec/GpBpUVaTEax1kSHlTvkzF/+d3w5roAQXaj5+SLA= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240508101745-af1ed7bc8a69/go.mod h1:ZQKf+0OLzCLYIisH/OdOIQuFRI6bDuw+jPBTATyHfFM= github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240220203239-09be0ea34540 h1:xFSv8561jsLtF6gYZr/zW2z5qUUAkcFkApin2mnbYTo=