Skip to content

Commit

Permalink
Merge branch 'develop' into BCI-1414-evm-prefix-cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
prashantkumar1982 authored Jun 21, 2023
2 parents 156d8b0 + bf4f2cb commit 0509266
Show file tree
Hide file tree
Showing 8 changed files with 506 additions and 17 deletions.
3 changes: 2 additions & 1 deletion core/services/ocr2/delegate.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ import (
"github.com/smartcontractkit/chainlink/v2/core/services/pipeline"
"github.com/smartcontractkit/chainlink/v2/core/services/relay"
evmrelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm"
functionsRelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/functions"
evmrelaytypes "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types"
"github.com/smartcontractkit/chainlink/v2/core/services/synchronization"
"github.com/smartcontractkit/chainlink/v2/core/services/telemetry"
Expand Down Expand Up @@ -955,7 +956,7 @@ func (d *Delegate) newServicesOCR2Functions(
},
lggr.Named("FunctionsRelayer"),
d.ethKs,
d.eventBroadcaster,
functionsRelay.FunctionsPlugin,
)
if err2 != nil {
return nil, err2
Expand Down
4 changes: 2 additions & 2 deletions core/services/relay/evm/config_poller.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"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"
)

// ConfigSet Common to all OCR2 evm based contracts: https://github.com/smartcontractkit/libocr/blob/master/contract2/dev/OCR2Abstract.sol
Expand Down Expand Up @@ -80,8 +81,7 @@ func configPollerFilterName(addr common.Address) string {
return logpoller.FilterName("OCR2ConfigPoller", addr.String())
}

