-
Notifications
You must be signed in to change notification settings - Fork 60
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
Conversation
.changeset/sour-elephants-sell.md
Outdated
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// 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 { |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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", |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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. |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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{} |
There was a problem hiding this comment.
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{} |
There was a problem hiding this comment.
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] |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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) { |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
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
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
… 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.
Previously, leader lane ORM was added to enabled Commit plugin to read multi-chain gas prices during
Observation
. This PR updatesReport
phase so Commit plugin can now report multi-chain gas prices.Important changes are: