Skip to content

Commit

Permalink
Merge branch 'ccip-develop' into mk/fix-int-test-wf
Browse files Browse the repository at this point in the history
  • Loading branch information
winder authored Aug 19, 2024
2 parents 983cdc5 + 48726fd commit e8a2370
Show file tree
Hide file tree
Showing 28 changed files with 2,699 additions and 116 deletions.
6 changes: 3 additions & 3 deletions commit/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -226,11 +226,11 @@ func (p *Plugin) ValidateObservation(
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 Expand Up @@ -347,7 +347,7 @@ func (p *Plugin) ShouldTransmitAcceptedReport(
return false, fmt.Errorf("decode commit plugin report: %w", err)
}

isValid, err := validateMerkleRootsState(ctx, p.lggr, decodedReport, p.ccipReader)
isValid, err := ValidateMerkleRootsState(ctx, p.lggr, decodedReport, p.ccipReader)
if !isValid {
return false, nil
}
Expand Down
14 changes: 12 additions & 2 deletions commit/plugin_e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -404,18 +404,28 @@ func newNode(

func setupHomeChainPoller(lggr logger.Logger, chainConfigInfos []reader.ChainConfigInfo) reader.HomeChain {
homeChainReader := mocks.NewContractReaderMock()
var firstCall = true
homeChainReader.On(
"GetLatestValue",
mock.Anything,
consts.ContractNameCCIPConfig,
consts.MethodNameGetAllChainConfigs,
mock.Anything,
mock.Anything,
mock.MatchedBy(func(input map[string]interface{}) bool {
_, pageIndexExists := input["pageIndex"]
_, pageSizeExists := input["pageSize"]
return pageIndexExists && pageSizeExists
}),
mock.Anything,
).Run(
func(args mock.Arguments) {
arg := args.Get(5).(*[]reader.ChainConfigInfo)
*arg = chainConfigInfos
if firstCall {
*arg = chainConfigInfos
firstCall = false
} else {
*arg = []reader.ChainConfigInfo{} // return empty for other pages
}
}).Return(nil)

homeChain := reader.NewHomeChainConfigPoller(
Expand Down
8 changes: 4 additions & 4 deletions commit/plugin_functions.go
Original file line number Diff line number Diff line change
Expand Up @@ -559,7 +559,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 @@ -575,7 +575,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 All @@ -591,8 +591,8 @@ func validateObservedGasPrices(gasPrices []cciptypes.GasPriceChain) error {
return nil
}

// validateMerkleRootsState merkle roots seq nums validation by comparing with on-chain state.
func validateMerkleRootsState(
// ValidateMerkleRootsState merkle roots seq nums validation by comparing with on-chain state.
func ValidateMerkleRootsState(
ctx context.Context,
lggr logger.Logger,
report cciptypes.CommitPluginReport,
Expand Down
6 changes: 3 additions & 3 deletions commit/plugin_functions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -647,7 +647,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 @@ -700,7 +700,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 Expand Up @@ -1546,7 +1546,7 @@ func Test_validateMerkleRootsState(t *testing.T) {
chains = append(chains, snc.ChainSel)
}
reader.On("NextSeqNum", ctx, chains).Return(tc.onchainNextSeqNums, nil)
valid, err := validateMerkleRootsState(ctx, lggr, rep, reader)
valid, err := ValidateMerkleRootsState(ctx, lggr, rep, reader)
if tc.expErr {
assert.Error(t, err)
return
Expand Down
53 changes: 53 additions & 0 deletions commitrmnocb/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# OCR3 Commit Plugin

## Context
The purpose of the OCR3 Commit Plugin is to write reports to a configured destination chain. These reports
contain metadata of cross-chain messages, from a set of source chains, that can be executed on the destination chain.

## Commit Plugin Design

The plugin is implemented as a state machine, and moves from state to state each round. There are 3 states:
1. SelectingIntervalsForReport
- Determine intervals to be included in the next report
2. BuildingReport
- Build a report from the intervals determined in the previous round
3. WaitingForReportTransmission
- Check if the maximum committed sequence numbers on the dest chain have changed since generating the most
recent report, i.e. check if the report has been committed.
- If the maximum committed sequence numbers have changed (i.e. the report has been committed) or the maximum
number of check attempts have been exhausted, move to the SelectingIntervalsForReport state and generate a new
report.
- If the maximum committed sequence numbers have _not_ changed (i.e. the report is still in-flight) and the
maximum number of check attempts are not been exhausted, move to the WaitingForReportTransmission state in order
to check again.

This approach leads to a clear separation of concerns and addresses the complications that can arise if a report
is not successfully transmitted (as we explicitly only continue once we know the previous report has been committed).
In this design, full messages are no longer in the observations, only merkle roots and intervals are. This reduces the
size of observations, which reduces bandwidth and improves performance.

This is the state machine diagram. States are in boxes, outcomes are within arrows.

Start
|
V
-------------------------------
| SelectingIntervalsForReport | <---------|
------------------------------- |
| |
ReportIntervalsSelected |
| |
V |
------------------ |
| BuildingReport | -- ReportEmpty --->|
------------------ |
| ReportTransmitted
ReportGenerated or
| ReportNotTransmitted
V |
-------------------------------- |
| WaitingForReportTransmission | -------->|
--------------------------------
| ^
| |
ReportNotYetTransmitted
73 changes: 73 additions & 0 deletions commitrmnocb/chain_support.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package commitrmnocb

import (
"fmt"

mapset "github.com/deckarep/golang-set/v2"
"github.com/smartcontractkit/libocr/commontypes"
libocrtypes "github.com/smartcontractkit/libocr/ragep2p/types"

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

"github.com/smartcontractkit/chainlink-ccip/internal/libs/slicelib"
"github.com/smartcontractkit/chainlink-ccip/internal/reader"
)

// ChainSupport contains functions that enable an oracle to determine which chains are accessible by itself and
// other oracles
type ChainSupport interface {
// SupportedChains returns the set of chains that the given Oracle is configured to access
SupportedChains(oracleID commontypes.OracleID) (mapset.Set[cciptypes.ChainSelector], error)

// SupportsDestChain returns true if the given oracle supports the dest chain, returns false otherwise
SupportsDestChain(oracle commontypes.OracleID) (bool, error)

// KnownSourceChainsSlice returns a list of all known source chains
KnownSourceChainsSlice() ([]cciptypes.ChainSelector, error)
}

type CCIPChainSupport struct {
lggr logger.Logger
homeChain reader.HomeChain
oracleIDToP2pID map[commontypes.OracleID]libocrtypes.PeerID
nodeID commontypes.OracleID
destChain cciptypes.ChainSelector
}

func (c CCIPChainSupport) KnownSourceChainsSlice() ([]cciptypes.ChainSelector, error) {
knownSourceChains, err := c.homeChain.GetKnownCCIPChains()
if err != nil {
c.lggr.Errorw("error getting known chains", "err", err)
return nil, fmt.Errorf("error getting known chains: %w", err)
}
knownSourceChainsSlice := knownSourceChains.ToSlice()
return slicelib.Filter(knownSourceChainsSlice, func(ch cciptypes.ChainSelector) bool { return ch != c.destChain }), nil
}

// SupportedChains returns the set of chains that the given Oracle is configured to access
func (c CCIPChainSupport) SupportedChains(oracleID commontypes.OracleID) (mapset.Set[cciptypes.ChainSelector], error) {
p2pID, exists := c.oracleIDToP2pID[oracleID]
if !exists {
return nil, fmt.Errorf("oracle ID %d not found in oracleIDToP2pID", c.nodeID)
}
supportedChains, err := c.homeChain.GetSupportedChainsForPeer(p2pID)
if err != nil {
c.lggr.Warnw("error getting supported chains", err)
return mapset.NewSet[cciptypes.ChainSelector](), fmt.Errorf("error getting supported chains: %w", err)
}

return supportedChains, nil
}

// SupportsDestChain returns true if the given oracle supports the dest chain, returns false otherwise
func (c CCIPChainSupport) SupportsDestChain(oracle commontypes.OracleID) (bool, error) {
destChainConfig, err := c.homeChain.GetChainConfig(c.destChain)
if err != nil {
return false, fmt.Errorf("get chain config: %w", err)
}
return destChainConfig.SupportedNodes.Contains(c.oracleIDToP2pID[oracle]), nil
}

// Interface compliance check
var _ ChainSupport = (*CCIPChainSupport)(nil)
Loading

0 comments on commit e8a2370

Please sign in to comment.