// NewConfigPoller creates a new ConfigPoller
func NewConfigPoller(lggr logger.Logger, destChainPoller logpoller.LogPoller, addr common.Address) (ConfigPoller, error) {
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}})
if err != nil {
return nil, err
Expand Down
14 changes: 3 additions & 11 deletions core/services/relay/evm/evm.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,21 +158,13 @@ func FilterNamesFromRelayArgs(args relaytypes.RelayArgs) (filterNames []string,
return filterNames, err
}

type ConfigPoller interface {
ocrtypes.ContractConfigTracker

Start()
Close() error
Replay(ctx context.Context, fromBlock int64) error
}

type configWatcher struct {
utils.StartStopOnce
lggr logger.Logger
contractAddress common.Address
contractABI abi.ABI
offchainDigester ocrtypes.OffchainConfigDigester
configPoller ConfigPoller
configPoller types.ConfigPoller
chain evm.Chain
runReplay bool
fromBlock uint64
Expand All @@ -185,7 +177,7 @@ func newConfigWatcher(lggr logger.Logger,
contractAddress common.Address,
contractABI abi.ABI,
offchainDigester ocrtypes.OffchainConfigDigester,
configPoller ConfigPoller,
configPoller types.ConfigPoller,
chain evm.Chain,
fromBlock uint64,
runReplay bool,
Expand Down Expand Up @@ -271,7 +263,7 @@ func newConfigProvider(lggr logger.Logger, chainSet evm.ChainSet, args relaytype
if err != nil {
return nil, errors.Wrap(err, "could not get contract ABI JSON")
}
var cp ConfigPoller
var cp types.ConfigPoller

if relayConfig.FeedID != nil {
cp, err = mercury.NewConfigPoller(
Expand Down
51 changes: 48 additions & 3 deletions core/services/relay/evm/functions.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
package evm

import (
"encoding/json"
"strings"

"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/pkg/errors"
"github.com/smartcontractkit/libocr/gethwrappers2/ocr2aggregator"
"github.com/smartcontractkit/libocr/offchainreporting2plus/chains/evmutil"
"github.com/smartcontractkit/libocr/offchainreporting2plus/types"

relaytypes "github.com/smartcontractkit/chainlink-relay/pkg/types"
"github.com/smartcontractkit/chainlink/v2/core/chains/evm"
"github.com/smartcontractkit/chainlink/v2/core/logger"
"github.com/smartcontractkit/chainlink/v2/core/services/keystore"
"github.com/smartcontractkit/chainlink/v2/core/services/pg"
functionsRelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/functions"
evmRelayTypes "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types"
)

type functionsProvider struct {
Expand All @@ -23,8 +32,8 @@ func (p *functionsProvider) ContractTransmitter() types.ContractTransmitter {
return p.contractTransmitter
}

func NewFunctionsProvider(chainSet evm.ChainSet, rargs relaytypes.RelayArgs, pargs relaytypes.PluginArgs, lggr logger.Logger, ethKeystore keystore.Eth, eventBroadcaster pg.EventBroadcaster) (relaytypes.Plugin, error) {
configWatcher, err := newConfigProvider(lggr, chainSet, rargs, eventBroadcaster)
func NewFunctionsProvider(chainSet evm.ChainSet, rargs relaytypes.RelayArgs, pargs relaytypes.PluginArgs, lggr logger.Logger, ethKeystore keystore.Eth, pluginType functionsRelay.FunctionsPluginType) (relaytypes.Plugin, error) {
configWatcher, err := newFunctionsConfigProvider(pluginType, chainSet, rargs, lggr)
if err != nil {
return nil, err
}
Expand All @@ -37,3 +46,39 @@ func NewFunctionsProvider(chainSet evm.ChainSet, rargs relaytypes.RelayArgs, par
contractTransmitter: contractTransmitter,
}, nil
}

func newFunctionsConfigProvider(pluginType functionsRelay.FunctionsPluginType, chainSet evm.ChainSet, args relaytypes.RelayArgs, lggr logger.Logger) (*configWatcher, error) {
var relayConfig evmRelayTypes.RelayConfig
err := json.Unmarshal(args.RelayConfig, &relayConfig)
if err != nil {
return nil, err
}
chain, err := chainSet.Get(relayConfig.ChainID.ToInt())
if err != nil {
return nil, err
}
if !common.IsHexAddress(args.ContractID) {
return nil, errors.Errorf("invalid contractID, expected hex address")
}

contractAddress := common.HexToAddress(args.ContractID)
contractABI, err := abi.JSON(strings.NewReader(ocr2aggregator.OCR2AggregatorMetaData.ABI))
if err != nil {
return nil, errors.Wrap(err, "could not get contract ABI JSON")
}

cp, err := functionsRelay.NewFunctionsConfigPoller(pluginType, chain.LogPoller(), contractAddress, lggr)
if err != nil {
return nil, err
}

offchainConfigDigester := functionsRelay.FunctionsOffchainConfigDigester{
PluginType: pluginType,
BaseDigester: evmutil.EVMOffchainConfigDigester{
ChainID: chain.ID().Uint64(),
ContractAddress: contractAddress,
},
}

return newConfigWatcher(lggr, contractAddress, contractABI, offchainConfigDigester, cp, chain, relayConfig.FromBlock, args.New), nil
}
177 changes: 177 additions & 0 deletions core/services/relay/evm/functions/config_poller.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
package functions

import (
"context"
"database/sql"
"encoding/binary"

"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/pkg/errors"
"github.com/smartcontractkit/libocr/gethwrappers2/ocr2aggregator"

ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2/types"

"github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller"
"github.com/smartcontractkit/chainlink/v2/core/logger"
"github.com/smartcontractkit/chainlink/v2/core/services/pg"
"github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types"
)

var _ types.ConfigPoller = &configPoller{}

type FunctionsPluginType int

const (
FunctionsPlugin FunctionsPluginType = iota
ThresholdPlugin
S4Plugin
)

type configPoller struct {
lggr logger.Logger
filterName string
destChainLogPoller logpoller.LogPoller
addr common.Address
pluginType FunctionsPluginType
}

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

var 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, errors.Wrap(err, "failed to unpack log data")
}
return unpacked, nil
}

func configFromLog(logData []byte, pluginType FunctionsPluginType) (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.String()))
}
var signers []ocrtypes.OnchainPublicKey
for _, addr := range unpacked.Signers {
addr := addr
signers = append(signers, addr[:])
}

// Replace the first two bytes of the config digest with the plugin type to avoid duplicate config digests between Functions plugins
switch pluginType {
case FunctionsPlugin:
// FunctionsPluginType should already have the correct prefix, so this is a no-op
case ThresholdPlugin:
binary.BigEndian.PutUint16(unpacked.ConfigDigest[:2], uint16(ThresholdDigestPrefix))
case S4Plugin:
binary.BigEndian.PutUint16(unpacked.ConfigDigest[:2], uint16(S4DigestPrefix))
default:
return ocrtypes.ContractConfig{}, errors.New("unknown plugin type")
}

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
}

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

func NewFunctionsConfigPoller(pluginType FunctionsPluginType, destChainPoller logpoller.LogPoller, addr common.Address, lggr logger.Logger) (types.ConfigPoller, error) {
err := destChainPoller.RegisterFilter(logpoller.Filter{Name: configPollerFilterName(addr), EventSigs: []common.Hash{ConfigSet}, Addresses: []common.Address{addr}})
if err != nil {
return nil, err
}

cp := &configPoller{
lggr: lggr,
filterName: configPollerFilterName(addr),
destChainLogPoller: destChainPoller,
addr: addr,
pluginType: pluginType,
}

return cp, nil
}

func (cp *configPoller) Start() {}

func (cp *configPoller) Close() error {
return nil
}

func (cp *configPoller) Notify() <-chan struct{} {
return nil
}

func (cp *configPoller) Replay(ctx context.Context, fromBlock int64) error {
return cp.destChainLogPoller.Replay(ctx, fromBlock)
}

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))
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
return 0, ocrtypes.ConfigDigest{}, nil
}
return 0, ocrtypes.ConfigDigest{}, err
}
latestConfigSet, err := configFromLog(latest.Data, cp.pluginType)
if err != nil {
return 0, ocrtypes.ConfigDigest{}, err
}
return uint64(latest.BlockNumber), latestConfigSet.ConfigDigest, nil
}

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))
if err != nil {
return ocrtypes.ContractConfig{}, err
}
latestConfigSet, err := configFromLog(lgs[len(lgs)-1].Data, cp.pluginType)
if err != nil {
return ocrtypes.ContractConfig{}, err
}
cp.lggr.Infow("LatestConfig", "latestConfig", latestConfigSet)
return latestConfigSet, nil
}

func (cp *configPoller) LatestBlockHeight(ctx context.Context) (blockHeight uint64, err error) {
latest, err := cp.destChainLogPoller.LatestBlock(pg.WithParentCtx(ctx))
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
return 0, nil
}
return 0, err
}
return uint64(latest), nil
}
Loading

0 comments on commit 0509266

Please sign in to comment.