Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Leader lane multi-chain gas price reports #1071

Merged
merged 17 commits into from
Jun 27, 2024
Merged

Conversation

matYang
Copy link
Collaborator

@matYang matYang commented Jun 24, 2024

Previously, leader lane ORM was added to enabled Commit plugin to read multi-chain gas prices during Observation. This PR updates Report phase so Commit plugin can now report multi-chain gas prices.

Important changes are:

  1. make use of the PriceReportingDisabled flag to skip price reports on non-leader lanes
  2. update gas price logic during Report to handle multi-chain gas prices

@matYang matYang marked this pull request as ready for review June 24, 2024 05:28
@matYang matYang requested a review from a team as a code owner June 24, 2024 05:28
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're not committing any changesets anymore

if err != nil {
return nil, err
}

// For backwards compatibility with the order release during phased rollout, include the default gas price on this lane
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// For backwards compatibility with the order release during phased rollout, include the default gas price on this lane
// For backwards compatibility with the older release during phased rollout, include the default gas price on this lane

ctx context.Context,
) (gasPricesUSD map[uint64]*big.Int, tokenPricesUSD map[cciptypes.Address]*big.Int, err error) {
// Do not observe prices if price reporting is disabled. Price reporting will be disabled for lanes that are not leader lanes.
if r.offchainConfig.PriceReportingDisabled {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it worth logging in these scenarios or nah?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also sidenote I wish this was PriceReportingEnabled instead

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah me too, this was defined in April under a different leader lane architecture that got killed due to LOOPPS, but Engops already update the tooling to include this flag, didn't wanna change it again

// During phased-rollout where some honest nodes may not have started observing the token yet, it requires 5 malicious node with 1 being the leader to successfully alter price.
// During regular operation, it requires 3 malicious nodes with 1 being the leader to temporarily delay price update for the token.
if len(perChainPriceObservations) < (2*(f-1) + 1) {
lggr.Warnf("Skipping chain with selector %d due to not enough valid observations: #obs=%d, f=%d", selector, len(perChainPriceObservations), f)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Worth logging the actual 2f-1 value?

return nil, nil, err
}
if gasPriceUpdatedRecently && !gasPriceDeviated {
r.lggr.Debugw("gas price was updated recently, skipping the update",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To reflect the condition, maybe add and not deviated sufficiently?

gasPriceUpdatedRecently := time.Since(latestGasPrice.timestamp) < r.offchainConfig.GasPriceHeartBeat
gasPriceDeviated, err := r.gasPriceEstimator.Deviates(newGasPrice, latestGasPrice.value)
for chainSelector, gasPriceObservations := range gasPriceObs {
newGasPrice, err := r.gasPriceEstimator.Median(gasPriceObservations) // Compute the median price
if err != nil {
return nil, nil, err
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do these returned err values have enough context to figure out where we failed exactly? This has happened before where its hard to deduce the exact place things stopped working

@@ -38,6 +38,7 @@ type PriceService interface {

// GetGasAndTokenPrices fetches source chain gas prices and relevant token prices from all lanes that touch the given dest chain.
// The prices have been written into the DB by each lane's PriceService in the background. The prices are denoted in USD.
// If the results are empty, they are in the form of empty maps, as opposed to being nil.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an interesting API contract

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cleaned up, added nil checks on ocr2.go

}

// Fetches multi-lane gas prices and token prices, for the given dest chain
gasPricesUSD, tokenPricesUSD, err = r.priceService.GetGasAndTokenPrices(ctx, r.destChainSelector)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Worth checking that gasPricesUSD and tokenPricesUSD are not nil and erroring if they are? Thats a breakage in the API contract

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

after the API cleanup, added explicit nil check

if err != nil {
return nil, err
}
// Set prices to empty maps if nil to be friendlier to JSON encoding
if gasPricesUSD == nil {
gasPricesUSD = map[uint64]*big.Int{}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe better to do this inside r.observePriceUpdates(ctx)

gasPricesUSD = map[uint64]*big.Int{}
}
if tokenPricesUSD == nil {
tokenPricesUSD = map[cciptypes.Address]*big.Int{}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same

tokenPricesUSD = map[cciptypes.Address]*big.Int{}
}
// For backwards compatibility with the older release during phased rollout, set the default gas price on this lane
defaultGasPricesUSD := gasPricesUSD[r.sourceChainSelector]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rename var to defaultGasPriceUSD and check if it exists in the map?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

renamed to sourceGasPriceUSD, it's ok if it does not exist, nil for this value is supported

// Fetches multi-lane gas prices and token prices, for the given dest chain
gasPricesUSD, tokenPricesUSD, err = r.priceService.GetGasAndTokenPrices(ctx, r.destChainSelector)
if err != nil {
return nil, nil, err
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wrap err?

if !timestamp.Before(gasUpdate.timestamp) {
gasUpdate = update{
timestamp := time.Unix(priceUpdate.TimestampUnixSec.Int64(), 0)
if priceUpdate.Value != nil && !timestamp.Before(latestUpdates[priceUpdate.DestChainSelector].timestamp) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

check if latestUpdates[priceUpdate.DestChainSelector] exists?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

update is a struct, I think it's intended that latestUpdates[priceUpdate.DestChainSelector] may not exist, if it doesn't, then timestamp is 0 so !timestamp.Before is always true, and that initializes the value

@matYang matYang enabled auto-merge (squash) June 27, 2024 13:41
@matYang matYang merged commit dc8599f into ccip-develop Jun 27, 2024
100 checks passed
@matYang matYang deleted the leader-lane-obs branch June 27, 2024 13:56
jarnaud pushed a commit that referenced this pull request Jul 4, 2024
Previously, leader lane ORM was added to enabled Commit plugin to read
multi-chain gas prices during `Observation`. This PR updates `Report`
phase so Commit plugin can now report multi-chain gas prices.

Important changes are:
1. make use of the PriceReportingDisabled flag to skip price reports on
non-leader lanes
2. update gas price logic during Report to handle multi-chain gas prices
asoliman92 pushed a commit that referenced this pull request Jul 31, 2024
Previously, leader lane ORM was added to enabled Commit plugin to read
multi-chain gas prices during `Observation`. This PR updates `Report`
phase so Commit plugin can now report multi-chain gas prices.

Important changes are:
1. make use of the PriceReportingDisabled flag to skip price reports on
non-leader lanes
2. update gas price logic during Report to handle multi-chain gas prices
b-gopalswami added a commit that referenced this pull request Aug 5, 2024
… in Test (#1120)

## Motivation
This [PR](#1071) introduces
leader lane feature. Setting leader lane will avoid duplicate gas price
fetch for the same destination from different source chain. Here in this
PR, the expectation is to add a test where leader lane is setup and
verify every commitstore report transaction hash emitted two
`UsdPerUnitGasUpdated` events.

## Solution
Introduce config variable to enable leader lane setup and based on
network pair, automatically define set of lanes as leader and non-leader
lanes, track the tx hash from the event `UsdPerUnitGasUpdated` and
ensure transaction count matches to the number of sources chain selector
expected.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants