Skip to content

Commit

Permalink
Interfaces and skeleton methods for ChainReader EVM POC (#10990)
Browse files Browse the repository at this point in the history
* Implement skeleton interfaces, structs, & methods for ChainReader EVM POC

- Read ChainReader config in from RelayConfig
- Add some initialization and validation relay skeletons

- Use medianProviderWrapper instead of passing medianContract separately

This avoids us having to modify the signature of NewMedianFactory, which
would require further modifications to all non-evm repos and chainlink-relay

- Add chain_reader_test.go with some basic relay tests

Co-authored-by: Jordan Krage <jmank88@gmail.com>

- Add chain reader config validation
- Add chain reader config validation tests
- Add config for chain reader median contract to cr validation testcases
- Add unimplemented Encode(), Decode(), GetMaxEncodingSize(), GetMaxDecodingSize()
- Add ChainReader() method to mock provider for plugin test
- Rename relaymercury.ChainReader to MercuryChainReader, resolve name collisions
- Add tests for errors during ChainReader construction
- Propagate InvalidConfig & any other errors back to client

We should ignore Unimplemented until node ops have been given ample time to migrate to the new job spec
(including a section for ChainReader config) so that we can remove the old product-specific
MedianContract component from MedianProvider. All other errors we can immediately start passing back
to the client, letting the core node decide how to handle them (eg. displaying an "invalid job spec"
message to the UI if the RelayConfig was invalid or the ContractID missing)

* Update relay versions

* Simplify chain reader config validation

* Update commit hashes one final time now that all relays are merged.

---------

Co-authored-by: ilija <pavlovicilija42@gmail.com>
  • Loading branch information
reductionista and ilija42 authored Dec 6, 2023
1 parent d65ca4f commit c17067b
Show file tree
Hide file tree
Showing 32 changed files with 828 additions and 100 deletions.
9 changes: 5 additions & 4 deletions core/scripts/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ require (
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/gin-gonic/gin v1.9.1 // indirect
github.com/go-asn1-ber/asn1-ber v1.5.4 // indirect
github.com/go-json-experiment/json v0.0.0-20231102232822-2e55bd4e08b0 // indirect
github.com/go-kit/kit v0.12.0 // indirect
github.com/go-kit/log v0.2.1 // indirect
github.com/go-ldap/ldap/v3 v3.4.5 // indirect
Expand Down Expand Up @@ -257,12 +258,12 @@ require (
github.com/shirou/gopsutil/v3 v3.23.10 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 // indirect
github.com/smartcontractkit/chainlink-common v0.1.7-0.20231204152334-1f32103bbb4c // indirect
github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542 // indirect
github.com/smartcontractkit/chainlink-common v0.1.7-0.20231205033838-dfac15e672d4 // indirect
github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231206164210-03f8b219402e // indirect
github.com/smartcontractkit/chainlink-data-streams v0.0.0-20231204152908-a6e3fe8ff2a1 // indirect
github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d // indirect
github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231129183458-faee879168b3 // indirect
github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231117204155-b253a2f56664 // indirect
github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231206154215-ec1718b7df3e // indirect
github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231205180940-ea2e3e916725 // indirect
github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20230906073235-9e478e5e19f1 // indirect
github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20230906073235-9e478e5e19f1 // indirect
github.com/smartcontractkit/wsrpc v0.7.2 // indirect
Expand Down
18 changes: 10 additions & 8 deletions core/scripts/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,8 @@ github.com/go-faster/errors v0.6.1/go.mod h1:5MGV2/2T9yvlrbhe9pD9LO5Z/2zCSq2T8j+
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-json-experiment/json v0.0.0-20231102232822-2e55bd4e08b0 h1:ymLjT4f35nQbASLnvxEde4XOBL+Sn7rFuV+FOJqkljg=
github.com/go-json-experiment/json v0.0.0-20231102232822-2e55bd4e08b0/go.mod h1:6daplAwHHGbUGib4990V3Il26O0OC4aRyvewaaAihaA=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.12.0 h1:e4o3o3IsBfAKQh5Qbbiqyfu97Ku7jrO/JbohvztANh4=
Expand Down Expand Up @@ -1212,18 +1214,18 @@ github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704 h1:T3lFWumv
github.com/smartcontractkit/caigo v0.0.0-20230621050857-b29a4ca8c704/go.mod h1:2QuJdEouTWjh5BDy5o/vgGXQtR4Gz8yH1IYB5eT7u4M=
github.com/smartcontractkit/chainlink-automation v1.0.1 h1:vVjBFq2Zsz21kPy1Pb0wpjF9zrbJX+zjXphDeeR4XZk=
github.com/smartcontractkit/chainlink-automation v1.0.1/go.mod h1:INSchkV3ntyDdlZKGWA030MPDpp6pbeuiRkRKYFCm2k=
github.com/smartcontractkit/chainlink-common v0.1.7-0.20231204152334-1f32103bbb4c h1:YFyo0pCmKkpB4EOSykCZFueRXNxQ7OhKiCnhoVIzydo=
github.com/smartcontractkit/chainlink-common v0.1.7-0.20231204152334-1f32103bbb4c/go.mod h1:Hrru9i7n+WEYyW2aIt3/YGPhxLX+HEGWnhk3yVXeDF8=
github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542 h1:oewYJtdRkJKUHCNDCj5C2LQe6Oq6qy975g931nfG0cc=
github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231117191236-12eab01a4542/go.mod h1:EpvRoycRD+kniYlz+pCpRT5e+fmPm0mSD/vmND+0oMg=
github.com/smartcontractkit/chainlink-common v0.1.7-0.20231205033838-dfac15e672d4 h1:2LC5HtHkAm7I1h5j4Uz0KTX+h4fo4z/5NoAARSF4ZVA=
github.com/smartcontractkit/chainlink-common v0.1.7-0.20231205033838-dfac15e672d4/go.mod h1:IdlfCN9rUs8Q/hrOYe8McNBIwEOHEsi0jilb3Cw77xs=
github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231206164210-03f8b219402e h1:xvqffqFec2HkEcUKrCkm4FDJRnn/+gHmvrE/dz3Zlw8=
github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20231206164210-03f8b219402e/go.mod h1:soVgcl4CbfR6hC9UptjuCQhz19HJaFEjwnOpiySkxg0=
github.com/smartcontractkit/chainlink-data-streams v0.0.0-20231204152908-a6e3fe8ff2a1 h1:xYqRgZO0nMSO8CBCMR0r3WA+LZ4kNL8a6bnbyk/oBtQ=
github.com/smartcontractkit/chainlink-data-streams v0.0.0-20231204152908-a6e3fe8ff2a1/go.mod h1:GuPvyXryvbiUZIHmPeLBz4L+yJKeyGUjrDfd1KNne+o=
github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d h1:w4MsbOtNk6nD/mcXLstHWk9hB6g7QLtcAfhPjhwvOaQ=
github.com/smartcontractkit/chainlink-feeds v0.0.0-20231127231053-2232d3a6766d/go.mod h1:YPAfLNowdBwiKiYOwgwtbJHi8AJWbcxkbOY0ItAvkfc=
github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231129183458-faee879168b3 h1:DudPr8ZNMEVgDwHBvnrpvK96JrGcGCG+LLBnlqaPGnE=
github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231129183458-faee879168b3/go.mod h1:UfW7/PZKon+iDEHtrHOfvMnS5GfYOW/SdMZ6P97rPEk=
github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231117204155-b253a2f56664 h1:yxaHuDTtj2xxtsR8b+LJw8xDvyr6v/F6GP3InsP4wPI=
github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231117204155-b253a2f56664/go.mod h1:3Fa+HQTZ3R3fPC0hUqugvoo+NEeo8Y4J2WOnQfi7O34=
github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231206154215-ec1718b7df3e h1:/tCHhoAJM+ittEHPZTtJsAgXmYujKiDW0ub9HXW9qtY=
github.com/smartcontractkit/chainlink-solana v1.0.3-0.20231206154215-ec1718b7df3e/go.mod h1:9YIi413QRRytafTzpWm+Z+5NWBNxSqokhKyeEZ3ynlA=
github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231205180940-ea2e3e916725 h1:NbhPVwxx+53WN/Uld1V6c4iLgoGvUYFOsVd2kfcexe8=
github.com/smartcontractkit/chainlink-starknet/relayer v0.0.1-beta-test.0.20231205180940-ea2e3e916725/go.mod h1:vHrPBipRL52NdPp77KXNU2k1IoCUa1B33N9otZQPYko=
github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868 h1:FFdvEzlYwcuVHkdZ8YnZR/XomeMGbz5E2F2HZI3I3w8=
github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868/go.mod h1:Kn1Hape05UzFZ7bOUnm3GVsHzP0TNrVmpfXYNHdqGGs=
github.com/smartcontractkit/go-plugin v0.0.0-20231003134350-e49dad63b306 h1:ko88+ZznniNJZbZPWAvHQU8SwKAdHngdDZ+pvVgB5ss=
Expand Down
3 changes: 1 addition & 2 deletions core/services/chainlink/relayer_factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,8 @@ import (
"errors"
"fmt"

"github.com/pelletier/go-toml/v2"

"github.com/jmoiron/sqlx"
"github.com/pelletier/go-toml/v2"

"github.com/smartcontractkit/chainlink-common/pkg/loop"
"github.com/smartcontractkit/chainlink-cosmos/pkg/cosmos"
Expand Down
1 change: 1 addition & 0 deletions core/services/functions/listener.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/smartcontractkit/libocr/commontypes"

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

"github.com/smartcontractkit/chainlink/v2/core/cbor"
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/client"
"github.com/smartcontractkit/chainlink/v2/core/logger"
Expand Down
1 change: 1 addition & 0 deletions core/services/ocr2/plugins/functions/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
libocr2 "github.com/smartcontractkit/libocr/offchainreporting2plus"

"github.com/smartcontractkit/chainlink-common/pkg/assets"

"github.com/smartcontractkit/chainlink/v2/core/bridges"
"github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm"
"github.com/smartcontractkit/chainlink/v2/core/logger"
Expand Down
68 changes: 68 additions & 0 deletions core/services/ocr2/plugins/median/plugin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package median

import (
"context"

"github.com/smartcontractkit/libocr/offchainreporting2/reportingplugin/median"
ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types"

"github.com/smartcontractkit/chainlink-common/pkg/logger"
"github.com/smartcontractkit/chainlink-common/pkg/loop"
"github.com/smartcontractkit/chainlink-common/pkg/services"
"github.com/smartcontractkit/chainlink-common/pkg/types"
)

type Plugin struct {
loop.Plugin
stop services.StopChan
}

func NewPlugin(lggr logger.Logger) *Plugin {
return &Plugin{Plugin: loop.Plugin{Logger: lggr}, stop: make(services.StopChan)}
}

func (p *Plugin) NewMedianFactory(ctx context.Context, provider types.MedianProvider, dataSource, juelsPerFeeCoin median.DataSource, errorLog loop.ErrorLog) (loop.ReportingPluginFactory, error) {
var ctxVals loop.ContextValues
ctxVals.SetValues(ctx)
lggr := logger.With(p.Logger, ctxVals.Args()...)

factory := median.NumericalMedianFactory{
ContractTransmitter: provider.MedianContract(),
DataSource: dataSource,
JuelsPerFeeCoinDataSource: juelsPerFeeCoin,
Logger: logger.NewOCRWrapper(lggr, true, func(msg string) {
ctx, cancelFn := p.stop.NewCtx()
defer cancelFn()
if err := errorLog.SaveError(ctx, msg); err != nil {
lggr.Errorw("Unable to save error", "err", msg)
}
}),
OnchainConfigCodec: provider.OnchainConfigCodec(),
ReportCodec: provider.ReportCodec(),
}
s := &reportingPluginFactoryService{lggr: logger.Named(lggr, "ReportingPluginFactory"), ReportingPluginFactory: factory}

p.SubService(s)

return s, nil
}

type reportingPluginFactoryService struct {
services.StateMachine
lggr logger.Logger
ocrtypes.ReportingPluginFactory
}

func (r *reportingPluginFactoryService) Name() string { return r.lggr.Name() }

func (r *reportingPluginFactoryService) Start(ctx context.Context) error {
return r.StartOnce("ReportingPluginFactory", func() error { return nil })
}

func (r *reportingPluginFactoryService) Close() error {
return r.StopOnce("ReportingPluginFactory", func() error { return nil })
}

func (r *reportingPluginFactoryService) HealthReport() map[string]error {
return map[string]error{r.Name(): r.Healthy()}
}
83 changes: 81 additions & 2 deletions core/services/ocr2/plugins/median/services.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,14 @@ import (
"encoding/json"
"errors"
"fmt"
"math/big"
"time"

"github.com/ethereum/go-ethereum/common"
libocr "github.com/smartcontractkit/libocr/offchainreporting2plus"
ocr2types "github.com/smartcontractkit/libocr/offchainreporting2plus/types"

mediantypes "github.com/smartcontractkit/libocr/offchainreporting2/reportingplugin/median"

"github.com/smartcontractkit/chainlink-common/pkg/loop"
"github.com/smartcontractkit/chainlink-common/pkg/types"
Expand Down Expand Up @@ -52,6 +57,21 @@ func (m *medianConfig) JobPipelineResultWriteQueueDepth() uint64 {
return m.jobPipelineResultWriteQueueDepth
}

// This wrapper avoids the need to modify the signature of NewMedianFactory in all of the non-evm
// relay repos as well as its primary definition in chainlink-common. Once ChainReader is implemented
// and working on all 4 blockchain families, we can remove the original MedianContract() method from
// MedianProvider and pass medianContract as a separate param to NewMedianFactory
type medianProviderWrapper struct {
types.MedianProvider
contract mediantypes.MedianContract
}

// Override relay's implementation of MedianContract with product plugin's implementation of
// MedianContract, making use of product-agnostic ChainReader to read the contract instead of relay MedianContract
func (m medianProviderWrapper) MedianContract() mediantypes.MedianContract {
return m.contract
}

func NewMedianServices(ctx context.Context,
jb job.Job,
isNewlyCreatedJob bool,
Expand Down Expand Up @@ -125,11 +145,24 @@ func NewMedianServices(ctx context.Context,
CreatedAt: time.Now(),
}, lggr)

if cmdName := env.MedianPluginCmd.Get(); cmdName != "" {
medianPluginCmd := env.MedianPluginCmd.Get()
medianLoopEnabled := medianPluginCmd != ""

// TODO BCF-2821 handle this properly as this blocks Solana chain reader dev
if !medianLoopEnabled && medianProvider.ChainReader() != nil {
lggr.Info("Chain Reader enabled")
medianProvider = medianProviderWrapper{
medianProvider, // attach newer MedianContract which uses ChainReader
newMedianContract(provider.ChainReader(), common.HexToAddress(spec.ContractID)),
}
} else {
lggr.Info("Chain Reader disabled")
}

if medianLoopEnabled {
// use unique logger names so we can use it to register a loop
medianLggr := lggr.Named("Median").Named(spec.ContractID).Named(spec.GetID())
cmdFn, telem, err2 := cfg.RegisterLOOP(medianLggr.Name(), cmdName)
cmdFn, telem, err2 := cfg.RegisterLOOP(medianLggr.Name(), medianPluginCmd)
if err2 != nil {
err = fmt.Errorf("failed to register loop: %w", err2)
abort()
Expand Down Expand Up @@ -159,3 +192,49 @@ func NewMedianServices(ctx context.Context,
}
return
}

type medianContract struct {
chainReader types.ChainReader
contract types.BoundContract
}

type latestTransmissionDetailsResponse struct {
configDigest ocr2types.ConfigDigest
epoch uint32
round uint8
latestAnswer *big.Int
latestTimestamp time.Time
}

type latestRoundRequested struct {
configDigest ocr2types.ConfigDigest
epoch uint32
round uint8
}

func (m *medianContract) LatestTransmissionDetails(ctx context.Context) (configDigest ocr2types.ConfigDigest, epoch uint32, round uint8, latestAnswer *big.Int, latestTimestamp time.Time, err error) {
var resp latestTransmissionDetailsResponse

err = m.chainReader.GetLatestValue(ctx, m.contract, "LatestTransmissionDetails", nil, &resp)
if err != nil {
return
}

return resp.configDigest, resp.epoch, resp.round, resp.latestAnswer, resp.latestTimestamp, err
}

func (m *medianContract) LatestRoundRequested(ctx context.Context, lookback time.Duration) (configDigest ocr2types.ConfigDigest, epoch uint32, round uint8, err error) {
var resp latestRoundRequested

err = m.chainReader.GetLatestValue(ctx, m.contract, "LatestRoundReported", map[string]string{}, &resp)
if err != nil {
return
}

return resp.configDigest, resp.epoch, resp.round, err
}

func newMedianContract(chainReader types.ChainReader, address common.Address) *medianContract {
contract := types.BoundContract{Address: address.String(), Name: "median", Pending: true}
return &medianContract{chainReader, contract}
}
2 changes: 1 addition & 1 deletion core/services/ocr2/plugins/mercury/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ func NewServices(
lggr,
saver,
chEnhancedTelem,
ocr2Provider.ChainReader(),
ocr2Provider.MercuryChainReader(),
ocr2Provider.MercuryServerFetcher(),
pluginConfig.InitialBlockNumber.Ptr(),
feedID,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ import (
ocrTypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types"

"github.com/smartcontractkit/chainlink-automation/pkg/v3/config"

"github.com/smartcontractkit/chainlink-common/pkg/types"

"github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"
Expand Down
1 change: 0 additions & 1 deletion core/services/ocr2/plugins/ocr2keeper/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import (
ocr2keepers20polling "github.com/smartcontractkit/chainlink-automation/pkg/v2/observer/polling"
ocr2keepers20runner "github.com/smartcontractkit/chainlink-automation/pkg/v2/runner"
ocr2keepers21 "github.com/smartcontractkit/chainlink-automation/pkg/v3/types"

"github.com/smartcontractkit/chainlink-common/pkg/types"

"github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm"
Expand Down
Loading

0 comments on commit c17067b

Please sign in to comment.