Skip to content

Commit

Permalink
revert all changes to core/services/relay/evm
Browse files Browse the repository at this point in the history
  • Loading branch information
poopoothegorilla committed Feb 27, 2024
1 parent 88e2236 commit f18a2c1
Show file tree
Hide file tree
Showing 36 changed files with 509 additions and 415 deletions.
8 changes: 4 additions & 4 deletions core/services/relay/evm/address.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,18 @@ import (

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
pkgerrors "github.com/pkg/errors"
"github.com/pkg/errors"
"github.com/smartcontractkit/libocr/offchainreporting2plus/types"
)

func AccountToAddress(accounts []types.Account) (addresses []common.Address, err error) {
for _, signer := range accounts {
bytes, err := hexutil.Decode(string(signer))
if err != nil {
return []common.Address{}, pkgerrors.Wrap(err, fmt.Sprintf("given address is not valid %s", signer))
return []common.Address{}, errors.Wrap(err, fmt.Sprintf("given address is not valid %s", signer))
}
if len(bytes) != 20 {
return []common.Address{}, pkgerrors.Errorf("address is not 20 bytes %s", signer)
return []common.Address{}, errors.Errorf("address is not 20 bytes %s", signer)
}
addresses = append(addresses, common.BytesToAddress(bytes))
}
Expand All @@ -26,7 +26,7 @@ func AccountToAddress(accounts []types.Account) (addresses []common.Address, err
func OnchainPublicKeyToAddress(publicKeys []types.OnchainPublicKey) (addresses []common.Address, err error) {
for _, signer := range publicKeys {
if len(signer) != 20 {
return []common.Address{}, pkgerrors.Errorf("address is not 20 bytes %s", signer)
return []common.Address{}, errors.Errorf("address is not 20 bytes %s", signer)
}
addresses = append(addresses, common.BytesToAddress(signer))
}
Expand Down
26 changes: 16 additions & 10 deletions core/services/relay/evm/chain_reader_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,19 +52,21 @@ func TestChainReader(t *testing.T) {
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.LatestValueHolderTransactor.TriggerEventWithDynamicTopic(it.auth, anyString)
require.NoError(t, err)
it.sim.Commit()
it.incNonce()
it.awaitTx(t, tx)
ctx := testutils.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)
Expand All @@ -84,20 +86,24 @@ func TestChainReader(t *testing.T) {

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))

ctx := testutils.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.Eventually(t, func() bool {
return cr.GetLatestValue(ctx, AnyContractName, triggerWithAllTopics, params, &latest) == nil
}, it.MaxWaitTimeForEvents(), time.Millisecond*10)

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)
Expand Down Expand Up @@ -257,7 +263,7 @@ func (it *chainReaderInterfaceTester) GetChainReader(t *testing.T) clcommontypes

lggr := logger.NullLogger
db := pgtest.NewSqlxDB(t)
lp := logpoller.NewLogPoller(logpoller.NewORM(testutils.SimulatedChainID, db, lggr, pgtest.NewQConfig(true)), it.chain.Client(), lggr, time.Millisecond, false, 0, 1, 1, 10000)
lp := logpoller.NewLogPoller(logpoller.NewORM(testutils.SimulatedChainID, db, lggr, pgtest.NewQConfig(true)), it.chain.Client(), lggr, time.Millisecond, false, 0, 1, 1, 10000, 0)
require.NoError(t, lp.Start(ctx))
it.chain.On("LogPoller").Return(lp)
cr, err := evm.NewChainReaderService(lggr, lp, it.chain, it.chainConfig)
Expand Down
25 changes: 25 additions & 0 deletions core/services/relay/evm/codec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,31 @@ func TestCodec(t *testing.T) {
})
}

func TestCodec_SimpleEncode(t *testing.T) {
codecName := "my_codec"
input := map[string]any{
"Report": int32(6),
"Meta": "abcdefg",
}
evmEncoderConfig := `[{"Name":"Report","Type":"int32"},{"Name":"Meta","Type":"string"}]`

codecConfig := types.CodecConfig{Configs: map[string]types.ChainCodecConfig{
codecName: {TypeABI: evmEncoderConfig},
}}
c, err := evm.NewCodec(codecConfig)
require.NoError(t, err)

result, err := c.Encode(testutils.Context(t), input, codecName)
require.NoError(t, err)
expected :=
"0000000000000000000000000000000000000000000000000000000000000006" + // int32(6)
"0000000000000000000000000000000000000000000000000000000000000040" + // total bytes occupied by the string (64)
"0000000000000000000000000000000000000000000000000000000000000007" + // length of the string (7 chars)
"6162636465666700000000000000000000000000000000000000000000000000" // actual string

require.Equal(t, expected, hexutil.Encode(result)[2:])
}

type codecInterfaceTester struct{}

func (it *codecInterfaceTester) Setup(_ *testing.T) {}
Expand Down
93 changes: 27 additions & 66 deletions core/services/relay/evm/config_poller.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,9 @@ import (
"database/sql"
"fmt"

"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
pkgerrors "github.com/pkg/errors"
"github.com/pkg/errors"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"

Expand All @@ -34,60 +33,9 @@ var (
)
)

