Skip to content

Commit

Permalink
Node API OCR3 delegate support (#11993)
Browse files Browse the repository at this point in the history
* OCR3 delegate support

* -Move adapters
-Convert if statement to switch

* - Add adapters tests
- Pin to new version of chainlink-common

* - Pin to new version of chainlink-common

* Fix go sum

* Pin to latest version of chainlink-common
  • Loading branch information
george-dorin authored Feb 12, 2024
1 parent 2784f9b commit c84f1b5
Show file tree
Hide file tree
Showing 10 changed files with 312 additions and 55 deletions.
2 changes: 1 addition & 1 deletion core/scripts/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ require (
github.com/pelletier/go-toml/v2 v2.1.1
github.com/shopspring/decimal v1.3.1
github.com/smartcontractkit/chainlink-automation v1.0.2-0.20240118014648-1ab6a88c9429
github.com/smartcontractkit/chainlink-common v0.1.7-0.20240209032254-f9b58810d8ca
github.com/smartcontractkit/chainlink-common v0.1.7-0.20240212160026-5d1fecc0a699
github.com/smartcontractkit/chainlink-vrf v0.0.0-20231120191722-fef03814f868
github.com/smartcontractkit/chainlink/v2 v2.0.0-00010101000000-000000000000
github.com/smartcontractkit/libocr v0.0.0-20240112202000-6359502d2ff1
Expand Down
4 changes: 2 additions & 2 deletions core/scripts/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1169,8 +1169,8 @@ 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.2-0.20240118014648-1ab6a88c9429 h1:xkejUBZhcBpBrTSfxc91Iwzadrb6SXw8ks69bHIQ9Ww=
github.com/smartcontractkit/chainlink-automation v1.0.2-0.20240118014648-1ab6a88c9429/go.mod h1:wJmVvDf4XSjsahWtfUq3wvIAYEAuhr7oxmxYnEL/LGQ=
github.com/smartcontractkit/chainlink-common v0.1.7-0.20240209032254-f9b58810d8ca h1:Vtu+x4788S9stmuioWtfyxCKro7dwnqJFy96IuMRB7k=
github.com/smartcontractkit/chainlink-common v0.1.7-0.20240209032254-f9b58810d8ca/go.mod h1:pRlQrvcizMmuHAUV4N96oO2e3XbA99JCQELLc6ES160=
github.com/smartcontractkit/chainlink-common v0.1.7-0.20240212160026-5d1fecc0a699 h1:XZ5A3s+DyRSnPisks6scNRGrW6Egb0wsFreVb/UEdP8=
github.com/smartcontractkit/chainlink-common v0.1.7-0.20240212160026-5d1fecc0a699/go.mod h1:pRlQrvcizMmuHAUV4N96oO2e3XbA99JCQELLc6ES160=
github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240206150430-fbccaa95af62 h1:DuSQLuq+Ilm3Q+2zn5agLrAi9UvFQmOUdKwZQKX0AFA=
github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240206150430-fbccaa95af62/go.mod h1:Ny6kBD8Houh5yZRmGiB0ovsLHdb4qOHHwBno9JZUT+Y=
github.com/smartcontractkit/chainlink-data-streams v0.0.0-20231204152908-a6e3fe8ff2a1 h1:xYqRgZO0nMSO8CBCMR0r3WA+LZ4kNL8a6bnbyk/oBtQ=
Expand Down
121 changes: 76 additions & 45 deletions core/services/ocr2/delegate.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
ocr2keepers20runner "github.com/smartcontractkit/chainlink-automation/pkg/v2/runner"
ocr2keepers21config "github.com/smartcontractkit/chainlink-automation/pkg/v3/config"
ocr2keepers21 "github.com/smartcontractkit/chainlink-automation/pkg/v3/plugin"
"github.com/smartcontractkit/chainlink-common/pkg/loop/reportingplugins/ocr3"
"github.com/smartcontractkit/chainlink/v2/core/config/env"

"github.com/smartcontractkit/chainlink-vrf/altbn_128"
Expand Down Expand Up @@ -519,33 +520,33 @@ func (d *Delegate) newServicesGenericPlugin(

// NOTE: we don't need to validate this config, since that happens as part of creating the job.
// See: validate/validate.go's `validateSpec`.
p := validate.OCR2GenericPluginConfig{}
err = json.Unmarshal(spec.PluginConfig.Bytes(), &p)
pCfg := validate.OCR2GenericPluginConfig{}
err = json.Unmarshal(spec.PluginConfig.Bytes(), &pCfg)
if err != nil {
return nil, err
}

plugEnv := env.NewPlugin(p.PluginName)
plugEnv := env.NewPlugin(pCfg.PluginName)

command := p.Command
command := pCfg.Command
if command == "" {
command = plugEnv.Cmd.Get()
}

// Add the default pipeline to the pluginConfig
p.Pipelines = append(
p.Pipelines,
pCfg.Pipelines = append(
pCfg.Pipelines,
validate.PipelineSpec{Name: "__DEFAULT_PIPELINE__", Spec: jb.Pipeline.Source},
)

rid, err := spec.RelayID()
if err != nil {
return nil, ErrJobSpecNoRelayer{PluginName: p.PluginName, Err: err}
return nil, ErrJobSpecNoRelayer{PluginName: pCfg.PluginName, Err: err}
}

relayer, err := d.RelayGetter.Get(rid)
if err != nil {
return nil, ErrRelayNotEnabled{Err: err, Relay: spec.Relay, PluginName: p.PluginName}
return nil, ErrRelayNotEnabled{Err: err, Relay: spec.Relay, PluginName: pCfg.PluginName}
}

provider, err := relayer.NewPluginProvider(ctx, types.RelayArgs{
Expand All @@ -554,7 +555,7 @@ func (d *Delegate) newServicesGenericPlugin(
ContractID: spec.ContractID,
New: d.isNewlyCreatedJob,
RelayConfig: spec.RelayConfig.Bytes(),
ProviderType: p.ProviderType,
ProviderType: pCfg.ProviderType,
}, types.PluginArgs{
TransmitterID: spec.TransmitterID.String,
PluginConfig: spec.PluginConfig.Bytes(),
Expand All @@ -564,39 +565,19 @@ func (d *Delegate) newServicesGenericPlugin(
}
srvs = append(srvs, provider)

oracleEndpoint := d.monitoringEndpointGen.GenMonitoringEndpoint(
rid.Network,
rid.ChainID,
spec.ContractID,
synchronization.TelemetryType(p.TelemetryType),
)
oracleArgs := libocr2.OCR2OracleArgs{
BinaryNetworkEndpointFactory: d.peerWrapper.Peer2,
V2Bootstrappers: bootstrapPeers,
Database: ocrDB,
LocalConfig: lc,
Logger: ocrLogger,
MonitoringEndpoint: oracleEndpoint,
OffchainKeyring: kb,
OnchainKeyring: kb,
ContractTransmitter: provider.ContractTransmitter(),
ContractConfigTracker: provider.ContractConfigTracker(),
OffchainConfigDigester: provider.OffchainConfigDigester(),
}

envVars, err := plugins.ParseEnvFile(plugEnv.Env.Get())
if err != nil {
return nil, fmt.Errorf("failed to parse median env file: %w", err)
}
if len(p.EnvVars) > 0 {
for k, v := range p.EnvVars {
if len(pCfg.EnvVars) > 0 {
for k, v := range pCfg.EnvVars {
envVars = append(envVars, k+"="+v)
}
}

pluginLggr := lggr.Named(p.PluginName).Named(spec.ContractID).Named(spec.GetID())
pluginLggr := lggr.Named(pCfg.PluginName).Named(spec.ContractID).Named(spec.GetID())
cmdFn, grpcOpts, err := d.cfg.RegisterLOOP(plugins.CmdConfig{
ID: fmt.Sprintf("%s-%s-%s", p.PluginName, spec.ContractID, spec.GetID()),
ID: fmt.Sprintf("%s-%s-%s", pCfg.PluginName, spec.ContractID, spec.GetID()),
Cmd: command,
Env: envVars,
})
Expand All @@ -616,7 +597,7 @@ func (d *Delegate) newServicesGenericPlugin(
//TODO: remove this workaround when the EVM relayer is running inside of an LOOPP
d.lggr.Info("provider is not a LOOPP provider, switching to provider server")

ps, err2 := relay.NewProviderServer(provider, types.OCR2PluginType(p.ProviderType), d.lggr)
ps, err2 := relay.NewProviderServer(provider, types.OCR2PluginType(pCfg.ProviderType), d.lggr)
if err2 != nil {
return nil, fmt.Errorf("cannot start EVM provider server: %s", err)
}
Expand All @@ -627,32 +608,82 @@ func (d *Delegate) newServicesGenericPlugin(
srvs = append(srvs, ps)
}

pc, err := json.Marshal(p.Config)
pc, err := json.Marshal(pCfg.Config)
if err != nil {
return nil, fmt.Errorf("cannot dump plugin config to string before sending to plugin: %s", err)
}

pluginConfig := types.ReportingPluginServiceConfig{
PluginName: p.PluginName,
PluginName: pCfg.PluginName,
Command: command,
ProviderType: p.ProviderType,
TelemetryType: p.TelemetryType,
ProviderType: pCfg.ProviderType,
TelemetryType: pCfg.TelemetryType,
PluginConfig: string(pc),
}

pr := generic.NewPipelineRunnerAdapter(pluginLggr, jb, d.pipelineRunner)
ta := generic.NewTelemetryAdapter(d.monitoringEndpointGen)

plugin := reportingplugins.NewLOOPPService(pluginLggr, grpcOpts, cmdFn, pluginConfig, providerClientConn, pr, ta, errorLog)
oracleArgs.ReportingPluginFactory = plugin
srvs = append(srvs, plugin)
oracleEndpoint := d.monitoringEndpointGen.GenMonitoringEndpoint(
rid.Network,
rid.ChainID,
spec.ContractID,
synchronization.TelemetryType(pCfg.TelemetryType),
)

oracle, err := libocr2.NewOracle(oracleArgs)
if err != nil {
return nil, err
switch pCfg.OCRVersion {
case 2:
plugin := reportingplugins.NewLOOPPService(pluginLggr, grpcOpts, cmdFn, pluginConfig, providerClientConn, pr, ta, errorLog)
oracleArgs := libocr2.OCR2OracleArgs{
BinaryNetworkEndpointFactory: d.peerWrapper.Peer2,
V2Bootstrappers: bootstrapPeers,
Database: ocrDB,
LocalConfig: lc,
Logger: ocrLogger,
MonitoringEndpoint: oracleEndpoint,
OffchainKeyring: kb,
OnchainKeyring: kb,
ContractTransmitter: provider.ContractTransmitter(),
ContractConfigTracker: provider.ContractConfigTracker(),
OffchainConfigDigester: provider.OffchainConfigDigester(),
}
oracleArgs.ReportingPluginFactory = plugin
srvs = append(srvs, plugin)
oracle, err := libocr2.NewOracle(oracleArgs)
if err != nil {
return nil, err
}
srvs = append(srvs, job.NewServiceAdapter(oracle))

case 3:
//OCR3 with OCR2 OnchainKeyring and ContractTransmitter
plugin := ocr3.NewLOOPPService(pluginLggr, grpcOpts, cmdFn, pluginConfig, providerClientConn, pr, ta, errorLog)
contractTransmitter := ocrcommon.NewOCR3ContractTransmitterAdapter(provider.ContractTransmitter())
oracleArgs := libocr2.OCR3OracleArgs[any]{
BinaryNetworkEndpointFactory: d.peerWrapper.Peer2,
V2Bootstrappers: bootstrapPeers,
ContractConfigTracker: provider.ContractConfigTracker(),
ContractTransmitter: contractTransmitter,
Database: ocrDB,
LocalConfig: lc,
Logger: ocrLogger,
MonitoringEndpoint: oracleEndpoint,
OffchainConfigDigester: provider.OffchainConfigDigester(),
OffchainKeyring: kb,
OnchainKeyring: ocrcommon.NewOCR3OnchainKeyringAdapter(kb),
}
oracleArgs.ReportingPluginFactory = plugin
srvs = append(srvs, plugin)
oracle, err := libocr2.NewOracle(oracleArgs)
if err != nil {
return nil, err
}
srvs = append(srvs, job.NewServiceAdapter(oracle))

default:
return nil, fmt.Errorf("unknown OCR version: %d", pCfg.OCRVersion)
}

srvs = append(srvs, job.NewServiceAdapter(oracle))
return srvs, nil
}

Expand Down
2 changes: 1 addition & 1 deletion core/services/ocr2/validate/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
"github.com/lib/pq"
"github.com/pelletier/go-toml"
pkgerrors "github.com/pkg/errors"

libocr2 "github.com/smartcontractkit/libocr/offchainreporting2plus"

"github.com/smartcontractkit/chainlink-common/pkg/types"
Expand Down Expand Up @@ -141,6 +140,7 @@ type innerConfig struct {
ProviderType string `json:"providerType"`
PluginName string `json:"pluginName"`
TelemetryType string `json:"telemetryType"`
OCRVersion int `json:"OCRVersion"`
Config
}

Expand Down
73 changes: 73 additions & 0 deletions core/services/ocrcommon/adapters.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package ocrcommon

import (
"context"

"github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3types"
ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types"
)

var _ ocr3types.OnchainKeyring[any] = (*OCR3OnchainKeyringAdapter)(nil)

type OCR3OnchainKeyringAdapter struct {
o ocrtypes.OnchainKeyring
}

func NewOCR3OnchainKeyringAdapter(o ocrtypes.OnchainKeyring) *OCR3OnchainKeyringAdapter {
return &OCR3OnchainKeyringAdapter{o}
}

func (k *OCR3OnchainKeyringAdapter) PublicKey() ocrtypes.OnchainPublicKey {
return k.o.PublicKey()
}

func (k *OCR3OnchainKeyringAdapter) Sign(digest ocrtypes.ConfigDigest, seqNr uint64, r ocr3types.ReportWithInfo[any]) (signature []byte, err error) {
return k.o.Sign(ocrtypes.ReportContext{
ReportTimestamp: ocrtypes.ReportTimestamp{
ConfigDigest: digest,
Epoch: uint32(seqNr),
Round: 0,
},
ExtraHash: [32]byte(make([]byte, 32)),
}, r.Report)
}

func (k *OCR3OnchainKeyringAdapter) Verify(opk ocrtypes.OnchainPublicKey, digest ocrtypes.ConfigDigest, seqNr uint64, ri ocr3types.ReportWithInfo[any], signature []byte) bool {
return k.o.Verify(opk, ocrtypes.ReportContext{
ReportTimestamp: ocrtypes.ReportTimestamp{
ConfigDigest: digest,
Epoch: uint32(seqNr),
Round: 0,
},
ExtraHash: [32]byte(make([]byte, 32)),
}, ri.Report, signature)
}

func (k *OCR3OnchainKeyringAdapter) MaxSignatureLength() int {
return k.o.MaxSignatureLength()
}

var _ ocr3types.ContractTransmitter[any] = (*OCR3ContractTransmitterAdapter)(nil)

type OCR3ContractTransmitterAdapter struct {
ct ocrtypes.ContractTransmitter
}

func NewOCR3ContractTransmitterAdapter(ct ocrtypes.ContractTransmitter) *OCR3ContractTransmitterAdapter {
return &OCR3ContractTransmitterAdapter{ct}
}

func (c *OCR3ContractTransmitterAdapter) Transmit(ctx context.Context, digest ocrtypes.ConfigDigest, seqNr uint64, r ocr3types.ReportWithInfo[any], signatures []ocrtypes.AttributedOnchainSignature) error {
return c.ct.Transmit(ctx, ocrtypes.ReportContext{
ReportTimestamp: ocrtypes.ReportTimestamp{
ConfigDigest: digest,
Epoch: uint32(seqNr),
Round: 0,
},
ExtraHash: [32]byte(make([]byte, 32)),
}, r.Report, signatures)
}

func (c *OCR3ContractTransmitterAdapter) FromAccount() (ocrtypes.Account, error) {
return c.ct.FromAccount()
}
Loading

0 comments on commit c84f1b5

Please sign in to comment.