Skip to content

Commit

Permalink
Implement CommitPlugin with RMN OffChain Blessing
Browse files Browse the repository at this point in the history
  • Loading branch information
rstout committed Jul 9, 2024
1 parent c13d96d commit 113e94e
Show file tree
Hide file tree
Showing 10 changed files with 898 additions and 6 deletions.
4 changes: 2 additions & 2 deletions commit/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -220,11 +220,11 @@ func (p *Plugin) ValidateObservation(_ ocr3types.OutcomeContext, _ types.Query,
return fmt.Errorf("validate observer %d reading eligibility: %w", ao.Observer, err)
}

if err := validateObservedTokenPrices(obs.TokenPrices); err != nil {
if err := ValidateObservedTokenPrices(obs.TokenPrices); err != nil {
return fmt.Errorf("validate token prices: %w", err)
}

if err := validateObservedGasPrices(obs.GasPrices); err != nil {
if err := ValidateObservedGasPrices(obs.GasPrices); err != nil {
return fmt.Errorf("validate gas prices: %w", err)
}

Expand Down
4 changes: 2 additions & 2 deletions commit/plugin_functions.go
Original file line number Diff line number Diff line change
Expand Up @@ -557,7 +557,7 @@ func validateObserverReadingEligibility(
return nil
}

func validateObservedTokenPrices(tokenPrices []cciptypes.TokenPrice) error {
func ValidateObservedTokenPrices(tokenPrices []cciptypes.TokenPrice) error {
tokensWithPrice := mapset.NewSet[types.Account]()
for _, t := range tokenPrices {
if tokensWithPrice.Contains(t.TokenID) {
Expand All @@ -573,7 +573,7 @@ func validateObservedTokenPrices(tokenPrices []cciptypes.TokenPrice) error {
return nil
}

func validateObservedGasPrices(gasPrices []cciptypes.GasPriceChain) error {
func ValidateObservedGasPrices(gasPrices []cciptypes.GasPriceChain) error {
// Duplicate gas prices must not appear for the same chain and must not be empty.
gasPriceChains := mapset.NewSet[cciptypes.ChainSelector]()
for _, g := range gasPrices {
Expand Down
4 changes: 2 additions & 2 deletions commit/plugin_functions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -649,7 +649,7 @@ func Test_validateObservedTokenPrices(t *testing.T) {

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
err := validateObservedTokenPrices(tc.tokenPrices)
err := ValidateObservedTokenPrices(tc.tokenPrices)
if tc.expErr {
assert.Error(t, err)
return
Expand Down Expand Up @@ -702,7 +702,7 @@ func Test_validateObservedGasPrices(t *testing.T) {

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
err := validateObservedGasPrices(tc.gasPrices)
err := ValidateObservedGasPrices(tc.gasPrices)
if tc.expErr {
assert.Error(t, err)
return
Expand Down
1 change: 1 addition & 0 deletions commit_rmn_ocb/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
TODO: doc
162 changes: 162 additions & 0 deletions commit_rmn_ocb/observation.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
package commitRmnOcb

import (
"context"
"fmt"

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

"github.com/smartcontractkit/chainlink-ccip/plugintypes"

cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccipocr3"
)

func (p *Plugin) ObservationQuorum(_ ocr3types.OutcomeContext, _ types.Query) (ocr3types.Quorum, error) {
// Across all chains we require at least 2F+1 observations.
return ocr3types.QuorumTwoFPlusOne, nil
}

// Observation TODO: doc
func (p *Plugin) Observation(
ctx context.Context, outCtx ocr3types.OutcomeContext, _ types.Query,
) (types.Observation, error) {
previousOutcome, nextState := p.decodeOutcome(outCtx.PreviousOutcome)

switch nextState {
case SelectingRangesForReport:
return CommitPluginObservation{
OnRampMaxSeqNums: p.ObserveOnRampMaxSeqNums(),
OffRampMaxSeqNums: p.ObserveOffRampMaxSeqNums(),
FChain: p.ObserveFChain(),
}.Encode()

case BuildingReport:
return CommitPluginObservation{
MerkleRoots: p.ObserveMerkleRoots(previousOutcome.RangesSelectedForReport),
GasPrices: p.ObserveGasPrices(ctx),
TokenPrices: p.ObserveTokenPrices(ctx),
FChain: p.ObserveFChain(),
}.Encode()

case WaitingForReportTransmission:
return CommitPluginObservation{
OffRampMaxSeqNums: p.ObserveOffRampMaxSeqNums(),
FChain: p.ObserveFChain(),
}.Encode()

default:
p.log.Warnw("Unexpected state", "state", nextState)
return types.Observation{}, nil
}
}

// ObserveOnRampMaxSeqNums TODO: doc
func (p *Plugin) ObserveOnRampMaxSeqNums() []plugintypes.SeqNumChain {
onRampMaxSeqNums, err := p.onChain.GetOnRampMaxSeqNums()
if err != nil {
p.log.Warnw("call to GetOnRampMaxSeqNums failed", "err", err)
}

return onRampMaxSeqNums
}

// ObserveOffRampMaxSeqNums TODO: doc
func (p *Plugin) ObserveOffRampMaxSeqNums() []plugintypes.SeqNumChain {
offRampMaxSeqNums, err := p.onChain.GetOffRampMaxSeqNums()
if err != nil {
p.log.Warnw("call to GetOffRampMaxSeqNums failed", "err", err)
}

return offRampMaxSeqNums
}

// ObserveMerkleRoots TODO: doc
// Return empty array on error
func (p *Plugin) ObserveMerkleRoots(ranges []ChainRange) []MerkleRootAndChain {
roots, err := p.onChain.GetMerkleRoots(ranges)
if err != nil {
p.log.Warnw("call to GetMerkleRoots failed", "err", err)
return nil
}

return roots
}

// ObserveGasPrices TODO: doc
// Return empty array on error
func (p *Plugin) ObserveGasPrices(ctx context.Context) []cciptypes.GasPriceChain {
// TODO: Should this be sourceChains or supportedChains?
chains := p.sourceChains()
if len(chains) == 0 {
return []cciptypes.GasPriceChain{}
}

gasPrices, err := p.ccipReader.GasPrices(ctx, chains)
if err != nil {
p.log.Warnw("failed to get gas prices", "err", err)
return []cciptypes.GasPriceChain{}
}

if len(gasPrices) != len(chains) {
p.log.Warnw(
"gas prices length mismatch",
"len(gasPrices)", len(gasPrices),
"len(chains)", len(chains),
)
return []cciptypes.GasPriceChain{}
}

gasPricesGwei := make([]cciptypes.GasPriceChain, 0, len(chains))
for i, chain := range chains {
gasPricesGwei = append(gasPricesGwei, cciptypes.NewGasPriceChain(gasPrices[i].Int, chain))
}

return gasPricesGwei
}

// ObserveTokenPrices TODO: doc
// Return empty array on error
func (p *Plugin) ObserveTokenPrices(ctx context.Context) []cciptypes.TokenPrice {
tokenPrices, err := p.observeTokenPricesHelper(ctx)
if err != nil {
p.log.Warnw("call to ObserveTokenPrices failed", "err", err)
}
return tokenPrices
}

// ObserveTokenPricesHelper TODO: doc
// Return empty array on error
func (p *Plugin) observeTokenPricesHelper(ctx context.Context) ([]cciptypes.TokenPrice, error) {
if p.cfg.TokenPricesObserver {
tokenPrices, err := p.tokenPricesReader.GetTokenPricesUSD(ctx, p.cfg.PricedTokens)
if err != nil {
return nil, err
}

if len(tokenPrices) != len(p.cfg.PricedTokens) {
return nil, fmt.Errorf("token prices length mismatch: got %d, expected %d",
len(tokenPrices), len(p.cfg.PricedTokens))
}

tokenPricesUSD := make([]cciptypes.TokenPrice, 0, len(p.cfg.PricedTokens))
for i, token := range p.cfg.PricedTokens {
tokenPricesUSD = append(tokenPricesUSD, cciptypes.NewTokenPrice(token, tokenPrices[i]))
}

return tokenPricesUSD, nil
} else {

Check failure on line 148 in commit_rmn_ocb/observation.go

View workflow job for this annotation

GitHub Actions / build-lint-test (1.21)

indent-error-flow: if block ends with a return statement, so drop this else and outdent its block (revive)
return nil, nil
}
}

// ObserveFChain TODO: doc
// Return empty array on error
func (p *Plugin) ObserveFChain() map[cciptypes.ChainSelector]int {
fChain, err := p.homeChain.GetFChain()
if err != nil {
p.log.Warnw("call to GetFChain failed", "err", err)
return map[cciptypes.ChainSelector]int{}
}
return fChain
}
Loading

0 comments on commit 113e94e

Please sign in to comment.