var (
// ConfigSet Common to all OCR2 evm based contracts: https://github.com/smartcontractkit/libocr/blob/master/contract2/dev/OCR2Abstract.sol
ConfigSet common.Hash

defaultABI abi.ABI
)

const configSetEventName = "ConfigSet"

func init() {
var err error
abiPointer, err := ocr2aggregator.OCR2AggregatorMetaData.GetAbi()
if err != nil {
panic(err)
}
defaultABI = *abiPointer
ConfigSet = defaultABI.Events[configSetEventName].ID
}

func unpackLogData(d []byte) (*ocr2aggregator.OCR2AggregatorConfigSet, error) {
unpacked := new(ocr2aggregator.OCR2AggregatorConfigSet)
err := defaultABI.UnpackIntoInterface(unpacked, configSetEventName, d)
if err != nil {
return nil, pkgerrors.Wrap(err, "failed to unpack log data")
}
return unpacked, nil
}

func configFromLog(logData []byte) (ocrtypes.ContractConfig, error) {
unpacked, err := unpackLogData(logData)
if err != nil {
return ocrtypes.ContractConfig{}, err
}

var transmitAccounts []ocrtypes.Account
for _, addr := range unpacked.Transmitters {
transmitAccounts = append(transmitAccounts, ocrtypes.Account(addr.Hex()))
}
var signers []ocrtypes.OnchainPublicKey
for _, addr := range unpacked.Signers {
addr := addr
signers = append(signers, addr[:])
}

return ocrtypes.ContractConfig{
ConfigDigest: unpacked.ConfigDigest,
ConfigCount: unpacked.ConfigCount,
Signers: signers,
Transmitters: transmitAccounts,
F: unpacked.F,
OnchainConfig: unpacked.OnchainConfig,
OffchainConfigVersion: unpacked.OffchainConfigVersion,
OffchainConfig: unpacked.OffchainConfig,
}, nil
type LogDecoder interface {
EventSig() common.Hash
Decode(rawLog []byte) (ocrtypes.ContractConfig, error)
}

type configPoller struct {
Expand All @@ -105,18 +53,30 @@ type configPoller struct {
// contract allows us work around such restrictions.
configStoreContractAddr *common.Address
configStoreContract *ocrconfigurationstoreevmsimple.OCRConfigurationStoreEVMSimple

// Depending on the exact contract used, the raw config log may be shaped
// in different ways
ld LogDecoder
}

func configPollerFilterName(addr common.Address) string {
return logpoller.FilterName("OCR2ConfigPoller", addr.String())
}

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)
type CPConfig struct {
Client client.Client
DestinationChainPoller logpoller.LogPoller
AggregatorContractAddress common.Address
ConfigStoreAddress *common.Address
LogDecoder LogDecoder
}

func NewConfigPoller(lggr logger.Logger, cfg CPConfig) (evmRelayTypes.ConfigPoller, error) {
return newConfigPoller(lggr, cfg.Client, cfg.DestinationChainPoller, cfg.AggregatorContractAddress, cfg.ConfigStoreAddress, cfg.LogDecoder)
}

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}})
func newConfigPoller(lggr logger.Logger, client client.Client, destChainPoller logpoller.LogPoller, aggregatorContractAddr common.Address, configStoreAddr *common.Address, ld LogDecoder) (*configPoller, error) {
err := destChainPoller.RegisterFilter(logpoller.Filter{Name: configPollerFilterName(aggregatorContractAddr), EventSigs: []common.Hash{ld.EventSig()}, Addresses: []common.Address{aggregatorContractAddr}})
if err != nil {
return nil, err
}
Expand All @@ -133,6 +93,7 @@ func newConfigPoller(lggr logger.Logger, client client.Client, destChainPoller l
aggregatorContractAddr: aggregatorContractAddr,
client: client,
aggregatorContract: aggregatorContract,
ld: ld,
}

if configStoreAddr != nil {
Expand Down Expand Up @@ -164,9 +125,9 @@ 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.aggregatorContractAddr, 1, pg.WithParentCtx(ctx))
latest, err := cp.destChainLogPoller.LatestLogByEventSigWithConfs(cp.ld.EventSig(), cp.aggregatorContractAddr, 1, pg.WithParentCtx(ctx))
if err != nil {
if pkgerrors.Is(err, sql.ErrNoRows) {
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)
Expand All @@ -176,7 +137,7 @@ func (cp *configPoller) LatestConfigDetails(ctx context.Context) (changedInBlock
}
return 0, ocrtypes.ConfigDigest{}, err
}
latestConfigSet, err := configFromLog(latest.Data)
latestConfigSet, err := cp.ld.Decode(latest.Data)
if err != nil {
return 0, ocrtypes.ConfigDigest{}, err
}
Expand All @@ -185,7 +146,7 @@ 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.aggregatorContractAddr, pg.WithParentCtx(ctx))
lgs, err := cp.destChainLogPoller.Logs(int64(changedInBlock), int64(changedInBlock), cp.ld.EventSig(), cp.aggregatorContractAddr, pg.WithParentCtx(ctx))
if err != nil {
return ocrtypes.ContractConfig{}, err
}
Expand All @@ -196,7 +157,7 @@ func (cp *configPoller) LatestConfig(ctx context.Context, changedInBlock uint64)
}
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)
latestConfigSet, err := cp.ld.Decode(lgs[len(lgs)-1].Data)
if err != nil {
return ocrtypes.ContractConfig{}, err
}
Expand All @@ -208,7 +169,7 @@ func (cp *configPoller) LatestConfig(ctx context.Context, changedInBlock uint64)
func (cp *configPoller) LatestBlockHeight(ctx context.Context) (blockHeight uint64, err error) {
latest, err := cp.destChainLogPoller.LatestBlock(pg.WithParentCtx(ctx))
if err != nil {
if pkgerrors.Is(err, sql.ErrNoRows) {
if errors.Is(err, sql.ErrNoRows) {
return 0, nil
}
return 0, err
Expand Down
23 changes: 13 additions & 10 deletions core/services/relay/evm/config_poller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/eth/ethconfig"
"github.com/onsi/gomega"
pkgerrors "github.com/pkg/errors"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
Expand All @@ -28,6 +28,7 @@ import (
ocrtypes2 "github.com/smartcontractkit/libocr/offchainreporting2plus/types"

"github.com/smartcontractkit/chainlink-common/pkg/services/servicetest"

"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"
Expand Down Expand Up @@ -55,6 +56,8 @@ func TestConfigPoller(t *testing.T) {
var linkTokenAddress common.Address
var accessAddress common.Address

ld := OCR2AggregatorLogDecoder

{
key, err := crypto.GenerateKey()
require.NoError(t, err)
Expand Down Expand Up @@ -87,12 +90,12 @@ func TestConfigPoller(t *testing.T) {
cfg := pgtest.NewQConfig(false)
ethClient = evmclient.NewSimulatedBackendClient(t, b, testutils.SimulatedChainID)
lorm := logpoller.NewORM(testutils.SimulatedChainID, db, lggr, cfg)
lp = logpoller.NewLogPoller(lorm, ethClient, lggr, 100*time.Millisecond, false, 1, 2, 2, 1000)
lp = logpoller.NewLogPoller(lorm, ethClient, lggr, 100*time.Millisecond, false, 1, 2, 2, 1000, 0)
servicetest.Run(t, lp)
}

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)
cp, err := NewConfigPoller(lggr, CPConfig{ethClient, lp, ocrAddress, nil, ld})
require.NoError(t, err)

_, err = cp.LatestConfig(testutils.Context(t), 0)
Expand All @@ -101,7 +104,7 @@ func TestConfigPoller(t *testing.T) {
})

t.Run("happy path (with config store)", func(t *testing.T) {
cp, err := NewConfigPoller(lggr, ethClient, lp, ocrAddress, &configStoreContractAddr)
cp, err := NewConfigPoller(lggr, CPConfig{ethClient, lp, ocrAddress, &configStoreContractAddr, ld})
require.NoError(t, err)
// Should have no config to begin with.
_, configDigest, err := cp.LatestConfigDetails(testutils.Context(t))
Expand Down Expand Up @@ -172,7 +175,7 @@ func TestConfigPoller(t *testing.T) {
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)
cp, err := newConfigPoller(lggr, ethClient, mp, ocrAddress, &configStoreContractAddr, ld)
require.NoError(t, err)

t.Run("when config has not been set, returns zero values", func(t *testing.T) {
Expand Down Expand Up @@ -208,8 +211,8 @@ func TestConfigPoller(t *testing.T) {
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, pkgerrors.New("something exploded"))
cp, err := newConfigPoller(lggr, failingClient, mp, ocrAddress, &configStoreContractAddr)
failingClient.On("CallContract", mock.Anything, mock.Anything, mock.Anything).Return(nil, errors.New("something exploded"))
cp, err := newConfigPoller(lggr, failingClient, mp, ocrAddress, &configStoreContractAddr, ld)
require.NoError(t, err)

cp.configStoreContractAddr = &configStoreContractAddr
Expand Down Expand Up @@ -248,7 +251,7 @@ func TestConfigPoller(t *testing.T) {
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)
cp, err := newConfigPoller(lggr, ethClient, mp, ocrAddress, &configStoreContractAddr, ld)
require.NoError(t, err)

t.Run("when config has not been set, returns error", func(t *testing.T) {
Expand Down Expand Up @@ -309,8 +312,8 @@ func TestConfigPoller(t *testing.T) {
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, pkgerrors.New("something exploded")).Once()
cp, err := newConfigPoller(lggr, failingClient, mp, ocrAddress, &configStoreContractAddr)
}), mock.Anything).Return(nil, errors.New("something exploded")).Once()
cp, err := newConfigPoller(lggr, failingClient, mp, ocrAddress, &configStoreContractAddr, ld)
require.NoError(t, err)

_, err = cp.LatestConfig(testutils.Context(t), 0)
Expand Down
Loading

0 comments on commit f18a2c1

Please sign in to comment.